]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge git://www.linux-watchdog.org/linux-watchdog
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 23 May 2012 22:42:42 +0000 (15:42 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 23 May 2012 22:42:42 +0000 (15:42 -0700)
Pull first set of watchdog updates from Wim Van Sebroeck:
 "This pull contains:

   - The removal of ixp2000_wdt
   - The addition of ie6xx_wdt
   - Some documentation fixes
   - Small fixes and improvements

  (Note: Part 2 will contain generic watchdog core changes + conversion
  of some more drivers)"

* git://www.linux-watchdog.org/linux-watchdog:
  Documentation/watchdog: Fix the file descriptor leak when no cmdline arg given
  Documentation/watchdog: close the fd when cmdline arg given
  Documentation/watchdog: Fix a small typo
  watchdog: s3c2410_wdt: Set timeout to actually achieved timeout
  watchdog: wm831x: Convert to gpio_request_one()
  watchdog: via_wdt: depends on PCI
  watchdog: ie6xx_wdt needs io.h
  watchdog: ie6xx_wdt.c: fix printk format warning
  watchdog: Add watchdog driver for Intel Atom E6XX
  watchdog: it87_wdt: Add support for IT8728F watchdog.
  watchdog: i6300esb: don't depend on X86
  watchdog: Use module_pci_driver
  watchdog: sch311x_wdt.c: Remove RESGEN
  watchdog: s3c2410-wdt: Use of_match_ptr().
  watchdog: Device tree support for pnx4008-wdt
  watchdog: ar7_wdt.c: use devm_request_and_ioremap
  watchdog: remove ixp2000 driver
  watchdog: sp5100_tco.c: quiet sparse noise about using plain integer was NULL pointer

755 files changed:
Documentation/ABI/testing/debugfs-pfo-nx-crypto [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices-power
Documentation/ABI/testing/sysfs-power
Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mxs-saif.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt [new file with mode: 0644]
Documentation/hwmon/ina2xx [new file with mode: 0644]
Documentation/hwmon/it87
Documentation/kernel-parameters.txt
Documentation/power/suspend-and-cpuhotplug.txt
Documentation/sound/alsa/ALSA-Configuration.txt
MAINTAINERS
Makefile
arch/alpha/include/asm/processor.h
arch/arm/include/asm/processor.h
arch/arm/mach-imx/Kconfig
arch/arm/mach-imx/mach-mx31_3ds.c
arch/arm/mach-imx/mach-mx31moboard.c
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-tegra/board-dt-tegra20.c
arch/arm/mach-tegra/board-harmony.c
arch/arm/mach-tegra/board-seaboard.c
arch/arm/mach-tegra/board-trimslice.c
arch/arm/mach-tegra/devices.c
arch/arm/mach-tegra/devices.h
arch/arm/mach-tegra/tegra2_clocks.c
arch/avr32/include/asm/processor.h
arch/blackfin/include/asm/processor.h
arch/c6x/include/asm/processor.h
arch/cris/include/asm/processor.h
arch/frv/include/asm/processor.h
arch/frv/kernel/process.c
arch/h8300/include/asm/processor.h
arch/hexagon/Kconfig
arch/hexagon/Makefile
arch/hexagon/include/asm/processor.h
arch/hexagon/include/asm/spinlock_types.h
arch/hexagon/kernel/dma.c
arch/hexagon/kernel/time.c
arch/hexagon/mm/vm_fault.c
arch/ia64/include/asm/Kbuild
arch/ia64/include/asm/processor.h
arch/ia64/kernel/fsys.S
arch/m32r/include/asm/processor.h
arch/m68k/include/asm/processor.h
arch/microblaze/include/asm/processor.h
arch/mips/Kconfig
arch/mips/include/asm/processor.h
arch/mn10300/include/asm/processor.h
arch/mn10300/kernel/process.c
arch/openrisc/include/asm/processor.h
arch/parisc/include/asm/kbdleds.h [new file with mode: 0644]
arch/parisc/include/asm/processor.h
arch/powerpc/Kconfig
arch/powerpc/Makefile
arch/powerpc/boot/dts/bluestone.dts
arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
arch/powerpc/configs/g5_defconfig
arch/powerpc/configs/maple_defconfig
arch/powerpc/configs/mpc85xx_defconfig
arch/powerpc/configs/mpc85xx_smp_defconfig
arch/powerpc/configs/pasemi_defconfig
arch/powerpc/configs/ps3_defconfig
arch/powerpc/include/asm/asm-compat.h
arch/powerpc/include/asm/cputhreads.h
arch/powerpc/include/asm/hvcall.h
arch/powerpc/include/asm/lppaca.h
arch/powerpc/include/asm/lv1call.h
arch/powerpc/include/asm/pSeries_reconfig.h
arch/powerpc/include/asm/ppc_asm.h
arch/powerpc/include/asm/processor.h
arch/powerpc/include/asm/ptrace.h
arch/powerpc/include/asm/switch_to.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/include/asm/vio.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/head_44x.S
arch/powerpc/kernel/head_fsl_booke.S
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/ptrace.c
arch/powerpc/kernel/ptrace32.c
arch/powerpc/kernel/vector.S
arch/powerpc/kernel/vio.c
arch/powerpc/lib/copyuser_64.S
arch/powerpc/lib/mem_64.S
arch/powerpc/lib/memcpy_64.S
arch/powerpc/platforms/44x/Kconfig
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/powermac/low_i2c.c
arch/powerpc/platforms/ps3/Kconfig
arch/powerpc/platforms/ps3/mm.c
arch/powerpc/platforms/ps3/platform.h
arch/powerpc/platforms/ps3/repository.c
arch/powerpc/platforms/pseries/eeh.c
arch/powerpc/platforms/pseries/plpar_wrappers.h
arch/powerpc/platforms/pseries/reconfig.c
arch/powerpc/sysdev/ppc4xx_msi.c
arch/s390/include/asm/processor.h
arch/score/include/asm/processor.h
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/boards/Kconfig
arch/sh/boards/board-edosk7705.c
arch/sh/boards/board-edosk7760.c
arch/sh/boards/board-espt.c
arch/sh/boards/board-magicpanelr2.c
arch/sh/boards/board-polaris.c
arch/sh/boards/board-secureedge5410.c
arch/sh/boards/board-sh7757lcr.c
arch/sh/boards/board-sh7785lcr.c
arch/sh/boards/board-urquell.c
arch/sh/boards/mach-ap325rxa/setup.c
arch/sh/boards/mach-cayman/setup.c
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boards/mach-hp6xx/setup.c
arch/sh/boards/mach-kfr2r09/setup.c
arch/sh/boards/mach-lboxre2/setup.c
arch/sh/boards/mach-microdev/setup.c
arch/sh/boards/mach-migor/setup.c
arch/sh/boards/mach-rsk/Kconfig
arch/sh/boards/mach-rsk/Makefile
arch/sh/boards/mach-rsk/devices-rsk7264.c [new file with mode: 0644]
arch/sh/boards/mach-rsk/devices-rsk7269.c [new file with mode: 0644]
arch/sh/boards/mach-sdk7780/setup.c
arch/sh/boards/mach-se/7206/setup.c
arch/sh/boards/mach-se/770x/setup.c
arch/sh/boards/mach-se/7721/setup.c
arch/sh/boards/mach-se/7722/setup.c
arch/sh/boards/mach-se/7724/setup.c
arch/sh/boards/mach-se/7751/setup.c
arch/sh/boards/mach-se/7780/setup.c
arch/sh/boards/mach-se/board-se7619.c
arch/sh/boards/mach-sh03/setup.c
arch/sh/boards/mach-sh7763rdp/setup.c
arch/sh/configs/rsk7264_defconfig [new file with mode: 0644]
arch/sh/configs/rsk7269_defconfig [new file with mode: 0644]
arch/sh/drivers/dma/Kconfig
arch/sh/drivers/dma/dma-sh.c
arch/sh/drivers/dma/dma-sysfs.c
arch/sh/drivers/pci/fixups-landisk.c
arch/sh/drivers/pci/fixups-r7780rp.c
arch/sh/drivers/pci/fixups-sdk7780.c
arch/sh/drivers/pci/fixups-se7751.c
arch/sh/drivers/pci/fixups-sh03.c
arch/sh/drivers/pci/fixups-snapgear.c
arch/sh/drivers/pci/pcie-sh7786.c
arch/sh/include/asm/dma-sh.h [deleted file]
arch/sh/include/asm/dma.h
arch/sh/include/asm/fixmap.h
arch/sh/include/asm/i2c-sh7760.h
arch/sh/include/asm/io.h
arch/sh/include/asm/io_noioport.h [new file with mode: 0644]
arch/sh/include/asm/irq.h
arch/sh/include/asm/kdebug.h
arch/sh/include/asm/kgdb.h
arch/sh/include/asm/machvec.h
arch/sh/include/asm/pgtable_64.h
arch/sh/include/asm/processor.h
arch/sh/include/asm/processor_32.h
arch/sh/include/asm/processor_64.h
arch/sh/include/asm/stackprotector.h [new file with mode: 0644]
arch/sh/include/asm/thread_info.h
arch/sh/include/asm/traps_64.h
arch/sh/include/cpu-sh2/cpu/dma.h [deleted file]
arch/sh/include/cpu-sh2a/cpu/dma.h [deleted file]
arch/sh/include/cpu-sh2a/cpu/sh7264.h [new file with mode: 0644]
arch/sh/include/cpu-sh2a/cpu/sh7269.h [new file with mode: 0644]
arch/sh/include/cpu-sh3/cpu/dma.h
arch/sh/include/cpu-sh4/cpu/dma-sh4a.h [deleted file]
arch/sh/include/cpu-sh4/cpu/dma.h
arch/sh/include/cpu-sh4/cpu/freq.h
arch/sh/include/cpu-sh4/cpu/sh7734.h [new file with mode: 0644]
arch/sh/include/cpu-sh4a/cpu/dma.h [new file with mode: 0644]
arch/sh/include/cpu-sh5/cpu/dma.h [deleted file]
arch/sh/include/mach-common/mach/hp6xx.h
arch/sh/include/mach-common/mach/lboxre2.h
arch/sh/include/mach-common/mach/sdk7780.h
arch/sh/include/mach-common/mach/titan.h
arch/sh/include/mach-dreamcast/mach/dma.h
arch/sh/include/mach-landisk/mach/iodata_landisk.h
arch/sh/include/mach-se/mach/se.h
arch/sh/include/mach-se/mach/se7343.h
arch/sh/include/mach-se/mach/se7721.h
arch/sh/include/mach-se/mach/se7722.h
arch/sh/include/mach-se/mach/se7724.h
arch/sh/include/mach-se/mach/se7751.h
arch/sh/include/mach-se/mach/se7780.h
arch/sh/kernel/cpu/proc.c
arch/sh/kernel/cpu/sh2/setup-sh7619.c
arch/sh/kernel/cpu/sh2a/Makefile
arch/sh/kernel/cpu/sh2a/clock-sh7264.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2a/clock-sh7269.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2a/probe.c
arch/sh/kernel/cpu/sh2a/setup-mxg.c
arch/sh/kernel/cpu/sh2a/setup-sh7201.c
arch/sh/kernel/cpu/sh2a/setup-sh7203.c
arch/sh/kernel/cpu/sh2a/setup-sh7206.c
arch/sh/kernel/cpu/sh2a/setup-sh7264.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2a/setup-sh7269.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh3/entry.S
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh770x.c
arch/sh/kernel/cpu/sh3/setup-sh7710.c
arch/sh/kernel/cpu/sh3/setup-sh7720.c
arch/sh/kernel/cpu/sh4/probe.c
arch/sh/kernel/cpu/sh4/setup-sh4-202.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/setup-sh7760.c
arch/sh/kernel/cpu/sh4a/Makefile
arch/sh/kernel/cpu/sh4a/clock-sh7734.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/setup-sh7343.c
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/sh4a/setup-sh7724.c
arch/sh/kernel/cpu/sh4a/setup-sh7734.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/setup-sh7757.c
arch/sh/kernel/cpu/sh4a/setup-sh7763.c
arch/sh/kernel/cpu/sh4a/setup-sh7770.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c
arch/sh/kernel/cpu/sh4a/setup-shx3.c
arch/sh/kernel/cpu/sh5/entry.S
arch/sh/kernel/cpu/sh5/fpu.c
arch/sh/kernel/irq.c
arch/sh/kernel/kgdb.c
arch/sh/kernel/machvec.c
arch/sh/kernel/process.c
arch/sh/kernel/process_32.c
arch/sh/kernel/traps_64.c
arch/sh/mm/Makefile
arch/sh/mm/fault.c [new file with mode: 0644]
arch/sh/mm/fault_32.c [deleted file]
arch/sh/mm/fault_64.c [deleted file]
arch/sh/mm/tlb-sh5.c
arch/sh/mm/tlbex_32.c [new file with mode: 0644]
arch/sh/mm/tlbex_64.c [new file with mode: 0644]
arch/sh/mm/tlbflush_64.c
arch/sh/tools/mach-types
arch/sparc/include/asm/processor_32.h
arch/sparc/include/asm/processor_64.h
arch/tile/include/asm/processor.h
arch/um/Kconfig.common
arch/um/defconfig
arch/um/drivers/chan_kern.c
arch/um/drivers/line.c
arch/um/drivers/net_kern.c
arch/um/drivers/port_kern.c
arch/um/drivers/xterm_kern.c
arch/um/include/asm/pgtable.h
arch/um/include/asm/processor-generic.h
arch/um/include/asm/thread_info.h
arch/um/include/shared/irq_kern.h
arch/um/kernel/irq.c
arch/um/kernel/process.c
arch/um/kernel/signal.c
arch/um/kernel/skas/syscall.c
arch/um/kernel/tlb.c
arch/um/os-Linux/skas/mem.c
arch/unicore32/include/asm/processor.h
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/boot/compressed/eboot.c
arch/x86/boot/header.S
arch/x86/boot/main.c
arch/x86/boot/tools/build.c
arch/x86/ia32/ia32entry.S
arch/x86/ia32/sys_ia32.c
arch/x86/include/asm/asm.h
arch/x86/include/asm/bootparam.h
arch/x86/include/asm/device.h
arch/x86/include/asm/dma-mapping.h
arch/x86/include/asm/kbdleds.h [new file with mode: 0644]
arch/x86/include/asm/kdebug.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/mmzone_32.h
arch/x86/include/asm/msr.h
arch/x86/include/asm/nops.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/segment.h
arch/x86/include/asm/spinlock.h
arch/x86/include/asm/tlbflush.h
arch/x86/include/asm/uaccess.h
arch/x86/include/asm/xsave.h
arch/x86/kernel/check.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/mce_amd.c
arch/x86/kernel/cpu/perf_event_amd.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/dumpstack_32.c
arch/x86/kernel/dumpstack_64.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/kprobes.c
arch/x86/kernel/microcode_core.c
arch/x86/kernel/nmi.c
arch/x86/kernel/nmi_selftest.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/smp.c
arch/x86/kernel/test_rodata.c
arch/x86/kernel/vsmp_64.c
arch/x86/kernel/xsave.c
arch/x86/lib/checksum_32.S
arch/x86/lib/copy_user_64.S
arch/x86/lib/copy_user_nocache_64.S
arch/x86/lib/csum-copy_64.S
arch/x86/lib/getuser.S
arch/x86/lib/putuser.S
arch/x86/lib/usercopy_32.c
arch/x86/mm/extable.c
arch/x86/mm/init.c
arch/x86/mm/init_64.c
arch/x86/mm/tlb.c
arch/x86/pci/Makefile
arch/x86/pci/fixup.c
arch/x86/pci/sta2x11-fixup.c [new file with mode: 0644]
arch/x86/platform/olpc/olpc-xo1-sci.c
arch/x86/um/asm/elf.h
arch/x86/um/asm/ptrace.h
arch/x86/um/asm/ptrace_32.h
arch/x86/um/asm/ptrace_64.h
arch/x86/um/checksum_32.S
arch/x86/um/shared/sysdep/ptrace.h
arch/x86/um/shared/sysdep/ptrace_32.h
arch/x86/um/shared/sysdep/ptrace_64.h
arch/x86/um/signal.c
arch/x86/um/sys_call_table_64.c
arch/x86/um/syscalls_32.c
arch/x86/um/sysrq_32.c
arch/x86/um/sysrq_64.c
arch/x86/um/tls_32.c
arch/x86/xen/xen-asm_32.S
arch/xtensa/include/asm/processor.h
arch/xtensa/kernel/process.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ata_generic.c
drivers/ata/ata_piix.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/pata_ep93xx.c [new file with mode: 0644]
drivers/base/power/domain.c
drivers/base/power/domain_governor.c
drivers/base/power/main.c
drivers/base/power/qos.c
drivers/base/power/runtime.c
drivers/base/power/sysfs.c
drivers/base/power/wakeup.c
drivers/base/regmap/Kconfig
drivers/char/hw_random/Kconfig
drivers/char/hw_random/Makefile
drivers/char/hw_random/pseries-rng.c [new file with mode: 0644]
drivers/crypto/Kconfig
drivers/crypto/nx/Makefile [new file with mode: 0644]
drivers/crypto/nx/nx-aes-cbc.c [new file with mode: 0644]
drivers/crypto/nx/nx-aes-ccm.c [new file with mode: 0644]
drivers/crypto/nx/nx-aes-ctr.c [new file with mode: 0644]
drivers/crypto/nx/nx-aes-ecb.c [new file with mode: 0644]
drivers/crypto/nx/nx-aes-gcm.c [new file with mode: 0644]
drivers/crypto/nx/nx-aes-xcbc.c [new file with mode: 0644]
drivers/crypto/nx/nx-sha256.c [new file with mode: 0644]
drivers/crypto/nx/nx-sha512.c [new file with mode: 0644]
drivers/crypto/nx/nx.c [new file with mode: 0644]
drivers/crypto/nx/nx.h [new file with mode: 0644]
drivers/crypto/nx/nx_csbcpb.h [new file with mode: 0644]
drivers/crypto/nx/nx_debugfs.c [new file with mode: 0644]
drivers/devfreq/governor_performance.c
drivers/devfreq/governor_powersave.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/acpi_power_meter.c
drivers/hwmon/ad7314.c
drivers/hwmon/fam15h_power.c
drivers/hwmon/ina2xx.c [new file with mode: 0644]
drivers/hwmon/it87.c
drivers/hwmon/k10temp.c
drivers/hwmon/k8temp.c
drivers/hwmon/ntc_thermistor.c
drivers/i2c/busses/i2c-powermac.c
drivers/macintosh/Kconfig
drivers/macintosh/Makefile
drivers/macintosh/ams/ams-i2c.c
drivers/macintosh/therm_adt746x.c
drivers/macintosh/windfarm.h
drivers/macintosh/windfarm_ad7417_sensor.c [new file with mode: 0644]
drivers/macintosh/windfarm_core.c
drivers/macintosh/windfarm_cpufreq_clamp.c
drivers/macintosh/windfarm_fcu_controls.c [new file with mode: 0644]
drivers/macintosh/windfarm_lm75_sensor.c
drivers/macintosh/windfarm_lm87_sensor.c [new file with mode: 0644]
drivers/macintosh/windfarm_max6690_sensor.c
drivers/macintosh/windfarm_mpu.h [new file with mode: 0644]
drivers/macintosh/windfarm_pm72.c [new file with mode: 0644]
drivers/macintosh/windfarm_pm81.c
drivers/macintosh/windfarm_pm91.c
drivers/macintosh/windfarm_rm31.c [new file with mode: 0644]
drivers/macintosh/windfarm_smu_controls.c
drivers/macintosh/windfarm_smu_sat.c
drivers/mfd/Kconfig
drivers/mfd/mc13xxx-core.c
drivers/ps3/ps3av.c
drivers/sh/clk/cpg.c
drivers/sh/intc/dynamic.c
drivers/tty/serial/sh-sci.c
drivers/tty/vt/keyboard.c
drivers/watchdog/Kconfig
drivers/watchdog/shwdt.c
fs/eventpoll.c
fs/exec.c
include/linux/capability.h
include/linux/cs5535.h
include/linux/eventpoll.h
include/linux/irq.h
include/linux/libata.h
include/linux/mfd/mc13xxx.h
include/linux/perf_event.h
include/linux/platform_data/ina2xx.h [new file with mode: 0644]
include/linux/pm.h
include/linux/pm_domain.h
include/linux/pm_runtime.h
include/linux/pm_wakeup.h
include/linux/serial_sci.h
include/linux/sh_clk.h
include/linux/sh_intc.h
include/linux/suspend.h
include/sound/asound.h
include/sound/asoundef.h
include/sound/cs42l52.h [new file with mode: 0644]
include/sound/max98095.h
include/sound/sh_fsi.h
include/sound/simple_card.h [new file with mode: 0644]
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc-dpcm.h [new file with mode: 0644]
include/sound/soc.h
include/trace/events/asoc.h
include/trace/events/power.h
init/Kconfig
kernel/events/core.c
kernel/extable.c
kernel/fork.c
kernel/irq/manage.c
kernel/power/Kconfig
kernel/power/Makefile
kernel/power/autosleep.c [new file with mode: 0644]
kernel/power/hibernate.c
kernel/power/main.c
kernel/power/power.h
kernel/power/swap.c
kernel/power/wakelock.c [new file with mode: 0644]
kernel/sched/core.c
lib/Kconfig.debug
scripts/.gitignore
scripts/Makefile
scripts/sortextable.c [new file with mode: 0644]
scripts/sortextable.h [new file with mode: 0644]
sound/atmel/ac97c.c
sound/core/jack.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/sound_oss.c
sound/drivers/aloop.c
sound/firewire/amdtp.c
sound/firewire/amdtp.h
sound/pci/Kconfig
sound/pci/ad1889.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.c
sound/pci/aw2/aw2-alsa.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106_main.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs5530.c
sound/pci/cs5535audio/cs5535audio.c
sound/pci/ctxfi/xfi.c
sound/pci/echoaudio/echoaudio.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/Makefile
sound/pci/hda/hda_auto_parser.c [new file with mode: 0644]
sound/pci/hda/hda_auto_parser.h [new file with mode: 0644]
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_jack.h
sound/pci/hda/hda_local.h
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/lola/lola.c
sound/pci/lx6464es/lx6464es.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/virtuoso.c
sound/pci/oxygen/xonar_dg.c
sound/pci/pcxhr/pcxhr.c
sound/pci/riptide/riptide.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/sis7019.c
sound/pci/sonicvibes.c
sound/pci/trident/trident.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/ymfpci/ymfpci.c
sound/sh/sh_dac_audio.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/blackfin/bf5xx-ssm2602.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad193x.c
sound/soc/codecs/adau1701.c
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/alc5623.c
sound/soc/codecs/alc5632.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs4271.c
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cs42l52.c [new file with mode: 0644]
sound/soc/codecs/cs42l52.h [new file with mode: 0644]
sound/soc/codecs/cs42l73.c
sound/soc/codecs/da7210.c
sound/soc/codecs/jz4740.c
sound/soc/codecs/lm49453.c [new file with mode: 0644]
sound/soc/codecs/lm49453.h [new file with mode: 0644]
sound/soc/codecs/max98095.c
sound/soc/codecs/max98095.h
sound/soc/codecs/mc13783.c [new file with mode: 0644]
sound/soc/codecs/mc13783.h [new file with mode: 0644]
sound/soc/codecs/ml26124.c [new file with mode: 0644]
sound/soc/codecs/ml26124.h [new file with mode: 0644]
sound/soc/codecs/omap-hdmi.c [new file with mode: 0644]
sound/soc/codecs/rt5631.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic26.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/uda134x.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wl1273.c
sound/soc/codecs/wm1250-ev1.c
sound/soc/codecs/wm5100-tables.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5100.h
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8737.c
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm8996.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm_hubs.c
sound/soc/codecs/wm_hubs.h
sound/soc/ep93xx/ep93xx-ac97.c
sound/soc/ep93xx/ep93xx-i2s.c
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/eukrea-tlv320.c [moved from sound/soc/imx/eukrea-tlv320.c with 99% similarity]
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/fsl_utils.c [new file with mode: 0644]
sound/soc/fsl/fsl_utils.h [new file with mode: 0644]
sound/soc/fsl/imx-audmux.c [moved from sound/soc/imx/imx-audmux.c with 100% similarity]
sound/soc/fsl/imx-audmux.h [moved from sound/soc/imx/imx-audmux.h with 100% similarity]
sound/soc/fsl/imx-mc13783.c [new file with mode: 0644]
sound/soc/fsl/imx-pcm-dma.c [moved from sound/soc/imx/imx-pcm-dma-mx2.c with 97% similarity]
sound/soc/fsl/imx-pcm-fiq.c [moved from sound/soc/imx/imx-pcm-fiq.c with 100% similarity]
sound/soc/fsl/imx-pcm.c [moved from sound/soc/imx/imx-pcm.c with 100% similarity]
sound/soc/fsl/imx-pcm.h [moved from sound/soc/imx/imx-pcm.h with 93% similarity]
sound/soc/fsl/imx-sgtl5000.c [new file with mode: 0644]
sound/soc/fsl/imx-ssi.c [moved from sound/soc/imx/imx-ssi.c with 99% similarity]
sound/soc/fsl/imx-ssi.h [moved from sound/soc/imx/imx-ssi.h with 100% similarity]
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/fsl/mx27vis-aic32x4.c [moved from sound/soc/imx/mx27vis-aic32x4.c with 100% similarity]
sound/soc/fsl/p1022_ds.c
sound/soc/fsl/phycore-ac97.c [moved from sound/soc/imx/phycore-ac97.c with 100% similarity]
sound/soc/fsl/wm1133-ev1.c [moved from sound/soc/imx/wm1133-ev1.c with 100% similarity]
sound/soc/generic/Kconfig [new file with mode: 0644]
sound/soc/generic/Makefile [new file with mode: 0644]
sound/soc/generic/simple-card.c [new file with mode: 0644]
sound/soc/imx/Kconfig [deleted file]
sound/soc/imx/Makefile [deleted file]
sound/soc/jz4740/jz4740-i2s.c
sound/soc/mxs/mxs-pcm.c
sound/soc/mxs/mxs-pcm.h
sound/soc/mxs/mxs-saif.c
sound/soc/mxs/mxs-saif.h
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/omap/Kconfig
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/samsung/littlemill.c
sound/soc/samsung/lowland.c
sound/soc/samsung/speyside.c
sound/soc/sh/Kconfig
sound/soc/sh/Makefile
sound/soc/sh/fsi-ak4642.c [deleted file]
sound/soc/sh/fsi-da7210.c [deleted file]
sound/soc/sh/fsi-hdmi.c [deleted file]
sound/soc/sh/fsi.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-jack.c
sound/soc/soc-pcm.c
sound/soc/tegra/Kconfig
sound/soc/tegra/Makefile
sound/soc/tegra/tegra20_das.c [new file with mode: 0644]
sound/soc/tegra/tegra20_das.h [new file with mode: 0644]
sound/soc/tegra/tegra20_i2s.c [new file with mode: 0644]
sound/soc/tegra/tegra20_i2s.h [new file with mode: 0644]
sound/soc/tegra/tegra20_spdif.c [new file with mode: 0644]
sound/soc/tegra/tegra20_spdif.h [new file with mode: 0644]
sound/soc/tegra/tegra30_ahub.c [new file with mode: 0644]
sound/soc/tegra/tegra30_ahub.h [new file with mode: 0644]
sound/soc/tegra/tegra30_i2s.c [new file with mode: 0644]
sound/soc/tegra/tegra30_i2s.h [new file with mode: 0644]
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_asoc_utils.c
sound/soc/tegra/tegra_asoc_utils.h
sound/soc/tegra/tegra_das.c [deleted file]
sound/soc/tegra/tegra_das.h [deleted file]
sound/soc/tegra/tegra_i2s.c [deleted file]
sound/soc/tegra/tegra_i2s.h [deleted file]
sound/soc/tegra/tegra_pcm.c
sound/soc/tegra/tegra_pcm.h
sound/soc/tegra/tegra_spdif.c [deleted file]
sound/soc/tegra/tegra_spdif.h [deleted file]
sound/soc/tegra/tegra_wm8753.c [new file with mode: 0644]
sound/soc/tegra/tegra_wm8903.c
sound/soc/tegra/trimslice.c
sound/soc/ux500/Kconfig [new file with mode: 0644]
sound/soc/ux500/Makefile [new file with mode: 0644]
sound/soc/ux500/ux500_msp_dai.c [new file with mode: 0644]
sound/soc/ux500/ux500_msp_dai.h [new file with mode: 0644]
sound/soc/ux500/ux500_msp_i2s.c [new file with mode: 0644]
sound/soc/ux500/ux500_msp_i2s.h [new file with mode: 0644]
sound/sound_core.c
sound/usb/card.c
sound/usb/card.h
sound/usb/endpoint.c
sound/usb/endpoint.h
sound/usb/mixer.c
sound/usb/mixer.h
sound/usb/mixer_maps.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
sound/usb/proc.c
sound/usb/stream.c
sound/usb/usbaudio.h
tools/perf/Documentation/perf-evlist.txt
tools/perf/Documentation/perf-record.txt
tools/perf/Makefile
tools/perf/builtin-buildid-list.c
tools/perf/builtin-evlist.c
tools/perf/builtin-inject.c
tools/perf/builtin-record.c
tools/perf/builtin-test.c
tools/perf/builtin-top.c
tools/perf/util/build-id.c
tools/perf/util/evsel.c
tools/perf/util/header.c
tools/perf/util/header.h
tools/perf/util/parse-events-test.c [new file with mode: 0644]
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-events.l
tools/perf/util/parse-events.y
tools/perf/util/pmu.c
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/session.c
tools/perf/util/types.h
tools/testing/ktest/sample.conf

diff --git a/Documentation/ABI/testing/debugfs-pfo-nx-crypto b/Documentation/ABI/testing/debugfs-pfo-nx-crypto
new file mode 100644 (file)
index 0000000..685d5a4
--- /dev/null
@@ -0,0 +1,45 @@
+What:          /sys/kernel/debug/nx-crypto/*
+Date:          March 2012
+KernelVersion: 3.4
+Contact:       Kent Yoder <key@linux.vnet.ibm.com>
+Description:
+
+  These debugfs interfaces are built by the nx-crypto driver, built in
+arch/powerpc/crypto/nx.
+
+Error Detection
+===============
+
+errors:
+- A u32 providing a total count of errors since the driver was loaded. The
+only errors counted here are those returned from the hcall, H_COP_OP.
+
+last_error:
+- The most recent non-zero return code from the H_COP_OP hcall. -EBUSY is not
+recorded here (the hcall will retry until -EBUSY goes away).
+
+last_error_pid:
+- The process ID of the process who received the most recent error from the
+hcall.
+
+Device Use
+==========
+
+aes_bytes:
+- The total number of bytes encrypted using AES in any of the driver's
+supported modes.
+
+aes_ops:
+- The total number of AES operations submitted to the hardware.
+
+sha256_bytes:
+- The total number of bytes hashed by the hardware using SHA-256.
+
+sha256_ops:
+- The total number of SHA-256 operations submitted to the hardware.
+
+sha512_bytes:
+- The total number of bytes hashed by the hardware using SHA-512.
+
+sha512_ops:
+- The total number of SHA-512 operations submitted to the hardware.
index 840f7d64d4835f5c93227ea9f948ac7f83116b31..45000f0db4d4b4f7779ee9dbd44e727613a930cf 100644 (file)
@@ -96,16 +96,26 @@ Description:
                is read-only.  If the device is not enabled to wake up the
                system from sleep states, this attribute is not present.
 
-What:          /sys/devices/.../power/wakeup_hit_count
-Date:          September 2010
+What:          /sys/devices/.../power/wakeup_abort_count
+Date:          February 2012
 Contact:       Rafael J. Wysocki <rjw@sisk.pl>
 Description:
-               The /sys/devices/.../wakeup_hit_count attribute contains the
+               The /sys/devices/.../wakeup_abort_count attribute contains the
                number of times the processing of a wakeup event associated with
-               the device might prevent the system from entering a sleep state.
-               This attribute is read-only.  If the device is not enabled to
-               wake up the system from sleep states, this attribute is not
-               present.
+               the device might have aborted system transition into a sleep
+               state in progress.  This attribute is read-only.  If the device
+               is not enabled to wake up the system from sleep states, this
+               attribute is not present.
+
+What:          /sys/devices/.../power/wakeup_expire_count
+Date:          February 2012
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/devices/.../wakeup_expire_count attribute contains the
+               number of times a wakeup event associated with the device has
+               been reported with a timeout that expired.  This attribute is
+               read-only.  If the device is not enabled to wake up the system
+               from sleep states, this attribute is not present.
 
 What:          /sys/devices/.../power/wakeup_active
 Date:          September 2010
@@ -148,6 +158,17 @@ Description:
                not enabled to wake up the system from sleep states, this
                attribute is not present.
 
+What:          /sys/devices/.../power/wakeup_prevent_sleep_time_ms
+Date:          February 2012
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/devices/.../wakeup_prevent_sleep_time_ms attribute
+               contains the total time the device has been preventing
+               opportunistic transitions to sleep states from occuring.
+               This attribute is read-only.  If the device is not enabled to
+               wake up the system from sleep states, this attribute is not
+               present.
+
 What:          /sys/devices/.../power/autosuspend_delay_ms
 Date:          September 2010
 Contact:       Alan Stern <stern@rowland.harvard.edu>
index b464d12761baf81023bb35da2e3aba01049fc81a..31725ffeeb3a3bc09bb4c712a3f88bfbe941aae8 100644 (file)
@@ -172,3 +172,62 @@ Description:
 
                Reading from this file will display the current value, which is
                set to 1 MB by default.
+
+What:          /sys/power/autosleep
+Date:          April 2012
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/power/autosleep file can be written one of the strings
+               returned by reads from /sys/power/state.  If that happens, a
+               work item attempting to trigger a transition of the system to
+               the sleep state represented by that string is queued up.  This
+               attempt will only succeed if there are no active wakeup sources
+               in the system at that time.  After every execution, regardless
+               of whether or not the attempt to put the system to sleep has
+               succeeded, the work item requeues itself until user space
+               writes "off" to /sys/power/autosleep.
+
+               Reading from this file causes the last string successfully
+               written to it to be returned.
+
+What:          /sys/power/wake_lock
+Date:          February 2012
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/power/wake_lock file allows user space to create
+               wakeup source objects and activate them on demand (if one of
+               those wakeup sources is active, reads from the
+               /sys/power/wakeup_count file block or return false).  When a
+               string without white space is written to /sys/power/wake_lock,
+               it will be assumed to represent a wakeup source name.  If there
+               is a wakeup source object with that name, it will be activated
+               (unless active already).  Otherwise, a new wakeup source object
+               will be registered, assigned the given name and activated.
+               If a string written to /sys/power/wake_lock contains white
+               space, the part of the string preceding the white space will be
+               regarded as a wakeup source name and handled as descrived above.
+               The other part of the string will be regarded as a timeout (in
+               nanoseconds) such that the wakeup source will be automatically
+               deactivated after it has expired.  The timeout, if present, is
+               set regardless of the current state of the wakeup source object
+               in question.
+
+               Reads from this file return a string consisting of the names of
+               wakeup sources created with the help of it that are active at
+               the moment, separated with spaces.
+
+
+What:          /sys/power/wake_unlock
+Date:          February 2012
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/power/wake_unlock file allows user space to deactivate
+               wakeup sources created with the help of /sys/power/wake_lock.
+               When a string is written to /sys/power/wake_unlock, it will be
+               assumed to represent the name of a wakeup source to deactivate.
+               If a wakeup source object of that name exists and is active at
+               the moment, it will be deactivated.
+
+               Reads from this file return a string consisting of the names of
+               wakeup sources created with the help of /sys/power/wake_lock
+               that are inactive at the moment, separated with spaces.
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt
new file mode 100644 (file)
index 0000000..e4acdd8
--- /dev/null
@@ -0,0 +1,49 @@
+Freescale i.MX audio complex with SGTL5000 codec
+
+Required properties:
+- compatible : "fsl,imx-audio-sgtl5000"
+- model : The user-visible name of this sound complex
+- ssi-controller : The phandle of the i.MX SSI controller
+- audio-codec : The phandle of the SGTL5000 audio codec
+- audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names could be power
+  supplies, SGTL5000 pins, and the jacks on the board:
+
+  Power supplies:
+   * Mic Bias
+
+  SGTL5000 pins:
+   * MIC_IN
+   * LINE_IN
+   * HP_OUT
+   * LINE_OUT
+
+  Board connectors:
+   * Mic Jack
+   * Line In Jack
+   * Headphone Jack
+   * Line Out Jack
+   * Ext Spk
+
+- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
+- mux-ext-port : The external port of the i.MX audio muxer
+
+Note: The AUDMUX port numbering should start at 1, which is consistent with
+hardware manual.
+
+Example:
+
+sound {
+       compatible = "fsl,imx51-babbage-sgtl5000",
+                    "fsl,imx-audio-sgtl5000";
+       model = "imx51-babbage-sgtl5000";
+       ssi-controller = <&ssi1>;
+       audio-codec = <&sgtl5000>;
+       audio-routing =
+               "MIC_IN", "Mic Jack",
+               "Mic Jack", "Mic Bias",
+               "Headphone Jack", "HP_OUT";
+       mux-int-port = <1>;
+       mux-ext-port = <3>;
+};
diff --git a/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt
new file mode 100644 (file)
index 0000000..601c518
--- /dev/null
@@ -0,0 +1,17 @@
+* Freescale MXS audio complex with SGTL5000 codec
+
+Required properties:
+- compatible: "fsl,mxs-audio-sgtl5000"
+- model: The user-visible name of this sound complex
+- saif-controllers: The phandle list of the MXS SAIF controller
+- audio-codec: The phandle of the SGTL5000 audio codec
+
+Example:
+
+sound {
+       compatible = "fsl,imx28-evk-sgtl5000",
+                    "fsl,mxs-audio-sgtl5000";
+       model = "imx28-evk-sgtl5000";
+       saif-controllers = <&saif0 &saif1>;
+       audio-codec = <&sgtl5000>;
+};
diff --git a/Documentation/devicetree/bindings/sound/mxs-saif.txt b/Documentation/devicetree/bindings/sound/mxs-saif.txt
new file mode 100644 (file)
index 0000000..c37ba61
--- /dev/null
@@ -0,0 +1,36 @@
+* Freescale MXS Serial Audio Interface (SAIF)
+
+Required properties:
+- compatible: Should be "fsl,<chip>-saif"
+- reg: Should contain registers location and length
+- interrupts: Should contain ERROR and DMA interrupts
+- fsl,saif-dma-channel: APBX DMA channel for the SAIF
+
+Optional properties:
+- fsl,saif-master: phandle to the master SAIF.  It's only required for
+  the slave SAIF.
+
+Note: Each SAIF controller should have an alias correctly numbered
+in "aliases" node.
+
+Example:
+
+aliases {
+       saif0 = &saif0;
+       saif1 = &saif1;
+};
+
+saif0: saif@80042000 {
+       compatible = "fsl,imx28-saif";
+       reg = <0x80042000 2000>;
+       interrupts = <59 80>;
+       fsl,saif-dma-channel = <4>;
+};
+
+saif1: saif@80046000 {
+       compatible = "fsl,imx28-saif";
+       reg = <0x80046000 2000>;
+       interrupts = <58 81>;
+       fsl,saif-dma-channel = <5>;
+       fsl,saif-master = <&saif0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt
new file mode 100644 (file)
index 0000000..1ac7b16
--- /dev/null
@@ -0,0 +1,32 @@
+NVIDIA Tegra30 AHUB (Audio Hub)
+
+Required properties:
+- compatible : "nvidia,tegra30-ahub"
+- reg : Should contain the register physical address and length for each of
+  the AHUB's APBIF registers and the AHUB's own registers.
+- interrupts : Should contain AHUB interrupt
+- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
+  request selector for the first APBIF channel.
+- ranges : The bus address mapping for the configlink register bus.
+  Can be empty since the mapping is 1:1.
+- #address-cells : For the configlink bus. Should be <1>;
+- #size-cells : For the configlink bus. Should be <1>.
+
+AHUB client modules need to specify the IDs of their CIFs (Client InterFaces).
+For RX CIFs, the numbers indicate the register number within AHUB routing
+register space (APBIF 0..3 RX, I2S 0..5 RX, DAM 0..2 RX 0..1, SPDIF RX 0..1).
+For TX CIFs, the numbers indicate the bit position within the AHUB routing
+registers (APBIF 0..3 TX, I2S 0..5 TX, DAM 0..2 TX, SPDIF TX 0..1).
+
+Example:
+
+ahub@70080000 {
+       compatible = "nvidia,tegra30-ahub";
+       reg = <0x70080000 0x200 0x70080200 0x100>;
+       interrupts = < 0 103 0x04 >;
+       nvidia,dma-request-selector = <&apbdma 1>;
+
+       ranges;
+       #address-cells = <1>;
+       #size-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt
new file mode 100644 (file)
index 0000000..dfa6c03
--- /dev/null
@@ -0,0 +1,15 @@
+NVIDIA Tegra30 I2S controller
+
+Required properties:
+- compatible : "nvidia,tegra30-i2s"
+- reg : Should contain I2S registers location and length
+- nvidia,ahub-cif-ids : The list of AHUB CIF IDs for this port, rx (playback)
+  first, tx (capture) second. See nvidia,tegra30-ahub.txt for values.
+
+Example:
+
+i2s@70002800 {
+       compatible = "nvidia,tegra30-i2s";
+       reg = <0x70080300 0x100>;
+       nvidia,ahub-cif-ids = <4 4>;
+};
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt b/Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt
new file mode 100644 (file)
index 0000000..04b14cf
--- /dev/null
@@ -0,0 +1,14 @@
+NVIDIA Tegra audio complex for TrimSlice
+
+Required properties:
+- compatible : "nvidia,tegra-audio-trimslice"
+- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
+- nvidia,audio-codec : The phandle of the WM8903 audio codec
+
+Example:
+
+sound {
+       compatible = "nvidia,tegra-audio-trimslice";
+       nvidia,i2s-controller = <&tegra_i2s1>;
+       nvidia,audio-codec = <&codec>;
+};
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt b/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt
new file mode 100644 (file)
index 0000000..c4dd39c
--- /dev/null
@@ -0,0 +1,54 @@
+NVIDIA Tegra audio complex
+
+Required properties:
+- compatible : "nvidia,tegra-audio-wm8753"
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the WM8753's pins, and the jacks on the board:
+
+  WM8753 pins:
+
+  * LOUT1
+  * LOUT2
+  * ROUT1
+  * ROUT2
+  * MONO1
+  * MONO2
+  * OUT3
+  * OUT4
+  * LINE1
+  * LINE2
+  * RXP
+  * RXN
+  * ACIN
+  * ACOP
+  * MIC1N
+  * MIC1
+  * MIC2N
+  * MIC2
+  * Mic Bias
+
+  Board connectors:
+
+  * Headphone Jack
+  * Mic Jack
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
+- nvidia,audio-codec : The phandle of the WM8753 audio codec
+Example:
+
+sound {
+       compatible = "nvidia,tegra-audio-wm8753-whistler",
+                    "nvidia,tegra-audio-wm8753"
+       nvidia,model = "tegra-wm8753-harmony";
+
+       nvidia,audio-routing =
+               "Headphone Jack", "LOUT1",
+               "Headphone Jack", "ROUT1";
+
+       nvidia,i2s-controller = <&i2s1>;
+       nvidia,audio-codec = <&wm8753>;
+};
+
diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx
new file mode 100644 (file)
index 0000000..f50a6cc
--- /dev/null
@@ -0,0 +1,29 @@
+Kernel driver ina2xx
+====================
+
+Supported chips:
+  * Texas Instruments INA219
+    Prefix: 'ina219'
+    Addresses: I2C 0x40 - 0x4f
+    Datasheet: Publicly available at the Texas Instruments website
+               http://www.ti.com/
+
+  * Texas Instruments INA226
+    Prefix: 'ina226'
+    Addresses: I2C 0x40 - 0x4f
+    Datasheet: Publicly available at the Texas Instruments website
+               http://www.ti.com/
+
+Author: Lothar Felten <l-felten@ti.com>
+
+Description
+-----------
+
+The INA219 is a high-side current shunt and power monitor with an I2C
+interface. The INA219 monitors both shunt drop and supply voltage, with
+programmable conversion times and filtering.
+
+The INA226 is a current shunt and power monitor with an I2C interface.
+The INA226 monitors both a shunt voltage drop and bus supply voltage.
+
+The shunt value in micro-ohms can be set via platform data.
index fba74557168491515001122baa170613f0658bca..87850d86c55995fe895524cf9550c38f8fd90bb0 100644 (file)
@@ -30,6 +30,14 @@ Supported chips:
     Prefix: 'it8728'
     Addresses scanned: from Super I/O config space (8 I/O ports)
     Datasheet: Not publicly available
+  * IT8782F
+    Prefix: 'it8782'
+    Addresses scanned: from Super I/O config space (8 I/O ports)
+    Datasheet: Not publicly available
+  * IT8783E/F
+    Prefix: 'it8783'
+    Addresses scanned: from Super I/O config space (8 I/O ports)
+    Datasheet: Not publicly available
   * SiS950   [clone of IT8705F]
     Prefix: 'it87'
     Addresses scanned: from Super I/O config space (8 I/O ports)
@@ -75,7 +83,8 @@ Description
 -----------
 
 This driver implements support for the IT8705F, IT8712F, IT8716F,
-IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E and SiS950 chips.
+IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8781F, IT8782F,
+IT8783E/F, and SiS950 chips.
 
 These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
 joysticks and other miscellaneous stuff. For hardware monitoring, they
@@ -99,11 +108,11 @@ The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E and later IT8712F revisions
 have support for 2 additional fans. The additional fans are supported by the
 driver.
 
-The IT8716F, IT8718F, IT8720F and IT8721F/IT8758E, and late IT8712F and
-IT8705F also have optional 16-bit tachometer counters for fans 1 to 3. This
-is better (no more fan clock divider mess) but not compatible with the older
-chips and revisions. The 16-bit tachometer mode is enabled by the driver when
-one of the above chips is detected.
+The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E, IT8782F, IT8783E/F, and late
+IT8712F and IT8705F also have optional 16-bit tachometer counters for fans 1 to
+3. This is better (no more fan clock divider mess) but not compatible with the
+older chips and revisions. The 16-bit tachometer mode is enabled by the driver
+when one of the above chips is detected.
 
 The IT8726F is just bit enhanced IT8716F with additional hardware
 for AMD power sequencing. Therefore the chip will appear as IT8716F
@@ -131,9 +140,10 @@ inputs can measure voltages between 0 and 4.08 volts, with a resolution of
 0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery
 voltage in8 does not have limit registers.
 
-On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside
-the chip (in7, in8 and optionally in3). The driver handles this transparently
-so user-space doesn't have to care.
+On the IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs are
+internal and scaled inside the chip (in7 (optional for IT8782F and IT8783E/F),
+in8 and optionally in3). The driver handles this transparently so user-space
+doesn't have to care.
 
 The VID lines (IT8712F/IT8716F/IT8718F/IT8720F) encode the core voltage value:
 the voltage level your processor should work with. This is hardcoded by
index 62aba89b04a2d9130d556d0ebb3c58442952b5c1..8cb10f77c723f4d4d6290684a5a698ff739417db 100644 (file)
@@ -2463,6 +2463,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        resume=         [SWSUSP]
                        Specify the partition device for software suspend
+                       Format:
+                       {/dev/<dev> | PARTUUID=<uuid> | <int>:<int> | <hex>}
 
        resume_offset=  [SWSUSP]
                        Specify the offset from the beginning of the partition
index f28f9a6f03472fb8915d965f792b9827c513fd8b..e13dafc8e8f15c681e485e1fe79423be0904ff2c 100644 (file)
@@ -29,7 +29,7 @@ More details follow:
 
                                   Write 'mem' to
                                 /sys/power/state
-                                    syfs file
+                                    sysfs file
                                         |
                                         v
                                Acquire pm_mutex lock
index 8c16d50f6cb6f67284220f5fb29785224b48965a..221b81016dba75e48b8ec0e253c13d97f5be5127 100644 (file)
@@ -1545,7 +1545,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for sound cards based on the C-Media CMI8786/8787/8788 chip:
     * Asound A-8788
-    * Asus Xonar DG
+    * Asus Xonar DG/DGX
     * AuzenTech X-Meridian
     * AuzenTech X-Meridian 2G
     * Bgears b-Enspirer
index 591a10c11257c44e8acd5fc312a4e3e089e6b61c..61dd168d349ac5ad1c6ac921174c840faa2c7e15 100644 (file)
@@ -6573,7 +6573,7 @@ M:        Paul Mundt <lethal@linux-sh.org>
 L:     linux-sh@vger.kernel.org
 W:     http://www.linux-sh.org
 Q:     http://patchwork.kernel.org/project/linux-sh/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git sh-latest
+T:     git git://github.com/pmundt/linux-sh.git sh-latest
 S:     Supported
 F:     Documentation/sh/
 F:     arch/sh/
@@ -6691,6 +6691,12 @@ F:       drivers/misc/tifm*
 F:     drivers/mmc/host/tifm_sd.c
 F:     include/linux/tifm.h
 
+TI LM49xxx FAMILY ASoC CODEC DRIVERS
+M:     M R Swami Reddy <mr.swami.reddy@ti.com>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     sound/soc/codecs/lm49453*
+
 TI TWL4030 SERIES SOC CODEC DRIVER
 M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
index 546515cd07f30c5354946991ecd382b183a02471..b62c1e09444a981ed738581de1318aad802a2840 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -566,6 +566,16 @@ else
 KBUILD_CFLAGS  += -O2
 endif
 
+ifdef CONFIG_READABLE_ASM
+# Disable optimizations that make assembler listings hard to read.
+# reorder blocks reorders the control in the function
+# ipa clone creates specialized cloned functions
+# partial inlining inlines only parts of functions
+KBUILD_CFLAGS += $(call cc-option,-fno-reorder-blocks,) \
+                 $(call cc-option,-fno-ipa-cp-clone,) \
+                 $(call cc-option,-fno-partial-inlining)
+endif
+
 include $(srctree)/arch/$(SRCARCH)/Makefile
 
 ifneq ($(CONFIG_FRAME_WARN),0)
@@ -786,6 +796,10 @@ quiet_cmd_vmlinux_version = GEN     .version
 quiet_cmd_sysmap = SYSMAP
       cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap
 
+# Sort exception table at build time
+quiet_cmd_sortextable = SORTEX
+      cmd_sortextable = $(objtree)/scripts/sortextable
+
 # Link of vmlinux
 # If CONFIG_KALLSYMS is set .version is already updated
 # Generate System.map and verify that the content is consistent
@@ -798,6 +812,12 @@ define rule_vmlinux__
        $(call cmd,vmlinux__)
        $(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
 
+       $(if $(CONFIG_BUILDTIME_EXTABLE_SORT),                          \
+         $(Q)$(if $($(quiet)cmd_sortextable),                          \
+           echo '  $($(quiet)cmd_sortextable)  vmlinux' &&)            \
+         $(cmd_sortextable)  vmlinux)
+
+
        $(Q)$(if $($(quiet)cmd_sysmap),                                      \
          echo '  $($(quiet)cmd_sysmap)  System.map' &&)                     \
        $(cmd_sysmap) $@ System.map;                                         \
index 94afe5859301f272eb6dedf7343f6e877f8fd77c..e37b887b3d9f636fdcb0b4615a8c648dfc3d364f 100644 (file)
@@ -49,9 +49,6 @@ extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 /* Create a kernel thread without removing it from tasklists.  */
 extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
index d7038fa223436227f14276406128ff9b247061d4..99afa7498260cdad985eaf9c74fd713095dd09f6 100644 (file)
@@ -77,9 +77,6 @@ struct task_struct;
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 unsigned long get_wchan(struct task_struct *p);
 
 #if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327)
index 7d6322ce5223ec6b1294cb478dd2e7ae8cfa1c1f..cca8c0c747946d0108ab034149b7e902c10cdc3e 100644 (file)
@@ -151,6 +151,7 @@ config MACH_MX25_3DS
        select IMX_HAVE_PLATFORM_IMX2_WDT
        select IMX_HAVE_PLATFORM_IMXDI_RTC
        select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_SSI
        select IMX_HAVE_PLATFORM_IMX_FB
        select IMX_HAVE_PLATFORM_IMX_KEYPAD
        select IMX_HAVE_PLATFORM_IMX_UART
@@ -495,6 +496,7 @@ config MACH_MX31MOBOARD
        select IMX_HAVE_PLATFORM_FSL_USB2_UDC
        select IMX_HAVE_PLATFORM_IMX2_WDT
        select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_SSI
        select IMX_HAVE_PLATFORM_IMX_UART
        select IMX_HAVE_PLATFORM_IPU_CORE
        select IMX_HAVE_PLATFORM_MXC_EHCI
index 4d1aab154400fb43e4e0de2ea38e49c932d278e0..4eafdf275ea28864d6dacf6667be7221cf2a9a22 100644 (file)
@@ -156,6 +156,11 @@ static int mx31_3ds_pins[] = {
        MX31_PIN_CSI_VSYNC__CSI_VSYNC,
        MX31_PIN_CSI_D5__GPIO3_5, /* CMOS PWDN */
        IOMUX_MODE(MX31_PIN_RI_DTE1, IOMUX_CONFIG_GPIO), /* CMOS reset */
+       /* SSI */
+       MX31_PIN_STXD4__STXD4,
+       MX31_PIN_SRXD4__SRXD4,
+       MX31_PIN_SCK4__SCK4,
+       MX31_PIN_SFS4__SFS4,
 };
 
 /*
@@ -488,12 +493,23 @@ static struct mc13xxx_regulator_init_data mx31_3ds_regulators[] = {
 };
 
 /* MC13783 */
+static struct mc13xxx_codec_platform_data mx31_3ds_codec = {
+       .dac_ssi_port = MC13783_SSI1_PORT,
+       .adc_ssi_port = MC13783_SSI1_PORT,
+};
+
 static struct mc13xxx_platform_data mc13783_pdata = {
        .regulators = {
                .regulators = mx31_3ds_regulators,
                .num_regulators = ARRAY_SIZE(mx31_3ds_regulators),
        },
-       .flags  = MC13XXX_USE_TOUCHSCREEN | MC13XXX_USE_RTC,
+       .codec = &mx31_3ds_codec,
+       .flags  = MC13XXX_USE_TOUCHSCREEN | MC13XXX_USE_RTC | MC13XXX_USE_CODEC,
+
+};
+
+static struct imx_ssi_platform_data mx31_3ds_ssi_pdata = {
+       .flags = IMX_SSI_DMA | IMX_SSI_NET,
 };
 
 /* SPI */
@@ -741,6 +757,10 @@ static void __init mx31_3ds_init(void)
        }
 
        mx31_3ds_init_camera();
+
+       imx31_add_imx_ssi(0, &mx31_3ds_ssi_pdata);
+
+       imx_add_platform_device("imx_mc13783", 0, NULL, 0, NULL, 0);
 }
 
 static void __init mx31_3ds_timer_init(void)
index 1dfe3c7a7be16da73314f96d4b9580aac7f7217b..016791f038b0a75e918077cecf4ecaff5452cabf 100644 (file)
@@ -47,6 +47,7 @@
 #include <mach/hardware.h>
 #include <mach/iomux-mx3.h>
 #include <mach/ulpi.h>
+#include <mach/ssi.h>
 
 #include "devices-imx31.h"
 
@@ -102,6 +103,9 @@ static unsigned int moboard_pins[] = {
        MX31_PIN_CSPI3_MOSI__MOSI, MX31_PIN_CSPI3_MISO__MISO,
        MX31_PIN_CSPI3_SCLK__SCLK, MX31_PIN_CSPI3_SPI_RDY__SPI_RDY,
        MX31_PIN_CSPI2_SS1__CSPI3_SS1,
+       /* SSI */
+       MX31_PIN_STXD4__STXD4, MX31_PIN_SRXD4__SRXD4,
+       MX31_PIN_SCK4__SCK4, MX31_PIN_SFS4__SFS4,
 };
 
 static struct physmap_flash_data mx31moboard_flash_data = {
@@ -276,6 +280,11 @@ static struct mc13xxx_buttons_platform_data moboard_buttons = {
        .b1on_key = KEY_POWER,
 };
 
+static struct mc13xxx_codec_platform_data moboard_codec = {
+       .dac_ssi_port = MC13783_SSI1_PORT,
+       .adc_ssi_port = MC13783_SSI1_PORT,
+};
+
 static struct mc13xxx_platform_data moboard_pmic = {
        .regulators = {
                .regulators = moboard_regulators,
@@ -283,7 +292,12 @@ static struct mc13xxx_platform_data moboard_pmic = {
        },
        .leds = &moboard_leds,
        .buttons = &moboard_buttons,
-       .flags = MC13XXX_USE_RTC | MC13XXX_USE_ADC,
+       .codec = &moboard_codec,
+       .flags = MC13XXX_USE_RTC | MC13XXX_USE_ADC | MC13XXX_USE_CODEC,
+};
+
+static struct imx_ssi_platform_data moboard_ssi_pdata = {
+       .flags = IMX_SSI_DMA | IMX_SSI_NET,
 };
 
 static struct spi_board_info moboard_spi_board_info[] __initdata = {
@@ -554,6 +568,10 @@ static void __init mx31moboard_init(void)
 
        moboard_usbh2_init();
 
+       imx31_add_imx_ssi(0, &moboard_ssi_pdata);
+
+       imx_add_platform_device("imx_mc13783", 0, NULL, 0, NULL, 0);
+
        pm_power_off = mx31moboard_poweroff;
 
        switch (mx31moboard_baseboard) {
index 98327b7a503cf97432b75a56d11be751c6910168..f31383c32f9cdfd121e65b1d4a026d7fbd3a2f01 100644 (file)
@@ -64,6 +64,7 @@ config MACH_AP4EVB
        depends on ARCH_SH7372
        select ARCH_REQUIRE_GPIOLIB
        select SH_LCD_MIPI_DSI
+       select SND_SOC_AK4642 if SND_SIMPLE_CARD
 
 choice
        prompt "AP4EVB LCD panel selection"
@@ -88,6 +89,7 @@ config MACH_MACKEREL
        bool "mackerel board"
        depends on ARCH_SH7372
        select ARCH_REQUIRE_GPIOLIB
+       select SND_SOC_AK4642 if SND_SIMPLE_CARD
 
 config MACH_KOTA2
        bool "KOTA2 board"
index 0c3caeba2f3e0c8e364ed30de6eafead5414550e..b540b8eb20ca91d860fdf75bab7ce97d4a675434 100644 (file)
@@ -50,6 +50,7 @@
 #include <media/soc_camera.h>
 
 #include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
 
 #include <video/sh_mobile_hdmi.h>
 #include <video/sh_mobile_lcdc.h>
@@ -785,17 +786,25 @@ static struct platform_device fsi_device = {
        },
 };
 
-static struct fsi_ak4642_info fsi2_ak4643_info = {
+static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = {
+       .fmt            = SND_SOC_DAIFMT_LEFT_J,
+       .codec_daifmt   = SND_SOC_DAIFMT_CBM_CFM,
+       .cpu_daifmt     = SND_SOC_DAIFMT_CBS_CFS,
+       .sysclk         = 11289600,
+};
+
+static struct asoc_simple_card_info fsi2_ak4643_info = {
        .name           = "AK4643",
        .card           = "FSI2A-AK4643",
        .cpu_dai        = "fsia-dai",
        .codec          = "ak4642-codec.0-0013",
        .platform       = "sh_fsi2",
-       .id             = FSI_PORT_A,
+       .codec_dai      = "ak4642-hifi",
+       .init           = &fsi2_ak4643_init_info,
 };
 
 static struct platform_device fsi_ak4643_device = {
-       .name   = "fsi-ak4642-audio",
+       .name   = "asoc-simple-card",
        .dev    = {
                .platform_data  = &fsi2_ak4643_info,
        },
@@ -900,8 +909,26 @@ static struct platform_device lcdc1_device = {
        },
 };
 
+static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
+       .cpu_daifmt     = SND_SOC_DAIFMT_CBM_CFM,
+};
+
+static struct asoc_simple_card_info fsi2_hdmi_info = {
+       .name           = "HDMI",
+       .card           = "FSI2B-HDMI",
+       .cpu_dai        = "fsib-dai",
+       .codec          = "sh-mobile-hdmi",
+       .platform       = "sh_fsi2",
+       .codec_dai      = "sh_mobile_hdmi-hifi",
+       .init           = &fsi2_hdmi_init_info,
+};
+
 static struct platform_device fsi_hdmi_device = {
-       .name           = "sh_fsi2_b_hdmi",
+       .name   = "asoc-simple-card",
+       .id     = 1,
+       .dev    = {
+               .platform_data  = &fsi2_hdmi_info,
+       },
 };
 
 static struct gpio_led ap4evb_leds[] = {
index aae2e24fde461cff506456b4fec94594e16f26cd..50c67b22d08749eab3b985da19b6706906127729 100644 (file)
@@ -53,6 +53,7 @@
 #include <media/soc_camera.h>
 #include <media/soc_camera_platform.h>
 #include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
 
 #include <mach/common.h>
 #include <mach/irqs.h>
@@ -502,8 +503,26 @@ static struct platform_device hdmi_lcdc_device = {
        },
 };
 
+static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
+       .cpu_daifmt     = SND_SOC_DAIFMT_CBM_CFM,
+};
+
+static struct asoc_simple_card_info fsi2_hdmi_info = {
+       .name           = "HDMI",
+       .card           = "FSI2B-HDMI",
+       .cpu_dai        = "fsib-dai",
+       .codec          = "sh-mobile-hdmi",
+       .platform       = "sh_fsi2",
+       .codec_dai      = "sh_mobile_hdmi-hifi",
+       .init           = &fsi2_hdmi_init_info,
+};
+
 static struct platform_device fsi_hdmi_device = {
-       .name           = "sh_fsi2_b_hdmi",
+       .name   = "asoc-simple-card",
+       .id     = 1,
+       .dev    = {
+               .platform_data  = &fsi2_hdmi_info,
+       },
 };
 
 static void __init hdmi_init_pm_clock(void)
@@ -945,17 +964,25 @@ static struct platform_device fsi_device = {
        },
 };
 
-static struct fsi_ak4642_info fsi2_ak4643_info = {
+static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = {
+       .fmt            = SND_SOC_DAIFMT_LEFT_J,
+       .codec_daifmt   = SND_SOC_DAIFMT_CBM_CFM,
+       .cpu_daifmt     = SND_SOC_DAIFMT_CBS_CFS,
+       .sysclk         = 11289600,
+};
+
+static struct asoc_simple_card_info fsi2_ak4643_info = {
        .name           = "AK4643",
        .card           = "FSI2A-AK4643",
        .cpu_dai        = "fsia-dai",
        .codec          = "ak4642-codec.0-0013",
        .platform       = "sh_fsi2",
-       .id             = FSI_PORT_A,
+       .codec_dai      = "ak4642-hifi",
+       .init           = &fsi2_ak4643_init_info,
 };
 
 static struct platform_device fsi_ak4643_device = {
-       .name   = "fsi-ak4642-audio",
+       .name   = "asoc-simple-card",
        .dev    = {
                .platform_data  = &fsi2_ak4643_info,
        },
index 8351c4c147ad47312a2fd35b955224d4fb1af31a..fac3eb1af17e0257c043b9cbb91181b35caf1f84 100644 (file)
@@ -55,9 +55,9 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C2_BASE, "tegra-i2c.1", NULL),
        OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C3_BASE, "tegra-i2c.2", NULL),
        OF_DEV_AUXDATA("nvidia,tegra20-i2c-dvc", TEGRA_DVC_BASE, "tegra-i2c.3", NULL),
-       OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.0", NULL),
-       OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra-i2s.1", NULL),
-       OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra-das", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra20-i2s.0", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra20-i2s.1", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra20-das", NULL),
        OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0",
                       &tegra_ehci1_pdata),
        OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1",
index 222182e002264de97fe3394079320c3502f22570..b906b3b6077b97a85a0e058605e4a6ccdfabb89a 100644 (file)
@@ -124,7 +124,6 @@ static struct platform_device *harmony_devices[] __initdata = {
        &tegra_ehci3_device,
        &tegra_i2s_device1,
        &tegra_das_device,
-       &tegra_pcm_device,
        &harmony_audio_device,
 };
 
index 20743bcec03abcd36fd4559fe4d3db95f4d89d91..79064c7a7907023eb1c4ffb82fc84aeddd44ca8c 100644 (file)
@@ -156,7 +156,6 @@ static struct platform_device *seaboard_devices[] __initdata = {
        &seaboard_gpio_keys_device,
        &tegra_i2s_device1,
        &tegra_das_device,
-       &tegra_pcm_device,
        &seaboard_audio_device,
 };
 
index 0a00183feeecc1ce5b52406fd90fc739ec88e84c..bc59b379c6fe609db1d413c874b24e54e1b378a2 100644 (file)
@@ -89,7 +89,6 @@ static struct platform_device *trimslice_devices[] __initdata = {
        &tegra_sdhci_device4,
        &tegra_i2s_device1,
        &tegra_das_device,
-       &tegra_pcm_device,
        &trimslice_audio_device,
 };
 
index bd3035e0cea164c8b8b1869fc5f06c2d048ef4e2..2d8dfa2faf8f09d0dcdfb8f301713912ca553782 100644 (file)
@@ -674,14 +674,14 @@ static struct resource i2s_resource2[] = {
 };
 
 struct platform_device tegra_i2s_device1 = {
-       .name           = "tegra-i2s",
+       .name           = "tegra20-i2s",
        .id             = 0,
        .resource       = i2s_resource1,
        .num_resources  = ARRAY_SIZE(i2s_resource1),
 };
 
 struct platform_device tegra_i2s_device2 = {
-       .name           = "tegra-i2s",
+       .name           = "tegra20-i2s",
        .id             = 1,
        .resource       = i2s_resource2,
        .num_resources  = ARRAY_SIZE(i2s_resource2),
@@ -696,13 +696,8 @@ static struct resource tegra_das_resources[] = {
 };
 
 struct platform_device tegra_das_device = {
-       .name           = "tegra-das",
+       .name           = "tegra20-das",
        .id             = -1,
        .num_resources  = ARRAY_SIZE(tegra_das_resources),
        .resource       = tegra_das_resources,
 };
-
-struct platform_device tegra_pcm_device = {
-       .name = "tegra-pcm-audio",
-       .id = -1,
-};
index ec455679b219a987dcade1063f7770559746e9f4..138c642e59f4cec93143845d8e072df332b083e3 100644 (file)
@@ -52,6 +52,5 @@ extern struct platform_device tegra_pmu_device;
 extern struct platform_device tegra_i2s_device1;
 extern struct platform_device tegra_i2s_device2;
 extern struct platform_device tegra_das_device;
-extern struct platform_device tegra_pcm_device;
 
 #endif
index 2cae5cbc20bae4f1e8b4f929377165d5a85c78d0..bae09b8598912b2f310ea854401457bcba9983da 100644 (file)
@@ -2148,8 +2148,8 @@ static struct clk tegra_list_clks[] = {
        PERIPH_CLK("apbdma",    "tegra-dma",            NULL,   34,     0,      108000000, mux_pclk,                    0),
        PERIPH_CLK("rtc",       "rtc-tegra",            NULL,   4,      0,      32768,     mux_clk_32k,                 PERIPH_NO_RESET),
        PERIPH_CLK("timer",     "timer",                NULL,   5,      0,      26000000,  mux_clk_m,                   0),
-       PERIPH_CLK("i2s1",      "tegra-i2s.0",          NULL,   11,     0x100,  26000000,  mux_pllaout0_audio2x_pllp_clkm,      MUX | DIV_U71),
-       PERIPH_CLK("i2s2",      "tegra-i2s.1",          NULL,   18,     0x104,  26000000,  mux_pllaout0_audio2x_pllp_clkm,      MUX | DIV_U71),
+       PERIPH_CLK("i2s1",      "tegra20-i2s.0",        NULL,   11,     0x100,  26000000,  mux_pllaout0_audio2x_pllp_clkm,      MUX | DIV_U71),
+       PERIPH_CLK("i2s2",      "tegra20-i2s.1",        NULL,   18,     0x104,  26000000,  mux_pllaout0_audio2x_pllp_clkm,      MUX | DIV_U71),
        PERIPH_CLK("spdif_out", "spdif_out",            NULL,   10,     0x108,  100000000, mux_pllaout0_audio2x_pllp_clkm,      MUX | DIV_U71),
        PERIPH_CLK("spdif_in",  "spdif_in",             NULL,   10,     0x10c,  100000000, mux_pllp_pllc_pllm,          MUX | DIV_U71),
        PERIPH_CLK("pwm",       "pwm",                  NULL,   17,     0x110,  432000000, mux_pllp_pllc_audio_clkm_clk32,      MUX | DIV_U71),
index 108502bc67706786d3125dff42be43f6a1d9b7d2..87d8baccc60e908c475c72dff993e4f5ec79a817 100644 (file)
@@ -145,9 +145,6 @@ extern void release_thread(struct task_struct *);
 /* Create a kernel thread without removing it from tasklists */
 extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while(0)
-
 /* Return saved PC of a blocked thread */
 #define thread_saved_pc(tsk)    ((tsk)->thread.cpu_context.pc)
 
index 8af7772e84ccfdcfbba38d1b11eca4cad1926d45..4ef7cfe43cebce8441a88c5dc876f980760e65ef 100644 (file)
@@ -75,8 +75,6 @@ static inline void release_thread(struct task_struct *dead_task)
 {
 }
 
-#define prepare_to_copy(tsk)   do { } while (0)
-
 extern int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags);
 
 /*
index 3ff7fab956ba1c2158f087a59050f8c45006f25a..c50af7ef1c96a5538252474e6ab37681141583a5 100644 (file)
@@ -92,9 +92,6 @@ static inline void release_thread(struct task_struct *dead_task)
 {
 }
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 #define copy_segments(tsk, mm)         do { } while (0)
index 8dc56ef08712dbf7e781ca7d92120fa006f8ef91..ef4e1bc3efc88686fbc4092f1e3661adffa285dc 100644 (file)
@@ -49,10 +49,6 @@ struct task_struct;
 #define task_pt_regs(task) user_regs(task_thread_info(task))
 #define current_regs() task_pt_regs(current)
 
-static inline void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 unsigned long get_wchan(struct task_struct *p);
index 9b1a92b73f6009af3f19fedafd9e3be0d3ab445c..a8311d364e2af377851d763ace6d0e38f8eabf93 100644 (file)
@@ -103,8 +103,6 @@ do {                                                        \
        __frame->sp     = (_usp);                       \
 } while(0)
 
-extern void prepare_to_copy(struct task_struct *tsk);
-
 /* Free all resources held by a thread. */
 static inline void release_thread(struct task_struct *dead_task)
 {
index ed09e9e2c6531aba44d51780631bce107f56e3c0..ff95f50efea5cf950829ffd455e7a1b9552a7ddf 100644 (file)
@@ -165,17 +165,6 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
        return do_fork(clone_flags, newsp, __frame, 0, parent_tidptr, child_tidptr);
 } /* end sys_clone() */
 
-/*****************************************************************************/
-/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
- */
-void prepare_to_copy(struct task_struct *tsk)
-{
-       //unlazy_fpu(tsk);
-} /* end prepare_to_copy() */
-
-/*****************************************************************************/
 /*
  * set up the kernel stack and exception frames for a new process
  */
index 61fabf1788c6b4e1a9c006d29a070b2b1bfb5904..4c9f6f87b6179f1c493ee3f2ed289dcda0a46bdc 100644 (file)
@@ -109,8 +109,6 @@ static inline void release_thread(struct task_struct *dead_task)
 
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-#define prepare_to_copy(tsk)   do { } while (0)
-
 /*
  * Free current thread data structures etc..
  */
index 22615dd022197ee8656d75eabf7fd4ba1ebb1347..bc979f770980ae4a286b8833980ee4be542aa985 100644 (file)
@@ -13,8 +13,8 @@ config HEXAGON
        # select ARCH_REQUIRE_GPIOLIB
        # select HAVE_CLK
        # select IRQ_PER_CPU
-       select HAVE_IRQ_WORK
        # select GENERIC_PENDING_IRQ if SMP
+       select HAVE_IRQ_WORK
        select GENERIC_ATOMIC64
        select HAVE_PERF_EVENTS
        select HAVE_GENERIC_HARDIRQS
@@ -26,7 +26,7 @@ config HEXAGON
        select NO_IOPORT
        select GENERIC_IOMAP
        select GENERIC_SMP_IDLE_THREAD
-       # mostly generic routines, with some accelerated ones
+       select STACKTRACE_SUPPORT
        ---help---
          Qualcomm Hexagon is a processor architecture designed for high
          performance and low power across a wide variety of applications.
@@ -73,15 +73,6 @@ config GENERIC_CSUM
 config GENERIC_IRQ_PROBE
        def_bool y
 
-#config ZONE_DMA
-#      bool
-#      default y
-
-config HAS_DMA
-       bool
-       select HAVE_DMA_ATTRS
-       default y
-
 config NEED_SG_DMA_LENGTH
        def_bool y
 
@@ -114,14 +105,11 @@ config GENERIC_BUG
        def_bool y
        depends on BUG
 
-config BUG
-       def_bool y
-
 menu "Machine selection"
 
 choice
        prompt "System type"
-       default HEXAGON_ARCH_V2
+       default HEXAGON_COMET
 
 config HEXAGON_COMET
        bool "Comet Board"
@@ -194,8 +182,7 @@ source "kernel/Kconfig.hz"
 source "kernel/time/Kconfig"
 
 config GENERIC_GPIO
-       bool "Generic GPIO support"
-       default n
+       def_bool n
 
 endmenu
 
index e27d030846aeec9873ed3c9ca935d3550cdeed4d..d00d900b256653b9a139e42a58032fea8fd374c0 100644 (file)
@@ -50,8 +50,3 @@ head-y := arch/hexagon/kernel/head.o
 core-y += arch/hexagon/kernel/ \
        arch/hexagon/mm/ \
        arch/hexagon/lib/
-
-#      arch/hexagon/platform/common/
-#
-#core-$(CONFIG_HEXAGON_COMET)          += arch/hexagon/platform/comet/
-#machine-$(CONFIG_HEXAGON_COMET)               := comet
index 20c5ddabbd8b4297e224a0557f5ca89b6a50e4d7..e8ea459002a4cf6adfc824092c87b94a5cacc891 100644 (file)
@@ -58,13 +58,6 @@ struct thread_struct {
 
 #define cpu_relax() __vmyield()
 
-/*
- * "Unlazying all lazy status" occurs here.
- */
-static inline void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
 /*
  * Decides where the kernel will search for a free chunk of vm space during
  * mmaps.
index 5e937af1c4ad7ae0ae20734a6851d6738b8cd42f..99b5a7575c21416449c856e17e9a85b15088a6fc 100644 (file)
@@ -21,8 +21,6 @@
 #ifndef _ASM_SPINLOCK_TYPES_H
 #define _ASM_SPINLOCK_TYPES_H
 
-#include <linux/version.h>
-
 #ifndef __LINUX_SPINLOCK_TYPES_H
 # error "please don't include this file directly"
 #endif
index 0f2367cc549311a3c8ba1911b0707699435716b2..2b48751aa5f75848c0e4d7674c412a479390ac5a 100644 (file)
@@ -54,7 +54,7 @@ static struct gen_pool *coherent_pool;
 
 /* Allocates from a pool of uncached memory that was reserved at boot time */
 
-void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
+static void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
                                 dma_addr_t *dma_addr, gfp_t flag,
                                 struct dma_attrs *attrs)
 {
index 5d9b33b67935529a38c437be63c55f4556a7f0c3..36ba641857112e1382579d16bd8badf1942115ae 100644 (file)
@@ -201,12 +201,10 @@ void __init time_init_deferred(void)
                resource = rtos_timer_device.resource;
 
        /*  ioremap here means this has to run later, after paging init  */
-       rtos_timer = ioremap(resource->start, resource->end
-               - resource->start + 1);
+       rtos_timer = ioremap(resource->start, resource_size(resource));
 
        if (!rtos_timer) {
-               release_mem_region(resource->start, resource->end
-                       - resource->start + 1);
+               release_mem_region(resource->start, resource_size(resource));
        }
        clocksource_register_khz(&hexagon_clocksource, pcycle_freq_mhz * 1000);
 
index c10b76ff9d65e9095dd0e885f5167651f56588e9..06695cc4fe58f09f61d73c0e28803de8b9dfbda3 100644 (file)
@@ -53,6 +53,8 @@ void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)
        int si_code = SEGV_MAPERR;
        int fault;
        const struct exception_table_entry *fixup;
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+                                (cause > 0 ? FAULT_FLAG_WRITE : 0);
 
        /*
         * If we're in an interrupt or have no user context,
@@ -63,6 +65,7 @@ void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)
 
        local_irq_enable();
 
+retry:
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
        if (!vma)
@@ -96,14 +99,23 @@ good_area:
                break;
        }
 
-       fault = handle_mm_fault(mm, vma, address, (cause > 0));
+       fault = handle_mm_fault(mm, vma, address, flags);
+
+       if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+               return;
 
        /* The most common case -- we are done. */
        if (likely(!(fault & VM_FAULT_ERROR))) {
-               if (fault & VM_FAULT_MAJOR)
-                       current->maj_flt++;
-               else
-                       current->min_flt++;
+               if (flags & FAULT_FLAG_ALLOW_RETRY) {
+                       if (fault & VM_FAULT_MAJOR)
+                               current->maj_flt++;
+                       else
+                               current->min_flt++;
+                       if (fault & VM_FAULT_RETRY) {
+                               flags &= ~FAULT_FLAG_ALLOW_RETRY;
+                               goto retry;
+                       }
+               }
 
                up_read(&mm->mmap_sem);
                return;
index 241d1c53ba692a2a62b8eae096576e31fbe5c246..d4eb9383f5f657718fba1b5467baa4c35257eb14 100644 (file)
@@ -1,6 +1,7 @@
 include include/asm-generic/Kbuild.asm
 
 header-y += break.h
+header-y += cmpxchg.h
 header-y += fpu.h
 header-y += gcc_intrin.h
 header-y += ia64regs.h
index f92f67aba6187b095f27cd4b2e751eed8f4dc38d..832dd3789e9d02c14471730ddfbbf85d60e816da 100644 (file)
@@ -34,8 +34,7 @@
  * each (assuming 8KB page size), for a total of 8TB of user virtual
  * address space.
  */
-#define TASK_SIZE_OF(tsk)      ((tsk)->thread.task_size)
-#define TASK_SIZE              TASK_SIZE_OF(current)
+#define TASK_SIZE              DEFAULT_TASK_SIZE
 
 /*
  * This decides where the kernel will search for a free chunk of vm
@@ -280,7 +279,6 @@ struct thread_struct {
        __u8 pad[3];
        __u64 ksp;                      /* kernel stack pointer */
        __u64 map_base;                 /* base address for get_unmapped_area() */
-       __u64 task_size;                /* limit for task size */
        __u64 rbs_bot;                  /* the base address for the RBS */
        int last_fph_cpu;               /* CPU that may hold the contents of f32-f127 */
 
@@ -303,7 +301,6 @@ struct thread_struct {
        .ksp =          0,                                      \
        .map_base =     DEFAULT_MAP_BASE,                       \
        .rbs_bot =      STACK_TOP - DEFAULT_USER_STACK_SIZE,    \
-       .task_size =    DEFAULT_TASK_SIZE,                      \
        .last_fph_cpu =  -1,                                    \
        INIT_THREAD_PM                                          \
        .dbr =          {0, },                                  \
@@ -343,9 +340,6 @@ struct task_struct;
  */
 #define release_thread(dead_task)
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 /*
  * This is the mechanism for creating a new kernel thread.
  *
index cc26edac0ec6e7768f25f1ea6ed60ca2d8d143a1..e662f178b990ab660526154dfa505c5452d57bf6 100644 (file)
@@ -371,175 +371,6 @@ ENTRY(fsys_clock_gettime)
        br.many .gettime
 END(fsys_clock_gettime)
 
-/*
- * long fsys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize).
- */
-#if _NSIG_WORDS != 1
-# error Sorry, fsys_rt_sigprocmask() needs to be updated for _NSIG_WORDS != 1.
-#endif
-ENTRY(fsys_rt_sigprocmask)
-       .prologue
-       .altrp b6
-       .body
-
-       add r2=IA64_TASK_BLOCKED_OFFSET,r16
-       add r9=TI_FLAGS+IA64_TASK_SIZE,r16
-       cmp4.ltu p6,p0=SIG_SETMASK,r32
-
-       cmp.ne p15,p0=r0,r34                    // oset != NULL?
-       tnat.nz p8,p0=r34
-       add r31=IA64_TASK_SIGHAND_OFFSET,r16
-       ;;
-       ld8 r3=[r2]                             // read/prefetch current->blocked
-       ld4 r9=[r9]
-       tnat.nz.or p6,p0=r35
-
-       cmp.ne.or p6,p0=_NSIG_WORDS*8,r35
-       tnat.nz.or p6,p0=r32
-(p6)   br.spnt.few .fail_einval                // fail with EINVAL
-       ;;
-#ifdef CONFIG_SMP
-       ld8 r31=[r31]                           // r31 <- current->sighand
-#endif
-       and r9=TIF_ALLWORK_MASK,r9
-       tnat.nz.or p8,p0=r33
-       ;;
-       cmp.ne p7,p0=0,r9
-       cmp.eq p6,p0=r0,r33                     // set == NULL?
-       add r31=IA64_SIGHAND_SIGLOCK_OFFSET,r31 // r31 <- current->sighand->siglock
-(p8)   br.spnt.few .fail_efault                // fail with EFAULT
-(p7)   br.spnt.many fsys_fallback_syscall      // got pending kernel work...
-(p6)   br.dpnt.many .store_mask                // -> short-circuit to just reading the signal mask
-
-       /* Argh, we actually have to do some work and _update_ the signal mask: */
-
-EX(.fail_efault, probe.r.fault r33, 3)         // verify user has read-access to *set
-EX(.fail_efault, ld8 r14=[r33])                        // r14 <- *set
-       mov r17=(1 << (SIGKILL - 1)) | (1 << (SIGSTOP - 1))
-       ;;
-
-       RSM_PSR_I(p0, r18, r19)                 // mask interrupt delivery
-       andcm r14=r14,r17                       // filter out SIGKILL & SIGSTOP
-       mov r8=EINVAL                   // default to EINVAL
-
-#ifdef CONFIG_SMP
-       // __ticket_spin_trylock(r31)
-       ld4 r17=[r31]
-       ;;
-       mov.m ar.ccv=r17
-       extr.u r9=r17,17,15
-       adds r19=1,r17
-       extr.u r18=r17,0,15
-       ;;
-       cmp.eq p6,p7=r9,r18
-       ;;
-(p6)   cmpxchg4.acq r9=[r31],r19,ar.ccv
-(p6)   dep.z r20=r19,1,15              // next serving ticket for unlock
-(p7)   br.cond.spnt.many .lock_contention
-       ;;
-       cmp4.eq p0,p7=r9,r17
-       adds r31=2,r31
-(p7)   br.cond.spnt.many .lock_contention
-       ld8 r3=[r2]                     // re-read current->blocked now that we hold the lock
-       ;;
-#else
-       ld8 r3=[r2]                     // re-read current->blocked now that we hold the lock
-#endif
-       add r18=IA64_TASK_PENDING_OFFSET+IA64_SIGPENDING_SIGNAL_OFFSET,r16
-       add r19=IA64_TASK_SIGNAL_OFFSET,r16
-       cmp4.eq p6,p0=SIG_BLOCK,r32
-       ;;
-       ld8 r19=[r19]                   // r19 <- current->signal
-       cmp4.eq p7,p0=SIG_UNBLOCK,r32
-       cmp4.eq p8,p0=SIG_SETMASK,r32
-       ;;
-       ld8 r18=[r18]                   // r18 <- current->pending.signal
-       .pred.rel.mutex p6,p7,p8
-(p6)   or r14=r3,r14                   // SIG_BLOCK
-(p7)   andcm r14=r3,r14                // SIG_UNBLOCK
-
-(p8)   mov r14=r14                     // SIG_SETMASK
-(p6)   mov r8=0                        // clear error code
-       // recalc_sigpending()
-       add r17=IA64_SIGNAL_GROUP_STOP_COUNT_OFFSET,r19
-
-       add r19=IA64_SIGNAL_SHARED_PENDING_OFFSET+IA64_SIGPENDING_SIGNAL_OFFSET,r19
-       ;;
-       ld4 r17=[r17]           // r17 <- current->signal->group_stop_count
-(p7)   mov r8=0                // clear error code
-
-       ld8 r19=[r19]           // r19 <- current->signal->shared_pending
-       ;;
-       cmp4.gt p6,p7=r17,r0    // p6/p7 <- (current->signal->group_stop_count > 0)?
-(p8)   mov r8=0                // clear error code
-
-       or r18=r18,r19          // r18 <- current->pending | current->signal->shared_pending
-       ;;
-       // r18 <- (current->pending | current->signal->shared_pending) & ~current->blocked:
-       andcm r18=r18,r14
-       add r9=TI_FLAGS+IA64_TASK_SIZE,r16
-       ;;
-
-(p7)   cmp.ne.or.andcm p6,p7=r18,r0            // p6/p7 <- signal pending
-       mov r19=0                                       // i must not leak kernel bits...
-(p6)   br.cond.dpnt.many .sig_pending
-       ;;
-
-1:     ld4 r17=[r9]                            // r17 <- current->thread_info->flags
-       ;;
-       mov ar.ccv=r17
-       and r18=~_TIF_SIGPENDING,r17            // r18 <- r17 & ~(1 << TIF_SIGPENDING)
-       ;;
-
-       st8 [r2]=r14                            // update current->blocked with new mask
-       cmpxchg4.acq r8=[r9],r18,ar.ccv         // current->thread_info->flags <- r18
-       ;;
-       cmp.ne p6,p0=r17,r8                     // update failed?
-(p6)   br.cond.spnt.few 1b                     // yes -> retry
-
-#ifdef CONFIG_SMP
-       // __ticket_spin_unlock(r31)
-       st2.rel [r31]=r20
-       mov r20=0                                       // i must not leak kernel bits...
-#endif
-       SSM_PSR_I(p0, p9, r31)
-       ;;
-
-       srlz.d                                  // ensure psr.i is set again
-       mov r18=0                                       // i must not leak kernel bits...
-
-.store_mask:
-EX(.fail_efault, (p15) probe.w.fault r34, 3)   // verify user has write-access to *oset
-EX(.fail_efault, (p15) st8 [r34]=r3)
-       mov r2=0                                        // i must not leak kernel bits...
-       mov r3=0                                        // i must not leak kernel bits...
-       mov r8=0                                // return 0
-       mov r9=0                                        // i must not leak kernel bits...
-       mov r14=0                                       // i must not leak kernel bits...
-       mov r17=0                                       // i must not leak kernel bits...
-       mov r31=0                                       // i must not leak kernel bits...
-       FSYS_RETURN
-
-.sig_pending:
-#ifdef CONFIG_SMP
-       // __ticket_spin_unlock(r31)
-       st2.rel [r31]=r20                       // release the lock
-#endif
-       SSM_PSR_I(p0, p9, r17)
-       ;;
-       srlz.d
-       br.sptk.many fsys_fallback_syscall      // with signal pending, do the heavy-weight syscall
-
-#ifdef CONFIG_SMP
-.lock_contention:
-       /* Rather than spinning here, fall back on doing a heavy-weight syscall.  */
-       SSM_PSR_I(p0, p9, r17)
-       ;;
-       srlz.d
-       br.sptk.many fsys_fallback_syscall
-#endif
-END(fsys_rt_sigprocmask)
-
 /*
  * fsys_getcpu doesn't use the third parameter in this implementation. It reads
  * current_thread_info()->cpu and corresponding node in cpu_to_node_map.
@@ -559,11 +390,15 @@ ENTRY(fsys_getcpu)
        ;;
        tnat.nz p7,p0 = r33                     // I guard against NaT argument
 (p7)    br.cond.spnt.few .fail_einval          // B
+       ;;
+       cmp.ne p6,p0=r32,r0
+       cmp.ne p7,p0=r33,r0
+       ;;
 #ifdef CONFIG_NUMA
        movl r17=cpu_to_node_map
        ;;
-EX(.fail_efault, probe.w.fault r32, 3)         // M This takes 5 cycles
-EX(.fail_efault, probe.w.fault r33, 3)         // M This takes 5 cycles
+EX(.fail_efault, (p6) probe.w.fault r32, 3)            // M This takes 5 cycles
+EX(.fail_efault, (p7) probe.w.fault r33, 3)            // M This takes 5 cycles
        shladd r18=r3,1,r17
        ;;
        ld2 r20=[r18]                           // r20 = cpu_to_node_map[cpu]
@@ -573,20 +408,20 @@ EX(.fail_efault, probe.w.fault r33, 3)            // M This takes 5 cycles
 (p8)   br.spnt.many fsys_fallback_syscall
        ;;
        ;;
-EX(.fail_efault, st4 [r32] = r3)
-EX(.fail_efault, st2 [r33] = r20)
+EX(.fail_efault, (p6) st4 [r32] = r3)
+EX(.fail_efault, (p7) st2 [r33] = r20)
        mov r8=0
        ;;
 #else
-EX(.fail_efault, probe.w.fault r32, 3)         // M This takes 5 cycles
-EX(.fail_efault, probe.w.fault r33, 3)         // M This takes 5 cycles
+EX(.fail_efault, (p6) probe.w.fault r32, 3)            // M This takes 5 cycles
+EX(.fail_efault, (p7) probe.w.fault r33, 3)            // M This takes 5 cycles
        and r2 = TIF_ALLWORK_MASK,r2
        ;;
        cmp.ne p8,p0=0,r2
 (p8)   br.spnt.many fsys_fallback_syscall
        ;;
-EX(.fail_efault, st4 [r32] = r3)
-EX(.fail_efault, st2 [r33] = r0)
+EX(.fail_efault, (p6) st4 [r32] = r3)
+EX(.fail_efault, (p7) st2 [r33] = r0)
        mov r8=0
        ;;
 #endif
@@ -916,7 +751,7 @@ paravirt_fsyscall_table:
        data8 0                         // sigaltstack
        data8 0                         // rt_sigaction
        data8 0                         // rt_sigpending
-       data8 fsys_rt_sigprocmask       // rt_sigprocmask
+       data8 0                         // rt_sigprocmask
        data8 0                         // rt_sigqueueinfo      // 1180
        data8 0                         // rt_sigreturn
        data8 0                         // rt_sigsuspend
index e1f46d7574602aa5ca4f3934097fed74c94cb005..da17253b5735ba2d81b37e929f59126628449da7 100644 (file)
@@ -118,8 +118,6 @@ struct mm_struct;
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-#define prepare_to_copy(tsk)   do { } while (0)
-
 /*
  * create a kernel thread without removing it from tasklists
  */
index 46460fa15d5cc66cbc68f39a3016b596c03af2ad..f17c42aff7ffb9aa592aebf2e118d99309d8e699 100644 (file)
@@ -153,9 +153,6 @@ static inline void release_thread(struct task_struct *dead_task)
 {
 }
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 /*
index bffb545272997b54c2a0090b398618f83320662a..af2bb9652392e9ecb80980c51a0ebf2b3390e526 100644 (file)
@@ -23,7 +23,6 @@ extern const struct seq_operations cpuinfo_op;
 
 # define cpu_relax()           barrier()
 # define cpu_sleep()           do {} while (0)
-# define prepare_to_copy(tsk)  do {} while (0)
 
 #define task_pt_regs(tsk) \
                (((struct pt_regs *)(THREAD_SIZE + task_stack_page(tsk))) - 1)
index f5e121213c229dd289bef22129d10337a97c54fa..85aad0321397fa420529d50bde88501f8f3e664a 100644 (file)
@@ -30,6 +30,7 @@ config MIPS
        select HAVE_MEMBLOCK_NODE_MAP
        select ARCH_DISCARD_MEMBLOCK
        select GENERIC_SMP_IDLE_THREAD
+       select BUILDTIME_EXTABLE_SORT
 
 menu "Machine selection"
 
index 20e9dcf42b27461f0584f01f79cfc3c1bb385edc..5e33fabe354de7e12e11dc4f64aa5d0be7464090 100644 (file)
@@ -310,9 +310,6 @@ struct task_struct;
 /* Free all resources held by a thread. */
 #define release_thread(thread) do { } while(0)
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 extern unsigned long thread_saved_pc(struct task_struct *tsk);
index f7b3c9ab2cb581fed5a838dfed13b916f9abbf4f..247928c9f549ec239e1e5556a1c7157674833bba 100644 (file)
@@ -139,9 +139,6 @@ static inline void start_thread(struct pt_regs *regs,
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-extern void prepare_to_copy(struct task_struct *tsk);
-
 /*
  * create a kernel thread without removing it from tasklists
  */
index 14707f25153b15f46e97a4ad68ca5dc521bc1984..7dab0cd364663e9ab9b6c8418cf9da51a28525c3 100644 (file)
@@ -208,12 +208,14 @@ void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
 }
 
 /*
- * this gets called before we allocate a new thread and copy the current task
- * into it so that we can store lazy state into memory
+ * this gets called so that we can store lazy state into memory and copy the
+ * current task into the new thread.
  */
-void prepare_to_copy(struct task_struct *tsk)
+int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
-       unlazy_fpu(tsk);
+       unlazy_fpu(src);
+       *dst = *src;
+       return 0;
 }
 
 /*
index f7516fa78b58a2e2311433f63a1a401d7de9d044..30462f1fe959298cdf492bd8c18e3879fce7a50f 100644 (file)
@@ -72,10 +72,6 @@ struct thread_struct {
 #define task_pt_regs(task) user_regs(task_thread_info(task))
 #define current_regs() user_regs(current_thread_info())
 
-extern inline void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
 #define INIT_SP         (sizeof(init_stack) + (unsigned long) &init_stack)
 
 #define INIT_THREAD  { }
diff --git a/arch/parisc/include/asm/kbdleds.h b/arch/parisc/include/asm/kbdleds.h
new file mode 100644 (file)
index 0000000..2e2e75a
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _ASM_PARISC_KBDLEDS_H
+#define _ASM_PARISC_KBDLEDS_H
+
+/*
+ * On HIL keyboards of PARISC machines there is no NumLock key and
+ * everyone expects the keypad to be used for numbers. That's why
+ * we can safely turn on the NUMLOCK bit.
+ */
+
+static inline int kbd_defleds(void)
+{
+#if defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)
+       return 1 << VC_NUMLOCK;
+#else
+       return 0;
+#endif
+}
+
+#endif /* _ASM_PARISC_KBDLEDS_H */
index acdf4cad6125ae78203c60ce06337e6a9e0354cb..0e8b7b8ce8a25046830f28367b4d4eb84d9e0813 100644 (file)
@@ -328,9 +328,6 @@ struct mm_struct;
 extern void release_thread(struct task_struct *);
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 extern void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm);
 
 extern unsigned long get_wchan(struct task_struct *p);
index 8a01098eaaca058c88fcee6ed7176f4f6b18d78b..0a947bd9c0760a8eff4aa79b1a08066af8e75fc4 100644 (file)
@@ -350,7 +350,7 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE
 
 config KEXEC
        bool "kexec system call (EXPERIMENTAL)"
-       depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP && !PPC_47x)) && EXPERIMENTAL
+       depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) && EXPERIMENTAL
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
@@ -367,7 +367,7 @@ config KEXEC
 
 config CRASH_DUMP
        bool "Build a kdump crash kernel"
-       depends on PPC64 || 6xx || FSL_BOOKE || (44x && !SMP && !PPC_47x)
+       depends on PPC64 || 6xx || FSL_BOOKE || (44x && !SMP)
        select RELOCATABLE if PPC64 || 44x
        select DYNAMIC_MEMSTART if FSL_BOOKE
        help
index 6524c6e2189651cb0c7b21f0b18076d1a5f07593..950d1f7a5a395baf7f5deae6d1e2888e9b92138b 100644 (file)
@@ -69,6 +69,16 @@ LDFLAGS_vmlinux      := $(LDFLAGS_vmlinux-y)
 
 CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=no -mcall-aixdesc
 CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple
+
+CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=power7,-mtune=power4)
+CFLAGS-$(CONFIG_CELL_CPU) += $(call cc-option,-mcpu=cell)
+CFLAGS-$(CONFIG_POWER4_CPU) += $(call cc-option,-mcpu=power4)
+CFLAGS-$(CONFIG_POWER5_CPU) += $(call cc-option,-mcpu=power5)
+CFLAGS-$(CONFIG_POWER6_CPU) += $(call cc-option,-mcpu=power6)
+CFLAGS-$(CONFIG_POWER7_CPU) += $(call cc-option,-mcpu=power7)
+
+CFLAGS-$(CONFIG_TUNE_CELL) += $(call cc-option,-mtune=cell)
+
 KBUILD_CPPFLAGS        += -Iarch/$(ARCH)
 KBUILD_AFLAGS  += -Iarch/$(ARCH)
 KBUILD_CFLAGS  += -msoft-float -pipe -Iarch/$(ARCH) $(CFLAGS-y)
@@ -76,32 +86,11 @@ CPP         = $(CC) -E $(KBUILD_CFLAGS)
 
 CHECKFLAGS     += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
 
-ifeq ($(CONFIG_PPC64),y)
-GCC_BROKEN_VEC := $(call cc-ifversion, -lt, 0400, y)
-
-ifeq ($(CONFIG_POWER4_ONLY),y)
-ifeq ($(CONFIG_ALTIVEC),y)
-ifeq ($(GCC_BROKEN_VEC),y)
-       KBUILD_CFLAGS += $(call cc-option,-mcpu=970)
-else
-       KBUILD_CFLAGS += $(call cc-option,-mcpu=power4)
-endif
-else
-       KBUILD_CFLAGS += $(call cc-option,-mcpu=power4)
-endif
-else
-       KBUILD_CFLAGS += $(call cc-option,-mtune=power4)
-endif
-endif
-
 KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
 
-ifeq ($(CONFIG_TUNE_CELL),y)
-       KBUILD_CFLAGS += $(call cc-option,-mtune=cell)
-endif
-
-# No AltiVec instruction when building kernel
+# No AltiVec or VSX instructions when building kernel
 KBUILD_CFLAGS += $(call cc-option,-mno-altivec)
+KBUILD_CFLAGS += $(call cc-option,-mno-vsx)
 
 # No SPE instruction when building kernel
 # (We use all available options to help semi-broken compilers)
@@ -160,6 +149,7 @@ core-$(CONFIG_KVM)          += arch/powerpc/kvm/
 core-$(CONFIG_PERF_EVENTS)     += arch/powerpc/perf/
 
 drivers-$(CONFIG_OPROFILE)     += arch/powerpc/oprofile/
+drivers-$(CONFIG_CRYPTO_DEV_NX) += drivers/crypto/nx/
 
 # Default to zImage, override when needed
 all: zImage
@@ -234,10 +224,11 @@ archprepare: checkbin
 # Use the file '.tmp_gas_check' for binutils tests, as gas won't output
 # to stdout and these checks are run even on install targets.
 TOUT   := .tmp_gas_check
-# Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later for altivec
-# instructions.
-# gcc-3.4 and binutils-2.14 are a fatal combination.
 
+# Check gcc and binutils versions:
+# - gcc-3.4 and binutils-2.14 are a fatal combination
+# - Require gcc 4.0 or above on 64-bit
+# - gcc-4.2.0 has issues compiling modules on 64-bit
 checkbin:
        @if test "$(call cc-version)" = "0304" ; then \
                if ! /bin/echo mftb 5 | $(AS) -v -mppc -many -o $(TOUT) >/dev/null 2>&1 ; then \
@@ -247,6 +238,12 @@ checkbin:
                        false; \
                fi ; \
        fi
+       @if test "$(call cc-version)" -lt "0400" \
+           && test "x${CONFIG_PPC64}" = "xy" ; then \
+                echo -n "Sorry, GCC v4.0 or above is required to build " ; \
+                echo "the 64-bit powerpc kernel." ; \
+                false ; \
+        fi
        @if test "$(call cc-fullversion)" = "040200" \
            && test "x${CONFIG_MODULES}${CONFIG_PPC64}" = "xyy" ; then \
                echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ; \
index 7bda373f10ef230a61744f029aad29af73f097a7..9d4917aebe6b06fc2ea42dd77eba97bddffe8e01 100644 (file)
                                0x0 0x0 0x0 0x3 &UIC3 0xe 0x4 /* swizzled int C */
                                0x0 0x0 0x0 0x4 &UIC3 0xf 0x4 /* swizzled int D */>;
                };
+
+               MSI: ppc4xx-msi@C10000000 {
+                       compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+                       reg = < 0xC 0x10000000 0x100
+                               0xC 0x10000000 0x100>;
+                       sdr-base = <0x36C>;
+                       msi-data = <0x00004440>;
+                       msi-mask = <0x0000ffe0>;
+                       interrupts =<0 1 2 3 4 5 6 7>;
+                       interrupt-parent = <&MSI>;
+                       #interrupt-cells = <1>;
+                       #address-cells = <0>;
+                       #size-cells = <0>;
+                       msi-available-ranges = <0x0 0x100>;
+                       interrupt-map = <
+                               0 &UIC3 0x18 1
+                               1 &UIC3 0x19 1
+                               2 &UIC3 0x1A 1
+                               3 &UIC3 0x1B 1
+                               4 &UIC3 0x1C 1
+                               5 &UIC3 0x1D 1
+                               6 &UIC3 0x1E 1
+                               7 &UIC3 0x1F 1
+                       >;
+               };
        };
 };
index 0db9ba0423ff9e2fea406de92234a05846681662..c09598b31de1bb6ded595721edf7e8cbb213ace9 100644 (file)
@@ -100,6 +100,7 @@ CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
 CONFIG_SND_SOC=y
+CONFIG_SND_POWERPC_SOC=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_CMOS=y
 CONFIG_EXT2_FS=y
index 1196c34163b748cf6cd41c97e5a9dfb7f962b39d..07b7f2af2dca7ed9e06f7baea8e46f904fcb8aba 100644 (file)
@@ -1,5 +1,4 @@
 CONFIG_PPC64=y
-CONFIG_POWER4_ONLY=y
 CONFIG_ALTIVEC=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=4
index 2244d370f24d0044048293a5414102aa4f9c6e94..02ac96b679b8585a943b60faaf338aeed434c95b 100644 (file)
@@ -1,5 +1,4 @@
 CONFIG_PPC64=y
-CONFIG_POWER4_ONLY=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=4
 CONFIG_EXPERIMENTAL=y
index d6b6df5e874355c7c67624f6bdc7dc2a83cbfd82..62bb723c5b54443e01efd6c0cf6827e8b8afd33e 100644 (file)
@@ -141,6 +141,7 @@ CONFIG_SND_INTEL8X0=y
 # CONFIG_SND_PPC is not set
 # CONFIG_SND_USB is not set
 CONFIG_SND_SOC=y
+CONFIG_SND_POWERPC_SOC=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
index 5b0e2926becd0ffdc6142c65a4f1d7fe3bf10969..d1828427ae55ffb7b998e277b36404679352f7cc 100644 (file)
@@ -143,6 +143,7 @@ CONFIG_SND_INTEL8X0=y
 # CONFIG_SND_PPC is not set
 # CONFIG_SND_USB is not set
 CONFIG_SND_SOC=y
+CONFIG_SND_POWERPC_SOC=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
index f4deb0b78cf061c7101ce17b041e9d6c032d400f..840a2c2d043085434b715dfffa3d4399e70f383b 100644 (file)
@@ -1,5 +1,4 @@
 CONFIG_PPC64=y
-CONFIG_POWER4_ONLY=y
 CONFIG_ALTIVEC=y
 # CONFIG_VIRT_CPU_ACCOUNTING is not set
 CONFIG_SMP=y
index ded867871e97bdbc645dce8e71ce1774b90c555e..c2f4b4a86ece9a2220cd4a06638088ad288fa316 100644 (file)
@@ -6,7 +6,6 @@ CONFIG_NR_CPUS=2
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
-CONFIG_SPARSE_IRQ=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_EMBEDDED=y
@@ -25,7 +24,6 @@ CONFIG_PS3_DISK=y
 CONFIG_PS3_ROM=y
 CONFIG_PS3_FLASH=y
 CONFIG_PS3_VRAM=m
-CONFIG_PS3_LPM=m
 # CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
 CONFIG_HIGH_RES_TIMERS=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
@@ -53,8 +51,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_DIAG is not set
 CONFIG_IPV6=y
 CONFIG_BT=m
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=m
@@ -63,7 +59,6 @@ CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=m
 CONFIG_BT_HCIBTUSB=m
 CONFIG_CFG80211=m
-# CONFIG_WIRELESS_EXT_SYSFS is not set
 CONFIG_MAC80211=m
 CONFIG_MAC80211_RC_PID=y
 # CONFIG_MAC80211_RC_MINSTREL is not set
@@ -181,7 +176,6 @@ CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_WRITECOUNT=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DEBUG_LIST=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_STACKOVERFLOW=y
 CONFIG_CRYPTO_CCM=m
index decad950f11a8e18e7ad4962343d58d77f7fa363..5d7fbe1950f93dc9e285360637cfc78324db66a6 100644 (file)
 #define PPC_LLARX(t, a, b, eh) PPC_LDARX(t, a, b, eh)
 #define PPC_STLCX      stringify_in_c(stdcx.)
 #define PPC_CNTLZL     stringify_in_c(cntlzd)
+#define PPC_MTOCRF(FXM, RS) MTOCRF((FXM), (RS))
 #define PPC_LR_STKOFF  16
 #define PPC_MIN_STKFRM 112
-
-/* Move to CR, single-entry optimized version. Only available
- * on POWER4 and later.
- */
-#ifdef CONFIG_POWER4_ONLY
-#define PPC_MTOCRF     stringify_in_c(mtocrf)
-#else
-#define PPC_MTOCRF     stringify_in_c(mtcrf)
-#endif
-
 #else /* 32-bit */
 
 /* operations for longs and pointers */
index ce516e5eb0d3523d5027f3957877cfe144ee7a3f..ac3eedb9b74ae073f5019dc960862d82e3605455 100644 (file)
@@ -9,7 +9,7 @@
  * Note: This implementation is limited to a power of 2 number of
  * threads per core and the same number for each core in the system
  * (though it would work if some processors had less threads as long
- * as the CPU numbers are still allocated, just not brought offline).
+ * as the CPU numbers are still allocated, just not brought online).
  *
  * However, the API allows for a different implementation in the future
  * if needed, as long as you only use the functions and not the variables
index 1c324ff55ea857f1f31c8f03468430fe7f1784a3..612252388190ccfafeab132ba93e84d8f60b632e 100644 (file)
 #define H_MR_CONDITION  -43
 #define H_NOT_ENOUGH_RESOURCES -44
 #define H_R_STATE       -45
-#define H_RESCINDEND    -46
-#define H_MULTI_THREADS_ACTIVE -9005
+#define H_RESCINDED     -46
+#define H_P2           -55
+#define H_P3           -56
+#define H_P4           -57
+#define H_P5           -58
+#define H_P6           -59
+#define H_P7           -60
+#define H_P8           -61
+#define H_P9           -62
+#define H_TOO_BIG      -64
+#define H_OVERLAP      -68
+#define H_INTERRUPT    -69
+#define H_BAD_DATA     -70
+#define H_NOT_ACTIVE   -71
+#define H_SG_LIST      -72
+#define H_OP_MODE      -73
+#define H_COP_HW       -74
+#define H_UNSUPPORTED_FLAG_START       -256
+#define H_UNSUPPORTED_FLAG_END         -511
+#define H_MULTI_THREADS_ACTIVE -9005
+#define H_OUTSTANDING_COP_OPS  -9006
 
 
 /* Long Busy is a condition that can be returned by the firmware
 #define H_GET_MPP              0x2D4
 #define H_HOME_NODE_ASSOCIATIVITY 0x2EC
 #define H_BEST_ENERGY          0x2F4
+#define H_RANDOM               0x300
+#define H_COP                  0x304
 #define H_GET_MPP_X            0x314
 #define MAX_HCALL_OPCODE       H_GET_MPP_X
 
index a76254af0aaa94024fcb999a923b04140ddd20d4..531fe0c3108f8e157b8a255cb6a2ae8fce142059 100644 (file)
 #define _ASM_POWERPC_LPPACA_H
 #ifdef __KERNEL__
 
-/* These definitions relate to hypervisors that only exist when using
+/*
+ * These definitions relate to hypervisors that only exist when using
  * a server type processor
  */
 #ifdef CONFIG_PPC_BOOK3S
 
-//=============================================================================
-//
-//     This control block contains the data that is shared between the
-//     hypervisor (PLIC) and the OS.
-//
-//
-//----------------------------------------------------------------------------
+/*
+ * This control block contains the data that is shared between the
+ * hypervisor and the OS.
+ */
 #include <linux/cache.h>
 #include <linux/threads.h>
 #include <asm/types.h>
  */
 #define NR_LPPACAS     1
 
-
-/* The Hypervisor barfs if the lppaca crosses a page boundary.  A 1k
- * alignment is sufficient to prevent this */
+/*
+ * The Hypervisor barfs if the lppaca crosses a page boundary.  A 1k
+ * alignment is sufficient to prevent this
+ */
 struct lppaca {
-//=============================================================================
-// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
-// NOTE: The xDynXyz fields are fields that will be dynamically changed by
-// PLIC when preparing to bring a processor online or when dispatching a
-// virtual processor!
-//=============================================================================
-       u32     desc;                   // Eye catcher 0xD397D781       x00-x03
-       u16     size;                   // Size of this struct          x04-x05
-       u16     reserved1;              // Reserved                     x06-x07
-       u16     reserved2:14;           // Reserved                     x08-x09
-       u8      shared_proc:1;          // Shared processor indicator   ...
-       u8      secondary_thread:1;     // Secondary thread indicator   ...
-       volatile u8 dyn_proc_status:8;  // Dynamic Status of this proc  x0A-x0A
-       u8      secondary_thread_count; // Secondary thread count       x0B-x0B
-       volatile u16 dyn_hv_phys_proc_index;// Dynamic HV Physical Proc Index0C-x0D
-       volatile u16 dyn_hv_log_proc_index;// Dynamic HV Logical Proc Indexx0E-x0F
-       u32     decr_val;               // Value for Decr programming   x10-x13
-       u32     pmc_val;                // Value for PMC regs           x14-x17
-       volatile u32 dyn_hw_node_id;    // Dynamic Hardware Node id     x18-x1B
-       volatile u32 dyn_hw_proc_id;    // Dynamic Hardware Proc Id     x1C-x1F
-       volatile u32 dyn_pir;           // Dynamic ProcIdReg value      x20-x23
-       u32     dsei_data;              // DSEI data                    x24-x27
-       u64     sprg3;                  // SPRG3 value                  x28-x2F
-       u8      reserved3[40];          // Reserved                     x30-x57
-       volatile u8 vphn_assoc_counts[8]; // Virtual processor home node
-                                       // associativity change counters x58-x5F
-       u8      reserved4[32];          // Reserved                     x60-x7F
-
-//=============================================================================
-// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data
-//=============================================================================
-       // This Dword contains a byte for each type of interrupt that can occur.
-       // The IPI is a count while the others are just a binary 1 or 0.
-       union {
-               u64     any_int;
-               struct {
-                       u16     reserved;       // Reserved - cleared by #mpasmbl
-                       u8      xirr_int;       // Indicates xXirrValue is valid or Immed IO
-                       u8      ipi_cnt;        // IPI Count
-                       u8      decr_int;       // DECR interrupt occurred
-                       u8      pdc_int;        // PDC interrupt occurred
-                       u8      quantum_int;    // Interrupt quantum reached
-                       u8      old_plic_deferred_ext_int;      // Old PLIC has a deferred XIRR pending
-               } fields;
-       } int_dword;
-
-       // Whenever any fields in this Dword are set then PLIC will defer the
-       // processing of external interrupts.  Note that PLIC will store the
-       // XIRR directly into the xXirrValue field so that another XIRR will
-       // not be presented until this one clears.  The layout of the low
-       // 4-bytes of this Dword is up to SLIC - PLIC just checks whether the
-       // entire Dword is zero or not.  A non-zero value in the low order
-       // 2-bytes will result in SLIC being granted the highest thread
-       // priority upon return.  A 0 will return to SLIC as medium priority.
-       u64     plic_defer_ints_area;   // Entire Dword
-
-       // Used to pass the real SRR0/1 from PLIC to SLIC as well as to
-       // pass the target SRR0/1 from SLIC to PLIC on a SetAsrAndRfid.
-       u64     saved_srr0;             // Saved SRR0                   x10-x17
-       u64     saved_srr1;             // Saved SRR1                   x18-x1F
-
-       // Used to pass parms from the OS to PLIC for SetAsrAndRfid
-       u64     saved_gpr3;             // Saved GPR3                   x20-x27
-       u64     saved_gpr4;             // Saved GPR4                   x28-x2F
-       union {
-               u64     saved_gpr5;     /* Saved GPR5               x30-x37 */
-               struct {
-                       u8      cede_latency_hint;  /*                  x30 */
-                       u8      reserved[7];        /*              x31-x36 */
-               } fields;
-       } gpr5_dword;
-
-
-       u8      dtl_enable_mask;        // Dispatch Trace Log mask      x38-x38
-       u8      donate_dedicated_cpu;   // Donate dedicated CPU cycles  x39-x39
-       u8      fpregs_in_use;          // FP regs in use               x3A-x3A
-       u8      pmcregs_in_use;         // PMC regs in use              x3B-x3B
-       volatile u32 saved_decr;        // Saved Decr Value             x3C-x3F
-       volatile u64 emulated_time_base;// Emulated TB for this thread  x40-x47
-       volatile u64 cur_plic_latency;  // Unaccounted PLIC latency     x48-x4F
-       u64     tot_plic_latency;       // Accumulated PLIC latency     x50-x57
-       u64     wait_state_cycles;      // Wait cycles for this proc    x58-x5F
-       u64     end_of_quantum;         // TB at end of quantum         x60-x67
-       u64     pdc_saved_sprg1;        // Saved SPRG1 for PMC int      x68-x6F
-       u64     pdc_saved_srr0;         // Saved SRR0 for PMC int       x70-x77
-       volatile u32 virtual_decr;      // Virtual DECR for shared procsx78-x7B
-       u16     slb_count;              // # of SLBs to maintain        x7C-x7D
-       u8      idle;                   // Indicate OS is idle          x7E
-       u8      vmxregs_in_use;         // VMX registers in use         x7F
-
-
-//=============================================================================
-// CACHE_LINE_3 0x0100 - 0x017F: This line is shared with other processors
-//=============================================================================
-       // This is the yield_count.  An "odd" value (low bit on) means that
-       // the processor is yielded (either because of an OS yield or a PLIC
-       // preempt).  An even value implies that the processor is currently
-       // executing.
-       // NOTE: This value will ALWAYS be zero for dedicated processors and
-       // will NEVER be zero for shared processors (ie, initialized to a 1).
-       volatile u32 yield_count;       // PLIC increments each dispatchx00-x03
-       volatile u32 dispersion_count;  // dispatch changed phys cpu    x04-x07
-       volatile u64 cmo_faults;        // CMO page fault count         x08-x0F
-       volatile u64 cmo_fault_time;    // CMO page fault time          x10-x17
-       u8      reserved7[104];         // Reserved                     x18-x7F
-
-//=============================================================================
-// CACHE_LINE_4-5 0x0180 - 0x027F Contains PMC interrupt data
-//=============================================================================
-       u32     page_ins;               // CMO Hint - # page ins by OS  x00-x03
-       u8      reserved8[148];         // Reserved                     x04-x97
-       volatile u64 dtl_idx;           // Dispatch Trace Log head idx  x98-x9F
-       u8      reserved9[96];          // Reserved                     xA0-xFF
+       /* cacheline 1 contains read-only data */
+
+       u32     desc;                   /* Eye catcher 0xD397D781 */
+       u16     size;                   /* Size of this struct */
+       u16     reserved1;
+       u16     reserved2:14;
+       u8      shared_proc:1;          /* Shared processor indicator */
+       u8      secondary_thread:1;     /* Secondary thread indicator */
+       u8      reserved3[14];
+       volatile u32 dyn_hw_node_id;    /* Dynamic hardware node id */
+       volatile u32 dyn_hw_proc_id;    /* Dynamic hardware proc id */
+       u8      reserved4[56];
+       volatile u8 vphn_assoc_counts[8]; /* Virtual processor home node */
+                                         /* associativity change counters */
+       u8      reserved5[32];
+
+       /* cacheline 2 contains local read-write data */
+
+       u8      reserved6[48];
+       u8      cede_latency_hint;
+       u8      reserved7[7];
+       u8      dtl_enable_mask;        /* Dispatch Trace Log mask */
+       u8      donate_dedicated_cpu;   /* Donate dedicated CPU cycles */
+       u8      fpregs_in_use;
+       u8      pmcregs_in_use;
+       u8      reserved8[28];
+       u64     wait_state_cycles;      /* Wait cycles for this proc */
+       u8      reserved9[28];
+       u16     slb_count;              /* # of SLBs to maintain */
+       u8      idle;                   /* Indicate OS is idle */
+       u8      vmxregs_in_use;
+
+       /* cacheline 3 is shared with other processors */
+
+       /*
+        * This is the yield_count.  An "odd" value (low bit on) means that
+        * the processor is yielded (either because of an OS yield or a
+        * hypervisor preempt).  An even value implies that the processor is
+        * currently executing.
+        * NOTE: This value will ALWAYS be zero for dedicated processors and
+        * will NEVER be zero for shared processors (ie, initialized to a 1).
+        */
+       volatile u32 yield_count;
+       volatile u32 dispersion_count;  /* dispatch changed physical cpu */
+       volatile u64 cmo_faults;        /* CMO page fault count */
+       volatile u64 cmo_fault_time;    /* CMO page fault time */
+       u8      reserved10[104];
+
+       /* cacheline 4-5 */
+
+       u32     page_ins;               /* CMO Hint - # page ins by OS */
+       u8      reserved11[148];
+       volatile u64 dtl_idx;           /* Dispatch Trace Log head index */
+       u8      reserved12[96];
 } __attribute__((__aligned__(0x400)));
 
 extern struct lppaca lppaca[];
@@ -172,13 +112,13 @@ extern struct lppaca lppaca[];
  * ESID is stored in the lower 64bits, then the VSID.
  */
 struct slb_shadow {
-       u32     persistent;             // Number of persistent SLBs    x00-x03
-       u32     buffer_length;          // Total shadow buffer length   x04-x07
-       u64     reserved;               // Alignment                    x08-x0f
+       u32     persistent;             /* Number of persistent SLBs */
+       u32     buffer_length;          /* Total shadow buffer length */
+       u64     reserved;
        struct  {
                u64     esid;
                u64     vsid;
-       } save_area[SLB_NUM_BOLTED];    //                              x10-x40
+       } save_area[SLB_NUM_BOLTED];
 } ____cacheline_aligned;
 
 extern struct slb_shadow slb_shadow[];
index 233f9ecae7616462acba110cef032904dfed8d27..f5117674bf92b1b1a10975dbd663cfddd5931f7f 100644 (file)
@@ -265,8 +265,8 @@ LV1_CALL(get_spe_irq_outlet,                            2, 1,  78 )
 LV1_CALL(set_spe_privilege_state_area_1_register,       3, 0,  79 )
 LV1_CALL(create_repository_node,                        6, 0,  90 )
 LV1_CALL(read_repository_node,                          5, 2,  91 )
-LV1_CALL(modify_repository_node_value,                  6, 0,  92 )
-LV1_CALL(remove_repository_node,                        4, 0,  93 )
+LV1_CALL(write_repository_node,                         6, 0,  92 )
+LV1_CALL(delete_repository_node,                        4, 0,  93 )
 LV1_CALL(read_htab_entries,                             2, 5,  95 )
 LV1_CALL(set_dabr,                                      2, 0,  96 )
 LV1_CALL(get_total_execution_time,                      2, 1, 103 )
index 23cd6cc30bcf8fa54ed2b48faa530e495f611bb4..c07edfe98b9899a4c81cf9e0f71e85b3a97df965 100644 (file)
 #define PSERIES_RECONFIG_REMOVE                0x0002
 #define PSERIES_DRCONF_MEM_ADD         0x0003
 #define PSERIES_DRCONF_MEM_REMOVE      0x0004
+#define PSERIES_UPDATE_PROPERTY                0x0005
+
+/**
+ * pSeries_reconfig_notify - Notifier value structure for OFDT property updates
+ *
+ * @node: Device tree node which owns the property being updated
+ * @property: Updated property
+ */
+struct pSeries_reconfig_prop_update {
+       struct device_node *node;
+       struct property *property;
+};
 
 #ifdef CONFIG_PPC_PSERIES
 extern int pSeries_reconfig_notifier_register(struct notifier_block *);
index 50f73aa2ba219acbb132795af18cc7f447e019ff..15444204a3a1d25049bca2b8115c7e88ed3d2d4f 100644 (file)
@@ -369,7 +369,15 @@ BEGIN_FTR_SECTION                  \
 END_FTR_SECTION_IFCLR(CPU_FTR_601)
 #endif
 
-       
+#ifdef CONFIG_PPC64
+#define MTOCRF(FXM, RS)                        \
+       BEGIN_FTR_SECTION_NESTED(848);  \
+       mtcrf   (FXM), (RS);            \
+       FTR_SECTION_ELSE_NESTED(848);   \
+       mtocrf (FXM), (RS);             \
+       ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_NOEXECUTE, 848)
+#endif
+
 /*
  * This instruction is not implemented on the PPC 603 or 601; however, on
  * the 403GCX and 405GP tlbia IS defined and tlbie is not.
index 48a26d379222ddee0be8d4e9e1a5fb06d18a71eb..55e85631c42e3be5ab150ce48e2d3dbf767e9c6a 100644 (file)
@@ -74,9 +74,6 @@ struct task_struct;
 void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp);
 void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-extern void prepare_to_copy(struct task_struct *tsk);
-
 /* Create a new kernel thread. */
 extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
index 84cc7840cd18f139e1410f50fc383baa8010d16b..9c21ed42aba6c593207d4b24b1b1523916c07716 100644 (file)
@@ -354,12 +354,6 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
 #define PTRACE_GETREGS64         22
 #define PTRACE_SETREGS64         23
 
-/* (old) PTRACE requests with inverted arguments */
-#define PPC_PTRACE_GETREGS     0x99    /* Get GPRs 0 - 31 */
-#define PPC_PTRACE_SETREGS     0x98    /* Set GPRs 0 - 31 */
-#define PPC_PTRACE_GETFPREGS   0x97    /* Get FPRs 0 - 31 */
-#define PPC_PTRACE_SETFPREGS   0x96    /* Set FPRs 0 - 31 */
-
 /* Calls to trace a 64bit program from a 32bit program */
 #define PPC_PTRACE_PEEKTEXT_3264 0x95
 #define PPC_PTRACE_PEEKDATA_3264 0x94
index caf82d0a00def0de572440332ce0c0ec3f507591..1a6320290d2616d971c2c09ca6da2281e5b766fb 100644 (file)
@@ -21,7 +21,6 @@ extern void disable_kernel_fp(void);
 extern void enable_kernel_fp(void);
 extern void flush_fp_to_thread(struct task_struct *);
 extern void enable_kernel_altivec(void);
-extern void giveup_altivec(struct task_struct *);
 extern void load_up_altivec(struct task_struct *);
 extern int emulate_altivec(struct pt_regs *);
 extern void __giveup_vsx(struct task_struct *);
@@ -40,10 +39,15 @@ static inline void discard_lazy_cpu_state(void)
 
 #ifdef CONFIG_ALTIVEC
 extern void flush_altivec_to_thread(struct task_struct *);
+extern void giveup_altivec(struct task_struct *);
+extern void giveup_altivec_notask(void);
 #else
 static inline void flush_altivec_to_thread(struct task_struct *t)
 {
 }
+static inline void giveup_altivec(struct task_struct *t)
+{
+}
 #endif
 
 #ifdef CONFIG_VSX
index 1a1bb00f061a9bcd13440359123bad1cc840bebf..a556ccc16b58d4560b004c1ee797f8e92c7c6506 100644 (file)
@@ -113,7 +113,6 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_NOERROR           (1<<TIF_NOERROR)
 #define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_SYSCALL_TRACEPOINT        (1<<TIF_SYSCALL_TRACEPOINT)
-#define _TIF_RUNLATCH          (1<<TIF_RUNLATCH)
 #define _TIF_SYSCALL_T_OR_A    (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
                                 _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT)
 
index 6bfd5ffe1d4fd287141523e10d1589d89472b636..b19adf751dd954c492b7afc062a76df896ef6b61 100644 (file)
 
 struct iommu_table;
 
+/*
+ * Platform Facilities Option (PFO)-specific data
+ */
+
+/* Starting unit address for PFO devices on the VIO BUS */
+#define VIO_BASE_PFO_UA        0x50000000
+
+/**
+ * vio_pfo_op - PFO operation parameters
+ *
+ * @flags: h_call subfunctions and modifiers
+ * @in: Input data block logical real address
+ * @inlen: If non-negative, the length of the input data block.  If negative,
+ *     the length of the input data descriptor list in bytes.
+ * @out: Output data block logical real address
+ * @outlen: If non-negative, the length of the input data block.  If negative,
+ *     the length of the input data descriptor list in bytes.
+ * @csbcpb: Logical real address of the 4k naturally-aligned storage block
+ *     containing the CSB & optional FC field specific CPB
+ * @timeout: # of milliseconds to retry h_call, 0 for no timeout.
+ * @hcall_err: pointer to return the h_call return value, else NULL
+ */
+struct vio_pfo_op {
+       u64 flags;
+       s64 in;
+       s64 inlen;
+       s64 out;
+       s64 outlen;
+       u64 csbcpb;
+       void *done;
+       unsigned long handle;
+       unsigned int timeout;
+       long hcall_err;
+};
+
+/* End PFO specific data */
+
+enum vio_dev_family {
+       VDEVICE,        /* The OF node is a child of /vdevice */
+       PFO,            /* The OF node is a child of /ibm,platform-facilities */
+};
+
 /**
  * vio_dev - This structure is used to describe virtual I/O devices.
  *
@@ -58,6 +100,7 @@ struct vio_dev {
        const char *name;
        const char *type;
        uint32_t unit_address;
+       uint32_t resource_id;
        unsigned int irq;
        struct {
                size_t desired;
@@ -65,6 +108,7 @@ struct vio_dev {
                size_t allocated;
                atomic_t allocs_failed;
        } cmo;
+       enum vio_dev_family family;
        struct device dev;
 };
 
@@ -95,6 +139,8 @@ extern void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired);
 
 extern void __devinit vio_unregister_device(struct vio_dev *dev);
 
+extern int vio_h_cop_sync(struct vio_dev *vdev, struct vio_pfo_op *op);
+
 struct device_node;
 
 extern struct vio_dev *vio_register_device_node(
index 34b8afe94a500f1b7191bce06ad23b2b32427725..4554dc2fe857262af77c26fa500bd669514460ee 100644 (file)
@@ -188,10 +188,6 @@ int main(void)
        DEFINE(SLBSHADOW_STACKESID,
               offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].esid));
        DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area));
-       DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0));
-       DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1));
-       DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int));
-       DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int));
        DEFINE(LPPACA_PMCINUSE, offsetof(struct lppaca, pmcregs_in_use));
        DEFINE(LPPACA_DTLIDX, offsetof(struct lppaca, dtl_idx));
        DEFINE(LPPACA_YIELDCOUNT, offsetof(struct lppaca, yield_count));
index ef2074c3e9062db06f6c4d5a3f03babff55bcce7..ed1718feb9d9c5e8ee2c55241663d31d99717e15 100644 (file)
@@ -63,15 +63,9 @@ system_call_common:
        std     r0,GPR0(r1)
        std     r10,GPR1(r1)
        ACCOUNT_CPU_USER_ENTRY(r10, r11)
-       /*
-        * This "crclr so" clears CR0.SO, which is the error indication on
-        * return from this system call.  There must be no cmp instruction
-        * between it and the "mfcr r9" below, otherwise if XER.SO is set,
-        * CR0.SO will get set, causing all system calls to appear to fail.
-        */
-       crclr   so
        std     r2,GPR2(r1)
        std     r3,GPR3(r1)
+       mfcr    r2
        std     r4,GPR4(r1)
        std     r5,GPR5(r1)
        std     r6,GPR6(r1)
@@ -82,18 +76,20 @@ system_call_common:
        std     r11,GPR10(r1)
        std     r11,GPR11(r1)
        std     r11,GPR12(r1)
+       std     r11,_XER(r1)
+       std     r11,_CTR(r1)
        std     r9,GPR13(r1)
-       mfcr    r9
        mflr    r10
+       /*
+        * This clears CR0.SO (bit 28), which is the error indication on
+        * return from this system call.
+        */
+       rldimi  r2,r11,28,(63-28)
        li      r11,0xc01
-       std     r9,_CCR(r1)
        std     r10,_LINK(r1)
        std     r11,_TRAP(r1)
-       mfxer   r9
-       mfctr   r10
-       std     r9,_XER(r1)
-       std     r10,_CTR(r1)
        std     r3,ORIG_GPR3(r1)
+       std     r2,_CCR(r1)
        ld      r2,PACATOC(r13)
        addi    r9,r1,STACK_FRAME_OVERHEAD
        ld      r11,exception_marker@toc(r2)
@@ -154,7 +150,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
        ld      r10,TI_FLAGS(r11)
        andi.   r11,r10,_TIF_SYSCALL_T_OR_A
        bne-    syscall_dotrace
-syscall_dotrace_cont:
+.Lsyscall_dotrace_cont:
        cmpldi  0,r0,NR_syscalls
        bge-    syscall_enosys
 
@@ -211,7 +207,7 @@ syscall_exit:
        cmpld   r3,r11
        ld      r5,_CCR(r1)
        bge-    syscall_error
-syscall_error_cont:
+.Lsyscall_error_cont:
        ld      r7,_NIP(r1)
 BEGIN_FTR_SECTION
        stdcx.  r0,0,r1                 /* to clear the reservation */
@@ -246,7 +242,7 @@ syscall_error:
        oris    r5,r5,0x1000    /* Set SO bit in CR */
        neg     r3,r3
        std     r5,_CCR(r1)
-       b       syscall_error_cont
+       b       .Lsyscall_error_cont
        
 /* Traced system call support */
 syscall_dotrace:
@@ -268,7 +264,7 @@ syscall_dotrace:
        addi    r9,r1,STACK_FRAME_OVERHEAD
        clrrdi  r10,r1,THREAD_SHIFT
        ld      r10,TI_FLAGS(r10)
-       b       syscall_dotrace_cont
+       b       .Lsyscall_dotrace_cont
 
 syscall_enosys:
        li      r3,-ENOSYS
index 8f880bc77c56a2a8cd811ca19a21677778856130..f7bed44ee165594abd3c37bf3387dec2c29d9dff 100644 (file)
@@ -94,12 +94,10 @@ machine_check_pSeries_1:
 data_access_pSeries:
        HMT_MEDIUM
        SET_SCRATCH0(r13)
-#ifndef CONFIG_POWER4_ONLY
 BEGIN_FTR_SECTION
        b       data_access_check_stab
 data_access_not_stab:
 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB)
-#endif
        EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD,
                                 KVMTEST, 0x300)
 
@@ -301,7 +299,6 @@ machine_check_fwnmi:
                                 EXC_STD, KVMTEST, 0x200)
        KVM_HANDLER_SKIP(PACA_EXMC, EXC_STD, 0x200)
 
-#ifndef CONFIG_POWER4_ONLY
        /* moved from 0x300 */
 data_access_check_stab:
        GET_PACA(r13)
@@ -328,7 +325,6 @@ do_stab_bolted_pSeries:
        GET_SCRATCH0(r10)
        std     r10,PACA_EXSLB+EX_R13(r13)
        EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD)
-#endif /* CONFIG_POWER4_ONLY */
 
        KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300)
        KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380)
index 7dd2981bcc50579a059f3a6fb446660d133eed2a..22d608e8bb7d258cdda03a64aba858addd7c81fd 100644 (file)
@@ -777,14 +777,6 @@ _GLOBAL(__fixup_440A_mcheck)
        sync
        blr
 
-/*
- * extern void giveup_altivec(struct task_struct *prev)
- *
- * The 44x core does not have an AltiVec unit.
- */
-_GLOBAL(giveup_altivec)
-       blr
-
 /*
  * extern void giveup_fpu(struct task_struct *prev)
  *
index 28e62598d0e81c10d18940b8461a969dd97ebde5..de80e0f9a2bded4d802bdaf9c4f71a2e29add915 100644 (file)
@@ -874,14 +874,6 @@ _GLOBAL(__setup_e500mc_ivors)
        sync
        blr
 
-/*
- * extern void giveup_altivec(struct task_struct *prev)
- *
- * The e500 core does not have an AltiVec unit.
- */
-_GLOBAL(giveup_altivec)
-       blr
-
 #ifdef CONFIG_SPE
 /*
  * extern void giveup_spe(struct task_struct *prev)
index 641da9e868ce192848e925f5778183c16a1e2928..7835a5e1ea5fed3a33bbc7878b0c9e6c26796489 100644 (file)
@@ -587,7 +587,7 @@ int irq_choose_cpu(const struct cpumask *mask)
 {
        int cpuid;
 
-       if (cpumask_equal(mask, cpu_all_mask)) {
+       if (cpumask_equal(mask, cpu_online_mask)) {
                static int irq_rover;
                static DEFINE_RAW_SPINLOCK(irq_rover_lock);
                unsigned long flags;
index 7cd07b42ca1a505c9a9bfbb3802277336537a514..386d57f66f28771de46265b5ad2ae0fbed32a8fa 100644 (file)
@@ -738,8 +738,23 @@ relocate_new_kernel:
        mr      r5, r31
 
        li      r0, 0
-#elif defined(CONFIG_44x)  && !defined(CONFIG_PPC_47x)
+#elif defined(CONFIG_44x)
 
+       /* Save our parameters */
+       mr      r29, r3
+       mr      r30, r4
+       mr      r31, r5
+
+#ifdef CONFIG_PPC_47x
+       /* Check for 47x cores */
+       mfspr   r3,SPRN_PVR
+       srwi    r3,r3,16
+       cmplwi  cr0,r3,PVR_476@h
+       beq     setup_map_47x
+       cmplwi  cr0,r3,PVR_476_ISS@h
+       beq     setup_map_47x
+#endif /* CONFIG_PPC_47x */
+       
 /*
  * Code for setting up 1:1 mapping for PPC440x for KEXEC
  *
@@ -753,16 +768,15 @@ relocate_new_kernel:
  * 5) Invalidate the tmp mapping.
  *
  * - Based on the kexec support code for FSL BookE
- * - Doesn't support 47x yet.
  *
  */
-       /* Save our parameters */
-       mr      r29, r3
-       mr      r30, r4
-       mr      r31, r5
 
-       /* Load our MSR_IS and TID to MMUCR for TLB search */
-       mfspr   r3,SPRN_PID
+       /* 
+        * Load the PID with kernel PID (0).
+        * Also load our MSR_IS and TID to MMUCR for TLB search.
+        */
+       li      r3, 0
+       mtspr   SPRN_PID, r3
        mfmsr   r4
        andi.   r4,r4,MSR_IS@l
        beq     wmmucr
@@ -900,6 +914,179 @@ next_tlb:
        li      r3, 0
        tlbwe   r3, r24, PPC44x_TLB_PAGEID
        sync
+       b       ppc44x_map_done
+
+#ifdef CONFIG_PPC_47x
+
+       /* 1:1 mapping for 47x */
+
+setup_map_47x:
+
+       /*
+        * Load the kernel pid (0) to PID and also to MMUCR[TID].
+        * Also set the MSR IS->MMUCR STS
+        */
+       li      r3, 0
+       mtspr   SPRN_PID, r3                    /* Set PID */
+       mfmsr   r4                              /* Get MSR */
+       andi.   r4, r4, MSR_IS@l                /* TS=1? */
+       beq     1f                              /* If not, leave STS=0 */
+       oris    r3, r3, PPC47x_MMUCR_STS@h      /* Set STS=1 */
+1:     mtspr   SPRN_MMUCR, r3                  /* Put MMUCR */
+       sync
+
+       /* Find the entry we are running from */
+       bl      2f
+2:     mflr    r23
+       tlbsx   r23, 0, r23
+       tlbre   r24, r23, 0                     /* TLB Word 0 */
+       tlbre   r25, r23, 1                     /* TLB Word 1 */
+       tlbre   r26, r23, 2                     /* TLB Word 2 */
+
+
+       /*
+        * Invalidates all the tlb entries by writing to 256 RPNs(r4)
+        * of 4k page size in all  4 ways (0-3 in r3).
+        * This would invalidate the entire UTLB including the one we are
+        * running from. However the shadow TLB entries would help us 
+        * to continue the execution, until we flush them (rfi/isync).
+        */
+       addis   r3, 0, 0x8000                   /* specify the way */
+       addi    r4, 0, 0                        /* TLB Word0 = (EPN=0, VALID = 0) */
+       addi    r5, 0, 0
+       b       clear_utlb_entry
+
+       /* Align the loop to speed things up. from head_44x.S */
+       .align  6
+
+clear_utlb_entry:
+
+       tlbwe   r4, r3, 0
+       tlbwe   r5, r3, 1
+       tlbwe   r5, r3, 2
+       addis   r3, r3, 0x2000                  /* Increment the way */
+       cmpwi   r3, 0
+       bne     clear_utlb_entry
+       addis   r3, 0, 0x8000
+       addis   r4, r4, 0x100                   /* Increment the EPN */
+       cmpwi   r4, 0
+       bne     clear_utlb_entry
+
+       /* Create the entries in the other address space */
+       mfmsr   r5
+       rlwinm  r7, r5, 27, 31, 31              /* Get the TS (Bit 26) from MSR */
+       xori    r7, r7, 1                       /* r7 = !TS */
+
+       insrwi  r24, r7, 1, 21                  /* Change the TS in the saved TLB word 0 */
+
+       /* 
+        * write out the TLB entries for the tmp mapping
+        * Use way '0' so that we could easily invalidate it later.
+        */
+       lis     r3, 0x8000                      /* Way '0' */ 
+
+       tlbwe   r24, r3, 0
+       tlbwe   r25, r3, 1
+       tlbwe   r26, r3, 2
+
+       /* Update the msr to the new TS */
+       insrwi  r5, r7, 1, 26
+
+       bl      1f
+1:     mflr    r6
+       addi    r6, r6, (2f-1b)
+
+       mtspr   SPRN_SRR0, r6
+       mtspr   SPRN_SRR1, r5
+       rfi
+
+       /* 
+        * Now we are in the tmp address space.
+        * Create a 1:1 mapping for 0-2GiB in the original TS.
+        */
+2:
+       li      r3, 0
+       li      r4, 0                           /* TLB Word 0 */
+       li      r5, 0                           /* TLB Word 1 */
+       li      r6, 0
+       ori     r6, r6, PPC47x_TLB2_S_RWX       /* TLB word 2 */
+
+       li      r8, 0                           /* PageIndex */
+
+       xori    r7, r7, 1                       /* revert back to original TS */
+
+write_utlb:
+       rotlwi  r5, r8, 28                      /* RPN = PageIndex * 256M */
+                                               /* ERPN = 0 as we don't use memory above 2G */
+
+       mr      r4, r5                          /* EPN = RPN */
+       ori     r4, r4, (PPC47x_TLB0_VALID | PPC47x_TLB0_256M)
+       insrwi  r4, r7, 1, 21                   /* Insert the TS to Word 0 */
+
+       tlbwe   r4, r3, 0                       /* Write out the entries */
+       tlbwe   r5, r3, 1
+       tlbwe   r6, r3, 2
+       addi    r8, r8, 1
+       cmpwi   r8, 8                           /* Have we completed ? */
+       bne     write_utlb
+
+       /* make sure we complete the TLB write up */
+       isync
+
+       /* 
+        * Prepare to jump to the 1:1 mapping.
+        * 1) Extract page size of the tmp mapping
+        *    DSIZ = TLB_Word0[22:27]
+        * 2) Calculate the physical address of the address
+        *    to jump to.
+        */
+       rlwinm  r10, r24, 0, 22, 27
+
+       cmpwi   r10, PPC47x_TLB0_4K
+       bne     0f
+       li      r10, 0x1000                     /* r10 = 4k */
+       bl      1f
+
+0:
+       /* Defaults to 256M */
+       lis     r10, 0x1000
+       
+       bl      1f
+1:     mflr    r4
+       addi    r4, r4, (2f-1b)                 /* virtual address  of 2f */
+
+       subi    r11, r10, 1                     /* offsetmask = Pagesize - 1 */
+       not     r10, r11                        /* Pagemask = ~(offsetmask) */
+
+       and     r5, r25, r10                    /* Physical page */
+       and     r6, r4, r11                     /* offset within the current page */
+
+       or      r5, r5, r6                      /* Physical address for 2f */
+
+       /* Switch the TS in MSR to the original one */
+       mfmsr   r8
+       insrwi  r8, r7, 1, 26
+
+       mtspr   SPRN_SRR1, r8
+       mtspr   SPRN_SRR0, r5
+       rfi
+
+2:
+       /* Invalidate the tmp mapping */
+       lis     r3, 0x8000                      /* Way '0' */
+
+       clrrwi  r24, r24, 12                    /* Clear the valid bit */
+       tlbwe   r24, r3, 0
+       tlbwe   r25, r3, 1
+       tlbwe   r26, r3, 2
+
+       /* Make sure we complete the TLB write and flush the shadow TLB */
+       isync
+
+#endif
+
+ppc44x_map_done:
+
 
        /* Restore the parameters */
        mr      r3, r29
index 0bb1f98613bab5041dcad6073eae70395db5970c..fbe1a12dc7f1ae8a2c4cdee3d2225f846f24ba15 100644 (file)
@@ -36,10 +36,7 @@ struct lppaca lppaca[] = {
        [0 ... (NR_LPPACAS-1)] = {
                .desc = 0xd397d781,     /* "LpPa" */
                .size = sizeof(struct lppaca),
-               .dyn_proc_status = 2,
-               .decr_val = 0x00ff0000,
                .fpregs_in_use = 1,
-               .end_of_quantum = 0xfffffffffffffffful,
                .slb_count = 64,
                .vmxregs_in_use = 0,
                .page_ins = 0,
index aa05935b69477766fc9c60d559bbed5a89f9b7f0..710f400476deb8461a98a1342c6ee1b669fbe686 100644 (file)
@@ -124,7 +124,7 @@ void enable_kernel_altivec(void)
        if (current->thread.regs && (current->thread.regs->msr & MSR_VEC))
                giveup_altivec(current);
        else
-               giveup_altivec(NULL);   /* just enable AltiVec for kernel - force */
+               giveup_altivec_notask();
 #else
        giveup_altivec(last_task_used_altivec);
 #endif /* CONFIG_SMP */
@@ -711,18 +711,21 @@ release_thread(struct task_struct *t)
 }
 
 /*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
+ * this gets called so that we can store coprocessor state into memory and
+ * copy the current task into the new thread.
  */
-void prepare_to_copy(struct task_struct *tsk)
+int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
-       flush_fp_to_thread(current);
-       flush_altivec_to_thread(current);
-       flush_vsx_to_thread(current);
-       flush_spe_to_thread(current);
+       flush_fp_to_thread(src);
+       flush_altivec_to_thread(src);
+       flush_vsx_to_thread(src);
+       flush_spe_to_thread(src);
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
-       flush_ptrace_hw_breakpoint(tsk);
+       flush_ptrace_hw_breakpoint(src);
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
+
+       *dst = *src;
+       return 0;
 }
 
 /*
index 99860273211b03a7c31958d0c8940bf56d51abec..1b488e5305c5f2d1cdfa889f3dfafead154b258c 100644 (file)
@@ -680,6 +680,9 @@ static void __init early_cmdline_parse(void)
 #define OV3_VMX                        0x40    /* VMX/Altivec */
 #define OV3_DFP                        0x20    /* decimal FP */
 
+/* Option vector 4: IBM PAPR implementation */
+#define OV4_MIN_ENT_CAP                0x01    /* minimum VP entitled capacity */
+
 /* Option vector 5: PAPR/OF options supported */
 #define OV5_LPAR               0x80    /* logical partitioning supported */
 #define OV5_SPLPAR             0x40    /* shared-processor LPAR supported */
@@ -701,6 +704,8 @@ static void __init early_cmdline_parse(void)
 #define OV5_XCMO                       0x00
 #endif
 #define OV5_TYPE1_AFFINITY     0x80    /* Type 1 NUMA affinity */
+#define OV5_PFO_HW_RNG         0x80    /* PFO Random Number Generator */
+#define OV5_PFO_HW_ENCR                0x20    /* PFO Encryption Accelerator */
 
 /* Option Vector 6: IBM PAPR hints */
 #define OV6_LINUX              0x02    /* Linux is our OS */
@@ -744,11 +749,12 @@ static unsigned char ibm_architecture_vec[] = {
        OV3_FP | OV3_VMX | OV3_DFP,
 
        /* option vector 4: IBM PAPR implementation */
-       2 - 2,                          /* length */
+       3 - 2,                          /* length */
        0,                              /* don't halt */
+       OV4_MIN_ENT_CAP,                /* minimum VP entitled capacity */
 
        /* option vector 5: PAPR/OF options */
-       13 - 2,                         /* length */
+       18 - 2,                         /* length */
        0,                              /* don't ignore, don't halt */
        OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY |
        OV5_DONATE_DEDICATE_CPU | OV5_MSI,
@@ -762,8 +768,13 @@ static unsigned char ibm_architecture_vec[] = {
         * must match by the macro below. Update the definition if
         * the structure layout changes.
         */
-#define IBM_ARCH_VEC_NRCORES_OFFSET    100
+#define IBM_ARCH_VEC_NRCORES_OFFSET    101
        W(NR_CPUS),                     /* number of cores supported */
+       0,
+       0,
+       0,
+       0,
+       OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR,
 
        /* option vector 6: IBM PAPR hints */
        4 - 2,                          /* length */
index dd5e214cdf21ec13ce19a6448572a0c937794d65..c10fc28b90920120a12c4bc6cc5c39dbf2780e6a 100644 (file)
@@ -1432,40 +1432,6 @@ static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
 #endif
 }
 
-/*
- * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
- * we mark them as obsolete now, they will be removed in a future version
- */
-static long arch_ptrace_old(struct task_struct *child, long request,
-                           unsigned long addr, unsigned long data)
-{
-       void __user *datavp = (void __user *) data;
-
-       switch (request) {
-       case PPC_PTRACE_GETREGS:        /* Get GPRs 0 - 31. */
-               return copy_regset_to_user(child, &user_ppc_native_view,
-                                          REGSET_GPR, 0, 32 * sizeof(long),
-                                          datavp);
-
-       case PPC_PTRACE_SETREGS:        /* Set GPRs 0 - 31. */
-               return copy_regset_from_user(child, &user_ppc_native_view,
-                                            REGSET_GPR, 0, 32 * sizeof(long),
-                                            datavp);
-
-       case PPC_PTRACE_GETFPREGS:      /* Get FPRs 0 - 31. */
-               return copy_regset_to_user(child, &user_ppc_native_view,
-                                          REGSET_FPR, 0, 32 * sizeof(double),
-                                          datavp);
-
-       case PPC_PTRACE_SETFPREGS:      /* Set FPRs 0 - 31. */
-               return copy_regset_from_user(child, &user_ppc_native_view,
-                                            REGSET_FPR, 0, 32 * sizeof(double),
-                                            datavp);
-       }
-
-       return -EPERM;
-}
-
 long arch_ptrace(struct task_struct *child, long request,
                 unsigned long addr, unsigned long data)
 {
@@ -1687,14 +1653,6 @@ long arch_ptrace(struct task_struct *child, long request,
                                             datavp);
 #endif
 
-       /* Old reverse args ptrace callss */
-       case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
-       case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
-       case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
-       case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */
-               ret = arch_ptrace_old(child, request, addr, data);
-               break;
-
        default:
                ret = ptrace_request(child, request, addr, data);
                break;
index 469349d14a97e18b56a3fae0d9b12362f325249c..8c21658719d96507efe14ba40c61c266ca99c738 100644 (file)
  * in exit.c or in signal.c.
  */
 
-/*
- * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
- * we mark them as obsolete now, they will be removed in a future version
- */
-static long compat_ptrace_old(struct task_struct *child, long request,
-                             long addr, long data)
-{
-       switch (request) {
-       case PPC_PTRACE_GETREGS:        /* Get GPRs 0 - 31. */
-               return copy_regset_to_user(child,
-                                          task_user_regset_view(current), 0,
-                                          0, 32 * sizeof(compat_long_t),
-                                          compat_ptr(data));
-
-       case PPC_PTRACE_SETREGS:        /* Set GPRs 0 - 31. */
-               return copy_regset_from_user(child,
-                                            task_user_regset_view(current), 0,
-                                            0, 32 * sizeof(compat_long_t),
-                                            compat_ptr(data));
-       }
-
-       return -EPERM;
-}
-
 /* Macros to workout the correct index for the FPR in the thread struct */
 #define FPRNUMBER(i) (((i) - PT_FPR0) >> 1)
 #define FPRHALF(i) (((i) - PT_FPR0) & 1)
@@ -308,8 +284,6 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
        case PTRACE_SETVSRREGS:
        case PTRACE_GETREGS64:
        case PTRACE_SETREGS64:
-       case PPC_PTRACE_GETFPREGS:
-       case PPC_PTRACE_SETFPREGS:
        case PTRACE_KILL:
        case PTRACE_SINGLESTEP:
        case PTRACE_DETACH:
@@ -322,12 +296,6 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                ret = arch_ptrace(child, request, addr, data);
                break;
 
-       /* Old reverse args ptrace callss */
-       case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
-       case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
-               ret = compat_ptrace_old(child, request, addr, data);
-               break;
-
        default:
                ret = compat_ptrace_request(child, request, addr, data);
                break;
index 4d5a3edff49ebfe5f660c9233c8bb94f39deb41c..e830289d2e4874af433f856d565813c949bee0a4 100644 (file)
@@ -89,6 +89,16 @@ _GLOBAL(load_up_altivec)
        /* restore registers and return */
        blr
 
+_GLOBAL(giveup_altivec_notask)
+       mfmsr   r3
+       andis.  r4,r3,MSR_VEC@h
+       bnelr                           /* Already enabled? */
+       oris    r3,r3,MSR_VEC@h
+       SYNC
+       MTMSRD(r3)                      /* enable use of VMX now */
+       isync
+       blr
+
 /*
  * giveup_altivec(tsk)
  * Disable VMX for the task given as the argument,
index a3a99901c8ecf4a1929815329a72a54146017603..cb87301ccd55a63a46f3069efe3b860e3da5c3c8 100644 (file)
@@ -14,7 +14,9 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+#include <linux/cpu.h>
 #include <linux/types.h>
+#include <linux/delay.h>
 #include <linux/stat.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -709,13 +711,26 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev)
        struct vio_driver *viodrv = to_vio_driver(dev->driver);
        unsigned long flags;
        size_t size;
+       bool dma_capable = false;
+
+       /* A device requires entitlement if it has a DMA window property */
+       switch (viodev->family) {
+       case VDEVICE:
+               if (of_get_property(viodev->dev.of_node,
+                                       "ibm,my-dma-window", NULL))
+                       dma_capable = true;
+               break;
+       case PFO:
+               dma_capable = false;
+               break;
+       default:
+               dev_warn(dev, "unknown device family: %d\n", viodev->family);
+               BUG();
+               break;
+       }
 
-       /*
-        * Check to see that device has a DMA window and configure
-        * entitlement for the device.
-        */
-       if (of_get_property(viodev->dev.of_node,
-                           "ibm,my-dma-window", NULL)) {
+       /* Configure entitlement for the device. */
+       if (dma_capable) {
                /* Check that the driver is CMO enabled and get desired DMA */
                if (!viodrv->get_desired_dma) {
                        dev_err(dev, "%s: device driver does not support CMO\n",
@@ -1050,6 +1065,94 @@ static void vio_cmo_sysfs_init(void) { }
 EXPORT_SYMBOL(vio_cmo_entitlement_update);
 EXPORT_SYMBOL(vio_cmo_set_dev_desired);
 
+
+/*
+ * Platform Facilities Option (PFO) support
+ */
+
+/**
+ * vio_h_cop_sync - Perform a synchronous PFO co-processor operation
+ *
+ * @vdev - Pointer to a struct vio_dev for device
+ * @op - Pointer to a struct vio_pfo_op for the operation parameters
+ *
+ * Calls the hypervisor to synchronously perform the PFO operation
+ * described in @op.  In the case of a busy response from the hypervisor,
+ * the operation will be re-submitted indefinitely unless a non-zero timeout
+ * is specified or an error occurs. The timeout places a limit on when to
+ * stop re-submitting a operation, the total time can be exceeded if an
+ * operation is in progress.
+ *
+ * If op->hcall_ret is not NULL, this will be set to the return from the
+ * last h_cop_op call or it will be 0 if an error not involving the h_call
+ * was encountered.
+ *
+ * Returns:
+ *     0 on success,
+ *     -EINVAL if the h_call fails due to an invalid parameter,
+ *     -E2BIG if the h_call can not be performed synchronously,
+ *     -EBUSY if a timeout is specified and has elapsed,
+ *     -EACCES if the memory area for data/status has been rescinded, or
+ *     -EPERM if a hardware fault has been indicated
+ */
+int vio_h_cop_sync(struct vio_dev *vdev, struct vio_pfo_op *op)
+{
+       struct device *dev = &vdev->dev;
+       unsigned long deadline = 0;
+       long hret = 0;
+       int ret = 0;
+
+       if (op->timeout)
+               deadline = jiffies + msecs_to_jiffies(op->timeout);
+
+       while (true) {
+               hret = plpar_hcall_norets(H_COP, op->flags,
+                               vdev->resource_id,
+                               op->in, op->inlen, op->out,
+                               op->outlen, op->csbcpb);
+
+               if (hret == H_SUCCESS ||
+                   (hret != H_NOT_ENOUGH_RESOURCES &&
+                    hret != H_BUSY && hret != H_RESOURCE) ||
+                   (op->timeout && time_after(deadline, jiffies)))
+                       break;
+
+               dev_dbg(dev, "%s: hcall ret(%ld), retrying.\n", __func__, hret);
+       }
+
+       switch (hret) {
+       case H_SUCCESS:
+               ret = 0;
+               break;
+       case H_OP_MODE:
+       case H_TOO_BIG:
+               ret = -E2BIG;
+               break;
+       case H_RESCINDED:
+               ret = -EACCES;
+               break;
+       case H_HARDWARE:
+               ret = -EPERM;
+               break;
+       case H_NOT_ENOUGH_RESOURCES:
+       case H_RESOURCE:
+       case H_BUSY:
+               ret = -EBUSY;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       if (ret)
+               dev_dbg(dev, "%s: Sync h_cop_op failure (ret:%d) (hret:%ld)\n",
+                               __func__, ret, hret);
+
+       op->hcall_err = hret;
+       return ret;
+}
+EXPORT_SYMBOL(vio_h_cop_sync);
+
 static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
 {
        const unsigned char *dma_window;
@@ -1211,35 +1314,87 @@ static void __devinit vio_dev_release(struct device *dev)
 struct vio_dev *vio_register_device_node(struct device_node *of_node)
 {
        struct vio_dev *viodev;
+       struct device_node *parent_node;
        const unsigned int *unit_address;
+       const unsigned int *pfo_resid = NULL;
+       enum vio_dev_family family;
+       const char *of_node_name = of_node->name ? of_node->name : "<unknown>";
 
-       /* we need the 'device_type' property, in order to match with drivers */
-       if (of_node->type == NULL) {
-               printk(KERN_WARNING "%s: node %s missing 'device_type'\n",
-                               __func__,
-                               of_node->name ? of_node->name : "<unknown>");
+       /*
+        * Determine if this node is a under the /vdevice node or under the
+        * /ibm,platform-facilities node.  This decides the device's family.
+        */
+       parent_node = of_get_parent(of_node);
+       if (parent_node) {
+               if (!strcmp(parent_node->full_name, "/ibm,platform-facilities"))
+                       family = PFO;
+               else if (!strcmp(parent_node->full_name, "/vdevice"))
+                       family = VDEVICE;
+               else {
+                       pr_warn("%s: parent(%s) of %s not recognized.\n",
+                                       __func__,
+                                       parent_node->full_name,
+                                       of_node_name);
+                       of_node_put(parent_node);
+                       return NULL;
+               }
+               of_node_put(parent_node);
+       } else {
+               pr_warn("%s: could not determine the parent of node %s.\n",
+                               __func__, of_node_name);
                return NULL;
        }
 
-       unit_address = of_get_property(of_node, "reg", NULL);
-       if (unit_address == NULL) {
-               printk(KERN_WARNING "%s: node %s missing 'reg'\n",
-                               __func__,
-                               of_node->name ? of_node->name : "<unknown>");
-               return NULL;
+       if (family == PFO) {
+               if (of_get_property(of_node, "interrupt-controller", NULL)) {
+                       pr_debug("%s: Skipping the interrupt controller %s.\n",
+                                       __func__, of_node_name);
+                       return NULL;
+               }
        }
 
        /* allocate a vio_dev for this node */
        viodev = kzalloc(sizeof(struct vio_dev), GFP_KERNEL);
-       if (viodev == NULL)
+       if (viodev == NULL) {
+               pr_warn("%s: allocation failure for VIO device.\n", __func__);
                return NULL;
+       }
 
-       viodev->irq = irq_of_parse_and_map(of_node, 0);
+       /* we need the 'device_type' property, in order to match with drivers */
+       viodev->family = family;
+       if (viodev->family == VDEVICE) {
+               if (of_node->type != NULL)
+                       viodev->type = of_node->type;
+               else {
+                       pr_warn("%s: node %s is missing the 'device_type' "
+                                       "property.\n", __func__, of_node_name);
+                       goto out;
+               }
+
+               unit_address = of_get_property(of_node, "reg", NULL);
+               if (unit_address == NULL) {
+                       pr_warn("%s: node %s missing 'reg'\n",
+                                       __func__, of_node_name);
+                       goto out;
+               }
+               dev_set_name(&viodev->dev, "%x", *unit_address);
+               viodev->irq = irq_of_parse_and_map(of_node, 0);
+               viodev->unit_address = *unit_address;
+       } else {
+               /* PFO devices need their resource_id for submitting COP_OPs
+                * This is an optional field for devices, but is required when
+                * performing synchronous ops */
+               pfo_resid = of_get_property(of_node, "ibm,resource-id", NULL);
+               if (pfo_resid != NULL)
+                       viodev->resource_id = *pfo_resid;
+
+               unit_address = NULL;
+               dev_set_name(&viodev->dev, "%s", of_node_name);
+               viodev->type = of_node_name;
+               viodev->irq = 0;
+       }
 
-       dev_set_name(&viodev->dev, "%x", *unit_address);
        viodev->name = of_node->name;
-       viodev->type = of_node->type;
-       viodev->unit_address = *unit_address;
        viodev->dev.of_node = of_node_get(of_node);
 
        if (firmware_has_feature(FW_FEATURE_CMO))
@@ -1267,16 +1422,51 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node)
        }
 
        return viodev;
+
+out:   /* Use this exit point for any return prior to device_register */
+       kfree(viodev);
+
+       return NULL;
 }
 EXPORT_SYMBOL(vio_register_device_node);
 
+/*
+ * vio_bus_scan_for_devices - Scan OF and register each child device
+ * @root_name - OF node name for the root of the subtree to search.
+ *             This must be non-NULL
+ *
+ * Starting from the root node provide, register the device node for
+ * each child beneath the root.
+ */
+static void vio_bus_scan_register_devices(char *root_name)
+{
+       struct device_node *node_root, *node_child;
+
+       if (!root_name)
+               return;
+
+       node_root = of_find_node_by_name(NULL, root_name);
+       if (node_root) {
+
+               /*
+                * Create struct vio_devices for each virtual device in
+                * the device tree. Drivers will associate with them later.
+                */
+               node_child = of_get_next_child(node_root, NULL);
+               while (node_child) {
+                       vio_register_device_node(node_child);
+                       node_child = of_get_next_child(node_root, node_child);
+               }
+               of_node_put(node_root);
+       }
+}
+
 /**
  * vio_bus_init: - Initialize the virtual IO bus
  */
 static int __init vio_bus_init(void)
 {
        int err;
-       struct device_node *node_vroot;
 
        if (firmware_has_feature(FW_FEATURE_CMO))
                vio_cmo_sysfs_init();
@@ -1301,19 +1491,8 @@ static int __init vio_bus_init(void)
        if (firmware_has_feature(FW_FEATURE_CMO))
                vio_cmo_bus_init();
 
-       node_vroot = of_find_node_by_name(NULL, "vdevice");
-       if (node_vroot) {
-               struct device_node *of_node;
-
-               /*
-                * Create struct vio_devices for each virtual device in
-                * the device tree. Drivers will associate with them later.
-                */
-               for (of_node = node_vroot->child; of_node != NULL;
-                               of_node = of_node->sibling)
-                       vio_register_device_node(of_node);
-               of_node_put(node_vroot);
-       }
+       vio_bus_scan_register_devices("vdevice");
+       vio_bus_scan_register_devices("ibm,platform-facilities");
 
        return 0;
 }
@@ -1436,12 +1615,28 @@ struct vio_dev *vio_find_node(struct device_node *vnode)
 {
        const uint32_t *unit_address;
        char kobj_name[20];
+       struct device_node *vnode_parent;
+       const char *dev_type;
+
+       vnode_parent = of_get_parent(vnode);
+       if (!vnode_parent)
+               return NULL;
+
+       dev_type = of_get_property(vnode_parent, "device_type", NULL);
+       of_node_put(vnode_parent);
+       if (!dev_type)
+               return NULL;
 
        /* construct the kobject name from the device node */
-       unit_address = of_get_property(vnode, "reg", NULL);
-       if (!unit_address)
+       if (!strcmp(dev_type, "vdevice")) {
+               unit_address = of_get_property(vnode, "reg", NULL);
+               if (!unit_address)
+                       return NULL;
+               snprintf(kobj_name, sizeof(kobj_name), "%x", *unit_address);
+       } else if (!strcmp(dev_type, "ibm,platform-facilities"))
+               snprintf(kobj_name, sizeof(kobj_name), "%s", vnode->name);
+       else
                return NULL;
-       snprintf(kobj_name, sizeof(kobj_name), "%x", *unit_address);
 
        return vio_find_name(kobj_name);
 }
index 773d38f90aaa27a46a0ee2e1593322b4fc947b25..d73a5901490018486fed19115fce46d88084f701 100644 (file)
@@ -30,7 +30,7 @@ _GLOBAL(__copy_tofrom_user_base)
        dcbt    0,r4
        beq     .Lcopy_page_4K
        andi.   r6,r6,7
-       PPC_MTOCRF      0x01,r5
+       PPC_MTOCRF(0x01,r5)
        blt     cr1,.Lshort_copy
 /* Below we want to nop out the bne if we're on a CPU that has the
  * CPU_FTR_UNALIGNED_LD_STD bit set and the CPU_FTR_CP_USE_DCBTZ bit
@@ -186,7 +186,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
        blr
 
 .Ldst_unaligned:
-       PPC_MTOCRF      0x01,r6         /* put #bytes to 8B bdry into cr7 */
+       PPC_MTOCRF(0x01,r6)             /* put #bytes to 8B bdry into cr7 */
        subf    r5,r6,r5
        li      r7,0
        cmpldi  cr1,r5,16
@@ -201,7 +201,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 2:     bf      cr7*4+1,3f
 37:    lwzx    r0,r7,r4
 83:    stwx    r0,r7,r3
-3:     PPC_MTOCRF      0x01,r5
+3:     PPC_MTOCRF(0x01,r5)
        add     r4,r6,r4
        add     r3,r6,r3
        b       .Ldst_aligned
index 11ce045e21fd1ab43518e6a58f8986d9390cb760..f4fcb0bc65639225b2fca58ace18025870bc471b 100644 (file)
@@ -19,7 +19,7 @@ _GLOBAL(memset)
        rlwimi  r4,r4,16,0,15
        cmplw   cr1,r5,r0               /* do we get that far? */
        rldimi  r4,r4,32,0
-       PPC_MTOCRF      1,r0
+       PPC_MTOCRF(1,r0)
        mr      r6,r3
        blt     cr1,8f
        beq+    3f                      /* if already 8-byte aligned */
@@ -49,7 +49,7 @@ _GLOBAL(memset)
        bdnz    4b
 5:     srwi.   r0,r5,3
        clrlwi  r5,r5,29
-       PPC_MTOCRF      1,r0
+       PPC_MTOCRF(1,r0)
        beq     8f
        bf      29,6f
        std     r4,0(r6)
@@ -65,7 +65,7 @@ _GLOBAL(memset)
        std     r4,0(r6)
        addi    r6,r6,8
 8:     cmpwi   r5,0
-       PPC_MTOCRF      1,r5
+       PPC_MTOCRF(1,r5)
        beqlr+
        bf      29,9f
        stw     r4,0(r6)
index e178922b2c2129e808a427464ce8fccc34643309..82fea3963e15d36f8c30577fce53e7bc30196ac3 100644 (file)
@@ -12,7 +12,7 @@
        .align  7
 _GLOBAL(memcpy)
        std     r3,48(r1)       /* save destination pointer for return value */
-       PPC_MTOCRF      0x01,r5
+       PPC_MTOCRF(0x01,r5)
        cmpldi  cr1,r5,16
        neg     r6,r3           # LS 3 bits = # bytes to 8-byte dest bdry
        andi.   r6,r6,7
@@ -154,7 +154,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
        blr
 
 .Ldst_unaligned:
-       PPC_MTOCRF      0x01,r6         # put #bytes to 8B bdry into cr7
+       PPC_MTOCRF(0x01,r6)             # put #bytes to 8B bdry into cr7
        subf    r5,r6,r5
        li      r7,0
        cmpldi  cr1,r5,16
@@ -169,7 +169,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 2:     bf      cr7*4+1,3f
        lwzx    r0,r7,r4
        stwx    r0,r7,r3
-3:     PPC_MTOCRF      0x01,r5
+3:     PPC_MTOCRF(0x01,r5)
        add     r4,r6,r4
        add     r3,r6,r3
        b       .Ldst_aligned
index 2e4e64abfab4ed751adb06dd2ffff0b476de35c9..8abf6fb8f41037232bc834ef0e87528ab456d8c7 100644 (file)
@@ -23,6 +23,8 @@ config BLUESTONE
        default n
        select PPC44x_SIMPLE
        select APM821xx
+       select PCI_MSI
+       select PPC4xx_MSI
        select PPC4xx_PCI_EXPRESS
        select IBM_EMAC_RGMII
        help
index 9c80fc07384a386e473474a0a3353a06109e642f..61c9550819a255395aff1403d348e19dc4a538e3 100644 (file)
@@ -78,6 +78,36 @@ config PPC_BOOK3E_64
 
 endchoice
 
+choice
+       prompt "CPU selection"
+       depends on PPC64
+       default GENERIC_CPU
+       help
+         This will create a kernel which is optimised for a particular CPU.
+         The resulting kernel may not run on other CPUs, so use this with care.
+
+         If unsure, select Generic.
+
+config GENERIC_CPU
+       bool "Generic"
+
+config CELL_CPU
+       bool "Cell Broadband Engine"
+
+config POWER4_CPU
+       bool "POWER4"
+
+config POWER5_CPU
+       bool "POWER5"
+
+config POWER6_CPU
+       bool "POWER6"
+
+config POWER7_CPU
+       bool "POWER7"
+
+endchoice
+
 config PPC_BOOK3S
        def_bool y
        depends on PPC_BOOK3S_32 || PPC_BOOK3S_64
@@ -86,15 +116,6 @@ config PPC_BOOK3E
        def_bool y
        depends on PPC_BOOK3E_64
 
-config POWER4_ONLY
-       bool "Optimize for POWER4"
-       depends on PPC64 && PPC_BOOK3S
-       default n
-       ---help---
-         Cause the compiler to optimize for POWER4/POWER5/PPC970 processors.
-         The resulting binary will not work on POWER3 or RS64 processors
-         when compiled with binutils 2.15 or later.
-
 config 6xx
        def_bool y
        depends on PPC32 && PPC_BOOK3S
index 03685a329d7dadde0c52643ddd85a4ee23211747..fc536f2971c0c02697aa5b4a8e885955d437a68e 100644 (file)
@@ -1503,6 +1503,7 @@ static int __init pmac_i2c_create_platform_devices(void)
                if (bus->platform_dev == NULL)
                        return -ENOMEM;
                bus->platform_dev->dev.platform_data = bus;
+               bus->platform_dev->dev.of_node = bus->busnode;
                platform_device_add(bus->platform_dev);
        }
 
index 476d9d9b24058d705b481cdf7285e4c76b339cb1..46b7f02325239fd45f946050e6a8d1e973a827ec 100644 (file)
@@ -7,7 +7,6 @@ config PPC_PS3
        select USB_OHCI_BIG_ENDIAN_MMIO
        select USB_ARCH_HAS_EHCI
        select USB_EHCI_BIG_ENDIAN_MMIO
-       select MEMORY_HOTPLUG
        select PPC_PCI_CHOICE
        help
          This option enables support for the Sony PS3 game console
@@ -74,7 +73,7 @@ config PS3_PS3AV
        help
          Include support for the PS3 AV Settings driver.
 
-         This support is required for graphics and sound. In
+         This support is required for PS3 graphics and sound. In
          general, all users will say Y or M.
 
 config PS3_SYS_MANAGER
@@ -85,9 +84,22 @@ config PS3_SYS_MANAGER
        help
          Include support for the PS3 System Manager.
 
-         This support is required for system control.  In
+         This support is required for PS3 system control.  In
          general, all users will say Y or M.
 
+config PS3_REPOSITORY_WRITE
+       bool "PS3 Repository write support" if PS3_ADVANCED
+       depends on PPC_PS3
+       default n
+       help
+         Enables support for writing to the PS3 System Repository.
+
+         This support is intended for bootloaders that need to store data
+         in the repository for later boot stages.
+
+         If in doubt, say N here and reduce the size of the kernel by a
+         small amount.
+
 config PS3_STORAGE
        depends on PPC_PS3
        tristate
@@ -122,7 +134,7 @@ config PS3_FLASH
 
          This support is required to access the PS3 FLASH ROM, which
          contains the boot loader and some boot options.
-         In general, all users will say Y or M.
+         In general, PS3 OtherOS users will say Y or M.
 
          As this driver needs a fixed buffer of 256 KiB of memory, it can
          be disabled on the kernel command line using "ps3flash=off", to
@@ -156,7 +168,7 @@ config PS3GELIC_UDBG
          via the Ethernet port (UDP port number 18194).
 
          This driver uses a trivial implementation and is independent
-         from the main network driver.
+         from the main PS3 gelic network driver.
 
          If in doubt, say N here.
 
index de2aea421707137a458509bfb33dfc62bb720fd8..0c9f643d9e2ac0e048121bd7e1f0557a2edcff00 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <linux/kernel.h>
 #include <linux/export.h>
-#include <linux/memory_hotplug.h>
 #include <linux/memblock.h>
 #include <linux/slab.h>
 
@@ -79,12 +78,14 @@ enum {
  * @base: base address
  * @size: size in bytes
  * @offset: difference between base and rm.size
+ * @destroy: flag if region should be destroyed upon shutdown
  */
 
 struct mem_region {
        u64 base;
        u64 size;
        unsigned long offset;
+       int destroy;
 };
 
 /**
@@ -96,7 +97,7 @@ struct mem_region {
  * The HV virtual address space (vas) allows for hotplug memory regions.
  * Memory regions can be created and destroyed in the vas at runtime.
  * @rm: real mode (bootmem) region
- * @r1: hotplug memory region(s)
+ * @r1: highmem region(s)
  *
  * ps3 addresses
  * virt_addr: a cpu 'translated' effective address
@@ -222,10 +223,6 @@ void ps3_mm_vas_destroy(void)
        }
 }
 
-/*============================================================================*/
-/* memory hotplug routines                                                    */
-/*============================================================================*/
-
 /**
  * ps3_mm_region_create - create a memory region in the vas
  * @r: pointer to a struct mem_region to accept initialized values
@@ -262,6 +259,7 @@ static int ps3_mm_region_create(struct mem_region *r, unsigned long size)
                goto zero_region;
        }
 
+       r->destroy = 1;
        r->offset = r->base - map.rm.size;
        return result;
 
@@ -279,7 +277,14 @@ static void ps3_mm_region_destroy(struct mem_region *r)
 {
        int result;
 
+       if (!r->destroy) {
+               pr_info("%s:%d: Not destroying high region: %llxh %llxh\n",
+                       __func__, __LINE__, r->base, r->size);
+               return;
+       }
+
        DBG("%s:%d: r->base = %llxh\n", __func__, __LINE__, r->base);
+
        if (r->base) {
                result = lv1_release_memory(r->base);
                BUG_ON(result);
@@ -288,50 +293,36 @@ static void ps3_mm_region_destroy(struct mem_region *r)
        }
 }
 
-/**
- * ps3_mm_add_memory - hot add memory
- */
-
-static int __init ps3_mm_add_memory(void)
+static int ps3_mm_get_repository_highmem(struct mem_region *r)
 {
        int result;
-       unsigned long start_addr;
-       unsigned long start_pfn;
-       unsigned long nr_pages;
-
-       if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
-               return -ENODEV;
 
-       BUG_ON(!mem_init_done);
+       /* Assume a single highmem region. */
 
-       start_addr = map.rm.size;
-       start_pfn = start_addr >> PAGE_SHIFT;
-       nr_pages = (map.r1.size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       result = ps3_repository_read_highmem_info(0, &r->base, &r->size);
 
-       DBG("%s:%d: start_addr %lxh, start_pfn %lxh, nr_pages %lxh\n",
-               __func__, __LINE__, start_addr, start_pfn, nr_pages);
-
-       result = add_memory(0, start_addr, map.r1.size);
+       if (result)
+               goto zero_region;
 
-       if (result) {
-               pr_err("%s:%d: add_memory failed: (%d)\n",
-                       __func__, __LINE__, result);
-               return result;
+       if (!r->base || !r->size) {
+               result = -1;
+               goto zero_region;
        }
 
-       memblock_add(start_addr, map.r1.size);
+       r->offset = r->base - map.rm.size;
 
-       result = online_pages(start_pfn, nr_pages);
+       DBG("%s:%d: Found high region in repository: %llxh %llxh\n",
+           __func__, __LINE__, r->base, r->size);
 
-       if (result)
-               pr_err("%s:%d: online_pages failed: (%d)\n",
-                       __func__, __LINE__, result);
+       return 0;
 
+zero_region:
+       DBG("%s:%d: No high region in repository.\n", __func__, __LINE__);
+
+       r->size = r->base = r->offset = 0;
        return result;
 }
 
-device_initcall(ps3_mm_add_memory);
-
 /*============================================================================*/
 /* dma routines                                                               */
 /*============================================================================*/
@@ -1217,13 +1208,23 @@ void __init ps3_mm_init(void)
        BUG_ON(map.rm.base);
        BUG_ON(!map.rm.size);
 
+       /* Check if we got the highmem region from an earlier boot step */
 
-       /* arrange to do this in ps3_mm_add_memory */
-       ps3_mm_region_create(&map.r1, map.total - map.rm.size);
+       if (ps3_mm_get_repository_highmem(&map.r1))
+               ps3_mm_region_create(&map.r1, map.total - map.rm.size);
 
        /* correct map.total for the real total amount of memory we use */
        map.total = map.rm.size + map.r1.size;
 
+       if (!map.r1.size) {
+               DBG("%s:%d: No highmem region found\n", __func__, __LINE__);
+       } else {
+               DBG("%s:%d: Adding highmem region: %llxh %llxh\n",
+                       __func__, __LINE__, map.rm.size,
+                       map.total - map.rm.size);
+               memblock_add(map.rm.size, map.total - map.rm.size);
+       }
+
        DBG(" <- %s:%d\n", __func__, __LINE__);
 }
 
index 1a633ed0fe98744d8994d7e6367180a11ab59a96..d71329a8e325af98798b6d5f653be6b0fdde3e71 100644 (file)
@@ -188,6 +188,22 @@ int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size);
 int ps3_repository_read_region_total(u64 *region_total);
 int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,
        u64 *region_total);
+int ps3_repository_read_highmem_region_count(unsigned int *region_count);
+int ps3_repository_read_highmem_base(unsigned int region_index,
+       u64 *highmem_base);
+int ps3_repository_read_highmem_size(unsigned int region_index,
+       u64 *highmem_size);
+int ps3_repository_read_highmem_info(unsigned int region_index,
+       u64 *highmem_base, u64 *highmem_size);
+
+int ps3_repository_write_highmem_region_count(unsigned int region_count);
+int ps3_repository_write_highmem_base(unsigned int region_index,
+       u64 highmem_base);
+int ps3_repository_write_highmem_size(unsigned int region_index,
+       u64 highmem_size);
+int ps3_repository_write_highmem_info(unsigned int region_index,
+       u64 highmem_base, u64 highmem_size);
+int ps3_repository_delete_highmem_info(unsigned int region_index);
 
 /* repository pme info */
 
index 7bdfea336f5e3b7a3e3ccae07401594f3e14d0ef..9b47ba7a5de774864f65163da84f31dbd54b5333 100644 (file)
@@ -778,6 +778,72 @@ int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total)
                : ps3_repository_read_region_total(region_total);
 }
 
+/**
+ * ps3_repository_read_highmem_region_count - Read the number of highmem regions
+ *
+ * Bootloaders must arrange the repository nodes such that regions are indexed
+ * with a region_index from 0 to region_count-1.
+ */
+
+int ps3_repository_read_highmem_region_count(unsigned int *region_count)
+{
+       int result;
+       u64 v1 = 0;
+
+       result = read_node(PS3_LPAR_ID_CURRENT,
+               make_first_field("highmem", 0),
+               make_field("region", 0),
+               make_field("count", 0),
+               0,
+               &v1, NULL);
+       *region_count = v1;
+       return result;
+}
+
+
+int ps3_repository_read_highmem_base(unsigned int region_index,
+       u64 *highmem_base)
+{
+       return read_node(PS3_LPAR_ID_CURRENT,
+               make_first_field("highmem", 0),
+               make_field("region", region_index),
+               make_field("base", 0),
+               0,
+               highmem_base, NULL);
+}
+
+int ps3_repository_read_highmem_size(unsigned int region_index,
+       u64 *highmem_size)
+{
+       return read_node(PS3_LPAR_ID_CURRENT,
+               make_first_field("highmem", 0),
+               make_field("region", region_index),
+               make_field("size", 0),
+               0,
+               highmem_size, NULL);
+}
+
+/**
+ * ps3_repository_read_highmem_info - Read high memory region info
+ * @region_index: Region index, {0,..,region_count-1}.
+ * @highmem_base: High memory base address.
+ * @highmem_size: High memory size.
+ *
+ * Bootloaders that preallocate highmem regions must place the
+ * region info into the repository at these well known nodes.
+ */
+
+int ps3_repository_read_highmem_info(unsigned int region_index,
+       u64 *highmem_base, u64 *highmem_size)
+{
+       int result;
+
+       *highmem_base = 0;
+       result = ps3_repository_read_highmem_base(region_index, highmem_base);
+       return result ? result
+               : ps3_repository_read_highmem_size(region_index, highmem_size);
+}
+
 /**
  * ps3_repository_read_num_spu_reserved - Number of physical spus reserved.
  * @num_spu: Number of physical spus.
@@ -1002,6 +1068,138 @@ int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar,
                            lpar, rights);
 }
 
+#if defined(CONFIG_PS3_REPOSITORY_WRITE)
+
+static int create_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
+{
+       int result;
+
+       dump_node(0, n1, n2, n3, n4, v1, v2);
+
+       result = lv1_create_repository_node(n1, n2, n3, n4, v1, v2);
+
+       if (result) {
+               pr_devel("%s:%d: lv1_create_repository_node failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
+static int delete_node(u64 n1, u64 n2, u64 n3, u64 n4)
+{
+       int result;
+
+       dump_node(0, n1, n2, n3, n4, 0, 0);
+
+       result = lv1_delete_repository_node(n1, n2, n3, n4);
+
+       if (result) {
+               pr_devel("%s:%d: lv1_delete_repository_node failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
+static int write_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
+{
+       int result;
+
+       result = create_node(n1, n2, n3, n4, v1, v2);
+
+       if (!result)
+               return 0;
+
+       result = lv1_write_repository_node(n1, n2, n3, n4, v1, v2);
+
+       if (result) {
+               pr_devel("%s:%d: lv1_write_repository_node failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
+int ps3_repository_write_highmem_region_count(unsigned int region_count)
+{
+       int result;
+       u64 v1 = (u64)region_count;
+
+       result = write_node(
+               make_first_field("highmem", 0),
+               make_field("region", 0),
+               make_field("count", 0),
+               0,
+               v1, 0);
+       return result;
+}
+
+int ps3_repository_write_highmem_base(unsigned int region_index,
+       u64 highmem_base)
+{
+       return write_node(
+               make_first_field("highmem", 0),
+               make_field("region", region_index),
+               make_field("base", 0),
+               0,
+               highmem_base, 0);
+}
+
+int ps3_repository_write_highmem_size(unsigned int region_index,
+       u64 highmem_size)
+{
+       return write_node(
+               make_first_field("highmem", 0),
+               make_field("region", region_index),
+               make_field("size", 0),
+               0,
+               highmem_size, 0);
+}
+
+int ps3_repository_write_highmem_info(unsigned int region_index,
+       u64 highmem_base, u64 highmem_size)
+{
+       int result;
+
+       result = ps3_repository_write_highmem_base(region_index, highmem_base);
+       return result ? result
+               : ps3_repository_write_highmem_size(region_index, highmem_size);
+}
+
+static int ps3_repository_delete_highmem_base(unsigned int region_index)
+{
+       return delete_node(
+               make_first_field("highmem", 0),
+               make_field("region", region_index),
+               make_field("base", 0),
+               0);
+}
+
+static int ps3_repository_delete_highmem_size(unsigned int region_index)
+{
+       return delete_node(
+               make_first_field("highmem", 0),
+               make_field("region", region_index),
+               make_field("size", 0),
+               0);
+}
+
+int ps3_repository_delete_highmem_info(unsigned int region_index)
+{
+       int result;
+
+       result = ps3_repository_delete_highmem_base(region_index);
+       result += ps3_repository_delete_highmem_size(region_index);
+
+       return result ? -1 : 0;
+}
+
+#endif /* defined(CONFIG_PS3_WRITE_REPOSITORY) */
+
 #if defined(DEBUG)
 
 int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)
index a75e37dc41aa7d94dc762c9f9c7afb23acab1841..ecd394cf34e604b24b71138d481f570cd0d926ac 100644 (file)
@@ -489,7 +489,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
         * a stack trace will help the device-driver authors figure
         * out what happened.  So print that out.
         */
-       dump_stack();
+       WARN(1, "EEH: failure detected\n");
        return 1;
 
 dn_unlock:
index 342797fc0f9c5f6e276993b6cf704380c1b3e464..13e8cc43adf7589d778b0ba05df274450728658c 100644 (file)
@@ -22,12 +22,12 @@ static inline long poll_pending(void)
 
 static inline u8 get_cede_latency_hint(void)
 {
-       return get_lppaca()->gpr5_dword.fields.cede_latency_hint;
+       return get_lppaca()->cede_latency_hint;
 }
 
 static inline void set_cede_latency_hint(u8 latency_hint)
 {
-       get_lppaca()->gpr5_dword.fields.cede_latency_hint = latency_hint;
+       get_lppaca()->cede_latency_hint = latency_hint;
 }
 
 static inline long cede_processor(void)
index 168651acdd83e003dae22f9bdee6147e89c1b1f5..7b3bf76ef8344f0d36c5d99fa221a175aec36bba 100644 (file)
@@ -103,11 +103,13 @@ int pSeries_reconfig_notifier_register(struct notifier_block *nb)
 {
        return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb);
 }
+EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_register);
 
 void pSeries_reconfig_notifier_unregister(struct notifier_block *nb)
 {
        blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb);
 }
+EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_unregister);
 
 int pSeries_reconfig_notify(unsigned long action, void *p)
 {
@@ -426,6 +428,7 @@ static int do_remove_property(char *buf, size_t bufsize)
 static int do_update_property(char *buf, size_t bufsize)
 {
        struct device_node *np;
+       struct pSeries_reconfig_prop_update upd_value;
        unsigned char *value;
        char *name, *end, *next_prop;
        int rc, length;
@@ -454,6 +457,10 @@ static int do_update_property(char *buf, size_t bufsize)
                return -ENODEV;
        }
 
+       upd_value.node = np;
+       upd_value.property = newprop;
+       pSeries_reconfig_notify(PSERIES_UPDATE_PROPERTY, &upd_value);
+
        rc = prom_update_property(np, newprop, oldprop);
        if (rc)
                return rc;
index 1c2d7af17bbe2f3501ff95060e119ced1ed565e8..82c6702dcbab7a756a7ed53de6c7638348f15c97 100644 (file)
 #include <linux/of_platform.h>
 #include <linux/interrupt.h>
 #include <linux/export.h>
+#include <linux/kernel.h>
 #include <asm/prom.h>
 #include <asm/hw_irq.h>
 #include <asm/ppc-pci.h>
-#include <boot/dcr.h>
+#include <asm/dcr.h>
 #include <asm/dcr-regs.h>
 #include <asm/msi_bitmap.h>
 
 #define PEIH_FLUSH0    0x30
 #define PEIH_FLUSH1    0x38
 #define PEIH_CNTRST    0x48
-#define NR_MSI_IRQS    4
+
+static int msi_irqs;
 
 struct ppc4xx_msi {
        u32 msi_addr_lo;
        u32 msi_addr_hi;
        void __iomem *msi_regs;
-       int msi_virqs[NR_MSI_IRQS];
+       int *msi_virqs;
        struct msi_bitmap bitmap;
        struct device_node *msi_dev;
 };
@@ -61,7 +63,7 @@ static int ppc4xx_msi_init_allocator(struct platform_device *dev,
 {
        int err;
 
-       err = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
+       err = msi_bitmap_alloc(&msi_data->bitmap, msi_irqs,
                              dev->dev.of_node);
        if (err)
                return err;
@@ -83,6 +85,11 @@ static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
        struct msi_desc *entry;
        struct ppc4xx_msi *msi_data = &ppc4xx_msi;
 
+       msi_data->msi_virqs = kmalloc((msi_irqs) * sizeof(int),
+                                           GFP_KERNEL);
+       if (!msi_data->msi_virqs)
+               return -ENOMEM;
+
        list_for_each_entry(entry, &dev->msi_list, list) {
                int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
                if (int_no >= 0)
@@ -150,12 +157,11 @@ static int ppc4xx_setup_pcieh_hw(struct platform_device *dev,
        if (!sdr_addr)
                return -1;
 
-       SDR0_WRITE(sdr_addr, (u64)res.start >> 32);      /*HIGH addr */
-       SDR0_WRITE(sdr_addr + 1, res.start & 0xFFFFFFFF); /* Low addr */
-
+       mtdcri(SDR0, *sdr_addr, upper_32_bits(res.start));      /*HIGH addr */
+       mtdcri(SDR0, *sdr_addr + 1, lower_32_bits(res.start));  /* Low addr */
 
        msi->msi_dev = of_find_node_by_name(NULL, "ppc4xx-msi");
-       if (msi->msi_dev)
+       if (!msi->msi_dev)
                return -ENODEV;
 
        msi->msi_regs = of_iomap(msi->msi_dev, 0);
@@ -167,9 +173,12 @@ static int ppc4xx_setup_pcieh_hw(struct platform_device *dev,
                (u32) (msi->msi_regs + PEIH_TERMADH), (u32) (msi->msi_regs));
 
        msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys, GFP_KERNEL);
-       msi->msi_addr_hi = 0x0;
-       msi->msi_addr_lo = (u32) msi_phys;
-       dev_dbg(&dev->dev, "PCIE-MSI: msi address 0x%x\n", msi->msi_addr_lo);
+       if (!msi_virt)
+               return -ENOMEM;
+       msi->msi_addr_hi = upper_32_bits(msi_phys);
+       msi->msi_addr_lo = lower_32_bits(msi_phys & 0xffffffff);
+       dev_dbg(&dev->dev, "PCIE-MSI: msi address high 0x%x, low 0x%x\n",
+               msi->msi_addr_hi, msi->msi_addr_lo);
 
        /* Progam the Interrupt handler Termination addr registers */
        out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
@@ -185,6 +194,8 @@ static int ppc4xx_setup_pcieh_hw(struct platform_device *dev,
        out_be32(msi->msi_regs + PEIH_MSIED, *msi_data);
        out_be32(msi->msi_regs + PEIH_MSIMK, *msi_mask);
 
+       dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys);
+
        return 0;
 }
 
@@ -194,7 +205,7 @@ static int ppc4xx_of_msi_remove(struct platform_device *dev)
        int i;
        int virq;
 
-       for (i = 0; i < NR_MSI_IRQS; i++) {
+       for (i = 0; i < msi_irqs; i++) {
                virq = msi->msi_virqs[i];
                if (virq != NO_IRQ)
                        irq_dispose_mapping(virq);
@@ -215,8 +226,6 @@ static int __devinit ppc4xx_msi_probe(struct platform_device *dev)
        struct resource res;
        int err = 0;
 
-       msi = &ppc4xx_msi;/*keep the msi data for further use*/
-
        dev_dbg(&dev->dev, "PCIE-MSI: Setting up MSI support...\n");
 
        msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
@@ -234,6 +243,10 @@ static int __devinit ppc4xx_msi_probe(struct platform_device *dev)
                goto error_out;
        }
 
+       msi_irqs = of_irq_count(dev->dev.of_node);
+       if (!msi_irqs)
+               return -ENODEV;
+
        if (ppc4xx_setup_pcieh_hw(dev, res, msi))
                goto error_out;
 
@@ -242,6 +255,7 @@ static int __devinit ppc4xx_msi_probe(struct platform_device *dev)
                dev_err(&dev->dev, "Error allocating MSI bitmap\n");
                goto error_out;
        }
+       ppc4xx_msi = *msi;
 
        ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
        ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
index d499b30ea487107b339c252dff39bf3ae5c9dfe9..6cbf31311673a37bc83de2be5add15bbc42ece5e 100644 (file)
@@ -141,9 +141,6 @@ struct seq_file;
 extern void release_thread(struct task_struct *);
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 /*
  * Return saved PC of a blocked thread.
  */
index 7e22f216d771ac93749ff5c1e876bd93c275eaf7..ab3aceb542094e7a80eda7158c96665ace799214 100644 (file)
@@ -26,7 +26,6 @@ extern unsigned long get_wchan(struct task_struct *p);
 
 #define cpu_relax()            barrier()
 #define release_thread(thread) do {} while (0)
-#define prepare_to_copy(tsk)   do {} while (0)
 
 /*
  * User space process size: 2GB. This is hardcoded into a few places,
index 04a8cb4700af142d8798c7bc9812198707fe630e..3e723aaa5e18adfa9588f5b7f642ff973f10dc69 100644 (file)
@@ -155,7 +155,8 @@ config ARCH_HAS_DEFAULT_IDLE
 
 config NO_IOPORT
        def_bool !PCI
-       depends on !SH_CAYMAN && !SH_SH4202_MICRODEV && !SH_SHMIN
+       depends on !SH_CAYMAN && !SH_SH4202_MICRODEV && !SH_SHMIN && \
+                  !SH_HP6XX && !SH_SOLUTION_ENGINE
 
 config IO_TRAPPED
        bool
@@ -286,6 +287,20 @@ config CPU_SUBTYPE_SH7263
        select SYS_SUPPORTS_CMT
        select SYS_SUPPORTS_MTU2
 
+config CPU_SUBTYPE_SH7264
+       bool "Support SH7264 processor"
+       select CPU_SH2A
+       select CPU_HAS_FPU
+       select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_MTU2
+
+config CPU_SUBTYPE_SH7269
+       bool "Support SH7269 processor"
+       select CPU_SH2A
+       select CPU_HAS_FPU
+       select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_MTU2
+
 config CPU_SUBTYPE_MXG
        bool "Support MX-G processor"
        select CPU_SH2A
@@ -425,6 +440,16 @@ config CPU_SUBTYPE_SH7724
        help
          Select SH7724 if you have an SH-MobileR2R CPU.
 
+config CPU_SUBTYPE_SH7734
+       bool "Support SH7734 processor"
+       select CPU_SH4A
+       select CPU_SHX2
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+       select USB_ARCH_HAS_OHCI
+       select USB_ARCH_HAS_EHCI
+       help
+         Select SH7734 if you have a SH4A SH7734 CPU.
+
 config CPU_SUBTYPE_SH7757
        bool "Support SH7757 processor"
        select CPU_SH4A
@@ -582,7 +607,9 @@ config SH_CLK_CPG
 config SH_CLK_CPG_LEGACY
        depends on SH_CLK_CPG
        def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE && \
-                     !CPU_SHX3 && !CPU_SUBTYPE_SH7757
+                     !CPU_SHX3 && !CPU_SUBTYPE_SH7757 && \
+                     !CPU_SUBTYPE_SH7734 && !CPU_SUBTYPE_SH7264 && \
+                     !CPU_SUBTYPE_SH7269
 
 source "kernel/time/Kconfig"
 
@@ -683,6 +710,20 @@ config SECCOMP
 
          If unsure, say N.
 
+config CC_STACKPROTECTOR
+       bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
+       depends on SUPERH32 && EXPERIMENTAL
+       help
+         This option turns on the -fstack-protector GCC feature. This
+         feature puts, at the beginning of functions, a canary value on
+         the stack just before the return address, and validates
+         the value just before actually returning.  Stack based buffer
+         overflows (that need to overwrite this return address) now also
+         overwrite the canary, which gets detected and the attack is then
+         neutralized via a kernel panic.
+
+         This feature requires gcc version 4.2 or above.
+
 config SMP
        bool "Symmetric multi-processing support"
        depends on SYS_SUPPORTS_SMP
index e14a676a0c7d51bb3c5656f0d7a3867bc6b5e544..46edf070da1c377574d8ce17e52a74416f9c896d 100644 (file)
@@ -199,6 +199,10 @@ ifeq ($(CONFIG_DWARF_UNWINDER),y)
   KBUILD_CFLAGS += -fasynchronous-unwind-tables
 endif
 
+ifeq ($(CONFIG_CC_STACKPROTECTOR),y)
+  KBUILD_CFLAGS += -fstack-protector
+endif
+
 libs-$(CONFIG_SUPERH32)                := arch/sh/lib/ $(libs-y)
 libs-$(CONFIG_SUPERH64)                := arch/sh/lib64/ $(libs-y)
 
index d893411022d53868a6d40baded1b55b8314d4081..1f56b35d32481b04de59a7415b0f0abe73b58db0 100644 (file)
@@ -54,6 +54,7 @@ config SH_7724_SOLUTION_ENGINE
        select SOLUTION_ENGINE
        depends on CPU_SUBTYPE_SH7724
        select ARCH_REQUIRE_GPIOLIB
+       select SND_SOC_AK4642 if SND_SIMPLE_CARD
        help
          Select 7724 SolutionEngine if configuring for a Hitachi SH7724
          evaluation board.
@@ -133,7 +134,8 @@ config SH_RTS7751R2D
 
 config SH_RSK
        bool "Renesas Starter Kit"
-       depends on CPU_SUBTYPE_SH7201 || CPU_SUBTYPE_SH7203
+       depends on CPU_SUBTYPE_SH7201 || CPU_SUBTYPE_SH7203 || \
+         CPU_SUBTYPE_SH7264 || CPU_SUBTYPE_SH7269
        help
         Select this option if configuring for any of the RSK+ MCU
         evaluation platforms.
@@ -223,6 +225,7 @@ config SH_ECOVEC
        bool "EcoVec"
        depends on CPU_SUBTYPE_SH7724
        select ARCH_REQUIRE_GPIOLIB
+       select SND_SOC_DA7210 if SND_SIMPLE_CARD
        help
          Renesas "R0P7724LC0011/21RL (EcoVec)" support.
 
@@ -338,8 +341,6 @@ config SH_APSH4AD0A
        help
          Select AP-SH4AD-0A if configuring for an ALPHAPROJECT AP-SH4AD-0A.
 
-endmenu
-
 source "arch/sh/boards/mach-r2d/Kconfig"
 source "arch/sh/boards/mach-highlander/Kconfig"
 source "arch/sh/boards/mach-sdk7780/Kconfig"
@@ -359,3 +360,5 @@ config SH_MAGIC_PANEL_R2_VERSION
 endmenu
 
 endif
+
+endmenu
index 541d8a28103538e2fa82706f9352a0875769e47c..5e24c17bbdada596e810726b6b8066864b7773f9 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/smc91x.h>
+#include <linux/sh_intc.h>
 #include <asm/machvec.h>
 #include <asm/sizes.h>
 
@@ -20,7 +21,7 @@
 #define SMC_IO_OFFSET  0x300
 #define SMC_IOADDR     (SMC_IOBASE + SMC_IO_OFFSET)
 
-#define ETHERNET_IRQ   0x09
+#define ETHERNET_IRQ   evt2irq(0x320)
 
 static void __init sh_edosk7705_init_irq(void)
 {
@@ -73,6 +74,5 @@ device_initcall(init_edosk7705_devices);
  */
 static struct sh_machine_vector mv_edosk7705 __initmv = {
        .mv_name                = "EDOSK7705",
-       .mv_nr_irqs             = 80,
        .mv_init_irq            = sh_edosk7705_init_irq,
 };
index e9656a2cc4cc0396fa6dd9689620514a3a454472..bab5b95139048a10d1e845b521ca74a4b84952a3 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/platform_device.h>
 #include <linux/smc91x.h>
 #include <linux/interrupt.h>
+#include <linux/sh_intc.h>
 #include <linux/i2c.h>
 #include <linux/mtd/physmap.h>
 #include <asm/machvec.h>
@@ -40,8 +41,6 @@
 #define SMC_IO_OFFSET  0x300
 #define SMC_IOADDR     (SMC_IOBASE + SMC_IO_OFFSET)
 
-#define ETHERNET_IRQ   5
-
 /* NOR flash */
 static struct mtd_partition edosk7760_nor_flash_partitions[] = {
        {
@@ -99,8 +98,8 @@ static struct resource sh7760_i2c1_res[] = {
                .end    = SH7760_I2C1_MMIOEND,
                .flags  = IORESOURCE_MEM,
        },{
-               .start  = SH7760_I2C1_IRQ,
-               .end    = SH7760_I2C1_IRQ,
+               .start  = evt2irq(0x9e0),
+               .end    = evt2irq(0x9e0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -122,8 +121,8 @@ static struct resource sh7760_i2c0_res[] = {
                .end    = SH7760_I2C0_MMIOEND,
                .flags  = IORESOURCE_MEM,
        }, {
-               .start  = SH7760_I2C0_IRQ,
-               .end    = SH7760_I2C0_IRQ,
+               .start  = evt2irq(0x9c0),
+               .end    = evt2irq(0x9c0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -150,8 +149,8 @@ static struct resource smc91x_res[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = ETHERNET_IRQ,
-               .end    = ETHERNET_IRQ,
+               .start  = evt2irq(0x2a0),
+               .end    = evt2irq(0x2a0),
                .flags  = IORESOURCE_IRQ ,
        }
 };
@@ -189,5 +188,4 @@ device_initcall(init_edosk7760_devices);
  */
 struct sh_machine_vector mv_edosk7760 __initmv = {
        .mv_name        = "EDOSK7760",
-       .mv_nr_irqs     = 128,
 };
index b3ae9d38cbc0fa277f1d82177489f946627ce30e..6cba0a7068bcf9f713a1ca79a233211a928c771a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/io.h>
 #include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
 #include <asm/machvec.h>
 #include <asm/sizes.h>
 
@@ -71,7 +72,7 @@ static struct resource sh_eth_resources[] = {
                .flags  = IORESOURCE_MEM,
        }, {
 
-               .start  = 57,   /* irq number */
+               .start  = evt2irq(0x920),   /* irq number */
                .flags  = IORESOURCE_IRQ,
        },
 };
index b2ca1d9948fbe0e614477bf091356a2527604f13..90568f9de3a42090b4a3e6e060e88d3b1f0f8d80 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/map.h>
+#include <linux/sh_intc.h>
 #include <mach/magicpanelr2.h>
 #include <asm/heartbeat.h>
 #include <cpu/sh7720.h>
@@ -245,8 +246,8 @@ static struct resource smsc911x_resources[] = {
                .flags          = IORESOURCE_MEM,
        },
        [1] = {
-               .start          = 35,
-               .end            = 35,
+               .start          = evt2irq(0x660),
+               .end            = evt2irq(0x660),
                .flags          = IORESOURCE_IRQ,
        },
 };
@@ -358,17 +359,17 @@ static void __init init_mpr2_IRQ(void)
 {
        plat_irq_setup_pins(IRQ_MODE_IRQ); /* install handlers for IRQ0-5 */
 
-       irq_set_irq_type(32, IRQ_TYPE_LEVEL_LOW);    /* IRQ0 CAN1 */
-       irq_set_irq_type(33, IRQ_TYPE_LEVEL_LOW);    /* IRQ1 CAN2 */
-       irq_set_irq_type(34, IRQ_TYPE_LEVEL_LOW);    /* IRQ2 CAN3 */
-       irq_set_irq_type(35, IRQ_TYPE_LEVEL_LOW);    /* IRQ3 SMSC9115 */
-       irq_set_irq_type(36, IRQ_TYPE_EDGE_RISING);  /* IRQ4 touchscreen */
-       irq_set_irq_type(37, IRQ_TYPE_EDGE_FALLING); /* IRQ5 touchscreen */
-
-       intc_set_priority(32, 13);              /* IRQ0 CAN1 */
-       intc_set_priority(33, 13);              /* IRQ0 CAN2 */
-       intc_set_priority(34, 13);              /* IRQ0 CAN3 */
-       intc_set_priority(35, 6);               /* IRQ3 SMSC9115 */
+       irq_set_irq_type(evt2irq(0x600), IRQ_TYPE_LEVEL_LOW);    /* IRQ0 CAN1 */
+       irq_set_irq_type(evt2irq(0x620), IRQ_TYPE_LEVEL_LOW);    /* IRQ1 CAN2 */
+       irq_set_irq_type(evt2irq(0x640), IRQ_TYPE_LEVEL_LOW);    /* IRQ2 CAN3 */
+       irq_set_irq_type(evt2irq(0x660), IRQ_TYPE_LEVEL_LOW);    /* IRQ3 SMSC9115 */
+       irq_set_irq_type(evt2irq(0x680), IRQ_TYPE_EDGE_RISING);  /* IRQ4 touchscreen */
+       irq_set_irq_type(evt2irq(0x6a0), IRQ_TYPE_EDGE_FALLING); /* IRQ5 touchscreen */
+
+       intc_set_priority(evt2irq(0x600), 13);          /* IRQ0 CAN1 */
+       intc_set_priority(evt2irq(0x620), 13);          /* IRQ0 CAN2 */
+       intc_set_priority(evt2irq(0x640), 13);          /* IRQ0 CAN3 */
+       intc_set_priority(evt2irq(0x660), 6);           /* IRQ3 SMSC9115 */
 }
 
 /*
index 594866356c247cbc6ecb2aa10943443f09ca2030..37d03c097ae9eb2683ab8f9d54fd519f586da602 100644 (file)
@@ -141,6 +141,5 @@ static void __init init_polaris_irq(void)
 
 static struct sh_machine_vector mv_polaris __initmv = {
        .mv_name                = "Polaris",
-       .mv_nr_irqs             = 61,
        .mv_init_irq            = init_polaris_irq,
 };
index 03820c3c93d4c32da3b9944c67394dc84b4606d0..98b36205aa7bf2723c871515c97801f1d18079b3 100644 (file)
@@ -71,6 +71,5 @@ static void __init init_snapgear_IRQ(void)
  */
 static struct sh_machine_vector mv_snapgear __initmv = {
        .mv_name                = "SnapGear SecureEdge5410",
-       .mv_nr_irqs             = 72,
        .mv_init_irq            = init_snapgear_IRQ,
 };
index 24b1ee410daaccd74eff9ee601ef8c87a077d0d7..5087f8bb4cffd64aed276f0d2d3f10c34c324498 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mmc/sh_mmcif.h>
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
 #include <linux/usb/renesas_usbhs.h>
 #include <cpu/sh7757.h>
 #include <asm/heartbeat.h>
@@ -65,8 +66,8 @@ static struct resource sh_eth0_resources[] = {
                .end    = 0xfef001ff,
                .flags  = IORESOURCE_MEM,
        }, {
-               .start  = 84,
-               .end    = 84,
+               .start  = evt2irq(0xc80),
+               .end    = evt2irq(0xc80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -94,8 +95,8 @@ static struct resource sh_eth1_resources[] = {
                .end    = 0xfef009ff,
                .flags  = IORESOURCE_MEM,
        }, {
-               .start  = 84,
-               .end    = 84,
+               .start  = evt2irq(0xc80),
+               .end    = evt2irq(0xc80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -139,8 +140,8 @@ static struct resource sh_eth_giga0_resources[] = {
                .end    = 0xfee01fff,
                .flags  = IORESOURCE_MEM,
        }, {
-               .start  = 315,
-               .end    = 315,
+               .start  = evt2irq(0x2960),
+               .end    = evt2irq(0x2960),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -174,8 +175,8 @@ static struct resource sh_eth_giga1_resources[] = {
                .end    = 0xfee01fff,
                .flags  = IORESOURCE_MEM,
        }, {
-               .start  = 316,
-               .end    = 316,
+               .start  = evt2irq(0x2980),
+               .end    = evt2irq(0x2980),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -206,11 +207,11 @@ static struct resource sh_mmcif_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 211,
+               .start  = evt2irq(0x1c60),
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
-               .start  = 212,
+               .start  = evt2irq(0x1c80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -248,7 +249,7 @@ static struct resource sdhi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -284,8 +285,8 @@ static struct resource usb0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 50,
-               .end    = 50,
+               .start  = evt2irq(0x840),
+               .end    = evt2irq(0x840),
                .flags  = IORESOURCE_IRQ,
        },
 };
index d0d6221d7c2eaef908b4804848c442923c970b21..2c4771ee84cd3e71f90733ea5c1833ddaa338f72 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/i2c-pca-platform.h>
 #include <linux/i2c-algo-pca.h>
 #include <linux/usb/r8a66597.h>
+#include <linux/sh_intc.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/clk.h>
@@ -105,8 +106,8 @@ static struct resource r8a66597_usb_host_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 2,
-               .end    = 2,
+               .start  = evt2irq(0x240),
+               .end    = evt2irq(0x240),
                .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
@@ -135,7 +136,7 @@ static struct resource sm501_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [2]     = {
-               .start  = 10,
+               .start  = evt2irq(0x340),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -223,8 +224,8 @@ static struct resource i2c_proto_resources[] = {
                .flags  = IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
        },
        [1] = {
-               .start  = 12,
-               .end    = 12,
+               .start  = evt2irq(0x380),
+               .end    = evt2irq(0x380),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -236,8 +237,8 @@ static struct resource i2c_resources[] = {
                .flags  = IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
        },
        [1] = {
-               .start  = 12,
-               .end    = 12,
+               .start  = evt2irq(0x380),
+               .end    = evt2irq(0x380),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 24e3316c5c179067839ca956da29f685b87246c2..b52abcc5259a41ea5c3ab15a426dcf75be3b36ed 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/clk.h>
+#include <linux/sh_intc.h>
 #include <mach/urquell.h>
 #include <cpu/sh7786.h>
 #include <asm/heartbeat.h>
@@ -78,7 +79,7 @@ static struct resource smc91x_eth_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 11,
+               .start  = evt2irq(0x360),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 8cf02e343333f158dac6a34b800fc9582437f43c..f33ebf447073d7800ed420e6456f28ebee043722 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/smsc911x.h>
 #include <linux/gpio.h>
 #include <linux/videodev2.h>
+#include <linux/sh_intc.h>
 #include <media/ov772x.h>
 #include <media/soc_camera.h>
 #include <media/soc_camera_platform.h>
@@ -47,8 +48,8 @@ static struct resource smsc9118_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 35,
-               .end    = 35,
+               .start  = evt2irq(0x660),
+               .end    = evt2irq(0x660),
                .flags  = IORESOURCE_IRQ,
        }
 };
@@ -166,7 +167,7 @@ static int ap320_wvga_set_brightness(int brightness)
                __raw_writew(0, FPGA_BKLREG);
                gpio_set_value(GPIO_PTS3, 1);
        }
-       
+
        return 0;
 }
 
@@ -236,7 +237,7 @@ static struct resource lcdc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 28,
+               .start  = evt2irq(0x580),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -404,7 +405,7 @@ static struct resource ceu_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 52,
+               .start  = evt2irq(0x880),
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
@@ -430,7 +431,7 @@ static struct resource sdhi0_cn3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 100,
+               .start  = evt2irq(0xe80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -457,7 +458,7 @@ static struct resource sdhi1_cn7_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 23,
+               .start  = evt2irq(0x4e0),
                .flags  = IORESOURCE_IRQ,
        },
 };
index e89e8e122a26850ab4ec4f31c0398b4d4973406e..340fd40b381dc348b2bf8e86e48a2f8ee52efdaa 100644 (file)
@@ -181,7 +181,6 @@ extern void init_cayman_irq(void);
 
 static struct sh_machine_vector mv_cayman __initmv = {
        .mv_name                = "Hitachi Cayman",
-       .mv_nr_irqs             = 64,
        .mv_ioport_map          = cayman_ioport_map,
        .mv_init_irq            = init_cayman_irq,
 };
index d12fe9ddf3da1a914562b104669273e9b99c28c3..4158d70c0dea3675e44582be719b57076876bb04 100644 (file)
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
 #include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
 #include <linux/videodev2.h>
 #include <video/sh_mobile_lcdc.h>
 #include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
 #include <media/sh_mobile_ceu.h>
 #include <media/soc_camera.h>
 #include <media/tw9910.h>
@@ -137,7 +139,7 @@ static struct resource sh_eth_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        [1] = {
-               .start = 91,
+               .start = evt2irq(0xd60),
                .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
        },
 };
@@ -178,8 +180,8 @@ static struct resource usb0_host_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 65,
-               .end    = 65,
+               .start  = evt2irq(0xa20),
+               .end    = evt2irq(0xa20),
                .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
@@ -214,8 +216,8 @@ static struct resource usb1_common_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 66,
-               .end    = 66,
+               .start  = evt2irq(0xa40),
+               .end    = evt2irq(0xa40),
                .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
@@ -261,8 +263,8 @@ static struct resource usbhs_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 66,
-               .end    = 66,
+               .start  = evt2irq(0xa40),
+               .end    = evt2irq(0xa40),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -348,7 +350,7 @@ static struct resource lcdc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 106,
+               .start  = evt2irq(0xf40),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -375,7 +377,7 @@ static struct resource ceu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 52,
+               .start  = evt2irq(0x880),
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
@@ -406,7 +408,7 @@ static struct resource ceu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 63,
+               .start  = evt2irq(0x9e0),
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
@@ -437,7 +439,7 @@ static struct i2c_board_info i2c1_devices[] = {
        },
        {
                I2C_BOARD_INFO("lis3lv02d", 0x1c),
-               .irq = 33,
+               .irq = evt2irq(0x620),
        }
 };
 
@@ -463,7 +465,7 @@ static struct resource keysc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 79,
+               .start  = evt2irq(0xbe0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -479,7 +481,8 @@ static struct platform_device keysc_device = {
 };
 
 /* TouchScreen */
-#define IRQ0 32
+#define IRQ0 evt2irq(0x600)
+
 static int ts_get_pendown_state(void)
 {
        int val = 0;
@@ -544,7 +547,7 @@ static struct resource sdhi0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 100,
+               .start  = evt2irq(0xe80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -588,7 +591,7 @@ static struct resource sdhi1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 23,
+               .start  = evt2irq(0x4e0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -653,7 +656,7 @@ static struct resource msiof0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 84,
+               .start  = evt2irq(0xc80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -794,7 +797,7 @@ static struct resource fsi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 108,
+               .start  = evt2irq(0xf80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -809,6 +812,30 @@ static struct platform_device fsi_device = {
        },
 };
 
+static struct asoc_simple_dai_init_info fsi_da7210_init_info = {
+       .fmt            = SND_SOC_DAIFMT_I2S,
+       .codec_daifmt   = SND_SOC_DAIFMT_CBM_CFM,
+       .cpu_daifmt     = SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct asoc_simple_card_info fsi_da7210_info = {
+       .name           = "DA7210",
+       .card           = "FSIB-DA7210",
+       .cpu_dai        = "fsib-dai",
+       .codec          = "da7210.0-001a",
+       .platform       = "sh_fsi.0",
+       .codec_dai      = "da7210-hifi",
+       .init           = &fsi_da7210_init_info,
+};
+
+static struct platform_device fsi_da7210_device = {
+       .name   = "asoc-simple-card",
+       .dev    = {
+               .platform_data  = &fsi_da7210_info,
+       },
+};
+
+
 /* IrDA */
 static struct resource irda_resources[] = {
        [0] = {
@@ -818,7 +845,7 @@ static struct resource irda_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -855,7 +882,7 @@ static struct resource sh_vou_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 55,
+               .start  = evt2irq(0x8e0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -891,12 +918,12 @@ static struct resource sh_mmcif_resources[] = {
        },
        [1] = {
                /* MMC2I */
-               .start  = 29,
+               .start  = evt2irq(0x5a0),
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
                /* MMC3I */
-               .start  = 30,
+               .start  = evt2irq(0x5c0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -945,6 +972,7 @@ static struct platform_device *ecovec_devices[] __initdata = {
        &camera_devices[1],
        &camera_devices[2],
        &fsi_device,
+       &fsi_da7210_device,
        &irda_device,
        &vou_device,
 #if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
index 8c9add5f4cfae08facb9bba4e525dd7713083b5c..05797b33f68ef5e4b6d6c0cd50ff3fd1c67c0f08 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
+#include <linux/sh_intc.h>
 #include <sound/sh_dac_audio.h>
 #include <asm/hd64461.h>
 #include <asm/io.h>
@@ -35,7 +36,7 @@ static struct resource cf_ide_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        [2] = {
-               .start = 77,
+               .start = evt2irq(0xba0),
                .flags = IORESOURCE_IRQ,
        },
 };
@@ -168,8 +169,6 @@ device_initcall(hp6xx_devices_setup);
 static struct sh_machine_vector mv_hp6xx __initmv = {
        .mv_name = "hp6xx",
        .mv_setup = hp6xx_setup,
-       /* IRQ's : CPU(64) + CCHIP(16) + FREE_TO_USE(6) */
-       .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM + 6,
        /* Enable IRQ0 -> IRQ3 in IRQ_MODE */
        .mv_init_irq = hp6xx_init_irq,
 };
index d04a55d3b877a4f7b1d9348486ca52662c91eef4..158c9176e42adc79fadeb78300ec14051a2a3801 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/i2c.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/videodev2.h>
+#include <linux/sh_intc.h>
 #include <media/rj54n1cb0c.h>
 #include <media/soc_camera.h>
 #include <media/sh_mobile_ceu.h>
@@ -110,7 +111,7 @@ static struct resource kfr2r09_sh_keysc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 79,
+               .start  = evt2irq(0xbe0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -175,7 +176,7 @@ static struct resource kfr2r09_sh_lcdc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 106,
+               .start  = evt2irq(0xf40),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -200,8 +201,8 @@ static struct resource kfr2r09_usb0_gadget_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 65,
-               .end    = 65,
+               .start  = evtirq(0xa20),
+               .end    = evtirq(0xa20),
                .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
@@ -230,8 +231,8 @@ static struct resource kfr2r09_ceu_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 52,
-               .end  = 52,
+               .start  = evt2irq(0x880),
+               .end    = evt2irq(0x880),
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
@@ -348,7 +349,7 @@ static struct resource kfr2r09_sh_sdhi0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 100,
+               .start  = evt2irq(0xe80),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 79b4e0d77b716e6141b8f05076aa7713c8602e86..6660622aa457103f1fb2b3306e1be37f5653b7a0 100644 (file)
@@ -79,6 +79,5 @@ device_initcall(lboxre2_devices_setup);
  */
 static struct sh_machine_vector mv_lboxre2 __initmv = {
        .mv_name                = "L-BOX RE2",
-       .mv_nr_irqs             = 72,
        .mv_init_irq            = init_lboxre2_IRQ,
 };
index d8a747291e03ed82a829e20e4e779013881f1197..6c66ee4d842bd467fd50b00aaabc9a4510bf306b 100644 (file)
@@ -194,7 +194,6 @@ device_initcall(microdev_devices_setup);
  */
 static struct sh_machine_vector mv_sh4202_microdev __initmv = {
        .mv_name                = "SH4-202 MicroDev",
-       .mv_nr_irqs             = 72,
        .mv_ioport_map          = microdev_ioport_map,
        .mv_init_irq            = init_microdev_irq,
 };
index ff6f69c6906ec83e3f467b3ea1354f2c13832900..34cd0c5ff2e1bd104e6de9ff407ff478d2bb1aa7 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/videodev2.h>
+#include <linux/sh_intc.h>
 #include <video/sh_mobile_lcdc.h>
 #include <media/sh_mobile_ceu.h>
 #include <media/ov772x.h>
@@ -54,7 +55,7 @@ static struct resource smc91x_eth_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 32, /* IRQ0 */
+               .start  = evt2irq(0x600), /* IRQ0 */
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
        },
 };
@@ -88,7 +89,7 @@ static struct resource sh_keysc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 79,
+               .start  = evt2irq(0xbe0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -285,7 +286,7 @@ static struct resource migor_lcdc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 28,
+               .start  = evt2irq(0x580),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -368,7 +369,7 @@ static struct resource migor_ceu_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 52,
+               .start  = evt2irq(0x880),
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
@@ -394,7 +395,7 @@ static struct resource sdhi_cn9_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 100,
+               .start  = evt2irq(0xe80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -420,7 +421,7 @@ static struct i2c_board_info migor_i2c_devices[] = {
        },
        {
                I2C_BOARD_INFO("migor_ts", 0x51),
-               .irq = 38, /* IRQ6 */
+               .irq = evt2irq(0x6c0), /* IRQ6 */
        },
        {
                I2C_BOARD_INFO("wm8978", 0x1a),
index aeff3b04220590f70a28de6d4ff960326a78b034..458a11ffd022106d3cdd2f8a233f98426702e06d 100644 (file)
@@ -13,6 +13,16 @@ config SH_RSK7203
        select ARCH_REQUIRE_GPIOLIB
        depends on CPU_SUBTYPE_SH7203
 
+config SH_RSK7264
+       bool "RSK2+SH7264"
+       select ARCH_REQUIRE_GPIOLIB
+       depends on CPU_SUBTYPE_SH7264
+
+config SH_RSK7269
+       bool "RSK2+SH7269"
+       select ARCH_REQUIRE_GPIOLIB
+       depends on CPU_SUBTYPE_SH7269
+
 endchoice
 
 endif
index 498da75ce38b747ef35f992336dbe6d2f6ee79e3..6a4e1b538a6201417a6c481de1a6dcb817535054 100644 (file)
@@ -1,2 +1,4 @@
 obj-y                          := setup.o
 obj-$(CONFIG_SH_RSK7203)       += devices-rsk7203.o
+obj-$(CONFIG_SH_RSK7264)       += devices-rsk7264.o
+obj-$(CONFIG_SH_RSK7269)       += devices-rsk7269.o
diff --git a/arch/sh/boards/mach-rsk/devices-rsk7264.c b/arch/sh/boards/mach-rsk/devices-rsk7264.c
new file mode 100644 (file)
index 0000000..7251e37
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * RSK+SH7264 Support.
+ *
+ * Copyright (C) 2012 Renesas Electronics Europe
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/smsc911x.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+
+static struct smsc911x_platform_config smsc911x_config = {
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+       .flags          = SMSC911X_USE_16BIT | SMSC911X_SWAP_FIFO,
+};
+
+static struct resource smsc911x_resources[] = {
+       [0] = {
+               .start          = 0x28000000,
+               .end            = 0x280000ff,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = 65,
+               .end            = 65,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device smsc911x_device = {
+       .name           = "smsc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smsc911x_resources),
+       .resource       = smsc911x_resources,
+       .dev            = {
+               .platform_data = &smsc911x_config,
+       },
+};
+
+static struct platform_device *rsk7264_devices[] __initdata = {
+       &smsc911x_device,
+};
+
+static int __init rsk7264_devices_setup(void)
+{
+       return platform_add_devices(rsk7264_devices,
+                                   ARRAY_SIZE(rsk7264_devices));
+}
+device_initcall(rsk7264_devices_setup);
diff --git a/arch/sh/boards/mach-rsk/devices-rsk7269.c b/arch/sh/boards/mach-rsk/devices-rsk7269.c
new file mode 100644 (file)
index 0000000..4a54459
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * RSK+SH7269 Support
+ *
+ * Copyright (C) 2012  Renesas Electronics Europe Ltd
+ * Copyright (C) 2012  Phil Edworthy
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/smsc911x.h>
+#include <linux/gpio.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+
+static struct smsc911x_platform_config smsc911x_config = {
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
+       .flags          = SMSC911X_USE_16BIT | SMSC911X_SWAP_FIFO,
+};
+
+static struct resource smsc911x_resources[] = {
+       [0] = {
+               .start          = 0x24000000,
+               .end            = 0x240000ff,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = 85,
+               .end            = 85,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device smsc911x_device = {
+       .name           = "smsc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smsc911x_resources),
+       .resource       = smsc911x_resources,
+       .dev            = {
+               .platform_data = &smsc911x_config,
+       },
+};
+
+static struct platform_device *rsk7269_devices[] __initdata = {
+       &smsc911x_device,
+};
+
+static int __init rsk7269_devices_setup(void)
+{
+       return platform_add_devices(rsk7269_devices,
+                                   ARRAY_SIZE(rsk7269_devices));
+}
+device_initcall(rsk7269_devices_setup);
index 4da38db4b5fef3c49cf85528fdae54814db8360b..2241659c32990c2336b95ce9bb4865ae1c502c32 100644 (file)
@@ -94,7 +94,6 @@ static void __init sdk7780_setup(char **cmdline_p)
 static struct sh_machine_vector mv_se7780 __initmv = {
        .mv_name        = "Renesas SDK7780-R3" ,
        .mv_setup               = sdk7780_setup,
-       .mv_nr_irqs             = 111,
        .mv_init_irq    = init_sdk7780_IRQ,
 };
 
index 8ab8330e3fd12f2551a6166e743c78b4ae3f3bfb..68883ec9568263cf813cb2dba49616dd55b78b61 100644 (file)
@@ -90,7 +90,6 @@ static int se7206_mode_pins(void)
 
 static struct sh_machine_vector mv_se __initmv = {
        .mv_name                = "SolutionEngine",
-       .mv_nr_irqs             = 256,
        .mv_init_irq            = init_se7206_IRQ,
        .mv_mode_pins           = se7206_mode_pins,
 };
index 31330c65c0cec9aa1b78abb69e5bcb95c9c4cd80..9759d6ba7ffb4d8d967f30d0ee0d72fe00c886fb 100644 (file)
@@ -184,16 +184,5 @@ device_initcall(se_devices_setup);
 static struct sh_machine_vector mv_se __initmv = {
        .mv_name                = "SolutionEngine",
        .mv_setup               = smsc_setup,
-#if defined(CONFIG_CPU_SH4)
-       .mv_nr_irqs             = 48,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
-       .mv_nr_irqs             = 32,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
-       .mv_nr_irqs             = 61,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
-       .mv_nr_irqs             = 86,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-       .mv_nr_irqs             = 104,
-#endif
        .mv_init_irq            = init_se_IRQ,
 };
index 7416ad7ee53a99c605e54d6a2668b82eb9ce0b05..a0b3dba34ebfb74740a57fa37bdc93a858c9ca52 100644 (file)
@@ -92,6 +92,5 @@ static void __init se7721_setup(char **cmdline_p)
 struct sh_machine_vector mv_se7721 __initmv = {
        .mv_name                = "Solution Engine 7721",
        .mv_setup               = se7721_setup,
-       .mv_nr_irqs             = 109,
        .mv_init_irq            = init_se7721_IRQ,
 };
index e1963fecd761ace85df196720c2c68c4f4d7a738..8f7f0550cfded7dcc2751db7e63e933d353bd510 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
 #include <linux/smc91x.h>
+#include <linux/sh_intc.h>
 #include <mach-se/mach/se7722.h>
 #include <mach-se/mach/mrshpc.h>
 #include <asm/machvec.h>
@@ -114,7 +115,7 @@ static struct resource sh_keysc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 79,
+               .start  = evt2irq(0xbe0),
                .flags  = IORESOURCE_IRQ,
        },
 };
index c540b16547c31c4f0608e86a2078c00fdc0d80f7..ffbf5bc7366bce549bb4843606dabd728e624b26 100644 (file)
 #include <linux/input/sh_keysc.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
 #include <linux/videodev2.h>
 #include <video/sh_mobile_lcdc.h>
 #include <media/sh_mobile_ceu.h>
 #include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
 #include <asm/io.h>
 #include <asm/heartbeat.h>
 #include <asm/clock.h>
@@ -197,7 +199,7 @@ static struct resource lcdc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 106,
+               .start  = evt2irq(0xf40),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -224,7 +226,7 @@ static struct resource ceu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 52,
+               .start  = evt2irq(0x880),
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
@@ -255,7 +257,7 @@ static struct resource ceu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 63,
+               .start  = evt2irq(0x9e0),
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
@@ -289,7 +291,7 @@ static struct resource fsi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 108,
+               .start  = evt2irq(0xf80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -304,17 +306,25 @@ static struct platform_device fsi_device = {
        },
 };
 
-static struct fsi_ak4642_info fsi_ak4642_info = {
+static struct asoc_simple_dai_init_info fsi2_ak4642_init_info = {
+       .fmt            = SND_SOC_DAIFMT_LEFT_J,
+       .codec_daifmt   = SND_SOC_DAIFMT_CBM_CFM,
+       .cpu_daifmt     = SND_SOC_DAIFMT_CBS_CFS,
+       .sysclk         = 11289600,
+};
+
+static struct asoc_simple_card_info fsi_ak4642_info = {
        .name           = "AK4642",
        .card           = "FSIA-AK4642",
        .cpu_dai        = "fsia-dai",
        .codec          = "ak4642-codec.0-0012",
        .platform       = "sh_fsi.0",
-       .id             = FSI_PORT_A,
+       .codec_dai      = "ak4642-hifi",
+       .init           = &fsi2_ak4642_init_info,
 };
 
 static struct platform_device fsi_ak4642_device = {
-       .name   = "fsi-ak4642-audio",
+       .name   = "asoc-simple-card",
        .dev    = {
                .platform_data  = &fsi_ak4642_info,
        },
@@ -343,7 +353,7 @@ static struct resource keysc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 79,
+               .start  = evt2irq(0xbe0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -366,7 +376,7 @@ static struct resource sh_eth_resources[] = {
                .flags = IORESOURCE_MEM,
        },
        [1] = {
-               .start = 91,
+               .start = evt2irq(0xd60),
                .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
        },
 };
@@ -397,8 +407,8 @@ static struct resource sh7724_usb0_host_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 65,
-               .end    = 65,
+               .start  = evt2irq(0xa20),
+               .end    = evt2irq(0xa20),
                .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
@@ -426,8 +436,8 @@ static struct resource sh7724_usb1_gadget_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 66,
-               .end    = 66,
+               .start  = evt2irq(0xa40),
+               .end    = evt2irq(0xa40),
                .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
@@ -452,7 +462,7 @@ static struct resource sdhi0_cn7_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 100,
+               .start  = evt2irq(0xe80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -481,7 +491,7 @@ static struct resource sdhi1_cn8_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 23,
+               .start  = evt2irq(0x4e0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -511,7 +521,7 @@ static struct resource irda_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -549,7 +559,7 @@ static struct resource sh_vou_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 55,
+               .start  = evt2irq(0x8e0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -595,6 +605,7 @@ static struct i2c_board_info i2c0_devices[] = {
 #define EEPROM_DATA 0xBA20600C
 #define EEPROM_STAT 0xBA206010
 #define EEPROM_STRT 0xBA206014
+
 static int __init sh_eth_is_eeprom_ready(void)
 {
        int t = 10000;
@@ -651,7 +662,6 @@ extern char ms7724se_sdram_enter_end;
 extern char ms7724se_sdram_leave_start;
 extern char ms7724se_sdram_leave_end;
 
-
 static int __init arch_setup(void)
 {
        /* enable I2C device */
@@ -928,5 +938,4 @@ device_initcall(devices_setup);
 static struct sh_machine_vector mv_ms7724se __initmv = {
        .mv_name        = "ms7724se",
        .mv_init_irq    = init_se7724_IRQ,
-       .mv_nr_irqs     = SE7724_FPGA_IRQ_BASE + SE7724_FPGA_IRQ_NR,
 };
index 4ed60c5e221f07a03e5a1df5124fcaec7fe29922..820f4e7ba0d2680b1ef1332acf90deb86ad95595 100644 (file)
@@ -55,6 +55,5 @@ device_initcall(se7751_devices_setup);
  */
 static struct sh_machine_vector mv_7751se __initmv = {
        .mv_name                = "7751 SolutionEngine",
-       .mv_nr_irqs             = 72,
        .mv_init_irq            = init_7751se_IRQ,
 };
index 6f7c207138e14ce10b4c009d7c87cd64a34a4a6b..ae5a1d84fdf8e0af6ff01ec897af817fc2ffdbf5 100644 (file)
@@ -110,6 +110,5 @@ static void __init se7780_setup(char **cmdline_p)
 static struct sh_machine_vector mv_se7780 __initmv = {
        .mv_name                = "Solution Engine 7780" ,
        .mv_setup               = se7780_setup ,
-       .mv_nr_irqs             = 111 ,
        .mv_init_irq            = init_se7780_IRQ,
 };
index 82b6d4a5dc024739939000dea42003a102255281..958bcd7aacc5bc2c56d9852d19eac4128fa00472 100644 (file)
@@ -22,6 +22,5 @@ static int se7619_mode_pins(void)
 
 static struct sh_machine_vector mv_se __initmv = {
        .mv_name                = "SolutionEngine",
-       .mv_nr_irqs             = 108,
        .mv_mode_pins           = se7619_mode_pins,
 };
index d4f79b2a6514a6a04dca6c45edccdb855c8054e9..f582dab59343dd2611e7bea07fa8f8ae03478420 100644 (file)
@@ -101,6 +101,5 @@ device_initcall(sh03_devices_setup);
 static struct sh_machine_vector mv_sh03 __initmv = {
        .mv_name                = "Interface (CTP/PCI-SH03)",
        .mv_setup               = sh03_setup,
-       .mv_nr_irqs             = 48,
        .mv_init_irq            = init_sh03_IRQ,
 };
index dd036f1661dbd297133c2c770eaf831ae5866abe..b7c75298dfb500d9cdadef5c316403c1767abef1 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/fb.h>
 #include <linux/io.h>
 #include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
 #include <mach/sh7763rdp.h>
 #include <asm/sh7760fb.h>
 
@@ -67,7 +68,7 @@ static struct platform_device sh7763rdp_nor_flash_device = {
  * SH-Ether
  *
  * SH Ether of SH7763 has multi IRQ handling.
- * (57,58,59 -> 57)
+ * (0x920,0x940,0x960 -> 0x920)
  */
 static struct resource sh_eth_resources[] = {
        {
@@ -79,7 +80,7 @@ static struct resource sh_eth_resources[] = {
                .end    = 0xFEE01FFF,
                .flags  = IORESOURCE_MEM,
        }, {
-               .start  = 57,   /* irq number */
+               .start  = evt2irq(0x920),   /* irq number */
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -213,6 +214,5 @@ static void __init sh7763rdp_setup(char **cmdline_p)
 static struct sh_machine_vector mv_sh7763rdp __initmv = {
        .mv_name = "sh7763drp",
        .mv_setup = sh7763rdp_setup,
-       .mv_nr_irqs = 112,
        .mv_init_irq = init_sh7763rdp_IRQ,
 };
diff --git a/arch/sh/configs/rsk7264_defconfig b/arch/sh/configs/rsk7264_defconfig
new file mode 100644 (file)
index 0000000..1600426
--- /dev/null
@@ -0,0 +1,80 @@
+CONFIG_LOCALVERSION="uClinux RSK2+SH7264"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_COUNTERS=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+CONFIG_MMAP_ALLOW_UNINITIALIZED=y
+CONFIG_PROFILING=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_CPU_SUBTYPE_SH7264=y
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_SH_RSK=y
+# CONFIG_SH_TIMER_MTU2 is not set
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_SMSC911X=y
+CONFIG_SMSC_PHY=y
+CONFIG_INPUT_FF_MEMLESS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=8
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HWMON is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_R8A66597_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_VFAT_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_FTRACE is not set
diff --git a/arch/sh/configs/rsk7269_defconfig b/arch/sh/configs/rsk7269_defconfig
new file mode 100644 (file)
index 0000000..9f062b5
--- /dev/null
@@ -0,0 +1,65 @@
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_CPU_SUBTYPE_SH7269=y
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x02000000
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_SH_RSK=y
+# CONFIG_SH_TIMER_MTU2 is not set
+CONFIG_SH_PCLK_FREQ=66700000
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FW_LOADER is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_SMSC911X=y
+CONFIG_SMSC_PHY=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=8
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HWMON is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_R8A66597_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_VFAT_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_FTRACE is not set
index 4d58eb0973d4f5ea9d048d4e53e949afb02bdfec..cfd5b90a862820c5a55cf69e2f9612ed1ba765b5 100644 (file)
@@ -40,23 +40,6 @@ config NR_ONCHIP_DMA_CHANNELS
          DMAC supports. This will be 4 for SH7750/SH7751/Sh7750S/SH7091 and 8 for the
          SH7750R/SH7751R/SH7760, 12 for the SH7723/SH7780/SH7785/SH7724, default is 6.
 
-config NR_DMA_CHANNELS_BOOL
-       depends on SH_DMA
-       bool "Override default number of maximum DMA channels"
-       help
-         This allows you to forcibly update the maximum number of supported
-         DMA channels for a given board. If this is unset, this will default
-         to the number of channels that the on-chip DMAC has.
-
-config NR_DMA_CHANNELS
-       int "Maximum number of DMA channels"
-       depends on SH_DMA && NR_DMA_CHANNELS_BOOL
-       default NR_ONCHIP_DMA_CHANNELS
-       help
-         This allows you to specify the maximum number of DMA channels to
-         support. Setting this to a higher value allows for cascading DMACs
-         with additional channels.
-
 config SH_DMABRG
        bool "SH7760 DMABRG support"
        depends on CPU_SUBTYPE_SH7760
index a60da6dd4d17780d4c1fb2cf8733ae8be31973c4..4c171f13b0e8792b5f88a564c1fef52e15218c22 100644 (file)
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/io.h>
 #include <mach-dreamcast/mach/dma.h>
 #include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/dma-sh.h>
+#include <asm/dma-register.h>
+#include <cpu/dma-register.h>
+#include <cpu/dma.h>
 
-#if defined(DMAE1_IRQ)
-#define NR_DMAE                2
-#else
-#define NR_DMAE                1
+/*
+ * Define the default configuration for dual address memory-memory transfer.
+ * The 0x400 value represents auto-request, external->external.
+ */
+#define RS_DUAL        (DM_INC | SM_INC | 0x400 | TS_INDEX2VAL(XMIT_SZ_32BIT))
+
+static unsigned long dma_find_base(unsigned int chan)
+{
+       unsigned long base = SH_DMAC_BASE0;
+
+#ifdef SH_DMAC_BASE1
+       if (chan >= 6)
+               base = SH_DMAC_BASE1;
 #endif
 
-static const char *dmae_name[] = {
-       "DMAC Address Error0", "DMAC Address Error1"
-};
+       return base;
+}
+
+static unsigned long dma_base_addr(unsigned int chan)
+{
+       unsigned long base = dma_find_base(chan);
+
+       /* Normalize offset calculation */
+       if (chan >= 9)
+               chan -= 6;
+       if (chan >= 4)
+               base += 0x10;
+
+       return base + (chan * 0x10);
+}
 
+#ifdef CONFIG_SH_DMA_IRQ_MULTI
 static inline unsigned int get_dmte_irq(unsigned int chan)
 {
-       unsigned int irq = 0;
-       if (chan < ARRAY_SIZE(dmte_irq_map))
-               irq = dmte_irq_map[chan];
-
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
-       if (irq > DMTE6_IRQ)
-               return DMTE6_IRQ;
-       return DMTE0_IRQ;
+       return chan >= 6 ? DMTE6_IRQ : DMTE0_IRQ;
+}
 #else
-       return irq;
+
+static unsigned int dmte_irq_map[] = {
+       DMTE0_IRQ, DMTE0_IRQ + 1, DMTE0_IRQ + 2, DMTE0_IRQ + 3,
+
+#ifdef DMTE4_IRQ
+       DMTE4_IRQ, DMTE4_IRQ + 1,
+#endif
+
+#ifdef DMTE6_IRQ
+       DMTE6_IRQ, DMTE6_IRQ + 1,
+#endif
+
+#ifdef DMTE8_IRQ
+       DMTE8_IRQ, DMTE9_IRQ, DMTE10_IRQ, DMTE11_IRQ,
 #endif
+};
+
+static inline unsigned int get_dmte_irq(unsigned int chan)
+{
+       return dmte_irq_map[chan];
 }
+#endif
 
 /*
  * We determine the correct shift size based off of the CHCR transmit size
@@ -53,9 +90,10 @@ static inline unsigned int get_dmte_irq(unsigned int chan)
  * iterations to complete the transfer.
  */
 static unsigned int ts_shift[] = TS_SHIFT;
+
 static inline unsigned int calc_xmit_shift(struct dma_channel *chan)
 {
-       u32 chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR);
+       u32 chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
        int cnt = ((chcr & CHCR_TS_LOW_MASK) >> CHCR_TS_LOW_SHIFT) |
                ((chcr & CHCR_TS_HIGH_MASK) >> CHCR_TS_HIGH_SHIFT);
 
@@ -73,13 +111,13 @@ static irqreturn_t dma_tei(int irq, void *dev_id)
        struct dma_channel *chan = dev_id;
        u32 chcr;
 
-       chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR);
+       chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
 
        if (!(chcr & CHCR_TE))
                return IRQ_NONE;
 
        chcr &= ~(CHCR_IE | CHCR_DE);
-       __raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR));
+       __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
 
        wake_up(&chan->wait_queue);
 
@@ -91,13 +129,8 @@ static int sh_dmac_request_dma(struct dma_channel *chan)
        if (unlikely(!(chan->flags & DMA_TEI_CAPABLE)))
                return 0;
 
-       return request_irq(get_dmte_irq(chan->chan), dma_tei,
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
-                               IRQF_SHARED,
-#else
-                               0,
-#endif
-                               chan->dev_id, chan);
+       return request_irq(get_dmte_irq(chan->chan), dma_tei, IRQF_SHARED,
+                          chan->dev_id, chan);
 }
 
 static void sh_dmac_free_dma(struct dma_channel *chan)
@@ -118,7 +151,7 @@ sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr)
                chan->flags &= ~DMA_TEI_CAPABLE;
        }
 
-       __raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR));
+       __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
 
        chan->flags |= DMA_CONFIGURED;
        return 0;
@@ -129,13 +162,13 @@ static void sh_dmac_enable_dma(struct dma_channel *chan)
        int irq;
        u32 chcr;
 
-       chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR);
+       chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
        chcr |= CHCR_DE;
 
        if (chan->flags & DMA_TEI_CAPABLE)
                chcr |= CHCR_IE;
 
-       __raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR));
+       __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
 
        if (chan->flags & DMA_TEI_CAPABLE) {
                irq = get_dmte_irq(chan->chan);
@@ -153,9 +186,9 @@ static void sh_dmac_disable_dma(struct dma_channel *chan)
                disable_irq(irq);
        }
 
-       chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR);
+       chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
        chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
-       __raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR));
+       __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
 }
 
 static int sh_dmac_xfer_dma(struct dma_channel *chan)
@@ -186,13 +219,13 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan)
         */
        if (chan->sar || (mach_is_dreamcast() &&
                          chan->chan == PVR2_CASCADE_CHAN))
-               __raw_writel(chan->sar, (dma_base_addr[chan->chan]+SAR));
+               __raw_writel(chan->sar, (dma_base_addr(chan->chan) + SAR));
        if (chan->dar || (mach_is_dreamcast() &&
                          chan->chan == PVR2_CASCADE_CHAN))
-               __raw_writel(chan->dar, (dma_base_addr[chan->chan] + DAR));
+               __raw_writel(chan->dar, (dma_base_addr(chan->chan) + DAR));
 
        __raw_writel(chan->count >> calc_xmit_shift(chan),
-               (dma_base_addr[chan->chan] + TCR));
+               (dma_base_addr(chan->chan) + TCR));
 
        sh_dmac_enable_dma(chan);
 
@@ -201,13 +234,32 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan)
 
 static int sh_dmac_get_dma_residue(struct dma_channel *chan)
 {
-       if (!(__raw_readl(dma_base_addr[chan->chan] + CHCR) & CHCR_DE))
+       if (!(__raw_readl(dma_base_addr(chan->chan) + CHCR) & CHCR_DE))
                return 0;
 
-       return __raw_readl(dma_base_addr[chan->chan] + TCR)
+       return __raw_readl(dma_base_addr(chan->chan) + TCR)
                 << calc_xmit_shift(chan);
 }
 
+/*
+ * DMAOR handling
+ */
+#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7724) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7785)
+#define NR_DMAOR       2
+#else
+#define NR_DMAOR       1
+#endif
+
+/*
+ * DMAOR bases are broken out amongst channel groups. DMAOR0 manages
+ * channels 0 - 5, DMAOR1 6 - 11 (optional).
+ */
+#define dmaor_read_reg(n)              __raw_readw(dma_find_base((n)*6))
+#define dmaor_write_reg(n, data)       __raw_writew(data, dma_find_base(n)*6)
+
 static inline int dmaor_reset(int no)
 {
        unsigned long dmaor = dmaor_read_reg(no);
@@ -228,36 +280,86 @@ static inline int dmaor_reset(int no)
        return 0;
 }
 
-#if defined(CONFIG_CPU_SH4)
-static irqreturn_t dma_err(int irq, void *dummy)
-{
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
-       int cnt = 0;
-       switch (irq) {
-#if defined(DMTE6_IRQ) && defined(DMAE1_IRQ)
-       case DMTE6_IRQ:
-               cnt++;
+/*
+ * DMAE handling
+ */
+#ifdef CONFIG_CPU_SH4
+
+#if defined(DMAE1_IRQ)
+#define NR_DMAE                2
+#else
+#define NR_DMAE                1
 #endif
-       case DMTE0_IRQ:
-               if (dmaor_read_reg(cnt) & (DMAOR_NMIF | DMAOR_AE)) {
-                       disable_irq(irq);
-                       /* DMA multi and error IRQ */
-                       return IRQ_HANDLED;
-               }
-       default:
-               return IRQ_NONE;
-       }
+
+static const char *dmae_name[] = {
+       "DMAC Address Error0",
+       "DMAC Address Error1"
+};
+
+#ifdef CONFIG_SH_DMA_IRQ_MULTI
+static inline unsigned int get_dma_error_irq(int n)
+{
+       return get_dmte_irq(n * 6);
+}
 #else
-       dmaor_reset(0);
-#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
-               defined(CONFIG_CPU_SUBTYPE_SH7780)      || \
-               defined(CONFIG_CPU_SUBTYPE_SH7785)
-       dmaor_reset(1);
+
+static unsigned int dmae_irq_map[] = {
+       DMAE0_IRQ,
+
+#ifdef DMAE1_IRQ
+       DMAE1_IRQ,
+#endif
+};
+
+static inline unsigned int get_dma_error_irq(int n)
+{
+       return dmae_irq_map[n];
+}
 #endif
+
+static irqreturn_t dma_err(int irq, void *dummy)
+{
+       int i;
+
+       for (i = 0; i < NR_DMAOR; i++)
+               dmaor_reset(i);
+
        disable_irq(irq);
 
        return IRQ_HANDLED;
-#endif
+}
+
+static int dmae_irq_init(void)
+{
+       int n;
+
+       for (n = 0; n < NR_DMAE; n++) {
+               int i = request_irq(get_dma_error_irq(n), dma_err,
+                                   IRQF_SHARED, dmae_name[n], NULL);
+               if (unlikely(i < 0)) {
+                       printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]);
+                       return i;
+               }
+       }
+
+       return 0;
+}
+
+static void dmae_irq_free(void)
+{
+       int n;
+
+       for (n = 0; n < NR_DMAE; n++)
+               free_irq(get_dma_error_irq(n), NULL);
+}
+#else
+static inline int dmae_irq_init(void)
+{
+       return 0;
+}
+
+static void dmae_irq_free(void)
+{
 }
 #endif
 
@@ -276,72 +378,34 @@ static struct dma_info sh_dmac_info = {
        .flags          = DMAC_CHANNELS_TEI_CAPABLE,
 };
 
-#ifdef CONFIG_CPU_SH4
-static unsigned int get_dma_error_irq(int n)
-{
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
-       return (n == 0) ? get_dmte_irq(0) : get_dmte_irq(6);
-#else
-       return (n == 0) ? DMAE0_IRQ :
-#if defined(DMAE1_IRQ)
-                               DMAE1_IRQ;
-#else
-                               -1;
-#endif
-#endif
-}
-#endif
-
 static int __init sh_dmac_init(void)
 {
        struct dma_info *info = &sh_dmac_info;
-       int i;
-
-#ifdef CONFIG_CPU_SH4
-       int n;
+       int i, rc;
 
-       for (n = 0; n < NR_DMAE; n++) {
-               i = request_irq(get_dma_error_irq(n), dma_err,
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
-                               IRQF_SHARED,
-#else
-                               0,
-#endif
-                               dmae_name[n], (void *)dmae_name[n]);
-               if (unlikely(i < 0)) {
-                       printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]);
-                       return i;
-               }
-       }
-#endif /* CONFIG_CPU_SH4 */
+       /*
+        * Initialize DMAE, for parts that support it.
+        */
+       rc = dmae_irq_init();
+       if (unlikely(rc != 0))
+               return rc;
 
        /*
         * Initialize DMAOR, and clean up any error flags that may have
         * been set.
         */
-       i = dmaor_reset(0);
-       if (unlikely(i != 0))
-               return i;
-#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
-               defined(CONFIG_CPU_SUBTYPE_SH7780)      || \
-               defined(CONFIG_CPU_SUBTYPE_SH7785)
-       i = dmaor_reset(1);
-       if (unlikely(i != 0))
-               return i;
-#endif
+       for (i = 0; i < NR_DMAOR; i++) {
+               rc = dmaor_reset(i);
+               if (unlikely(rc != 0))
+                       return rc;
+       }
 
        return register_dmac(info);
 }
 
 static void __exit sh_dmac_exit(void)
 {
-#ifdef CONFIG_CPU_SH4
-       int n;
-
-       for (n = 0; n < NR_DMAE; n++) {
-               free_irq(get_dma_error_irq(n), (void *)dmae_name[n]);
-       }
-#endif /* CONFIG_CPU_SH4 */
+       dmae_irq_free();
        unregister_dmac(&sh_dmac_info);
 }
 
index 67ee956038138b2ca039512a48995085271e36dd..4b15feda54b04a24061830868a1d4fc1fdf2bff1 100644 (file)
@@ -29,7 +29,7 @@ static ssize_t dma_show_devices(struct device *dev,
        ssize_t len = 0;
        int i;
 
-       for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+       for (i = 0; i < 16; i++) {
                struct dma_info *info = get_dma_info(i);
                struct dma_channel *channel = get_dma_channel(i);
 
index ecb1d106063813badede4185d636230f2f00e879..db5b40a98e62aa53a013f050e62098fd6b97643a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
+#include <linux/sh_intc.h>
 #include "pci-sh4.h"
 
 #define PCIMCR_MRSET_OFF       0xBFFFFFFF
@@ -27,7 +28,7 @@ int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
         * slot2: pin1-4 = irq7,8,5,6
         * slot3: pin1-4 = irq8,5,6,7
         */
-       int irq = ((slot + pin - 1) & 0x3) + 5;
+       int irq = ((slot + pin - 1) & 0x3) + evt2irq(0x2a0);
 
        if ((slot | (pin - 1)) > 0x3) {
                printk(KERN_WARNING "PCI: Bad IRQ mapping request for slot %d pin %c\n",
index f9370dce0b70a710f8340e62f09f87a422d7eda4..57ed3f09d0c2b838d5e0daa372b319ff32fb3565 100644 (file)
  */
 #include <linux/pci.h>
 #include <linux/io.h>
+#include <linux/sh_intc.h>
 #include "pci-sh4.h"
 
-static char irq_tab[] __initdata = {
-       65, 66, 67, 68,
-};
-
 int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
-       return irq_tab[slot];
+       return evt2irq(0xa20) + slot;
 }
index 0b8472501b885044b33ebaaaee4b4b8fb5065f9e..c0a015ae6ecf718df7a2bfba9ea4fc4edd35bd82 100644 (file)
  */
 #include <linux/pci.h>
 #include <linux/io.h>
+#include <linux/sh_intc.h>
 #include "pci-sh4.h"
 
+#define IRQ_INTA       evt2irq(0xa20)
+#define IRQ_INTB       evt2irq(0xa40)
+#define IRQ_INTC       evt2irq(0xa60)
+#define IRQ_INTD       evt2irq(0xa80)
+
 /* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
 static char sdk7780_irq_tab[4][16] __initdata = {
        /* INTA */
-       { 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+       { IRQ_INTA, IRQ_INTD, IRQ_INTC, IRQ_INTD, -1, -1, -1, -1, -1, -1,
+         -1, -1, -1, -1, -1, -1 },
        /* INTB */
-       { 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+       { IRQ_INTB, IRQ_INTA, -1, IRQ_INTA, -1, -1, -1, -1, -1, -1, -1, -1,
+         -1, -1, -1, -1 },
        /* INTC */
-       { 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+       { IRQ_INTC, IRQ_INTB, -1, IRQ_INTB, -1, -1, -1, -1, -1, -1, -1, -1,
+         -1, -1, -1, -1 },
        /* INTD */
-       { 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+       { IRQ_INTD, IRQ_INTC, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+         -1, -1, -1 },
 };
 
 int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
index 2ec146c3fa4468453e946c026ae2f58a0d803e61..84a88ca9200821c4fbd9b1266967ded716c89d72 100644 (file)
@@ -4,13 +4,14 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/io.h>
+#include <linux/sh_intc.h>
 #include "pci-sh4.h"
 
 int __init pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
 {
         switch (slot) {
-        case 0: return 13;
-        case 1: return 13;     /* AMD Ethernet controller */
+        case 0: return evt2irq(0x3a0);
+        case 1: return evt2irq(0x3a0); /* AMD Ethernet controller */
         case 2: return -1;
         case 3: return -1;
         case 4: return -1;
index 1615e5906168117c7a81ae73b42f7f2c42b1137a..16207bef9f52586dee90548d6c472e318dbc3a68 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/sh_intc.h>
 
 int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
@@ -9,21 +10,21 @@ int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 
        if (dev->bus->number == 0) {
                switch (slot) {
-               case 4: return 5;       /* eth0       */
-               case 8: return 5;       /* eth1       */
-               case 6: return 2;       /* PCI bridge */
+               case 4: return evt2irq(0x2a0);  /* eth0       */
+               case 8: return evt2irq(0x2a0);  /* eth1       */
+               case 6: return evt2irq(0x240);  /* PCI bridge */
                default:
                        printk(KERN_ERR "PCI: Bad IRQ mapping request "
                                        "for slot %d\n", slot);
-                       return 2;
+                       return evt2irq(0x240);
                }
        } else {
                switch (pin) {
-               case 0:   irq =  2; break;
-               case 1:   irq =  2; break;
-               case 2:   irq =  2; break;
-               case 3:   irq =  2; break;
-               case 4:   irq =  2; break;
+               case 0:   irq =  evt2irq(0x240); break;
+               case 1:   irq =  evt2irq(0x240); break;
+               case 2:   irq =  evt2irq(0x240); break;
+               case 3:   irq =  evt2irq(0x240); break;
+               case 4:   irq =  evt2irq(0x240); break;
                default:  irq = -1; break;
                }
        }
index 4a093c648d124099a4df0d775cc23ad2980f5951..6e33ba4cd0765254ea0f7c0b7c274c2f3cf92b0d 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/sh_intc.h>
 #include "pci-sh4.h"
 
 int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
@@ -24,11 +25,11 @@ int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 
        switch (slot) {
        case 8:  /* the PCI bridge */ break;
-       case 11: irq = 8;  break; /* USB    */
-       case 12: irq = 11; break; /* PCMCIA */
-       case 13: irq = 5;  break; /* eth0   */
-       case 14: irq = 8;  break; /* eth1   */
-       case 15: irq = 11; break; /* safenet (unused) */
+       case 11: irq = evt2irq(0x300); break; /* USB    */
+       case 12: irq = evt2irq(0x360); break; /* PCMCIA */
+       case 13: irq = evt2irq(0x2a0); break; /* eth0   */
+       case 14: irq = evt2irq(0x300); break; /* eth1   */
+       case 15: irq = evt2irq(0x360); break; /* safenet (unused) */
        }
 
        printk("PCI: Mapping SnapGear IRQ for slot %d, pin %c to irq %d\n",
index 4df27c4fbf999e68d03e598175b50d84c22aaa81..c045142f73385978cd8e740ebb235ca40c40ad02 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/sh_clk.h>
+#include <linux/sh_intc.h>
 #include "pcie-sh7786.h"
 #include <asm/sizes.h>
 
@@ -468,7 +469,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port)
 
 int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
-        return 71;
+        return evt2irq(0xae0);
 }
 
 static int __init sh7786_pcie_core_init(void)
diff --git a/arch/sh/include/asm/dma-sh.h b/arch/sh/include/asm/dma-sh.h
deleted file mode 100644 (file)
index f3acb8e..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * arch/sh/include/asm/dma-sh.h
- *
- * Copyright (C) 2000  Takashi YOSHII
- * Copyright (C) 2003  Paul Mundt
- *
- * 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 __DMA_SH_H
-#define __DMA_SH_H
-
-#include <asm/dma-register.h>
-#include <cpu/dma-register.h>
-#include <cpu/dma.h>
-
-/* DMAOR contorl: The DMAOR access size is different by CPU.*/
-#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7724) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785)
-#define dmaor_read_reg(n) \
-    (n ? __raw_readw(SH_DMAC_BASE1 + DMAOR) \
-       : __raw_readw(SH_DMAC_BASE0 + DMAOR))
-#define dmaor_write_reg(n, data) \
-    (n ? __raw_writew(data, SH_DMAC_BASE1 + DMAOR) \
-    : __raw_writew(data, SH_DMAC_BASE0 + DMAOR))
-#else /* Other CPU */
-#define dmaor_read_reg(n) __raw_readw(SH_DMAC_BASE0 + DMAOR)
-#define dmaor_write_reg(n, data) __raw_writew(data, SH_DMAC_BASE0 + DMAOR)
-#endif
-
-static int dmte_irq_map[] __maybe_unused = {
-#if (MAX_DMA_CHANNELS >= 4)
-    DMTE0_IRQ,
-    DMTE0_IRQ + 1,
-    DMTE0_IRQ + 2,
-    DMTE0_IRQ + 3,
-#endif
-#if (MAX_DMA_CHANNELS >= 6)
-    DMTE4_IRQ,
-    DMTE4_IRQ + 1,
-#endif
-#if (MAX_DMA_CHANNELS >= 8)
-    DMTE6_IRQ,
-    DMTE6_IRQ + 1,
-#endif
-#if (MAX_DMA_CHANNELS >= 12)
-    DMTE8_IRQ,
-    DMTE9_IRQ,
-    DMTE10_IRQ,
-    DMTE11_IRQ,
-#endif
-};
-
-/*
- * Define the default configuration for dual address memory-memory transfer.
- * The 0x400 value represents auto-request, external->external.
- */
-#define RS_DUAL        (DM_INC | SM_INC | 0x400 | TS_INDEX2VAL(XMIT_SZ_32BIT))
-
-/* DMA base address */
-static u32 dma_base_addr[] __maybe_unused = {
-#if (MAX_DMA_CHANNELS >= 4)
-       SH_DMAC_BASE0 + 0x00,   /* channel 0 */
-       SH_DMAC_BASE0 + 0x10,
-       SH_DMAC_BASE0 + 0x20,
-       SH_DMAC_BASE0 + 0x30,
-#endif
-#if (MAX_DMA_CHANNELS >= 6)
-       SH_DMAC_BASE0 + 0x50,
-       SH_DMAC_BASE0 + 0x60,
-#endif
-#if (MAX_DMA_CHANNELS >= 8)
-       SH_DMAC_BASE1 + 0x00,
-       SH_DMAC_BASE1 + 0x10,
-#endif
-#if (MAX_DMA_CHANNELS >= 12)
-       SH_DMAC_BASE1 + 0x20,
-       SH_DMAC_BASE1 + 0x30,
-       SH_DMAC_BASE1 + 0x50,
-       SH_DMAC_BASE1 + 0x60, /* channel 11 */
-#endif
-};
-
-#endif /* __DMA_SH_H */
index 6aa2080c0065c66a925b02e0cdd67b14e6007e5a..fb6e4f7b00a2c48fed82aa09b5cf72c837959b36 100644 (file)
 #include <linux/wait.h>
 #include <linux/sched.h>
 #include <linux/device.h>
-#include <cpu/dma.h>
 #include <asm-generic/dma.h>
 
-#ifdef CONFIG_NR_DMA_CHANNELS
-#  define MAX_DMA_CHANNELS     (CONFIG_NR_DMA_CHANNELS)
-#elif defined(CONFIG_NR_ONCHIP_DMA_CHANNELS)
-#  define MAX_DMA_CHANNELS     (CONFIG_NR_ONCHIP_DMA_CHANNELS)
-#else
-#  define MAX_DMA_CHANNELS     0
-#endif
-
 /*
  * Read and write modes can mean drastically different things depending on the
  * channel configuration. Consult your DMAC documentation and module
index bd7e79a1265345691caf54cc4e1d21198e7e0adf..cbe0186b679433d988263f73945df8f3940e99d8 100644 (file)
@@ -96,7 +96,7 @@ extern void __clear_fixmap(enum fixed_addresses idx, pgprot_t flags);
 #ifdef CONFIG_SUPERH32
 #define FIXADDR_TOP    (P4SEG - PAGE_SIZE)
 #else
-#define FIXADDR_TOP    (0xff000000 - PAGE_SIZE)
+#define FIXADDR_TOP    ((unsigned long)(-PAGE_SIZE))
 #endif
 #define FIXADDR_SIZE   (__end_of_fixed_addresses << PAGE_SHIFT)
 #define FIXADDR_START  (FIXADDR_TOP - FIXADDR_SIZE)
index 24182116711fa308e5977c83a621d6dadb4b14cf..69fee1239b03308a998ac965f4793f4decc5b5d6 100644 (file)
@@ -9,11 +9,9 @@
 
 #define SH7760_I2C0_MMIO       0xFE140000
 #define SH7760_I2C0_MMIOEND    0xFE14003B
-#define SH7760_I2C0_IRQ                62
 
 #define SH7760_I2C1_MMIO       0xFE150000
 #define SH7760_I2C1_MMIOEND    0xFE15003B
-#define SH7760_I2C1_IRQ                63
 
 struct sh7760_i2c_platdata {
        unsigned int speed_khz;
index ec464a6b95fe2cbd790bd63c17302a533f239a6e..0cf60a62881435559ddec1d1c930ba2d71298a5c 100644 (file)
@@ -218,8 +218,13 @@ __BUILD_IOPORT_STRING(w, u16)
 __BUILD_IOPORT_STRING(l, u32)
 __BUILD_IOPORT_STRING(q, u64)
 
+#else /* !CONFIG_HAS_IOPORT */
+
+#include <asm/io_noioport.h>
+
 #endif
 
+
 #define IO_SPACE_LIMIT 0xffffffff
 
 /* synco on SH-4A, otherwise a nop */
diff --git a/arch/sh/include/asm/io_noioport.h b/arch/sh/include/asm/io_noioport.h
new file mode 100644 (file)
index 0000000..e136d28
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __ASM_SH_IO_NOIOPORT_H
+#define __ASM_SH_IO_NOIOPORT_H
+
+static inline u8 inb(unsigned long addr)
+{
+       BUG();
+       return -1;
+}
+
+static inline u16 inw(unsigned long addr)
+{
+       BUG();
+       return -1;
+}
+
+static inline u32 inl(unsigned long addr)
+{
+       BUG();
+       return -1;
+}
+
+#define outb(x, y)     BUG()
+#define outw(x, y)     BUG()
+#define outl(x, y)     BUG()
+
+#define inb_p(addr)    inb(addr)
+#define inw_p(addr)    inw(addr)
+#define inl_p(addr)    inl(addr)
+#define outb_p(x, addr)        outb((x), (addr))
+#define outw_p(x, addr)        outw((x), (addr))
+#define outl_p(x, addr)        outl((x), (addr))
+
+#define insb(a, b, c)  BUG()
+#define insw(a, b, c)  BUG()
+#define insl(a, b, c)  BUG()
+
+#define outsb(a, b, c) BUG()
+#define outsw(a, b, c) BUG()
+#define outsl(a, b, c) BUG()
+
+#endif /* __ASM_SH_IO_NOIOPORT_H */
index 2a62017eb2750705d1b07f7defb21532c8ccbf27..0e4f532e47379d1af1ded1eae3fc9f086a7966c2 100644 (file)
@@ -5,12 +5,15 @@
 #include <asm/machvec.h>
 
 /*
- * A sane default based on a reasonable vector table size, platforms are
- * advised to cap this at the hard limit that they're interested in
- * through the machvec.
+ * Only legacy non-sparseirq platforms have to set a reasonably sane
+ * value here. sparseirq platforms allocate their irq_descs on the fly,
+ * so will expand automatically based on the number of registered IRQs.
  */
-#define NR_IRQS                        512
-#define NR_IRQS_LEGACY         8       /* Legacy external IRQ0-7 */
+#ifdef CONFIG_SPARSE_IRQ
+# define NR_IRQS               8
+#else
+# define NR_IRQS               512
+#endif
 
 /*
  * This is a special IRQ number for indicating that no IRQ has been
index 5f6d2e9ccb7c24f16e4420ab3153d5746e0d66e9..a6201f10c2730878ae987cec8c01142f96569561 100644 (file)
@@ -10,4 +10,6 @@ enum die_val {
        DIE_SSTEP,
 };
 
+extern void printk_address(unsigned long address, int reliable);
+
 #endif /* __ASM_SH_KDEBUG_H */
index f3613952d1aeb8469a0581b91fcd35c3c80ca3d0..9e7d2d1b03e0adc7dc7e6225bd072f5d8164e35a 100644 (file)
@@ -4,18 +4,6 @@
 #include <asm/cacheflush.h>
 #include <asm/ptrace.h>
 
-/* Same as pt_regs but has vbr in place of syscall_nr */
-struct kgdb_regs {
-        unsigned long regs[16];
-        unsigned long pc;
-        unsigned long pr;
-        unsigned long sr;
-        unsigned long gbr;
-        unsigned long mach;
-        unsigned long macl;
-        unsigned long vbr;
-};
-
 enum regnames {
        GDB_R0, GDB_R1, GDB_R2, GDB_R3, GDB_R4, GDB_R5, GDB_R6, GDB_R7,
        GDB_R8, GDB_R9, GDB_R10, GDB_R11, GDB_R12, GDB_R13, GDB_R14, GDB_R15,
@@ -23,17 +11,27 @@ enum regnames {
        GDB_PC, GDB_PR, GDB_SR, GDB_GBR, GDB_MACH, GDB_MACL, GDB_VBR,
 };
 
-#define NUMREGBYTES    ((GDB_VBR + 1) * 4)
+#define _GP_REGS       16
+#define _EXTRA_REGS    7
+#define GDB_SIZEOF_REG sizeof(u32)
+
+#define DBG_MAX_REG_NUM        (_GP_REGS + _EXTRA_REGS)
+#define NUMREGBYTES    (DBG_MAX_REG_NUM * sizeof(GDB_SIZEOF_REG))
 
 static inline void arch_kgdb_breakpoint(void)
 {
        __asm__ __volatile__ ("trapa #0x3c\n");
 }
 
-#define BUFMAX                 2048
-
-#define CACHE_FLUSH_IS_SAFE    1
 #define BREAK_INSTR_SIZE       2
+#define BUFMAX                 2048
+
+#ifdef CONFIG_SMP
+# define CACHE_FLUSH_IS_SAFE   0
+#else
+# define CACHE_FLUSH_IS_SAFE   1
+#endif
+
 #define GDB_ADJUSTS_BREAK_OFFSET
 
 #endif /* __ASM_SH_KGDB_H */
index 57c5c3d0f39fe4b1bfdff174b544045a9c8baac8..eb9c20d971dd56f0b752f3cf75830ec1743fad4f 100644 (file)
@@ -17,7 +17,6 @@
 struct sh_machine_vector {
        void (*mv_setup)(char **cmdline_p);
        const char *mv_name;
-       int mv_nr_irqs;
 
        int (*mv_irq_demux)(int irq);
        void (*mv_init_irq)(void);
index 42cb9dd52161169c838c57b854fb05dc6a85de81..dda8c82601b9c3cc2d41ee95f489ca8def3a1819 100644 (file)
@@ -87,9 +87,6 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
 #define pte_unmap(pte)         do { } while (0)
 
 #ifndef __ASSEMBLY__
-#define IOBASE_VADDR   0xff000000
-#define IOBASE_END     0xffffffff
-
 /*
  * PTEL coherent flags.
  * See Chapter 17 ST50 CPU Core Volume 1, Architecture.
index 6dbc1be28a0fee9de709270afecbc604ba3ab0d3..3d14aeaef57cb04fee2df91df2d9d87ea65505d1 100644 (file)
@@ -18,7 +18,8 @@ enum cpu_type {
        CPU_SH7619,
 
        /* SH-2A types */
-       CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_MXG,
+       CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_SH7264, CPU_SH7269,
+       CPU_MXG,
 
        /* SH-3 types */
        CPU_SH7705, CPU_SH7706, CPU_SH7707,
@@ -32,7 +33,7 @@ enum cpu_type {
 
        /* SH-4A types */
        CPU_SH7763, CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785, CPU_SH7786,
-       CPU_SH7723, CPU_SH7724, CPU_SH7757, CPU_SHX3,
+       CPU_SH7723, CPU_SH7724, CPU_SH7757, CPU_SH7734, CPU_SHX3,
 
        /* SH4AL-DSP types */
        CPU_SH7343, CPU_SH7722, CPU_SH7366, CPU_SH7372,
index 900f8d72ffe2d86e902e590d53b180d73871da7a..b6311fd2d066a1db774409f1dac29f2b856290e4 100644 (file)
@@ -126,9 +126,6 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_pc, unsigned lo
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-void prepare_to_copy(struct task_struct *tsk);
-
 /*
  * create a kernel thread without removing it from tasklists
  */
index e25c4c7d6b63171221e247cea5f6ee45136efaf7..cd6029fb2c015f89742e3519b5b04172ef39ce5e 100644 (file)
@@ -121,7 +121,6 @@ struct thread_struct {
           NULL for a kernel thread. */
        struct pt_regs *uregs;
 
-       unsigned long trap_no, error_code;
        unsigned long address;
        /* Hardware debugging registers may come here */
 
@@ -138,8 +137,6 @@ struct thread_struct {
        .pc             = 0,                    \
         .kregs         = &fake_swapper_regs,   \
        .uregs          = NULL,                 \
-       .trap_no        = 0,                    \
-       .error_code     = 0,                    \
        .address        = 0,                    \
        .flags          = 0,                    \
 }
@@ -172,7 +169,6 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 #define copy_segments(p, mm)   do { } while (0)
 #define release_segments(mm)   do { } while (0)
 #define forget_segments()      do { } while (0)
-#define prepare_to_copy(tsk)   do { } while (0)
 /*
  * FPU lazy state save handling.
  */
diff --git a/arch/sh/include/asm/stackprotector.h b/arch/sh/include/asm/stackprotector.h
new file mode 100644 (file)
index 0000000..d9df3a7
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __ASM_SH_STACKPROTECTOR_H
+#define __ASM_SH_STACKPROTECTOR_H
+
+#include <linux/random.h>
+#include <linux/version.h>
+
+extern unsigned long __stack_chk_guard;
+
+/*
+ * Initialize the stackprotector canary value.
+ *
+ * NOTE: this must only be called from functions that never return,
+ * and it must always be inlined.
+ */
+static __always_inline void boot_init_stack_canary(void)
+{
+       unsigned long canary;
+
+       /* Try to get a semi random initial value. */
+       get_random_bytes(&canary, sizeof(canary));
+       canary ^= LINUX_VERSION_CODE;
+
+       current->stack_canary = canary;
+       __stack_chk_guard = current->stack_canary;
+}
+
+#endif /* __ASM_SH_STACKPROTECTOR_H */
index b6902061d4dcc22890281580871cd68b9b373399..0c04ffc4f12c41d344eded872aea06aaf7232e2b 100644 (file)
  *  - Incorporating suggestions made by Linus Torvalds and Dave Miller
  */
 #ifdef __KERNEL__
+
 #include <asm/page.h>
 
+/*
+ * Page fault error code bits
+ */
+#define FAULT_CODE_WRITE       (1 << 0)        /* write access */
+#define FAULT_CODE_INITIAL     (1 << 1)        /* initial page write */
+#define FAULT_CODE_ITLB                (1 << 2)        /* ITLB miss */
+#define FAULT_CODE_PROT                (1 << 3)        /* protection fault */
+#define FAULT_CODE_USER                (1 << 4)        /* user-mode access */
+
 #ifndef __ASSEMBLY__
 #include <asm/processor.h>
 
@@ -98,10 +108,13 @@ extern void init_thread_xstate(void);
 #endif /* __ASSEMBLY__ */
 
 /*
- * thread information flags
- * - these are process state flags that various assembly files may need to access
- * - pending work-to-be-done flags are in LSW
- * - other flags in MSW
+ * Thread information flags
+ *
+ * - Limited to 24 bits, upper byte used for fault code encoding.
+ *
+ * - _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within 2 bytes, or
+ *   we blow the tst immediate size constraints and need to fix up
+ *   arch/sh/kernel/entry-common.S.
  */
 #define TIF_SYSCALL_TRACE      0       /* syscall trace active */
 #define TIF_SIGPENDING         1       /* signal pending */
@@ -124,12 +137,6 @@ extern void init_thread_xstate(void);
 #define _TIF_SYSCALL_TRACEPOINT        (1 << TIF_SYSCALL_TRACEPOINT)
 #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
 
-/*
- * _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within 2 bytes, or we
- * blow the tst immediate size constraints and need to fix up
- * arch/sh/kernel/entry-common.S.
- */
-
 /* work to do in syscall trace */
 #define _TIF_WORK_SYSCALL_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
                                 _TIF_SYSCALL_AUDIT | _TIF_SECCOMP    | \
@@ -156,6 +163,7 @@ extern void init_thread_xstate(void);
 #define TS_USEDFPU             0x0002  /* FPU used by this task this quantum */
 
 #ifndef __ASSEMBLY__
+
 #define HAVE_SET_RESTORE_SIGMASK       1
 static inline void set_restore_sigmask(void)
 {
@@ -163,6 +171,24 @@ static inline void set_restore_sigmask(void)
        ti->status |= TS_RESTORE_SIGMASK;
        set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags);
 }
+
+#define TI_FLAG_FAULT_CODE_SHIFT       24
+
+/*
+ * Additional thread flag encoding
+ */
+static inline void set_thread_fault_code(unsigned int val)
+{
+       struct thread_info *ti = current_thread_info();
+       ti->flags = (ti->flags & (~0 >> (32 - TI_FLAG_FAULT_CODE_SHIFT)))
+               | (val << TI_FLAG_FAULT_CODE_SHIFT);
+}
+
+static inline unsigned int get_thread_fault_code(void)
+{
+       struct thread_info *ti = current_thread_info();
+       return ti->flags >> TI_FLAG_FAULT_CODE_SHIFT;
+}
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index c52d7f9a06c1a1de9f718a42c9570a78cb58b01d..ef5eff9194498fa96288ba168357cde40181ebe6 100644 (file)
 #ifndef __ASM_SH_TRAPS_64_H
 #define __ASM_SH_TRAPS_64_H
 
+#include <cpu/registers.h>
+
 extern void phys_stext(void);
 
+#define lookup_exception_vector()              \
+({                                             \
+       unsigned long _vec;                     \
+                                               \
+       __asm__ __volatile__ (                  \
+               "getcon " __EXPEVT ", %0\n\t"   \
+               : "=r" (_vec)                   \
+       );                                      \
+                                               \
+       _vec;                                   \
+})
+
 static inline void trigger_address_error(void)
 {
        phys_stext();
diff --git a/arch/sh/include/cpu-sh2/cpu/dma.h b/arch/sh/include/cpu-sh2/cpu/dma.h
deleted file mode 100644 (file)
index d66b43c..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Definitions for the SH-2 DMAC.
- *
- * Copyright (C) 2003  Paul Mundt
- *
- * 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 __ASM_CPU_SH2_DMA_H
-#define __ASM_CPU_SH2_DMA_H
-
-#define SH_MAX_DMA_CHANNELS    2
-
-#define SAR    ((unsigned long[]){ 0xffffff80, 0xffffff90 })
-#define DAR    ((unsigned long[]){ 0xffffff84, 0xffffff94 })
-#define DMATCR ((unsigned long[]){ 0xffffff88, 0xffffff98 })
-#define CHCR   ((unsigned long[]){ 0xfffffffc, 0xffffff9c })
-
-#define DMAOR  0xffffffb0
-
-#endif /* __ASM_CPU_SH2_DMA_H */
-
diff --git a/arch/sh/include/cpu-sh2a/cpu/dma.h b/arch/sh/include/cpu-sh2a/cpu/dma.h
deleted file mode 100644 (file)
index 27a13ef..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <cpu-sh2/cpu/dma.h>
diff --git a/arch/sh/include/cpu-sh2a/cpu/sh7264.h b/arch/sh/include/cpu-sh2a/cpu/sh7264.h
new file mode 100644 (file)
index 0000000..4d1ef6d
--- /dev/null
@@ -0,0 +1,176 @@
+#ifndef __ASM_SH7264_H__
+#define __ASM_SH7264_H__
+
+enum {
+       /* Port A */
+       GPIO_PA3, GPIO_PA2, GPIO_PA1, GPIO_PA0,
+
+       /* Port B */
+       GPIO_PB22, GPIO_PB21, GPIO_PB20,
+       GPIO_PB19, GPIO_PB18, GPIO_PB17, GPIO_PB16,
+       GPIO_PB15, GPIO_PB14, GPIO_PB13, GPIO_PB12,
+       GPIO_PB11, GPIO_PB10, GPIO_PB9, GPIO_PB8,
+       GPIO_PB7, GPIO_PB6, GPIO_PB5, GPIO_PB4,
+       GPIO_PB3, GPIO_PB2, GPIO_PB1,
+
+       /* Port C */
+       GPIO_PC10, GPIO_PC9, GPIO_PC8,
+       GPIO_PC7, GPIO_PC6, GPIO_PC5, GPIO_PC4,
+       GPIO_PC3, GPIO_PC2, GPIO_PC1, GPIO_PC0,
+
+       /* Port D */
+       GPIO_PD15, GPIO_PD14, GPIO_PD13, GPIO_PD12,
+       GPIO_PD11, GPIO_PD10, GPIO_PD9, GPIO_PD8,
+       GPIO_PD7, GPIO_PD6, GPIO_PD5, GPIO_PD4,
+       GPIO_PD3, GPIO_PD2, GPIO_PD1, GPIO_PD0,
+
+       /* Port E */
+       GPIO_PE5, GPIO_PE4,
+       GPIO_PE3, GPIO_PE2, GPIO_PE1, GPIO_PE0,
+
+       /* Port F */
+       GPIO_PF12,
+       GPIO_PF11, GPIO_PF10, GPIO_PF9, GPIO_PF8,
+       GPIO_PF7, GPIO_PF6, GPIO_PF5, GPIO_PF4,
+       GPIO_PF3, GPIO_PF2, GPIO_PF1, GPIO_PF0,
+
+       /* Port G */
+       GPIO_PG24,
+       GPIO_PG23, GPIO_PG22, GPIO_PG21, GPIO_PG20,
+       GPIO_PG19, GPIO_PG18, GPIO_PG17, GPIO_PG16,
+       GPIO_PG15, GPIO_PG14, GPIO_PG13, GPIO_PG12,
+       GPIO_PG11, GPIO_PG10, GPIO_PG9, GPIO_PG8,
+       GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
+       GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
+
+       /* Port H */
+       GPIO_PH7, GPIO_PH6, GPIO_PH5, GPIO_PH4,
+       GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
+
+       /* Port I - not on device */
+
+       /* Port J */
+       GPIO_PJ11, GPIO_PJ10, GPIO_PJ9, GPIO_PJ8,
+       GPIO_PJ7, GPIO_PJ6, GPIO_PJ5, GPIO_PJ4,
+       GPIO_PJ3, GPIO_PJ2, GPIO_PJ1, GPIO_PJ0,
+
+       /* Port K */
+       GPIO_PK11, GPIO_PK10, GPIO_PK9, GPIO_PK8,
+       GPIO_PK7, GPIO_PK6, GPIO_PK5, GPIO_PK4,
+       GPIO_PK3, GPIO_PK2, GPIO_PK1, GPIO_PK0,
+
+       /* INTC: IRQ and PINT on PB/PD/PE */
+       GPIO_FN_PINT7_PG, GPIO_FN_PINT6_PG, GPIO_FN_PINT5_PG, GPIO_FN_PINT4_PG,
+       GPIO_FN_PINT3_PG, GPIO_FN_PINT2_PG, GPIO_FN_PINT1_PG,
+
+       GPIO_FN_IRQ7_PC, GPIO_FN_IRQ6_PC, GPIO_FN_IRQ5_PC, GPIO_FN_IRQ4_PC,
+       GPIO_FN_IRQ3_PG, GPIO_FN_IRQ2_PG, GPIO_FN_IRQ1_PJ, GPIO_FN_IRQ0_PJ,
+       GPIO_FN_IRQ3_PE, GPIO_FN_IRQ2_PE, GPIO_FN_IRQ1_PE, GPIO_FN_IRQ0_PE,
+
+       /* WDT */
+       GPIO_FN_WDTOVF,
+
+       /* CAN */
+       GPIO_FN_CTX1, GPIO_FN_CRX1, GPIO_FN_CTX0, GPIO_FN_CTX0_CTX1,
+       GPIO_FN_CRX0, GPIO_FN_CRX0_CRX1,
+
+       /* DMAC */
+       GPIO_FN_TEND0, GPIO_FN_DACK0, GPIO_FN_DREQ0,
+       GPIO_FN_TEND1, GPIO_FN_DACK1, GPIO_FN_DREQ1,
+
+       /* ADC */
+       GPIO_FN_ADTRG,
+
+       /* BSC */
+
+       GPIO_FN_A25, GPIO_FN_A24,
+       GPIO_FN_A23, GPIO_FN_A22, GPIO_FN_A21, GPIO_FN_A20,
+       GPIO_FN_A19, GPIO_FN_A18, GPIO_FN_A17, GPIO_FN_A16,
+       GPIO_FN_A15, GPIO_FN_A14, GPIO_FN_A13, GPIO_FN_A12,
+       GPIO_FN_A11, GPIO_FN_A10, GPIO_FN_A9, GPIO_FN_A8,
+       GPIO_FN_A7, GPIO_FN_A6, GPIO_FN_A5, GPIO_FN_A4,
+       GPIO_FN_A3, GPIO_FN_A2, GPIO_FN_A1, GPIO_FN_A0,
+       GPIO_FN_D15, GPIO_FN_D14, GPIO_FN_D13, GPIO_FN_D12,
+       GPIO_FN_D11, GPIO_FN_D10, GPIO_FN_D9, GPIO_FN_D8,
+       GPIO_FN_D7, GPIO_FN_D6, GPIO_FN_D5, GPIO_FN_D4,
+       GPIO_FN_D3, GPIO_FN_D2, GPIO_FN_D1, GPIO_FN_D0,
+
+       GPIO_FN_BS,
+       GPIO_FN_CS4, GPIO_FN_CS3, GPIO_FN_CS2, GPIO_FN_CS1, GPIO_FN_CS0,
+       GPIO_FN_CS6CE1B, GPIO_FN_CS5CE1A,
+       GPIO_FN_CE2A, GPIO_FN_CE2B,
+       GPIO_FN_RD, GPIO_FN_RDWR,
+       GPIO_FN_ICIOWRAH, GPIO_FN_ICIORD,
+       GPIO_FN_WE1DQMUWE, GPIO_FN_WE0DQML,
+       GPIO_FN_RAS, GPIO_FN_CAS, GPIO_FN_CKE,
+       GPIO_FN_WAIT, GPIO_FN_BREQ, GPIO_FN_BACK,
+       GPIO_FN_IOIS16,
+
+       /* TMU */
+       GPIO_FN_TIOC4D, GPIO_FN_TIOC4C, GPIO_FN_TIOC4B, GPIO_FN_TIOC4A,
+       GPIO_FN_TIOC3D, GPIO_FN_TIOC3C, GPIO_FN_TIOC3B, GPIO_FN_TIOC3A,
+       GPIO_FN_TIOC2B, GPIO_FN_TIOC1B, GPIO_FN_TIOC2A, GPIO_FN_TIOC1A,
+       GPIO_FN_TIOC0D, GPIO_FN_TIOC0C, GPIO_FN_TIOC0B, GPIO_FN_TIOC0A,
+       GPIO_FN_TCLKD, GPIO_FN_TCLKC, GPIO_FN_TCLKB, GPIO_FN_TCLKA,
+
+       /* SSU */
+       GPIO_FN_SCS0_PD, GPIO_FN_SSO0_PD, GPIO_FN_SSI0_PD, GPIO_FN_SSCK0_PD,
+       GPIO_FN_SCS0_PF, GPIO_FN_SSO0_PF, GPIO_FN_SSI0_PF, GPIO_FN_SSCK0_PF,
+       GPIO_FN_SCS1_PD, GPIO_FN_SSO1_PD, GPIO_FN_SSI1_PD, GPIO_FN_SSCK1_PD,
+       GPIO_FN_SCS1_PF, GPIO_FN_SSO1_PF, GPIO_FN_SSI1_PF, GPIO_FN_SSCK1_PF,
+
+       /* SCIF */
+       GPIO_FN_SCK0, GPIO_FN_SCK1, GPIO_FN_SCK2, GPIO_FN_SCK3,
+       GPIO_FN_RXD0, GPIO_FN_RXD1, GPIO_FN_RXD2, GPIO_FN_RXD3,
+       GPIO_FN_TXD0, GPIO_FN_TXD1, GPIO_FN_TXD2, GPIO_FN_TXD3,
+       GPIO_FN_RXD4, GPIO_FN_RXD5, GPIO_FN_RXD6, GPIO_FN_RXD7,
+       GPIO_FN_TXD4, GPIO_FN_TXD5, GPIO_FN_TXD6, GPIO_FN_TXD7,
+       GPIO_FN_RTS1, GPIO_FN_RTS3, GPIO_FN_CTS1, GPIO_FN_CTS3,
+
+       /* RSPI */
+       GPIO_FN_RSPCK0, GPIO_FN_MOSI0,
+       GPIO_FN_MISO0_PF12, GPIO_FN_MISO1,
+       GPIO_FN_SSL00,
+       GPIO_FN_RSPCK1, GPIO_FN_MOSI1,
+       GPIO_FN_MISO1_PG19, GPIO_FN_SSL10,
+
+       /* IIC3 */
+       GPIO_FN_SCL0, GPIO_FN_SCL1, GPIO_FN_SCL2,
+       GPIO_FN_SDA2, GPIO_FN_SDA1, GPIO_FN_SDA0,
+
+       /* SSI */
+       GPIO_FN_SSISCK0, GPIO_FN_SSIWS0, GPIO_FN_SSITXD0, GPIO_FN_SSIRXD0,
+       GPIO_FN_SSIWS1, GPIO_FN_SSIWS2, GPIO_FN_SSIWS3,
+       GPIO_FN_SSISCK1, GPIO_FN_SSISCK2, GPIO_FN_SSISCK3,
+       GPIO_FN_SSIDATA1, GPIO_FN_SSIDATA2, GPIO_FN_SSIDATA3,
+       GPIO_FN_AUDIO_CLK,
+
+       /* SIOF */
+       GPIO_FN_SIOFTXD, GPIO_FN_SIOFRXD, GPIO_FN_SIOFSYNC, GPIO_FN_SIOFSCK,
+
+       /* SPDIF */
+       GPIO_FN_SPDIF_IN,
+       GPIO_FN_SPDIF_OUT,
+
+       /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+       GPIO_FN_FCE,
+       GPIO_FN_FRB,
+
+       /* VDC3 */
+       GPIO_FN_DV_CLK, GPIO_FN_DV_VSYNC, GPIO_FN_DV_HSYNC,
+       GPIO_FN_DV_DATA7, GPIO_FN_DV_DATA6, GPIO_FN_DV_DATA5, GPIO_FN_DV_DATA4,
+       GPIO_FN_DV_DATA3, GPIO_FN_DV_DATA2, GPIO_FN_DV_DATA1, GPIO_FN_DV_DATA0,
+       GPIO_FN_LCD_CLK, GPIO_FN_LCD_EXTCLK,
+       GPIO_FN_LCD_VSYNC, GPIO_FN_LCD_HSYNC, GPIO_FN_LCD_DE,
+       GPIO_FN_LCD_DATA15, GPIO_FN_LCD_DATA14,
+       GPIO_FN_LCD_DATA13, GPIO_FN_LCD_DATA12,
+       GPIO_FN_LCD_DATA11, GPIO_FN_LCD_DATA10,
+       GPIO_FN_LCD_DATA9, GPIO_FN_LCD_DATA8,
+       GPIO_FN_LCD_DATA7, GPIO_FN_LCD_DATA6,
+       GPIO_FN_LCD_DATA5, GPIO_FN_LCD_DATA4,
+       GPIO_FN_LCD_DATA3, GPIO_FN_LCD_DATA2,
+       GPIO_FN_LCD_DATA1, GPIO_FN_LCD_DATA0,
+       GPIO_FN_LCD_M_DISP,
+};
+
+#endif /* __ASM_SH7264_H__ */
diff --git a/arch/sh/include/cpu-sh2a/cpu/sh7269.h b/arch/sh/include/cpu-sh2a/cpu/sh7269.h
new file mode 100644 (file)
index 0000000..48d1449
--- /dev/null
@@ -0,0 +1,201 @@
+#ifndef __ASM_SH7269_H__
+#define __ASM_SH7269_H__
+
+enum {
+       /* Port A */
+       GPIO_PA1, GPIO_PA0,
+
+       /* Port B */
+       GPIO_PB22, GPIO_PB21, GPIO_PB20,
+       GPIO_PB19, GPIO_PB18, GPIO_PB17, GPIO_PB16,
+       GPIO_PB15, GPIO_PB14, GPIO_PB13, GPIO_PB12,
+       GPIO_PB11, GPIO_PB10, GPIO_PB9, GPIO_PB8,
+       GPIO_PB7, GPIO_PB6, GPIO_PB5, GPIO_PB4,
+       GPIO_PB3, GPIO_PB2, GPIO_PB1,
+
+       /* Port C */
+       GPIO_PC8,
+       GPIO_PC7, GPIO_PC6, GPIO_PC5, GPIO_PC4,
+       GPIO_PC3, GPIO_PC2, GPIO_PC1, GPIO_PC0,
+
+       /* Port D */
+       GPIO_PD15, GPIO_PD14, GPIO_PD13, GPIO_PD12,
+       GPIO_PD11, GPIO_PD10, GPIO_PD9, GPIO_PD8,
+       GPIO_PD7, GPIO_PD6, GPIO_PD5, GPIO_PD4,
+       GPIO_PD3, GPIO_PD2, GPIO_PD1, GPIO_PD0,
+
+       /* Port E */
+       GPIO_PE7, GPIO_PE6, GPIO_PE5, GPIO_PE4,
+       GPIO_PE3, GPIO_PE2, GPIO_PE1, GPIO_PE0,
+
+       /* Port F */
+       GPIO_PF23, GPIO_PF22, GPIO_PF21, GPIO_PF20,
+       GPIO_PF19, GPIO_PF18, GPIO_PF17, GPIO_PF16,
+       GPIO_PF15, GPIO_PF14, GPIO_PF13, GPIO_PF12,
+       GPIO_PF11, GPIO_PF10, GPIO_PF9, GPIO_PF8,
+       GPIO_PF7, GPIO_PF6, GPIO_PF5, GPIO_PF4,
+       GPIO_PF3, GPIO_PF2, GPIO_PF1, GPIO_PF0,
+
+       /* Port G */
+       GPIO_PG27, GPIO_PG26, GPIO_PG25, GPIO_PG24,
+       GPIO_PG23, GPIO_PG22, GPIO_PG21, GPIO_PG20,
+       GPIO_PG19, GPIO_PG18, GPIO_PG17, GPIO_PG16,
+       GPIO_PG15, GPIO_PG14, GPIO_PG13, GPIO_PG12,
+       GPIO_PG11, GPIO_PG10, GPIO_PG9, GPIO_PG8,
+       GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
+       GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
+
+       /* Port H */
+       GPIO_PH7, GPIO_PH6, GPIO_PH5, GPIO_PH4,
+       GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
+
+       /* Port I - not on device */
+
+       /* Port J */
+       GPIO_PJ31, GPIO_PJ30, GPIO_PJ29, GPIO_PJ28,
+       GPIO_PJ27, GPIO_PJ26, GPIO_PJ25, GPIO_PJ24,
+       GPIO_PJ23, GPIO_PJ22, GPIO_PJ21, GPIO_PJ20,
+       GPIO_PJ19, GPIO_PJ18, GPIO_PJ17, GPIO_PJ16,
+       GPIO_PJ15, GPIO_PJ14, GPIO_PJ13, GPIO_PJ12,
+       GPIO_PJ11, GPIO_PJ10, GPIO_PJ9, GPIO_PJ8,
+       GPIO_PJ7, GPIO_PJ6, GPIO_PJ5, GPIO_PJ4,
+       GPIO_PJ3, GPIO_PJ2, GPIO_PJ1, GPIO_PJ0,
+
+       /* INTC: IRQ and PINT */
+       GPIO_FN_IRQ7_PG, GPIO_FN_IRQ6_PG, GPIO_FN_IRQ5_PG, GPIO_FN_IRQ4_PG,
+       GPIO_FN_IRQ3_PG, GPIO_FN_IRQ2_PG, GPIO_FN_IRQ1_PG, GPIO_FN_IRQ0_PG,
+       GPIO_FN_IRQ7_PF, GPIO_FN_IRQ6_PF, GPIO_FN_IRQ5_PF, GPIO_FN_IRQ4_PF,
+       GPIO_FN_IRQ3_PJ, GPIO_FN_IRQ2_PJ, GPIO_FN_IRQ1_PJ, GPIO_FN_IRQ0_PJ,
+       GPIO_FN_IRQ1_PC, GPIO_FN_IRQ0_PC,
+
+       GPIO_FN_PINT7_PG, GPIO_FN_PINT6_PG, GPIO_FN_PINT5_PG, GPIO_FN_PINT4_PG,
+       GPIO_FN_PINT3_PG, GPIO_FN_PINT2_PG, GPIO_FN_PINT1_PG, GPIO_FN_PINT0_PG,
+       GPIO_FN_PINT7_PH, GPIO_FN_PINT6_PH, GPIO_FN_PINT5_PH, GPIO_FN_PINT4_PH,
+       GPIO_FN_PINT3_PH, GPIO_FN_PINT2_PH, GPIO_FN_PINT1_PH, GPIO_FN_PINT0_PH,
+       GPIO_FN_PINT7_PJ, GPIO_FN_PINT6_PJ, GPIO_FN_PINT5_PJ, GPIO_FN_PINT4_PJ,
+       GPIO_FN_PINT3_PJ, GPIO_FN_PINT2_PJ, GPIO_FN_PINT1_PJ, GPIO_FN_PINT0_PJ,
+
+       /* WDT */
+       GPIO_FN_WDTOVF,
+
+       /* CAN */
+       GPIO_FN_CTX1, GPIO_FN_CRX1, GPIO_FN_CTX0, GPIO_FN_CTX0_CTX1,
+       GPIO_FN_CRX0, GPIO_FN_CRX0_CRX1, GPIO_FN_CRX0_CRX1_CRX2,
+
+       /* DMAC */
+       GPIO_FN_TEND0, GPIO_FN_DACK0, GPIO_FN_DREQ0,
+       GPIO_FN_TEND1, GPIO_FN_DACK1, GPIO_FN_DREQ1,
+
+       /* ADC */
+       GPIO_FN_ADTRG,
+
+       /* BSC */
+       GPIO_FN_A25, GPIO_FN_A24,
+       GPIO_FN_A23, GPIO_FN_A22, GPIO_FN_A21, GPIO_FN_A20,
+       GPIO_FN_A19, GPIO_FN_A18, GPIO_FN_A17, GPIO_FN_A16,
+       GPIO_FN_A15, GPIO_FN_A14, GPIO_FN_A13, GPIO_FN_A12,
+       GPIO_FN_A11, GPIO_FN_A10, GPIO_FN_A9, GPIO_FN_A8,
+       GPIO_FN_A7, GPIO_FN_A6, GPIO_FN_A5, GPIO_FN_A4,
+       GPIO_FN_A3, GPIO_FN_A2, GPIO_FN_A1, GPIO_FN_A0,
+       GPIO_FN_D15, GPIO_FN_D14, GPIO_FN_D13, GPIO_FN_D12,
+       GPIO_FN_D11, GPIO_FN_D10, GPIO_FN_D9, GPIO_FN_D8,
+       GPIO_FN_D7, GPIO_FN_D6, GPIO_FN_D5, GPIO_FN_D4,
+       GPIO_FN_D3, GPIO_FN_D2, GPIO_FN_D1, GPIO_FN_D0,
+
+       GPIO_FN_BS,
+       GPIO_FN_CS4, GPIO_FN_CS3, GPIO_FN_CS2, GPIO_FN_CS1, GPIO_FN_CS0,
+       GPIO_FN_CS5CE1A,
+       GPIO_FN_CE2A, GPIO_FN_CE2B,
+       GPIO_FN_RD, GPIO_FN_RDWR,
+       GPIO_FN_WE3ICIOWRAHDQMUU, GPIO_FN_WE2ICIORDDQMUL,
+       GPIO_FN_WE1DQMUWE, GPIO_FN_WE0DQML,
+       GPIO_FN_RAS, GPIO_FN_CAS, GPIO_FN_CKE,
+       GPIO_FN_WAIT, GPIO_FN_BREQ, GPIO_FN_BACK,
+       GPIO_FN_IOIS16,
+
+       /* TMU */
+       GPIO_FN_TIOC4D, GPIO_FN_TIOC4C, GPIO_FN_TIOC4B, GPIO_FN_TIOC4A,
+       GPIO_FN_TIOC3D, GPIO_FN_TIOC3C, GPIO_FN_TIOC3B, GPIO_FN_TIOC3A,
+       GPIO_FN_TIOC2B, GPIO_FN_TIOC1B, GPIO_FN_TIOC2A, GPIO_FN_TIOC1A,
+       GPIO_FN_TIOC0D, GPIO_FN_TIOC0C, GPIO_FN_TIOC0B, GPIO_FN_TIOC0A,
+       GPIO_FN_TCLKD, GPIO_FN_TCLKC, GPIO_FN_TCLKB, GPIO_FN_TCLKA,
+
+       /* SSU */
+       GPIO_FN_SCS0_PD, GPIO_FN_SSO0_PD, GPIO_FN_SSI0_PD, GPIO_FN_SSCK0_PD,
+       GPIO_FN_SCS0_PF, GPIO_FN_SSO0_PF, GPIO_FN_SSI0_PF, GPIO_FN_SSCK0_PF,
+       GPIO_FN_SCS1_PD, GPIO_FN_SSO1_PD, GPIO_FN_SSI1_PD, GPIO_FN_SSCK1_PD,
+       GPIO_FN_SCS1_PF, GPIO_FN_SSO1_PF, GPIO_FN_SSI1_PF, GPIO_FN_SSCK1_PF,
+
+       /* SCIF */
+       GPIO_FN_SCK0, GPIO_FN_RXD0, GPIO_FN_TXD0,
+       GPIO_FN_SCK1, GPIO_FN_RXD1, GPIO_FN_TXD1, GPIO_FN_RTS1, GPIO_FN_CTS1,
+       GPIO_FN_SCK2, GPIO_FN_RXD2, GPIO_FN_TXD2,
+       GPIO_FN_SCK3, GPIO_FN_RXD3, GPIO_FN_TXD3,
+       GPIO_FN_SCK4, GPIO_FN_RXD4, GPIO_FN_TXD4,
+       GPIO_FN_SCK5, GPIO_FN_RXD5, GPIO_FN_TXD5, GPIO_FN_RTS5, GPIO_FN_CTS5,
+       GPIO_FN_SCK6, GPIO_FN_RXD6, GPIO_FN_TXD6,
+       GPIO_FN_SCK7, GPIO_FN_RXD7, GPIO_FN_TXD7, GPIO_FN_RTS7, GPIO_FN_CTS7,
+
+       /* RSPI */
+       GPIO_FN_MISO0_PJ19, GPIO_FN_MISO0_PB20,
+       GPIO_FN_MOSI0_PJ18, GPIO_FN_MOSI0_PB19,
+       GPIO_FN_SSL00_PJ17, GPIO_FN_SSL00_PB18,
+       GPIO_FN_RSPCK0_PJ16, GPIO_FN_RSPCK0_PB17,
+       GPIO_FN_RSPCK1, GPIO_FN_MOSI1,
+       GPIO_FN_MISO1, GPIO_FN_SSL10,
+
+       /* IIC3 */
+       GPIO_FN_SCL0, GPIO_FN_SCL1, GPIO_FN_SCL2,
+       GPIO_FN_SDA2, GPIO_FN_SDA1, GPIO_FN_SDA0,
+
+       /* SSI */
+       GPIO_FN_SSISCK0, GPIO_FN_SSIWS0, GPIO_FN_SSITXD0, GPIO_FN_SSIRXD0,
+       GPIO_FN_SSIWS1, GPIO_FN_SSIWS2, GPIO_FN_SSIWS3,
+       GPIO_FN_SSISCK1, GPIO_FN_SSISCK2, GPIO_FN_SSISCK3,
+       GPIO_FN_SSIDATA1, GPIO_FN_SSIDATA2, GPIO_FN_SSIDATA3,
+       GPIO_FN_AUDIO_CLK,
+       GPIO_FN_AUDIO_XOUT,
+
+       /* SIOF */
+       GPIO_FN_SIOFTXD, GPIO_FN_SIOFRXD, GPIO_FN_SIOFSYNC, GPIO_FN_SIOFSCK,
+
+       /* SPDIF */
+       GPIO_FN_SPDIF_IN,
+       GPIO_FN_SPDIF_OUT,
+
+       /* NANDFMC  */ /* NOTE Controller is not available in boot mode 0 */
+       GPIO_FN_FCE,
+       GPIO_FN_FRB,
+
+       /* VDC */
+       GPIO_FN_DV_CLK, GPIO_FN_DV_VSYNC, GPIO_FN_DV_HSYNC,
+       GPIO_FN_DV_DATA23, GPIO_FN_DV_DATA22,
+       GPIO_FN_DV_DATA21, GPIO_FN_DV_DATA20,
+       GPIO_FN_DV_DATA19, GPIO_FN_DV_DATA18,
+       GPIO_FN_DV_DATA17, GPIO_FN_DV_DATA16,
+       GPIO_FN_DV_DATA15, GPIO_FN_DV_DATA14,
+       GPIO_FN_DV_DATA13, GPIO_FN_DV_DATA12,
+       GPIO_FN_DV_DATA11, GPIO_FN_DV_DATA10,
+       GPIO_FN_DV_DATA9, GPIO_FN_DV_DATA8,
+       GPIO_FN_DV_DATA7, GPIO_FN_DV_DATA6,
+       GPIO_FN_DV_DATA5, GPIO_FN_DV_DATA4,
+       GPIO_FN_DV_DATA3, GPIO_FN_DV_DATA2,
+       GPIO_FN_DV_DATA1, GPIO_FN_DV_DATA0,
+       GPIO_FN_LCD_CLK, GPIO_FN_LCD_EXTCLK,
+       GPIO_FN_LCD_VSYNC, GPIO_FN_LCD_HSYNC, GPIO_FN_LCD_DE,
+       GPIO_FN_LCD_DATA23, GPIO_FN_LCD_DATA22,
+       GPIO_FN_LCD_DATA21, GPIO_FN_LCD_DATA20,
+       GPIO_FN_LCD_DATA19, GPIO_FN_LCD_DATA18,
+       GPIO_FN_LCD_DATA17, GPIO_FN_LCD_DATA16,
+       GPIO_FN_LCD_DATA15, GPIO_FN_LCD_DATA14,
+       GPIO_FN_LCD_DATA13, GPIO_FN_LCD_DATA12,
+       GPIO_FN_LCD_DATA11, GPIO_FN_LCD_DATA10,
+       GPIO_FN_LCD_DATA9, GPIO_FN_LCD_DATA8,
+       GPIO_FN_LCD_DATA7, GPIO_FN_LCD_DATA6,
+       GPIO_FN_LCD_DATA5, GPIO_FN_LCD_DATA4,
+       GPIO_FN_LCD_DATA3, GPIO_FN_LCD_DATA2,
+       GPIO_FN_LCD_DATA1, GPIO_FN_LCD_DATA0,
+       GPIO_FN_LCD_M_DISP,
+};
+
+#endif /* __ASM_SH7269_H__ */
index 24e28b91c9d58d2b37c40ff0d1bde66f0a6aaf71..bccb4144a5e375f1a6413f7c28cf113a28d2ca2e 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ASM_CPU_SH3_DMA_H
 #define __ASM_CPU_SH3_DMA_H
 
+#include <linux/sh_intc.h>
+
 #if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
     defined(CONFIG_CPU_SUBTYPE_SH7721) || \
     defined(CONFIG_CPU_SUBTYPE_SH7710) || \
 #define SH_DMAC_BASE0  0xa4000020
 #endif
 
-#define DMTE0_IRQ      48
-#define DMTE4_IRQ      76
-
-/* Definitions for the SuperH DMAC */
-#define TM_BURST       0x00000020
-#define TS_8           0x00000000
-#define TS_16          0x00000008
-#define TS_32          0x00000010
-#define TS_128         0x00000018
+#define DMTE0_IRQ      evt2irq(0x800)
+#define DMTE4_IRQ      evt2irq(0xb80)
 
 #endif /* __ASM_CPU_SH3_DMA_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h b/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h
deleted file mode 100644 (file)
index 9647e68..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef __ASM_SH_CPU_SH4_DMA_SH7780_H
-#define __ASM_SH_CPU_SH4_DMA_SH7780_H
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7343) || \
-       defined(CONFIG_CPU_SUBTYPE_SH7730)
-#define DMTE0_IRQ      48
-#define DMTE4_IRQ      76
-#define DMAE0_IRQ      78      /* DMA Error IRQ*/
-#define SH_DMAC_BASE0  0xFE008020
-#define SH_DMARS_BASE0 0xFE009000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-#define DMTE0_IRQ      48
-#define DMTE4_IRQ      76
-#define DMAE0_IRQ      78      /* DMA Error IRQ*/
-#define SH_DMAC_BASE0  0xFE008020
-#define SH_DMARS_BASE0 0xFE009000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
-       defined(CONFIG_CPU_SUBTYPE_SH7764)
-#define DMTE0_IRQ      34
-#define DMTE4_IRQ      44
-#define DMAE0_IRQ      38
-#define SH_DMAC_BASE0  0xFF608020
-#define SH_DMARS_BASE0 0xFF609000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
-#define DMTE0_IRQ      48      /* DMAC0A*/
-#define DMTE4_IRQ      76      /* DMAC0B */
-#define DMTE6_IRQ      40
-#define DMTE8_IRQ      42      /* DMAC1A */
-#define DMTE9_IRQ      43
-#define DMTE10_IRQ     72      /* DMAC1B */
-#define DMTE11_IRQ     73
-#define DMAE0_IRQ      78      /* DMA Error IRQ*/
-#define DMAE1_IRQ      74      /* DMA Error IRQ*/
-#define SH_DMAC_BASE0  0xFE008020
-#define SH_DMAC_BASE1  0xFDC08020
-#define SH_DMARS_BASE0 0xFDC09000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
-#define DMTE0_IRQ      48      /* DMAC0A*/
-#define DMTE4_IRQ      76      /* DMAC0B */
-#define DMTE6_IRQ      40
-#define DMTE8_IRQ      42      /* DMAC1A */
-#define DMTE9_IRQ      43
-#define DMTE10_IRQ     72      /* DMAC1B */
-#define DMTE11_IRQ     73
-#define DMAE0_IRQ      78      /* DMA Error IRQ*/
-#define DMAE1_IRQ      74      /* DMA Error IRQ*/
-#define SH_DMAC_BASE0  0xFE008020
-#define SH_DMAC_BASE1  0xFDC08020
-#define SH_DMARS_BASE0 0xFE009000
-#define SH_DMARS_BASE1 0xFDC09000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-#define DMTE0_IRQ      34
-#define DMTE4_IRQ      44
-#define DMTE6_IRQ      46
-#define DMTE8_IRQ      92
-#define DMTE9_IRQ      93
-#define DMTE10_IRQ     94
-#define DMTE11_IRQ     95
-#define DMAE0_IRQ      38      /* DMA Error IRQ */
-#define SH_DMAC_BASE0  0xFC808020
-#define SH_DMAC_BASE1  0xFC818020
-#define SH_DMARS_BASE0 0xFC809000
-#else /* SH7785 */
-#define DMTE0_IRQ      33
-#define DMTE4_IRQ      37
-#define DMTE6_IRQ      52
-#define DMTE8_IRQ      54
-#define DMTE9_IRQ      55
-#define DMTE10_IRQ     56
-#define DMTE11_IRQ     57
-#define DMAE0_IRQ      39      /* DMA Error IRQ0 */
-#define DMAE1_IRQ      58      /* DMA Error IRQ1 */
-#define SH_DMAC_BASE0  0xFC808020
-#define SH_DMAC_BASE1  0xFCC08020
-#define SH_DMARS_BASE0 0xFC809000
-#endif
-
-#define REQ_HE         0x000000C0
-#define REQ_H          0x00000080
-#define REQ_LE         0x00000040
-#define TM_BURST       0x00000020
-
-#endif /* __ASM_SH_CPU_SH4_DMA_SH7780_H */
index ca747e93c2ed7d73cfc426986fbf4caa294042a7..a520eb219621a71cd27f0bc9f97d8c574cf5ff31 100644 (file)
@@ -1,32 +1,17 @@
 #ifndef __ASM_CPU_SH4_DMA_H
 #define __ASM_CPU_SH4_DMA_H
 
-/* SH7751/7760/7780 DMA IRQ sources */
+#include <linux/sh_intc.h>
 
-#ifdef CONFIG_CPU_SH4A
-
-#include <cpu/dma-sh4a.h>
-
-#else /* CONFIG_CPU_SH4A */
 /*
  * SH7750/SH7751/SH7760
  */
-#define DMTE0_IRQ      34
-#define DMTE4_IRQ      44
-#define DMTE6_IRQ      46
-#define DMAE0_IRQ      38
+#define DMTE0_IRQ      evt2irq(0x640)
+#define DMTE4_IRQ      evt2irq(0x780)
+#define DMTE6_IRQ      evt2irq(0x7c0)
+#define DMAE0_IRQ      evt2irq(0x6c0)
 
 #define SH_DMAC_BASE0  0xffa00000
 #define SH_DMAC_BASE1  0xffa00070
-/* Definitions for the SuperH DMAC */
-#define TM_BURST       0x00000080
-#define TS_8           0x00000010
-#define TS_16          0x00000020
-#define TS_32          0x00000030
-#define TS_64          0x00000000
-
-#define DMAOR_COD      0x00000008
-
-#endif
 
 #endif /* __ASM_CPU_SH4_DMA_H */
index cffd25ed02400fb472fe8e56bcc5067ae373d7f0..1631fc238e6f006439cb2a64b05fbca27e016caa 100644 (file)
 #define MSTPCR1                        0xa4150034
 #define MSTPCR2                        0xa4150038
 
+#elif defined(CONFIG_CPU_SUBTYPE_SH7734)
+#define FRQCR0                 0xffc80000
+#define FRQCR2                 0xffc80008
+#define FRQMR1                 0xffc80014
+#define FRQMR2                 0xffc80018
 #elif defined(CONFIG_CPU_SUBTYPE_SH7785)
 #define FRQCR0                 0xffc80000
 #define FRQCR1                 0xffc80004
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7734.h b/arch/sh/include/cpu-sh4/cpu/sh7734.h
new file mode 100644 (file)
index 0000000..2fb9a7b
--- /dev/null
@@ -0,0 +1,306 @@
+#ifndef __ASM_SH7734_H__
+#define __ASM_SH7734_H__
+
+/* Pin Function Controller:
+ * GPIO_FN_xx - GPIO used to select pin function
+ * GPIO_GP_x_x - GPIO mapped to real I/O pin on CPU
+ */
+enum {
+       GPIO_GP_0_0, GPIO_GP_0_1, GPIO_GP_0_2, GPIO_GP_0_3,
+       GPIO_GP_0_4, GPIO_GP_0_5, GPIO_GP_0_6, GPIO_GP_0_7,
+       GPIO_GP_0_8, GPIO_GP_0_9, GPIO_GP_0_10, GPIO_GP_0_11,
+       GPIO_GP_0_12, GPIO_GP_0_13, GPIO_GP_0_14, GPIO_GP_0_15,
+       GPIO_GP_0_16, GPIO_GP_0_17, GPIO_GP_0_18, GPIO_GP_0_19,
+       GPIO_GP_0_20, GPIO_GP_0_21, GPIO_GP_0_22, GPIO_GP_0_23,
+       GPIO_GP_0_24, GPIO_GP_0_25, GPIO_GP_0_26, GPIO_GP_0_27,
+       GPIO_GP_0_28, GPIO_GP_0_29, GPIO_GP_0_30, GPIO_GP_0_31,
+
+       GPIO_GP_1_0, GPIO_GP_1_1, GPIO_GP_1_2, GPIO_GP_1_3,
+       GPIO_GP_1_4, GPIO_GP_1_5, GPIO_GP_1_6, GPIO_GP_1_7,
+       GPIO_GP_1_8, GPIO_GP_1_9, GPIO_GP_1_10, GPIO_GP_1_11,
+       GPIO_GP_1_12, GPIO_GP_1_13, GPIO_GP_1_14, GPIO_GP_1_15,
+       GPIO_GP_1_16, GPIO_GP_1_17, GPIO_GP_1_18, GPIO_GP_1_19,
+       GPIO_GP_1_20, GPIO_GP_1_21, GPIO_GP_1_22, GPIO_GP_1_23,
+       GPIO_GP_1_24, GPIO_GP_1_25, GPIO_GP_1_26, GPIO_GP_1_27,
+       GPIO_GP_1_28, GPIO_GP_1_29, GPIO_GP_1_30, GPIO_GP_1_31,
+
+       GPIO_GP_2_0, GPIO_GP_2_1, GPIO_GP_2_2, GPIO_GP_2_3,
+       GPIO_GP_2_4, GPIO_GP_2_5, GPIO_GP_2_6, GPIO_GP_2_7,
+       GPIO_GP_2_8, GPIO_GP_2_9, GPIO_GP_2_10, GPIO_GP_2_11,
+       GPIO_GP_2_12, GPIO_GP_2_13, GPIO_GP_2_14, GPIO_GP_2_15,
+       GPIO_GP_2_16, GPIO_GP_2_17, GPIO_GP_2_18, GPIO_GP_2_19,
+       GPIO_GP_2_20, GPIO_GP_2_21, GPIO_GP_2_22, GPIO_GP_2_23,
+       GPIO_GP_2_24, GPIO_GP_2_25, GPIO_GP_2_26, GPIO_GP_2_27,
+       GPIO_GP_2_28, GPIO_GP_2_29, GPIO_GP_2_30, GPIO_GP_2_31,
+
+       GPIO_GP_3_0, GPIO_GP_3_1, GPIO_GP_3_2, GPIO_GP_3_3,
+       GPIO_GP_3_4, GPIO_GP_3_5, GPIO_GP_3_6, GPIO_GP_3_7,
+       GPIO_GP_3_8, GPIO_GP_3_9, GPIO_GP_3_10, GPIO_GP_3_11,
+       GPIO_GP_3_12, GPIO_GP_3_13, GPIO_GP_3_14, GPIO_GP_3_15,
+       GPIO_GP_3_16, GPIO_GP_3_17, GPIO_GP_3_18, GPIO_GP_3_19,
+       GPIO_GP_3_20, GPIO_GP_3_21, GPIO_GP_3_22, GPIO_GP_3_23,
+       GPIO_GP_3_24, GPIO_GP_3_25, GPIO_GP_3_26, GPIO_GP_3_27,
+       GPIO_GP_3_28, GPIO_GP_3_29, GPIO_GP_3_30, GPIO_GP_3_31,
+
+       GPIO_GP_4_0, GPIO_GP_4_1, GPIO_GP_4_2, GPIO_GP_4_3,
+       GPIO_GP_4_4, GPIO_GP_4_5, GPIO_GP_4_6, GPIO_GP_4_7,
+       GPIO_GP_4_8, GPIO_GP_4_9, GPIO_GP_4_10, GPIO_GP_4_11,
+       GPIO_GP_4_12, GPIO_GP_4_13, GPIO_GP_4_14, GPIO_GP_4_15,
+       GPIO_GP_4_16, GPIO_GP_4_17, GPIO_GP_4_18, GPIO_GP_4_19,
+       GPIO_GP_4_20, GPIO_GP_4_21, GPIO_GP_4_22, GPIO_GP_4_23,
+       GPIO_GP_4_24, GPIO_GP_4_25, GPIO_GP_4_26, GPIO_GP_4_27,
+       GPIO_GP_4_28, GPIO_GP_4_29, GPIO_GP_4_30, GPIO_GP_4_31,
+
+       GPIO_GP_5_0, GPIO_GP_5_1, GPIO_GP_5_2, GPIO_GP_5_3,
+       GPIO_GP_5_4, GPIO_GP_5_5, GPIO_GP_5_6, GPIO_GP_5_7,
+       GPIO_GP_5_8, GPIO_GP_5_9, GPIO_GP_5_10, GPIO_GP_5_11,
+
+       GPIO_FN_CLKOUT, GPIO_FN_BS, GPIO_FN_CS0, GPIO_FN_EX_CS0, GPIO_FN_RD,
+               GPIO_FN_WE0, GPIO_FN_WE1,
+
+       GPIO_FN_SCL0, GPIO_FN_PENC0, GPIO_FN_USB_OVC0,
+
+       GPIO_FN_IRQ2_B, GPIO_FN_IRQ3_B,
+
+       /* IPSR0 */
+       GPIO_FN_A15, GPIO_FN_ST0_VCO_CLKIN, GPIO_FN_LCD_DATA15_A,
+               GPIO_FN_TIOC3D_C,
+       GPIO_FN_A14, GPIO_FN_LCD_DATA14_A, GPIO_FN_TIOC3C_C,
+       GPIO_FN_A13, GPIO_FN_LCD_DATA13_A, GPIO_FN_TIOC3B_C,
+       GPIO_FN_A12, GPIO_FN_LCD_DATA12_A, GPIO_FN_TIOC3A_C,
+       GPIO_FN_A11, GPIO_FN_ST0_D7, GPIO_FN_LCD_DATA11_A,
+               GPIO_FN_TIOC2B_C,
+       GPIO_FN_A10, GPIO_FN_ST0_D6, GPIO_FN_LCD_DATA10_A,
+               GPIO_FN_TIOC2A_C,
+       GPIO_FN_A9, GPIO_FN_ST0_D5, GPIO_FN_LCD_DATA9_A,
+               GPIO_FN_TIOC1B_C,
+       GPIO_FN_A8, GPIO_FN_ST0_D4, GPIO_FN_LCD_DATA8_A,
+               GPIO_FN_TIOC1A_C,
+       GPIO_FN_A7, GPIO_FN_ST0_D3, GPIO_FN_LCD_DATA7_A, GPIO_FN_TIOC0D_C,
+       GPIO_FN_A6, GPIO_FN_ST0_D2, GPIO_FN_LCD_DATA6_A, GPIO_FN_TIOC0C_C,
+       GPIO_FN_A5, GPIO_FN_ST0_D1, GPIO_FN_LCD_DATA5_A, GPIO_FN_TIOC0B_C,
+       GPIO_FN_A4, GPIO_FN_ST0_D0, GPIO_FN_LCD_DATA4_A, GPIO_FN_TIOC0A_C,
+       GPIO_FN_A3, GPIO_FN_ST0_VLD, GPIO_FN_LCD_DATA3_A, GPIO_FN_TCLKD_C,
+       GPIO_FN_A2, GPIO_FN_ST0_SYC, GPIO_FN_LCD_DATA2_A, GPIO_FN_TCLKC_C,
+       GPIO_FN_A1, GPIO_FN_ST0_REQ, GPIO_FN_LCD_DATA1_A, GPIO_FN_TCLKB_C,
+       GPIO_FN_A0, GPIO_FN_ST0_CLKIN, GPIO_FN_LCD_DATA0_A, GPIO_FN_TCLKA_C,
+
+       /* IPSR1 */
+       GPIO_FN_D3, GPIO_FN_SD0_DAT3_A, GPIO_FN_MMC_D3_A, GPIO_FN_ST1_D6,
+               GPIO_FN_FD3_A,
+       GPIO_FN_D2, GPIO_FN_SD0_DAT2_A, GPIO_FN_MMC_D2_A, GPIO_FN_ST1_D5,
+               GPIO_FN_FD2_A,
+       GPIO_FN_D1, GPIO_FN_SD0_DAT1_A, GPIO_FN_MMC_D1_A, GPIO_FN_ST1_D4,
+               GPIO_FN_FD1_A,
+       GPIO_FN_D0, GPIO_FN_SD0_DAT0_A, GPIO_FN_MMC_D0_A, GPIO_FN_ST1_D3,
+               GPIO_FN_FD0_A,
+       GPIO_FN_A25, GPIO_FN_TX2_D, GPIO_FN_ST1_D2,
+       GPIO_FN_A24, GPIO_FN_RX2_D, GPIO_FN_ST1_D1,
+       GPIO_FN_A23, GPIO_FN_ST1_D0, GPIO_FN_LCD_M_DISP_A,
+       GPIO_FN_A22, GPIO_FN_ST1_VLD, GPIO_FN_LCD_VEPWC_A,
+       GPIO_FN_A21, GPIO_FN_ST1_SYC, GPIO_FN_LCD_VCPWC_A,
+       GPIO_FN_A20, GPIO_FN_ST1_REQ, GPIO_FN_LCD_FLM_A,
+       GPIO_FN_A19, GPIO_FN_ST1_CLKIN, GPIO_FN_LCD_CLK_A, GPIO_FN_TIOC4D_C,
+       GPIO_FN_A18, GPIO_FN_ST1_PWM, GPIO_FN_LCD_CL2_A, GPIO_FN_TIOC4C_C,
+       GPIO_FN_A17, GPIO_FN_ST1_VCO_CLKIN, GPIO_FN_LCD_CL1_A, GPIO_FN_TIOC4B_C,
+       GPIO_FN_A16, GPIO_FN_ST0_PWM, GPIO_FN_LCD_DON_A, GPIO_FN_TIOC4A_C,
+
+       /* IPSR2 */
+       GPIO_FN_D14, GPIO_FN_TX2_B, GPIO_FN_FSE_A, GPIO_FN_ET0_TX_CLK_B,
+       GPIO_FN_D13, GPIO_FN_RX2_B, GPIO_FN_FRB_A,      GPIO_FN_ET0_ETXD6_B,
+       GPIO_FN_D12, GPIO_FN_FWE_A, GPIO_FN_ET0_ETXD5_B,
+       GPIO_FN_D11, GPIO_FN_RSPI_MISO_A, GPIO_FN_QMI_QIO1_A,
+               GPIO_FN_FRE_A, GPIO_FN_ET0_ETXD3_B,
+       GPIO_FN_D10, GPIO_FN_RSPI_MOSI_A, GPIO_FN_QMO_QIO0_A,
+               GPIO_FN_FALE_A, GPIO_FN_ET0_ETXD2_B,
+       GPIO_FN_D9, GPIO_FN_SD0_CMD_A, GPIO_FN_MMC_CMD_A, GPIO_FN_QIO3_A,
+               GPIO_FN_FCLE_A, GPIO_FN_ET0_ETXD1_B,
+       GPIO_FN_D8, GPIO_FN_SD0_CLK_A, GPIO_FN_MMC_CLK_A, GPIO_FN_QIO2_A,
+               GPIO_FN_FCE_A, GPIO_FN_ET0_GTX_CLK_B,
+       GPIO_FN_D7, GPIO_FN_RSPI_SSL_A, GPIO_FN_MMC_D7_A, GPIO_FN_QSSL_A,
+               GPIO_FN_FD7_A,
+       GPIO_FN_D6, GPIO_FN_RSPI_RSPCK_A, GPIO_FN_MMC_D6_A, GPIO_FN_QSPCLK_A,
+               GPIO_FN_FD6_A,
+       GPIO_FN_D5, GPIO_FN_SD0_WP_A, GPIO_FN_MMC_D5_A, GPIO_FN_FD5_A,
+       GPIO_FN_D4, GPIO_FN_SD0_CD_A, GPIO_FN_MMC_D4_A, GPIO_FN_ST1_D7,
+               GPIO_FN_FD4_A,
+
+       /* IPSR3 */
+       GPIO_FN_DRACK0, GPIO_FN_SD1_DAT2_A, GPIO_FN_ATAG, GPIO_FN_TCLK1_A,
+               GPIO_FN_ET0_ETXD7,
+       GPIO_FN_EX_WAIT2, GPIO_FN_SD1_DAT1_A, GPIO_FN_DACK2, GPIO_FN_CAN1_RX_C,
+               GPIO_FN_ET0_MAGIC_C, GPIO_FN_ET0_ETXD6_A,
+       GPIO_FN_EX_WAIT1, GPIO_FN_SD1_DAT0_A, GPIO_FN_DREQ2, GPIO_FN_CAN1_TX_C,
+               GPIO_FN_ET0_LINK_C, GPIO_FN_ET0_ETXD5_A,
+       GPIO_FN_EX_WAIT0, GPIO_FN_TCLK1_B,
+       GPIO_FN_RD_WR, GPIO_FN_TCLK0,
+       GPIO_FN_EX_CS5, GPIO_FN_SD1_CMD_A, GPIO_FN_ATADIR, GPIO_FN_QSSL_B,
+               GPIO_FN_ET0_ETXD3_A,
+       GPIO_FN_EX_CS4, GPIO_FN_SD1_WP_A, GPIO_FN_ATAWR, GPIO_FN_QMI_QIO1_B,
+               GPIO_FN_ET0_ETXD2_A,
+       GPIO_FN_EX_CS3, GPIO_FN_SD1_CD_A, GPIO_FN_ATARD, GPIO_FN_QMO_QIO0_B,
+               GPIO_FN_ET0_ETXD1_A,
+       GPIO_FN_EX_CS2, GPIO_FN_TX3_B, GPIO_FN_ATACS1, GPIO_FN_QSPCLK_B,
+               GPIO_FN_ET0_GTX_CLK_A,
+       GPIO_FN_EX_CS1, GPIO_FN_RX3_B, GPIO_FN_ATACS0, GPIO_FN_QIO2_B,
+               GPIO_FN_ET0_ETXD0,
+       GPIO_FN_CS1_A26, GPIO_FN_QIO3_B,
+       GPIO_FN_D15, GPIO_FN_SCK2_B,
+
+       /* IPSR4 */
+       GPIO_FN_SCK2_A, GPIO_FN_VI0_G3,
+       GPIO_FN_RTS1_B, GPIO_FN_VI0_G2,
+       GPIO_FN_CTS1_B, GPIO_FN_VI0_DATA7_VI0_G1,
+       GPIO_FN_TX1_B, GPIO_FN_VI0_DATA6_VI0_G0, GPIO_FN_ET0_PHY_INT_A,
+       GPIO_FN_RX1_B, GPIO_FN_VI0_DATA5_VI0_B5, GPIO_FN_ET0_MAGIC_A,
+       GPIO_FN_SCK1_B, GPIO_FN_VI0_DATA4_VI0_B4, GPIO_FN_ET0_LINK_A,
+       GPIO_FN_RTS0_B, GPIO_FN_VI0_DATA3_VI0_B3, GPIO_FN_ET0_MDIO_A,
+       GPIO_FN_CTS0_B, GPIO_FN_VI0_DATA2_VI0_B2, GPIO_FN_RMII0_MDIO_A,
+               GPIO_FN_ET0_MDC,
+       GPIO_FN_HTX0_A, GPIO_FN_TX1_A, GPIO_FN_VI0_DATA1_VI0_B1,
+               GPIO_FN_RMII0_MDC_A, GPIO_FN_ET0_COL,
+       GPIO_FN_HRX0_A, GPIO_FN_RX1_A, GPIO_FN_VI0_DATA0_VI0_B0,
+               GPIO_FN_RMII0_CRS_DV_A, GPIO_FN_ET0_CRS,
+       GPIO_FN_HSCK0_A, GPIO_FN_SCK1_A, GPIO_FN_VI0_VSYNC,
+               GPIO_FN_RMII0_RX_ER_A, GPIO_FN_ET0_RX_ER,
+       GPIO_FN_HRTS0_A, GPIO_FN_RTS1_A, GPIO_FN_VI0_HSYNC,
+               GPIO_FN_RMII0_TXD_EN_A, GPIO_FN_ET0_RX_DV,
+       GPIO_FN_HCTS0_A, GPIO_FN_CTS1_A, GPIO_FN_VI0_FIELD,
+               GPIO_FN_RMII0_RXD1_A, GPIO_FN_ET0_ERXD7,
+
+       /* IPSR5 */
+       GPIO_FN_SD2_CLK_A, GPIO_FN_RX2_A, GPIO_FN_VI0_G4, GPIO_FN_ET0_RX_CLK_B,
+       GPIO_FN_SD2_CMD_A, GPIO_FN_TX2_A, GPIO_FN_VI0_G5, GPIO_FN_ET0_ERXD2_B,
+       GPIO_FN_SD2_DAT0_A, GPIO_FN_RX3_A, GPIO_FN_VI0_R0, GPIO_FN_ET0_ERXD3_B,
+       GPIO_FN_SD2_DAT1_A, GPIO_FN_TX3_A, GPIO_FN_VI0_R1, GPIO_FN_ET0_MDIO_B,
+       GPIO_FN_SD2_DAT2_A, GPIO_FN_RX4_A, GPIO_FN_VI0_R2, GPIO_FN_ET0_LINK_B,
+       GPIO_FN_SD2_DAT3_A, GPIO_FN_TX4_A, GPIO_FN_VI0_R3, GPIO_FN_ET0_MAGIC_B,
+       GPIO_FN_SD2_CD_A, GPIO_FN_RX5_A, GPIO_FN_VI0_R4, GPIO_FN_ET0_PHY_INT_B,
+       GPIO_FN_SD2_WP_A, GPIO_FN_TX5_A, GPIO_FN_VI0_R5,
+       GPIO_FN_REF125CK, GPIO_FN_ADTRG, GPIO_FN_RX5_C,
+       GPIO_FN_REF50CK, GPIO_FN_CTS1_E, GPIO_FN_HCTS0_D,
+
+       /* IPSR6 */
+       GPIO_FN_DU0_DR0, GPIO_FN_SCIF_CLK_B, GPIO_FN_HRX0_D, GPIO_FN_IETX_A,
+               GPIO_FN_TCLKA_A, GPIO_FN_HIFD00,
+       GPIO_FN_DU0_DR1, GPIO_FN_SCK0_B, GPIO_FN_HTX0_D, GPIO_FN_IERX_A,
+               GPIO_FN_TCLKB_A, GPIO_FN_HIFD01,
+       GPIO_FN_DU0_DR2, GPIO_FN_RX0_B, GPIO_FN_TCLKC_A, GPIO_FN_HIFD02,
+       GPIO_FN_DU0_DR3, GPIO_FN_TX0_B, GPIO_FN_TCLKD_A, GPIO_FN_HIFD03,
+       GPIO_FN_DU0_DR4, GPIO_FN_CTS0_C, GPIO_FN_TIOC0A_A, GPIO_FN_HIFD04,
+       GPIO_FN_DU0_DR5, GPIO_FN_RTS0_C, GPIO_FN_TIOC0B_A, GPIO_FN_HIFD05,
+       GPIO_FN_DU0_DR6, GPIO_FN_SCK1_C, GPIO_FN_TIOC0C_A, GPIO_FN_HIFD06,
+       GPIO_FN_DU0_DR7, GPIO_FN_RX1_C, GPIO_FN_TIOC0D_A, GPIO_FN_HIFD07,
+       GPIO_FN_DU0_DG0, GPIO_FN_TX1_C, GPIO_FN_HSCK0_D, GPIO_FN_IECLK_A,
+               GPIO_FN_TIOC1A_A, GPIO_FN_HIFD08,
+       GPIO_FN_DU0_DG1, GPIO_FN_CTS1_C, GPIO_FN_HRTS0_D, GPIO_FN_TIOC1B_A,
+               GPIO_FN_HIFD09,
+
+       /* IPSR7 */
+       GPIO_FN_DU0_DG2, GPIO_FN_RTS1_C, GPIO_FN_RMII0_MDC_B, GPIO_FN_TIOC2A_A,
+               GPIO_FN_HIFD10,
+       GPIO_FN_DU0_DG3, GPIO_FN_SCK2_C, GPIO_FN_RMII0_MDIO_B, GPIO_FN_TIOC2B_A,
+               GPIO_FN_HIFD11,
+       GPIO_FN_DU0_DG4, GPIO_FN_RX2_C, GPIO_FN_RMII0_CRS_DV_B,
+               GPIO_FN_TIOC3A_A, GPIO_FN_HIFD12,
+       GPIO_FN_DU0_DG5, GPIO_FN_TX2_C, GPIO_FN_RMII0_RX_ER_B,
+               GPIO_FN_TIOC3B_A, GPIO_FN_HIFD13,
+       GPIO_FN_DU0_DG6, GPIO_FN_RX3_C, GPIO_FN_RMII0_RXD0_B,
+               GPIO_FN_TIOC3C_A, GPIO_FN_HIFD14,
+       GPIO_FN_DU0_DG7, GPIO_FN_TX3_C, GPIO_FN_RMII0_RXD1_B,
+               GPIO_FN_TIOC3D_A, GPIO_FN_HIFD15,
+       GPIO_FN_DU0_DB0, GPIO_FN_RX4_C, GPIO_FN_RMII0_TXD_EN_B,
+               GPIO_FN_TIOC4A_A, GPIO_FN_HIFCS,
+       GPIO_FN_DU0_DB1, GPIO_FN_TX4_C, GPIO_FN_RMII0_TXD0_B,
+               GPIO_FN_TIOC4B_A, GPIO_FN_HIFRS,
+       GPIO_FN_DU0_DB2, GPIO_FN_RX5_B, GPIO_FN_RMII0_TXD1_B,
+               GPIO_FN_TIOC4C_A, GPIO_FN_HIFWR,
+       GPIO_FN_DU0_DB3, GPIO_FN_TX5_B, GPIO_FN_TIOC4D_A, GPIO_FN_HIFRD,
+       GPIO_FN_DU0_DB4, GPIO_FN_HIFINT,
+
+       /* IPSR8 */
+       GPIO_FN_DU0_DB5, GPIO_FN_HIFDREQ,
+       GPIO_FN_DU0_DB6, GPIO_FN_HIFRDY,
+       GPIO_FN_DU0_DB7, GPIO_FN_SSI_SCK0_B, GPIO_FN_HIFEBL_B,
+       GPIO_FN_DU0_DOTCLKIN, GPIO_FN_HSPI_CS0_C, GPIO_FN_SSI_WS0_B,
+       GPIO_FN_DU0_DOTCLKOUT, GPIO_FN_HSPI_CLK0_C, GPIO_FN_SSI_SDATA0_B,
+       GPIO_FN_DU0_EXHSYNC_DU0_HSYNC, GPIO_FN_HSPI_TX0_C, GPIO_FN_SSI_SCK1_B,
+       GPIO_FN_DU0_EXVSYNC_DU0_VSYNC, GPIO_FN_HSPI_RX0_C, GPIO_FN_SSI_WS1_B,
+       GPIO_FN_DU0_EXODDF_DU0_ODDF, GPIO_FN_CAN0_RX_B, GPIO_FN_HSCK0_B,
+               GPIO_FN_SSI_SDATA1_B,
+       GPIO_FN_DU0_DISP, GPIO_FN_CAN0_TX_B, GPIO_FN_HRX0_B,
+               GPIO_FN_AUDIO_CLKA_B,
+       GPIO_FN_DU0_CDE, GPIO_FN_HTX0_B, GPIO_FN_AUDIO_CLKB_B,
+               GPIO_FN_LCD_VCPWC_B,
+       GPIO_FN_IRQ0_A, GPIO_FN_HSPI_TX_B, GPIO_FN_RX3_E, GPIO_FN_ET0_ERXD0,
+       GPIO_FN_IRQ1_A, GPIO_FN_HSPI_RX_B, GPIO_FN_TX3_E, GPIO_FN_ET0_ERXD1,
+       GPIO_FN_IRQ2_A, GPIO_FN_CTS0_A, GPIO_FN_HCTS0_B, GPIO_FN_ET0_ERXD2_A,
+       GPIO_FN_IRQ3_A, GPIO_FN_RTS0_A, GPIO_FN_HRTS0_B, GPIO_FN_ET0_ERXD3_A,
+
+       /* IPSR9 */
+       GPIO_FN_VI1_CLK_A, GPIO_FN_FD0_B, GPIO_FN_LCD_DATA0_B,
+       GPIO_FN_VI1_0_A, GPIO_FN_FD1_B, GPIO_FN_LCD_DATA1_B,
+       GPIO_FN_VI1_1_A, GPIO_FN_FD2_B, GPIO_FN_LCD_DATA2_B,
+       GPIO_FN_VI1_2_A, GPIO_FN_FD3_B, GPIO_FN_LCD_DATA3_B,
+       GPIO_FN_VI1_3_A, GPIO_FN_FD4_B, GPIO_FN_LCD_DATA4_B,
+       GPIO_FN_VI1_4_A, GPIO_FN_FD5_B, GPIO_FN_LCD_DATA5_B,
+       GPIO_FN_VI1_5_A, GPIO_FN_FD6_B, GPIO_FN_LCD_DATA6_B,
+       GPIO_FN_VI1_6_A, GPIO_FN_FD7_B, GPIO_FN_LCD_DATA7_B,
+       GPIO_FN_VI1_7_A, GPIO_FN_FCE_B, GPIO_FN_LCD_DATA8_B,
+       GPIO_FN_SSI_SCK0_A, GPIO_FN_TIOC1A_B, GPIO_FN_LCD_DATA9_B,
+       GPIO_FN_SSI_WS0_A, GPIO_FN_TIOC1B_B, GPIO_FN_LCD_DATA10_B,
+       GPIO_FN_SSI_SDATA0_A, GPIO_FN_VI1_0_B, GPIO_FN_TIOC2A_B,
+               GPIO_FN_LCD_DATA11_B,
+       GPIO_FN_SSI_SCK1_A, GPIO_FN_VI1_1_B, GPIO_FN_TIOC2B_B,
+               GPIO_FN_LCD_DATA12_B,
+       GPIO_FN_SSI_WS1_A, GPIO_FN_VI1_2_B, GPIO_FN_LCD_DATA13_B,
+       GPIO_FN_SSI_SDATA1_A, GPIO_FN_VI1_3_B, GPIO_FN_LCD_DATA14_B,
+
+       /* IPSR10 */
+       GPIO_FN_SSI_SCK23, GPIO_FN_VI1_4_B, GPIO_FN_RX1_D, GPIO_FN_FCLE_B,
+               GPIO_FN_LCD_DATA15_B,
+       GPIO_FN_SSI_WS23, GPIO_FN_VI1_5_B, GPIO_FN_TX1_D, GPIO_FN_HSCK0_C,
+               GPIO_FN_FALE_B, GPIO_FN_LCD_DON_B,
+       GPIO_FN_SSI_SDATA2, GPIO_FN_VI1_6_B, GPIO_FN_HRX0_C, GPIO_FN_FRE_B,
+               GPIO_FN_LCD_CL1_B,
+       GPIO_FN_SSI_SDATA3, GPIO_FN_VI1_7_B, GPIO_FN_HTX0_C, GPIO_FN_FWE_B,
+               GPIO_FN_LCD_CL2_B,
+       GPIO_FN_AUDIO_CLKA_A, GPIO_FN_VI1_CLK_B, GPIO_FN_SCK1_D,
+               GPIO_FN_IECLK_B, GPIO_FN_LCD_FLM_B,
+       GPIO_FN_AUDIO_CLKB_A, GPIO_FN_LCD_CLK_B,
+       GPIO_FN_AUDIO_CLKC, GPIO_FN_SCK1_E, GPIO_FN_HCTS0_C, GPIO_FN_FRB_B,
+               GPIO_FN_LCD_VEPWC_B,
+       GPIO_FN_AUDIO_CLKOUT, GPIO_FN_TX1_E, GPIO_FN_HRTS0_C, GPIO_FN_FSE_B,
+               GPIO_FN_LCD_M_DISP_B,
+       GPIO_FN_CAN_CLK_A, GPIO_FN_RX4_D,
+       GPIO_FN_CAN0_TX_A, GPIO_FN_TX4_D, GPIO_FN_MLB_CLK,
+       GPIO_FN_CAN1_RX_A, GPIO_FN_IRQ1_B,
+       GPIO_FN_CAN0_RX_A, GPIO_FN_IRQ0_B, GPIO_FN_MLB_SIG,
+       GPIO_FN_CAN1_TX_A, GPIO_FN_TX5_C, GPIO_FN_MLB_DAT,
+
+       /* IPSR11 */
+       GPIO_FN_SCL1, GPIO_FN_SCIF_CLK_C,
+       GPIO_FN_SDA1, GPIO_FN_RX1_E,
+       GPIO_FN_SDA0, GPIO_FN_HIFEBL_A,
+       GPIO_FN_SDSELF, GPIO_FN_RTS1_E,
+       GPIO_FN_SCIF_CLK_A, GPIO_FN_HSPI_CLK_A, GPIO_FN_VI0_CLK,
+               GPIO_FN_RMII0_TXD0_A, GPIO_FN_ET0_ERXD4,
+       GPIO_FN_SCK0_A, GPIO_FN_HSPI_CS_A, GPIO_FN_VI0_CLKENB,
+               GPIO_FN_RMII0_TXD1_A, GPIO_FN_ET0_ERXD5,
+       GPIO_FN_RX0_A, GPIO_FN_HSPI_RX_A, GPIO_FN_RMII0_RXD0_A,
+               GPIO_FN_ET0_ERXD6,
+       GPIO_FN_TX0_A, GPIO_FN_HSPI_TX_A,
+       GPIO_FN_PENC1, GPIO_FN_TX3_D, GPIO_FN_CAN1_TX_B, GPIO_FN_TX5_D,
+               GPIO_FN_IETX_B,
+       GPIO_FN_USB_OVC1, GPIO_FN_RX3_D, GPIO_FN_CAN1_RX_B, GPIO_FN_RX5_D,
+               GPIO_FN_IERX_B,
+       GPIO_FN_DREQ0, GPIO_FN_SD1_CLK_A, GPIO_FN_ET0_TX_EN,
+       GPIO_FN_DACK0, GPIO_FN_SD1_DAT3_A, GPIO_FN_ET0_TX_ER,
+       GPIO_FN_DREQ1, GPIO_FN_HSPI_CLK_B, GPIO_FN_RX4_B, GPIO_FN_ET0_PHY_INT_C,
+               GPIO_FN_ET0_TX_CLK_A,
+       GPIO_FN_DACK1, GPIO_FN_HSPI_CS_B, GPIO_FN_TX4_B, GPIO_FN_ET0_RX_CLK_A,
+       GPIO_FN_PRESETOUT, GPIO_FN_ST_CLKOUT,
+
+};
+
+#endif /* __ASM_SH7734_H__ */
diff --git a/arch/sh/include/cpu-sh4a/cpu/dma.h b/arch/sh/include/cpu-sh4a/cpu/dma.h
new file mode 100644 (file)
index 0000000..89afb65
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef __ASM_SH_CPU_SH4_DMA_SH7780_H
+#define __ASM_SH_CPU_SH4_DMA_SH7780_H
+
+#include <linux/sh_intc.h>
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7343) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7730)
+#define DMTE0_IRQ      evt2irq(0x800)
+#define DMTE4_IRQ      evt2irq(0xb80)
+#define DMAE0_IRQ      evt2irq(0xbc0)  /* DMA Error IRQ*/
+#define SH_DMAC_BASE0  0xFE008020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+#define DMTE0_IRQ      evt2irq(0x800)
+#define DMTE4_IRQ      evt2irq(0xb80)
+#define DMAE0_IRQ      evt2irq(0xbc0)  /* DMA Error IRQ*/
+#define SH_DMAC_BASE0  0xFE008020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7764)
+#define DMTE0_IRQ      evt2irq(0x640)
+#define DMTE4_IRQ      evt2irq(0x780)
+#define DMAE0_IRQ      evt2irq(0x6c0)
+#define SH_DMAC_BASE0  0xFF608020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
+#define DMTE0_IRQ      evt2irq(0x800)  /* DMAC0A*/
+#define DMTE4_IRQ      evt2irq(0xb80)  /* DMAC0B */
+#define DMTE6_IRQ      evt2irq(0x700)
+#define DMTE8_IRQ      evt2irq(0x740)  /* DMAC1A */
+#define DMTE9_IRQ      evt2irq(0x760)
+#define DMTE10_IRQ     evt2irq(0xb00)  /* DMAC1B */
+#define DMTE11_IRQ     evt2irq(0xb20)
+#define DMAE0_IRQ      evt2irq(0xbc0)  /* DMA Error IRQ*/
+#define DMAE1_IRQ      evt2irq(0xb40)  /* DMA Error IRQ*/
+#define SH_DMAC_BASE0  0xFE008020
+#define SH_DMAC_BASE1  0xFDC08020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
+#define DMTE0_IRQ      evt2irq(0x800)  /* DMAC0A*/
+#define DMTE4_IRQ      evt2irq(0xb80)  /* DMAC0B */
+#define DMTE6_IRQ      evt2irq(0x700)
+#define DMTE8_IRQ      evt2irq(0x740)  /* DMAC1A */
+#define DMTE9_IRQ      evt2irq(0x760)
+#define DMTE10_IRQ     evt2irq(0xb00)  /* DMAC1B */
+#define DMTE11_IRQ     evt2irq(0xb20)
+#define DMAE0_IRQ      evt2irq(0xbc0)  /* DMA Error IRQ*/
+#define DMAE1_IRQ      evt2irq(0xb40)  /* DMA Error IRQ*/
+#define SH_DMAC_BASE0  0xFE008020
+#define SH_DMAC_BASE1  0xFDC08020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+#define DMTE0_IRQ      evt2irq(0x640)
+#define DMTE4_IRQ      evt2irq(0x780)
+#define DMTE6_IRQ      evt2irq(0x7c0)
+#define DMTE8_IRQ      evt2irq(0xd80)
+#define DMTE9_IRQ      evt2irq(0xda0)
+#define DMTE10_IRQ     evt2irq(0xdc0)
+#define DMTE11_IRQ     evt2irq(0xde0)
+#define DMAE0_IRQ      evt2irq(0x6c0)  /* DMA Error IRQ */
+#define SH_DMAC_BASE0  0xFC808020
+#define SH_DMAC_BASE1  0xFC818020
+#else /* SH7785 */
+#define DMTE0_IRQ      evt2irq(0x620)
+#define DMTE4_IRQ      evt2irq(0x6a0)
+#define DMTE6_IRQ      evt2irq(0x880)
+#define DMTE8_IRQ      evt2irq(0x8c0)
+#define DMTE9_IRQ      evt2irq(0x8e0)
+#define DMTE10_IRQ     evt2irq(0x900)
+#define DMTE11_IRQ     evt2irq(0x920)
+#define DMAE0_IRQ      evt2irq(0x6e0)  /* DMA Error IRQ0 */
+#define DMAE1_IRQ      evt2irq(0x940)  /* DMA Error IRQ1 */
+#define SH_DMAC_BASE0  0xFC808020
+#define SH_DMAC_BASE1  0xFCC08020
+#endif
+
+#endif /* __ASM_SH_CPU_SH4_DMA_SH7780_H */
diff --git a/arch/sh/include/cpu-sh5/cpu/dma.h b/arch/sh/include/cpu-sh5/cpu/dma.h
deleted file mode 100644 (file)
index 7bf6bb3..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_SH_CPU_SH5_DMA_H
-#define __ASM_SH_CPU_SH5_DMA_H
-
-/* Nothing yet */
-
-#endif /* __ASM_SH_CPU_SH5_DMA_H */
index bcc301ac12f4b07e7d7424717b5d278ce1e48cdc..6aaaf8596e6a823c0c17b74bb55849e46e97818d 100644 (file)
@@ -9,10 +9,11 @@
  * for more details.
  *
  */
+#include <linux/sh_intc.h>
 
-#define HP680_BTN_IRQ          32      /* IRQ0_IRQ */
-#define HP680_TS_IRQ           35      /* IRQ3_IRQ */
-#define HP680_HD64461_IRQ      36      /* IRQ4_IRQ */
+#define HP680_BTN_IRQ          evt2irq(0x600)  /* IRQ0_IRQ */
+#define HP680_TS_IRQ           evt2irq(0x660)  /* IRQ3_IRQ */
+#define HP680_HD64461_IRQ      evt2irq(0x680)  /* IRQ4_IRQ */
 
 #define DAC_LCD_BRIGHTNESS     0
 #define DAC_SPEAKER_VOLUME     1
index e6d160504923c2620d1c87f1288ce20895dff265..3a4dcc5c74eea28187046d39af6ce3c946706b81 100644 (file)
  * for more details.
  *
  */
+#include <linux/sh_intc.h>
 
-#define IRQ_CF1                9       /* CF1 */
-#define IRQ_CF0                10      /* CF0 */
-#define IRQ_INTD       11      /* INTD */
-#define IRQ_ETH1       12      /* Ether1 */
-#define IRQ_ETH0       13      /* Ether0 */
-#define IRQ_INTA       14      /* INTA */
+#define IRQ_CF1                evt2irq(0x320)  /* CF1 */
+#define IRQ_CF0                evt2irq(0x340)  /* CF0 */
+#define IRQ_INTD       evt2irq(0x360)  /* INTD */
+#define IRQ_ETH1       evt2irq(0x380)  /* Ether1 */
+#define IRQ_ETH0       evt2irq(0x3a0)  /* Ether0 */
+#define IRQ_INTA       evt2irq(0x3c0)  /* INTA */
 
 void init_lboxre2_IRQ(void);
 
index 697dc865f21b6ed038c2f7e84542566691727460..ce64e02e9b50f462dc4e3706bf7076462d39c194 100644 (file)
@@ -11,6 +11,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
+#include <linux/sh_intc.h>
 #include <asm/addrspace.h>
 
 /* Box specific addresses.  */
@@ -67,9 +68,9 @@
 
 #define SDK7780_NR_IRL                 15
 /* IDE/ATA interrupt */
-#define IRQ_CFCARD                             14
+#define IRQ_CFCARD                     evt2irq(0x3c0)
 /* SMC interrupt */
-#define IRQ_ETHERNET                   6
+#define IRQ_ETHERNET                   evt2irq(0x2c0)
 
 
 /* arch/sh/boards/renesas/sdk7780/irq.c */
index 4a674d27cbb8f4931b0d54dfbb5a52e4dd22ecd6..fa3cd801cf2ea37c866313f3620565ccd9c26320 100644 (file)
@@ -4,14 +4,16 @@
 #ifndef _ASM_SH_TITAN_H
 #define _ASM_SH_TITAN_H
 
+#include <linux/sh_intc.h>
+
 #define __IO_PREFIX titan
 #include <asm/io_generic.h>
 
 /* IRQ assignments */
-#define TITAN_IRQ_WAN          2       /* eth0 (WAN) */
-#define TITAN_IRQ_LAN          5       /* eth1 (LAN) */
-#define TITAN_IRQ_MPCIA                8       /* mPCI A */
-#define TITAN_IRQ_MPCIB                11      /* mPCI B */
-#define TITAN_IRQ_USB          11      /* USB */
+#define TITAN_IRQ_WAN          evt2irq(0x240)  /* eth0 (WAN) */
+#define TITAN_IRQ_LAN          evt2irq(0x2a0)  /* eth1 (LAN) */
+#define TITAN_IRQ_MPCIA                evt2irq(0x300)  /* mPCI A */
+#define TITAN_IRQ_MPCIB                evt2irq(0x360)  /* mPCI B */
+#define TITAN_IRQ_USB          evt2irq(0x360)  /* USB */
 
 #endif /* __ASM_SH_TITAN_H */
index ddd68e7887054f2a8ca344d3e8e2ae4d038af059..1dbfdf701c9de0e16fc1b318f87e5bb414954c02 100644 (file)
@@ -11,9 +11,7 @@
 #define __ASM_SH_DREAMCAST_DMA_H
 
 /* Number of DMA channels */
-#define ONCHIP_NR_DMA_CHANNELS 4
 #define G2_NR_DMA_CHANNELS     4
-#define PVR2_NR_DMA_CHANNELS   1
 
 /* Channels for cascading */
 #define PVR2_CASCADE_CHAN      2
index f432773a957187e93524ca2b5222056632d26f3c..ceeea48cc7af8846a47b8d880d6dcb14f39c3d47 100644 (file)
@@ -8,6 +8,7 @@
  *
  * IO-DATA LANDISK support
  */
+#include <linux/sh_intc.h>
 
 /* Box specific addresses.  */
 
 #define PA_PIDE_OFFSET 0x40            /* CF IDE Offset */
 #define PA_SIDE_OFFSET 0x40            /* HDD IDE Offset */
 
-#define IRQ_PCIINTA    5               /* PCI INTA IRQ */
-#define IRQ_PCIINTB    6               /* PCI INTB IRQ */
-#define IRQ_PCIINTC    7               /* PCI INTC IRQ */
-#define IRQ_PCIINTD    8               /* PCI INTD IRQ */
-#define IRQ_ATA                9               /* ATA IRQ */
-#define IRQ_FATA       10              /* FATA IRQ */
-#define IRQ_POWER      11              /* Power Switch IRQ */
-#define IRQ_BUTTON     12              /* USL-5P Button IRQ */
-#define IRQ_FAULT      13              /* USL-5P Fault  IRQ */
+#define IRQ_PCIINTA    evt2irq(0x2a0)  /* PCI INTA IRQ */
+#define IRQ_PCIINTB    evt2irq(0x2c0)  /* PCI INTB IRQ */
+#define IRQ_PCIINTC    evt2irq(0x2e0)  /* PCI INTC IRQ */
+#define IRQ_PCIINTD    evt2irq(0x300)  /* PCI INTD IRQ */
+#define IRQ_ATA                evt2irq(0x320)  /* ATA IRQ */
+#define IRQ_FATA       evt2irq(0x340)  /* FATA IRQ */
+#define IRQ_POWER      evt2irq(0x360)  /* Power Switch IRQ */
+#define IRQ_BUTTON     evt2irq(0x380)  /* USL-5P Button IRQ */
+#define IRQ_FAULT      evt2irq(0x3a0)  /* USL-5P Fault  IRQ */
 
 void init_landisk_IRQ(void);
 
index 14be91c5a2f0f7f1c062d6afbe8aac38cf1ea953..8a6d44b4987b393867b4213b13df548203dfce6c 100644 (file)
@@ -8,6 +8,7 @@
  *
  * Hitachi SolutionEngine support
  */
+#include <linux/sh_intc.h>
 
 /* Box specific addresses.  */
 
 #define INTC_IPRD       0xa4000018UL
 #define INTC_IPRE       0xa400001aUL
 
-#define IRQ0_IRQ        32
-#define IRQ1_IRQ        33
+#define IRQ0_IRQ        evt2irq(0x600)
+#define IRQ1_IRQ        evt2irq(0x620)
 #endif
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7705)
-#define IRQ_STNIC      12
-#define IRQ_CFCARD     14
+#define IRQ_STNIC      evt2irq(0x380)
+#define IRQ_CFCARD     evt2irq(0x3c0)
 #else
-#define IRQ_STNIC      10
-#define IRQ_CFCARD     7
+#define IRQ_STNIC      evt2irq(0x340)
+#define IRQ_CFCARD     evt2irq(0x2e0)
 #endif
 
 /* SH Ether support (SH7710/SH7712) */
 # define PHY_ID 0x01
 #endif
 /* Ether IRQ */
-#define SH_ETH0_IRQ    80
-#define SH_ETH1_IRQ    81
-#define SH_TSU_IRQ     82
+#define SH_ETH0_IRQ    evt2irq(0xc00)
+#define SH_ETH1_IRQ    evt2irq(0xc20)
+#define SH_TSU_IRQ     evt2irq(0xc40)
 
 void init_se_IRQ(void);
 
index 8d8170d6cc43dbbb189055c6195f9f5748e2f62d..50b5d575dff090ccf0b081e3ab4b41fb98cd976c 100644 (file)
@@ -8,6 +8,7 @@
  *
  * SH-Mobile SolutionEngine 7343 support
  */
+#include <linux/sh_intc.h>
 
 /* Box specific addresses.  */
 
 #define FPGA_IN                0xb1400000
 #define FPGA_OUT       0xb1400002
 
-#define IRQ0_IRQ        32
-#define IRQ1_IRQ        33
-#define IRQ4_IRQ        36
-#define IRQ5_IRQ        37
+#define IRQ0_IRQ        evt2irq(0x600)
+#define IRQ1_IRQ        evt2irq(0x620)
+#define IRQ4_IRQ        evt2irq(0x680)
+#define IRQ5_IRQ        evt2irq(0x6a0)
 
 #define SE7343_FPGA_IRQ_MRSHPC0        0
 #define SE7343_FPGA_IRQ_MRSHPC1        1
index b957f60411938dfb3a07ce71aa821a77e4b45d23..eabd0538de44137dc445e70fb4025a8ebbe6629b 100644 (file)
@@ -11,6 +11,8 @@
 
 #ifndef __ASM_SH_SE7721_H
 #define __ASM_SH_SE7721_H
+
+#include <linux/sh_intc.h>
 #include <asm/addrspace.h>
 
 /* Box specific addresses. */
@@ -49,9 +51,9 @@
 #define MRSHPC_PCIC_INFO       (PA_MRSHPC + 30)
 
 #define PA_LED         0xB6800000      /* 8bit LED */
-#define PA_FPGA                0xB7000000      /* FPGA base address */
+#define PA_FPGA                0xB7000000      /* FPGA base address */
 
-#define MRSHPC_IRQ0    10
+#define MRSHPC_IRQ0    evt2irq(0x340)
 
 #define FPGA_ILSR1     (PA_FPGA + 0x02)
 #define FPGA_ILSR2     (PA_FPGA + 0x03)
index 16505bfb8a9e5443ccc5b6102565f444d671dc47..201081ebdbce7f8ef881a591d23029f93777739e 100644 (file)
@@ -13,6 +13,7 @@
  * for more details.
  *
  */
+#include <linux/sh_intc.h>
 #include <asm/addrspace.h>
 
 /* Box specific addresses.  */
@@ -31,7 +32,7 @@
 
 #define PA_PERIPHERAL  0xB0000000
 
-#define PA_PCIC         PA_PERIPHERAL                  /* MR-SHPC-01 PCMCIA */
+#define PA_PCIC         PA_PERIPHERAL          /* MR-SHPC-01 PCMCIA */
 #define PA_MRSHPC       (PA_PERIPHERAL + 0x003fffe0)    /* MR-SHPC-01 PCMCIA controller */
 #define PA_MRSHPC_MW1   (PA_PERIPHERAL + 0x00400000)    /* MR-SHPC-01 memory window base */
 #define PA_MRSHPC_MW2   (PA_PERIPHERAL + 0x00500000)    /* MR-SHPC-01 attribute window base */
@@ -51,7 +52,7 @@
 #define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
 
 #define PA_LED         (PA_PERIPHERAL + 0x00800000)    /* 8bit LED */
-#define PA_FPGA                (PA_PERIPHERAL + 0x01800000)    /* FPGA base address */
+#define PA_FPGA                (PA_PERIPHERAL + 0x01800000)    /* FPGA base address */
 
 #define PA_LAN         (PA_AREA6_IO + 0)               /* SMC LAN91C111 */
 /* GPIO */
@@ -77,8 +78,8 @@
 #define PORT_HIZCRC     0xA405015CUL
 
 /* IRQ */
-#define IRQ0_IRQ        32
-#define IRQ1_IRQ        33
+#define IRQ0_IRQ        evt2irq(0x600)
+#define IRQ1_IRQ        evt2irq(0x620)
 
 #define IRQ01_MODE      0xb1800000
 #define IRQ01_STS       0xb1800004
index 29514a39d0f5135afe8ba400a262e2ec77f72f49..be842dd1ca0281f15213b9c841720a1b8108215f 100644 (file)
@@ -18,6 +18,7 @@
  * for more details.
  *
  */
+#include <linux/sh_intc.h>
 #include <asm/addrspace.h>
 
 /* SH Eth */
@@ -35,9 +36,9 @@
 #define IRQ2_MR                (0xba200028)
 
 /* IRQ */
-#define IRQ0_IRQ        32
-#define IRQ1_IRQ        33
-#define IRQ2_IRQ        34
+#define IRQ0_IRQ        evt2irq(0x600)
+#define IRQ1_IRQ        evt2irq(0x620)
+#define IRQ2_IRQ        evt2irq(0x640)
 
 /* Bits in IRQ012 registers */
 #define SE7724_FPGA_IRQ_BASE   220
index b36792ac5d6601827dd56f22ea7de6ec63fb7fa6..271871793d59c3b4c4d110f5c1cb259de0c20367 100644 (file)
@@ -11,6 +11,7 @@
  * Modified for 7751 Solution Engine by
  * Ian da Silva and Jeremy Siegel, 2001.
  */
+#include <linux/sh_intc.h>
 
 /* Box specific addresses.  */
 
@@ -63,7 +64,7 @@
 #define BCR_ILCRF      (PA_BCR + 10)
 #define BCR_ILCRG      (PA_BCR + 12)
 
-#define IRQ_79C973     13
+#define IRQ_79C973     evt2irq(0x3a0)
 
 void init_7751se_IRQ(void);
 
index 40e9b41458cd62b07084bf963089de53339740a1..bde357cf81bd19514c20ffc4144974dc88852b12 100644 (file)
@@ -12,6 +12,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
+#include <linux/sh_intc.h>
 #include <asm/addrspace.h>
 
 /* Box specific addresses.  */
 #define IRQPOS_PCCPW            (0 * 4)
 
 /* IDE interrupt */
-#define IRQ_IDE0                67 /* iVDR */
+#define IRQ_IDE0                evt2irq(0xa60) /* iVDR */
 
 /* SMC interrupt */
-#define SMC_IRQ                 8
+#define SMC_IRQ                 evt2irq(0x300)
 
 /* SM501 interrupt */
-#define SM501_IRQ               0
+#define SM501_IRQ               evt2irq(0x200)
 
 /* interrupt pin */
 #define IRQPIN_EXTINT1          0 /* IRQ0 pin */
index f47be8727b3bc9b41f930ea7938679df2e21f001..9e6624c9108bcf77bbc525909195c2a0cb6e5d69 100644 (file)
@@ -7,6 +7,7 @@
 static const char *cpu_name[] = {
        [CPU_SH7201]    = "SH7201",
        [CPU_SH7203]    = "SH7203",     [CPU_SH7263]    = "SH7263",
+       [CPU_SH7264]    = "SH7264",     [CPU_SH7269]    = "SH7269",
        [CPU_SH7206]    = "SH7206",     [CPU_SH7619]    = "SH7619",
        [CPU_SH7705]    = "SH7705",     [CPU_SH7706]    = "SH7706",
        [CPU_SH7707]    = "SH7707",     [CPU_SH7708]    = "SH7708",
@@ -25,7 +26,8 @@ static const char *cpu_name[] = {
        [CPU_SH5_101]   = "SH5-101",    [CPU_SH5_103]   = "SH5-103",
        [CPU_MXG]       = "MX-G",       [CPU_SH7723]    = "SH7723",
        [CPU_SH7366]    = "SH7366",     [CPU_SH7724]    = "SH7724",
-       [CPU_SH7372]    = "SH7372",     [CPU_SH_NONE]   = "Unknown"
+       [CPU_SH7372]    = "SH7372",     [CPU_SH7734]    = "SH7734",
+       [CPU_SH_NONE]   = "Unknown"
 };
 
 const char *get_cpu_subtype(struct sh_cpuinfo *c)
index 0f8befccf9fad37116e12172baf93184051da20f..e0b740c831c7e172f42beb3c8ce957d9a22bb032 100644 (file)
@@ -65,7 +65,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 88, 88, 88, 88 },
+       .irqs           = SCIx_IRQ_MUXED(88),
 };
 
 static struct platform_device scif0_device = {
@@ -82,7 +82,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 92, 92, 92, 92 },
+       .irqs           = SCIx_IRQ_MUXED(92),
 };
 
 static struct platform_device scif1_device = {
@@ -99,7 +99,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 96, 96, 96, 96 },
+       .irqs           = SCIx_IRQ_MUXED(96),
 };
 
 static struct platform_device scif2_device = {
index 45f85c77ef75dc614940c4bdab0d18573a53b8bc..7fdc102d0dd65572149abfface163e58468f6512 100644 (file)
@@ -11,10 +11,14 @@ obj-$(CONFIG_SH_FPU)        += fpu.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7201)       += setup-sh7201.o clock-sh7201.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7203)       += setup-sh7203.o clock-sh7203.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7263)       += setup-sh7203.o clock-sh7203.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7264)       += setup-sh7264.o clock-sh7264.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7206)       += setup-sh7206.o clock-sh7206.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7269)       += setup-sh7269.o clock-sh7269.o
 obj-$(CONFIG_CPU_SUBTYPE_MXG)          += setup-mxg.o clock-sh7206.o
 
 # Pinmux setup
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7203)    := pinmux-sh7203.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SH7264)    := pinmux-sh7264.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SH7269)    := pinmux-sh7269.o
 
 obj-$(CONFIG_GENERIC_GPIO)     += $(pinmux-y)
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7264.c b/arch/sh/kernel/cpu/sh2a/clock-sh7264.c
new file mode 100644 (file)
index 0000000..fdf585c
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/clock-sh7264.c
+ *
+ * SH7264 clock framework support
+ *
+ * Copyright (C) 2012  Phil Edworthy
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <asm/clock.h>
+
+/* SH7264 registers */
+#define FRQCR          0xfffe0010
+#define STBCR3         0xfffe0408
+#define STBCR4         0xfffe040c
+#define STBCR5         0xfffe0410
+#define STBCR6         0xfffe0414
+#define STBCR7         0xfffe0418
+#define STBCR8         0xfffe041c
+
+static const unsigned int pll1rate[] = {8, 12};
+
+static unsigned int pll1_div;
+
+/* Fixed 32 KHz root clock for RTC */
+static struct clk r_clk = {
+       .rate           = 32768,
+};
+
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+       .rate           = 18000000,
+};
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+       unsigned long rate = clk->parent->rate / pll1_div;
+       return rate * pll1rate[(__raw_readw(FRQCR) >> 8) & 1];
+}
+
+static struct sh_clk_ops pll_clk_ops = {
+       .recalc         = pll_recalc,
+};
+
+static struct clk pll_clk = {
+       .ops            = &pll_clk_ops,
+       .parent         = &extal_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+struct clk *main_clks[] = {
+       &r_clk,
+       &extal_clk,
+       &pll_clk,
+};
+
+static int div2[] = { 1, 2, 3, 4, 6, 8, 12 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+       .divisors = div2,
+       .nr_divisors = ARRAY_SIZE(div2),
+};
+
+static struct clk_div4_table div4_table = {
+       .div_mult_table = &div4_div_mult_table,
+};
+
+enum { DIV4_I, DIV4_P,
+       DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+  SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
+
+/* The mask field specifies the div2 entries that are valid */
+struct clk div4_clks[DIV4_NR] = {
+       [DIV4_I] = DIV4(FRQCR, 4, 0x7,  CLK_ENABLE_REG_16BIT
+                                       | CLK_ENABLE_ON_INIT),
+       [DIV4_P] = DIV4(FRQCR, 0, 0x78, CLK_ENABLE_REG_16BIT),
+};
+
+enum { MSTP77, MSTP74, MSTP72,
+       MSTP60,
+       MSTP35, MSTP34, MSTP33, MSTP32, MSTP30,
+       MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+       [MSTP77] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 7, 0), /* SCIF */
+       [MSTP74] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 4, 0), /* VDC */
+       [MSTP72] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 2, 0), /* CMT */
+       [MSTP60] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR6, 0, 0), /* USB */
+       [MSTP35] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 6, 0), /* MTU2 */
+       [MSTP34] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 4, 0), /* SDHI0 */
+       [MSTP33] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 3, 0), /* SDHI1 */
+       [MSTP32] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 2, 0), /* ADC */
+       [MSTP30] = SH_CLK_MSTP8(&r_clk, STBCR3, 0, 0),  /* RTC */
+};
+
+static struct clk_lookup lookups[] = {
+       /* main clocks */
+       CLKDEV_CON_ID("rclk", &r_clk),
+       CLKDEV_CON_ID("extal", &extal_clk),
+       CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+       /* DIV4 clocks */
+       CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+       CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+
+       /* MSTP clocks */
+       CLKDEV_CON_ID("sci_ick", &mstp_clks[MSTP77]),
+       CLKDEV_CON_ID("vdc3", &mstp_clks[MSTP74]),
+       CLKDEV_CON_ID("cmt_fck", &mstp_clks[MSTP72]),
+       CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
+       CLKDEV_CON_ID("mtu2_fck", &mstp_clks[MSTP35]),
+       CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP34]),
+       CLKDEV_CON_ID("sdhi1", &mstp_clks[MSTP33]),
+       CLKDEV_CON_ID("adc0", &mstp_clks[MSTP32]),
+       CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP30]),
+};
+
+int __init arch_clk_init(void)
+{
+       int k, ret = 0;
+
+       if (test_mode_pin(MODE_PIN0)) {
+               if (test_mode_pin(MODE_PIN1))
+                       pll1_div = 3;
+               else
+                       pll1_div = 4;
+       } else
+               pll1_div = 1;
+
+       for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+               ret = clk_register(main_clks[k]);
+
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+       if (!ret)
+               ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
+
+       return ret;
+}
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7269.c b/arch/sh/kernel/cpu/sh2a/clock-sh7269.c
new file mode 100644 (file)
index 0000000..6b78762
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/clock-sh7269.c
+ *
+ * SH7269 clock framework support
+ *
+ * Copyright (C) 2012  Phil Edworthy
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <asm/clock.h>
+
+/* SH7269 registers */
+#define FRQCR          0xfffe0010
+#define STBCR3                 0xfffe0408
+#define STBCR4                 0xfffe040c
+#define STBCR5                 0xfffe0410
+#define STBCR6                 0xfffe0414
+#define STBCR7                 0xfffe0418
+
+#define PLL_RATE 20
+
+/* Fixed 32 KHz root clock for RTC */
+static struct clk r_clk = {
+       .rate           = 32768,
+};
+
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+       .rate           = 13340000,
+};
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+       return clk->parent->rate * PLL_RATE;
+}
+
+static struct sh_clk_ops pll_clk_ops = {
+       .recalc         = pll_recalc,
+};
+
+static struct clk pll_clk = {
+       .ops            = &pll_clk_ops,
+       .parent         = &extal_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+static unsigned long peripheral0_recalc(struct clk *clk)
+{
+       return clk->parent->rate / 8;
+}
+
+static struct sh_clk_ops peripheral0_clk_ops = {
+       .recalc         = peripheral0_recalc,
+};
+
+static struct clk peripheral0_clk = {
+       .ops            = &peripheral0_clk_ops,
+       .parent         = &pll_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+static unsigned long peripheral1_recalc(struct clk *clk)
+{
+       return clk->parent->rate / 4;
+}
+
+static struct sh_clk_ops peripheral1_clk_ops = {
+       .recalc         = peripheral1_recalc,
+};
+
+static struct clk peripheral1_clk = {
+       .ops            = &peripheral1_clk_ops,
+       .parent         = &pll_clk,
+       .flags          = CLK_ENABLE_ON_INIT,
+};
+
+struct clk *main_clks[] = {
+       &r_clk,
+       &extal_clk,
+       &pll_clk,
+       &peripheral0_clk,
+       &peripheral1_clk,
+};
+
+static int div2[] = { 1, 2, 0, 4 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+       .divisors = div2,
+       .nr_divisors = ARRAY_SIZE(div2),
+};
+
+static struct clk_div4_table div4_table = {
+       .div_mult_table = &div4_div_mult_table,
+};
+
+enum { DIV4_I, DIV4_B,
+       DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+  SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
+
+/* The mask field specifies the div2 entries that are valid */
+struct clk div4_clks[DIV4_NR] = {
+       [DIV4_I]  = DIV4(FRQCR, 8, 0xB, CLK_ENABLE_REG_16BIT
+                                       | CLK_ENABLE_ON_INIT),
+       [DIV4_B]  = DIV4(FRQCR, 4, 0xA, CLK_ENABLE_REG_16BIT
+                                       | CLK_ENABLE_ON_INIT),
+};
+
+enum { MSTP72,
+       MSTP60,
+       MSTP47, MSTP46, MSTP45, MSTP44, MSTP43, MSTP42, MSTP41, MSTP40,
+       MSTP35, MSTP32, MSTP30,
+       MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+       [MSTP72] = SH_CLK_MSTP8(&peripheral0_clk, STBCR7, 2, 0), /* CMT */
+       [MSTP60] = SH_CLK_MSTP8(&peripheral1_clk, STBCR6, 0, 0), /* USB */
+       [MSTP47] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 7, 0), /* SCIF0 */
+       [MSTP46] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 6, 0), /* SCIF1 */
+       [MSTP45] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 5, 0), /* SCIF2 */
+       [MSTP44] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 4, 0), /* SCIF3 */
+       [MSTP43] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 3, 0), /* SCIF4 */
+       [MSTP42] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 2, 0), /* SCIF5 */
+       [MSTP41] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 1, 0), /* SCIF6 */
+       [MSTP40] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 0, 0), /* SCIF7 */
+       [MSTP35] = SH_CLK_MSTP8(&peripheral0_clk, STBCR3, 5, 0), /* MTU2 */
+       [MSTP32] = SH_CLK_MSTP8(&peripheral1_clk, STBCR3, 2, 0), /* ADC */
+       [MSTP30] = SH_CLK_MSTP8(&r_clk, STBCR3, 0, 0), /* RTC */
+};
+
+static struct clk_lookup lookups[] = {
+       /* main clocks */
+       CLKDEV_CON_ID("rclk", &r_clk),
+       CLKDEV_CON_ID("extal", &extal_clk),
+       CLKDEV_CON_ID("pll_clk", &pll_clk),
+       CLKDEV_CON_ID("peripheral_clk", &peripheral1_clk),
+
+       /* DIV4 clocks */
+       CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+       CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
+
+       /* MSTP clocks */
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP47]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP46]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP45]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP44]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP43]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP42]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.6", &mstp_clks[MSTP41]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.7", &mstp_clks[MSTP40]),
+       CLKDEV_CON_ID("cmt_fck", &mstp_clks[MSTP72]),
+       CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
+       CLKDEV_CON_ID("mtu2_fck", &mstp_clks[MSTP35]),
+       CLKDEV_CON_ID("adc0", &mstp_clks[MSTP32]),
+       CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP30]),
+};
+
+int __init arch_clk_init(void)
+{
+       int k, ret = 0;
+
+       for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+               ret = clk_register(main_clks[k]);
+
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+       if (!ret)
+               ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
+
+       return ret;
+}
diff --git a/arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c b/arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c
new file mode 100644 (file)
index 0000000..b055b55
--- /dev/null
@@ -0,0 +1,2136 @@
+/*
+ * SH7264 Pinmux
+ *
+ *  Copyright (C) 2012  Renesas Electronics Europe Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7264.h>
+
+enum {
+       PINMUX_RESERVED = 0,
+
+       PINMUX_DATA_BEGIN,
+       /* Port A */
+       PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+       /* Port B */
+       PB22_DATA, PB21_DATA, PB20_DATA,
+       PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA,
+       PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+       PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+       PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+       PB3_DATA, PB2_DATA, PB1_DATA,
+       /* Port C */
+       PC10_DATA, PC9_DATA, PC8_DATA,
+       PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+       PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+       /* Port D */
+       PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+       PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+       PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+       PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+       /* Port E */
+       PE5_DATA, PE4_DATA,
+       PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+       /* Port F */
+       PF12_DATA,
+       PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+       PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+       PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+       /* Port G */
+       PG24_DATA,
+       PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+       PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA,
+       PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+       PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+       PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+       PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+       /* Port H */
+       /* NOTE - Port H does not have a Data Register, but PH Data is
+          connected to PH Port Register */
+       PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+       PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+       /* Port I - not on device */
+       /* Port J */
+       PJ12_DATA,
+       PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+       PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+       PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA,
+       /* Port K */
+       PK12_DATA,
+       PK11_DATA, PK10_DATA, PK9_DATA, PK8_DATA,
+       PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
+       PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA,
+       PINMUX_DATA_END,
+
+       PINMUX_INPUT_BEGIN,
+       FORCE_IN,
+       /* Port A */
+       PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+       /* Port B */
+       PB22_IN, PB21_IN, PB20_IN,
+       PB19_IN, PB18_IN, PB17_IN, PB16_IN,
+       PB15_IN, PB14_IN, PB13_IN, PB12_IN,
+       PB11_IN, PB10_IN, PB9_IN, PB8_IN,
+       PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+       PB3_IN, PB2_IN, PB1_IN,
+       /* Port C */
+       PC10_IN, PC9_IN, PC8_IN,
+       PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+       PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+       /* Port D */
+       PD15_IN, PD14_IN, PD13_IN, PD12_IN,
+       PD11_IN, PD10_IN, PD9_IN, PD8_IN,
+       PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+       PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+       /* Port E */
+       PE5_IN, PE4_IN,
+       PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+       /* Port F */
+       PF12_IN,
+       PF11_IN, PF10_IN, PF9_IN, PF8_IN,
+       PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+       PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+       /* Port G */
+       PG24_IN,
+       PG23_IN, PG22_IN, PG21_IN, PG20_IN,
+       PG19_IN, PG18_IN, PG17_IN, PG16_IN,
+       PG15_IN, PG14_IN, PG13_IN, PG12_IN,
+       PG11_IN, PG10_IN, PG9_IN, PG8_IN,
+       PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+       PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+       /* Port H - Port H does not have a Data Register */
+       /* Port I - not on device */
+       /* Port J */
+       PJ12_IN,
+       PJ11_IN, PJ10_IN, PJ9_IN, PJ8_IN,
+       PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
+       PJ3_IN, PJ2_IN, PJ1_IN, PJ0_IN,
+       /* Port K */
+       PK12_IN,
+       PK11_IN, PK10_IN, PK9_IN, PK8_IN,
+       PK7_IN, PK6_IN, PK5_IN, PK4_IN,
+       PK3_IN, PK2_IN, PK1_IN, PK0_IN,
+       PINMUX_INPUT_END,
+
+       PINMUX_OUTPUT_BEGIN,
+       FORCE_OUT,
+       /* Port A */
+       PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
+       /* Port B */
+       PB22_OUT, PB21_OUT, PB20_OUT,
+       PB19_OUT, PB18_OUT, PB17_OUT, PB16_OUT,
+       PB15_OUT, PB14_OUT, PB13_OUT, PB12_OUT,
+       PB11_OUT, PB10_OUT, PB9_OUT, PB8_OUT,
+       PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+       PB3_OUT, PB2_OUT, PB1_OUT,
+       /* Port C */
+       PC10_OUT, PC9_OUT, PC8_OUT,
+       PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+       PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+       /* Port D */
+       PD15_OUT, PD14_OUT, PD13_OUT, PD12_OUT,
+       PD11_OUT, PD10_OUT, PD9_OUT, PD8_OUT,
+       PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+       PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+       /* Port E */
+       PE5_OUT, PE4_OUT,
+       PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+       /* Port F */
+       PF12_OUT,
+       PF11_OUT, PF10_OUT, PF9_OUT, PF8_OUT,
+       PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+       PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+       /* Port G */
+       PG24_OUT,
+       PG23_OUT, PG22_OUT, PG21_OUT, PG20_OUT,
+       PG19_OUT, PG18_OUT, PG17_OUT, PG16_OUT,
+       PG15_OUT, PG14_OUT, PG13_OUT, PG12_OUT,
+       PG11_OUT, PG10_OUT, PG9_OUT, PG8_OUT,
+       PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+       PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+       /* Port H - Port H does not have a Data Register */
+       /* Port I - not on device */
+       /* Port J */
+       PJ12_OUT,
+       PJ11_OUT, PJ10_OUT, PJ9_OUT, PJ8_OUT,
+       PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
+       PJ3_OUT, PJ2_OUT, PJ1_OUT, PJ0_OUT,
+       /* Port K */
+       PK12_OUT,
+       PK11_OUT, PK10_OUT, PK9_OUT, PK8_OUT,
+       PK7_OUT, PK6_OUT, PK5_OUT, PK4_OUT,
+       PK3_OUT, PK2_OUT, PK1_OUT, PK0_OUT,
+       PINMUX_OUTPUT_END,
+
+       PINMUX_FUNCTION_BEGIN,
+       /* Port A */
+       PA3_IOR_IN, PA3_IOR_OUT,
+       PA2_IOR_IN, PA2_IOR_OUT,
+       PA1_IOR_IN, PA1_IOR_OUT,
+       PA0_IOR_IN, PA0_IOR_OUT,
+
+       /* Port B */
+       PB11_IOR_IN, PB11_IOR_OUT,
+       PB10_IOR_IN, PB10_IOR_OUT,
+       PB9_IOR_IN, PB9_IOR_OUT,
+       PB8_IOR_IN, PB8_IOR_OUT,
+
+       PB22MD_00, PB22MD_01, PB22MD_10,
+       PB21MD_0, PB21MD_1,
+       PB20MD_0, PB20MD_1,
+       PB19MD_00, PB19MD_01, PB19MD_10, PB19MD_11,
+       PB18MD_00, PB18MD_01, PB18MD_10, PB18MD_11,
+       PB17MD_00, PB17MD_01, PB17MD_10, PB17MD_11,
+       PB16MD_00, PB16MD_01, PB16MD_10, PB16MD_11,
+       PB15MD_00, PB15MD_01, PB15MD_10, PB15MD_11,
+       PB14MD_00, PB14MD_01, PB14MD_10, PB14MD_11,
+       PB13MD_00, PB13MD_01, PB13MD_10, PB13MD_11,
+       PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
+       PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11,
+       PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11,
+       PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11,
+       PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11,
+       PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
+       PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
+       PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
+       PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
+       PB3MD_0, PB3MD_1,
+       PB2MD_0, PB2MD_1,
+       PB1MD_0, PB1MD_1,
+
+       /* Port C */
+       PC14_IOR_IN, PC14_IOR_OUT,
+       PC13_IOR_IN, PC13_IOR_OUT,
+       PC12_IOR_IN, PC12_IOR_OUT,
+       PC11_IOR_IN, PC11_IOR_OUT,
+       PC10_IOR_IN, PC10_IOR_OUT,
+       PC9_IOR_IN, PC9_IOR_OUT,
+       PC8_IOR_IN, PC8_IOR_OUT,
+       PC7_IOR_IN, PC7_IOR_OUT,
+       PC6_IOR_IN, PC6_IOR_OUT,
+       PC5_IOR_IN, PC5_IOR_OUT,
+       PC4_IOR_IN, PC4_IOR_OUT,
+       PC3_IOR_IN, PC3_IOR_OUT,
+       PC2_IOR_IN, PC2_IOR_OUT,
+       PC1_IOR_IN, PC1_IOR_OUT,
+       PC0_IOR_IN, PC0_IOR_OUT,
+
+       PC10MD_0, PC10MD_1,
+       PC9MD_0, PC9MD_1,
+       PC8MD_00, PC8MD_01, PC8MD_10, PC8MD_11,
+       PC7MD_00, PC7MD_01, PC7MD_10, PC7MD_11,
+       PC6MD_00, PC6MD_01, PC6MD_10, PC6MD_11,
+       PC5MD_00, PC5MD_01, PC5MD_10, PC5MD_11,
+       PC4MD_0, PC4MD_1,
+       PC3MD_0, PC3MD_1,
+       PC2MD_0, PC2MD_1,
+       PC1MD_0, PC1MD_1,
+       PC0MD_0, PC0MD_1,
+
+       /* Port D */
+       PD15_IOR_IN, PD15_IOR_OUT,
+       PD14_IOR_IN, PD14_IOR_OUT,
+       PD13_IOR_IN, PD13_IOR_OUT,
+       PD12_IOR_IN, PD12_IOR_OUT,
+       PD11_IOR_IN, PD11_IOR_OUT,
+       PD10_IOR_IN, PD10_IOR_OUT,
+       PD9_IOR_IN, PD9_IOR_OUT,
+       PD8_IOR_IN, PD8_IOR_OUT,
+       PD7_IOR_IN, PD7_IOR_OUT,
+       PD6_IOR_IN, PD6_IOR_OUT,
+       PD5_IOR_IN, PD5_IOR_OUT,
+       PD4_IOR_IN, PD4_IOR_OUT,
+       PD3_IOR_IN, PD3_IOR_OUT,
+       PD2_IOR_IN, PD2_IOR_OUT,
+       PD1_IOR_IN, PD1_IOR_OUT,
+       PD0_IOR_IN, PD0_IOR_OUT,
+
+       PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11,
+       PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11,
+       PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11,
+       PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11,
+       PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11,
+       PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11,
+       PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11,
+       PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11,
+       PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11,
+       PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11,
+       PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11,
+       PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11,
+       PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11,
+       PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11,
+       PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11,
+       PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11,
+
+       /* Port E */
+       PE5_IOR_IN, PE5_IOR_OUT,
+       PE4_IOR_IN, PE4_IOR_OUT,
+       PE3_IOR_IN, PE3_IOR_OUT,
+       PE2_IOR_IN, PE2_IOR_OUT,
+       PE1_IOR_IN, PE1_IOR_OUT,
+       PE0_IOR_IN, PE0_IOR_OUT,
+
+       PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11,
+       PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11,
+       PE3MD_00, PE3MD_01, PE3MD_10, PE3MD_11,
+       PE2MD_00, PE2MD_01, PE2MD_10, PE2MD_11,
+       PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+       PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
+       PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11,
+
+       /* Port F */
+       PF12_IOR_IN, PF12_IOR_OUT,
+       PF11_IOR_IN, PF11_IOR_OUT,
+       PF10_IOR_IN, PF10_IOR_OUT,
+       PF9_IOR_IN, PF9_IOR_OUT,
+       PF8_IOR_IN, PF8_IOR_OUT,
+       PF7_IOR_IN, PF7_IOR_OUT,
+       PF6_IOR_IN, PF6_IOR_OUT,
+       PF5_IOR_IN, PF5_IOR_OUT,
+       PF4_IOR_IN, PF4_IOR_OUT,
+       PF3_IOR_IN, PF3_IOR_OUT,
+       PF2_IOR_IN, PF2_IOR_OUT,
+       PF1_IOR_IN, PF1_IOR_OUT,
+       PF0_IOR_IN, PF0_IOR_OUT,
+
+       PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
+       PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
+       PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+       PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
+       PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+       PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
+       PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+       PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
+       PF8MD_00, PF8MD_01, PF8MD_10, PF8MD_11,
+       PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+       PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
+       PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+       PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
+       PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+       PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
+       PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+       PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
+       PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+       PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
+       PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+       PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
+       PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+       PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
+       PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+       PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
+
+       /* Port G */
+       PG24_IOR_IN, PG24_IOR_OUT,
+       PG23_IOR_IN, PG23_IOR_OUT,
+       PG22_IOR_IN, PG22_IOR_OUT,
+       PG21_IOR_IN, PG21_IOR_OUT,
+       PG20_IOR_IN, PG20_IOR_OUT,
+       PG19_IOR_IN, PG19_IOR_OUT,
+       PG18_IOR_IN, PG18_IOR_OUT,
+       PG17_IOR_IN, PG17_IOR_OUT,
+       PG16_IOR_IN, PG16_IOR_OUT,
+       PG15_IOR_IN, PG15_IOR_OUT,
+       PG14_IOR_IN, PG14_IOR_OUT,
+       PG13_IOR_IN, PG13_IOR_OUT,
+       PG12_IOR_IN, PG12_IOR_OUT,
+       PG11_IOR_IN, PG11_IOR_OUT,
+       PG10_IOR_IN, PG10_IOR_OUT,
+       PG9_IOR_IN, PG9_IOR_OUT,
+       PG8_IOR_IN, PG8_IOR_OUT,
+       PG7_IOR_IN, PG7_IOR_OUT,
+       PG6_IOR_IN, PG6_IOR_OUT,
+       PG5_IOR_IN, PG5_IOR_OUT,
+       PG4_IOR_IN, PG4_IOR_OUT,
+       PG3_IOR_IN, PG3_IOR_OUT,
+       PG2_IOR_IN, PG2_IOR_OUT,
+       PG1_IOR_IN, PG1_IOR_OUT,
+       PG0_IOR_IN, PG0_IOR_OUT,
+
+       PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11,
+       PG23MD_00, PG23MD_01, PG23MD_10, PG23MD_11,
+       PG22MD_00, PG22MD_01, PG22MD_10, PG22MD_11,
+       PG21MD_00, PG21MD_01, PG21MD_10, PG21MD_11,
+       PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+       PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
+       PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+       PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
+       PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+       PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
+       PG17MD_000, PG17MD_001, PG17MD_010, PG17MD_011,
+       PG17MD_100, PG17MD_101, PG17MD_110, PG17MD_111,
+       PG16MD_000, PG16MD_001, PG16MD_010, PG16MD_011,
+       PG16MD_100, PG16MD_101, PG16MD_110, PG16MD_111,
+       PG15MD_000, PG15MD_001, PG15MD_010, PG15MD_011,
+       PG15MD_100, PG15MD_101, PG15MD_110, PG15MD_111,
+       PG14MD_000, PG14MD_001, PG14MD_010, PG14MD_011,
+       PG14MD_100, PG14MD_101, PG14MD_110, PG14MD_111,
+       PG13MD_000, PG13MD_001, PG13MD_010, PG13MD_011,
+       PG13MD_100, PG13MD_101, PG13MD_110, PG13MD_111,
+       PG12MD_000, PG12MD_001, PG12MD_010, PG12MD_011,
+       PG12MD_100, PG12MD_101, PG12MD_110, PG12MD_111,
+       PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+       PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
+       PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+       PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
+       PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+       PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
+       PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+       PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
+       PG7MD_00, PG7MD_01, PG7MD_10, PG7MD_11,
+       PG6MD_00, PG6MD_01, PG6MD_10, PG6MD_11,
+       PG5MD_00, PG5MD_01, PG5MD_10, PG5MD_11,
+       PG4MD_00, PG4MD_01, PG4MD_10, PG4MD_11,
+       PG3MD_00, PG3MD_01, PG3MD_10, PG3MD_11,
+       PG2MD_00, PG2MD_01, PG2MD_10, PG2MD_11,
+       PG1MD_00, PG1MD_01, PG1MD_10, PG1MD_11,
+       PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+       PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
+
+       /* Port H */
+       PH7MD_0, PH7MD_1,
+       PH6MD_0, PH6MD_1,
+       PH5MD_0, PH5MD_1,
+       PH4MD_0, PH4MD_1,
+       PH3MD_0, PH3MD_1,
+       PH2MD_0, PH2MD_1,
+       PH1MD_0, PH1MD_1,
+       PH0MD_0, PH0MD_1,
+
+       /* Port I - not on device */
+
+       /* Port J */
+       PJ11_IOR_IN, PJ11_IOR_OUT,
+       PJ10_IOR_IN, PJ10_IOR_OUT,
+       PJ9_IOR_IN, PJ9_IOR_OUT,
+       PJ8_IOR_IN, PJ8_IOR_OUT,
+       PJ7_IOR_IN, PJ7_IOR_OUT,
+       PJ6_IOR_IN, PJ6_IOR_OUT,
+       PJ5_IOR_IN, PJ5_IOR_OUT,
+       PJ4_IOR_IN, PJ4_IOR_OUT,
+       PJ3_IOR_IN, PJ3_IOR_OUT,
+       PJ2_IOR_IN, PJ2_IOR_OUT,
+       PJ1_IOR_IN, PJ1_IOR_OUT,
+       PJ0_IOR_IN, PJ0_IOR_OUT,
+
+       PJ11MD_00, PJ11MD_01, PJ11MD_10, PJ11MD_11,
+       PJ10MD_00, PJ10MD_01, PJ10MD_10, PJ10MD_11,
+       PJ9MD_00, PJ9MD_01, PJ9MD_10, PJ9MD_11,
+       PJ8MD_00, PJ8MD_01, PJ8MD_10, PJ8MD_11,
+       PJ7MD_00, PJ7MD_01, PJ7MD_10, PJ7MD_11,
+       PJ6MD_00, PJ6MD_01, PJ6MD_10, PJ6MD_11,
+       PJ5MD_00, PJ5MD_01, PJ5MD_10, PJ5MD_11,
+       PJ4MD_00, PJ4MD_01, PJ4MD_10, PJ4MD_11,
+       PJ3MD_00, PJ3MD_01, PJ3MD_10, PJ3MD_11,
+       PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+       PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
+       PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+       PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
+       PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+       PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
+
+       /* Port K */
+       PK11_IOR_IN, PK11_IOR_OUT,
+       PK10_IOR_IN, PK10_IOR_OUT,
+       PK9_IOR_IN, PK9_IOR_OUT,
+       PK8_IOR_IN, PK8_IOR_OUT,
+       PK7_IOR_IN, PK7_IOR_OUT,
+       PK6_IOR_IN, PK6_IOR_OUT,
+       PK5_IOR_IN, PK5_IOR_OUT,
+       PK4_IOR_IN, PK4_IOR_OUT,
+       PK3_IOR_IN, PK3_IOR_OUT,
+       PK2_IOR_IN, PK2_IOR_OUT,
+       PK1_IOR_IN, PK1_IOR_OUT,
+       PK0_IOR_IN, PK0_IOR_OUT,
+
+       PK11MD_00, PK11MD_01, PK11MD_10, PK11MD_11,
+       PK10MD_00, PK10MD_01, PK10MD_10, PK10MD_11,
+       PK9MD_00, PK9MD_01, PK9MD_10, PK9MD_11,
+       PK8MD_00, PK8MD_01, PK8MD_10, PK8MD_11,
+       PK7MD_00, PK7MD_01, PK7MD_10, PK7MD_11,
+       PK6MD_00, PK6MD_01, PK6MD_10, PK6MD_11,
+       PK5MD_00, PK5MD_01, PK5MD_10, PK5MD_11,
+       PK4MD_00, PK4MD_01, PK4MD_10, PK4MD_11,
+       PK3MD_00, PK3MD_01, PK3MD_10, PK3MD_11,
+       PK2MD_00, PK2MD_01, PK2MD_10, PK2MD_11,
+       PK1MD_00, PK1MD_01, PK1MD_10, PK1MD_11,
+       PK0MD_00, PK0MD_01, PK0MD_10, PK0MD_11,
+       PINMUX_FUNCTION_END,
+
+       PINMUX_MARK_BEGIN,
+       /* Port A */
+
+       /* Port B */
+
+       /* Port C */
+
+       /* Port D */
+
+       /* Port E */
+
+       /* Port F */
+
+       /* Port G */
+
+       /* Port H */
+       PHAN7_MARK, PHAN6_MARK, PHAN5_MARK, PHAN4_MARK,
+       PHAN3_MARK, PHAN2_MARK, PHAN1_MARK, PHAN0_MARK,
+
+       /* Port I - not on device */
+
+       /* Port J */
+
+       /* Port K */
+
+       IRQ7_PC_MARK, IRQ6_PC_MARK, IRQ5_PC_MARK, IRQ4_PC_MARK,
+       IRQ3_PG_MARK, IRQ2_PG_MARK, IRQ1_PJ_MARK, IRQ0_PJ_MARK,
+       IRQ3_PE_MARK, IRQ2_PE_MARK, IRQ1_PE_MARK, IRQ0_PE_MARK,
+
+       PINT7_PG_MARK, PINT6_PG_MARK, PINT5_PG_MARK, PINT4_PG_MARK,
+       PINT3_PG_MARK, PINT2_PG_MARK, PINT1_PG_MARK, PINT0_PG_MARK,
+
+       SD_CD_MARK, SD_D0_MARK, SD_D1_MARK, SD_D2_MARK, SD_D3_MARK,
+       SD_WP_MARK, SD_CLK_MARK, SD_CMD_MARK,
+       CRX0_MARK, CRX1_MARK,
+       CTX0_MARK, CTX1_MARK,
+
+       PWM1A_MARK, PWM1B_MARK, PWM1C_MARK, PWM1D_MARK,
+       PWM1E_MARK, PWM1F_MARK, PWM1G_MARK, PWM1H_MARK,
+       PWM2A_MARK, PWM2B_MARK, PWM2C_MARK, PWM2D_MARK,
+       PWM2E_MARK, PWM2F_MARK, PWM2G_MARK, PWM2H_MARK,
+       IERXD_MARK, IETXD_MARK,
+       CRX0CRX1_MARK,
+       WDTOVF_MARK,
+
+       CRX0X1_MARK,
+
+       /* DMAC */
+       TEND0_MARK, DACK0_MARK, DREQ0_MARK,
+       TEND1_MARK, DACK1_MARK, DREQ1_MARK,
+
+       /* ADC */
+       ADTRG_MARK,
+
+       /* BSC */
+       A25_MARK, A24_MARK,
+       A23_MARK, A22_MARK, A21_MARK, A20_MARK,
+       A19_MARK, A18_MARK, A17_MARK, A16_MARK,
+       A15_MARK, A14_MARK, A13_MARK, A12_MARK,
+       A11_MARK, A10_MARK, A9_MARK, A8_MARK,
+       A7_MARK, A6_MARK, A5_MARK, A4_MARK,
+       A3_MARK, A2_MARK, A1_MARK, A0_MARK,
+       D15_MARK, D14_MARK, D13_MARK, D12_MARK,
+       D11_MARK, D10_MARK, D9_MARK, D8_MARK,
+       D7_MARK, D6_MARK, D5_MARK, D4_MARK,
+       D3_MARK, D2_MARK, D1_MARK, D0_MARK,
+       BS_MARK,
+       CS4_MARK, CS3_MARK, CS2_MARK, CS1_MARK, CS0_MARK,
+       CS6CE1B_MARK, CS5CE1A_MARK,
+       CE2A_MARK, CE2B_MARK,
+       RD_MARK, RDWR_MARK,
+       ICIOWRAH_MARK,
+       ICIORD_MARK,
+       WE1DQMUWE_MARK,
+       WE0DQML_MARK,
+       RAS_MARK, CAS_MARK, CKE_MARK,
+       WAIT_MARK, BREQ_MARK, BACK_MARK, IOIS16_MARK,
+
+       /* TMU */
+       TIOC0A_MARK, TIOC0B_MARK, TIOC0C_MARK, TIOC0D_MARK,
+       TIOC1A_MARK, TIOC1B_MARK,
+       TIOC2A_MARK, TIOC2B_MARK,
+       TIOC3A_MARK, TIOC3B_MARK, TIOC3C_MARK, TIOC3D_MARK,
+       TIOC4A_MARK, TIOC4B_MARK, TIOC4C_MARK, TIOC4D_MARK,
+       TCLKA_MARK,     TCLKB_MARK, TCLKC_MARK, TCLKD_MARK,
+
+       /* SCIF */
+       SCK0_MARK, SCK1_MARK, SCK2_MARK, SCK3_MARK,
+       RXD0_MARK, RXD1_MARK, RXD2_MARK, RXD3_MARK,
+       TXD0_MARK, TXD1_MARK, TXD2_MARK, TXD3_MARK,
+       RXD4_MARK, RXD5_MARK, RXD6_MARK, RXD7_MARK,
+       TXD4_MARK, TXD5_MARK, TXD6_MARK, TXD7_MARK,
+       RTS1_MARK, RTS3_MARK,
+       CTS1_MARK, CTS3_MARK,
+
+       /* RSPI */
+       RSPCK0_MARK, RSPCK1_MARK,
+       MOSI0_MARK, MOSI1_MARK,
+       MISO0_PF12_MARK, MISO1_MARK, MISO1_PG19_MARK,
+       SSL00_MARK, SSL10_MARK,
+
+       /* IIC3 */
+       SCL0_MARK, SCL1_MARK, SCL2_MARK,
+       SDA0_MARK, SDA1_MARK, SDA2_MARK,
+
+       /* SSI */
+       SSISCK0_MARK,
+       SSIWS0_MARK,
+       SSITXD0_MARK,
+       SSIRXD0_MARK,
+       SSIWS1_MARK, SSIWS2_MARK, SSIWS3_MARK,
+       SSISCK1_MARK, SSISCK2_MARK, SSISCK3_MARK,
+       SSIDATA1_MARK, SSIDATA2_MARK, SSIDATA3_MARK,
+       AUDIO_CLK_MARK,
+
+       /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+       SIOFTXD_MARK, SIOFRXD_MARK, SIOFSYNC_MARK, SIOFSCK_MARK,
+
+       /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+       SPDIF_IN_MARK, SPDIF_OUT_MARK,
+
+       /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+       FCE_MARK,
+       FRB_MARK,
+
+       /* VDC3 */
+       DV_CLK_MARK,
+       DV_VSYNC_MARK, DV_HSYNC_MARK,
+       DV_DATA7_MARK, DV_DATA6_MARK, DV_DATA5_MARK, DV_DATA4_MARK,
+       DV_DATA3_MARK, DV_DATA2_MARK, DV_DATA1_MARK, DV_DATA0_MARK,
+       LCD_CLK_MARK, LCD_EXTCLK_MARK,
+       LCD_VSYNC_MARK, LCD_HSYNC_MARK, LCD_DE_MARK,
+       LCD_DATA15_MARK, LCD_DATA14_MARK, LCD_DATA13_MARK, LCD_DATA12_MARK,
+       LCD_DATA11_MARK, LCD_DATA10_MARK, LCD_DATA9_MARK, LCD_DATA8_MARK,
+       LCD_DATA7_MARK, LCD_DATA6_MARK, LCD_DATA5_MARK, LCD_DATA4_MARK,
+       LCD_DATA3_MARK, LCD_DATA2_MARK, LCD_DATA1_MARK, LCD_DATA0_MARK,
+       LCD_M_DISP_MARK,
+       PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+
+       /* Port A */
+       PINMUX_DATA(PA3_DATA, PA3_IN),
+       PINMUX_DATA(PA2_DATA, PA2_IN),
+       PINMUX_DATA(PA1_DATA, PA1_IN),
+       PINMUX_DATA(PA0_DATA, PA0_IN),
+
+       /* Port B */
+       PINMUX_DATA(PB22_DATA, PB22MD_00, PB22_IN, PB22_OUT),
+       PINMUX_DATA(A22_MARK, PB22MD_01),
+       PINMUX_DATA(CS4_MARK, PB22MD_10),
+
+       PINMUX_DATA(PB21_DATA, PB21MD_0, PB21_IN, PB21_OUT),
+       PINMUX_DATA(A21_MARK, PB21MD_1),
+       PINMUX_DATA(A20_MARK, PB20MD_1),
+       PINMUX_DATA(A19_MARK, PB19MD_01),
+       PINMUX_DATA(A18_MARK, PB18MD_01),
+       PINMUX_DATA(A17_MARK, PB17MD_01),
+       PINMUX_DATA(A16_MARK, PB16MD_01),
+       PINMUX_DATA(A15_MARK, PB15MD_01),
+       PINMUX_DATA(A14_MARK, PB14MD_01),
+       PINMUX_DATA(A13_MARK, PB13MD_01),
+       PINMUX_DATA(A12_MARK, PB12MD_01),
+       PINMUX_DATA(A11_MARK, PB11MD_01),
+       PINMUX_DATA(A10_MARK, PB10MD_01),
+       PINMUX_DATA(A9_MARK, PB9MD_01),
+       PINMUX_DATA(A8_MARK, PB8MD_01),
+       PINMUX_DATA(A7_MARK, PB7MD_01),
+       PINMUX_DATA(A6_MARK, PB6MD_01),
+       PINMUX_DATA(A5_MARK, PB5MD_01),
+       PINMUX_DATA(A4_MARK, PB4MD_01),
+       PINMUX_DATA(A3_MARK, PB3MD_1),
+       PINMUX_DATA(A2_MARK, PB2MD_1),
+       PINMUX_DATA(A1_MARK, PB1MD_1),
+
+       /* Port C */
+       PINMUX_DATA(PC10_DATA, PC10MD_0),
+       PINMUX_DATA(TIOC2B_MARK, PC1MD_1),
+       PINMUX_DATA(PC9_DATA, PC9MD_0),
+       PINMUX_DATA(TIOC2A_MARK, PC9MD_1),
+       PINMUX_DATA(PC8_DATA, PC8MD_00),
+       PINMUX_DATA(CS3_MARK, PC8MD_01),
+       PINMUX_DATA(TIOC4D_MARK, PC8MD_10),
+       PINMUX_DATA(IRQ7_PC_MARK, PC8MD_11),
+       PINMUX_DATA(PC7_DATA, PC7MD_00),
+       PINMUX_DATA(CKE_MARK, PC7MD_01),
+       PINMUX_DATA(TIOC4C_MARK, PC7MD_10),
+       PINMUX_DATA(IRQ6_PC_MARK, PC7MD_11),
+       PINMUX_DATA(PC6_DATA, PC6MD_00),
+       PINMUX_DATA(CAS_MARK, PC6MD_01),
+       PINMUX_DATA(TIOC4B_MARK, PC6MD_10),
+       PINMUX_DATA(IRQ5_PC_MARK, PC6MD_11),
+       PINMUX_DATA(PC5_DATA, PC5MD_00),
+       PINMUX_DATA(RAS_MARK, PC5MD_01),
+       PINMUX_DATA(TIOC4A_MARK, PC5MD_10),
+       PINMUX_DATA(IRQ4_PC_MARK, PC5MD_11),
+       PINMUX_DATA(PC4_DATA, PC4MD_0),
+       PINMUX_DATA(WE1DQMUWE_MARK, PC4MD_1),
+       PINMUX_DATA(PC3_DATA, PC3MD_0),
+       PINMUX_DATA(WE0DQML_MARK, PC3MD_1),
+       PINMUX_DATA(PC2_DATA, PC2MD_0),
+       PINMUX_DATA(RDWR_MARK, PC2MD_1),
+       PINMUX_DATA(PC1_DATA, PC1MD_0),
+       PINMUX_DATA(RD_MARK, PC1MD_1),
+       PINMUX_DATA(PC0_DATA, PC0MD_0),
+       PINMUX_DATA(CS0_MARK, PC0MD_1),
+
+       /* Port D */
+       PINMUX_DATA(D15_MARK, PD15MD_01),
+       PINMUX_DATA(D14_MARK, PD14MD_01),
+       PINMUX_DATA(D13_MARK, PD13MD_01),
+       PINMUX_DATA(D12_MARK, PD12MD_01),
+       PINMUX_DATA(D11_MARK, PD11MD_01),
+       PINMUX_DATA(D10_MARK, PD10MD_01),
+       PINMUX_DATA(D9_MARK, PD9MD_01),
+       PINMUX_DATA(D8_MARK, PD8MD_01),
+       PINMUX_DATA(D7_MARK, PD7MD_01),
+       PINMUX_DATA(D6_MARK, PD6MD_01),
+       PINMUX_DATA(D5_MARK, PD5MD_01),
+       PINMUX_DATA(D4_MARK, PD4MD_01),
+       PINMUX_DATA(D3_MARK, PD3MD_01),
+       PINMUX_DATA(D2_MARK, PD2MD_01),
+       PINMUX_DATA(D1_MARK, PD1MD_01),
+       PINMUX_DATA(D0_MARK, PD0MD_01),
+
+       /* Port E */
+       PINMUX_DATA(PE5_DATA, PE5MD_00),
+       PINMUX_DATA(SDA2_MARK, PE5MD_01),
+       PINMUX_DATA(DV_HSYNC_MARK, PE5MD_11),
+
+       PINMUX_DATA(PE4_DATA, PE4MD_00),
+       PINMUX_DATA(SCL2_MARK, PE4MD_01),
+       PINMUX_DATA(DV_VSYNC_MARK, PE4MD_11),
+
+       PINMUX_DATA(PE3_DATA, PE3MD_00),
+       PINMUX_DATA(SDA1_MARK, PE3MD_01),
+       PINMUX_DATA(IRQ3_PE_MARK, PE3MD_11),
+
+       PINMUX_DATA(PE2_DATA, PE2MD_00),
+       PINMUX_DATA(SCL1_MARK, PE2MD_01),
+       PINMUX_DATA(IRQ2_PE_MARK, PE2MD_11),
+
+       PINMUX_DATA(PE1_DATA, PE1MD_000),
+       PINMUX_DATA(SDA0_MARK, PE1MD_001),
+       PINMUX_DATA(IOIS16_MARK, PE1MD_010),
+       PINMUX_DATA(IRQ1_PE_MARK, PE1MD_011),
+       PINMUX_DATA(TCLKA_MARK, PE1MD_100),
+       PINMUX_DATA(ADTRG_MARK, PE1MD_101),
+
+       PINMUX_DATA(PE0_DATA, PE0MD_00),
+       PINMUX_DATA(SCL0_MARK, PE0MD_01),
+       PINMUX_DATA(AUDIO_CLK_MARK, PE0MD_10),
+       PINMUX_DATA(IRQ0_PE_MARK, PE0MD_11),
+
+       /* Port F */
+       PINMUX_DATA(PF12_DATA, PF12MD_000),
+       PINMUX_DATA(BS_MARK, PF12MD_001),
+       PINMUX_DATA(MISO0_PF12_MARK, PF12MD_011),
+       PINMUX_DATA(TIOC3D_MARK, PF12MD_100),
+       PINMUX_DATA(SPDIF_OUT_MARK, PF12MD_101),
+
+       PINMUX_DATA(PF11_DATA, PF11MD_000),
+       PINMUX_DATA(A25_MARK, PF11MD_001),
+       PINMUX_DATA(SSIDATA3_MARK, PF11MD_010),
+       PINMUX_DATA(MOSI0_MARK, PF11MD_011),
+       PINMUX_DATA(TIOC3C_MARK, PF11MD_100),
+       PINMUX_DATA(SPDIF_IN_MARK, PF11MD_101),
+
+       PINMUX_DATA(PF10_DATA, PF10MD_000),
+       PINMUX_DATA(A24_MARK, PF10MD_001),
+       PINMUX_DATA(SSIWS3_MARK, PF10MD_010),
+       PINMUX_DATA(SSL00_MARK, PF10MD_011),
+       PINMUX_DATA(TIOC3B_MARK, PF10MD_100),
+       PINMUX_DATA(FCE_MARK, PF10MD_101),
+
+       PINMUX_DATA(PF9_DATA, PF9MD_000),
+       PINMUX_DATA(A23_MARK, PF9MD_001),
+       PINMUX_DATA(SSISCK3_MARK, PF9MD_010),
+       PINMUX_DATA(RSPCK0_MARK, PF9MD_011),
+       PINMUX_DATA(TIOC3A_MARK, PF9MD_100),
+       PINMUX_DATA(FRB_MARK, PF9MD_101),
+
+       PINMUX_DATA(PF8_DATA, PF8MD_00),
+       PINMUX_DATA(CE2B_MARK, PF8MD_01),
+       PINMUX_DATA(SSIDATA3_MARK, PF8MD_10),
+       PINMUX_DATA(DV_CLK_MARK, PF8MD_11),
+
+       PINMUX_DATA(PF7_DATA, PF7MD_000),
+       PINMUX_DATA(CE2A_MARK, PF7MD_001),
+       PINMUX_DATA(SSIWS3_MARK, PF7MD_010),
+       PINMUX_DATA(DV_DATA7_MARK, PF7MD_011),
+       PINMUX_DATA(TCLKD_MARK, PF7MD_100),
+
+       PINMUX_DATA(PF6_DATA, PF6MD_000),
+       PINMUX_DATA(CS6CE1B_MARK, PF6MD_001),
+       PINMUX_DATA(SSISCK3_MARK, PF6MD_010),
+       PINMUX_DATA(DV_DATA6_MARK, PF6MD_011),
+       PINMUX_DATA(TCLKB_MARK, PF6MD_100),
+
+       PINMUX_DATA(PF5_DATA, PF5MD_000),
+       PINMUX_DATA(CS5CE1A_MARK, PF5MD_001),
+       PINMUX_DATA(SSIDATA2_MARK, PF5MD_010),
+       PINMUX_DATA(DV_DATA5_MARK, PF5MD_011),
+       PINMUX_DATA(TCLKC_MARK, PF5MD_100),
+
+       PINMUX_DATA(PF4_DATA, PF4MD_000),
+       PINMUX_DATA(ICIOWRAH_MARK, PF4MD_001),
+       PINMUX_DATA(SSIWS2_MARK, PF4MD_010),
+       PINMUX_DATA(DV_DATA4_MARK, PF4MD_011),
+       PINMUX_DATA(TXD3_MARK, PF4MD_100),
+
+       PINMUX_DATA(PF3_DATA, PF3MD_000),
+       PINMUX_DATA(ICIORD_MARK, PF3MD_001),
+       PINMUX_DATA(SSISCK2_MARK, PF3MD_010),
+       PINMUX_DATA(DV_DATA3_MARK, PF3MD_011),
+       PINMUX_DATA(RXD3_MARK, PF3MD_100),
+
+       PINMUX_DATA(PF2_DATA, PF2MD_000),
+       PINMUX_DATA(BACK_MARK, PF2MD_001),
+       PINMUX_DATA(SSIDATA1_MARK, PF2MD_010),
+       PINMUX_DATA(DV_DATA2_MARK, PF2MD_011),
+       PINMUX_DATA(TXD2_MARK, PF2MD_100),
+       PINMUX_DATA(DACK0_MARK, PF2MD_101),
+
+       PINMUX_DATA(PF1_DATA, PF1MD_000),
+       PINMUX_DATA(BREQ_MARK, PF1MD_001),
+       PINMUX_DATA(SSIWS1_MARK, PF1MD_010),
+       PINMUX_DATA(DV_DATA1_MARK, PF1MD_011),
+       PINMUX_DATA(RXD2_MARK, PF1MD_100),
+       PINMUX_DATA(DREQ0_MARK, PF1MD_101),
+
+       PINMUX_DATA(PF0_DATA, PF0MD_000),
+       PINMUX_DATA(WAIT_MARK, PF0MD_001),
+       PINMUX_DATA(SSISCK1_MARK, PF0MD_010),
+       PINMUX_DATA(DV_DATA0_MARK, PF0MD_011),
+       PINMUX_DATA(SCK2_MARK, PF0MD_100),
+       PINMUX_DATA(TEND0_MARK, PF0MD_101),
+
+       /* Port G */
+       PINMUX_DATA(PG24_DATA, PG24MD_00),
+       PINMUX_DATA(MOSI0_MARK, PG24MD_01),
+       PINMUX_DATA(TIOC0D_MARK, PG24MD_10),
+
+       PINMUX_DATA(PG23_DATA, PG23MD_00),
+       PINMUX_DATA(MOSI1_MARK, PG23MD_01),
+       PINMUX_DATA(TIOC0C_MARK, PG23MD_10),
+
+       PINMUX_DATA(PG22_DATA, PG22MD_00),
+       PINMUX_DATA(SSL10_MARK, PG22MD_01),
+       PINMUX_DATA(TIOC0B_MARK, PG22MD_10),
+
+       PINMUX_DATA(PG21_DATA, PG21MD_00),
+       PINMUX_DATA(RSPCK1_MARK, PG21MD_01),
+       PINMUX_DATA(TIOC0A_MARK, PG21MD_10),
+
+       PINMUX_DATA(PG20_DATA, PG20MD_000),
+       PINMUX_DATA(LCD_EXTCLK_MARK, PG20MD_001),
+       PINMUX_DATA(MISO1_MARK, PG20MD_011),
+       PINMUX_DATA(TXD7_MARK, PG20MD_100),
+
+       PINMUX_DATA(PG19_DATA, PG19MD_000),
+       PINMUX_DATA(LCD_CLK_MARK, PG19MD_001),
+       PINMUX_DATA(TIOC2B_MARK, PG19MD_010),
+       PINMUX_DATA(MISO1_PG19_MARK, PG19MD_011),
+       PINMUX_DATA(RXD7_MARK, PG19MD_100),
+
+       PINMUX_DATA(PG18_DATA, PG18MD_000),
+       PINMUX_DATA(LCD_DE_MARK, PG18MD_001),
+       PINMUX_DATA(TIOC2A_MARK, PG18MD_010),
+       PINMUX_DATA(SSL10_MARK, PG18MD_011),
+       PINMUX_DATA(TXD6_MARK, PG18MD_100),
+
+       PINMUX_DATA(PG17_DATA, PG17MD_000),
+       PINMUX_DATA(LCD_HSYNC_MARK, PG17MD_001),
+       PINMUX_DATA(TIOC1B_MARK, PG17MD_010),
+       PINMUX_DATA(RSPCK1_MARK, PG17MD_011),
+       PINMUX_DATA(RXD6_MARK, PG17MD_100),
+
+       PINMUX_DATA(PG16_DATA, PG16MD_000),
+       PINMUX_DATA(LCD_VSYNC_MARK, PG16MD_001),
+       PINMUX_DATA(TIOC1A_MARK, PG16MD_010),
+       PINMUX_DATA(TXD3_MARK, PG16MD_011),
+       PINMUX_DATA(CTS1_MARK, PG16MD_100),
+
+       PINMUX_DATA(PG15_DATA, PG15MD_000),
+       PINMUX_DATA(LCD_DATA15_MARK, PG15MD_001),
+       PINMUX_DATA(TIOC0D_MARK, PG15MD_010),
+       PINMUX_DATA(RXD3_MARK, PG15MD_011),
+       PINMUX_DATA(RTS1_MARK, PG15MD_100),
+
+       PINMUX_DATA(PG14_DATA, PG14MD_000),
+       PINMUX_DATA(LCD_DATA14_MARK, PG14MD_001),
+       PINMUX_DATA(TIOC0C_MARK, PG14MD_010),
+       PINMUX_DATA(SCK1_MARK, PG14MD_100),
+
+       PINMUX_DATA(PG13_DATA, PG13MD_000),
+       PINMUX_DATA(LCD_DATA13_MARK, PG13MD_001),
+       PINMUX_DATA(TIOC0B_MARK, PG13MD_010),
+       PINMUX_DATA(TXD1_MARK, PG13MD_100),
+
+       PINMUX_DATA(PG12_DATA, PG12MD_000),
+       PINMUX_DATA(LCD_DATA12_MARK, PG12MD_001),
+       PINMUX_DATA(TIOC0A_MARK, PG12MD_010),
+       PINMUX_DATA(RXD1_MARK, PG12MD_100),
+
+       PINMUX_DATA(PG11_DATA, PG11MD_000),
+       PINMUX_DATA(LCD_DATA11_MARK, PG11MD_001),
+       PINMUX_DATA(SSITXD0_MARK, PG11MD_010),
+       PINMUX_DATA(IRQ3_PG_MARK, PG11MD_011),
+       PINMUX_DATA(TXD5_MARK, PG11MD_100),
+       PINMUX_DATA(SIOFTXD_MARK, PG11MD_101),
+
+       PINMUX_DATA(PG10_DATA, PG10MD_000),
+       PINMUX_DATA(LCD_DATA10_MARK, PG10MD_001),
+       PINMUX_DATA(SSIRXD0_MARK, PG10MD_010),
+       PINMUX_DATA(IRQ2_PG_MARK, PG10MD_011),
+       PINMUX_DATA(RXD5_MARK, PG10MD_100),
+       PINMUX_DATA(SIOFRXD_MARK, PG10MD_101),
+
+       PINMUX_DATA(PG9_DATA, PG9MD_000),
+       PINMUX_DATA(LCD_DATA9_MARK, PG9MD_001),
+       PINMUX_DATA(SSIWS0_MARK, PG9MD_010),
+       PINMUX_DATA(TXD4_MARK, PG9MD_100),
+       PINMUX_DATA(SIOFSYNC_MARK, PG9MD_101),
+
+       PINMUX_DATA(PG8_DATA, PG8MD_000),
+       PINMUX_DATA(LCD_DATA8_MARK, PG8MD_001),
+       PINMUX_DATA(SSISCK0_MARK, PG8MD_010),
+       PINMUX_DATA(RXD4_MARK, PG8MD_100),
+       PINMUX_DATA(SIOFSCK_MARK, PG8MD_101),
+
+       PINMUX_DATA(PG7_DATA, PG7MD_00),
+       PINMUX_DATA(LCD_DATA7_MARK, PG7MD_01),
+       PINMUX_DATA(SD_CD_MARK, PG7MD_10),
+       PINMUX_DATA(PINT7_PG_MARK, PG7MD_11),
+
+       PINMUX_DATA(PG6_DATA, PG7MD_00),
+       PINMUX_DATA(LCD_DATA6_MARK, PG7MD_01),
+       PINMUX_DATA(SD_WP_MARK, PG7MD_10),
+       PINMUX_DATA(PINT6_PG_MARK, PG7MD_11),
+
+       PINMUX_DATA(PG5_DATA, PG5MD_00),
+       PINMUX_DATA(LCD_DATA5_MARK, PG5MD_01),
+       PINMUX_DATA(SD_D1_MARK, PG5MD_10),
+       PINMUX_DATA(PINT5_PG_MARK, PG5MD_11),
+
+       PINMUX_DATA(PG4_DATA, PG4MD_00),
+       PINMUX_DATA(LCD_DATA4_MARK, PG4MD_01),
+       PINMUX_DATA(SD_D0_MARK, PG4MD_10),
+       PINMUX_DATA(PINT4_PG_MARK, PG4MD_11),
+
+       PINMUX_DATA(PG3_DATA, PG3MD_00),
+       PINMUX_DATA(LCD_DATA3_MARK, PG3MD_01),
+       PINMUX_DATA(SD_CLK_MARK, PG3MD_10),
+       PINMUX_DATA(PINT3_PG_MARK, PG3MD_11),
+
+       PINMUX_DATA(PG2_DATA, PG2MD_00),
+       PINMUX_DATA(LCD_DATA2_MARK, PG2MD_01),
+       PINMUX_DATA(SD_CMD_MARK, PG2MD_10),
+       PINMUX_DATA(PINT2_PG_MARK, PG2MD_11),
+
+       PINMUX_DATA(PG1_DATA, PG1MD_00),
+       PINMUX_DATA(LCD_DATA1_MARK, PG1MD_01),
+       PINMUX_DATA(SD_D3_MARK, PG1MD_10),
+       PINMUX_DATA(PINT1_PG_MARK, PG1MD_11),
+
+       PINMUX_DATA(PG0_DATA, PG0MD_000),
+       PINMUX_DATA(LCD_DATA0_MARK, PG0MD_001),
+       PINMUX_DATA(SD_D2_MARK, PG0MD_010),
+       PINMUX_DATA(PINT0_PG_MARK, PG0MD_011),
+       PINMUX_DATA(WDTOVF_MARK, PG0MD_100),
+
+       /* Port H */
+       PINMUX_DATA(PH7_DATA, PH7MD_0),
+       PINMUX_DATA(PHAN7_MARK, PH7MD_1),
+
+       PINMUX_DATA(PH6_DATA, PH6MD_0),
+       PINMUX_DATA(PHAN6_MARK, PH6MD_1),
+
+       PINMUX_DATA(PH5_DATA, PH5MD_0),
+       PINMUX_DATA(PHAN5_MARK, PH5MD_1),
+
+       PINMUX_DATA(PH4_DATA, PH4MD_0),
+       PINMUX_DATA(PHAN4_MARK, PH4MD_1),
+
+       PINMUX_DATA(PH3_DATA, PH3MD_0),
+       PINMUX_DATA(PHAN3_MARK, PH3MD_1),
+
+       PINMUX_DATA(PH2_DATA, PH2MD_0),
+       PINMUX_DATA(PHAN2_MARK, PH2MD_1),
+
+       PINMUX_DATA(PH1_DATA, PH1MD_0),
+       PINMUX_DATA(PHAN1_MARK, PH1MD_1),
+
+       PINMUX_DATA(PH0_DATA, PH0MD_0),
+       PINMUX_DATA(PHAN0_MARK, PH0MD_1),
+
+       /* Port I - not on device */
+
+       /* Port J */
+       PINMUX_DATA(PJ11_DATA, PJ11MD_00),
+       PINMUX_DATA(PWM2H_MARK, PJ11MD_01),
+       PINMUX_DATA(DACK1_MARK, PJ11MD_10),
+
+       PINMUX_DATA(PJ10_DATA, PJ10MD_00),
+       PINMUX_DATA(PWM2G_MARK, PJ10MD_01),
+       PINMUX_DATA(DREQ1_MARK, PJ10MD_10),
+
+       PINMUX_DATA(PJ9_DATA, PJ9MD_00),
+       PINMUX_DATA(PWM2F_MARK, PJ9MD_01),
+       PINMUX_DATA(TEND1_MARK, PJ9MD_10),
+
+       PINMUX_DATA(PJ8_DATA, PJ8MD_00),
+       PINMUX_DATA(PWM2E_MARK, PJ8MD_01),
+       PINMUX_DATA(RTS3_MARK, PJ8MD_10),
+
+       PINMUX_DATA(PJ7_DATA, PJ7MD_00),
+       PINMUX_DATA(TIOC1B_MARK, PJ7MD_01),
+       PINMUX_DATA(CTS3_MARK, PJ7MD_10),
+
+       PINMUX_DATA(PJ6_DATA, PJ6MD_00),
+       PINMUX_DATA(TIOC1A_MARK, PJ6MD_01),
+       PINMUX_DATA(SCK3_MARK, PJ6MD_10),
+
+       PINMUX_DATA(PJ5_DATA, PJ5MD_00),
+       PINMUX_DATA(IERXD_MARK, PJ5MD_01),
+       PINMUX_DATA(TXD3_MARK, PJ5MD_10),
+
+       PINMUX_DATA(PJ4_DATA, PJ4MD_00),
+       PINMUX_DATA(IETXD_MARK, PJ4MD_01),
+       PINMUX_DATA(RXD3_MARK, PJ4MD_10),
+
+       PINMUX_DATA(PJ3_DATA, PJ3MD_00),
+       PINMUX_DATA(CRX1_MARK, PJ3MD_01),
+       PINMUX_DATA(CRX0X1_MARK, PJ3MD_10),
+       PINMUX_DATA(IRQ1_PJ_MARK, PJ3MD_11),
+
+       PINMUX_DATA(PJ2_DATA, PJ2MD_000),
+       PINMUX_DATA(CTX1_MARK, PJ2MD_001),
+       PINMUX_DATA(CRX0CRX1_MARK, PJ2MD_010),
+       PINMUX_DATA(CS2_MARK, PJ2MD_011),
+       PINMUX_DATA(SCK0_MARK, PJ2MD_100),
+       PINMUX_DATA(LCD_M_DISP_MARK, PJ2MD_101),
+
+       PINMUX_DATA(PJ1_DATA, PJ1MD_000),
+       PINMUX_DATA(CRX0_MARK, PJ1MD_001),
+       PINMUX_DATA(IERXD_MARK, PJ1MD_010),
+       PINMUX_DATA(IRQ0_PJ_MARK, PJ1MD_011),
+       PINMUX_DATA(RXD0_MARK, PJ1MD_100),
+
+       PINMUX_DATA(PJ0_DATA, PJ0MD_000),
+       PINMUX_DATA(CTX0_MARK, PJ0MD_001),
+       PINMUX_DATA(IERXD_MARK, PJ0MD_010),
+       PINMUX_DATA(CS1_MARK, PJ0MD_011),
+       PINMUX_DATA(TXD0_MARK, PJ0MD_100),
+       PINMUX_DATA(A0_MARK, PJ0MD_101),
+
+       /* Port K */
+       PINMUX_DATA(PK11_DATA, PK11MD_00),
+       PINMUX_DATA(PWM2D_MARK, PK11MD_01),
+       PINMUX_DATA(SSITXD0_MARK, PK11MD_10),
+
+       PINMUX_DATA(PK10_DATA, PK10MD_00),
+       PINMUX_DATA(PWM2C_MARK, PK10MD_01),
+       PINMUX_DATA(SSIRXD0_MARK, PK10MD_10),
+
+       PINMUX_DATA(PK9_DATA, PK9MD_00),
+       PINMUX_DATA(PWM2B_MARK, PK9MD_01),
+       PINMUX_DATA(SSIWS0_MARK, PK9MD_10),
+
+       PINMUX_DATA(PK8_DATA, PK8MD_00),
+       PINMUX_DATA(PWM2A_MARK, PK8MD_01),
+       PINMUX_DATA(SSISCK0_MARK, PK8MD_10),
+
+       PINMUX_DATA(PK7_DATA, PK7MD_00),
+       PINMUX_DATA(PWM1H_MARK, PK7MD_01),
+       PINMUX_DATA(SD_CD_MARK, PK7MD_10),
+
+       PINMUX_DATA(PK6_DATA, PK6MD_00),
+       PINMUX_DATA(PWM1G_MARK, PK6MD_01),
+       PINMUX_DATA(SD_WP_MARK, PK6MD_10),
+
+       PINMUX_DATA(PK5_DATA, PK5MD_00),
+       PINMUX_DATA(PWM1F_MARK, PK5MD_01),
+       PINMUX_DATA(SD_D1_MARK, PK5MD_10),
+
+       PINMUX_DATA(PK4_DATA, PK4MD_00),
+       PINMUX_DATA(PWM1E_MARK, PK4MD_01),
+       PINMUX_DATA(SD_D0_MARK, PK4MD_10),
+
+       PINMUX_DATA(PK3_DATA, PK3MD_00),
+       PINMUX_DATA(PWM1D_MARK, PK3MD_01),
+       PINMUX_DATA(SD_CLK_MARK, PK3MD_10),
+
+       PINMUX_DATA(PK2_DATA, PK2MD_00),
+       PINMUX_DATA(PWM1C_MARK, PK2MD_01),
+       PINMUX_DATA(SD_CMD_MARK, PK2MD_10),
+
+       PINMUX_DATA(PK1_DATA, PK1MD_00),
+       PINMUX_DATA(PWM1B_MARK, PK1MD_01),
+       PINMUX_DATA(SD_D3_MARK, PK1MD_10),
+
+       PINMUX_DATA(PK0_DATA, PK0MD_00),
+       PINMUX_DATA(PWM1A_MARK, PK0MD_01),
+       PINMUX_DATA(SD_D2_MARK, PK0MD_10),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+
+       /* Port A */
+       PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+       PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+       PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+       PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+       /* Port B */
+       PINMUX_GPIO(GPIO_PB22, PB22_DATA),
+       PINMUX_GPIO(GPIO_PB21, PB21_DATA),
+       PINMUX_GPIO(GPIO_PB20, PB20_DATA),
+       PINMUX_GPIO(GPIO_PB19, PB19_DATA),
+       PINMUX_GPIO(GPIO_PB18, PB18_DATA),
+       PINMUX_GPIO(GPIO_PB17, PB17_DATA),
+       PINMUX_GPIO(GPIO_PB16, PB16_DATA),
+       PINMUX_GPIO(GPIO_PB15, PB15_DATA),
+       PINMUX_GPIO(GPIO_PB14, PB14_DATA),
+       PINMUX_GPIO(GPIO_PB13, PB13_DATA),
+       PINMUX_GPIO(GPIO_PB12, PB12_DATA),
+       PINMUX_GPIO(GPIO_PB11, PB11_DATA),
+       PINMUX_GPIO(GPIO_PB10, PB10_DATA),
+       PINMUX_GPIO(GPIO_PB9, PB9_DATA),
+       PINMUX_GPIO(GPIO_PB8, PB8_DATA),
+       PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+       PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+       PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+       PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+       PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+       PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+       PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+
+       /* Port C */
+       PINMUX_GPIO(GPIO_PC10, PC10_DATA),
+       PINMUX_GPIO(GPIO_PC9, PC9_DATA),
+       PINMUX_GPIO(GPIO_PC8, PC8_DATA),
+       PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+       PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+       PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+       PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+       PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+       PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+       PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+       PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+       /* Port D */
+       PINMUX_GPIO(GPIO_PD15, PD15_DATA),
+       PINMUX_GPIO(GPIO_PD14, PD14_DATA),
+       PINMUX_GPIO(GPIO_PD13, PD13_DATA),
+       PINMUX_GPIO(GPIO_PD12, PD12_DATA),
+       PINMUX_GPIO(GPIO_PD11, PD11_DATA),
+       PINMUX_GPIO(GPIO_PD10, PD10_DATA),
+       PINMUX_GPIO(GPIO_PD9, PD9_DATA),
+       PINMUX_GPIO(GPIO_PD8, PD8_DATA),
+       PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+       PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+       PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+       PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+       PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+       PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+       PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+       PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+       /* Port E */
+       PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+       PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+       PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+       PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+       PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+       PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+       /* Port F */
+       PINMUX_GPIO(GPIO_PF12, PF12_DATA),
+       PINMUX_GPIO(GPIO_PF11, PF11_DATA),
+       PINMUX_GPIO(GPIO_PF10, PF10_DATA),
+       PINMUX_GPIO(GPIO_PF9, PF9_DATA),
+       PINMUX_GPIO(GPIO_PF8, PF8_DATA),
+       PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+       PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+       PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+       PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+       PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+       PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+       PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+       PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+       /* Port G */
+       PINMUX_GPIO(GPIO_PG24, PG24_DATA),
+       PINMUX_GPIO(GPIO_PG23, PG23_DATA),
+       PINMUX_GPIO(GPIO_PG22, PG22_DATA),
+       PINMUX_GPIO(GPIO_PG21, PG21_DATA),
+       PINMUX_GPIO(GPIO_PG20, PG20_DATA),
+       PINMUX_GPIO(GPIO_PG19, PG19_DATA),
+       PINMUX_GPIO(GPIO_PG18, PG18_DATA),
+       PINMUX_GPIO(GPIO_PG17, PG17_DATA),
+       PINMUX_GPIO(GPIO_PG16, PG16_DATA),
+       PINMUX_GPIO(GPIO_PG15, PG15_DATA),
+       PINMUX_GPIO(GPIO_PG14, PG14_DATA),
+       PINMUX_GPIO(GPIO_PG13, PG13_DATA),
+       PINMUX_GPIO(GPIO_PG12, PG12_DATA),
+       PINMUX_GPIO(GPIO_PG11, PG11_DATA),
+       PINMUX_GPIO(GPIO_PG10, PG10_DATA),
+       PINMUX_GPIO(GPIO_PG9, PG9_DATA),
+       PINMUX_GPIO(GPIO_PG8, PG8_DATA),
+       PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+       PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+       PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+       PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+       PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+       PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+       PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+       PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+       /* Port H - Port H does not have a Data Register */
+
+       /* Port I - not on device */
+
+       /* Port J */
+       PINMUX_GPIO(GPIO_PJ11, PJ11_DATA),
+       PINMUX_GPIO(GPIO_PJ10, PJ10_DATA),
+       PINMUX_GPIO(GPIO_PJ9, PJ9_DATA),
+       PINMUX_GPIO(GPIO_PJ8, PJ8_DATA),
+       PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
+       PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
+       PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
+       PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
+       PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
+       PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
+       PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
+       PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
+
+       /* Port K */
+       PINMUX_GPIO(GPIO_PK11, PK11_DATA),
+       PINMUX_GPIO(GPIO_PK10, PK10_DATA),
+       PINMUX_GPIO(GPIO_PK9, PK9_DATA),
+       PINMUX_GPIO(GPIO_PK8, PK8_DATA),
+       PINMUX_GPIO(GPIO_PK7, PK7_DATA),
+       PINMUX_GPIO(GPIO_PK6, PK6_DATA),
+       PINMUX_GPIO(GPIO_PK5, PK5_DATA),
+       PINMUX_GPIO(GPIO_PK4, PK4_DATA),
+       PINMUX_GPIO(GPIO_PK3, PK3_DATA),
+       PINMUX_GPIO(GPIO_PK2, PK2_DATA),
+       PINMUX_GPIO(GPIO_PK1, PK1_DATA),
+       PINMUX_GPIO(GPIO_PK0, PK0_DATA),
+
+       /* INTC */
+       PINMUX_GPIO(GPIO_FN_PINT7_PG, PINT7_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT6_PG, PINT6_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT5_PG, PINT5_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT4_PG, PINT4_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT3_PG, PINT3_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT2_PG, PINT2_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT1_PG, PINT1_PG_MARK),
+
+       PINMUX_GPIO(GPIO_FN_IRQ7_PC, IRQ7_PC_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ6_PC, IRQ6_PC_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ5_PC, IRQ5_PC_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ4_PC, IRQ4_PC_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ3_PG, IRQ3_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ2_PG, IRQ2_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ1_PJ, IRQ1_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ0_PJ, IRQ0_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ3_PE, IRQ3_PE_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ2_PE, IRQ2_PE_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ1_PE, IRQ1_PE_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ0_PE, IRQ0_PE_MARK),
+
+       /* WDT */
+       PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
+
+       /* CAN */
+       PINMUX_GPIO(GPIO_FN_CTX1, CTX1_MARK),
+       PINMUX_GPIO(GPIO_FN_CRX1, CRX1_MARK),
+       PINMUX_GPIO(GPIO_FN_CTX0, CTX0_MARK),
+       PINMUX_GPIO(GPIO_FN_CRX0, CRX0_MARK),
+       PINMUX_GPIO(GPIO_FN_CRX0_CRX1, CRX0CRX1_MARK),
+
+       /* DMAC */
+       PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+       PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+
+       /* ADC */
+       PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
+
+       /* BSCh */
+       PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+       PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+       PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+       PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+       PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
+       PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
+       PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
+       PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
+       PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
+       PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
+       PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
+       PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
+       PINMUX_GPIO(GPIO_FN_A13, A13_MARK),
+       PINMUX_GPIO(GPIO_FN_A12, A12_MARK),
+       PINMUX_GPIO(GPIO_FN_A11, A11_MARK),
+       PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
+       PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
+       PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+       PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
+       PINMUX_GPIO(GPIO_FN_A6, A6_MARK),
+       PINMUX_GPIO(GPIO_FN_A5, A5_MARK),
+       PINMUX_GPIO(GPIO_FN_A4, A4_MARK),
+       PINMUX_GPIO(GPIO_FN_A3, A3_MARK),
+       PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
+       PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
+       PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+
+       PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+       PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+       PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+       PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+       PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+       PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+       PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+       PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+       PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
+       PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
+       PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
+       PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
+       PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
+       PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
+       PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
+       PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+       PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+       PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+       PINMUX_GPIO(GPIO_FN_CS3, CS3_MARK),
+       PINMUX_GPIO(GPIO_FN_CS2, CS2_MARK),
+       PINMUX_GPIO(GPIO_FN_CS1, CS1_MARK),
+       PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
+       PINMUX_GPIO(GPIO_FN_CS6CE1B, CS6CE1B_MARK),
+       PINMUX_GPIO(GPIO_FN_CS5CE1A, CS5CE1A_MARK),
+       PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+       PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+       PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+       PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
+       PINMUX_GPIO(GPIO_FN_ICIOWRAH, ICIOWRAH_MARK),
+       PINMUX_GPIO(GPIO_FN_ICIORD, ICIORD_MARK),
+       PINMUX_GPIO(GPIO_FN_WE1DQMUWE, WE1DQMUWE_MARK),
+       PINMUX_GPIO(GPIO_FN_WE0DQML, WE0DQML_MARK),
+       PINMUX_GPIO(GPIO_FN_RAS, RAS_MARK),
+       PINMUX_GPIO(GPIO_FN_CAS, CAS_MARK),
+       PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
+       PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
+       PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+       PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+       PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+
+       /* TMU */
+       PINMUX_GPIO(GPIO_FN_TIOC4D, TIOC4D_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC4C, TIOC4C_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC4B, TIOC4B_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC4A, TIOC4A_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC3D, TIOC3D_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC3C, TIOC3C_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC3B, TIOC3B_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC3A, TIOC3A_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC2B, TIOC2B_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC1B, TIOC1B_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC2A, TIOC2A_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC1A, TIOC1A_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC0D, TIOC0D_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC0C, TIOC0C_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC0B, TIOC0B_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC0A, TIOC0A_MARK),
+       PINMUX_GPIO(GPIO_FN_TCLKD, TCLKD_MARK),
+       PINMUX_GPIO(GPIO_FN_TCLKC, TCLKC_MARK),
+       PINMUX_GPIO(GPIO_FN_TCLKB, TCLKB_MARK),
+       PINMUX_GPIO(GPIO_FN_TCLKA, TCLKA_MARK),
+
+       /* SCIF */
+       PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+       PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
+       PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD5, TXD5_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD5, RXD5_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD6, TXD6_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD6, RXD6_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD7, TXD7_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD7, RXD7_MARK),
+       PINMUX_GPIO(GPIO_FN_RTS1, RTS1_MARK),
+       PINMUX_GPIO(GPIO_FN_CTS1, CTS1_MARK),
+
+       /* RSPI */
+       PINMUX_GPIO(GPIO_FN_RSPCK0, RSPCK0_MARK),
+       PINMUX_GPIO(GPIO_FN_MOSI0, MOSI0_MARK),
+       PINMUX_GPIO(GPIO_FN_MISO0_PF12, MISO0_PF12_MARK),
+       PINMUX_GPIO(GPIO_FN_MISO1, MISO1_MARK),
+       PINMUX_GPIO(GPIO_FN_SSL00, SSL00_MARK),
+       PINMUX_GPIO(GPIO_FN_RSPCK1, RSPCK1_MARK),
+       PINMUX_GPIO(GPIO_FN_MOSI1, MOSI1_MARK),
+       PINMUX_GPIO(GPIO_FN_MISO1_PG19, MISO1_PG19_MARK),
+       PINMUX_GPIO(GPIO_FN_SSL10, SSL10_MARK),
+
+       /* IIC3 */
+       PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
+       PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
+       PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
+       PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
+       PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
+       PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
+
+       /* SSI */
+       PINMUX_GPIO(GPIO_FN_SSISCK0, SSISCK0_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIWS0, SSIWS0_MARK),
+       PINMUX_GPIO(GPIO_FN_SSITXD0, SSITXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIRXD0, SSIRXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIWS1, SSIWS1_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIWS2, SSIWS2_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIWS3, SSIWS3_MARK),
+       PINMUX_GPIO(GPIO_FN_SSISCK1, SSISCK1_MARK),
+       PINMUX_GPIO(GPIO_FN_SSISCK2, SSISCK2_MARK),
+       PINMUX_GPIO(GPIO_FN_SSISCK3, SSISCK3_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIDATA1, SSIDATA1_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIDATA2, SSIDATA2_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIDATA3, SSIDATA3_MARK),
+       PINMUX_GPIO(GPIO_FN_AUDIO_CLK, AUDIO_CLK_MARK),
+
+       /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+       PINMUX_GPIO(GPIO_FN_SIOFTXD, SIOFTXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SIOFRXD, SIOFRXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SIOFSYNC, SIOFSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_SIOFSCK, SIOFSCK_MARK),
+
+       /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+       PINMUX_GPIO(GPIO_FN_SPDIF_IN, SPDIF_IN_MARK),
+       PINMUX_GPIO(GPIO_FN_SPDIF_OUT, SPDIF_OUT_MARK),
+
+       /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+       PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
+       PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+
+       /* VDC3 */
+       PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
+
+       PINMUX_GPIO(GPIO_FN_DV_DATA7, DV_DATA7_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA6, DV_DATA6_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA5, DV_DATA5_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA4, DV_DATA4_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA3, DV_DATA3_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA2, DV_DATA2_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA1, DV_DATA1_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA0, DV_DATA0_MARK),
+
+       PINMUX_GPIO(GPIO_FN_LCD_CLK, LCD_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_EXTCLK, LCD_EXTCLK_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_VSYNC, LCD_VSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_HSYNC, LCD_HSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DE, LCD_DE_MARK),
+
+       PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
+
+       PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+       { PINMUX_CFG_REG("PAIOR0", 0xfffe3812, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PA3_IN, PA3_OUT,
+               PA2_IN, PA2_OUT,
+               PA1_IN, PA1_OUT,
+               PA0_IN, PA0_OUT }
+       },
+
+       { PINMUX_CFG_REG("PBCR5", 0xfffe3824, 16, 4) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PB22MD_00, PB22MD_01, PB22MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PB21MD_0, PB21MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB20MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+
+       },
+       { PINMUX_CFG_REG("PBCR4", 0xfffe3826, 16, 4) {
+               0, PB19MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB18MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB17MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB16MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PBCR3", 0xfffe3828, 16, 4) {
+               0, PB15MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB14MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB13MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB12MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PBCR2", 0xfffe382a, 16, 4) {
+               0, PB11MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB10MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB9MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB8MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PBCR1", 0xfffe382c, 16, 4) {
+               0, PB7MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB6MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB5MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB4MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PBCR0", 0xfffe382e, 16, 4) {
+               0, PB3MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB2MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB1MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PBIOR1", 0xfffe3830, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0,
+               PB22_IN, PB22_OUT,
+               PB21_IN, PB21_OUT,
+               PB20_IN, PB20_OUT,
+               PB19_IN, PB19_OUT,
+               PB18_IN, PB18_OUT,
+               PB17_IN, PB17_OUT,
+               PB16_IN, PB16_OUT }
+       },
+
+       { PINMUX_CFG_REG("PBIOR0", 0xfffe3832, 16, 1) {
+               PB15_IN, PB15_OUT,
+               PB14_IN, PB14_OUT,
+               PB13_IN, PB13_OUT,
+               PB12_IN, PB12_OUT,
+               PB11_IN, PB11_OUT,
+               PB10_IN, PB10_OUT,
+               PB9_IN, PB9_OUT,
+               PB8_IN, PB8_OUT,
+               PB7_IN, PB7_OUT,
+               PB6_IN, PB6_OUT,
+               PB5_IN, PB5_OUT,
+               PB4_IN, PB4_OUT,
+               PB3_IN, PB3_OUT,
+               PB2_IN, PB2_OUT,
+               PB1_IN, PB1_OUT,
+               0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PCCR2", 0xfffe384a, 16, 4) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PC10MD_0, PC10MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PC9MD_0, PC9MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PC8MD_00, PC8MD_01, PC8MD_10, PC8MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PCCR1", 0xfffe384c, 16, 4) {
+               PC7MD_00, PC7MD_01, PC7MD_10, PC7MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PC6MD_00, PC6MD_01, PC6MD_10, PC6MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PC5MD_00, PC5MD_01, PC5MD_10, PC5MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PC4MD_0, PC4MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PCCR0", 0xfffe384e, 16, 4) {
+               PC3MD_0, PC3MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PC2MD_0, PC2MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PC1MD_0, PC1MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PC0MD_0, PC0MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               PC10_IN, PC10_OUT,
+               PC9_IN, PC9_OUT,
+               PC8_IN, PC8_OUT,
+               PC7_IN, PC7_OUT,
+               PC6_IN, PC6_OUT,
+               PC5_IN, PC5_OUT,
+               PC4_IN, PC4_OUT,
+               PC3_IN, PC3_OUT,
+               PC2_IN, PC2_OUT,
+               PC1_IN, PC1_OUT,
+               PC0_IN, PC0_OUT
+        }
+       },
+
+       { PINMUX_CFG_REG("PDCR3", 0xfffe3868, 16, 4) {
+               0, PD15MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PD14MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PD13MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PD12MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PDCR2", 0xfffe386a, 16, 4) {
+               0, PD11MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PD10MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PD9MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PD8MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PDCR1", 0xfffe386c, 16, 4) {
+               0, PD7MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PD6MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PD5MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PD4MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PDCR0", 0xfffe386e, 16, 4) {
+               0, PD3MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PD2MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PD1MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PD0MD_01, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PDIOR0", 0xfffe3872, 16, 1) {
+               PD15_IN, PD15_OUT,
+               PD14_IN, PD14_OUT,
+               PD13_IN, PD13_OUT,
+               PD12_IN, PD12_OUT,
+               PD11_IN, PD11_OUT,
+               PD10_IN, PD10_OUT,
+               PD9_IN, PD9_OUT,
+               PD8_IN, PD8_OUT,
+               PD7_IN, PD7_OUT,
+               PD6_IN, PD6_OUT,
+               PD5_IN, PD5_OUT,
+               PD4_IN, PD4_OUT,
+               PD3_IN, PD3_OUT,
+               PD2_IN, PD2_OUT,
+               PD1_IN, PD1_OUT,
+               PD0_IN, PD0_OUT }
+       },
+
+       { PINMUX_CFG_REG("PECR1", 0xfffe388c, 16, 4) {
+               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,
+               PE5MD_00, PE5MD_01, 0, PE5MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PE4MD_00, PE4MD_01, 0, PE4MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PECR0", 0xfffe388e, 16, 4) {
+               PE3MD_00, PE3MD_01, 0, PE3MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PE2MD_00, PE2MD_01, 0, PE2MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+               PE1MD_100, PE1MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PEIOR0", 0xfffe3892, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0,
+               PE5_IN, PE5_OUT,
+               PE4_IN, PE4_OUT,
+               PE3_IN, PE3_OUT,
+               PE2_IN, PE2_OUT,
+               PE1_IN, PE1_OUT,
+               PE0_IN, PE0_OUT }
+       },
+
+       { PINMUX_CFG_REG("PFCR3", 0xfffe38a8, 16, 4) {
+               PF12MD_000, PF12MD_001, 0, PF12MD_011,
+               PF12MD_100, PF12MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PFCR2", 0xfffe38aa, 16, 4) {
+               PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+               PF11MD_100, PF11MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+               PF10MD_100, PF10MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+               PF9MD_100, PF9MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PF8MD_00, PF8MD_01, PF8MD_10, PF8MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PFCR1", 0xfffe38ac, 16, 4) {
+               PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+               PF7MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+               PF6MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+               PF5MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+               PF4MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PFCR0", 0xfffe38ae, 16, 4) {
+               PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+               PF3MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+               PF2MD_100, PF2MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+               PF1MD_100, PF1MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0
+        }
+       },
+
+       { PINMUX_CFG_REG("PFIOR0", 0xfffe38b2, 16, 1) {
+               0, 0, 0, 0, 0, 0,
+               PF12_IN, PF12_OUT,
+               PF11_IN, PF11_OUT,
+               PF10_IN, PF10_OUT,
+               PF9_IN, PF9_OUT,
+               PF8_IN, PF8_OUT,
+               PF7_IN, PF7_OUT,
+               PF6_IN, PF6_OUT,
+               PF5_IN, PF5_OUT,
+               PF4_IN, PF4_OUT,
+               PF3_IN, PF3_OUT,
+               PF2_IN, PF2_OUT,
+               PF1_IN, PF1_OUT,
+               PF0_IN, PF0_OUT }
+       },
+
+       { PINMUX_CFG_REG("PGCR7", 0xfffe38c0, 16, 4) {
+               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, 0, 0,
+               PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+               PG0MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PGCR6", 0xfffe38c2, 16, 4) {
+               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, 0, 0,
+               PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PGCR5", 0xfffe38c4, 16, 4) {
+               PG23MD_00, PG23MD_01, PG23MD_10, PG23MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG22MD_00, PG22MD_01, PG22MD_10, PG22MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG21MD_00, PG21MD_01, PG21MD_10, PG21MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+               PG20MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PGCR4", 0xfffe38c6, 16, 4) {
+               PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+               PG19MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+               PG18MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG17MD_000, PG17MD_001, PG17MD_010, PG17MD_011,
+               PG17MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG16MD_000, PG16MD_001, PG16MD_010, PG16MD_011,
+               PG16MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PGCR3", 0xfffe38c8, 16, 4) {
+               PG15MD_000, PG15MD_001, PG15MD_010, PG15MD_011,
+               PG15MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG14MD_000, PG14MD_001, PG14MD_010, 0,
+               PG14MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG13MD_000, PG13MD_001, PG13MD_010, 0,
+               PG13MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG12MD_000, PG12MD_001, PG12MD_010, 0,
+               PG12MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PGCR2", 0xfffe38ca, 16, 4) {
+               PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+               PG11MD_100, PG11MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+               PG10MD_100, PG10MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+               PG9MD_100, PG9MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+               PG8MD_100, PG8MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PGCR1", 0xfffe38cc, 16, 4) {
+               PG7MD_00, PG7MD_01, PG7MD_10, PG7MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG6MD_00, PG6MD_01, PG6MD_10, PG6MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG5MD_00, PG5MD_01, PG5MD_10, PG5MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG4MD_00, PG4MD_01, PG4MD_10, PG4MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PGCR0", 0xfffe38ce, 16, 4) {
+               PG3MD_00, PG3MD_01, PG3MD_10, PG3MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG2MD_00, PG2MD_01, PG2MD_10, PG2MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG1MD_00, PG1MD_01, PG1MD_10, PG1MD_11, 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 }
+       },
+       { PINMUX_CFG_REG("PGIOR1", 0xfffe38d0, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0,
+               PG24_IN, PG24_OUT,
+               PG23_IN, PG23_OUT,
+               PG22_IN, PG22_OUT,
+               PG21_IN, PG21_OUT,
+               PG20_IN, PG20_OUT,
+               PG19_IN, PG19_OUT,
+               PG18_IN, PG18_OUT,
+               PG17_IN, PG17_OUT,
+               PG16_IN, PG16_OUT }
+       },
+
+       { PINMUX_CFG_REG("PGIOR0", 0xfffe38d2, 16, 1) {
+               PG15_IN, PG15_OUT,
+               PG14_IN, PG14_OUT,
+               PG13_IN, PG13_OUT,
+               PG12_IN, PG12_OUT,
+               PG11_IN, PG11_OUT,
+               PG10_IN, PG10_OUT,
+               PG9_IN, PG9_OUT,
+               PG8_IN, PG8_OUT,
+               PG7_IN, PG7_OUT,
+               PG6_IN, PG6_OUT,
+               PG5_IN, PG5_OUT,
+               PG4_IN, PG4_OUT,
+               PG3_IN, PG3_OUT,
+               PG2_IN, PG2_OUT,
+               PG1_IN, PG1_OUT,
+               PG0_IN, PG0_OUT
+        }
+       },
+
+       { PINMUX_CFG_REG("PHCR1", 0xfffe38ec, 16, 4) {
+               PH7MD_0, PH7MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PH6MD_0, PH6MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PH5MD_0, PH5MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PH4MD_0, PH4MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PHCR0", 0xfffe38ee, 16, 4) {
+               PH3MD_0, PH3MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PH2MD_0, PH2MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PH1MD_0, PH1MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PH0MD_0, PH0MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PJCR2", 0xfffe390a, 16, 4) {
+               PJ11MD_00, PJ11MD_01, PJ11MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PJ10MD_00, PJ10MD_01, PJ10MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PJ9MD_00, PJ9MD_01, PJ9MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PJ8MD_00, PJ8MD_01, PJ8MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PJCR1", 0xfffe390c, 16, 4) {
+               PJ7MD_00, PJ7MD_01, PJ7MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PJ6MD_00, PJ6MD_01, PJ6MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PJ5MD_00, PJ5MD_01, PJ5MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PJ4MD_00, PJ4MD_01, PJ4MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PJCR0", 0xfffe390e, 16, 4) {
+               PJ3MD_00, PJ3MD_01, PJ3MD_10, PJ3MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+               PJ2MD_100, PJ2MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+               PJ1MD_100, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+               PJ0MD_100, PJ0MD_101, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, }
+       },
+       { PINMUX_CFG_REG("PJIOR0", 0xfffe3912, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PJ11_IN, PJ11_OUT,
+               PJ10_IN, PJ10_OUT,
+               PJ9_IN, PJ9_OUT,
+               PJ8_IN, PJ8_OUT,
+               PJ7_IN, PJ7_OUT,
+               PJ6_IN, PJ6_OUT,
+               PJ5_IN, PJ5_OUT,
+               PJ4_IN, PJ4_OUT,
+               PJ3_IN, PJ3_OUT,
+               PJ2_IN, PJ2_OUT,
+               PJ1_IN, PJ1_OUT,
+               PJ0_IN, PJ0_OUT }
+       },
+
+       { PINMUX_CFG_REG("PKCR2", 0xfffe392a, 16, 4) {
+               PK11MD_00, PK11MD_01, PK11MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PK10MD_00, PK10MD_01, PK10MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PK9MD_00, PK9MD_01, PK9MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PK8MD_00, PK8MD_01, PK8MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PKCR1", 0xfffe392c, 16, 4) {
+               PK7MD_00, PK7MD_01, PK7MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PK6MD_00, PK6MD_01, PK6MD_10, 0,  0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PK5MD_00, PK5MD_01, PK5MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PK4MD_00, PK4MD_01, PK4MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PKCR0", 0xfffe392e, 16, 4) {
+               PK3MD_00, PK3MD_01, PK3MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PK2MD_00, PK2MD_01, PK2MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PK1MD_00, PK1MD_01, PK1MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PK0MD_00, PK0MD_01, PK0MD_10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PKIOR0", 0xfffe3932, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PJ11_IN, PJ11_OUT,
+               PJ10_IN, PJ10_OUT,
+               PJ9_IN, PJ9_OUT,
+               PJ8_IN, PJ8_OUT,
+               PJ7_IN, PJ7_OUT,
+               PJ6_IN, PJ6_OUT,
+               PJ5_IN, PJ5_OUT,
+               PJ4_IN, PJ4_OUT,
+               PJ3_IN, PJ3_OUT,
+               PJ2_IN, PJ2_OUT,
+               PJ1_IN, PJ1_OUT,
+               PJ0_IN, PJ0_OUT }
+       },
+       {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+       { PINMUX_DATA_REG("PADR1", 0xfffe3814, 16) {
+               0, 0, 0, 0, 0, 0, 0, PA3_DATA,
+               0, 0, 0, 0, 0, 0, 0, PA2_DATA }
+       },
+
+       { PINMUX_DATA_REG("PADR0", 0xfffe3816, 16) {
+               0, 0, 0, 0, 0, 0, 0, PA1_DATA,
+               0, 0, 0, 0, 0, 0, 0, PA0_DATA }
+       },
+
+       { PINMUX_DATA_REG("PBDR1", 0xfffe3834, 16) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB22_DATA, PB21_DATA, PB20_DATA,
+               PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA }
+       },
+
+       { PINMUX_DATA_REG("PBDR0", 0xfffe3836, 16) {
+               PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+               PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+               PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+               PB3_DATA, PB2_DATA, PB1_DATA, 0 }
+       },
+
+       { PINMUX_DATA_REG("PCDR0", 0xfffe3856, 16) {
+               0, 0, 0, 0,
+               0, PC10_DATA, PC9_DATA, PC8_DATA,
+               PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+               PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
+       },
+
+       { PINMUX_DATA_REG("PDDR0", 0xfffe3876, 16) {
+               PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+               PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+               PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+               PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
+       },
+
+       { PINMUX_DATA_REG("PEDR0", 0xfffe3896, 16) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, PE5_DATA, PE4_DATA,
+               PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
+       },
+
+       { PINMUX_DATA_REG("PFDR0", 0xfffe38b6, 16) {
+               0, 0, 0, PF12_DATA,
+               PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+               PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+               PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
+       },
+
+       { PINMUX_DATA_REG("PGDR1", 0xfffe38d4, 16) {
+               0, 0, 0, 0, 0, 0, 0, PG24_DATA,
+               PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+               PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA }
+       },
+
+       { PINMUX_DATA_REG("PGDR0", 0xfffe38d6, 16) {
+               PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+               PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+               PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+               PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA }
+       },
+       { PINMUX_DATA_REG("PJDR0", 0xfffe3916, 16) {
+               0, 0, 0, PJ12_DATA,
+               PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+               PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+               PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA }
+       },
+       { PINMUX_DATA_REG("PKDR0", 0xfffe3936, 16) {
+               0, 0, 0, PK12_DATA,
+               PK11_DATA, PK10_DATA, PK9_DATA, PK8_DATA,
+               PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
+               PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA }
+       },
+       { }
+};
+
+static struct pinmux_info sh7264_pinmux_info = {
+       .name = "sh7264_pfc",
+       .reserved_id = PINMUX_RESERVED,
+       .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+       .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END, FORCE_IN },
+       .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END, FORCE_OUT },
+       .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+       .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+       .first_gpio = GPIO_PA3,
+       .last_gpio = GPIO_FN_LCD_M_DISP,
+
+       .gpios = pinmux_gpios,
+       .cfg_regs = pinmux_config_regs,
+       .data_regs = pinmux_data_regs,
+
+       .gpio_data = pinmux_data,
+       .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+static int __init plat_pinmux_setup(void)
+{
+       return register_pinmux(&sh7264_pinmux_info);
+}
+arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c b/arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c
new file mode 100644 (file)
index 0000000..f25127c
--- /dev/null
@@ -0,0 +1,2800 @@
+/*
+ * SH7269 Pinmux
+ *
+ * Copyright (C) 2012  Renesas Electronics Europe Ltd
+ * Copyright (C) 2012  Phil Edworthy
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7269.h>
+
+enum {
+       PINMUX_RESERVED = 0,
+
+       PINMUX_DATA_BEGIN,
+       /* Port A */
+       PA1_DATA, PA0_DATA,
+       /* Port B */
+       PB22_DATA, PB21_DATA, PB20_DATA,
+       PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA,
+       PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+       PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+       PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+       PB3_DATA, PB2_DATA, PB1_DATA,
+       /* Port C */
+       PC8_DATA,
+       PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+       PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+       /* Port D */
+       PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+       PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+       PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+       PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+       /* Port E */
+       PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+       PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+       /* Port F */
+       PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
+       PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA,
+       PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
+       PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+       PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+       PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+       /* Port G */
+       PG27_DATA, PG26_DATA, PG25_DATA, PG24_DATA,
+       PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+       PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA,
+       PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+       PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+       PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+       PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+       /* Port H */
+       /* NOTE - Port H does not have a Data Register, but PH Data is
+          connected to PH Port Register */
+       PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+       PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+       /* Port I - not on device */
+       /* Port J */
+       PJ31_DATA, PJ30_DATA, PJ29_DATA, PJ28_DATA,
+       PJ27_DATA, PJ26_DATA, PJ25_DATA, PJ24_DATA,
+       PJ23_DATA, PJ22_DATA, PJ21_DATA, PJ20_DATA,
+       PJ19_DATA, PJ18_DATA, PJ17_DATA, PJ16_DATA,
+       PJ15_DATA, PJ14_DATA, PJ13_DATA, PJ12_DATA,
+       PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+       PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+       PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA,
+       PINMUX_DATA_END,
+
+       PINMUX_INPUT_BEGIN,
+       FORCE_IN,
+       /* Port A */
+       PA1_IN, PA0_IN,
+       /* Port B */
+       PB22_IN, PB21_IN, PB20_IN,
+       PB19_IN, PB18_IN, PB17_IN, PB16_IN,
+       PB15_IN, PB14_IN, PB13_IN, PB12_IN,
+       PB11_IN, PB10_IN, PB9_IN, PB8_IN,
+       PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+       PB3_IN, PB2_IN, PB1_IN,
+       /* Port C */
+       PC8_IN,
+       PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+       PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+       /* Port D */
+       PD15_IN, PD14_IN, PD13_IN, PD12_IN,
+       PD11_IN, PD10_IN, PD9_IN, PD8_IN,
+       PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+       PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+       /* Port E */
+       PE7_IN, PE6_IN, PE5_IN, PE4_IN,
+       PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+       /* Port F */
+       PF23_IN, PF22_IN, PF21_IN, PF20_IN,
+       PF19_IN, PF18_IN, PF17_IN, PF16_IN,
+       PF15_IN, PF14_IN, PF13_IN, PF12_IN,
+       PF11_IN, PF10_IN, PF9_IN, PF8_IN,
+       PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+       PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+       /* Port G */
+       PG27_IN, PG26_IN, PG25_IN, PG24_IN,
+       PG23_IN, PG22_IN, PG21_IN, PG20_IN,
+       PG19_IN, PG18_IN, PG17_IN, PG16_IN,
+       PG15_IN, PG14_IN, PG13_IN, PG12_IN,
+       PG11_IN, PG10_IN, PG9_IN, PG8_IN,
+       PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+       PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+       /* Port H - Port H does not have a Data Register */
+       /* Port I - not on device */
+       /* Port J */
+       PJ31_IN, PJ30_IN, PJ29_IN, PJ28_IN,
+       PJ27_IN, PJ26_IN, PJ25_IN, PJ24_IN,
+       PJ23_IN, PJ22_IN, PJ21_IN, PJ20_IN,
+       PJ19_IN, PJ18_IN, PJ17_IN, PJ16_IN,
+       PJ15_IN, PJ14_IN, PJ13_IN, PJ12_IN,
+       PJ11_IN, PJ10_IN, PJ9_IN, PJ8_IN,
+       PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
+       PJ3_IN, PJ2_IN, PJ1_IN, PJ0_IN,
+       PINMUX_INPUT_END,
+
+       PINMUX_OUTPUT_BEGIN,
+       FORCE_OUT,
+       /* Port A */
+       PA1_OUT, PA0_OUT,
+       /* Port B */
+       PB22_OUT, PB21_OUT, PB20_OUT,
+       PB19_OUT, PB18_OUT, PB17_OUT, PB16_OUT,
+       PB15_OUT, PB14_OUT, PB13_OUT, PB12_OUT,
+       PB11_OUT, PB10_OUT, PB9_OUT, PB8_OUT,
+       PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+       PB3_OUT, PB2_OUT, PB1_OUT,
+       /* Port C */
+       PC8_OUT,
+       PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+       PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+       /* Port D */
+       PD15_OUT, PD14_OUT, PD13_OUT, PD12_OUT,
+       PD11_OUT, PD10_OUT, PD9_OUT, PD8_OUT,
+       PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+       PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+       /* Port E */
+       PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
+       PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+       /* Port F */
+       PF23_OUT, PF22_OUT, PF21_OUT, PF20_OUT,
+       PF19_OUT, PF18_OUT, PF17_OUT, PF16_OUT,
+       PF15_OUT, PF14_OUT, PF13_OUT, PF12_OUT,
+       PF11_OUT, PF10_OUT, PF9_OUT, PF8_OUT,
+       PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+       PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+       /* Port G */
+       PG27_OUT, PG26_OUT, PG25_OUT, PG24_OUT,
+       PG23_OUT, PG22_OUT, PG21_OUT, PG20_OUT,
+       PG19_OUT, PG18_OUT, PG17_OUT, PG16_OUT,
+       PG15_OUT, PG14_OUT, PG13_OUT, PG12_OUT,
+       PG11_OUT, PG10_OUT, PG9_OUT, PG8_OUT,
+       PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+       PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+       /* Port H - Port H does not have a Data Register */
+       /* Port I - not on device */
+       /* Port J */
+       PJ31_OUT, PJ30_OUT, PJ29_OUT, PJ28_OUT,
+       PJ27_OUT, PJ26_OUT, PJ25_OUT, PJ24_OUT,
+       PJ23_OUT, PJ22_OUT, PJ21_OUT, PJ20_OUT,
+       PJ19_OUT, PJ18_OUT, PJ17_OUT, PJ16_OUT,
+       PJ15_OUT, PJ14_OUT, PJ13_OUT, PJ12_OUT,
+       PJ11_OUT, PJ10_OUT, PJ9_OUT, PJ8_OUT,
+       PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
+       PJ3_OUT, PJ2_OUT, PJ1_OUT, PJ0_OUT,
+       PINMUX_OUTPUT_END,
+
+       PINMUX_FUNCTION_BEGIN,
+       /* Port A */
+       PA1_IOR_IN, PA1_IOR_OUT,
+       PA0_IOR_IN, PA0_IOR_OUT,
+
+       /* Port B */
+       PB22_IOR_IN, PB22_IOR_OUT,
+       PB21_IOR_IN, PB21_IOR_OUT,
+       PB20_IOR_IN, PB20_IOR_OUT,
+       PB19_IOR_IN, PB19_IOR_OUT,
+       PB18_IOR_IN, PB18_IOR_OUT,
+       PB17_IOR_IN, PB17_IOR_OUT,
+       PB16_IOR_IN, PB16_IOR_OUT,
+
+       PB15_IOR_IN, PB15_IOR_OUT,
+       PB14_IOR_IN, PB14_IOR_OUT,
+       PB13_IOR_IN, PB13_IOR_OUT,
+       PB12_IOR_IN, PB12_IOR_OUT,
+       PB11_IOR_IN, PB11_IOR_OUT,
+       PB10_IOR_IN, PB10_IOR_OUT,
+       PB9_IOR_IN, PB9_IOR_OUT,
+       PB8_IOR_IN, PB8_IOR_OUT,
+
+       PB7_IOR_IN, PB7_IOR_OUT,
+       PB6_IOR_IN, PB6_IOR_OUT,
+       PB5_IOR_IN, PB5_IOR_OUT,
+       PB4_IOR_IN, PB4_IOR_OUT,
+       PB3_IOR_IN, PB3_IOR_OUT,
+       PB2_IOR_IN, PB2_IOR_OUT,
+       PB1_IOR_IN, PB1_IOR_OUT,
+       PB0_IOR_IN, PB0_IOR_OUT,
+
+       PB22MD_000, PB22MD_001, PB22MD_010, PB22MD_011,
+       PB22MD_100, PB22MD_101, PB22MD_110, PB22MD_111,
+       PB21MD_00, PB21MD_01, PB21MD_10, PB21MD_11,
+       PB20MD_000, PB20MD_001, PB20MD_010, PB20MD_011,
+       PB20MD_100, PB20MD_101, PB20MD_110, PB20MD_111,
+       PB19MD_000, PB19MD_001, PB19MD_010, PB19MD_011,
+       PB19MD_100, PB19MD_101, PB19MD_110, PB19MD_111,
+       PB18MD_000, PB18MD_001, PB18MD_010, PB18MD_011,
+       PB18MD_100, PB18MD_101, PB18MD_110, PB18MD_111,
+       PB17MD_000, PB17MD_001, PB17MD_010, PB17MD_011,
+       PB17MD_100, PB17MD_101, PB17MD_110, PB17MD_111,
+       PB16MD_000, PB16MD_001, PB16MD_010, PB16MD_011,
+       PB16MD_100, PB16MD_101, PB16MD_110, PB16MD_111,
+       PB15MD_000, PB15MD_001, PB15MD_010, PB15MD_011,
+       PB15MD_100, PB15MD_101, PB15MD_110, PB15MD_111,
+       PB14MD_000, PB14MD_001, PB14MD_010, PB14MD_011,
+       PB14MD_100, PB14MD_101, PB14MD_110, PB14MD_111,
+       PB13MD_000, PB13MD_001, PB13MD_010, PB13MD_011,
+       PB13MD_100, PB13MD_101, PB13MD_110, PB13MD_111,
+       PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
+
+       PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11,
+       PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11,
+       PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11,
+       PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11,
+
+       PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
+       PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
+       PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
+       PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
+
+       PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11,
+       PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11,
+       PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11,
+
+       /* Port C */
+       PC8_IOR_IN, PC8_IOR_OUT,
+       PC7_IOR_IN, PC7_IOR_OUT,
+       PC6_IOR_IN, PC6_IOR_OUT,
+       PC5_IOR_IN, PC5_IOR_OUT,
+       PC4_IOR_IN, PC4_IOR_OUT,
+       PC3_IOR_IN, PC3_IOR_OUT,
+       PC2_IOR_IN, PC2_IOR_OUT,
+       PC1_IOR_IN, PC1_IOR_OUT,
+       PC0_IOR_IN, PC0_IOR_OUT,
+
+       PC8MD_000, PC8MD_001, PC8MD_010, PC8MD_011,
+       PC8MD_100, PC8MD_101, PC8MD_110, PC8MD_111,
+       PC7MD_000, PC7MD_001, PC7MD_010, PC7MD_011,
+       PC7MD_100, PC7MD_101, PC7MD_110, PC7MD_111,
+       PC6MD_000, PC6MD_001, PC6MD_010, PC6MD_011,
+       PC6MD_100, PC6MD_101, PC6MD_110, PC6MD_111,
+       PC5MD_000, PC5MD_001, PC5MD_010, PC5MD_011,
+       PC5MD_100, PC5MD_101, PC5MD_110, PC5MD_111,
+       PC4MD_00, PC4MD_01, PC4MD_10, PC4MD_11,
+
+       PC3MD_00, PC3MD_01, PC3MD_10, PC3MD_11,
+       PC2MD_00, PC2MD_01, PC2MD_10, PC2MD_11,
+       PC1MD_0, PC1MD_1,
+       PC0MD_0, PC0MD_1,
+
+       /* Port D */
+       PD15_IOR_IN, PD15_IOR_OUT,
+       PD14_IOR_IN, PD14_IOR_OUT,
+       PD13_IOR_IN, PD13_IOR_OUT,
+       PD12_IOR_IN, PD12_IOR_OUT,
+       PD11_IOR_IN, PD11_IOR_OUT,
+       PD10_IOR_IN, PD10_IOR_OUT,
+       PD9_IOR_IN, PD9_IOR_OUT,
+       PD8_IOR_IN, PD8_IOR_OUT,
+       PD7_IOR_IN, PD7_IOR_OUT,
+       PD6_IOR_IN, PD6_IOR_OUT,
+       PD5_IOR_IN, PD5_IOR_OUT,
+       PD4_IOR_IN, PD4_IOR_OUT,
+       PD3_IOR_IN, PD3_IOR_OUT,
+       PD2_IOR_IN, PD2_IOR_OUT,
+       PD1_IOR_IN, PD1_IOR_OUT,
+       PD0_IOR_IN, PD0_IOR_OUT,
+
+       PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11,
+       PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11,
+       PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11,
+       PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11,
+
+       PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11,
+       PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11,
+       PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11,
+       PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11,
+
+       PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11,
+       PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11,
+       PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11,
+       PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11,
+
+       PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11,
+       PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11,
+       PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11,
+       PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11,
+
+       /* Port E */
+       PE7_IOR_IN, PE7_IOR_OUT,
+       PE6_IOR_IN, PE6_IOR_OUT,
+       PE5_IOR_IN, PE5_IOR_OUT,
+       PE4_IOR_IN, PE4_IOR_OUT,
+       PE3_IOR_IN, PE3_IOR_OUT,
+       PE2_IOR_IN, PE2_IOR_OUT,
+       PE1_IOR_IN, PE1_IOR_OUT,
+       PE0_IOR_IN, PE0_IOR_OUT,
+
+       PE7MD_00, PE7MD_01, PE7MD_10, PE7MD_11,
+       PE6MD_00, PE6MD_01, PE6MD_10, PE6MD_11,
+       PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11,
+       PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11,
+
+       PE3MD_000, PE3MD_001, PE3MD_010, PE3MD_011,
+       PE3MD_100, PE3MD_101, PE3MD_110, PE3MD_111,
+       PE2MD_000, PE2MD_001, PE2MD_010, PE2MD_011,
+       PE2MD_100, PE2MD_101, PE2MD_110, PE2MD_111,
+       PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+       PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
+       PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11,
+
+       /* Port F */
+       PF23_IOR_IN, PF23_IOR_OUT,
+       PF22_IOR_IN, PF22_IOR_OUT,
+       PF21_IOR_IN, PF21_IOR_OUT,
+       PF20_IOR_IN, PF20_IOR_OUT,
+       PF19_IOR_IN, PF19_IOR_OUT,
+       PF18_IOR_IN, PF18_IOR_OUT,
+       PF17_IOR_IN, PF17_IOR_OUT,
+       PF16_IOR_IN, PF16_IOR_OUT,
+       PF15_IOR_IN, PF15_IOR_OUT,
+       PF14_IOR_IN, PF14_IOR_OUT,
+       PF13_IOR_IN, PF13_IOR_OUT,
+       PF12_IOR_IN, PF12_IOR_OUT,
+       PF11_IOR_IN, PF11_IOR_OUT,
+       PF10_IOR_IN, PF10_IOR_OUT,
+       PF9_IOR_IN, PF9_IOR_OUT,
+       PF8_IOR_IN, PF8_IOR_OUT,
+       PF7_IOR_IN, PF7_IOR_OUT,
+       PF6_IOR_IN, PF6_IOR_OUT,
+       PF5_IOR_IN, PF5_IOR_OUT,
+       PF4_IOR_IN, PF4_IOR_OUT,
+       PF3_IOR_IN, PF3_IOR_OUT,
+       PF2_IOR_IN, PF2_IOR_OUT,
+       PF1_IOR_IN, PF1_IOR_OUT,
+       PF0_IOR_IN, PF0_IOR_OUT,
+
+       PF23MD_000, PF23MD_001, PF23MD_010, PF23MD_011,
+       PF23MD_100, PF23MD_101, PF23MD_110, PF23MD_111,
+       PF22MD_000, PF22MD_001, PF22MD_010, PF22MD_011,
+       PF22MD_100, PF22MD_101, PF22MD_110, PF22MD_111,
+       PF21MD_000, PF21MD_001, PF21MD_010, PF21MD_011,
+       PF21MD_100, PF21MD_101, PF21MD_110, PF21MD_111,
+       PF20MD_000, PF20MD_001, PF20MD_010, PF20MD_011,
+       PF20MD_100, PF20MD_101, PF20MD_110, PF20MD_111,
+
+       PF19MD_000, PF19MD_001, PF19MD_010, PF19MD_011,
+       PF19MD_100, PF19MD_101, PF19MD_110, PF19MD_111,
+       PF18MD_000, PF18MD_001, PF18MD_010, PF18MD_011,
+       PF18MD_100, PF18MD_101, PF18MD_110, PF18MD_111,
+       PF17MD_000, PF17MD_001, PF17MD_010, PF17MD_011,
+       PF17MD_100, PF17MD_101, PF17MD_110, PF17MD_111,
+       PF16MD_000, PF16MD_001, PF16MD_010, PF16MD_011,
+       PF16MD_100, PF16MD_101, PF16MD_110, PF16MD_111,
+
+       PF15MD_000, PF15MD_001, PF15MD_010, PF15MD_011,
+       PF15MD_100, PF15MD_101, PF15MD_110, PF15MD_111,
+       PF14MD_000, PF14MD_001, PF14MD_010, PF14MD_011,
+       PF14MD_100, PF14MD_101, PF14MD_110, PF14MD_111,
+       PF13MD_000, PF13MD_001, PF13MD_010, PF13MD_011,
+       PF13MD_100, PF13MD_101, PF13MD_110, PF13MD_111,
+       PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
+       PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
+
+       PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+       PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
+       PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+       PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
+       PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+       PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
+       PF8MD_000, PF8MD_001, PF8MD_010, PF8MD_011,
+       PF8MD_100, PF8MD_101, PF8MD_110, PF8MD_111,
+
+       PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+       PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
+       PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+       PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
+       PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+       PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
+       PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+       PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
+
+       PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+       PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
+       PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+       PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
+       PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+       PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
+       PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+       PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
+
+       /* Port G */
+       PG27_IOR_IN, PG27_IOR_OUT,
+       PG26_IOR_IN, PG26_IOR_OUT,
+       PG25_IOR_IN, PG25_IOR_OUT,
+       PG24_IOR_IN, PG24_IOR_OUT,
+       PG23_IOR_IN, PG23_IOR_OUT,
+       PG22_IOR_IN, PG22_IOR_OUT,
+       PG21_IOR_IN, PG21_IOR_OUT,
+       PG20_IOR_IN, PG20_IOR_OUT,
+       PG19_IOR_IN, PG19_IOR_OUT,
+       PG18_IOR_IN, PG18_IOR_OUT,
+       PG17_IOR_IN, PG17_IOR_OUT,
+       PG16_IOR_IN, PG16_IOR_OUT,
+       PG15_IOR_IN, PG15_IOR_OUT,
+       PG14_IOR_IN, PG14_IOR_OUT,
+       PG13_IOR_IN, PG13_IOR_OUT,
+       PG12_IOR_IN, PG12_IOR_OUT,
+       PG11_IOR_IN, PG11_IOR_OUT,
+       PG10_IOR_IN, PG10_IOR_OUT,
+       PG9_IOR_IN, PG9_IOR_OUT,
+       PG8_IOR_IN, PG8_IOR_OUT,
+       PG7_IOR_IN, PG7_IOR_OUT,
+       PG6_IOR_IN, PG6_IOR_OUT,
+       PG5_IOR_IN, PG5_IOR_OUT,
+       PG4_IOR_IN, PG4_IOR_OUT,
+       PG3_IOR_IN, PG3_IOR_OUT,
+       PG2_IOR_IN, PG2_IOR_OUT,
+       PG1_IOR_IN, PG1_IOR_OUT,
+       PG0_IOR_IN, PG0_IOR_OUT,
+
+       PG27MD_00, PG27MD_01, PG27MD_10, PG27MD_11,
+       PG26MD_00, PG26MD_01, PG26MD_10, PG26MD_11,
+       PG25MD_00, PG25MD_01, PG25MD_10, PG25MD_11,
+       PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11,
+
+       PG23MD_000, PG23MD_001, PG23MD_010, PG23MD_011,
+       PG23MD_100, PG23MD_101, PG23MD_110, PG23MD_111,
+       PG22MD_000, PG22MD_001, PG22MD_010, PG22MD_011,
+       PG22MD_100, PG22MD_101, PG22MD_110, PG22MD_111,
+       PG21MD_000, PG21MD_001, PG21MD_010, PG21MD_011,
+       PG21MD_100, PG21MD_101, PG21MD_110, PG21MD_111,
+       PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+       PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
+
+       PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+       PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
+       PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+       PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
+       PG17MD_00, PG17MD_01, PG17MD_10, PG17MD_11,
+       PG16MD_00, PG16MD_01, PG16MD_10, PG16MD_11,
+
+       PG15MD_00, PG15MD_01, PG15MD_10, PG15MD_11,
+       PG14MD_00, PG14MD_01, PG14MD_10, PG14MD_11,
+       PG13MD_00, PG13MD_01, PG13MD_10, PG13MD_11,
+       PG12MD_00, PG12MD_01, PG12MD_10, PG12MD_11,
+
+       PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+       PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
+       PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+       PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
+       PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+       PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
+       PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+       PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
+
+       PG7MD_000, PG7MD_001, PG7MD_010, PG7MD_011,
+       PG7MD_100, PG7MD_101, PG7MD_110, PG7MD_111,
+       PG6MD_000, PG6MD_001, PG6MD_010, PG6MD_011,
+       PG6MD_100, PG6MD_101, PG6MD_110, PG6MD_111,
+       PG5MD_000, PG5MD_001, PG5MD_010, PG5MD_011,
+       PG5MD_100, PG5MD_101, PG5MD_110, PG5MD_111,
+       PG4MD_000, PG4MD_001, PG4MD_010, PG4MD_011,
+       PG4MD_100, PG4MD_101, PG4MD_110, PG4MD_111,
+
+       PG3MD_000, PG3MD_001, PG3MD_010, PG3MD_011,
+       PG3MD_100, PG3MD_101, PG3MD_110, PG3MD_111,
+       PG2MD_000, PG2MD_001, PG2MD_010, PG2MD_011,
+       PG2MD_100, PG2MD_101, PG2MD_110, PG2MD_111,
+       PG1MD_000, PG1MD_001, PG1MD_010, PG1MD_011,
+       PG1MD_100, PG1MD_101, PG1MD_110, PG1MD_111,
+       PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+       PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
+
+       /* Port H */
+       PH7MD_00, PH7MD_01, PH7MD_10, PH7MD_11,
+       PH6MD_00, PH6MD_01, PH6MD_10, PH6MD_11,
+       PH5MD_00, PH5MD_01, PH5MD_10, PH5MD_11,
+       PH4MD_00, PH4MD_01, PH4MD_10, PH4MD_11,
+
+       PH3MD_00, PH3MD_01, PH3MD_10, PH3MD_11,
+       PH2MD_00, PH2MD_01, PH2MD_10, PH2MD_11,
+       PH1MD_00, PH1MD_01, PH1MD_10, PH1MD_11,
+       PH0MD_00, PH0MD_01, PH0MD_10, PH0MD_11,
+
+       /* Port I - not on device */
+
+       /* Port J */
+       PJ31_IOR_IN, PJ31_IOR_OUT,
+       PJ30_IOR_IN, PJ30_IOR_OUT,
+       PJ29_IOR_IN, PJ29_IOR_OUT,
+       PJ28_IOR_IN, PJ28_IOR_OUT,
+       PJ27_IOR_IN, PJ27_IOR_OUT,
+       PJ26_IOR_IN, PJ26_IOR_OUT,
+       PJ25_IOR_IN, PJ25_IOR_OUT,
+       PJ24_IOR_IN, PJ24_IOR_OUT,
+       PJ23_IOR_IN, PJ23_IOR_OUT,
+       PJ22_IOR_IN, PJ22_IOR_OUT,
+       PJ21_IOR_IN, PJ21_IOR_OUT,
+       PJ20_IOR_IN, PJ20_IOR_OUT,
+       PJ19_IOR_IN, PJ19_IOR_OUT,
+       PJ18_IOR_IN, PJ18_IOR_OUT,
+       PJ17_IOR_IN, PJ17_IOR_OUT,
+       PJ16_IOR_IN, PJ16_IOR_OUT,
+       PJ15_IOR_IN, PJ15_IOR_OUT,
+       PJ14_IOR_IN, PJ14_IOR_OUT,
+       PJ13_IOR_IN, PJ13_IOR_OUT,
+       PJ12_IOR_IN, PJ12_IOR_OUT,
+       PJ11_IOR_IN, PJ11_IOR_OUT,
+       PJ10_IOR_IN, PJ10_IOR_OUT,
+       PJ9_IOR_IN, PJ9_IOR_OUT,
+       PJ8_IOR_IN, PJ8_IOR_OUT,
+       PJ7_IOR_IN, PJ7_IOR_OUT,
+       PJ6_IOR_IN, PJ6_IOR_OUT,
+       PJ5_IOR_IN, PJ5_IOR_OUT,
+       PJ4_IOR_IN, PJ4_IOR_OUT,
+       PJ3_IOR_IN, PJ3_IOR_OUT,
+       PJ2_IOR_IN, PJ2_IOR_OUT,
+       PJ1_IOR_IN, PJ1_IOR_OUT,
+       PJ0_IOR_IN, PJ0_IOR_OUT,
+
+       PJ31MD_0, PJ31MD_1,
+       PJ30MD_000, PJ30MD_001, PJ30MD_010, PJ30MD_011,
+       PJ30MD_100, PJ30MD_101, PJ30MD_110, PJ30MD_111,
+       PJ29MD_000, PJ29MD_001, PJ29MD_010, PJ29MD_011,
+       PJ29MD_100, PJ29MD_101, PJ29MD_110, PJ29MD_111,
+       PJ28MD_000, PJ28MD_001, PJ28MD_010, PJ28MD_011,
+       PJ28MD_100, PJ28MD_101, PJ28MD_110, PJ28MD_111,
+
+       PJ27MD_000, PJ27MD_001, PJ27MD_010, PJ27MD_011,
+       PJ27MD_100, PJ27MD_101, PJ27MD_110, PJ27MD_111,
+       PJ26MD_000, PJ26MD_001, PJ26MD_010, PJ26MD_011,
+       PJ26MD_100, PJ26MD_101, PJ26MD_110, PJ26MD_111,
+       PJ25MD_000, PJ25MD_001, PJ25MD_010, PJ25MD_011,
+       PJ25MD_100, PJ25MD_101, PJ25MD_110, PJ25MD_111,
+       PJ24MD_000, PJ24MD_001, PJ24MD_010, PJ24MD_011,
+       PJ24MD_100, PJ24MD_101, PJ24MD_110, PJ24MD_111,
+
+       PJ23MD_000, PJ23MD_001, PJ23MD_010, PJ23MD_011,
+       PJ23MD_100, PJ23MD_101, PJ23MD_110, PJ23MD_111,
+       PJ22MD_000, PJ22MD_001, PJ22MD_010, PJ22MD_011,
+       PJ22MD_100, PJ22MD_101, PJ22MD_110, PJ22MD_111,
+       PJ21MD_000, PJ21MD_001, PJ21MD_010, PJ21MD_011,
+       PJ21MD_100, PJ21MD_101, PJ21MD_110, PJ21MD_111,
+       PJ20MD_000, PJ20MD_001, PJ20MD_010, PJ20MD_011,
+       PJ20MD_100, PJ20MD_101, PJ20MD_110, PJ20MD_111,
+
+       PJ19MD_000, PJ19MD_001, PJ19MD_010, PJ19MD_011,
+       PJ19MD_100, PJ19MD_101, PJ19MD_110, PJ19MD_111,
+       PJ18MD_000, PJ18MD_001, PJ18MD_010, PJ18MD_011,
+       PJ18MD_100, PJ18MD_101, PJ18MD_110, PJ18MD_111,
+       PJ17MD_000, PJ17MD_001, PJ17MD_010, PJ17MD_011,
+       PJ17MD_100, PJ17MD_101, PJ17MD_110, PJ17MD_111,
+       PJ16MD_000, PJ16MD_001, PJ16MD_010, PJ16MD_011,
+       PJ16MD_100, PJ16MD_101, PJ16MD_110, PJ16MD_111,
+
+       PJ15MD_000, PJ15MD_001, PJ15MD_010, PJ15MD_011,
+       PJ15MD_100, PJ15MD_101, PJ15MD_110, PJ15MD_111,
+       PJ14MD_000, PJ14MD_001, PJ14MD_010, PJ14MD_011,
+       PJ14MD_100, PJ14MD_101, PJ14MD_110, PJ14MD_111,
+       PJ13MD_000, PJ13MD_001, PJ13MD_010, PJ13MD_011,
+       PJ13MD_100, PJ13MD_101, PJ13MD_110, PJ13MD_111,
+       PJ12MD_000, PJ12MD_001, PJ12MD_010, PJ12MD_011,
+       PJ12MD_100, PJ12MD_101, PJ12MD_110, PJ12MD_111,
+
+       PJ11MD_000, PJ11MD_001, PJ11MD_010, PJ11MD_011,
+       PJ11MD_100, PJ11MD_101, PJ11MD_110, PJ11MD_111,
+       PJ10MD_000, PJ10MD_001, PJ10MD_010, PJ10MD_011,
+       PJ10MD_100, PJ10MD_101, PJ10MD_110, PJ10MD_111,
+       PJ9MD_000, PJ9MD_001, PJ9MD_010, PJ9MD_011,
+       PJ9MD_100, PJ9MD_101, PJ9MD_110, PJ9MD_111,
+       PJ8MD_000, PJ8MD_001, PJ8MD_010, PJ8MD_011,
+       PJ8MD_100, PJ8MD_101, PJ8MD_110, PJ8MD_111,
+
+       PJ7MD_000, PJ7MD_001, PJ7MD_010, PJ7MD_011,
+       PJ7MD_100, PJ7MD_101, PJ7MD_110, PJ7MD_111,
+       PJ6MD_000, PJ6MD_001, PJ6MD_010, PJ6MD_011,
+       PJ6MD_100, PJ6MD_101, PJ6MD_110, PJ6MD_111,
+       PJ5MD_000, PJ5MD_001, PJ5MD_010, PJ5MD_011,
+       PJ5MD_100, PJ5MD_101, PJ5MD_110, PJ5MD_111,
+       PJ4MD_000, PJ4MD_001, PJ4MD_010, PJ4MD_011,
+       PJ4MD_100, PJ4MD_101, PJ4MD_110, PJ4MD_111,
+
+       PJ3MD_000, PJ3MD_001, PJ3MD_010, PJ3MD_011,
+       PJ3MD_100, PJ3MD_101, PJ3MD_110, PJ3MD_111,
+       PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+       PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
+       PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+       PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
+       PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+       PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
+
+       PINMUX_FUNCTION_END,
+
+       PINMUX_MARK_BEGIN,
+       /* Port H */
+       PHAN7_MARK, PHAN6_MARK, PHAN5_MARK, PHAN4_MARK,
+       PHAN3_MARK, PHAN2_MARK, PHAN1_MARK, PHAN0_MARK,
+
+       /* IRQs */
+       IRQ7_PG_MARK, IRQ6_PG_MARK, IRQ5_PG_MARK, IRQ4_PG_MARK,
+       IRQ3_PG_MARK, IRQ2_PG_MARK, IRQ1_PG_MARK, IRQ0_PG_MARK,
+       IRQ7_PF_MARK, IRQ6_PF_MARK, IRQ5_PF_MARK, IRQ4_PF_MARK,
+       IRQ3_PJ_MARK, IRQ2_PJ_MARK, IRQ1_PJ_MARK, IRQ0_PJ_MARK,
+       IRQ1_PC_MARK, IRQ0_PC_MARK,
+
+       PINT7_PG_MARK, PINT6_PG_MARK, PINT5_PG_MARK, PINT4_PG_MARK,
+       PINT3_PG_MARK, PINT2_PG_MARK, PINT1_PG_MARK, PINT0_PG_MARK,
+       PINT7_PH_MARK, PINT6_PH_MARK, PINT5_PH_MARK, PINT4_PH_MARK,
+       PINT3_PH_MARK, PINT2_PH_MARK, PINT1_PH_MARK, PINT0_PH_MARK,
+       PINT7_PJ_MARK, PINT6_PJ_MARK, PINT5_PJ_MARK, PINT4_PJ_MARK,
+       PINT3_PJ_MARK, PINT2_PJ_MARK, PINT1_PJ_MARK, PINT0_PJ_MARK,
+
+       /* SD */
+       SD_D0_MARK, SD_D1_MARK, SD_D2_MARK, SD_D3_MARK,
+       SD_WP_MARK, SD_CLK_MARK, SD_CMD_MARK, SD_CD_MARK,
+
+       /* MMC */
+       MMC_D0_MARK, MMC_D1_MARK, MMC_D2_MARK, MMC_D3_MARK,
+       MMC_D4_MARK, MMC_D5_MARK, MMC_D6_MARK, MMC_D7_MARK,
+       MMC_CLK_MARK, MMC_CMD_MARK, MMC_CD_MARK,
+
+       /* PWM */
+       PWM1A_MARK, PWM1B_MARK, PWM1C_MARK, PWM1D_MARK,
+       PWM1E_MARK, PWM1F_MARK, PWM1G_MARK, PWM1H_MARK,
+       PWM2A_MARK, PWM2B_MARK, PWM2C_MARK, PWM2D_MARK,
+       PWM2E_MARK, PWM2F_MARK, PWM2G_MARK, PWM2H_MARK,
+
+       /* IEBus */
+       IERXD_MARK, IETXD_MARK,
+
+       /* WDT */
+       WDTOVF_MARK,
+
+       /* DMAC */
+       TEND0_MARK, DACK0_MARK, DREQ0_MARK,
+       TEND1_MARK, DACK1_MARK, DREQ1_MARK,
+
+       /* ADC */
+       ADTRG_MARK,
+
+       /* BSC */
+       A25_MARK, A24_MARK,
+       A23_MARK, A22_MARK, A21_MARK, A20_MARK,
+       A19_MARK, A18_MARK, A17_MARK, A16_MARK,
+       A15_MARK, A14_MARK, A13_MARK, A12_MARK,
+       A11_MARK, A10_MARK, A9_MARK, A8_MARK,
+       A7_MARK, A6_MARK, A5_MARK, A4_MARK,
+       A3_MARK, A2_MARK, A1_MARK, A0_MARK,
+       D31_MARK, D30_MARK, D29_MARK, D28_MARK,
+       D27_MARK, D26_MARK, D25_MARK, D24_MARK,
+       D23_MARK, D22_MARK, D21_MARK, D20_MARK,
+       D19_MARK, D18_MARK, D17_MARK, D16_MARK,
+       D15_MARK, D14_MARK, D13_MARK, D12_MARK,
+       D11_MARK, D10_MARK, D9_MARK, D8_MARK,
+       D7_MARK, D6_MARK, D5_MARK, D4_MARK,
+       D3_MARK, D2_MARK, D1_MARK, D0_MARK,
+       BS_MARK,
+       CS4_MARK, CS3_MARK, CS2_MARK, CS1_MARK, CS0_MARK,
+       CS5CE1A_MARK,
+       CE2A_MARK, CE2B_MARK,
+       RD_MARK, RDWR_MARK,
+       WE3ICIOWRAHDQMUU_MARK,
+       WE2ICIORDDQMUL_MARK,
+       WE1DQMUWE_MARK,
+       WE0DQML_MARK,
+       RAS_MARK, CAS_MARK, CKE_MARK,
+       WAIT_MARK, BREQ_MARK, BACK_MARK, IOIS16_MARK,
+
+       /* TMU */
+       TIOC0A_MARK, TIOC0B_MARK, TIOC0C_MARK, TIOC0D_MARK,
+       TIOC1A_MARK, TIOC1B_MARK,
+       TIOC2A_MARK, TIOC2B_MARK,
+       TIOC3A_MARK, TIOC3B_MARK, TIOC3C_MARK, TIOC3D_MARK,
+       TIOC4A_MARK, TIOC4B_MARK, TIOC4C_MARK, TIOC4D_MARK,
+       TCLKA_MARK, TCLKB_MARK, TCLKC_MARK, TCLKD_MARK,
+
+       /* SCIF */
+       SCK0_MARK, RXD0_MARK, TXD0_MARK,
+       SCK1_MARK, RXD1_MARK, TXD1_MARK, RTS1_MARK, CTS1_MARK,
+       SCK2_MARK, RXD2_MARK, TXD2_MARK,
+       SCK3_MARK, RXD3_MARK, TXD3_MARK,
+       SCK4_MARK, RXD4_MARK, TXD4_MARK,
+       SCK5_MARK, RXD5_MARK, TXD5_MARK, RTS5_MARK, CTS5_MARK,
+       SCK6_MARK, RXD6_MARK, TXD6_MARK,
+       SCK7_MARK, RXD7_MARK, TXD7_MARK, RTS7_MARK, CTS7_MARK,
+
+       /* RSPI */
+       MISO0_PB20_MARK, MOSI0_PB19_MARK, SSL00_PB18_MARK, RSPCK0_PB17_MARK,
+       MISO0_PJ19_MARK, MOSI0_PJ18_MARK, SSL00_PJ17_MARK, RSPCK0_PJ16_MARK,
+       MISO1_MARK, MOSI1_MARK, SSL10_MARK, RSPCK1_MARK,
+
+       /* IIC3 */
+       SCL0_MARK, SDA0_MARK,
+       SCL1_MARK, SDA1_MARK,
+       SCL2_MARK, SDA2_MARK,
+       SCL3_MARK, SDA3_MARK,
+
+       /* SSI */
+       SSISCK0_MARK, SSIWS0_MARK, SSITXD0_MARK, SSIRXD0_MARK,
+       SSISCK1_MARK, SSIWS1_MARK, SSIDATA1_MARK,
+       SSISCK2_MARK, SSIWS2_MARK, SSIDATA2_MARK,
+       SSISCK3_MARK, SSIWS3_MARK, SSIDATA3_MARK,
+       SSISCK4_MARK, SSIWS4_MARK, SSIDATA4_MARK,
+       SSISCK5_MARK, SSIWS5_MARK, SSIDATA5_MARK,
+       AUDIO_CLK_MARK,
+       AUDIO_XOUT_MARK,
+
+       /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+       SIOFTXD_MARK, SIOFRXD_MARK, SIOFSYNC_MARK, SIOFSCK_MARK,
+
+       /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+       SPDIF_IN_MARK, SPDIF_OUT_MARK,
+       SPDIF_IN_PJ24_MARK, SPDIF_OUT_PJ25_MARK,
+
+       /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+       FCE_MARK,
+       FRB_MARK,
+
+       /* CAN */
+       CRX0_MARK, CTX0_MARK,
+       CRX1_MARK, CTX1_MARK,
+       CRX2_MARK, CTX2_MARK,
+       CRX0CRX1_MARK,
+       CRX0CRX1CRX2_MARK,
+       CTX0CTX1CTX2_MARK,
+       CRX1_PJ22_MARK, CTX1_PJ23_MARK,
+       CRX2_PJ20_MARK, CTX2_PJ21_MARK,
+       CRX0CRX1_PJ22_MARK,
+       CRX0CRX1CRX2_PJ20_MARK,
+
+       /* VDC */
+       DV_CLK_MARK,
+       DV_VSYNC_MARK, DV_HSYNC_MARK,
+       DV_DATA23_MARK, DV_DATA22_MARK, DV_DATA21_MARK, DV_DATA20_MARK,
+       DV_DATA19_MARK, DV_DATA18_MARK, DV_DATA17_MARK, DV_DATA16_MARK,
+       DV_DATA15_MARK, DV_DATA14_MARK, DV_DATA13_MARK, DV_DATA12_MARK,
+       DV_DATA11_MARK, DV_DATA10_MARK, DV_DATA9_MARK, DV_DATA8_MARK,
+       DV_DATA7_MARK, DV_DATA6_MARK, DV_DATA5_MARK, DV_DATA4_MARK,
+       DV_DATA3_MARK, DV_DATA2_MARK, DV_DATA1_MARK, DV_DATA0_MARK,
+       LCD_CLK_MARK, LCD_EXTCLK_MARK,
+       LCD_VSYNC_MARK, LCD_HSYNC_MARK, LCD_DE_MARK,
+       LCD_DATA23_MARK, LCD_DATA22_MARK, LCD_DATA21_MARK, LCD_DATA20_MARK,
+       LCD_DATA19_MARK, LCD_DATA18_MARK, LCD_DATA17_MARK, LCD_DATA16_MARK,
+       LCD_DATA15_MARK, LCD_DATA14_MARK, LCD_DATA13_MARK, LCD_DATA12_MARK,
+       LCD_DATA11_MARK, LCD_DATA10_MARK, LCD_DATA9_MARK, LCD_DATA8_MARK,
+       LCD_DATA7_MARK, LCD_DATA6_MARK, LCD_DATA5_MARK, LCD_DATA4_MARK,
+       LCD_DATA3_MARK, LCD_DATA2_MARK, LCD_DATA1_MARK, LCD_DATA0_MARK,
+       LCD_TCON6_MARK, LCD_TCON5_MARK, LCD_TCON4_MARK,
+       LCD_TCON3_MARK, LCD_TCON2_MARK, LCD_TCON1_MARK, LCD_TCON0_MARK,
+       LCD_M_DISP_MARK,
+       PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+
+       /* Port A */
+       PINMUX_DATA(PA1_DATA, PA1_IN),
+       PINMUX_DATA(PA0_DATA, PA0_IN),
+
+       /* Port B */
+       PINMUX_DATA(PB22_DATA, PB22MD_000, PB22_IN, PB22_OUT),
+       PINMUX_DATA(A22_MARK, PB22MD_001),
+       PINMUX_DATA(CTX2_MARK, PB22MD_010),
+       PINMUX_DATA(IETXD_MARK, PB22MD_011),
+       PINMUX_DATA(CS4_MARK, PB22MD_100),
+
+       PINMUX_DATA(PB21_DATA, PB21MD_00, PB21_IN, PB21_OUT),
+       PINMUX_DATA(A21_MARK, PB21MD_01),
+       PINMUX_DATA(CRX2_MARK, PB21MD_10),
+       PINMUX_DATA(IERXD_MARK, PB21MD_11),
+
+       PINMUX_DATA(A20_MARK, PB20MD_001),
+       PINMUX_DATA(A19_MARK, PB19MD_001),
+       PINMUX_DATA(A18_MARK, PB18MD_001),
+       PINMUX_DATA(A17_MARK, PB17MD_001),
+       PINMUX_DATA(A16_MARK, PB16MD_001),
+       PINMUX_DATA(A15_MARK, PB15MD_001),
+       PINMUX_DATA(A14_MARK, PB14MD_001),
+       PINMUX_DATA(A13_MARK, PB13MD_001),
+       PINMUX_DATA(A12_MARK, PB12MD_01),
+       PINMUX_DATA(A11_MARK, PB11MD_01),
+       PINMUX_DATA(A10_MARK, PB10MD_01),
+       PINMUX_DATA(A9_MARK, PB9MD_01),
+       PINMUX_DATA(A8_MARK, PB8MD_01),
+       PINMUX_DATA(A7_MARK, PB7MD_01),
+       PINMUX_DATA(A6_MARK, PB6MD_01),
+       PINMUX_DATA(A5_MARK, PB5MD_01),
+       PINMUX_DATA(A4_MARK, PB4MD_01),
+       PINMUX_DATA(A3_MARK, PB3MD_01),
+       PINMUX_DATA(A2_MARK, PB2MD_01),
+       PINMUX_DATA(A1_MARK, PB1MD_01),
+
+       /* Port C */
+       PINMUX_DATA(PC8_DATA, PC8MD_000),
+       PINMUX_DATA(CS3_MARK, PC8MD_001),
+       PINMUX_DATA(TXD7_MARK, PC8MD_010),
+       PINMUX_DATA(CTX1_MARK, PC8MD_011),
+
+       PINMUX_DATA(PC7_DATA, PC7MD_000),
+       PINMUX_DATA(CKE_MARK, PC7MD_001),
+       PINMUX_DATA(RXD7_MARK, PC7MD_010),
+       PINMUX_DATA(CRX1_MARK, PC7MD_011),
+       PINMUX_DATA(CRX0CRX1_MARK, PC7MD_100),
+       PINMUX_DATA(IRQ1_PC_MARK, PC7MD_101),
+
+       PINMUX_DATA(PC6_DATA, PC6MD_000),
+       PINMUX_DATA(CAS_MARK, PC6MD_001),
+       PINMUX_DATA(SCK7_MARK, PC6MD_010),
+       PINMUX_DATA(CTX0_MARK, PC6MD_011),
+
+       PINMUX_DATA(PC5_DATA, PC5MD_000),
+       PINMUX_DATA(RAS_MARK, PC5MD_001),
+       PINMUX_DATA(CRX0_MARK, PC5MD_011),
+       PINMUX_DATA(CTX0CTX1CTX2_MARK, PC5MD_100),
+       PINMUX_DATA(IRQ0_PC_MARK, PC5MD_101),
+
+       PINMUX_DATA(PC4_DATA, PC4MD_00),
+       PINMUX_DATA(WE1DQMUWE_MARK, PC4MD_01),
+       PINMUX_DATA(TXD6_MARK, PC4MD_10),
+
+       PINMUX_DATA(PC3_DATA, PC3MD_00),
+       PINMUX_DATA(WE0DQML_MARK, PC3MD_01),
+       PINMUX_DATA(RXD6_MARK, PC3MD_10),
+
+       PINMUX_DATA(PC2_DATA, PC2MD_00),
+       PINMUX_DATA(RDWR_MARK, PC2MD_01),
+       PINMUX_DATA(SCK5_MARK, PC2MD_10),
+
+       PINMUX_DATA(PC1_DATA, PC1MD_0),
+       PINMUX_DATA(RD_MARK, PC1MD_1),
+
+       PINMUX_DATA(PC0_DATA, PC0MD_0),
+       PINMUX_DATA(CS0_MARK, PC0MD_1),
+
+       /* Port D */
+       PINMUX_DATA(D15_MARK, PD15MD_01),
+       PINMUX_DATA(D14_MARK, PD14MD_01),
+
+       PINMUX_DATA(PD13_DATA, PD13MD_00),
+       PINMUX_DATA(D13_MARK, PD13MD_01),
+       PINMUX_DATA(PWM2F_MARK, PD13MD_10),
+
+       PINMUX_DATA(PD12_DATA, PD12MD_00),
+       PINMUX_DATA(D12_MARK, PD12MD_01),
+       PINMUX_DATA(PWM2E_MARK, PD12MD_10),
+
+       PINMUX_DATA(D11_MARK, PD11MD_01),
+       PINMUX_DATA(D10_MARK, PD10MD_01),
+       PINMUX_DATA(D9_MARK, PD9MD_01),
+       PINMUX_DATA(D8_MARK, PD8MD_01),
+       PINMUX_DATA(D7_MARK, PD7MD_01),
+       PINMUX_DATA(D6_MARK, PD6MD_01),
+       PINMUX_DATA(D5_MARK, PD5MD_01),
+       PINMUX_DATA(D4_MARK, PD4MD_01),
+       PINMUX_DATA(D3_MARK, PD3MD_01),
+       PINMUX_DATA(D2_MARK, PD2MD_01),
+       PINMUX_DATA(D1_MARK, PD1MD_01),
+       PINMUX_DATA(D0_MARK, PD0MD_01),
+
+       /* Port E */
+       PINMUX_DATA(PE7_DATA, PE7MD_00),
+       PINMUX_DATA(SDA3_MARK, PE7MD_01),
+       PINMUX_DATA(RXD7_MARK, PE7MD_10),
+
+       PINMUX_DATA(PE6_DATA, PE6MD_00),
+       PINMUX_DATA(SCL3_MARK, PE6MD_01),
+       PINMUX_DATA(RXD6_MARK, PE6MD_10),
+
+       PINMUX_DATA(PE5_DATA, PE5MD_00),
+       PINMUX_DATA(SDA2_MARK, PE5MD_01),
+       PINMUX_DATA(RXD5_MARK, PE5MD_10),
+       PINMUX_DATA(DV_HSYNC_MARK, PE5MD_11),
+
+       PINMUX_DATA(PE4_DATA, PE4MD_00),
+       PINMUX_DATA(SCL2_MARK, PE4MD_01),
+       PINMUX_DATA(DV_VSYNC_MARK, PE4MD_11),
+
+       PINMUX_DATA(PE3_DATA, PE3MD_000),
+       PINMUX_DATA(SDA1_MARK, PE3MD_001),
+       PINMUX_DATA(TCLKD_MARK, PE3MD_010),
+       PINMUX_DATA(ADTRG_MARK, PE3MD_011),
+       PINMUX_DATA(DV_HSYNC_MARK, PE3MD_100),
+
+       PINMUX_DATA(PE2_DATA, PE2MD_000),
+       PINMUX_DATA(SCL1_MARK, PE2MD_001),
+       PINMUX_DATA(TCLKD_MARK, PE2MD_010),
+       PINMUX_DATA(IOIS16_MARK, PE2MD_011),
+       PINMUX_DATA(DV_VSYNC_MARK, PE2MD_100),
+
+       PINMUX_DATA(PE1_DATA, PE1MD_000),
+       PINMUX_DATA(SDA0_MARK, PE1MD_001),
+       PINMUX_DATA(TCLKB_MARK, PE1MD_010),
+       PINMUX_DATA(AUDIO_CLK_MARK, PE1MD_010),
+       PINMUX_DATA(DV_CLK_MARK, PE1MD_100),
+
+       PINMUX_DATA(PE0_DATA, PE0MD_00),
+       PINMUX_DATA(SCL0_MARK, PE0MD_01),
+       PINMUX_DATA(TCLKA_MARK, PE0MD_10),
+       PINMUX_DATA(LCD_EXTCLK_MARK, PE0MD_11),
+
+       /* Port F */
+       PINMUX_DATA(PF23_DATA, PF23MD_000),
+       PINMUX_DATA(SD_D2_MARK, PF23MD_001),
+       PINMUX_DATA(TXD3_MARK, PF23MD_100),
+       PINMUX_DATA(MMC_D2_MARK, PF23MD_101),
+
+       PINMUX_DATA(PF22_DATA, PF22MD_000),
+       PINMUX_DATA(SD_D3_MARK, PF22MD_001),
+       PINMUX_DATA(RXD3_MARK, PF22MD_100),
+       PINMUX_DATA(MMC_D3_MARK, PF22MD_101),
+
+       PINMUX_DATA(PF21_DATA, PF21MD_000),
+       PINMUX_DATA(SD_CMD_MARK, PF21MD_001),
+       PINMUX_DATA(SCK3_MARK, PF21MD_100),
+       PINMUX_DATA(MMC_CMD_MARK, PF21MD_101),
+
+       PINMUX_DATA(PF20_DATA, PF20MD_000),
+       PINMUX_DATA(SD_CLK_MARK, PF20MD_001),
+       PINMUX_DATA(SSIDATA3_MARK, PF20MD_010),
+       PINMUX_DATA(MMC_CLK_MARK, PF20MD_101),
+
+       PINMUX_DATA(PF19_DATA, PF19MD_000),
+       PINMUX_DATA(SD_D0_MARK, PF19MD_001),
+       PINMUX_DATA(SSIWS3_MARK, PF19MD_010),
+       PINMUX_DATA(IRQ7_PF_MARK, PF19MD_100),
+       PINMUX_DATA(MMC_D0_MARK, PF19MD_101),
+
+       PINMUX_DATA(PF18_DATA, PF18MD_000),
+       PINMUX_DATA(SD_D1_MARK, PF18MD_001),
+       PINMUX_DATA(SSISCK3_MARK, PF18MD_010),
+       PINMUX_DATA(IRQ6_PF_MARK, PF18MD_100),
+       PINMUX_DATA(MMC_D1_MARK, PF18MD_101),
+
+       PINMUX_DATA(PF17_DATA, PF17MD_000),
+       PINMUX_DATA(SD_WP_MARK, PF17MD_001),
+       PINMUX_DATA(FRB_MARK, PF17MD_011),
+       PINMUX_DATA(IRQ5_PF_MARK, PF17MD_100),
+
+       PINMUX_DATA(PF16_DATA, PF16MD_000),
+       PINMUX_DATA(SD_CD_MARK, PF16MD_001),
+       PINMUX_DATA(FCE_MARK, PF16MD_011),
+       PINMUX_DATA(IRQ4_PF_MARK, PF16MD_100),
+       PINMUX_DATA(MMC_CD_MARK, PF16MD_101),
+
+       PINMUX_DATA(PF15_DATA, PF15MD_000),
+       PINMUX_DATA(A0_MARK, PF15MD_001),
+       PINMUX_DATA(SSIDATA2_MARK, PF15MD_010),
+       PINMUX_DATA(WDTOVF_MARK, PF15MD_011),
+       PINMUX_DATA(TXD2_MARK, PF15MD_100),
+
+       PINMUX_DATA(PF14_DATA, PF14MD_000),
+       PINMUX_DATA(A25_MARK, PF14MD_001),
+       PINMUX_DATA(SSIWS2_MARK, PF14MD_010),
+       PINMUX_DATA(RXD2_MARK, PF14MD_100),
+
+       PINMUX_DATA(PF13_DATA, PF13MD_000),
+       PINMUX_DATA(A24_MARK, PF13MD_001),
+       PINMUX_DATA(SSISCK2_MARK, PF13MD_010),
+       PINMUX_DATA(SCK2_MARK, PF13MD_100),
+
+       PINMUX_DATA(PF12_DATA, PF12MD_000),
+       PINMUX_DATA(SSIDATA1_MARK, PF12MD_010),
+       PINMUX_DATA(DV_DATA12_MARK, PF12MD_011),
+       PINMUX_DATA(TXD1_MARK, PF12MD_100),
+       PINMUX_DATA(MMC_D7_MARK, PF12MD_101),
+
+       PINMUX_DATA(PF11_DATA, PF11MD_000),
+       PINMUX_DATA(SSIWS1_MARK, PF11MD_010),
+       PINMUX_DATA(DV_DATA2_MARK, PF11MD_011),
+       PINMUX_DATA(RXD1_MARK, PF11MD_100),
+       PINMUX_DATA(MMC_D6_MARK, PF11MD_101),
+
+       PINMUX_DATA(PF10_DATA, PF10MD_000),
+       PINMUX_DATA(CS1_MARK, PF10MD_001),
+       PINMUX_DATA(SSISCK1_MARK, PF10MD_010),
+       PINMUX_DATA(DV_DATA1_MARK, PF10MD_011),
+       PINMUX_DATA(SCK1_MARK, PF10MD_100),
+       PINMUX_DATA(MMC_D5_MARK, PF10MD_101),
+
+       PINMUX_DATA(PF9_DATA, PF9MD_000),
+       PINMUX_DATA(BS_MARK, PF9MD_001),
+       PINMUX_DATA(DV_DATA0_MARK, PF9MD_011),
+       PINMUX_DATA(SCK0_MARK, PF9MD_100),
+       PINMUX_DATA(MMC_D4_MARK, PF9MD_101),
+       PINMUX_DATA(RTS1_MARK, PF9MD_110),
+
+       PINMUX_DATA(PF8_DATA, PF8MD_000),
+       PINMUX_DATA(A23_MARK, PF8MD_001),
+       PINMUX_DATA(TXD0_MARK, PF8MD_100),
+
+       PINMUX_DATA(PF7_DATA, PF7MD_000),
+       PINMUX_DATA(SSIRXD0_MARK, PF7MD_010),
+       PINMUX_DATA(RXD0_MARK, PF7MD_100),
+       PINMUX_DATA(CTS1_MARK, PF7MD_110),
+
+       PINMUX_DATA(PF6_DATA, PF6MD_000),
+       PINMUX_DATA(CE2A_MARK, PF6MD_001),
+       PINMUX_DATA(SSITXD0_MARK, PF6MD_010),
+
+       PINMUX_DATA(PF5_DATA, PF5MD_000),
+       PINMUX_DATA(SSIWS0_MARK, PF5MD_010),
+
+       PINMUX_DATA(PF4_DATA, PF4MD_000),
+       PINMUX_DATA(CS5CE1A_MARK, PF4MD_001),
+       PINMUX_DATA(SSISCK0_MARK, PF4MD_010),
+
+       PINMUX_DATA(PF3_DATA, PF3MD_000),
+       PINMUX_DATA(CS2_MARK, PF3MD_001),
+       PINMUX_DATA(MISO1_MARK, PF3MD_011),
+       PINMUX_DATA(TIOC4D_MARK, PF3MD_100),
+
+       PINMUX_DATA(PF2_DATA, PF2MD_000),
+       PINMUX_DATA(WAIT_MARK, PF2MD_001),
+       PINMUX_DATA(MOSI1_MARK, PF2MD_011),
+       PINMUX_DATA(TIOC4C_MARK, PF2MD_100),
+       PINMUX_DATA(TEND0_MARK, PF2MD_101),
+
+       PINMUX_DATA(PF1_DATA, PF1MD_000),
+       PINMUX_DATA(BACK_MARK, PF1MD_001),
+       PINMUX_DATA(TIOC4B_MARK, PF1MD_100),
+       PINMUX_DATA(DACK0_MARK, PF1MD_101),
+
+       PINMUX_DATA(PF0_DATA, PF0MD_000),
+       PINMUX_DATA(BREQ_MARK, PF0MD_001),
+       PINMUX_DATA(RSPCK1_MARK, PF0MD_011),
+       PINMUX_DATA(TIOC4A_MARK, PF0MD_100),
+       PINMUX_DATA(DREQ0_MARK, PF0MD_101),
+
+       /* Port G */
+       PINMUX_DATA(PG27_DATA, PG27MD_00),
+       PINMUX_DATA(LCD_TCON2_MARK, PG27MD_10),
+       PINMUX_DATA(LCD_EXTCLK_MARK, PG27MD_11),
+
+       PINMUX_DATA(PG26_DATA, PG26MD_00),
+       PINMUX_DATA(LCD_TCON1_MARK, PG26MD_10),
+
+       PINMUX_DATA(PG25_DATA, PG25MD_00),
+       PINMUX_DATA(LCD_TCON0_MARK, PG25MD_10),
+
+       PINMUX_DATA(PG24_DATA, PG24MD_00),
+       PINMUX_DATA(LCD_CLK_MARK, PG24MD_10),
+
+       PINMUX_DATA(PG23_DATA, PG23MD_000),
+       PINMUX_DATA(LCD_DATA23_MARK, PG23MD_010),
+       PINMUX_DATA(LCD_TCON6_MARK, PG23MD_011),
+       PINMUX_DATA(TXD5_MARK, PG23MD_100),
+
+       PINMUX_DATA(PG22_DATA, PG22MD_000),
+       PINMUX_DATA(LCD_DATA22_MARK, PG22MD_010),
+       PINMUX_DATA(LCD_TCON5_MARK, PG22MD_011),
+       PINMUX_DATA(RXD5_MARK, PG22MD_100),
+
+       PINMUX_DATA(PG21_DATA, PG21MD_000),
+       PINMUX_DATA(DV_DATA7_MARK, PG21MD_001),
+       PINMUX_DATA(LCD_DATA21_MARK, PG21MD_010),
+       PINMUX_DATA(LCD_TCON4_MARK, PG21MD_011),
+       PINMUX_DATA(TXD4_MARK, PG21MD_100),
+
+       PINMUX_DATA(PG20_DATA, PG20MD_000),
+       PINMUX_DATA(DV_DATA6_MARK, PG20MD_001),
+       PINMUX_DATA(LCD_DATA20_MARK, PG21MD_010),
+       PINMUX_DATA(LCD_TCON3_MARK, PG20MD_011),
+       PINMUX_DATA(RXD4_MARK, PG20MD_100),
+
+       PINMUX_DATA(PG19_DATA, PG19MD_000),
+       PINMUX_DATA(DV_DATA5_MARK, PG19MD_001),
+       PINMUX_DATA(LCD_DATA19_MARK, PG19MD_010),
+       PINMUX_DATA(SPDIF_OUT_MARK, PG19MD_011),
+       PINMUX_DATA(SCK5_MARK, PG19MD_100),
+
+       PINMUX_DATA(PG18_DATA, PG18MD_000),
+       PINMUX_DATA(DV_DATA4_MARK, PG18MD_001),
+       PINMUX_DATA(LCD_DATA18_MARK, PG18MD_010),
+       PINMUX_DATA(SPDIF_IN_MARK, PG18MD_011),
+       PINMUX_DATA(SCK4_MARK, PG18MD_100),
+
+// TODO hardware manual has PG17 3 bits wide in reg picture and 2 bits in description
+// we're going with 2 bits
+       PINMUX_DATA(PG17_DATA, PG17MD_00),
+       PINMUX_DATA(WE3ICIOWRAHDQMUU_MARK, PG17MD_01),
+       PINMUX_DATA(LCD_DATA17_MARK, PG17MD_10),
+
+// TODO hardware manual has PG16 3 bits wide in reg picture and 2 bits in description
+// we're going with 2 bits
+       PINMUX_DATA(PG16_DATA, PG16MD_00),
+       PINMUX_DATA(WE2ICIORDDQMUL_MARK, PG16MD_01),
+       PINMUX_DATA(LCD_DATA16_MARK, PG16MD_10),
+
+       PINMUX_DATA(PG15_DATA, PG15MD_00),
+       PINMUX_DATA(D31_MARK, PG15MD_01),
+       PINMUX_DATA(LCD_DATA15_MARK, PG15MD_10),
+       PINMUX_DATA(PINT7_PG_MARK, PG15MD_11),
+
+       PINMUX_DATA(PG14_DATA, PG14MD_00),
+       PINMUX_DATA(D30_MARK, PG14MD_01),
+       PINMUX_DATA(LCD_DATA14_MARK, PG14MD_10),
+       PINMUX_DATA(PINT6_PG_MARK, PG14MD_11),
+
+       PINMUX_DATA(PG13_DATA, PG13MD_00),
+       PINMUX_DATA(D29_MARK, PG13MD_01),
+       PINMUX_DATA(LCD_DATA13_MARK, PG13MD_10),
+       PINMUX_DATA(PINT5_PG_MARK, PG13MD_11),
+
+       PINMUX_DATA(PG12_DATA, PG12MD_00),
+       PINMUX_DATA(D28_MARK, PG12MD_01),
+       PINMUX_DATA(LCD_DATA12_MARK, PG12MD_10),
+       PINMUX_DATA(PINT4_PG_MARK, PG12MD_11),
+
+       PINMUX_DATA(PG11_DATA, PG11MD_000),
+       PINMUX_DATA(D27_MARK, PG11MD_001),
+       PINMUX_DATA(LCD_DATA11_MARK, PG11MD_010),
+       PINMUX_DATA(PINT3_PG_MARK, PG11MD_011),
+       PINMUX_DATA(TIOC3D_MARK, PG11MD_100),
+
+       PINMUX_DATA(PG10_DATA, PG10MD_000),
+       PINMUX_DATA(D26_MARK, PG10MD_001),
+       PINMUX_DATA(LCD_DATA10_MARK, PG10MD_010),
+       PINMUX_DATA(PINT2_PG_MARK, PG10MD_011),
+       PINMUX_DATA(TIOC3C_MARK, PG10MD_100),
+
+       PINMUX_DATA(PG9_DATA, PG9MD_000),
+       PINMUX_DATA(D25_MARK, PG9MD_001),
+       PINMUX_DATA(LCD_DATA9_MARK, PG9MD_010),
+       PINMUX_DATA(PINT1_PG_MARK, PG9MD_011),
+       PINMUX_DATA(TIOC3B_MARK, PG9MD_100),
+
+       PINMUX_DATA(PG8_DATA, PG8MD_000),
+       PINMUX_DATA(D24_MARK, PG8MD_001),
+       PINMUX_DATA(LCD_DATA8_MARK, PG8MD_010),
+       PINMUX_DATA(PINT0_PG_MARK, PG8MD_011),
+       PINMUX_DATA(TIOC3A_MARK, PG8MD_100),
+
+       PINMUX_DATA(PG7_DATA, PG7MD_000),
+       PINMUX_DATA(D23_MARK, PG7MD_001),
+       PINMUX_DATA(LCD_DATA7_MARK, PG7MD_010),
+       PINMUX_DATA(IRQ7_PG_MARK, PG7MD_011),
+       PINMUX_DATA(TIOC2B_MARK, PG7MD_100),
+
+       PINMUX_DATA(PG6_DATA, PG6MD_000),
+       PINMUX_DATA(D22_MARK, PG6MD_001),
+       PINMUX_DATA(LCD_DATA6_MARK, PG6MD_010),
+       PINMUX_DATA(IRQ6_PG_MARK, PG6MD_011),
+       PINMUX_DATA(TIOC2A_MARK, PG6MD_100),
+
+       PINMUX_DATA(PG5_DATA, PG5MD_000),
+       PINMUX_DATA(D21_MARK, PG5MD_001),
+       PINMUX_DATA(LCD_DATA5_MARK, PG5MD_010),
+       PINMUX_DATA(IRQ5_PG_MARK, PG5MD_011),
+       PINMUX_DATA(TIOC1B_MARK, PG5MD_100),
+
+       PINMUX_DATA(PG4_DATA, PG4MD_000),
+       PINMUX_DATA(D20_MARK, PG4MD_001),
+       PINMUX_DATA(LCD_DATA4_MARK, PG4MD_010),
+       PINMUX_DATA(IRQ4_PG_MARK, PG4MD_011),
+       PINMUX_DATA(TIOC1A_MARK, PG4MD_100),
+
+       PINMUX_DATA(PG3_DATA, PG3MD_000),
+       PINMUX_DATA(D19_MARK, PG3MD_001),
+       PINMUX_DATA(LCD_DATA3_MARK, PG3MD_010),
+       PINMUX_DATA(IRQ3_PG_MARK, PG3MD_011),
+       PINMUX_DATA(TIOC0D_MARK, PG3MD_100),
+
+       PINMUX_DATA(PG2_DATA, PG2MD_000),
+       PINMUX_DATA(D18_MARK, PG2MD_001),
+       PINMUX_DATA(LCD_DATA2_MARK, PG2MD_010),
+       PINMUX_DATA(IRQ2_PG_MARK, PG2MD_011),
+       PINMUX_DATA(TIOC0C_MARK, PG2MD_100),
+
+       PINMUX_DATA(PG1_DATA, PG1MD_000),
+       PINMUX_DATA(D17_MARK, PG1MD_001),
+       PINMUX_DATA(LCD_DATA1_MARK, PG1MD_010),
+       PINMUX_DATA(IRQ1_PG_MARK, PG1MD_011),
+       PINMUX_DATA(TIOC0B_MARK, PG1MD_100),
+
+       PINMUX_DATA(PG0_DATA, PG0MD_000),
+       PINMUX_DATA(D16_MARK, PG0MD_001),
+       PINMUX_DATA(LCD_DATA0_MARK, PG0MD_010),
+       PINMUX_DATA(IRQ0_PG_MARK, PG0MD_011),
+       PINMUX_DATA(TIOC0A_MARK, PG0MD_100),
+
+       /* Port H */
+       PINMUX_DATA(PH7_DATA, PH7MD_00),
+       PINMUX_DATA(PHAN7_MARK, PH7MD_01),
+       PINMUX_DATA(PINT7_PH_MARK, PH7MD_10),
+
+       PINMUX_DATA(PH6_DATA, PH6MD_00),
+       PINMUX_DATA(PHAN6_MARK, PH6MD_01),
+       PINMUX_DATA(PINT6_PH_MARK, PH6MD_10),
+
+       PINMUX_DATA(PH5_DATA, PH5MD_00),
+       PINMUX_DATA(PHAN5_MARK, PH5MD_01),
+       PINMUX_DATA(PINT5_PH_MARK, PH5MD_10),
+       PINMUX_DATA(LCD_EXTCLK_MARK, PH5MD_11),
+
+       PINMUX_DATA(PH4_DATA, PH4MD_00),
+       PINMUX_DATA(PHAN4_MARK, PH4MD_01),
+       PINMUX_DATA(PINT4_PH_MARK, PH4MD_10),
+
+       PINMUX_DATA(PH3_DATA, PH3MD_00),
+       PINMUX_DATA(PHAN3_MARK, PH3MD_01),
+       PINMUX_DATA(PINT3_PH_MARK, PH3MD_10),
+
+       PINMUX_DATA(PH2_DATA, PH2MD_00),
+       PINMUX_DATA(PHAN2_MARK, PH2MD_01),
+       PINMUX_DATA(PINT2_PH_MARK, PH2MD_10),
+
+       PINMUX_DATA(PH1_DATA, PH1MD_00),
+       PINMUX_DATA(PHAN1_MARK, PH1MD_01),
+       PINMUX_DATA(PINT1_PH_MARK, PH1MD_10),
+
+       PINMUX_DATA(PH0_DATA, PH0MD_00),
+       PINMUX_DATA(PHAN0_MARK, PH0MD_01),
+       PINMUX_DATA(PINT0_PH_MARK, PH0MD_10),
+
+       /* Port I - not on device */
+
+       /* Port J */
+       PINMUX_DATA(PJ31_DATA, PJ31MD_0),
+       PINMUX_DATA(DV_CLK_MARK, PJ31MD_1),
+
+       PINMUX_DATA(PJ30_DATA, PJ30MD_000),
+       PINMUX_DATA(SSIDATA5_MARK, PJ30MD_010),
+       PINMUX_DATA(TIOC2B_MARK, PJ30MD_100),
+       PINMUX_DATA(IETXD_MARK, PJ30MD_101),
+
+       PINMUX_DATA(PJ29_DATA, PJ29MD_000),
+       PINMUX_DATA(SSIWS5_MARK, PJ29MD_010),
+       PINMUX_DATA(TIOC2A_MARK, PJ29MD_100),
+       PINMUX_DATA(IERXD_MARK, PJ29MD_101),
+
+       PINMUX_DATA(PJ28_DATA, PJ28MD_000),
+       PINMUX_DATA(SSISCK5_MARK, PJ28MD_010),
+       PINMUX_DATA(TIOC1B_MARK, PJ28MD_100),
+       PINMUX_DATA(RTS7_MARK, PJ28MD_101),
+
+       PINMUX_DATA(PJ27_DATA, PJ27MD_000),
+       PINMUX_DATA(TIOC1A_MARK, PJ27MD_100),
+       PINMUX_DATA(CTS7_MARK, PJ27MD_101),
+
+       PINMUX_DATA(PJ26_DATA, PJ26MD_000),
+       PINMUX_DATA(SSIDATA4_MARK, PJ26MD_010),
+       PINMUX_DATA(LCD_TCON5_MARK, PJ26MD_011),
+       PINMUX_DATA(TXD7_MARK, PJ26MD_101),
+
+       PINMUX_DATA(PJ25_DATA, PJ25MD_000),
+       PINMUX_DATA(SSIWS4_MARK, PJ25MD_010),
+       PINMUX_DATA(LCD_TCON4_MARK, PJ25MD_011),
+       PINMUX_DATA(SPDIF_OUT_MARK, PJ25MD_100),
+       PINMUX_DATA(RXD7_MARK, PJ25MD_101),
+
+       PINMUX_DATA(PJ24_DATA, PJ24MD_000),
+       PINMUX_DATA(SSISCK4_MARK, PJ24MD_010),
+       PINMUX_DATA(LCD_TCON3_MARK, PJ24MD_011),
+       PINMUX_DATA(SPDIF_IN_MARK, PJ24MD_100),
+       PINMUX_DATA(SCK7_MARK, PJ24MD_101),
+
+       PINMUX_DATA(PJ23_DATA, PJ23MD_000),
+       PINMUX_DATA(DV_DATA23_MARK, PJ23MD_001),
+       PINMUX_DATA(LCD_DATA23_MARK, PJ23MD_010),
+       PINMUX_DATA(LCD_TCON6_MARK, PJ23MD_011),
+       PINMUX_DATA(IRQ3_PJ_MARK, PJ23MD_100),
+       PINMUX_DATA(CTX1_MARK, PJ23MD_101),
+
+       PINMUX_DATA(PJ22_DATA, PJ22MD_000),
+       PINMUX_DATA(DV_DATA22_MARK, PJ22MD_001),
+       PINMUX_DATA(LCD_DATA22_MARK, PJ22MD_010),
+       PINMUX_DATA(LCD_TCON5_MARK, PJ22MD_011),
+       PINMUX_DATA(IRQ2_PJ_MARK, PJ22MD_100),
+       PINMUX_DATA(CRX1_MARK, PJ22MD_101),
+       PINMUX_DATA(CRX0CRX1_MARK, PJ22MD_110),
+
+       PINMUX_DATA(PJ21_DATA, PJ21MD_000),
+       PINMUX_DATA(DV_DATA21_MARK, PJ21MD_001),
+       PINMUX_DATA(LCD_DATA21_MARK, PJ21MD_010),
+       PINMUX_DATA(LCD_TCON4_MARK, PJ21MD_011),
+       PINMUX_DATA(IRQ1_PJ_MARK, PJ21MD_100),
+       PINMUX_DATA(CTX2_MARK, PJ21MD_101),
+
+       PINMUX_DATA(PJ20_DATA, PJ20MD_000),
+       PINMUX_DATA(DV_DATA20_MARK, PJ20MD_001),
+       PINMUX_DATA(LCD_DATA20_MARK, PJ20MD_010),
+       PINMUX_DATA(LCD_TCON3_MARK, PJ20MD_011),
+       PINMUX_DATA(IRQ0_PJ_MARK, PJ20MD_100),
+       PINMUX_DATA(CRX2_MARK, PJ20MD_101),
+       PINMUX_DATA(CRX0CRX1CRX2_PJ20_MARK, PJ20MD_110),
+
+       PINMUX_DATA(PJ19_DATA, PJ19MD_000),
+       PINMUX_DATA(DV_DATA19_MARK, PJ19MD_001),
+       PINMUX_DATA(LCD_DATA19_MARK, PJ19MD_010),
+       PINMUX_DATA(MISO0_PJ19_MARK, PJ19MD_011),
+       PINMUX_DATA(TIOC0D_MARK, PJ19MD_100),
+       PINMUX_DATA(SIOFRXD_MARK, PJ19MD_101),
+       PINMUX_DATA(AUDIO_XOUT_MARK, PJ19MD_110),
+
+       PINMUX_DATA(PJ18_DATA, PJ18MD_000),
+       PINMUX_DATA(DV_DATA18_MARK, PJ18MD_001),
+       PINMUX_DATA(LCD_DATA18_MARK, PJ18MD_010),
+       PINMUX_DATA(MOSI0_PJ18_MARK, PJ18MD_011),
+       PINMUX_DATA(TIOC0C_MARK, PJ18MD_100),
+       PINMUX_DATA(SIOFTXD_MARK, PJ18MD_101),
+
+       PINMUX_DATA(PJ17_DATA, PJ17MD_000),
+       PINMUX_DATA(DV_DATA17_MARK, PJ17MD_001),
+       PINMUX_DATA(LCD_DATA17_MARK, PJ17MD_010),
+       PINMUX_DATA(SSL00_PJ17_MARK, PJ17MD_011),
+       PINMUX_DATA(TIOC0B_MARK, PJ17MD_100),
+       PINMUX_DATA(SIOFSYNC_MARK, PJ17MD_101),
+
+       PINMUX_DATA(PJ16_DATA, PJ16MD_000),
+       PINMUX_DATA(DV_DATA16_MARK, PJ16MD_001),
+       PINMUX_DATA(LCD_DATA16_MARK, PJ16MD_010),
+       PINMUX_DATA(RSPCK0_PJ16_MARK, PJ16MD_011),
+       PINMUX_DATA(TIOC0A_MARK, PJ16MD_100),
+       PINMUX_DATA(SIOFSCK_MARK, PJ16MD_101),
+
+       PINMUX_DATA(PJ15_DATA, PJ15MD_000),
+       PINMUX_DATA(DV_DATA15_MARK, PJ15MD_001),
+       PINMUX_DATA(LCD_DATA15_MARK, PJ15MD_010),
+       PINMUX_DATA(PINT7_PJ_MARK, PJ15MD_011),
+       PINMUX_DATA(PWM2H_MARK, PJ15MD_100),
+       PINMUX_DATA(TXD7_MARK, PJ15MD_101),
+
+       PINMUX_DATA(PJ14_DATA, PJ14MD_000),
+       PINMUX_DATA(DV_DATA14_MARK, PJ14MD_001),
+       PINMUX_DATA(LCD_DATA14_MARK, PJ14MD_010),
+       PINMUX_DATA(PINT6_PJ_MARK, PJ14MD_011),
+       PINMUX_DATA(PWM2G_MARK, PJ14MD_100),
+       PINMUX_DATA(TXD6_MARK, PJ14MD_101),
+
+       PINMUX_DATA(PJ13_DATA, PJ13MD_000),
+       PINMUX_DATA(DV_DATA13_MARK, PJ13MD_001),
+       PINMUX_DATA(LCD_DATA13_MARK, PJ13MD_010),
+       PINMUX_DATA(PINT5_PJ_MARK, PJ13MD_011),
+       PINMUX_DATA(PWM2F_MARK, PJ13MD_100),
+       PINMUX_DATA(TXD5_MARK, PJ13MD_101),
+
+       PINMUX_DATA(PJ12_DATA, PJ12MD_000),
+       PINMUX_DATA(DV_DATA12_MARK, PJ12MD_001),
+       PINMUX_DATA(LCD_DATA12_MARK, PJ12MD_010),
+       PINMUX_DATA(PINT4_PJ_MARK, PJ12MD_011),
+       PINMUX_DATA(PWM2E_MARK, PJ12MD_100),
+       PINMUX_DATA(SCK7_MARK, PJ12MD_101),
+
+       PINMUX_DATA(PJ11_DATA, PJ11MD_000),
+       PINMUX_DATA(DV_DATA11_MARK, PJ11MD_001),
+       PINMUX_DATA(LCD_DATA11_MARK, PJ11MD_010),
+       PINMUX_DATA(PINT3_PJ_MARK, PJ11MD_011),
+       PINMUX_DATA(PWM2D_MARK, PJ11MD_100),
+       PINMUX_DATA(SCK6_MARK, PJ11MD_101),
+
+       PINMUX_DATA(PJ10_DATA, PJ10MD_000),
+       PINMUX_DATA(DV_DATA10_MARK, PJ10MD_001),
+       PINMUX_DATA(LCD_DATA10_MARK, PJ10MD_010),
+       PINMUX_DATA(PINT2_PJ_MARK, PJ10MD_011),
+       PINMUX_DATA(PWM2C_MARK, PJ10MD_100),
+       PINMUX_DATA(SCK5_MARK, PJ10MD_101),
+
+       PINMUX_DATA(PJ9_DATA, PJ9MD_000),
+       PINMUX_DATA(DV_DATA9_MARK, PJ9MD_001),
+       PINMUX_DATA(LCD_DATA9_MARK, PJ9MD_010),
+       PINMUX_DATA(PINT1_PJ_MARK, PJ9MD_011),
+       PINMUX_DATA(PWM2B_MARK, PJ9MD_100),
+       PINMUX_DATA(RTS5_MARK, PJ9MD_101),
+
+       PINMUX_DATA(PJ8_DATA, PJ8MD_000),
+       PINMUX_DATA(DV_DATA8_MARK, PJ8MD_001),
+       PINMUX_DATA(LCD_DATA8_MARK, PJ8MD_010),
+       PINMUX_DATA(PINT0_PJ_MARK, PJ8MD_011),
+       PINMUX_DATA(PWM2A_MARK, PJ8MD_100),
+       PINMUX_DATA(CTS5_MARK, PJ8MD_101),
+
+       PINMUX_DATA(PJ7_DATA, PJ7MD_000),
+       PINMUX_DATA(DV_DATA7_MARK, PJ7MD_001),
+       PINMUX_DATA(LCD_DATA7_MARK, PJ7MD_010),
+       PINMUX_DATA(SD_D2_MARK, PJ7MD_011),
+       PINMUX_DATA(PWM1H_MARK, PJ7MD_100),
+
+       PINMUX_DATA(PJ6_DATA, PJ6MD_000),
+       PINMUX_DATA(DV_DATA6_MARK, PJ6MD_001),
+       PINMUX_DATA(LCD_DATA6_MARK, PJ6MD_010),
+       PINMUX_DATA(SD_D3_MARK, PJ6MD_011),
+       PINMUX_DATA(PWM1G_MARK, PJ6MD_100),
+
+       PINMUX_DATA(PJ5_DATA, PJ5MD_000),
+       PINMUX_DATA(DV_DATA5_MARK, PJ5MD_001),
+       PINMUX_DATA(LCD_DATA5_MARK, PJ5MD_010),
+       PINMUX_DATA(SD_CMD_MARK, PJ5MD_011),
+       PINMUX_DATA(PWM1F_MARK, PJ5MD_100),
+
+       PINMUX_DATA(PJ4_DATA, PJ4MD_000),
+       PINMUX_DATA(DV_DATA4_MARK, PJ4MD_001),
+       PINMUX_DATA(LCD_DATA4_MARK, PJ4MD_010),
+       PINMUX_DATA(SD_CLK_MARK, PJ4MD_011),
+       PINMUX_DATA(PWM1E_MARK, PJ4MD_100),
+
+       PINMUX_DATA(PJ3_DATA, PJ3MD_000),
+       PINMUX_DATA(DV_DATA3_MARK, PJ3MD_001),
+       PINMUX_DATA(LCD_DATA3_MARK, PJ3MD_010),
+       PINMUX_DATA(SD_D0_MARK, PJ3MD_011),
+       PINMUX_DATA(PWM1D_MARK, PJ3MD_100),
+
+       PINMUX_DATA(PJ2_DATA, PJ2MD_000),
+       PINMUX_DATA(DV_DATA2_MARK, PJ2MD_001),
+       PINMUX_DATA(LCD_DATA2_MARK, PJ2MD_010),
+       PINMUX_DATA(SD_D1_MARK, PJ2MD_011),
+       PINMUX_DATA(PWM1C_MARK, PJ2MD_100),
+
+       PINMUX_DATA(PJ1_DATA, PJ1MD_000),
+       PINMUX_DATA(DV_DATA1_MARK, PJ1MD_001),
+       PINMUX_DATA(LCD_DATA1_MARK, PJ1MD_010),
+       PINMUX_DATA(SD_WP_MARK, PJ1MD_011),
+       PINMUX_DATA(PWM1B_MARK, PJ1MD_100),
+
+       PINMUX_DATA(PJ0_DATA, PJ0MD_000),
+       PINMUX_DATA(DV_DATA0_MARK, PJ0MD_001),
+       PINMUX_DATA(LCD_DATA0_MARK, PJ0MD_010),
+       PINMUX_DATA(SD_CD_MARK, PJ0MD_011),
+       PINMUX_DATA(PWM1A_MARK, PJ0MD_100),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+       /* Port A */
+       PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+       PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+       /* Port B */
+       PINMUX_GPIO(GPIO_PB22, PB22_DATA),
+       PINMUX_GPIO(GPIO_PB21, PB21_DATA),
+       PINMUX_GPIO(GPIO_PB20, PB20_DATA),
+       PINMUX_GPIO(GPIO_PB19, PB19_DATA),
+       PINMUX_GPIO(GPIO_PB18, PB18_DATA),
+       PINMUX_GPIO(GPIO_PB17, PB17_DATA),
+       PINMUX_GPIO(GPIO_PB16, PB16_DATA),
+       PINMUX_GPIO(GPIO_PB15, PB15_DATA),
+       PINMUX_GPIO(GPIO_PB14, PB14_DATA),
+       PINMUX_GPIO(GPIO_PB13, PB13_DATA),
+       PINMUX_GPIO(GPIO_PB12, PB12_DATA),
+       PINMUX_GPIO(GPIO_PB11, PB11_DATA),
+       PINMUX_GPIO(GPIO_PB10, PB10_DATA),
+       PINMUX_GPIO(GPIO_PB9, PB9_DATA),
+       PINMUX_GPIO(GPIO_PB8, PB8_DATA),
+       PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+       PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+       PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+       PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+       PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+       PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+       PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+
+       /* Port C */
+       PINMUX_GPIO(GPIO_PC8, PC8_DATA),
+       PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+       PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+       PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+       PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+       PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+       PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+       PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+       PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+       /* Port D */
+       PINMUX_GPIO(GPIO_PD15, PD15_DATA),
+       PINMUX_GPIO(GPIO_PD14, PD14_DATA),
+       PINMUX_GPIO(GPIO_PD13, PD13_DATA),
+       PINMUX_GPIO(GPIO_PD12, PD12_DATA),
+       PINMUX_GPIO(GPIO_PD11, PD11_DATA),
+       PINMUX_GPIO(GPIO_PD10, PD10_DATA),
+       PINMUX_GPIO(GPIO_PD9, PD9_DATA),
+       PINMUX_GPIO(GPIO_PD8, PD8_DATA),
+       PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+       PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+       PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+       PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+       PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+       PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+       PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+       PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+       /* Port E */
+       PINMUX_GPIO(GPIO_PE7, PE7_DATA),
+       PINMUX_GPIO(GPIO_PE6, PE6_DATA),
+       PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+       PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+       PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+       PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+       PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+       PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+       /* Port F */
+       PINMUX_GPIO(GPIO_PF23, PF23_DATA),
+       PINMUX_GPIO(GPIO_PF22, PF22_DATA),
+       PINMUX_GPIO(GPIO_PF21, PF21_DATA),
+       PINMUX_GPIO(GPIO_PF20, PF20_DATA),
+       PINMUX_GPIO(GPIO_PF19, PF19_DATA),
+       PINMUX_GPIO(GPIO_PF18, PF18_DATA),
+       PINMUX_GPIO(GPIO_PF17, PF17_DATA),
+       PINMUX_GPIO(GPIO_PF16, PF16_DATA),
+       PINMUX_GPIO(GPIO_PF15, PF15_DATA),
+       PINMUX_GPIO(GPIO_PF14, PF14_DATA),
+       PINMUX_GPIO(GPIO_PF13, PF13_DATA),
+       PINMUX_GPIO(GPIO_PF12, PF12_DATA),
+       PINMUX_GPIO(GPIO_PF11, PF11_DATA),
+       PINMUX_GPIO(GPIO_PF10, PF10_DATA),
+       PINMUX_GPIO(GPIO_PF9, PF9_DATA),
+       PINMUX_GPIO(GPIO_PF8, PF8_DATA),
+       PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+       PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+       PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+       PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+       PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+       PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+       PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+       PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+       /* Port G */
+       PINMUX_GPIO(GPIO_PG27, PG27_DATA),
+       PINMUX_GPIO(GPIO_PG26, PG26_DATA),
+       PINMUX_GPIO(GPIO_PG25, PG25_DATA),
+       PINMUX_GPIO(GPIO_PG24, PG24_DATA),
+       PINMUX_GPIO(GPIO_PG23, PG23_DATA),
+       PINMUX_GPIO(GPIO_PG22, PG22_DATA),
+       PINMUX_GPIO(GPIO_PG21, PG21_DATA),
+       PINMUX_GPIO(GPIO_PG20, PG20_DATA),
+       PINMUX_GPIO(GPIO_PG19, PG19_DATA),
+       PINMUX_GPIO(GPIO_PG18, PG18_DATA),
+       PINMUX_GPIO(GPIO_PG17, PG17_DATA),
+       PINMUX_GPIO(GPIO_PG16, PG16_DATA),
+       PINMUX_GPIO(GPIO_PG15, PG15_DATA),
+       PINMUX_GPIO(GPIO_PG14, PG14_DATA),
+       PINMUX_GPIO(GPIO_PG13, PG13_DATA),
+       PINMUX_GPIO(GPIO_PG12, PG12_DATA),
+       PINMUX_GPIO(GPIO_PG11, PG11_DATA),
+       PINMUX_GPIO(GPIO_PG10, PG10_DATA),
+       PINMUX_GPIO(GPIO_PG9, PG9_DATA),
+       PINMUX_GPIO(GPIO_PG8, PG8_DATA),
+       PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+       PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+       PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+       PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+       PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+       PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+       PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+       PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+       /* Port H - Port H does not have a Data Register */
+
+       /* Port I - not on device */
+
+       /* Port J */
+       PINMUX_GPIO(GPIO_PJ31, PJ31_DATA),
+       PINMUX_GPIO(GPIO_PJ30, PJ30_DATA),
+       PINMUX_GPIO(GPIO_PJ29, PJ29_DATA),
+       PINMUX_GPIO(GPIO_PJ28, PJ28_DATA),
+       PINMUX_GPIO(GPIO_PJ27, PJ27_DATA),
+       PINMUX_GPIO(GPIO_PJ26, PJ26_DATA),
+       PINMUX_GPIO(GPIO_PJ25, PJ25_DATA),
+       PINMUX_GPIO(GPIO_PJ24, PJ24_DATA),
+       PINMUX_GPIO(GPIO_PJ23, PJ23_DATA),
+       PINMUX_GPIO(GPIO_PJ22, PJ22_DATA),
+       PINMUX_GPIO(GPIO_PJ21, PJ21_DATA),
+       PINMUX_GPIO(GPIO_PJ20, PJ20_DATA),
+       PINMUX_GPIO(GPIO_PJ19, PJ19_DATA),
+       PINMUX_GPIO(GPIO_PJ18, PJ18_DATA),
+       PINMUX_GPIO(GPIO_PJ17, PJ17_DATA),
+       PINMUX_GPIO(GPIO_PJ16, PJ16_DATA),
+       PINMUX_GPIO(GPIO_PJ15, PJ15_DATA),
+       PINMUX_GPIO(GPIO_PJ14, PJ14_DATA),
+       PINMUX_GPIO(GPIO_PJ13, PJ13_DATA),
+       PINMUX_GPIO(GPIO_PJ12, PJ12_DATA),
+       PINMUX_GPIO(GPIO_PJ11, PJ11_DATA),
+       PINMUX_GPIO(GPIO_PJ10, PJ10_DATA),
+       PINMUX_GPIO(GPIO_PJ9, PJ9_DATA),
+       PINMUX_GPIO(GPIO_PJ8, PJ8_DATA),
+       PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
+       PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
+       PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
+       PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
+       PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
+       PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
+       PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
+       PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
+
+       /* INTC */
+       PINMUX_GPIO(GPIO_FN_IRQ7_PG, IRQ7_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ6_PG, IRQ6_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ5_PG, IRQ5_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ4_PG, IRQ4_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ3_PG, IRQ3_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ2_PG, IRQ2_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ1_PG, IRQ1_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ0_PG, IRQ0_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ7_PF, IRQ7_PF_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ6_PF, IRQ6_PF_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ5_PF, IRQ5_PF_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ4_PF, IRQ4_PF_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ3_PJ, IRQ3_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ2_PJ, IRQ2_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ1_PJ, IRQ1_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ0_PJ, IRQ0_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ1_PC, IRQ1_PC_MARK),
+       PINMUX_GPIO(GPIO_FN_IRQ0_PC, IRQ0_PC_MARK),
+
+       PINMUX_GPIO(GPIO_FN_PINT7_PG, PINT7_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT6_PG, PINT6_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT5_PG, PINT5_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT4_PG, PINT4_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT3_PG, PINT3_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT2_PG, PINT2_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT1_PG, PINT1_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT0_PG, PINT0_PG_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT7_PH, PINT7_PH_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT6_PH, PINT6_PH_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT5_PH, PINT5_PH_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT4_PH, PINT4_PH_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT3_PH, PINT3_PH_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT2_PH, PINT2_PH_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT1_PH, PINT1_PH_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT0_PH, PINT0_PH_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT7_PJ, PINT7_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT6_PJ, PINT6_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT5_PJ, PINT5_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT4_PJ, PINT4_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT3_PJ, PINT3_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT2_PJ, PINT2_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT1_PJ, PINT1_PJ_MARK),
+       PINMUX_GPIO(GPIO_FN_PINT0_PJ, PINT0_PJ_MARK),
+
+       /* WDT */
+       PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
+
+       /* CAN */
+       PINMUX_GPIO(GPIO_FN_CTX1, CTX1_MARK),
+       PINMUX_GPIO(GPIO_FN_CRX1, CRX1_MARK),
+       PINMUX_GPIO(GPIO_FN_CTX0, CTX0_MARK),
+       PINMUX_GPIO(GPIO_FN_CRX0, CRX0_MARK),
+       PINMUX_GPIO(GPIO_FN_CRX0_CRX1, CRX0CRX1_MARK),
+       PINMUX_GPIO(GPIO_FN_CRX0_CRX1_CRX2, CRX0CRX1CRX2_MARK),
+
+       /* DMAC */
+       PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+       PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+       PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+       PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+
+       /* ADC */
+       PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
+
+       /* BSCh */
+       PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+       PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+       PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+       PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+       PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
+       PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
+       PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
+       PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
+       PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
+       PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
+       PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
+       PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
+       PINMUX_GPIO(GPIO_FN_A13, A13_MARK),
+       PINMUX_GPIO(GPIO_FN_A12, A12_MARK),
+       PINMUX_GPIO(GPIO_FN_A11, A11_MARK),
+       PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
+       PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
+       PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+       PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
+       PINMUX_GPIO(GPIO_FN_A6, A6_MARK),
+       PINMUX_GPIO(GPIO_FN_A5, A5_MARK),
+       PINMUX_GPIO(GPIO_FN_A4, A4_MARK),
+       PINMUX_GPIO(GPIO_FN_A3, A3_MARK),
+       PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
+       PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
+       PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+
+       PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+       PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+       PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+       PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+       PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+       PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+       PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+       PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+       PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
+       PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
+       PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
+       PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
+       PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
+       PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
+       PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
+       PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+       PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+       PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+       PINMUX_GPIO(GPIO_FN_CS3, CS3_MARK),
+       PINMUX_GPIO(GPIO_FN_CS2, CS2_MARK),
+       PINMUX_GPIO(GPIO_FN_CS1, CS1_MARK),
+       PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
+       PINMUX_GPIO(GPIO_FN_CS5CE1A, CS5CE1A_MARK),
+       PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+       PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+       PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+       PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
+       PINMUX_GPIO(GPIO_FN_WE3ICIOWRAHDQMUU, WE3ICIOWRAHDQMUU_MARK),
+       PINMUX_GPIO(GPIO_FN_WE2ICIORDDQMUL, WE2ICIORDDQMUL_MARK),
+       PINMUX_GPIO(GPIO_FN_WE1DQMUWE, WE1DQMUWE_MARK),
+       PINMUX_GPIO(GPIO_FN_WE0DQML, WE0DQML_MARK),
+       PINMUX_GPIO(GPIO_FN_RAS, RAS_MARK),
+       PINMUX_GPIO(GPIO_FN_CAS, CAS_MARK),
+       PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
+       PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
+       PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+       PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+       PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+
+       /* TMU */
+       PINMUX_GPIO(GPIO_FN_TIOC4D, TIOC4D_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC4C, TIOC4C_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC4B, TIOC4B_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC4A, TIOC4A_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC3D, TIOC3D_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC3C, TIOC3C_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC3B, TIOC3B_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC3A, TIOC3A_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC2B, TIOC2B_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC1B, TIOC1B_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC2A, TIOC2A_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC1A, TIOC1A_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC0D, TIOC0D_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC0C, TIOC0C_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC0B, TIOC0B_MARK),
+       PINMUX_GPIO(GPIO_FN_TIOC0A, TIOC0A_MARK),
+       PINMUX_GPIO(GPIO_FN_TCLKD, TCLKD_MARK),
+       PINMUX_GPIO(GPIO_FN_TCLKC, TCLKC_MARK),
+       PINMUX_GPIO(GPIO_FN_TCLKB, TCLKB_MARK),
+       PINMUX_GPIO(GPIO_FN_TCLKA, TCLKA_MARK),
+
+       /* SCIF */
+       PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
+       PINMUX_GPIO(GPIO_FN_RTS1, RTS1_MARK),
+       PINMUX_GPIO(GPIO_FN_CTS1, CTS1_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK5, SCK5_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD5, TXD5_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD5, RXD5_MARK),
+       PINMUX_GPIO(GPIO_FN_RTS5, RTS5_MARK),
+       PINMUX_GPIO(GPIO_FN_CTS5, CTS5_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK6, SCK6_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD6, TXD6_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD6, RXD6_MARK),
+       PINMUX_GPIO(GPIO_FN_SCK7, SCK7_MARK),
+       PINMUX_GPIO(GPIO_FN_TXD7, TXD7_MARK),
+       PINMUX_GPIO(GPIO_FN_RXD7, RXD7_MARK),
+       PINMUX_GPIO(GPIO_FN_RTS7, RTS7_MARK),
+       PINMUX_GPIO(GPIO_FN_CTS7, CTS7_MARK),
+
+       /* RSPI */
+       PINMUX_GPIO(GPIO_FN_RSPCK0_PJ16, RSPCK0_PJ16_MARK),
+       PINMUX_GPIO(GPIO_FN_SSL00_PJ17, SSL00_PJ17_MARK),
+       PINMUX_GPIO(GPIO_FN_MOSI0_PJ18, MOSI0_PJ18_MARK),
+       PINMUX_GPIO(GPIO_FN_MISO0_PJ19, MISO0_PJ19_MARK),
+       PINMUX_GPIO(GPIO_FN_RSPCK0_PB17, RSPCK0_PB17_MARK),
+       PINMUX_GPIO(GPIO_FN_SSL00_PB18, SSL00_PB18_MARK),
+       PINMUX_GPIO(GPIO_FN_MOSI0_PB19, MOSI0_PB19_MARK),
+       PINMUX_GPIO(GPIO_FN_MISO0_PB20, MISO0_PB20_MARK),
+       PINMUX_GPIO(GPIO_FN_RSPCK1, RSPCK1_MARK),
+       PINMUX_GPIO(GPIO_FN_MOSI1, MOSI1_MARK),
+       PINMUX_GPIO(GPIO_FN_MISO1, MISO1_MARK),
+       PINMUX_GPIO(GPIO_FN_SSL10, SSL10_MARK),
+
+       /* IIC3 */
+       PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
+       PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
+       PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
+       PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
+       PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
+       PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
+
+       /* SSI */
+       PINMUX_GPIO(GPIO_FN_SSISCK0, SSISCK0_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIWS0, SSIWS0_MARK),
+       PINMUX_GPIO(GPIO_FN_SSITXD0, SSITXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIRXD0, SSIRXD0_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIWS1, SSIWS1_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIWS2, SSIWS2_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIWS3, SSIWS3_MARK),
+       PINMUX_GPIO(GPIO_FN_SSISCK1, SSISCK1_MARK),
+       PINMUX_GPIO(GPIO_FN_SSISCK2, SSISCK2_MARK),
+       PINMUX_GPIO(GPIO_FN_SSISCK3, SSISCK3_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIDATA1, SSIDATA1_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIDATA2, SSIDATA2_MARK),
+       PINMUX_GPIO(GPIO_FN_SSIDATA3, SSIDATA3_MARK),
+       PINMUX_GPIO(GPIO_FN_AUDIO_CLK, AUDIO_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_AUDIO_XOUT, AUDIO_XOUT_MARK),
+
+       /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+       PINMUX_GPIO(GPIO_FN_SIOFTXD, SIOFTXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SIOFRXD, SIOFRXD_MARK),
+       PINMUX_GPIO(GPIO_FN_SIOFSYNC, SIOFSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_SIOFSCK, SIOFSCK_MARK),
+
+       /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+       PINMUX_GPIO(GPIO_FN_SPDIF_IN, SPDIF_IN_MARK),
+       PINMUX_GPIO(GPIO_FN_SPDIF_OUT, SPDIF_OUT_MARK),
+
+       /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+       PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
+       PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+
+       /* VDC3 */
+       PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
+
+       PINMUX_GPIO(GPIO_FN_DV_DATA23, DV_DATA23_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA22, DV_DATA22_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA21, DV_DATA21_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA20, DV_DATA20_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA19, DV_DATA19_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA18, DV_DATA18_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA17, DV_DATA17_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA16, DV_DATA16_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA15, DV_DATA15_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA14, DV_DATA14_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA13, DV_DATA13_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA12, DV_DATA12_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA11, DV_DATA11_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA10, DV_DATA10_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA9, DV_DATA9_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA8, DV_DATA8_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA7, DV_DATA7_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA6, DV_DATA6_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA5, DV_DATA5_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA4, DV_DATA4_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA3, DV_DATA3_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA2, DV_DATA2_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA1, DV_DATA1_MARK),
+       PINMUX_GPIO(GPIO_FN_DV_DATA0, DV_DATA0_MARK),
+
+       PINMUX_GPIO(GPIO_FN_LCD_CLK, LCD_CLK_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_EXTCLK, LCD_EXTCLK_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_VSYNC, LCD_VSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_HSYNC, LCD_HSYNC_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DE, LCD_DE_MARK),
+
+       PINMUX_GPIO(GPIO_FN_LCD_DATA23, LCD_DATA23_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA22, LCD_DATA22_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA21, LCD_DATA21_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA20, LCD_DATA20_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA19, LCD_DATA19_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA18, LCD_DATA18_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA17, LCD_DATA17_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA16, LCD_DATA16_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
+
+       PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+       /* "name" addr register_size Field_Width */
+
+       /* where Field_Width is 1 for single mode registers or 4 for upto 16
+          mode registers and modes are described in assending order [0..16] */
+
+       { PINMUX_CFG_REG("PAIOR0", 0xfffe3812, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, PA1_IN, PA1_OUT,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, PA0_IN, PA0_OUT }
+       },
+       { PINMUX_CFG_REG("PBCR5", 0xfffe3824, 16, 4) {
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB22MD_000, PB22MD_001, PB22MD_010, PB22MD_011,
+               PB22MD_100, PB22MD_101, PB22MD_110, PB22MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB21MD_00, PB21MD_01, PB21MD_10, PB21MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB20MD_000, PB20MD_001, PB20MD_010, PB20MD_011,
+               PB20MD_100, PB20MD_101, PB20MD_110, PB20MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PBCR4", 0xfffe3826, 16, 4) {
+               PB19MD_000, PB19MD_001, PB19MD_010, PB19MD_011,
+               PB19MD_100, PB19MD_101, PB19MD_110, PB19MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB18MD_000, PB18MD_001, PB18MD_010, PB18MD_011,
+               PB18MD_100, PB18MD_101, PB18MD_110, PB18MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB17MD_000, PB17MD_001, PB17MD_010, PB17MD_011,
+               PB17MD_100, PB17MD_101, PB17MD_110, PB17MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB16MD_000, PB16MD_001, PB16MD_010, PB16MD_011,
+               PB16MD_100, PB16MD_101, PB16MD_110, PB16MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PBCR3", 0xfffe3828, 16, 4) {
+               PB15MD_000, PB15MD_001, PB15MD_010, PB15MD_011,
+               PB15MD_100, PB15MD_101, PB15MD_110, PB15MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB14MD_000, PB14MD_001, PB14MD_010, PB14MD_011,
+               PB14MD_100, PB14MD_101, PB14MD_110, PB14MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB13MD_000, PB13MD_001, PB13MD_010, PB13MD_011,
+               PB13MD_100, PB13MD_101, PB13MD_110, PB13MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PBCR2", 0xfffe382a, 16, 4) {
+               PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PBCR1", 0xfffe382c, 16, 4) {
+               PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PBCR0", 0xfffe382e, 16, 4) {
+               PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11, 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 }
+       },
+
+       { PINMUX_CFG_REG("PBIOR1", 0xfffe3830, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0,
+               PB22_IN, PB22_OUT,
+               PB21_IN, PB21_OUT,
+               PB20_IN, PB20_OUT,
+               PB19_IN, PB19_OUT,
+               PB18_IN, PB18_OUT,
+               PB17_IN, PB17_OUT,
+               PB16_IN, PB16_OUT }
+       },
+       { PINMUX_CFG_REG("PBIOR0", 0xfffe3832, 16, 1) {
+               PB15_IN, PB15_OUT,
+               PB14_IN, PB14_OUT,
+               PB13_IN, PB13_OUT,
+               PB12_IN, PB12_OUT,
+               PB11_IN, PB11_OUT,
+               PB10_IN, PB10_OUT,
+               PB9_IN, PB9_OUT,
+               PB8_IN, PB8_OUT,
+               PB7_IN, PB7_OUT,
+               PB6_IN, PB6_OUT,
+               PB5_IN, PB5_OUT,
+               PB4_IN, PB4_OUT,
+               PB3_IN, PB3_OUT,
+               PB2_IN, PB2_OUT,
+               PB1_IN, PB1_OUT,
+               0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PCCR2", 0xfffe384a, 16, 4) {
+               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, 0, 0,
+
+               PC8MD_000, PC8MD_001, PC8MD_010, PC8MD_011,
+               PC8MD_100, PC8MD_101, PC8MD_110, PC8MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PCCR1", 0xfffe384c, 16, 4) {
+               PC7MD_000, PC7MD_001, PC7MD_010, PC7MD_011,
+               PC7MD_100, PC7MD_101, PC7MD_110, PC7MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PC6MD_000, PC6MD_001, PC6MD_010, PC6MD_011,
+               PC6MD_100, PC6MD_101, PC6MD_110, PC6MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PC5MD_000, PC5MD_001, PC5MD_010, PC5MD_011,
+               PC5MD_100, PC5MD_101, PC5MD_110, PC5MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PC4MD_00, PC4MD_01, PC4MD_10, PC4MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PCCR0", 0xfffe384e, 16, 4) {
+               PC3MD_00, PC3MD_01, PC3MD_10, PC3MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PC2MD_00, PC2MD_01, PC2MD_10, PC2MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PC1MD_0, PC1MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PC0MD_0, PC0MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               PC8_IN, PC8_OUT,
+               PC7_IN, PC7_OUT,
+               PC6_IN, PC6_OUT,
+               PC5_IN, PC5_OUT,
+               PC4_IN, PC4_OUT,
+               PC3_IN, PC3_OUT,
+               PC2_IN, PC2_OUT,
+               PC1_IN, PC1_OUT,
+               PC0_IN, PC0_OUT }
+       },
+
+       { PINMUX_CFG_REG("PDCR3", 0xfffe3868, 16, 4) {
+               PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PDCR2", 0xfffe386a, 16, 4) {
+               PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PDCR1", 0xfffe386c, 16, 4) {
+               PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PDCR0", 0xfffe386e, 16, 4) {
+               PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PDIOR0", 0xfffe3872, 16, 1) {
+               PD15_IN, PD15_OUT,
+               PD14_IN, PD14_OUT,
+               PD13_IN, PD13_OUT,
+               PD12_IN, PD12_OUT,
+               PD11_IN, PD11_OUT,
+               PD10_IN, PD10_OUT,
+               PD9_IN, PD9_OUT,
+               PD8_IN, PD8_OUT,
+               PD7_IN, PD7_OUT,
+               PD6_IN, PD6_OUT,
+               PD5_IN, PD5_OUT,
+               PD4_IN, PD4_OUT,
+               PD3_IN, PD3_OUT,
+               PD2_IN, PD2_OUT,
+               PD1_IN, PD1_OUT,
+               PD0_IN, PD0_OUT }
+       },
+
+       { PINMUX_CFG_REG("PECR1", 0xfffe388c, 16, 4) {
+               PE7MD_00, PE7MD_01, PE7MD_10, PE7MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PE6MD_00, PE6MD_01, PE6MD_10, PE6MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PECR0", 0xfffe388e, 16, 4) {
+               PE3MD_000, PE3MD_001, PE3MD_010, PE3MD_011,
+               PE3MD_100, PE3MD_101, PE3MD_110, PE3MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PE2MD_000, PE2MD_001, PE2MD_010, PE2MD_011,
+               PE2MD_100, PE2MD_101, PE2MD_110, PE2MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+               PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PEIOR0", 0xfffe3892, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PE7_IN, PE7_OUT,
+               PE6_IN, PE6_OUT,
+               PE5_IN, PE5_OUT,
+               PE4_IN, PE4_OUT,
+               PE3_IN, PE3_OUT,
+               PE2_IN, PE2_OUT,
+               PE1_IN, PE1_OUT,
+               PE0_IN, PE0_OUT }
+       },
+
+       { PINMUX_CFG_REG("PFCR6", 0xfffe38a2, 16, 4) {
+               PF23MD_000, PF23MD_001, PF23MD_010, PF23MD_011,
+               PF23MD_100, PF23MD_101, PF23MD_110, PF23MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF22MD_000, PF22MD_001, PF22MD_010, PF22MD_011,
+               PF22MD_100, PF22MD_101, PF22MD_110, PF22MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF21MD_000, PF21MD_001, PF21MD_010, PF21MD_011,
+               PF21MD_100, PF21MD_101, PF21MD_110, PF21MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF20MD_000, PF20MD_001, PF20MD_010, PF20MD_011,
+               PF20MD_100, PF20MD_101, PF20MD_110, PF20MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PFCR5", 0xfffe38a4, 16, 4) {
+               PF19MD_000, PF19MD_001, PF19MD_010, PF19MD_011,
+               PF19MD_100, PF19MD_101, PF19MD_110, PF19MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF18MD_000, PF18MD_001, PF18MD_010, PF18MD_011,
+               PF18MD_100, PF18MD_101, PF18MD_110, PF18MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF17MD_000, PF17MD_001, PF17MD_010, PF17MD_011,
+               PF17MD_100, PF17MD_101, PF17MD_110, PF17MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF16MD_000, PF16MD_001, PF16MD_010, PF16MD_011,
+               PF16MD_100, PF16MD_101, PF16MD_110, PF16MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PFCR4", 0xfffe38a6, 16, 4) {
+               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, 0, 0,
+
+               PF15MD_000, PF15MD_001, PF15MD_010, PF15MD_011,
+               PF15MD_100, PF15MD_101, PF15MD_110, PF15MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PFCR3", 0xfffe38a8, 16, 4) {
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF14MD_000, PF14MD_001, PF14MD_010, PF14MD_011,
+               PF14MD_100, PF14MD_101, PF14MD_110, PF14MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF13MD_000, PF13MD_001, PF13MD_010, PF13MD_011,
+               PF13MD_100, PF13MD_101, PF13MD_110, PF13MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
+               PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PFCR2", 0xfffe38aa, 16, 4) {
+               PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+               PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+               PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+               PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF8MD_000, PF8MD_001, PF8MD_010, PF8MD_011,
+               PF8MD_100, PF8MD_101, PF8MD_110, PF8MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PFCR1", 0xfffe38ac, 16, 4) {
+               PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+               PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+               PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+               PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+               PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PFCR0", 0xfffe38ae, 16, 4) {
+               PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+               PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+               PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+               PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+               PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PFIOR1", 0xfffe38b0, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PF23_IN, PF23_OUT,
+               PF22_IN, PF22_OUT,
+               PF21_IN, PF21_OUT,
+               PF20_IN, PF20_OUT,
+               PF19_IN, PF19_OUT,
+               PF18_IN, PF18_OUT,
+               PF17_IN, PF17_OUT,
+               PF16_IN, PF16_OUT }
+       },
+       { PINMUX_CFG_REG("PFIOR0", 0xfffe38b2, 16, 1) {
+               PF15_IN, PF15_OUT,
+               PF14_IN, PF14_OUT,
+               PF13_IN, PF13_OUT,
+               PF12_IN, PF12_OUT,
+               PF11_IN, PF11_OUT,
+               PF10_IN, PF10_OUT,
+               PF9_IN, PF9_OUT,
+               PF8_IN, PF8_OUT,
+               PF7_IN, PF7_OUT,
+               PF6_IN, PF6_OUT,
+               PF5_IN, PF5_OUT,
+               PF4_IN, PF4_OUT,
+               PF3_IN, PF3_OUT,
+               PF2_IN, PF2_OUT,
+               PF1_IN, PF1_OUT,
+               PF0_IN, PF0_OUT }
+       },
+
+       { PINMUX_CFG_REG("PGCR6", 0xfffe38c2, 16, 4) {
+               PG27MD_00, PG27MD_01, PG27MD_10, PG27MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG26MD_00, PG26MD_01, PG26MD_10, PG26MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG25MD_00, PG25MD_01, PG25MD_10, PG25MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PGCR5", 0xfffe38c4, 16, 4) {
+               PG23MD_000, PG23MD_001, PG23MD_010, PG23MD_011,
+               PG23MD_100, PG23MD_101, PG23MD_110, PG23MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG22MD_000, PG22MD_001, PG22MD_010, PG22MD_011,
+               PG22MD_100, PG22MD_101, PG22MD_110, PG22MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG21MD_000, PG21MD_001, PG21MD_010, PG21MD_011,
+               PG21MD_100, PG21MD_101, PG21MD_110, PG21MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+               PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PGCR4", 0xfffe38c6, 16, 4) {
+               PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+               PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+               PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG17MD_00, PG17MD_01, PG17MD_10, PG17MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG16MD_00, PG16MD_01, PG16MD_10, PG16MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PGCR3", 0xfffe38c8, 16, 4) {
+               PG15MD_00, PG15MD_01, PG15MD_10, PG15MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG14MD_00, PG14MD_01, PG14MD_10, PG14MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG13MD_00, PG13MD_01, PG13MD_10, PG13MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG12MD_00, PG12MD_01, PG12MD_10, PG12MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PGCR2", 0xfffe38ca, 16, 4) {
+               PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+               PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+               PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+               PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+               PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PGCR1", 0xfffe38cc, 16, 4) {
+               PG7MD_000, PG7MD_001, PG7MD_010, PG7MD_011,
+               PG7MD_100, PG7MD_101, PG7MD_110, PG7MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG6MD_000, PG6MD_001, PG6MD_010, PG6MD_011,
+               PG6MD_100, PG6MD_101, PG6MD_110, PG6MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG5MD_000, PG5MD_001, PG5MD_010, PG5MD_011,
+               PG5MD_100, PG5MD_101, PG5MD_110, PG5MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG4MD_000, PG4MD_001, PG4MD_010, PG4MD_011,
+               PG4MD_100, PG4MD_101, PG4MD_110, PG4MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PGCR0", 0xfffe38ce, 16, 4) {
+               PG3MD_000, PG3MD_001, PG3MD_010, PG3MD_011,
+               PG3MD_100, PG3MD_101, PG3MD_110, PG3MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG2MD_000, PG2MD_001, PG2MD_010, PG2MD_011,
+               PG2MD_100, PG2MD_101, PG2MD_110, PG2MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG1MD_000, PG1MD_001, PG1MD_010, PG1MD_011,
+               PG1MD_100, PG1MD_101, PG1MD_110, PG1MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+               PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PGIOR1", 0xfffe38d0, 16, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PG27_IN, PG27_OUT,
+               PG26_IN, PG26_OUT,
+               PG25_IN, PG25_OUT,
+               PG24_IN, PG24_OUT,
+               PG23_IN, PG23_OUT,
+               PG22_IN, PG22_OUT,
+               PG21_IN, PG21_OUT,
+               PG20_IN, PG20_OUT,
+               PG19_IN, PG19_OUT,
+               PG18_IN, PG18_OUT,
+               PG17_IN, PG17_OUT,
+               PG16_IN, PG16_OUT }
+       },
+       { PINMUX_CFG_REG("PGIOR0", 0xfffe38d2, 16, 1) {
+               PG15_IN, PG15_OUT,
+               PG14_IN, PG14_OUT,
+               PG13_IN, PG13_OUT,
+               PG12_IN, PG12_OUT,
+               PG11_IN, PG11_OUT,
+               PG10_IN, PG10_OUT,
+               PG9_IN, PG9_OUT,
+               PG8_IN, PG8_OUT,
+               PG7_IN, PG7_OUT,
+               PG6_IN, PG6_OUT,
+               PG5_IN, PG5_OUT,
+               PG4_IN, PG4_OUT,
+               PG3_IN, PG3_OUT,
+               PG2_IN, PG2_OUT,
+               PG1_IN, PG1_OUT,
+               PG0_IN, PG0_OUT }
+       },
+
+       { PINMUX_CFG_REG("PHCR1", 0xfffe38ec, 16, 4) {
+               PH7MD_00, PH7MD_01, PH7MD_10, PH7MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PH6MD_00, PH6MD_01, PH6MD_10, PH6MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PH5MD_00, PH5MD_01, PH5MD_10, PH5MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PH4MD_00, PH4MD_01, PH4MD_10, PH4MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PHCR0", 0xfffe38ee, 16, 4) {
+               PH3MD_00, PH3MD_01, PH3MD_10, PH3MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PH2MD_00, PH2MD_01, PH2MD_10, PH2MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PH1MD_00, PH1MD_01, PH1MD_10, PH1MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PH0MD_00, PH0MD_01, PH0MD_10, PH0MD_11, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PJCR7", 0xfffe3900, 16, 4) {
+               PJ31MD_0, PJ31MD_1, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ30MD_000, PJ30MD_001, PJ30MD_010, PJ30MD_011,
+               PJ30MD_100, PJ30MD_101, PJ30MD_110, PJ30MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ29MD_000, PJ29MD_001, PJ29MD_010, PJ29MD_011,
+               PJ29MD_100, PJ29MD_101, PJ29MD_110, PJ29MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ28MD_000, PJ28MD_001, PJ28MD_010, PJ28MD_011,
+               PJ28MD_100, PJ28MD_101, PJ28MD_110, PJ28MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PJCR6", 0xfffe3902, 16, 4) {
+               PJ27MD_000, PJ27MD_001, PJ27MD_010, PJ27MD_011,
+               PJ27MD_100, PJ27MD_101, PJ27MD_110, PJ27MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ26MD_000, PJ26MD_001, PJ26MD_010, PJ26MD_011,
+               PJ26MD_100, PJ26MD_101, PJ26MD_110, PJ26MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ25MD_000, PJ25MD_001, PJ25MD_010, PJ25MD_011,
+               PJ25MD_100, PJ25MD_101, PJ25MD_110, PJ25MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ24MD_000, PJ24MD_001, PJ24MD_010, PJ24MD_011,
+               PJ24MD_100, PJ24MD_101, PJ24MD_110, PJ24MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PJCR5", 0xfffe3904, 16, 4) {
+               PJ23MD_000, PJ23MD_001, PJ23MD_010, PJ23MD_011,
+               PJ23MD_100, PJ23MD_101, PJ23MD_110, PJ23MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ22MD_000, PJ22MD_001, PJ22MD_010, PJ22MD_011,
+               PJ22MD_100, PJ22MD_101, PJ22MD_110, PJ22MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ21MD_000, PJ21MD_001, PJ21MD_010, PJ21MD_011,
+               PJ21MD_100, PJ21MD_101, PJ21MD_110, PJ21MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ20MD_000, PJ20MD_001, PJ20MD_010, PJ20MD_011,
+               PJ20MD_100, PJ20MD_101, PJ20MD_110, PJ20MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PJCR4", 0xfffe3906, 16, 4) {
+               PJ19MD_000, PJ19MD_001, PJ19MD_010, PJ19MD_011,
+               PJ19MD_100, PJ19MD_101, PJ19MD_110, PJ19MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ18MD_000, PJ18MD_001, PJ18MD_010, PJ18MD_011,
+               PJ18MD_100, PJ18MD_101, PJ18MD_110, PJ18MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ17MD_000, PJ17MD_001, PJ17MD_010, PJ17MD_011,
+               PJ17MD_100, PJ17MD_101, PJ17MD_110, PJ17MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ16MD_000, PJ16MD_001, PJ16MD_010, PJ16MD_011,
+               PJ16MD_100, PJ16MD_101, PJ16MD_110, PJ16MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PJCR3", 0xfffe3908, 16, 4) {
+               PJ15MD_000, PJ15MD_001, PJ15MD_010, PJ15MD_011,
+               PJ15MD_100, PJ15MD_101, PJ15MD_110, PJ15MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ14MD_000, PJ14MD_001, PJ14MD_010, PJ14MD_011,
+               PJ14MD_100, PJ14MD_101, PJ14MD_110, PJ14MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ13MD_000, PJ13MD_001, PJ13MD_010, PJ13MD_011,
+               PJ13MD_100, PJ13MD_101, PJ13MD_110, PJ13MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ12MD_000, PJ12MD_001, PJ12MD_010, PJ12MD_011,
+               PJ12MD_100, PJ12MD_101, PJ12MD_110, PJ12MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PJCR2", 0xfffe390a, 16, 4) {
+               PJ11MD_000, PJ11MD_001, PJ11MD_010, PJ11MD_011,
+               PJ11MD_100, PJ11MD_101, PJ11MD_110, PJ11MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ10MD_000, PJ10MD_001, PJ10MD_010, PJ10MD_011,
+               PJ10MD_100, PJ10MD_101, PJ10MD_110, PJ10MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ9MD_000, PJ9MD_001, PJ9MD_010, PJ9MD_011,
+               PJ9MD_100, PJ9MD_101, PJ9MD_110, PJ9MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ8MD_000, PJ8MD_001, PJ8MD_010, PJ8MD_011,
+               PJ8MD_100, PJ8MD_101, PJ8MD_110, PJ8MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PJCR1", 0xfffe390c, 16, 4) {
+               PJ7MD_000, PJ7MD_001, PJ7MD_010, PJ7MD_011,
+               PJ7MD_100, PJ7MD_101, PJ7MD_110, PJ7MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ6MD_000, PJ6MD_001, PJ6MD_010, PJ6MD_011,
+               PJ6MD_100, PJ6MD_101, PJ6MD_110, PJ6MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ5MD_000, PJ5MD_001, PJ5MD_010, PJ5MD_011,
+               PJ5MD_100, PJ5MD_101, PJ5MD_110, PJ5MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ4MD_000, PJ4MD_001, PJ4MD_010, PJ4MD_011,
+               PJ4MD_100, PJ4MD_101, PJ4MD_110, PJ4MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG("PJCR0", 0xfffe390e, 16, 4) {
+               PJ3MD_000, PJ3MD_001, PJ3MD_010, PJ3MD_011,
+               PJ3MD_100, PJ3MD_101, PJ3MD_110, PJ3MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+               PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+               PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0,
+
+               PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+               PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
+               0, 0, 0, 0, 0, 0, 0, 0 }
+       },
+
+       { PINMUX_CFG_REG("PJIOR1", 0xfffe3910, 16, 1) {
+               PJ31_IN, PJ31_OUT,
+               PJ30_IN, PJ30_OUT,
+               PJ29_IN, PJ29_OUT,
+               PJ28_IN, PJ28_OUT,
+               PJ27_IN, PJ27_OUT,
+               PJ26_IN, PJ26_OUT,
+               PJ25_IN, PJ25_OUT,
+               PJ24_IN, PJ24_OUT,
+               PJ23_IN, PJ23_OUT,
+               PJ22_IN, PJ22_OUT,
+               PJ21_IN, PJ21_OUT,
+               PJ20_IN, PJ20_OUT,
+               PJ19_IN, PJ19_OUT,
+               PJ18_IN, PJ18_OUT,
+               PJ17_IN, PJ17_OUT,
+               PJ16_IN, PJ16_OUT }
+       },
+       { PINMUX_CFG_REG("PJIOR0", 0xfffe3912, 16, 1) {
+               PJ15_IN, PJ15_OUT,
+               PJ14_IN, PJ14_OUT,
+               PJ13_IN, PJ13_OUT,
+               PJ12_IN, PJ12_OUT,
+               PJ11_IN, PJ11_OUT,
+               PJ10_IN, PJ10_OUT,
+               PJ9_IN, PJ9_OUT,
+               PJ8_IN, PJ8_OUT,
+               PJ7_IN, PJ7_OUT,
+               PJ6_IN, PJ6_OUT,
+               PJ5_IN, PJ5_OUT,
+               PJ4_IN, PJ4_OUT,
+               PJ3_IN, PJ3_OUT,
+               PJ2_IN, PJ2_OUT,
+               PJ1_IN, PJ1_OUT,
+               PJ0_IN, PJ0_OUT }
+       },
+
+       {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+       { PINMUX_DATA_REG("PADR0", 0xfffe3816, 16) {
+               0, 0, 0, 0, 0, 0, 0, PA1_DATA,
+               0, 0, 0, 0, 0, 0, 0, PA0_DATA }
+       },
+
+       { PINMUX_DATA_REG("PBDR1", 0xfffe3834, 16) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, PB22_DATA, PB21_DATA, PB20_DATA,
+               PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA }
+       },
+       { PINMUX_DATA_REG("PBDR0", 0xfffe3836, 16) {
+               PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+               PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+               PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+               PB3_DATA, PB2_DATA, PB1_DATA, 0 }
+       },
+
+       { PINMUX_DATA_REG("PCDR0", 0xfffe3856, 16) {
+               0, 0, 0, 0,
+               0, 0, 0, PC8_DATA,
+               PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+               PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
+       },
+
+       { PINMUX_DATA_REG("PDDR0", 0xfffe3876, 16) {
+               PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+               PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+               PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+               PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
+       },
+
+       { PINMUX_DATA_REG("PEDR0", 0xfffe3896, 16) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+               PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
+       },
+
+       { PINMUX_DATA_REG("PFDR1", 0xfffe38b4, 16) {
+               0, 0, 0, 0, 0, 0, 0, 0,
+               PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
+               PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA }
+       },
+       { PINMUX_DATA_REG("PFDR0", 0xfffe38b6, 16) {
+               PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
+               PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+               PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+               PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
+       },
+
+       { PINMUX_DATA_REG("PGDR1", 0xfffe38d4, 16) {
+               0, 0, 0, 0,
+               PG27_DATA, PG26_DATA, PG25_DATA, PG24_DATA,
+               PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+               PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA }
+       },
+       { PINMUX_DATA_REG("PGDR0", 0xfffe38d6, 16) {
+               PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+               PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+               PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+               PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA }
+       },
+
+       { PINMUX_DATA_REG("PJDR1", 0xfffe3914, 16) {
+               PJ31_DATA, PJ30_DATA, PJ29_DATA, PJ28_DATA,
+               PJ27_DATA, PJ26_DATA, PJ25_DATA, PJ24_DATA,
+               PJ23_DATA, PJ22_DATA, PJ21_DATA, PJ20_DATA,
+               PJ19_DATA, PJ18_DATA, PJ17_DATA, PJ16_DATA }
+       },
+       { PINMUX_DATA_REG("PJDR0", 0xfffe3916, 16) {
+               PJ15_DATA, PJ14_DATA, PJ13_DATA, PJ12_DATA,
+               PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+               PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+               PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA }
+       },
+
+       { }
+};
+
+static struct pinmux_info sh7269_pinmux_info = {
+       .name = "sh7269_pfc",
+       .reserved_id = PINMUX_RESERVED,
+       .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+       .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END, FORCE_IN },
+       .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END, FORCE_OUT },
+       .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+       .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+       .first_gpio = GPIO_PA1,
+       .last_gpio = GPIO_FN_LCD_M_DISP,
+
+       .gpios = pinmux_gpios,
+       .cfg_regs = pinmux_config_regs,
+       .data_regs = pinmux_data_regs,
+
+       .gpio_data = pinmux_data,
+       .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+static int __init plat_pinmux_setup(void)
+{
+       return register_pinmux(&sh7269_pinmux_info);
+}
+arch_initcall(plat_pinmux_setup);
index 48e97a2a0c8d26b66287a7254ebc9b5495a2934d..5170b6aa4129e5d0f6648e6ec6014d9289f75d86 100644 (file)
@@ -29,6 +29,12 @@ void __cpuinit cpu_probe(void)
 #elif defined(CONFIG_CPU_SUBTYPE_SH7263)
        boot_cpu_data.type                      = CPU_SH7263;
        boot_cpu_data.flags                     |= CPU_HAS_FPU;
+#elif defined(CONFIG_CPU_SUBTYPE_SH7264)
+       boot_cpu_data.type                      = CPU_SH7264;
+       boot_cpu_data.flags                     |= CPU_HAS_FPU;
+#elif defined(CONFIG_CPU_SUBTYPE_SH7269)
+       boot_cpu_data.type                      = CPU_SH7269;
+       boot_cpu_data.flags                     |= CPU_HAS_FPU;
 #elif defined(CONFIG_CPU_SUBTYPE_SH7206)
        boot_cpu_data.type                      = CPU_SH7206;
        boot_cpu_data.flags                     |= CPU_HAS_DSP;
index 949bf2bac28c9e9c72feb8b6774299db0eef1018..f7f1cf2af3028dc8a5f4d3dfeacf5370ea3e0176 100644 (file)
@@ -204,7 +204,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 220, 220, 220, 220 },
+       .irqs           = SCIx_IRQ_MUXED(220),
 };
 
 static struct platform_device scif0_device = {
index 9df558dcdb865a12771b3c1a20b90ea272477ec7..7b84785b89624664ba8a028696128f8a188c534c 100644 (file)
@@ -183,7 +183,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 180, 180, 180, 180 }
+       .irqs           = SCIx_IRQ_MUXED(180),
 };
 
 static struct platform_device scif0_device = {
@@ -200,7 +200,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 184, 184, 184, 184 }
+       .irqs           = SCIx_IRQ_MUXED(184),
 };
 
 static struct platform_device scif1_device = {
@@ -217,7 +217,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 188, 188, 188, 188 }
+       .irqs           = SCIx_IRQ_MUXED(188),
 };
 
 static struct platform_device scif2_device = {
@@ -234,7 +234,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 192, 192, 192, 192 }
+       .irqs           = SCIx_IRQ_MUXED(192),
 };
 
 static struct platform_device scif3_device = {
@@ -251,7 +251,7 @@ static struct plat_sci_port scif4_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 196, 196, 196, 196 }
+       .irqs           = SCIx_IRQ_MUXED(196),
 };
 
 static struct platform_device scif4_device = {
@@ -268,7 +268,7 @@ static struct plat_sci_port scif5_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 200, 200, 200, 200 }
+       .irqs           = SCIx_IRQ_MUXED(200),
 };
 
 static struct platform_device scif5_device = {
@@ -285,7 +285,7 @@ static struct plat_sci_port scif6_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 204, 204, 204, 204 }
+       .irqs           = SCIx_IRQ_MUXED(204),
 };
 
 static struct platform_device scif6_device = {
@@ -302,7 +302,7 @@ static struct plat_sci_port scif7_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 208, 208, 208, 208 }
+       .irqs           = SCIx_IRQ_MUXED(208),
 };
 
 static struct platform_device scif7_device = {
index 0bd744f9a3b7051c966266b47f13172bb0d4b4a6..bfc33f6a28c3492b3a3ec54116d0d5d3dcea1aa9 100644 (file)
@@ -180,7 +180,7 @@ static struct plat_sci_port scif0_platform_data = {
                          SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           =  { 192, 192, 192, 192 },
+       .irqs           = SCIx_IRQ_MUXED(192),
        .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -199,7 +199,7 @@ static struct plat_sci_port scif1_platform_data = {
                          SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           =  { 196, 196, 196, 196 },
+       .irqs           = SCIx_IRQ_MUXED(196),
        .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -218,7 +218,7 @@ static struct plat_sci_port scif2_platform_data = {
                          SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           =  { 200, 200, 200, 200 },
+       .irqs           = SCIx_IRQ_MUXED(200),
        .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -237,7 +237,7 @@ static struct plat_sci_port scif3_platform_data = {
                          SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           =  { 204, 204, 204, 204 },
+       .irqs           = SCIx_IRQ_MUXED(204),
        .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
 };
 
index 5d14f849aea3f9b632902cfdcf7bfe0c735f5a30..a5010741de854cd00383b4d9431cc43b73122bc1 100644 (file)
@@ -139,7 +139,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 240, 240, 240, 240 },
+       .irqs           = SCIx_IRQ_MUXED(240),
 };
 
 static struct platform_device scif0_device = {
@@ -156,7 +156,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 244, 244, 244, 244 },
+       .irqs           = SCIx_IRQ_MUXED(244),
 };
 
 static struct platform_device scif1_device = {
@@ -173,7 +173,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 248, 248, 248, 248 },
+       .irqs           = SCIx_IRQ_MUXED(248),
 };
 
 static struct platform_device scif2_device = {
@@ -190,7 +190,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 252, 252, 252, 252 },
+       .irqs           = SCIx_IRQ_MUXED(252),
 };
 
 static struct platform_device scif3_device = {
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7264.c b/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
new file mode 100644 (file)
index 0000000..ce5c1b5
--- /dev/null
@@ -0,0 +1,606 @@
+/*
+ * SH7264 Setup
+ *
+ * Copyright (C) 2012  Renesas Electronics Europe Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serial_sci.h>
+#include <linux/usb/r8a66597.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
+
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+       PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
+
+       DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
+       DMAC8, DMAC9, DMAC10, DMAC11, DMAC12, DMAC13, DMAC14, DMAC15,
+       USB, VDC3, CMT0, CMT1, BSC, WDT,
+       MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
+       MTU3_ABCD, MTU3_TCI3V, MTU4_ABCD, MTU4_TCI4V,
+       PWMT1, PWMT2, ADC_ADI,
+       SSIF0, SSII1, SSII2, SSII3,
+       RSPDIF,
+       IIC30, IIC31, IIC32, IIC33,
+       SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
+       SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
+       SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
+       SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
+       SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI,
+       SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI,
+       SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI,
+       SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI,
+       SIO_FIFO, RSPIC0, RSPIC1,
+       RCAN0, RCAN1, IEBC, CD_ROMD,
+       NFMC, SDHI, RTC,
+       SRCC0, SRCC1, DCOMU, OFFI, IFEI,
+
+       /* interrupt groups */
+       PINT, SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
+       INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
+       INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69),
+       INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
+
+       INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
+       INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
+       INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
+       INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
+
+       INTC_IRQ(DMAC0, 108), INTC_IRQ(DMAC0, 109),
+       INTC_IRQ(DMAC1, 112), INTC_IRQ(DMAC1, 113),
+       INTC_IRQ(DMAC2, 116), INTC_IRQ(DMAC2, 117),
+       INTC_IRQ(DMAC3, 120), INTC_IRQ(DMAC3, 121),
+       INTC_IRQ(DMAC4, 124), INTC_IRQ(DMAC4, 125),
+       INTC_IRQ(DMAC5, 128), INTC_IRQ(DMAC5, 129),
+       INTC_IRQ(DMAC6, 132), INTC_IRQ(DMAC6, 133),
+       INTC_IRQ(DMAC7, 136), INTC_IRQ(DMAC7, 137),
+       INTC_IRQ(DMAC8, 140), INTC_IRQ(DMAC8, 141),
+       INTC_IRQ(DMAC9, 144), INTC_IRQ(DMAC9, 145),
+       INTC_IRQ(DMAC10, 148), INTC_IRQ(DMAC10, 149),
+       INTC_IRQ(DMAC11, 152), INTC_IRQ(DMAC11, 153),
+       INTC_IRQ(DMAC12, 156), INTC_IRQ(DMAC12, 157),
+       INTC_IRQ(DMAC13, 160), INTC_IRQ(DMAC13, 161),
+       INTC_IRQ(DMAC14, 164), INTC_IRQ(DMAC14, 165),
+       INTC_IRQ(DMAC15, 168), INTC_IRQ(DMAC15, 169),
+
+       INTC_IRQ(USB, 170),
+       INTC_IRQ(VDC3, 171), INTC_IRQ(VDC3, 172),
+       INTC_IRQ(VDC3, 173), INTC_IRQ(VDC3, 174),
+       INTC_IRQ(CMT0, 175), INTC_IRQ(CMT1, 176),
+       INTC_IRQ(BSC, 177), INTC_IRQ(WDT, 178),
+
+       INTC_IRQ(MTU0_ABCD, 179), INTC_IRQ(MTU0_ABCD, 180),
+       INTC_IRQ(MTU0_ABCD, 181), INTC_IRQ(MTU0_ABCD, 182),
+       INTC_IRQ(MTU0_VEF, 183),
+       INTC_IRQ(MTU0_VEF, 184), INTC_IRQ(MTU0_VEF, 185),
+       INTC_IRQ(MTU1_AB, 186), INTC_IRQ(MTU1_AB, 187),
+       INTC_IRQ(MTU1_VU, 188), INTC_IRQ(MTU1_VU, 189),
+       INTC_IRQ(MTU2_AB, 190), INTC_IRQ(MTU2_AB, 191),
+       INTC_IRQ(MTU2_VU, 192), INTC_IRQ(MTU2_VU, 193),
+       INTC_IRQ(MTU3_ABCD, 194), INTC_IRQ(MTU3_ABCD, 195),
+       INTC_IRQ(MTU3_ABCD, 196), INTC_IRQ(MTU3_ABCD, 197),
+       INTC_IRQ(MTU3_TCI3V, 198),
+       INTC_IRQ(MTU4_ABCD, 199), INTC_IRQ(MTU4_ABCD, 200),
+       INTC_IRQ(MTU4_ABCD, 201), INTC_IRQ(MTU4_ABCD, 202),
+       INTC_IRQ(MTU4_TCI4V, 203),
+
+       INTC_IRQ(PWMT1, 204), INTC_IRQ(PWMT2, 205),
+
+       INTC_IRQ(ADC_ADI, 206),
+
+       INTC_IRQ(SSIF0, 207), INTC_IRQ(SSIF0, 208),
+       INTC_IRQ(SSIF0, 209),
+       INTC_IRQ(SSII1, 210), INTC_IRQ(SSII1, 211),
+       INTC_IRQ(SSII2, 212), INTC_IRQ(SSII2, 213),
+       INTC_IRQ(SSII3, 214), INTC_IRQ(SSII3, 215),
+
+       INTC_IRQ(RSPDIF, 216),
+
+       INTC_IRQ(IIC30, 217), INTC_IRQ(IIC30, 218),
+       INTC_IRQ(IIC30, 219), INTC_IRQ(IIC30, 220),
+       INTC_IRQ(IIC30, 221),
+       INTC_IRQ(IIC31, 222), INTC_IRQ(IIC31, 223),
+       INTC_IRQ(IIC31, 224), INTC_IRQ(IIC31, 225),
+       INTC_IRQ(IIC31, 226),
+       INTC_IRQ(IIC32, 227), INTC_IRQ(IIC32, 228),
+       INTC_IRQ(IIC32, 229), INTC_IRQ(IIC32, 230),
+       INTC_IRQ(IIC32, 231),
+
+       INTC_IRQ(SCIF0_BRI, 232), INTC_IRQ(SCIF0_ERI, 233),
+       INTC_IRQ(SCIF0_RXI, 234), INTC_IRQ(SCIF0_TXI, 235),
+       INTC_IRQ(SCIF1_BRI, 236), INTC_IRQ(SCIF1_ERI, 237),
+       INTC_IRQ(SCIF1_RXI, 238), INTC_IRQ(SCIF1_TXI, 239),
+       INTC_IRQ(SCIF2_BRI, 240), INTC_IRQ(SCIF2_ERI, 241),
+       INTC_IRQ(SCIF2_RXI, 242), INTC_IRQ(SCIF2_TXI, 243),
+       INTC_IRQ(SCIF3_BRI, 244), INTC_IRQ(SCIF3_ERI, 245),
+       INTC_IRQ(SCIF3_RXI, 246), INTC_IRQ(SCIF3_TXI, 247),
+       INTC_IRQ(SCIF4_BRI, 248), INTC_IRQ(SCIF4_ERI, 249),
+       INTC_IRQ(SCIF4_RXI, 250), INTC_IRQ(SCIF4_TXI, 251),
+       INTC_IRQ(SCIF5_BRI, 252), INTC_IRQ(SCIF5_ERI, 253),
+       INTC_IRQ(SCIF5_RXI, 254), INTC_IRQ(SCIF5_TXI, 255),
+       INTC_IRQ(SCIF6_BRI, 256), INTC_IRQ(SCIF6_ERI, 257),
+       INTC_IRQ(SCIF6_RXI, 258), INTC_IRQ(SCIF6_TXI, 259),
+       INTC_IRQ(SCIF7_BRI, 260), INTC_IRQ(SCIF7_ERI, 261),
+       INTC_IRQ(SCIF7_RXI, 262), INTC_IRQ(SCIF7_TXI, 263),
+
+       INTC_IRQ(SIO_FIFO, 264),
+
+       INTC_IRQ(RSPIC0, 265), INTC_IRQ(RSPIC0, 266),
+       INTC_IRQ(RSPIC0, 267),
+       INTC_IRQ(RSPIC1, 268), INTC_IRQ(RSPIC1, 269),
+       INTC_IRQ(RSPIC1, 270),
+
+       INTC_IRQ(RCAN0, 271), INTC_IRQ(RCAN0, 272),
+       INTC_IRQ(RCAN0, 273), INTC_IRQ(RCAN0, 274),
+       INTC_IRQ(RCAN0, 275),
+       INTC_IRQ(RCAN1, 276), INTC_IRQ(RCAN1, 277),
+       INTC_IRQ(RCAN1, 278), INTC_IRQ(RCAN1, 279),
+       INTC_IRQ(RCAN1, 280),
+
+       INTC_IRQ(IEBC, 281),
+
+       INTC_IRQ(CD_ROMD, 282), INTC_IRQ(CD_ROMD, 283),
+       INTC_IRQ(CD_ROMD, 284), INTC_IRQ(CD_ROMD, 285),
+       INTC_IRQ(CD_ROMD, 286), INTC_IRQ(CD_ROMD, 287),
+
+       INTC_IRQ(NFMC, 288), INTC_IRQ(NFMC, 289),
+       INTC_IRQ(NFMC, 290), INTC_IRQ(NFMC, 291),
+
+       INTC_IRQ(SDHI, 292), INTC_IRQ(SDHI, 293),
+       INTC_IRQ(SDHI, 294),
+
+       INTC_IRQ(RTC, 296), INTC_IRQ(RTC, 297),
+       INTC_IRQ(RTC, 298),
+
+       INTC_IRQ(SRCC0, 299), INTC_IRQ(SRCC0, 300),
+       INTC_IRQ(SRCC0, 301), INTC_IRQ(SRCC0, 302),
+       INTC_IRQ(SRCC0, 303),
+       INTC_IRQ(SRCC1, 304), INTC_IRQ(SRCC1, 305),
+       INTC_IRQ(SRCC1, 306), INTC_IRQ(SRCC1, 307),
+       INTC_IRQ(SRCC1, 308),
+
+       INTC_IRQ(DCOMU, 310), INTC_IRQ(DCOMU, 311),
+       INTC_IRQ(DCOMU, 312),
+};
+
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
+                  PINT4, PINT5, PINT6, PINT7),
+       INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
+       INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
+       INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+       INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
+       INTC_GROUP(SCIF4, SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI),
+       INTC_GROUP(SCIF5, SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI),
+       INTC_GROUP(SCIF6, SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI),
+       INTC_GROUP(SCIF7, SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+       { 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+       { 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, 0, 0 } },
+       { 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0,  DMAC1,  DMAC2,  DMAC3 } },
+       { 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4,  DMAC5,  DMAC6,  DMAC7 } },
+       { 0xfffe0c04, 0, 16, 4, /* IPR08 */ { DMAC8,  DMAC9,
+                                             DMAC10, DMAC11 } },
+       { 0xfffe0c06, 0, 16, 4, /* IPR09 */ { DMAC12, DMAC13,
+                                             DMAC14, DMAC15 } },
+       { 0xfffe0c08, 0, 16, 4, /* IPR10 */ { USB, VDC3, CMT0, CMT1 } },
+       { 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { BSC, WDT, MTU0_ABCD, MTU0_VEF } },
+       { 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { MTU1_AB, MTU1_VU,
+                                             MTU2_AB, MTU2_VU } },
+       { 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { MTU3_ABCD, MTU3_TCI3V,
+                                             MTU4_ABCD, MTU4_TCI4V } },
+       { 0xfffe0c10, 0, 16, 4, /* IPR14 */ { PWMT1, PWMT2, ADC_ADI, 0 } },
+       { 0xfffe0c12, 0, 16, 4, /* IPR15 */ { SSIF0, SSII1, SSII2, SSII3 } },
+       { 0xfffe0c14, 0, 16, 4, /* IPR16 */ { RSPDIF, IIC30, IIC31, IIC32 } },
+       { 0xfffe0c16, 0, 16, 4, /* IPR17 */ { SCIF0, SCIF1, SCIF2, SCIF3 } },
+       { 0xfffe0c18, 0, 16, 4, /* IPR18 */ { SCIF4, SCIF5, SCIF6, SCIF7 } },
+       { 0xfffe0c1a, 0, 16, 4, /* IPR19 */ { SIO_FIFO, 0, RSPIC0, RSPIC1, } },
+       { 0xfffe0c1c, 0, 16, 4, /* IPR20 */ { RCAN0, RCAN1, IEBC, CD_ROMD } },
+       { 0xfffe0c1e, 0, 16, 4, /* IPR21 */ { NFMC, SDHI, RTC, 0 } },
+       { 0xfffe0c20, 0, 16, 4, /* IPR22 */ { SRCC0, SRCC1, 0, DCOMU } },
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { 0xfffe0808, 0, 16, /* PINTER */
+         { 0, 0, 0, 0, 0, 0, 0, 0,
+           PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7264", vectors, groups,
+                        mask_registers, prio_registers, NULL);
+
+static struct plat_sci_port scif0_platform_data = {
+       .mapbase        = 0xfffe8000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 233, 234, 235, 232 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif0_device = {
+       .name           = "sh-sci",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &scif0_platform_data,
+       },
+};
+
+static struct plat_sci_port scif1_platform_data = {
+       .mapbase        = 0xfffe8800,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 237, 238, 239, 236 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif1_device = {
+       .name           = "sh-sci",
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &scif1_platform_data,
+       },
+};
+
+static struct plat_sci_port scif2_platform_data = {
+       .mapbase        = 0xfffe9000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 241, 242, 243, 240 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif2_device = {
+       .name           = "sh-sci",
+       .id             = 2,
+       .dev            = {
+               .platform_data  = &scif2_platform_data,
+       },
+};
+
+static struct plat_sci_port scif3_platform_data = {
+       .mapbase        = 0xfffe9800,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 245, 246, 247, 244 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif3_device = {
+       .name           = "sh-sci",
+       .id             = 3,
+       .dev            = {
+               .platform_data  = &scif3_platform_data,
+       },
+};
+
+static struct plat_sci_port scif4_platform_data = {
+       .mapbase        = 0xfffea000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 249, 250, 251, 248 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif4_device = {
+       .name           = "sh-sci",
+       .id             = 4,
+       .dev            = {
+               .platform_data  = &scif4_platform_data,
+       },
+};
+
+static struct plat_sci_port scif5_platform_data = {
+       .mapbase        = 0xfffea800,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 253, 254, 255, 252 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif5_device = {
+       .name           = "sh-sci",
+       .id             = 5,
+       .dev            = {
+               .platform_data  = &scif5_platform_data,
+       },
+};
+
+static struct plat_sci_port scif6_platform_data = {
+       .mapbase        = 0xfffeb000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 257, 258, 259, 256 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif6_device = {
+       .name           = "sh-sci",
+       .id             = 6,
+       .dev            = {
+               .platform_data  = &scif6_platform_data,
+       },
+};
+
+static struct plat_sci_port scif7_platform_data = {
+       .mapbase        = 0xfffeb800,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 261, 262, 263, 260 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif7_device = {
+       .name           = "sh-sci",
+       .id             = 7,
+       .dev            = {
+               .platform_data  = &scif7_platform_data,
+       },
+};
+
+static struct sh_timer_config cmt0_platform_data = {
+       .channel_offset = 0x02,
+       .timer_bit = 0,
+       .clockevent_rating = 125,
+       .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt0_resources[] = {
+       [0] = {
+               .name   = "CMT0",
+               .start  = 0xfffec002,
+               .end    = 0xfffec007,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 175,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt0_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt0_platform_data,
+       },
+       .resource       = cmt0_resources,
+       .num_resources  = ARRAY_SIZE(cmt0_resources),
+};
+
+static struct sh_timer_config cmt1_platform_data = {
+       .name = "CMT1",
+       .channel_offset = 0x08,
+       .timer_bit = 1,
+       .clockevent_rating = 125,
+       .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt1_resources[] = {
+       [0] = {
+               .name   = "CMT1",
+               .start  = 0xfffec008,
+               .end    = 0xfffec00d,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 176,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt1_device = {
+       .name           = "sh_cmt",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &cmt1_platform_data,
+       },
+       .resource       = cmt1_resources,
+       .num_resources  = ARRAY_SIZE(cmt1_resources),
+};
+
+static struct sh_timer_config mtu2_0_platform_data = {
+       .name = "MTU2_0",
+       .channel_offset = -0x80,
+       .timer_bit = 0,
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_0_resources[] = {
+       [0] = {
+               .name   = "MTU2_0",
+               .start  = 0xfffe4300,
+               .end    = 0xfffe4326,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 179,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_0_device = {
+       .name           = "sh_mtu2",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &mtu2_0_platform_data,
+       },
+       .resource       = mtu2_0_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_0_resources),
+};
+
+static struct sh_timer_config mtu2_1_platform_data = {
+       .name = "MTU2_1",
+       .channel_offset = -0x100,
+       .timer_bit = 1,
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_1_resources[] = {
+       [0] = {
+               .name   = "MTU2_1",
+               .start  = 0xfffe4380,
+               .end    = 0xfffe4390,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 186,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_1_device = {
+       .name           = "sh_mtu2",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &mtu2_1_platform_data,
+       },
+       .resource       = mtu2_1_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_1_resources),
+};
+
+static struct resource rtc_resources[] = {
+       [0] = {
+               .start  = 0xfffe6000,
+               .end    = 0xfffe6000 + 0x30 - 1,
+               .flags  = IORESOURCE_IO,
+       },
+       [1] = {
+               /* Shared Period/Carry/Alarm IRQ */
+               .start  = 296,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device rtc_device = {
+       .name           = "sh-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(rtc_resources),
+       .resource       = rtc_resources,
+};
+
+/* USB Host */
+static void usb_port_power(int port, int power)
+{
+       __raw_writew(0x200 , 0xffffc0c2) ; /* Initialise UACS25 */
+}
+
+static struct r8a66597_platdata r8a66597_data = {
+       .on_chip = 1,
+       .endian = 1,
+       .port_power = usb_port_power,
+};
+
+static struct resource r8a66597_usb_host_resources[] = {
+       [0] = {
+               .start  = 0xffffc000,
+               .end    = 0xffffc0e4,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 170,
+               .end    = 170,
+               .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
+       },
+};
+
+static struct platform_device r8a66597_usb_host_device = {
+       .name           = "r8a66597_hcd",
+       .id             = 0,
+       .dev = {
+               .dma_mask               = NULL,         /*  not use dma */
+               .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = &r8a66597_data,
+       },
+       .num_resources  = ARRAY_SIZE(r8a66597_usb_host_resources),
+       .resource       = r8a66597_usb_host_resources,
+};
+
+static struct platform_device *sh7264_devices[] __initdata = {
+       &scif0_device,
+       &scif1_device,
+       &scif2_device,
+       &scif3_device,
+       &scif4_device,
+       &scif5_device,
+       &scif6_device,
+       &scif7_device,
+       &cmt0_device,
+       &cmt1_device,
+       &mtu2_0_device,
+       &mtu2_1_device,
+       &rtc_device,
+       &r8a66597_usb_host_device,
+};
+
+static int __init sh7264_devices_setup(void)
+{
+       return platform_add_devices(sh7264_devices,
+                                   ARRAY_SIZE(sh7264_devices));
+}
+arch_initcall(sh7264_devices_setup);
+
+void __init plat_irq_setup(void)
+{
+       register_intc_controller(&intc_desc);
+}
+
+static struct platform_device *sh7264_early_devices[] __initdata = {
+       &scif0_device,
+       &scif1_device,
+       &scif2_device,
+       &scif3_device,
+       &scif4_device,
+       &scif5_device,
+       &scif6_device,
+       &scif7_device,
+       &cmt0_device,
+       &cmt1_device,
+       &mtu2_0_device,
+       &mtu2_1_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7264_early_devices,
+                                  ARRAY_SIZE(sh7264_early_devices));
+}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7269.c b/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
new file mode 100644 (file)
index 0000000..e82ae9d
--- /dev/null
@@ -0,0 +1,615 @@
+/*
+ * SH7269 Setup
+ *
+ * Copyright (C) 2012  Renesas Electronics Europe Ltd
+ * Copyright (C) 2012  Phil Edworthy
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serial_sci.h>
+#include <linux/usb/r8a66597.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
+
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+       PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
+
+       DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
+       DMAC8, DMAC9, DMAC10, DMAC11, DMAC12, DMAC13, DMAC14, DMAC15,
+       USB, VDC4, CMT0, CMT1, BSC, WDT,
+       MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
+       MTU3_ABCD, MTU3_TCI3V, MTU4_ABCD, MTU4_TCI4V,
+       PWMT1, PWMT2, ADC_ADI,
+       SSIF0, SSII1, SSII2, SSII3, SSII4, SSII5,
+       RSPDIF,
+       IIC30, IIC31, IIC32, IIC33,
+       SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
+       SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
+       SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
+       SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
+       SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI,
+       SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI,
+       SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI,
+       SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI,
+       RCAN0, RCAN1, RCAN2,
+       RSPIC0, RSPIC1,
+       IEBC, CD_ROMD,
+       NFMC,
+       SDHI0, SDHI1,
+       RTC,
+       SRCC0, SRCC1, SRCC2,
+
+       /* interrupt groups */
+       PINT, SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
+       INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
+       INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69),
+       INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
+
+       INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
+       INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
+       INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
+       INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
+
+       INTC_IRQ(DMAC0, 108), INTC_IRQ(DMAC0, 109),
+       INTC_IRQ(DMAC1, 112), INTC_IRQ(DMAC1, 113),
+       INTC_IRQ(DMAC2, 116), INTC_IRQ(DMAC2, 117),
+       INTC_IRQ(DMAC3, 120), INTC_IRQ(DMAC3, 121),
+       INTC_IRQ(DMAC4, 124), INTC_IRQ(DMAC4, 125),
+       INTC_IRQ(DMAC5, 128), INTC_IRQ(DMAC5, 129),
+       INTC_IRQ(DMAC6, 132), INTC_IRQ(DMAC6, 133),
+       INTC_IRQ(DMAC7, 136), INTC_IRQ(DMAC7, 137),
+       INTC_IRQ(DMAC8, 140), INTC_IRQ(DMAC8, 141),
+       INTC_IRQ(DMAC9, 144), INTC_IRQ(DMAC9, 145),
+       INTC_IRQ(DMAC10, 148), INTC_IRQ(DMAC10, 149),
+       INTC_IRQ(DMAC11, 152), INTC_IRQ(DMAC11, 153),
+       INTC_IRQ(DMAC12, 156), INTC_IRQ(DMAC12, 157),
+       INTC_IRQ(DMAC13, 160), INTC_IRQ(DMAC13, 161),
+       INTC_IRQ(DMAC14, 164), INTC_IRQ(DMAC14, 165),
+       INTC_IRQ(DMAC15, 168), INTC_IRQ(DMAC15, 169),
+
+       INTC_IRQ(USB, 170),
+
+       INTC_IRQ(VDC4, 171), INTC_IRQ(VDC4, 172),
+       INTC_IRQ(VDC4, 173), INTC_IRQ(VDC4, 174),
+       INTC_IRQ(VDC4, 175), INTC_IRQ(VDC4, 176),
+       INTC_IRQ(VDC4, 177), INTC_IRQ(VDC4, 177),
+
+       INTC_IRQ(CMT0, 188), INTC_IRQ(CMT1, 189),
+
+       INTC_IRQ(BSC, 190), INTC_IRQ(WDT, 191),
+
+       INTC_IRQ(MTU0_ABCD, 192), INTC_IRQ(MTU0_ABCD, 193),
+       INTC_IRQ(MTU0_ABCD, 194), INTC_IRQ(MTU0_ABCD, 195),
+       INTC_IRQ(MTU0_VEF, 196), INTC_IRQ(MTU0_VEF, 197),
+       INTC_IRQ(MTU0_VEF, 198),
+       INTC_IRQ(MTU1_AB, 199), INTC_IRQ(MTU1_AB, 200),
+       INTC_IRQ(MTU1_VU, 201), INTC_IRQ(MTU1_VU, 202),
+       INTC_IRQ(MTU2_AB, 203), INTC_IRQ(MTU2_AB, 204),
+       INTC_IRQ(MTU2_VU, 205), INTC_IRQ(MTU2_VU, 206),
+       INTC_IRQ(MTU3_ABCD, 207), INTC_IRQ(MTU3_ABCD, 208),
+       INTC_IRQ(MTU3_ABCD, 209), INTC_IRQ(MTU3_ABCD, 210),
+       INTC_IRQ(MTU3_TCI3V, 211),
+       INTC_IRQ(MTU4_ABCD, 212), INTC_IRQ(MTU4_ABCD, 213),
+       INTC_IRQ(MTU4_ABCD, 214), INTC_IRQ(MTU4_ABCD, 215),
+       INTC_IRQ(MTU4_TCI4V, 216),
+
+       INTC_IRQ(PWMT1, 217), INTC_IRQ(PWMT2, 218),
+
+       INTC_IRQ(ADC_ADI, 223),
+
+       INTC_IRQ(SSIF0, 224), INTC_IRQ(SSIF0, 225),
+       INTC_IRQ(SSIF0, 226),
+       INTC_IRQ(SSII1, 227), INTC_IRQ(SSII1, 228),
+       INTC_IRQ(SSII2, 229), INTC_IRQ(SSII2, 230),
+       INTC_IRQ(SSII3, 231), INTC_IRQ(SSII3, 232),
+       INTC_IRQ(SSII4, 233), INTC_IRQ(SSII4, 234),
+       INTC_IRQ(SSII5, 235), INTC_IRQ(SSII5, 236),
+
+       INTC_IRQ(RSPDIF, 237),
+
+       INTC_IRQ(IIC30, 238), INTC_IRQ(IIC30, 239),
+       INTC_IRQ(IIC30, 240), INTC_IRQ(IIC30, 241),
+       INTC_IRQ(IIC30, 242),
+       INTC_IRQ(IIC31, 243), INTC_IRQ(IIC31, 244),
+       INTC_IRQ(IIC31, 245), INTC_IRQ(IIC31, 246),
+       INTC_IRQ(IIC31, 247),
+       INTC_IRQ(IIC32, 248), INTC_IRQ(IIC32, 249),
+       INTC_IRQ(IIC32, 250), INTC_IRQ(IIC32, 251),
+       INTC_IRQ(IIC32, 252),
+       INTC_IRQ(IIC33, 253), INTC_IRQ(IIC33, 254),
+       INTC_IRQ(IIC33, 255), INTC_IRQ(IIC33, 256),
+       INTC_IRQ(IIC33, 257),
+
+       INTC_IRQ(SCIF0_BRI, 258), INTC_IRQ(SCIF0_ERI, 259),
+       INTC_IRQ(SCIF0_RXI, 260), INTC_IRQ(SCIF0_TXI, 261),
+       INTC_IRQ(SCIF1_BRI, 262), INTC_IRQ(SCIF1_ERI, 263),
+       INTC_IRQ(SCIF1_RXI, 264), INTC_IRQ(SCIF1_TXI, 265),
+       INTC_IRQ(SCIF2_BRI, 266), INTC_IRQ(SCIF2_ERI, 267),
+       INTC_IRQ(SCIF2_RXI, 268), INTC_IRQ(SCIF2_TXI, 269),
+       INTC_IRQ(SCIF3_BRI, 270), INTC_IRQ(SCIF3_ERI, 271),
+       INTC_IRQ(SCIF3_RXI, 272), INTC_IRQ(SCIF3_TXI, 273),
+       INTC_IRQ(SCIF4_BRI, 274), INTC_IRQ(SCIF4_ERI, 275),
+       INTC_IRQ(SCIF4_RXI, 276), INTC_IRQ(SCIF4_TXI, 277),
+       INTC_IRQ(SCIF5_BRI, 278), INTC_IRQ(SCIF5_ERI, 279),
+       INTC_IRQ(SCIF5_RXI, 280), INTC_IRQ(SCIF5_TXI, 281),
+       INTC_IRQ(SCIF6_BRI, 282), INTC_IRQ(SCIF6_ERI, 283),
+       INTC_IRQ(SCIF6_RXI, 284), INTC_IRQ(SCIF6_TXI, 285),
+       INTC_IRQ(SCIF7_BRI, 286), INTC_IRQ(SCIF7_ERI, 287),
+       INTC_IRQ(SCIF7_RXI, 288), INTC_IRQ(SCIF7_TXI, 289),
+
+       INTC_IRQ(RCAN0, 291), INTC_IRQ(RCAN0, 292),
+       INTC_IRQ(RCAN0, 293), INTC_IRQ(RCAN0, 294),
+       INTC_IRQ(RCAN0, 295),
+       INTC_IRQ(RCAN1, 296), INTC_IRQ(RCAN1, 297),
+       INTC_IRQ(RCAN1, 298), INTC_IRQ(RCAN1, 299),
+       INTC_IRQ(RCAN1, 300),
+       INTC_IRQ(RCAN2, 301), INTC_IRQ(RCAN2, 302),
+       INTC_IRQ(RCAN2, 303), INTC_IRQ(RCAN2, 304),
+       INTC_IRQ(RCAN2, 305),
+
+       INTC_IRQ(RSPIC0, 306), INTC_IRQ(RSPIC0, 307),
+       INTC_IRQ(RSPIC0, 308),
+       INTC_IRQ(RSPIC1, 309), INTC_IRQ(RSPIC1, 310),
+       INTC_IRQ(RSPIC1, 311),
+
+       INTC_IRQ(IEBC, 318),
+
+       INTC_IRQ(CD_ROMD, 319), INTC_IRQ(CD_ROMD, 320),
+       INTC_IRQ(CD_ROMD, 321), INTC_IRQ(CD_ROMD, 322),
+       INTC_IRQ(CD_ROMD, 323), INTC_IRQ(CD_ROMD, 324),
+
+       INTC_IRQ(NFMC, 325), INTC_IRQ(NFMC, 326),
+       INTC_IRQ(NFMC, 327), INTC_IRQ(NFMC, 328),
+
+       INTC_IRQ(SDHI0, 332), INTC_IRQ(SDHI0, 333),
+       INTC_IRQ(SDHI0, 334),
+       INTC_IRQ(SDHI1, 335), INTC_IRQ(SDHI1, 336),
+       INTC_IRQ(SDHI1, 337),
+
+       INTC_IRQ(RTC, 338), INTC_IRQ(RTC, 339),
+       INTC_IRQ(RTC, 340),
+
+       INTC_IRQ(SRCC0, 341), INTC_IRQ(SRCC0, 342),
+       INTC_IRQ(SRCC0, 343), INTC_IRQ(SRCC0, 344),
+       INTC_IRQ(SRCC0, 345),
+       INTC_IRQ(SRCC1, 346), INTC_IRQ(SRCC1, 347),
+       INTC_IRQ(SRCC1, 348), INTC_IRQ(SRCC1, 349),
+       INTC_IRQ(SRCC1, 350),
+       INTC_IRQ(SRCC2, 351), INTC_IRQ(SRCC2, 352),
+       INTC_IRQ(SRCC2, 353), INTC_IRQ(SRCC2, 354),
+       INTC_IRQ(SRCC2, 355),
+};
+
+static struct intc_group groups[] __initdata = {
+       INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
+                  PINT4, PINT5, PINT6, PINT7),
+       INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
+       INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
+       INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+       INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
+       INTC_GROUP(SCIF4, SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI),
+       INTC_GROUP(SCIF5, SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI),
+       INTC_GROUP(SCIF6, SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI),
+       INTC_GROUP(SCIF7, SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+       { 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+       { 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, 0, 0 } },
+       { 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0,  DMAC1, DMAC2,  DMAC3 } },
+       { 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4,  DMAC5, DMAC6,  DMAC7 } },
+       { 0xfffe0c04, 0, 16, 4, /* IPR08 */ { DMAC8,  DMAC9,
+                                             DMAC10, DMAC11 } },
+       { 0xfffe0c06, 0, 16, 4, /* IPR09 */ { DMAC12, DMAC13,
+                                             DMAC14, DMAC15 } },
+       { 0xfffe0c08, 0, 16, 4, /* IPR10 */ { USB, VDC4, VDC4, VDC4 } },
+       { 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { 0, 0, 0, 0 } },
+       { 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { CMT0, CMT1, BSC, WDT } },
+       { 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { MTU0_ABCD, MTU0_VEF,
+                                             MTU1_AB, MTU1_VU } },
+       { 0xfffe0c10, 0, 16, 4, /* IPR14 */ { MTU2_AB, MTU2_VU,
+                                             MTU3_ABCD, MTU3_TCI3V } },
+       { 0xfffe0c12, 0, 16, 4, /* IPR15 */ { MTU4_ABCD, MTU4_TCI4V,
+                                             PWMT1, PWMT2 } },
+       { 0xfffe0c14, 0, 16, 4, /* IPR16 */ { 0, 0, 0, 0 } },
+       { 0xfffe0c16, 0, 16, 4, /* IPR17 */ { ADC_ADI, SSIF0, SSII1, SSII2 } },
+       { 0xfffe0c18, 0, 16, 4, /* IPR18 */ { SSII3, SSII4, SSII5,  RSPDIF} },
+       { 0xfffe0c1a, 0, 16, 4, /* IPR19 */ { IIC30, IIC31, IIC32, IIC33 } },
+       { 0xfffe0c1c, 0, 16, 4, /* IPR20 */ { SCIF0, SCIF1, SCIF2, SCIF3 } },
+       { 0xfffe0c1e, 0, 16, 4, /* IPR21 */ { SCIF4, SCIF5, SCIF6, SCIF7 } },
+       { 0xfffe0c20, 0, 16, 4, /* IPR22 */ { 0, RCAN0, RCAN1, RCAN2 } },
+       { 0xfffe0c22, 0, 16, 4, /* IPR23 */ { RSPIC0, RSPIC1, 0, 0 } },
+       { 0xfffe0c24, 0, 16, 4, /* IPR24 */ { IEBC, CD_ROMD, NFMC, 0 } },
+       { 0xfffe0c26, 0, 16, 4, /* IPR25 */ { SDHI0, SDHI1, RTC, 0 } },
+       { 0xfffe0c28, 0, 16, 4, /* IPR26 */ { SRCC0, SRCC1, SRCC2, 0 } },
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { 0xfffe0808, 0, 16, /* PINTER */
+         { 0, 0, 0, 0, 0, 0, 0, 0,
+           PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7269", vectors, groups,
+                        mask_registers, prio_registers, NULL);
+
+static struct plat_sci_port scif0_platform_data = {
+       .mapbase        = 0xe8007000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 259, 260, 261, 258 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif0_device = {
+       .name           = "sh-sci",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &scif0_platform_data,
+       },
+};
+
+static struct plat_sci_port scif1_platform_data = {
+       .mapbase        = 0xe8007800,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 263, 264, 265, 262 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif1_device = {
+       .name           = "sh-sci",
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &scif1_platform_data,
+       },
+};
+
+static struct plat_sci_port scif2_platform_data = {
+       .mapbase        = 0xe8008000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 267, 268, 269, 266 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif2_device = {
+       .name           = "sh-sci",
+       .id             = 2,
+       .dev            = {
+               .platform_data  = &scif2_platform_data,
+       },
+};
+
+static struct plat_sci_port scif3_platform_data = {
+       .mapbase        = 0xe8008800,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 271, 272, 273, 270 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif3_device = {
+       .name           = "sh-sci",
+       .id             = 3,
+       .dev            = {
+               .platform_data  = &scif3_platform_data,
+       },
+};
+
+static struct plat_sci_port scif4_platform_data = {
+       .mapbase        = 0xe8009000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 275, 276, 277, 274 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif4_device = {
+       .name           = "sh-sci",
+       .id             = 4,
+       .dev            = {
+               .platform_data  = &scif4_platform_data,
+       },
+};
+
+static struct plat_sci_port scif5_platform_data = {
+       .mapbase        = 0xe8009800,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 279, 280, 281, 278 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif5_device = {
+       .name           = "sh-sci",
+       .id             = 5,
+       .dev            = {
+               .platform_data  = &scif5_platform_data,
+       },
+};
+
+static struct plat_sci_port scif6_platform_data = {
+       .mapbase        = 0xe800a000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 283, 284, 285, 282 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif6_device = {
+       .name           = "sh-sci",
+       .id             = 6,
+       .dev            = {
+               .platform_data  = &scif6_platform_data,
+       },
+};
+
+static struct plat_sci_port scif7_platform_data = {
+       .mapbase        = 0xe800a800,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+                         SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           =  { 287, 288, 289, 286 },
+       .regtype        = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif7_device = {
+       .name           = "sh-sci",
+       .id             = 7,
+       .dev            = {
+               .platform_data  = &scif7_platform_data,
+       },
+};
+
+static struct sh_timer_config cmt0_platform_data = {
+       .channel_offset = 0x02,
+       .timer_bit = 0,
+       .clockevent_rating = 125,
+       .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt0_resources[] = {
+       [0] = {
+               .start  = 0xfffec002,
+               .end    = 0xfffec007,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 188,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt0_device = {
+       .name           = "sh_cmt",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &cmt0_platform_data,
+       },
+       .resource       = cmt0_resources,
+       .num_resources  = ARRAY_SIZE(cmt0_resources),
+};
+
+static struct sh_timer_config cmt1_platform_data = {
+       .channel_offset = 0x08,
+       .timer_bit = 1,
+       .clockevent_rating = 125,
+       .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt1_resources[] = {
+       [0] = {
+               .start  = 0xfffec008,
+               .end    = 0xfffec00d,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 189,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt1_device = {
+       .name           = "sh_cmt",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &cmt1_platform_data,
+       },
+       .resource       = cmt1_resources,
+       .num_resources  = ARRAY_SIZE(cmt1_resources),
+};
+
+static struct sh_timer_config mtu2_0_platform_data = {
+       .channel_offset = -0x80,
+       .timer_bit = 0,
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_0_resources[] = {
+       [0] = {
+               .start  = 0xfffe4300,
+               .end    = 0xfffe4326,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 192,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_0_device = {
+       .name           = "sh_mtu2",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &mtu2_0_platform_data,
+       },
+       .resource       = mtu2_0_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_0_resources),
+};
+
+static struct sh_timer_config mtu2_1_platform_data = {
+       .channel_offset = -0x100,
+       .timer_bit = 1,
+       .clockevent_rating = 200,
+};
+
+static struct resource mtu2_1_resources[] = {
+       [0] = {
+               .start  = 0xfffe4380,
+               .end    = 0xfffe4390,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 203,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mtu2_1_device = {
+       .name           = "sh_mtu2",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &mtu2_1_platform_data,
+       },
+       .resource       = mtu2_1_resources,
+       .num_resources  = ARRAY_SIZE(mtu2_1_resources),
+};
+
+static struct resource rtc_resources[] = {
+       [0] = {
+               .start  = 0xfffe6000,
+               .end    = 0xfffe6000 + 0x30 - 1,
+               .flags  = IORESOURCE_IO,
+       },
+       [1] = {
+               /* Shared Period/Carry/Alarm IRQ */
+               .start  = 338,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device rtc_device = {
+       .name           = "sh-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(rtc_resources),
+       .resource       = rtc_resources,
+};
+
+/* USB Host */
+static struct r8a66597_platdata r8a66597_data = {
+       .on_chip = 1,
+       .endian = 1,
+};
+
+static struct resource r8a66597_usb_host_resources[] = {
+       [0] = {
+               .start  = 0xe8010000,
+               .end    = 0xe80100e4,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 170,
+               .end    = 170,
+               .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
+       },
+};
+
+static struct platform_device r8a66597_usb_host_device = {
+       .name           = "r8a66597_hcd",
+       .id             = 0,
+       .dev = {
+               .dma_mask               = NULL,         /*  not use dma */
+               .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = &r8a66597_data,
+       },
+       .num_resources  = ARRAY_SIZE(r8a66597_usb_host_resources),
+       .resource       = r8a66597_usb_host_resources,
+};
+
+static struct platform_device *sh7269_devices[] __initdata = {
+       &scif0_device,
+       &scif1_device,
+       &scif2_device,
+       &scif3_device,
+       &scif4_device,
+       &scif5_device,
+       &scif6_device,
+       &scif7_device,
+       &cmt0_device,
+       &cmt1_device,
+       &mtu2_0_device,
+       &mtu2_1_device,
+       &rtc_device,
+       &r8a66597_usb_host_device,
+};
+
+static int __init sh7269_devices_setup(void)
+{
+       return platform_add_devices(sh7269_devices,
+                                   ARRAY_SIZE(sh7269_devices));
+}
+arch_initcall(sh7269_devices_setup);
+
+void __init plat_irq_setup(void)
+{
+       register_intc_controller(&intc_desc);
+}
+
+static struct platform_device *sh7269_early_devices[] __initdata = {
+       &scif0_device,
+       &scif1_device,
+       &scif2_device,
+       &scif3_device,
+       &scif4_device,
+       &scif5_device,
+       &scif6_device,
+       &scif7_device,
+       &cmt0_device,
+       &cmt1_device,
+       &mtu2_0_device,
+       &mtu2_1_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7269_early_devices,
+                                  ARRAY_SIZE(sh7269_early_devices));
+}
index f6a389c996cbbb16ce9b8cf5daaf45b34db16188..262db6ec067ba0716b3511834ffd7f41eab2fde6 100644 (file)
@@ -2,7 +2,7 @@
  * arch/sh/kernel/cpu/sh3/entry.S
  *
  *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
- *  Copyright (C) 2003 - 2006  Paul Mundt
+ *  Copyright (C) 2003 - 2012  Paul Mundt
  *
  * 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
@@ -17,6 +17,7 @@
 #include <cpu/mmu_context.h>
 #include <asm/page.h>
 #include <asm/cache.h>
+#include <asm/thread_info.h>
 
 ! NOTE:
 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
@@ -114,22 +115,22 @@ ENTRY(tlb_miss_load)
        .align  2
 ENTRY(tlb_miss_store)
        bra     call_handle_tlbmiss
-        mov    #1, r5
+        mov    #FAULT_CODE_WRITE, r5
 
        .align  2
 ENTRY(initial_page_write)
        bra     call_handle_tlbmiss
-        mov    #2, r5
+        mov    #FAULT_CODE_INITIAL, r5
 
        .align  2
 ENTRY(tlb_protection_violation_load)
        bra     call_do_page_fault
-        mov    #0, r5
+        mov    #FAULT_CODE_PROT, r5
 
        .align  2
 ENTRY(tlb_protection_violation_store)
        bra     call_do_page_fault
-        mov    #1, r5
+        mov    #(FAULT_CODE_PROT | FAULT_CODE_WRITE), r5
 
 call_handle_tlbmiss:
        mov.l   1f, r0
index 2309618c015d06ec8b86d75882a21ce036db2cce..03e4c96f2b11d64ee86af9ab47e6343c22a384d4 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <asm/rtc.h>
 #include <cpu/serial.h>
 
@@ -75,7 +76,7 @@ static struct plat_sci_port scif0_platform_data = {
                          SCSCR_RE  | SCSCR_CKE1 | SCSCR_CKE0,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIF,
-       .irqs           = { 56, 56, 56 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x900)),
        .ops            = &sh770x_sci_port_ops,
        .regtype        = SCIx_SH7705_SCIF_REGTYPE,
 };
@@ -94,7 +95,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_TIE | SCSCR_RIE | SCSCR_TE | SCSCR_RE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIF,
-       .irqs           = { 52, 52, 52 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x880)),
        .ops            = &sh770x_sci_port_ops,
        .regtype        = SCIx_SH7705_SCIF_REGTYPE,
 };
@@ -114,7 +115,7 @@ static struct resource rtc_resources[] = {
                .flags  = IORESOURCE_IO,
        },
        [1] =   {
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -146,7 +147,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -174,7 +175,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -201,7 +202,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 3f3d5fe5892d08c32671c382f9371d71f056e5e9..ba26cd9ce69b7b581d0fea85965a16f0a6dedb4b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <cpu/serial.h>
 
 enum {
@@ -95,7 +96,7 @@ static struct resource rtc_resources[] = {
                .flags  = IORESOURCE_IO,
        },
        [1] =   {
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -114,7 +115,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_TE | SCSCR_RE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCI,
-       .irqs           = { 23, 23, 23, 0 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x4e0)),
        .ops            = &sh770x_sci_port_ops,
        .regshift       = 1,
 };
@@ -135,7 +136,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_TE | SCSCR_RE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 56, 56, 56, 56 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x900)),
        .ops            = &sh770x_sci_port_ops,
        .regtype        = SCIx_SH3_SCIF_REGTYPE,
 };
@@ -157,7 +158,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_TE | SCSCR_RE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_IRDA,
-       .irqs           = { 52, 52, 52, 52 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x880)),
        .ops            = &sh770x_sci_port_ops,
        .regshift       = 1,
 };
@@ -184,7 +185,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -212,7 +213,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -239,7 +240,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 78f6b01d42c3c8cf0def51c3d341f05c4fc9cb49..93c9c5e24a7abbe7e7c5b832b0497c54be6adb03 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <asm/rtc.h>
 
 enum {
@@ -77,7 +78,7 @@ static struct resource rtc_resources[] = {
                .flags  = IORESOURCE_IO,
        },
        [1] =   {
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -103,7 +104,7 @@ static struct plat_sci_port scif0_platform_data = {
                          SCSCR_CKE1 | SCSCR_CKE0,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 52, 52, 52, 52 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x880)),
 };
 
 static struct platform_device scif0_device = {
@@ -121,7 +122,7 @@ static struct plat_sci_port scif1_platform_data = {
                          SCSCR_CKE1 | SCSCR_CKE0,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 56, 56, 56, 56 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x900)),
 };
 
 static struct platform_device scif1_device = {
@@ -145,7 +146,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -173,7 +174,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -200,7 +201,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 94920345c14db53d144e9dc2513eaa7c67fd690b..0c2f1b2c2e1973440465e679ec1dd674e2522836 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <asm/rtc.h>
 #include <cpu/serial.h>
 
@@ -30,7 +31,7 @@ static struct resource rtc_resources[] = {
        },
        [1] = {
                /* Shared Period/Carry/Alarm IRQ */
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -55,7 +56,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIF,
-       .irqs           = { 80, 80, 80, 80 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc00)),
        .ops            = &sh7720_sci_port_ops,
        .regtype        = SCIx_SH7705_SCIF_REGTYPE,
 };
@@ -74,7 +75,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIF,
-       .irqs           = { 81, 81, 81, 81 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc20)),
        .ops            = &sh7720_sci_port_ops,
        .regtype        = SCIx_SH7705_SCIF_REGTYPE,
 };
@@ -94,13 +95,14 @@ static struct resource usb_ohci_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 67,
-               .end    = 67,
+               .start  = evt2irq(0xa60),
+               .end    = evt2irq(0xa60),
                .flags  = IORESOURCE_IRQ,
        },
 };
 
 static u64 usb_ohci_dma_mask = 0xffffffffUL;
+
 static struct platform_device usb_ohci_device = {
        .name           = "sh_ohci",
        .id             = -1,
@@ -121,8 +123,8 @@ static struct resource usbf_resources[] = {
        },
        [1] = {
                .name   = "sh_udc",
-               .start  = 65,
-               .end    = 65,
+               .start  = evt2irq(0xa20),
+               .end    = evt2irq(0xa20),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -152,7 +154,7 @@ static struct resource cmt0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 104,
+               .start  = evt2irq(0xf00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -179,7 +181,7 @@ static struct resource cmt1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 104,
+               .start  = evt2irq(0xf00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -206,7 +208,7 @@ static struct resource cmt2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 104,
+               .start  = evt2irq(0xf00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -233,7 +235,7 @@ static struct resource cmt3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 104,
+               .start  = evt2irq(0xf00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -260,7 +262,7 @@ static struct resource cmt4_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 104,
+               .start  = evt2irq(0xf00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -288,7 +290,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -316,7 +318,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -343,7 +345,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 971cf0fce4f5ce7988f0f0aee831f6a6c38ee27b..0fbbd50bc8ad3fe81e6b963e8041da0e605f3ce1 100644 (file)
@@ -158,6 +158,9 @@ void __cpuinit cpu_probe(void)
                case 0x40: /* yon-ten-go */
                        boot_cpu_data.type = CPU_SH7372;
                        break;
+               case 0xE0: /* 0x4E0 */
+                       boot_cpu_data.type = CPU_SH7734; /* SH7733/SH7734 */
+                       break;
 
                }
                break;
index 5b2833159b7dd1842856f08302f2cd4a2c09f8a6..2a5320aa73bbbf8e3df126559bb0cf8514cd3a0b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/io.h>
 
 static struct plat_sci_port scif0_platform_data = {
@@ -21,7 +22,10 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 40, 41, 43, 42 },
+       .irqs           = { evt2irq(0x700),
+                           evt2irq(0x720),
+                           evt2irq(0x760),
+                           evt2irq(0x740) },
 };
 
 static struct platform_device scif0_device = {
@@ -45,7 +49,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -73,7 +77,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -100,7 +104,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 98cc0c794c765abc4d7397086058c69a20c9e3d2..04a45512596f310fb50367c04424610ec8e83459 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/serial.h>
 #include <linux/io.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/serial_sci.h>
 #include <generated/machtypes.h>
 
@@ -24,7 +25,7 @@ static struct resource rtc_resources[] = {
        },
        [1] = {
                /* Shared Period/Carry/Alarm IRQ */
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -43,7 +44,7 @@ static struct plat_sci_port sci_platform_data = {
        .scscr          = SCSCR_TE | SCSCR_RE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCI,
-       .irqs           = { 23, 23, 23, 0 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x4e0)),
        .regshift       = 2,
 };
 
@@ -61,7 +62,7 @@ static struct plat_sci_port scif_platform_data = {
        .scscr          = SCSCR_TE | SCSCR_RE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 40, 40, 40, 40 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x700)),
 };
 
 static struct platform_device scif_device = {
@@ -85,7 +86,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -113,7 +114,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -140,7 +141,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -172,7 +173,7 @@ static struct resource tmu3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 72,
+               .start  = evt2irq(0xb00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -199,7 +200,7 @@ static struct resource tmu4_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 76,
+               .start  = evt2irq(0xb80),
                .flags  = IORESOURCE_IRQ,
        },
 };
index c0b4c774700ec4fd07bf4def628f6dd80ceafd4b..98e075ada44eee248b8f44d52ccddab7bbd53432 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/serial_sci.h>
 #include <linux/io.h>
 
@@ -132,7 +133,10 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 52, 53, 55, 54 },
+       .irqs           = { evt2irq(0x880),
+                           evt2irq(0x8a0),
+                           evt2irq(0x8e0),
+                           evt2irq(0x8c0) },
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -150,7 +154,10 @@ static struct plat_sci_port scif1_platform_data = {
        .type           = PORT_SCIF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
-       .irqs           = { 72, 73, 75, 74 },
+       .irqs           = { evt2irq(0xb00),
+                           evt2irq(0xb20),
+                           evt2irq(0xb60),
+                           evt2irq(0xb40) },
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -168,7 +175,10 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 76, 77, 79, 78 },
+       .irqs           = { evt2irq(0xb80),
+                           evt2irq(0xba0),
+                           evt2irq(0xbe0),
+                           evt2irq(0xbc0) },
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -186,7 +196,9 @@ static struct plat_sci_port scif3_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCI,
-       .irqs           = { 80, 81, 82, 0 },
+       .irqs           = { evt2irq(0xc00),
+                           evt2irq(0xc20),
+                           evt2irq(0xc40), },
        .regshift       = 2,
 };
 
@@ -211,7 +223,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -239,7 +251,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -266,7 +278,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 0b22d108f4c5fccc16620b65ebf24202650f3572..8fc6ec2be2fa6076ed8644fce2cb126342239449 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7343)      += setup-sh7343.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7722)       += setup-sh7722.o serial-sh7722.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7723)       += setup-sh7723.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7724)       += setup-sh7724.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7734)       += setup-sh7734.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7366)       += setup-sh7366.o
 obj-$(CONFIG_CPU_SUBTYPE_SHX3)         += setup-shx3.o intc-shx3.o
 
@@ -30,6 +31,7 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7343)    := clock-sh7343.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7722)     := clock-sh7722.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7723)     := clock-sh7723.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7724)     := clock-sh7724.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7734)     := clock-sh7734.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7366)     := clock-sh7366.o
 clock-$(CONFIG_CPU_SUBTYPE_SHX3)       := clock-shx3.o
 
@@ -37,6 +39,7 @@ clock-$(CONFIG_CPU_SUBTYPE_SHX3)      := clock-shx3.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7722)    := pinmux-sh7722.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7723)    := pinmux-sh7723.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7724)    := pinmux-sh7724.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SH7734)    := pinmux-sh7734.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7757)    := pinmux-sh7757.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7785)    := pinmux-sh7785.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7786)    := pinmux-sh7786.o
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7734.c b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
new file mode 100644 (file)
index 0000000..1697642
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7734.c
+ *
+ * Clock framework for SH7734
+ *
+ * Copyright (C) 2011, 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ * Copyright (C) 2011, 2012 Renesas Solutions Corp.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+
+static struct clk extal_clk = {
+       .rate       = 33333333,
+};
+
+#define MODEMR          (0xFFCC0020)
+#define MODEMR_MASK     (0x6)
+#define MODEMR_533MHZ   (0x2)
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+       int mode = 12;
+       u32 r = __raw_readl(MODEMR);
+
+       if ((r & MODEMR_MASK) & MODEMR_533MHZ)
+               mode = 16;
+
+       return clk->parent->rate * mode;
+}
+
+static struct sh_clk_ops pll_clk_ops = {
+       .recalc         = pll_recalc,
+};
+
+static struct clk pll_clk = {
+       .ops        = &pll_clk_ops,
+       .parent     = &extal_clk,
+       .flags      = CLK_ENABLE_ON_INIT,
+};
+
+static struct clk *main_clks[] = {
+       &extal_clk,
+       &pll_clk,
+};
+
+static int multipliers[] = { 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+static int divisors[] = { 1, 3, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+       .divisors = divisors,
+       .nr_divisors = ARRAY_SIZE(divisors),
+       .multipliers = multipliers,
+       .nr_multipliers = ARRAY_SIZE(multipliers),
+};
+
+static struct clk_div4_table div4_table = {
+       .div_mult_table = &div4_div_mult_table,
+};
+
+enum { DIV4_I, DIV4_S, DIV4_B, DIV4_M, DIV4_S1, DIV4_P, DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+       SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
+
+struct clk div4_clks[DIV4_NR] = {
+       [DIV4_I] = DIV4(FRQMR1, 28, 0x0003, CLK_ENABLE_ON_INIT),
+       [DIV4_S] = DIV4(FRQMR1, 20, 0x000C, CLK_ENABLE_ON_INIT),
+       [DIV4_B] = DIV4(FRQMR1, 16, 0x0140, CLK_ENABLE_ON_INIT),
+       [DIV4_M] = DIV4(FRQMR1, 12, 0x0004, CLK_ENABLE_ON_INIT),
+       [DIV4_S1] = DIV4(FRQMR1, 4, 0x0030, CLK_ENABLE_ON_INIT),
+       [DIV4_P] = DIV4(FRQMR1, 0, 0x0140, CLK_ENABLE_ON_INIT),
+};
+
+#define MSTPCR0        0xFFC80030
+#define MSTPCR1        0xFFC80034
+#define MSTPCR3        0xFFC8003C
+
+enum {
+       MSTP030, MSTP029, /* IIC */
+       MSTP026, MSTP025, MSTP024, /* SCIF */
+       MSTP023,
+       MSTP022, MSTP021,
+       MSTP019, /* HSCIF */
+       MSTP016, MSTP015, MSTP014, /* TMU / TIMER */
+       MSTP012, MSTP011, MSTP010, MSTP009, MSTP008, /* SSI */
+       MSTP007, /* HSPI */
+       MSTP115, /* ADMAC */
+       MSTP114, /* GETHER */
+       MSTP111, /* DMAC */
+       MSTP109, /* VIDEOIN1 */
+       MSTP108, /* VIDEOIN0 */
+       MSTP107, /* RGPVBG */
+       MSTP106, /* 2DG */
+       MSTP103, /* VIEW */
+       MSTP100, /* USB */
+       MSTP331, /* MMC */
+       MSTP330, /* MIMLB */
+       MSTP323, /* SDHI0 */
+       MSTP322, /* SDHI1 */
+       MSTP321, /* SDHI2 */
+       MSTP320, /* RQSPI */
+       MSTP319, /* SRC0 */
+       MSTP318, /* SRC1 */
+       MSTP317, /* RSPI */
+       MSTP316, /* RCAN0 */
+       MSTP315, /* RCAN1 */
+       MSTP314, /* FLTCL */
+       MSTP313, /* ADC */
+       MSTP312, /* MTU */
+       MSTP304, /* IE-BUS */
+       MSTP303, /* RTC */
+       MSTP302, /* HIF */
+       MSTP301, /* STIF0 */
+       MSTP300, /* STIF1 */
+       MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+       /* MSTPCR0 */
+       [MSTP030] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 30, 0),
+       [MSTP029] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 29, 0),
+       [MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0),
+       [MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0),
+       [MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0),
+       [MSTP023] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 23, 0),
+       [MSTP022] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 22, 0),
+       [MSTP021] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 21, 0),
+       [MSTP019] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
+       [MSTP016] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 16, 0),
+       [MSTP015] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
+       [MSTP014] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 14, 0),
+       [MSTP012] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 12, 0),
+       [MSTP011] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 11, 0),
+       [MSTP010] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
+       [MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
+       [MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
+       [MSTP007] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
+
+       /* MSTPCR1 */
+       [MSTP115] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 15, 0),
+       [MSTP114] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 14, 0),
+       [MSTP111] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 11, 0),
+       [MSTP109] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
+       [MSTP108] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 8, 0),
+       [MSTP107] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 7, 0),
+       [MSTP106] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 6, 0),
+       [MSTP103] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 3, 0),
+       [MSTP100] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 0, 0),
+
+       /* MSTPCR3 */
+       [MSTP331] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 31, 0),
+       [MSTP330] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 30, 0),
+       [MSTP323] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 23, 0),
+       [MSTP322] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 22, 0),
+       [MSTP321] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 21, 0),
+       [MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 20, 0),
+       [MSTP319] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 19, 0),
+       [MSTP318] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 18, 0),
+       [MSTP317] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 17, 0),
+       [MSTP316] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 16, 0),
+       [MSTP315] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 15, 0),
+       [MSTP314] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 14, 0),
+       [MSTP313] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 13, 0),
+       [MSTP312] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 12, 0),
+       [MSTP304] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3,  4, 0),
+       [MSTP303] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3,  3, 0),
+       [MSTP302] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3,  2, 0),
+       [MSTP301] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3,  1, 0),
+       [MSTP300] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3,  0, 0),
+};
+
+static struct clk_lookup lookups[] = {
+       /* main clocks */
+       CLKDEV_CON_ID("extal", &extal_clk),
+       CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+       /* clocks */
+       CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+       CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_S]),
+       CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_M]),
+       CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
+       CLKDEV_CON_ID("shyway_clk1", &div4_clks[DIV4_S1]),
+       CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+
+       /* MSTP32 clocks */
+       CLKDEV_DEV_ID("i2c-sh7734.0", &mstp_clks[MSTP030]),
+       CLKDEV_DEV_ID("i2c-sh7734.1", &mstp_clks[MSTP029]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP026]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP024]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP023]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP022]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP021]),
+       CLKDEV_CON_ID("hscif", &mstp_clks[MSTP019]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[MSTP016]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[MSTP016]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[MSTP016]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[MSTP015]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[MSTP015]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[MSTP015]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.6", &mstp_clks[MSTP014]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.7", &mstp_clks[MSTP014]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.8", &mstp_clks[MSTP014]),
+       CLKDEV_CON_ID("ssi0", &mstp_clks[MSTP012]),
+       CLKDEV_CON_ID("ssi1", &mstp_clks[MSTP011]),
+       CLKDEV_CON_ID("ssi2", &mstp_clks[MSTP010]),
+       CLKDEV_CON_ID("ssi3", &mstp_clks[MSTP009]),
+       CLKDEV_CON_ID("sss", &mstp_clks[MSTP008]),
+       CLKDEV_CON_ID("hspi", &mstp_clks[MSTP007]),
+       CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP100]),
+       CLKDEV_CON_ID("videoin0", &mstp_clks[MSTP109]),
+       CLKDEV_CON_ID("videoin1", &mstp_clks[MSTP108]),
+       CLKDEV_CON_ID("rgpvg", &mstp_clks[MSTP107]),
+       CLKDEV_CON_ID("2dg", &mstp_clks[MSTP106]),
+       CLKDEV_CON_ID("view", &mstp_clks[MSTP103]),
+
+       CLKDEV_CON_ID("mmc0", &mstp_clks[MSTP331]),
+       CLKDEV_CON_ID("mimlb0", &mstp_clks[MSTP330]),
+       CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP323]),
+       CLKDEV_CON_ID("sdhi1", &mstp_clks[MSTP322]),
+       CLKDEV_CON_ID("sdhi2", &mstp_clks[MSTP321]),
+       CLKDEV_CON_ID("rqspi0", &mstp_clks[MSTP320]),
+       CLKDEV_CON_ID("src0", &mstp_clks[MSTP319]),
+       CLKDEV_CON_ID("src1", &mstp_clks[MSTP318]),
+       CLKDEV_CON_ID("rsp0", &mstp_clks[MSTP317]),
+       CLKDEV_CON_ID("rcan0", &mstp_clks[MSTP316]),
+       CLKDEV_CON_ID("rcan1", &mstp_clks[MSTP315]),
+       CLKDEV_CON_ID("fltcl0", &mstp_clks[MSTP314]),
+       CLKDEV_CON_ID("adc0", &mstp_clks[MSTP313]),
+       CLKDEV_CON_ID("mtu0", &mstp_clks[MSTP312]),
+       CLKDEV_CON_ID("iebus0", &mstp_clks[MSTP304]),
+       CLKDEV_DEV_ID("sh-eth.0", &mstp_clks[MSTP114]),
+       CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP303]),
+       CLKDEV_CON_ID("hif0", &mstp_clks[MSTP302]),
+       CLKDEV_CON_ID("stif0", &mstp_clks[MSTP301]),
+       CLKDEV_CON_ID("stif1", &mstp_clks[MSTP300]),
+};
+
+int __init arch_clk_init(void)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < ARRAY_SIZE(main_clks); i++)
+               ret |= clk_register(main_clks[i]);
+
+       for (i = 0; i < ARRAY_SIZE(lookups); i++)
+               clkdev_add(&lookups[i]);
+
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+                       &div4_table);
+
+       if (!ret)
+               ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+
+       return ret;
+}
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c
new file mode 100644 (file)
index 0000000..eed3b9d
--- /dev/null
@@ -0,0 +1,2497 @@
+/*
+ * SH7734 processor support - PFC hardware block
+ *
+ * Copyright (C) 2012  Renesas Solutions Corp.
+ * Copyright (C) 2012  Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/ioport.h>
+#include <cpu/sh7734.h>
+
+#define CPU_32_PORT(fn, pfx, sfx)                              \
+       PORT_10(fn, pfx, sfx), PORT_10(fn, pfx##1, sfx),        \
+       PORT_10(fn, pfx##2, sfx), PORT_1(fn, pfx##30, sfx),     \
+       PORT_1(fn, pfx##31, sfx)
+
+#define CPU_32_PORT5(fn, pfx, sfx)                             \
+       PORT_1(fn, pfx##0, sfx), PORT_1(fn, pfx##1, sfx),       \
+       PORT_1(fn, pfx##2, sfx), PORT_1(fn, pfx##3, sfx),       \
+       PORT_1(fn, pfx##4, sfx), PORT_1(fn, pfx##5, sfx),       \
+       PORT_1(fn, pfx##6, sfx), PORT_1(fn, pfx##7, sfx),       \
+       PORT_1(fn, pfx##8, sfx), PORT_1(fn, pfx##9, sfx),       \
+       PORT_1(fn, pfx##10, sfx), PORT_1(fn, pfx##11, sfx)
+
+/* GPSR0 - GPSR5 */
+#define CPU_ALL_PORT(fn, pfx, sfx)                             \
+       CPU_32_PORT(fn, pfx##_0_, sfx),                 \
+       CPU_32_PORT(fn, pfx##_1_, sfx),                         \
+       CPU_32_PORT(fn, pfx##_2_, sfx),                         \
+       CPU_32_PORT(fn, pfx##_3_, sfx),                         \
+       CPU_32_PORT(fn, pfx##_4_, sfx),                         \
+       CPU_32_PORT5(fn, pfx##_5_, sfx)
+
+#define _GP_GPIO(pfx, sfx) PINMUX_GPIO(GPIO_GP##pfx, GP##pfx##_DATA)
+#define _GP_DATA(pfx, sfx) PINMUX_DATA(GP##pfx##_DATA, GP##pfx##_FN,   \
+                                      GP##pfx##_IN, GP##pfx##_OUT)
+
+#define _GP_INOUTSEL(pfx, sfx) GP##pfx##_IN, GP##pfx##_OUT
+#define _GP_INDT(pfx, sfx) GP##pfx##_DATA
+
+#define GP_ALL(str)    CPU_ALL_PORT(_PORT_ALL, GP, str)
+#define PINMUX_GPIO_GP_ALL()   CPU_ALL_PORT(_GP_GPIO, , unused)
+#define PINMUX_DATA_GP_ALL()   CPU_ALL_PORT(_GP_DATA, , unused)
+
+#define PORT_10_REV(fn, pfx, sfx)      \
+       PORT_1(fn, pfx##9, sfx), PORT_1(fn, pfx##8, sfx),       \
+       PORT_1(fn, pfx##7, sfx), PORT_1(fn, pfx##6, sfx),       \
+       PORT_1(fn, pfx##5, sfx), PORT_1(fn, pfx##4, sfx),       \
+       PORT_1(fn, pfx##3, sfx), PORT_1(fn, pfx##2, sfx),       \
+       PORT_1(fn, pfx##1, sfx), PORT_1(fn, pfx##0, sfx)
+
+#define CPU_32_PORT_REV(fn, pfx, sfx)  \
+       PORT_1(fn, pfx##31, sfx), PORT_1(fn, pfx##30, sfx),     \
+       PORT_10_REV(fn, pfx##2, sfx), PORT_10_REV(fn, pfx##1, sfx),     \
+       PORT_10_REV(fn, pfx, sfx)
+
+#define GP_INOUTSEL(bank) CPU_32_PORT_REV(_GP_INOUTSEL, _##bank##_, unused)
+#define GP_INDT(bank) CPU_32_PORT_REV(_GP_INDT, _##bank##_, unused)
+
+#define PINMUX_IPSR_DATA(ipsr, fn) PINMUX_DATA(fn##_MARK, FN_##ipsr, FN_##fn)
+#define PINMUX_IPSR_MODSEL_DATA(ipsr, fn, ms) PINMUX_DATA(fn##_MARK, FN_##ms, \
+                                                         FN_##ipsr, FN_##fn)
+
+enum {
+       PINMUX_RESERVED = 0,
+
+       PINMUX_DATA_BEGIN,
+       GP_ALL(DATA), /* GP_0_0_DATA -> GP_5_11_DATA */
+       PINMUX_DATA_END,
+
+       PINMUX_INPUT_BEGIN,
+       GP_ALL(IN), /* GP_0_0_IN -> GP_5_11_IN */
+       PINMUX_INPUT_END,
+
+       PINMUX_OUTPUT_BEGIN,
+       GP_ALL(OUT), /* GP_0_0_OUT -> GP_5_11_OUT */
+       PINMUX_OUTPUT_END,
+
+       PINMUX_FUNCTION_BEGIN,
+       GP_ALL(FN), /* GP_0_0_FN -> GP_5_11_FN */
+
+       /* GPSR0 */
+       FN_IP1_9_8, FN_IP1_11_10, FN_IP1_13_12, FN_IP1_15_14,
+       FN_IP0_7_6, FN_IP0_9_8, FN_IP0_11_10, FN_IP0_13_12,
+       FN_IP0_15_14, FN_IP0_17_16, FN_IP0_19_18, FN_IP0_21_20,
+       FN_IP0_23_22, FN_IP0_25_24, FN_IP0_27_26, FN_IP0_29_28,
+       FN_IP0_31_30, FN_IP1_1_0, FN_IP1_3_2, FN_IP1_5_4,
+       FN_IP1_7_6, FN_IP11_28, FN_IP0_1_0, FN_IP0_3_2,
+       FN_IP0_5_4, FN_IP1_17_16, FN_IP1_19_18, FN_IP1_22_20,
+       FN_IP1_25_23, FN_IP1_28_26, FN_IP1_31_29, FN_IP2_2_0,
+
+       /* GPSR1 */
+       FN_IP3_20, FN_IP3_29_27, FN_IP11_20_19, FN_IP11_22_21,
+       FN_IP2_16_14, FN_IP2_19_17, FN_IP2_22_20, FN_IP2_24_23,
+       FN_IP2_27_25, FN_IP2_30_28, FN_IP3_1_0, FN_CLKOUT,
+       FN_BS, FN_CS0, FN_IP3_2, FN_EX_CS0,
+       FN_IP3_5_3, FN_IP3_8_6, FN_IP3_11_9, FN_IP3_14_12,
+       FN_IP3_17_15, FN_RD, FN_IP3_19_18, FN_WE0,
+       FN_WE1, FN_IP2_4_3, FN_IP3_23_21, FN_IP3_26_24,
+       FN_IP2_7_5, FN_IP2_10_8, FN_IP2_13_11, FN_IP11_25_23,
+
+       /* GPSR2 */
+       FN_IP11_6_4, FN_IP11_9_7, FN_IP11_11_10, FN_IP4_2_0,
+       FN_IP8_29_28, FN_IP11_27_26, FN_IP8_22_20, FN_IP8_25_23,
+       FN_IP11_12, FN_IP8_27_26, FN_IP4_5_3, FN_IP4_8_6,
+       FN_IP4_11_9, FN_IP4_14_12, FN_IP4_17_15, FN_IP4_19_18,
+       FN_IP4_21_20, FN_IP4_23_22, FN_IP4_25_24, FN_IP4_27_26,
+       FN_IP4_29_28, FN_IP4_31_30, FN_IP5_2_0, FN_IP5_5_3,
+       FN_IP5_8_6, FN_IP5_11_9, FN_IP5_14_12, FN_IP5_17_15,
+       FN_IP5_20_18, FN_IP5_22_21, FN_IP5_24_23, FN_IP5_26_25,
+
+       /* GPSR3 */
+       FN_IP6_2_0, FN_IP6_5_3, FN_IP6_7_6, FN_IP6_9_8,
+       FN_IP6_11_10, FN_IP6_13_12, FN_IP6_15_14, FN_IP6_17_16,
+       FN_IP6_20_18, FN_IP6_23_21, FN_IP7_2_0, FN_IP7_5_3,
+       FN_IP7_8_6, FN_IP7_11_9, FN_IP7_14_12, FN_IP7_17_15,
+       FN_IP7_20_18, FN_IP7_23_21, FN_IP7_26_24, FN_IP7_28_27,
+       FN_IP7_30_29, FN_IP8_1_0, FN_IP8_3_2, FN_IP8_5_4,
+       FN_IP8_7_6, FN_IP8_9_8, FN_IP8_11_10, FN_IP8_13_12,
+       FN_IP8_15_14, FN_IP8_17_16, FN_IP8_19_18, FN_IP9_1_0,
+
+       /* GPSR4 */
+       FN_IP9_19_18, FN_IP9_21_20, FN_IP9_23_22, FN_IP9_25_24,
+       FN_IP9_11_10, FN_IP9_13_12, FN_IP9_15_14, FN_IP9_17_16,
+       FN_IP9_3_2, FN_IP9_5_4, FN_IP9_7_6, FN_IP9_9_8,
+       FN_IP9_27_26, FN_IP9_29_28, FN_IP10_2_0, FN_IP10_5_3,
+       FN_IP10_8_6, FN_IP10_11_9, FN_IP10_14_12, FN_IP10_15,
+       FN_IP10_18_16, FN_IP10_21_19, FN_IP11_0, FN_IP11_1,
+       FN_SCL0, FN_IP11_2, FN_PENC0, FN_IP11_15_13, /* Need check*/
+       FN_USB_OVC0, FN_IP11_18_16,
+       FN_IP10_22, FN_IP10_24_23,
+
+       /* GPSR5 */
+       FN_IP10_25, FN_IP11_3, FN_IRQ2_B, FN_IRQ3_B,
+       FN_IP10_27_26, /* 10 */
+       FN_IP10_29_28, /* 11 */
+
+       /* IPSR0 */
+       FN_A15, FN_ST0_VCO_CLKIN, FN_LCD_DATA15_A, FN_TIOC3D_C,
+       FN_A14, FN_LCD_DATA14_A, FN_TIOC3C_C,
+       FN_A13, FN_LCD_DATA13_A, FN_TIOC3B_C,
+       FN_A12, FN_LCD_DATA12_A, FN_TIOC3A_C,
+       FN_A11, FN_ST0_D7, FN_LCD_DATA11_A, FN_TIOC2B_C,
+       FN_A10, FN_ST0_D6, FN_LCD_DATA10_A, FN_TIOC2A_C,
+       FN_A9, FN_ST0_D5, FN_LCD_DATA9_A, FN_TIOC1B_C,
+       FN_A8, FN_ST0_D4, FN_LCD_DATA8_A, FN_TIOC1A_C,
+       FN_A7, FN_ST0_D3, FN_LCD_DATA7_A, FN_TIOC0D_C,
+       FN_A6, FN_ST0_D2, FN_LCD_DATA6_A, FN_TIOC0C_C,
+       FN_A5, FN_ST0_D1, FN_LCD_DATA5_A, FN_TIOC0B_C,
+       FN_A4, FN_ST0_D0, FN_LCD_DATA4_A, FN_TIOC0A_C,
+       FN_A3, FN_ST0_VLD, FN_LCD_DATA3_A, FN_TCLKD_C,
+       FN_A2, FN_ST0_SYC, FN_LCD_DATA2_A, FN_TCLKC_C,
+       FN_A1, FN_ST0_REQ, FN_LCD_DATA1_A, FN_TCLKB_C,
+       FN_A0, FN_ST0_CLKIN, FN_LCD_DATA0_A, FN_TCLKA_C,
+
+       /* IPSR1 */
+       FN_D3, FN_SD0_DAT3_A, FN_MMC_D3_A, FN_ST1_D6, FN_FD3_A,
+       FN_D2, FN_SD0_DAT2_A, FN_MMC_D2_A, FN_ST1_D5, FN_FD2_A,
+       FN_D1, FN_SD0_DAT1_A, FN_MMC_D1_A, FN_ST1_D4, FN_FD1_A,
+       FN_D0, FN_SD0_DAT0_A, FN_MMC_D0_A, FN_ST1_D3, FN_FD0_A,
+       FN_A25, FN_TX2_D, FN_ST1_D2,
+       FN_A24, FN_RX2_D, FN_ST1_D1,
+       FN_A23, FN_ST1_D0, FN_LCD_M_DISP_A,
+       FN_A22, FN_ST1_VLD, FN_LCD_VEPWC_A,
+       FN_A21, FN_ST1_SYC, FN_LCD_VCPWC_A,
+       FN_A20, FN_ST1_REQ, FN_LCD_FLM_A,
+       FN_A19, FN_ST1_CLKIN, FN_LCD_CLK_A,     FN_TIOC4D_C,
+       FN_A18, FN_ST1_PWM, FN_LCD_CL2_A, FN_TIOC4C_C,
+       FN_A17, FN_ST1_VCO_CLKIN, FN_LCD_CL1_A, FN_TIOC4B_C,
+       FN_A16, FN_ST0_PWM, FN_LCD_DON_A, FN_TIOC4A_C,
+
+       /* IPSR2 */
+       FN_D14, FN_TX2_B, FN_FSE_A, FN_ET0_TX_CLK_B,
+       FN_D13, FN_RX2_B, FN_FRB_A,     FN_ET0_ETXD6_B,
+       FN_D12, FN_FWE_A, FN_ET0_ETXD5_B,
+       FN_D11, FN_RSPI_MISO_A, FN_QMI_QIO1_A, FN_FRE_A,
+               FN_ET0_ETXD3_B,
+       FN_D10, FN_RSPI_MOSI_A, FN_QMO_QIO0_A, FN_FALE_A,
+               FN_ET0_ETXD2_B,
+       FN_D9, FN_SD0_CMD_A, FN_MMC_CMD_A, FN_QIO3_A, FN_FCLE_A,
+               FN_ET0_ETXD1_B,
+       FN_D8, FN_SD0_CLK_A, FN_MMC_CLK_A, FN_QIO2_A, FN_FCE_A,
+               FN_ET0_GTX_CLK_B,
+       FN_D7, FN_RSPI_SSL_A, FN_MMC_D7_A, FN_QSSL_A, FN_FD7_A,
+       FN_D6, FN_RSPI_RSPCK_A, FN_MMC_D6_A, FN_QSPCLK_A, FN_FD6_A,
+       FN_D5, FN_SD0_WP_A, FN_MMC_D5_A, FN_FD5_A,
+       FN_D4, FN_SD0_CD_A, FN_MMC_D4_A, FN_ST1_D7, FN_FD4_A,
+
+       /* IPSR3 */
+       FN_DRACK0, FN_SD1_DAT2_A, FN_ATAG, FN_TCLK1_A, FN_ET0_ETXD7,
+       FN_EX_WAIT2, FN_SD1_DAT1_A, FN_DACK2, FN_CAN1_RX_C,
+               FN_ET0_MAGIC_C, FN_ET0_ETXD6_A,
+       FN_EX_WAIT1, FN_SD1_DAT0_A, FN_DREQ2, FN_CAN1_TX_C,
+               FN_ET0_LINK_C, FN_ET0_ETXD5_A,
+       FN_EX_WAIT0, FN_TCLK1_B,
+       FN_RD_WR, FN_TCLK0, FN_CAN_CLK_B, FN_ET0_ETXD4,
+       FN_EX_CS5, FN_SD1_CMD_A, FN_ATADIR, FN_QSSL_B, FN_ET0_ETXD3_A,
+       FN_EX_CS4, FN_SD1_WP_A, FN_ATAWR, FN_QMI_QIO1_B, FN_ET0_ETXD2_A,
+       FN_EX_CS3, FN_SD1_CD_A, FN_ATARD, FN_QMO_QIO0_B, FN_ET0_ETXD1_A,
+       FN_EX_CS2, FN_TX3_B, FN_ATACS1, FN_QSPCLK_B, FN_ET0_GTX_CLK_A,
+       FN_EX_CS1, FN_RX3_B, FN_ATACS0, FN_QIO2_B, FN_ET0_ETXD0,
+       FN_CS1_A26, FN_QIO3_B,
+       FN_D15, FN_SCK2_B,
+
+       /* IPSR4 */
+       FN_SCK2_A, FN_VI0_G3,
+       FN_RTS1_B, FN_VI0_G2,
+       FN_CTS1_B, FN_VI0_DATA7_VI0_G1,
+       FN_TX1_B, FN_VI0_DATA6_VI0_G0, FN_ET0_PHY_INT_A,
+       FN_RX1_B, FN_VI0_DATA5_VI0_B5, FN_ET0_MAGIC_A,
+       FN_SCK1_B, FN_VI0_DATA4_VI0_B4, FN_ET0_LINK_A,
+       FN_RTS0_B, FN_VI0_DATA3_VI0_B3, FN_ET0_MDIO_A,
+       FN_CTS0_B, FN_VI0_DATA2_VI0_B2, FN_RMII0_MDIO_A, FN_ET0_MDC,
+       FN_HTX0_A, FN_TX1_A, FN_VI0_DATA1_VI0_B1, FN_RMII0_MDC_A, FN_ET0_COL,
+       FN_HRX0_A, FN_RX1_A, FN_VI0_DATA0_VI0_B0, FN_RMII0_CRS_DV_A, FN_ET0_CRS,
+       FN_HSCK0_A, FN_SCK1_A, FN_VI0_VSYNC, FN_RMII0_RX_ER_A, FN_ET0_RX_ER,
+       FN_HRTS0_A, FN_RTS1_A, FN_VI0_HSYNC, FN_RMII0_TXD_EN_A, FN_ET0_RX_DV,
+       FN_HCTS0_A, FN_CTS1_A, FN_VI0_FIELD, FN_RMII0_RXD1_A, FN_ET0_ERXD7,
+
+       /* IPSR5 */
+       FN_SD2_CLK_A, FN_RX2_A, FN_VI0_G4, FN_ET0_RX_CLK_B,
+       FN_SD2_CMD_A, FN_TX2_A, FN_VI0_G5, FN_ET0_ERXD2_B,
+       FN_SD2_DAT0_A, FN_RX3_A, FN_VI0_R0, FN_ET0_ERXD3_B,
+       FN_SD2_DAT1_A, FN_TX3_A, FN_VI0_R1, FN_ET0_MDIO_B,
+       FN_SD2_DAT2_A, FN_RX4_A, FN_VI0_R2, FN_ET0_LINK_B,
+       FN_SD2_DAT3_A, FN_TX4_A, FN_VI0_R3, FN_ET0_MAGIC_B,
+       FN_SD2_CD_A, FN_RX5_A, FN_VI0_R4, FN_ET0_PHY_INT_B,
+       FN_SD2_WP_A, FN_TX5_A, FN_VI0_R5,
+       FN_REF125CK, FN_ADTRG, FN_RX5_C,
+       FN_REF50CK, FN_CTS1_E, FN_HCTS0_D,
+
+       /* IPSR6 */
+       FN_DU0_DR0, FN_SCIF_CLK_B, FN_HRX0_D, FN_IETX_A, FN_TCLKA_A, FN_HIFD00,
+       FN_DU0_DR1, FN_SCK0_B, FN_HTX0_D, FN_IERX_A, FN_TCLKB_A, FN_HIFD01,
+       FN_DU0_DR2, FN_RX0_B, FN_TCLKC_A, FN_HIFD02,
+       FN_DU0_DR3, FN_TX0_B, FN_TCLKD_A, FN_HIFD03,
+       FN_DU0_DR4, FN_CTS0_C, FN_TIOC0A_A, FN_HIFD04,
+       FN_DU0_DR5, FN_RTS0_C, FN_TIOC0B_A, FN_HIFD05,
+       FN_DU0_DR6, FN_SCK1_C, FN_TIOC0C_A, FN_HIFD06,
+       FN_DU0_DR7, FN_RX1_C, FN_TIOC0D_A, FN_HIFD07,
+       FN_DU0_DG0, FN_TX1_C, FN_HSCK0_D, FN_IECLK_A, FN_TIOC1A_A, FN_HIFD08,
+       FN_DU0_DG1, FN_CTS1_C, FN_HRTS0_D, FN_TIOC1B_A, FN_HIFD09,
+
+       /* IPSR7 */
+       FN_DU0_DG2, FN_RTS1_C, FN_RMII0_MDC_B, FN_TIOC2A_A, FN_HIFD10,
+       FN_DU0_DG3, FN_SCK2_C, FN_RMII0_MDIO_B, FN_TIOC2B_A, FN_HIFD11,
+       FN_DU0_DG4, FN_RX2_C, FN_RMII0_CRS_DV_B, FN_TIOC3A_A, FN_HIFD12,
+       FN_DU0_DG5, FN_TX2_C, FN_RMII0_RX_ER_B, FN_TIOC3B_A, FN_HIFD13,
+       FN_DU0_DG6, FN_RX3_C, FN_RMII0_RXD0_B, FN_TIOC3C_A, FN_HIFD14,
+       FN_DU0_DG7, FN_TX3_C, FN_RMII0_RXD1_B, FN_TIOC3D_A, FN_HIFD15,
+       FN_DU0_DB0, FN_RX4_C, FN_RMII0_TXD_EN_B, FN_TIOC4A_A, FN_HIFCS,
+       FN_DU0_DB1, FN_TX4_C, FN_RMII0_TXD0_B, FN_TIOC4B_A, FN_HIFRS,
+       FN_DU0_DB2, FN_RX5_B, FN_RMII0_TXD1_B, FN_TIOC4C_A, FN_HIFWR,
+       FN_DU0_DB3, FN_TX5_B, FN_TIOC4D_A, FN_HIFRD,
+       FN_DU0_DB4, FN_HIFINT,
+
+       /* IPSR8 */
+       FN_DU0_DB5, FN_HIFDREQ,
+       FN_DU0_DB6, FN_HIFRDY,
+       FN_DU0_DB7, FN_SSI_SCK0_B, FN_HIFEBL_B,
+       FN_DU0_DOTCLKIN, FN_HSPI_CS0_C, FN_SSI_WS0_B,
+       FN_DU0_DOTCLKOUT, FN_HSPI_CLK0_C, FN_SSI_SDATA0_B,
+       FN_DU0_EXHSYNC_DU0_HSYNC, FN_HSPI_TX0_C, FN_SSI_SCK1_B,
+       FN_DU0_EXVSYNC_DU0_VSYNC, FN_HSPI_RX0_C, FN_SSI_WS1_B,
+       FN_DU0_EXODDF_DU0_ODDF, FN_CAN0_RX_B, FN_HSCK0_B, FN_SSI_SDATA1_B,
+       FN_DU0_DISP, FN_CAN0_TX_B, FN_HRX0_B, FN_AUDIO_CLKA_B,
+       FN_DU0_CDE, FN_HTX0_B, FN_AUDIO_CLKB_B, FN_LCD_VCPWC_B,
+       FN_IRQ0_A, FN_HSPI_TX_B, FN_RX3_E, FN_ET0_ERXD0,
+       FN_IRQ1_A, FN_HSPI_RX_B, FN_TX3_E, FN_ET0_ERXD1,
+       FN_IRQ2_A, FN_CTS0_A, FN_HCTS0_B, FN_ET0_ERXD2_A,
+       FN_IRQ3_A, FN_RTS0_A, FN_HRTS0_B, FN_ET0_ERXD3_A,
+
+       /* IPSR9 */
+       FN_VI1_CLK_A, FN_FD0_B, FN_LCD_DATA0_B,
+       FN_VI1_0_A, FN_FD1_B, FN_LCD_DATA1_B,
+       FN_VI1_1_A, FN_FD2_B, FN_LCD_DATA2_B,
+       FN_VI1_2_A, FN_FD3_B, FN_LCD_DATA3_B,
+       FN_VI1_3_A, FN_FD4_B, FN_LCD_DATA4_B,
+       FN_VI1_4_A, FN_FD5_B, FN_LCD_DATA5_B,
+       FN_VI1_5_A, FN_FD6_B, FN_LCD_DATA6_B,
+       FN_VI1_6_A, FN_FD7_B, FN_LCD_DATA7_B,
+       FN_VI1_7_A, FN_FCE_B, FN_LCD_DATA8_B,
+       FN_SSI_SCK0_A, FN_TIOC1A_B, FN_LCD_DATA9_B,
+       FN_SSI_WS0_A, FN_TIOC1B_B, FN_LCD_DATA10_B,
+       FN_SSI_SDATA0_A, FN_VI1_0_B, FN_TIOC2A_B, FN_LCD_DATA11_B,
+       FN_SSI_SCK1_A, FN_VI1_1_B, FN_TIOC2B_B, FN_LCD_DATA12_B,
+       FN_SSI_WS1_A, FN_VI1_2_B, FN_LCD_DATA13_B,
+       FN_SSI_SDATA1_A, FN_VI1_3_B, FN_LCD_DATA14_B,
+
+       /* IPSR10 */
+       FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B, FN_LCD_DATA15_B,
+       FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B, FN_LCD_DON_B,
+       FN_SSI_SDATA2, FN_VI1_6_B, FN_HRX0_C, FN_FRE_B, FN_LCD_CL1_B,
+       FN_SSI_SDATA3, FN_VI1_7_B, FN_HTX0_C, FN_FWE_B, FN_LCD_CL2_B,
+       FN_AUDIO_CLKA_A, FN_VI1_CLK_B, FN_SCK1_D, FN_IECLK_B, FN_LCD_FLM_B,
+       FN_AUDIO_CLKB_A, FN_LCD_CLK_B,
+       FN_AUDIO_CLKC, FN_SCK1_E, FN_HCTS0_C, FN_FRB_B, FN_LCD_VEPWC_B,
+       FN_AUDIO_CLKOUT, FN_TX1_E, FN_HRTS0_C, FN_FSE_B, FN_LCD_M_DISP_B,
+       FN_CAN_CLK_A, FN_RX4_D,
+       FN_CAN0_TX_A, FN_TX4_D, FN_MLB_CLK,
+       FN_CAN1_RX_A, FN_IRQ1_B,
+       FN_CAN0_RX_A, FN_IRQ0_B, FN_MLB_SIG,
+       FN_CAN1_TX_A, FN_TX5_C, FN_MLB_DAT,
+
+       /* IPSR11 */
+       FN_SCL1, FN_SCIF_CLK_C,
+       FN_SDA1, FN_RX1_E,
+       FN_SDA0, FN_HIFEBL_A,
+       FN_SDSELF, FN_RTS1_E,
+       FN_SCIF_CLK_A, FN_HSPI_CLK_A, FN_VI0_CLK, FN_RMII0_TXD0_A, FN_ET0_ERXD4,
+       FN_SCK0_A, FN_HSPI_CS_A, FN_VI0_CLKENB, FN_RMII0_TXD1_A, FN_ET0_ERXD5,
+       FN_RX0_A, FN_HSPI_RX_A, FN_RMII0_RXD0_A, FN_ET0_ERXD6,
+       FN_TX0_A, FN_HSPI_TX_A,
+       FN_PENC1, FN_TX3_D, FN_CAN1_TX_B, FN_TX5_D, FN_IETX_B,
+       FN_USB_OVC1, FN_RX3_D, FN_CAN1_RX_B, FN_RX5_D, FN_IERX_B,
+       FN_DREQ0, FN_SD1_CLK_A, FN_ET0_TX_EN,
+       FN_DACK0, FN_SD1_DAT3_A, FN_ET0_TX_ER,
+       FN_DREQ1, FN_HSPI_CLK_B, FN_RX4_B, FN_ET0_PHY_INT_C, FN_ET0_TX_CLK_A,
+       FN_DACK1, FN_HSPI_CS_B, FN_TX4_B, FN_ET0_RX_CLK_A,
+       FN_PRESETOUT, FN_ST_CLKOUT,
+
+       /* MOD_SEL1 */
+       FN_SEL_IEBUS_0, FN_SEL_IEBUS_1,
+       FN_SEL_RQSPI_0, FN_SEL_RQSPI_1,
+       FN_SEL_VIN1_0, FN_SEL_VIN1_1,
+       FN_SEL_HIF_0, FN_SEL_HIF_1,
+       FN_SEL_RSPI_0, FN_SEL_RSPI_1,
+       FN_SEL_LCDC_0, FN_SEL_LCDC_1,
+       FN_SEL_ET0_CTL_0, FN_SEL_ET0_CTL_1, FN_SEL_ET0_CTL_2,
+       FN_SEL_ET0_0, FN_SEL_ET0_1,
+       FN_SEL_RMII_0, FN_SEL_RMII_1,
+       FN_SEL_TMU_0, FN_SEL_TMU_1,
+       FN_SEL_HSPI_0, FN_SEL_HSPI_1, FN_SEL_HSPI_2,
+       FN_SEL_HSCIF_0, FN_SEL_HSCIF_1, FN_SEL_HSCIF_2, FN_SEL_HSCIF_3,
+       FN_SEL_RCAN_CLK_0, FN_SEL_RCAN_CLK_1,
+       FN_SEL_RCAN1_0, FN_SEL_RCAN1_1, FN_SEL_RCAN1_2,
+       FN_SEL_RCAN0_0, FN_SEL_RCAN0_1,
+       FN_SEL_SDHI2_0, FN_SEL_SDHI2_1,
+       FN_SEL_SDHI1_0, FN_SEL_SDHI1_1,
+       FN_SEL_SDHI0_0, FN_SEL_SDHI0_1,
+       FN_SEL_SSI1_0, FN_SEL_SSI1_1,
+       FN_SEL_SSI0_0, FN_SEL_SSI0_1,
+       FN_SEL_AUDIO_CLKB_0, FN_SEL_AUDIO_CLKB_1,
+       FN_SEL_AUDIO_CLKA_0, FN_SEL_AUDIO_CLKA_1,
+       FN_SEL_FLCTL_0, FN_SEL_FLCTL_1,
+       FN_SEL_MMC_0, FN_SEL_MMC_1,
+       FN_SEL_INTC_0, FN_SEL_INTC_1,
+
+       /* MOD_SEL2 */
+       FN_SEL_MTU2_CLK_0, FN_SEL_MTU2_CLK_1,
+       FN_SEL_MTU2_CH4_0, FN_SEL_MTU2_CH4_1,
+       FN_SEL_MTU2_CH3_0, FN_SEL_MTU2_CH3_1,
+       FN_SEL_MTU2_CH2_0, FN_SEL_MTU2_CH2_1, FN_SEL_MTU2_CH2_2,
+       FN_SEL_MTU2_CH1_0, FN_SEL_MTU2_CH1_1, FN_SEL_MTU2_CH1_2,
+       FN_SEL_MTU2_CH0_0, FN_SEL_MTU2_CH0_1,
+       FN_SEL_SCIF5_0, FN_SEL_SCIF5_1,
+       FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
+       FN_SEL_SCIF4_0, FN_SEL_SCIF4_1,
+       FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
+       FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2,
+               FN_SEL_SCIF3_3, FN_SEL_SCIF3_4,
+       FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2,
+               FN_SEL_SCIF2_3,
+       FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2,
+               FN_SEL_SCIF1_3, FN_SEL_SCIF1_4,
+       FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2,
+       FN_SEL_SCIF_CLK_0, FN_SEL_SCIF_CLK_1, FN_SEL_SCIF_CLK_2,
+
+       PINMUX_FUNCTION_END,
+
+       PINMUX_MARK_BEGIN,
+
+       CLKOUT_MARK, BS_MARK, CS0_MARK, EX_CS0_MARK, RD_MARK,
+       WE0_MARK, WE1_MARK,
+
+       SCL0_MARK, PENC0_MARK, USB_OVC0_MARK,
+
+       IRQ2_B_MARK, IRQ3_B_MARK,
+
+       /* IPSR0 */
+       A15_MARK, ST0_VCO_CLKIN_MARK, LCD_DATA15_A_MARK, TIOC3D_C_MARK,
+       A14_MARK, LCD_DATA14_A_MARK, TIOC3C_C_MARK,
+       A13_MARK, LCD_DATA13_A_MARK, TIOC3B_C_MARK,
+       A12_MARK, LCD_DATA12_A_MARK, TIOC3A_C_MARK,
+       A11_MARK, ST0_D7_MARK, LCD_DATA11_A_MARK, TIOC2B_C_MARK,
+       A10_MARK, ST0_D6_MARK, LCD_DATA10_A_MARK, TIOC2A_C_MARK,
+       A9_MARK, ST0_D5_MARK, LCD_DATA9_A_MARK, TIOC1B_C_MARK,
+       A8_MARK, ST0_D4_MARK, LCD_DATA8_A_MARK, TIOC1A_C_MARK,
+       A7_MARK, ST0_D3_MARK, LCD_DATA7_A_MARK, TIOC0D_C_MARK,
+       A6_MARK, ST0_D2_MARK, LCD_DATA6_A_MARK, TIOC0C_C_MARK,
+       A5_MARK, ST0_D1_MARK, LCD_DATA5_A_MARK, TIOC0B_C_MARK,
+       A4_MARK, ST0_D0_MARK, LCD_DATA4_A_MARK, TIOC0A_C_MARK,
+       A3_MARK, ST0_VLD_MARK, LCD_DATA3_A_MARK, TCLKD_C_MARK,
+       A2_MARK, ST0_SYC_MARK, LCD_DATA2_A_MARK, TCLKC_C_MARK,
+       A1_MARK, ST0_REQ_MARK, LCD_DATA1_A_MARK, TCLKB_C_MARK,
+       A0_MARK, ST0_CLKIN_MARK, LCD_DATA0_A_MARK, TCLKA_C_MARK,
+
+       /* IPSR1 */
+       D3_MARK, SD0_DAT3_A_MARK, MMC_D3_A_MARK, ST1_D6_MARK, FD3_A_MARK,
+       D2_MARK, SD0_DAT2_A_MARK, MMC_D2_A_MARK, ST1_D5_MARK, FD2_A_MARK,
+       D1_MARK, SD0_DAT1_A_MARK, MMC_D1_A_MARK, ST1_D4_MARK, FD1_A_MARK,
+       D0_MARK, SD0_DAT0_A_MARK, MMC_D0_A_MARK, ST1_D3_MARK, FD0_A_MARK,
+       A25_MARK, TX2_D_MARK, ST1_D2_MARK,
+       A24_MARK, RX2_D_MARK, ST1_D1_MARK,
+       A23_MARK, ST1_D0_MARK, LCD_M_DISP_A_MARK,
+       A22_MARK, ST1_VLD_MARK, LCD_VEPWC_A_MARK,
+       A21_MARK, ST1_SYC_MARK, LCD_VCPWC_A_MARK,
+       A20_MARK, ST1_REQ_MARK, LCD_FLM_A_MARK,
+       A19_MARK, ST1_CLKIN_MARK, LCD_CLK_A_MARK,       TIOC4D_C_MARK,
+       A18_MARK, ST1_PWM_MARK, LCD_CL2_A_MARK, TIOC4C_C_MARK,
+       A17_MARK, ST1_VCO_CLKIN_MARK, LCD_CL1_A_MARK, TIOC4B_C_MARK,
+       A16_MARK, ST0_PWM_MARK, LCD_DON_A_MARK, TIOC4A_C_MARK,
+
+       /* IPSR2 */
+       D14_MARK, TX2_B_MARK, FSE_A_MARK, ET0_TX_CLK_B_MARK,
+       D13_MARK, RX2_B_MARK, FRB_A_MARK, ET0_ETXD6_B_MARK,
+       D12_MARK, FWE_A_MARK, ET0_ETXD5_B_MARK,
+       D11_MARK, RSPI_MISO_A_MARK, QMI_QIO1_A_MARK, FRE_A_MARK,
+               ET0_ETXD3_B_MARK,
+       D10_MARK, RSPI_MOSI_A_MARK, QMO_QIO0_A_MARK, FALE_A_MARK,
+               ET0_ETXD2_B_MARK,
+       D9_MARK, SD0_CMD_A_MARK, MMC_CMD_A_MARK, QIO3_A_MARK,
+               FCLE_A_MARK, ET0_ETXD1_B_MARK,
+       D8_MARK, SD0_CLK_A_MARK, MMC_CLK_A_MARK, QIO2_A_MARK,
+               FCE_A_MARK, ET0_GTX_CLK_B_MARK,
+       D7_MARK, RSPI_SSL_A_MARK, MMC_D7_A_MARK, QSSL_A_MARK,
+               FD7_A_MARK,
+       D6_MARK, RSPI_RSPCK_A_MARK, MMC_D6_A_MARK, QSPCLK_A_MARK,
+               FD6_A_MARK,
+       D5_MARK, SD0_WP_A_MARK, MMC_D5_A_MARK, FD5_A_MARK,
+       D4_MARK, SD0_CD_A_MARK, MMC_D4_A_MARK, ST1_D7_MARK,
+               FD4_A_MARK,
+
+       /* IPSR3 */
+       DRACK0_MARK, SD1_DAT2_A_MARK, ATAG_MARK, TCLK1_A_MARK, ET0_ETXD7_MARK,
+       EX_WAIT2_MARK, SD1_DAT1_A_MARK, DACK2_MARK, CAN1_RX_C_MARK,
+               ET0_MAGIC_C_MARK, ET0_ETXD6_A_MARK,
+       EX_WAIT1_MARK, SD1_DAT0_A_MARK, DREQ2_MARK, CAN1_TX_C_MARK,
+               ET0_LINK_C_MARK, ET0_ETXD5_A_MARK,
+       EX_WAIT0_MARK, TCLK1_B_MARK,
+       RD_WR_MARK, TCLK0_MARK, CAN_CLK_B_MARK, ET0_ETXD4_MARK,
+       EX_CS5_MARK, SD1_CMD_A_MARK, ATADIR_MARK, QSSL_B_MARK,
+               ET0_ETXD3_A_MARK,
+       EX_CS4_MARK, SD1_WP_A_MARK, ATAWR_MARK, QMI_QIO1_B_MARK,
+               ET0_ETXD2_A_MARK,
+       EX_CS3_MARK, SD1_CD_A_MARK, ATARD_MARK, QMO_QIO0_B_MARK,
+               ET0_ETXD1_A_MARK,
+       EX_CS2_MARK, TX3_B_MARK, ATACS1_MARK, QSPCLK_B_MARK,
+               ET0_GTX_CLK_A_MARK,
+       EX_CS1_MARK, RX3_B_MARK, ATACS0_MARK, QIO2_B_MARK,
+               ET0_ETXD0_MARK,
+       CS1_A26_MARK, QIO3_B_MARK,
+       D15_MARK, SCK2_B_MARK,
+
+       /* IPSR4 */
+       SCK2_A_MARK, VI0_G3_MARK,
+       RTS1_B_MARK, VI0_G2_MARK,
+       CTS1_B_MARK, VI0_DATA7_VI0_G1_MARK,
+       TX1_B_MARK, VI0_DATA6_VI0_G0_MARK, ET0_PHY_INT_A_MARK,
+       RX1_B_MARK, VI0_DATA5_VI0_B5_MARK, ET0_MAGIC_A_MARK,
+       SCK1_B_MARK, VI0_DATA4_VI0_B4_MARK, ET0_LINK_A_MARK,
+       RTS0_B_MARK, VI0_DATA3_VI0_B3_MARK, ET0_MDIO_A_MARK,
+       CTS0_B_MARK, VI0_DATA2_VI0_B2_MARK, RMII0_MDIO_A_MARK,
+               ET0_MDC_MARK,
+       HTX0_A_MARK, TX1_A_MARK, VI0_DATA1_VI0_B1_MARK,
+               RMII0_MDC_A_MARK, ET0_COL_MARK,
+       HRX0_A_MARK, RX1_A_MARK, VI0_DATA0_VI0_B0_MARK,
+               RMII0_CRS_DV_A_MARK, ET0_CRS_MARK,
+       HSCK0_A_MARK, SCK1_A_MARK, VI0_VSYNC_MARK,
+               RMII0_RX_ER_A_MARK, ET0_RX_ER_MARK,
+       HRTS0_A_MARK, RTS1_A_MARK, VI0_HSYNC_MARK,
+               RMII0_TXD_EN_A_MARK, ET0_RX_DV_MARK,
+       HCTS0_A_MARK, CTS1_A_MARK, VI0_FIELD_MARK,
+               RMII0_RXD1_A_MARK, ET0_ERXD7_MARK,
+
+       /* IPSR5 */
+       SD2_CLK_A_MARK, RX2_A_MARK, VI0_G4_MARK, ET0_RX_CLK_B_MARK,
+       SD2_CMD_A_MARK, TX2_A_MARK, VI0_G5_MARK, ET0_ERXD2_B_MARK,
+       SD2_DAT0_A_MARK, RX3_A_MARK, VI0_R0_MARK, ET0_ERXD3_B_MARK,
+       SD2_DAT1_A_MARK, TX3_A_MARK, VI0_R1_MARK, ET0_MDIO_B_MARK,
+       SD2_DAT2_A_MARK, RX4_A_MARK, VI0_R2_MARK, ET0_LINK_B_MARK,
+       SD2_DAT3_A_MARK, TX4_A_MARK, VI0_R3_MARK, ET0_MAGIC_B_MARK,
+       SD2_CD_A_MARK, RX5_A_MARK, VI0_R4_MARK, ET0_PHY_INT_B_MARK,
+       SD2_WP_A_MARK, TX5_A_MARK, VI0_R5_MARK,
+       REF125CK_MARK, ADTRG_MARK, RX5_C_MARK,
+       REF50CK_MARK, CTS1_E_MARK, HCTS0_D_MARK,
+
+       /* IPSR6 */
+       DU0_DR0_MARK, SCIF_CLK_B_MARK, HRX0_D_MARK, IETX_A_MARK,
+               TCLKA_A_MARK, HIFD00_MARK,
+       DU0_DR1_MARK, SCK0_B_MARK, HTX0_D_MARK, IERX_A_MARK,
+               TCLKB_A_MARK, HIFD01_MARK,
+       DU0_DR2_MARK, RX0_B_MARK, TCLKC_A_MARK, HIFD02_MARK,
+       DU0_DR3_MARK, TX0_B_MARK, TCLKD_A_MARK, HIFD03_MARK,
+       DU0_DR4_MARK, CTS0_C_MARK, TIOC0A_A_MARK, HIFD04_MARK,
+       DU0_DR5_MARK, RTS0_C_MARK, TIOC0B_A_MARK, HIFD05_MARK,
+       DU0_DR6_MARK, SCK1_C_MARK, TIOC0C_A_MARK, HIFD06_MARK,
+       DU0_DR7_MARK, RX1_C_MARK, TIOC0D_A_MARK, HIFD07_MARK,
+       DU0_DG0_MARK, TX1_C_MARK, HSCK0_D_MARK, IECLK_A_MARK,
+               TIOC1A_A_MARK, HIFD08_MARK,
+       DU0_DG1_MARK, CTS1_C_MARK, HRTS0_D_MARK, TIOC1B_A_MARK,
+               HIFD09_MARK,
+
+       /* IPSR7 */
+       DU0_DG2_MARK, RTS1_C_MARK, RMII0_MDC_B_MARK, TIOC2A_A_MARK,
+               HIFD10_MARK,
+       DU0_DG3_MARK, SCK2_C_MARK, RMII0_MDIO_B_MARK, TIOC2B_A_MARK,
+               HIFD11_MARK,
+       DU0_DG4_MARK, RX2_C_MARK, RMII0_CRS_DV_B_MARK, TIOC3A_A_MARK,
+               HIFD12_MARK,
+       DU0_DG5_MARK, TX2_C_MARK, RMII0_RX_ER_B_MARK, TIOC3B_A_MARK,
+               HIFD13_MARK,
+       DU0_DG6_MARK, RX3_C_MARK, RMII0_RXD0_B_MARK, TIOC3C_A_MARK,
+               HIFD14_MARK,
+       DU0_DG7_MARK, TX3_C_MARK, RMII0_RXD1_B_MARK, TIOC3D_A_MARK,
+               HIFD15_MARK,
+       DU0_DB0_MARK, RX4_C_MARK, RMII0_TXD_EN_B_MARK, TIOC4A_A_MARK,
+               HIFCS_MARK,
+       DU0_DB1_MARK, TX4_C_MARK, RMII0_TXD0_B_MARK, TIOC4B_A_MARK,
+               HIFRS_MARK,
+       DU0_DB2_MARK, RX5_B_MARK, RMII0_TXD1_B_MARK, TIOC4C_A_MARK,
+               HIFWR_MARK,
+       DU0_DB3_MARK, TX5_B_MARK, TIOC4D_A_MARK, HIFRD_MARK,
+       DU0_DB4_MARK, HIFINT_MARK,
+
+       /* IPSR8 */
+       DU0_DB5_MARK, HIFDREQ_MARK,
+       DU0_DB6_MARK, HIFRDY_MARK,
+       DU0_DB7_MARK, SSI_SCK0_B_MARK, HIFEBL_B_MARK,
+       DU0_DOTCLKIN_MARK, HSPI_CS0_C_MARK, SSI_WS0_B_MARK,
+       DU0_DOTCLKOUT_MARK, HSPI_CLK0_C_MARK, SSI_SDATA0_B_MARK,
+       DU0_EXHSYNC_DU0_HSYNC_MARK, HSPI_TX0_C_MARK, SSI_SCK1_B_MARK,
+       DU0_EXVSYNC_DU0_VSYNC_MARK, HSPI_RX0_C_MARK, SSI_WS1_B_MARK,
+       DU0_EXODDF_DU0_ODDF_MARK, CAN0_RX_B_MARK, HSCK0_B_MARK,
+               SSI_SDATA1_B_MARK,
+       DU0_DISP_MARK, CAN0_TX_B_MARK, HRX0_B_MARK, AUDIO_CLKA_B_MARK,
+       DU0_CDE_MARK, HTX0_B_MARK, AUDIO_CLKB_B_MARK, LCD_VCPWC_B_MARK,
+       IRQ0_A_MARK, HSPI_TX_B_MARK, RX3_E_MARK, ET0_ERXD0_MARK,
+       IRQ1_A_MARK, HSPI_RX_B_MARK, TX3_E_MARK, ET0_ERXD1_MARK,
+       IRQ2_A_MARK, CTS0_A_MARK, HCTS0_B_MARK, ET0_ERXD2_A_MARK,
+       IRQ3_A_MARK, RTS0_A_MARK, HRTS0_B_MARK, ET0_ERXD3_A_MARK,
+
+       /* IPSR9 */
+       VI1_CLK_A_MARK, FD0_B_MARK, LCD_DATA0_B_MARK,
+       VI1_0_A_MARK, FD1_B_MARK, LCD_DATA1_B_MARK,
+       VI1_1_A_MARK, FD2_B_MARK, LCD_DATA2_B_MARK,
+       VI1_2_A_MARK, FD3_B_MARK, LCD_DATA3_B_MARK,
+       VI1_3_A_MARK, FD4_B_MARK, LCD_DATA4_B_MARK,
+       VI1_4_A_MARK, FD5_B_MARK, LCD_DATA5_B_MARK,
+       VI1_5_A_MARK, FD6_B_MARK, LCD_DATA6_B_MARK,
+       VI1_6_A_MARK, FD7_B_MARK, LCD_DATA7_B_MARK,
+       VI1_7_A_MARK, FCE_B_MARK, LCD_DATA8_B_MARK,
+       SSI_SCK0_A_MARK, TIOC1A_B_MARK, LCD_DATA9_B_MARK,
+       SSI_WS0_A_MARK, TIOC1B_B_MARK, LCD_DATA10_B_MARK,
+       SSI_SDATA0_A_MARK, VI1_0_B_MARK, TIOC2A_B_MARK, LCD_DATA11_B_MARK,
+       SSI_SCK1_A_MARK, VI1_1_B_MARK, TIOC2B_B_MARK, LCD_DATA12_B_MARK,
+       SSI_WS1_A_MARK, VI1_2_B_MARK, LCD_DATA13_B_MARK,
+       SSI_SDATA1_A_MARK, VI1_3_B_MARK, LCD_DATA14_B_MARK,
+
+       /* IPSR10 */
+       SSI_SCK23_MARK, VI1_4_B_MARK, RX1_D_MARK, FCLE_B_MARK,
+               LCD_DATA15_B_MARK,
+       SSI_WS23_MARK, VI1_5_B_MARK, TX1_D_MARK, HSCK0_C_MARK,
+               FALE_B_MARK, LCD_DON_B_MARK,
+       SSI_SDATA2_MARK, VI1_6_B_MARK, HRX0_C_MARK, FRE_B_MARK,
+               LCD_CL1_B_MARK,
+       SSI_SDATA3_MARK, VI1_7_B_MARK, HTX0_C_MARK, FWE_B_MARK,
+               LCD_CL2_B_MARK,
+       AUDIO_CLKA_A_MARK, VI1_CLK_B_MARK, SCK1_D_MARK, IECLK_B_MARK,
+               LCD_FLM_B_MARK,
+       AUDIO_CLKB_A_MARK, LCD_CLK_B_MARK,
+       AUDIO_CLKC_MARK, SCK1_E_MARK, HCTS0_C_MARK, FRB_B_MARK,
+               LCD_VEPWC_B_MARK,
+       AUDIO_CLKOUT_MARK, TX1_E_MARK, HRTS0_C_MARK, FSE_B_MARK,
+               LCD_M_DISP_B_MARK,
+       CAN_CLK_A_MARK, RX4_D_MARK,
+       CAN0_TX_A_MARK, TX4_D_MARK, MLB_CLK_MARK,
+       CAN1_RX_A_MARK, IRQ1_B_MARK,
+       CAN0_RX_A_MARK, IRQ0_B_MARK, MLB_SIG_MARK,
+       CAN1_TX_A_MARK, TX5_C_MARK, MLB_DAT_MARK,
+
+       /* IPSR11 */
+       SCL1_MARK, SCIF_CLK_C_MARK,
+       SDA1_MARK, RX1_E_MARK,
+       SDA0_MARK, HIFEBL_A_MARK,
+       SDSELF_MARK, RTS1_E_MARK,
+       SCIF_CLK_A_MARK, HSPI_CLK_A_MARK, VI0_CLK_MARK, RMII0_TXD0_A_MARK,
+               ET0_ERXD4_MARK,
+       SCK0_A_MARK, HSPI_CS_A_MARK, VI0_CLKENB_MARK, RMII0_TXD1_A_MARK,
+               ET0_ERXD5_MARK,
+       RX0_A_MARK, HSPI_RX_A_MARK, RMII0_RXD0_A_MARK, ET0_ERXD6_MARK,
+       TX0_A_MARK, HSPI_TX_A_MARK,
+       PENC1_MARK, TX3_D_MARK, CAN1_TX_B_MARK, TX5_D_MARK,
+               IETX_B_MARK,
+       USB_OVC1_MARK, RX3_D_MARK, CAN1_RX_B_MARK, RX5_D_MARK,
+               IERX_B_MARK,
+       DREQ0_MARK, SD1_CLK_A_MARK, ET0_TX_EN_MARK,
+       DACK0_MARK, SD1_DAT3_A_MARK, ET0_TX_ER_MARK,
+       DREQ1_MARK, HSPI_CLK_B_MARK, RX4_B_MARK, ET0_PHY_INT_C_MARK,
+               ET0_TX_CLK_A_MARK,
+       DACK1_MARK, HSPI_CS_B_MARK, TX4_B_MARK, ET0_RX_CLK_A_MARK,
+       PRESETOUT_MARK, ST_CLKOUT_MARK,
+
+       PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+       PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
+
+       PINMUX_DATA(CLKOUT_MARK, FN_CLKOUT),
+       PINMUX_DATA(BS_MARK, FN_BS), PINMUX_DATA(CS0_MARK, FN_CS0),
+       PINMUX_DATA(EX_CS0_MARK, FN_EX_CS0),
+       PINMUX_DATA(RD_MARK, FN_RD), PINMUX_DATA(WE0_MARK, FN_WE0),
+       PINMUX_DATA(WE1_MARK, FN_WE1),
+       PINMUX_DATA(SCL0_MARK, FN_SCL0), PINMUX_DATA(PENC0_MARK, FN_PENC0),
+       PINMUX_DATA(USB_OVC0_MARK, FN_USB_OVC0),
+       PINMUX_DATA(IRQ2_B_MARK, FN_IRQ2_B),
+               PINMUX_DATA(IRQ3_B_MARK, FN_IRQ3_B),
+
+       /* IPSR0 */
+       PINMUX_IPSR_DATA(IP0_1_0, A0),
+       PINMUX_IPSR_DATA(IP0_1_0, ST0_CLKIN),
+       PINMUX_IPSR_MODSEL_DATA(IP0_1_0, LCD_DATA0_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_1_0, TCLKA_C, SEL_MTU2_CLK_1),
+
+       PINMUX_IPSR_DATA(IP0_3_2, A1),
+       PINMUX_IPSR_DATA(IP0_3_2, ST0_REQ),
+       PINMUX_IPSR_MODSEL_DATA(IP0_3_2, LCD_DATA1_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_3_2, TCLKB_C, SEL_MTU2_CLK_1),
+
+       PINMUX_IPSR_DATA(IP0_5_4, A2),
+       PINMUX_IPSR_DATA(IP0_5_4, ST0_SYC),
+       PINMUX_IPSR_MODSEL_DATA(IP0_5_4, LCD_DATA2_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_5_4, TCLKC_C, SEL_MTU2_CLK_1),
+
+       PINMUX_IPSR_DATA(IP0_7_6, A3),
+       PINMUX_IPSR_DATA(IP0_7_6, ST0_VLD),
+       PINMUX_IPSR_MODSEL_DATA(IP0_7_6, LCD_DATA3_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_7_6, TCLKD_C, SEL_MTU2_CLK_1),
+
+       PINMUX_IPSR_DATA(IP0_9_8, A4),
+       PINMUX_IPSR_DATA(IP0_9_8, ST0_D0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_9_8, LCD_DATA4_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_9_8, TIOC0A_C, SEL_MTU2_CH0_1),
+
+       PINMUX_IPSR_DATA(IP0_11_10, A5),
+       PINMUX_IPSR_DATA(IP0_11_10, ST0_D1),
+       PINMUX_IPSR_MODSEL_DATA(IP0_11_10, LCD_DATA5_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_11_10, TIOC0B_C, SEL_MTU2_CH0_1),
+
+       PINMUX_IPSR_DATA(IP0_13_12, A6),
+       PINMUX_IPSR_DATA(IP0_13_12, ST0_D2),
+       PINMUX_IPSR_MODSEL_DATA(IP0_13_12, LCD_DATA6_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_13_12, TIOC0C_C, SEL_MTU2_CH0_1),
+
+       PINMUX_IPSR_DATA(IP0_15_14, A7),
+       PINMUX_IPSR_DATA(IP0_15_14, ST0_D3),
+       PINMUX_IPSR_MODSEL_DATA(IP0_15_14, LCD_DATA7_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_15_14, TIOC0D_C, SEL_MTU2_CH0_1),
+
+       PINMUX_IPSR_DATA(IP0_17_16, A8),
+       PINMUX_IPSR_DATA(IP0_17_16, ST0_D4),
+       PINMUX_IPSR_MODSEL_DATA(IP0_17_16, LCD_DATA8_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_17_16, TIOC1A_C, SEL_MTU2_CH1_2),
+
+       PINMUX_IPSR_DATA(IP0_19_18, A9),
+       PINMUX_IPSR_DATA(IP0_19_18, ST0_D5),
+       PINMUX_IPSR_MODSEL_DATA(IP0_19_18, LCD_DATA9_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_19_18, TIOC1B_C, SEL_MTU2_CH1_2),
+
+       PINMUX_IPSR_DATA(IP0_21_20, A10),
+       PINMUX_IPSR_DATA(IP0_21_20, ST0_D6),
+       PINMUX_IPSR_MODSEL_DATA(IP0_21_20, LCD_DATA10_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_21_20, TIOC2A_C, SEL_MTU2_CH2_2),
+
+       PINMUX_IPSR_DATA(IP0_23_22, A11),
+       PINMUX_IPSR_DATA(IP0_23_22, ST0_D7),
+       PINMUX_IPSR_MODSEL_DATA(IP0_23_22, LCD_DATA11_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_23_22, TIOC2B_C, SEL_MTU2_CH2_2),
+
+       PINMUX_IPSR_DATA(IP0_25_24, A12),
+       PINMUX_IPSR_MODSEL_DATA(IP0_25_24, LCD_DATA12_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_25_24, TIOC3A_C, SEL_MTU2_CH3_1),
+
+       PINMUX_IPSR_DATA(IP0_27_26, A13),
+       PINMUX_IPSR_MODSEL_DATA(IP0_27_26, LCD_DATA13_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_27_26, TIOC3B_C, SEL_MTU2_CH3_1),
+
+       PINMUX_IPSR_DATA(IP0_29_28, A14),
+       PINMUX_IPSR_MODSEL_DATA(IP0_29_28, LCD_DATA14_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_29_28, TIOC3C_C, SEL_MTU2_CH3_1),
+
+       PINMUX_IPSR_DATA(IP0_31_30, A15),
+       PINMUX_IPSR_DATA(IP0_31_30, ST0_VCO_CLKIN),
+       PINMUX_IPSR_MODSEL_DATA(IP0_31_30, LCD_DATA15_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_31_30, TIOC3D_C, SEL_MTU2_CH3_1),
+
+
+       /* IPSR1 */
+       PINMUX_IPSR_DATA(IP1_1_0, A16),
+       PINMUX_IPSR_DATA(IP1_1_0, ST0_PWM),
+       PINMUX_IPSR_MODSEL_DATA(IP1_1_0, LCD_DON_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_1_0, TIOC4A_C, SEL_MTU2_CH4_1),
+
+       PINMUX_IPSR_DATA(IP1_3_2, A17),
+       PINMUX_IPSR_DATA(IP1_3_2, ST1_VCO_CLKIN),
+       PINMUX_IPSR_MODSEL_DATA(IP1_3_2, LCD_CL1_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_3_2, TIOC4B_C, SEL_MTU2_CH4_1),
+
+       PINMUX_IPSR_DATA(IP1_5_4, A18),
+       PINMUX_IPSR_DATA(IP1_5_4, ST1_PWM),
+       PINMUX_IPSR_MODSEL_DATA(IP1_5_4, LCD_CL2_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_5_4, TIOC4C_C, SEL_MTU2_CH4_1),
+
+       PINMUX_IPSR_DATA(IP1_7_6, A19),
+       PINMUX_IPSR_DATA(IP1_7_6, ST1_CLKIN),
+       PINMUX_IPSR_MODSEL_DATA(IP1_7_6, LCD_CLK_A, SEL_LCDC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_7_6, TIOC4D_C, SEL_MTU2_CH4_1),
+
+       PINMUX_IPSR_DATA(IP1_9_8, A20),
+       PINMUX_IPSR_DATA(IP1_9_8, ST1_REQ),
+       PINMUX_IPSR_MODSEL_DATA(IP1_9_8, LCD_FLM_A, SEL_LCDC_0),
+
+       PINMUX_IPSR_DATA(IP1_11_10, A21),
+       PINMUX_IPSR_DATA(IP1_11_10, ST1_SYC),
+       PINMUX_IPSR_MODSEL_DATA(IP1_11_10, LCD_VCPWC_A, SEL_LCDC_0),
+
+       PINMUX_IPSR_DATA(IP1_13_12, A22),
+       PINMUX_IPSR_DATA(IP1_13_12, ST1_VLD),
+       PINMUX_IPSR_MODSEL_DATA(IP1_13_12, LCD_VEPWC_A, SEL_LCDC_0),
+
+       PINMUX_IPSR_DATA(IP1_15_14, A23),
+       PINMUX_IPSR_DATA(IP1_15_14, ST1_D0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_15_14, LCD_M_DISP_A, SEL_LCDC_0),
+
+       PINMUX_IPSR_DATA(IP1_17_16, A24),
+       PINMUX_IPSR_MODSEL_DATA(IP1_17_16, RX2_D, SEL_SCIF2_3),
+       PINMUX_IPSR_DATA(IP1_17_16, ST1_D1),
+
+       PINMUX_IPSR_DATA(IP1_19_18, A25),
+       PINMUX_IPSR_MODSEL_DATA(IP1_17_16, RX2_D, SEL_SCIF2_3),
+       PINMUX_IPSR_DATA(IP1_17_16, ST1_D2),
+
+       PINMUX_IPSR_DATA(IP1_22_20, D0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_22_20, SD0_DAT0_A, SEL_SDHI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_22_20, MMC_D0_A, SEL_MMC_0),
+       PINMUX_IPSR_DATA(IP1_22_20, ST1_D3),
+       PINMUX_IPSR_MODSEL_DATA(IP1_22_20, FD0_A, SEL_FLCTL_0),
+
+       PINMUX_IPSR_DATA(IP1_25_23, D1),
+       PINMUX_IPSR_MODSEL_DATA(IP1_25_23, SD0_DAT0_A, SEL_SDHI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_25_23, MMC_D1_A, SEL_MMC_0),
+       PINMUX_IPSR_DATA(IP1_25_23, ST1_D4),
+       PINMUX_IPSR_MODSEL_DATA(IP1_25_23, FD1_A, SEL_FLCTL_0),
+
+       PINMUX_IPSR_DATA(IP1_28_26, D2),
+       PINMUX_IPSR_MODSEL_DATA(IP1_28_26, SD0_DAT0_A, SEL_SDHI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_28_26, MMC_D2_A, SEL_MMC_0),
+       PINMUX_IPSR_DATA(IP1_28_26, ST1_D5),
+       PINMUX_IPSR_MODSEL_DATA(IP1_28_26, FD2_A, SEL_FLCTL_0),
+
+       PINMUX_IPSR_DATA(IP1_31_29, D3),
+       PINMUX_IPSR_MODSEL_DATA(IP1_31_29, SD0_DAT0_A, SEL_SDHI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_31_29, MMC_D3_A, SEL_MMC_0),
+       PINMUX_IPSR_DATA(IP1_31_29, ST1_D6),
+       PINMUX_IPSR_MODSEL_DATA(IP1_31_29, FD3_A, SEL_FLCTL_0),
+
+       /* IPSR2 */
+       PINMUX_IPSR_DATA(IP2_2_0, D4),
+       PINMUX_IPSR_MODSEL_DATA(IP2_2_0, SD0_CD_A, SEL_SDHI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_2_0, MMC_D4_A, SEL_MMC_0),
+       PINMUX_IPSR_DATA(IP2_2_0, ST1_D7),
+       PINMUX_IPSR_MODSEL_DATA(IP2_2_0, FD4_A, SEL_FLCTL_0),
+
+       PINMUX_IPSR_DATA(IP2_4_3, D5),
+       PINMUX_IPSR_MODSEL_DATA(IP2_4_3, SD0_WP_A, SEL_SDHI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_4_3, MMC_D5_A, SEL_MMC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_4_3, FD5_A, SEL_FLCTL_0),
+
+       PINMUX_IPSR_DATA(IP2_7_5, D6),
+       PINMUX_IPSR_MODSEL_DATA(IP2_7_5, RSPI_RSPCK_A, SEL_RSPI_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_7_5, MMC_D6_A, SEL_MMC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_7_5, QSPCLK_A, SEL_RQSPI_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_7_5, FD6_A, SEL_FLCTL_0),
+
+       PINMUX_IPSR_DATA(IP2_10_8, D7),
+       PINMUX_IPSR_MODSEL_DATA(IP2_10_8, RSPI_SSL_A, SEL_RSPI_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_10_8, MMC_D7_A, SEL_MMC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_10_8, QSSL_A, SEL_RQSPI_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_10_8, FD7_A, SEL_FLCTL_0),
+
+       PINMUX_IPSR_DATA(IP2_13_11, D8),
+       PINMUX_IPSR_MODSEL_DATA(IP2_13_11, SD0_CLK_A, SEL_SDHI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_13_11, MMC_CLK_A, SEL_MMC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_13_11, QIO2_A, SEL_RQSPI_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_13_11, FCE_A, SEL_FLCTL_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_13_11, ET0_GTX_CLK_B, SEL_ET0_1),
+
+       PINMUX_IPSR_DATA(IP2_16_14, D9),
+       PINMUX_IPSR_MODSEL_DATA(IP2_16_14, SD0_CMD_A, SEL_SDHI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_16_14, MMC_CMD_A, SEL_MMC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_16_14, QIO3_A, SEL_RQSPI_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_16_14, FCLE_A, SEL_FLCTL_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_16_14, ET0_ETXD1_B, SEL_ET0_1),
+
+       PINMUX_IPSR_DATA(IP2_19_17, D10),
+       PINMUX_IPSR_MODSEL_DATA(IP2_19_17, RSPI_MOSI_A, SEL_RSPI_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_19_17, QMO_QIO0_A, SEL_RQSPI_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_19_17, FALE_A, SEL_FLCTL_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_19_17, ET0_ETXD2_B, SEL_ET0_1),
+
+       PINMUX_IPSR_DATA(IP2_22_20, D11),
+       PINMUX_IPSR_MODSEL_DATA(IP2_22_20, RSPI_MISO_A, SEL_RSPI_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_22_20, QMI_QIO1_A, SEL_RQSPI_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_22_20, FRE_A, SEL_FLCTL_0),
+
+       PINMUX_IPSR_DATA(IP2_24_23, D12),
+       PINMUX_IPSR_MODSEL_DATA(IP2_24_23, FWE_A, SEL_FLCTL_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_24_23, ET0_ETXD5_B, SEL_ET0_1),
+
+       PINMUX_IPSR_DATA(IP2_27_25, D13),
+       PINMUX_IPSR_MODSEL_DATA(IP2_27_25, RX2_B, SEL_SCIF2_1),
+       PINMUX_IPSR_MODSEL_DATA(IP2_27_25, FRB_A, SEL_FLCTL_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_27_25, ET0_ETXD6_B, SEL_ET0_1),
+
+       PINMUX_IPSR_DATA(IP2_30_28, D14),
+       PINMUX_IPSR_MODSEL_DATA(IP2_30_28, TX2_B, SEL_SCIF2_1),
+       PINMUX_IPSR_MODSEL_DATA(IP2_30_28, FSE_A, SEL_FLCTL_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_30_28, ET0_TX_CLK_B, SEL_ET0_1),
+
+       /* IPSR3 */
+       PINMUX_IPSR_DATA(IP3_1_0, D15),
+       PINMUX_IPSR_MODSEL_DATA(IP3_1_0, SCK2_B, SEL_SCIF2_1),
+
+       PINMUX_IPSR_DATA(IP3_2, CS1_A26),
+       PINMUX_IPSR_MODSEL_DATA(IP3_2, QIO3_B, SEL_RQSPI_1),
+
+       PINMUX_IPSR_DATA(IP3_5_3, EX_CS1),
+       PINMUX_IPSR_MODSEL_DATA(IP3_5_3, RX3_B, SEL_SCIF2_1),
+       PINMUX_IPSR_DATA(IP3_5_3, ATACS0),
+       PINMUX_IPSR_MODSEL_DATA(IP3_5_3, QIO2_B, SEL_RQSPI_1),
+       PINMUX_IPSR_DATA(IP3_5_3, ET0_ETXD0),
+
+       PINMUX_IPSR_DATA(IP3_8_6, EX_CS2),
+       PINMUX_IPSR_MODSEL_DATA(IP3_8_6, TX3_B, SEL_SCIF3_1),
+       PINMUX_IPSR_DATA(IP3_8_6, ATACS1),
+       PINMUX_IPSR_MODSEL_DATA(IP3_8_6, QSPCLK_B, SEL_RQSPI_1),
+       PINMUX_IPSR_MODSEL_DATA(IP3_8_6, ET0_GTX_CLK_A, SEL_ET0_0),
+
+       PINMUX_IPSR_DATA(IP3_11_9, EX_CS3),
+       PINMUX_IPSR_MODSEL_DATA(IP3_11_9, SD1_CD_A, SEL_SDHI1_0),
+       PINMUX_IPSR_DATA(IP3_11_9, ATARD),
+       PINMUX_IPSR_MODSEL_DATA(IP3_11_9, QMO_QIO0_B, SEL_RQSPI_1),
+       PINMUX_IPSR_MODSEL_DATA(IP3_11_9, ET0_ETXD1_A, SEL_ET0_0),
+
+       PINMUX_IPSR_DATA(IP3_14_12, EX_CS4),
+       PINMUX_IPSR_MODSEL_DATA(IP3_14_12, SD1_WP_A, SEL_SDHI1_0),
+       PINMUX_IPSR_DATA(IP3_14_12, ATAWR),
+       PINMUX_IPSR_MODSEL_DATA(IP3_14_12, QMI_QIO1_B, SEL_RQSPI_1),
+       PINMUX_IPSR_MODSEL_DATA(IP3_14_12, ET0_ETXD2_A, SEL_ET0_0),
+
+       PINMUX_IPSR_DATA(IP3_17_15, EX_CS5),
+       PINMUX_IPSR_MODSEL_DATA(IP3_17_15, SD1_CMD_A, SEL_SDHI1_0),
+       PINMUX_IPSR_DATA(IP3_17_15, ATADIR),
+       PINMUX_IPSR_MODSEL_DATA(IP3_17_15, QSSL_B, SEL_RQSPI_1),
+       PINMUX_IPSR_MODSEL_DATA(IP3_17_15, ET0_ETXD3_A, SEL_ET0_0),
+
+       PINMUX_IPSR_DATA(IP3_19_18, RD_WR),
+       PINMUX_IPSR_DATA(IP3_19_18, TCLK0),
+       PINMUX_IPSR_MODSEL_DATA(IP3_19_18, CAN_CLK_B, SEL_RCAN_CLK_1),
+       PINMUX_IPSR_DATA(IP3_19_18, ET0_ETXD4),
+
+       PINMUX_IPSR_DATA(IP3_20, EX_WAIT0),
+       PINMUX_IPSR_MODSEL_DATA(IP3_20, TCLK1_B, SEL_TMU_1),
+
+       PINMUX_IPSR_DATA(IP3_23_21, EX_WAIT1),
+       PINMUX_IPSR_MODSEL_DATA(IP3_23_21, SD1_DAT0_A, SEL_SDHI1_0),
+       PINMUX_IPSR_DATA(IP3_23_21, DREQ2),
+       PINMUX_IPSR_MODSEL_DATA(IP3_23_21, CAN1_TX_C, SEL_RCAN1_2),
+       PINMUX_IPSR_MODSEL_DATA(IP3_23_21, ET0_LINK_C, SEL_ET0_CTL_2),
+       PINMUX_IPSR_MODSEL_DATA(IP3_23_21, ET0_ETXD5_A, SEL_ET0_0),
+
+       PINMUX_IPSR_DATA(IP3_26_24, EX_WAIT2),
+       PINMUX_IPSR_MODSEL_DATA(IP3_26_24, SD1_DAT1_A, SEL_SDHI1_0),
+       PINMUX_IPSR_DATA(IP3_26_24, DACK2),
+       PINMUX_IPSR_MODSEL_DATA(IP3_26_24, CAN1_RX_C, SEL_RCAN1_2),
+       PINMUX_IPSR_MODSEL_DATA(IP3_26_24, ET0_MAGIC_C, SEL_ET0_CTL_2),
+       PINMUX_IPSR_MODSEL_DATA(IP3_26_24, ET0_ETXD6_A, SEL_ET0_0),
+
+       PINMUX_IPSR_DATA(IP3_29_27, DRACK0),
+       PINMUX_IPSR_MODSEL_DATA(IP3_29_27, SD1_DAT2_A, SEL_SDHI1_0),
+       PINMUX_IPSR_DATA(IP3_29_27, ATAG),
+       PINMUX_IPSR_MODSEL_DATA(IP3_29_27, TCLK1_A, SEL_TMU_0),
+       PINMUX_IPSR_DATA(IP3_29_27, ET0_ETXD7),
+
+       /* IPSR4 */
+       PINMUX_IPSR_MODSEL_DATA(IP4_2_0, HCTS0_A, SEL_HSCIF_0),
+       PINMUX_IPSR_MODSEL_DATA(IP4_2_0, CTS1_A, SEL_SCIF1_0),
+       PINMUX_IPSR_DATA(IP4_2_0, VI0_FIELD),
+       PINMUX_IPSR_MODSEL_DATA(IP4_2_0, RMII0_RXD1_A, SEL_RMII_0),
+       PINMUX_IPSR_DATA(IP4_2_0, ET0_ERXD7),
+
+       PINMUX_IPSR_MODSEL_DATA(IP4_5_3, HRTS0_A, SEL_HSCIF_0),
+       PINMUX_IPSR_MODSEL_DATA(IP4_5_3, RTS1_A, SEL_SCIF1_0),
+       PINMUX_IPSR_DATA(IP4_5_3, VI0_HSYNC),
+       PINMUX_IPSR_MODSEL_DATA(IP4_5_3, RMII0_TXD_EN_A, SEL_RMII_0),
+       PINMUX_IPSR_DATA(IP4_5_3, ET0_RX_DV),
+
+       PINMUX_IPSR_MODSEL_DATA(IP4_8_6, HSCK0_A, SEL_HSCIF_0),
+       PINMUX_IPSR_MODSEL_DATA(IP4_8_6, SCK1_A, SEL_SCIF1_0),
+       PINMUX_IPSR_DATA(IP4_8_6, VI0_VSYNC),
+       PINMUX_IPSR_MODSEL_DATA(IP4_8_6, RMII0_RX_ER_A, SEL_RMII_0),
+       PINMUX_IPSR_DATA(IP4_8_6, ET0_RX_ER),
+
+       PINMUX_IPSR_MODSEL_DATA(IP4_11_9, HRX0_A, SEL_HSCIF_0),
+       PINMUX_IPSR_MODSEL_DATA(IP4_11_9, RX1_A, SEL_SCIF1_0),
+       PINMUX_IPSR_DATA(IP4_11_9, VI0_DATA0_VI0_B0),
+       PINMUX_IPSR_MODSEL_DATA(IP4_11_9, RMII0_CRS_DV_A, SEL_RMII_0),
+       PINMUX_IPSR_DATA(IP4_11_9, ET0_CRS),
+
+       PINMUX_IPSR_MODSEL_DATA(IP4_14_12, HTX0_A, SEL_HSCIF_0),
+       PINMUX_IPSR_MODSEL_DATA(IP4_14_12, TX1_A, SEL_SCIF1_0),
+       PINMUX_IPSR_DATA(IP4_14_12, VI0_DATA1_VI0_B1),
+       PINMUX_IPSR_MODSEL_DATA(IP4_14_12, RMII0_MDC_A, SEL_RMII_0),
+       PINMUX_IPSR_DATA(IP4_14_12, ET0_COL),
+
+       PINMUX_IPSR_MODSEL_DATA(IP4_17_15, CTS0_B, SEL_SCIF0_1),
+       PINMUX_IPSR_DATA(IP4_17_15, VI0_DATA2_VI0_B2),
+       PINMUX_IPSR_MODSEL_DATA(IP4_17_15, RMII0_MDIO_A, SEL_RMII_0),
+       PINMUX_IPSR_DATA(IP4_17_15, ET0_MDC),
+
+       PINMUX_IPSR_MODSEL_DATA(IP4_19_18, RTS0_B, SEL_SCIF0_1),
+       PINMUX_IPSR_DATA(IP4_19_18, VI0_DATA3_VI0_B3),
+       PINMUX_IPSR_MODSEL_DATA(IP4_19_18, ET0_MDIO_A, SEL_ET0_0),
+
+       PINMUX_IPSR_MODSEL_DATA(IP4_21_20, SCK1_B, SEL_SCIF1_1),
+       PINMUX_IPSR_DATA(IP4_21_20, VI0_DATA4_VI0_B4),
+       PINMUX_IPSR_MODSEL_DATA(IP4_21_20, ET0_LINK_A, SEL_ET0_CTL_0),
+
+       PINMUX_IPSR_MODSEL_DATA(IP4_23_22, RX1_B, SEL_SCIF1_1),
+       PINMUX_IPSR_DATA(IP4_23_22, VI0_DATA5_VI0_B5),
+       PINMUX_IPSR_MODSEL_DATA(IP4_23_22, ET0_MAGIC_A, SEL_ET0_CTL_0),
+
+       PINMUX_IPSR_MODSEL_DATA(IP4_25_24, TX1_B, SEL_SCIF1_1),
+       PINMUX_IPSR_DATA(IP4_25_24, VI0_DATA6_VI0_G0),
+       PINMUX_IPSR_MODSEL_DATA(IP4_25_24, ET0_PHY_INT_A, SEL_ET0_CTL_0),
+
+       PINMUX_IPSR_MODSEL_DATA(IP4_27_26, CTS1_B, SEL_SCIF1_1),
+       PINMUX_IPSR_DATA(IP4_27_26, VI0_DATA7_VI0_G1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP4_29_28, RTS1_B, SEL_SCIF1_1),
+       PINMUX_IPSR_DATA(IP4_29_28, VI0_G2),
+
+       PINMUX_IPSR_MODSEL_DATA(IP4_31_30, SCK2_A, SEL_SCIF2_0),
+       PINMUX_IPSR_DATA(IP4_31_30, VI0_G3),
+
+       /* IPSR5 */
+       PINMUX_IPSR_MODSEL_DATA(IP5_2_0, SD2_CLK_A, SEL_SDHI2_0),
+       PINMUX_IPSR_MODSEL_DATA(IP5_2_0, RX2_A, SEL_SCIF2_0),
+       PINMUX_IPSR_DATA(IP5_2_0, VI0_G4),
+       PINMUX_IPSR_MODSEL_DATA(IP5_2_0, ET0_RX_CLK_B, SEL_ET0_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP5_5_3, SD2_CMD_A, SEL_SDHI2_0),
+       PINMUX_IPSR_MODSEL_DATA(IP5_5_3, TX2_A, SEL_SCIF2_0),
+       PINMUX_IPSR_DATA(IP5_5_3, VI0_G5),
+       PINMUX_IPSR_MODSEL_DATA(IP5_5_3, ET0_ERXD2_B, SEL_ET0_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP5_8_6, SD2_DAT0_A, SEL_SDHI2_0),
+       PINMUX_IPSR_MODSEL_DATA(IP5_8_6, RX3_A, SEL_SCIF3_0),
+       PINMUX_IPSR_DATA(IP4_8_6, VI0_R0),
+       PINMUX_IPSR_MODSEL_DATA(IP4_8_6, ET0_ERXD2_B, SEL_ET0_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP5_11_9, SD2_DAT1_A, SEL_SDHI2_0),
+       PINMUX_IPSR_MODSEL_DATA(IP5_11_9, TX3_A, SEL_SCIF3_0),
+       PINMUX_IPSR_DATA(IP5_11_9, VI0_R1),
+       PINMUX_IPSR_MODSEL_DATA(IP5_11_9, ET0_MDIO_B, SEL_ET0_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP5_14_12, SD2_DAT2_A, SEL_SDHI2_0),
+       PINMUX_IPSR_MODSEL_DATA(IP5_14_12, RX4_A, SEL_SCIF4_0),
+       PINMUX_IPSR_DATA(IP5_14_12, VI0_R2),
+       PINMUX_IPSR_MODSEL_DATA(IP5_14_12, ET0_LINK_B, SEL_ET0_CTL_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP5_17_15, SD2_DAT3_A, SEL_SDHI2_0),
+       PINMUX_IPSR_MODSEL_DATA(IP5_17_15, TX4_A, SEL_SCIF4_0),
+       PINMUX_IPSR_DATA(IP5_17_15, VI0_R3),
+       PINMUX_IPSR_MODSEL_DATA(IP5_17_15, ET0_MAGIC_B, SEL_ET0_CTL_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP5_20_18, SD2_CD_A, SEL_SDHI2_0),
+       PINMUX_IPSR_MODSEL_DATA(IP5_20_18, RX5_A, SEL_SCIF5_0),
+       PINMUX_IPSR_DATA(IP5_20_18, VI0_R4),
+       PINMUX_IPSR_MODSEL_DATA(IP5_20_18, ET0_PHY_INT_B, SEL_ET0_CTL_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP5_22_21, SD2_WP_A, SEL_SDHI2_0),
+       PINMUX_IPSR_MODSEL_DATA(IP5_22_21, TX5_A, SEL_SCIF5_0),
+       PINMUX_IPSR_DATA(IP5_22_21, VI0_R5),
+
+       PINMUX_IPSR_DATA(IP5_24_23, REF125CK),
+       PINMUX_IPSR_DATA(IP5_24_23, ADTRG),
+       PINMUX_IPSR_MODSEL_DATA(IP5_24_23, RX5_C, SEL_SCIF5_2),
+       PINMUX_IPSR_DATA(IP5_26_25, REF50CK),
+       PINMUX_IPSR_MODSEL_DATA(IP5_26_25, CTS1_E, SEL_SCIF1_3),
+       PINMUX_IPSR_MODSEL_DATA(IP5_26_25, HCTS0_D, SEL_HSCIF_3),
+
+       /* IPSR6 */
+       PINMUX_IPSR_DATA(IP6_2_0, DU0_DR0),
+       PINMUX_IPSR_MODSEL_DATA(IP6_2_0, SCIF_CLK_B, SEL_SCIF_CLK_1),
+       PINMUX_IPSR_MODSEL_DATA(IP6_2_0, HRX0_D, SEL_HSCIF_3),
+       PINMUX_IPSR_MODSEL_DATA(IP6_2_0, IETX_A, SEL_IEBUS_0),
+       PINMUX_IPSR_MODSEL_DATA(IP6_2_0, TCLKA_A, SEL_MTU2_CLK_0),
+       PINMUX_IPSR_DATA(IP6_2_0, HIFD00),
+
+       PINMUX_IPSR_DATA(IP6_5_3, DU0_DR1),
+       PINMUX_IPSR_MODSEL_DATA(IP6_5_3, SCK0_B, SEL_SCIF0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP6_5_3, HTX0_D, SEL_HSCIF_3),
+       PINMUX_IPSR_MODSEL_DATA(IP6_5_3, IERX_A, SEL_IEBUS_0),
+       PINMUX_IPSR_MODSEL_DATA(IP6_5_3, TCLKB_A, SEL_MTU2_CLK_0),
+       PINMUX_IPSR_DATA(IP6_5_3, HIFD01),
+
+       PINMUX_IPSR_DATA(IP6_7_6, DU0_DR2),
+       PINMUX_IPSR_MODSEL_DATA(IP6_7_6, RX0_B, SEL_SCIF0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP6_7_6, TCLKC_A, SEL_MTU2_CLK_0),
+       PINMUX_IPSR_DATA(IP6_7_6, HIFD02),
+
+       PINMUX_IPSR_DATA(IP6_9_8, DU0_DR3),
+       PINMUX_IPSR_MODSEL_DATA(IP6_9_8, TX0_B, SEL_SCIF0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP6_9_8, TCLKD_A, SEL_MTU2_CLK_0),
+       PINMUX_IPSR_DATA(IP6_9_8, HIFD03),
+
+       PINMUX_IPSR_DATA(IP6_11_10, DU0_DR4),
+       PINMUX_IPSR_MODSEL_DATA(IP6_11_10, CTS0_C, SEL_SCIF0_2),
+       PINMUX_IPSR_MODSEL_DATA(IP6_11_10, TIOC0A_A, SEL_MTU2_CH0_0),
+       PINMUX_IPSR_DATA(IP6_11_10, HIFD04),
+
+       PINMUX_IPSR_DATA(IP6_13_12, DU0_DR5),
+       PINMUX_IPSR_MODSEL_DATA(IP6_13_12, RTS0_C, SEL_SCIF0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP6_13_12, TIOC0B_A, SEL_MTU2_CH0_0),
+       PINMUX_IPSR_DATA(IP6_13_12, HIFD05),
+
+       PINMUX_IPSR_DATA(IP6_15_14, DU0_DR6),
+       PINMUX_IPSR_MODSEL_DATA(IP6_15_14, SCK1_C, SEL_SCIF1_2),
+       PINMUX_IPSR_MODSEL_DATA(IP6_15_14, TIOC0C_A, SEL_MTU2_CH0_0),
+       PINMUX_IPSR_DATA(IP6_15_14, HIFD06),
+
+       PINMUX_IPSR_DATA(IP6_17_16, DU0_DR7),
+       PINMUX_IPSR_MODSEL_DATA(IP6_17_16, RX1_C, SEL_SCIF1_2),
+       PINMUX_IPSR_MODSEL_DATA(IP6_17_16, TIOC0D_A, SEL_MTU2_CH0_0),
+       PINMUX_IPSR_DATA(IP6_17_16, HIFD07),
+
+       PINMUX_IPSR_DATA(IP6_20_18, DU0_DG0),
+       PINMUX_IPSR_MODSEL_DATA(IP6_20_18, TX1_C, SEL_SCIF1_2),
+       PINMUX_IPSR_MODSEL_DATA(IP6_20_18, HSCK0_D, SEL_HSCIF_3),
+       PINMUX_IPSR_MODSEL_DATA(IP6_20_18, IECLK_A, SEL_IEBUS_0),
+       PINMUX_IPSR_MODSEL_DATA(IP6_20_18, TIOC1A_A, SEL_MTU2_CH1_0),
+       PINMUX_IPSR_DATA(IP6_20_18, HIFD08),
+
+       PINMUX_IPSR_DATA(IP6_23_21, DU0_DG1),
+       PINMUX_IPSR_MODSEL_DATA(IP6_23_21, CTS1_C, SEL_SCIF1_2),
+       PINMUX_IPSR_MODSEL_DATA(IP6_23_21, HRTS0_D, SEL_HSCIF_3),
+       PINMUX_IPSR_MODSEL_DATA(IP6_23_21, TIOC1B_A, SEL_MTU2_CH1_0),
+       PINMUX_IPSR_DATA(IP6_23_21, HIFD09),
+
+       /* IPSR7 */
+       PINMUX_IPSR_DATA(IP7_2_0, DU0_DG2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_2_0, RTS1_C, SEL_SCIF1_2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_2_0, RMII0_MDC_B, SEL_RMII_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_2_0, TIOC2A_A, SEL_MTU2_CH2_0),
+       PINMUX_IPSR_DATA(IP7_2_0, HIFD10),
+
+       PINMUX_IPSR_DATA(IP7_5_3, DU0_DG3),
+       PINMUX_IPSR_MODSEL_DATA(IP7_5_3, SCK2_C, SEL_SCIF2_2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_5_3, RMII0_MDIO_B, SEL_RMII_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_5_3, TIOC2B_A, SEL_MTU2_CH2_0),
+       PINMUX_IPSR_DATA(IP7_5_3, HIFD11),
+
+       PINMUX_IPSR_DATA(IP7_8_6, DU0_DG4),
+       PINMUX_IPSR_MODSEL_DATA(IP7_8_6, RX2_C, SEL_SCIF2_2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_8_6, RMII0_CRS_DV_B, SEL_RMII_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_8_6, TIOC3A_A, SEL_MTU2_CH3_0),
+       PINMUX_IPSR_DATA(IP7_8_6, HIFD12),
+
+       PINMUX_IPSR_DATA(IP7_11_9, DU0_DG5),
+       PINMUX_IPSR_MODSEL_DATA(IP7_11_9, TX2_C, SEL_SCIF2_2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_11_9, RMII0_RX_ER_B, SEL_RMII_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_11_9, TIOC3B_A, SEL_MTU2_CH3_0),
+       PINMUX_IPSR_DATA(IP7_11_9, HIFD13),
+
+       PINMUX_IPSR_DATA(IP7_14_12, DU0_DG6),
+       PINMUX_IPSR_MODSEL_DATA(IP7_14_12, RX3_C, SEL_SCIF3_2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_14_12, RMII0_RXD0_B, SEL_RMII_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_14_12, TIOC3C_A, SEL_MTU2_CH3_0),
+       PINMUX_IPSR_DATA(IP7_14_12, HIFD14),
+
+       PINMUX_IPSR_DATA(IP7_17_15, DU0_DG7),
+       PINMUX_IPSR_MODSEL_DATA(IP7_17_15, TX3_C, SEL_SCIF3_2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_17_15, RMII0_RXD1_B, SEL_RMII_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_17_15, TIOC3D_A, SEL_MTU2_CH3_0),
+       PINMUX_IPSR_DATA(IP7_17_15, HIFD15),
+
+       PINMUX_IPSR_DATA(IP7_20_18, DU0_DB0),
+       PINMUX_IPSR_MODSEL_DATA(IP7_20_18, RX4_C, SEL_SCIF4_2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_20_18, RMII0_TXD_EN_B, SEL_RMII_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_20_18, TIOC4A_A, SEL_MTU2_CH4_0),
+       PINMUX_IPSR_DATA(IP7_20_18, HIFCS),
+
+       PINMUX_IPSR_DATA(IP7_23_21, DU0_DB1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_23_21, TX4_C, SEL_SCIF4_2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_23_21, RMII0_TXD0_B, SEL_RMII_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_23_21, TIOC4B_A, SEL_MTU2_CH4_0),
+       PINMUX_IPSR_DATA(IP7_23_21, HIFWR),
+
+       PINMUX_IPSR_DATA(IP7_26_24, DU0_DB2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_26_24, RX5_B, SEL_SCIF5_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_26_24, RMII0_TXD1_B, SEL_RMII_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_26_24, TIOC4C_A, SEL_MTU2_CH4_0),
+
+       PINMUX_IPSR_DATA(IP7_28_27, DU0_DB3),
+       PINMUX_IPSR_MODSEL_DATA(IP7_28_27, TX5_B, SEL_SCIF5_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_28_27, TIOC4D_A, SEL_MTU2_CH4_0),
+       PINMUX_IPSR_DATA(IP7_28_27, HIFRD),
+
+       PINMUX_IPSR_DATA(IP7_30_29, DU0_DB4),
+       PINMUX_IPSR_DATA(IP7_30_29, HIFINT),
+
+       /* IPSR8 */
+       PINMUX_IPSR_DATA(IP8_1_0, DU0_DB5),
+       PINMUX_IPSR_DATA(IP8_1_0, HIFDREQ),
+
+       PINMUX_IPSR_DATA(IP8_3_2, DU0_DB6),
+       PINMUX_IPSR_DATA(IP8_3_2, HIFRDY),
+
+       PINMUX_IPSR_DATA(IP8_5_4, DU0_DB7),
+       PINMUX_IPSR_MODSEL_DATA(IP8_5_4, SSI_SCK0_B, SEL_SSI0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_5_4, HIFEBL_B, SEL_HIF_1),
+
+       PINMUX_IPSR_DATA(IP8_7_6, DU0_DOTCLKIN),
+       PINMUX_IPSR_MODSEL_DATA(IP8_7_6, HSPI_CS0_C, SEL_HSPI_2),
+       PINMUX_IPSR_MODSEL_DATA(IP8_7_6, SSI_WS0_B, SEL_SSI0_1),
+
+       PINMUX_IPSR_DATA(IP8_9_8, DU0_DOTCLKOUT),
+       PINMUX_IPSR_MODSEL_DATA(IP8_9_8, HSPI_CLK0_C, SEL_HSPI_2),
+       PINMUX_IPSR_MODSEL_DATA(IP8_9_8, SSI_SDATA0_B, SEL_SSI0_1),
+
+       PINMUX_IPSR_DATA(IP8_11_10, DU0_EXHSYNC_DU0_HSYNC),
+       PINMUX_IPSR_MODSEL_DATA(IP8_11_10, HSPI_TX0_C, SEL_HSPI_2),
+       PINMUX_IPSR_MODSEL_DATA(IP8_11_10, SSI_SCK1_B, SEL_SSI1_1),
+
+       PINMUX_IPSR_DATA(IP8_13_12, DU0_EXVSYNC_DU0_VSYNC),
+       PINMUX_IPSR_MODSEL_DATA(IP8_13_12, HSPI_RX0_C, SEL_HSPI_2),
+       PINMUX_IPSR_MODSEL_DATA(IP8_13_12, SSI_WS1_B, SEL_SSI1_1),
+
+       PINMUX_IPSR_DATA(IP8_15_14, DU0_EXODDF_DU0_ODDF),
+       PINMUX_IPSR_MODSEL_DATA(IP8_15_14, CAN0_RX_B, SEL_RCAN0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_15_14, HSCK0_B, SEL_HSCIF_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_15_14, SSI_SDATA1_B, SEL_SSI1_1),
+
+       PINMUX_IPSR_DATA(IP8_17_16, DU0_DISP),
+       PINMUX_IPSR_MODSEL_DATA(IP8_17_16, CAN0_TX_B, SEL_RCAN0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_17_16, HRX0_B, SEL_HSCIF_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_17_16, AUDIO_CLKA_B, SEL_AUDIO_CLKA_1),
+
+       PINMUX_IPSR_DATA(IP8_19_18, DU0_CDE),
+       PINMUX_IPSR_MODSEL_DATA(IP8_19_18, HTX0_B, SEL_HSCIF_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_19_18, AUDIO_CLKB_B, SEL_AUDIO_CLKB_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_19_18, LCD_VCPWC_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP8_22_20, IRQ0_A, SEL_INTC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP8_22_20, HSPI_TX_B, SEL_HSPI_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_22_20, RX3_E, SEL_SCIF3_4),
+       PINMUX_IPSR_DATA(IP8_22_20, ET0_ERXD0),
+
+       PINMUX_IPSR_MODSEL_DATA(IP8_25_23, IRQ1_A, SEL_INTC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP8_25_23, HSPI_RX_B, SEL_HSPI_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_25_23, TX3_E, SEL_SCIF3_4),
+       PINMUX_IPSR_DATA(IP8_25_23, ET0_ERXD1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP8_27_26, IRQ2_A, SEL_INTC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP8_27_26, CTS0_A, SEL_SCIF0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP8_27_26, HCTS0_B, SEL_HSCIF_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_27_26, ET0_ERXD2_A, SEL_ET0_0),
+
+       PINMUX_IPSR_MODSEL_DATA(IP8_29_28, IRQ3_A, SEL_INTC_0),
+       PINMUX_IPSR_MODSEL_DATA(IP8_29_28, RTS0_A, SEL_SCIF0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP8_29_28, HRTS0_B, SEL_HSCIF_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_29_28, ET0_ERXD3_A, SEL_ET0_0),
+
+       /* IPSR9 */
+       PINMUX_IPSR_MODSEL_DATA(IP9_1_0, VI1_CLK_A, SEL_VIN1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_1_0, FD0_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_1_0, LCD_DATA0_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_3_2, VI1_0_A, SEL_VIN1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_3_2, FD1_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_3_2, LCD_DATA1_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_5_4, VI1_1_A, SEL_VIN1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_5_4, FD2_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_5_4, LCD_DATA2_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_7_6, VI1_2_A, SEL_VIN1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_7_6, FD3_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_7_6, LCD_DATA3_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_9_8, VI1_3_A, SEL_VIN1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_9_8, FD4_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_9_8, LCD_DATA4_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_11_10, VI1_4_A, SEL_VIN1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_11_10, FD5_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_11_10, LCD_DATA5_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_13_12, VI1_5_A, SEL_VIN1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_13_12, FD6_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_13_12, LCD_DATA6_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_15_14, VI1_6_A, SEL_VIN1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_15_14, FD7_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_15_14, LCD_DATA7_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_17_16, VI1_7_A, SEL_VIN1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_17_16, FCE_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_17_16, LCD_DATA8_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_19_18, SSI_SCK0_A, SEL_SSI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_19_18, TIOC1A_B, SEL_MTU2_CH1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_19_18, LCD_DATA9_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_21_20, SSI_WS0_A, SEL_SSI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_21_20, TIOC1B_B, SEL_MTU2_CH1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_21_20, LCD_DATA10_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_23_22, SSI_SDATA0_A, SEL_SSI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_23_22, VI1_0_B, SEL_VIN1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_23_22, TIOC2A_B, SEL_MTU2_CH2_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_23_22, LCD_DATA11_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_25_24, SSI_SCK1_A, SEL_SSI1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_25_24, VI1_1_B, SEL_VIN1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_25_24, TIOC2B_B, SEL_MTU2_CH2_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_25_24, LCD_DATA12_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_27_26, SSI_WS1_A, SEL_SSI1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_27_26, VI1_2_B, SEL_VIN1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_27_26, LCD_DATA13_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_29_28, SSI_SDATA1_A, SEL_SSI1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_29_28, VI1_3_B, SEL_VIN1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_29_28, LCD_DATA14_B, SEL_LCDC_1),
+
+       /* IPSE10 */
+       PINMUX_IPSR_DATA(IP10_2_0, SSI_SCK23),
+       PINMUX_IPSR_MODSEL_DATA(IP10_2_0, VI1_4_B, SEL_VIN1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_2_0, RX1_D, SEL_SCIF1_3),
+       PINMUX_IPSR_MODSEL_DATA(IP10_2_0, FCLE_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_2_0, LCD_DATA15_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_DATA(IP10_5_3, SSI_WS23),
+       PINMUX_IPSR_MODSEL_DATA(IP10_5_3, VI1_5_B, SEL_VIN1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_5_3, TX1_D, SEL_SCIF1_3),
+       PINMUX_IPSR_MODSEL_DATA(IP10_5_3, HSCK0_C, SEL_HSCIF_2),
+       PINMUX_IPSR_MODSEL_DATA(IP10_5_3, FALE_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_5_3, LCD_DON_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_DATA(IP10_8_6, SSI_SDATA2),
+       PINMUX_IPSR_MODSEL_DATA(IP10_8_6, VI1_6_B, SEL_VIN1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_8_6, HRX0_C, SEL_HSCIF_2),
+       PINMUX_IPSR_MODSEL_DATA(IP10_8_6, FRE_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_8_6, LCD_CL1_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_DATA(IP10_11_9, SSI_SDATA3),
+       PINMUX_IPSR_MODSEL_DATA(IP10_11_9, VI1_7_B, SEL_VIN1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_11_9, HTX0_C, SEL_HSCIF_2),
+       PINMUX_IPSR_MODSEL_DATA(IP10_11_9, FWE_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_11_9, LCD_CL2_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP10_14_12, AUDIO_CLKA_A, SEL_AUDIO_CLKA_0),
+       PINMUX_IPSR_MODSEL_DATA(IP10_14_12, VI1_CLK_B, SEL_VIN1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_14_12, SCK1_D, SEL_SCIF1_3),
+       PINMUX_IPSR_MODSEL_DATA(IP10_14_12, IECLK_B, SEL_IEBUS_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_14_12, LCD_FLM_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP10_15, AUDIO_CLKB_A, SEL_AUDIO_CLKB_0),
+       PINMUX_IPSR_MODSEL_DATA(IP10_15, LCD_CLK_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_DATA(IP10_18_16, AUDIO_CLKC),
+       PINMUX_IPSR_MODSEL_DATA(IP10_18_16, SCK1_E, SEL_SCIF1_4),
+       PINMUX_IPSR_MODSEL_DATA(IP10_18_16, HCTS0_C, SEL_HSCIF_2),
+       PINMUX_IPSR_MODSEL_DATA(IP10_18_16, FRB_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_18_16, LCD_VEPWC_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_DATA(IP10_21_19, AUDIO_CLKOUT),
+       PINMUX_IPSR_MODSEL_DATA(IP10_21_19, TX1_E, SEL_SCIF1_4),
+       PINMUX_IPSR_MODSEL_DATA(IP10_21_19, HRTS0_C, SEL_HSCIF_2),
+       PINMUX_IPSR_MODSEL_DATA(IP10_21_19, FSE_B, SEL_FLCTL_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_21_19, LCD_M_DISP_B, SEL_LCDC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP10_22, CAN_CLK_A, SEL_RCAN_CLK_0),
+       PINMUX_IPSR_MODSEL_DATA(IP10_22, RX4_D, SEL_SCIF4_3),
+
+       PINMUX_IPSR_MODSEL_DATA(IP10_24_23, CAN0_TX_A, SEL_RCAN0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP10_24_23, TX4_D, SEL_SCIF4_3),
+       PINMUX_IPSR_DATA(IP10_24_23, MLB_CLK),
+
+       PINMUX_IPSR_MODSEL_DATA(IP10_25, CAN1_RX_A, SEL_RCAN1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP10_25, IRQ1_B, SEL_INTC_1),
+
+       PINMUX_IPSR_MODSEL_DATA(IP10_27_26, CAN0_RX_A, SEL_RCAN0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP10_27_26, IRQ0_B, SEL_INTC_1),
+       PINMUX_IPSR_DATA(IP10_27_26, MLB_SIG),
+
+       PINMUX_IPSR_MODSEL_DATA(IP10_29_28, CAN1_TX_A, SEL_RCAN1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP10_29_28, TX5_C, SEL_SCIF1_2),
+       PINMUX_IPSR_DATA(IP10_29_28, MLB_DAT),
+
+       /* IPSR11 */
+       PINMUX_IPSR_DATA(IP11_0, SCL1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_0, SCIF_CLK_C, SEL_SCIF_CLK_2),
+
+       PINMUX_IPSR_DATA(IP11_1, SDA1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_0, RX1_E, SEL_SCIF1_4),
+
+       PINMUX_IPSR_DATA(IP11_2, SDA0),
+       PINMUX_IPSR_MODSEL_DATA(IP11_2, HIFEBL_A, SEL_HIF_0),
+
+       PINMUX_IPSR_DATA(IP11_3, SDSELF),
+       PINMUX_IPSR_MODSEL_DATA(IP11_3, RTS1_E, SEL_SCIF1_3),
+
+       PINMUX_IPSR_MODSEL_DATA(IP11_6_4, SCIF_CLK_A, SEL_SCIF_CLK_0),
+       PINMUX_IPSR_MODSEL_DATA(IP11_6_4, HSPI_CLK_A, SEL_HSPI_0),
+       PINMUX_IPSR_DATA(IP11_6_4, VI0_CLK),
+       PINMUX_IPSR_MODSEL_DATA(IP11_6_4, RMII0_TXD0_A, SEL_RMII_0),
+       PINMUX_IPSR_DATA(IP11_6_4, ET0_ERXD4),
+
+       PINMUX_IPSR_MODSEL_DATA(IP11_9_7, SCK0_A, SEL_SCIF0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP11_9_7, HSPI_CS_A, SEL_HSPI_0),
+       PINMUX_IPSR_DATA(IP11_9_7, VI0_CLKENB),
+       PINMUX_IPSR_MODSEL_DATA(IP11_9_7, RMII0_TXD1_A, SEL_RMII_0),
+       PINMUX_IPSR_DATA(IP11_9_7, ET0_ERXD5),
+
+       PINMUX_IPSR_MODSEL_DATA(IP11_11_10, RX0_A, SEL_SCIF0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP11_11_10, HSPI_RX_A, SEL_HSPI_0),
+       PINMUX_IPSR_MODSEL_DATA(IP11_11_10, RMII0_RXD0_A, SEL_RMII_0),
+       PINMUX_IPSR_DATA(IP11_11_10, ET0_ERXD6),
+
+       PINMUX_IPSR_MODSEL_DATA(IP11_12, TX0_A, SEL_SCIF0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP11_12, HSPI_TX_A, SEL_HSPI_0),
+
+       PINMUX_IPSR_DATA(IP11_15_13, PENC1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_15_13, TX3_D, SEL_SCIF3_3),
+       PINMUX_IPSR_MODSEL_DATA(IP11_15_13, CAN1_TX_B,  SEL_RCAN1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_15_13, TX5_D, SEL_SCIF5_3),
+       PINMUX_IPSR_MODSEL_DATA(IP11_15_13, IETX_B, SEL_IEBUS_1),
+
+       PINMUX_IPSR_DATA(IP11_18_16, USB_OVC1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_18_16, RX3_D, SEL_SCIF3_3),
+       PINMUX_IPSR_MODSEL_DATA(IP11_18_16, CAN1_RX_B, SEL_RCAN1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_18_16, RX5_D, SEL_SCIF5_3),
+       PINMUX_IPSR_MODSEL_DATA(IP11_18_16, IERX_B, SEL_IEBUS_1),
+
+       PINMUX_IPSR_DATA(IP11_20_19, DREQ0),
+       PINMUX_IPSR_MODSEL_DATA(IP11_20_19, SD1_CLK_A, SEL_SDHI1_0),
+       PINMUX_IPSR_DATA(IP11_20_19, ET0_TX_EN),
+
+       PINMUX_IPSR_DATA(IP11_22_21, DACK0),
+       PINMUX_IPSR_MODSEL_DATA(IP11_22_21, SD1_DAT3_A, SEL_SDHI1_0),
+       PINMUX_IPSR_DATA(IP11_22_21, ET0_TX_ER),
+
+       PINMUX_IPSR_DATA(IP11_25_23, DREQ1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_25_23, HSPI_CLK_B, SEL_HSPI_1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_25_23, RX4_B, SEL_SCIF4_1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_25_23, ET0_PHY_INT_C, SEL_ET0_CTL_0),
+       PINMUX_IPSR_MODSEL_DATA(IP11_25_23, ET0_TX_CLK_A, SEL_ET0_0),
+
+       PINMUX_IPSR_DATA(IP11_27_26, DACK1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_27_26, HSPI_CS_B, SEL_HSPI_1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_27_26, TX4_B, SEL_SCIF3_1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_27_26, ET0_RX_CLK_A, SEL_ET0_0),
+
+       PINMUX_IPSR_DATA(IP11_28, PRESETOUT),
+       PINMUX_IPSR_DATA(IP11_28, ST_CLKOUT),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+       PINMUX_GPIO_GP_ALL(),
+
+       GPIO_FN(CLKOUT), GPIO_FN(BS), GPIO_FN(CS0), GPIO_FN(EX_CS0),
+       GPIO_FN(RD), GPIO_FN(WE0), GPIO_FN(WE1),
+       GPIO_FN(SCL0), GPIO_FN(PENC0), GPIO_FN(USB_OVC0),
+       GPIO_FN(IRQ2_B), GPIO_FN(IRQ3_B),
+
+       /* IPSR0 */
+       GPIO_FN(A0), GPIO_FN(ST0_CLKIN), GPIO_FN(LCD_DATA0_A),
+       GPIO_FN(TCLKA_C),
+       GPIO_FN(A1), GPIO_FN(ST0_REQ), GPIO_FN(LCD_DATA1_A),
+       GPIO_FN(TCLKB_C),
+       GPIO_FN(A2), GPIO_FN(ST0_SYC), GPIO_FN(LCD_DATA2_A),
+       GPIO_FN(TCLKC_C),
+       GPIO_FN(A3), GPIO_FN(ST0_VLD), GPIO_FN(LCD_DATA3_A),
+       GPIO_FN(TCLKD_C),
+       GPIO_FN(A4), GPIO_FN(ST0_D0), GPIO_FN(LCD_DATA4_A),
+       GPIO_FN(TIOC0A_C),
+       GPIO_FN(A5), GPIO_FN(ST0_D1), GPIO_FN(LCD_DATA5_A),
+       GPIO_FN(TIOC0B_C),
+       GPIO_FN(A6), GPIO_FN(ST0_D2), GPIO_FN(LCD_DATA6_A),
+       GPIO_FN(TIOC0C_C),
+       GPIO_FN(A7), GPIO_FN(ST0_D3), GPIO_FN(LCD_DATA7_A),
+       GPIO_FN(TIOC0D_C),
+       GPIO_FN(A8), GPIO_FN(ST0_D4), GPIO_FN(LCD_DATA8_A),
+       GPIO_FN(TIOC1A_C),
+       GPIO_FN(A9), GPIO_FN(ST0_D5), GPIO_FN(LCD_DATA9_A),
+       GPIO_FN(TIOC1B_C),
+       GPIO_FN(A10), GPIO_FN(ST0_D6), GPIO_FN(LCD_DATA10_A),
+       GPIO_FN(TIOC2A_C),
+       GPIO_FN(A11), GPIO_FN(ST0_D7), GPIO_FN(LCD_DATA11_A),
+       GPIO_FN(TIOC2B_C),
+       GPIO_FN(A12), GPIO_FN(LCD_DATA12_A), GPIO_FN(TIOC3A_C),
+       GPIO_FN(A13), GPIO_FN(LCD_DATA13_A), GPIO_FN(TIOC3B_C),
+       GPIO_FN(A14), GPIO_FN(LCD_DATA14_A), GPIO_FN(TIOC3C_C),
+       GPIO_FN(A15), GPIO_FN(ST0_VCO_CLKIN), GPIO_FN(LCD_DATA15_A),
+       GPIO_FN(TIOC3D_C),
+
+       /* IPSR1 */
+       GPIO_FN(A16), GPIO_FN(ST0_PWM), GPIO_FN(LCD_DON_A),
+       GPIO_FN(TIOC4A_C),
+       GPIO_FN(A17), GPIO_FN(ST1_VCO_CLKIN), GPIO_FN(LCD_CL1_A),
+       GPIO_FN(TIOC4B_C),
+       GPIO_FN(A18), GPIO_FN(ST1_PWM), GPIO_FN(LCD_CL2_A),
+       GPIO_FN(TIOC4C_C),
+       GPIO_FN(A19), GPIO_FN(ST1_CLKIN), GPIO_FN(LCD_CLK_A),
+       GPIO_FN(TIOC4D_C),
+       GPIO_FN(A20), GPIO_FN(ST1_REQ), GPIO_FN(LCD_FLM_A),
+       GPIO_FN(A21), GPIO_FN(ST1_SYC), GPIO_FN(LCD_VCPWC_A),
+       GPIO_FN(A22), GPIO_FN(ST1_VLD), GPIO_FN(LCD_VEPWC_A),
+       GPIO_FN(A23), GPIO_FN(ST1_D0), GPIO_FN(LCD_M_DISP_A),
+       GPIO_FN(A24), GPIO_FN(RX2_D), GPIO_FN(ST1_D1),
+       GPIO_FN(A25), GPIO_FN(TX2_D), GPIO_FN(ST1_D2),
+       GPIO_FN(D0), GPIO_FN(SD0_DAT0_A), GPIO_FN(MMC_D0_A),
+       GPIO_FN(ST1_D3), GPIO_FN(FD0_A),
+       GPIO_FN(D1), GPIO_FN(SD0_DAT1_A), GPIO_FN(MMC_D1_A),
+       GPIO_FN(ST1_D4), GPIO_FN(FD1_A),
+       GPIO_FN(D2), GPIO_FN(SD0_DAT2_A), GPIO_FN(MMC_D2_A),
+       GPIO_FN(ST1_D5), GPIO_FN(FD2_A),
+       GPIO_FN(D3), GPIO_FN(SD0_DAT3_A), GPIO_FN(MMC_D3_A),
+       GPIO_FN(ST1_D6), GPIO_FN(FD3_A),
+
+       /* IPSR2 */
+       GPIO_FN(D4), GPIO_FN(SD0_CD_A), GPIO_FN(MMC_D4_A), GPIO_FN(ST1_D7),
+       GPIO_FN(FD4_A),
+       GPIO_FN(D5), GPIO_FN(SD0_WP_A), GPIO_FN(MMC_D5_A), GPIO_FN(FD5_A),
+       GPIO_FN(D6), GPIO_FN(RSPI_RSPCK_A), GPIO_FN(MMC_D6_A),
+               GPIO_FN(QSPCLK_A),
+       GPIO_FN(FD6_A),
+       GPIO_FN(D7), GPIO_FN(RSPI_SSL_A), GPIO_FN(MMC_D7_A), GPIO_FN(QSSL_A),
+       GPIO_FN(FD7_A),
+       GPIO_FN(D8), GPIO_FN(SD0_CLK_A), GPIO_FN(MMC_CLK_A), GPIO_FN(QIO2_A),
+       GPIO_FN(FCE_A), GPIO_FN(ET0_GTX_CLK_B),
+       GPIO_FN(D9), GPIO_FN(SD0_CMD_A), GPIO_FN(MMC_CMD_A), GPIO_FN(QIO3_A),
+       GPIO_FN(FCLE_A), GPIO_FN(ET0_ETXD1_B),
+       GPIO_FN(D10), GPIO_FN(RSPI_MOSI_A), GPIO_FN(QMO_QIO0_A),
+               GPIO_FN(FALE_A), GPIO_FN(ET0_ETXD2_B),
+       GPIO_FN(D11), GPIO_FN(RSPI_MISO_A), GPIO_FN(QMI_QIO1_A), GPIO_FN(FRE_A),
+               GPIO_FN(ET0_ETXD3_B),
+       GPIO_FN(D12), GPIO_FN(FWE_A), GPIO_FN(ET0_ETXD5_B),
+       GPIO_FN(D13), GPIO_FN(RX2_B), GPIO_FN(FRB_A), GPIO_FN(ET0_ETXD6_B),
+       GPIO_FN(D14), GPIO_FN(TX2_B), GPIO_FN(FSE_A), GPIO_FN(ET0_TX_CLK_B),
+
+       /* IPSR3 */
+       GPIO_FN(D15), GPIO_FN(SCK2_B),
+       GPIO_FN(CS1_A26), GPIO_FN(QIO3_B),
+       GPIO_FN(EX_CS1), GPIO_FN(RX3_B), GPIO_FN(ATACS0), GPIO_FN(QIO2_B),
+       GPIO_FN(ET0_ETXD0),
+       GPIO_FN(EX_CS2), GPIO_FN(TX3_B), GPIO_FN(ATACS1), GPIO_FN(QSPCLK_B),
+       GPIO_FN(ET0_GTX_CLK_A),
+       GPIO_FN(EX_CS3), GPIO_FN(SD1_CD_A), GPIO_FN(ATARD), GPIO_FN(QMO_QIO0_B),
+       GPIO_FN(ET0_ETXD1_A),
+       GPIO_FN(EX_CS4), GPIO_FN(SD1_WP_A), GPIO_FN(ATAWR), GPIO_FN(QMI_QIO1_B),
+       GPIO_FN(ET0_ETXD2_A),
+       GPIO_FN(EX_CS5), GPIO_FN(SD1_CMD_A), GPIO_FN(ATADIR), GPIO_FN(QSSL_B),
+       GPIO_FN(ET0_ETXD3_A),
+       GPIO_FN(RD_WR), GPIO_FN(TCLK1_B),
+       GPIO_FN(EX_WAIT0), GPIO_FN(TCLK1_B),
+       GPIO_FN(EX_WAIT1), GPIO_FN(SD1_DAT0_A), GPIO_FN(DREQ2),
+               GPIO_FN(CAN1_TX_C), GPIO_FN(ET0_LINK_C), GPIO_FN(ET0_ETXD5_A),
+       GPIO_FN(EX_WAIT2), GPIO_FN(SD1_DAT1_A), GPIO_FN(DACK2),
+               GPIO_FN(CAN1_RX_C), GPIO_FN(ET0_MAGIC_C), GPIO_FN(ET0_ETXD6_A),
+       GPIO_FN(DRACK0), GPIO_FN(SD1_DAT2_A), GPIO_FN(ATAG), GPIO_FN(TCLK1_A),
+       GPIO_FN(ET0_ETXD7),
+
+       /* IPSR4 */
+       GPIO_FN(HCTS0_A), GPIO_FN(CTS1_A), GPIO_FN(VI0_FIELD),
+               GPIO_FN(RMII0_RXD1_A), GPIO_FN(ET0_ERXD7),
+       GPIO_FN(HRTS0_A), GPIO_FN(RTS1_A), GPIO_FN(VI0_HSYNC),
+               GPIO_FN(RMII0_TXD_EN_A), GPIO_FN(ET0_RX_DV),
+       GPIO_FN(HSCK0_A), GPIO_FN(SCK1_A), GPIO_FN(VI0_VSYNC),
+               GPIO_FN(RMII0_RX_ER_A), GPIO_FN(ET0_RX_ER),
+       GPIO_FN(HRX0_A), GPIO_FN(RX1_A), GPIO_FN(VI0_DATA0_VI0_B0),
+               GPIO_FN(RMII0_CRS_DV_A), GPIO_FN(ET0_CRS),
+       GPIO_FN(HTX0_A), GPIO_FN(TX1_A), GPIO_FN(VI0_DATA1_VI0_B1),
+               GPIO_FN(RMII0_MDC_A), GPIO_FN(ET0_COL),
+       GPIO_FN(CTS0_B), GPIO_FN(VI0_DATA2_VI0_B2), GPIO_FN(RMII0_MDIO_A),
+               GPIO_FN(ET0_MDC),
+       GPIO_FN(RTS0_B), GPIO_FN(VI0_DATA3_VI0_B3), GPIO_FN(ET0_MDIO_A),
+       GPIO_FN(SCK1_B), GPIO_FN(VI0_DATA4_VI0_B4), GPIO_FN(ET0_LINK_A),
+       GPIO_FN(RX1_B), GPIO_FN(VI0_DATA5_VI0_B5), GPIO_FN(ET0_MAGIC_A),
+       GPIO_FN(TX1_B), GPIO_FN(VI0_DATA6_VI0_G0), GPIO_FN(ET0_PHY_INT_A),
+       GPIO_FN(CTS1_B), GPIO_FN(VI0_DATA7_VI0_G1),
+       GPIO_FN(RTS1_B), GPIO_FN(VI0_G2),
+       GPIO_FN(SCK2_A), GPIO_FN(VI0_G3),
+
+       /* IPSR5 */
+       GPIO_FN(REF50CK), GPIO_FN(CTS1_E), GPIO_FN(HCTS0_D),
+       GPIO_FN(REF125CK), GPIO_FN(ADTRG), GPIO_FN(RX5_C),
+       GPIO_FN(SD2_WP_A), GPIO_FN(TX5_A), GPIO_FN(VI0_R5),
+       GPIO_FN(SD2_CD_A), GPIO_FN(RX5_A), GPIO_FN(VI0_R4),
+               GPIO_FN(ET0_PHY_INT_B),
+       GPIO_FN(SD2_DAT3_A), GPIO_FN(TX4_A), GPIO_FN(VI0_R3),
+               GPIO_FN(ET0_MAGIC_B),
+       GPIO_FN(SD2_DAT2_A), GPIO_FN(RX4_A), GPIO_FN(VI0_R2),
+               GPIO_FN(ET0_LINK_B),
+       GPIO_FN(SD2_DAT1_A), GPIO_FN(TX3_A), GPIO_FN(VI0_R1),
+               GPIO_FN(ET0_MDIO_B),
+       GPIO_FN(SD2_DAT0_A), GPIO_FN(RX3_A), GPIO_FN(VI0_R0),
+               GPIO_FN(ET0_ERXD3_B),
+       GPIO_FN(SD2_CMD_A), GPIO_FN(TX2_A), GPIO_FN(VI0_G5),
+               GPIO_FN(ET0_ERXD2_B),
+       GPIO_FN(SD2_CLK_A), GPIO_FN(RX2_A), GPIO_FN(VI0_G4),
+               GPIO_FN(ET0_RX_CLK_B),
+
+       /* IPSR6 */
+       GPIO_FN(DU0_DG1), GPIO_FN(CTS1_C), GPIO_FN(HRTS0_D),
+               GPIO_FN(TIOC1B_A), GPIO_FN(HIFD09),
+       GPIO_FN(DU0_DG0), GPIO_FN(TX1_C), GPIO_FN(HSCK0_D),
+               GPIO_FN(IECLK_A), GPIO_FN(TIOC1A_A), GPIO_FN(HIFD08),
+       GPIO_FN(DU0_DR7), GPIO_FN(RX1_C), GPIO_FN(TIOC0D_A),
+               GPIO_FN(HIFD07),
+       GPIO_FN(DU0_DR6), GPIO_FN(SCK1_C), GPIO_FN(TIOC0C_A),
+               GPIO_FN(HIFD06),
+       GPIO_FN(DU0_DR5), GPIO_FN(RTS0_C), GPIO_FN(TIOC0B_A),
+               GPIO_FN(HIFD05),
+       GPIO_FN(DU0_DR4), GPIO_FN(CTS0_C), GPIO_FN(TIOC0A_A),
+               GPIO_FN(HIFD04),
+       GPIO_FN(DU0_DR3), GPIO_FN(TX0_B), GPIO_FN(TCLKD_A), GPIO_FN(HIFD03),
+       GPIO_FN(DU0_DR2), GPIO_FN(RX0_B), GPIO_FN(TCLKC_A), GPIO_FN(HIFD02),
+       GPIO_FN(DU0_DR1), GPIO_FN(SCK0_B), GPIO_FN(HTX0_D),
+               GPIO_FN(IERX_A), GPIO_FN(TCLKB_A), GPIO_FN(HIFD01),
+       GPIO_FN(DU0_DR0), GPIO_FN(SCIF_CLK_B), GPIO_FN(HRX0_D),
+               GPIO_FN(IETX_A), GPIO_FN(TCLKA_A), GPIO_FN(HIFD00),
+
+       /* IPSR7 */
+       GPIO_FN(DU0_DB4), GPIO_FN(HIFINT),
+       GPIO_FN(DU0_DB3), GPIO_FN(TX5_B), GPIO_FN(TIOC4D_A), GPIO_FN(HIFRD),
+       GPIO_FN(DU0_DB2), GPIO_FN(RX5_B), GPIO_FN(RMII0_TXD1_B),
+               GPIO_FN(TIOC4C_A), GPIO_FN(HIFWR),
+       GPIO_FN(DU0_DB1), GPIO_FN(TX4_C), GPIO_FN(RMII0_TXD0_B),
+               GPIO_FN(TIOC4B_A), GPIO_FN(HIFRS),
+       GPIO_FN(DU0_DB0), GPIO_FN(RX4_C), GPIO_FN(RMII0_TXD_EN_B),
+               GPIO_FN(TIOC4A_A), GPIO_FN(HIFCS),
+       GPIO_FN(DU0_DG7), GPIO_FN(TX3_C), GPIO_FN(RMII0_RXD1_B),
+               GPIO_FN(TIOC3D_A), GPIO_FN(HIFD15),
+       GPIO_FN(DU0_DG6), GPIO_FN(RX3_C), GPIO_FN(RMII0_RXD0_B),
+               GPIO_FN(TIOC3C_A), GPIO_FN(HIFD14),
+       GPIO_FN(DU0_DG5), GPIO_FN(TX2_C), GPIO_FN(RMII0_RX_ER_B),
+               GPIO_FN(TIOC3B_A), GPIO_FN(HIFD13),
+       GPIO_FN(DU0_DG4), GPIO_FN(RX2_C), GPIO_FN(RMII0_CRS_DV_B),
+               GPIO_FN(TIOC3A_A), GPIO_FN(HIFD12),
+       GPIO_FN(DU0_DG3), GPIO_FN(SCK2_C), GPIO_FN(RMII0_MDIO_B),
+               GPIO_FN(TIOC2B_A), GPIO_FN(HIFD11),
+       GPIO_FN(DU0_DG2), GPIO_FN(RTS1_C), GPIO_FN(RMII0_MDC_B),
+               GPIO_FN(TIOC2A_A), GPIO_FN(HIFD10),
+
+       /* IPSR8 */
+       GPIO_FN(IRQ3_A), GPIO_FN(RTS0_A), GPIO_FN(HRTS0_B),
+               GPIO_FN(ET0_ERXD3_A),
+       GPIO_FN(IRQ2_A), GPIO_FN(CTS0_A), GPIO_FN(HCTS0_B),
+               GPIO_FN(ET0_ERXD2_A),
+       GPIO_FN(IRQ1_A), GPIO_FN(HSPI_RX_B), GPIO_FN(TX3_E),
+               GPIO_FN(ET0_ERXD1),
+       GPIO_FN(IRQ0_A), GPIO_FN(HSPI_TX_B), GPIO_FN(RX3_E),
+               GPIO_FN(ET0_ERXD0),
+       GPIO_FN(DU0_CDE), GPIO_FN(HTX0_B), GPIO_FN(AUDIO_CLKB_B),
+               GPIO_FN(LCD_VCPWC_B),
+       GPIO_FN(DU0_DISP), GPIO_FN(CAN0_TX_B), GPIO_FN(HRX0_B),
+               GPIO_FN(AUDIO_CLKA_B),
+       GPIO_FN(DU0_EXODDF_DU0_ODDF), GPIO_FN(CAN0_RX_B), GPIO_FN(HSCK0_B),
+               GPIO_FN(SSI_SDATA1_B),
+       GPIO_FN(DU0_EXVSYNC_DU0_VSYNC), GPIO_FN(HSPI_RX0_C),
+               GPIO_FN(SSI_WS1_B),
+       GPIO_FN(DU0_EXHSYNC_DU0_HSYNC), GPIO_FN(HSPI_TX0_C),
+               GPIO_FN(SSI_SCK1_B),
+       GPIO_FN(DU0_DOTCLKOUT), GPIO_FN(HSPI_CLK0_C),
+               GPIO_FN(SSI_SDATA0_B),
+       GPIO_FN(DU0_DOTCLKIN), GPIO_FN(HSPI_CS0_C),
+               GPIO_FN(SSI_WS0_B),
+       GPIO_FN(DU0_DB7), GPIO_FN(SSI_SCK0_B), GPIO_FN(HIFEBL_B),
+       GPIO_FN(DU0_DB6), GPIO_FN(HIFRDY),
+       GPIO_FN(DU0_DB5), GPIO_FN(HIFDREQ),
+
+       /* IPSR9 */
+       GPIO_FN(SSI_SDATA1_A), GPIO_FN(VI1_3_B), GPIO_FN(LCD_DATA14_B),
+       GPIO_FN(SSI_WS1_A), GPIO_FN(VI1_2_B), GPIO_FN(LCD_DATA13_B),
+       GPIO_FN(SSI_SCK1_A), GPIO_FN(VI1_1_B), GPIO_FN(TIOC2B_B),
+               GPIO_FN(LCD_DATA12_B),
+       GPIO_FN(SSI_SDATA0_A), GPIO_FN(VI1_0_B), GPIO_FN(TIOC2A_B),
+               GPIO_FN(LCD_DATA11_B),
+       GPIO_FN(SSI_WS0_A), GPIO_FN(TIOC1B_B), GPIO_FN(LCD_DATA10_B),
+       GPIO_FN(SSI_SCK0_A), GPIO_FN(TIOC1A_B), GPIO_FN(LCD_DATA9_B),
+       GPIO_FN(VI1_7_A), GPIO_FN(FCE_B), GPIO_FN(LCD_DATA8_B),
+       GPIO_FN(VI1_6_A), GPIO_FN(FD7_B), GPIO_FN(LCD_DATA7_B),
+       GPIO_FN(VI1_5_A), GPIO_FN(FD6_B), GPIO_FN(LCD_DATA6_B),
+       GPIO_FN(VI1_4_A), GPIO_FN(FD5_B), GPIO_FN(LCD_DATA5_B),
+       GPIO_FN(VI1_3_A), GPIO_FN(FD4_B), GPIO_FN(LCD_DATA4_B),
+       GPIO_FN(VI1_2_A), GPIO_FN(FD3_B), GPIO_FN(LCD_DATA3_B),
+       GPIO_FN(VI1_1_A), GPIO_FN(FD2_B), GPIO_FN(LCD_DATA2_B),
+       GPIO_FN(VI1_0_A), GPIO_FN(FD1_B), GPIO_FN(LCD_DATA1_B),
+       GPIO_FN(VI1_CLK_A), GPIO_FN(FD0_B), GPIO_FN(LCD_DATA0_B),
+
+       /* IPSR10 */
+       GPIO_FN(CAN1_TX_A), GPIO_FN(TX5_C), GPIO_FN(MLB_DAT),
+       GPIO_FN(CAN0_RX_A), GPIO_FN(IRQ0_B), GPIO_FN(MLB_SIG),
+       GPIO_FN(CAN1_RX_A), GPIO_FN(IRQ1_B),
+       GPIO_FN(CAN0_TX_A), GPIO_FN(TX4_D), GPIO_FN(MLB_CLK),
+       GPIO_FN(CAN_CLK_A), GPIO_FN(RX4_D),
+       GPIO_FN(AUDIO_CLKOUT), GPIO_FN(TX1_E), GPIO_FN(HRTS0_C),
+               GPIO_FN(FSE_B), GPIO_FN(LCD_M_DISP_B),
+       GPIO_FN(AUDIO_CLKC), GPIO_FN(SCK1_E), GPIO_FN(HCTS0_C),
+               GPIO_FN(FRB_B), GPIO_FN(LCD_VEPWC_B),
+       GPIO_FN(AUDIO_CLKB_A), GPIO_FN(LCD_CLK_B),
+       GPIO_FN(AUDIO_CLKA_A), GPIO_FN(VI1_CLK_B), GPIO_FN(SCK1_D),
+               GPIO_FN(IECLK_B), GPIO_FN(LCD_FLM_B),
+       GPIO_FN(SSI_SDATA3), GPIO_FN(VI1_7_B), GPIO_FN(HTX0_C),
+               GPIO_FN(FWE_B), GPIO_FN(LCD_CL2_B),
+       GPIO_FN(SSI_SDATA2), GPIO_FN(VI1_6_B), GPIO_FN(HRX0_C),
+               GPIO_FN(FRE_B), GPIO_FN(LCD_CL1_B),
+       GPIO_FN(SSI_WS23), GPIO_FN(VI1_5_B), GPIO_FN(TX1_D),
+               GPIO_FN(HSCK0_C), GPIO_FN(FALE_B), GPIO_FN(LCD_DON_B),
+       GPIO_FN(SSI_SCK23), GPIO_FN(VI1_4_B), GPIO_FN(RX1_D),
+               GPIO_FN(FCLE_B), GPIO_FN(LCD_DATA15_B),
+
+       /* IPSR11 */
+       GPIO_FN(PRESETOUT), GPIO_FN(ST_CLKOUT),
+       GPIO_FN(DACK1), GPIO_FN(HSPI_CS_B), GPIO_FN(TX4_B),
+               GPIO_FN(ET0_RX_CLK_A),
+       GPIO_FN(DREQ1), GPIO_FN(HSPI_CLK_B), GPIO_FN(RX4_B),
+               GPIO_FN(ET0_PHY_INT_C), GPIO_FN(ET0_TX_CLK_A),
+       GPIO_FN(DACK0), GPIO_FN(SD1_DAT3_A), GPIO_FN(ET0_TX_ER),
+       GPIO_FN(DREQ0), GPIO_FN(SD1_CLK_A), GPIO_FN(ET0_TX_EN),
+       GPIO_FN(USB_OVC1), GPIO_FN(RX3_D), GPIO_FN(CAN1_RX_B),
+               GPIO_FN(RX5_D), GPIO_FN(IERX_B),
+       GPIO_FN(PENC1), GPIO_FN(TX3_D), GPIO_FN(CAN1_TX_B),
+               GPIO_FN(TX5_D), GPIO_FN(IETX_B),
+       GPIO_FN(TX0_A), GPIO_FN(HSPI_TX_A),
+       GPIO_FN(RX0_A), GPIO_FN(HSPI_RX_A), GPIO_FN(RMII0_RXD0_A),
+               GPIO_FN(ET0_ERXD6),
+       GPIO_FN(SCK0_A), GPIO_FN(HSPI_CS_A), GPIO_FN(VI0_CLKENB),
+               GPIO_FN(RMII0_TXD1_A), GPIO_FN(ET0_ERXD5),
+       GPIO_FN(SCIF_CLK_A), GPIO_FN(HSPI_CLK_A), GPIO_FN(VI0_CLK),
+               GPIO_FN(RMII0_TXD0_A), GPIO_FN(ET0_ERXD4),
+       GPIO_FN(SDSELF), GPIO_FN(RTS1_E),
+       GPIO_FN(SDA0), GPIO_FN(HIFEBL_A),
+       GPIO_FN(SDA1), GPIO_FN(RX1_E),
+       GPIO_FN(SCL1), GPIO_FN(SCIF_CLK_C),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+       { PINMUX_CFG_REG("GPSR0", 0xFFFC0004, 32, 1) {
+               GP_0_31_FN, FN_IP2_2_0,
+               GP_0_30_FN, FN_IP1_31_29,
+               GP_0_29_FN, FN_IP1_28_26,
+               GP_0_28_FN, FN_IP1_25_23,
+               GP_0_27_FN, FN_IP1_22_20,
+               GP_0_26_FN, FN_IP1_19_18,
+               GP_0_25_FN, FN_IP1_17_16,
+               GP_0_24_FN, FN_IP0_5_4,
+               GP_0_23_FN, FN_IP0_3_2,
+               GP_0_22_FN, FN_IP0_1_0,
+               GP_0_21_FN, FN_IP11_28,
+               GP_0_20_FN, FN_IP1_7_6,
+               GP_0_19_FN, FN_IP1_5_4,
+               GP_0_18_FN, FN_IP1_3_2,
+               GP_0_17_FN, FN_IP1_1_0,
+               GP_0_16_FN, FN_IP0_31_30,
+               GP_0_15_FN, FN_IP0_29_28,
+               GP_0_14_FN, FN_IP0_27_26,
+               GP_0_13_FN, FN_IP0_25_24,
+               GP_0_12_FN, FN_IP0_23_22,
+               GP_0_11_FN, FN_IP0_21_20,
+               GP_0_10_FN, FN_IP0_19_18,
+               GP_0_9_FN, FN_IP0_17_16,
+               GP_0_8_FN, FN_IP0_15_14,
+               GP_0_7_FN, FN_IP0_13_12,
+               GP_0_6_FN, FN_IP0_11_10,
+               GP_0_5_FN, FN_IP0_9_8,
+               GP_0_4_FN, FN_IP0_7_6,
+               GP_0_3_FN, FN_IP1_15_14,
+               GP_0_2_FN, FN_IP1_13_12,
+               GP_0_1_FN, FN_IP1_11_10,
+               GP_0_0_FN, FN_IP1_9_8 }
+       },
+       { PINMUX_CFG_REG("GPSR1", 0xFFFC0008, 32, 1) {
+               GP_1_31_FN, FN_IP11_25_23,
+               GP_1_30_FN, FN_IP2_13_11,
+               GP_1_29_FN, FN_IP2_10_8,
+               GP_1_28_FN, FN_IP2_7_5,
+               GP_1_27_FN, FN_IP3_26_24,
+               GP_1_26_FN, FN_IP3_23_21,
+               GP_1_25_FN, FN_IP2_4_3,
+               GP_1_24_FN, FN_WE1,
+               GP_1_23_FN, FN_WE0,
+               GP_1_22_FN, FN_IP3_19_18,
+               GP_1_21_FN, FN_RD,
+               GP_1_20_FN, FN_IP3_17_15,
+               GP_1_19_FN, FN_IP3_14_12,
+               GP_1_18_FN, FN_IP3_11_9,
+               GP_1_17_FN, FN_IP3_8_6,
+               GP_1_16_FN, FN_IP3_5_3,
+               GP_1_15_FN, FN_EX_CS0,
+               GP_1_14_FN, FN_IP3_2,
+               GP_1_13_FN, FN_CS0,
+               GP_1_12_FN, FN_BS,
+               GP_1_11_FN, FN_CLKOUT,
+               GP_1_10_FN, FN_IP3_1_0,
+               GP_1_9_FN, FN_IP2_30_28,
+               GP_1_8_FN, FN_IP2_27_25,
+               GP_1_7_FN, FN_IP2_24_23,
+               GP_1_6_FN, FN_IP2_22_20,
+               GP_1_5_FN, FN_IP2_19_17,
+               GP_1_4_FN, FN_IP2_16_14,
+               GP_1_3_FN, FN_IP11_22_21,
+               GP_1_2_FN, FN_IP11_20_19,
+               GP_1_1_FN, FN_IP3_29_27,
+               GP_1_0_FN, FN_IP3_20 }
+       },
+       { PINMUX_CFG_REG("GPSR2", 0xFFFC000C, 32, 1) {
+               GP_2_31_FN, FN_IP4_31_30,
+               GP_2_30_FN, FN_IP5_2_0,
+               GP_2_29_FN, FN_IP5_5_3,
+               GP_2_28_FN, FN_IP5_8_6,
+               GP_2_27_FN, FN_IP5_11_9,
+               GP_2_26_FN, FN_IP5_14_12,
+               GP_2_25_FN, FN_IP5_17_15,
+               GP_2_24_FN, FN_IP5_20_18,
+               GP_2_23_FN, FN_IP5_22_21,
+               GP_2_22_FN, FN_IP5_24_23,
+               GP_2_21_FN, FN_IP5_26_25,
+               GP_2_20_FN, FN_IP4_29_28,
+               GP_2_19_FN, FN_IP4_27_26,
+               GP_2_18_FN, FN_IP4_25_24,
+               GP_2_17_FN, FN_IP4_23_22,
+               GP_2_16_FN, FN_IP4_21_20,
+               GP_2_15_FN, FN_IP4_19_18,
+               GP_2_14_FN, FN_IP4_17_15,
+               GP_2_13_FN, FN_IP4_14_12,
+               GP_2_12_FN, FN_IP4_11_9,
+               GP_2_11_FN, FN_IP4_8_6,
+               GP_2_10_FN, FN_IP4_5_3,
+               GP_2_9_FN, FN_IP8_27_26,
+               GP_2_8_FN, FN_IP11_12,
+               GP_2_7_FN, FN_IP8_25_23,
+               GP_2_6_FN, FN_IP8_22_20,
+               GP_2_5_FN, FN_IP11_27_26,
+               GP_2_4_FN, FN_IP8_29_28,
+               GP_2_3_FN, FN_IP4_2_0,
+               GP_2_2_FN, FN_IP11_11_10,
+               GP_2_1_FN, FN_IP11_9_7,
+               GP_2_0_FN, FN_IP11_6_4 }
+       },
+       { PINMUX_CFG_REG("GPSR3", 0xFFFC0010, 32, 1) {
+               GP_3_31_FN, FN_IP9_1_0,
+               GP_3_30_FN, FN_IP8_19_18,
+               GP_3_29_FN, FN_IP8_17_16,
+               GP_3_28_FN, FN_IP8_15_14,
+               GP_3_27_FN, FN_IP8_13_12,
+               GP_3_26_FN, FN_IP8_11_10,
+               GP_3_25_FN, FN_IP8_9_8,
+               GP_3_24_FN, FN_IP8_7_6,
+               GP_3_23_FN, FN_IP8_5_4,
+               GP_3_22_FN, FN_IP8_3_2,
+               GP_3_21_FN, FN_IP8_1_0,
+               GP_3_20_FN, FN_IP7_30_29,
+               GP_3_19_FN, FN_IP7_28_27,
+               GP_3_18_FN, FN_IP7_26_24,
+               GP_3_17_FN, FN_IP7_23_21,
+               GP_3_16_FN, FN_IP7_20_18,
+               GP_3_15_FN, FN_IP7_17_15,
+               GP_3_14_FN, FN_IP7_14_12,
+               GP_3_13_FN, FN_IP7_11_9,
+               GP_3_12_FN, FN_IP7_8_6,
+               GP_3_11_FN, FN_IP7_5_3,
+               GP_3_10_FN, FN_IP7_2_0,
+               GP_3_9_FN, FN_IP6_23_21,
+               GP_3_8_FN, FN_IP6_20_18,
+               GP_3_7_FN, FN_IP6_17_16,
+               GP_3_6_FN, FN_IP6_15_14,
+               GP_3_5_FN, FN_IP6_13_12,
+               GP_3_4_FN, FN_IP6_11_10,
+               GP_3_3_FN, FN_IP6_9_8,
+               GP_3_2_FN, FN_IP6_7_6,
+               GP_3_1_FN, FN_IP6_5_3,
+               GP_3_0_FN, FN_IP6_2_0 }
+       },
+
+       { PINMUX_CFG_REG("GPSR4", 0xFFFC0014, 32, 1) {
+               GP_4_31_FN, FN_IP10_24_23,
+               GP_4_30_FN, FN_IP10_22,
+               GP_4_29_FN, FN_IP11_18_16,
+               GP_4_28_FN, FN_USB_OVC0,
+               GP_4_27_FN, FN_IP11_15_13,
+               GP_4_26_FN, FN_PENC0,
+               GP_4_25_FN, FN_IP11_2,
+               GP_4_24_FN, FN_SCL0,
+               GP_4_23_FN, FN_IP11_1,
+               GP_4_22_FN, FN_IP11_0,
+               GP_4_21_FN, FN_IP10_21_19,
+               GP_4_20_FN, FN_IP10_18_16,
+               GP_4_19_FN, FN_IP10_15,
+               GP_4_18_FN, FN_IP10_14_12,
+               GP_4_17_FN, FN_IP10_11_9,
+               GP_4_16_FN, FN_IP10_8_6,
+               GP_4_15_FN, FN_IP10_5_3,
+               GP_4_14_FN, FN_IP10_2_0,
+               GP_4_13_FN, FN_IP9_29_28,
+               GP_4_12_FN, FN_IP9_27_26,
+               GP_4_11_FN, FN_IP9_9_8,
+               GP_4_10_FN, FN_IP9_7_6,
+               GP_4_9_FN, FN_IP9_5_4,
+               GP_4_8_FN, FN_IP9_3_2,
+               GP_4_7_FN, FN_IP9_17_16,
+               GP_4_6_FN, FN_IP9_15_14,
+               GP_4_5_FN, FN_IP9_13_12,
+               GP_4_4_FN, FN_IP9_11_10,
+               GP_4_3_FN, FN_IP9_25_24,
+               GP_4_2_FN, FN_IP9_23_22,
+               GP_4_1_FN, FN_IP9_21_20,
+               GP_4_0_FN, FN_IP9_19_18 }
+       },
+       { PINMUX_CFG_REG("GPSR5", 0xFFFC0018, 32, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0, /* 31 - 28 */
+               0, 0, 0, 0, 0, 0, 0, 0, /* 27 - 24 */
+               0, 0, 0, 0, 0, 0, 0, 0, /* 23 - 20 */
+               0, 0, 0, 0, 0, 0, 0, 0, /* 19 - 16 */
+               0, 0, 0, 0, 0, 0, 0, 0, /* 15 - 12 */
+               GP_5_11_FN, FN_IP10_29_28,
+               GP_5_10_FN, FN_IP10_27_26,
+               0, 0, 0, 0, 0, 0, 0, 0, /* 9 - 6 */
+               0, 0, 0, 0, /* 5, 4 */
+               GP_5_3_FN, FN_IRQ3_B,
+               GP_5_2_FN, FN_IRQ2_B,
+               GP_5_1_FN, FN_IP11_3,
+               GP_5_0_FN, FN_IP10_25 }
+       },
+
+       { PINMUX_CFG_REG_VAR("IPSR0", 0xFFFC001C, 32,
+                       2, 2, 2, 2, 2, 2, 2, 2,
+                       2, 2, 2, 2, 2, 2, 2, 2) {
+               /* IP0_31_30 [2] */
+               FN_A15, FN_ST0_VCO_CLKIN, FN_LCD_DATA15_A,
+                       FN_TIOC3D_C,
+               /* IP0_29_28 [2] */
+               FN_A14, FN_LCD_DATA14_A, FN_TIOC3C_C, 0,
+               /* IP0_27_26 [2] */
+               FN_A13, FN_LCD_DATA13_A, FN_TIOC3B_C, 0,
+               /* IP0_25_24 [2] */
+               FN_A12, FN_LCD_DATA12_A, FN_TIOC3A_C, 0,
+               /* IP0_23_22 [2] */
+               FN_A11, FN_ST0_D7, FN_LCD_DATA11_A, FN_TIOC2B_C,
+               /* IP0_21_20 [2] */
+               FN_A10, FN_ST0_D6, FN_LCD_DATA10_A, FN_TIOC2A_C,
+               /* IP0_19_18 [2] */
+               FN_A9, FN_ST0_D5, FN_LCD_DATA9_A, FN_TIOC1B_C,
+               /* IP0_17_16 [2] */
+               FN_A8, FN_ST0_D4, FN_LCD_DATA8_A, FN_TIOC1A_C,
+               /* IP0_15_14 [2] */
+               FN_A7, FN_ST0_D3, FN_LCD_DATA7_A, FN_TIOC0D_C,
+               /* IP0_13_12 [2] */
+               FN_A6, FN_ST0_D2, FN_LCD_DATA6_A, FN_TIOC0C_C,
+               /* IP0_11_10 [2] */
+               FN_A5, FN_ST0_D1, FN_LCD_DATA5_A, FN_TIOC0B_C,
+               /* IP0_9_8 [2] */
+               FN_A4, FN_ST0_D0, FN_LCD_DATA4_A, FN_TIOC0A_C,
+               /* IP0_7_6 [2] */
+               FN_A3, FN_ST0_VLD, FN_LCD_DATA3_A, FN_TCLKD_C,
+               /* IP0_5_4 [2] */
+               FN_A2, FN_ST0_SYC, FN_LCD_DATA2_A, FN_TCLKC_C,
+               /* IP0_3_2 [2] */
+               FN_A1, FN_ST0_REQ, FN_LCD_DATA1_A, FN_TCLKB_C,
+               /* IP0_1_0 [2] */
+               FN_A0, FN_ST0_CLKIN, FN_LCD_DATA0_A, FN_TCLKA_C }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR1", 0xFFFC0020, 32,
+                       3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) {
+               /* IP1_31_29 [3] */
+               FN_D3, FN_SD0_DAT3_A, FN_MMC_D3_A, FN_ST1_D6,
+                       FN_FD3_A, 0, 0, 0,
+               /* IP1_28_26 [3] */
+               FN_D2, FN_SD0_DAT2_A, FN_MMC_D2_A, FN_ST1_D5,
+                       FN_FD2_A, 0, 0, 0,
+               /* IP1_25_23 [3] */
+               FN_D1, FN_SD0_DAT1_A, FN_MMC_D1_A, FN_ST1_D4,
+                       FN_FD1_A, 0, 0, 0,
+               /* IP1_22_20 [3] */
+               FN_D0, FN_SD0_DAT0_A, FN_MMC_D0_A, FN_ST1_D3,
+                       FN_FD0_A, 0, 0, 0,
+               /* IP1_19_18 [2] */
+               FN_A25, FN_TX2_D, FN_ST1_D2, 0,
+               /* IP1_17_16 [2] */
+               FN_A24, FN_RX2_D, FN_ST1_D1, 0,
+               /* IP1_15_14 [2] */
+               FN_A23, FN_ST1_D0, FN_LCD_M_DISP_A, 0,
+               /* IP1_13_12 [2] */
+               FN_A22, FN_ST1_VLD, FN_LCD_VEPWC_A, 0,
+               /* IP1_11_10 [2] */
+               FN_A21, FN_ST1_SYC, FN_LCD_VCPWC_A, 0,
+               /* IP1_9_8 [2] */
+               FN_A20, FN_ST1_REQ, FN_LCD_FLM_A, 0,
+               /* IP1_7_6 [2] */
+               FN_A19, FN_ST1_CLKIN, FN_LCD_CLK_A,     FN_TIOC4D_C,
+               /* IP1_5_4 [2] */
+               FN_A18, FN_ST1_PWM, FN_LCD_CL2_A, FN_TIOC4C_C,
+               /* IP1_3_2 [2] */
+               FN_A17, FN_ST1_VCO_CLKIN, FN_LCD_CL1_A, FN_TIOC4B_C,
+               /* IP1_1_0 [2] */
+               FN_A16, FN_ST0_PWM, FN_LCD_DON_A, FN_TIOC4A_C }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR2", 0xFFFC0024, 32,
+                            1, 3, 3, 2, 3, 3, 3, 3, 3, 3, 2, 3) {
+               /* IP2_31 [1] */
+               0, 0,
+               /* IP2_30_28 [3] */
+               FN_D14, FN_TX2_B, 0, FN_FSE_A,
+                       FN_ET0_TX_CLK_B, 0, 0, 0,
+               /* IP2_27_25 [3] */
+               FN_D13, FN_RX2_B, 0, FN_FRB_A,
+                       FN_ET0_ETXD6_B, 0, 0, 0,
+               /* IP2_24_23 [2] */
+               FN_D12, 0, FN_FWE_A, FN_ET0_ETXD5_B,
+               /* IP2_22_20 [3] */
+               FN_D11, FN_RSPI_MISO_A, 0, FN_QMI_QIO1_A,
+                       FN_FRE_A, FN_ET0_ETXD3_B, 0, 0,
+               /* IP2_19_17 [3] */
+               FN_D10, FN_RSPI_MOSI_A, 0, FN_QMO_QIO0_A,
+                       FN_FALE_A, FN_ET0_ETXD2_B, 0, 0,
+               /* IP2_16_14 [3] */
+               FN_D9, FN_SD0_CMD_A, FN_MMC_CMD_A, FN_QIO3_A,
+                       FN_FCLE_A, FN_ET0_ETXD1_B, 0, 0,
+               /* IP2_13_11 [3] */
+               FN_D8, FN_SD0_CLK_A, FN_MMC_CLK_A, FN_QIO2_A,
+                       FN_FCE_A, FN_ET0_GTX_CLK_B, 0, 0,
+               /* IP2_10_8 [3] */
+               FN_D7, FN_RSPI_SSL_A, FN_MMC_D7_A, FN_QSSL_A,
+                       FN_FD7_A, 0, 0, 0,
+               /* IP2_7_5 [3] */
+               FN_D6, FN_RSPI_RSPCK_A, FN_MMC_D6_A, FN_QSPCLK_A,
+                       FN_FD6_A, 0, 0, 0,
+               /* IP2_4_3 [2] */
+               FN_D5, FN_SD0_WP_A, FN_MMC_D5_A, FN_FD5_A,
+               /* IP2_2_0 [3] */
+               FN_D4, FN_SD0_CD_A, FN_MMC_D4_A, FN_ST1_D7,
+                       FN_FD4_A, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR3", 0xFFFC0028, 32,
+                               2, 3, 3, 3, 1, 2, 3, 3, 3, 3, 3, 1, 2) {
+           /* IP3_31_30 [2] */
+               0, 0, 0, 0,
+           /* IP3_29_27 [3] */
+               FN_DRACK0, FN_SD1_DAT2_A, FN_ATAG, FN_TCLK1_A,
+               FN_ET0_ETXD7, 0, 0, 0,
+           /* IP3_26_24 [3] */
+               FN_EX_WAIT2, FN_SD1_DAT1_A, FN_DACK2, FN_CAN1_RX_C,
+               FN_ET0_MAGIC_C, FN_ET0_ETXD6_A, 0, 0,
+           /* IP3_23_21 [3] */
+               FN_EX_WAIT1, FN_SD1_DAT0_A, FN_DREQ2, FN_CAN1_TX_C,
+               FN_ET0_LINK_C, FN_ET0_ETXD5_A, 0, 0,
+           /* IP3_20 [1] */
+               FN_EX_WAIT0, FN_TCLK1_B,
+           /* IP3_19_18 [2] */
+               FN_RD_WR, FN_TCLK1_B, 0, 0,
+           /* IP3_17_15 [3] */
+               FN_EX_CS5, FN_SD1_CMD_A, FN_ATADIR, FN_QSSL_B,
+               FN_ET0_ETXD3_A, 0, 0, 0,
+           /* IP3_14_12 [3] */
+               FN_EX_CS4, FN_SD1_WP_A, FN_ATAWR, FN_QMI_QIO1_B,
+               FN_ET0_ETXD2_A, 0, 0, 0,
+           /* IP3_11_9 [3] */
+               FN_EX_CS3, FN_SD1_CD_A, FN_ATARD, FN_QMO_QIO0_B,
+               FN_ET0_ETXD1_A, 0, 0, 0,
+           /* IP3_8_6 [3] */
+               FN_EX_CS2, FN_TX3_B, FN_ATACS1, FN_QSPCLK_B,
+               FN_ET0_GTX_CLK_A, 0, 0, 0,
+           /* IP3_5_3 [3] */
+               FN_EX_CS1, FN_RX3_B, FN_ATACS0, FN_QIO2_B,
+               FN_ET0_ETXD0, 0, 0, 0,
+           /* IP3_2 [1] */
+               FN_CS1_A26, FN_QIO3_B,
+           /* IP3_1_0 [2] */
+               FN_D15, FN_SCK2_B, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR4", 0xFFFC002C, 32,
+                               2, 2, 2, 2, 2, 2 , 2, 3, 3, 3, 3, 3, 3) {
+           /* IP4_31_30 [2] */
+               0, FN_SCK2_A, FN_VI0_G3, 0,
+           /* IP4_29_28 [2] */
+               0, FN_RTS1_B, FN_VI0_G2, 0,
+           /* IP4_27_26 [2] */
+               0, FN_CTS1_B, FN_VI0_DATA7_VI0_G1, 0,
+           /* IP4_25_24 [2] */
+               0, FN_TX1_B, FN_VI0_DATA6_VI0_G0, FN_ET0_PHY_INT_A,
+           /* IP4_23_22 [2] */
+               0, FN_RX1_B, FN_VI0_DATA5_VI0_B5, FN_ET0_MAGIC_A,
+           /* IP4_21_20 [2] */
+               0, FN_SCK1_B, FN_VI0_DATA4_VI0_B4, FN_ET0_LINK_A,
+           /* IP4_19_18 [2] */
+               0, FN_RTS0_B, FN_VI0_DATA3_VI0_B3, FN_ET0_MDIO_A,
+           /* IP4_17_15 [3] */
+               0, FN_CTS0_B, FN_VI0_DATA2_VI0_B2, FN_RMII0_MDIO_A,
+                       FN_ET0_MDC, 0, 0, 0,
+           /* IP4_14_12 [3] */
+               FN_HTX0_A, FN_TX1_A, FN_VI0_DATA1_VI0_B1, FN_RMII0_MDC_A,
+                       FN_ET0_COL, 0, 0, 0,
+           /* IP4_11_9 [3] */
+               FN_HRX0_A, FN_RX1_A, FN_VI0_DATA0_VI0_B0, FN_RMII0_CRS_DV_A,
+                       FN_ET0_CRS, 0, 0, 0,
+           /* IP4_8_6 [3] */
+               FN_HSCK0_A, FN_SCK1_A, FN_VI0_VSYNC, FN_RMII0_RX_ER_A,
+                       FN_ET0_RX_ER, 0, 0, 0,
+           /* IP4_5_3 [3] */
+               FN_HRTS0_A, FN_RTS1_A, FN_VI0_HSYNC, FN_RMII0_TXD_EN_A,
+                       FN_ET0_RX_DV, 0, 0, 0,
+           /* IP4_2_0 [3] */
+               FN_HCTS0_A, FN_CTS1_A, FN_VI0_FIELD, FN_RMII0_RXD1_A,
+                       FN_ET0_ERXD7, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR5", 0xFFFC0030, 32,
+                               1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3) {
+           /* IP5_31 [1] */
+           0, 0,
+           /* IP5_30 [1] */
+           0, 0,
+           /* IP5_29 [1] */
+           0, 0,
+           /* IP5_28 [1] */
+           0, 0,
+           /* IP5_27 [1] */
+           0, 0,
+           /* IP5_26_25 [2] */
+               FN_REF50CK, FN_CTS1_E, FN_HCTS0_D, 0,
+           /* IP5_24_23 [2] */
+               FN_REF125CK, FN_ADTRG, FN_RX5_C, 0,
+           /* IP5_22_21 [2] */
+               FN_SD2_WP_A, FN_TX5_A, FN_VI0_R5, 0,
+           /* IP5_20_18 [3] */
+               FN_SD2_CD_A, FN_RX5_A, FN_VI0_R4, 0,
+               0, 0, 0, FN_ET0_PHY_INT_B,
+           /* IP5_17_15 [3] */
+               FN_SD2_DAT3_A, FN_TX4_A, FN_VI0_R3, 0,
+               0, 0, 0, FN_ET0_MAGIC_B,
+           /* IP5_14_12 [3] */
+               FN_SD2_DAT2_A, FN_RX4_A, FN_VI0_R2, 0,
+               0, 0, 0, FN_ET0_LINK_B,
+           /* IP5_11_9 [3] */
+               FN_SD2_DAT1_A, FN_TX3_A, FN_VI0_R1, 0,
+               0, 0, 0, FN_ET0_MDIO_B,
+           /* IP5_8_6 [3] */
+               FN_SD2_DAT0_A, FN_RX3_A, FN_VI0_R0, 0,
+               0, 0, 0, FN_ET0_ERXD3_B,
+           /* IP5_5_3 [3] */
+               FN_SD2_CMD_A, FN_TX2_A, FN_VI0_G5, 0,
+               0, 0, 0, FN_ET0_ERXD2_B,
+           /* IP5_2_0 [3] */
+               FN_SD2_CLK_A, FN_RX2_A, FN_VI0_G4, 0,
+               FN_ET0_RX_CLK_B, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR6", 0xFFFC0034, 32,
+                               1, 1, 1, 1, 1, 1, 1, 1,
+                               3, 3, 2, 2, 2, 2, 2, 2, 3, 3) {
+           /* IP5_31 [1] */
+           0, 0,
+           /* IP6_30 [1] */
+           0, 0,
+           /* IP6_29 [1] */
+           0, 0,
+           /* IP6_28 [1] */
+           0, 0,
+           /* IP6_27 [1] */
+           0, 0,
+           /* IP6_26 [1] */
+           0, 0,
+           /* IP6_25 [1] */
+           0, 0,
+           /* IP6_24 [1] */
+           0, 0,
+           /* IP6_23_21 [3] */
+               FN_DU0_DG1, FN_CTS1_C, FN_HRTS0_D, FN_TIOC1B_A,
+               FN_HIFD09, 0, 0, 0,
+           /* IP6_20_18 [3] */
+               FN_DU0_DG0, FN_TX1_C, FN_HSCK0_D, FN_IECLK_A,
+               FN_TIOC1A_A, FN_HIFD08, 0, 0,
+           /* IP6_17_16 [2] */
+               FN_DU0_DR7, FN_RX1_C, FN_TIOC0D_A, FN_HIFD07,
+           /* IP6_15_14 [2] */
+               FN_DU0_DR6, FN_SCK1_C, FN_TIOC0C_A, FN_HIFD06,
+           /* IP6_13_12 [2] */
+               FN_DU0_DR5, FN_RTS0_C, FN_TIOC0B_A, FN_HIFD05,
+           /* IP6_11_10 [2] */
+               FN_DU0_DR4, FN_CTS0_C, FN_TIOC0A_A, FN_HIFD04,
+           /* IP6_9_8 [2] */
+               FN_DU0_DR3, FN_TX0_B, FN_TCLKD_A, FN_HIFD03,
+           /* IP6_7_6 [2] */
+               FN_DU0_DR2, FN_RX0_B, FN_TCLKC_A, FN_HIFD02,
+           /* IP6_5_3 [3] */
+               FN_DU0_DR1, FN_SCK0_B, FN_HTX0_D, FN_IERX_A,
+               FN_TCLKB_A, FN_HIFD01, 0, 0,
+           /* IP6_2_0 [3] */
+               FN_DU0_DR0, FN_SCIF_CLK_B, FN_HRX0_D, FN_IETX_A,
+               FN_TCLKA_A, FN_HIFD00, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR7", 0xFFFC0038, 32,
+                            1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3) {
+           /* IP7_31 [1] */
+           0, 0,
+           /* IP7_30_29 [2] */
+               FN_DU0_DB4, 0, FN_HIFINT, 0,
+           /* IP7_28_27 [2] */
+               FN_DU0_DB3, FN_TX5_B, FN_TIOC4D_A, FN_HIFRD,
+           /* IP7_26_24 [3] */
+               FN_DU0_DB2, FN_RX5_B, FN_RMII0_TXD1_B, FN_TIOC4C_A,
+               FN_HIFWR, 0, 0, 0,
+           /* IP7_23_21 [3] */
+               FN_DU0_DB1, FN_TX4_C, FN_RMII0_TXD0_B, FN_TIOC4B_A,
+               FN_HIFRS, 0, 0, 0,
+           /* IP7_20_18 [3] */
+               FN_DU0_DB0, FN_RX4_C, FN_RMII0_TXD_EN_B, FN_TIOC4A_A,
+               FN_HIFCS, 0, 0, 0,
+           /* IP7_17_15 [3] */
+               FN_DU0_DG7, FN_TX3_C, FN_RMII0_RXD1_B, FN_TIOC3D_A,
+               FN_HIFD15, 0, 0, 0,
+           /* IP7_14_12 [3] */
+               FN_DU0_DG6, FN_RX3_C, FN_RMII0_RXD0_B, FN_TIOC3C_A,
+               FN_HIFD14, 0, 0, 0,
+           /* IP7_11_9 [3] */
+               FN_DU0_DG5, FN_TX2_C, FN_RMII0_RX_ER_B, FN_TIOC3B_A,
+               FN_HIFD13, 0, 0, 0,
+           /* IP7_8_6 [3] */
+               FN_DU0_DG4, FN_RX2_C, FN_RMII0_CRS_DV_B, FN_TIOC3A_A,
+               FN_HIFD12, 0, 0, 0,
+           /* IP7_5_3 [3] */
+               FN_DU0_DG3, FN_SCK2_C, FN_RMII0_MDIO_B, FN_TIOC2B_A,
+               FN_HIFD11, 0, 0, 0,
+           /* IP7_2_0 [3] */
+               FN_DU0_DG2, FN_RTS1_C, FN_RMII0_MDC_B, FN_TIOC2A_A,
+               FN_HIFD10, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR8", 0xFFFC003C, 32,
+                            2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) {
+           /* IP9_31_30 [2] */
+           0, 0, 0, 0,
+           /* IP8_29_28 [2] */
+               FN_IRQ3_A, FN_RTS0_A, FN_HRTS0_B, FN_ET0_ERXD3_A,
+           /* IP8_27_26 [2] */
+               FN_IRQ2_A, FN_CTS0_A, FN_HCTS0_B, FN_ET0_ERXD2_A,
+           /* IP8_25_23 [3] */
+               FN_IRQ1_A, 0, FN_HSPI_RX_B, FN_TX3_E,
+                       FN_ET0_ERXD1, 0, 0, 0,
+           /* IP8_22_20 [3] */
+               FN_IRQ0_A, 0, FN_HSPI_TX_B, FN_RX3_E,
+                       FN_ET0_ERXD0, 0, 0, 0,
+           /* IP8_19_18 [2] */
+               FN_DU0_CDE, FN_HTX0_B, FN_AUDIO_CLKB_B, FN_LCD_VCPWC_B,
+           /* IP8_17_16 [2] */
+               FN_DU0_DISP, FN_CAN0_TX_B, FN_HRX0_B, FN_AUDIO_CLKA_B,
+           /* IP8_15_14 [2] */
+               FN_DU0_EXODDF_DU0_ODDF, FN_CAN0_RX_B, FN_HSCK0_B,
+                       FN_SSI_SDATA1_B,
+           /* IP8_13_12 [2] */
+               FN_DU0_EXVSYNC_DU0_VSYNC, 0, FN_HSPI_RX0_C, FN_SSI_WS1_B,
+           /* IP8_11_10 [2] */
+               FN_DU0_EXHSYNC_DU0_HSYNC, 0, FN_HSPI_TX0_C, FN_SSI_SCK1_B,
+           /* IP8_9_8 [2] */
+               FN_DU0_DOTCLKOUT, 0, FN_HSPI_CLK0_C, FN_SSI_SDATA0_B,
+           /* IP8_7_6 [2] */
+               FN_DU0_DOTCLKIN, 0, FN_HSPI_CS0_C, FN_SSI_WS0_B,
+           /* IP8_5_4 [2] */
+               FN_DU0_DB7, 0, FN_SSI_SCK0_B, FN_HIFEBL_B,
+           /* IP8_3_2 [2] */
+               FN_DU0_DB6, 0, FN_HIFRDY, 0,
+           /* IP8_1_0 [2] */
+               FN_DU0_DB5, 0, FN_HIFDREQ, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR9", 0xFFFC0040, 32,
+                            2, 2, 2, 2, 2, 2, 2, 2,
+                            2, 2, 2, 2, 2, 2, 2, 2) {
+           /* IP9_31_30 [2] */
+           0, 0, 0, 0,
+           /* IP9_29_28 [2] */
+               FN_SSI_SDATA1_A, FN_VI1_3_B, FN_LCD_DATA14_B, 0,
+           /* IP9_27_26 [2] */
+               FN_SSI_WS1_A, FN_VI1_2_B, FN_LCD_DATA13_B, 0,
+           /* IP9_25_24 [2] */
+               FN_SSI_SCK1_A, FN_VI1_1_B, FN_TIOC2B_B, FN_LCD_DATA12_B,
+           /* IP9_23_22 [2] */
+               FN_SSI_SDATA0_A, FN_VI1_0_B, FN_TIOC2A_B, FN_LCD_DATA11_B,
+           /* IP9_21_20 [2] */
+               FN_SSI_WS0_A, FN_TIOC1B_B, FN_LCD_DATA10_B, 0,
+           /* IP9_19_18 [2] */
+               FN_SSI_SCK0_A, FN_TIOC1A_B, FN_LCD_DATA9_B, 0,
+           /* IP9_17_16 [2] */
+               FN_VI1_7_A, FN_FCE_B, FN_LCD_DATA8_B, 0,
+           /* IP9_15_14 [2] */
+               FN_VI1_6_A, 0, FN_FD7_B, FN_LCD_DATA7_B,
+           /* IP9_13_12 [2] */
+               FN_VI1_5_A, 0, FN_FD6_B, FN_LCD_DATA6_B,
+           /* IP9_11_10 [2] */
+               FN_VI1_4_A, 0, FN_FD5_B, FN_LCD_DATA5_B,
+           /* IP9_9_8 [2] */
+               FN_VI1_3_A, 0, FN_FD4_B, FN_LCD_DATA4_B,
+           /* IP9_7_6 [2] */
+               FN_VI1_2_A, 0, FN_FD3_B, FN_LCD_DATA3_B,
+           /* IP9_5_4 [2] */
+               FN_VI1_1_A, 0, FN_FD2_B, FN_LCD_DATA2_B,
+           /* IP9_3_2 [2] */
+               FN_VI1_0_A, 0, FN_FD1_B, FN_LCD_DATA1_B,
+           /* IP9_1_0 [2] */
+               FN_VI1_CLK_A, 0, FN_FD0_B, FN_LCD_DATA0_B }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR10", 0xFFFC0044, 32,
+                                       2, 2, 2, 1, 2, 1, 3,
+                                       3, 1, 3, 3, 3, 3, 3) {
+           /* IP9_31_30 [2] */
+           0, 0, 0, 0,
+           /* IP10_29_28 [2] */
+               FN_CAN1_TX_A, FN_TX5_C, FN_MLB_DAT, 0,
+           /* IP10_27_26 [2] */
+               FN_CAN0_RX_A, FN_IRQ0_B, FN_MLB_SIG, 0,
+           /* IP10_25 [1] */
+               FN_CAN1_RX_A, FN_IRQ1_B,
+           /* IP10_24_23 [2] */
+               FN_CAN0_TX_A, FN_TX4_D, FN_MLB_CLK, 0,
+           /* IP10_22 [1] */
+               FN_CAN_CLK_A, FN_RX4_D,
+           /* IP10_21_19 [3] */
+               FN_AUDIO_CLKOUT, FN_TX1_E, FN_HRTS0_C, FN_FSE_B,
+               FN_LCD_M_DISP_B, 0, 0, 0,
+           /* IP10_18_16 [3] */
+               FN_AUDIO_CLKC, FN_SCK1_E, FN_HCTS0_C, FN_FRB_B,
+               FN_LCD_VEPWC_B, 0, 0, 0,
+           /* IP10_15 [1] */
+               FN_AUDIO_CLKB_A, FN_LCD_CLK_B,
+           /* IP10_14_12 [3] */
+               FN_AUDIO_CLKA_A, FN_VI1_CLK_B, FN_SCK1_D, FN_IECLK_B,
+               FN_LCD_FLM_B, 0, 0, 0,
+           /* IP10_11_9 [3] */
+               FN_SSI_SDATA3, FN_VI1_7_B, FN_HTX0_C, FN_FWE_B,
+               FN_LCD_CL2_B, 0, 0, 0,
+           /* IP10_8_6 [3] */
+               FN_SSI_SDATA2, FN_VI1_6_B, FN_HRX0_C, FN_FRE_B,
+               FN_LCD_CL1_B, 0, 0, 0,
+           /* IP10_5_3 [3] */
+               FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B,
+               FN_LCD_DON_B, 0, 0, 0,
+           /* IP10_2_0 [3] */
+               FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B,
+               FN_LCD_DATA15_B, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR11", 0xFFFC0048, 32,
+                       3, 1, 2, 2, 2, 3, 3, 1, 2, 3, 3, 1, 1, 1, 1) {
+           /* IP11_31_29 [3] */
+           0, 0, 0, 0, 0, 0, 0, 0,
+           /* IP11_28 [1] */
+               FN_PRESETOUT, FN_ST_CLKOUT,
+           /* IP11_27_26 [2] */
+               FN_DACK1, FN_HSPI_CS_B, FN_TX4_B, FN_ET0_RX_CLK_A,
+           /* IP11_25_23 [3] */
+               FN_DREQ1, FN_HSPI_CLK_B, FN_RX4_B, FN_ET0_PHY_INT_C,
+               FN_ET0_TX_CLK_A, 0, 0, 0,
+           /* IP11_22_21 [2] */
+               FN_DACK0, FN_SD1_DAT3_A, FN_ET0_TX_ER, 0,
+           /* IP11_20_19 [2] */
+               FN_DREQ0, FN_SD1_CLK_A, FN_ET0_TX_EN, 0,
+           /* IP11_18_16 [3] */
+               FN_USB_OVC1, FN_RX3_D, FN_CAN1_RX_B, FN_RX5_D,
+               FN_IERX_B, 0, 0, 0,
+           /* IP11_15_13 [3] */
+               FN_PENC1, FN_TX3_D, FN_CAN1_TX_B, FN_TX5_D,
+               FN_IETX_B, 0, 0, 0,
+           /* IP11_12 [1] */
+               FN_TX0_A, FN_HSPI_TX_A,
+           /* IP11_11_10 [2] */
+               FN_RX0_A, FN_HSPI_RX_A, FN_RMII0_RXD0_A, FN_ET0_ERXD6,
+           /* IP11_9_7 [3] */
+               FN_SCK0_A, FN_HSPI_CS_A, FN_VI0_CLKENB, FN_RMII0_TXD1_A,
+               FN_ET0_ERXD5, 0, 0, 0,
+           /* IP11_6_4 [3] */
+               FN_SCIF_CLK_A, FN_HSPI_CLK_A, FN_VI0_CLK, FN_RMII0_TXD0_A,
+               FN_ET0_ERXD4, 0, 0, 0,
+           /* IP11_3 [1] */
+               FN_SDSELF, FN_RTS1_E,
+           /* IP11_2 [1] */
+               FN_SDA0, FN_HIFEBL_A,
+           /* IP11_1 [1] */
+               FN_SDA1, FN_RX1_E,
+           /* IP11_0 [1] */
+               FN_SCL1, FN_SCIF_CLK_C }
+       },
+       { PINMUX_CFG_REG_VAR("MOD_SEL1", 0xFFFC004C, 32,
+                               3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2,
+                               1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) {
+               /* SEL1_31_29 [3] */
+               0, 0, 0, 0, 0, 0, 0, 0,
+               /* SEL1_28 [1] */
+               FN_SEL_IEBUS_0, FN_SEL_IEBUS_1,
+               /* SEL1_27 [1] */
+               FN_SEL_RQSPI_0, FN_SEL_RQSPI_1,
+               /* SEL1_26 [1] */
+               FN_SEL_VIN1_0, FN_SEL_VIN1_1,
+               /* SEL1_25 [1] */
+               FN_SEL_HIF_0, FN_SEL_HIF_1,
+               /* SEL1_24 [1] */
+               FN_SEL_RSPI_0, FN_SEL_RSPI_1,
+               /* SEL1_23 [1] */
+               FN_SEL_LCDC_0, FN_SEL_LCDC_1,
+               /* SEL1_22_21 [2] */
+               FN_SEL_ET0_CTL_0, FN_SEL_ET0_CTL_1, FN_SEL_ET0_CTL_2, 0,
+               /* SEL1_20 [1] */
+               FN_SEL_ET0_0, FN_SEL_ET0_1,
+               /* SEL1_19 [1] */
+               FN_SEL_RMII_0, FN_SEL_RMII_1,
+               /* SEL1_18 [1] */
+               FN_SEL_TMU_0, FN_SEL_TMU_1,
+               /* SEL1_17_16 [2] */
+               FN_SEL_HSPI_0, FN_SEL_HSPI_1, FN_SEL_HSPI_2, 0,
+               /* SEL1_15_14 [2] */
+               FN_SEL_HSCIF_0, FN_SEL_HSCIF_1, FN_SEL_HSCIF_2, FN_SEL_HSCIF_3,
+               /* SEL1_13 [1] */
+               FN_SEL_RCAN_CLK_0, FN_SEL_RCAN_CLK_1,
+               /* SEL1_12_11 [2] */
+               FN_SEL_RCAN1_0, FN_SEL_RCAN1_1, FN_SEL_RCAN1_2, 0,
+               /* SEL1_10 [1] */
+               FN_SEL_RCAN0_0, FN_SEL_RCAN0_1,
+               /* SEL1_9 [1] */
+               FN_SEL_SDHI2_0, FN_SEL_SDHI2_1,
+               /* SEL1_8 [1] */
+               FN_SEL_SDHI1_0, FN_SEL_SDHI1_1,
+               /* SEL1_7 [1] */
+               FN_SEL_SDHI0_0, FN_SEL_SDHI0_1,
+               /* SEL1_6 [1] */
+               FN_SEL_SSI1_0, FN_SEL_SSI1_1,
+               /* SEL1_5 [1] */
+               FN_SEL_SSI0_0, FN_SEL_SSI0_1,
+               /* SEL1_4 [1] */
+               FN_SEL_AUDIO_CLKB_0, FN_SEL_AUDIO_CLKB_1,
+               /* SEL1_3 [1] */
+               FN_SEL_AUDIO_CLKA_0, FN_SEL_AUDIO_CLKA_1,
+               /* SEL1_2 [1] */
+               FN_SEL_FLCTL_0, FN_SEL_FLCTL_1,
+               /* SEL1_1 [1] */
+               FN_SEL_MMC_0, FN_SEL_MMC_1,
+               /* SEL1_0 [1] */
+               FN_SEL_INTC_0, FN_SEL_INTC_1 }
+       },
+       { PINMUX_CFG_REG_VAR("MOD_SEL2", 0xFFFC0050, 32,
+                               1, 1, 1, 1, 1, 1, 1, 1,
+                               1, 1, 1, 2, 2, 1, 2, 2, 3, 2, 3, 2, 2) {
+               /* SEL2_31 [1] */
+               0, 0,
+               /* SEL2_30 [1] */
+               0, 0,
+               /* SEL2_29 [1] */
+               0, 0,
+               /* SEL2_28 [1] */
+               0, 0,
+               /* SEL2_27 [1] */
+               0, 0,
+               /* SEL2_26 [1] */
+               0, 0,
+               /* SEL2_25 [1] */
+               0, 0,
+               /* SEL2_24 [1] */
+               0, 0,
+               /* SEL2_23 [1] */
+               FN_SEL_MTU2_CLK_0, FN_SEL_MTU2_CLK_1,
+               /* SEL2_22 [1] */
+               FN_SEL_MTU2_CH4_0, FN_SEL_MTU2_CH4_1,
+               /* SEL2_21 [1] */
+               FN_SEL_MTU2_CH3_0, FN_SEL_MTU2_CH3_1,
+               /* SEL2_20_19 [2] */
+               FN_SEL_MTU2_CH2_0, FN_SEL_MTU2_CH2_1, FN_SEL_MTU2_CH2_2, 0,
+               /* SEL2_18_17 [2] */
+               FN_SEL_MTU2_CH1_0, FN_SEL_MTU2_CH1_1, FN_SEL_MTU2_CH1_2, 0,
+               /* SEL2_16 [1] */
+               FN_SEL_MTU2_CH0_0, FN_SEL_MTU2_CH0_1,
+               /* SEL2_15_14 [2] */
+               FN_SEL_SCIF5_0, FN_SEL_SCIF5_1, FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
+               /* SEL2_13_12 [2] */
+               FN_SEL_SCIF4_0, FN_SEL_SCIF4_1, FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
+               /* SEL2_11_9 [3] */
+               FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2, FN_SEL_SCIF3_3,
+               FN_SEL_SCIF3_4, 0, 0, 0,
+               /* SEL2_8_7 [2] */
+               FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2, FN_SEL_SCIF2_3,
+               /* SEL2_6_4 [3] */
+               FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2, FN_SEL_SCIF1_3,
+                       FN_SEL_SCIF1_4, 0, 0, 0,
+               /* SEL2_3_2 [2] */
+               FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2, 0,
+               /* SEL2_1_0 [2] */
+               FN_SEL_SCIF_CLK_0, FN_SEL_SCIF_CLK_1, FN_SEL_SCIF_CLK_2, 0  }
+       },
+       /* GPIO 0 - 5*/
+       { PINMUX_CFG_REG("INOUTSEL0", 0xFFC40004, 32, 1) { GP_INOUTSEL(0) } },
+       { PINMUX_CFG_REG("INOUTSEL1", 0xFFC41004, 32, 1) { GP_INOUTSEL(1) } },
+       { PINMUX_CFG_REG("INOUTSEL2", 0xFFC42004, 32, 1) { GP_INOUTSEL(2) } },
+       { PINMUX_CFG_REG("INOUTSEL3", 0xFFC43004, 32, 1) { GP_INOUTSEL(3) } },
+       { PINMUX_CFG_REG("INOUTSEL4", 0xFFC44004, 32, 1) { GP_INOUTSEL(4) } },
+       { PINMUX_CFG_REG("INOUTSEL5", 0xffc45004, 32, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 31 - 24 */
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 23 - 16 */
+               0, 0, 0, 0, 0, 0, 0, 0, /* 15 - 12 */
+               GP_5_11_IN, GP_5_11_OUT,
+               GP_5_10_IN, GP_5_10_OUT,
+               GP_5_9_IN, GP_5_9_OUT,
+               GP_5_8_IN, GP_5_8_OUT,
+               GP_5_7_IN, GP_5_7_OUT,
+               GP_5_6_IN, GP_5_6_OUT,
+               GP_5_5_IN, GP_5_5_OUT,
+               GP_5_4_IN, GP_5_4_OUT,
+               GP_5_3_IN, GP_5_3_OUT,
+               GP_5_2_IN, GP_5_2_OUT,
+               GP_5_1_IN, GP_5_1_OUT,
+               GP_5_0_IN, GP_5_0_OUT }
+       },
+       { },
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+       /* GPIO 0 - 5*/
+       { PINMUX_DATA_REG("INDT0", 0xFFC4000C, 32) { GP_INDT(0) } },
+       { PINMUX_DATA_REG("INDT1", 0xFFC4100C, 32) { GP_INDT(1) } },
+       { PINMUX_DATA_REG("INDT2", 0xFFC4200C, 32) { GP_INDT(2) } },
+       { PINMUX_DATA_REG("INDT3", 0xFFC4300C, 32) { GP_INDT(3) } },
+       { PINMUX_DATA_REG("INDT4", 0xFFC4400C, 32) { GP_INDT(4) } },
+       { PINMUX_DATA_REG("INDT5", 0xFFC4500C, 32) {
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0,
+               GP_5_11_DATA, GP_5_10_DATA, GP_5_9_DATA, GP_5_8_DATA,
+               GP_5_7_DATA, GP_5_6_DATA, GP_5_5_DATA, GP_5_4_DATA,
+               GP_5_3_DATA, GP_5_2_DATA, GP_5_1_DATA, GP_5_0_DATA }
+       },
+       { },
+};
+
+static struct resource sh7734_pfc_resources[] = {
+       [0] = { /* PFC */
+               .start  = 0xFFFC0000,
+               .end    = 0xFFFC011C,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = { /* GPIO */
+               .start  = 0xFFC40000,
+               .end    = 0xFFC4502B,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+static struct pinmux_info sh7734_pinmux_info = {
+       .name = "sh7734_pfc",
+
+       .resource = sh7734_pfc_resources,
+       .num_resources = ARRAY_SIZE(sh7734_pfc_resources),
+
+       .unlock_reg = 0xFFFC0000,
+
+       .reserved_id = PINMUX_RESERVED,
+       .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+       .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+       .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+       .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+       .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+       .first_gpio = GPIO_GP_0_0,
+       .last_gpio = GPIO_FN_ST_CLKOUT,
+
+       .gpios = pinmux_gpios,
+       .cfg_regs = pinmux_config_regs,
+       .data_regs = pinmux_data_regs,
+
+       .gpio_data = pinmux_data,
+       .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+static int __init plat_pinmux_setup(void)
+{
+       return register_pinmux(&sh7734_pinmux_info);
+}
+arch_initcall(plat_pinmux_setup);
index 1b8848317e9c1bc65b90b7aa101215f9592f30f6..b91ea8300a3e8f9383cccfc758bf174c8d0a2f97 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <asm/clock.h>
 
 /* Serial */
@@ -22,7 +23,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 80, 80, 80, 80 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc00)),
 };
 
 static struct platform_device scif0_device = {
@@ -39,7 +40,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 81, 81, 81, 81 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc20)),
 };
 
 static struct platform_device scif1_device = {
@@ -56,7 +57,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 82, 82, 82, 82 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc40)),
 };
 
 static struct platform_device scif2_device = {
@@ -73,7 +74,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 83, 83, 83, 83 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc60)),
 };
 
 static struct platform_device scif3_device = {
@@ -92,8 +93,8 @@ static struct resource iic0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 96,
-               .end    = 99,
+               .start  = evt2irq(0xe00),
+               .end    = evt2irq(0xe60),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -113,8 +114,8 @@ static struct resource iic1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 44,
-               .end    = 47,
+               .start  = evt2irq(0x780),
+               .end    = evt2irq(0x7e0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -129,7 +130,7 @@ static struct platform_device iic1_device = {
 static struct uio_info vpu_platform_data = {
        .name = "VPU4",
        .version = "0",
-       .irq = 60,
+       .irq = evt2irq(0x980),
 };
 
 static struct resource vpu_resources[] = {
@@ -157,7 +158,7 @@ static struct platform_device vpu_device = {
 static struct uio_info veu_platform_data = {
        .name = "VEU",
        .version = "0",
-       .irq = 54,
+       .irq = evt2irq(0x8c0),
 };
 
 static struct resource veu_resources[] = {
@@ -185,7 +186,7 @@ static struct platform_device veu_device = {
 static struct uio_info jpu_platform_data = {
        .name = "JPU",
        .version = "0",
-       .irq = 27,
+       .irq = evt2irq(0x560),
 };
 
 static struct resource jpu_resources[] = {
@@ -224,7 +225,7 @@ static struct resource cmt_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 104,
+               .start  = evt2irq(0xf00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -252,7 +253,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -280,7 +281,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -307,7 +308,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 87773869a2f3e952f8eb18a10b700f01cfe14e6e..0bd09d51419fefebc683e8c0edf476e232694298 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/usb/r8a66597.h>
 #include <asm/clock.h>
 
@@ -25,7 +26,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 80, 80, 80, 80 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc00)),
 };
 
 static struct platform_device scif0_device = {
@@ -44,8 +45,8 @@ static struct resource iic_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 96,
-               .end    = 99,
+               .start  = evt2irq(0xe00),
+               .end    = evt2irq(0xe60),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -68,8 +69,8 @@ static struct resource usb_host_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 65,
-               .end    = 65,
+               .start  = evt2irq(0xa20),
+               .end    = evt2irq(0xa20),
                .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
@@ -89,7 +90,7 @@ static struct platform_device usb_host_device = {
 static struct uio_info vpu_platform_data = {
        .name = "VPU5",
        .version = "0",
-       .irq = 60,
+       .irq = evt2irq(0x980),
 };
 
 static struct resource vpu_resources[] = {
@@ -117,7 +118,7 @@ static struct platform_device vpu_device = {
 static struct uio_info veu0_platform_data = {
        .name = "VEU",
        .version = "0",
-       .irq = 54,
+       .irq = evt2irq(0x8c0),
 };
 
 static struct resource veu0_resources[] = {
@@ -145,7 +146,7 @@ static struct platform_device veu0_device = {
 static struct uio_info veu1_platform_data = {
        .name = "VEU",
        .version = "0",
-       .irq = 27,
+       .irq = evt2irq(0x560),
 };
 
 static struct resource veu1_resources[] = {
@@ -184,7 +185,7 @@ static struct resource cmt_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 104,
+               .start  = evt2irq(0xf00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -240,7 +241,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -267,7 +268,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 8420d4bc8bfc53ee9ff373ba0bb4a0afff358508..0f5a21907da627ad31566dc43d906699c8f8e7d2 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/uio_driver.h>
 #include <linux/usb/m66592.h>
 
@@ -147,20 +148,20 @@ static struct resource sh7722_dmae_resources[] = {
        },
        {
                .name   = "error_irq",
-               .start  = 78,
-               .end    = 78,
+               .start  = evt2irq(0xbc0),
+               .end    = evt2irq(0xbc0),
                .flags  = IORESOURCE_IRQ,
        },
        {
                /* IRQ for channels 0-3 */
-               .start  = 48,
-               .end    = 51,
+               .start  = evt2irq(0x800),
+               .end    = evt2irq(0x860),
                .flags  = IORESOURCE_IRQ,
        },
        {
                /* IRQ for channels 4-5 */
-               .start  = 76,
-               .end    = 77,
+               .start  = evt2irq(0xb80),
+               .end    = evt2irq(0xba0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -182,7 +183,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 80, 80, 80, 80 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc00)),
        .ops            = &sh7722_sci_port_ops,
        .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
@@ -201,7 +202,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 81, 81, 81, 81 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc20)),
        .ops            = &sh7722_sci_port_ops,
        .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
@@ -220,7 +221,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 82, 82, 82, 82 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc40)),
        .ops            = &sh7722_sci_port_ops,
        .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
@@ -241,17 +242,17 @@ static struct resource rtc_resources[] = {
        },
        [1] = {
                /* Period IRQ */
-               .start  = 45,
+               .start  = evt2irq(0x7a0),
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
                /* Carry IRQ */
-               .start  = 46,
+               .start  = evt2irq(0x7c0),
                .flags  = IORESOURCE_IRQ,
        },
        [3] = {
                /* Alarm IRQ */
-               .start  = 44,
+               .start  = evt2irq(0x780),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -275,8 +276,8 @@ static struct resource usbf_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 65,
-               .end    = 65,
+               .start  = evt2irq(0xa20),
+               .end    = evt2irq(0xa20),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -301,8 +302,8 @@ static struct resource iic_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 96,
-               .end    = 99,
+               .start  = evt2irq(0xe00),
+               .end    = evt2irq(0xe60),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -317,7 +318,7 @@ static struct platform_device iic_device = {
 static struct uio_info vpu_platform_data = {
        .name = "VPU4",
        .version = "0",
-       .irq = 60,
+       .irq = evt2irq(0x980),
 };
 
 static struct resource vpu_resources[] = {
@@ -345,7 +346,7 @@ static struct platform_device vpu_device = {
 static struct uio_info veu_platform_data = {
        .name = "VEU",
        .version = "0",
-       .irq = 54,
+       .irq = evt2irq(0x8c0),
 };
 
 static struct resource veu_resources[] = {
@@ -373,7 +374,7 @@ static struct platform_device veu_device = {
 static struct uio_info jpu_platform_data = {
        .name = "JPU",
        .version = "0",
-       .irq = 27,
+       .irq = evt2irq(0x560),
 };
 
 static struct resource jpu_resources[] = {
@@ -412,7 +413,7 @@ static struct resource cmt_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 104,
+               .start  = evt2irq(0xf00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -440,7 +441,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -468,7 +469,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -525,7 +526,7 @@ static struct resource siu_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 108,
+               .start  = evt2irq(0xf80),
                .flags  = IORESOURCE_IRQ,
        },
 };
index a188c9ea4393b3443b8564a020b7c6bb3ae9c1e1..28d6fd835fe001a5b7a7692da577c26e9ba50e4a 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/uio_driver.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/io.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
@@ -28,7 +29,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 80, 80, 80, 80 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc00)),
        .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
@@ -47,7 +48,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 81, 81, 81, 81 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc20)),
        .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
@@ -66,7 +67,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 82, 82, 82, 82 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc40)),
        .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
@@ -85,7 +86,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
        .type           = PORT_SCIFA,
-       .irqs           = { 56, 56, 56, 56 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x900)),
 };
 
 static struct platform_device scif3_device = {
@@ -103,7 +104,7 @@ static struct plat_sci_port scif4_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
        .type           = PORT_SCIFA,
-       .irqs           = { 88, 88, 88, 88 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xd00)),
 };
 
 static struct platform_device scif4_device = {
@@ -121,7 +122,7 @@ static struct plat_sci_port scif5_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
        .type           = PORT_SCIFA,
-       .irqs           = { 109, 109, 109, 109 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xfa0)),
 };
 
 static struct platform_device scif5_device = {
@@ -135,7 +136,7 @@ static struct platform_device scif5_device = {
 static struct uio_info vpu_platform_data = {
        .name = "VPU5",
        .version = "0",
-       .irq = 60,
+       .irq = evt2irq(0x980),
 };
 
 static struct resource vpu_resources[] = {
@@ -163,7 +164,7 @@ static struct platform_device vpu_device = {
 static struct uio_info veu0_platform_data = {
        .name = "VEU2H",
        .version = "0",
-       .irq = 54,
+       .irq = evt2irq(0x8c0),
 };
 
 static struct resource veu0_resources[] = {
@@ -191,7 +192,7 @@ static struct platform_device veu0_device = {
 static struct uio_info veu1_platform_data = {
        .name = "VEU2H",
        .version = "0",
-       .irq = 27,
+       .irq = evt2irq(0x560),
 };
 
 static struct resource veu1_resources[] = {
@@ -230,7 +231,7 @@ static struct resource cmt_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 104,
+               .start  = evt2irq(0xf00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -258,7 +259,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -286,7 +287,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -313,7 +314,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -340,7 +341,7 @@ static struct resource tmu3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 57,
+               .start  = evt2irq(0x920),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -367,7 +368,7 @@ static struct resource tmu4_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 58,
+               .start  = evt2irq(0x940),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -394,7 +395,7 @@ static struct resource tmu5_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 57,
+               .start  = evt2irq(0x920),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -417,17 +418,17 @@ static struct resource rtc_resources[] = {
        },
        [1] = {
                /* Period IRQ */
-               .start  = 69,
+               .start  = evt2irq(0xaa0),
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
                /* Carry IRQ */
-               .start  = 70,
+               .start  = evt2irq(0xac0),
                .flags  = IORESOURCE_IRQ,
        },
        [3] = {
                /* Alarm IRQ */
-               .start  = 68,
+               .start  = evt2irq(0xa80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -450,8 +451,8 @@ static struct resource sh7723_usb_host_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 65,
-               .end    = 65,
+               .start  = evt2irq(0xa20),
+               .end    = evt2irq(0xa20),
                .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
@@ -476,8 +477,8 @@ static struct resource iic_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 96,
-               .end    = 99,
+               .start  = evt2irq(0xe00),
+               .end    = evt2irq(0xe60),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 4c671cfe68aaaf517b4087fb98b2a13c8d73db6c..26b74c2f94968de7f56ead9227fe46751c6b67b6 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/uio_driver.h>
 #include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/io.h>
 #include <linux/notifier.h>
 
@@ -215,20 +216,20 @@ static struct resource sh7724_dmae0_resources[] = {
        },
        {
                .name   = "error_irq",
-               .start  = 78,
-               .end    = 78,
+               .start  = evt2irq(0xbc0),
+               .end    = evt2irq(0xbc0),
                .flags  = IORESOURCE_IRQ,
        },
        {
                /* IRQ for channels 0-3 */
-               .start  = 48,
-               .end    = 51,
+               .start  = evt2irq(0x800),
+               .end    = evt2irq(0x860),
                .flags  = IORESOURCE_IRQ,
        },
        {
                /* IRQ for channels 4-5 */
-               .start  = 76,
-               .end    = 77,
+               .start  = evt2irq(0xb80),
+               .end    = evt2irq(0xba0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -249,20 +250,20 @@ static struct resource sh7724_dmae1_resources[] = {
        },
        {
                .name   = "error_irq",
-               .start  = 74,
-               .end    = 74,
+               .start  = evt2irq(0xb40),
+               .end    = evt2irq(0xb40),
                .flags  = IORESOURCE_IRQ,
        },
        {
                /* IRQ for channels 0-3 */
-               .start  = 40,
-               .end    = 43,
+               .start  = evt2irq(0x700),
+               .end    = evt2irq(0x760),
                .flags  = IORESOURCE_IRQ,
        },
        {
                /* IRQ for channels 4-5 */
-               .start  = 72,
-               .end    = 73,
+               .start  = evt2irq(0xb00),
+               .end    = evt2irq(0xb20),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -295,7 +296,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 80, 80, 80, 80 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc00)),
        .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
@@ -314,7 +315,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 81, 81, 81, 81 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc20)),
        .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
@@ -333,7 +334,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 82, 82, 82, 82 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xc40)),
        .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
@@ -352,7 +353,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
        .type           = PORT_SCIFA,
-       .irqs           = { 56, 56, 56, 56 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x900)),
 };
 
 static struct platform_device scif3_device = {
@@ -370,7 +371,7 @@ static struct plat_sci_port scif4_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
        .type           = PORT_SCIFA,
-       .irqs           = { 88, 88, 88, 88 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xd00)),
 };
 
 static struct platform_device scif4_device = {
@@ -388,7 +389,7 @@ static struct plat_sci_port scif5_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
        .type           = PORT_SCIFA,
-       .irqs           = { 109, 109, 109, 109 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xfa0)),
 };
 
 static struct platform_device scif5_device = {
@@ -408,17 +409,17 @@ static struct resource rtc_resources[] = {
        },
        [1] = {
                /* Period IRQ */
-               .start  = 69,
+               .start  = evt2irq(0xaa0),
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
                /* Carry IRQ */
-               .start  = 70,
+               .start  = evt2irq(0xac0),
                .flags  = IORESOURCE_IRQ,
        },
        [3] = {
                /* Alarm IRQ */
-               .start  = 68,
+               .start  = evt2irq(0xa80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -439,8 +440,8 @@ static struct resource iic0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 96,
-               .end    = 99,
+               .start  = evt2irq(0xe00),
+               .end    = evt2irq(0xe60),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -461,8 +462,8 @@ static struct resource iic1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 92,
-               .end    = 95,
+               .start  = evt2irq(0xd80),
+               .end    = evt2irq(0xde0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -478,7 +479,7 @@ static struct platform_device iic1_device = {
 static struct uio_info vpu_platform_data = {
        .name = "VPU5F",
        .version = "0",
-       .irq = 60,
+       .irq = evt2irq(0x980),
 };
 
 static struct resource vpu_resources[] = {
@@ -507,7 +508,7 @@ static struct platform_device vpu_device = {
 static struct uio_info veu0_platform_data = {
        .name = "VEU3F0",
        .version = "0",
-       .irq = 83,
+       .irq = evt2irq(0xc60),
 };
 
 static struct resource veu0_resources[] = {
@@ -536,7 +537,7 @@ static struct platform_device veu0_device = {
 static struct uio_info veu1_platform_data = {
        .name = "VEU3F1",
        .version = "0",
-       .irq = 54,
+       .irq = evt2irq(0x8c0),
 };
 
 static struct resource veu1_resources[] = {
@@ -633,7 +634,7 @@ static struct resource cmt_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 104,
+               .start  = evt2irq(0xf00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -661,7 +662,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -689,7 +690,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -716,7 +717,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -744,7 +745,7 @@ static struct resource tmu3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 57,
+               .start  = evt2irq(0x920),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -771,7 +772,7 @@ static struct resource tmu4_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 58,
+               .start  = evt2irq(0x940),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -798,7 +799,7 @@ static struct resource tmu5_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 57,
+               .start  = evt2irq(0x920),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -817,7 +818,7 @@ static struct platform_device tmu5_device = {
 static struct uio_info jpu_platform_data = {
        .name = "JPU",
        .version = "0",
-       .irq = 27,
+       .irq = evt2irq(0x560),
 };
 
 static struct resource jpu_resources[] = {
@@ -846,7 +847,7 @@ static struct platform_device jpu_device = {
 static struct uio_info spu0_platform_data = {
        .name = "SPU2DSP0",
        .version = "0",
-       .irq = 86,
+       .irq = evt2irq(0xcc0),
 };
 
 static struct resource spu0_resources[] = {
@@ -875,7 +876,7 @@ static struct platform_device spu0_device = {
 static struct uio_info spu1_platform_data = {
        .name = "SPU2DSP1",
        .version = "0",
-       .irq = 87,
+       .irq = evt2irq(0xce0),
 };
 
 static struct resource spu1_resources[] = {
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7734.c b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
new file mode 100644 (file)
index 0000000..f799971
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/setup-sh7734.c
+
+ * SH7734 Setup
+ *
+ * Copyright (C) 2011,2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ * Copyright (C) 2011,2012 Renesas Solutions Corp.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
+#include <asm/clock.h>
+#include <asm/irq.h>
+#include <cpu/sh7734.h>
+
+/* SCIF */
+static struct plat_sci_port scif0_platform_data = {
+       .mapbase        = 0xFFE40000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x8C0)),
+       .regtype        = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif0_device = {
+       .name           = "sh-sci",
+       .id                     = 0,
+       .dev            = {
+               .platform_data  = &scif0_platform_data,
+       },
+};
+
+static struct plat_sci_port scif1_platform_data = {
+       .mapbase        = 0xFFE41000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x8E0)),
+       .regtype        = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif1_device = {
+       .name           = "sh-sci",
+       .id         = 1,
+       .dev            = {
+               .platform_data = &scif1_platform_data,
+       },
+};
+
+static struct plat_sci_port scif2_platform_data = {
+       .mapbase        = 0xFFE42000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x900)),
+       .regtype        = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif2_device = {
+       .name           = "sh-sci",
+       .id         = 2,
+       .dev            = {
+               .platform_data = &scif2_platform_data,
+       },
+};
+
+static struct plat_sci_port scif3_platform_data = {
+       .mapbase        = 0xFFE43000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x920)),
+       .regtype        = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif3_device = {
+       .name           = "sh-sci",
+       .id             = 3,
+       .dev            = {
+               .platform_data  = &scif3_platform_data,
+       },
+};
+
+static struct plat_sci_port scif4_platform_data = {
+       .mapbase        = 0xFFE44000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x940)),
+       .regtype        = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif4_device = {
+       .name           = "sh-sci",
+       .id             = 4,
+       .dev            = {
+               .platform_data  = &scif4_platform_data,
+       },
+};
+
+static struct plat_sci_port scif5_platform_data = {
+       .mapbase        = 0xFFE43000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x960)),
+       .regtype                = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif5_device = {
+       .name           = "sh-sci",
+       .id             = 5,
+       .dev            = {
+               .platform_data  = &scif5_platform_data,
+       },
+};
+
+/* RTC */
+static struct resource rtc_resources[] = {
+       [0] = {
+               .name   = "rtc",
+               .start  = 0xFFFC5000,
+               .end    = 0xFFFC5000 + 0x26 - 1,
+               .flags  = IORESOURCE_IO,
+       },
+       [1] = {
+               .start  = evt2irq(0xC00),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device rtc_device = {
+       .name           = "sh-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(rtc_resources),
+       .resource       = rtc_resources,
+};
+
+/* I2C 0 */
+static struct resource i2c0_resources[] = {
+       [0] = {
+               .name   = "IIC0",
+               .start  = 0xFFC70000,
+               .end    = 0xFFC7000A - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x860),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device i2c0_device = {
+       .name           = "i2c-sh7734",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(i2c0_resources),
+       .resource       = i2c0_resources,
+};
+
+/* TMU */
+static struct sh_timer_config tmu0_platform_data = {
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+       [0] = {
+               .start  = 0xFFD80008,
+               .end    = 0xFFD80014 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x400),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu0_device = {
+       .name   = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu0_platform_data,
+       },
+       .resource       = tmu0_resources,
+       .num_resources  = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+       [0] = {
+               .start  = 0xFFD80014,
+               .end    = 0xFFD80020 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x420),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu1_device = {
+       .name           = "sh_tmu",
+       .id                     = 1,
+       .dev = {
+               .platform_data  = &tmu1_platform_data,
+       },
+       .resource       = tmu1_resources,
+       .num_resources  = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+};
+
+static struct resource tmu2_resources[] = {
+       [0] = {
+               .start  = 0xFFD80020,
+               .end    = 0xFFD80030 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x440),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu2_device = {
+       .name           = "sh_tmu",
+       .id                     = 2,
+       .dev = {
+               .platform_data  = &tmu2_platform_data,
+       },
+       .resource       = tmu2_resources,
+       .num_resources  = ARRAY_SIZE(tmu2_resources),
+};
+
+
+static struct sh_timer_config tmu3_platform_data = {
+       .channel_offset = 0x04,
+       .timer_bit = 0,
+};
+
+static struct resource tmu3_resources[] = {
+       [0] = {
+               .start  = 0xFFD81008,
+               .end    = 0xFFD81014 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x480),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu3_device = {
+       .name           = "sh_tmu",
+       .id                     = 3,
+       .dev = {
+               .platform_data  = &tmu3_platform_data,
+       },
+       .resource       = tmu3_resources,
+       .num_resources  = ARRAY_SIZE(tmu3_resources),
+};
+
+static struct sh_timer_config tmu4_platform_data = {
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+};
+
+static struct resource tmu4_resources[] = {
+       [0] = {
+               .start  = 0xFFD81014,
+               .end    = 0xFFD81020 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x4A0),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu4_device = {
+       .name           = "sh_tmu",
+       .id                     = 4,
+       .dev = {
+               .platform_data  = &tmu4_platform_data,
+       },
+       .resource       = tmu4_resources,
+       .num_resources  = ARRAY_SIZE(tmu4_resources),
+};
+
+static struct sh_timer_config tmu5_platform_data = {
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+};
+
+static struct resource tmu5_resources[] = {
+       [0] = {
+               .start  = 0xFFD81020,
+               .end    = 0xFFD81030 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x4C0),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu5_device = {
+       .name           = "sh_tmu",
+       .id                     = 5,
+       .dev = {
+               .platform_data  = &tmu5_platform_data,
+       },
+       .resource       = tmu5_resources,
+       .num_resources  = ARRAY_SIZE(tmu5_resources),
+};
+
+static struct sh_timer_config tmu6_platform_data = {
+       .channel_offset = 0x4,
+       .timer_bit = 0,
+};
+
+static struct resource tmu6_resources[] = {
+       [0] = {
+               .start  = 0xFFD82008,
+               .end    = 0xFFD82014 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x500),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu6_device = {
+       .name           = "sh_tmu",
+       .id                     = 6,
+       .dev = {
+               .platform_data  = &tmu6_platform_data,
+       },
+       .resource       = tmu6_resources,
+       .num_resources  = ARRAY_SIZE(tmu6_resources),
+};
+
+static struct sh_timer_config tmu7_platform_data = {
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+};
+
+static struct resource tmu7_resources[] = {
+       [0] = {
+               .start  = 0xFFD82014,
+               .end    = 0xFFD82020 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x520),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu7_device = {
+       .name           = "sh_tmu",
+       .id                     = 7,
+       .dev = {
+               .platform_data  = &tmu7_platform_data,
+       },
+       .resource       = tmu7_resources,
+       .num_resources  = ARRAY_SIZE(tmu7_resources),
+};
+
+static struct sh_timer_config tmu8_platform_data = {
+       .channel_offset = 0x1c,
+       .timer_bit = 2,
+};
+
+static struct resource tmu8_resources[] = {
+       [0] = {
+               .start  = 0xFFD82020,
+               .end    = 0xFFD82030 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x540),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu8_device = {
+       .name           = "sh_tmu",
+       .id                     = 8,
+       .dev = {
+               .platform_data  = &tmu8_platform_data,
+       },
+       .resource       = tmu8_resources,
+       .num_resources  = ARRAY_SIZE(tmu8_resources),
+};
+
+static struct platform_device *sh7734_devices[] __initdata = {
+       &scif0_device,
+       &scif1_device,
+       &scif2_device,
+       &scif3_device,
+       &scif4_device,
+       &scif5_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
+       &tmu6_device,
+       &tmu7_device,
+       &tmu8_device,
+       &rtc_device,
+};
+
+static struct platform_device *sh7734_early_devices[] __initdata = {
+       &scif0_device,
+       &scif1_device,
+       &scif2_device,
+       &scif3_device,
+       &scif4_device,
+       &scif5_device,
+       &tmu0_device,
+       &tmu1_device,
+       &tmu2_device,
+       &tmu3_device,
+       &tmu4_device,
+       &tmu5_device,
+       &tmu6_device,
+       &tmu7_device,
+       &tmu8_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+       early_platform_add_devices(sh7734_early_devices,
+               ARRAY_SIZE(sh7734_early_devices));
+}
+
+#define GROUP 0
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+
+       IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
+       IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
+       IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
+       IRL0_HHLL, IRL0_HHLH, IRL0_HHHL,
+
+       IRQ0, IRQ1, IRQ2, IRQ3,
+       DU,
+       TMU00, TMU10, TMU20, TMU21,
+       TMU30, TMU40, TMU50, TMU51,
+       TMU60, TMU70, TMU80,
+       RESET_WDT,
+       USB,
+       HUDI,
+       SHDMAC,
+       SSI0, SSI1,     SSI2, SSI3,
+       VIN0,
+       RGPVG,
+       _2DG,
+       MMC,
+       HSPI,
+       LBSCATA,
+       I2C0,
+       RCAN0,
+       MIMLB,
+       SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5,
+       LBSCDMAC0, LBSCDMAC1, LBSCDMAC2,
+       RCAN1,
+       SDHI0, SDHI1,
+       IEBUS,
+       HPBDMAC0_3, HPBDMAC4_10, HPBDMAC11_18, HPBDMAC19_22, HPBDMAC23_25_27_28,
+       RTC,
+       VIN1,
+       LCDC,
+       SRC0, SRC1,
+       GETHER,
+       SDHI2,
+       GPIO0_3, GPIO4_5,
+       STIF0, STIF1,
+       ADMAC,
+       HIF,
+       FLCTL,
+       ADC,
+       MTU2,
+       RSPI,
+       QSPI,
+       HSCIF,
+       VEU3F_VE3,
+
+       /* Group */
+       /* Mask */
+       STIF_M,
+       GPIO_M,
+       HPBDMAC_M,
+       LBSCDMAC_M,
+       RCAN_M,
+       SRC_M,
+       SCIF_M,
+       LCDC_M,
+       _2DG_M,
+       VIN_M,
+       TMU_3_M,
+       TMU_0_M,
+
+       /* Priority */
+       RCAN_P,
+       LBSCDMAC_P,
+
+       /* Common */
+       SDHI,
+       SSI,
+       SPI,
+};
+
+static struct intc_vect vectors[] __initdata = {
+       INTC_VECT(DU, 0x3E0),
+       INTC_VECT(TMU00, 0x400),
+       INTC_VECT(TMU10, 0x420),
+       INTC_VECT(TMU20, 0x440),
+       INTC_VECT(TMU30, 0x480),
+       INTC_VECT(TMU40, 0x4A0),
+       INTC_VECT(TMU50, 0x4C0),
+       INTC_VECT(TMU51, 0x4E0),
+       INTC_VECT(TMU60, 0x500),
+       INTC_VECT(TMU70, 0x520),
+       INTC_VECT(TMU80, 0x540),
+       INTC_VECT(RESET_WDT, 0x560),
+       INTC_VECT(USB, 0x580),
+       INTC_VECT(HUDI, 0x600),
+       INTC_VECT(SHDMAC, 0x620),
+       INTC_VECT(SSI0, 0x6C0),
+       INTC_VECT(SSI1, 0x6E0),
+       INTC_VECT(SSI2, 0x700),
+       INTC_VECT(SSI3, 0x720),
+       INTC_VECT(VIN0, 0x740),
+       INTC_VECT(RGPVG, 0x760),
+       INTC_VECT(_2DG, 0x780),
+       INTC_VECT(MMC, 0x7A0),
+       INTC_VECT(HSPI, 0x7E0),
+       INTC_VECT(LBSCATA, 0x840),
+       INTC_VECT(I2C0, 0x860),
+       INTC_VECT(RCAN0, 0x880),
+       INTC_VECT(SCIF0, 0x8A0),
+       INTC_VECT(SCIF1, 0x8C0),
+       INTC_VECT(SCIF2, 0x900),
+       INTC_VECT(SCIF3, 0x920),
+       INTC_VECT(SCIF4, 0x940),
+       INTC_VECT(SCIF5, 0x960),
+       INTC_VECT(LBSCDMAC0, 0x9E0),
+       INTC_VECT(LBSCDMAC1, 0xA00),
+       INTC_VECT(LBSCDMAC2, 0xA20),
+       INTC_VECT(RCAN1, 0xA60),
+       INTC_VECT(SDHI0, 0xAE0),
+       INTC_VECT(SDHI1, 0xB00),
+       INTC_VECT(IEBUS, 0xB20),
+       INTC_VECT(HPBDMAC0_3, 0xB60),
+       INTC_VECT(HPBDMAC4_10, 0xB80),
+       INTC_VECT(HPBDMAC11_18, 0xBA0),
+       INTC_VECT(HPBDMAC19_22, 0xBC0),
+       INTC_VECT(HPBDMAC23_25_27_28, 0xBE0),
+       INTC_VECT(RTC, 0xC00),
+       INTC_VECT(VIN1, 0xC20),
+       INTC_VECT(LCDC, 0xC40),
+       INTC_VECT(SRC0, 0xC60),
+       INTC_VECT(SRC1, 0xC80),
+       INTC_VECT(GETHER, 0xCA0),
+       INTC_VECT(SDHI2, 0xCC0),
+       INTC_VECT(GPIO0_3, 0xCE0),
+       INTC_VECT(GPIO4_5, 0xD00),
+       INTC_VECT(STIF0, 0xD20),
+       INTC_VECT(STIF1, 0xD40),
+       INTC_VECT(ADMAC, 0xDA0),
+       INTC_VECT(HIF, 0xDC0),
+       INTC_VECT(FLCTL, 0xDE0),
+       INTC_VECT(ADC, 0xE00),
+       INTC_VECT(MTU2, 0xE20),
+       INTC_VECT(RSPI, 0xE40),
+       INTC_VECT(QSPI, 0xE60),
+       INTC_VECT(HSCIF, 0xFC0),
+       INTC_VECT(VEU3F_VE3, 0xF40),
+};
+
+static struct intc_group groups[] __initdata = {
+       /* Common */
+       INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2),
+       INTC_GROUP(SPI, HSPI, RSPI, QSPI),
+       INTC_GROUP(SSI, SSI0, SSI1, SSI2, SSI3),
+
+       /* Mask group */
+       INTC_GROUP(STIF_M, STIF0, STIF1), /* 22 */
+       INTC_GROUP(GPIO_M, GPIO0_3, GPIO4_5), /* 21 */
+       INTC_GROUP(HPBDMAC_M, HPBDMAC0_3, HPBDMAC4_10, HPBDMAC11_18,
+                       HPBDMAC19_22, HPBDMAC23_25_27_28), /* 19 */
+       INTC_GROUP(LBSCDMAC_M, LBSCDMAC0, LBSCDMAC1, LBSCDMAC2), /* 18 */
+       INTC_GROUP(RCAN_M, RCAN0, RCAN1, IEBUS), /* 17 */
+       INTC_GROUP(SRC_M, SRC0, SRC1), /* 16 */
+       INTC_GROUP(SCIF_M, SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5,
+                       HSCIF), /* 14 */
+       INTC_GROUP(LCDC_M, LCDC, MIMLB), /* 13 */
+       INTC_GROUP(_2DG_M, _2DG, RGPVG), /* 12 */
+       INTC_GROUP(VIN_M, VIN0, VIN1), /* 10 */
+       INTC_GROUP(TMU_3_M, TMU30, TMU40, TMU50, TMU51,
+                       TMU60, TMU60, TMU70, TMU80), /* 2 */
+       INTC_GROUP(TMU_0_M, TMU00, TMU10, TMU20, TMU21), /* 1 */
+
+       /* Priority group*/
+       INTC_GROUP(RCAN_P, RCAN0, RCAN1), /* INT2PRI5 */
+       INTC_GROUP(LBSCDMAC_P, LBSCDMAC0, LBSCDMAC1), /* INT2PRI5 */
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+       { 0xFF804040, 0xFF804044, 32, /* INT2MSKRG / INT2MSKCR */
+         { 0,
+               VEU3F_VE3,
+               SDHI, /* SDHI 0-2 */
+               ADMAC,
+               FLCTL,
+               RESET_WDT,
+               HIF,
+               ADC,
+               MTU2,
+               STIF_M, /* STIF 0,1 */
+               GPIO_M, /* GPIO 0-5*/
+               GETHER,
+               HPBDMAC_M, /* HPBDMAC 0_3 - 23_25_27_28 */
+               LBSCDMAC_M, /* LBSCDMAC 0 - 2 */
+               RCAN_M, /* RCAN, IEBUS */
+               SRC_M,  /* SRC 0,1 */
+               LBSCATA,
+               SCIF_M, /* SCIF 0-5, HSCIF */
+               LCDC_M, /* LCDC, MIMLB */
+               _2DG_M, /* 2DG, RGPVG */
+               SPI, /* HSPI, RSPI, QSPI */
+               VIN_M,  /* VIN0, 1 */
+               SSI,    /* SSI 0-3 */
+               USB,
+               SHDMAC,
+               HUDI,
+               MMC,
+               RTC,
+               I2C0, /* I2C */ /* I2C 0, 1*/
+               TMU_3_M, /* TMU30 - TMU80 */
+               TMU_0_M, /* TMU00 - TMU21 */
+               DU } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+       { 0xFF804000, 0, 32, 8, /* INT2PRI0 */
+               { DU, TMU00, TMU10, TMU20 } },
+       { 0xFF804004, 0, 32, 8, /* INT2PRI1 */
+               { TMU30, TMU60, RTC, SDHI } },
+       { 0xFF804008, 0, 32, 8, /* INT2PRI2 */
+               { HUDI, SHDMAC, USB, SSI } },
+       { 0xFF80400C, 0, 32, 8, /* INT2PRI3 */
+               { VIN0, SPI, _2DG, LBSCATA } },
+       { 0xFF804010, 0, 32, 8, /* INT2PRI4 */
+               { SCIF0, SCIF3, HSCIF, LCDC } },
+       { 0xFF804014, 0, 32, 8, /* INT2PRI5 */
+               { RCAN_P, LBSCDMAC_P, LBSCDMAC2, MMC } },
+       { 0xFF804018, 0, 32, 8, /* INT2PRI6 */
+               { HPBDMAC0_3, HPBDMAC4_10, HPBDMAC11_18, HPBDMAC19_22 } },
+       { 0xFF80401C, 0, 32, 8, /* INT2PRI7 */
+               { HPBDMAC23_25_27_28, I2C0, SRC0, SRC1 } },
+       { 0xFF804020, 0, 32, 8, /* INT2PRI8 */
+               { 0 /* ADIF */, VIN1, RESET_WDT, HIF } },
+       { 0xFF804024, 0, 32, 8, /* INT2PRI9 */
+               { ADMAC, FLCTL, GPIO0_3, GPIO4_5 } },
+       { 0xFF804028, 0, 32, 8, /* INT2PRI10 */
+               { STIF0, STIF1, VEU3F_VE3, GETHER } },
+       { 0xFF80402C, 0, 32, 8, /* INT2PRI11 */
+               { MTU2, RGPVG, MIMLB, IEBUS } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7734", vectors, groups,
+       mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+
+static struct intc_vect irq3210_vectors[] __initdata = {
+       INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+       INTC_VECT(IRQ2, 0x2C0), INTC_VECT(IRQ3, 0x300),
+};
+
+static struct intc_sense_reg irq3210_sense_registers[] __initdata = {
+       { 0xFF80201C, 32, 2, /* ICR1 */
+       { IRQ0, IRQ1, IRQ2, IRQ3, } },
+};
+
+static struct intc_mask_reg irq3210_ack_registers[] __initdata = {
+       { 0xFF802024, 0, 32, /* INTREQ */
+       { IRQ0, IRQ1, IRQ2, IRQ3, } },
+};
+
+static struct intc_mask_reg irq3210_mask_registers[] __initdata = {
+       { 0xFF802044, 0xFF802064, 32, /* INTMSK0 / INTMSKCLR0 */
+       { IRQ0, IRQ1, IRQ2, IRQ3, } },
+};
+
+static struct intc_prio_reg irq3210_prio_registers[] __initdata = {
+       { 0xFF802010, 0, 32, 4, /* INTPRI */
+       { IRQ0, IRQ1, IRQ2, IRQ3, } },
+};
+
+static DECLARE_INTC_DESC_ACK(intc_desc_irq3210, "sh7734-irq3210",
+       irq3210_vectors, NULL,
+       irq3210_mask_registers, irq3210_prio_registers,
+       irq3210_sense_registers, irq3210_ack_registers);
+
+/* External interrupt pins in IRL mode */
+
+static struct intc_vect vectors_irl3210[] __initdata = {
+       INTC_VECT(IRL0_LLLL, 0x200), INTC_VECT(IRL0_LLLH, 0x220),
+       INTC_VECT(IRL0_LLHL, 0x240), INTC_VECT(IRL0_LLHH, 0x260),
+       INTC_VECT(IRL0_LHLL, 0x280), INTC_VECT(IRL0_LHLH, 0x2a0),
+       INTC_VECT(IRL0_LHHL, 0x2c0), INTC_VECT(IRL0_LHHH, 0x2e0),
+       INTC_VECT(IRL0_HLLL, 0x300), INTC_VECT(IRL0_HLLH, 0x320),
+       INTC_VECT(IRL0_HLHL, 0x340), INTC_VECT(IRL0_HLHH, 0x360),
+       INTC_VECT(IRL0_HHLL, 0x380), INTC_VECT(IRL0_HHLH, 0x3a0),
+       INTC_VECT(IRL0_HHHL, 0x3c0),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irl3210, "sh7734-irl3210",
+       vectors_irl3210, NULL, mask_registers, NULL, NULL);
+
+#define INTC_ICR0              0xFF802000
+#define INTC_INTMSK0    0xFF802044
+#define INTC_INTMSK1    0xFF802048
+#define INTC_INTMSKCLR0 0xFF802064
+#define INTC_INTMSKCLR1 0xFF802068
+
+void __init plat_irq_setup(void)
+{
+       /* disable IRQ3-0 */
+       __raw_writel(0xF0000000, INTC_INTMSK0);
+
+       /* disable IRL3-0 */
+       __raw_writel(0x80000000, INTC_INTMSK1);
+
+       /* select IRL mode for IRL3-0 */
+       __raw_writel(__raw_readl(INTC_ICR0) & ~0x00800000, INTC_ICR0);
+
+       /* disable holding function, ie enable "SH-4 Mode (LVLMODE)" */
+       __raw_writel(__raw_readl(INTC_ICR0) | 0x00200000, INTC_ICR0);
+
+       register_intc_controller(&intc_desc);
+}
+
+void __init plat_irq_setup_pins(int mode)
+{
+       switch (mode) {
+       case IRQ_MODE_IRQ3210:
+               /* select IRQ mode for IRL3-0 */
+               __raw_writel(__raw_readl(INTC_ICR0) | 0x00800000, INTC_ICR0);
+               register_intc_controller(&intc_desc_irq3210);
+               break;
+       case IRQ_MODE_IRL3210:
+               /* enable IRL0-3 but don't provide any masking */
+               __raw_writel(0x80000000, INTC_INTMSKCLR1);
+               __raw_writel(0xf0000000, INTC_INTMSKCLR0);
+               break;
+       case IRQ_MODE_IRL3210_MASK:
+               /* enable IRL0-3 and mask using cpu intc controller */
+               __raw_writel(0x80000000, INTC_INTMSKCLR0);
+               register_intc_controller(&intc_desc_irl3210);
+               break;
+       default:
+               BUG();
+       }
+}
index c8836cffa2167471ebd3f55eeee28bab1dc758aa..a7708425afa9d955e5144c451a4d9264bc60726d 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/sh_timer.h>
 #include <linux/sh_dma.h>
-
+#include <linux/sh_intc.h>
 #include <cpu/dma-register.h>
 #include <cpu/sh7757.h>
 
@@ -28,7 +28,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 40, 40, 40, 40 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x700)),
 };
 
 static struct platform_device scif2_device = {
@@ -45,7 +45,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 76, 76, 76, 76 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xb80)),
 };
 
 static struct platform_device scif3_device = {
@@ -62,7 +62,7 @@ static struct plat_sci_port scif4_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 104, 104, 104, 104 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xF00)),
 };
 
 static struct platform_device scif4_device = {
@@ -86,7 +86,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 28,
+               .start  = evt2irq(0x580),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -114,7 +114,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 29,
+               .start  = evt2irq(0x5a0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -136,7 +136,7 @@ static struct resource spi0_resources[] = {
                .flags  = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
        },
        [1] = {
-               .start  = 86,
+               .start  = evt2irq(0xcc0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -466,8 +466,8 @@ static struct resource sh7757_dmae0_resources[] = {
        },
        {
                .name   = "error_irq",
-               .start  = 34,
-               .end    = 34,
+               .start  = evt2irq(0x640),
+               .end    = evt2irq(0x640),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
 };
@@ -488,56 +488,56 @@ static struct resource sh7757_dmae1_resources[] = {
        },
        {
                .name   = "error_irq",
-               .start  = 34,
-               .end    = 34,
+               .start  = evt2irq(0x640),
+               .end    = evt2irq(0x640),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
        {
                /* IRQ for channels 4 */
-               .start  = 46,
-               .end    = 46,
+               .start  = evt2irq(0x7c0),
+               .end    = evt2irq(0x7c0),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
        {
                /* IRQ for channels 5 */
-               .start  = 46,
-               .end    = 46,
+               .start  = evt2irq(0x7c0),
+               .end    = evt2irq(0x7c0),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
        {
                /* IRQ for channels 6 */
-               .start  = 88,
-               .end    = 88,
+               .start  = evt2irq(0xd00),
+               .end    = evt2irq(0xd00),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
        {
                /* IRQ for channels 7 */
-               .start  = 88,
-               .end    = 88,
+               .start  = evt2irq(0xd00),
+               .end    = evt2irq(0xd00),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
        {
                /* IRQ for channels 8 */
-               .start  = 88,
-               .end    = 88,
+               .start  = evt2irq(0xd00),
+               .end    = evt2irq(0xd00),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
        {
                /* IRQ for channels 9 */
-               .start  = 88,
-               .end    = 88,
+               .start  = evt2irq(0xd00),
+               .end    = evt2irq(0xd00),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
        {
                /* IRQ for channels 10 */
-               .start  = 88,
-               .end    = 88,
+               .start  = evt2irq(0xd00),
+               .end    = evt2irq(0xd00),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
        {
                /* IRQ for channels 11 */
-               .start  = 88,
-               .end    = 88,
+               .start  = evt2irq(0xd00),
+               .end    = evt2irq(0xd00),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
 };
@@ -558,20 +558,20 @@ static struct resource sh7757_dmae2_resources[] = {
        },
        {
                .name   = "error_irq",
-               .start  = 323,
-               .end    = 323,
+               .start  = evt2irq(0x2a60),
+               .end    = evt2irq(0x2a60),
                .flags  = IORESOURCE_IRQ,
        },
        {
                /* IRQ for channels 12 to 16 */
-               .start  = 272,
-               .end    = 276,
+               .start  = evt2irq(0x2400),
+               .end    = evt2irq(0x2480),
                .flags  = IORESOURCE_IRQ,
        },
        {
                /* IRQ for channel 17 */
-               .start  = 279,
-               .end    = 279,
+               .start  = evt2irq(0x24e0),
+               .end    = evt2irq(0x24e0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -592,20 +592,20 @@ static struct resource sh7757_dmae3_resources[] = {
        },
        {
                .name   = "error_irq",
-               .start  = 324,
-               .end    = 324,
+               .start  = evt2irq(0x2a80),
+               .end    = evt2irq(0x2a80),
                .flags  = IORESOURCE_IRQ,
        },
        {
                /* IRQ for channels 18 to 22 */
-               .start  = 280,
-               .end    = 284,
+               .start  = evt2irq(0x2500),
+               .end    = evt2irq(0x2580),
                .flags  = IORESOURCE_IRQ,
        },
        {
                /* IRQ for channel 23 */
-               .start  = 288,
-               .end    = 288,
+               .start  = evt2irq(0x2600),
+               .end    = evt2irq(0x2600),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -668,7 +668,7 @@ static struct resource spi1_resources[] = {
                .flags  = IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
        },
        {
-               .start  = 54,
+               .start  = evt2irq(0x8c0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -687,7 +687,7 @@ static struct resource rspi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               .start  = 220,
+               .start  = evt2irq(0x1d80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -706,8 +706,8 @@ static struct resource usb_ehci_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 57,
-               .end    = 57,
+               .start  = evt2irq(0x920),
+               .end    = evt2irq(0x920),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -730,8 +730,8 @@ static struct resource usb_ohci_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 57,
-               .end    = 57,
+               .start  = evt2irq(0x920),
+               .end    = evt2irq(0x920),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 00113515f23389d82baeab61841fc5c2a54d2e4b..bd0a8fbe610f678077cad20dc1b5af07f9b46b8b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/io.h>
 #include <linux/serial_sci.h>
 
@@ -22,7 +23,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 40, 40, 40, 40 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x700)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -40,7 +41,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 76, 76, 76, 76 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xb80)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -58,7 +59,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 104, 104, 104, 104 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xf00)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -78,7 +79,7 @@ static struct resource rtc_resources[] = {
        },
        [1] = {
                /* Shared Period/Carry/Alarm IRQ */
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -97,13 +98,14 @@ static struct resource usb_ohci_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 83,
-               .end    = 83,
+               .start  = evt2irq(0xc60),
+               .end    = evt2irq(0xc60),
                .flags  = IORESOURCE_IRQ,
        },
 };
 
 static u64 usb_ohci_dma_mask = 0xffffffffUL;
+
 static struct platform_device usb_ohci_device = {
        .name           = "sh_ohci",
        .id             = -1,
@@ -122,8 +124,8 @@ static struct resource usbf_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 84,
-               .end    = 84,
+               .start  = evt2irq(0xc80),
+               .end    = evt2irq(0xc80),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -152,7 +154,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 28,
+               .start  = evt2irq(0x580),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -180,7 +182,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 29,
+               .start  = evt2irq(0x5a0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -207,7 +209,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 30,
+               .start  = evt2irq(0x5c0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -234,7 +236,7 @@ static struct resource tmu3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 96,
+               .start  = evt2irq(0xe00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -261,7 +263,7 @@ static struct resource tmu4_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 97,
+               .start  = evt2irq(0xe20),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -288,7 +290,7 @@ static struct resource tmu5_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 98,
+               .start  = evt2irq(0xe40),
                .flags  = IORESOURCE_IRQ,
        },
 };
index 2c6aa22cf5f6438e311cabe2ed44dee60e09ec43..256ea7a451641bc79071b77da0dc76915d6bdc41 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <linux/io.h>
 
 static struct plat_sci_port scif0_platform_data = {
@@ -20,7 +21,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 61, 61, 61, 61 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x9a0)),
 };
 
 static struct platform_device scif0_device = {
@@ -37,7 +38,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 62, 62, 62, 62 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x9c0)),
 };
 
 static struct platform_device scif1_device = {
@@ -54,7 +55,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 63, 63, 63, 63 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x9e0)),
 };
 
 static struct platform_device scif2_device = {
@@ -71,7 +72,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 64, 64, 64, 64 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xa00)),
 };
 
 static struct platform_device scif3_device = {
@@ -88,7 +89,7 @@ static struct plat_sci_port scif4_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 65, 65, 65, 65 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xa20)),
 };
 
 static struct platform_device scif4_device = {
@@ -105,7 +106,7 @@ static struct plat_sci_port scif5_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 66, 66, 66, 66 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xa40)),
 };
 
 static struct platform_device scif5_device = {
@@ -122,7 +123,7 @@ static struct plat_sci_port scif6_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 67, 67, 67, 67 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xa60)),
 };
 
 static struct platform_device scif6_device = {
@@ -139,7 +140,7 @@ static struct plat_sci_port scif7_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 68, 68, 68, 68 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xa80)),
 };
 
 static struct platform_device scif7_device = {
@@ -156,7 +157,7 @@ static struct plat_sci_port scif8_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 69, 69, 69, 69 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xaa0)),
 };
 
 static struct platform_device scif8_device = {
@@ -173,7 +174,7 @@ static struct plat_sci_port scif9_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 70, 70, 70, 70 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xac0)),
 };
 
 static struct platform_device scif9_device = {
@@ -197,7 +198,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -225,7 +226,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -252,7 +253,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -279,7 +280,7 @@ static struct resource tmu3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 19,
+               .start  = evt2irq(0x460),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -306,7 +307,7 @@ static struct resource tmu4_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -333,7 +334,7 @@ static struct resource tmu5_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 21,
+               .start  = evt2irq(0x4a0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -360,7 +361,7 @@ static struct resource tmu6_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 22,
+               .start  = evt2irq(0x4c0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -387,7 +388,7 @@ static struct resource tmu7_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 23,
+               .start  = evt2irq(0x4e0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -414,7 +415,7 @@ static struct resource tmu8_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 24,
+               .start  = evt2irq(0x500),
                .flags  = IORESOURCE_IRQ,
        },
 };
index d431b0052d0c87b58a75d175096068bcb2a70781..de45b704687a07b695995a7d357dde59ce30fda9 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <cpu/dma-register.h>
 
 static struct plat_sci_port scif0_platform_data = {
@@ -22,7 +23,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 40, 40, 40, 40 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x700)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -40,7 +41,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 76, 76, 76, 76 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0xb80)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -65,7 +66,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 28,
+               .start  = evt2irq(0x580),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -93,7 +94,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 29,
+               .start  = evt2irq(0x5a0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -120,7 +121,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 30,
+               .start  = evt2irq(0x5c0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -147,7 +148,7 @@ static struct resource tmu3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 96,
+               .start  = evt2irq(0xe00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -174,7 +175,7 @@ static struct resource tmu4_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 97,
+               .start  = evt2irq(0xe20),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -201,7 +202,7 @@ static struct resource tmu5_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 98,
+               .start  = evt2irq(0xe40),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -224,7 +225,7 @@ static struct resource rtc_resources[] = {
        },
        [1] = {
                /* Shared Period/Carry/Alarm IRQ */
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -321,10 +322,13 @@ static struct resource sh7780_dmae0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               /* Real DMA error IRQ is 38, and channel IRQs are 34-37, 44-45 */
+               /*
+                * Real DMA error vector is 0x6c0, and channel
+                * vectors are 0x640-0x6a0, 0x780-0x7a0
+                */
                .name   = "error_irq",
-               .start  = 34,
-               .end    = 34,
+               .start  = evt2irq(0x640),
+               .end    = evt2irq(0x640),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
 };
@@ -338,10 +342,13 @@ static struct resource sh7780_dmae1_resources[] = {
        },
        /* DMAC1 has no DMARS */
        {
-               /* Real DMA error IRQ is 38, and channel IRQs are 46-47, 92-95 */
+               /*
+                * Real DMA error vector is 0x6c0, and channel
+                * vectors are 0x7c0-0x7e0, 0xd80-0xde0
+                */
                .name   = "error_irq",
-               .start  = 46,
-               .end    = 46,
+               .start  = evt2irq(0x7c0),
+               .end    = evt2irq(0x7c0),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
 };
index 81588ef15a6c09df110760888e33141f21633d6d..0968ecb962e6611fa30198bac2f2609a43093e98 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/mm.h>
 #include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <asm/mmzone.h>
 #include <cpu/dma-register.h>
 
@@ -24,7 +25,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 40, 40, 40, 40 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x700)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -42,7 +43,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 44, 44, 44, 44 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x780)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -60,7 +61,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 60, 60, 60, 60 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x980)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -78,7 +79,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 61, 61, 61, 61 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x9a0)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -96,7 +97,7 @@ static struct plat_sci_port scif4_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 62, 62, 62, 62 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x9c0)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -114,7 +115,7 @@ static struct plat_sci_port scif5_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 63, 63, 63, 63 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x9e0)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -139,7 +140,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 28,
+               .start  = evt2irq(0x580),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -167,7 +168,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 29,
+               .start  = evt2irq(0x5a0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -194,7 +195,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 30,
+               .start  = evt2irq(0x5c0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -221,7 +222,7 @@ static struct resource tmu3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 96,
+               .start  = evt2irq(0xe00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -248,7 +249,7 @@ static struct resource tmu4_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 97,
+               .start  = evt2irq(0xe20),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -275,7 +276,7 @@ static struct resource tmu5_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 98,
+               .start  = evt2irq(0xe40),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -375,10 +376,13 @@ static struct resource sh7785_dmae0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               /* Real DMA error IRQ is 39, and channel IRQs are 33-38 */
+               /*
+                * Real DMA error vector is 0x6e0, and channel
+                * vectors are 0x620-0x6c0
+                */
                .name   = "error_irq",
-               .start  = 33,
-               .end    = 33,
+               .start  = evt2irq(0x620),
+               .end    = evt2irq(0x620),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
 };
@@ -392,10 +396,13 @@ static struct resource sh7785_dmae1_resources[] = {
        },
        /* DMAC1 has no DMARS */
        {
-               /* Real DMA error IRQ is 58, and channel IRQs are 52-57 */
+               /*
+                * Real DMA error vector is 0x940, and channel
+                * vectors are 0x880-0x920
+                */
                .name   = "error_irq",
-               .start  = 52,
-               .end    = 52,
+               .start  = evt2irq(0x880),
+               .end    = evt2irq(0x880),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
        },
 };
index 599022d73b283237413bb0a5a3f874fad4e2affc..2e6952f87848e287a6ad042414fc8f3d9532ccc8 100644 (file)
@@ -32,7 +32,10 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 40, 41, 43, 42 },
+       .irqs           = { evt2irq(0x700),
+                           evt2irq(0x720),
+                           evt2irq(0x760),
+                           evt2irq(0x740) },
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -53,7 +56,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 44, 44, 44, 44 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x780)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -71,7 +74,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 50, 50, 50, 50 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x840)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -89,7 +92,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 51, 51, 51, 51 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x860)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -107,7 +110,7 @@ static struct plat_sci_port scif4_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 52, 52, 52, 52 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x880)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -125,7 +128,7 @@ static struct plat_sci_port scif5_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
-       .irqs           = { 53, 53, 53, 53 },
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x8a0)),
        .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
@@ -150,7 +153,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -178,7 +181,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -205,7 +208,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -232,7 +235,7 @@ static struct resource tmu3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -259,7 +262,7 @@ static struct resource tmu4_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 21,
+               .start  = evt2irq(0x4a0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -286,7 +289,7 @@ static struct resource tmu5_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 22,
+               .start  = evt2irq(0x4c0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -313,7 +316,7 @@ static struct resource tmu6_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 45,
+               .start  = evt2irq(0x7a0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -340,7 +343,7 @@ static struct resource tmu7_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 45,
+               .start  = evt2irq(0x7a0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -367,7 +370,7 @@ static struct resource tmu8_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 45,
+               .start  = evt2irq(0x7a0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -394,7 +397,7 @@ static struct resource tmu9_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 46,
+               .start  = evt2irq(0x7c0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -421,7 +424,7 @@ static struct resource tmu10_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 46,
+               .start  = evt2irq(0x7c0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -448,7 +451,7 @@ static struct resource tmu11_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 46,
+               .start  = evt2irq(0x7c0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -550,8 +553,8 @@ static struct resource usb_ehci_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 77,
-               .end    = 77,
+               .start  = evt2irq(0xba0),
+               .end    = evt2irq(0xba0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -574,8 +577,8 @@ static struct resource usb_ohci_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 77,
-               .end    = 77,
+               .start  = evt2irq(0xba0),
+               .end    = evt2irq(0xba0),
                .flags  = IORESOURCE_IRQ,
        },
 };
index bb208806dc1a595a669cad9b511a9b431b971ab2..688f7ed1bab1e1590b4a1674f26598d9d58becfe 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
 #include <cpu/shx3.h>
 #include <asm/mmzone.h>
 
@@ -32,7 +33,10 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 40, 41, 43, 42 },
+       .irqs           = { evt2irq(0x700),
+                           evt2irq(0x720),
+                           evt2irq(0x760),
+                           evt2irq(0x740) },
 };
 
 static struct platform_device scif0_device = {
@@ -49,7 +53,10 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 44, 45, 47, 46 },
+       .irqs           = { evt2irq(0x780),
+                           evt2irq(0x7a0),
+                           evt2irq(0x7e0),
+                           evt2irq(0x7c0) },
 };
 
 static struct platform_device scif1_device = {
@@ -66,7 +73,10 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
-       .irqs           = { 52, 53, 55, 54 },
+       .irqs           = { evt2irq(0x880),
+                           evt2irq(0x8a0),
+                           evt2irq(0x8e0),
+                           evt2irq(0x8c0) },
 };
 
 static struct platform_device scif2_device = {
@@ -90,7 +100,7 @@ static struct resource tmu0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 16,
+               .start  = evt2irq(0x400),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -118,7 +128,7 @@ static struct resource tmu1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 17,
+               .start  = evt2irq(0x420),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -145,7 +155,7 @@ static struct resource tmu2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 18,
+               .start  = evt2irq(0x440),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -172,7 +182,7 @@ static struct resource tmu3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 19,
+               .start  = evt2irq(0x460),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -199,7 +209,7 @@ static struct resource tmu4_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 20,
+               .start  = evt2irq(0x480),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -226,7 +236,7 @@ static struct resource tmu5_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = 21,
+               .start  = evt2irq(0x4a0),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -484,9 +494,6 @@ void __init plat_irq_setup_pins(int mode)
 
 void __init plat_irq_setup(void)
 {
-       reserve_intc_vectors(vectors_irq, ARRAY_SIZE(vectors_irq));
-       reserve_intc_vectors(vectors_irl, ARRAY_SIZE(vectors_irl));
-
        register_intc_controller(&intc_desc);
 }
 
index 6b80295dd7a4bd5a612faf9001467c5be95c150d..ff1f0e6e9becd18f111d3a3d83730fd4860dfe02 100644 (file)
@@ -335,7 +335,7 @@ tlb_miss:
        /* If the fast path handler fixed the fault, just drop through quickly
           to the restore code right away to return to the excepting context.
           */
-       beqi/u  r2, 0, tr1
+       bnei/u  r2, 0, tr1
 
 fast_tlb_miss_restore:
        ld.q    SP, SAVED_TR0, r2
@@ -1079,9 +1079,8 @@ restore_all:
  *
  * Kernel TLB fault handlers will get a slightly different interface.
  * (r2)   struct pt_regs *, original register's frame pointer
- * (r3)   writeaccess, whether it's a store fault as opposed to load fault
- * (r4)   execaccess, whether it's a ITLB fault as opposed to DTLB fault
- * (r5)   Effective Address of fault
+ * (r3)   page fault error code (see asm/thread_info.h)
+ * (r4)   Effective Address of fault
  * (LINK) return address
  * (SP)   = r2
  *
@@ -1092,26 +1091,25 @@ restore_all:
 tlb_miss_load:
        or      SP, ZERO, r2
        or      ZERO, ZERO, r3          /* Read */
-       or      ZERO, ZERO, r4          /* Data */
-       getcon  TEA, r5
+       getcon  TEA, r4
        pta     call_do_page_fault, tr0
        beq     ZERO, ZERO, tr0
 
 tlb_miss_store:
        or      SP, ZERO, r2
-       movi    1, r3                   /* Write */
-       or      ZERO, ZERO, r4          /* Data */
-       getcon  TEA, r5
+       movi    FAULT_CODE_WRITE, r3            /* Write */
+       getcon  TEA, r4
        pta     call_do_page_fault, tr0
        beq     ZERO, ZERO, tr0
 
 itlb_miss_or_IRQ:
        pta     its_IRQ, tr0
        beqi/u  r4, EVENT_INTERRUPT, tr0
+
+       /* ITLB miss */
        or      SP, ZERO, r2
-       or      ZERO, ZERO, r3          /* Read */
-       movi    1, r4                   /* Text */
-       getcon  TEA, r5
+       movi    FAULT_CODE_ITLB, r3
+       getcon  TEA, r4
        /* Fall through */
 
 call_do_page_fault:
index 4b3bb35e99f3701db410d641d810d929ba853677..9f8713aa7184f3b4da3ad9ea46f8a1d629362eaf 100644 (file)
@@ -107,8 +107,5 @@ asmlinkage void do_fpu_error(unsigned long ex, struct pt_regs *regs)
 
        regs->pc += 4;
 
-       tsk->thread.trap_no = 11;
-       tsk->thread.error_code = 0;
-
        force_sig(SIGFPE, tsk);
 }
index a3ee91971129099826493db6c23b463417284f56..dadce735f7465ee449b83070bf10148303c1b3c8 100644 (file)
@@ -234,8 +234,10 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SPARSE_IRQ
 int __init arch_probe_nr_irqs(void)
 {
-       nr_irqs = sh_mv.mv_nr_irqs;
-       return NR_IRQS_LEGACY;
+       /*
+        * No pre-allocated IRQs.
+        */
+       return 0;
 }
 #endif
 
index b117781bfea2914efef3579cbe696cd29f399f00..38b313909ac943ac208d57ffa5584c1253331c85 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SuperH KGDB support
  *
- * Copyright (C) 2008 - 2009  Paul Mundt
+ * Copyright (C) 2008 - 2012  Paul Mundt
  *
  * Single stepping taken from the old stub by Henry Bell and Jeremy Siegel.
  *
@@ -164,42 +164,89 @@ static void undo_single_step(struct pt_regs *linux_regs)
        stepped_opcode = 0;
 }
 
-void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
-{
-       int i;
+struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
+       { "r0",         GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) },
+       { "r1",         GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) },
+       { "r2",         GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) },
+       { "r3",         GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) },
+       { "r4",         GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) },
+       { "r5",         GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) },
+       { "r6",         GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) },
+       { "r7",         GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) },
+       { "r8",         GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) },
+       { "r9",         GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) },
+       { "r10",        GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) },
+       { "r11",        GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) },
+       { "r12",        GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) },
+       { "r13",        GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) },
+       { "r14",        GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) },
+       { "r15",        GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) },
+       { "pc",         GDB_SIZEOF_REG, offsetof(struct pt_regs, pc) },
+       { "pr",         GDB_SIZEOF_REG, offsetof(struct pt_regs, pr) },
+       { "sr",         GDB_SIZEOF_REG, offsetof(struct pt_regs, sr) },
+       { "gbr",        GDB_SIZEOF_REG, offsetof(struct pt_regs, gbr) },
+       { "mach",       GDB_SIZEOF_REG, offsetof(struct pt_regs, mach) },
+       { "macl",       GDB_SIZEOF_REG, offsetof(struct pt_regs, macl) },
+       { "vbr",        GDB_SIZEOF_REG, -1 },
+};
 
-       for (i = 0; i < 16; i++)
-               gdb_regs[GDB_R0 + i] = regs->regs[i];
+int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
+{
+       if (regno < 0 || regno >= DBG_MAX_REG_NUM)
+               return -EINVAL;
 
-       gdb_regs[GDB_PC] = regs->pc;
-       gdb_regs[GDB_PR] = regs->pr;
-       gdb_regs[GDB_SR] = regs->sr;
-       gdb_regs[GDB_GBR] = regs->gbr;
-       gdb_regs[GDB_MACH] = regs->mach;
-       gdb_regs[GDB_MACL] = regs->macl;
+       if (dbg_reg_def[regno].offset != -1)
+               memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
+                      dbg_reg_def[regno].size);
 
-       __asm__ __volatile__ ("stc vbr, %0" : "=r" (gdb_regs[GDB_VBR]));
+       return 0;
 }
 
-void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
 {
-       int i;
+       if (regno >= DBG_MAX_REG_NUM || regno < 0)
+               return NULL;
 
-       for (i = 0; i < 16; i++)
-               regs->regs[GDB_R0 + i] = gdb_regs[GDB_R0 + i];
+       if (dbg_reg_def[regno].size != -1)
+               memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
+                      dbg_reg_def[regno].size);
+
+       switch (regno) {
+       case GDB_VBR:
+               __asm__ __volatile__ ("stc vbr, %0" : "=r" (mem));
+               break;
+       }
 
-       regs->pc = gdb_regs[GDB_PC];
-       regs->pr = gdb_regs[GDB_PR];
-       regs->sr = gdb_regs[GDB_SR];
-       regs->gbr = gdb_regs[GDB_GBR];
-       regs->mach = gdb_regs[GDB_MACH];
-       regs->macl = gdb_regs[GDB_MACL];
+       return dbg_reg_def[regno].name;
 }
 
 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
 {
+       struct pt_regs *thread_regs = task_pt_regs(p);
+       int reg;
+
+       /* Initialize to zero */
+       for (reg = 0; reg < DBG_MAX_REG_NUM; reg++)
+               gdb_regs[reg] = 0;
+
+       /*
+        * Copy out GP regs 8 to 14.
+        *
+        * switch_to() relies on SR.RB toggling, so regs 0->7 are banked
+        * and need privileged instructions to get to. The r15 value we
+        * fetch from the thread info directly.
+        */
+       for (reg = GDB_R8; reg < GDB_R15; reg++)
+               gdb_regs[reg] = thread_regs->regs[reg];
+
        gdb_regs[GDB_R15] = p->thread.sp;
        gdb_regs[GDB_PC] = p->thread.pc;
+
+       /*
+        * Additional registers we have context for
+        */
+       gdb_regs[GDB_PR] = thread_regs->pr;
+       gdb_regs[GDB_GBR] = thread_regs->gbr;
 }
 
 int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
@@ -264,6 +311,18 @@ BUILD_TRAP_HANDLER(singlestep)
        local_irq_restore(flags);
 }
 
+static void kgdb_call_nmi_hook(void *ignored)
+{
+       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+       local_irq_enable();
+       smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+       local_irq_disable();
+}
+
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
 {
        int ret;
index 3d722e49db0826a843ee1e5c03a9fe09e90da236..ec05f491c3471ea1e5e57a0ef9b93409f996c008 100644 (file)
@@ -121,7 +121,4 @@ void __init sh_mv_setup(void)
        mv_set(irq_demux);
        mv_set(mode_pins);
        mv_set(mem_init);
-
-       if (!sh_mv.mv_nr_irqs)
-               sh_mv.mv_nr_irqs = NR_IRQS;
 }
index f2621abdf01d9ffeb8c6538bf966103ac869947e..9b7a459a4613d8573a7c84ac3bf970402431c31e 100644 (file)
@@ -2,12 +2,26 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/export.h>
+#include <linux/stackprotector.h>
 
 struct kmem_cache *task_xstate_cachep = NULL;
 unsigned int xstate_size;
 
+#ifdef CONFIG_CC_STACKPROTECTOR
+unsigned long __stack_chk_guard __read_mostly;
+EXPORT_SYMBOL(__stack_chk_guard);
+#endif
+
+/*
+ * this gets called so that we can store lazy state into memory and copy the
+ * current task into the new thread.
+ */
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
+#ifdef CONFIG_SUPERH32
+       unlazy_fpu(src, task_pt_regs(src));
+#endif
        *dst = *src;
 
        if (src->thread.xstate) {
index 94273aaf78c1605da62d82ea61dc14a746ec5dff..59521e8a164dae01da367f2f60aef2e0a737551e 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/ftrace.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/prefetch.h>
+#include <linux/stackprotector.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/fpu.h>
@@ -155,15 +156,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 }
 EXPORT_SYMBOL(dump_fpu);
 
-/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
- */
-void prepare_to_copy(struct task_struct *tsk)
-{
-       unlazy_fpu(tsk, task_pt_regs(tsk));
-}
-
 asmlinkage void ret_from_fork(void);
 
 int copy_thread(unsigned long clone_flags, unsigned long usp,
@@ -220,6 +212,10 @@ __switch_to(struct task_struct *prev, struct task_struct *next)
 {
        struct thread_struct *next_t = &next->thread;
 
+#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+       __stack_chk_guard = next->stack_canary;
+#endif
+
        unlazy_fpu(prev, task_pt_regs(prev));
 
        /* we're going to use this soon, after a few expensive things */
index 6c0486094e48cd074a4fd43cb59ea4db9bd8769c..8dae93ed8aff77586c50df0f6830e23f48f13c75 100644 (file)
@@ -283,8 +283,6 @@ static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_na
                unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk)
 {
        show_excp_regs(fn_name, trapnr, signr, regs);
-       tsk->thread.error_code = error_code;
-       tsk->thread.trap_no = trapnr;
 
        if (user_mode(regs))
                force_sig(signr, tsk);
index 2228c8cee4d6cecebafaa37a29857c77f9d80f08..cee6b9999d86011781e6a973270967c7e937762f 100644 (file)
@@ -15,8 +15,8 @@ cacheops-$(CONFIG_CPU_SHX3)           += cache-shx3.o
 obj-y                  += $(cacheops-y)
 
 mmu-y                  := nommu.o extable_32.o
-mmu-$(CONFIG_MMU)      := extable_$(BITS).o fault_$(BITS).o gup.o \
-                          ioremap.o kmap.o pgtable.o tlbflush_$(BITS).o
+mmu-$(CONFIG_MMU)      := extable_$(BITS).o fault.o gup.o ioremap.o kmap.o \
+                          pgtable.o tlbex_$(BITS).o tlbflush_$(BITS).o
 
 obj-y                  += $(mmu-y)
 
@@ -44,7 +44,7 @@ obj-$(CONFIG_HAVE_SRAM_POOL)  += sram.o
 
 GCOV_PROFILE_pmb.o := n
 
-# Special flags for fault_64.o.  This puts restrictions on the number of
+# Special flags for tlbex_64.o.  This puts restrictions on the number of
 # caller-save registers that the compiler can target when building this file.
 # This is required because the code is called from a context in entry.S where
 # very few registers have been saved in the exception handler (for speed
@@ -59,7 +59,7 @@ GCOV_PROFILE_pmb.o := n
 # The resources not listed below are callee save, i.e. the compiler is free to
 # use any of them and will spill them to the stack itself.
 
-CFLAGS_fault_64.o += -ffixed-r7 \
+CFLAGS_tlbex_64.o += -ffixed-r7 \
        -ffixed-r8 -ffixed-r9 -ffixed-r10 -ffixed-r11 -ffixed-r12 \
        -ffixed-r13 -ffixed-r14 -ffixed-r16 -ffixed-r17 -ffixed-r19 \
        -ffixed-r20 -ffixed-r21 -ffixed-r22 -ffixed-r23 \
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
new file mode 100644 (file)
index 0000000..1fc25d8
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * Page fault handler for SH with an MMU.
+ *
+ *  Copyright (C) 1999  Niibe Yutaka
+ *  Copyright (C) 2003 - 2012  Paul Mundt
+ *
+ *  Based on linux/arch/i386/mm/fault.c:
+ *   Copyright (C) 1995  Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/hardirq.h>
+#include <linux/kprobes.h>
+#include <linux/perf_event.h>
+#include <linux/kdebug.h>
+#include <asm/io_trapped.h>
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+#include <asm/traps.h>
+
+static inline int notify_page_fault(struct pt_regs *regs, int trap)
+{
+       int ret = 0;
+
+       if (kprobes_built_in() && !user_mode(regs)) {
+               preempt_disable();
+               if (kprobe_running() && kprobe_fault_handler(regs, trap))
+                       ret = 1;
+               preempt_enable();
+       }
+
+       return ret;
+}
+
+static void
+force_sig_info_fault(int si_signo, int si_code, unsigned long address,
+                    struct task_struct *tsk)
+{
+       siginfo_t info;
+
+       info.si_signo   = si_signo;
+       info.si_errno   = 0;
+       info.si_code    = si_code;
+       info.si_addr    = (void __user *)address;
+
+       force_sig_info(si_signo, &info, tsk);
+}
+
+/*
+ * This is useful to dump out the page tables associated with
+ * 'addr' in mm 'mm'.
+ */
+static void show_pte(struct mm_struct *mm, unsigned long addr)
+{
+       pgd_t *pgd;
+
+       if (mm)
+               pgd = mm->pgd;
+       else
+               pgd = get_TTB();
+
+       printk(KERN_ALERT "pgd = %p\n", pgd);
+       pgd += pgd_index(addr);
+       printk(KERN_ALERT "[%08lx] *pgd=%0*Lx", addr,
+              (u32)(sizeof(*pgd) * 2), (u64)pgd_val(*pgd));
+
+       do {
+               pud_t *pud;
+               pmd_t *pmd;
+               pte_t *pte;
+
+               if (pgd_none(*pgd))
+                       break;
+
+               if (pgd_bad(*pgd)) {
+                       printk("(bad)");
+                       break;
+               }
+
+               pud = pud_offset(pgd, addr);
+               if (PTRS_PER_PUD != 1)
+                       printk(", *pud=%0*Lx", (u32)(sizeof(*pud) * 2),
+                              (u64)pud_val(*pud));
+
+               if (pud_none(*pud))
+                       break;
+
+               if (pud_bad(*pud)) {
+                       printk("(bad)");
+                       break;
+               }
+
+               pmd = pmd_offset(pud, addr);
+               if (PTRS_PER_PMD != 1)
+                       printk(", *pmd=%0*Lx", (u32)(sizeof(*pmd) * 2),
+                              (u64)pmd_val(*pmd));
+
+               if (pmd_none(*pmd))
+                       break;
+
+               if (pmd_bad(*pmd)) {
+                       printk("(bad)");
+                       break;
+               }
+
+               /* We must not map this if we have highmem enabled */
+               if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT)))
+                       break;
+
+               pte = pte_offset_kernel(pmd, addr);
+               printk(", *pte=%0*Lx", (u32)(sizeof(*pte) * 2),
+                      (u64)pte_val(*pte));
+       } while (0);
+
+       printk("\n");
+}
+
+static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
+{
+       unsigned index = pgd_index(address);
+       pgd_t *pgd_k;
+       pud_t *pud, *pud_k;
+       pmd_t *pmd, *pmd_k;
+
+       pgd += index;
+       pgd_k = init_mm.pgd + index;
+
+       if (!pgd_present(*pgd_k))
+               return NULL;
+
+       pud = pud_offset(pgd, address);
+       pud_k = pud_offset(pgd_k, address);
+       if (!pud_present(*pud_k))
+               return NULL;
+
+       if (!pud_present(*pud))
+           set_pud(pud, *pud_k);
+
+       pmd = pmd_offset(pud, address);
+       pmd_k = pmd_offset(pud_k, address);
+       if (!pmd_present(*pmd_k))
+               return NULL;
+
+       if (!pmd_present(*pmd))
+               set_pmd(pmd, *pmd_k);
+       else {
+               /*
+                * The page tables are fully synchronised so there must
+                * be another reason for the fault. Return NULL here to
+                * signal that we have not taken care of the fault.
+                */
+               BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
+               return NULL;
+       }
+
+       return pmd_k;
+}
+
+#ifdef CONFIG_SH_STORE_QUEUES
+#define __FAULT_ADDR_LIMIT     P3_ADDR_MAX
+#else
+#define __FAULT_ADDR_LIMIT     VMALLOC_END
+#endif
+
+/*
+ * Handle a fault on the vmalloc or module mapping area
+ */
+static noinline int vmalloc_fault(unsigned long address)
+{
+       pgd_t *pgd_k;
+       pmd_t *pmd_k;
+       pte_t *pte_k;
+
+       /* Make sure we are in vmalloc/module/P3 area: */
+       if (!(address >= VMALLOC_START && address < __FAULT_ADDR_LIMIT))
+               return -1;
+
+       /*
+        * Synchronize this task's top level page-table
+        * with the 'reference' page table.
+        *
+        * Do _not_ use "current" here. We might be inside
+        * an interrupt in the middle of a task switch..
+        */
+       pgd_k = get_TTB();
+       pmd_k = vmalloc_sync_one(pgd_k, address);
+       if (!pmd_k)
+               return -1;
+
+       pte_k = pte_offset_kernel(pmd_k, address);
+       if (!pte_present(*pte_k))
+               return -1;
+
+       return 0;
+}
+
+static void
+show_fault_oops(struct pt_regs *regs, unsigned long address)
+{
+       if (!oops_may_print())
+               return;
+
+       printk(KERN_ALERT "BUG: unable to handle kernel ");
+       if (address < PAGE_SIZE)
+               printk(KERN_CONT "NULL pointer dereference");
+       else
+               printk(KERN_CONT "paging request");
+
+       printk(KERN_CONT " at %08lx\n", address);
+       printk(KERN_ALERT "PC:");
+       printk_address(regs->pc, 1);
+
+       show_pte(NULL, address);
+}
+
+static noinline void
+no_context(struct pt_regs *regs, unsigned long error_code,
+          unsigned long address)
+{
+       /* Are we prepared to handle this kernel fault?  */
+       if (fixup_exception(regs))
+               return;
+
+       if (handle_trapped_io(regs, address))
+               return;
+
+       /*
+        * Oops. The kernel tried to access some bad page. We'll have to
+        * terminate things with extreme prejudice.
+        */
+       bust_spinlocks(1);
+
+       show_fault_oops(regs, address);
+
+       die("Oops", regs, error_code);
+       bust_spinlocks(0);
+       do_exit(SIGKILL);
+}
+
+static void
+__bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
+                      unsigned long address, int si_code)
+{
+       struct task_struct *tsk = current;
+
+       /* User mode accesses just cause a SIGSEGV */
+       if (user_mode(regs)) {
+               /*
+                * It's possible to have interrupts off here:
+                */
+               local_irq_enable();
+
+               force_sig_info_fault(SIGSEGV, si_code, address, tsk);
+
+               return;
+       }
+
+       no_context(regs, error_code, address);
+}
+
+static noinline void
+bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
+                    unsigned long address)
+{
+       __bad_area_nosemaphore(regs, error_code, address, SEGV_MAPERR);
+}
+
+static void
+__bad_area(struct pt_regs *regs, unsigned long error_code,
+          unsigned long address, int si_code)
+{
+       struct mm_struct *mm = current->mm;
+
+       /*
+        * Something tried to access memory that isn't in our memory map..
+        * Fix it, but check if it's kernel or user first..
+        */
+       up_read(&mm->mmap_sem);
+
+       __bad_area_nosemaphore(regs, error_code, address, si_code);
+}
+
+static noinline void
+bad_area(struct pt_regs *regs, unsigned long error_code, unsigned long address)
+{
+       __bad_area(regs, error_code, address, SEGV_MAPERR);
+}
+
+static noinline void
+bad_area_access_error(struct pt_regs *regs, unsigned long error_code,
+                     unsigned long address)
+{
+       __bad_area(regs, error_code, address, SEGV_ACCERR);
+}
+
+static void out_of_memory(void)
+{
+       /*
+        * We ran out of memory, call the OOM killer, and return the userspace
+        * (which will retry the fault, or kill us if we got oom-killed):
+        */
+       up_read(&current->mm->mmap_sem);
+
+       pagefault_out_of_memory();
+}
+
+static void
+do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address)
+{
+       struct task_struct *tsk = current;
+       struct mm_struct *mm = tsk->mm;
+
+       up_read(&mm->mmap_sem);
+
+       /* Kernel mode? Handle exceptions or die: */
+       if (!user_mode(regs))
+               no_context(regs, error_code, address);
+
+       force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
+}
+
+static noinline int
+mm_fault_error(struct pt_regs *regs, unsigned long error_code,
+              unsigned long address, unsigned int fault)
+{
+       /*
+        * Pagefault was interrupted by SIGKILL. We have no reason to
+        * continue pagefault.
+        */
+       if (fatal_signal_pending(current)) {
+               if (!(fault & VM_FAULT_RETRY))
+                       up_read(&current->mm->mmap_sem);
+               if (!user_mode(regs))
+                       no_context(regs, error_code, address);
+               return 1;
+       }
+
+       if (!(fault & VM_FAULT_ERROR))
+               return 0;
+
+       if (fault & VM_FAULT_OOM) {
+               /* Kernel mode? Handle exceptions or die: */
+               if (!user_mode(regs)) {
+                       up_read(&current->mm->mmap_sem);
+                       no_context(regs, error_code, address);
+                       return 1;
+               }
+
+               out_of_memory();
+       } else {
+               if (fault & VM_FAULT_SIGBUS)
+                       do_sigbus(regs, error_code, address);
+               else
+                       BUG();
+       }
+
+       return 1;
+}
+
+static inline int access_error(int error_code, struct vm_area_struct *vma)
+{
+       if (error_code & FAULT_CODE_WRITE) {
+               /* write, present and write, not present: */
+               if (unlikely(!(vma->vm_flags & VM_WRITE)))
+                       return 1;
+               return 0;
+       }
+
+       /* ITLB miss on NX page */
+       if (unlikely((error_code & FAULT_CODE_ITLB) &&
+                    !(vma->vm_flags & VM_EXEC)))
+               return 1;
+
+       /* read, not present: */
+       if (unlikely(!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))))
+               return 1;
+
+       return 0;
+}
+
+static int fault_in_kernel_space(unsigned long address)
+{
+       return address >= TASK_SIZE;
+}
+
+/*
+ * This routine handles page faults.  It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ */
+asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
+                                       unsigned long error_code,
+                                       unsigned long address)
+{
+       unsigned long vec;
+       struct task_struct *tsk;
+       struct mm_struct *mm;
+       struct vm_area_struct * vma;
+       int fault;
+       int write = error_code & FAULT_CODE_WRITE;
+       unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+                             (write ? FAULT_FLAG_WRITE : 0));
+
+       tsk = current;
+       mm = tsk->mm;
+       vec = lookup_exception_vector();
+
+       /*
+        * We fault-in kernel-space virtual memory on-demand. The
+        * 'reference' page table is init_mm.pgd.
+        *
+        * NOTE! We MUST NOT take any locks for this case. We may
+        * be in an interrupt or a critical region, and should
+        * only copy the information from the master page table,
+        * nothing more.
+        */
+       if (unlikely(fault_in_kernel_space(address))) {
+               if (vmalloc_fault(address) >= 0)
+                       return;
+               if (notify_page_fault(regs, vec))
+                       return;
+
+               bad_area_nosemaphore(regs, error_code, address);
+               return;
+       }
+
+       if (unlikely(notify_page_fault(regs, vec)))
+               return;
+
+       /* Only enable interrupts if they were on before the fault */
+       if ((regs->sr & SR_IMASK) != SR_IMASK)
+               local_irq_enable();
+
+       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
+
+       /*
+        * If we're in an interrupt, have no user context or are running
+        * in an atomic region then we must not take the fault:
+        */
+       if (unlikely(in_atomic() || !mm)) {
+               bad_area_nosemaphore(regs, error_code, address);
+               return;
+       }
+
+retry:
+       down_read(&mm->mmap_sem);
+
+       vma = find_vma(mm, address);
+       if (unlikely(!vma)) {
+               bad_area(regs, error_code, address);
+               return;
+       }
+       if (likely(vma->vm_start <= address))
+               goto good_area;
+       if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) {
+               bad_area(regs, error_code, address);
+               return;
+       }
+       if (unlikely(expand_stack(vma, address))) {
+               bad_area(regs, error_code, address);
+               return;
+       }
+
+       /*
+        * Ok, we have a good vm_area for this memory access, so
+        * we can handle it..
+        */
+good_area:
+       if (unlikely(access_error(error_code, vma))) {
+               bad_area_access_error(regs, error_code, address);
+               return;
+       }
+
+       set_thread_fault_code(error_code);
+
+       /*
+        * If for any reason at all we couldn't handle the fault,
+        * make sure we exit gracefully rather than endlessly redo
+        * the fault.
+        */
+       fault = handle_mm_fault(mm, vma, address, flags);
+
+       if (unlikely(fault & (VM_FAULT_RETRY | VM_FAULT_ERROR)))
+               if (mm_fault_error(regs, error_code, address, fault))
+                       return;
+
+       if (flags & FAULT_FLAG_ALLOW_RETRY) {
+               if (fault & VM_FAULT_MAJOR) {
+                       tsk->maj_flt++;
+                       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
+                                     regs, address);
+               } else {
+                       tsk->min_flt++;
+                       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
+                                     regs, address);
+               }
+               if (fault & VM_FAULT_RETRY) {
+                       flags &= ~FAULT_FLAG_ALLOW_RETRY;
+
+                       /*
+                        * No need to up_read(&mm->mmap_sem) as we would
+                        * have already released it in __lock_page_or_retry
+                        * in mm/filemap.c.
+                        */
+                       goto retry;
+               }
+       }
+
+       up_read(&mm->mmap_sem);
+}
diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c
deleted file mode 100644 (file)
index e99b104..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Page fault handler for SH with an MMU.
- *
- *  Copyright (C) 1999  Niibe Yutaka
- *  Copyright (C) 2003 - 2009  Paul Mundt
- *
- *  Based on linux/arch/i386/mm/fault.c:
- *   Copyright (C) 1995  Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/hardirq.h>
-#include <linux/kprobes.h>
-#include <linux/perf_event.h>
-#include <asm/io_trapped.h>
-#include <asm/mmu_context.h>
-#include <asm/tlbflush.h>
-#include <asm/traps.h>
-
-static inline int notify_page_fault(struct pt_regs *regs, int trap)
-{
-       int ret = 0;
-
-       if (kprobes_built_in() && !user_mode(regs)) {
-               preempt_disable();
-               if (kprobe_running() && kprobe_fault_handler(regs, trap))
-                       ret = 1;
-               preempt_enable();
-       }
-
-       return ret;
-}
-
-static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
-{
-       unsigned index = pgd_index(address);
-       pgd_t *pgd_k;
-       pud_t *pud, *pud_k;
-       pmd_t *pmd, *pmd_k;
-
-       pgd += index;
-       pgd_k = init_mm.pgd + index;
-
-       if (!pgd_present(*pgd_k))
-               return NULL;
-
-       pud = pud_offset(pgd, address);
-       pud_k = pud_offset(pgd_k, address);
-       if (!pud_present(*pud_k))
-               return NULL;
-
-       if (!pud_present(*pud))
-           set_pud(pud, *pud_k);
-
-       pmd = pmd_offset(pud, address);
-       pmd_k = pmd_offset(pud_k, address);
-       if (!pmd_present(*pmd_k))
-               return NULL;
-
-       if (!pmd_present(*pmd))
-               set_pmd(pmd, *pmd_k);
-       else {
-               /*
-                * The page tables are fully synchronised so there must
-                * be another reason for the fault. Return NULL here to
-                * signal that we have not taken care of the fault.
-                */
-               BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
-               return NULL;
-       }
-
-       return pmd_k;
-}
-
-/*
- * Handle a fault on the vmalloc or module mapping area
- */
-static noinline int vmalloc_fault(unsigned long address)
-{
-       pgd_t *pgd_k;
-       pmd_t *pmd_k;
-       pte_t *pte_k;
-
-       /* Make sure we are in vmalloc/module/P3 area: */
-       if (!(address >= P3SEG && address < P3_ADDR_MAX))
-               return -1;
-
-       /*
-        * Synchronize this task's top level page-table
-        * with the 'reference' page table.
-        *
-        * Do _not_ use "current" here. We might be inside
-        * an interrupt in the middle of a task switch..
-        */
-       pgd_k = get_TTB();
-       pmd_k = vmalloc_sync_one(pgd_k, address);
-       if (!pmd_k)
-               return -1;
-
-       pte_k = pte_offset_kernel(pmd_k, address);
-       if (!pte_present(*pte_k))
-               return -1;
-
-       return 0;
-}
-
-static int fault_in_kernel_space(unsigned long address)
-{
-       return address >= TASK_SIZE;
-}
-
-/*
- * This routine handles page faults.  It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
-asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
-                                       unsigned long writeaccess,
-                                       unsigned long address)
-{
-       unsigned long vec;
-       struct task_struct *tsk;
-       struct mm_struct *mm;
-       struct vm_area_struct * vma;
-       int si_code;
-       int fault;
-       siginfo_t info;
-
-       tsk = current;
-       mm = tsk->mm;
-       si_code = SEGV_MAPERR;
-       vec = lookup_exception_vector();
-
-       /*
-        * We fault-in kernel-space virtual memory on-demand. The
-        * 'reference' page table is init_mm.pgd.
-        *
-        * NOTE! We MUST NOT take any locks for this case. We may
-        * be in an interrupt or a critical region, and should
-        * only copy the information from the master page table,
-        * nothing more.
-        */
-       if (unlikely(fault_in_kernel_space(address))) {
-               if (vmalloc_fault(address) >= 0)
-                       return;
-               if (notify_page_fault(regs, vec))
-                       return;
-
-               goto bad_area_nosemaphore;
-       }
-
-       if (unlikely(notify_page_fault(regs, vec)))
-               return;
-
-       /* Only enable interrupts if they were on before the fault */
-       if ((regs->sr & SR_IMASK) != SR_IMASK)
-               local_irq_enable();
-
-       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
-
-       /*
-        * If we're in an interrupt, have no user context or are running
-        * in an atomic region then we must not take the fault:
-        */
-       if (in_atomic() || !mm)
-               goto no_context;
-
-       down_read(&mm->mmap_sem);
-
-       vma = find_vma(mm, address);
-       if (!vma)
-               goto bad_area;
-       if (vma->vm_start <= address)
-               goto good_area;
-       if (!(vma->vm_flags & VM_GROWSDOWN))
-               goto bad_area;
-       if (expand_stack(vma, address))
-               goto bad_area;
-
-       /*
-        * Ok, we have a good vm_area for this memory access, so
-        * we can handle it..
-        */
-good_area:
-       si_code = SEGV_ACCERR;
-       if (writeaccess) {
-               if (!(vma->vm_flags & VM_WRITE))
-                       goto bad_area;
-       } else {
-               if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
-                       goto bad_area;
-       }
-
-       /*
-        * If for any reason at all we couldn't handle the fault,
-        * make sure we exit gracefully rather than endlessly redo
-        * the fault.
-        */
-       fault = handle_mm_fault(mm, vma, address, writeaccess ? FAULT_FLAG_WRITE : 0);
-       if (unlikely(fault & VM_FAULT_ERROR)) {
-               if (fault & VM_FAULT_OOM)
-                       goto out_of_memory;
-               else if (fault & VM_FAULT_SIGBUS)
-                       goto do_sigbus;
-               BUG();
-       }
-       if (fault & VM_FAULT_MAJOR) {
-               tsk->maj_flt++;
-               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
-                                    regs, address);
-       } else {
-               tsk->min_flt++;
-               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
-                                    regs, address);
-       }
-
-       up_read(&mm->mmap_sem);
-       return;
-
-       /*
-        * Something tried to access memory that isn't in our memory map..
-        * Fix it, but check if it's kernel or user first..
-        */
-bad_area:
-       up_read(&mm->mmap_sem);
-
-bad_area_nosemaphore:
-       if (user_mode(regs)) {
-               info.si_signo = SIGSEGV;
-               info.si_errno = 0;
-               info.si_code = si_code;
-               info.si_addr = (void *) address;
-               force_sig_info(SIGSEGV, &info, tsk);
-               return;
-       }
-
-no_context:
-       /* Are we prepared to handle this kernel fault?  */
-       if (fixup_exception(regs))
-               return;
-
-       if (handle_trapped_io(regs, address))
-               return;
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- *
- */
-
-       bust_spinlocks(1);
-
-       if (oops_may_print()) {
-               unsigned long page;
-
-               if (address < PAGE_SIZE)
-                       printk(KERN_ALERT "Unable to handle kernel NULL "
-                                         "pointer dereference");
-               else
-                       printk(KERN_ALERT "Unable to handle kernel paging "
-                                         "request");
-               printk(" at virtual address %08lx\n", address);
-               printk(KERN_ALERT "pc = %08lx\n", regs->pc);
-               page = (unsigned long)get_TTB();
-               if (page) {
-                       page = ((__typeof__(page) *)page)[address >> PGDIR_SHIFT];
-                       printk(KERN_ALERT "*pde = %08lx\n", page);
-                       if (page & _PAGE_PRESENT) {
-                               page &= PAGE_MASK;
-                               address &= 0x003ff000;
-                               page = ((__typeof__(page) *)
-                                               __va(page))[address >>
-                                                           PAGE_SHIFT];
-                               printk(KERN_ALERT "*pte = %08lx\n", page);
-                       }
-               }
-       }
-
-       die("Oops", regs, writeaccess);
-       bust_spinlocks(0);
-       do_exit(SIGKILL);
-
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-out_of_memory:
-       up_read(&mm->mmap_sem);
-       if (!user_mode(regs))
-               goto no_context;
-       pagefault_out_of_memory();
-       return;
-
-do_sigbus:
-       up_read(&mm->mmap_sem);
-
-       /*
-        * Send a sigbus, regardless of whether we were in kernel
-        * or user mode.
-        */
-       info.si_signo = SIGBUS;
-       info.si_errno = 0;
-       info.si_code = BUS_ADRERR;
-       info.si_addr = (void *)address;
-       force_sig_info(SIGBUS, &info, tsk);
-
-       /* Kernel mode? Handle exceptions or die */
-       if (!user_mode(regs))
-               goto no_context;
-}
-
-/*
- * Called with interrupts disabled.
- */
-asmlinkage int __kprobes
-handle_tlbmiss(struct pt_regs *regs, unsigned long writeaccess,
-              unsigned long address)
-{
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *pte;
-       pte_t entry;
-
-       /*
-        * We don't take page faults for P1, P2, and parts of P4, these
-        * are always mapped, whether it be due to legacy behaviour in
-        * 29-bit mode, or due to PMB configuration in 32-bit mode.
-        */
-       if (address >= P3SEG && address < P3_ADDR_MAX) {
-               pgd = pgd_offset_k(address);
-       } else {
-               if (unlikely(address >= TASK_SIZE || !current->mm))
-                       return 1;
-
-               pgd = pgd_offset(current->mm, address);
-       }
-
-       pud = pud_offset(pgd, address);
-       if (pud_none_or_clear_bad(pud))
-               return 1;
-       pmd = pmd_offset(pud, address);
-       if (pmd_none_or_clear_bad(pmd))
-               return 1;
-       pte = pte_offset_kernel(pmd, address);
-       entry = *pte;
-       if (unlikely(pte_none(entry) || pte_not_present(entry)))
-               return 1;
-       if (unlikely(writeaccess && !pte_write(entry)))
-               return 1;
-
-       if (writeaccess)
-               entry = pte_mkdirty(entry);
-       entry = pte_mkyoung(entry);
-
-       set_pte(pte, entry);
-
-#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SMP)
-       /*
-        * SH-4 does not set MMUCR.RC to the corresponding TLB entry in
-        * the case of an initial page write exception, so we need to
-        * flush it in order to avoid potential TLB entry duplication.
-        */
-       if (writeaccess == 2)
-               local_flush_tlb_one(get_asid(), address & PAGE_MASK);
-#endif
-
-       update_mmu_cache(NULL, address, pte);
-
-       return 0;
-}
diff --git a/arch/sh/mm/fault_64.c b/arch/sh/mm/fault_64.c
deleted file mode 100644 (file)
index 44a3410..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * The SH64 TLB miss.
- *
- * Original code from fault.c
- * Copyright (C) 2000, 2001  Paolo Alberelli
- *
- * Fast PTE->TLB refill path
- * Copyright (C) 2003 Richard.Curnow@superh.com
- *
- * IMPORTANT NOTES :
- * The do_fast_page_fault function is called from a context in entry.S
- * where very few registers have been saved.  In particular, the code in
- * this file must be compiled not to use ANY caller-save registers that
- * are not part of the restricted save set.  Also, it means that code in
- * this file must not make calls to functions elsewhere in the kernel, or
- * else the excepting context will see corruption in its caller-save
- * registers.  Plus, the entry.S save area is non-reentrant, so this code
- * has to run with SR.BL==1, i.e. no interrupts taken inside it and panic
- * on any exception.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <asm/tlb.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-#include <asm/mmu_context.h>
-#include <cpu/registers.h>
-
-/* Callable from fault.c, so not static */
-inline void __do_tlb_refill(unsigned long address,
-                            unsigned long long is_text_not_data, pte_t *pte)
-{
-       unsigned long long ptel;
-       unsigned long long pteh=0;
-       struct tlb_info *tlbp;
-       unsigned long long next;
-
-       /* Get PTEL first */
-       ptel = pte_val(*pte);
-
-       /*
-        * Set PTEH register
-        */
-       pteh = neff_sign_extend(address & MMU_VPN_MASK);
-
-       /* Set the ASID. */
-       pteh |= get_asid() << PTEH_ASID_SHIFT;
-       pteh |= PTEH_VALID;
-
-       /* Set PTEL register, set_pte has performed the sign extension */
-       ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
-
-       tlbp = is_text_not_data ? &(cpu_data->itlb) : &(cpu_data->dtlb);
-       next = tlbp->next;
-       __flush_tlb_slot(next);
-       asm volatile ("putcfg %0,1,%2\n\n\t"
-                     "putcfg %0,0,%1\n"
-                     :  : "r" (next), "r" (pteh), "r" (ptel) );
-
-       next += TLB_STEP;
-       if (next > tlbp->last) next = tlbp->first;
-       tlbp->next = next;
-
-}
-
-static int handle_vmalloc_fault(struct mm_struct *mm,
-                               unsigned long protection_flags,
-                                unsigned long long textaccess,
-                               unsigned long address)
-{
-       pgd_t *dir;
-       pud_t *pud;
-       pmd_t *pmd;
-       static pte_t *pte;
-       pte_t entry;
-
-       dir = pgd_offset_k(address);
-
-       pud = pud_offset(dir, address);
-       if (pud_none_or_clear_bad(pud))
-               return 0;
-
-       pmd = pmd_offset(pud, address);
-       if (pmd_none_or_clear_bad(pmd))
-               return 0;
-
-       pte = pte_offset_kernel(pmd, address);
-       entry = *pte;
-
-       if (pte_none(entry) || !pte_present(entry))
-               return 0;
-       if ((pte_val(entry) & protection_flags) != protection_flags)
-               return 0;
-
-        __do_tlb_refill(address, textaccess, pte);
-
-       return 1;
-}
-
-static int handle_tlbmiss(struct mm_struct *mm,
-                         unsigned long long protection_flags,
-                         unsigned long long textaccess,
-                         unsigned long address)
-{
-       pgd_t *dir;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *pte;
-       pte_t entry;
-
-       /* NB. The PGD currently only contains a single entry - there is no
-          page table tree stored for the top half of the address space since
-          virtual pages in that region should never be mapped in user mode.
-          (In kernel mode, the only things in that region are the 512Mb super
-          page (locked in), and vmalloc (modules) +  I/O device pages (handled
-          by handle_vmalloc_fault), so no PGD for the upper half is required
-          by kernel mode either).
-
-          See how mm->pgd is allocated and initialised in pgd_alloc to see why
-          the next test is necessary.  - RPC */
-       if (address >= (unsigned long) TASK_SIZE)
-               /* upper half - never has page table entries. */
-               return 0;
-
-       dir = pgd_offset(mm, address);
-       if (pgd_none(*dir) || !pgd_present(*dir))
-               return 0;
-       if (!pgd_present(*dir))
-               return 0;
-
-       pud = pud_offset(dir, address);
-       if (pud_none(*pud) || !pud_present(*pud))
-               return 0;
-
-       pmd = pmd_offset(pud, address);
-       if (pmd_none(*pmd) || !pmd_present(*pmd))
-               return 0;
-
-       pte = pte_offset_kernel(pmd, address);
-       entry = *pte;
-
-       if (pte_none(entry) || !pte_present(entry))
-               return 0;
-
-       /*
-        * If the page doesn't have sufficient protection bits set to
-        * service the kind of fault being handled, there's not much
-        * point doing the TLB refill.  Punt the fault to the general
-        * handler.
-        */
-       if ((pte_val(entry) & protection_flags) != protection_flags)
-               return 0;
-
-        __do_tlb_refill(address, textaccess, pte);
-
-       return 1;
-}
-
-/*
- * Put all this information into one structure so that everything is just
- * arithmetic relative to a single base address.  This reduces the number
- * of movi/shori pairs needed just to load addresses of static data.
- */
-struct expevt_lookup {
-       unsigned short protection_flags[8];
-       unsigned char  is_text_access[8];
-       unsigned char  is_write_access[8];
-};
-
-#define PRU (1<<9)
-#define PRW (1<<8)
-#define PRX (1<<7)
-#define PRR (1<<6)
-
-#define DIRTY (_PAGE_DIRTY | _PAGE_ACCESSED)
-#define YOUNG (_PAGE_ACCESSED)
-
-/* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether
-   the fault happened in user mode or privileged mode. */
-static struct expevt_lookup expevt_lookup_table = {
-       .protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW},
-       .is_text_access   = {1,   1,   0, 0, 0,   0,   0,   0}
-};
-
-/*
-   This routine handles page faults that can be serviced just by refilling a
-   TLB entry from an existing page table entry.  (This case represents a very
-   large majority of page faults.) Return 1 if the fault was successfully
-   handled.  Return 0 if the fault could not be handled.  (This leads into the
-   general fault handling in fault.c which deals with mapping file-backed
-   pages, stack growth, segmentation faults, swapping etc etc)
- */
-asmlinkage int do_fast_page_fault(unsigned long long ssr_md,
-                                 unsigned long long expevt,
-                                 unsigned long address)
-{
-       struct task_struct *tsk;
-       struct mm_struct *mm;
-       unsigned long long textaccess;
-       unsigned long long protection_flags;
-       unsigned long long index;
-       unsigned long long expevt4;
-
-       /* The next few lines implement a way of hashing EXPEVT into a
-        * small array index which can be used to lookup parameters
-        * specific to the type of TLBMISS being handled.
-        *
-        * Note:
-        *      ITLBMISS has EXPEVT==0xa40
-        *      RTLBMISS has EXPEVT==0x040
-        *      WTLBMISS has EXPEVT==0x060
-        */
-       expevt4 = (expevt >> 4);
-       /* TODO : xor ssr_md into this expression too. Then we can check
-        * that PRU is set when it needs to be. */
-       index = expevt4 ^ (expevt4 >> 5);
-       index &= 7;
-       protection_flags = expevt_lookup_table.protection_flags[index];
-       textaccess       = expevt_lookup_table.is_text_access[index];
-
-       /* SIM
-        * Note this is now called with interrupts still disabled
-        * This is to cope with being called for a missing IO port
-        * address with interrupts disabled. This should be fixed as
-        * soon as we have a better 'fast path' miss handler.
-        *
-        * Plus take care how you try and debug this stuff.
-        * For example, writing debug data to a port which you
-        * have just faulted on is not going to work.
-        */
-
-       tsk = current;
-       mm = tsk->mm;
-
-       if ((address >= VMALLOC_START && address < VMALLOC_END) ||
-           (address >= IOBASE_VADDR  && address < IOBASE_END)) {
-               if (ssr_md)
-                       /*
-                        * Process-contexts can never have this address
-                        * range mapped
-                        */
-                       if (handle_vmalloc_fault(mm, protection_flags,
-                                                textaccess, address))
-                               return 1;
-       } else if (!in_interrupt() && mm) {
-               if (handle_tlbmiss(mm, protection_flags, textaccess, address))
-                       return 1;
-       }
-
-       return 0;
-}
index f27dbe1c15992ed3f5f74a431de1ceea710c29c6..3aea25dc431ae27e24547e3e8b2c9f455790e4f8 100644 (file)
@@ -182,3 +182,43 @@ void tlb_unwire_entry(void)
 
        local_irq_restore(flags);
 }
+
+void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+{
+       unsigned long long ptel;
+       unsigned long long pteh=0;
+       struct tlb_info *tlbp;
+       unsigned long long next;
+       unsigned int fault_code = get_thread_fault_code();
+
+       /* Get PTEL first */
+       ptel = pte.pte_low;
+
+       /*
+        * Set PTEH register
+        */
+       pteh = neff_sign_extend(address & MMU_VPN_MASK);
+
+       /* Set the ASID. */
+       pteh |= get_asid() << PTEH_ASID_SHIFT;
+       pteh |= PTEH_VALID;
+
+       /* Set PTEL register, set_pte has performed the sign extension */
+       ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
+
+       if (fault_code & FAULT_CODE_ITLB)
+               tlbp = &cpu_data->itlb;
+       else
+               tlbp = &cpu_data->dtlb;
+
+       next = tlbp->next;
+       __flush_tlb_slot(next);
+       asm volatile ("putcfg %0,1,%2\n\n\t"
+                     "putcfg %0,0,%1\n"
+                     :  : "r" (next), "r" (pteh), "r" (ptel) );
+
+       next += TLB_STEP;
+       if (next > tlbp->last)
+               next = tlbp->first;
+       tlbp->next = next;
+}
diff --git a/arch/sh/mm/tlbex_32.c b/arch/sh/mm/tlbex_32.c
new file mode 100644 (file)
index 0000000..382262d
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * TLB miss handler for SH with an MMU.
+ *
+ *  Copyright (C) 1999  Niibe Yutaka
+ *  Copyright (C) 2003 - 2012  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kprobes.h>
+#include <linux/kdebug.h>
+#include <asm/mmu_context.h>
+#include <asm/thread_info.h>
+
+/*
+ * Called with interrupts disabled.
+ */
+asmlinkage int __kprobes
+handle_tlbmiss(struct pt_regs *regs, unsigned long error_code,
+              unsigned long address)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+       pte_t entry;
+
+       /*
+        * We don't take page faults for P1, P2, and parts of P4, these
+        * are always mapped, whether it be due to legacy behaviour in
+        * 29-bit mode, or due to PMB configuration in 32-bit mode.
+        */
+       if (address >= P3SEG && address < P3_ADDR_MAX) {
+               pgd = pgd_offset_k(address);
+       } else {
+               if (unlikely(address >= TASK_SIZE || !current->mm))
+                       return 1;
+
+               pgd = pgd_offset(current->mm, address);
+       }
+
+       pud = pud_offset(pgd, address);
+       if (pud_none_or_clear_bad(pud))
+               return 1;
+       pmd = pmd_offset(pud, address);
+       if (pmd_none_or_clear_bad(pmd))
+               return 1;
+       pte = pte_offset_kernel(pmd, address);
+       entry = *pte;
+       if (unlikely(pte_none(entry) || pte_not_present(entry)))
+               return 1;
+       if (unlikely(error_code && !pte_write(entry)))
+               return 1;
+
+       if (error_code)
+               entry = pte_mkdirty(entry);
+       entry = pte_mkyoung(entry);
+
+       set_pte(pte, entry);
+
+#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SMP)
+       /*
+        * SH-4 does not set MMUCR.RC to the corresponding TLB entry in
+        * the case of an initial page write exception, so we need to
+        * flush it in order to avoid potential TLB entry duplication.
+        */
+       if (error_code == FAULT_CODE_INITIAL)
+               local_flush_tlb_one(get_asid(), address & PAGE_MASK);
+#endif
+
+       set_thread_fault_code(error_code);
+       update_mmu_cache(NULL, address, pte);
+
+       return 0;
+}
diff --git a/arch/sh/mm/tlbex_64.c b/arch/sh/mm/tlbex_64.c
new file mode 100644 (file)
index 0000000..8557548
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * The SH64 TLB miss.
+ *
+ * Original code from fault.c
+ * Copyright (C) 2000, 2001  Paolo Alberelli
+ *
+ * Fast PTE->TLB refill path
+ * Copyright (C) 2003 Richard.Curnow@superh.com
+ *
+ * IMPORTANT NOTES :
+ * The do_fast_page_fault function is called from a context in entry.S
+ * where very few registers have been saved.  In particular, the code in
+ * this file must be compiled not to use ANY caller-save registers that
+ * are not part of the restricted save set.  Also, it means that code in
+ * this file must not make calls to functions elsewhere in the kernel, or
+ * else the excepting context will see corruption in its caller-save
+ * registers.  Plus, the entry.S save area is non-reentrant, so this code
+ * has to run with SR.BL==1, i.e. no interrupts taken inside it and panic
+ * on any exception.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/kprobes.h>
+#include <asm/tlb.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+
+static int handle_tlbmiss(unsigned long long protection_flags,
+                         unsigned long address)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+       pte_t entry;
+
+       if (is_vmalloc_addr((void *)address)) {
+               pgd = pgd_offset_k(address);
+       } else {
+               if (unlikely(address >= TASK_SIZE || !current->mm))
+                       return 1;
+
+               pgd = pgd_offset(current->mm, address);
+       }
+
+       pud = pud_offset(pgd, address);
+       if (pud_none(*pud) || !pud_present(*pud))
+               return 1;
+
+       pmd = pmd_offset(pud, address);
+       if (pmd_none(*pmd) || !pmd_present(*pmd))
+               return 1;
+
+       pte = pte_offset_kernel(pmd, address);
+       entry = *pte;
+       if (pte_none(entry) || !pte_present(entry))
+               return 1;
+
+       /*
+        * If the page doesn't have sufficient protection bits set to
+        * service the kind of fault being handled, there's not much
+        * point doing the TLB refill.  Punt the fault to the general
+        * handler.
+        */
+       if ((pte_val(entry) & protection_flags) != protection_flags)
+               return 1;
+
+       update_mmu_cache(NULL, address, pte);
+
+       return 0;
+}
+
+/*
+ * Put all this information into one structure so that everything is just
+ * arithmetic relative to a single base address.  This reduces the number
+ * of movi/shori pairs needed just to load addresses of static data.
+ */
+struct expevt_lookup {
+       unsigned short protection_flags[8];
+       unsigned char  is_text_access[8];
+       unsigned char  is_write_access[8];
+};
+
+#define PRU (1<<9)
+#define PRW (1<<8)
+#define PRX (1<<7)
+#define PRR (1<<6)
+
+/* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether
+   the fault happened in user mode or privileged mode. */
+static struct expevt_lookup expevt_lookup_table = {
+       .protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW},
+       .is_text_access   = {1,   1,   0, 0, 0,   0,   0,   0}
+};
+
+static inline unsigned int
+expevt_to_fault_code(unsigned long expevt)
+{
+       if (expevt == 0xa40)
+               return FAULT_CODE_ITLB;
+       else if (expevt == 0x060)
+               return FAULT_CODE_WRITE;
+
+       return 0;
+}
+
+/*
+   This routine handles page faults that can be serviced just by refilling a
+   TLB entry from an existing page table entry.  (This case represents a very
+   large majority of page faults.) Return 1 if the fault was successfully
+   handled.  Return 0 if the fault could not be handled.  (This leads into the
+   general fault handling in fault.c which deals with mapping file-backed
+   pages, stack growth, segmentation faults, swapping etc etc)
+ */
+asmlinkage int __kprobes
+do_fast_page_fault(unsigned long long ssr_md, unsigned long long expevt,
+                  unsigned long address)
+{
+       unsigned long long protection_flags;
+       unsigned long long index;
+       unsigned long long expevt4;
+       unsigned int fault_code;
+
+       /* The next few lines implement a way of hashing EXPEVT into a
+        * small array index which can be used to lookup parameters
+        * specific to the type of TLBMISS being handled.
+        *
+        * Note:
+        *      ITLBMISS has EXPEVT==0xa40
+        *      RTLBMISS has EXPEVT==0x040
+        *      WTLBMISS has EXPEVT==0x060
+        */
+       expevt4 = (expevt >> 4);
+       /* TODO : xor ssr_md into this expression too. Then we can check
+        * that PRU is set when it needs to be. */
+       index = expevt4 ^ (expevt4 >> 5);
+       index &= 7;
+
+       fault_code = expevt_to_fault_code(expevt);
+
+       protection_flags = expevt_lookup_table.protection_flags[index];
+
+       if (expevt_lookup_table.is_text_access[index])
+               fault_code |= FAULT_CODE_ITLB;
+       if (!ssr_md)
+               fault_code |= FAULT_CODE_USER;
+
+       set_thread_fault_code(fault_code);
+
+       return handle_tlbmiss(protection_flags, address);
+}
index 11c5a18f10ed9655c5fbc7acc6e5202b28b05e93..f33fdd2558e8ef74a56b2693e454e976f7c8cdbc 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2000, 2001  Paolo Alberelli
  * Copyright (C) 2003  Richard Curnow (/proc/tlb, bug fixes)
- * Copyright (C) 2003 - 2009 Paul Mundt
+ * Copyright (C) 2003 - 2012 Paul Mundt
  *
  * 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
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 
-extern void die(const char *,struct pt_regs *,long);
-
-#define PFLAG(val,flag)   (( (val) & (flag) ) ? #flag : "" )
-#define PPROT(flag) PFLAG(pgprot_val(prot),flag)
-
-static inline void print_prots(pgprot_t prot)
-{
-       printk("prot is 0x%016llx\n",pgprot_val(prot));
-
-       printk("%s %s %s %s %s\n",PPROT(_PAGE_SHARED),PPROT(_PAGE_READ),
-              PPROT(_PAGE_EXECUTE),PPROT(_PAGE_WRITE),PPROT(_PAGE_USER));
-}
-
-static inline void print_vma(struct vm_area_struct *vma)
-{
-       printk("vma start 0x%08lx\n", vma->vm_start);
-       printk("vma end   0x%08lx\n", vma->vm_end);
-
-       print_prots(vma->vm_page_prot);
-       printk("vm_flags 0x%08lx\n", vma->vm_flags);
-}
-
-static inline void print_task(struct task_struct *tsk)
-{
-       printk("Task pid %d\n", task_pid_nr(tsk));
-}
-
-static pte_t *lookup_pte(struct mm_struct *mm, unsigned long address)
-{
-       pgd_t *dir;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *pte;
-       pte_t entry;
-
-       dir = pgd_offset(mm, address);
-       if (pgd_none(*dir))
-               return NULL;
-
-       pud = pud_offset(dir, address);
-       if (pud_none(*pud))
-               return NULL;
-
-       pmd = pmd_offset(pud, address);
-       if (pmd_none(*pmd))
-               return NULL;
-
-       pte = pte_offset_kernel(pmd, address);
-       entry = *pte;
-       if (pte_none(entry) || !pte_present(entry))
-               return NULL;
-
-       return pte;
-}
-
-/*
- * This routine handles page faults.  It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
-                             unsigned long textaccess, unsigned long address)
-{
-       struct task_struct *tsk;
-       struct mm_struct *mm;
-       struct vm_area_struct * vma;
-       const struct exception_table_entry *fixup;
-       pte_t *pte;
-       int fault;
-
-       /* SIM
-        * Note this is now called with interrupts still disabled
-        * This is to cope with being called for a missing IO port
-        * address with interrupts disabled. This should be fixed as
-        * soon as we have a better 'fast path' miss handler.
-        *
-        * Plus take care how you try and debug this stuff.
-        * For example, writing debug data to a port which you
-        * have just faulted on is not going to work.
-        */
-
-       tsk = current;
-       mm = tsk->mm;
-
-       /* Not an IO address, so reenable interrupts */
-       local_irq_enable();
-
-       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
-
-       /*
-        * If we're in an interrupt or have no user
-        * context, we must not take the fault..
-        */
-       if (in_atomic() || !mm)
-               goto no_context;
-
-       /* TLB misses upon some cache flushes get done under cli() */
-       down_read(&mm->mmap_sem);
-
-       vma = find_vma(mm, address);
-
-       if (!vma) {
-#ifdef DEBUG_FAULT
-               print_task(tsk);
-               printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
-                      __func__, __LINE__,
-                      address,regs->pc,textaccess,writeaccess);
-               show_regs(regs);
-#endif
-               goto bad_area;
-       }
-       if (vma->vm_start <= address) {
-               goto good_area;
-       }
-
-       if (!(vma->vm_flags & VM_GROWSDOWN)) {
-#ifdef DEBUG_FAULT
-               print_task(tsk);
-               printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
-                      __func__, __LINE__,
-                      address,regs->pc,textaccess,writeaccess);
-               show_regs(regs);
-
-               print_vma(vma);
-#endif
-               goto bad_area;
-       }
-       if (expand_stack(vma, address)) {
-#ifdef DEBUG_FAULT
-               print_task(tsk);
-               printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
-                      __func__, __LINE__,
-                      address,regs->pc,textaccess,writeaccess);
-               show_regs(regs);
-#endif
-               goto bad_area;
-       }
-/*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
-       if (textaccess) {
-               if (!(vma->vm_flags & VM_EXEC))
-                       goto bad_area;
-       } else {
-               if (writeaccess) {
-                       if (!(vma->vm_flags & VM_WRITE))
-                               goto bad_area;
-               } else {
-                       if (!(vma->vm_flags & VM_READ))
-                               goto bad_area;
-               }
-       }
-
-       /*
-        * If for any reason at all we couldn't handle the fault,
-        * make sure we exit gracefully rather than endlessly redo
-        * the fault.
-        */
-       fault = handle_mm_fault(mm, vma, address, writeaccess ? FAULT_FLAG_WRITE : 0);
-       if (unlikely(fault & VM_FAULT_ERROR)) {
-               if (fault & VM_FAULT_OOM)
-                       goto out_of_memory;
-               else if (fault & VM_FAULT_SIGBUS)
-                       goto do_sigbus;
-               BUG();
-       }
-
-       if (fault & VM_FAULT_MAJOR) {
-               tsk->maj_flt++;
-               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
-                                    regs, address);
-       } else {
-               tsk->min_flt++;
-               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
-                                    regs, address);
-       }
-
-       /* If we get here, the page fault has been handled.  Do the TLB refill
-          now from the newly-setup PTE, to avoid having to fault again right
-          away on the same instruction. */
-       pte = lookup_pte (mm, address);
-       if (!pte) {
-               /* From empirical evidence, we can get here, due to
-                  !pte_present(pte).  (e.g. if a swap-in occurs, and the page
-                  is swapped back out again before the process that wanted it
-                  gets rescheduled?) */
-               goto no_pte;
-       }
-
-       __do_tlb_refill(address, textaccess, pte);
-
-no_pte:
-
-       up_read(&mm->mmap_sem);
-       return;
-
-/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
-#ifdef DEBUG_FAULT
-       printk("fault:bad area\n");
-#endif
-       up_read(&mm->mmap_sem);
-
-       if (user_mode(regs)) {
-               static int count=0;
-               siginfo_t info;
-               if (count < 4) {
-                       /* This is really to help debug faults when starting
-                        * usermode, so only need a few */
-                       count++;
-                       printk("user mode bad_area address=%08lx pid=%d (%s) pc=%08lx\n",
-                               address, task_pid_nr(current), current->comm,
-                               (unsigned long) regs->pc);
-#if 0
-                       show_regs(regs);
-#endif
-               }
-               if (is_global_init(tsk)) {
-                       panic("INIT had user mode bad_area\n");
-               }
-               tsk->thread.address = address;
-               tsk->thread.error_code = writeaccess;
-               info.si_signo = SIGSEGV;
-               info.si_errno = 0;
-               info.si_addr = (void *) address;
-               force_sig_info(SIGSEGV, &info, tsk);
-               return;
-       }
-
-no_context:
-#ifdef DEBUG_FAULT
-       printk("fault:No context\n");
-#endif
-       /* Are we prepared to handle this kernel fault?  */
-       fixup = search_exception_tables(regs->pc);
-       if (fixup) {
-               regs->pc = fixup->fixup;
-               return;
-       }
-
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- *
- */
-       if (address < PAGE_SIZE)
-               printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-       else
-               printk(KERN_ALERT "Unable to handle kernel paging request");
-       printk(" at virtual address %08lx\n", address);
-       printk(KERN_ALERT "pc = %08Lx%08Lx\n", regs->pc >> 32, regs->pc & 0xffffffff);
-       die("Oops", regs, writeaccess);
-       do_exit(SIGKILL);
-
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-out_of_memory:
-       up_read(&mm->mmap_sem);
-       if (!user_mode(regs))
-               goto no_context;
-       pagefault_out_of_memory();
-       return;
-
-do_sigbus:
-       printk("fault:Do sigbus\n");
-       up_read(&mm->mmap_sem);
-
-       /*
-        * Send a sigbus, regardless of whether we were in kernel
-        * or user mode.
-        */
-       tsk->thread.address = address;
-       tsk->thread.error_code = writeaccess;
-       tsk->thread.trap_no = 14;
-       force_sig(SIGBUS, tsk);
-
-       /* Kernel mode? Handle exceptions or die */
-       if (!user_mode(regs))
-               goto no_context;
-}
-
 void local_flush_tlb_one(unsigned long asid, unsigned long page)
 {
        unsigned long long match, pteh=0, lpage;
@@ -458,7 +170,3 @@ void __flush_tlb_global(void)
 {
        flush_tlb_all();
 }
-
-void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
-{
-}
index 6dd56c4d0054441c0e80b572eb9458514284b19e..569977e52c91dbac2ca8509236b87443ed614a21 100644 (file)
@@ -51,6 +51,8 @@ SDK7780                       SH_SDK7780
 MIGOR                  SH_MIGOR
 RSK7201                        SH_RSK7201
 RSK7203                        SH_RSK7203
+RSK7264                        SH_RSK7264
+RSK7269                        SH_RSK7269
 AP325RXA               SH_AP325RXA
 SH2007                 SH_SH2007
 SH7757LCR              SH_SH7757LCR
index 9cbd854fdfdd8a4fc0e49e52b838170941026309..f74ac9ee33a8ef461f0277af60731adf7a0f904a 100644 (file)
@@ -108,9 +108,6 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc,
 #define release_thread(tsk)            do { } while(0)
 extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 extern unsigned long get_wchan(struct task_struct *);
 
 #define task_pt_regs(tsk) ((tsk)->thread.kregs)
index e713db249931fb3895cfcd842176187b8d948f71..67df5cc1001126cbc3fddaaabebc9e7e53e556f8 100644 (file)
@@ -186,9 +186,6 @@ do { \
 /* Free all resources held by a thread. */
 #define release_thread(tsk)            do { } while (0)
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 extern unsigned long get_wchan(struct task_struct *task);
index 34c1e01ffb5e24648c4171fccedcd3257ef5e0da..15cd8a4a06ce1dc62170444629edc7c17d9da2ab 100644 (file)
@@ -210,9 +210,6 @@ static inline void release_thread(struct task_struct *dead_task)
        /* Nothing for now */
 }
 
-/* Prepare to copy thread state - unlazy all lazy status. */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
 extern int do_work_pending(struct pt_regs *regs, u32 flags);
index 20a49ba93cb9d537d3f0149fc2e60cb770c2c43d..43ef890d292c22081907f7983639f620d49c8483 100644 (file)
@@ -56,11 +56,6 @@ config GENERIC_CLOCKEVENTS
        bool
        default y
 
-# Used in kernel/irq/manage.c and include/linux/irq.h
-config IRQ_RELEASE_METHOD
-       bool
-       default y
-
 config HZ
        int
        default 100
index fdc97e2c3d7370d69eb6f07fc133e993c0db8069..7823ab12e6a4fb1d27406878f2e1219cd2c5d897 100644 (file)
@@ -12,7 +12,6 @@ CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_BUG=y
 CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_IRQ_RELEASE_METHOD=y
 CONFIG_HZ=100
 
 #
index ca4c7ebfd0aa592141021d779f1d49feac0f33a2..45e248c2f43c7c1c8c618aea0eb41980fd28a046 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/tty_flip.h>
 #include "chan.h"
 #include "os.h"
+#include "irq_kern.h"
 
 #ifdef CONFIG_NOCONFIG_CHAN
 static void *not_configged_init(char *str, int device,
@@ -213,9 +214,9 @@ void free_irqs(void)
                chan = list_entry(ele, struct chan, free_list);
 
                if (chan->input && chan->enabled)
-                       free_irq(chan->line->driver->read_irq, chan);
+                       um_free_irq(chan->line->driver->read_irq, chan);
                if (chan->output && chan->enabled)
-                       free_irq(chan->line->driver->write_irq, chan);
+                       um_free_irq(chan->line->driver->write_irq, chan);
                chan->enabled = 0;
        }
 }
@@ -234,9 +235,9 @@ static void close_one_chan(struct chan *chan, int delay_free_irq)
        }
        else {
                if (chan->input && chan->enabled)
-                       free_irq(chan->line->driver->read_irq, chan);
+                       um_free_irq(chan->line->driver->read_irq, chan);
                if (chan->output && chan->enabled)
-                       free_irq(chan->line->driver->write_irq, chan);
+                       um_free_irq(chan->line->driver->write_irq, chan);
                chan->enabled = 0;
        }
        if (chan->ops->close != NULL)
index 4ab0d9c0911c7bd6fe42ac7369211ef1f4914d07..acfd0e0fd0c98cfcabe626581eea0a722c86b6ff 100644 (file)
@@ -699,7 +699,7 @@ struct winch {
 static void __free_winch(struct work_struct *work)
 {
        struct winch *winch = container_of(work, struct winch, work);
-       free_irq(WINCH_IRQ, winch);
+       um_free_irq(WINCH_IRQ, winch);
 
        if (winch->pid != -1)
                os_kill_process(winch->pid, 1);
index 95f4416e6d9f3574b2a2b85acf6ff6b858fa344a..0d60c5685c2655505a0a0b7c2ed63d19e4b679a8 100644 (file)
@@ -195,7 +195,7 @@ static int uml_net_close(struct net_device *dev)
 
        netif_stop_queue(dev);
 
-       free_irq(dev->irq, dev);
+       um_free_irq(dev->irq, dev);
        if (lp->close != NULL)
                (*lp->close)(lp->fd, &lp->user);
        lp->fd = -1;
@@ -835,7 +835,7 @@ static void close_devices(void)
        spin_lock(&opened_lock);
        list_for_each(ele, &opened) {
                lp = list_entry(ele, struct uml_net_private, list);
-               free_irq(lp->dev->irq, lp->dev);
+               um_free_irq(lp->dev->irq, lp->dev);
                if ((lp->close != NULL) && (lp->fd >= 0))
                        (*lp->close)(lp->fd, &lp->user);
                if (lp->remove != NULL)
index e31680e662a473eeee0d4e62543110b533b6d70d..11866ffd45a988c24da3b38c07d806f2f5f2e1c5 100644 (file)
@@ -254,7 +254,7 @@ int port_wait(void *data)
                 * connection.  Then we loop here throwing out failed
                 * connections until a good one is found.
                 */
-               free_irq(TELNETD_IRQ, conn);
+               um_free_irq(TELNETD_IRQ, conn);
 
                if (conn->fd >= 0)
                        break;
index 8bd130f0bda351e4295752f0d2d1c8e451752330..b68bbe269e018cb00154781eec3706060e1b1c8d 100644 (file)
@@ -65,7 +65,7 @@ int xterm_fd(int socket, int *pid_out)
         * isn't set) this will hang... */
        wait_for_completion(&data->ready);
 
-       free_irq(XTERM_IRQ, data);
+       um_free_irq(XTERM_IRQ, data);
 
        ret = data->new_fd;
        *pid_out = data->pid;
index 6a3f9845743ea485c24254696ff4b41646e418d0..5888f1b834771a102a7d212581ec1f3eb9aff3b2 100644 (file)
@@ -273,6 +273,12 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval)
 }
 #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
+#define __HAVE_ARCH_PTE_SAME
+static inline int pte_same(pte_t pte_a, pte_t pte_b)
+{
+       return !((pte_val(pte_a) ^ pte_val(pte_b)) & ~_PAGE_NEWPAGE);
+}
+
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
@@ -348,11 +354,11 @@ extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
 #define update_mmu_cache(vma,address,ptep) do ; while (0)
 
 /* Encode and de-code a swap entry */
-#define __swp_type(x)                  (((x).val >> 4) & 0x3f)
+#define __swp_type(x)                  (((x).val >> 5) & 0x1f)
 #define __swp_offset(x)                        ((x).val >> 11)
 
 #define __swp_entry(type, offset) \
-       ((swp_entry_t) { ((type) << 4) | ((offset) << 11) })
+       ((swp_entry_t) { ((type) << 5) | ((offset) << 11) })
 #define __pte_to_swp_entry(pte) \
        ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) })
 #define __swp_entry_to_pte(x)          ((pte_t) { (x).val })
index 7827394a5b6cd0443fb2b0201244a0e790506920..69f1c57a8d0dc895c727b74e1a53f8acd6c94a4c 100644 (file)
@@ -74,11 +74,6 @@ static inline void release_thread(struct task_struct *task)
 
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-static inline void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
-
 extern unsigned long thread_saved_pc(struct task_struct *t);
 
 static inline void mm_copy_segments(struct mm_struct *from_mm,
index 200c4ab1240c3deeaad3eb98d8ef1a46ef3c64e6..c04e5ab68f56a3f14d3831c501c3af66b0d2610b 100644 (file)
@@ -71,6 +71,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_MEMDIE             5       /* is terminating due to OOM killer */
 #define TIF_SYSCALL_AUDIT      6
 #define TIF_RESTORE_SIGMASK    7
+#define TIF_NOTIFY_RESUME      8
 
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
@@ -78,6 +79,5 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_POLLING_NRFLAG     (1 << TIF_POLLING_NRFLAG)
 #define _TIF_MEMDIE            (1 << TIF_MEMDIE)
 #define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
-#define _TIF_RESTORE_SIGMASK   (1 << TIF_RESTORE_SIGMASK)
 
 #endif
index b05d22f3d84e2450420a38adf8f641a106d5e236..7a5bfa6291b807c039ab5f150e357266b415b414 100644 (file)
@@ -13,6 +13,6 @@ extern int um_request_irq(unsigned int irq, int fd, int type,
                          irq_handler_t handler,
                          unsigned long irqflags,  const char * devname,
                          void *dev_id);
-
+void um_free_irq(unsigned int irq, void *dev);
 #endif
 
index 71b8c947e5efde749730ee3c8844b860dab15b4c..00506c3d5d6e5ce9cabe83fa7163c67fdec4eb7f 100644 (file)
@@ -297,6 +297,13 @@ unsigned int do_IRQ(int irq, struct uml_pt_regs *regs)
        return 1;
 }
 
+void um_free_irq(unsigned int irq, void *dev)
+{
+       free_irq_by_irq_and_dev(irq, dev);
+       free_irq(irq, dev);
+}
+EXPORT_SYMBOL(um_free_irq);
+
 int um_request_irq(unsigned int irq, int fd, int type,
                   irq_handler_t handler,
                   unsigned long irqflags, const char * devname,
@@ -327,7 +334,6 @@ static void dummy(struct irq_data *d)
 /* This is used for everything else than the timer. */
 static struct irq_chip normal_irq_type = {
        .name = "SIGIO",
-       .release = free_irq_by_irq_and_dev,
        .irq_disable = dummy,
        .irq_enable = dummy,
        .irq_ack = dummy,
@@ -335,7 +341,6 @@ static struct irq_chip normal_irq_type = {
 
 static struct irq_chip SIGVTALRM_irq_type = {
        .name = "SIGVTALRM",
-       .release = free_irq_by_irq_and_dev,
        .irq_disable = dummy,
        .irq_enable = dummy,
        .irq_ack = dummy,
index 2b73dedb44cacdda741b3e5774346c93b37b1b22..3a2235e0abc3e18dec7862208364bb8de2d6916c 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/seq_file.h>
 #include <linux/tick.h>
 #include <linux/threads.h>
+#include <linux/tracehook.h>
 #include <asm/current.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
@@ -114,8 +115,13 @@ void interrupt_end(void)
 {
        if (need_resched())
                schedule();
-       if (test_tsk_thread_flag(current, TIF_SIGPENDING))
+       if (test_thread_flag(TIF_SIGPENDING))
                do_signal();
+       if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+               tracehook_notify_resume(&current->thread.regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
+       }
 }
 
 void exit_thread(void)
@@ -190,7 +196,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
        if (current->thread.forking) {
                memcpy(&p->thread.regs.regs, &regs->regs,
                       sizeof(p->thread.regs.regs));
-               REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.gp, 0);
+               UPT_SET_SYSCALL_RETURN(&p->thread.regs.regs, 0);
                if (sp != 0)
                        REGS_SP(p->thread.regs.regs.gp) = sp;
 
index fb12f4c5e649f60e8ddd847f88fc7c72b5639d24..187118fbe1bce19473f7f5bda0b434d458f351e4 100644 (file)
@@ -29,9 +29,6 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,
        unsigned long sp;
        int err;
 
-       /* Always make any pending restarted system calls return -EINTR */
-       current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
        /* Did we come from a system call? */
        if (PT_REGS_SYSCALL_NR(regs) >= 0) {
                /* If so, check system call restarting.. */
@@ -77,15 +74,14 @@ static int kern_do_signal(struct pt_regs *regs)
 {
        struct k_sigaction ka_copy;
        siginfo_t info;
-       sigset_t *oldset;
        int sig, handled_sig = 0;
 
-       if (test_thread_flag(TIF_RESTORE_SIGMASK))
-               oldset = &current->saved_sigmask;
-       else
-               oldset = &current->blocked;
-
        while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) {
+               sigset_t *oldset;
+               if (test_thread_flag(TIF_RESTORE_SIGMASK))
+                       oldset = &current->saved_sigmask;
+               else
+                       oldset = &current->blocked;
                handled_sig = 1;
                /* Whee!  Actually deliver the signal.  */
                if (!handle_signal(regs, sig, &ka_copy, &info, oldset)) {
index f5173e1ec3ac0b7f7bf7ccfe86a2d5a63b60e3b8..05fbeb480e0b554f313185ef97a6482c61b4fb72 100644 (file)
@@ -34,7 +34,7 @@ void handle_syscall(struct uml_pt_regs *r)
                result = -ENOSYS;
        else result = EXECUTE_SYSCALL(syscall, regs);
 
-       REGS_SET_SYSCALL_RETURN(r->gp, result);
+       UPT_SET_SYSCALL_RETURN(r, result);
 
        syscall_trace(r, 1);
 }
index 7f3d4d86431a0801ffbc37fc2273b2f373ed5444..f819af951c19004b61be77050e699ed8897cb45d 100644 (file)
@@ -75,6 +75,7 @@ static int do_ops(struct host_vm_change *hvc, int end,
                default:
                        printk(KERN_ERR "Unknown op type %d in do_ops\n",
                               op->type);
+                       BUG();
                        break;
                }
        }
index c0afff7af4bd0f8151c2f2210ae8a89d9768d4bd..90b310d29179e3aca968d4aabc9f095a25216889 100644 (file)
@@ -48,10 +48,6 @@ __initcall(init_syscall_regs);
 
 extern int proc_mm;
 
-int single_count = 0;
-int multi_count = 0;
-int multi_op_count = 0;
-
 static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
 {
        int n, i;
@@ -64,8 +60,6 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
                /* FIXME: Need to look up userspace_pid by cpu */
                pid = userspace_pid[0];
 
-       multi_count++;
-
        n = ptrace_setregs(pid, syscall_regs);
        if (n < 0) {
                printk(UM_KERN_ERR "Registers - \n");
@@ -126,9 +120,6 @@ long run_syscall_stub(struct mm_id * mm_idp, int syscall,
 {
        unsigned long *stack = check_init_stack(mm_idp, *addr);
 
-       if (done && *addr == NULL)
-               single_count++;
-
        *stack += sizeof(long);
        stack += *stack / sizeof(long);
 
@@ -141,7 +132,6 @@ long run_syscall_stub(struct mm_id * mm_idp, int syscall,
        *stack++ = args[5];
        *stack++ = expected;
        *stack = 0;
-       multi_op_count++;
 
        if (!done && ((((unsigned long) stack) & ~UM_KERN_PAGE_MASK) <
                     UM_KERN_PAGE_SIZE - 10 * sizeof(long))) {
index f0d780a51f9b5dec74a5310fe0f1fd2c4fdc7b28..14382cb09657f67333f5a32f4d95910ae10e0b1d 100644 (file)
@@ -68,9 +68,6 @@ struct task_struct;
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 unsigned long get_wchan(struct task_struct *p);
 
 #define cpu_relax()                    barrier()
index 7b383d8da7b93d4091fadbff8db13036e0f838ff..4d37072c498a8b20853e1bfdd887d720c554a051 100644 (file)
@@ -12,6 +12,7 @@ config X86_32
 
 config X86_64
        def_bool 64BIT
+       select X86_DEV_DMA_OPS
 
 ### Arch settings
 config X86
@@ -83,6 +84,7 @@ config X86
        select DCACHE_WORD_ACCESS
        select GENERIC_SMP_IDLE_THREAD
        select HAVE_ARCH_SECCOMP_FILTER
+       select BUILDTIME_EXTABLE_SORT
 
 config INSTRUCTION_DECODER
        def_bool (KPROBES || PERF_EVENTS)
@@ -326,6 +328,7 @@ config X86_EXTENDED_PLATFORM
                NUMAQ (IBM/Sequent)
                RDC R-321x SoC
                SGI 320/540 (Visual Workstation)
+               STA2X11-based (e.g. Northville)
                Summit/EXA (IBM x440)
                Unisys ES7000 IA32 series
                Moorestown MID devices
@@ -372,6 +375,7 @@ config X86_VSMP
        select PARAVIRT
        depends on X86_64 && PCI
        depends on X86_EXTENDED_PLATFORM
+       depends on SMP
        ---help---
          Support for ScaleMP vSMP systems.  Say 'Y' here if this kernel is
          supposed to run on these EM64T-based machines.  Only choose this option
@@ -458,10 +462,10 @@ config X86_32_NON_STANDARD
        depends on X86_32 && SMP
        depends on X86_EXTENDED_PLATFORM
        ---help---
-         This option compiles in the NUMAQ, Summit, bigsmp, ES7000, default
-         subarchitectures.  It is intended for a generic binary kernel.
-         if you select them all, kernel will probe it one by one. and will
-         fallback to default.
+         This option compiles in the NUMAQ, Summit, bigsmp, ES7000,
+         STA2X11, default subarchitectures.  It is intended for a generic
+         binary kernel. If you select them all, kernel will probe it
+         one by one and will fallback to default.
 
 # Alphabetically sorted list of Non standard 32 bit platforms
 
@@ -501,6 +505,22 @@ config X86_VISWS
          A kernel compiled for the Visual Workstation will run on general
          PCs as well. See <file:Documentation/sgi-visws.txt> for details.
 
+config STA2X11
+       bool "STA2X11 Companion Chip Support"
+       depends on X86_32_NON_STANDARD && PCI
+       select X86_DEV_DMA_OPS
+       select X86_DMA_REMAP
+       select SWIOTLB
+       select MFD_STA2X11
+       select ARCH_REQUIRE_GPIOLIB
+       default n
+       ---help---
+         This adds support for boards based on the STA2X11 IO-Hub,
+         a.k.a. "ConneXt". The chip is used in place of the standard
+         PC chipset, so all "standard" peripherals are missing. If this
+         option is selected the kernel will still be able to boot on
+         standard PC machines.
+
 config X86_SUMMIT
        bool "Summit/EXA (IBM x440)"
        depends on X86_32_NON_STANDARD
@@ -1237,10 +1257,6 @@ config NODES_SHIFT
          Specify the maximum number of NUMA Nodes available on the target
          system.  Increases memory reserved to accommodate various tables.
 
-config HAVE_ARCH_BOOTMEM
-       def_bool y
-       depends on X86_32 && NUMA
-
 config HAVE_ARCH_ALLOC_REMAP
        def_bool y
        depends on X86_32 && NUMA
@@ -2213,6 +2229,14 @@ config HAVE_TEXT_POKE_SMP
        bool
        select STOP_MACHINE if SMP
 
+config X86_DEV_DMA_OPS
+       bool
+       depends on X86_64 || STA2X11
+
+config X86_DMA_REMAP
+       bool
+       depends on STA2X11
+
 source "net/Kconfig"
 
 source "drivers/Kconfig"
index 277418ff8b525cfcd0f998739ec65a10c52cdd2f..dc611a40a336eeb4eba02da5d34ea505d969df19 100644 (file)
@@ -205,6 +205,7 @@ archclean:
        $(Q)rm -rf $(objtree)/arch/i386
        $(Q)rm -rf $(objtree)/arch/x86_64
        $(Q)$(MAKE) $(clean)=$(boot)
+       $(Q)$(MAKE) $(clean)=arch/x86/tools
 
 define archhelp
   echo  '* bzImage      - Compressed kernel image (arch/x86/boot/bzImage)'
index 0cdfc0d2315e51d84c0c0383bbd3b82020b52ceb..2c14e76bb4c71255ee9c1d9b29b171dd73a33d60 100644 (file)
@@ -904,11 +904,19 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table)
 
        memset(boot_params, 0x0, 0x4000);
 
-       /* Copy first two sectors to boot_params */
-       memcpy(boot_params, image->image_base, 1024);
-
        hdr = &boot_params->hdr;
 
+       /* Copy the second sector to boot_params */
+       memcpy(&hdr->jump, image->image_base + 512, 512);
+
+       /*
+        * Fill out some of the header fields ourselves because the
+        * EFI firmware loader doesn't load the first sector.
+        */
+       hdr->root_flags = 1;
+       hdr->vid_mode = 0xffff;
+       hdr->boot_flag = 0xAA55;
+
        /*
         * The EFI firmware loader could have placed the kernel image
         * anywhere in memory, but the kernel has various restrictions
index f1bbeeb091489d43267975234b0c0403e9cbffe5..8bbea6aa40d9705b68e1dd9531b7c9c74d96a106 100644 (file)
@@ -147,7 +147,7 @@ optional_header:
        # Filled in by build.c
        .long   0x0000                          # AddressOfEntryPoint
 
-       .long   0x0000                          # BaseOfCode
+       .long   0x0200                          # BaseOfCode
 #ifdef CONFIG_X86_32
        .long   0                               # data
 #endif
@@ -189,7 +189,7 @@ extra_header_fields:
        .quad   0                               # SizeOfHeapCommit
 #endif
        .long   0                               # LoaderFlags
-       .long   0x1                             # NumberOfRvaAndSizes
+       .long   0x6                             # NumberOfRvaAndSizes
 
        .quad   0                               # ExportTable
        .quad   0                               # ImportTable
@@ -217,18 +217,17 @@ section_table:
 
        #
        # The EFI application loader requires a relocation section
-       # because EFI applications are relocatable and not having
-       # this section seems to confuse it. But since we don't need
-       # the loader to fixup any relocs for us just fill it with a
-       # single dummy reloc.
+       # because EFI applications must be relocatable. But since
+       # we don't need the loader to fixup any relocs for us, we
+       # just create an empty (zero-length) .reloc section header.
        #
        .ascii  ".reloc"
        .byte   0
        .byte   0
-       .long   reloc_end - reloc_start
-       .long   reloc_start
-       .long   reloc_end - reloc_start         # SizeOfRawData
-       .long   reloc_start                     # PointerToRawData
+       .long   0
+       .long   0
+       .long   0                               # SizeOfRawData
+       .long   0                               # PointerToRawData
        .long   0                               # PointerToRelocations
        .long   0                               # PointerToLineNumbers
        .word   0                               # NumberOfRelocations
@@ -469,10 +468,3 @@ setup_corrupt:
 
        .data
 dummy: .long   0
-
-       .section .reloc
-reloc_start:
-       .long   dummy - reloc_start
-       .long   10
-       .word   0
-reloc_end:
index 40358c8905befe2cdf8c8ef6055300e00e08a3a0..cf6083d444f4710ff79b8f41b2cdc65113c83eb0 100644 (file)
@@ -57,14 +57,20 @@ static void copy_boot_params(void)
 }
 
 /*
- * Set the keyboard repeat rate to maximum.  Unclear why this
+ * Query the keyboard lock status as given by the BIOS, and
+ * set the keyboard repeat rate to maximum.  Unclear why the latter
  * is done here; this might be possible to kill off as stale code.
  */
-static void keyboard_set_repeat(void)
+static void keyboard_init(void)
 {
-       struct biosregs ireg;
+       struct biosregs ireg, oreg;
        initregs(&ireg);
-       ireg.ax = 0x0305;
+
+       ireg.ah = 0x02;         /* Get keyboard status */
+       intcall(0x16, &ireg, &oreg);
+       boot_params.kbd_status = oreg.al;
+
+       ireg.ax = 0x0305;       /* Set keyboard repeat rate */
        intcall(0x16, &ireg, NULL);
 }
 
@@ -151,8 +157,8 @@ void main(void)
        /* Detect memory layout */
        detect_memory();
 
-       /* Set keyboard repeat rate (why?) */
-       keyboard_set_repeat();
+       /* Set keyboard repeat rate (why?) and query the lock flags */
+       keyboard_init();
 
        /* Query MCA information */
        query_mca();
index 24443a3320838ede8cdf995525851794e8d1052a..3f61f6e2b46f3ece150f20b409c1e652f3dd301b 100644 (file)
@@ -198,12 +198,19 @@ int main(int argc, char ** argv)
 
        pe_header = get_unaligned_le32(&buf[0x3c]);
 
-       /* Size of code */
-       put_unaligned_le32(file_sz, &buf[pe_header + 0x1c]);
-
        /* Size of image */
        put_unaligned_le32(file_sz, &buf[pe_header + 0x50]);
 
+       /*
+        * Subtract the size of the first section (512 bytes) which
+        * includes the header and .reloc section. The remaining size
+        * is that of the .text section.
+        */
+       file_sz -= 512;
+
+       /* Size of code */
+       put_unaligned_le32(file_sz, &buf[pe_header + 0x1c]);
+
 #ifdef CONFIG_X86_32
        /*
         * Address of entry point.
@@ -216,8 +223,14 @@ int main(int argc, char ** argv)
        /* .text size */
        put_unaligned_le32(file_sz, &buf[pe_header + 0xb0]);
 
+       /* .text vma */
+       put_unaligned_le32(0x200, &buf[pe_header + 0xb4]);
+
        /* .text size of initialised data */
        put_unaligned_le32(file_sz, &buf[pe_header + 0xb8]);
+
+       /* .text file offset */
+       put_unaligned_le32(0x200, &buf[pe_header + 0xbc]);
 #else
        /*
         * Address of entry point. startup_32 is at the beginning and
@@ -231,9 +244,14 @@ int main(int argc, char ** argv)
        /* .text size */
        put_unaligned_le32(file_sz, &buf[pe_header + 0xc0]);
 
+       /* .text vma */
+       put_unaligned_le32(0x200, &buf[pe_header + 0xc4]);
+
        /* .text size of initialised data */
        put_unaligned_le32(file_sz, &buf[pe_header + 0xc8]);
 
+       /* .text file offset */
+       put_unaligned_le32(0x200, &buf[pe_header + 0xcc]);
 #endif /* CONFIG_X86_32 */
 #endif /* CONFIG_EFI_STUB */
 
index e3e734005e19c1849dfb6f6be7a5b26f2fc9b374..20e5f7ba0e6b2e428297a1fd144db588199e6aad 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/thread_info.h>   
 #include <asm/segment.h>
 #include <asm/irqflags.h>
+#include <asm/asm.h>
 #include <linux/linkage.h>
 #include <linux/err.h>
 
@@ -146,9 +147,7 @@ ENTRY(ia32_sysenter_target)
        /* no need to do an access_ok check here because rbp has been
           32bit zero extended */ 
 1:     movl    (%rbp),%ebp
-       .section __ex_table,"a"
-       .quad 1b,ia32_badarg
-       .previous       
+       _ASM_EXTABLE(1b,ia32_badarg)
        orl     $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
        testl   $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
        CFI_REMEMBER_STATE
@@ -303,9 +302,7 @@ ENTRY(ia32_cstar_target)
           32bit zero extended */ 
        /* hardware stack frame is complete now */      
 1:     movl    (%r8),%r9d
-       .section __ex_table,"a"
-       .quad 1b,ia32_badarg
-       .previous       
+       _ASM_EXTABLE(1b,ia32_badarg)
        orl     $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
        testl   $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
        CFI_REMEMBER_STATE
index aec2202a596cb0348aa6e5c1b397cff09d3a3386..edca9c0a79ccbecb73f2cc90973525f658ba66d7 100644 (file)
@@ -287,11 +287,6 @@ asmlinkage long sys32_sigaction(int sig, struct old_sigaction32 __user *act,
        return ret;
 }
 
-asmlinkage long sys32_alarm(unsigned int seconds)
-{
-       return alarm_setitimer(seconds);
-}
-
 asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr,
                              int options)
 {
@@ -300,11 +295,6 @@ asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr,
 
 /* 32-bit timeval and related flotsam.  */
 
-asmlinkage long sys32_sysfs(int option, u32 arg1, u32 arg2)
-{
-       return sys_sysfs(option, arg1, arg2);
-}
-
 asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
                                    struct compat_timespec __user *interval)
 {
@@ -375,19 +365,6 @@ asmlinkage long sys32_pwrite(unsigned int fd, const char __user *ubuf,
 }
 
 
-asmlinkage long sys32_personality(unsigned long personality)
-{
-       int ret;
-
-       if (personality(current->personality) == PER_LINUX32 &&
-               personality == PER_LINUX)
-               personality = PER_LINUX32;
-       ret = sys_personality(personality);
-       if (ret == PER_LINUX32)
-               ret = PER_LINUX;
-       return ret;
-}
-
 asmlinkage long sys32_sendfile(int out_fd, int in_fd,
                               compat_off_t __user *offset, s32 count)
 {
index 9412d6558c88099e428dc370366bfd9db663546b..1c2d247f65cefa10091010848d8c03265dda8f5f 100644 (file)
@@ -4,11 +4,9 @@
 #ifdef __ASSEMBLY__
 # define __ASM_FORM(x) x
 # define __ASM_FORM_COMMA(x) x,
-# define __ASM_EX_SEC  .section __ex_table, "a"
 #else
 # define __ASM_FORM(x) " " #x " "
 # define __ASM_FORM_COMMA(x) " " #x ","
-# define __ASM_EX_SEC  " .section __ex_table,\"a\"\n"
 #endif
 
 #ifdef CONFIG_X86_32
 
 /* Exception table entry */
 #ifdef __ASSEMBLY__
-# define _ASM_EXTABLE(from,to)     \
-       __ASM_EX_SEC ;              \
-       _ASM_ALIGN ;                \
-       _ASM_PTR from , to ;        \
-       .previous
+# define _ASM_EXTABLE(from,to)                                 \
+       .pushsection "__ex_table","a" ;                         \
+       .balign 8 ;                                             \
+       .long (from) - . ;                                      \
+       .long (to) - . ;                                        \
+       .popsection
+
+# define _ASM_EXTABLE_EX(from,to)                              \
+       .pushsection "__ex_table","a" ;                         \
+       .balign 8 ;                                             \
+       .long (from) - . ;                                      \
+       .long (to) - . + 0x7ffffff0 ;                           \
+       .popsection
 #else
-# define _ASM_EXTABLE(from,to) \
-       __ASM_EX_SEC    \
-       _ASM_ALIGN "\n" \
-       _ASM_PTR #from "," #to "\n" \
-       " .previous\n"
+# define _ASM_EXTABLE(from,to)                                 \
+       " .pushsection \"__ex_table\",\"a\"\n"                  \
+       " .balign 8\n"                                          \
+       " .long (" #from ") - .\n"                              \
+       " .long (" #to ") - .\n"                                \
+       " .popsection\n"
+
+# define _ASM_EXTABLE_EX(from,to)                              \
+       " .pushsection \"__ex_table\",\"a\"\n"                  \
+       " .balign 8\n"                                          \
+       " .long (" #from ") - .\n"                              \
+       " .long (" #to ") - . + 0x7ffffff0\n"                   \
+       " .popsection\n"
 #endif
 
 #endif /* _ASM_X86_ASM_H */
index 2f90c51cc49d740ed849cfc8775b3478fd6987f5..eb45aa6b1f272e3676fdd295daf035765bc422a6 100644 (file)
@@ -112,7 +112,8 @@ struct boot_params {
        __u8  e820_entries;                             /* 0x1e8 */
        __u8  eddbuf_entries;                           /* 0x1e9 */
        __u8  edd_mbr_sig_buf_entries;                  /* 0x1ea */
-       __u8  _pad6[6];                                 /* 0x1eb */
+       __u8  kbd_status;                               /* 0x1eb */
+       __u8  _pad6[5];                                 /* 0x1ec */
        struct setup_header hdr;    /* setup header */  /* 0x1f1 */
        __u8  _pad7[0x290-0x1f1-sizeof(struct setup_header)];
        __u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX];      /* 0x290 */
index 63a2a03d7d516947eb945a856a988cb8284b8dcd..93e1c55f14ab42503be641ed305eb6863f52a200 100644 (file)
@@ -5,8 +5,8 @@ struct dev_archdata {
 #ifdef CONFIG_ACPI
        void    *acpi_handle;
 #endif
-#ifdef CONFIG_X86_64
-struct dma_map_ops *dma_ops;
+#ifdef CONFIG_X86_DEV_DMA_OPS
+       struct dma_map_ops *dma_ops;
 #endif
 #if defined(CONFIG_INTEL_IOMMU) || defined(CONFIG_AMD_IOMMU)
        void *iommu; /* hook for IOMMU specific extension */
index 4b4331d71935c7cf0d477e1c3a06b93072e4b463..61c0bd25845af0b1ceea8892df20dd717dd2d148 100644 (file)
@@ -30,7 +30,7 @@ extern struct dma_map_ops *dma_ops;
 
 static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 {
-#ifdef CONFIG_X86_32
+#ifndef CONFIG_X86_DEV_DMA_OPS
        return dma_ops;
 #else
        if (unlikely(!dev) || !dev->archdata.dma_ops)
@@ -62,6 +62,12 @@ extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
                                        dma_addr_t *dma_addr, gfp_t flag,
                                        struct dma_attrs *attrs);
 
+#ifdef CONFIG_X86_DMA_REMAP /* Platform code defines bridge-specific code */
+extern bool dma_capable(struct device *dev, dma_addr_t addr, size_t size);
+extern dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
+extern phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr);
+#else
+
 static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
 {
        if (!dev->dma_mask)
@@ -79,6 +85,7 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
 {
        return daddr;
 }
+#endif /* CONFIG_X86_DMA_REMAP */
 
 static inline void
 dma_cache_sync(struct device *dev, void *vaddr, size_t size,
diff --git a/arch/x86/include/asm/kbdleds.h b/arch/x86/include/asm/kbdleds.h
new file mode 100644 (file)
index 0000000..f27ac5f
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _ASM_X86_KBDLEDS_H
+#define _ASM_X86_KBDLEDS_H
+
+/*
+ * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
+ * This seems a good reason to start with NumLock off. That's why on X86 we
+ * ask the bios for the correct state.
+ */
+
+#include <asm/setup.h>
+
+static inline int kbd_defleds(void)
+{
+       return boot_params.kbd_status & 0x20 ? (1 << VC_NUMLOCK) : 0;
+}
+
+#endif /* _ASM_X86_KBDLEDS_H */
index d73f1571bde72ee744109afed9337306fd39a414..2c37aadcbc350a48756e05e00b9b227eb2808d2b 100644 (file)
@@ -24,7 +24,6 @@ enum die_val {
 extern void printk_address(unsigned long address, int reliable);
 extern void die(const char *, struct pt_regs *,long);
 extern int __must_check __die(const char *, struct pt_regs *, long);
-extern void show_registers(struct pt_regs *regs);
 extern void show_trace(struct task_struct *t, struct pt_regs *regs,
                       unsigned long *sp, unsigned long bp);
 extern void __show_regs(struct pt_regs *regs, int all);
index e216ba066e798cbd7be31892ac76afcc78055c0b..e5b97be12d2a6798aadfb4a67c4839ed01aafe31 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/desc.h>
 #include <asm/mtrr.h>
 #include <asm/msr-index.h>
+#include <asm/asm.h>
 
 #define KVM_MAX_VCPUS 254
 #define KVM_SOFT_MAX_VCPUS 160
@@ -921,9 +922,7 @@ extern bool kvm_rebooting;
        __ASM_SIZE(push) " $666b \n\t"        \
        "call kvm_spurious_fault \n\t"        \
        ".popsection \n\t" \
-       ".pushsection __ex_table, \"a\" \n\t" \
-       _ASM_PTR " 666b, 667b \n\t" \
-       ".popsection"
+       _ASM_EXTABLE(666b, 667b)
 
 #define __kvm_handle_fault_on_reboot(insn)             \
        ____kvm_handle_fault_on_reboot(insn, "")
index 55728e12147364d9ab1ffd9beed91e8dcc09cca8..eb05fb3b02fb5c012eeb9423c53c20d75f2c79fb 100644 (file)
@@ -61,10 +61,4 @@ static inline int pfn_valid(int pfn)
 
 #endif /* CONFIG_DISCONTIGMEM */
 
-#ifdef CONFIG_NEED_MULTIPLE_NODES
-/* always use node 0 for bootmem on this numa platform */
-#define bootmem_arch_preferred_node(__bdata, size, align, goal, limit) \
-       (NODE_DATA(0)->bdata)
-#endif /* CONFIG_NEED_MULTIPLE_NODES */
-
 #endif /* _ASM_X86_MMZONE_32_H */
index 95203d40ffdde69d014c986453905280b49ee9e5..084ef95274cd78ceb51b1ea7a208a7a5e486199a 100644 (file)
@@ -169,14 +169,7 @@ static inline int wrmsr_safe(unsigned msr, unsigned low, unsigned high)
        return native_write_msr_safe(msr, low, high);
 }
 
-/*
- * rdmsr with exception handling.
- *
- * Please note that the exception handling works only after we've
- * switched to the "smart" #GP handler in trap_init() which knows about
- * exception tables - using this macro earlier than that causes machine
- * hangs on boxes which do not implement the @msr in the first argument.
- */
+/* rdmsr with exception handling */
 #define rdmsr_safe(msr, p1, p2)                                        \
 ({                                                             \
        int __err;                                              \
index 405b4032a60b37200e2e2ecfae8289c792800755..aff2b3356101487dbdfefddd73853e6f4dbf7b6e 100644 (file)
 #define P6_NOP8        0x0f,0x1f,0x84,0x00,0,0,0,0
 #define P6_NOP5_ATOMIC P6_NOP5
 
+#ifdef __ASSEMBLY__
+#define _ASM_MK_NOP(x) .byte x
+#else
 #define _ASM_MK_NOP(x) ".byte " __stringify(x) "\n"
+#endif
 
 #if defined(CONFIG_MK7)
 #define ASM_NOP1 _ASM_MK_NOP(K7_NOP1)
index aa0f913083676a5b618ad733a36f9471176dcb88..6cbbabf52707f9d492a3e3d6687c37b24369cdfb 100644 (file)
@@ -1023,10 +1023,8 @@ extern void default_banner(void);
                  call PARA_INDIRECT(pv_cpu_ops+PV_CPU_swapgs)          \
                 )
 
-#define GET_CR2_INTO_RCX                               \
-       call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2); \
-       movq %rax, %rcx;                                \
-       xorq %rax, %rax;
+#define GET_CR2_INTO_RAX                               \
+       call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2)
 
 #define PARAVIRT_ADJUST_EXCEPTION_FRAME                                        \
        PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_adjust_exception_frame), \
index ccbb1ea99ccbd24dc63fa73721e05832fd93e25a..7745b257f035a8b1438078c670ce49dc1613051f 100644 (file)
@@ -579,9 +579,6 @@ extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy state */
-extern void prepare_to_copy(struct task_struct *tsk);
-
 unsigned long get_wchan(struct task_struct *p);
 
 /*
index 165466233ab0376192d94b6cd6a8d327a4c22d00..c48a95035a77888c9ba2210f2f33fd19250a952b 100644 (file)
 
 #define IDT_ENTRIES 256
 #define NUM_EXCEPTION_VECTORS 32
+/* Bitmask of exception vectors which push an error code on the stack */
+#define EXCEPTION_ERRCODE_MASK  0x00027d00
 #define GDT_SIZE (GDT_ENTRIES * 8)
 #define GDT_ENTRY_TLS_ENTRIES 3
 #define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8)
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
-extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][10];
+extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][2+2+5];
 
 /*
  * Load a segment. Fall back on loading the zero
index 76bfa2cf301df366e8b4b0ac2865ec009fc1eedd..b315a33867f25963808ebe9fc81ec9889a8deca7 100644 (file)
 
 #ifdef CONFIG_X86_32
 # define LOCK_PTR_REG "a"
-# define REG_PTR_MODE "k"
 #else
 # define LOCK_PTR_REG "D"
-# define REG_PTR_MODE "q"
 #endif
 
 #if defined(CONFIG_X86_32) && \
index 1620d23f14d7ab0a066e2d07823b98c475006df2..36a1a2ab87d26f6f65aded36434adec5121a4aa5 100644 (file)
@@ -62,11 +62,7 @@ static inline void __flush_tlb_one(unsigned long addr)
                __flush_tlb();
 }
 
-#ifdef CONFIG_X86_32
-# define TLB_FLUSH_ALL 0xffffffff
-#else
-# define TLB_FLUSH_ALL -1ULL
-#endif
+#define TLB_FLUSH_ALL  -1UL
 
 /*
  * TLB flushing:
index e0544597cfe7b30a0e40d52c9d13cb65a6bf3d6c..851fe0dc13bc18c33c79b8d54deb06e899ae63ad 100644 (file)
 #define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0))
 
 /*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue.  No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
+ * The exception table consists of pairs of addresses relative to the
+ * exception table enty itself: the first is the address of an
+ * instruction that is allowed to fault, and the second is the address
+ * at which the program should continue.  No registers are modified,
+ * so it is entirely up to the continuation code to figure out what to
+ * do.
  *
  * All the routines below use bits of fixup code that are out of line
  * with the main instruction path.  This means when everything is well,
  */
 
 struct exception_table_entry {
-       unsigned long insn, fixup;
+       int insn, fixup;
 };
+/* This is not the generic standard exception_table_entry format */
+#define ARCH_HAS_SORT_EXTABLE
+#define ARCH_HAS_SEARCH_EXTABLE
 
 extern int fixup_exception(struct pt_regs *regs);
+extern int early_fixup_exception(unsigned long *ip);
 
 /*
  * These are the main single-value transfer routines.  They automatically
@@ -202,8 +207,8 @@ extern int __get_user_bad(void);
        asm volatile("1:        movl %%eax,0(%1)\n"                     \
                     "2:        movl %%edx,4(%1)\n"                     \
                     "3:\n"                                             \
-                    _ASM_EXTABLE(1b, 2b - 1b)                          \
-                    _ASM_EXTABLE(2b, 3b - 2b)                          \
+                    _ASM_EXTABLE_EX(1b, 2b)                            \
+                    _ASM_EXTABLE_EX(2b, 3b)                            \
                     : : "A" (x), "r" (addr))
 
 #define __put_user_x8(x, ptr, __ret_pu)                                \
@@ -408,7 +413,7 @@ do {                                                                        \
 #define __get_user_asm_ex(x, addr, itype, rtype, ltype)                        \
        asm volatile("1:        mov"itype" %1,%"rtype"0\n"              \
                     "2:\n"                                             \
-                    _ASM_EXTABLE(1b, 2b - 1b)                          \
+                    _ASM_EXTABLE_EX(1b, 2b)                            \
                     : ltype(x) : "m" (__m(addr)))
 
 #define __put_user_nocheck(x, ptr, size)                       \
@@ -450,7 +455,7 @@ struct __large_struct { unsigned long buf[100]; };
 #define __put_user_asm_ex(x, addr, itype, rtype, ltype)                        \
        asm volatile("1:        mov"itype" %"rtype"0,%1\n"              \
                     "2:\n"                                             \
-                    _ASM_EXTABLE(1b, 2b - 1b)                          \
+                    _ASM_EXTABLE_EX(1b, 2b)                            \
                     : : ltype(x), "m" (__m(addr)))
 
 /*
index c6ce2452f10ce2dba165593d3492a9eb5056f4d3..8a1b6f9b594a71bbf960635dc1dbfeb07eecbd52 100644 (file)
@@ -80,10 +80,7 @@ static inline int xsave_user(struct xsave_struct __user *buf)
                             "3:  movl $-1,%[err]\n"
                             "    jmp  2b\n"
                             ".previous\n"
-                            ".section __ex_table,\"a\"\n"
-                            _ASM_ALIGN "\n"
-                            _ASM_PTR "1b,3b\n"
-                            ".previous"
+                            _ASM_EXTABLE(1b,3b)
                             : [err] "=r" (err)
                             : "D" (buf), "a" (-1), "d" (-1), "0" (0)
                             : "memory");
@@ -106,10 +103,7 @@ static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
                             "3:  movl $-1,%[err]\n"
                             "    jmp  2b\n"
                             ".previous\n"
-                            ".section __ex_table,\"a\"\n"
-                            _ASM_ALIGN "\n"
-                            _ASM_PTR "1b,3b\n"
-                            ".previous"
+                            _ASM_EXTABLE(1b,3b)
                             : [err] "=r" (err)
                             : "D" (xstate), "a" (lmask), "d" (hmask), "0" (0)
                             : "memory");       /* memory required? */
index 5da1269e8ddcbcb55ff840d90dd912502fd582d5..e2dbcb7dabdd6287f9410bae67a3e0adf5a9e1de 100644 (file)
@@ -27,21 +27,29 @@ static int num_scan_areas;
 
 static __init int set_corruption_check(char *arg)
 {
-       char *end;
+       ssize_t ret;
+       unsigned long val;
 
-       memory_corruption_check = simple_strtol(arg, &end, 10);
+       ret = kstrtoul(arg, 10, &val);
+       if (ret)
+               return ret;
 
-       return (*end == 0) ? 0 : -EINVAL;
+       memory_corruption_check = val;
+       return 0;
 }
 early_param("memory_corruption_check", set_corruption_check);
 
 static __init int set_corruption_check_period(char *arg)
 {
-       char *end;
+       ssize_t ret;
+       unsigned long val;
 
-       corruption_check_period = simple_strtoul(arg, &end, 10);
+       ret = kstrtoul(arg, 10, &val);
+       if (ret)
+               return ret;
 
-       return (*end == 0) ? 0 : -EINVAL;
+       corruption_check_period = val;
+       return 0;
 }
 early_param("memory_corruption_check_period", set_corruption_check_period);
 
index b8f3653dddbc2daccf1d0da1990e74b8cab57202..9a7c90d80bc4c87bafd96cb73efb46ced84b5276 100644 (file)
@@ -615,14 +615,14 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
                                        new_l2 = this_leaf.size/1024;
                                        num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
                                        index_msb = get_count_order(num_threads_sharing);
-                                       l2_id = c->apicid >> index_msb;
+                                       l2_id = c->apicid & ~((1 << index_msb) - 1);
                                        break;
                                case 3:
                                        new_l3 = this_leaf.size/1024;
                                        num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
                                        index_msb = get_count_order(
                                                        num_threads_sharing);
-                                       l3_id = c->apicid >> index_msb;
+                                       l3_id = c->apicid & ~((1 << index_msb) - 1);
                                        break;
                                default:
                                        break;
index 297edb1b1fb35c6c9109200e98f14f45f4a12583..2afcbd253e1da1768a10eeb6bdb9a74d286048b7 100644 (file)
@@ -1431,6 +1431,43 @@ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
                 */
                 if (c->x86 == 6 && banks > 0)
                        mce_banks[0].ctl = 0;
+
+                /*
+                 * Turn off MC4_MISC thresholding banks on those models since
+                 * they're not supported there.
+                 */
+                if (c->x86 == 0x15 &&
+                    (c->x86_model >= 0x10 && c->x86_model <= 0x1f)) {
+                        int i;
+                        u64 val, hwcr;
+                        bool need_toggle;
+                        u32 msrs[] = {
+                               0x00000413, /* MC4_MISC0 */
+                               0xc0000408, /* MC4_MISC1 */
+                        };
+
+                        rdmsrl(MSR_K7_HWCR, hwcr);
+
+                        /* McStatusWrEn has to be set */
+                        need_toggle = !(hwcr & BIT(18));
+
+                        if (need_toggle)
+                                wrmsrl(MSR_K7_HWCR, hwcr | BIT(18));
+
+                        for (i = 0; i < ARRAY_SIZE(msrs); i++) {
+                                rdmsrl(msrs[i], val);
+
+                                /* CntP bit set? */
+                                if (val & BIT(62)) {
+                                        val &= ~BIT(62);
+                                        wrmsrl(msrs[i], val);
+                                }
+                        }
+
+                        /* restore old settings */
+                        if (need_toggle)
+                                wrmsrl(MSR_K7_HWCR, hwcr);
+                }
        }
 
        if (c->x86_vendor == X86_VENDOR_INTEL) {
index 99b57179f9129b770d0e3f069f09ab06f4f686ec..f4873a64f46dcb2dac8db0c3585afecc642e70ee 100644 (file)
@@ -51,6 +51,7 @@ struct threshold_block {
        unsigned int            cpu;
        u32                     address;
        u16                     interrupt_enable;
+       bool                    interrupt_capable;
        u16                     threshold_limit;
        struct kobject          kobj;
        struct list_head        miscj;
@@ -83,6 +84,21 @@ struct thresh_restart {
        u16                     old_limit;
 };
 
+static bool lvt_interrupt_supported(unsigned int bank, u32 msr_high_bits)
+{
+       /*
+        * bank 4 supports APIC LVT interrupts implicitly since forever.
+        */
+       if (bank == 4)
+               return true;
+
+       /*
+        * IntP: interrupt present; if this bit is set, the thresholding
+        * bank can generate APIC LVT interrupts
+        */
+       return msr_high_bits & BIT(28);
+}
+
 static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
 {
        int msr = (hi & MASK_LVTOFF_HI) >> 20;
@@ -104,8 +120,10 @@ static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
        return 1;
 };
 
-/* must be called with correct cpu affinity */
-/* Called via smp_call_function_single() */
+/*
+ * Called via smp_call_function_single(), must be called with correct
+ * cpu affinity.
+ */
 static void threshold_restart_bank(void *_tr)
 {
        struct thresh_restart *tr = _tr;
@@ -128,6 +146,12 @@ static void threshold_restart_bank(void *_tr)
                    (new_count & THRESHOLD_MAX);
        }
 
+       /* clear IntType */
+       hi &= ~MASK_INT_TYPE_HI;
+
+       if (!tr->b->interrupt_capable)
+               goto done;
+
        if (tr->set_lvt_off) {
                if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) {
                        /* set new lvt offset */
@@ -136,9 +160,10 @@ static void threshold_restart_bank(void *_tr)
                }
        }
 
-       tr->b->interrupt_enable ?
-           (hi = (hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) :
-           (hi &= ~MASK_INT_TYPE_HI);
+       if (tr->b->interrupt_enable)
+               hi |= INT_TYPE_APIC;
+
+ done:
 
        hi |= MASK_COUNT_EN_HI;
        wrmsr(tr->b->address, lo, hi);
@@ -202,14 +227,17 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
                        if (shared_bank[bank] && c->cpu_core_id)
                                break;
 
-                       offset = setup_APIC_mce(offset,
-                                               (high & MASK_LVTOFF_HI) >> 20);
-
                        memset(&b, 0, sizeof(b));
-                       b.cpu           = cpu;
-                       b.bank          = bank;
-                       b.block         = block;
-                       b.address       = address;
+                       b.cpu                   = cpu;
+                       b.bank                  = bank;
+                       b.block                 = block;
+                       b.address               = address;
+                       b.interrupt_capable     = lvt_interrupt_supported(bank, high);
+
+                       if (b.interrupt_capable) {
+                               int new = (high & MASK_LVTOFF_HI) >> 20;
+                               offset  = setup_APIC_mce(offset, new);
+                       }
 
                        mce_threshold_block_init(&b, offset);
                        mce_threshold_vector = amd_threshold_interrupt;
@@ -309,6 +337,9 @@ store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size)
        struct thresh_restart tr;
        unsigned long new;
 
+       if (!b->interrupt_capable)
+               return -EINVAL;
+
        if (strict_strtoul(buf, 0, &new) < 0)
                return -EINVAL;
 
@@ -390,10 +421,10 @@ RW_ATTR(threshold_limit);
 RW_ATTR(error_count);
 
 static struct attribute *default_attrs[] = {
-       &interrupt_enable.attr,
        &threshold_limit.attr,
        &error_count.attr,
-       NULL
+       NULL,   /* possibly interrupt_enable if supported, see below */
+       NULL,
 };
 
 #define to_block(k)    container_of(k, struct threshold_block, kobj)
@@ -467,8 +498,14 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
        b->cpu                  = cpu;
        b->address              = address;
        b->interrupt_enable     = 0;
+       b->interrupt_capable    = lvt_interrupt_supported(bank, high);
        b->threshold_limit      = THRESHOLD_MAX;
 
+       if (b->interrupt_capable)
+               threshold_ktype.default_attrs[2] = &interrupt_enable.attr;
+       else
+               threshold_ktype.default_attrs[2] = NULL;
+
        INIT_LIST_HEAD(&b->miscj);
 
        if (per_cpu(threshold_banks, cpu)[bank]->blocks) {
index 65652265fffde3124fc6e164307f4970c3b8ce32..11a4eb9131d5cbddc70ca663ab4c3eb27add8143 100644 (file)
@@ -496,6 +496,7 @@ static __initconst const struct x86_pmu amd_pmu = {
  * 0x023       DE      PERF_CTL[2:0]
  * 0x02D       LS      PERF_CTL[3]
  * 0x02E       LS      PERF_CTL[3,0]
+ * 0x031       LS      PERF_CTL[2:0] (**)
  * 0x043       CU      PERF_CTL[2:0]
  * 0x045       CU      PERF_CTL[2:0]
  * 0x046       CU      PERF_CTL[2:0]
@@ -509,10 +510,12 @@ static __initconst const struct x86_pmu amd_pmu = {
  * 0x0DD       LS      PERF_CTL[5:0]
  * 0x0DE       LS      PERF_CTL[5:0]
  * 0x0DF       LS      PERF_CTL[5:0]
+ * 0x1C0       EX      PERF_CTL[5:3]
  * 0x1D6       EX      PERF_CTL[5:0]
  * 0x1D8       EX      PERF_CTL[5:0]
  *
- * (*) depending on the umask all FPU counters may be used
+ * (*)  depending on the umask all FPU counters may be used
+ * (**) only one unitmask enabled at a time
  */
 
 static struct event_constraint amd_f15_PMC0  = EVENT_CONSTRAINT(0, 0x01, 0);
@@ -562,6 +565,12 @@ amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *ev
                        return &amd_f15_PMC3;
                case 0x02E:
                        return &amd_f15_PMC30;
+               case 0x031:
+                       if (hweight_long(hwc->config & ARCH_PERFMON_EVENTSEL_UMASK) <= 1)
+                               return &amd_f15_PMC20;
+                       return &emptyconstraint;
+               case 0x1C0:
+                       return &amd_f15_PMC53;
                default:
                        return &amd_f15_PMC50;
                }
index 1b81839b6c8890f261e486429db51f37a9c68042..571246d81edf38da34a533391ec3841c54b45d8b 100644 (file)
@@ -271,7 +271,7 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err)
                        current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP)
                return 1;
 
-       show_registers(regs);
+       show_regs(regs);
 #ifdef CONFIG_X86_32
        if (user_mode_vm(regs)) {
                sp = regs->sp;
@@ -311,16 +311,33 @@ void die(const char *str, struct pt_regs *regs, long err)
 
 static int __init kstack_setup(char *s)
 {
+       ssize_t ret;
+       unsigned long val;
+
        if (!s)
                return -EINVAL;
-       kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+
+       ret = kstrtoul(s, 0, &val);
+       if (ret)
+               return ret;
+       kstack_depth_to_print = val;
        return 0;
 }
 early_param("kstack", kstack_setup);
 
 static int __init code_bytes_setup(char *s)
 {
-       code_bytes = simple_strtoul(s, NULL, 0);
+       ssize_t ret;
+       unsigned long val;
+
+       if (!s)
+               return -EINVAL;
+
+       ret = kstrtoul(s, 0, &val);
+       if (ret)
+               return ret;
+
+       code_bytes = val;
        if (code_bytes > 8192)
                code_bytes = 8192;
 
index 88ec9129271dcae3a10bcb428325b0fb083eb62d..e0b1d783daabfb94fcd2b85ff54ffcc7709a2a16 100644 (file)
@@ -82,7 +82,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
 }
 
 
-void show_registers(struct pt_regs *regs)
+void show_regs(struct pt_regs *regs)
 {
        int i;
 
index 17107bd6e1f0af06b5e59b1c48d452305a8b3214..791b76122aa8b0b627eb39e3ac6028701a9a868c 100644 (file)
@@ -245,7 +245,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
        show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
 
-void show_registers(struct pt_regs *regs)
+void show_regs(struct pt_regs *regs)
 {
        int i;
        unsigned long sp;
index 7b784f4ef1e483876ad98e432283d1ba82c890a1..01ccf9b71473ce18ffe0cccf5fa09fd379dcf4cf 100644 (file)
@@ -56,6 +56,7 @@
 #include <asm/irq_vectors.h>
 #include <asm/cpufeature.h>
 #include <asm/alternative-asm.h>
+#include <asm/asm.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
 #include <linux/elf-em.h>
 .pushsection .fixup, "ax"
 99:    movl $0, (%esp)
        jmp 98b
-.section __ex_table, "a"
-       .align 4
-       .long 98b, 99b
 .popsection
+       _ASM_EXTABLE(98b,99b)
 .endm
 
 .macro PTGS_TO_GS
 .pushsection .fixup, "ax"
 99:    movl $0, PT_GS(%esp)
        jmp 98b
-.section __ex_table, "a"
-       .align 4
-       .long 98b, 99b
 .popsection
+       _ASM_EXTABLE(98b,99b)
 .endm
 
 .macro GS_TO_REG reg
        jmp 2b
 6:     movl $0, (%esp)
        jmp 3b
-.section __ex_table, "a"
-       .align 4
-       .long 1b, 4b
-       .long 2b, 5b
-       .long 3b, 6b
 .popsection
+       _ASM_EXTABLE(1b,4b)
+       _ASM_EXTABLE(2b,5b)
+       _ASM_EXTABLE(3b,6b)
        POP_GS_EX
 .endm
 
@@ -415,10 +410,7 @@ sysenter_past_esp:
        jae syscall_fault
 1:     movl (%ebp),%ebp
        movl %ebp,PT_EBP(%esp)
-.section __ex_table,"a"
-       .align 4
-       .long 1b,syscall_fault
-.previous
+       _ASM_EXTABLE(1b,syscall_fault)
 
        GET_THREAD_INFO(%ebp)
 
@@ -485,10 +477,8 @@ sysexit_audit:
 .pushsection .fixup,"ax"
 2:     movl $0,PT_FS(%esp)
        jmp 1b
-.section __ex_table,"a"
-       .align 4
-       .long 1b,2b
 .popsection
+       _ASM_EXTABLE(1b,2b)
        PTGS_TO_GS_EX
 ENDPROC(ia32_sysenter_target)
 
@@ -543,10 +533,7 @@ ENTRY(iret_exc)
        pushl $do_iret_error
        jmp error_code
 .previous
-.section __ex_table,"a"
-       .align 4
-       .long irq_return,iret_exc
-.previous
+       _ASM_EXTABLE(irq_return,iret_exc)
 
        CFI_RESTORE_STATE
 ldt_ss:
@@ -901,10 +888,7 @@ END(device_not_available)
 #ifdef CONFIG_PARAVIRT
 ENTRY(native_iret)
        iret
-.section __ex_table,"a"
-       .align 4
-       .long native_iret, iret_exc
-.previous
+       _ASM_EXTABLE(native_iret, iret_exc)
 END(native_iret)
 
 ENTRY(native_irq_enable_sysexit)
@@ -1093,13 +1077,10 @@ ENTRY(xen_failsafe_callback)
        movl %eax,16(%esp)
        jmp 4b
 .previous
-.section __ex_table,"a"
-       .align 4
-       .long 1b,6b
-       .long 2b,7b
-       .long 3b,8b
-       .long 4b,9b
-.previous
+       _ASM_EXTABLE(1b,6b)
+       _ASM_EXTABLE(2b,7b)
+       _ASM_EXTABLE(3b,8b)
+       _ASM_EXTABLE(4b,9b)
 ENDPROC(xen_failsafe_callback)
 
 BUILD_INTERRUPT3(xen_hvm_callback_vector, XEN_HVM_EVTCHN_CALLBACK,
index cdc79b5cfcd925c014010a3fe60723a14143616a..320852d02026171d537b58bd95868113fa458d10 100644 (file)
@@ -55,6 +55,7 @@
 #include <asm/paravirt.h>
 #include <asm/ftrace.h>
 #include <asm/percpu.h>
+#include <asm/asm.h>
 #include <linux/err.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
@@ -900,18 +901,12 @@ restore_args:
 
 irq_return:
        INTERRUPT_RETURN
-
-       .section __ex_table, "a"
-       .quad irq_return, bad_iret
-       .previous
+       _ASM_EXTABLE(irq_return, bad_iret)
 
 #ifdef CONFIG_PARAVIRT
 ENTRY(native_iret)
        iretq
-
-       .section __ex_table,"a"
-       .quad native_iret, bad_iret
-       .previous
+       _ASM_EXTABLE(native_iret, bad_iret)
 #endif
 
        .section .fixup,"ax"
@@ -1181,10 +1176,7 @@ gs_change:
        CFI_ENDPROC
 END(native_load_gs_index)
 
-       .section __ex_table,"a"
-       .align 8
-       .quad gs_change,bad_gs
-       .previous
+       _ASM_EXTABLE(gs_change,bad_gs)
        .section .fixup,"ax"
        /* running with kernelgs */
 bad_gs:
index ce0be7cd085e025759da9b1fd6445d34e7772de0..463c9797ca6ab5f392bc65c6fbe1c1ddfc699c18 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/msr-index.h>
 #include <asm/cpufeature.h>
 #include <asm/percpu.h>
+#include <asm/nops.h>
 
 /* Physical address */
 #define pa(X) ((X) - __PAGE_OFFSET)
@@ -363,28 +364,23 @@ default_entry:
        pushl $0
        popfl
 
-#ifdef CONFIG_SMP
-       cmpb $0, ready
-       jnz checkCPUtype
-#endif /* CONFIG_SMP */
-
 /*
  * start system 32-bit setup. We need to re-do some of the things done
  * in 16-bit mode for the "real" operations.
  */
-       call setup_idt
-
-checkCPUtype:
-
-       movl $-1,X86_CPUID              #  -1 for no CPUID initially
-
+       movl setup_once_ref,%eax
+       andl %eax,%eax
+       jz 1f                           # Did we do this already?
+       call *%eax
+1:
+       
 /* check if it is 486 or 386. */
 /*
  * XXX - this does a lot of unnecessary setup.  Alignment checks don't
  * apply at our cpl of 0 and the stack ought to be aligned already, and
  * we don't need to preserve eflags.
  */
-
+       movl $-1,X86_CPUID      # -1 for no CPUID initially
        movb $3,X86             # at least 386
        pushfl                  # push EFLAGS
        popl %eax               # get EFLAGS
@@ -450,21 +446,6 @@ is386:     movl $2,%ecx            # set MP
        movl $(__KERNEL_PERCPU), %eax
        movl %eax,%fs                   # set this cpu's percpu
 
-#ifdef CONFIG_CC_STACKPROTECTOR
-       /*
-        * The linker can't handle this by relocation.  Manually set
-        * base address in stack canary segment descriptor.
-        */
-       cmpb $0,ready
-       jne 1f
-       movl $gdt_page,%eax
-       movl $stack_canary,%ecx
-       movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax)
-       shrl $16, %ecx
-       movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax)
-       movb %ch, 8 * GDT_ENTRY_STACK_CANARY + 7(%eax)
-1:
-#endif
        movl $(__KERNEL_STACK_CANARY),%eax
        movl %eax,%gs
 
@@ -473,7 +454,6 @@ is386:      movl $2,%ecx            # set MP
 
        cld                     # gcc2 wants the direction flag cleared at all times
        pushl $0                # fake return address for unwinder
-       movb $1, ready
        jmp *(initial_code)
 
 /*
@@ -495,81 +475,122 @@ check_x87:
        .byte 0xDB,0xE4         /* fsetpm for 287, ignored by 387 */
        ret
 
+       
+#include "verify_cpu.S"
+
 /*
- *  setup_idt
+ *  setup_once
  *
- *  sets up a idt with 256 entries pointing to
- *  ignore_int, interrupt gates. It doesn't actually load
- *  idt - that can be done only after paging has been enabled
- *  and the kernel moved to PAGE_OFFSET. Interrupts
- *  are enabled elsewhere, when we can be relatively
- *  sure everything is ok.
+ *  The setup work we only want to run on the BSP.
  *
  *  Warning: %esi is live across this function.
  */
-setup_idt:
-       lea ignore_int,%edx
-       movl $(__KERNEL_CS << 16),%eax
-       movw %dx,%ax            /* selector = 0x0010 = cs */
-       movw $0x8E00,%dx        /* interrupt gate - dpl=0, present */
+__INIT
+setup_once:
+       /*
+        * Set up a idt with 256 entries pointing to ignore_int,
+        * interrupt gates. It doesn't actually load idt - that needs
+        * to be done on each CPU. Interrupts are enabled elsewhere,
+        * when we can be relatively sure everything is ok.
+        */
 
-       lea idt_table,%edi
-       mov $256,%ecx
-rp_sidt:
+       movl $idt_table,%edi
+       movl $early_idt_handlers,%eax
+       movl $NUM_EXCEPTION_VECTORS,%ecx
+1:
        movl %eax,(%edi)
-       movl %edx,4(%edi)
+       movl %eax,4(%edi)
+       /* interrupt gate, dpl=0, present */
+       movl $(0x8E000000 + __KERNEL_CS),2(%edi)
+       addl $9,%eax
        addl $8,%edi
-       dec %ecx
-       jne rp_sidt
+       loop 1b
 
-.macro set_early_handler handler,trapno
-       lea \handler,%edx
+       movl $256 - NUM_EXCEPTION_VECTORS,%ecx
+       movl $ignore_int,%edx
        movl $(__KERNEL_CS << 16),%eax
-       movw %dx,%ax
+       movw %dx,%ax            /* selector = 0x0010 = cs */
        movw $0x8E00,%dx        /* interrupt gate - dpl=0, present */
-       lea idt_table,%edi
-       movl %eax,8*\trapno(%edi)
-       movl %edx,8*\trapno+4(%edi)
-.endm
+2:
+       movl %eax,(%edi)
+       movl %edx,4(%edi)
+       addl $8,%edi
+       loop 2b
 
-       set_early_handler handler=early_divide_err,trapno=0
-       set_early_handler handler=early_illegal_opcode,trapno=6
-       set_early_handler handler=early_protection_fault,trapno=13
-       set_early_handler handler=early_page_fault,trapno=14
+#ifdef CONFIG_CC_STACKPROTECTOR
+       /*
+        * Configure the stack canary. The linker can't handle this by
+        * relocation.  Manually set base address in stack canary
+        * segment descriptor.
+        */
+       movl $gdt_page,%eax
+       movl $stack_canary,%ecx
+       movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax)
+       shrl $16, %ecx
+       movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax)
+       movb %ch, 8 * GDT_ENTRY_STACK_CANARY + 7(%eax)
+#endif
 
+       andl $0,setup_once_ref  /* Once is enough, thanks */
        ret
 
-early_divide_err:
-       xor %edx,%edx
-       pushl $0        /* fake errcode */
-       jmp early_fault
+ENTRY(early_idt_handlers)
+       # 36(%esp) %eflags
+       # 32(%esp) %cs
+       # 28(%esp) %eip
+       # 24(%rsp) error code
+       i = 0
+       .rept NUM_EXCEPTION_VECTORS
+       .if (EXCEPTION_ERRCODE_MASK >> i) & 1
+       ASM_NOP2
+       .else
+       pushl $0                # Dummy error code, to make stack frame uniform
+       .endif
+       pushl $i                # 20(%esp) Vector number
+       jmp early_idt_handler
+       i = i + 1
+       .endr
+ENDPROC(early_idt_handlers)
+       
+       /* This is global to keep gas from relaxing the jumps */
+ENTRY(early_idt_handler)
+       cld
+       cmpl $2,%ss:early_recursion_flag
+       je hlt_loop
+       incl %ss:early_recursion_flag
 
-early_illegal_opcode:
-       movl $6,%edx
-       pushl $0        /* fake errcode */
-       jmp early_fault
+       push %eax               # 16(%esp)
+       push %ecx               # 12(%esp)
+       push %edx               #  8(%esp)
+       push %ds                #  4(%esp)
+       push %es                #  0(%esp)
+       movl $(__KERNEL_DS),%eax
+       movl %eax,%ds
+       movl %eax,%es
 
-early_protection_fault:
-       movl $13,%edx
-       jmp early_fault
+       cmpl $(__KERNEL_CS),32(%esp)
+       jne 10f
 
-early_page_fault:
-       movl $14,%edx
-       jmp early_fault
+       leal 28(%esp),%eax      # Pointer to %eip
+       call early_fixup_exception
+       andl %eax,%eax
+       jnz ex_entry            /* found an exception entry */
 
-early_fault:
-       cld
+10:
 #ifdef CONFIG_PRINTK
-       pusha
-       movl $(__KERNEL_DS),%eax
-       movl %eax,%ds
-       movl %eax,%es
-       cmpl $2,early_recursion_flag
-       je hlt_loop
-       incl early_recursion_flag
+       xorl %eax,%eax
+       movw %ax,2(%esp)        /* clean up the segment values on some cpus */
+       movw %ax,6(%esp)
+       movw %ax,34(%esp)
+       leal  40(%esp),%eax
+       pushl %eax              /* %esp before the exception */
+       pushl %ebx
+       pushl %ebp
+       pushl %esi
+       pushl %edi
        movl %cr2,%eax
        pushl %eax
-       pushl %edx              /* trapno */
+       pushl (20+6*4)(%esp)    /* trapno */
        pushl $fault_msg
        call printk
 #endif
@@ -578,6 +599,17 @@ hlt_loop:
        hlt
        jmp hlt_loop
 
+ex_entry:
+       pop %es
+       pop %ds
+       pop %edx
+       pop %ecx
+       pop %eax
+       addl $8,%esp            /* drop vector number and error code */
+       decl %ss:early_recursion_flag
+       iret
+ENDPROC(early_idt_handler)
+
 /* This is the default interrupt "handler" :-) */
        ALIGN
 ignore_int:
@@ -611,13 +643,18 @@ ignore_int:
        popl %eax
 #endif
        iret
+ENDPROC(ignore_int)
+__INITDATA
+       .align 4
+early_recursion_flag:
+       .long 0
 
-#include "verify_cpu.S"
-
-       __REFDATA
-.align 4
+__REFDATA
+       .align 4
 ENTRY(initial_code)
        .long i386_start_kernel
+ENTRY(setup_once_ref)
+       .long setup_once
 
 /*
  * BSS section
@@ -670,22 +707,19 @@ ENTRY(initial_page_table)
 ENTRY(stack_start)
        .long init_thread_union+THREAD_SIZE
 
-early_recursion_flag:
-       .long 0
-
-ready: .byte 0
-
+__INITRODATA
 int_msg:
        .asciz "Unknown interrupt or fault at: %p %p %p\n"
 
 fault_msg:
 /* fault info: */
        .ascii "BUG: Int %d: CR2 %p\n"
-/* pusha regs: */
-       .ascii "     EDI %p  ESI %p  EBP %p  ESP %p\n"
-       .ascii "     EBX %p  EDX %p  ECX %p  EAX %p\n"
+/* regs pushed in early_idt_handler: */
+       .ascii "     EDI %p  ESI %p  EBP %p  EBX %p\n"
+       .ascii "     ESP %p   ES %p   DS %p\n"
+       .ascii "     EDX %p  ECX %p  EAX %p\n"
 /* fault frame: */
-       .ascii "     err %p  EIP %p   CS %p  flg %p\n"
+       .ascii "     vec %p  err %p  EIP %p   CS %p  flg %p\n"
        .ascii "Stack: %p %p %p %p %p %p %p %p\n"
        .ascii "       %p %p %p %p %p %p %p %p\n"
        .asciz "       %p %p %p %p %p %p %p %p\n"
@@ -699,6 +733,7 @@ fault_msg:
  * segment size, and 32-bit linear address value:
  */
 
+       .data
 .globl boot_gdt_descr
 .globl idt_descr
 
index 40f4eb3766d1d2a669790d36d3c6e28eff42b87b..7a40f2447321d5c6af500be479844ac6379a98b3 100644 (file)
 #include <asm/cache.h>
 #include <asm/processor-flags.h>
 #include <asm/percpu.h>
+#include <asm/nops.h>
 
 #ifdef CONFIG_PARAVIRT
 #include <asm/asm-offsets.h>
 #include <asm/paravirt.h>
+#define GET_CR2_INTO(reg) GET_CR2_INTO_RAX ; movq %rax, reg
 #else
-#define GET_CR2_INTO_RCX movq %cr2, %rcx
+#define GET_CR2_INTO(reg) movq %cr2, reg
+#define INTERRUPT_RETURN iretq
 #endif
 
 /* we are not able to switch in one step to the final KERNEL ADDRESS SPACE
@@ -270,36 +273,56 @@ bad_address:
        jmp bad_address
 
        .section ".init.text","ax"
-#ifdef CONFIG_EARLY_PRINTK
        .globl early_idt_handlers
 early_idt_handlers:
+       # 104(%rsp) %rflags
+       #  96(%rsp) %cs
+       #  88(%rsp) %rip
+       #  80(%rsp) error code
        i = 0
        .rept NUM_EXCEPTION_VECTORS
-       movl $i, %esi
+       .if (EXCEPTION_ERRCODE_MASK >> i) & 1
+       ASM_NOP2
+       .else
+       pushq $0                # Dummy error code, to make stack frame uniform
+       .endif
+       pushq $i                # 72(%rsp) Vector number
        jmp early_idt_handler
        i = i + 1
        .endr
-#endif
 
 ENTRY(early_idt_handler)
-#ifdef CONFIG_EARLY_PRINTK
+       cld
+
        cmpl $2,early_recursion_flag(%rip)
        jz  1f
        incl early_recursion_flag(%rip)
-       GET_CR2_INTO_RCX
-       movq %rcx,%r9
-       xorl %r8d,%r8d          # zero for error code
-       movl %esi,%ecx          # get vector number
-       # Test %ecx against mask of vectors that push error code.
-       cmpl $31,%ecx
-       ja 0f
-       movl $1,%eax
-       salq %cl,%rax
-       testl $0x27d00,%eax
-       je 0f
-       popq %r8                # get error code
-0:     movq 0(%rsp),%rcx       # get ip
-       movq 8(%rsp),%rdx       # get cs
+
+       pushq %rax              # 64(%rsp)
+       pushq %rcx              # 56(%rsp)
+       pushq %rdx              # 48(%rsp)
+       pushq %rsi              # 40(%rsp)
+       pushq %rdi              # 32(%rsp)
+       pushq %r8               # 24(%rsp)
+       pushq %r9               # 16(%rsp)
+       pushq %r10              #  8(%rsp)
+       pushq %r11              #  0(%rsp)
+
+       cmpl $__KERNEL_CS,96(%rsp)
+       jne 10f
+
+       leaq 88(%rsp),%rdi      # Pointer to %rip
+       call early_fixup_exception
+       andl %eax,%eax
+       jnz 20f                 # Found an exception entry
+
+10:
+#ifdef CONFIG_EARLY_PRINTK
+       GET_CR2_INTO(%r9)       # can clobber any volatile register if pv
+       movl 80(%rsp),%r8d      # error code
+       movl 72(%rsp),%esi      # vector number
+       movl 96(%rsp),%edx      # %cs
+       movq 88(%rsp),%rcx      # %rip
        xorl %eax,%eax
        leaq early_idt_msg(%rip),%rdi
        call early_printk
@@ -308,17 +331,32 @@ ENTRY(early_idt_handler)
        call dump_stack
 #ifdef CONFIG_KALLSYMS 
        leaq early_idt_ripmsg(%rip),%rdi
-       movq 0(%rsp),%rsi       # get rip again
+       movq 40(%rsp),%rsi      # %rip again
        call __print_symbol
 #endif
 #endif /* EARLY_PRINTK */
 1:     hlt
        jmp 1b
 
-#ifdef CONFIG_EARLY_PRINTK
+20:    # Exception table entry found
+       popq %r11
+       popq %r10
+       popq %r9
+       popq %r8
+       popq %rdi
+       popq %rsi
+       popq %rdx
+       popq %rcx
+       popq %rax
+       addq $16,%rsp           # drop vector number and error code
+       decl early_recursion_flag(%rip)
+       INTERRUPT_RETURN
+
+       .balign 4
 early_recursion_flag:
        .long 0
 
+#ifdef CONFIG_EARLY_PRINTK
 early_idt_msg:
        .asciz "PANIC: early exception %02lx rip %lx:%lx error %lx cr2 %lx\n"
 early_idt_ripmsg:
index e213fc8408d2b644b8476be8c26b1d1b5d2bbbb8..e2f751efb7b1ef25ce9329a49128a48c1dcf9c3f 100644 (file)
@@ -1037,9 +1037,9 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
                               "current sp %p does not match saved sp %p\n",
                               stack_addr(regs), kcb->jprobe_saved_sp);
                        printk(KERN_ERR "Saved registers for jprobe %p\n", jp);
-                       show_registers(saved_regs);
+                       show_regs(saved_regs);
                        printk(KERN_ERR "Current registers\n");
-                       show_registers(regs);
+                       show_regs(regs);
                        BUG();
                }
                *regs = kcb->jprobe_saved_regs;
index c9bda6d6035c83b06b2ac5e26aebca76b9fc4f34..fbdfc6917180f8f5379033cc408d164573d027e5 100644 (file)
@@ -299,12 +299,11 @@ static ssize_t reload_store(struct device *dev,
 {
        unsigned long val;
        int cpu = dev->id;
-       int ret = 0;
-       char *end;
+       ssize_t ret = 0;
 
-       val = simple_strtoul(buf, &end, 0);
-       if (end == buf)
-               return -EINVAL;
+       ret = kstrtoul(buf, 0, &val);
+       if (ret)
+               return ret;
 
        if (val == 1) {
                get_online_cpus();
index a1faed5ac6a240dcb57d988d9a0b6de2b2279740..bffdfd48c1f2707fa6c0049699211adadf523e75 100644 (file)
@@ -209,7 +209,7 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
        pr_emerg(
        "NMI: IOCK error (debug interrupt?) for reason %02x on CPU %d.\n",
                 reason, smp_processor_id());
-       show_registers(regs);
+       show_regs(regs);
 
        if (panic_on_io_nmi)
                panic("NMI IOCK error: Not continuing");
index ff3698625081506a7acf686f40aa8cd42ccde3c7..e31bf8d5c4d2e410126f397cdb764c281b1693fc 100644 (file)
@@ -118,15 +118,15 @@ static void __init dotest(void (*testcase_fn)(void), int expected)
                unexpected_testcase_failures++;
 
                if (nmi_fail == FAILURE)
-                       printk("FAILED |");
+                       printk(KERN_CONT "FAILED |");
                else if (nmi_fail == TIMEOUT)
-                       printk("TIMEOUT|");
+                       printk(KERN_CONT "TIMEOUT|");
                else
-                       printk("ERROR  |");
+                       printk(KERN_CONT "ERROR  |");
                dump_stack();
        } else {
                testcase_successes++;
-               printk("  ok  |");
+               printk(KERN_CONT "  ok  |");
        }
        testcase_total++;
 
@@ -151,10 +151,10 @@ void __init nmi_selftest(void)
 
        print_testname("remote IPI");
        dotest(remote_ipi, SUCCESS);
-       printk("\n");
+       printk(KERN_CONT "\n");
        print_testname("local IPI");
        dotest(local_ipi, SUCCESS);
-       printk("\n");
+       printk(KERN_CONT "\n");
 
        cleanup_nmi_testsuite();
 
index d0b2fb9ccbb16e1e9dc09afe32cb48fa38bfe81c..b72838bae64ab296bfd0bdd9e63297132d6c56e5 100644 (file)
@@ -1480,8 +1480,9 @@ cleanup:
 static int __init calgary_parse_options(char *p)
 {
        unsigned int bridge;
+       unsigned long val;
        size_t len;
-       char* endp;
+       ssize_t ret;
 
        while (*p) {
                if (!strncmp(p, "64k", 3))
@@ -1512,10 +1513,11 @@ static int __init calgary_parse_options(char *p)
                                ++p;
                        if (*p == '\0')
                                break;
-                       bridge = simple_strtoul(p, &endp, 0);
-                       if (p == endp)
+                       ret = kstrtoul(p, 0, &val);
+                       if (ret)
                                break;
 
+                       bridge = val;
                        if (bridge < MAX_PHB_BUS_NUM) {
                                printk(KERN_INFO "Calgary: disabling "
                                       "translation for PHB %#x\n", bridge);
index 8040b752ee4fc9fe0dfa7ba6ddbbba00b019f696..735279e54e59a56d3f3ce97288f2d81fc98491d6 100644 (file)
@@ -56,10 +56,16 @@ EXPORT_SYMBOL_GPL(idle_notifier_unregister);
 struct kmem_cache *task_xstate_cachep;
 EXPORT_SYMBOL_GPL(task_xstate_cachep);
 
+/*
+ * this gets called so that we can store lazy state into memory and copy the
+ * current task into the new thread.
+ */
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
        int ret;
 
+       unlazy_fpu(src);
+
        *dst = *src;
        if (fpu_allocated(&src->thread.fpu)) {
                memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
@@ -89,6 +95,16 @@ void arch_task_cache_init(void)
                                  SLAB_PANIC | SLAB_NOTRACK, NULL);
 }
 
+static inline void drop_fpu(struct task_struct *tsk)
+{
+       /*
+        * Forget coprocessor state..
+        */
+       tsk->fpu_counter = 0;
+       clear_fpu(tsk);
+       clear_used_math();
+}
+
 /*
  * Free current thread data structures etc..
  */
@@ -111,12 +127,8 @@ void exit_thread(void)
                put_cpu();
                kfree(bp);
        }
-}
 
-void show_regs(struct pt_regs *regs)
-{
-       show_registers(regs);
-       show_trace(NULL, regs, (unsigned long *)kernel_stack_pointer(regs), 0);
+       drop_fpu(me);
 }
 
 void show_regs_common(void)
@@ -151,12 +163,7 @@ void flush_thread(void)
 
        flush_ptrace_hw_breakpoint(tsk);
        memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
-       /*
-        * Forget coprocessor state..
-        */
-       tsk->fpu_counter = 0;
-       clear_fpu(tsk);
-       clear_used_math();
+       drop_fpu(tsk);
 }
 
 static void hard_disable_TSC(void)
index 01d8d40ccaf63cda8e6e2ac9eceb6c60e0fb7c6a..516fa186121b6d7dd82d9b73e1fa79ed11aa323a 100644 (file)
@@ -126,15 +126,6 @@ void release_thread(struct task_struct *dead_task)
        release_vm86_irqs(dead_task);
 }
 
-/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
- */
-void prepare_to_copy(struct task_struct *tsk)
-{
-       unlazy_fpu(tsk);
-}
-
 int copy_thread(unsigned long clone_flags, unsigned long sp,
        unsigned long unused,
        struct task_struct *p, struct pt_regs *regs)
index 28e810255a0a90396c4ad69d94e31796edc0bffb..61cdf7fdf09961757d7a6f8ba595df63a5a123b3 100644 (file)
@@ -145,15 +145,6 @@ static inline u32 read_32bit_tls(struct task_struct *t, int tls)
        return get_desc_base(&t->thread.tls_array[tls]);
 }
 
-/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
- */
-void prepare_to_copy(struct task_struct *tsk)
-{
-       unlazy_fpu(tsk);
-}
-
 int copy_thread(unsigned long clone_flags, unsigned long sp,
                unsigned long unused,
        struct task_struct *p, struct pt_regs *regs)
index d840e69a853c0ed3fb48d1bd9f6abc2367275efa..77215c23fba1250dc9b45085e36d99d7356358b7 100644 (file)
@@ -39,7 +39,8 @@ static int reboot_mode;
 enum reboot_type reboot_type = BOOT_ACPI;
 int reboot_force;
 
-/* This variable is used privately to keep track of whether or not
+/*
+ * This variable is used privately to keep track of whether or not
  * reboot_type is still set to its default value (i.e., reboot= hasn't
  * been set on the command line).  This is needed so that we can
  * suppress DMI scanning for reboot quirks.  Without it, it's
@@ -51,7 +52,8 @@ static int reboot_default = 1;
 static int reboot_cpu = -1;
 #endif
 
-/* This is set if we need to go through the 'emergency' path.
+/*
+ * This is set if we need to go through the 'emergency' path.
  * When machine_emergency_restart() is called, we may be on
  * an inconsistent state and won't be able to do a clean cleanup
  */
@@ -60,22 +62,24 @@ static int reboot_emergency;
 /* This is set by the PCI code if either type 1 or type 2 PCI is detected */
 bool port_cf9_safe = false;
 
-/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
-   warm   Don't set the cold reboot flag
-   cold   Set the cold reboot flag
-   bios   Reboot by jumping through the BIOS (only for X86_32)
-   smp    Reboot by executing reset on BSP or other CPU (only for X86_32)
-   triple Force a triple fault (init)
-   kbd    Use the keyboard controller. cold reset (default)
-   acpi   Use the RESET_REG in the FADT
-   efi    Use efi reset_system runtime service
-   pci    Use the so-called "PCI reset register", CF9
-   force  Avoid anything that could hang.
+/*
+ * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
+ * warm   Don't set the cold reboot flag
+ * cold   Set the cold reboot flag
+ * bios   Reboot by jumping through the BIOS (only for X86_32)
+ * smp    Reboot by executing reset on BSP or other CPU (only for X86_32)
+ * triple Force a triple fault (init)
+ * kbd    Use the keyboard controller. cold reset (default)
+ * acpi   Use the RESET_REG in the FADT
+ * efi    Use efi reset_system runtime service
+ * pci    Use the so-called "PCI reset register", CF9
+ * force  Avoid anything that could hang.
  */
 static int __init reboot_setup(char *str)
 {
        for (;;) {
-               /* Having anything passed on the command line via
+               /*
+                * Having anything passed on the command line via
                 * reboot= will cause us to disable DMI checking
                 * below.
                 */
@@ -98,9 +102,11 @@ static int __init reboot_setup(char *str)
                                if (isdigit(*(str+2)))
                                        reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
                        }
-                               /* we will leave sorting out the final value
-                                  when we are ready to reboot, since we might not
-                                  have detected BSP APIC ID or smp_num_cpu */
+                       /*
+                        * We will leave sorting out the final value
+                        * when we are ready to reboot, since we might not
+                        * have detected BSP APIC ID or smp_num_cpu
+                        */
                        break;
 #endif /* CONFIG_SMP */
 
@@ -150,6 +156,82 @@ static int __init set_bios_reboot(const struct dmi_system_id *d)
        return 0;
 }
 
+extern const unsigned char machine_real_restart_asm[];
+extern const u64 machine_real_restart_gdt[3];
+
+void machine_real_restart(unsigned int type)
+{
+       void *restart_va;
+       unsigned long restart_pa;
+       void (*restart_lowmem)(unsigned int);
+       u64 *lowmem_gdt;
+
+       local_irq_disable();
+
+       /*
+        * Write zero to CMOS register number 0x0f, which the BIOS POST
+        * routine will recognize as telling it to do a proper reboot.  (Well
+        * that's what this book in front of me says -- it may only apply to
+        * the Phoenix BIOS though, it's not clear).  At the same time,
+        * disable NMIs by setting the top bit in the CMOS address register,
+        * as we're about to do peculiar things to the CPU.  I'm not sure if
+        * `outb_p' is needed instead of just `outb'.  Use it to be on the
+        * safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
+        */
+       spin_lock(&rtc_lock);
+       CMOS_WRITE(0x00, 0x8f);
+       spin_unlock(&rtc_lock);
+
+       /*
+        * Switch back to the initial page table.
+        */
+       load_cr3(initial_page_table);
+
+       /*
+        * Write 0x1234 to absolute memory location 0x472.  The BIOS reads
+        * this on booting to tell it to "Bypass memory test (also warm
+        * boot)".  This seems like a fairly standard thing that gets set by
+        * REBOOT.COM programs, and the previous reset routine did this
+        * too. */
+       *((unsigned short *)0x472) = reboot_mode;
+
+       /* Patch the GDT in the low memory trampoline */
+       lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt);
+
+       restart_va = TRAMPOLINE_SYM(machine_real_restart_asm);
+       restart_pa = virt_to_phys(restart_va);
+       restart_lowmem = (void (*)(unsigned int))restart_pa;
+
+       /* GDT[0]: GDT self-pointer */
+       lowmem_gdt[0] =
+               (u64)(sizeof(machine_real_restart_gdt) - 1) +
+               ((u64)virt_to_phys(lowmem_gdt) << 16);
+       /* GDT[1]: 64K real mode code segment */
+       lowmem_gdt[1] =
+               GDT_ENTRY(0x009b, restart_pa, 0xffff);
+
+       /* Jump to the identity-mapped low memory code */
+       restart_lowmem(type);
+}
+#ifdef CONFIG_APM_MODULE
+EXPORT_SYMBOL(machine_real_restart);
+#endif
+
+#endif /* CONFIG_X86_32 */
+
+/*
+ * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
+ */
+static int __init set_pci_reboot(const struct dmi_system_id *d)
+{
+       if (reboot_type != BOOT_CF9) {
+               reboot_type = BOOT_CF9;
+               printk(KERN_INFO "%s series board detected. "
+                      "Selecting PCI-method for reboots.\n", d->ident);
+       }
+       return 0;
+}
+
 static int __init set_kbd_reboot(const struct dmi_system_id *d)
 {
        if (reboot_type != BOOT_KBD) {
@@ -159,7 +241,12 @@ static int __init set_kbd_reboot(const struct dmi_system_id *d)
        return 0;
 }
 
+/*
+ * This is a single dmi_table handling all reboot quirks.  Note that
+ * REBOOT_BIOS is only available for 32bit
+ */
 static struct dmi_system_id __initdata reboot_dmi_table[] = {
+#ifdef CONFIG_X86_32
        {       /* Handle problems with rebooting on Dell E520's */
                .callback = set_bios_reboot,
                .ident = "Dell E520",
@@ -184,7 +271,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
                },
        },
-       {       /* Handle problems with rebooting on Dell Optiplex 745's SFF*/
+       {       /* Handle problems with rebooting on Dell Optiplex 745's SFF */
                .callback = set_bios_reboot,
                .ident = "Dell OptiPlex 745",
                .matches = {
@@ -192,7 +279,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
                },
        },
-       {       /* Handle problems with rebooting on Dell Optiplex 745's DFF*/
+       {       /* Handle problems with rebooting on Dell Optiplex 745's DFF */
                .callback = set_bios_reboot,
                .ident = "Dell OptiPlex 745",
                .matches = {
@@ -201,7 +288,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
                },
        },
-       {       /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
+       {       /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
                .callback = set_bios_reboot,
                .ident = "Dell OptiPlex 745",
                .matches = {
@@ -210,7 +297,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
                },
        },
-       {   /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
+       {       /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
                .callback = set_bios_reboot,
                .ident = "Dell OptiPlex 330",
                .matches = {
@@ -219,7 +306,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
                },
        },
-       {   /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
+       {       /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
                .callback = set_bios_reboot,
                .ident = "Dell OptiPlex 360",
                .matches = {
@@ -228,7 +315,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
                },
        },
-       {       /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G*/
+       {       /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */
                .callback = set_bios_reboot,
                .ident = "Dell OptiPlex 760",
                .matches = {
@@ -301,7 +388,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"),
                },
        },
-       {       /* Handle problems with rebooting on ASUS P4S800 */
+       {       /* Handle problems with rebooting on ASUS P4S800 */
                .callback = set_bios_reboot,
                .ident = "ASUS P4S800",
                .matches = {
@@ -309,7 +396,9 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
                },
        },
-       { /* Handle reboot issue on Acer Aspire one */
+#endif /* CONFIG_X86_32 */
+
+       {       /* Handle reboot issue on Acer Aspire one */
                .callback = set_kbd_reboot,
                .ident = "Acer Aspire One A110",
                .matches = {
@@ -317,96 +406,6 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
                },
        },
-       { }
-};
-
-static int __init reboot_init(void)
-{
-       /* Only do the DMI check if reboot_type hasn't been overridden
-        * on the command line
-        */
-       if (reboot_default) {
-               dmi_check_system(reboot_dmi_table);
-       }
-       return 0;
-}
-core_initcall(reboot_init);
-
-extern const unsigned char machine_real_restart_asm[];
-extern const u64 machine_real_restart_gdt[3];
-
-void machine_real_restart(unsigned int type)
-{
-       void *restart_va;
-       unsigned long restart_pa;
-       void (*restart_lowmem)(unsigned int);
-       u64 *lowmem_gdt;
-
-       local_irq_disable();
-
-       /* Write zero to CMOS register number 0x0f, which the BIOS POST
-          routine will recognize as telling it to do a proper reboot.  (Well
-          that's what this book in front of me says -- it may only apply to
-          the Phoenix BIOS though, it's not clear).  At the same time,
-          disable NMIs by setting the top bit in the CMOS address register,
-          as we're about to do peculiar things to the CPU.  I'm not sure if
-          `outb_p' is needed instead of just `outb'.  Use it to be on the
-          safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
-        */
-       spin_lock(&rtc_lock);
-       CMOS_WRITE(0x00, 0x8f);
-       spin_unlock(&rtc_lock);
-
-       /*
-        * Switch back to the initial page table.
-        */
-       load_cr3(initial_page_table);
-
-       /* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
-          this on booting to tell it to "Bypass memory test (also warm
-          boot)".  This seems like a fairly standard thing that gets set by
-          REBOOT.COM programs, and the previous reset routine did this
-          too. */
-       *((unsigned short *)0x472) = reboot_mode;
-
-       /* Patch the GDT in the low memory trampoline */
-       lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt);
-
-       restart_va = TRAMPOLINE_SYM(machine_real_restart_asm);
-       restart_pa = virt_to_phys(restart_va);
-       restart_lowmem = (void (*)(unsigned int))restart_pa;
-
-       /* GDT[0]: GDT self-pointer */
-       lowmem_gdt[0] =
-               (u64)(sizeof(machine_real_restart_gdt) - 1) +
-               ((u64)virt_to_phys(lowmem_gdt) << 16);
-       /* GDT[1]: 64K real mode code segment */
-       lowmem_gdt[1] =
-               GDT_ENTRY(0x009b, restart_pa, 0xffff);
-
-       /* Jump to the identity-mapped low memory code */
-       restart_lowmem(type);
-}
-#ifdef CONFIG_APM_MODULE
-EXPORT_SYMBOL(machine_real_restart);
-#endif
-
-#endif /* CONFIG_X86_32 */
-
-/*
- * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
- */
-static int __init set_pci_reboot(const struct dmi_system_id *d)
-{
-       if (reboot_type != BOOT_CF9) {
-               reboot_type = BOOT_CF9;
-               printk(KERN_INFO "%s series board detected. "
-                      "Selecting PCI-method for reboots.\n", d->ident);
-       }
-       return 0;
-}
-
-static struct dmi_system_id __initdata pci_reboot_dmi_table[] = {
        {       /* Handle problems with rebooting on Apple MacBook5 */
                .callback = set_pci_reboot,
                .ident = "Apple MacBook5",
@@ -474,17 +473,17 @@ static struct dmi_system_id __initdata pci_reboot_dmi_table[] = {
        { }
 };
 
-static int __init pci_reboot_init(void)
+static int __init reboot_init(void)
 {
-       /* Only do the DMI check if reboot_type hasn't been overridden
+       /*
+        * Only do the DMI check if reboot_type hasn't been overridden
         * on the command line
         */
-       if (reboot_default) {
-               dmi_check_system(pci_reboot_dmi_table);
-       }
+       if (reboot_default)
+               dmi_check_system(reboot_dmi_table);
        return 0;
 }
-core_initcall(pci_reboot_init);
+core_initcall(reboot_init);
 
 static inline void kb_wait(void)
 {
@@ -502,14 +501,14 @@ static void vmxoff_nmi(int cpu, struct pt_regs *regs)
        cpu_emergency_vmxoff();
 }
 
-/* Use NMIs as IPIs to tell all CPUs to disable virtualization
- */
+/* Use NMIs as IPIs to tell all CPUs to disable virtualization */
 static void emergency_vmx_disable_all(void)
 {
        /* Just make sure we won't change CPUs while doing this */
        local_irq_disable();
 
-       /* We need to disable VMX on all CPUs before rebooting, otherwise
+       /*
+        * We need to disable VMX on all CPUs before rebooting, otherwise
         * we risk hanging up the machine, because the CPU ignore INIT
         * signals when VMX is enabled.
         *
@@ -528,8 +527,7 @@ static void emergency_vmx_disable_all(void)
         * is still enabling VMX.
         */
        if (cpu_has_vmx() && cpu_vmx_enabled()) {
-               /* Disable VMX on this CPU.
-                */
+               /* Disable VMX on this CPU. */
                cpu_vmxoff();
 
                /* Halt and disable VMX on the other CPUs */
@@ -574,12 +572,12 @@ static void native_machine_emergency_restart(void)
                /* Could also try the reset bit in the Hammer NB */
                switch (reboot_type) {
                case BOOT_KBD:
-                       mach_reboot_fixups(); /* for board specific fixups */
+                       mach_reboot_fixups(); /* For board specific fixups */
 
                        for (i = 0; i < 10; i++) {
                                kb_wait();
                                udelay(50);
-                               outb(0xfe, 0x64); /* pulse reset low */
+                               outb(0xfe, 0x64); /* Pulse reset low */
                                udelay(50);
                        }
                        if (attempt == 0 && orig_reboot_type == BOOT_ACPI) {
@@ -621,7 +619,7 @@ static void native_machine_emergency_restart(void)
 
                case BOOT_CF9:
                        port_cf9_safe = true;
-                       /* fall through */
+                       /* Fall through */
 
                case BOOT_CF9_COND:
                        if (port_cf9_safe) {
@@ -659,7 +657,8 @@ void native_machine_shutdown(void)
        /* Make certain I only run on the appropriate processor */
        set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
 
-       /* O.K Now that I'm on the appropriate processor,
+       /*
+        * O.K Now that I'm on the appropriate processor,
         * stop all of the others.
         */
        stop_other_cpus();
@@ -697,12 +696,11 @@ static void native_machine_restart(char *__unused)
 
 static void native_machine_halt(void)
 {
-       /* stop other cpus and apics */
+       /* Stop other cpus and apics */
        machine_shutdown();
 
        tboot_shutdown(TB_SHUTDOWN_HALT);
 
-       /* stop this cpu */
        stop_this_cpu(NULL);
 }
 
@@ -713,7 +711,7 @@ static void native_machine_power_off(void)
                        machine_shutdown();
                pm_power_off();
        }
-       /* a fallback in case there is no PM info available */
+       /* A fallback in case there is no PM info available */
        tboot_shutdown(TB_SHUTDOWN_HALT);
 }
 
@@ -775,7 +773,8 @@ static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
 
        cpu = raw_smp_processor_id();
 
-       /* Don't do anything if this handler is invoked on crashing cpu.
+       /*
+        * Don't do anything if this handler is invoked on crashing cpu.
         * Otherwise, system will completely hang. Crashing cpu can get
         * an NMI if system was initially booted with nmi_watchdog parameter.
         */
@@ -799,7 +798,8 @@ static void smp_send_nmi_allbutself(void)
        apic->send_IPI_allbutself(NMI_VECTOR);
 }
 
-/* Halt all other CPUs, calling the specified function on each of them
+/*
+ * Halt all other CPUs, calling the specified function on each of them
  *
  * This function can be used to halt all other CPUs on crash
  * or emergency reboot time. The function passed as parameter
@@ -810,7 +810,7 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback)
        unsigned long msecs;
        local_irq_disable();
 
-       /* Make a note of crashing cpu. Will be used in NMI callback.*/
+       /* Make a note of crashing cpu. Will be used in NMI callback. */
        crashing_cpu = safe_smp_processor_id();
 
        shootdown_callback = callback;
@@ -819,8 +819,9 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback)
        /* Would it be better to replace the trap vector here? */
        if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback,
                                 NMI_FLAG_FIRST, "crash"))
-               return;         /* return what? */
-       /* Ensure the new callback function is set before sending
+               return;         /* Return what? */
+       /*
+        * Ensure the new callback function is set before sending
         * out the NMI
         */
        wmb();
index 7e67c5a71061eb7389dcf8ea7526028f4eb7619f..9b4204e0666585d116233a4a1bed964df9f5d125 100644 (file)
@@ -393,10 +393,9 @@ static void __init reserve_initrd(void)
        initrd_start = 0;
 
        if (ramdisk_size >= (end_of_lowmem>>1)) {
-               memblock_free(ramdisk_image, ramdisk_end - ramdisk_image);
-               printk(KERN_ERR "initrd too large to handle, "
-                      "disabling initrd\n");
-               return;
+               panic("initrd too large to handle, "
+                      "disabling initrd (%lld needed, %lld available)\n",
+                      ramdisk_size, end_of_lowmem>>1);
        }
 
        printk(KERN_INFO "RAMDISK: %08llx - %08llx\n", ramdisk_image,
index 66c74f481cab36bca09f95aa68b98160a41a1fbc..48d2b7ded4222cfc008a997f5e2d054830c023a1 100644 (file)
  *     about nothing of note with C stepping upwards.
  */
 
+static atomic_t stopping_cpu = ATOMIC_INIT(-1);
+static bool smp_no_nmi_ipi = false;
+
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
@@ -149,8 +152,6 @@ void native_send_call_func_ipi(const struct cpumask *mask)
        free_cpumask_var(allbutself);
 }
 
-static atomic_t stopping_cpu = ATOMIC_INIT(-1);
-
 static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs)
 {
        /* We are registered on stopping cpu too, avoid spurious NMI */
@@ -162,7 +163,19 @@ static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs)
        return NMI_HANDLED;
 }
 
-static void native_nmi_stop_other_cpus(int wait)
+/*
+ * this function calls the 'stop' function on all other CPUs in the system.
+ */
+
+asmlinkage void smp_reboot_interrupt(void)
+{
+       ack_APIC_irq();
+       irq_enter();
+       stop_this_cpu(NULL);
+       irq_exit();
+}
+
+static void native_stop_other_cpus(int wait)
 {
        unsigned long flags;
        unsigned long timeout;
@@ -174,20 +187,25 @@ static void native_nmi_stop_other_cpus(int wait)
         * Use an own vector here because smp_call_function
         * does lots of things not suitable in a panic situation.
         */
+
+       /*
+        * We start by using the REBOOT_VECTOR irq.
+        * The irq is treated as a sync point to allow critical
+        * regions of code on other cpus to release their spin locks
+        * and re-enable irqs.  Jumping straight to an NMI might
+        * accidentally cause deadlocks with further shutdown/panic
+        * code.  By syncing, we give the cpus up to one second to
+        * finish their work before we force them off with the NMI.
+        */
        if (num_online_cpus() > 1) {
                /* did someone beat us here? */
                if (atomic_cmpxchg(&stopping_cpu, -1, safe_smp_processor_id()) != -1)
                        return;
 
-               if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback,
-                                        NMI_FLAG_FIRST, "smp_stop"))
-                       /* Note: we ignore failures here */
-                       return;
-
-               /* sync above data before sending NMI */
+               /* sync above data before sending IRQ */
                wmb();
 
-               apic->send_IPI_allbutself(NMI_VECTOR);
+               apic->send_IPI_allbutself(REBOOT_VECTOR);
 
                /*
                 * Don't wait longer than a second if the caller
@@ -197,63 +215,37 @@ static void native_nmi_stop_other_cpus(int wait)
                while (num_online_cpus() > 1 && (wait || timeout--))
                        udelay(1);
        }
+       
+       /* if the REBOOT_VECTOR didn't work, try with the NMI */
+       if ((num_online_cpus() > 1) && (!smp_no_nmi_ipi))  {
+               if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback,
+                                        NMI_FLAG_FIRST, "smp_stop"))
+                       /* Note: we ignore failures here */
+                       /* Hope the REBOOT_IRQ is good enough */
+                       goto finish;
 
-       local_irq_save(flags);
-       disable_local_APIC();
-       local_irq_restore(flags);
-}
-
-/*
- * this function calls the 'stop' function on all other CPUs in the system.
- */
-
-asmlinkage void smp_reboot_interrupt(void)
-{
-       ack_APIC_irq();
-       irq_enter();
-       stop_this_cpu(NULL);
-       irq_exit();
-}
-
-static void native_irq_stop_other_cpus(int wait)
-{
-       unsigned long flags;
-       unsigned long timeout;
+               /* sync above data before sending IRQ */
+               wmb();
 
-       if (reboot_force)
-               return;
+               pr_emerg("Shutting down cpus with NMI\n");
 
-       /*
-        * Use an own vector here because smp_call_function
-        * does lots of things not suitable in a panic situation.
-        * On most systems we could also use an NMI here,
-        * but there are a few systems around where NMI
-        * is problematic so stay with an non NMI for now
-        * (this implies we cannot stop CPUs spinning with irq off
-        * currently)
-        */
-       if (num_online_cpus() > 1) {
-               apic->send_IPI_allbutself(REBOOT_VECTOR);
+               apic->send_IPI_allbutself(NMI_VECTOR);
 
                /*
-                * Don't wait longer than a second if the caller
+                * Don't wait longer than a 10 ms if the caller
                 * didn't ask us to wait.
                 */
-               timeout = USEC_PER_SEC;
+               timeout = USEC_PER_MSEC * 10;
                while (num_online_cpus() > 1 && (wait || timeout--))
                        udelay(1);
        }
 
+finish:
        local_irq_save(flags);
        disable_local_APIC();
        local_irq_restore(flags);
 }
 
-static void native_smp_disable_nmi_ipi(void)
-{
-       smp_ops.stop_other_cpus = native_irq_stop_other_cpus;
-}
-
 /*
  * Reschedule call back.
  */
@@ -287,8 +279,8 @@ void smp_call_function_single_interrupt(struct pt_regs *regs)
 
 static int __init nonmi_ipi_setup(char *str)
 {
-        native_smp_disable_nmi_ipi();
-        return 1;
+       smp_no_nmi_ipi = true;
+       return 1;
 }
 
 __setup("nonmi_ipi", nonmi_ipi_setup);
@@ -298,7 +290,7 @@ struct smp_ops smp_ops = {
        .smp_prepare_cpus       = native_smp_prepare_cpus,
        .smp_cpus_done          = native_smp_cpus_done,
 
-       .stop_other_cpus        = native_nmi_stop_other_cpus,
+       .stop_other_cpus        = native_stop_other_cpus,
        .smp_send_reschedule    = native_smp_send_reschedule,
 
        .cpu_up                 = native_cpu_up,
index c29e235792afee3d5b0cbc59a54528f3959f111c..b79133abda48d9c025eb1dad8ddf5a0b20ac1090 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <asm/cacheflush.h>
 #include <asm/sections.h>
+#include <asm/asm.h>
 
 int rodata_test(void)
 {
@@ -42,14 +43,7 @@ int rodata_test(void)
                ".section .fixup,\"ax\"\n"
                "2:     jmp 1b\n"
                ".previous\n"
-               ".section __ex_table,\"a\"\n"
-               "       .align 16\n"
-#ifdef CONFIG_X86_32
-               "       .long 0b,2b\n"
-#else
-               "       .quad 0b,2b\n"
-#endif
-               ".previous"
+               _ASM_EXTABLE(0b,2b)
                : [rslt] "=r" (result)
                : [rodata_test] "r" (&rodata_test_data), [zero] "r" (0UL)
        );
index a1d804bcd48357554cc017f4b63c217eb2b84eaa..8eeb55a551b423fdce43eb432c8f8f5599246848 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/pci_ids.h>
 #include <linux/pci_regs.h>
+#include <linux/smp.h>
 
 #include <asm/apic.h>
 #include <asm/pci-direct.h>
@@ -22,6 +23,8 @@
 #include <asm/paravirt.h>
 #include <asm/setup.h>
 
+#define TOPOLOGY_REGISTER_OFFSET 0x10
+
 #if defined CONFIG_PCI && defined CONFIG_PARAVIRT
 /*
  * Interrupt control on vSMPowered systems:
@@ -149,12 +152,49 @@ int is_vsmp_box(void)
        return 0;
 }
 #endif
+
+static void __init vsmp_cap_cpus(void)
+{
+#if !defined(CONFIG_X86_VSMP) && defined(CONFIG_SMP)
+       void __iomem *address;
+       unsigned int cfg, topology, node_shift, maxcpus;
+
+       /*
+        * CONFIG_X86_VSMP is not configured, so limit the number CPUs to the
+        * ones present in the first board, unless explicitly overridden by
+        * setup_max_cpus
+        */
+       if (setup_max_cpus != NR_CPUS)
+               return;
+
+       /* Read the vSMP Foundation topology register */
+       cfg = read_pci_config(0, 0x1f, 0, PCI_BASE_ADDRESS_0);
+       address = early_ioremap(cfg + TOPOLOGY_REGISTER_OFFSET, 4);
+       if (WARN_ON(!address))
+               return;
+
+       topology = readl(address);
+       node_shift = (topology >> 16) & 0x7;
+       if (!node_shift)
+               /* The value 0 should be decoded as 8 */
+               node_shift = 8;
+       maxcpus = (topology & ((1 << node_shift) - 1)) + 1;
+
+       pr_info("vSMP CTL: Capping CPUs to %d (CONFIG_X86_VSMP is unset)\n",
+               maxcpus);
+       setup_max_cpus = maxcpus;
+       early_iounmap(address, 4);
+#endif
+}
+
 void __init vsmp_init(void)
 {
        detect_vsmp_box();
        if (!is_vsmp_box())
                return;
 
+       vsmp_cap_cpus();
+
        set_vsmp_pv_ops();
        return;
 }
index e62728e30b014a0214a3735210c7d51cde7e061c..bd18149b2b0f09532870075a274ff1576b5de1d7 100644 (file)
@@ -48,8 +48,6 @@ void __sanitize_i387_state(struct task_struct *tsk)
        if (!fx)
                return;
 
-       BUG_ON(__thread_has_fpu(tsk));
-
        xstate_bv = tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv;
 
        /*
index 78d16a554db00f51c13b7d49df2c4cfafabcb276..2af5df3ade7c03e70f3056617d5982540a8cb5b8 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/linkage.h>
 #include <asm/dwarf2.h>
 #include <asm/errno.h>
+#include <asm/asm.h>
                                
 /*
  * computes a partial checksum, e.g. for TCP/UDP fragments
@@ -282,15 +283,11 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,
 
 #define SRC(y...)                      \
        9999: y;                        \
-       .section __ex_table, "a";       \
-       .long 9999b, 6001f      ;       \
-       .previous
+       _ASM_EXTABLE(9999b, 6001f)
 
 #define DST(y...)                      \
        9999: y;                        \
-       .section __ex_table, "a";       \
-       .long 9999b, 6002f      ;       \
-       .previous
+       _ASM_EXTABLE(9999b, 6002f)
 
 #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
 
index 024840266ba0d94144697de13194417d0427d22f..5b2995f4557a8c6e8d38ba4461db8d5e34c983c6 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/thread_info.h>
 #include <asm/cpufeature.h>
 #include <asm/alternative-asm.h>
+#include <asm/asm.h>
 
 /*
  * By placing feature2 after feature1 in altinstructions section, we logically
        jmp copy_user_handle_tail
        .previous
 
-       .section __ex_table,"a"
-       .align 8
-       .quad 100b,103b
-       .quad 101b,103b
-       .previous
+       _ASM_EXTABLE(100b,103b)
+       _ASM_EXTABLE(101b,103b)
 #endif
        .endm
 
@@ -191,29 +189,26 @@ ENTRY(copy_user_generic_unrolled)
 60:    jmp copy_user_handle_tail /* ecx is zerorest also */
        .previous
 
-       .section __ex_table,"a"
-       .align 8
-       .quad 1b,30b
-       .quad 2b,30b
-       .quad 3b,30b
-       .quad 4b,30b
-       .quad 5b,30b
-       .quad 6b,30b
-       .quad 7b,30b
-       .quad 8b,30b
-       .quad 9b,30b
-       .quad 10b,30b
-       .quad 11b,30b
-       .quad 12b,30b
-       .quad 13b,30b
-       .quad 14b,30b
-       .quad 15b,30b
-       .quad 16b,30b
-       .quad 18b,40b
-       .quad 19b,40b
-       .quad 21b,50b
-       .quad 22b,50b
-       .previous
+       _ASM_EXTABLE(1b,30b)
+       _ASM_EXTABLE(2b,30b)
+       _ASM_EXTABLE(3b,30b)
+       _ASM_EXTABLE(4b,30b)
+       _ASM_EXTABLE(5b,30b)
+       _ASM_EXTABLE(6b,30b)
+       _ASM_EXTABLE(7b,30b)
+       _ASM_EXTABLE(8b,30b)
+       _ASM_EXTABLE(9b,30b)
+       _ASM_EXTABLE(10b,30b)
+       _ASM_EXTABLE(11b,30b)
+       _ASM_EXTABLE(12b,30b)
+       _ASM_EXTABLE(13b,30b)
+       _ASM_EXTABLE(14b,30b)
+       _ASM_EXTABLE(15b,30b)
+       _ASM_EXTABLE(16b,30b)
+       _ASM_EXTABLE(18b,40b)
+       _ASM_EXTABLE(19b,40b)
+       _ASM_EXTABLE(21b,50b)
+       _ASM_EXTABLE(22b,50b)
        CFI_ENDPROC
 ENDPROC(copy_user_generic_unrolled)
 
@@ -259,11 +254,8 @@ ENTRY(copy_user_generic_string)
        jmp copy_user_handle_tail
        .previous
 
-       .section __ex_table,"a"
-       .align 8
-       .quad 1b,11b
-       .quad 3b,12b
-       .previous
+       _ASM_EXTABLE(1b,11b)
+       _ASM_EXTABLE(3b,12b)
        CFI_ENDPROC
 ENDPROC(copy_user_generic_string)
 
@@ -294,9 +286,6 @@ ENTRY(copy_user_enhanced_fast_string)
        jmp copy_user_handle_tail
        .previous
 
-       .section __ex_table,"a"
-       .align 8
-       .quad 1b,12b
-       .previous
+       _ASM_EXTABLE(1b,12b)
        CFI_ENDPROC
 ENDPROC(copy_user_enhanced_fast_string)
index cb0c112386fba0a7b0a349ab9f372aab0761edc7..cacddc7163eb17969dac60cad117ca79fb54e8f2 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/current.h>
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
+#include <asm/asm.h>
 
        .macro ALIGN_DESTINATION
 #ifdef FIX_ALIGNMENT
        jmp copy_user_handle_tail
        .previous
 
-       .section __ex_table,"a"
-       .align 8
-       .quad 100b,103b
-       .quad 101b,103b
-       .previous
+       _ASM_EXTABLE(100b,103b)
+       _ASM_EXTABLE(101b,103b)
 #endif
        .endm
 
@@ -111,27 +109,25 @@ ENTRY(__copy_user_nocache)
        jmp copy_user_handle_tail
        .previous
 
-       .section __ex_table,"a"
-       .quad 1b,30b
-       .quad 2b,30b
-       .quad 3b,30b
-       .quad 4b,30b
-       .quad 5b,30b
-       .quad 6b,30b
-       .quad 7b,30b
-       .quad 8b,30b
-       .quad 9b,30b
-       .quad 10b,30b
-       .quad 11b,30b
-       .quad 12b,30b
-       .quad 13b,30b
-       .quad 14b,30b
-       .quad 15b,30b
-       .quad 16b,30b
-       .quad 18b,40b
-       .quad 19b,40b
-       .quad 21b,50b
-       .quad 22b,50b
-       .previous
+       _ASM_EXTABLE(1b,30b)
+       _ASM_EXTABLE(2b,30b)
+       _ASM_EXTABLE(3b,30b)
+       _ASM_EXTABLE(4b,30b)
+       _ASM_EXTABLE(5b,30b)
+       _ASM_EXTABLE(6b,30b)
+       _ASM_EXTABLE(7b,30b)
+       _ASM_EXTABLE(8b,30b)
+       _ASM_EXTABLE(9b,30b)
+       _ASM_EXTABLE(10b,30b)
+       _ASM_EXTABLE(11b,30b)
+       _ASM_EXTABLE(12b,30b)
+       _ASM_EXTABLE(13b,30b)
+       _ASM_EXTABLE(14b,30b)
+       _ASM_EXTABLE(15b,30b)
+       _ASM_EXTABLE(16b,30b)
+       _ASM_EXTABLE(18b,40b)
+       _ASM_EXTABLE(19b,40b)
+       _ASM_EXTABLE(21b,50b)
+       _ASM_EXTABLE(22b,50b)
        CFI_ENDPROC
 ENDPROC(__copy_user_nocache)
index fb903b758da8534847ef3c4c97840d91972abdf4..2419d5fefae30ac2453fabf71c633ede013d2e4a 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/linkage.h>
 #include <asm/dwarf2.h>
 #include <asm/errno.h>
+#include <asm/asm.h>
 
 /*
  * Checksum copy with exception handling.
 
        .macro source
 10:
-       .section __ex_table, "a"
-       .align 8
-       .quad 10b, .Lbad_source
-       .previous
+       _ASM_EXTABLE(10b, .Lbad_source)
        .endm
 
        .macro dest
 20:
-       .section __ex_table, "a"
-       .align 8
-       .quad 20b, .Lbad_dest
-       .previous
+       _ASM_EXTABLE(20b, .Lbad_dest)
        .endm
 
        .macro ignore L=.Lignore
 30:
-       .section __ex_table, "a"
-       .align 8
-       .quad 30b, \L
-       .previous
+       _ASM_EXTABLE(30b, \L)
        .endm
 
 
index 51f1504cddd9f20fa50e010c66ec0d83da2c2215..b33b1fb1e6d46728ed707f640063306ca99c2ae2 100644 (file)
@@ -95,10 +95,9 @@ bad_get_user:
        CFI_ENDPROC
 END(bad_get_user)
 
-.section __ex_table,"a"
-       _ASM_PTR 1b,bad_get_user
-       _ASM_PTR 2b,bad_get_user
-       _ASM_PTR 3b,bad_get_user
+       _ASM_EXTABLE(1b,bad_get_user)
+       _ASM_EXTABLE(2b,bad_get_user)
+       _ASM_EXTABLE(3b,bad_get_user)
 #ifdef CONFIG_X86_64
-       _ASM_PTR 4b,bad_get_user
+       _ASM_EXTABLE(4b,bad_get_user)
 #endif
index 36b0d15ae6e97edcc9217743a06422a6e5f5fe2e..7f951c8f76c45186bfb44ad5308a27e8ebe38db1 100644 (file)
@@ -86,12 +86,10 @@ bad_put_user:
        EXIT
 END(bad_put_user)
 
-.section __ex_table,"a"
-       _ASM_PTR 1b,bad_put_user
-       _ASM_PTR 2b,bad_put_user
-       _ASM_PTR 3b,bad_put_user
-       _ASM_PTR 4b,bad_put_user
+       _ASM_EXTABLE(1b,bad_put_user)
+       _ASM_EXTABLE(2b,bad_put_user)
+       _ASM_EXTABLE(3b,bad_put_user)
+       _ASM_EXTABLE(4b,bad_put_user)
 #ifdef CONFIG_X86_32
-       _ASM_PTR 5b,bad_put_user
+       _ASM_EXTABLE(5b,bad_put_user)
 #endif
-.previous
index ef2a6a5d78e39ddc71c2c51d90dc56f9cbcab9ef..883b216c60b2d51059985c716da365aef5e9bfbf 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/interrupt.h>
 #include <asm/uaccess.h>
 #include <asm/mmx.h>
+#include <asm/asm.h>
 
 #ifdef CONFIG_X86_INTEL_USERCOPY
 /*
@@ -127,10 +128,7 @@ long strnlen_user(const char __user *s, long n)
                "3:     movb $1,%%al\n"
                "       jmp 1b\n"
                ".previous\n"
-               ".section __ex_table,\"a\"\n"
-               "       .align 4\n"
-               "       .long 0b,2b\n"
-               ".previous"
+               _ASM_EXTABLE(0b,2b)
                :"=&r" (n), "=&D" (s), "=&a" (res), "=&c" (tmp)
                :"0" (n), "1" (s), "2" (0), "3" (mask)
                :"cc");
@@ -199,47 +197,44 @@ __copy_user_intel(void __user *to, const void *from, unsigned long size)
                       "101:   lea 0(%%eax,%0,4),%0\n"
                       "       jmp 100b\n"
                       ".previous\n"
-                      ".section __ex_table,\"a\"\n"
-                      "       .align 4\n"
-                      "       .long 1b,100b\n"
-                      "       .long 2b,100b\n"
-                      "       .long 3b,100b\n"
-                      "       .long 4b,100b\n"
-                      "       .long 5b,100b\n"
-                      "       .long 6b,100b\n"
-                      "       .long 7b,100b\n"
-                      "       .long 8b,100b\n"
-                      "       .long 9b,100b\n"
-                      "       .long 10b,100b\n"
-                      "       .long 11b,100b\n"
-                      "       .long 12b,100b\n"
-                      "       .long 13b,100b\n"
-                      "       .long 14b,100b\n"
-                      "       .long 15b,100b\n"
-                      "       .long 16b,100b\n"
-                      "       .long 17b,100b\n"
-                      "       .long 18b,100b\n"
-                      "       .long 19b,100b\n"
-                      "       .long 20b,100b\n"
-                      "       .long 21b,100b\n"
-                      "       .long 22b,100b\n"
-                      "       .long 23b,100b\n"
-                      "       .long 24b,100b\n"
-                      "       .long 25b,100b\n"
-                      "       .long 26b,100b\n"
-                      "       .long 27b,100b\n"
-                      "       .long 28b,100b\n"
-                      "       .long 29b,100b\n"
-                      "       .long 30b,100b\n"
-                      "       .long 31b,100b\n"
-                      "       .long 32b,100b\n"
-                      "       .long 33b,100b\n"
-                      "       .long 34b,100b\n"
-                      "       .long 35b,100b\n"
-                      "       .long 36b,100b\n"
-                      "       .long 37b,100b\n"
-                      "       .long 99b,101b\n"
-                      ".previous"
+                      _ASM_EXTABLE(1b,100b)
+                      _ASM_EXTABLE(2b,100b)
+                      _ASM_EXTABLE(3b,100b)
+                      _ASM_EXTABLE(4b,100b)
+                      _ASM_EXTABLE(5b,100b)
+                      _ASM_EXTABLE(6b,100b)
+                      _ASM_EXTABLE(7b,100b)
+                      _ASM_EXTABLE(8b,100b)
+                      _ASM_EXTABLE(9b,100b)
+                      _ASM_EXTABLE(10b,100b)
+                      _ASM_EXTABLE(11b,100b)
+                      _ASM_EXTABLE(12b,100b)
+                      _ASM_EXTABLE(13b,100b)
+                      _ASM_EXTABLE(14b,100b)
+                      _ASM_EXTABLE(15b,100b)
+                      _ASM_EXTABLE(16b,100b)
+                      _ASM_EXTABLE(17b,100b)
+                      _ASM_EXTABLE(18b,100b)
+                      _ASM_EXTABLE(19b,100b)
+                      _ASM_EXTABLE(20b,100b)
+                      _ASM_EXTABLE(21b,100b)
+                      _ASM_EXTABLE(22b,100b)
+                      _ASM_EXTABLE(23b,100b)
+                      _ASM_EXTABLE(24b,100b)
+                      _ASM_EXTABLE(25b,100b)
+                      _ASM_EXTABLE(26b,100b)
+                      _ASM_EXTABLE(27b,100b)
+                      _ASM_EXTABLE(28b,100b)
+                      _ASM_EXTABLE(29b,100b)
+                      _ASM_EXTABLE(30b,100b)
+                      _ASM_EXTABLE(31b,100b)
+                      _ASM_EXTABLE(32b,100b)
+                      _ASM_EXTABLE(33b,100b)
+                      _ASM_EXTABLE(34b,100b)
+                      _ASM_EXTABLE(35b,100b)
+                      _ASM_EXTABLE(36b,100b)
+                      _ASM_EXTABLE(37b,100b)
+                      _ASM_EXTABLE(99b,101b)
                       : "=&c"(size), "=&D" (d0), "=&S" (d1)
                       :  "1"(to), "2"(from), "0"(size)
                       : "eax", "edx", "memory");
@@ -312,29 +307,26 @@ __copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size)
                       "        popl %0\n"
                       "        jmp 8b\n"
                       ".previous\n"
-                      ".section __ex_table,\"a\"\n"
-                      "        .align 4\n"
-                      "        .long 0b,16b\n"
-                      "        .long 1b,16b\n"
-                      "        .long 2b,16b\n"
-                      "        .long 21b,16b\n"
-                      "        .long 3b,16b\n"
-                      "        .long 31b,16b\n"
-                      "        .long 4b,16b\n"
-                      "        .long 41b,16b\n"
-                      "        .long 10b,16b\n"
-                      "        .long 51b,16b\n"
-                      "        .long 11b,16b\n"
-                      "        .long 61b,16b\n"
-                      "        .long 12b,16b\n"
-                      "        .long 71b,16b\n"
-                      "        .long 13b,16b\n"
-                      "        .long 81b,16b\n"
-                      "        .long 14b,16b\n"
-                      "        .long 91b,16b\n"
-                      "        .long 6b,9b\n"
-                      "        .long 7b,16b\n"
-                      ".previous"
+                      _ASM_EXTABLE(0b,16b)
+                      _ASM_EXTABLE(1b,16b)
+                      _ASM_EXTABLE(2b,16b)
+                      _ASM_EXTABLE(21b,16b)
+                      _ASM_EXTABLE(3b,16b)
+                      _ASM_EXTABLE(31b,16b)
+                      _ASM_EXTABLE(4b,16b)
+                      _ASM_EXTABLE(41b,16b)
+                      _ASM_EXTABLE(10b,16b)
+                      _ASM_EXTABLE(51b,16b)
+                      _ASM_EXTABLE(11b,16b)
+                      _ASM_EXTABLE(61b,16b)
+                      _ASM_EXTABLE(12b,16b)
+                      _ASM_EXTABLE(71b,16b)
+                      _ASM_EXTABLE(13b,16b)
+                      _ASM_EXTABLE(81b,16b)
+                      _ASM_EXTABLE(14b,16b)
+                      _ASM_EXTABLE(91b,16b)
+                      _ASM_EXTABLE(6b,9b)
+                      _ASM_EXTABLE(7b,16b)
                       : "=&c"(size), "=&D" (d0), "=&S" (d1)
                       :  "1"(to), "2"(from), "0"(size)
                       : "eax", "edx", "memory");
@@ -414,29 +406,26 @@ static unsigned long __copy_user_zeroing_intel_nocache(void *to,
               "        popl %0\n"
               "        jmp 8b\n"
               ".previous\n"
-              ".section __ex_table,\"a\"\n"
-              "        .align 4\n"
-              "        .long 0b,16b\n"
-              "        .long 1b,16b\n"
-              "        .long 2b,16b\n"
-              "        .long 21b,16b\n"
-              "        .long 3b,16b\n"
-              "        .long 31b,16b\n"
-              "        .long 4b,16b\n"
-              "        .long 41b,16b\n"
-              "        .long 10b,16b\n"
-              "        .long 51b,16b\n"
-              "        .long 11b,16b\n"
-              "        .long 61b,16b\n"
-              "        .long 12b,16b\n"
-              "        .long 71b,16b\n"
-              "        .long 13b,16b\n"
-              "        .long 81b,16b\n"
-              "        .long 14b,16b\n"
-              "        .long 91b,16b\n"
-              "        .long 6b,9b\n"
-              "        .long 7b,16b\n"
-              ".previous"
+              _ASM_EXTABLE(0b,16b)
+              _ASM_EXTABLE(1b,16b)
+              _ASM_EXTABLE(2b,16b)
+              _ASM_EXTABLE(21b,16b)
+              _ASM_EXTABLE(3b,16b)
+              _ASM_EXTABLE(31b,16b)
+              _ASM_EXTABLE(4b,16b)
+              _ASM_EXTABLE(41b,16b)
+              _ASM_EXTABLE(10b,16b)
+              _ASM_EXTABLE(51b,16b)
+              _ASM_EXTABLE(11b,16b)
+              _ASM_EXTABLE(61b,16b)
+              _ASM_EXTABLE(12b,16b)
+              _ASM_EXTABLE(71b,16b)
+              _ASM_EXTABLE(13b,16b)
+              _ASM_EXTABLE(81b,16b)
+              _ASM_EXTABLE(14b,16b)
+              _ASM_EXTABLE(91b,16b)
+              _ASM_EXTABLE(6b,9b)
+              _ASM_EXTABLE(7b,16b)
               : "=&c"(size), "=&D" (d0), "=&S" (d1)
               :  "1"(to), "2"(from), "0"(size)
               : "eax", "edx", "memory");
@@ -505,29 +494,26 @@ static unsigned long __copy_user_intel_nocache(void *to,
               "9:      lea 0(%%eax,%0,4),%0\n"
               "16:     jmp 8b\n"
               ".previous\n"
-              ".section __ex_table,\"a\"\n"
-              "        .align 4\n"
-              "        .long 0b,16b\n"
-              "        .long 1b,16b\n"
-              "        .long 2b,16b\n"
-              "        .long 21b,16b\n"
-              "        .long 3b,16b\n"
-              "        .long 31b,16b\n"
-              "        .long 4b,16b\n"
-              "        .long 41b,16b\n"
-              "        .long 10b,16b\n"
-              "        .long 51b,16b\n"
-              "        .long 11b,16b\n"
-              "        .long 61b,16b\n"
-              "        .long 12b,16b\n"
-              "        .long 71b,16b\n"
-              "        .long 13b,16b\n"
-              "        .long 81b,16b\n"
-              "        .long 14b,16b\n"
-              "        .long 91b,16b\n"
-              "        .long 6b,9b\n"
-              "        .long 7b,16b\n"
-              ".previous"
+              _ASM_EXTABLE(0b,16b)
+              _ASM_EXTABLE(1b,16b)
+              _ASM_EXTABLE(2b,16b)
+              _ASM_EXTABLE(21b,16b)
+              _ASM_EXTABLE(3b,16b)
+              _ASM_EXTABLE(31b,16b)
+              _ASM_EXTABLE(4b,16b)
+              _ASM_EXTABLE(41b,16b)
+              _ASM_EXTABLE(10b,16b)
+              _ASM_EXTABLE(51b,16b)
+              _ASM_EXTABLE(11b,16b)
+              _ASM_EXTABLE(61b,16b)
+              _ASM_EXTABLE(12b,16b)
+              _ASM_EXTABLE(71b,16b)
+              _ASM_EXTABLE(13b,16b)
+              _ASM_EXTABLE(81b,16b)
+              _ASM_EXTABLE(14b,16b)
+              _ASM_EXTABLE(91b,16b)
+              _ASM_EXTABLE(6b,9b)
+              _ASM_EXTABLE(7b,16b)
               : "=&c"(size), "=&D" (d0), "=&S" (d1)
               :  "1"(to), "2"(from), "0"(size)
               : "eax", "edx", "memory");
@@ -574,12 +560,9 @@ do {                                                                       \
                "3:     lea 0(%3,%0,4),%0\n"                            \
                "       jmp 2b\n"                                       \
                ".previous\n"                                           \
-               ".section __ex_table,\"a\"\n"                           \
-               "       .align 4\n"                                     \
-               "       .long 4b,5b\n"                                  \
-               "       .long 0b,3b\n"                                  \
-               "       .long 1b,2b\n"                                  \
-               ".previous"                                             \
+               _ASM_EXTABLE(4b,5b)                                     \
+               _ASM_EXTABLE(0b,3b)                                     \
+               _ASM_EXTABLE(1b,2b)                                     \
                : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2)   \
                : "3"(size), "0"(size), "1"(to), "2"(from)              \
                : "memory");                                            \
@@ -616,12 +599,9 @@ do {                                                                       \
                "       popl %0\n"                                      \
                "       jmp 2b\n"                                       \
                ".previous\n"                                           \
-               ".section __ex_table,\"a\"\n"                           \
-               "       .align 4\n"                                     \
-               "       .long 4b,5b\n"                                  \
-               "       .long 0b,3b\n"                                  \
-               "       .long 1b,6b\n"                                  \
-               ".previous"                                             \
+               _ASM_EXTABLE(4b,5b)                                     \
+               _ASM_EXTABLE(0b,3b)                                     \
+               _ASM_EXTABLE(1b,6b)                                     \
                : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2)   \
                : "3"(size), "0"(size), "1"(to), "2"(from)              \
                : "memory");                                            \
index 1fb85dbe390ab7a1810c88ff5e60ee4f380bb93a..903ec1e9c3263f7f7ce6e1f5a59e7a32b224dc85 100644 (file)
@@ -1,11 +1,23 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/sort.h>
 #include <asm/uaccess.h>
 
+static inline unsigned long
+ex_insn_addr(const struct exception_table_entry *x)
+{
+       return (unsigned long)&x->insn + x->insn;
+}
+static inline unsigned long
+ex_fixup_addr(const struct exception_table_entry *x)
+{
+       return (unsigned long)&x->fixup + x->fixup;
+}
 
 int fixup_exception(struct pt_regs *regs)
 {
        const struct exception_table_entry *fixup;
+       unsigned long new_ip;
 
 #ifdef CONFIG_PNPBIOS
        if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
@@ -23,15 +35,135 @@ int fixup_exception(struct pt_regs *regs)
 
        fixup = search_exception_tables(regs->ip);
        if (fixup) {
-               /* If fixup is less than 16, it means uaccess error */
-               if (fixup->fixup < 16) {
+               new_ip = ex_fixup_addr(fixup);
+
+               if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
+                       /* Special hack for uaccess_err */
                        current_thread_info()->uaccess_err = 1;
-                       regs->ip += fixup->fixup;
-                       return 1;
+                       new_ip -= 0x7ffffff0;
                }
-               regs->ip = fixup->fixup;
+               regs->ip = new_ip;
                return 1;
        }
 
        return 0;
 }
+
+/* Restricted version used during very early boot */
+int __init early_fixup_exception(unsigned long *ip)
+{
+       const struct exception_table_entry *fixup;
+       unsigned long new_ip;
+
+       fixup = search_exception_tables(*ip);
+       if (fixup) {
+               new_ip = ex_fixup_addr(fixup);
+
+               if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
+                       /* uaccess handling not supported during early boot */
+                       return 0;
+               }
+
+               *ip = new_ip;
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Search one exception table for an entry corresponding to the
+ * given instruction address, and return the address of the entry,
+ * or NULL if none is found.
+ * We use a binary search, and thus we assume that the table is
+ * already sorted.
+ */
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+              const struct exception_table_entry *last,
+              unsigned long value)
+{
+       while (first <= last) {
+               const struct exception_table_entry *mid;
+               unsigned long addr;
+
+               mid = ((last - first) >> 1) + first;
+               addr = ex_insn_addr(mid);
+               if (addr < value)
+                       first = mid + 1;
+               else if (addr > value)
+                       last = mid - 1;
+               else
+                       return mid;
+        }
+        return NULL;
+}
+
+/*
+ * The exception table needs to be sorted so that the binary
+ * search that we use to find entries in it works properly.
+ * This is used both for the kernel exception table and for
+ * the exception tables of modules that get loaded.
+ *
+ */
+static int cmp_ex(const void *a, const void *b)
+{
+       const struct exception_table_entry *x = a, *y = b;
+
+       /*
+        * This value will always end up fittin in an int, because on
+        * both i386 and x86-64 the kernel symbol-reachable address
+        * space is < 2 GiB.
+        *
+        * This compare is only valid after normalization.
+        */
+       return x->insn - y->insn;
+}
+
+void sort_extable(struct exception_table_entry *start,
+                 struct exception_table_entry *finish)
+{
+       struct exception_table_entry *p;
+       int i;
+
+       /* Convert all entries to being relative to the start of the section */
+       i = 0;
+       for (p = start; p < finish; p++) {
+               p->insn += i;
+               i += 4;
+               p->fixup += i;
+               i += 4;
+       }
+
+       sort(start, finish - start, sizeof(struct exception_table_entry),
+            cmp_ex, NULL);
+
+       /* Denormalize all entries */
+       i = 0;
+       for (p = start; p < finish; p++) {
+               p->insn -= i;
+               i += 4;
+               p->fixup -= i;
+               i += 4;
+       }
+}
+
+#ifdef CONFIG_MODULES
+/*
+ * If the exception table is sorted, any referring to the module init
+ * will be at the beginning or the end.
+ */
+void trim_init_extable(struct module *m)
+{
+       /*trim the beginning*/
+       while (m->num_exentries &&
+              within_module_init(ex_insn_addr(&m->extable[0]), m)) {
+               m->extable++;
+               m->num_exentries--;
+       }
+       /*trim the end*/
+       while (m->num_exentries &&
+              within_module_init(ex_insn_addr(&m->extable[m->num_exentries-1]), m))
+               m->num_exentries--;
+}
+#endif /* CONFIG_MODULES */
index 4f0cec7e4ffbc0259937ffd4f5994b76ba8b4a30..319b6f2fb8b9dc56300c082ab06a266673b091c9 100644 (file)
@@ -29,8 +29,14 @@ int direct_gbpages
 #endif
 ;
 
-static void __init find_early_table_space(unsigned long end, int use_pse,
-                                         int use_gbpages)
+struct map_range {
+       unsigned long start;
+       unsigned long end;
+       unsigned page_size_mask;
+};
+
+static void __init find_early_table_space(struct map_range *mr, unsigned long end,
+                                         int use_pse, int use_gbpages)
 {
        unsigned long puds, pmds, ptes, tables, start = 0, good_end = end;
        phys_addr_t base;
@@ -55,6 +61,9 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
 #ifdef CONFIG_X86_32
                extra += PMD_SIZE;
 #endif
+               /* The first 2/4M doesn't use large pages. */
+               extra += mr->end - mr->start;
+
                ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT;
        } else
                ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT;
@@ -84,12 +93,6 @@ void __init native_pagetable_reserve(u64 start, u64 end)
        memblock_reserve(start, end - start);
 }
 
-struct map_range {
-       unsigned long start;
-       unsigned long end;
-       unsigned page_size_mask;
-};
-
 #ifdef CONFIG_X86_32
 #define NR_RANGE_MR 3
 #else /* CONFIG_X86_64 */
@@ -261,7 +264,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
         * nodes are discovered.
         */
        if (!after_bootmem)
-               find_early_table_space(end, use_pse, use_gbpages);
+               find_early_table_space(&mr[0], end, use_pse, use_gbpages);
 
        for (i = 0; i < nr_range; i++)
                ret = kernel_physical_mapping_init(mr[i].start, mr[i].end,
index fc18be0f6f29151de06c0a640e2a4e9a67d89ba4..2b6b4a3c8beb8727d27b1cdba22411fe0d271efb 100644 (file)
@@ -407,12 +407,12 @@ static unsigned long __meminit
 phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
              unsigned long page_size_mask, pgprot_t prot)
 {
-       unsigned long pages = 0;
+       unsigned long pages = 0, next;
        unsigned long last_map_addr = end;
 
        int i = pmd_index(address);
 
-       for (; i < PTRS_PER_PMD; i++, address += PMD_SIZE) {
+       for (; i < PTRS_PER_PMD; i++, address = next) {
                unsigned long pte_phys;
                pmd_t *pmd = pmd_page + pmd_index(address);
                pte_t *pte;
@@ -426,6 +426,8 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
                        break;
                }
 
+               next = (address & PMD_MASK) + PMD_SIZE;
+
                if (pmd_val(*pmd)) {
                        if (!pmd_large(*pmd)) {
                                spin_lock(&init_mm.page_table_lock);
@@ -449,7 +451,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
                         * attributes.
                         */
                        if (page_size_mask & (1 << PG_LEVEL_2M)) {
-                               pages++;
+                               last_map_addr = next;
                                continue;
                        }
                        new_prot = pte_pgprot(pte_clrhuge(*(pte_t *)pmd));
@@ -462,7 +464,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
                                pfn_pte(address >> PAGE_SHIFT,
                                        __pgprot(pgprot_val(prot) | _PAGE_PSE)));
                        spin_unlock(&init_mm.page_table_lock);
-                       last_map_addr = (address & PMD_MASK) + PMD_SIZE;
+                       last_map_addr = next;
                        continue;
                }
 
@@ -482,11 +484,11 @@ static unsigned long __meminit
 phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
                         unsigned long page_size_mask)
 {
-       unsigned long pages = 0;
+       unsigned long pages = 0, next;
        unsigned long last_map_addr = end;
        int i = pud_index(addr);
 
-       for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE) {
+       for (; i < PTRS_PER_PUD; i++, addr = next) {
                unsigned long pmd_phys;
                pud_t *pud = pud_page + pud_index(addr);
                pmd_t *pmd;
@@ -495,8 +497,9 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
                if (addr >= end)
                        break;
 
-               if (!after_bootmem &&
-                               !e820_any_mapped(addr, addr+PUD_SIZE, 0)) {
+               next = (addr & PUD_MASK) + PUD_SIZE;
+
+               if (!after_bootmem && !e820_any_mapped(addr, next, 0)) {
                        set_pud(pud, __pud(0));
                        continue;
                }
@@ -523,7 +526,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
                         * attributes.
                         */
                        if (page_size_mask & (1 << PG_LEVEL_1G)) {
-                               pages++;
+                               last_map_addr = next;
                                continue;
                        }
                        prot = pte_pgprot(pte_clrhuge(*(pte_t *)pud));
@@ -535,7 +538,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
                        set_pte((pte_t *)pud,
                                pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
                        spin_unlock(&init_mm.page_table_lock);
-                       last_map_addr = (addr & PUD_MASK) + PUD_SIZE;
+                       last_map_addr = next;
                        continue;
                }
 
index 3804471db1046ec17ea76be9ba04417fa650142c..5e57e113b72c1388bc89599a88a79cd237a67330 100644 (file)
@@ -61,11 +61,13 @@ static DEFINE_PER_CPU_READ_MOSTLY(int, tlb_vector_offset);
  */
 void leave_mm(int cpu)
 {
+       struct mm_struct *active_mm = this_cpu_read(cpu_tlbstate.active_mm);
        if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK)
                BUG();
-       cpumask_clear_cpu(cpu,
-                         mm_cpumask(this_cpu_read(cpu_tlbstate.active_mm)));
-       load_cr3(swapper_pg_dir);
+       if (cpumask_test_cpu(cpu, mm_cpumask(active_mm))) {
+               cpumask_clear_cpu(cpu, mm_cpumask(active_mm));
+               load_cr3(swapper_pg_dir);
+       }
 }
 EXPORT_SYMBOL_GPL(leave_mm);
 
index e76e18c94a3cd7933e5ca6c720b6e0b131cf2ca8..3af5a1e79c9ccc5ebe98c64b3af921562f397141 100644 (file)
@@ -11,6 +11,8 @@ obj-$(CONFIG_X86_INTEL_CE)      += ce4100.o
 obj-$(CONFIG_ACPI)             += acpi.o
 obj-y                          += legacy.o irq.o
 
+obj-$(CONFIG_STA2X11)           += sta2x11-fixup.o
+
 obj-$(CONFIG_X86_VISWS)                += visws.o
 
 obj-$(CONFIG_X86_NUMAQ)                += numaq_32.o
index d0e6e403b4f671d0ba3b9b1456fcc8d68c3ff24b..5dd467bd6121a3d01f86315746aa2039977fa420 100644 (file)
@@ -519,3 +519,20 @@ static void sb600_disable_hpet_bar(struct pci_dev *dev)
        }
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, 0x4385, sb600_disable_hpet_bar);
+
+/*
+ * Twinhead H12Y needs us to block out a region otherwise we map devices
+ * there and any access kills the box.
+ *
+ *   See: https://bugzilla.kernel.org/show_bug.cgi?id=10231
+ *
+ * Match off the LPC and svid/sdid (older kernels lose the bridge subvendor)
+ */
+static void __devinit twinhead_reserve_killing_zone(struct pci_dev *dev)
+{
+        if (dev->subsystem_vendor == 0x14FF && dev->subsystem_device == 0xA003) {
+                pr_info("Reserving memory on Twinhead H12Y\n");
+                request_mem_region(0xFFB00000, 0x100000, "twinhead");
+        }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x27B9, twinhead_reserve_killing_zone);
diff --git a/arch/x86/pci/sta2x11-fixup.c b/arch/x86/pci/sta2x11-fixup.c
new file mode 100644 (file)
index 0000000..9d8a509
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * arch/x86/pci/sta2x11-fixup.c
+ * glue code for lib/swiotlb.c and DMA translation between STA2x11
+ * AMBA memory mapping and the X86 memory mapping
+ *
+ * ST Microelectronics ConneXt (STA2X11/STA2X10)
+ *
+ * Copyright (c) 2010-2011 Wind River Systems, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/export.h>
+#include <linux/list.h>
+
+#define STA2X11_SWIOTLB_SIZE (4*1024*1024)
+extern int swiotlb_late_init_with_default_size(size_t default_size);
+
+/*
+ * We build a list of bus numbers that are under the ConneXt. The
+ * main bridge hosts 4 busses, which are the 4 endpoints, in order.
+ */
+#define STA2X11_NR_EP          4       /* 0..3 included */
+#define STA2X11_NR_FUNCS       8       /* 0..7 included */
+#define STA2X11_AMBA_SIZE      (512 << 20)
+
+struct sta2x11_ahb_regs { /* saved during suspend */
+       u32 base, pexlbase, pexhbase, crw;
+};
+
+struct sta2x11_mapping {
+       u32 amba_base;
+       int is_suspended;
+       struct sta2x11_ahb_regs regs[STA2X11_NR_FUNCS];
+};
+
+struct sta2x11_instance {
+       struct list_head list;
+       int bus0;
+       struct sta2x11_mapping map[STA2X11_NR_EP];
+};
+
+static LIST_HEAD(sta2x11_instance_list);
+
+/* At probe time, record new instances of this bridge (likely one only) */
+static void sta2x11_new_instance(struct pci_dev *pdev)
+{
+       struct sta2x11_instance *instance;
+
+       instance = kzalloc(sizeof(*instance), GFP_ATOMIC);
+       if (!instance)
+               return;
+       /* This has a subordinate bridge, with 4 more-subordinate ones */
+       instance->bus0 = pdev->subordinate->number + 1;
+
+       if (list_empty(&sta2x11_instance_list)) {
+               int size = STA2X11_SWIOTLB_SIZE;
+               /* First instance: register your own swiotlb area */
+               dev_info(&pdev->dev, "Using SWIOTLB (size %i)\n", size);
+               if (swiotlb_late_init_with_default_size(size))
+                       dev_emerg(&pdev->dev, "init swiotlb failed\n");
+       }
+       list_add(&instance->list, &sta2x11_instance_list);
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, 0xcc17, sta2x11_new_instance);
+
+/*
+ * Utility functions used in this file from below
+ */
+static struct sta2x11_instance *sta2x11_pdev_to_instance(struct pci_dev *pdev)
+{
+       struct sta2x11_instance *instance;
+       int ep;
+
+       list_for_each_entry(instance, &sta2x11_instance_list, list) {
+               ep = pdev->bus->number - instance->bus0;
+               if (ep >= 0 && ep < STA2X11_NR_EP)
+                       return instance;
+       }
+       return NULL;
+}
+
+static int sta2x11_pdev_to_ep(struct pci_dev *pdev)
+{
+       struct sta2x11_instance *instance;
+
+       instance = sta2x11_pdev_to_instance(pdev);
+       if (!instance)
+               return -1;
+
+       return pdev->bus->number - instance->bus0;
+}
+
+static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev)
+{
+       struct sta2x11_instance *instance;
+       int ep;
+
+       instance = sta2x11_pdev_to_instance(pdev);
+       if (!instance)
+               return NULL;
+       ep = sta2x11_pdev_to_ep(pdev);
+       return instance->map + ep;
+}
+
+/* This is exported, as some devices need to access the MFD registers */
+struct sta2x11_instance *sta2x11_get_instance(struct pci_dev *pdev)
+{
+       return sta2x11_pdev_to_instance(pdev);
+}
+EXPORT_SYMBOL(sta2x11_get_instance);
+
+
+/**
+ * p2a - Translate physical address to STA2x11 AMBA address,
+ *       used for DMA transfers to STA2x11
+ * @p: Physical address
+ * @pdev: PCI device (must be hosted within the connext)
+ */
+static dma_addr_t p2a(dma_addr_t p, struct pci_dev *pdev)
+{
+       struct sta2x11_mapping *map;
+       dma_addr_t a;
+
+       map = sta2x11_pdev_to_mapping(pdev);
+       a = p + map->amba_base;
+       return a;
+}
+
+/**
+ * a2p - Translate STA2x11 AMBA address to physical address
+ *       used for DMA transfers from STA2x11
+ * @a: STA2x11 AMBA address
+ * @pdev: PCI device (must be hosted within the connext)
+ */
+static dma_addr_t a2p(dma_addr_t a, struct pci_dev *pdev)
+{
+       struct sta2x11_mapping *map;
+       dma_addr_t p;
+
+       map = sta2x11_pdev_to_mapping(pdev);
+       p = a - map->amba_base;
+       return p;
+}
+
+/**
+ * sta2x11_swiotlb_alloc_coherent - Allocate swiotlb bounce buffers
+ *     returns virtual address. This is the only "special" function here.
+ * @dev: PCI device
+ * @size: Size of the buffer
+ * @dma_handle: DMA address
+ * @flags: memory flags
+ */
+static void *sta2x11_swiotlb_alloc_coherent(struct device *dev,
+                                           size_t size,
+                                           dma_addr_t *dma_handle,
+                                           gfp_t flags,
+                                           struct dma_attrs *attrs)
+{
+       void *vaddr;
+
+       vaddr = dma_generic_alloc_coherent(dev, size, dma_handle, flags, attrs);
+       if (!vaddr)
+               vaddr = swiotlb_alloc_coherent(dev, size, dma_handle, flags);
+       *dma_handle = p2a(*dma_handle, to_pci_dev(dev));
+       return vaddr;
+}
+
+/* We have our own dma_ops: the same as swiotlb but from alloc (above) */
+static struct dma_map_ops sta2x11_dma_ops = {
+       .alloc = sta2x11_swiotlb_alloc_coherent,
+       .free = swiotlb_free_coherent,
+       .map_page = swiotlb_map_page,
+       .unmap_page = swiotlb_unmap_page,
+       .map_sg = swiotlb_map_sg_attrs,
+       .unmap_sg = swiotlb_unmap_sg_attrs,
+       .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+       .sync_single_for_device = swiotlb_sync_single_for_device,
+       .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+       .sync_sg_for_device = swiotlb_sync_sg_for_device,
+       .mapping_error = swiotlb_dma_mapping_error,
+       .dma_supported = NULL, /* FIXME: we should use this instead! */
+};
+
+/* At setup time, we use our own ops if the device is a ConneXt one */
+static void sta2x11_setup_pdev(struct pci_dev *pdev)
+{
+       struct sta2x11_instance *instance = sta2x11_pdev_to_instance(pdev);
+
+       if (!instance) /* either a sta2x11 bridge or another ST device */
+               return;
+       pci_set_consistent_dma_mask(pdev, STA2X11_AMBA_SIZE - 1);
+       pci_set_dma_mask(pdev, STA2X11_AMBA_SIZE - 1);
+       pdev->dev.archdata.dma_ops = &sta2x11_dma_ops;
+
+       /* We must enable all devices as master, for audio DMA to work */
+       pci_set_master(pdev);
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_setup_pdev);
+
+/*
+ * The following three functions are exported (used in swiotlb: FIXME)
+ */
+/**
+ * dma_capable - Check if device can manage DMA transfers (FIXME: kill it)
+ * @dev: device for a PCI device
+ * @addr: DMA address
+ * @size: DMA size
+ */
+bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+{
+       struct sta2x11_mapping *map;
+
+       if (dev->archdata.dma_ops != &sta2x11_dma_ops) {
+               if (!dev->dma_mask)
+                       return false;
+               return addr + size - 1 <= *dev->dma_mask;
+       }
+
+       map = sta2x11_pdev_to_mapping(to_pci_dev(dev));
+
+       if (!map || (addr < map->amba_base))
+               return false;
+       if (addr + size >= map->amba_base + STA2X11_AMBA_SIZE) {
+               return false;
+       }
+
+       return true;
+}
+
+/**
+ * phys_to_dma - Return the DMA AMBA address used for this STA2x11 device
+ * @dev: device for a PCI device
+ * @paddr: Physical address
+ */
+dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+       if (dev->archdata.dma_ops != &sta2x11_dma_ops)
+               return paddr;
+       return p2a(paddr, to_pci_dev(dev));
+}
+
+/**
+ * dma_to_phys - Return the physical address used for this STA2x11 DMA address
+ * @dev: device for a PCI device
+ * @daddr: STA2x11 AMBA DMA address
+ */
+phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+       if (dev->archdata.dma_ops != &sta2x11_dma_ops)
+               return daddr;
+       return a2p(daddr, to_pci_dev(dev));
+}
+
+
+/*
+ * At boot we must set up the mappings for the pcie-to-amba bridge.
+ * It involves device access, and the same happens at suspend/resume time
+ */
+
+#define AHB_MAPB               0xCA4
+#define AHB_CRW(i)             (AHB_MAPB + 0  + (i) * 0x10)
+#define AHB_CRW_SZMASK                 0xfffffc00UL
+#define AHB_CRW_ENABLE                 (1 << 0)
+#define AHB_CRW_WTYPE_MEM              (2 << 1)
+#define AHB_CRW_ROE                    (1UL << 3)      /* Relax Order Ena */
+#define AHB_CRW_NSE                    (1UL << 4)      /* No Snoop Enable */
+#define AHB_BASE(i)            (AHB_MAPB + 4  + (i) * 0x10)
+#define AHB_PEXLBASE(i)                (AHB_MAPB + 8  + (i) * 0x10)
+#define AHB_PEXHBASE(i)                (AHB_MAPB + 12 + (i) * 0x10)
+
+/* At probe time, enable mapping for each endpoint, using the pdev */
+static void sta2x11_map_ep(struct pci_dev *pdev)
+{
+       struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
+       int i;
+
+       if (!map)
+               return;
+       pci_read_config_dword(pdev, AHB_BASE(0), &map->amba_base);
+
+       /* Configure AHB mapping */
+       pci_write_config_dword(pdev, AHB_PEXLBASE(0), 0);
+       pci_write_config_dword(pdev, AHB_PEXHBASE(0), 0);
+       pci_write_config_dword(pdev, AHB_CRW(0), STA2X11_AMBA_SIZE |
+                              AHB_CRW_WTYPE_MEM | AHB_CRW_ENABLE);
+
+       /* Disable all the other windows */
+       for (i = 1; i < STA2X11_NR_FUNCS; i++)
+               pci_write_config_dword(pdev, AHB_CRW(i), 0);
+
+       dev_info(&pdev->dev,
+                "sta2x11: Map EP %i: AMBA address %#8x-%#8x\n",
+                sta2x11_pdev_to_ep(pdev),  map->amba_base,
+                map->amba_base + STA2X11_AMBA_SIZE - 1);
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_map_ep);
+
+#ifdef CONFIG_PM /* Some register values must be saved and restored */
+
+static void suspend_mapping(struct pci_dev *pdev)
+{
+       struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
+       int i;
+
+       if (!map)
+               return;
+
+       if (map->is_suspended)
+               return;
+       map->is_suspended = 1;
+
+       /* Save all window configs */
+       for (i = 0; i < STA2X11_NR_FUNCS; i++) {
+               struct sta2x11_ahb_regs *regs = map->regs + i;
+
+               pci_read_config_dword(pdev, AHB_BASE(i), &regs->base);
+               pci_read_config_dword(pdev, AHB_PEXLBASE(i), &regs->pexlbase);
+               pci_read_config_dword(pdev, AHB_PEXHBASE(i), &regs->pexhbase);
+               pci_read_config_dword(pdev, AHB_CRW(i), &regs->crw);
+       }
+}
+DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, suspend_mapping);
+
+static void resume_mapping(struct pci_dev *pdev)
+{
+       struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
+       int i;
+
+       if (!map)
+               return;
+
+
+       if (!map->is_suspended)
+               goto out;
+       map->is_suspended = 0;
+
+       /* Restore all window configs */
+       for (i = 0; i < STA2X11_NR_FUNCS; i++) {
+               struct sta2x11_ahb_regs *regs = map->regs + i;
+
+               pci_write_config_dword(pdev, AHB_BASE(i), regs->base);
+               pci_write_config_dword(pdev, AHB_PEXLBASE(i), regs->pexlbase);
+               pci_write_config_dword(pdev, AHB_PEXHBASE(i), regs->pexhbase);
+               pci_write_config_dword(pdev, AHB_CRW(i), regs->crw);
+       }
+out:
+       pci_set_master(pdev); /* Like at boot, enable master on all devices */
+}
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, resume_mapping);
+
+#endif /* CONFIG_PM */
index 1d4c783d732517751efdd9de28977da44822a96e..04b8c73659c528f6f8d6b049b6a10a1ada3f3d20 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
+#include <linux/pm_wakeup.h>
 #include <linux/mfd/core.h>
 #include <linux/power_supply.h>
 #include <linux/suspend.h>
@@ -83,8 +84,12 @@ static void send_ebook_state(void)
                return;
        }
 
+       if (!!test_bit(SW_TABLET_MODE, ebook_switch_idev->sw) == state)
+               return; /* Nothing new to report. */
+
        input_report_switch(ebook_switch_idev, SW_TABLET_MODE, state);
        input_sync(ebook_switch_idev);
+       pm_wakeup_event(&ebook_switch_idev->dev, 0);
 }
 
 static void flip_lid_inverter(void)
@@ -123,8 +128,12 @@ static void detect_lid_state(void)
 /* Report current lid switch state through input layer */
 static void send_lid_state(void)
 {
+       if (!!test_bit(SW_LID, lid_switch_idev->sw) == !lid_open)
+               return; /* Nothing new to report. */
+
        input_report_switch(lid_switch_idev, SW_LID, !lid_open);
        input_sync(lid_switch_idev);
+       pm_wakeup_event(&lid_switch_idev->dev, 0);
 }
 
 static ssize_t lid_wake_mode_show(struct device *dev,
@@ -213,11 +222,30 @@ static irqreturn_t xo1_sci_intr(int irq, void *dev_id)
 
        dev_dbg(&pdev->dev, "sts %x gpe %x\n", sts, gpe);
 
-       if (sts & CS5536_PWRBTN_FLAG && !(sts & CS5536_WAK_FLAG)) {
-               input_report_key(power_button_idev, KEY_POWER, 1);
-               input_sync(power_button_idev);
-               input_report_key(power_button_idev, KEY_POWER, 0);
-               input_sync(power_button_idev);
+       if (sts & CS5536_PWRBTN_FLAG) {
+               if (!(sts & CS5536_WAK_FLAG)) {
+                       /* Only report power button input when it was pressed
+                        * during regular operation (as opposed to when it
+                        * was used to wake the system). */
+                       input_report_key(power_button_idev, KEY_POWER, 1);
+                       input_sync(power_button_idev);
+                       input_report_key(power_button_idev, KEY_POWER, 0);
+                       input_sync(power_button_idev);
+               }
+               /* Report the wakeup event in all cases. */
+               pm_wakeup_event(&power_button_idev->dev, 0);
+       }
+
+       if ((sts & (CS5536_RTC_FLAG | CS5536_WAK_FLAG)) ==
+                       (CS5536_RTC_FLAG | CS5536_WAK_FLAG)) {
+               /* When the system is woken by the RTC alarm, report the
+                * event on the rtc device. */
+               struct device *rtc = bus_find_device_by_name(
+                       &platform_bus_type, NULL, "rtc_cmos");
+               if (rtc) {
+                       pm_wakeup_event(rtc, 0);
+                       put_device(rtc);
+               }
        }
 
        if (gpe & CS5536_GPIOM7_PME_FLAG) { /* EC GPIO */
@@ -310,9 +338,10 @@ static int __devinit setup_sci_interrupt(struct platform_device *pdev)
                outb(lo, CS5536_PIC_INT_SEL2);
        }
 
-       /* Enable SCI from power button, and clear pending interrupts */
+       /* Enable interesting SCI events, and clear pending interrupts */
        sts = inl(acpi_base + CS5536_PM1_STS);
-       outl((CS5536_PM_PWRBTN << 16) | 0xffff, acpi_base + CS5536_PM1_STS);
+       outl(((CS5536_PM_PWRBTN | CS5536_PM_RTC) << 16) | 0xffff,
+            acpi_base + CS5536_PM1_STS);
 
        r = request_irq(sci_irq, xo1_sci_intr, 0, DRV_NAME, pdev);
        if (r)
index f3b0633b69a110b96a6de06060744f1535cdf781..0e07adc8cbe41b58b43d5d50ba20daf250294579 100644 (file)
 #define ELF_ARCH        EM_386
 
 #define ELF_PLAT_INIT(regs, load_addr) do { \
-       PT_REGS_EBX(regs) = 0; \
-       PT_REGS_ECX(regs) = 0; \
-       PT_REGS_EDX(regs) = 0; \
-       PT_REGS_ESI(regs) = 0; \
-       PT_REGS_EDI(regs) = 0; \
-       PT_REGS_EBP(regs) = 0; \
-       PT_REGS_EAX(regs) = 0; \
+       PT_REGS_BX(regs) = 0; \
+       PT_REGS_CX(regs) = 0; \
+       PT_REGS_DX(regs) = 0; \
+       PT_REGS_SI(regs) = 0; \
+       PT_REGS_DI(regs) = 0; \
+       PT_REGS_BP(regs) = 0; \
+       PT_REGS_AX(regs) = 0; \
 } while (0)
 
 /* Shamelessly stolen from include/asm-i386/elf.h */
 
 #define ELF_CORE_COPY_REGS(pr_reg, regs) do {  \
-       pr_reg[0] = PT_REGS_EBX(regs);          \
-       pr_reg[1] = PT_REGS_ECX(regs);          \
-       pr_reg[2] = PT_REGS_EDX(regs);          \
-       pr_reg[3] = PT_REGS_ESI(regs);          \
-       pr_reg[4] = PT_REGS_EDI(regs);          \
-       pr_reg[5] = PT_REGS_EBP(regs);          \
-       pr_reg[6] = PT_REGS_EAX(regs);          \
+       pr_reg[0] = PT_REGS_BX(regs);           \
+       pr_reg[1] = PT_REGS_CX(regs);           \
+       pr_reg[2] = PT_REGS_DX(regs);           \
+       pr_reg[3] = PT_REGS_SI(regs);           \
+       pr_reg[4] = PT_REGS_DI(regs);           \
+       pr_reg[5] = PT_REGS_BP(regs);           \
+       pr_reg[6] = PT_REGS_AX(regs);           \
        pr_reg[7] = PT_REGS_DS(regs);           \
        pr_reg[8] = PT_REGS_ES(regs);           \
        /* fake once used fs and gs selectors? */       \
@@ -130,13 +130,13 @@ do {                                                              \
 #define ELF_ARCH        EM_X86_64
 
 #define ELF_PLAT_INIT(regs, load_addr)    do { \
-       PT_REGS_RBX(regs) = 0; \
-       PT_REGS_RCX(regs) = 0; \
-       PT_REGS_RDX(regs) = 0; \
-       PT_REGS_RSI(regs) = 0; \
-       PT_REGS_RDI(regs) = 0; \
-       PT_REGS_RBP(regs) = 0; \
-       PT_REGS_RAX(regs) = 0; \
+       PT_REGS_BX(regs) = 0; \
+       PT_REGS_CX(regs) = 0; \
+       PT_REGS_DX(regs) = 0; \
+       PT_REGS_SI(regs) = 0; \
+       PT_REGS_DI(regs) = 0; \
+       PT_REGS_BP(regs) = 0; \
+       PT_REGS_AX(regs) = 0; \
        PT_REGS_R8(regs) = 0; \
        PT_REGS_R9(regs) = 0; \
        PT_REGS_R10(regs) = 0; \
index c8aca8c501b0e4d2c106d77ca0e676192a435aaa..950dfb7b84173aed904594624f9c33bda6380ebf 100644 (file)
@@ -1,5 +1,39 @@
+#ifndef __UM_X86_PTRACE_H
+#define __UM_X86_PTRACE_H
+
 #ifdef CONFIG_X86_32
 # include "ptrace_32.h"
 #else
 # include "ptrace_64.h"
 #endif
+
+#define PT_REGS_AX(r) UPT_AX(&(r)->regs)
+#define PT_REGS_BX(r) UPT_BX(&(r)->regs)
+#define PT_REGS_CX(r) UPT_CX(&(r)->regs)
+#define PT_REGS_DX(r) UPT_DX(&(r)->regs)
+
+#define PT_REGS_SI(r) UPT_SI(&(r)->regs)
+#define PT_REGS_DI(r) UPT_DI(&(r)->regs)
+#define PT_REGS_BP(r) UPT_BP(&(r)->regs)
+#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
+
+#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
+#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
+#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
+#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
+
+#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_AX(r)
+#define PT_REGS_SYSCALL_RET(r) PT_REGS_AX(r)
+
+#define PT_FIX_EXEC_STACK(sp) do ; while(0)
+
+#define profile_pc(regs) PT_REGS_IP(regs)
+
+#define UPT_RESTART_SYSCALL(r) (UPT_IP(r) -= 2)
+#define UPT_SET_SYSCALL_RETURN(r, res) (UPT_AX(r) = (res))
+
+static inline long regs_return_value(struct uml_pt_regs *regs)
+{
+       return UPT_AX(regs);
+}
+#endif /* __UM_X86_PTRACE_H */
index 5d2a59112537b17fff28cb627747f5d33f48abb0..2cf225351b655df2259be924d54fc7f06632d5ac 100644 (file)
 #include "linux/compiler.h"
 #include "asm/ptrace-generic.h"
 
-#define PT_REGS_EAX(r) UPT_EAX(&(r)->regs)
-#define PT_REGS_EBX(r) UPT_EBX(&(r)->regs)
-#define PT_REGS_ECX(r) UPT_ECX(&(r)->regs)
-#define PT_REGS_EDX(r) UPT_EDX(&(r)->regs)
-#define PT_REGS_ESI(r) UPT_ESI(&(r)->regs)
-#define PT_REGS_EDI(r) UPT_EDI(&(r)->regs)
-#define PT_REGS_EBP(r) UPT_EBP(&(r)->regs)
-
-#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
-#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
-#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
-#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
-#define PT_REGS_FS(r) UPT_FS(&(r)->regs)
-#define PT_REGS_GS(r) UPT_GS(&(r)->regs)
-
-#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
-
-#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_EAX(r)
-#define PT_REGS_SYSCALL_RET(r) PT_REGS_EAX(r)
-#define PT_FIX_EXEC_STACK(sp) do ; while(0)
-
-#define profile_pc(regs) PT_REGS_IP(regs)
-
 #define user_mode(r) UPT_IS_USER(&(r)->regs)
 
 /*
index 706a0d80545c7c01d7c71dafa4c6765e0ad6dbb1..ea7bff39432029a1b030ce58ee4857ff2be06d83 100644 (file)
 
 #define HOST_AUDIT_ARCH AUDIT_ARCH_X86_64
 
-#define PT_REGS_RBX(r) UPT_RBX(&(r)->regs)
-#define PT_REGS_RCX(r) UPT_RCX(&(r)->regs)
-#define PT_REGS_RDX(r) UPT_RDX(&(r)->regs)
-#define PT_REGS_RSI(r) UPT_RSI(&(r)->regs)
-#define PT_REGS_RDI(r) UPT_RDI(&(r)->regs)
-#define PT_REGS_RBP(r) UPT_RBP(&(r)->regs)
-#define PT_REGS_RAX(r) UPT_RAX(&(r)->regs)
 #define PT_REGS_R8(r) UPT_R8(&(r)->regs)
 #define PT_REGS_R9(r) UPT_R9(&(r)->regs)
 #define PT_REGS_R10(r) UPT_R10(&(r)->regs)
 #define PT_REGS_R14(r) UPT_R14(&(r)->regs)
 #define PT_REGS_R15(r) UPT_R15(&(r)->regs)
 
-#define PT_REGS_FS(r) UPT_FS(&(r)->regs)
-#define PT_REGS_GS(r) UPT_GS(&(r)->regs)
-#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
-#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
-#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
-#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
-
-#define PT_REGS_ORIG_RAX(r) UPT_ORIG_RAX(&(r)->regs)
-#define PT_REGS_RIP(r) UPT_IP(&(r)->regs)
-#define PT_REGS_SP(r) UPT_SP(&(r)->regs)
-
-#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
-
 /* XXX */
 #define user_mode(r) UPT_IS_USER(&(r)->regs)
-#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_RAX(r)
-#define PT_REGS_SYSCALL_RET(r) PT_REGS_RAX(r)
-
-#define PT_FIX_EXEC_STACK(sp) do ; while(0)
-
-#define profile_pc(regs) PT_REGS_IP(regs)
 
 struct user_desc;
 
index f058d2f82e189b0bea284da767766ed1ba20a781..8d0c420465cce0cf897278e03f25904a51cd92ff 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 #include <asm/errno.h>
+#include <asm/asm.h>
                                
 /*
  * computes a partial checksum, e.g. for TCP/UDP fragments
@@ -232,15 +233,11 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,
 
 #define SRC(y...)                      \
        9999: y;                        \
-       .section __ex_table, "a";       \
-       .long 9999b, 6001f      ;       \
-       .previous
+       _ASM_EXTABLE(9999b, 6001f)
 
 #define DST(y...)                      \
        9999: y;                        \
-       .section __ex_table, "a";       \
-       .long 9999b, 6002f      ;       \
-       .previous
+       _ASM_EXTABLE(9999b, 6002f)
 
 .align 4
 
index 2bbe1ec2d96ab1a4d8ae8ab540eae7f9360c2db4..6ce2d76eb9083daf283998775465b0b18cbb9c2f 100644 (file)
@@ -1,15 +1,74 @@
 #ifndef __SYSDEP_X86_PTRACE_H
 #define __SYSDEP_X86_PTRACE_H
 
+#include <generated/user_constants.h>
+#include "sysdep/faultinfo.h"
+
+#define MAX_REG_OFFSET (UM_FRAME_SIZE)
+#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long))
+
+#define REGS_IP(r) ((r)[HOST_IP])
+#define REGS_SP(r) ((r)[HOST_SP])
+#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
+#define REGS_AX(r) ((r)[HOST_AX])
+#define REGS_BX(r) ((r)[HOST_BX])
+#define REGS_CX(r) ((r)[HOST_CX])
+#define REGS_DX(r) ((r)[HOST_DX])
+#define REGS_SI(r) ((r)[HOST_SI])
+#define REGS_DI(r) ((r)[HOST_DI])
+#define REGS_BP(r) ((r)[HOST_BP])
+#define REGS_CS(r) ((r)[HOST_CS])
+#define REGS_SS(r) ((r)[HOST_SS])
+#define REGS_DS(r) ((r)[HOST_DS])
+#define REGS_ES(r) ((r)[HOST_ES])
+
+#define UPT_IP(r) REGS_IP((r)->gp)
+#define UPT_SP(r) REGS_SP((r)->gp)
+#define UPT_EFLAGS(r) REGS_EFLAGS((r)->gp)
+#define UPT_AX(r) REGS_AX((r)->gp)
+#define UPT_BX(r) REGS_BX((r)->gp)
+#define UPT_CX(r) REGS_CX((r)->gp)
+#define UPT_DX(r) REGS_DX((r)->gp)
+#define UPT_SI(r) REGS_SI((r)->gp)
+#define UPT_DI(r) REGS_DI((r)->gp)
+#define UPT_BP(r) REGS_BP((r)->gp)
+#define UPT_CS(r) REGS_CS((r)->gp)
+#define UPT_SS(r) REGS_SS((r)->gp)
+#define UPT_DS(r) REGS_DS((r)->gp)
+#define UPT_ES(r) REGS_ES((r)->gp)
+
 #ifdef __i386__
 #include "ptrace_32.h"
 #else
 #include "ptrace_64.h"
 #endif
 
-static inline long regs_return_value(struct uml_pt_regs *regs)
-{
-       return UPT_SYSCALL_RET(regs);
-}
+struct syscall_args {
+       unsigned long args[6];
+};
+
+#define SYSCALL_ARGS(r) ((struct syscall_args) \
+                        { .args = { UPT_SYSCALL_ARG1(r),        \
+                                    UPT_SYSCALL_ARG2(r),        \
+                                    UPT_SYSCALL_ARG3(r),        \
+                                    UPT_SYSCALL_ARG4(r),        \
+                                    UPT_SYSCALL_ARG5(r),        \
+                                    UPT_SYSCALL_ARG6(r) } } )
+
+struct uml_pt_regs {
+       unsigned long gp[MAX_REG_NR];
+       unsigned long fp[MAX_FP_NR];
+       struct faultinfo faultinfo;
+       long syscall;
+       int is_user;
+};
+
+#define EMPTY_UML_PT_REGS { }
+
+#define UPT_SYSCALL_NR(r) ((r)->syscall)
+#define UPT_FAULTINFO(r) (&(r)->faultinfo)
+#define UPT_IS_USER(r) ((r)->is_user)
+
+extern int user_context(unsigned long sp);
 
 #endif /* __SYSDEP_X86_PTRACE_H */
index befd1df32ed0ac65fe8ab829355d71191666e393..b94a108de1dc894e77c9e49310e4d0a12d177ce8 100644 (file)
@@ -6,11 +6,7 @@
 #ifndef __SYSDEP_I386_PTRACE_H
 #define __SYSDEP_I386_PTRACE_H
 
-#include <generated/user_constants.h>
-#include "sysdep/faultinfo.h"
-
-#define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long))
-#define MAX_REG_OFFSET (UM_FRAME_SIZE)
+#define MAX_FP_NR HOST_FPX_SIZE
 
 static inline void update_debugregs(int seq) {}
 
@@ -24,90 +20,16 @@ void set_using_sysemu(int value);
 int get_using_sysemu(void);
 extern int sysemu_supported;
 
-#define REGS_IP(r) ((r)[HOST_IP])
-#define REGS_SP(r) ((r)[HOST_SP])
-#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
-#define REGS_EAX(r) ((r)[HOST_AX])
-#define REGS_EBX(r) ((r)[HOST_BX])
-#define REGS_ECX(r) ((r)[HOST_CX])
-#define REGS_EDX(r) ((r)[HOST_DX])
-#define REGS_ESI(r) ((r)[HOST_SI])
-#define REGS_EDI(r) ((r)[HOST_DI])
-#define REGS_EBP(r) ((r)[HOST_BP])
-#define REGS_CS(r) ((r)[HOST_CS])
-#define REGS_SS(r) ((r)[HOST_SS])
-#define REGS_DS(r) ((r)[HOST_DS])
-#define REGS_ES(r) ((r)[HOST_ES])
-#define REGS_FS(r) ((r)[HOST_FS])
-#define REGS_GS(r) ((r)[HOST_GS])
-
-#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res)
-
-#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
-#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
-
 #ifndef PTRACE_SYSEMU_SINGLESTEP
 #define PTRACE_SYSEMU_SINGLESTEP 32
 #endif
 
-struct uml_pt_regs {
-       unsigned long gp[MAX_REG_NR];
-       unsigned long fp[HOST_FPX_SIZE];
-       struct faultinfo faultinfo;
-       long syscall;
-       int is_user;
-};
-
-#define EMPTY_UML_PT_REGS { }
-
-#define UPT_IP(r) REGS_IP((r)->gp)
-#define UPT_SP(r) REGS_SP((r)->gp)
-#define UPT_EFLAGS(r) REGS_EFLAGS((r)->gp)
-#define UPT_EAX(r) REGS_EAX((r)->gp)
-#define UPT_EBX(r) REGS_EBX((r)->gp)
-#define UPT_ECX(r) REGS_ECX((r)->gp)
-#define UPT_EDX(r) REGS_EDX((r)->gp)
-#define UPT_ESI(r) REGS_ESI((r)->gp)
-#define UPT_EDI(r) REGS_EDI((r)->gp)
-#define UPT_EBP(r) REGS_EBP((r)->gp)
-#define UPT_ORIG_EAX(r) ((r)->syscall)
-#define UPT_CS(r) REGS_CS((r)->gp)
-#define UPT_SS(r) REGS_SS((r)->gp)
-#define UPT_DS(r) REGS_DS((r)->gp)
-#define UPT_ES(r) REGS_ES((r)->gp)
-#define UPT_FS(r) REGS_FS((r)->gp)
-#define UPT_GS(r) REGS_GS((r)->gp)
-
-#define UPT_SYSCALL_ARG1(r) UPT_EBX(r)
-#define UPT_SYSCALL_ARG2(r) UPT_ECX(r)
-#define UPT_SYSCALL_ARG3(r) UPT_EDX(r)
-#define UPT_SYSCALL_ARG4(r) UPT_ESI(r)
-#define UPT_SYSCALL_ARG5(r) UPT_EDI(r)
-#define UPT_SYSCALL_ARG6(r) UPT_EBP(r)
-
-extern int user_context(unsigned long sp);
-
-#define UPT_IS_USER(r) ((r)->is_user)
-
-struct syscall_args {
-       unsigned long args[6];
-};
-
-#define SYSCALL_ARGS(r) ((struct syscall_args) \
-                        { .args = { UPT_SYSCALL_ARG1(r),       \
-                                    UPT_SYSCALL_ARG2(r),       \
-                                    UPT_SYSCALL_ARG3(r),       \
-                                    UPT_SYSCALL_ARG4(r),       \
-                                    UPT_SYSCALL_ARG5(r),       \
-                                    UPT_SYSCALL_ARG6(r) } } )
-
-#define UPT_RESTART_SYSCALL(r) REGS_RESTART_SYSCALL((r)->gp)
-
-#define UPT_ORIG_SYSCALL(r) UPT_EAX(r)
-#define UPT_SYSCALL_NR(r) UPT_ORIG_EAX(r)
-#define UPT_SYSCALL_RET(r) UPT_EAX(r)
-
-#define UPT_FAULTINFO(r) (&(r)->faultinfo)
+#define UPT_SYSCALL_ARG1(r) UPT_BX(r)
+#define UPT_SYSCALL_ARG2(r) UPT_CX(r)
+#define UPT_SYSCALL_ARG3(r) UPT_DX(r)
+#define UPT_SYSCALL_ARG4(r) UPT_SI(r)
+#define UPT_SYSCALL_ARG5(r) UPT_DI(r)
+#define UPT_SYSCALL_ARG6(r) UPT_BP(r)
 
 extern void arch_init_registers(int pid);
 
index 031edc53ac5704e9871065df305a79a4ac77c65d..919789f1071e472cc41eadbfb8c1a217a1badbb0 100644 (file)
@@ -8,22 +8,8 @@
 #ifndef __SYSDEP_X86_64_PTRACE_H
 #define __SYSDEP_X86_64_PTRACE_H
 
-#include <generated/user_constants.h>
-#include "sysdep/faultinfo.h"
+#define MAX_FP_NR HOST_FP_SIZE
 
-#define MAX_REG_OFFSET (UM_FRAME_SIZE)
-#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long))
-
-#define REGS_IP(r) ((r)[HOST_IP])
-#define REGS_SP(r) ((r)[HOST_SP])
-
-#define REGS_RBX(r) ((r)[HOST_BX])
-#define REGS_RCX(r) ((r)[HOST_CX])
-#define REGS_RDX(r) ((r)[HOST_DX])
-#define REGS_RSI(r) ((r)[HOST_SI])
-#define REGS_RDI(r) ((r)[HOST_DI])
-#define REGS_RBP(r) ((r)[HOST_BP])
-#define REGS_RAX(r) ((r)[HOST_AX])
 #define REGS_R8(r) ((r)[HOST_R8])
 #define REGS_R9(r) ((r)[HOST_R9])
 #define REGS_R10(r) ((r)[HOST_R10])
@@ -32,9 +18,6 @@
 #define REGS_R13(r) ((r)[HOST_R13])
 #define REGS_R14(r) ((r)[HOST_R14])
 #define REGS_R15(r) ((r)[HOST_R15])
-#define REGS_CS(r) ((r)[HOST_CS])
-#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
-#define REGS_SS(r) ((r)[HOST_SS])
 
 #define HOST_FS_BASE 21
 #define HOST_GS_BASE 22
 #define GS (HOST_GS * sizeof(long))
 #endif
 
-#define REGS_FS_BASE(r) ((r)[HOST_FS_BASE])
-#define REGS_GS_BASE(r) ((r)[HOST_GS_BASE])
-#define REGS_DS(r) ((r)[HOST_DS])
-#define REGS_ES(r) ((r)[HOST_ES])
-#define REGS_FS(r) ((r)[HOST_FS])
-#define REGS_GS(r) ((r)[HOST_GS])
-
-#define REGS_ORIG_RAX(r) ((r)[HOST_ORIG_AX])
-
-#define REGS_SET_SYSCALL_RETURN(r, res) REGS_RAX(r) = (res)
-
-#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
-#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
-
-#define REGS_FAULT_ADDR(r) ((r)->fault_addr)
-
-#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type)
-
-#define REGS_TRAP(r) ((r)->trap_type)
-
-#define REGS_ERR(r) ((r)->fault_type)
-
-struct uml_pt_regs {
-       unsigned long gp[MAX_REG_NR];
-       unsigned long fp[HOST_FP_SIZE];
-       struct faultinfo faultinfo;
-       long syscall;
-       int is_user;
-};
-
-#define EMPTY_UML_PT_REGS { }
-
-#define UPT_RBX(r) REGS_RBX((r)->gp)
-#define UPT_RCX(r) REGS_RCX((r)->gp)
-#define UPT_RDX(r) REGS_RDX((r)->gp)
-#define UPT_RSI(r) REGS_RSI((r)->gp)
-#define UPT_RDI(r) REGS_RDI((r)->gp)
-#define UPT_RBP(r) REGS_RBP((r)->gp)
-#define UPT_RAX(r) REGS_RAX((r)->gp)
 #define UPT_R8(r) REGS_R8((r)->gp)
 #define UPT_R9(r) REGS_R9((r)->gp)
 #define UPT_R10(r) REGS_R10((r)->gp)
@@ -105,51 +49,14 @@ struct uml_pt_regs {
 #define UPT_R13(r) REGS_R13((r)->gp)
 #define UPT_R14(r) REGS_R14((r)->gp)
 #define UPT_R15(r) REGS_R15((r)->gp)
-#define UPT_CS(r) REGS_CS((r)->gp)
-#define UPT_FS_BASE(r) REGS_FS_BASE((r)->gp)
-#define UPT_FS(r) REGS_FS((r)->gp)
-#define UPT_GS_BASE(r) REGS_GS_BASE((r)->gp)
-#define UPT_GS(r) REGS_GS((r)->gp)
-#define UPT_DS(r) REGS_DS((r)->gp)
-#define UPT_ES(r) REGS_ES((r)->gp)
-#define UPT_CS(r) REGS_CS((r)->gp)
-#define UPT_SS(r) REGS_SS((r)->gp)
-#define UPT_ORIG_RAX(r) REGS_ORIG_RAX((r)->gp)
-
-#define UPT_IP(r) REGS_IP((r)->gp)
-#define UPT_SP(r) REGS_SP((r)->gp)
-
-#define UPT_EFLAGS(r) REGS_EFLAGS((r)->gp)
-#define UPT_SYSCALL_NR(r) ((r)->syscall)
-#define UPT_SYSCALL_RET(r) UPT_RAX(r)
-
-extern int user_context(unsigned long sp);
 
-#define UPT_IS_USER(r) ((r)->is_user)
-
-#define UPT_SYSCALL_ARG1(r) UPT_RDI(r)
-#define UPT_SYSCALL_ARG2(r) UPT_RSI(r)
-#define UPT_SYSCALL_ARG3(r) UPT_RDX(r)
+#define UPT_SYSCALL_ARG1(r) UPT_DI(r)
+#define UPT_SYSCALL_ARG2(r) UPT_SI(r)
+#define UPT_SYSCALL_ARG3(r) UPT_DX(r)
 #define UPT_SYSCALL_ARG4(r) UPT_R10(r)
 #define UPT_SYSCALL_ARG5(r) UPT_R8(r)
 #define UPT_SYSCALL_ARG6(r) UPT_R9(r)
 
-struct syscall_args {
-       unsigned long args[6];
-};
-
-#define SYSCALL_ARGS(r) ((struct syscall_args) \
-                        { .args = { UPT_SYSCALL_ARG1(r),        \
-                                    UPT_SYSCALL_ARG2(r),        \
-                                    UPT_SYSCALL_ARG3(r),        \
-                                    UPT_SYSCALL_ARG4(r),        \
-                                    UPT_SYSCALL_ARG5(r),        \
-                                    UPT_SYSCALL_ARG6(r) } } )
-
-#define UPT_RESTART_SYSCALL(r) REGS_RESTART_SYSCALL((r)->gp)
-
-#define UPT_FAULTINFO(r) (&(r)->faultinfo)
-
 static inline void arch_init_registers(int pid)
 {
 }
index 4883b9546016e90cb1643c763e3c5ba9ce8b4188..bb0fb03b9f85f268912e7b6851f74787c8ee8e4a 100644 (file)
@@ -156,6 +156,9 @@ static int copy_sc_from_user(struct pt_regs *regs,
        struct sigcontext sc;
        int err, pid;
 
+       /* Always make any pending restarted system calls return -EINTR */
+       current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
        err = copy_from_user(&sc, from, sizeof(sc));
        if (err)
                return err;
@@ -410,9 +413,9 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
 
        PT_REGS_SP(regs) = (unsigned long) frame;
        PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
-       PT_REGS_EAX(regs) = (unsigned long) sig;
-       PT_REGS_EDX(regs) = (unsigned long) 0;
-       PT_REGS_ECX(regs) = (unsigned long) 0;
+       PT_REGS_AX(regs) = (unsigned long) sig;
+       PT_REGS_DX(regs) = (unsigned long) 0;
+       PT_REGS_CX(regs) = (unsigned long) 0;
 
        if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
                ptrace_notify(SIGTRAP);
@@ -460,9 +463,9 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
 
        PT_REGS_SP(regs) = (unsigned long) frame;
        PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
-       PT_REGS_EAX(regs) = (unsigned long) sig;
-       PT_REGS_EDX(regs) = (unsigned long) &frame->info;
-       PT_REGS_ECX(regs) = (unsigned long) &frame->uc;
+       PT_REGS_AX(regs) = (unsigned long) sig;
+       PT_REGS_DX(regs) = (unsigned long) &frame->info;
+       PT_REGS_CX(regs) = (unsigned long) &frame->uc;
 
        if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
                ptrace_notify(SIGTRAP);
@@ -541,8 +544,8 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
                               set->sig[0]);
        err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate);
        if (sizeof(*set) == 16) {
-               __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
-               __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
+               err |= __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
+               err |= __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
        }
        else
                err |= __copy_to_user(&frame->uc.uc_sigmask, set,
@@ -570,17 +573,17 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
        }
 
        PT_REGS_SP(regs) = (unsigned long) frame;
-       PT_REGS_RDI(regs) = sig;
+       PT_REGS_DI(regs) = sig;
        /* In case the signal handler was declared without prototypes */
-       PT_REGS_RAX(regs) = 0;
+       PT_REGS_AX(regs) = 0;
 
        /*
         * This also works for non SA_SIGINFO handlers because they expect the
         * next argument after the signal number on the stack.
         */
-       PT_REGS_RSI(regs) = (unsigned long) &frame->info;
-       PT_REGS_RDX(regs) = (unsigned long) &frame->uc;
-       PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler;
+       PT_REGS_SI(regs) = (unsigned long) &frame->info;
+       PT_REGS_DX(regs) = (unsigned long) &frame->uc;
+       PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
  out:
        return err;
 }
index 9924776f42650476eac999666fcc29b09ccb9a28..170bd926a69cd4eddbd64d03f0da41d719879bd0 100644 (file)
@@ -31,7 +31,6 @@
 #define stub_fork sys_fork
 #define stub_vfork sys_vfork
 #define stub_execve sys_execve
-#define stub_rt_sigsuspend sys_rt_sigsuspend
 #define stub_sigaltstack sys_sigaltstack
 #define stub_rt_sigreturn sys_rt_sigreturn
 
index 70ca357393b86fb747895d1a11110324ccd1a4cf..b853e8600b9dc1d00e74151a7e16b8af61a8bfda 100644 (file)
@@ -44,10 +44,10 @@ long sys_sigaction(int sig, const struct old_sigaction __user *act,
                old_sigset_t mask;
                if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
                    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
-                   __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+                   __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+                   __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+                   __get_user(mask, &act->sa_mask))
                        return -EFAULT;
-               __get_user(new_ka.sa.sa_flags, &act->sa_flags);
-               __get_user(mask, &act->sa_mask);
                siginitset(&new_ka.sa.sa_mask, mask);
        }
 
@@ -56,10 +56,10 @@ long sys_sigaction(int sig, const struct old_sigaction __user *act,
        if (!ret && oact) {
                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
                    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
-                   __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+                   __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+                   __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+                   __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
                        return -EFAULT;
-               __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
-               __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
        }
 
        return ret;
index 171b3e9dc86777e54cb8a06a43a29e55bb810688..2d5cc51e9bef7c312c7e3837d07e3cde5180d4a0 100644 (file)
@@ -23,12 +23,10 @@ void show_regs(struct pt_regs *regs)
         printk(" EFLAGS: %08lx\n    %s\n", PT_REGS_EFLAGS(regs),
               print_tainted());
         printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
-                PT_REGS_EAX(regs), PT_REGS_EBX(regs), 
-              PT_REGS_ECX(regs), 
-              PT_REGS_EDX(regs));
+               PT_REGS_AX(regs), PT_REGS_BX(regs), 
+              PT_REGS_CX(regs), PT_REGS_DX(regs));
         printk("ESI: %08lx EDI: %08lx EBP: %08lx",
-              PT_REGS_ESI(regs), PT_REGS_EDI(regs), 
-              PT_REGS_EBP(regs));
+              PT_REGS_SI(regs), PT_REGS_DI(regs), PT_REGS_BP(regs));
         printk(" DS: %04lx ES: %04lx\n",
               0xffff & PT_REGS_DS(regs), 
               0xffff & PT_REGS_ES(regs));
index e8913436d7dc4d82dfec31f8566b2bebd37b11db..08258f17996926de8db8943c4fc1fdccbce38efa 100644 (file)
@@ -19,15 +19,15 @@ void __show_regs(struct pt_regs *regs)
        printk(KERN_INFO "Pid: %d, comm: %.20s %s %s\n", task_pid_nr(current),
                current->comm, print_tainted(), init_utsname()->release);
        printk(KERN_INFO "RIP: %04lx:[<%016lx>]\n", PT_REGS_CS(regs) & 0xffff,
-              PT_REGS_RIP(regs));
+              PT_REGS_IP(regs));
        printk(KERN_INFO "RSP: %016lx  EFLAGS: %08lx\n", PT_REGS_SP(regs),
               PT_REGS_EFLAGS(regs));
        printk(KERN_INFO "RAX: %016lx RBX: %016lx RCX: %016lx\n",
-              PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs));
+              PT_REGS_AX(regs), PT_REGS_BX(regs), PT_REGS_CX(regs));
        printk(KERN_INFO "RDX: %016lx RSI: %016lx RDI: %016lx\n",
-              PT_REGS_RDX(regs), PT_REGS_RSI(regs), PT_REGS_RDI(regs));
+              PT_REGS_DX(regs), PT_REGS_SI(regs), PT_REGS_DI(regs));
        printk(KERN_INFO "RBP: %016lx R08: %016lx R09: %016lx\n",
-              PT_REGS_RBP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs));
+              PT_REGS_BP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs));
        printk(KERN_INFO "R10: %016lx R11: %016lx R12: %016lx\n",
               PT_REGS_R10(regs), PT_REGS_R11(regs), PT_REGS_R12(regs));
        printk(KERN_INFO "R13: %016lx R14: %016lx R15: %016lx\n",
index c6c7131e563bcab77bf69cdfc1ef9160c8c6f9d4..baba84f8ecb8ad8783a00943d31002f35880a7d0 100644 (file)
@@ -219,7 +219,7 @@ int arch_copy_tls(struct task_struct *new)
        int idx, ret = -EFAULT;
 
        if (copy_from_user(&info,
-                          (void __user *) UPT_ESI(&new->thread.regs.regs),
+                          (void __user *) UPT_SI(&new->thread.regs.regs),
                           sizeof(info)))
                goto out;
 
index b040b0e518caf0a0fe382999b36c2c04e7344860..f9643fc50de571636347a1e0510d45f916728967 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/thread_info.h>
 #include <asm/processor-flags.h>
 #include <asm/segment.h>
+#include <asm/asm.h>
 
 #include <xen/interface/xen.h>
 
@@ -137,10 +138,7 @@ iret_restore_end:
 
 1:     iret
 xen_iret_end_crit:
-.section __ex_table, "a"
-       .align 4
-       .long 1b, iret_exc
-.previous
+       _ASM_EXTABLE(1b, iret_exc)
 
 hyper_iret:
        /* put this out of line since its very rarely used */
index 3acb26e8dead4d2336e1313333027b6e74461ed3..5c371d8d45284a1c35808d2b9e4928db03cc7652 100644 (file)
@@ -168,9 +168,6 @@ struct mm_struct;
 /* Free all resources held by a thread. */
 #define release_thread(thread) do { } while(0)
 
-/* Prepare to copy thread state - unlazy all lazy status */
-extern void prepare_to_copy(struct task_struct*);
-
 /* Create a kernel thread without removing it from tasklists */
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
index 6a2d6edf8f728af36bf4da4fc1587e79057bdf46..9b306e550e3f06ddfa342c041c7793543702c4b3 100644 (file)
@@ -140,13 +140,16 @@ void flush_thread(void)
 }
 
 /*
- * This is called before the thread is copied. 
+ * this gets called so that we can store coprocessor state into memory and
+ * copy the current task into the new thread.
  */
-void prepare_to_copy(struct task_struct *tsk)
+int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
 #if XTENSA_HAVE_COPROCESSORS
-       coprocessor_flush_all(task_thread_info(tsk));
+       coprocessor_flush_all(task_thread_info(src));
 #endif
+       *dst = *src;
+       return 0;
 }
 
 /*
index 6bdedd7cca2cd3cd630370732b71b8b530992ca9..2be8ef1d30935af81a9b7ac3b721750fdda6b3cd 100644 (file)
@@ -416,6 +416,15 @@ config PATA_EFAR
 
          If unsure, say N.
 
+config PATA_EP93XX
+       tristate "Cirrus Logic EP93xx PATA support"
+       depends on ARCH_EP93XX
+       help
+         This option enables support for the PATA controller in
+         the Cirrus Logic EP9312 and EP9315 ARM CPU.
+
+         If unsure, say N.
+
 config PATA_HPT366
        tristate "HPT 366/368 PATA support"
        depends on PCI
index 6ece5b7231a38de3c404c91abd67e5cb2fb1490d..a454a139b1d20531f899897ab6fcc7b689e44556 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_PATA_CS5535)     += pata_cs5535.o
 obj-$(CONFIG_PATA_CS5536)      += pata_cs5536.o
 obj-$(CONFIG_PATA_CYPRESS)     += pata_cypress.o
 obj-$(CONFIG_PATA_EFAR)                += pata_efar.o
+obj-$(CONFIG_PATA_EP93XX)      += pata_ep93xx.o
 obj-$(CONFIG_PATA_HPT366)      += pata_hpt366.o
 obj-$(CONFIG_PATA_HPT37X)      += pata_hpt37x.o
 obj-$(CONFIG_PATA_HPT3X2N)     += pata_hpt3x2n.o
index 7df56ec318193015282cf200e3e4ba9cc6658a12..aae115600b7435ba3944fc7a0fff5f3bdae43037 100644 (file)
@@ -177,7 +177,7 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
        if ((id->driver_data & ATA_GEN_CLASS_MATCH) && all_generic_ide == 0)
                return -ENODEV;
 
-       if (id->driver_data & ATA_GEN_INTEL_IDER)
+       if ((id->driver_data & ATA_GEN_INTEL_IDER) && !all_generic_ide)
                if (!is_intel_ider(dev))
                        return -ENODEV;
 
index 7857e8fd0a3e56e007004492482b3e306d8ba089..3c809bfbccf58a2af573be99719a4fda77bd3815 100644 (file)
@@ -1554,6 +1554,39 @@ static bool piix_broken_system_poweroff(struct pci_dev *pdev)
        return false;
 }
 
+static int prefer_ms_hyperv = 1;
+module_param(prefer_ms_hyperv, int, 0);
+
+static void piix_ignore_devices_quirk(struct ata_host *host)
+{
+#if IS_ENABLED(CONFIG_HYPERV_STORAGE)
+       static const struct dmi_system_id ignore_hyperv[] = {
+               {
+                       /* On Hyper-V hypervisors the disks are exposed on
+                        * both the emulated SATA controller and on the
+                        * paravirtualised drivers.  The CD/DVD devices
+                        * are only exposed on the emulated controller.
+                        * Request we ignore ATA devices on this host.
+                        */
+                       .ident = "Hyper-V Virtual Machine",
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR,
+                                               "Microsoft Corporation"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+                       },
+               },
+               { }     /* terminate list */
+       };
+       const struct dmi_system_id *dmi = dmi_first_match(ignore_hyperv);
+
+       if (dmi && prefer_ms_hyperv) {
+               host->flags |= ATA_HOST_IGNORE_ATA;
+               dev_info(host->dev, "%s detected, ATA device ignore set\n",
+                       dmi->ident);
+       }
+#endif
+}
+
 /**
  *     piix_init_one - Register PIIX ATA PCI device with kernel services
  *     @pdev: PCI device to register
@@ -1669,6 +1702,9 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
        }
        host->flags |= ATA_HOST_PARALLEL_SCAN;
 
+       /* Allow hosts to specify device types to ignore when scanning. */
+       piix_ignore_devices_quirk(host);
+
        pci_set_master(pdev);
        return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht);
 }
index 23763a1ec570aa08149e23f65de1a7fb0087c860..cece3a4d11eaeb70bf2323a53f027d28439bd543 100644 (file)
@@ -1973,6 +1973,12 @@ retry:
        if (class == ATA_DEV_ATA) {
                if (!ata_id_is_ata(id) && !ata_id_is_cfa(id))
                        goto err_out;
+               if (ap->host->flags & ATA_HOST_IGNORE_ATA &&
+                                                       ata_id_is_ata(id)) {
+                       ata_dev_dbg(dev,
+                               "host indicates ignore ATA devices, ignored\n");
+                       return -ENOENT;
+               }
        } else {
                if (ata_id_is_ata(id))
                        goto err_out;
@@ -4051,6 +4057,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "_NEC DV5800A",       NULL,           ATA_HORKAGE_NODMA },
        { "SAMSUNG CD-ROM SN-124", "N001",      ATA_HORKAGE_NODMA },
        { "Seagate STT20000A", NULL,            ATA_HORKAGE_NODMA },
+       { "2GB ATA Flash Disk", "ADMA428M",     ATA_HORKAGE_NODMA },
        /* Odd clown on sil3726/4726 PMPs */
        { "Config  Disk",       NULL,           ATA_HORKAGE_DISABLE },
 
index d1fbd59ead167b50544749e40f711ba09e138083..6d53cf9b3b6ea443a1f477314a87ee6c46c292b3 100644 (file)
@@ -2046,6 +2046,26 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev,
        return action;
 }
 
+/**
+ *     ata_eh_worth_retry - analyze error and decide whether to retry
+ *     @qc: qc to possibly retry
+ *
+ *     Look at the cause of the error and decide if a retry
+ *     might be useful or not.  We don't want to retry media errors
+ *     because the drive itself has probably already taken 10-30 seconds
+ *     doing its own internal retries before reporting the failure.
+ */
+static inline int ata_eh_worth_retry(struct ata_queued_cmd *qc)
+{
+       if (qc->flags & AC_ERR_MEDIA)
+               return 0;       /* don't retry media errors */
+       if (qc->flags & ATA_QCFLAG_IO)
+               return 1;       /* otherwise retry anything from fs stack */
+       if (qc->err_mask & AC_ERR_INVALID)
+               return 0;       /* don't retry these */
+       return qc->err_mask != AC_ERR_DEV;  /* retry if not dev error */
+}
+
 /**
  *     ata_eh_link_autopsy - analyze error and determine recovery action
  *     @link: host link to perform autopsy on
@@ -2120,9 +2140,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
                        qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
 
                /* determine whether the command is worth retrying */
-               if (qc->flags & ATA_QCFLAG_IO ||
-                   (!(qc->err_mask & AC_ERR_INVALID) &&
-                    qc->err_mask != AC_ERR_DEV))
+               if (ata_eh_worth_retry(qc))
                        qc->flags |= ATA_QCFLAG_RETRY;
 
                /* accumulate error info */
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
new file mode 100644 (file)
index 0000000..6ef2e37
--- /dev/null
@@ -0,0 +1,1044 @@
+/*
+ * EP93XX PATA controller driver.
+ *
+ * Copyright (c) 2012, Metasoft s.c.
+ *     Rafal Prylowski <prylowski@metasoft.pl>
+ *
+ * Based on pata_scc.c, pata_icside.c and on earlier version of EP93XX
+ * PATA driver by Lennert Buytenhek and Alessandro Zummo.
+ * Read/Write timings, resource management and other improvements
+ * from driver by Joao Ramos and Bartlomiej Zolnierkiewicz.
+ * DMA engine support based on spi-ep93xx.c by Mika Westerberg.
+ *
+ * Original copyrights:
+ *
+ * Support for Cirrus Logic's EP93xx (EP9312, EP9315) CPUs
+ * PATA host controller driver.
+ *
+ * Copyright (c) 2009, Bartlomiej Zolnierkiewicz
+ *
+ * Heavily based on the ep93xx-ide.c driver:
+ *
+ * Copyright (c) 2009, Joao Ramos <joao.ramos@inov.pt>
+ *                   INESC Inovacao (INOV)
+ *
+ * EP93XX PATA controller driver.
+ * Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * An ATA driver for the Cirrus Logic EP93xx PATA controller.
+ *
+ * Based on an earlier version by Alessandro Zummo, which is:
+ *   Copyright (C) 2006 Tower Technologies
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/ktime.h>
+
+#include <mach/dma.h>
+#include <mach/platform.h>
+
+#define DRV_NAME       "ep93xx-ide"
+#define DRV_VERSION    "1.0"
+
+enum {
+       /* IDE Control Register */
+       IDECTRL                         = 0x00,
+       IDECTRL_CS0N                    = (1 << 0),
+       IDECTRL_CS1N                    = (1 << 1),
+       IDECTRL_DIORN                   = (1 << 5),
+       IDECTRL_DIOWN                   = (1 << 6),
+       IDECTRL_INTRQ                   = (1 << 9),
+       IDECTRL_IORDY                   = (1 << 10),
+       /*
+        * the device IDE register to be accessed is selected through
+        * IDECTRL register's specific bitfields 'DA', 'CS1N' and 'CS0N':
+        *   b4   b3   b2    b1     b0
+        *   A2   A1   A0   CS1N   CS0N
+        * the values filled in this structure allows the value to be directly
+        * ORed to the IDECTRL register, hence giving directly the A[2:0] and
+        * CS1N/CS0N values for each IDE register.
+        * The values correspond to the transformation:
+        *   ((real IDE address) << 2) | CS1N value << 1 | CS0N value
+        */
+       IDECTRL_ADDR_CMD                = 0 + 2, /* CS1 */
+       IDECTRL_ADDR_DATA               = (ATA_REG_DATA << 2) + 2,
+       IDECTRL_ADDR_ERROR              = (ATA_REG_ERR << 2) + 2,
+       IDECTRL_ADDR_FEATURE            = (ATA_REG_FEATURE << 2) + 2,
+       IDECTRL_ADDR_NSECT              = (ATA_REG_NSECT << 2) + 2,
+       IDECTRL_ADDR_LBAL               = (ATA_REG_LBAL << 2) + 2,
+       IDECTRL_ADDR_LBAM               = (ATA_REG_LBAM << 2) + 2,
+       IDECTRL_ADDR_LBAH               = (ATA_REG_LBAH << 2) + 2,
+       IDECTRL_ADDR_DEVICE             = (ATA_REG_DEVICE << 2) + 2,
+       IDECTRL_ADDR_STATUS             = (ATA_REG_STATUS << 2) + 2,
+       IDECTRL_ADDR_COMMAND            = (ATA_REG_CMD << 2) + 2,
+       IDECTRL_ADDR_ALTSTATUS          = (0x06 << 2) + 1, /* CS0 */
+       IDECTRL_ADDR_CTL                = (0x06 << 2) + 1, /* CS0 */
+
+       /* IDE Configuration Register */
+       IDECFG                          = 0x04,
+       IDECFG_IDEEN                    = (1 << 0),
+       IDECFG_PIO                      = (1 << 1),
+       IDECFG_MDMA                     = (1 << 2),
+       IDECFG_UDMA                     = (1 << 3),
+       IDECFG_MODE_SHIFT               = 4,
+       IDECFG_MODE_MASK                = (0xf << 4),
+       IDECFG_WST_SHIFT                = 8,
+       IDECFG_WST_MASK                 = (0x3 << 8),
+
+       /* MDMA Operation Register */
+       IDEMDMAOP                       = 0x08,
+
+       /* UDMA Operation Register */
+       IDEUDMAOP                       = 0x0c,
+       IDEUDMAOP_UEN                   = (1 << 0),
+       IDEUDMAOP_RWOP                  = (1 << 1),
+
+       /* PIO/MDMA/UDMA Data Registers */
+       IDEDATAOUT                      = 0x10,
+       IDEDATAIN                       = 0x14,
+       IDEMDMADATAOUT                  = 0x18,
+       IDEMDMADATAIN                   = 0x1c,
+       IDEUDMADATAOUT                  = 0x20,
+       IDEUDMADATAIN                   = 0x24,
+
+       /* UDMA Status Register */
+       IDEUDMASTS                      = 0x28,
+       IDEUDMASTS_DMAIDE               = (1 << 16),
+       IDEUDMASTS_INTIDE               = (1 << 17),
+       IDEUDMASTS_SBUSY                = (1 << 18),
+       IDEUDMASTS_NDO                  = (1 << 24),
+       IDEUDMASTS_NDI                  = (1 << 25),
+       IDEUDMASTS_N4X                  = (1 << 26),
+
+       /* UDMA Debug Status Register */
+       IDEUDMADEBUG                    = 0x2c,
+};
+
+struct ep93xx_pata_data {
+       const struct platform_device *pdev;
+       void __iomem *ide_base;
+       struct ata_timing t;
+       bool iordy;
+
+       unsigned long udma_in_phys;
+       unsigned long udma_out_phys;
+
+       struct dma_chan *dma_rx_channel;
+       struct ep93xx_dma_data dma_rx_data;
+       struct dma_chan *dma_tx_channel;
+       struct ep93xx_dma_data dma_tx_data;
+};
+
+static void ep93xx_pata_clear_regs(void __iomem *base)
+{
+       writel(IDECTRL_CS0N | IDECTRL_CS1N | IDECTRL_DIORN |
+               IDECTRL_DIOWN, base + IDECTRL);
+
+       writel(0, base + IDECFG);
+       writel(0, base + IDEMDMAOP);
+       writel(0, base + IDEUDMAOP);
+       writel(0, base + IDEDATAOUT);
+       writel(0, base + IDEDATAIN);
+       writel(0, base + IDEMDMADATAOUT);
+       writel(0, base + IDEMDMADATAIN);
+       writel(0, base + IDEUDMADATAOUT);
+       writel(0, base + IDEUDMADATAIN);
+       writel(0, base + IDEUDMADEBUG);
+}
+
+static bool ep93xx_pata_check_iordy(void __iomem *base)
+{
+       return !!(readl(base + IDECTRL) & IDECTRL_IORDY);
+}
+
+/*
+ * According to EP93xx User's Guide, WST field of IDECFG specifies number
+ * of HCLK cycles to hold the data bus after a PIO write operation.
+ * It should be programmed to guarantee following delays:
+ *
+ * PIO Mode   [ns]
+ * 0          30
+ * 1          20
+ * 2          15
+ * 3          10
+ * 4          5
+ *
+ * Maximum possible value for HCLK is 100MHz.
+ */
+static int ep93xx_pata_get_wst(int pio_mode)
+{
+       int val;
+
+       if (pio_mode == 0)
+               val = 3;
+       else if (pio_mode < 3)
+               val = 2;
+       else
+               val = 1;
+
+       return val << IDECFG_WST_SHIFT;
+}
+
+static void ep93xx_pata_enable_pio(void __iomem *base, int pio_mode)
+{
+       writel(IDECFG_IDEEN | IDECFG_PIO |
+               ep93xx_pata_get_wst(pio_mode) |
+               (pio_mode << IDECFG_MODE_SHIFT), base + IDECFG);
+}
+
+/*
+ * Based on delay loop found in mach-pxa/mp900.c.
+ *
+ * Single iteration should take 5 cpu cycles. This is 25ns assuming the
+ * fastest ep93xx cpu speed (200MHz) and is better optimized for PIO4 timings
+ * than eg. 20ns.
+ */
+static void ep93xx_pata_delay(unsigned long count)
+{
+       __asm__ volatile (
+               "0:\n"
+               "mov r0, r0\n"
+               "subs %0, %1, #1\n"
+               "bge 0b\n"
+               : "=r" (count)
+               : "0" (count)
+       );
+}
+
+static unsigned long ep93xx_pata_wait_for_iordy(void __iomem *base,
+                                               unsigned long t2)
+{
+       /*
+        * According to ATA specification, IORDY pin can be first sampled
+        * tA = 35ns after activation of DIOR-/DIOW-. Maximum IORDY pulse
+        * width is tB = 1250ns.
+        *
+        * We are already t2 delay loop iterations after activation of
+        * DIOR-/DIOW-, so we set timeout to (1250 + 35) / 25 - t2 additional
+        * delay loop iterations.
+        */
+       unsigned long start = (1250 + 35) / 25 - t2;
+       unsigned long counter = start;
+
+       while (!ep93xx_pata_check_iordy(base) && counter--)
+               ep93xx_pata_delay(1);
+       return start - counter;
+}
+
+/* common part at start of ep93xx_pata_read/write() */
+static void ep93xx_pata_rw_begin(void __iomem *base, unsigned long addr,
+                                unsigned long t1)
+{
+       writel(IDECTRL_DIOWN | IDECTRL_DIORN | addr, base + IDECTRL);
+       ep93xx_pata_delay(t1);
+}
+
+/* common part at end of ep93xx_pata_read/write() */
+static void ep93xx_pata_rw_end(void __iomem *base, unsigned long addr,
+                              bool iordy, unsigned long t0, unsigned long t2,
+                              unsigned long t2i)
+{
+       ep93xx_pata_delay(t2);
+       /* lengthen t2 if needed */
+       if (iordy)
+               t2 += ep93xx_pata_wait_for_iordy(base, t2);
+       writel(IDECTRL_DIOWN | IDECTRL_DIORN | addr, base + IDECTRL);
+       if (t0 > t2 && t0 - t2 > t2i)
+               ep93xx_pata_delay(t0 - t2);
+       else
+               ep93xx_pata_delay(t2i);
+}
+
+static u16 ep93xx_pata_read(struct ep93xx_pata_data *drv_data,
+                           unsigned long addr,
+                           bool reg)
+{
+       void __iomem *base = drv_data->ide_base;
+       const struct ata_timing *t = &drv_data->t;
+       unsigned long t0 = reg ? t->cyc8b : t->cycle;
+       unsigned long t2 = reg ? t->act8b : t->active;
+       unsigned long t2i = reg ? t->rec8b : t->recover;
+
+       ep93xx_pata_rw_begin(base, addr, t->setup);
+       writel(IDECTRL_DIOWN | addr, base + IDECTRL);
+       /*
+        * The IDEDATAIN register is loaded from the DD pins at the positive
+        * edge of the DIORN signal. (EP93xx UG p27-14)
+        */
+       ep93xx_pata_rw_end(base, addr, drv_data->iordy, t0, t2, t2i);
+       return readl(base + IDEDATAIN);
+}
+
+/* IDE register read */
+static u16 ep93xx_pata_read_reg(struct ep93xx_pata_data *drv_data,
+                               unsigned long addr)
+{
+       return ep93xx_pata_read(drv_data, addr, true);
+}
+
+/* PIO data read */
+static u16 ep93xx_pata_read_data(struct ep93xx_pata_data *drv_data,
+                                unsigned long addr)
+{
+       return ep93xx_pata_read(drv_data, addr, false);
+}
+
+static void ep93xx_pata_write(struct ep93xx_pata_data *drv_data,
+                             u16 value, unsigned long addr,
+                             bool reg)
+{
+       void __iomem *base = drv_data->ide_base;
+       const struct ata_timing *t = &drv_data->t;
+       unsigned long t0 = reg ? t->cyc8b : t->cycle;
+       unsigned long t2 = reg ? t->act8b : t->active;
+       unsigned long t2i = reg ? t->rec8b : t->recover;
+
+       ep93xx_pata_rw_begin(base, addr, t->setup);
+       /*
+        * Value from IDEDATAOUT register is driven onto the DD pins when
+        * DIOWN is low. (EP93xx UG p27-13)
+        */
+       writel(value, base + IDEDATAOUT);
+       writel(IDECTRL_DIORN | addr, base + IDECTRL);
+       ep93xx_pata_rw_end(base, addr, drv_data->iordy, t0, t2, t2i);
+}
+
+/* IDE register write */
+static void ep93xx_pata_write_reg(struct ep93xx_pata_data *drv_data,
+                                 u16 value, unsigned long addr)
+{
+       ep93xx_pata_write(drv_data, value, addr, true);
+}
+
+/* PIO data write */
+static void ep93xx_pata_write_data(struct ep93xx_pata_data *drv_data,
+                                  u16 value, unsigned long addr)
+{
+       ep93xx_pata_write(drv_data, value, addr, false);
+}
+
+static void ep93xx_pata_set_piomode(struct ata_port *ap,
+                                   struct ata_device *adev)
+{
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+       struct ata_device *pair = ata_dev_pair(adev);
+       /*
+        * Calculate timings for the delay loop, assuming ep93xx cpu speed
+        * is 200MHz (maximum possible for ep93xx). If actual cpu speed is
+        * slower, we will wait a bit longer in each delay.
+        * Additional division of cpu speed by 5, because single iteration
+        * of our delay loop takes 5 cpu cycles (25ns).
+        */
+       unsigned long T = 1000000 / (200 / 5);
+
+       ata_timing_compute(adev, adev->pio_mode, &drv_data->t, T, 0);
+       if (pair && pair->pio_mode) {
+               struct ata_timing t;
+               ata_timing_compute(pair, pair->pio_mode, &t, T, 0);
+               ata_timing_merge(&t, &drv_data->t, &drv_data->t,
+                       ATA_TIMING_SETUP | ATA_TIMING_8BIT);
+       }
+       drv_data->iordy = ata_pio_need_iordy(adev);
+
+       ep93xx_pata_enable_pio(drv_data->ide_base,
+                              adev->pio_mode - XFER_PIO_0);
+}
+
+/* Note: original code is ata_sff_check_status */
+static u8 ep93xx_pata_check_status(struct ata_port *ap)
+{
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+       return ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_STATUS);
+}
+
+static u8 ep93xx_pata_check_altstatus(struct ata_port *ap)
+{
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+       return ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_ALTSTATUS);
+}
+
+/* Note: original code is ata_sff_tf_load */
+static void ep93xx_pata_tf_load(struct ata_port *ap,
+                               const struct ata_taskfile *tf)
+{
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+       unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+       if (tf->ctl != ap->last_ctl) {
+               ep93xx_pata_write_reg(drv_data, tf->ctl, IDECTRL_ADDR_CTL);
+               ap->last_ctl = tf->ctl;
+               ata_wait_idle(ap);
+       }
+
+       if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+               ep93xx_pata_write_reg(drv_data, tf->hob_feature,
+                       IDECTRL_ADDR_FEATURE);
+               ep93xx_pata_write_reg(drv_data, tf->hob_nsect,
+                       IDECTRL_ADDR_NSECT);
+               ep93xx_pata_write_reg(drv_data, tf->hob_lbal,
+                       IDECTRL_ADDR_LBAL);
+               ep93xx_pata_write_reg(drv_data, tf->hob_lbam,
+                       IDECTRL_ADDR_LBAM);
+               ep93xx_pata_write_reg(drv_data, tf->hob_lbah,
+                       IDECTRL_ADDR_LBAH);
+       }
+
+       if (is_addr) {
+               ep93xx_pata_write_reg(drv_data, tf->feature,
+                       IDECTRL_ADDR_FEATURE);
+               ep93xx_pata_write_reg(drv_data, tf->nsect, IDECTRL_ADDR_NSECT);
+               ep93xx_pata_write_reg(drv_data, tf->lbal, IDECTRL_ADDR_LBAL);
+               ep93xx_pata_write_reg(drv_data, tf->lbam, IDECTRL_ADDR_LBAM);
+               ep93xx_pata_write_reg(drv_data, tf->lbah, IDECTRL_ADDR_LBAH);
+       }
+
+       if (tf->flags & ATA_TFLAG_DEVICE)
+               ep93xx_pata_write_reg(drv_data, tf->device,
+                       IDECTRL_ADDR_DEVICE);
+
+       ata_wait_idle(ap);
+}
+
+/* Note: original code is ata_sff_tf_read */
+static void ep93xx_pata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+       tf->command = ep93xx_pata_check_status(ap);
+       tf->feature = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_FEATURE);
+       tf->nsect = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_NSECT);
+       tf->lbal = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAL);
+       tf->lbam = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAM);
+       tf->lbah = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAH);
+       tf->device = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_DEVICE);
+
+       if (tf->flags & ATA_TFLAG_LBA48) {
+               ep93xx_pata_write_reg(drv_data, tf->ctl | ATA_HOB,
+                       IDECTRL_ADDR_CTL);
+               tf->hob_feature = ep93xx_pata_read_reg(drv_data,
+                       IDECTRL_ADDR_FEATURE);
+               tf->hob_nsect = ep93xx_pata_read_reg(drv_data,
+                       IDECTRL_ADDR_NSECT);
+               tf->hob_lbal = ep93xx_pata_read_reg(drv_data,
+                       IDECTRL_ADDR_LBAL);
+               tf->hob_lbam = ep93xx_pata_read_reg(drv_data,
+                       IDECTRL_ADDR_LBAM);
+               tf->hob_lbah = ep93xx_pata_read_reg(drv_data,
+                       IDECTRL_ADDR_LBAH);
+               ep93xx_pata_write_reg(drv_data, tf->ctl, IDECTRL_ADDR_CTL);
+               ap->last_ctl = tf->ctl;
+       }
+}
+
+/* Note: original code is ata_sff_exec_command */
+static void ep93xx_pata_exec_command(struct ata_port *ap,
+                                    const struct ata_taskfile *tf)
+{
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+       ep93xx_pata_write_reg(drv_data, tf->command,
+                         IDECTRL_ADDR_COMMAND);
+       ata_sff_pause(ap);
+}
+
+/* Note: original code is ata_sff_dev_select */
+static void ep93xx_pata_dev_select(struct ata_port *ap, unsigned int device)
+{
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+       u8 tmp = ATA_DEVICE_OBS;
+
+       if (device != 0)
+               tmp |= ATA_DEV1;
+
+       ep93xx_pata_write_reg(drv_data, tmp, IDECTRL_ADDR_DEVICE);
+       ata_sff_pause(ap);      /* needed; also flushes, for mmio */
+}
+
+/* Note: original code is ata_sff_set_devctl */
+static void ep93xx_pata_set_devctl(struct ata_port *ap, u8 ctl)
+{
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+       ep93xx_pata_write_reg(drv_data, ctl, IDECTRL_ADDR_CTL);
+}
+
+/* Note: original code is ata_sff_data_xfer */
+static unsigned int ep93xx_pata_data_xfer(struct ata_device *adev,
+                                         unsigned char *buf,
+                                         unsigned int buflen, int rw)
+{
+       struct ata_port *ap = adev->link->ap;
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+       u16 *data = (u16 *)buf;
+       unsigned int words = buflen >> 1;
+
+       /* Transfer multiple of 2 bytes */
+       while (words--)
+               if (rw == READ)
+                       *data++ = cpu_to_le16(
+                               ep93xx_pata_read_data(
+                                       drv_data, IDECTRL_ADDR_DATA));
+               else
+                       ep93xx_pata_write_data(drv_data, le16_to_cpu(*data++),
+                               IDECTRL_ADDR_DATA);
+
+       /* Transfer trailing 1 byte, if any. */
+       if (unlikely(buflen & 0x01)) {
+               unsigned char pad[2] = { };
+
+               buf += buflen - 1;
+
+               if (rw == READ) {
+                       *pad = cpu_to_le16(
+                               ep93xx_pata_read_data(
+                                       drv_data, IDECTRL_ADDR_DATA));
+                       *buf = pad[0];
+               } else {
+                       pad[0] = *buf;
+                       ep93xx_pata_write_data(drv_data, le16_to_cpu(*pad),
+                                         IDECTRL_ADDR_DATA);
+               }
+               words++;
+       }
+
+       return words << 1;
+}
+
+/* Note: original code is ata_devchk */
+static bool ep93xx_pata_device_is_present(struct ata_port *ap,
+                                         unsigned int device)
+{
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+       u8 nsect, lbal;
+
+       ap->ops->sff_dev_select(ap, device);
+
+       ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_NSECT);
+       ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_LBAL);
+
+       ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_NSECT);
+       ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_LBAL);
+
+       ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_NSECT);
+       ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_LBAL);
+
+       nsect = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_NSECT);
+       lbal = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAL);
+
+       if ((nsect == 0x55) && (lbal == 0xaa))
+               return true;
+
+       return false;
+}
+
+/* Note: original code is ata_sff_wait_after_reset */
+static int ep93xx_pata_wait_after_reset(struct ata_link *link,
+                                       unsigned int devmask,
+                                       unsigned long deadline)
+{
+       struct ata_port *ap = link->ap;
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+       unsigned int dev0 = devmask & (1 << 0);
+       unsigned int dev1 = devmask & (1 << 1);
+       int rc, ret = 0;
+
+       ata_msleep(ap, ATA_WAIT_AFTER_RESET);
+
+       /* always check readiness of the master device */
+       rc = ata_sff_wait_ready(link, deadline);
+       /*
+        * -ENODEV means the odd clown forgot the D7 pulldown resistor
+        * and TF status is 0xff, bail out on it too.
+        */
+       if (rc)
+               return rc;
+
+       /*
+        * if device 1 was found in ata_devchk, wait for register
+        * access briefly, then wait for BSY to clear.
+        */
+       if (dev1) {
+               int i;
+
+               ap->ops->sff_dev_select(ap, 1);
+
+               /*
+                * Wait for register access.  Some ATAPI devices fail
+                * to set nsect/lbal after reset, so don't waste too
+                * much time on it.  We're gonna wait for !BSY anyway.
+                */
+               for (i = 0; i < 2; i++) {
+                       u8 nsect, lbal;
+
+                       nsect = ep93xx_pata_read_reg(drv_data,
+                               IDECTRL_ADDR_NSECT);
+                       lbal = ep93xx_pata_read_reg(drv_data,
+                               IDECTRL_ADDR_LBAL);
+                       if (nsect == 1 && lbal == 1)
+                               break;
+                       msleep(50);     /* give drive a breather */
+               }
+
+               rc = ata_sff_wait_ready(link, deadline);
+               if (rc) {
+                       if (rc != -ENODEV)
+                               return rc;
+                       ret = rc;
+               }
+       }
+       /* is all this really necessary? */
+       ap->ops->sff_dev_select(ap, 0);
+       if (dev1)
+               ap->ops->sff_dev_select(ap, 1);
+       if (dev0)
+               ap->ops->sff_dev_select(ap, 0);
+
+       return ret;
+}
+
+/* Note: original code is ata_bus_softreset */
+static int ep93xx_pata_bus_softreset(struct ata_port *ap, unsigned int devmask,
+                                    unsigned long deadline)
+{
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+       ep93xx_pata_write_reg(drv_data, ap->ctl, IDECTRL_ADDR_CTL);
+       udelay(20);             /* FIXME: flush */
+       ep93xx_pata_write_reg(drv_data, ap->ctl | ATA_SRST, IDECTRL_ADDR_CTL);
+       udelay(20);             /* FIXME: flush */
+       ep93xx_pata_write_reg(drv_data, ap->ctl, IDECTRL_ADDR_CTL);
+       ap->last_ctl = ap->ctl;
+
+       return ep93xx_pata_wait_after_reset(&ap->link, devmask, deadline);
+}
+
+static void ep93xx_pata_release_dma(struct ep93xx_pata_data *drv_data)
+{
+       if (drv_data->dma_rx_channel) {
+               dma_release_channel(drv_data->dma_rx_channel);
+               drv_data->dma_rx_channel = NULL;
+       }
+       if (drv_data->dma_tx_channel) {
+               dma_release_channel(drv_data->dma_tx_channel);
+               drv_data->dma_tx_channel = NULL;
+       }
+}
+
+static bool ep93xx_pata_dma_filter(struct dma_chan *chan, void *filter_param)
+{
+       if (ep93xx_dma_chan_is_m2p(chan))
+               return false;
+
+       chan->private = filter_param;
+       return true;
+}
+
+static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
+{
+       const struct platform_device *pdev = drv_data->pdev;
+       dma_cap_mask_t mask;
+       struct dma_slave_config conf;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       /*
+        * Request two channels for IDE. Another possibility would be
+        * to request only one channel, and reprogram it's direction at
+        * start of new transfer.
+        */
+       drv_data->dma_rx_data.port = EP93XX_DMA_IDE;
+       drv_data->dma_rx_data.direction = DMA_FROM_DEVICE;
+       drv_data->dma_rx_data.name = "ep93xx-pata-rx";
+       drv_data->dma_rx_channel = dma_request_channel(mask,
+               ep93xx_pata_dma_filter, &drv_data->dma_rx_data);
+       if (!drv_data->dma_rx_channel)
+               return;
+
+       drv_data->dma_tx_data.port = EP93XX_DMA_IDE;
+       drv_data->dma_tx_data.direction = DMA_TO_DEVICE;
+       drv_data->dma_tx_data.name = "ep93xx-pata-tx";
+       drv_data->dma_tx_channel = dma_request_channel(mask,
+               ep93xx_pata_dma_filter, &drv_data->dma_tx_data);
+       if (!drv_data->dma_tx_channel) {
+               dma_release_channel(drv_data->dma_rx_channel);
+               return;
+       }
+
+       /* Configure receive channel direction and source address */
+       memset(&conf, 0, sizeof(conf));
+       conf.direction = DMA_FROM_DEVICE;
+       conf.src_addr = drv_data->udma_in_phys;
+       conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       if (dmaengine_slave_config(drv_data->dma_rx_channel, &conf)) {
+               dev_err(&pdev->dev, "failed to configure rx dma channel\n");
+               ep93xx_pata_release_dma(drv_data);
+               return;
+       }
+
+       /* Configure transmit channel direction and destination address */
+       memset(&conf, 0, sizeof(conf));
+       conf.direction = DMA_TO_DEVICE;
+       conf.dst_addr = drv_data->udma_out_phys;
+       conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       if (dmaengine_slave_config(drv_data->dma_tx_channel, &conf)) {
+               dev_err(&pdev->dev, "failed to configure tx dma channel\n");
+               ep93xx_pata_release_dma(drv_data);
+       }
+}
+
+static void ep93xx_pata_dma_start(struct ata_queued_cmd *qc)
+{
+       struct dma_async_tx_descriptor *txd;
+       struct ep93xx_pata_data *drv_data = qc->ap->host->private_data;
+       void __iomem *base = drv_data->ide_base;
+       struct ata_device *adev = qc->dev;
+       u32 v = qc->dma_dir == DMA_TO_DEVICE ? IDEUDMAOP_RWOP : 0;
+       struct dma_chan *channel = qc->dma_dir == DMA_TO_DEVICE
+               ? drv_data->dma_tx_channel : drv_data->dma_rx_channel;
+
+       txd = channel->device->device_prep_slave_sg(channel, qc->sg,
+                qc->n_elem, qc->dma_dir, DMA_CTRL_ACK, NULL);
+       if (!txd) {
+               dev_err(qc->ap->dev, "failed to prepare slave for sg dma\n");
+               return;
+       }
+       txd->callback = NULL;
+       txd->callback_param = NULL;
+
+       if (dmaengine_submit(txd) < 0) {
+               dev_err(qc->ap->dev, "failed to submit dma transfer\n");
+               return;
+       }
+       dma_async_issue_pending(channel);
+
+       /*
+        * When enabling UDMA operation, IDEUDMAOP register needs to be
+        * programmed in three step sequence:
+        * 1) set or clear the RWOP bit,
+        * 2) perform dummy read of the register,
+        * 3) set the UEN bit.
+        */
+       writel(v, base + IDEUDMAOP);
+       readl(base + IDEUDMAOP);
+       writel(v | IDEUDMAOP_UEN, base + IDEUDMAOP);
+
+       writel(IDECFG_IDEEN | IDECFG_UDMA |
+               ((adev->xfer_mode - XFER_UDMA_0) << IDECFG_MODE_SHIFT),
+               base + IDECFG);
+}
+
+static void ep93xx_pata_dma_stop(struct ata_queued_cmd *qc)
+{
+       struct ep93xx_pata_data *drv_data = qc->ap->host->private_data;
+       void __iomem *base = drv_data->ide_base;
+
+       /* terminate all dma transfers, if not yet finished */
+       dmaengine_terminate_all(drv_data->dma_rx_channel);
+       dmaengine_terminate_all(drv_data->dma_tx_channel);
+
+       /*
+        * To properly stop IDE-DMA, IDEUDMAOP register must to be cleared
+        * and IDECTRL register must be set to default value.
+        */
+       writel(0, base + IDEUDMAOP);
+       writel(readl(base + IDECTRL) | IDECTRL_DIOWN | IDECTRL_DIORN |
+               IDECTRL_CS0N | IDECTRL_CS1N, base + IDECTRL);
+
+       ep93xx_pata_enable_pio(drv_data->ide_base,
+               qc->dev->pio_mode - XFER_PIO_0);
+
+       ata_sff_dma_pause(qc->ap);
+}
+
+static void ep93xx_pata_dma_setup(struct ata_queued_cmd *qc)
+{
+       qc->ap->ops->sff_exec_command(qc->ap, &qc->tf);
+}
+
+static u8 ep93xx_pata_dma_status(struct ata_port *ap)
+{
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+       u32 val = readl(drv_data->ide_base + IDEUDMASTS);
+
+       /*
+        * UDMA Status Register bits:
+        *
+        * DMAIDE - DMA request signal from UDMA state machine,
+        * INTIDE - INT line generated by UDMA because of errors in the
+        *          state machine,
+        * SBUSY - UDMA state machine busy, not in idle state,
+        * NDO   - error for data-out not completed,
+        * NDI   - error for data-in not completed,
+        * N4X   - error for data transferred not multiplies of four
+        *         32-bit words.
+        * (EP93xx UG p27-17)
+        */
+       if (val & IDEUDMASTS_NDO || val & IDEUDMASTS_NDI ||
+           val & IDEUDMASTS_N4X || val & IDEUDMASTS_INTIDE)
+               return ATA_DMA_ERR;
+
+       /* read INTRQ (INT[3]) pin input state */
+       if (readl(drv_data->ide_base + IDECTRL) & IDECTRL_INTRQ)
+               return ATA_DMA_INTR;
+
+       if (val & IDEUDMASTS_SBUSY || val & IDEUDMASTS_DMAIDE)
+               return ATA_DMA_ACTIVE;
+
+       return 0;
+}
+
+/* Note: original code is ata_sff_softreset */
+static int ep93xx_pata_softreset(struct ata_link *al, unsigned int *classes,
+                                unsigned long deadline)
+{
+       struct ata_port *ap = al->ap;
+       unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+       unsigned int devmask = 0;
+       int rc;
+       u8 err;
+
+       /* determine if device 0/1 are present */
+       if (ep93xx_pata_device_is_present(ap, 0))
+               devmask |= (1 << 0);
+       if (slave_possible && ep93xx_pata_device_is_present(ap, 1))
+               devmask |= (1 << 1);
+
+       /* select device 0 again */
+       ap->ops->sff_dev_select(al->ap, 0);
+
+       /* issue bus reset */
+       rc = ep93xx_pata_bus_softreset(ap, devmask, deadline);
+       /* if link is ocuppied, -ENODEV too is an error */
+       if (rc && (rc != -ENODEV || sata_scr_valid(al))) {
+               ata_link_printk(al, KERN_ERR, "SRST failed (errno=%d)\n",
+                               rc);
+               return rc;
+       }
+
+       /* determine by signature whether we have ATA or ATAPI devices */
+       classes[0] = ata_sff_dev_classify(&al->device[0], devmask & (1 << 0),
+                                         &err);
+       if (slave_possible && err != 0x81)
+               classes[1] = ata_sff_dev_classify(&al->device[1],
+                                                 devmask & (1 << 1), &err);
+
+       return 0;
+}
+
+/* Note: original code is ata_sff_drain_fifo */
+static void ep93xx_pata_drain_fifo(struct ata_queued_cmd *qc)
+{
+       int count;
+       struct ata_port *ap;
+       struct ep93xx_pata_data *drv_data;
+
+       /* We only need to flush incoming data when a command was running */
+       if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+               return;
+
+       ap = qc->ap;
+       drv_data = ap->host->private_data;
+       /* Drain up to 64K of data before we give up this recovery method */
+       for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ)
+                    && count < 65536; count += 2)
+               ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_DATA);
+
+       /* Can become DEBUG later */
+       if (count)
+               ata_port_printk(ap, KERN_DEBUG,
+                               "drained %d bytes to clear DRQ.\n", count);
+
+}
+
+static int ep93xx_pata_port_start(struct ata_port *ap)
+{
+       struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+       /*
+        * Set timings to safe values at startup (= number of ns from ATA
+        * specification), we'll switch to properly calculated values later.
+        */
+       drv_data->t = *ata_timing_find_mode(XFER_PIO_0);
+       return 0;
+}
+
+static struct scsi_host_template ep93xx_pata_sht = {
+       ATA_BASE_SHT(DRV_NAME),
+       /* ep93xx dma implementation limit */
+       .sg_tablesize           = 32,
+       /* ep93xx dma can't transfer 65536 bytes at once */
+       .dma_boundary           = 0x7fff,
+};
+
+static struct ata_port_operations ep93xx_pata_port_ops = {
+       .inherits               = &ata_bmdma_port_ops,
+
+       .qc_prep                = ata_noop_qc_prep,
+
+       .softreset              = ep93xx_pata_softreset,
+       .hardreset              = ATA_OP_NULL,
+
+       .sff_dev_select         = ep93xx_pata_dev_select,
+       .sff_set_devctl         = ep93xx_pata_set_devctl,
+       .sff_check_status       = ep93xx_pata_check_status,
+       .sff_check_altstatus    = ep93xx_pata_check_altstatus,
+       .sff_tf_load            = ep93xx_pata_tf_load,
+       .sff_tf_read            = ep93xx_pata_tf_read,
+       .sff_exec_command       = ep93xx_pata_exec_command,
+       .sff_data_xfer          = ep93xx_pata_data_xfer,
+       .sff_drain_fifo         = ep93xx_pata_drain_fifo,
+       .sff_irq_clear          = ATA_OP_NULL,
+
+       .set_piomode            = ep93xx_pata_set_piomode,
+
+       .bmdma_setup            = ep93xx_pata_dma_setup,
+       .bmdma_start            = ep93xx_pata_dma_start,
+       .bmdma_stop             = ep93xx_pata_dma_stop,
+       .bmdma_status           = ep93xx_pata_dma_status,
+
+       .cable_detect           = ata_cable_unknown,
+       .port_start             = ep93xx_pata_port_start,
+};
+
+static int __devinit ep93xx_pata_probe(struct platform_device *pdev)
+{
+       struct ep93xx_pata_data *drv_data;
+       struct ata_host *host;
+       struct ata_port *ap;
+       unsigned int irq;
+       struct resource *mem_res;
+       void __iomem *ide_base;
+       int err;
+
+       err = ep93xx_ide_acquire_gpio(pdev);
+       if (err)
+               return err;
+
+       /* INT[3] (IRQ_EP93XX_EXT3) line connected as pull down */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               err = -ENXIO;
+               goto err_rel_gpio;
+       }
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_res) {
+               err = -ENXIO;
+               goto err_rel_gpio;
+       }
+
+       ide_base = devm_request_and_ioremap(&pdev->dev, mem_res);
+       if (!ide_base) {
+               err = -ENXIO;
+               goto err_rel_gpio;
+       }
+
+       drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
+       if (!drv_data) {
+               err = -ENXIO;
+               goto err_rel_gpio;
+       }
+
+       platform_set_drvdata(pdev, drv_data);
+       drv_data->pdev = pdev;
+       drv_data->ide_base = ide_base;
+       drv_data->udma_in_phys = mem_res->start + IDEUDMADATAIN;
+       drv_data->udma_out_phys = mem_res->start + IDEUDMADATAOUT;
+       ep93xx_pata_dma_init(drv_data);
+
+       /* allocate host */
+       host = ata_host_alloc(&pdev->dev, 1);
+       if (!host) {
+               err = -ENXIO;
+               goto err_rel_dma;
+       }
+
+       ep93xx_pata_clear_regs(ide_base);
+
+       host->private_data = drv_data;
+
+       ap = host->ports[0];
+       ap->dev = &pdev->dev;
+       ap->ops = &ep93xx_pata_port_ops;
+       ap->flags |= ATA_FLAG_SLAVE_POSS;
+       ap->pio_mask = ATA_PIO4;
+
+       /*
+        * Maximum UDMA modes:
+        * EP931x rev.E0 - UDMA2
+        * EP931x rev.E1 - UDMA3
+        * EP931x rev.E2 - UDMA4
+        *
+        * MWDMA support was removed from EP931x rev.E2,
+        * so this driver supports only UDMA modes.
+        */
+       if (drv_data->dma_rx_channel && drv_data->dma_tx_channel) {
+               int chip_rev = ep93xx_chip_revision();
+
+               if (chip_rev == EP93XX_CHIP_REV_E1)
+                       ap->udma_mask = ATA_UDMA3;
+               else if (chip_rev == EP93XX_CHIP_REV_E2)
+                       ap->udma_mask = ATA_UDMA4;
+               else
+                       ap->udma_mask = ATA_UDMA2;
+       }
+
+       /* defaults, pio 0 */
+       ep93xx_pata_enable_pio(ide_base, 0);
+
+       dev_info(&pdev->dev, "version " DRV_VERSION "\n");
+
+       /* activate host */
+       err = ata_host_activate(host, irq, ata_bmdma_interrupt, 0,
+               &ep93xx_pata_sht);
+       if (err == 0)
+               return 0;
+
+err_rel_dma:
+       ep93xx_pata_release_dma(drv_data);
+err_rel_gpio:
+       ep93xx_ide_release_gpio(pdev);
+       return err;
+}
+
+static int __devexit ep93xx_pata_remove(struct platform_device *pdev)
+{
+       struct ata_host *host = platform_get_drvdata(pdev);
+       struct ep93xx_pata_data *drv_data = host->private_data;
+
+       ata_host_detach(host);
+       ep93xx_pata_release_dma(drv_data);
+       ep93xx_pata_clear_regs(drv_data->ide_base);
+       ep93xx_ide_release_gpio(pdev);
+       return 0;
+}
+
+static struct platform_driver ep93xx_pata_platform_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = ep93xx_pata_probe,
+       .remove = __devexit_p(ep93xx_pata_remove),
+};
+
+module_platform_driver(ep93xx_pata_platform_driver);
+
+MODULE_AUTHOR("Alessandro Zummo, Lennert Buytenhek, Joao Ramos, "
+               "Bartlomiej Zolnierkiewicz, Rafal Prylowski");
+MODULE_DESCRIPTION("low-level driver for cirrus ep93xx IDE controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:pata_ep93xx");
index 73ce9fbe983961598d53f3bbeef0057cda084d4b..83aa694a8efe582f92365f193a07afcb5210b80d 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_domain.h>
+#include <linux/pm_qos.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/sched.h>
        ktime_t __start = ktime_get();                                          \
        type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev);         \
        s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start));           \
-       struct generic_pm_domain_data *__gpd_data = dev_gpd_data(dev);          \
-       if (__elapsed > __gpd_data->td.field) {                                 \
-               __gpd_data->td.field = __elapsed;                               \
+       struct gpd_timing_data *__td = &dev_gpd_data(dev)->td;                  \
+       if (!__retval && __elapsed > __td->field) {                             \
+               __td->field = __elapsed;                                        \
                dev_warn(dev, name " latency exceeded, new value %lld ns\n",    \
                        __elapsed);                                             \
+               genpd->max_off_time_changed = true;                             \
+               __td->constraint_changed = true;                                \
        }                                                                       \
        __retval;                                                               \
 })
@@ -211,6 +214,7 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd)
                elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
                if (elapsed_ns > genpd->power_on_latency_ns) {
                        genpd->power_on_latency_ns = elapsed_ns;
+                       genpd->max_off_time_changed = true;
                        if (genpd->name)
                                pr_warning("%s: Power-on latency exceeded, "
                                        "new value %lld ns\n", genpd->name,
@@ -247,6 +251,53 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
 
 #ifdef CONFIG_PM_RUNTIME
 
+static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
+                                    unsigned long val, void *ptr)
+{
+       struct generic_pm_domain_data *gpd_data;
+       struct device *dev;
+
+       gpd_data = container_of(nb, struct generic_pm_domain_data, nb);
+
+       mutex_lock(&gpd_data->lock);
+       dev = gpd_data->base.dev;
+       if (!dev) {
+               mutex_unlock(&gpd_data->lock);
+               return NOTIFY_DONE;
+       }
+       mutex_unlock(&gpd_data->lock);
+
+       for (;;) {
+               struct generic_pm_domain *genpd;
+               struct pm_domain_data *pdd;
+
+               spin_lock_irq(&dev->power.lock);
+
+               pdd = dev->power.subsys_data ?
+                               dev->power.subsys_data->domain_data : NULL;
+               if (pdd) {
+                       to_gpd_data(pdd)->td.constraint_changed = true;
+                       genpd = dev_to_genpd(dev);
+               } else {
+                       genpd = ERR_PTR(-ENODATA);
+               }
+
+               spin_unlock_irq(&dev->power.lock);
+
+               if (!IS_ERR(genpd)) {
+                       mutex_lock(&genpd->lock);
+                       genpd->max_off_time_changed = true;
+                       mutex_unlock(&genpd->lock);
+               }
+
+               dev = dev->parent;
+               if (!dev || dev->power.ignore_children)
+                       break;
+       }
+
+       return NOTIFY_DONE;
+}
+
 /**
  * __pm_genpd_save_device - Save the pre-suspend state of a device.
  * @pdd: Domain data of the device to save the state of.
@@ -435,6 +486,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
                elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
                if (elapsed_ns > genpd->power_off_latency_ns) {
                        genpd->power_off_latency_ns = elapsed_ns;
+                       genpd->max_off_time_changed = true;
                        if (genpd->name)
                                pr_warning("%s: Power-off latency exceeded, "
                                        "new value %lld ns\n", genpd->name,
@@ -443,17 +495,6 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
        }
 
        genpd->status = GPD_STATE_POWER_OFF;
-       genpd->power_off_time = ktime_get();
-
-       /* Update PM QoS information for devices in the domain. */
-       list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
-               struct gpd_timing_data *td = &to_gpd_data(pdd)->td;
-
-               pm_runtime_update_max_time_suspended(pdd->dev,
-                                       td->start_latency_ns +
-                                       td->restore_state_latency_ns +
-                                       genpd->power_on_latency_ns);
-       }
 
        list_for_each_entry(link, &genpd->slave_links, slave_node) {
                genpd_sd_counter_dec(link->master);
@@ -514,9 +555,6 @@ static int pm_genpd_runtime_suspend(struct device *dev)
        if (ret)
                return ret;
 
-       pm_runtime_update_max_time_suspended(dev,
-                               dev_gpd_data(dev)->td.start_latency_ns);
-
        /*
         * If power.irq_safe is set, this routine will be run with interrupts
         * off, so it can't use mutexes.
@@ -613,6 +651,12 @@ void pm_genpd_poweroff_unused(void)
 
 #else
 
+static inline int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
+                                           unsigned long val, void *ptr)
+{
+       return NOTIFY_DONE;
+}
+
 static inline void genpd_power_off_work_fn(struct work_struct *work) {}
 
 #define pm_genpd_runtime_suspend       NULL
@@ -1209,12 +1253,15 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
        if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
                return -EINVAL;
 
-       genpd_acquire_lock(genpd);
+       gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
+       if (!gpd_data)
+               return -ENOMEM;
 
-       if (genpd->status == GPD_STATE_POWER_OFF) {
-               ret = -EINVAL;
-               goto out;
-       }
+       mutex_init(&gpd_data->lock);
+       gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
+       dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+
+       genpd_acquire_lock(genpd);
 
        if (genpd->prepared_count > 0) {
                ret = -EAGAIN;
@@ -1227,26 +1274,35 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
                        goto out;
                }
 
-       gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
-       if (!gpd_data) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
        genpd->device_count++;
+       genpd->max_off_time_changed = true;
 
-       dev->pm_domain = &genpd->domain;
        dev_pm_get_subsys_data(dev);
+
+       mutex_lock(&gpd_data->lock);
+       spin_lock_irq(&dev->power.lock);
+       dev->pm_domain = &genpd->domain;
        dev->power.subsys_data->domain_data = &gpd_data->base;
        gpd_data->base.dev = dev;
-       gpd_data->need_restore = false;
        list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
+       gpd_data->need_restore = genpd->status == GPD_STATE_POWER_OFF;
        if (td)
                gpd_data->td = *td;
 
+       gpd_data->td.constraint_changed = true;
+       gpd_data->td.effective_constraint_ns = -1;
+       spin_unlock_irq(&dev->power.lock);
+       mutex_unlock(&gpd_data->lock);
+
+       genpd_release_lock(genpd);
+
+       return 0;
+
  out:
        genpd_release_lock(genpd);
 
+       dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+       kfree(gpd_data);
        return ret;
 }
 
@@ -1290,12 +1346,15 @@ int __pm_genpd_of_add_device(struct device_node *genpd_node, struct device *dev,
 int pm_genpd_remove_device(struct generic_pm_domain *genpd,
                           struct device *dev)
 {
+       struct generic_pm_domain_data *gpd_data;
        struct pm_domain_data *pdd;
-       int ret = -EINVAL;
+       int ret = 0;
 
        dev_dbg(dev, "%s()\n", __func__);
 
-       if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
+       if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)
+           ||  IS_ERR_OR_NULL(dev->pm_domain)
+           ||  pd_to_genpd(dev->pm_domain) != genpd)
                return -EINVAL;
 
        genpd_acquire_lock(genpd);
@@ -1305,21 +1364,27 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
                goto out;
        }
 
-       list_for_each_entry(pdd, &genpd->dev_list, list_node) {
-               if (pdd->dev != dev)
-                       continue;
+       genpd->device_count--;
+       genpd->max_off_time_changed = true;
 
-               list_del_init(&pdd->list_node);
-               pdd->dev = NULL;
-               dev_pm_put_subsys_data(dev);
-               dev->pm_domain = NULL;
-               kfree(to_gpd_data(pdd));
+       spin_lock_irq(&dev->power.lock);
+       dev->pm_domain = NULL;
+       pdd = dev->power.subsys_data->domain_data;
+       list_del_init(&pdd->list_node);
+       dev->power.subsys_data->domain_data = NULL;
+       spin_unlock_irq(&dev->power.lock);
 
-               genpd->device_count--;
+       gpd_data = to_gpd_data(pdd);
+       mutex_lock(&gpd_data->lock);
+       pdd->dev = NULL;
+       mutex_unlock(&gpd_data->lock);
 
-               ret = 0;
-               break;
-       }
+       genpd_release_lock(genpd);
+
+       dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+       kfree(gpd_data);
+       dev_pm_put_subsys_data(dev);
+       return 0;
 
  out:
        genpd_release_lock(genpd);
@@ -1347,6 +1412,26 @@ void pm_genpd_dev_always_on(struct device *dev, bool val)
 }
 EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on);
 
+/**
+ * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag.
+ * @dev: Device to set/unset the flag for.
+ * @val: The new value of the device's "need restore" flag.
+ */
+void pm_genpd_dev_need_restore(struct device *dev, bool val)
+{
+       struct pm_subsys_data *psd;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->power.lock, flags);
+
+       psd = dev_to_psd(dev);
+       if (psd && psd->domain_data)
+               to_gpd_data(psd->domain_data)->need_restore = val;
+
+       spin_unlock_irqrestore(&dev->power.lock, flags);
+}
+EXPORT_SYMBOL_GPL(pm_genpd_dev_need_restore);
+
 /**
  * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
  * @genpd: Master PM domain to add the subdomain to.
@@ -1378,7 +1463,7 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
                goto out;
        }
 
-       list_for_each_entry(link, &genpd->slave_links, slave_node) {
+       list_for_each_entry(link, &genpd->master_links, master_node) {
                if (link->slave == subdomain && link->master == genpd) {
                        ret = -EINVAL;
                        goto out;
@@ -1690,6 +1775,7 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
        genpd->resume_count = 0;
        genpd->device_count = 0;
        genpd->max_off_time_ns = -1;
+       genpd->max_off_time_changed = true;
        genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
        genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
        genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
index 66a265bf5867d1b516a03f34e8e50946db4c1e3e..28dee3053f1fa14e4e29afedbc29260b757feb77 100644 (file)
 
 #ifdef CONFIG_PM_RUNTIME
 
+static int dev_update_qos_constraint(struct device *dev, void *data)
+{
+       s64 *constraint_ns_p = data;
+       s32 constraint_ns = -1;
+
+       if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
+               constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
+
+       if (constraint_ns < 0) {
+               constraint_ns = dev_pm_qos_read_value(dev);
+               constraint_ns *= NSEC_PER_USEC;
+       }
+       if (constraint_ns == 0)
+               return 0;
+
+       /*
+        * constraint_ns cannot be negative here, because the device has been
+        * suspended.
+        */
+       if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
+               *constraint_ns_p = constraint_ns;
+
+       return 0;
+}
+
 /**
  * default_stop_ok - Default PM domain governor routine for stopping devices.
  * @dev: Device to check.
 bool default_stop_ok(struct device *dev)
 {
        struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+       unsigned long flags;
+       s64 constraint_ns;
 
        dev_dbg(dev, "%s()\n", __func__);
 
-       if (dev->power.max_time_suspended_ns < 0 || td->break_even_ns == 0)
-               return true;
+       spin_lock_irqsave(&dev->power.lock, flags);
+
+       if (!td->constraint_changed) {
+               bool ret = td->cached_stop_ok;
 
-       return td->stop_latency_ns + td->start_latency_ns < td->break_even_ns
-               && td->break_even_ns < dev->power.max_time_suspended_ns;
+               spin_unlock_irqrestore(&dev->power.lock, flags);
+               return ret;
+       }
+       td->constraint_changed = false;
+       td->cached_stop_ok = false;
+       td->effective_constraint_ns = -1;
+       constraint_ns = __dev_pm_qos_read_value(dev);
+
+       spin_unlock_irqrestore(&dev->power.lock, flags);
+
+       if (constraint_ns < 0)
+               return false;
+
+       constraint_ns *= NSEC_PER_USEC;
+       /*
+        * We can walk the children without any additional locking, because
+        * they all have been suspended at this point and their
+        * effective_constraint_ns fields won't be modified in parallel with us.
+        */
+       if (!dev->power.ignore_children)
+               device_for_each_child(dev, &constraint_ns,
+                                     dev_update_qos_constraint);
+
+       if (constraint_ns > 0) {
+               constraint_ns -= td->start_latency_ns;
+               if (constraint_ns == 0)
+                       return false;
+       }
+       td->effective_constraint_ns = constraint_ns;
+       td->cached_stop_ok = constraint_ns > td->stop_latency_ns ||
+                               constraint_ns == 0;
+       /*
+        * The children have been suspended already, so we don't need to take
+        * their stop latencies into account here.
+        */
+       return td->cached_stop_ok;
 }
 
 /**
@@ -42,9 +105,27 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
        struct generic_pm_domain *genpd = pd_to_genpd(pd);
        struct gpd_link *link;
        struct pm_domain_data *pdd;
-       s64 min_dev_off_time_ns;
+       s64 min_off_time_ns;
        s64 off_on_time_ns;
-       ktime_t time_now = ktime_get();
+
+       if (genpd->max_off_time_changed) {
+               struct gpd_link *link;
+
+               /*
+                * We have to invalidate the cached results for the masters, so
+                * use the observation that default_power_down_ok() is not
+                * going to be called for any master until this instance
+                * returns.
+                */
+               list_for_each_entry(link, &genpd->slave_links, slave_node)
+                       link->master->max_off_time_changed = true;
+
+               genpd->max_off_time_changed = false;
+               genpd->cached_power_down_ok = false;
+               genpd->max_off_time_ns = -1;
+       } else {
+               return genpd->cached_power_down_ok;
+       }
 
        off_on_time_ns = genpd->power_off_latency_ns +
                                genpd->power_on_latency_ns;
@@ -61,6 +142,7 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
                                to_gpd_data(pdd)->td.save_state_latency_ns;
        }
 
+       min_off_time_ns = -1;
        /*
         * Check if subdomains can be off for enough time.
         *
@@ -73,8 +155,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
                if (sd_max_off_ns < 0)
                        continue;
 
-               sd_max_off_ns -= ktime_to_ns(ktime_sub(time_now,
-                                                      sd->power_off_time));
                /*
                 * Check if the subdomain is allowed to be off long enough for
                 * the current domain to turn off and on (that's how much time
@@ -82,60 +162,64 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
                 */
                if (sd_max_off_ns <= off_on_time_ns)
                        return false;
+
+               if (min_off_time_ns > sd_max_off_ns || min_off_time_ns < 0)
+                       min_off_time_ns = sd_max_off_ns;
        }
 
        /*
         * Check if the devices in the domain can be off enough time.
         */
-       min_dev_off_time_ns = -1;
        list_for_each_entry(pdd, &genpd->dev_list, list_node) {
                struct gpd_timing_data *td;
-               struct device *dev = pdd->dev;
-               s64 dev_off_time_ns;
+               s64 constraint_ns;
 
-               if (!dev->driver || dev->power.max_time_suspended_ns < 0)
+               if (!pdd->dev->driver)
                        continue;
 
+               /*
+                * Check if the device is allowed to be off long enough for the
+                * domain to turn off and on (that's how much time it will
+                * have to wait worst case).
+                */
                td = &to_gpd_data(pdd)->td;
-               dev_off_time_ns = dev->power.max_time_suspended_ns -
-                       (td->start_latency_ns + td->restore_state_latency_ns +
-                               ktime_to_ns(ktime_sub(time_now,
-                                               dev->power.suspend_time)));
-               if (dev_off_time_ns <= off_on_time_ns)
-                       return false;
-
-               if (min_dev_off_time_ns > dev_off_time_ns
-                   || min_dev_off_time_ns < 0)
-                       min_dev_off_time_ns = dev_off_time_ns;
-       }
+               constraint_ns = td->effective_constraint_ns;
+               /* default_stop_ok() need not be called before us. */
+               if (constraint_ns < 0) {
+                       constraint_ns = dev_pm_qos_read_value(pdd->dev);
+                       constraint_ns *= NSEC_PER_USEC;
+               }
+               if (constraint_ns == 0)
+                       continue;
 
-       if (min_dev_off_time_ns < 0) {
                /*
-                * There are no latency constraints, so the domain can spend
-                * arbitrary time in the "off" state.
+                * constraint_ns cannot be negative here, because the device has
+                * been suspended.
                 */
-               genpd->max_off_time_ns = -1;
-               return true;
+               constraint_ns -= td->restore_state_latency_ns;
+               if (constraint_ns <= off_on_time_ns)
+                       return false;
+
+               if (min_off_time_ns > constraint_ns || min_off_time_ns < 0)
+                       min_off_time_ns = constraint_ns;
        }
 
+       genpd->cached_power_down_ok = true;
+
        /*
-        * The difference between the computed minimum delta and the time needed
-        * to turn the domain on is the maximum theoretical time this domain can
-        * spend in the "off" state.
+        * If the computed minimum device off time is negative, there are no
+        * latency constraints, so the domain can spend arbitrary time in the
+        * "off" state.
         */
-       min_dev_off_time_ns -= genpd->power_on_latency_ns;
+       if (min_off_time_ns < 0)
+               return true;
 
        /*
-        * If the difference between the computed minimum delta and the time
-        * needed to turn the domain off and back on on is smaller than the
-        * domain's power break even time, removing power from the domain is not
-        * worth it.
+        * The difference between the computed minimum subdomain or device off
+        * time and the time needed to turn the domain on is the maximum
+        * theoretical time this domain can spend in the "off" state.
         */
-       if (genpd->break_even_ns >
-           min_dev_off_time_ns - genpd->power_off_latency_ns)
-               return false;
-
-       genpd->max_off_time_ns = min_dev_off_time_ns;
+       genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns;
        return true;
 }
 
index b462c0e341cbf6721fc2ab1dc7f59314f344f625..e0fb5b0435a350abaa5a23c30e76f4e5d691001a 100644 (file)
@@ -889,6 +889,11 @@ static int dpm_suspend_noirq(pm_message_t state)
                if (!list_empty(&dev->power.entry))
                        list_move(&dev->power.entry, &dpm_noirq_list);
                put_device(dev);
+
+               if (pm_wakeup_pending()) {
+                       error = -EBUSY;
+                       break;
+               }
        }
        mutex_unlock(&dpm_list_mtx);
        if (error)
@@ -962,6 +967,11 @@ static int dpm_suspend_late(pm_message_t state)
                if (!list_empty(&dev->power.entry))
                        list_move(&dev->power.entry, &dpm_late_early_list);
                put_device(dev);
+
+               if (pm_wakeup_pending()) {
+                       error = -EBUSY;
+                       break;
+               }
        }
        mutex_unlock(&dpm_list_mtx);
        if (error)
index 71855570922de8248a04fb762d633c2ff80895da..fd849a2c4fa8fdaa4ae3ac10a8ce853b9e14bec7 100644 (file)
@@ -352,21 +352,26 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
  *
  * Will register the notifier into a notification chain that gets called
  * upon changes to the target value for the device.
+ *
+ * If the device's constraints object doesn't exist when this routine is called,
+ * it will be created (or error code will be returned if that fails).
  */
 int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
 {
-       int retval = 0;
+       int ret = 0;
 
        mutex_lock(&dev_pm_qos_mtx);
 
-       /* Silently return if the constraints object is not present. */
-       if (dev->power.constraints)
-               retval = blocking_notifier_chain_register(
-                               dev->power.constraints->notifiers,
-                               notifier);
+       if (!dev->power.constraints)
+               ret = dev->power.power_state.event != PM_EVENT_INVALID ?
+                       dev_pm_qos_constraints_allocate(dev) : -ENODEV;
+
+       if (!ret)
+               ret = blocking_notifier_chain_register(
+                               dev->power.constraints->notifiers, notifier);
 
        mutex_unlock(&dev_pm_qos_mtx);
-       return retval;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
 
index bd0f3949bcf920a50c3a1baf586f620b4ef88394..59894873a3b37de88a50d3b5e1f22ce67e454858 100644 (file)
@@ -282,47 +282,6 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
        return retval != -EACCES ? retval : -EIO;
 }
 
-struct rpm_qos_data {
-       ktime_t time_now;
-       s64 constraint_ns;
-};
-
-/**
- * rpm_update_qos_constraint - Update a given PM QoS constraint data.
- * @dev: Device whose timing data to use.
- * @data: PM QoS constraint data to update.
- *
- * Use the suspend timing data of @dev to update PM QoS constraint data pointed
- * to by @data.
- */
-static int rpm_update_qos_constraint(struct device *dev, void *data)
-{
-       struct rpm_qos_data *qos = data;
-       unsigned long flags;
-       s64 delta_ns;
-       int ret = 0;
-
-       spin_lock_irqsave(&dev->power.lock, flags);
-
-       if (dev->power.max_time_suspended_ns < 0)
-               goto out;
-
-       delta_ns = dev->power.max_time_suspended_ns -
-               ktime_to_ns(ktime_sub(qos->time_now, dev->power.suspend_time));
-       if (delta_ns <= 0) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       if (qos->constraint_ns > delta_ns || qos->constraint_ns == 0)
-               qos->constraint_ns = delta_ns;
-
- out:
-       spin_unlock_irqrestore(&dev->power.lock, flags);
-
-       return ret;
-}
-
 /**
  * rpm_suspend - Carry out runtime suspend of given device.
  * @dev: Device to suspend.
@@ -349,7 +308,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
 {
        int (*callback)(struct device *);
        struct device *parent = NULL;
-       struct rpm_qos_data qos;
        int retval;
 
        trace_rpm_suspend(dev, rpmflags);
@@ -445,38 +403,14 @@ static int rpm_suspend(struct device *dev, int rpmflags)
                goto out;
        }
 
-       qos.constraint_ns = __dev_pm_qos_read_value(dev);
-       if (qos.constraint_ns < 0) {
-               /* Negative constraint means "never suspend". */
+       if (__dev_pm_qos_read_value(dev) < 0) {
+               /* Negative PM QoS constraint means "never suspend". */
                retval = -EPERM;
                goto out;
        }
-       qos.constraint_ns *= NSEC_PER_USEC;
-       qos.time_now = ktime_get();
 
        __update_runtime_status(dev, RPM_SUSPENDING);
 
-       if (!dev->power.ignore_children) {
-               if (dev->power.irq_safe)
-                       spin_unlock(&dev->power.lock);
-               else
-                       spin_unlock_irq(&dev->power.lock);
-
-               retval = device_for_each_child(dev, &qos,
-                                              rpm_update_qos_constraint);
-
-               if (dev->power.irq_safe)
-                       spin_lock(&dev->power.lock);
-               else
-                       spin_lock_irq(&dev->power.lock);
-
-               if (retval)
-                       goto fail;
-       }
-
-       dev->power.suspend_time = qos.time_now;
-       dev->power.max_time_suspended_ns = qos.constraint_ns ? : -1;
-
        if (dev->pm_domain)
                callback = dev->pm_domain->ops.runtime_suspend;
        else if (dev->type && dev->type->pm)
@@ -529,8 +463,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
 
  fail:
        __update_runtime_status(dev, RPM_ACTIVE);
-       dev->power.suspend_time = ktime_set(0, 0);
-       dev->power.max_time_suspended_ns = -1;
        dev->power.deferred_resume = false;
        wake_up_all(&dev->power.wait_queue);
 
@@ -704,9 +636,6 @@ static int rpm_resume(struct device *dev, int rpmflags)
        if (dev->power.no_callbacks)
                goto no_callback;       /* Assume success. */
 
-       dev->power.suspend_time = ktime_set(0, 0);
-       dev->power.max_time_suspended_ns = -1;
-
        __update_runtime_status(dev, RPM_RESUMING);
 
        if (dev->pm_domain)
@@ -1369,9 +1298,6 @@ void pm_runtime_init(struct device *dev)
        setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
                        (unsigned long)dev);
 
-       dev->power.suspend_time = ktime_set(0, 0);
-       dev->power.max_time_suspended_ns = -1;
-
        init_waitqueue_head(&dev->power.wait_queue);
 }
 
@@ -1389,28 +1315,3 @@ void pm_runtime_remove(struct device *dev)
        if (dev->power.irq_safe && dev->parent)
                pm_runtime_put_sync(dev->parent);
 }
-
-/**
- * pm_runtime_update_max_time_suspended - Update device's suspend time data.
- * @dev: Device to handle.
- * @delta_ns: Value to subtract from the device's max_time_suspended_ns field.
- *
- * Update the device's power.max_time_suspended_ns field by subtracting
- * @delta_ns from it.  The resulting value of power.max_time_suspended_ns is
- * never negative.
- */
-void pm_runtime_update_max_time_suspended(struct device *dev, s64 delta_ns)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->power.lock, flags);
-
-       if (delta_ns > 0 && dev->power.max_time_suspended_ns > 0) {
-               if (dev->power.max_time_suspended_ns > delta_ns)
-                       dev->power.max_time_suspended_ns -= delta_ns;
-               else
-                       dev->power.max_time_suspended_ns = 0;
-       }
-
-       spin_unlock_irqrestore(&dev->power.lock, flags);
-}
index 95c12f6cb5b90da6257b95f839da60bfe3235c97..48be2ad4dd2cb4f54c592bfdcaf99f2aa509ca8c 100644 (file)
@@ -314,22 +314,41 @@ static ssize_t wakeup_active_count_show(struct device *dev,
 
 static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL);
 
-static ssize_t wakeup_hit_count_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
+static ssize_t wakeup_abort_count_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       unsigned long count = 0;
+       bool enabled = false;
+
+       spin_lock_irq(&dev->power.lock);
+       if (dev->power.wakeup) {
+               count = dev->power.wakeup->wakeup_count;
+               enabled = true;
+       }
+       spin_unlock_irq(&dev->power.lock);
+       return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_abort_count, 0444, wakeup_abort_count_show, NULL);
+
+static ssize_t wakeup_expire_count_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
 {
        unsigned long count = 0;
        bool enabled = false;
 
        spin_lock_irq(&dev->power.lock);
        if (dev->power.wakeup) {
-               count = dev->power.wakeup->hit_count;
+               count = dev->power.wakeup->expire_count;
                enabled = true;
        }
        spin_unlock_irq(&dev->power.lock);
        return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
 }
 
-static DEVICE_ATTR(wakeup_hit_count, 0444, wakeup_hit_count_show, NULL);
+static DEVICE_ATTR(wakeup_expire_count, 0444, wakeup_expire_count_show, NULL);
 
 static ssize_t wakeup_active_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
@@ -398,6 +417,27 @@ static ssize_t wakeup_last_time_show(struct device *dev,
 }
 
 static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL);
+
+#ifdef CONFIG_PM_AUTOSLEEP
+static ssize_t wakeup_prevent_sleep_time_show(struct device *dev,
+                                             struct device_attribute *attr,
+                                             char *buf)
+{
+       s64 msec = 0;
+       bool enabled = false;
+
+       spin_lock_irq(&dev->power.lock);
+       if (dev->power.wakeup) {
+               msec = ktime_to_ms(dev->power.wakeup->prevent_sleep_time);
+               enabled = true;
+       }
+       spin_unlock_irq(&dev->power.lock);
+       return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_prevent_sleep_time_ms, 0444,
+                  wakeup_prevent_sleep_time_show, NULL);
+#endif /* CONFIG_PM_AUTOSLEEP */
 #endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PM_ADVANCED_DEBUG
@@ -486,11 +526,15 @@ static struct attribute *wakeup_attrs[] = {
        &dev_attr_wakeup.attr,
        &dev_attr_wakeup_count.attr,
        &dev_attr_wakeup_active_count.attr,
-       &dev_attr_wakeup_hit_count.attr,
+       &dev_attr_wakeup_abort_count.attr,
+       &dev_attr_wakeup_expire_count.attr,
        &dev_attr_wakeup_active.attr,
        &dev_attr_wakeup_total_time_ms.attr,
        &dev_attr_wakeup_max_time_ms.attr,
        &dev_attr_wakeup_last_time_ms.attr,
+#ifdef CONFIG_PM_AUTOSLEEP
+       &dev_attr_wakeup_prevent_sleep_time_ms.attr,
+#endif
 #endif
        NULL,
 };
index 2a3e581b8dcd167fa676eedc44b3426c8dc9d08a..cbb463b3a750e30bc70d7d8de40ff7555e7670ee 100644 (file)
 #include <linux/suspend.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
+#include <trace/events/power.h>
 
 #include "power.h"
 
-#define TIMEOUT                100
-
 /*
  * If set, the suspend/hibernate code will abort transitions to a sleep state
  * if wakeup events are registered during or immediately before the transition.
  */
-bool events_check_enabled;
+bool events_check_enabled __read_mostly;
 
 /*
  * Combined counters of registered wakeup events and wakeup events in progress.
@@ -52,6 +51,8 @@ static void pm_wakeup_timer_fn(unsigned long data);
 
 static LIST_HEAD(wakeup_sources);
 
+static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);
+
 /**
  * wakeup_source_prepare - Prepare a new wakeup source for initialization.
  * @ws: Wakeup source to prepare.
@@ -132,6 +133,7 @@ void wakeup_source_add(struct wakeup_source *ws)
        spin_lock_init(&ws->lock);
        setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);
        ws->active = false;
+       ws->last_time = ktime_get();
 
        spin_lock_irq(&events_lock);
        list_add_rcu(&ws->entry, &wakeup_sources);
@@ -374,12 +376,33 @@ EXPORT_SYMBOL_GPL(device_set_wakeup_enable);
  */
 static void wakeup_source_activate(struct wakeup_source *ws)
 {
+       unsigned int cec;
+
        ws->active = true;
        ws->active_count++;
        ws->last_time = ktime_get();
+       if (ws->autosleep_enabled)
+               ws->start_prevent_time = ws->last_time;
 
        /* Increment the counter of events in progress. */
-       atomic_inc(&combined_event_count);
+       cec = atomic_inc_return(&combined_event_count);
+
+       trace_wakeup_source_activate(ws->name, cec);
+}
+
+/**
+ * wakeup_source_report_event - Report wakeup event using the given source.
+ * @ws: Wakeup source to report the event for.
+ */
+static void wakeup_source_report_event(struct wakeup_source *ws)
+{
+       ws->event_count++;
+       /* This is racy, but the counter is approximate anyway. */
+       if (events_check_enabled)
+               ws->wakeup_count++;
+
+       if (!ws->active)
+               wakeup_source_activate(ws);
 }
 
 /**
@@ -397,10 +420,7 @@ void __pm_stay_awake(struct wakeup_source *ws)
 
        spin_lock_irqsave(&ws->lock, flags);
 
-       ws->event_count++;
-       if (!ws->active)
-               wakeup_source_activate(ws);
-
+       wakeup_source_report_event(ws);
        del_timer(&ws->timer);
        ws->timer_expires = 0;
 
@@ -432,6 +452,17 @@ void pm_stay_awake(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(pm_stay_awake);
 
+#ifdef CONFIG_PM_AUTOSLEEP
+static void update_prevent_sleep_time(struct wakeup_source *ws, ktime_t now)
+{
+       ktime_t delta = ktime_sub(now, ws->start_prevent_time);
+       ws->prevent_sleep_time = ktime_add(ws->prevent_sleep_time, delta);
+}
+#else
+static inline void update_prevent_sleep_time(struct wakeup_source *ws,
+                                            ktime_t now) {}
+#endif
+
 /**
  * wakup_source_deactivate - Mark given wakeup source as inactive.
  * @ws: Wakeup source to handle.
@@ -442,6 +473,7 @@ EXPORT_SYMBOL_GPL(pm_stay_awake);
  */
 static void wakeup_source_deactivate(struct wakeup_source *ws)
 {
+       unsigned int cnt, inpr, cec;
        ktime_t duration;
        ktime_t now;
 
@@ -468,14 +500,23 @@ static void wakeup_source_deactivate(struct wakeup_source *ws)
        if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))
                ws->max_time = duration;
 
+       ws->last_time = now;
        del_timer(&ws->timer);
        ws->timer_expires = 0;
 
+       if (ws->autosleep_enabled)
+               update_prevent_sleep_time(ws, now);
+
        /*
         * Increment the counter of registered wakeup events and decrement the
         * couter of wakeup events in progress simultaneously.
         */
-       atomic_add(MAX_IN_PROGRESS, &combined_event_count);
+       cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count);
+       trace_wakeup_source_deactivate(ws->name, cec);
+
+       split_counters(&cnt, &inpr);
+       if (!inpr && waitqueue_active(&wakeup_count_wait_queue))
+               wake_up(&wakeup_count_wait_queue);
 }
 
 /**
@@ -536,8 +577,10 @@ static void pm_wakeup_timer_fn(unsigned long data)
        spin_lock_irqsave(&ws->lock, flags);
 
        if (ws->active && ws->timer_expires
-           && time_after_eq(jiffies, ws->timer_expires))
+           && time_after_eq(jiffies, ws->timer_expires)) {
                wakeup_source_deactivate(ws);
+               ws->expire_count++;
+       }
 
        spin_unlock_irqrestore(&ws->lock, flags);
 }
@@ -564,9 +607,7 @@ void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec)
 
        spin_lock_irqsave(&ws->lock, flags);
 
-       ws->event_count++;
-       if (!ws->active)
-               wakeup_source_activate(ws);
+       wakeup_source_report_event(ws);
 
        if (!msec) {
                wakeup_source_deactivate(ws);
@@ -608,24 +649,6 @@ void pm_wakeup_event(struct device *dev, unsigned int msec)
 }
 EXPORT_SYMBOL_GPL(pm_wakeup_event);
 
-/**
- * pm_wakeup_update_hit_counts - Update hit counts of all active wakeup sources.
- */
-static void pm_wakeup_update_hit_counts(void)
-{
-       unsigned long flags;
-       struct wakeup_source *ws;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
-               spin_lock_irqsave(&ws->lock, flags);
-               if (ws->active)
-                       ws->hit_count++;
-               spin_unlock_irqrestore(&ws->lock, flags);
-       }
-       rcu_read_unlock();
-}
-
 /**
  * pm_wakeup_pending - Check if power transition in progress should be aborted.
  *
@@ -648,32 +671,38 @@ bool pm_wakeup_pending(void)
                events_check_enabled = !ret;
        }
        spin_unlock_irqrestore(&events_lock, flags);
-       if (ret)
-               pm_wakeup_update_hit_counts();
        return ret;
 }
 
 /**
  * pm_get_wakeup_count - Read the number of registered wakeup events.
  * @count: Address to store the value at.
+ * @block: Whether or not to block.
  *
- * Store the number of registered wakeup events at the address in @count.  Block
- * if the current number of wakeup events being processed is nonzero.
+ * Store the number of registered wakeup events at the address in @count.  If
+ * @block is set, block until the current number of wakeup events being
+ * processed is zero.
  *
- * Return 'false' if the wait for the number of wakeup events being processed to
- * drop down to zero has been interrupted by a signal (and the current number
- * of wakeup events being processed is still nonzero).  Otherwise return 'true'.
+ * Return 'false' if the current number of wakeup events being processed is
+ * nonzero.  Otherwise return 'true'.
  */
-bool pm_get_wakeup_count(unsigned int *count)
+bool pm_get_wakeup_count(unsigned int *count, bool block)
 {
        unsigned int cnt, inpr;
 
-       for (;;) {
-               split_counters(&cnt, &inpr);
-               if (inpr == 0 || signal_pending(current))
-                       break;
-               pm_wakeup_update_hit_counts();
-               schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT));
+       if (block) {
+               DEFINE_WAIT(wait);
+
+               for (;;) {
+                       prepare_to_wait(&wakeup_count_wait_queue, &wait,
+                                       TASK_INTERRUPTIBLE);
+                       split_counters(&cnt, &inpr);
+                       if (inpr == 0 || signal_pending(current))
+                               break;
+
+                       schedule();
+               }
+               finish_wait(&wakeup_count_wait_queue, &wait);
        }
 
        split_counters(&cnt, &inpr);
@@ -703,11 +732,37 @@ bool pm_save_wakeup_count(unsigned int count)
                events_check_enabled = true;
        }
        spin_unlock_irq(&events_lock);
-       if (!events_check_enabled)
-               pm_wakeup_update_hit_counts();
        return events_check_enabled;
 }
 
+#ifdef CONFIG_PM_AUTOSLEEP
+/**
+ * pm_wakep_autosleep_enabled - Modify autosleep_enabled for all wakeup sources.
+ * @enabled: Whether to set or to clear the autosleep_enabled flags.
+ */
+void pm_wakep_autosleep_enabled(bool set)
+{
+       struct wakeup_source *ws;
+       ktime_t now = ktime_get();
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+               spin_lock_irq(&ws->lock);
+               if (ws->autosleep_enabled != set) {
+                       ws->autosleep_enabled = set;
+                       if (ws->active) {
+                               if (set)
+                                       ws->start_prevent_time = now;
+                               else
+                                       update_prevent_sleep_time(ws, now);
+                       }
+               }
+               spin_unlock_irq(&ws->lock);
+       }
+       rcu_read_unlock();
+}
+#endif /* CONFIG_PM_AUTOSLEEP */
+
 static struct dentry *wakeup_sources_stats_dentry;
 
 /**
@@ -723,27 +778,37 @@ static int print_wakeup_source_stats(struct seq_file *m,
        ktime_t max_time;
        unsigned long active_count;
        ktime_t active_time;
+       ktime_t prevent_sleep_time;
        int ret;
 
        spin_lock_irqsave(&ws->lock, flags);
 
        total_time = ws->total_time;
        max_time = ws->max_time;
+       prevent_sleep_time = ws->prevent_sleep_time;
        active_count = ws->active_count;
        if (ws->active) {
-               active_time = ktime_sub(ktime_get(), ws->last_time);
+               ktime_t now = ktime_get();
+
+               active_time = ktime_sub(now, ws->last_time);
                total_time = ktime_add(total_time, active_time);
                if (active_time.tv64 > max_time.tv64)
                        max_time = active_time;
+
+               if (ws->autosleep_enabled)
+                       prevent_sleep_time = ktime_add(prevent_sleep_time,
+                               ktime_sub(now, ws->start_prevent_time));
        } else {
                active_time = ktime_set(0, 0);
        }
 
-       ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t"
-                       "%lld\t\t%lld\t\t%lld\t\t%lld\n",
-                       ws->name, active_count, ws->event_count, ws->hit_count,
+       ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t"
+                       "%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",
+                       ws->name, active_count, ws->event_count,
+                       ws->wakeup_count, ws->expire_count,
                        ktime_to_ms(active_time), ktime_to_ms(total_time),
-                       ktime_to_ms(max_time), ktime_to_ms(ws->last_time));
+                       ktime_to_ms(max_time), ktime_to_ms(ws->last_time),
+                       ktime_to_ms(prevent_sleep_time));
 
        spin_unlock_irqrestore(&ws->lock, flags);
 
@@ -758,8 +823,9 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
 {
        struct wakeup_source *ws;
 
-       seq_puts(m, "name\t\tactive_count\tevent_count\thit_count\t"
-               "active_since\ttotal_time\tmax_time\tlast_change\n");
+       seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
+               "expire_count\tactive_since\ttotal_time\tmax_time\t"
+               "last_change\tprevent_suspend_time\n");
 
        rcu_read_lock();
        list_for_each_entry_rcu(ws, &wakeup_sources, entry)
index 9ef0a5326f170e9f4b0b8c3a661842c2f98e2668..6be390bd8bd1bc3f0fa1e3bfc38cd56f36bfa6be 100644 (file)
@@ -6,6 +6,7 @@ config REGMAP
        default y if (REGMAP_I2C || REGMAP_SPI)
        select LZO_COMPRESS
        select LZO_DECOMPRESS
+       select IRQ_DOMAIN if REGMAP_IRQ
        bool
 
 config REGMAP_I2C
index b2402eb076c787eafd111d643982f0a6422bb41a..c225314468ee82d42abfe2a769a80d233e9087b1 100644 (file)
@@ -250,3 +250,16 @@ config UML_RANDOM
          (check your distro, or download from
          http://sourceforge.net/projects/gkernel/).  rngd periodically reads
          /dev/hwrng and injects the entropy into /dev/random.
+
+config HW_RANDOM_PSERIES
+       tristate "pSeries HW Random Number Generator support"
+       depends on HW_RANDOM && PPC64 && IBMVIO
+       default HW_RANDOM
+       ---help---
+         This driver provides kernel-side support for the Random Number
+         Generator hardware found on POWER7+ machines and above
+
+         To compile this driver as a module, choose M here: the
+         module will be called pseries-rng.
+
+         If unsure, say Y.
index b2ff5265a99637690d874b09a267775a2bfdda66..d901dfa3032104773e735f5fb3c16e23994a4e70 100644 (file)
@@ -22,3 +22,4 @@ obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
 obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
 obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o
 obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o
+obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c
new file mode 100644 (file)
index 0000000..5f11979
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 Michael Neuling IBM Corporation
+ *
+ * Driver for the pseries hardware RNG for POWER7+ and above
+ *
+ * This program is free software; you can 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
+ */
+
+#include <linux/module.h>
+#include <linux/hw_random.h>
+#include <asm/vio.h>
+
+#define MODULE_NAME "pseries-rng"
+
+static int pseries_rng_data_read(struct hwrng *rng, u32 *data)
+{
+       if (plpar_hcall(H_RANDOM, (unsigned long *)data) != H_SUCCESS) {
+               printk(KERN_ERR "pseries rng hcall error\n");
+               return 0;
+       }
+       return 8;
+}
+
+/**
+ * pseries_rng_get_desired_dma - Return desired DMA allocate for CMO operations
+ *
+ * This is a required function for a driver to operate in a CMO environment
+ * but this device does not make use of DMA allocations, return 0.
+ *
+ * Return value:
+ *     Number of bytes of IO data the driver will need to perform well -> 0
+ */
+static unsigned long pseries_rng_get_desired_dma(struct vio_dev *vdev)
+{
+       return 0;
+};
+
+static struct hwrng pseries_rng = {
+       .name           = MODULE_NAME,
+       .data_read      = pseries_rng_data_read,
+};
+
+static int __init pseries_rng_probe(struct vio_dev *dev,
+               const struct vio_device_id *id)
+{
+       return hwrng_register(&pseries_rng);
+}
+
+static int __exit pseries_rng_remove(struct vio_dev *dev)
+{
+       hwrng_unregister(&pseries_rng);
+       return 0;
+}
+
+static struct vio_device_id pseries_rng_driver_ids[] = {
+       { "ibm,random-v1", "ibm,random"},
+       { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, pseries_rng_driver_ids);
+
+static struct vio_driver pseries_rng_driver = {
+       .name = MODULE_NAME,
+       .probe = pseries_rng_probe,
+       .remove = pseries_rng_remove,
+       .get_desired_dma = pseries_rng_get_desired_dma,
+       .id_table = pseries_rng_driver_ids
+};
+
+static int __init rng_init(void)
+{
+       printk(KERN_INFO "Registering IBM pSeries RNG driver\n");
+       return vio_register_driver(&pseries_rng_driver);
+}
+
+module_init(rng_init);
+
+static void __exit rng_exit(void)
+{
+       vio_unregister_driver(&pseries_rng_driver);
+}
+module_exit(rng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Neuling <mikey@neuling.org>");
+MODULE_DESCRIPTION("H/W RNG driver for IBM pSeries processors");
index 371f13cc38eb7bf0259c0edf823f31f0701c31de..6373fa0ddb65e5c7a1ecab5d94281e3b4e17222a 100644 (file)
@@ -297,4 +297,21 @@ config CRYPTO_DEV_TEGRA_AES
          To compile this driver as a module, choose M here: the module
          will be called tegra-aes.
 
+config CRYPTO_DEV_NX
+       tristate "Support for Power7+ in-Nest cryptographic accleration"
+       depends on PPC64 && IBMVIO
+       select CRYPTO_AES
+       select CRYPTO_CBC
+       select CRYPTO_ECB
+       select CRYPTO_CCM
+       select CRYPTO_GCM
+       select CRYPTO_AUTHENC
+       select CRYPTO_XCBC
+       select CRYPTO_SHA256
+       select CRYPTO_SHA512
+       help
+         Support for Power7+ in-Nest cryptographic acceleration. This
+         module supports acceleration for AES and SHA2 algorithms. If you
+         choose 'M' here, this module will be called nx_crypto.
+
 endif # CRYPTO_HW
diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile
new file mode 100644 (file)
index 0000000..411ce59
--- /dev/null
@@ -0,0 +1,11 @@
+obj-$(CONFIG_CRYPTO_DEV_NX) += nx-crypto.o
+nx-crypto-objs := nx.o \
+                 nx_debugfs.o \
+                 nx-aes-cbc.o \
+                 nx-aes-ecb.o \
+                 nx-aes-gcm.o \
+                 nx-aes-ccm.o \
+                 nx-aes-ctr.o \
+                 nx-aes-xcbc.o \
+                 nx-sha256.o \
+                 nx-sha512.o
diff --git a/drivers/crypto/nx/nx-aes-cbc.c b/drivers/crypto/nx/nx-aes-cbc.c
new file mode 100644 (file)
index 0000000..69ed796
--- /dev/null
@@ -0,0 +1,141 @@
+/**
+ * AES CBC routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int cbc_aes_nx_set_key(struct crypto_tfm *tfm,
+                             const u8          *in_key,
+                             unsigned int       key_len)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+
+       nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+       switch (key_len) {
+       case AES_KEYSIZE_128:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+               break;
+       case AES_KEYSIZE_192:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+               break;
+       case AES_KEYSIZE_256:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       csbcpb->cpb.hdr.mode = NX_MODE_AES_CBC;
+       memcpy(csbcpb->cpb.aes_cbc.key, in_key, key_len);
+
+       return 0;
+}
+
+static int cbc_aes_nx_crypt(struct blkcipher_desc *desc,
+                           struct scatterlist    *dst,
+                           struct scatterlist    *src,
+                           unsigned int           nbytes,
+                           int                    enc)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       int rc;
+
+       if (nbytes > nx_ctx->ap->databytelen)
+               return -EINVAL;
+
+       if (enc)
+               NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+       else
+               NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+
+       rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes,
+                              csbcpb->cpb.aes_cbc.iv);
+       if (rc)
+               goto out;
+
+       if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->aes_ops));
+       atomic64_add(csbcpb->csb.processed_byte_count,
+                    &(nx_ctx->stats->aes_bytes));
+out:
+       return rc;
+}
+
+static int cbc_aes_nx_encrypt(struct blkcipher_desc *desc,
+                             struct scatterlist    *dst,
+                             struct scatterlist    *src,
+                             unsigned int           nbytes)
+{
+       return cbc_aes_nx_crypt(desc, dst, src, nbytes, 1);
+}
+
+static int cbc_aes_nx_decrypt(struct blkcipher_desc *desc,
+                             struct scatterlist    *dst,
+                             struct scatterlist    *src,
+                             unsigned int           nbytes)
+{
+       return cbc_aes_nx_crypt(desc, dst, src, nbytes, 0);
+}
+
+struct crypto_alg nx_cbc_aes_alg = {
+       .cra_name        = "cbc(aes)",
+       .cra_driver_name = "cbc-aes-nx",
+       .cra_priority    = 300,
+       .cra_flags       = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize   = AES_BLOCK_SIZE,
+       .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+       .cra_type        = &crypto_blkcipher_type,
+       .cra_module      = THIS_MODULE,
+       .cra_list        = LIST_HEAD_INIT(nx_cbc_aes_alg.cra_list),
+       .cra_init        = nx_crypto_ctx_aes_cbc_init,
+       .cra_exit        = nx_crypto_ctx_exit,
+       .cra_blkcipher = {
+               .min_keysize = AES_MIN_KEY_SIZE,
+               .max_keysize = AES_MAX_KEY_SIZE,
+               .ivsize      = AES_BLOCK_SIZE,
+               .setkey      = cbc_aes_nx_set_key,
+               .encrypt     = cbc_aes_nx_encrypt,
+               .decrypt     = cbc_aes_nx_decrypt,
+       }
+};
diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c
new file mode 100644 (file)
index 0000000..7aeac67
--- /dev/null
@@ -0,0 +1,468 @@
+/**
+ * AES CCM routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2012 International Business Machines 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; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/aead.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int ccm_aes_nx_set_key(struct crypto_aead *tfm,
+                             const u8           *in_key,
+                             unsigned int        key_len)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
+
+       nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+       switch (key_len) {
+       case AES_KEYSIZE_128:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+               NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       csbcpb->cpb.hdr.mode = NX_MODE_AES_CCM;
+       memcpy(csbcpb->cpb.aes_ccm.key, in_key, key_len);
+
+       csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_CCA;
+       memcpy(csbcpb_aead->cpb.aes_cca.key, in_key, key_len);
+
+       return 0;
+
+}
+
+static int ccm4309_aes_nx_set_key(struct crypto_aead *tfm,
+                                 const u8           *in_key,
+                                 unsigned int        key_len)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+
+       if (key_len < 3)
+               return -EINVAL;
+
+       key_len -= 3;
+
+       memcpy(nx_ctx->priv.ccm.nonce, in_key + key_len, 3);
+
+       return ccm_aes_nx_set_key(tfm, in_key, key_len);
+}
+
+static int ccm_aes_nx_setauthsize(struct crypto_aead *tfm,
+                                 unsigned int authsize)
+{
+       switch (authsize) {
+       case 4:
+       case 6:
+       case 8:
+       case 10:
+       case 12:
+       case 14:
+       case 16:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       crypto_aead_crt(tfm)->authsize = authsize;
+
+       return 0;
+}
+
+static int ccm4309_aes_nx_setauthsize(struct crypto_aead *tfm,
+                                     unsigned int authsize)
+{
+       switch (authsize) {
+       case 8:
+       case 12:
+       case 16:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       crypto_aead_crt(tfm)->authsize = authsize;
+
+       return 0;
+}
+
+/* taken from crypto/ccm.c */
+static int set_msg_len(u8 *block, unsigned int msglen, int csize)
+{
+       __be32 data;
+
+       memset(block, 0, csize);
+       block += csize;
+
+       if (csize >= 4)
+               csize = 4;
+       else if (msglen > (unsigned int)(1 << (8 * csize)))
+               return -EOVERFLOW;
+
+       data = cpu_to_be32(msglen);
+       memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
+
+       return 0;
+}
+
+/* taken from crypto/ccm.c */
+static inline int crypto_ccm_check_iv(const u8 *iv)
+{
+       /* 2 <= L <= 8, so 1 <= L' <= 7. */
+       if (1 > iv[0] || iv[0] > 7)
+               return -EINVAL;
+
+       return 0;
+}
+
+/* based on code from crypto/ccm.c */
+static int generate_b0(u8 *iv, unsigned int assoclen, unsigned int authsize,
+                      unsigned int cryptlen, u8 *b0)
+{
+       unsigned int l, lp, m = authsize;
+       int rc;
+
+       memcpy(b0, iv, 16);
+
+       lp = b0[0];
+       l = lp + 1;
+
+       /* set m, bits 3-5 */
+       *b0 |= (8 * ((m - 2) / 2));
+
+       /* set adata, bit 6, if associated data is used */
+       if (assoclen)
+               *b0 |= 64;
+
+       rc = set_msg_len(b0 + 16 - l, cryptlen, l);
+
+       return rc;
+}
+
+static int generate_pat(u8                   *iv,
+                       struct aead_request  *req,
+                       struct nx_crypto_ctx *nx_ctx,
+                       unsigned int          authsize,
+                       unsigned int          nbytes,
+                       u8                   *out)
+{
+       struct nx_sg *nx_insg = nx_ctx->in_sg;
+       struct nx_sg *nx_outsg = nx_ctx->out_sg;
+       unsigned int iauth_len = 0;
+       struct vio_pfo_op *op = NULL;
+       u8 tmp[16], *b1 = NULL, *b0 = NULL, *result = NULL;
+       int rc;
+
+       /* zero the ctr value */
+       memset(iv + 15 - iv[0], 0, iv[0] + 1);
+
+       if (!req->assoclen) {
+               b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
+       } else if (req->assoclen <= 14) {
+               /* if associated data is 14 bytes or less, we do 1 GCM
+                * operation on 2 AES blocks, B0 (stored in the csbcpb) and B1,
+                * which is fed in through the source buffers here */
+               b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
+               b1 = nx_ctx->priv.ccm.iauth_tag;
+               iauth_len = req->assoclen;
+
+               nx_insg = nx_build_sg_list(nx_insg, b1, 16, nx_ctx->ap->sglen);
+               nx_outsg = nx_build_sg_list(nx_outsg, tmp, 16,
+                                           nx_ctx->ap->sglen);
+
+               /* inlen should be negative, indicating to phyp that its a
+                * pointer to an sg list */
+               nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) *
+                                       sizeof(struct nx_sg);
+               nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) *
+                                       sizeof(struct nx_sg);
+
+               NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+               NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_INTERMEDIATE;
+
+               op = &nx_ctx->op;
+               result = nx_ctx->csbcpb->cpb.aes_ccm.out_pat_or_mac;
+       } else if (req->assoclen <= 65280) {
+               /* if associated data is less than (2^16 - 2^8), we construct
+                * B1 differently and feed in the associated data to a CCA
+                * operation */
+               b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
+               b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
+               iauth_len = 14;
+
+               /* remaining assoc data must have scatterlist built for it */
+               nx_insg = nx_walk_and_build(nx_insg, nx_ctx->ap->sglen,
+                                           req->assoc, iauth_len,
+                                           req->assoclen - iauth_len);
+               nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) *
+                                               sizeof(struct nx_sg);
+
+               op = &nx_ctx->op_aead;
+               result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
+       } else {
+               /* if associated data is less than (2^32), we construct B1
+                * differently yet again and feed in the associated data to a
+                * CCA operation */
+               pr_err("associated data len is %u bytes (returning -EINVAL)\n",
+                      req->assoclen);
+               rc = -EINVAL;
+       }
+
+       rc = generate_b0(iv, req->assoclen, authsize, nbytes, b0);
+       if (rc)
+               goto done;
+
+       if (b1) {
+               memset(b1, 0, 16);
+               *(u16 *)b1 = (u16)req->assoclen;
+
+               scatterwalk_map_and_copy(b1 + 2, req->assoc, 0,
+                                        iauth_len, SCATTERWALK_FROM_SG);
+
+               rc = nx_hcall_sync(nx_ctx, op,
+                                  req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+               if (rc)
+                       goto done;
+
+               atomic_inc(&(nx_ctx->stats->aes_ops));
+               atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
+
+               memcpy(out, result, AES_BLOCK_SIZE);
+       }
+done:
+       return rc;
+}
+
+static int ccm_nx_decrypt(struct aead_request   *req,
+                         struct blkcipher_desc *desc)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       unsigned int nbytes = req->cryptlen;
+       unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
+       struct nx_ccm_priv *priv = &nx_ctx->priv.ccm;
+       int rc = -1;
+
+       if (nbytes > nx_ctx->ap->databytelen)
+               return -EINVAL;
+
+       nbytes -= authsize;
+
+       /* copy out the auth tag to compare with later */
+       scatterwalk_map_and_copy(priv->oauth_tag,
+                                req->src, nbytes, authsize,
+                                SCATTERWALK_FROM_SG);
+
+       rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes,
+                         csbcpb->cpb.aes_ccm.in_pat_or_b0);
+       if (rc)
+               goto out;
+
+       rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, nbytes,
+                              csbcpb->cpb.aes_ccm.iv_or_ctr);
+       if (rc)
+               goto out;
+
+       NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+       NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->aes_ops));
+       atomic64_add(csbcpb->csb.processed_byte_count,
+                    &(nx_ctx->stats->aes_bytes));
+
+       rc = memcmp(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
+                   authsize) ? -EBADMSG : 0;
+out:
+       return rc;
+}
+
+static int ccm_nx_encrypt(struct aead_request   *req,
+                         struct blkcipher_desc *desc)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       unsigned int nbytes = req->cryptlen;
+       unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
+       int rc = -1;
+
+       if (nbytes > nx_ctx->ap->databytelen)
+               return -EINVAL;
+
+       rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes,
+                         csbcpb->cpb.aes_ccm.in_pat_or_b0);
+       if (rc)
+               goto out;
+
+       rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, nbytes,
+                              csbcpb->cpb.aes_ccm.iv_or_ctr);
+       if (rc)
+               goto out;
+
+       NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+       NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->aes_ops));
+       atomic64_add(csbcpb->csb.processed_byte_count,
+                    &(nx_ctx->stats->aes_bytes));
+
+       /* copy out the auth tag */
+       scatterwalk_map_and_copy(csbcpb->cpb.aes_ccm.out_pat_or_mac,
+                                req->dst, nbytes, authsize,
+                                SCATTERWALK_TO_SG);
+out:
+       return rc;
+}
+
+static int ccm4309_aes_nx_encrypt(struct aead_request *req)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       struct blkcipher_desc desc;
+       u8 *iv = nx_ctx->priv.ccm.iv;
+
+       iv[0] = 3;
+       memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
+       memcpy(iv + 4, req->iv, 8);
+
+       desc.info = iv;
+       desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+       return ccm_nx_encrypt(req, &desc);
+}
+
+static int ccm_aes_nx_encrypt(struct aead_request *req)
+{
+       struct blkcipher_desc desc;
+       int rc;
+
+       desc.info = req->iv;
+       desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+       rc = crypto_ccm_check_iv(desc.info);
+       if (rc)
+               return rc;
+
+       return ccm_nx_encrypt(req, &desc);
+}
+
+static int ccm4309_aes_nx_decrypt(struct aead_request *req)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       struct blkcipher_desc desc;
+       u8 *iv = nx_ctx->priv.ccm.iv;
+
+       iv[0] = 3;
+       memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
+       memcpy(iv + 4, req->iv, 8);
+
+       desc.info = iv;
+       desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+       return ccm_nx_decrypt(req, &desc);
+}
+
+static int ccm_aes_nx_decrypt(struct aead_request *req)
+{
+       struct blkcipher_desc desc;
+       int rc;
+
+       desc.info = req->iv;
+       desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+       rc = crypto_ccm_check_iv(desc.info);
+       if (rc)
+               return rc;
+
+       return ccm_nx_decrypt(req, &desc);
+}
+
+/* tell the block cipher walk routines that this is a stream cipher by
+ * setting cra_blocksize to 1. Even using blkcipher_walk_virt_block
+ * during encrypt/decrypt doesn't solve this problem, because it calls
+ * blkcipher_walk_done under the covers, which doesn't use walk->blocksize,
+ * but instead uses this tfm->blocksize. */
+struct crypto_alg nx_ccm_aes_alg = {
+       .cra_name        = "ccm(aes)",
+       .cra_driver_name = "ccm-aes-nx",
+       .cra_priority    = 300,
+       .cra_flags       = CRYPTO_ALG_TYPE_AEAD |
+                          CRYPTO_ALG_NEED_FALLBACK,
+       .cra_blocksize   = 1,
+       .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+       .cra_type        = &crypto_aead_type,
+       .cra_module      = THIS_MODULE,
+       .cra_list        = LIST_HEAD_INIT(nx_ccm_aes_alg.cra_list),
+       .cra_init        = nx_crypto_ctx_aes_ccm_init,
+       .cra_exit        = nx_crypto_ctx_exit,
+       .cra_aead = {
+               .ivsize      = AES_BLOCK_SIZE,
+               .maxauthsize = AES_BLOCK_SIZE,
+               .setkey      = ccm_aes_nx_set_key,
+               .setauthsize = ccm_aes_nx_setauthsize,
+               .encrypt     = ccm_aes_nx_encrypt,
+               .decrypt     = ccm_aes_nx_decrypt,
+       }
+};
+
+struct crypto_alg nx_ccm4309_aes_alg = {
+       .cra_name        = "rfc4309(ccm(aes))",
+       .cra_driver_name = "rfc4309-ccm-aes-nx",
+       .cra_priority    = 300,
+       .cra_flags       = CRYPTO_ALG_TYPE_AEAD |
+                          CRYPTO_ALG_NEED_FALLBACK,
+       .cra_blocksize   = 1,
+       .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+       .cra_type        = &crypto_nivaead_type,
+       .cra_module      = THIS_MODULE,
+       .cra_list        = LIST_HEAD_INIT(nx_ccm4309_aes_alg.cra_list),
+       .cra_init        = nx_crypto_ctx_aes_ccm_init,
+       .cra_exit        = nx_crypto_ctx_exit,
+       .cra_aead = {
+               .ivsize      = 8,
+               .maxauthsize = AES_BLOCK_SIZE,
+               .setkey      = ccm4309_aes_nx_set_key,
+               .setauthsize = ccm4309_aes_nx_setauthsize,
+               .encrypt     = ccm4309_aes_nx_encrypt,
+               .decrypt     = ccm4309_aes_nx_decrypt,
+               .geniv       = "seqiv",
+       }
+};
diff --git a/drivers/crypto/nx/nx-aes-ctr.c b/drivers/crypto/nx/nx-aes-ctr.c
new file mode 100644 (file)
index 0000000..52d4eb0
--- /dev/null
@@ -0,0 +1,178 @@
+/**
+ * AES CTR routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/aes.h>
+#include <crypto/ctr.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int ctr_aes_nx_set_key(struct crypto_tfm *tfm,
+                             const u8          *in_key,
+                             unsigned int       key_len)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+
+       nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+       switch (key_len) {
+       case AES_KEYSIZE_128:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+               break;
+       case AES_KEYSIZE_192:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+               break;
+       case AES_KEYSIZE_256:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       csbcpb->cpb.hdr.mode = NX_MODE_AES_CTR;
+       memcpy(csbcpb->cpb.aes_ctr.key, in_key, key_len);
+
+       return 0;
+}
+
+static int ctr3686_aes_nx_set_key(struct crypto_tfm *tfm,
+                                 const u8          *in_key,
+                                 unsigned int       key_len)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+
+       if (key_len < CTR_RFC3686_NONCE_SIZE)
+               return -EINVAL;
+
+       memcpy(nx_ctx->priv.ctr.iv,
+              in_key + key_len - CTR_RFC3686_NONCE_SIZE,
+              CTR_RFC3686_NONCE_SIZE);
+
+       key_len -= CTR_RFC3686_NONCE_SIZE;
+
+       return ctr_aes_nx_set_key(tfm, in_key, key_len);
+}
+
+static int ctr_aes_nx_crypt(struct blkcipher_desc *desc,
+                           struct scatterlist    *dst,
+                           struct scatterlist    *src,
+                           unsigned int           nbytes)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       int rc;
+
+       if (nbytes > nx_ctx->ap->databytelen)
+               return -EINVAL;
+
+       rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes,
+                              csbcpb->cpb.aes_ctr.iv);
+       if (rc)
+               goto out;
+
+       if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->aes_ops));
+       atomic64_add(csbcpb->csb.processed_byte_count,
+                    &(nx_ctx->stats->aes_bytes));
+out:
+       return rc;
+}
+
+static int ctr3686_aes_nx_crypt(struct blkcipher_desc *desc,
+                               struct scatterlist    *dst,
+                               struct scatterlist    *src,
+                               unsigned int           nbytes)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+       u8 *iv = nx_ctx->priv.ctr.iv;
+
+       memcpy(iv + CTR_RFC3686_NONCE_SIZE,
+              desc->info, CTR_RFC3686_IV_SIZE);
+       iv[15] = 1;
+
+       desc->info = nx_ctx->priv.ctr.iv;
+
+       return ctr_aes_nx_crypt(desc, dst, src, nbytes);
+}
+
+struct crypto_alg nx_ctr_aes_alg = {
+       .cra_name        = "ctr(aes)",
+       .cra_driver_name = "ctr-aes-nx",
+       .cra_priority    = 300,
+       .cra_flags       = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize   = 1,
+       .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+       .cra_type        = &crypto_blkcipher_type,
+       .cra_module      = THIS_MODULE,
+       .cra_list        = LIST_HEAD_INIT(nx_ctr_aes_alg.cra_list),
+       .cra_init        = nx_crypto_ctx_aes_ctr_init,
+       .cra_exit        = nx_crypto_ctx_exit,
+       .cra_blkcipher = {
+               .min_keysize = AES_MIN_KEY_SIZE,
+               .max_keysize = AES_MAX_KEY_SIZE,
+               .ivsize      = AES_BLOCK_SIZE,
+               .setkey      = ctr_aes_nx_set_key,
+               .encrypt     = ctr_aes_nx_crypt,
+               .decrypt     = ctr_aes_nx_crypt,
+       }
+};
+
+struct crypto_alg nx_ctr3686_aes_alg = {
+       .cra_name        = "rfc3686(ctr(aes))",
+       .cra_driver_name = "rfc3686-ctr-aes-nx",
+       .cra_priority    = 300,
+       .cra_flags       = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize   = 1,
+       .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+       .cra_type        = &crypto_blkcipher_type,
+       .cra_module      = THIS_MODULE,
+       .cra_list        = LIST_HEAD_INIT(nx_ctr3686_aes_alg.cra_list),
+       .cra_init        = nx_crypto_ctx_aes_ctr_init,
+       .cra_exit        = nx_crypto_ctx_exit,
+       .cra_blkcipher = {
+               .min_keysize = AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE,
+               .max_keysize = AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE,
+               .ivsize      = CTR_RFC3686_IV_SIZE,
+               .geniv       = "seqiv",
+               .setkey      = ctr3686_aes_nx_set_key,
+               .encrypt     = ctr3686_aes_nx_crypt,
+               .decrypt     = ctr3686_aes_nx_crypt,
+       }
+};
diff --git a/drivers/crypto/nx/nx-aes-ecb.c b/drivers/crypto/nx/nx-aes-ecb.c
new file mode 100644 (file)
index 0000000..7b77bc2
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * AES ECB routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int ecb_aes_nx_set_key(struct crypto_tfm *tfm,
+                             const u8          *in_key,
+                             unsigned int       key_len)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+       struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+
+       nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+       switch (key_len) {
+       case AES_KEYSIZE_128:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+               break;
+       case AES_KEYSIZE_192:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+               break;
+       case AES_KEYSIZE_256:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       csbcpb->cpb.hdr.mode = NX_MODE_AES_ECB;
+       memcpy(csbcpb->cpb.aes_ecb.key, in_key, key_len);
+
+       return 0;
+}
+
+static int ecb_aes_nx_crypt(struct blkcipher_desc *desc,
+                           struct scatterlist    *dst,
+                           struct scatterlist    *src,
+                           unsigned int           nbytes,
+                           int                    enc)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       int rc;
+
+       if (nbytes > nx_ctx->ap->databytelen)
+               return -EINVAL;
+
+       if (enc)
+               NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+       else
+               NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+
+       rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes, NULL);
+       if (rc)
+               goto out;
+
+       if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->aes_ops));
+       atomic64_add(csbcpb->csb.processed_byte_count,
+                    &(nx_ctx->stats->aes_bytes));
+out:
+       return rc;
+}
+
+static int ecb_aes_nx_encrypt(struct blkcipher_desc *desc,
+                             struct scatterlist    *dst,
+                             struct scatterlist    *src,
+                             unsigned int           nbytes)
+{
+       return ecb_aes_nx_crypt(desc, dst, src, nbytes, 1);
+}
+
+static int ecb_aes_nx_decrypt(struct blkcipher_desc *desc,
+                             struct scatterlist    *dst,
+                             struct scatterlist    *src,
+                             unsigned int           nbytes)
+{
+       return ecb_aes_nx_crypt(desc, dst, src, nbytes, 0);
+}
+
+struct crypto_alg nx_ecb_aes_alg = {
+       .cra_name        = "ecb(aes)",
+       .cra_driver_name = "ecb-aes-nx",
+       .cra_priority    = 300,
+       .cra_flags       = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize   = AES_BLOCK_SIZE,
+       .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+       .cra_type        = &crypto_blkcipher_type,
+       .cra_module      = THIS_MODULE,
+       .cra_list        = LIST_HEAD_INIT(nx_ecb_aes_alg.cra_list),
+       .cra_init        = nx_crypto_ctx_aes_ecb_init,
+       .cra_exit        = nx_crypto_ctx_exit,
+       .cra_blkcipher = {
+               .min_keysize = AES_MIN_KEY_SIZE,
+               .max_keysize = AES_MAX_KEY_SIZE,
+               .setkey      = ecb_aes_nx_set_key,
+               .encrypt     = ecb_aes_nx_encrypt,
+               .decrypt     = ecb_aes_nx_decrypt,
+       }
+};
diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c
new file mode 100644 (file)
index 0000000..9ab1c73
--- /dev/null
@@ -0,0 +1,353 @@
+/**
+ * AES GCM routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2012 International Business Machines 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; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/aead.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int gcm_aes_nx_set_key(struct crypto_aead *tfm,
+                             const u8           *in_key,
+                             unsigned int        key_len)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
+
+       nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+       switch (key_len) {
+       case AES_KEYSIZE_128:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+               NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+               break;
+       case AES_KEYSIZE_192:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+               NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_192);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+               break;
+       case AES_KEYSIZE_256:
+               NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+               NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_256);
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       csbcpb->cpb.hdr.mode = NX_MODE_AES_GCM;
+       memcpy(csbcpb->cpb.aes_gcm.key, in_key, key_len);
+
+       csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_GCA;
+       memcpy(csbcpb_aead->cpb.aes_gca.key, in_key, key_len);
+
+       return 0;
+}
+
+static int gcm4106_aes_nx_set_key(struct crypto_aead *tfm,
+                                 const u8           *in_key,
+                                 unsigned int        key_len)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+       char *nonce = nx_ctx->priv.gcm.nonce;
+       int rc;
+
+       if (key_len < 4)
+               return -EINVAL;
+
+       key_len -= 4;
+
+       rc = gcm_aes_nx_set_key(tfm, in_key, key_len);
+       if (rc)
+               goto out;
+
+       memcpy(nonce, in_key + key_len, 4);
+out:
+       return rc;
+}
+
+static int gcm_aes_nx_setauthsize(struct crypto_aead *tfm,
+                                 unsigned int authsize)
+{
+       if (authsize > crypto_aead_alg(tfm)->maxauthsize)
+               return -EINVAL;
+
+       crypto_aead_crt(tfm)->authsize = authsize;
+
+       return 0;
+}
+
+static int gcm4106_aes_nx_setauthsize(struct crypto_aead *tfm,
+                                     unsigned int authsize)
+{
+       switch (authsize) {
+       case 8:
+       case 12:
+       case 16:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       crypto_aead_crt(tfm)->authsize = authsize;
+
+       return 0;
+}
+
+static int nx_gca(struct nx_crypto_ctx  *nx_ctx,
+                 struct aead_request   *req,
+                 u8                    *out)
+{
+       struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
+       int rc = -EINVAL;
+       struct scatter_walk walk;
+       struct nx_sg *nx_sg = nx_ctx->in_sg;
+
+       if (req->assoclen > nx_ctx->ap->databytelen)
+               goto out;
+
+       if (req->assoclen <= AES_BLOCK_SIZE) {
+               scatterwalk_start(&walk, req->assoc);
+               scatterwalk_copychunks(out, &walk, req->assoclen,
+                                      SCATTERWALK_FROM_SG);
+               scatterwalk_done(&walk, SCATTERWALK_FROM_SG, 0);
+
+               rc = 0;
+               goto out;
+       }
+
+       nx_sg = nx_walk_and_build(nx_sg, nx_ctx->ap->sglen, req->assoc, 0,
+                                 req->assoclen);
+       nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_sg) * sizeof(struct nx_sg);
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op_aead,
+                          req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->aes_ops));
+       atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
+
+       memcpy(out, csbcpb_aead->cpb.aes_gca.out_pat, AES_BLOCK_SIZE);
+out:
+       return rc;
+}
+
+static int gcm_aes_nx_crypt(struct aead_request *req, int enc)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       struct blkcipher_desc desc;
+       unsigned int nbytes = req->cryptlen;
+       int rc = -EINVAL;
+
+       if (nbytes > nx_ctx->ap->databytelen)
+               goto out;
+
+       desc.info = nx_ctx->priv.gcm.iv;
+       /* initialize the counter */
+       *(u32 *)(desc.info + NX_GCM_CTR_OFFSET) = 1;
+
+       /* For scenarios where the input message is zero length, AES CTR mode
+        * may be used. Set the source data to be a single block (16B) of all
+        * zeros, and set the input IV value to be the same as the GMAC IV
+        * value. - nx_wb 4.8.1.3 */
+       if (nbytes == 0) {
+               char src[AES_BLOCK_SIZE] = {};
+               struct scatterlist sg;
+
+               desc.tfm = crypto_alloc_blkcipher("ctr(aes)", 0, 0);
+               if (IS_ERR(desc.tfm)) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+
+               crypto_blkcipher_setkey(desc.tfm, csbcpb->cpb.aes_gcm.key,
+                       NX_CPB_KEY_SIZE(csbcpb) == NX_KS_AES_128 ? 16 :
+                       NX_CPB_KEY_SIZE(csbcpb) == NX_KS_AES_192 ? 24 : 32);
+
+               sg_init_one(&sg, src, AES_BLOCK_SIZE);
+               if (enc)
+                       crypto_blkcipher_encrypt_iv(&desc, req->dst, &sg,
+                                                   AES_BLOCK_SIZE);
+               else
+                       crypto_blkcipher_decrypt_iv(&desc, req->dst, &sg,
+                                                   AES_BLOCK_SIZE);
+               crypto_free_blkcipher(desc.tfm);
+
+               rc = 0;
+               goto out;
+       }
+
+       desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+       csbcpb->cpb.aes_gcm.bit_length_aad = req->assoclen * 8;
+
+       if (req->assoclen) {
+               rc = nx_gca(nx_ctx, req, csbcpb->cpb.aes_gcm.in_pat_or_aad);
+               if (rc)
+                       goto out;
+       }
+
+       if (enc)
+               NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+       else
+               nbytes -= AES_BLOCK_SIZE;
+
+       csbcpb->cpb.aes_gcm.bit_length_data = nbytes * 8;
+
+       rc = nx_build_sg_lists(nx_ctx, &desc, req->dst, req->src, nbytes,
+                              csbcpb->cpb.aes_gcm.iv_or_cnt);
+       if (rc)
+               goto out;
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->aes_ops));
+       atomic64_add(csbcpb->csb.processed_byte_count,
+                    &(nx_ctx->stats->aes_bytes));
+
+       if (enc) {
+               /* copy out the auth tag */
+               scatterwalk_map_and_copy(csbcpb->cpb.aes_gcm.out_pat_or_mac,
+                                req->dst, nbytes,
+                                crypto_aead_authsize(crypto_aead_reqtfm(req)),
+                                SCATTERWALK_TO_SG);
+       } else if (req->assoclen) {
+               u8 *itag = nx_ctx->priv.gcm.iauth_tag;
+               u8 *otag = csbcpb->cpb.aes_gcm.out_pat_or_mac;
+
+               scatterwalk_map_and_copy(itag, req->dst, nbytes,
+                                crypto_aead_authsize(crypto_aead_reqtfm(req)),
+                                SCATTERWALK_FROM_SG);
+               rc = memcmp(itag, otag,
+                           crypto_aead_authsize(crypto_aead_reqtfm(req))) ?
+                    -EBADMSG : 0;
+       }
+out:
+       return rc;
+}
+
+static int gcm_aes_nx_encrypt(struct aead_request *req)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       char *iv = nx_ctx->priv.gcm.iv;
+
+       memcpy(iv, req->iv, 12);
+
+       return gcm_aes_nx_crypt(req, 1);
+}
+
+static int gcm_aes_nx_decrypt(struct aead_request *req)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       char *iv = nx_ctx->priv.gcm.iv;
+
+       memcpy(iv, req->iv, 12);
+
+       return gcm_aes_nx_crypt(req, 0);
+}
+
+static int gcm4106_aes_nx_encrypt(struct aead_request *req)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       char *iv = nx_ctx->priv.gcm.iv;
+       char *nonce = nx_ctx->priv.gcm.nonce;
+
+       memcpy(iv, nonce, NX_GCM4106_NONCE_LEN);
+       memcpy(iv + NX_GCM4106_NONCE_LEN, req->iv, 8);
+
+       return gcm_aes_nx_crypt(req, 1);
+}
+
+static int gcm4106_aes_nx_decrypt(struct aead_request *req)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       char *iv = nx_ctx->priv.gcm.iv;
+       char *nonce = nx_ctx->priv.gcm.nonce;
+
+       memcpy(iv, nonce, NX_GCM4106_NONCE_LEN);
+       memcpy(iv + NX_GCM4106_NONCE_LEN, req->iv, 8);
+
+       return gcm_aes_nx_crypt(req, 0);
+}
+
+/* tell the block cipher walk routines that this is a stream cipher by
+ * setting cra_blocksize to 1. Even using blkcipher_walk_virt_block
+ * during encrypt/decrypt doesn't solve this problem, because it calls
+ * blkcipher_walk_done under the covers, which doesn't use walk->blocksize,
+ * but instead uses this tfm->blocksize. */
+struct crypto_alg nx_gcm_aes_alg = {
+       .cra_name        = "gcm(aes)",
+       .cra_driver_name = "gcm-aes-nx",
+       .cra_priority    = 300,
+       .cra_flags       = CRYPTO_ALG_TYPE_AEAD,
+       .cra_blocksize   = 1,
+       .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+       .cra_type        = &crypto_aead_type,
+       .cra_module      = THIS_MODULE,
+       .cra_list        = LIST_HEAD_INIT(nx_gcm_aes_alg.cra_list),
+       .cra_init        = nx_crypto_ctx_aes_gcm_init,
+       .cra_exit        = nx_crypto_ctx_exit,
+       .cra_aead = {
+               .ivsize      = AES_BLOCK_SIZE,
+               .maxauthsize = AES_BLOCK_SIZE,
+               .setkey      = gcm_aes_nx_set_key,
+               .setauthsize = gcm_aes_nx_setauthsize,
+               .encrypt     = gcm_aes_nx_encrypt,
+               .decrypt     = gcm_aes_nx_decrypt,
+       }
+};
+
+struct crypto_alg nx_gcm4106_aes_alg = {
+       .cra_name        = "rfc4106(gcm(aes))",
+       .cra_driver_name = "rfc4106-gcm-aes-nx",
+       .cra_priority    = 300,
+       .cra_flags       = CRYPTO_ALG_TYPE_AEAD,
+       .cra_blocksize   = 1,
+       .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+       .cra_type        = &crypto_nivaead_type,
+       .cra_module      = THIS_MODULE,
+       .cra_list        = LIST_HEAD_INIT(nx_gcm4106_aes_alg.cra_list),
+       .cra_init        = nx_crypto_ctx_aes_gcm_init,
+       .cra_exit        = nx_crypto_ctx_exit,
+       .cra_aead = {
+               .ivsize      = 8,
+               .maxauthsize = AES_BLOCK_SIZE,
+               .geniv       = "seqiv",
+               .setkey      = gcm4106_aes_nx_set_key,
+               .setauthsize = gcm4106_aes_nx_setauthsize,
+               .encrypt     = gcm4106_aes_nx_encrypt,
+               .decrypt     = gcm4106_aes_nx_decrypt,
+       }
+};
diff --git a/drivers/crypto/nx/nx-aes-xcbc.c b/drivers/crypto/nx/nx-aes-xcbc.c
new file mode 100644 (file)
index 0000000..93923e4
--- /dev/null
@@ -0,0 +1,236 @@
+/**
+ * AES XCBC routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+struct xcbc_state {
+       u8 state[AES_BLOCK_SIZE];
+       unsigned int count;
+       u8 buffer[AES_BLOCK_SIZE];
+};
+
+static int nx_xcbc_set_key(struct crypto_shash *desc,
+                          const u8            *in_key,
+                          unsigned int         key_len)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_shash_ctx(desc);
+
+       switch (key_len) {
+       case AES_KEYSIZE_128:
+               nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       memcpy(nx_ctx->priv.xcbc.key, in_key, key_len);
+
+       return 0;
+}
+
+static int nx_xcbc_init(struct shash_desc *desc)
+{
+       struct xcbc_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       struct nx_sg *out_sg;
+
+       nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+       memset(sctx, 0, sizeof *sctx);
+
+       NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+       csbcpb->cpb.hdr.mode = NX_MODE_AES_XCBC_MAC;
+
+       memcpy(csbcpb->cpb.aes_xcbc.key, nx_ctx->priv.xcbc.key, AES_BLOCK_SIZE);
+       memset(nx_ctx->priv.xcbc.key, 0, sizeof *nx_ctx->priv.xcbc.key);
+
+       out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+                                 AES_BLOCK_SIZE, nx_ctx->ap->sglen);
+       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+       return 0;
+}
+
+static int nx_xcbc_update(struct shash_desc *desc,
+                         const u8          *data,
+                         unsigned int       len)
+{
+       struct xcbc_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       struct nx_sg *in_sg;
+       u32 to_process, leftover;
+       int rc = 0;
+
+       if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+               /* we've hit the nx chip previously and we're updating again,
+                * so copy over the partial digest */
+               memcpy(csbcpb->cpb.aes_xcbc.cv,
+                      csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
+       }
+
+       /* 2 cases for total data len:
+        *  1: <= AES_BLOCK_SIZE: copy into state, return 0
+        *  2: > AES_BLOCK_SIZE: process X blocks, copy in leftover
+        */
+       if (len + sctx->count <= AES_BLOCK_SIZE) {
+               memcpy(sctx->buffer + sctx->count, data, len);
+               sctx->count += len;
+               goto out;
+       }
+
+       /* to_process: the AES_BLOCK_SIZE data chunk to process in this
+        * update */
+       to_process = (sctx->count + len) & ~(AES_BLOCK_SIZE - 1);
+       leftover = (sctx->count + len) & (AES_BLOCK_SIZE - 1);
+
+       /* the hardware will not accept a 0 byte operation for this algorithm
+        * and the operation MUST be finalized to be correct. So if we happen
+        * to get an update that falls on a block sized boundary, we must
+        * save off the last block to finalize with later. */
+       if (!leftover) {
+               to_process -= AES_BLOCK_SIZE;
+               leftover = AES_BLOCK_SIZE;
+       }
+
+       if (sctx->count) {
+               in_sg = nx_build_sg_list(nx_ctx->in_sg, sctx->buffer,
+                                        sctx->count, nx_ctx->ap->sglen);
+               in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+                                        to_process - sctx->count,
+                                        nx_ctx->ap->sglen);
+               nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+                                       sizeof(struct nx_sg);
+       } else {
+               in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data, to_process,
+                                        nx_ctx->ap->sglen);
+               nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+                                       sizeof(struct nx_sg);
+       }
+
+       NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+
+       if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->aes_ops));
+
+       /* copy the leftover back into the state struct */
+       memcpy(sctx->buffer, data + len - leftover, leftover);
+       sctx->count = leftover;
+
+       /* everything after the first update is continuation */
+       NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+out:
+       return rc;
+}
+
+static int nx_xcbc_final(struct shash_desc *desc, u8 *out)
+{
+       struct xcbc_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+       struct nx_sg *in_sg, *out_sg;
+       int rc = 0;
+
+       if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+               /* we've hit the nx chip previously, now we're finalizing,
+                * so copy over the partial digest */
+               memcpy(csbcpb->cpb.aes_xcbc.cv,
+                      csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
+       } else if (sctx->count == 0) {
+               /* we've never seen an update, so this is a 0 byte op. The
+                * hardware cannot handle a 0 byte op, so just copy out the
+                * known 0 byte result. This is cheaper than allocating a
+                * software context to do a 0 byte op */
+               u8 data[] = { 0x75, 0xf0, 0x25, 0x1d, 0x52, 0x8a, 0xc0, 0x1c,
+                             0x45, 0x73, 0xdf, 0xd5, 0x84, 0xd7, 0x9f, 0x29 };
+               memcpy(out, data, sizeof(data));
+               goto out;
+       }
+
+       /* final is represented by continuing the operation and indicating that
+        * this is not an intermediate operation */
+       NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+       in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buffer,
+                                sctx->count, nx_ctx->ap->sglen);
+       out_sg = nx_build_sg_list(nx_ctx->out_sg, out, AES_BLOCK_SIZE,
+                                 nx_ctx->ap->sglen);
+
+       nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+       if (!nx_ctx->op.outlen) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->aes_ops));
+
+       memcpy(out, csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
+out:
+       return rc;
+}
+
+struct shash_alg nx_shash_aes_xcbc_alg = {
+       .digestsize = AES_BLOCK_SIZE,
+       .init       = nx_xcbc_init,
+       .update     = nx_xcbc_update,
+       .final      = nx_xcbc_final,
+       .setkey     = nx_xcbc_set_key,
+       .descsize   = sizeof(struct xcbc_state),
+       .statesize  = sizeof(struct xcbc_state),
+       .base       = {
+               .cra_name        = "xcbc(aes)",
+               .cra_driver_name = "xcbc-aes-nx",
+               .cra_priority    = 300,
+               .cra_flags       = CRYPTO_ALG_TYPE_SHASH,
+               .cra_blocksize   = AES_BLOCK_SIZE,
+               .cra_module      = THIS_MODULE,
+               .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+               .cra_init        = nx_crypto_ctx_aes_xcbc_init,
+               .cra_exit        = nx_crypto_ctx_exit,
+       }
+};
diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c
new file mode 100644 (file)
index 0000000..9767315
--- /dev/null
@@ -0,0 +1,246 @@
+/**
+ * SHA-256 routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <linux/module.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int nx_sha256_init(struct shash_desc *desc)
+{
+       struct sha256_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_sg *out_sg;
+
+       nx_ctx_init(nx_ctx, HCOP_FC_SHA);
+
+       memset(sctx, 0, sizeof *sctx);
+
+       nx_ctx->ap = &nx_ctx->props[NX_PROPS_SHA256];
+
+       NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA256);
+       out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+                                 SHA256_DIGEST_SIZE, nx_ctx->ap->sglen);
+       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+       return 0;
+}
+
+static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
+                           unsigned int len)
+{
+       struct sha256_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+       struct nx_sg *in_sg;
+       u64 to_process, leftover;
+       int rc = 0;
+
+       if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+               /* we've hit the nx chip previously and we're updating again,
+                * so copy over the partial digest */
+               memcpy(csbcpb->cpb.sha256.input_partial_digest,
+                      csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
+       }
+
+       /* 2 cases for total data len:
+        *  1: <= SHA256_BLOCK_SIZE: copy into state, return 0
+        *  2: > SHA256_BLOCK_SIZE: process X blocks, copy in leftover
+        */
+       if (len + sctx->count <= SHA256_BLOCK_SIZE) {
+               memcpy(sctx->buf + sctx->count, data, len);
+               sctx->count += len;
+               goto out;
+       }
+
+       /* to_process: the SHA256_BLOCK_SIZE data chunk to process in this
+        * update */
+       to_process = (sctx->count + len) & ~(SHA256_BLOCK_SIZE - 1);
+       leftover = (sctx->count + len) & (SHA256_BLOCK_SIZE - 1);
+
+       if (sctx->count) {
+               in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
+                                        sctx->count, nx_ctx->ap->sglen);
+               in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+                                        to_process - sctx->count,
+                                        nx_ctx->ap->sglen);
+               nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+                                       sizeof(struct nx_sg);
+       } else {
+               in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data,
+                                        to_process, nx_ctx->ap->sglen);
+               nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+                                       sizeof(struct nx_sg);
+       }
+
+       NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+
+       if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->sha256_ops));
+
+       /* copy the leftover back into the state struct */
+       memcpy(sctx->buf, data + len - leftover, leftover);
+       sctx->count = leftover;
+
+       csbcpb->cpb.sha256.message_bit_length += (u64)
+               (csbcpb->cpb.sha256.spbc * 8);
+
+       /* everything after the first update is continuation */
+       NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+out:
+       return rc;
+}
+
+static int nx_sha256_final(struct shash_desc *desc, u8 *out)
+{
+       struct sha256_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+       struct nx_sg *in_sg, *out_sg;
+       int rc;
+
+       if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+               /* we've hit the nx chip previously, now we're finalizing,
+                * so copy over the partial digest */
+               memcpy(csbcpb->cpb.sha256.input_partial_digest,
+                      csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
+       }
+
+       /* final is represented by continuing the operation and indicating that
+        * this is not an intermediate operation */
+       NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+       csbcpb->cpb.sha256.message_bit_length += (u64)(sctx->count * 8);
+
+       in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
+                                sctx->count, nx_ctx->ap->sglen);
+       out_sg = nx_build_sg_list(nx_ctx->out_sg, out, SHA256_DIGEST_SIZE,
+                                 nx_ctx->ap->sglen);
+       nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+       if (!nx_ctx->op.outlen) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->sha256_ops));
+
+       atomic64_add(csbcpb->cpb.sha256.message_bit_length,
+                    &(nx_ctx->stats->sha256_bytes));
+       memcpy(out, csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
+out:
+       return rc;
+}
+
+static int nx_sha256_export(struct shash_desc *desc, void *out)
+{
+       struct sha256_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+       struct sha256_state *octx = out;
+
+       octx->count = sctx->count +
+                     (csbcpb->cpb.sha256.message_bit_length / 8);
+       memcpy(octx->buf, sctx->buf, sizeof(octx->buf));
+
+       /* if no data has been processed yet, we need to export SHA256's
+        * initial data, in case this context gets imported into a software
+        * context */
+       if (csbcpb->cpb.sha256.message_bit_length)
+               memcpy(octx->state, csbcpb->cpb.sha256.message_digest,
+                      SHA256_DIGEST_SIZE);
+       else {
+               octx->state[0] = SHA256_H0;
+               octx->state[1] = SHA256_H1;
+               octx->state[2] = SHA256_H2;
+               octx->state[3] = SHA256_H3;
+               octx->state[4] = SHA256_H4;
+               octx->state[5] = SHA256_H5;
+               octx->state[6] = SHA256_H6;
+               octx->state[7] = SHA256_H7;
+       }
+
+       return 0;
+}
+
+static int nx_sha256_import(struct shash_desc *desc, const void *in)
+{
+       struct sha256_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+       const struct sha256_state *ictx = in;
+
+       memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+
+       sctx->count = ictx->count & 0x3f;
+       csbcpb->cpb.sha256.message_bit_length = (ictx->count & ~0x3f) * 8;
+
+       if (csbcpb->cpb.sha256.message_bit_length) {
+               memcpy(csbcpb->cpb.sha256.message_digest, ictx->state,
+                      SHA256_DIGEST_SIZE);
+
+               NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+               NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+       }
+
+       return 0;
+}
+
+struct shash_alg nx_shash_sha256_alg = {
+       .digestsize = SHA256_DIGEST_SIZE,
+       .init       = nx_sha256_init,
+       .update     = nx_sha256_update,
+       .final      = nx_sha256_final,
+       .export     = nx_sha256_export,
+       .import     = nx_sha256_import,
+       .descsize   = sizeof(struct sha256_state),
+       .statesize  = sizeof(struct sha256_state),
+       .base       = {
+               .cra_name        = "sha256",
+               .cra_driver_name = "sha256-nx",
+               .cra_priority    = 300,
+               .cra_flags       = CRYPTO_ALG_TYPE_SHASH,
+               .cra_blocksize   = SHA256_BLOCK_SIZE,
+               .cra_module      = THIS_MODULE,
+               .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+               .cra_init        = nx_crypto_ctx_sha_init,
+               .cra_exit        = nx_crypto_ctx_exit,
+       }
+};
diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c
new file mode 100644 (file)
index 0000000..3177b8c
--- /dev/null
@@ -0,0 +1,265 @@
+/**
+ * SHA-512 routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <linux/module.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int nx_sha512_init(struct shash_desc *desc)
+{
+       struct sha512_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_sg *out_sg;
+
+       nx_ctx_init(nx_ctx, HCOP_FC_SHA);
+
+       memset(sctx, 0, sizeof *sctx);
+
+       nx_ctx->ap = &nx_ctx->props[NX_PROPS_SHA512];
+
+       NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA512);
+       out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+                                 SHA512_DIGEST_SIZE, nx_ctx->ap->sglen);
+       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+       return 0;
+}
+
+static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
+                           unsigned int len)
+{
+       struct sha512_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+       struct nx_sg *in_sg;
+       u64 to_process, leftover, spbc_bits;
+       int rc = 0;
+
+       if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+               /* we've hit the nx chip previously and we're updating again,
+                * so copy over the partial digest */
+               memcpy(csbcpb->cpb.sha512.input_partial_digest,
+                      csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
+       }
+
+       /* 2 cases for total data len:
+        *  1: <= SHA512_BLOCK_SIZE: copy into state, return 0
+        *  2: > SHA512_BLOCK_SIZE: process X blocks, copy in leftover
+        */
+       if ((u64)len + sctx->count[0] <= SHA512_BLOCK_SIZE) {
+               memcpy(sctx->buf + sctx->count[0], data, len);
+               sctx->count[0] += len;
+               goto out;
+       }
+
+       /* to_process: the SHA512_BLOCK_SIZE data chunk to process in this
+        * update */
+       to_process = (sctx->count[0] + len) & ~(SHA512_BLOCK_SIZE - 1);
+       leftover = (sctx->count[0] + len) & (SHA512_BLOCK_SIZE - 1);
+
+       if (sctx->count[0]) {
+               in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
+                                        sctx->count[0], nx_ctx->ap->sglen);
+               in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+                                        to_process - sctx->count[0],
+                                        nx_ctx->ap->sglen);
+               nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+                                       sizeof(struct nx_sg);
+       } else {
+               in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data,
+                                        to_process, nx_ctx->ap->sglen);
+               nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+                                       sizeof(struct nx_sg);
+       }
+
+       NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+
+       if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->sha512_ops));
+
+       /* copy the leftover back into the state struct */
+       memcpy(sctx->buf, data + len - leftover, leftover);
+       sctx->count[0] = leftover;
+
+       spbc_bits = csbcpb->cpb.sha512.spbc * 8;
+       csbcpb->cpb.sha512.message_bit_length_lo += spbc_bits;
+       if (csbcpb->cpb.sha512.message_bit_length_lo < spbc_bits)
+               csbcpb->cpb.sha512.message_bit_length_hi++;
+
+       /* everything after the first update is continuation */
+       NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+out:
+       return rc;
+}
+
+static int nx_sha512_final(struct shash_desc *desc, u8 *out)
+{
+       struct sha512_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+       struct nx_sg *in_sg, *out_sg;
+       u64 count0;
+       int rc;
+
+       if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+               /* we've hit the nx chip previously, now we're finalizing,
+                * so copy over the partial digest */
+               memcpy(csbcpb->cpb.sha512.input_partial_digest,
+                      csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
+       }
+
+       /* final is represented by continuing the operation and indicating that
+        * this is not an intermediate operation */
+       NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+       count0 = sctx->count[0] * 8;
+
+       csbcpb->cpb.sha512.message_bit_length_lo += count0;
+       if (csbcpb->cpb.sha512.message_bit_length_lo < count0)
+               csbcpb->cpb.sha512.message_bit_length_hi++;
+
+       in_sg = nx_build_sg_list(nx_ctx->in_sg, sctx->buf, sctx->count[0],
+                                nx_ctx->ap->sglen);
+       out_sg = nx_build_sg_list(nx_ctx->out_sg, out, SHA512_DIGEST_SIZE,
+                                 nx_ctx->ap->sglen);
+       nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+       if (!nx_ctx->op.outlen) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+                          desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+       if (rc)
+               goto out;
+
+       atomic_inc(&(nx_ctx->stats->sha512_ops));
+       atomic64_add(csbcpb->cpb.sha512.message_bit_length_lo,
+                    &(nx_ctx->stats->sha512_bytes));
+
+       memcpy(out, csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
+out:
+       return rc;
+}
+
+static int nx_sha512_export(struct shash_desc *desc, void *out)
+{
+       struct sha512_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+       struct sha512_state *octx = out;
+
+       /* move message_bit_length (128 bits) into count and convert its value
+        * to bytes */
+       octx->count[0] = csbcpb->cpb.sha512.message_bit_length_lo >> 3 |
+                        ((csbcpb->cpb.sha512.message_bit_length_hi & 7) << 61);
+       octx->count[1] = csbcpb->cpb.sha512.message_bit_length_hi >> 3;
+
+       octx->count[0] += sctx->count[0];
+       if (octx->count[0] < sctx->count[0])
+               octx->count[1]++;
+
+       memcpy(octx->buf, sctx->buf, sizeof(octx->buf));
+
+       /* if no data has been processed yet, we need to export SHA512's
+        * initial data, in case this context gets imported into a software
+        * context */
+       if (csbcpb->cpb.sha512.message_bit_length_hi ||
+           csbcpb->cpb.sha512.message_bit_length_lo)
+               memcpy(octx->state, csbcpb->cpb.sha512.message_digest,
+                      SHA512_DIGEST_SIZE);
+       else {
+               octx->state[0] = SHA512_H0;
+               octx->state[1] = SHA512_H1;
+               octx->state[2] = SHA512_H2;
+               octx->state[3] = SHA512_H3;
+               octx->state[4] = SHA512_H4;
+               octx->state[5] = SHA512_H5;
+               octx->state[6] = SHA512_H6;
+               octx->state[7] = SHA512_H7;
+       }
+
+       return 0;
+}
+
+static int nx_sha512_import(struct shash_desc *desc, const void *in)
+{
+       struct sha512_state *sctx = shash_desc_ctx(desc);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+       const struct sha512_state *ictx = in;
+
+       memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+       sctx->count[0] = ictx->count[0] & 0x3f;
+       csbcpb->cpb.sha512.message_bit_length_lo = (ictx->count[0] & ~0x3f)
+                                                       << 3;
+       csbcpb->cpb.sha512.message_bit_length_hi = ictx->count[1] << 3 |
+                                                  ictx->count[0] >> 61;
+
+       if (csbcpb->cpb.sha512.message_bit_length_hi ||
+           csbcpb->cpb.sha512.message_bit_length_lo) {
+               memcpy(csbcpb->cpb.sha512.message_digest, ictx->state,
+                      SHA512_DIGEST_SIZE);
+
+               NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+               NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+       }
+
+       return 0;
+}
+
+struct shash_alg nx_shash_sha512_alg = {
+       .digestsize = SHA512_DIGEST_SIZE,
+       .init       = nx_sha512_init,
+       .update     = nx_sha512_update,
+       .final      = nx_sha512_final,
+       .export     = nx_sha512_export,
+       .import     = nx_sha512_import,
+       .descsize   = sizeof(struct sha512_state),
+       .statesize  = sizeof(struct sha512_state),
+       .base       = {
+               .cra_name        = "sha512",
+               .cra_driver_name = "sha512-nx",
+               .cra_priority    = 300,
+               .cra_flags       = CRYPTO_ALG_TYPE_SHASH,
+               .cra_blocksize   = SHA512_BLOCK_SIZE,
+               .cra_module      = THIS_MODULE,
+               .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
+               .cra_init        = nx_crypto_ctx_sha_init,
+               .cra_exit        = nx_crypto_ctx_exit,
+       }
+};
diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c
new file mode 100644 (file)
index 0000000..d7f179c
--- /dev/null
@@ -0,0 +1,716 @@
+/**
+ * Routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/hash.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <asm/pSeries_reconfig.h>
+#include <asm/abs_addr.h>
+#include <asm/hvcall.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+/**
+ * nx_hcall_sync - make an H_COP_OP hcall for the passed in op structure
+ *
+ * @nx_ctx: the crypto context handle
+ * @op: PFO operation struct to pass in
+ * @may_sleep: flag indicating the request can sleep
+ *
+ * Make the hcall, retrying while the hardware is busy. If we cannot yield
+ * the thread, limit the number of retries to 10 here.
+ */
+int nx_hcall_sync(struct nx_crypto_ctx *nx_ctx,
+                 struct vio_pfo_op    *op,
+                 u32                   may_sleep)
+{
+       int rc, retries = 10;
+       struct vio_dev *viodev = nx_driver.viodev;
+
+       atomic_inc(&(nx_ctx->stats->sync_ops));
+
+       do {
+               rc = vio_h_cop_sync(viodev, op);
+       } while ((rc == -EBUSY && !may_sleep && retries--) ||
+                (rc == -EBUSY && may_sleep && cond_resched()));
+
+       if (rc) {
+               dev_dbg(&viodev->dev, "vio_h_cop_sync failed: rc: %d "
+                       "hcall rc: %ld\n", rc, op->hcall_err);
+               atomic_inc(&(nx_ctx->stats->errors));
+               atomic_set(&(nx_ctx->stats->last_error), op->hcall_err);
+               atomic_set(&(nx_ctx->stats->last_error_pid), current->pid);
+       }
+
+       return rc;
+}
+
+/**
+ * nx_build_sg_list - build an NX scatter list describing a single  buffer
+ *
+ * @sg_head: pointer to the first scatter list element to build
+ * @start_addr: pointer to the linear buffer
+ * @len: length of the data at @start_addr
+ * @sgmax: the largest number of scatter list elements we're allowed to create
+ *
+ * This function will start writing nx_sg elements at @sg_head and keep
+ * writing them until all of the data from @start_addr is described or
+ * until sgmax elements have been written. Scatter list elements will be
+ * created such that none of the elements describes a buffer that crosses a 4K
+ * boundary.
+ */
+struct nx_sg *nx_build_sg_list(struct nx_sg *sg_head,
+                              u8           *start_addr,
+                              unsigned int  len,
+                              u32           sgmax)
+{
+       unsigned int sg_len = 0;
+       struct nx_sg *sg;
+       u64 sg_addr = (u64)start_addr;
+       u64 end_addr;
+
+       /* determine the start and end for this address range - slightly
+        * different if this is in VMALLOC_REGION */
+       if (is_vmalloc_addr(start_addr))
+               sg_addr = phys_to_abs(page_to_phys(vmalloc_to_page(start_addr)))
+                         + offset_in_page(sg_addr);
+       else
+               sg_addr = virt_to_abs(sg_addr);
+
+       end_addr = sg_addr + len;
+
+       /* each iteration will write one struct nx_sg element and add the
+        * length of data described by that element to sg_len. Once @len bytes
+        * have been described (or @sgmax elements have been written), the
+        * loop ends. min_t is used to ensure @end_addr falls on the same page
+        * as sg_addr, if not, we need to create another nx_sg element for the
+        * data on the next page */
+       for (sg = sg_head; sg_len < len; sg++) {
+               sg->addr = sg_addr;
+               sg_addr = min_t(u64, NX_PAGE_NUM(sg_addr + NX_PAGE_SIZE), end_addr);
+               sg->len = sg_addr - sg->addr;
+               sg_len += sg->len;
+
+               if ((sg - sg_head) == sgmax) {
+                       pr_err("nx: scatter/gather list overflow, pid: %d\n",
+                              current->pid);
+                       return NULL;
+               }
+       }
+
+       /* return the moved sg_head pointer */
+       return sg;
+}
+
+/**
+ * nx_walk_and_build - walk a linux scatterlist and build an nx scatterlist
+ *
+ * @nx_dst: pointer to the first nx_sg element to write
+ * @sglen: max number of nx_sg entries we're allowed to write
+ * @sg_src: pointer to the source linux scatterlist to walk
+ * @start: number of bytes to fast-forward past at the beginning of @sg_src
+ * @src_len: number of bytes to walk in @sg_src
+ */
+struct nx_sg *nx_walk_and_build(struct nx_sg       *nx_dst,
+                               unsigned int        sglen,
+                               struct scatterlist *sg_src,
+                               unsigned int        start,
+                               unsigned int        src_len)
+{
+       struct scatter_walk walk;
+       struct nx_sg *nx_sg = nx_dst;
+       unsigned int n, offset = 0, len = src_len;
+       char *dst;
+
+       /* we need to fast forward through @start bytes first */
+       for (;;) {
+               scatterwalk_start(&walk, sg_src);
+
+               if (start < offset + sg_src->length)
+                       break;
+
+               offset += sg_src->length;
+               sg_src = scatterwalk_sg_next(sg_src);
+       }
+
+       /* start - offset is the number of bytes to advance in the scatterlist
+        * element we're currently looking at */
+       scatterwalk_advance(&walk, start - offset);
+
+       while (len && nx_sg) {
+               n = scatterwalk_clamp(&walk, len);
+               if (!n) {
+                       scatterwalk_start(&walk, sg_next(walk.sg));
+                       n = scatterwalk_clamp(&walk, len);
+               }
+               dst = scatterwalk_map(&walk);
+
+               nx_sg = nx_build_sg_list(nx_sg, dst, n, sglen);
+               len -= n;
+
+               scatterwalk_unmap(dst);
+               scatterwalk_advance(&walk, n);
+               scatterwalk_done(&walk, SCATTERWALK_FROM_SG, len);
+       }
+
+       /* return the moved destination pointer */
+       return nx_sg;
+}
+
+/**
+ * nx_build_sg_lists - walk the input scatterlists and build arrays of NX
+ *                     scatterlists based on them.
+ *
+ * @nx_ctx: NX crypto context for the lists we're building
+ * @desc: the block cipher descriptor for the operation
+ * @dst: destination scatterlist
+ * @src: source scatterlist
+ * @nbytes: length of data described in the scatterlists
+ * @iv: destination for the iv data, if the algorithm requires it
+ *
+ * This is common code shared by all the AES algorithms. It uses the block
+ * cipher walk routines to traverse input and output scatterlists, building
+ * corresponding NX scatterlists
+ */
+int nx_build_sg_lists(struct nx_crypto_ctx  *nx_ctx,
+                     struct blkcipher_desc *desc,
+                     struct scatterlist    *dst,
+                     struct scatterlist    *src,
+                     unsigned int           nbytes,
+                     u8                    *iv)
+{
+       struct nx_sg *nx_insg = nx_ctx->in_sg;
+       struct nx_sg *nx_outsg = nx_ctx->out_sg;
+       struct blkcipher_walk walk;
+       int rc;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       rc = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
+       if (rc)
+               goto out;
+
+       if (iv)
+               memcpy(iv, walk.iv, AES_BLOCK_SIZE);
+
+       while (walk.nbytes) {
+               nx_insg = nx_build_sg_list(nx_insg, walk.src.virt.addr,
+                                          walk.nbytes, nx_ctx->ap->sglen);
+               nx_outsg = nx_build_sg_list(nx_outsg, walk.dst.virt.addr,
+                                           walk.nbytes, nx_ctx->ap->sglen);
+
+               rc = blkcipher_walk_done(desc, &walk, 0);
+               if (rc)
+                       break;
+       }
+
+       if (walk.nbytes) {
+               nx_insg = nx_build_sg_list(nx_insg, walk.src.virt.addr,
+                                          walk.nbytes, nx_ctx->ap->sglen);
+               nx_outsg = nx_build_sg_list(nx_outsg, walk.dst.virt.addr,
+                                           walk.nbytes, nx_ctx->ap->sglen);
+
+               rc = 0;
+       }
+
+       /* these lengths should be negative, which will indicate to phyp that
+        * the input and output parameters are scatterlists, not linear
+        * buffers */
+       nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) * sizeof(struct nx_sg);
+       nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) * sizeof(struct nx_sg);
+out:
+       return rc;
+}
+
+/**
+ * nx_ctx_init - initialize an nx_ctx's vio_pfo_op struct
+ *
+ * @nx_ctx: the nx context to initialize
+ * @function: the function code for the op
+ */
+void nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function)
+{
+       memset(nx_ctx->kmem, 0, nx_ctx->kmem_len);
+       nx_ctx->csbcpb->csb.valid |= NX_CSB_VALID_BIT;
+
+       nx_ctx->op.flags = function;
+       nx_ctx->op.csbcpb = virt_to_abs(nx_ctx->csbcpb);
+       nx_ctx->op.in = virt_to_abs(nx_ctx->in_sg);
+       nx_ctx->op.out = virt_to_abs(nx_ctx->out_sg);
+
+       if (nx_ctx->csbcpb_aead) {
+               nx_ctx->csbcpb_aead->csb.valid |= NX_CSB_VALID_BIT;
+
+               nx_ctx->op_aead.flags = function;
+               nx_ctx->op_aead.csbcpb = virt_to_abs(nx_ctx->csbcpb_aead);
+               nx_ctx->op_aead.in = virt_to_abs(nx_ctx->in_sg);
+               nx_ctx->op_aead.out = virt_to_abs(nx_ctx->out_sg);
+       }
+}
+
+static void nx_of_update_status(struct device   *dev,
+                              struct property *p,
+                              struct nx_of    *props)
+{
+       if (!strncmp(p->value, "okay", p->length)) {
+               props->status = NX_WAITING;
+               props->flags |= NX_OF_FLAG_STATUS_SET;
+       } else {
+               dev_info(dev, "%s: status '%s' is not 'okay'\n", __func__,
+                        (char *)p->value);
+       }
+}
+
+static void nx_of_update_sglen(struct device   *dev,
+                              struct property *p,
+                              struct nx_of    *props)
+{
+       if (p->length != sizeof(props->max_sg_len)) {
+               dev_err(dev, "%s: unexpected format for "
+                       "ibm,max-sg-len property\n", __func__);
+               dev_dbg(dev, "%s: ibm,max-sg-len is %d bytes "
+                       "long, expected %zd bytes\n", __func__,
+                       p->length, sizeof(props->max_sg_len));
+               return;
+       }
+
+       props->max_sg_len = *(u32 *)p->value;
+       props->flags |= NX_OF_FLAG_MAXSGLEN_SET;
+}
+
+static void nx_of_update_msc(struct device   *dev,
+                            struct property *p,
+                            struct nx_of    *props)
+{
+       struct msc_triplet *trip;
+       struct max_sync_cop *msc;
+       unsigned int bytes_so_far, i, lenp;
+
+       msc = (struct max_sync_cop *)p->value;
+       lenp = p->length;
+
+       /* You can't tell if the data read in for this property is sane by its
+        * size alone. This is because there are sizes embedded in the data
+        * structure. The best we can do is check lengths as we parse and bail
+        * as soon as a length error is detected. */
+       bytes_so_far = 0;
+
+       while ((bytes_so_far + sizeof(struct max_sync_cop)) <= lenp) {
+               bytes_so_far += sizeof(struct max_sync_cop);
+
+               trip = msc->trip;
+
+               for (i = 0;
+                    ((bytes_so_far + sizeof(struct msc_triplet)) <= lenp) &&
+                    i < msc->triplets;
+                    i++) {
+                       if (msc->fc > NX_MAX_FC || msc->mode > NX_MAX_MODE) {
+                               dev_err(dev, "unknown function code/mode "
+                                       "combo: %d/%d (ignored)\n", msc->fc,
+                                       msc->mode);
+                               goto next_loop;
+                       }
+
+                       switch (trip->keybitlen) {
+                       case 128:
+                       case 160:
+                               props->ap[msc->fc][msc->mode][0].databytelen =
+                                       trip->databytelen;
+                               props->ap[msc->fc][msc->mode][0].sglen =
+                                       trip->sglen;
+                               break;
+                       case 192:
+                               props->ap[msc->fc][msc->mode][1].databytelen =
+                                       trip->databytelen;
+                               props->ap[msc->fc][msc->mode][1].sglen =
+                                       trip->sglen;
+                               break;
+                       case 256:
+                               if (msc->fc == NX_FC_AES) {
+                                       props->ap[msc->fc][msc->mode][2].
+                                               databytelen = trip->databytelen;
+                                       props->ap[msc->fc][msc->mode][2].sglen =
+                                               trip->sglen;
+                               } else if (msc->fc == NX_FC_AES_HMAC ||
+                                          msc->fc == NX_FC_SHA) {
+                                       props->ap[msc->fc][msc->mode][1].
+                                               databytelen = trip->databytelen;
+                                       props->ap[msc->fc][msc->mode][1].sglen =
+                                               trip->sglen;
+                               } else {
+                                       dev_warn(dev, "unknown function "
+                                               "code/key bit len combo"
+                                               ": (%u/256)\n", msc->fc);
+                               }
+                               break;
+                       case 512:
+                               props->ap[msc->fc][msc->mode][2].databytelen =
+                                       trip->databytelen;
+                               props->ap[msc->fc][msc->mode][2].sglen =
+                                       trip->sglen;
+                               break;
+                       default:
+                               dev_warn(dev, "unknown function code/key bit "
+                                        "len combo: (%u/%u)\n", msc->fc,
+                                        trip->keybitlen);
+                               break;
+                       }
+next_loop:
+                       bytes_so_far += sizeof(struct msc_triplet);
+                       trip++;
+               }
+
+               msc = (struct max_sync_cop *)trip;
+       }
+
+       props->flags |= NX_OF_FLAG_MAXSYNCCOP_SET;
+}
+
+/**
+ * nx_of_init - read openFirmware values from the device tree
+ *
+ * @dev: device handle
+ * @props: pointer to struct to hold the properties values
+ *
+ * Called once at driver probe time, this function will read out the
+ * openFirmware properties we use at runtime. If all the OF properties are
+ * acceptable, when we exit this function props->flags will indicate that
+ * we're ready to register our crypto algorithms.
+ */
+static void nx_of_init(struct device *dev, struct nx_of *props)
+{
+       struct device_node *base_node = dev->of_node;
+       struct property *p;
+
+       p = of_find_property(base_node, "status", NULL);
+       if (!p)
+               dev_info(dev, "%s: property 'status' not found\n", __func__);
+       else
+               nx_of_update_status(dev, p, props);
+
+       p = of_find_property(base_node, "ibm,max-sg-len", NULL);
+       if (!p)
+               dev_info(dev, "%s: property 'ibm,max-sg-len' not found\n",
+                        __func__);
+       else
+               nx_of_update_sglen(dev, p, props);
+
+       p = of_find_property(base_node, "ibm,max-sync-cop", NULL);
+       if (!p)
+               dev_info(dev, "%s: property 'ibm,max-sync-cop' not found\n",
+                        __func__);
+       else
+               nx_of_update_msc(dev, p, props);
+}
+
+/**
+ * nx_register_algs - register algorithms with the crypto API
+ *
+ * Called from nx_probe()
+ *
+ * If all OF properties are in an acceptable state, the driver flags will
+ * indicate that we're ready and we'll create our debugfs files and register
+ * out crypto algorithms.
+ */
+static int nx_register_algs(void)
+{
+       int rc = -1;
+
+       if (nx_driver.of.flags != NX_OF_FLAG_MASK_READY)
+               goto out;
+
+       memset(&nx_driver.stats, 0, sizeof(struct nx_stats));
+
+       rc = NX_DEBUGFS_INIT(&nx_driver);
+       if (rc)
+               goto out;
+
+       rc = crypto_register_alg(&nx_ecb_aes_alg);
+       if (rc)
+               goto out;
+
+       rc = crypto_register_alg(&nx_cbc_aes_alg);
+       if (rc)
+               goto out_unreg_ecb;
+
+       rc = crypto_register_alg(&nx_ctr_aes_alg);
+       if (rc)
+               goto out_unreg_cbc;
+
+       rc = crypto_register_alg(&nx_ctr3686_aes_alg);
+       if (rc)
+               goto out_unreg_ctr;
+
+       rc = crypto_register_alg(&nx_gcm_aes_alg);
+       if (rc)
+               goto out_unreg_ctr3686;
+
+       rc = crypto_register_alg(&nx_gcm4106_aes_alg);
+       if (rc)
+               goto out_unreg_gcm;
+
+       rc = crypto_register_alg(&nx_ccm_aes_alg);
+       if (rc)
+               goto out_unreg_gcm4106;
+
+       rc = crypto_register_alg(&nx_ccm4309_aes_alg);
+       if (rc)
+               goto out_unreg_ccm;
+
+       rc = crypto_register_shash(&nx_shash_sha256_alg);
+       if (rc)
+               goto out_unreg_ccm4309;
+
+       rc = crypto_register_shash(&nx_shash_sha512_alg);
+       if (rc)
+               goto out_unreg_s256;
+
+       rc = crypto_register_shash(&nx_shash_aes_xcbc_alg);
+       if (rc)
+               goto out_unreg_s512;
+
+       nx_driver.of.status = NX_OKAY;
+
+       goto out;
+
+out_unreg_s512:
+       crypto_unregister_shash(&nx_shash_sha512_alg);
+out_unreg_s256:
+       crypto_unregister_shash(&nx_shash_sha256_alg);
+out_unreg_ccm4309:
+       crypto_unregister_alg(&nx_ccm4309_aes_alg);
+out_unreg_ccm:
+       crypto_unregister_alg(&nx_ccm_aes_alg);
+out_unreg_gcm4106:
+       crypto_unregister_alg(&nx_gcm4106_aes_alg);
+out_unreg_gcm:
+       crypto_unregister_alg(&nx_gcm_aes_alg);
+out_unreg_ctr3686:
+       crypto_unregister_alg(&nx_ctr3686_aes_alg);
+out_unreg_ctr:
+       crypto_unregister_alg(&nx_ctr_aes_alg);
+out_unreg_cbc:
+       crypto_unregister_alg(&nx_cbc_aes_alg);
+out_unreg_ecb:
+       crypto_unregister_alg(&nx_ecb_aes_alg);
+out:
+       return rc;
+}
+
+/**
+ * nx_crypto_ctx_init - create and initialize a crypto api context
+ *
+ * @nx_ctx: the crypto api context
+ * @fc: function code for the context
+ * @mode: the function code specific mode for this context
+ */
+static int nx_crypto_ctx_init(struct nx_crypto_ctx *nx_ctx, u32 fc, u32 mode)
+{
+       if (nx_driver.of.status != NX_OKAY) {
+               pr_err("Attempt to initialize NX crypto context while device "
+                      "is not available!\n");
+               return -ENODEV;
+       }
+
+       /* we need an extra page for csbcpb_aead for these modes */
+       if (mode == NX_MODE_AES_GCM || mode == NX_MODE_AES_CCM)
+               nx_ctx->kmem_len = (4 * NX_PAGE_SIZE) +
+                                  sizeof(struct nx_csbcpb);
+       else
+               nx_ctx->kmem_len = (3 * NX_PAGE_SIZE) +
+                                  sizeof(struct nx_csbcpb);
+
+       nx_ctx->kmem = kmalloc(nx_ctx->kmem_len, GFP_KERNEL);
+       if (!nx_ctx->kmem)
+               return -ENOMEM;
+
+       /* the csbcpb and scatterlists must be 4K aligned pages */
+       nx_ctx->csbcpb = (struct nx_csbcpb *)(round_up((u64)nx_ctx->kmem,
+                                                      (u64)NX_PAGE_SIZE));
+       nx_ctx->in_sg = (struct nx_sg *)((u8 *)nx_ctx->csbcpb + NX_PAGE_SIZE);
+       nx_ctx->out_sg = (struct nx_sg *)((u8 *)nx_ctx->in_sg + NX_PAGE_SIZE);
+
+       if (mode == NX_MODE_AES_GCM || mode == NX_MODE_AES_CCM)
+               nx_ctx->csbcpb_aead =
+                       (struct nx_csbcpb *)((u8 *)nx_ctx->out_sg +
+                                            NX_PAGE_SIZE);
+
+       /* give each context a pointer to global stats and their OF
+        * properties */
+       nx_ctx->stats = &nx_driver.stats;
+       memcpy(nx_ctx->props, nx_driver.of.ap[fc][mode],
+              sizeof(struct alg_props) * 3);
+
+       return 0;
+}
+
+/* entry points from the crypto tfm initializers */
+int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm)
+{
+       return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+                                 NX_MODE_AES_CCM);
+}
+
+int nx_crypto_ctx_aes_gcm_init(struct crypto_tfm *tfm)
+{
+       return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+                                 NX_MODE_AES_GCM);
+}
+
+int nx_crypto_ctx_aes_ctr_init(struct crypto_tfm *tfm)
+{
+       return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+                                 NX_MODE_AES_CTR);
+}
+
+int nx_crypto_ctx_aes_cbc_init(struct crypto_tfm *tfm)
+{
+       return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+                                 NX_MODE_AES_CBC);
+}
+
+int nx_crypto_ctx_aes_ecb_init(struct crypto_tfm *tfm)
+{
+       return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+                                 NX_MODE_AES_ECB);
+}
+
+int nx_crypto_ctx_sha_init(struct crypto_tfm *tfm)
+{
+       return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_SHA, NX_MODE_SHA);
+}
+
+int nx_crypto_ctx_aes_xcbc_init(struct crypto_tfm *tfm)
+{
+       return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+                                 NX_MODE_AES_XCBC_MAC);
+}
+
+/**
+ * nx_crypto_ctx_exit - destroy a crypto api context
+ *
+ * @tfm: the crypto transform pointer for the context
+ *
+ * As crypto API contexts are destroyed, this exit hook is called to free the
+ * memory associated with it.
+ */
+void nx_crypto_ctx_exit(struct crypto_tfm *tfm)
+{
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+
+       kzfree(nx_ctx->kmem);
+       nx_ctx->csbcpb = NULL;
+       nx_ctx->csbcpb_aead = NULL;
+       nx_ctx->in_sg = NULL;
+       nx_ctx->out_sg = NULL;
+}
+
+static int __devinit nx_probe(struct vio_dev *viodev,
+                             const struct vio_device_id *id)
+{
+       dev_dbg(&viodev->dev, "driver probed: %s resource id: 0x%x\n",
+               viodev->name, viodev->resource_id);
+
+       if (nx_driver.viodev) {
+               dev_err(&viodev->dev, "%s: Attempt to register more than one "
+                       "instance of the hardware\n", __func__);
+               return -EINVAL;
+       }
+
+       nx_driver.viodev = viodev;
+
+       nx_of_init(&viodev->dev, &nx_driver.of);
+
+       return nx_register_algs();
+}
+
+static int __devexit nx_remove(struct vio_dev *viodev)
+{
+       dev_dbg(&viodev->dev, "entering nx_remove for UA 0x%x\n",
+               viodev->unit_address);
+
+       if (nx_driver.of.status == NX_OKAY) {
+               NX_DEBUGFS_FINI(&nx_driver);
+
+               crypto_unregister_alg(&nx_ccm_aes_alg);
+               crypto_unregister_alg(&nx_ccm4309_aes_alg);
+               crypto_unregister_alg(&nx_gcm_aes_alg);
+               crypto_unregister_alg(&nx_gcm4106_aes_alg);
+               crypto_unregister_alg(&nx_ctr_aes_alg);
+               crypto_unregister_alg(&nx_ctr3686_aes_alg);
+               crypto_unregister_alg(&nx_cbc_aes_alg);
+               crypto_unregister_alg(&nx_ecb_aes_alg);
+               crypto_unregister_shash(&nx_shash_sha256_alg);
+               crypto_unregister_shash(&nx_shash_sha512_alg);
+               crypto_unregister_shash(&nx_shash_aes_xcbc_alg);
+       }
+
+       return 0;
+}
+
+
+/* module wide initialization/cleanup */
+static int __init nx_init(void)
+{
+       return vio_register_driver(&nx_driver.viodriver);
+}
+
+static void __exit nx_fini(void)
+{
+       vio_unregister_driver(&nx_driver.viodriver);
+}
+
+static struct vio_device_id nx_crypto_driver_ids[] __devinitdata = {
+       { "ibm,sym-encryption-v1", "ibm,sym-encryption" },
+       { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, nx_crypto_driver_ids);
+
+/* driver state structure */
+struct nx_crypto_driver nx_driver = {
+       .viodriver = {
+               .id_table = nx_crypto_driver_ids,
+               .probe = nx_probe,
+               .remove = nx_remove,
+               .name  = NX_NAME,
+       },
+};
+
+module_init(nx_init);
+module_exit(nx_fini);
+
+MODULE_AUTHOR("Kent Yoder <yoder1@us.ibm.com>");
+MODULE_DESCRIPTION(NX_STRING);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(NX_VERSION);
diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h
new file mode 100644 (file)
index 0000000..3232b18
--- /dev/null
@@ -0,0 +1,193 @@
+
+#ifndef __NX_H__
+#define __NX_H__
+
+#define NX_NAME                "nx-crypto"
+#define NX_STRING      "IBM Power7+ Nest Accelerator Crypto Driver"
+#define NX_VERSION     "1.0"
+
+static const char nx_driver_string[] = NX_STRING;
+static const char nx_driver_version[] = NX_VERSION;
+
+/* a scatterlist in the format PHYP is expecting */
+struct nx_sg {
+       u64 addr;
+       u32 rsvd;
+       u32 len;
+} __attribute((packed));
+
+#define NX_PAGE_SIZE           (4096)
+#define NX_MAX_SG_ENTRIES      (NX_PAGE_SIZE/(sizeof(struct nx_sg)))
+
+enum nx_status {
+       NX_DISABLED,
+       NX_WAITING,
+       NX_OKAY
+};
+
+/* msc_triplet and max_sync_cop are used only to assist in parsing the
+ * openFirmware property */
+struct msc_triplet {
+       u32 keybitlen;
+       u32 databytelen;
+       u32 sglen;
+} __packed;
+
+struct max_sync_cop {
+       u32 fc;
+       u32 mode;
+       u32 triplets;
+       struct msc_triplet trip[0];
+} __packed;
+
+struct alg_props {
+       u32 databytelen;
+       u32 sglen;
+};
+
+#define NX_OF_FLAG_MAXSGLEN_SET                (1)
+#define NX_OF_FLAG_STATUS_SET          (2)
+#define NX_OF_FLAG_MAXSYNCCOP_SET      (4)
+#define NX_OF_FLAG_MASK_READY          (NX_OF_FLAG_MAXSGLEN_SET | \
+                                        NX_OF_FLAG_STATUS_SET |   \
+                                        NX_OF_FLAG_MAXSYNCCOP_SET)
+struct nx_of {
+       u32 flags;
+       u32 max_sg_len;
+       enum nx_status status;
+       struct alg_props ap[NX_MAX_FC][NX_MAX_MODE][3];
+};
+
+struct nx_stats {
+       atomic_t aes_ops;
+       atomic64_t aes_bytes;
+       atomic_t sha256_ops;
+       atomic64_t sha256_bytes;
+       atomic_t sha512_ops;
+       atomic64_t sha512_bytes;
+
+       atomic_t sync_ops;
+
+       atomic_t errors;
+       atomic_t last_error;
+       atomic_t last_error_pid;
+};
+
+struct nx_debugfs {
+       struct dentry *dfs_root;
+       struct dentry *dfs_aes_ops, *dfs_aes_bytes;
+       struct dentry *dfs_sha256_ops, *dfs_sha256_bytes;
+       struct dentry *dfs_sha512_ops, *dfs_sha512_bytes;
+       struct dentry *dfs_errors, *dfs_last_error, *dfs_last_error_pid;
+};
+
+struct nx_crypto_driver {
+       struct nx_stats    stats;
+       struct nx_of       of;
+       struct vio_dev    *viodev;
+       struct vio_driver  viodriver;
+       struct nx_debugfs  dfs;
+};
+
+#define NX_GCM4106_NONCE_LEN           (4)
+#define NX_GCM_CTR_OFFSET              (12)
+struct nx_gcm_priv {
+       u8 iv[16];
+       u8 iauth_tag[16];
+       u8 nonce[NX_GCM4106_NONCE_LEN];
+};
+
+#define NX_CCM_AES_KEY_LEN             (16)
+#define NX_CCM4309_AES_KEY_LEN         (19)
+#define NX_CCM4309_NONCE_LEN           (3)
+struct nx_ccm_priv {
+       u8 iv[16];
+       u8 b0[16];
+       u8 iauth_tag[16];
+       u8 oauth_tag[16];
+       u8 nonce[NX_CCM4309_NONCE_LEN];
+};
+
+struct nx_xcbc_priv {
+       u8 key[16];
+};
+
+struct nx_ctr_priv {
+       u8 iv[16];
+};
+
+struct nx_crypto_ctx {
+       void *kmem;               /* unaligned, kmalloc'd buffer */
+       size_t kmem_len;          /* length of kmem */
+       struct nx_csbcpb *csbcpb; /* aligned page given to phyp @ hcall time */
+       struct vio_pfo_op op;     /* operation struct with hcall parameters */
+       struct nx_csbcpb *csbcpb_aead; /* secondary csbcpb used by AEAD algs */
+       struct vio_pfo_op op_aead;/* operation struct for csbcpb_aead */
+
+       struct nx_sg *in_sg;      /* aligned pointer into kmem to an sg list */
+       struct nx_sg *out_sg;     /* aligned pointer into kmem to an sg list */
+
+       struct alg_props *ap;     /* pointer into props based on our key size */
+       struct alg_props props[3];/* openFirmware properties for requests */
+       struct nx_stats *stats;   /* pointer into an nx_crypto_driver for stats
+                                    reporting */
+
+       union {
+               struct nx_gcm_priv gcm;
+               struct nx_ccm_priv ccm;
+               struct nx_xcbc_priv xcbc;
+               struct nx_ctr_priv ctr;
+       } priv;
+};
+
+/* prototypes */
+int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_gcm_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_xcbc_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_ctr_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_cbc_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_ecb_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_sha_init(struct crypto_tfm *tfm);
+void nx_crypto_ctx_exit(struct crypto_tfm *tfm);
+void nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function);
+int nx_hcall_sync(struct nx_crypto_ctx *ctx, struct vio_pfo_op *op,
+                 u32 may_sleep);
+struct nx_sg *nx_build_sg_list(struct nx_sg *, u8 *, unsigned int, u32);
+int nx_build_sg_lists(struct nx_crypto_ctx *, struct blkcipher_desc *,
+                     struct scatterlist *, struct scatterlist *, unsigned int,
+                     u8 *);
+struct nx_sg *nx_walk_and_build(struct nx_sg *, unsigned int,
+                               struct scatterlist *, unsigned int,
+                               unsigned int);
+
+#ifdef CONFIG_DEBUG_FS
+#define NX_DEBUGFS_INIT(drv)   nx_debugfs_init(drv)
+#define NX_DEBUGFS_FINI(drv)   nx_debugfs_fini(drv)
+
+int nx_debugfs_init(struct nx_crypto_driver *);
+void nx_debugfs_fini(struct nx_crypto_driver *);
+#else
+#define NX_DEBUGFS_INIT(drv)   (0)
+#define NX_DEBUGFS_FINI(drv)   (0)
+#endif
+
+#define NX_PAGE_NUM(x)         ((u64)(x) & 0xfffffffffffff000ULL)
+
+extern struct crypto_alg nx_cbc_aes_alg;
+extern struct crypto_alg nx_ecb_aes_alg;
+extern struct crypto_alg nx_gcm_aes_alg;
+extern struct crypto_alg nx_gcm4106_aes_alg;
+extern struct crypto_alg nx_ctr_aes_alg;
+extern struct crypto_alg nx_ctr3686_aes_alg;
+extern struct crypto_alg nx_ccm_aes_alg;
+extern struct crypto_alg nx_ccm4309_aes_alg;
+extern struct shash_alg nx_shash_aes_xcbc_alg;
+extern struct shash_alg nx_shash_sha512_alg;
+extern struct shash_alg nx_shash_sha256_alg;
+
+extern struct nx_crypto_driver nx_driver;
+
+#define SCATTERWALK_TO_SG      1
+#define SCATTERWALK_FROM_SG    0
+
+#endif
diff --git a/drivers/crypto/nx/nx_csbcpb.h b/drivers/crypto/nx/nx_csbcpb.h
new file mode 100644 (file)
index 0000000..a304f95
--- /dev/null
@@ -0,0 +1,205 @@
+
+#ifndef __NX_CSBCPB_H__
+#define __NX_CSBCPB_H__
+
+struct cop_symcpb_aes_ecb {
+       u8 key[32];
+       u8 __rsvd[80];
+} __packed;
+
+struct cop_symcpb_aes_cbc {
+       u8 iv[16];
+       u8 key[32];
+       u8 cv[16];
+       u32 spbc;
+       u8 __rsvd[44];
+} __packed;
+
+struct cop_symcpb_aes_gca {
+       u8 in_pat[16];
+       u8 key[32];
+       u8 out_pat[16];
+       u32 spbc;
+       u8 __rsvd[44];
+} __packed;
+
+struct cop_symcpb_aes_gcm {
+       u8 in_pat_or_aad[16];
+       u8 iv_or_cnt[16];
+       u64 bit_length_aad;
+       u64 bit_length_data;
+       u8 in_s0[16];
+       u8 key[32];
+       u8 __rsvd1[16];
+       u8 out_pat_or_mac[16];
+       u8 out_s0[16];
+       u8 out_cnt[16];
+       u32 spbc;
+       u8 __rsvd2[12];
+} __packed;
+
+struct cop_symcpb_aes_ctr {
+       u8 iv[16];
+       u8 key[32];
+       u8 cv[16];
+       u32 spbc;
+       u8 __rsvd2[44];
+} __packed;
+
+struct cop_symcpb_aes_cca {
+       u8 b0[16];
+       u8 b1[16];
+       u8 key[16];
+       u8 out_pat_or_b0[16];
+       u32 spbc;
+       u8 __rsvd[44];
+} __packed;
+
+struct cop_symcpb_aes_ccm {
+       u8 in_pat_or_b0[16];
+       u8 iv_or_ctr[16];
+       u8 in_s0[16];
+       u8 key[16];
+       u8 __rsvd1[48];
+       u8 out_pat_or_mac[16];
+       u8 out_s0[16];
+       u8 out_ctr[16];
+       u32 spbc;
+       u8 __rsvd2[12];
+} __packed;
+
+struct cop_symcpb_aes_xcbc {
+       u8 cv[16];
+       u8 key[16];
+       u8 __rsvd1[16];
+       u8 out_cv_mac[16];
+       u32 spbc;
+       u8 __rsvd2[44];
+} __packed;
+
+struct cop_symcpb_sha256 {
+       u64 message_bit_length;
+       u64 __rsvd1;
+       u8 input_partial_digest[32];
+       u8 message_digest[32];
+       u32 spbc;
+       u8 __rsvd2[44];
+} __packed;
+
+struct cop_symcpb_sha512 {
+       u64 message_bit_length_hi;
+       u64 message_bit_length_lo;
+       u8 input_partial_digest[64];
+       u8 __rsvd1[32];
+       u8 message_digest[64];
+       u32 spbc;
+       u8 __rsvd2[76];
+} __packed;
+
+#define NX_FDM_INTERMEDIATE            0x01
+#define NX_FDM_CONTINUATION            0x02
+#define NX_FDM_ENDE_ENCRYPT            0x80
+
+#define NX_CPB_FDM(c)                  ((c)->cpb.hdr.fdm)
+#define NX_CPB_KS_DS(c)                        ((c)->cpb.hdr.ks_ds)
+
+#define NX_CPB_KEY_SIZE(c)             (NX_CPB_KS_DS(c) >> 4)
+#define NX_CPB_SET_KEY_SIZE(c, x)      NX_CPB_KS_DS(c) |= ((x) << 4)
+#define NX_CPB_SET_DIGEST_SIZE(c, x)   NX_CPB_KS_DS(c) |= (x)
+
+struct cop_symcpb_header {
+       u8 mode;
+       u8 fdm;
+       u8 ks_ds;
+       u8 pad_byte;
+       u8 __rsvd[12];
+} __packed;
+
+struct cop_parameter_block {
+       struct cop_symcpb_header hdr;
+       union {
+               struct cop_symcpb_aes_ecb  aes_ecb;
+               struct cop_symcpb_aes_cbc  aes_cbc;
+               struct cop_symcpb_aes_gca  aes_gca;
+               struct cop_symcpb_aes_gcm  aes_gcm;
+               struct cop_symcpb_aes_cca  aes_cca;
+               struct cop_symcpb_aes_ccm  aes_ccm;
+               struct cop_symcpb_aes_ctr  aes_ctr;
+               struct cop_symcpb_aes_xcbc aes_xcbc;
+               struct cop_symcpb_sha256   sha256;
+               struct cop_symcpb_sha512   sha512;
+       };
+} __packed;
+
+#define NX_CSB_VALID_BIT       0x80
+
+/* co-processor status block */
+struct cop_status_block {
+       u8 valid;
+       u8 crb_seq_number;
+       u8 completion_code;
+       u8 completion_extension;
+       u32 processed_byte_count;
+       u64 address;
+} __packed;
+
+/* Nest accelerator workbook section 4.4 */
+struct nx_csbcpb {
+       unsigned char __rsvd[112];
+       struct cop_status_block csb;
+       struct cop_parameter_block cpb;
+} __packed;
+
+/* nx_csbcpb related definitions */
+#define NX_MODE_AES_ECB                        0
+#define NX_MODE_AES_CBC                        1
+#define NX_MODE_AES_GMAC               2
+#define NX_MODE_AES_GCA                        3
+#define NX_MODE_AES_GCM                        4
+#define NX_MODE_AES_CCA                        5
+#define NX_MODE_AES_CCM                        6
+#define NX_MODE_AES_CTR                        7
+#define NX_MODE_AES_XCBC_MAC           20
+#define NX_MODE_SHA                    0
+#define NX_MODE_SHA_HMAC               1
+#define NX_MODE_AES_CBC_HMAC_ETA       8
+#define NX_MODE_AES_CBC_HMAC_ATE       9
+#define NX_MODE_AES_CBC_HMAC_EAA       10
+#define NX_MODE_AES_CTR_HMAC_ETA       12
+#define NX_MODE_AES_CTR_HMAC_ATE       13
+#define NX_MODE_AES_CTR_HMAC_EAA       14
+
+#define NX_FDM_CI_FULL         0
+#define NX_FDM_CI_FIRST                1
+#define NX_FDM_CI_LAST         2
+#define NX_FDM_CI_MIDDLE       3
+
+#define NX_FDM_PR_NONE         0
+#define NX_FDM_PR_PAD          1
+
+#define NX_KS_AES_128          1
+#define NX_KS_AES_192          2
+#define NX_KS_AES_256          3
+
+#define NX_DS_SHA256           2
+#define NX_DS_SHA512           3
+
+#define NX_FC_AES              0
+#define NX_FC_SHA              2
+#define NX_FC_AES_HMAC         6
+
+#define NX_MAX_FC              (NX_FC_AES_HMAC + 1)
+#define NX_MAX_MODE            (NX_MODE_AES_XCBC_MAC + 1)
+
+#define HCOP_FC_AES          NX_FC_AES
+#define HCOP_FC_SHA          NX_FC_SHA
+#define HCOP_FC_AES_HMAC     NX_FC_AES_HMAC
+
+/* indices into the array of algorithm properties */
+#define NX_PROPS_AES_128               0
+#define NX_PROPS_AES_192               1
+#define NX_PROPS_AES_256               2
+#define NX_PROPS_SHA256                        1
+#define NX_PROPS_SHA512                        2
+
+#endif
diff --git a/drivers/crypto/nx/nx_debugfs.c b/drivers/crypto/nx/nx_debugfs.c
new file mode 100644 (file)
index 0000000..7ab2e8d
--- /dev/null
@@ -0,0 +1,103 @@
+/**
+ * debugfs routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * 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.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <linux/device.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+#ifdef CONFIG_DEBUG_FS
+
+/*
+ * debugfs
+ *
+ * For documentation on these attributes, please see:
+ *
+ * Documentation/ABI/testing/debugfs-pfo-nx-crypto
+ */
+
+int nx_debugfs_init(struct nx_crypto_driver *drv)
+{
+       struct nx_debugfs *dfs = &drv->dfs;
+
+       dfs->dfs_root = debugfs_create_dir(NX_NAME, NULL);
+
+       dfs->dfs_aes_ops =
+               debugfs_create_u32("aes_ops",
+                                  S_IRUSR | S_IRGRP | S_IROTH,
+                                  dfs->dfs_root, (u32 *)&drv->stats.aes_ops);
+       dfs->dfs_sha256_ops =
+               debugfs_create_u32("sha256_ops",
+                                  S_IRUSR | S_IRGRP | S_IROTH,
+                                  dfs->dfs_root,
+                                  (u32 *)&drv->stats.sha256_ops);
+       dfs->dfs_sha512_ops =
+               debugfs_create_u32("sha512_ops",
+                                  S_IRUSR | S_IRGRP | S_IROTH,
+                                  dfs->dfs_root,
+                                  (u32 *)&drv->stats.sha512_ops);
+       dfs->dfs_aes_bytes =
+               debugfs_create_u64("aes_bytes",
+                                  S_IRUSR | S_IRGRP | S_IROTH,
+                                  dfs->dfs_root,
+                                  (u64 *)&drv->stats.aes_bytes);
+       dfs->dfs_sha256_bytes =
+               debugfs_create_u64("sha256_bytes",
+                                  S_IRUSR | S_IRGRP | S_IROTH,
+                                  dfs->dfs_root,
+                                  (u64 *)&drv->stats.sha256_bytes);
+       dfs->dfs_sha512_bytes =
+               debugfs_create_u64("sha512_bytes",
+                                  S_IRUSR | S_IRGRP | S_IROTH,
+                                  dfs->dfs_root,
+                                  (u64 *)&drv->stats.sha512_bytes);
+       dfs->dfs_errors =
+               debugfs_create_u32("errors",
+                                  S_IRUSR | S_IRGRP | S_IROTH,
+                                  dfs->dfs_root, (u32 *)&drv->stats.errors);
+       dfs->dfs_last_error =
+               debugfs_create_u32("last_error",
+                                  S_IRUSR | S_IRGRP | S_IROTH,
+                                  dfs->dfs_root,
+                                  (u32 *)&drv->stats.last_error);
+       dfs->dfs_last_error_pid =
+               debugfs_create_u32("last_error_pid",
+                                  S_IRUSR | S_IRGRP | S_IROTH,
+                                  dfs->dfs_root,
+                                  (u32 *)&drv->stats.last_error_pid);
+       return 0;
+}
+
+void
+nx_debugfs_fini(struct nx_crypto_driver *drv)
+{
+       debugfs_remove_recursive(drv->dfs.dfs_root);
+}
+
+#endif
index 574a06b1b1deb4d431cddd1d7a399bcb9a7825f4..af75ddd4f158b5de78f9d5bc44ec2f9c579e78a5 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/devfreq.h>
+#include "governor.h"
 
 static int devfreq_performance_func(struct devfreq *df,
                                    unsigned long *freq)
@@ -25,8 +26,14 @@ static int devfreq_performance_func(struct devfreq *df,
        return 0;
 }
 
+static int performance_init(struct devfreq *devfreq)
+{
+       return update_devfreq(devfreq);
+}
+
 const struct devfreq_governor devfreq_performance = {
        .name = "performance",
+       .init = performance_init,
        .get_target_freq = devfreq_performance_func,
        .no_central_polling = true,
 };
index d742d4a82d6a0da726f620ae5505e4d5c642c95b..fec0cdbd24773fd531b5c300bfb4afb5111d9545 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/devfreq.h>
+#include "governor.h"
 
 static int devfreq_powersave_func(struct devfreq *df,
                                  unsigned long *freq)
@@ -22,8 +23,14 @@ static int devfreq_powersave_func(struct devfreq *df,
        return 0;
 }
 
+static int powersave_init(struct devfreq *devfreq)
+{
+       return update_devfreq(devfreq);
+}
+
 const struct devfreq_governor devfreq_powersave = {
        .name = "powersave",
+       .init = powersave_init,
        .get_target_freq = devfreq_powersave_func,
        .no_central_polling = true,
 };
index e466ecba8dc1f7707e022f56973a1fc2d3754289..7cd9bf42108b7368803322d7116c3a8951d30a1b 100644 (file)
@@ -1102,6 +1102,19 @@ config SENSORS_AMC6821
          This driver can also be build as a module.  If so, the module
          will be called amc6821.
 
+config SENSORS_INA2XX
+       tristate "Texas Instruments INA219, INA226"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for INA219 and INA226 power
+         monitor chips.
+
+         The INA2xx driver is configured for the default configuration of
+         the part as described in the datasheet.
+         Default value for Rshunt is 10 mOhms.
+         This driver can also be built as a module.  If so, the module
+         will be called ina2xx.
+
 config SENSORS_THMC50
        tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
        depends on I2C
index 6d3f11f71815356ba3e7f777a4fb4d48d4d6aeca..e1eeac13b85182389d108c3e65a94aa64fa76222 100644 (file)
@@ -62,6 +62,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
 obj-$(CONFIG_SENSORS_I5K_AMB)  += i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)   += ibmaem.o
 obj-$(CONFIG_SENSORS_IBMPEX)   += ibmpex.o
+obj-$(CONFIG_SENSORS_INA2XX)   += ina2xx.o
 obj-$(CONFIG_SENSORS_IT87)     += it87.o
 obj-$(CONFIG_SENSORS_JC42)     += jc42.o
 obj-$(CONFIG_SENSORS_JZ4740)   += jz4740-hwmon.o
index 9140236a0182b4f73d80efbab7d6fdac11aca539..34ad5a27a7e9fcd68b7597f799a99387f421c835 100644 (file)
@@ -107,15 +107,7 @@ struct acpi_power_meter_resource {
        struct kobject          *holders_dir;
 };
 
-struct ro_sensor_template {
-       char *label;
-       ssize_t (*show)(struct device *dev,
-                       struct device_attribute *devattr,
-                       char *buf);
-       int index;
-};
-
-struct rw_sensor_template {
+struct sensor_template {
        char *label;
        ssize_t (*show)(struct device *dev,
                        struct device_attribute *devattr,
@@ -469,52 +461,67 @@ static ssize_t show_name(struct device *dev,
        return sprintf(buf, "%s\n", ACPI_POWER_METER_NAME);
 }
 
+#define RO_SENSOR_TEMPLATE(_label, _show, _index)      \
+       {                                               \
+               .label = _label,                        \
+               .show  = _show,                         \
+               .index = _index,                        \
+       }
+
+#define RW_SENSOR_TEMPLATE(_label, _show, _set, _index)        \
+       {                                               \
+               .label = _label,                        \
+               .show  = _show,                         \
+               .set   = _set,                          \
+               .index = _index,                        \
+       }
+
 /* Sensor descriptions.  If you add a sensor, update NUM_SENSORS above! */
-static struct ro_sensor_template meter_ro_attrs[] = {
-{POWER_AVERAGE_NAME, show_power, 0},
-{"power1_accuracy", show_accuracy, 0},
-{"power1_average_interval_min", show_val, 0},
-{"power1_average_interval_max", show_val, 1},
-{"power1_is_battery", show_val, 5},
-{NULL, NULL, 0},
+static struct sensor_template meter_attrs[] = {
+       RO_SENSOR_TEMPLATE(POWER_AVERAGE_NAME, show_power, 0),
+       RO_SENSOR_TEMPLATE("power1_accuracy", show_accuracy, 0),
+       RO_SENSOR_TEMPLATE("power1_average_interval_min", show_val, 0),
+       RO_SENSOR_TEMPLATE("power1_average_interval_max", show_val, 1),
+       RO_SENSOR_TEMPLATE("power1_is_battery", show_val, 5),
+       RW_SENSOR_TEMPLATE(POWER_AVG_INTERVAL_NAME, show_avg_interval,
+               set_avg_interval, 0),
+       {},
 };
 
-static struct rw_sensor_template meter_rw_attrs[] = {
-{POWER_AVG_INTERVAL_NAME, show_avg_interval, set_avg_interval, 0},
-{NULL, NULL, NULL, 0},
+static struct sensor_template misc_cap_attrs[] = {
+       RO_SENSOR_TEMPLATE("power1_cap_min", show_val, 2),
+       RO_SENSOR_TEMPLATE("power1_cap_max", show_val, 3),
+       RO_SENSOR_TEMPLATE("power1_cap_hyst", show_val, 4),
+       RO_SENSOR_TEMPLATE(POWER_ALARM_NAME, show_val, 6),
+       {},
 };
 
-static struct ro_sensor_template misc_cap_attrs[] = {
-{"power1_cap_min", show_val, 2},
-{"power1_cap_max", show_val, 3},
-{"power1_cap_hyst", show_val, 4},
-{POWER_ALARM_NAME, show_val, 6},
-{NULL, NULL, 0},
+static struct sensor_template ro_cap_attrs[] = {
+       RO_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, 0),
+       {},
 };
 
-static struct ro_sensor_template ro_cap_attrs[] = {
-{POWER_CAP_NAME, show_cap, 0},
-{NULL, NULL, 0},
+static struct sensor_template rw_cap_attrs[] = {
+       RW_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, set_cap, 0),
+       {},
 };
 
-static struct rw_sensor_template rw_cap_attrs[] = {
-{POWER_CAP_NAME, show_cap, set_cap, 0},
-{NULL, NULL, NULL, 0},
+static struct sensor_template trip_attrs[] = {
+       RW_SENSOR_TEMPLATE("power1_average_min", show_val, set_trip, 7),
+       RW_SENSOR_TEMPLATE("power1_average_max", show_val, set_trip, 8),
+       {},
 };
 
-static struct rw_sensor_template trip_attrs[] = {
-{"power1_average_min", show_val, set_trip, 7},
-{"power1_average_max", show_val, set_trip, 8},
-{NULL, NULL, NULL, 0},
+static struct sensor_template misc_attrs[] = {
+       RO_SENSOR_TEMPLATE("name", show_name, 0),
+       RO_SENSOR_TEMPLATE("power1_model_number", show_str, 0),
+       RO_SENSOR_TEMPLATE("power1_oem_info", show_str, 2),
+       RO_SENSOR_TEMPLATE("power1_serial_number", show_str, 1),
+       {},
 };
 
-static struct ro_sensor_template misc_attrs[] = {
-{"name", show_name, 0},
-{"power1_model_number", show_str, 0},
-{"power1_oem_info", show_str, 2},
-{"power1_serial_number", show_str, 1},
-{NULL, NULL, 0},
-};
+#undef RO_SENSOR_TEMPLATE
+#undef RW_SENSOR_TEMPLATE
 
 /* Read power domain data */
 static void remove_domain_devices(struct acpi_power_meter_resource *resource)
@@ -619,49 +626,24 @@ end:
 }
 
 /* Registration and deregistration */
-static int register_ro_attrs(struct acpi_power_meter_resource *resource,
-                            struct ro_sensor_template *ro)
+static int register_attrs(struct acpi_power_meter_resource *resource,
+                         struct sensor_template *attrs)
 {
        struct device *dev = &resource->acpi_dev->dev;
        struct sensor_device_attribute *sensors =
                &resource->sensors[resource->num_sensors];
        int res = 0;
 
-       while (ro->label) {
-               sensors->dev_attr.attr.name = ro->label;
+       while (attrs->label) {
+               sensors->dev_attr.attr.name = attrs->label;
                sensors->dev_attr.attr.mode = S_IRUGO;
-               sensors->dev_attr.show = ro->show;
-               sensors->index = ro->index;
+               sensors->dev_attr.show = attrs->show;
+               sensors->index = attrs->index;
 
-               sysfs_attr_init(&sensors->dev_attr.attr);
-               res = device_create_file(dev, &sensors->dev_attr);
-               if (res) {
-                       sensors->dev_attr.attr.name = NULL;
-                       goto error;
+               if (attrs->set) {
+                       sensors->dev_attr.attr.mode |= S_IWUSR;
+                       sensors->dev_attr.store = attrs->set;
                }
-               sensors++;
-               resource->num_sensors++;
-               ro++;
-       }
-
-error:
-       return res;
-}
-
-static int register_rw_attrs(struct acpi_power_meter_resource *resource,
-                            struct rw_sensor_template *rw)
-{
-       struct device *dev = &resource->acpi_dev->dev;
-       struct sensor_device_attribute *sensors =
-               &resource->sensors[resource->num_sensors];
-       int res = 0;
-
-       while (rw->label) {
-               sensors->dev_attr.attr.name = rw->label;
-               sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR;
-               sensors->dev_attr.show = rw->show;
-               sensors->dev_attr.store = rw->set;
-               sensors->index = rw->index;
 
                sysfs_attr_init(&sensors->dev_attr.attr);
                res = device_create_file(dev, &sensors->dev_attr);
@@ -671,7 +653,7 @@ static int register_rw_attrs(struct acpi_power_meter_resource *resource,
                }
                sensors++;
                resource->num_sensors++;
-               rw++;
+               attrs++;
        }
 
 error:
@@ -703,10 +685,7 @@ static int setup_attrs(struct acpi_power_meter_resource *resource)
                return res;
 
        if (resource->caps.flags & POWER_METER_CAN_MEASURE) {
-               res = register_ro_attrs(resource, meter_ro_attrs);
-               if (res)
-                       goto error;
-               res = register_rw_attrs(resource, meter_rw_attrs);
+               res = register_attrs(resource, meter_attrs);
                if (res)
                        goto error;
        }
@@ -718,28 +697,27 @@ static int setup_attrs(struct acpi_power_meter_resource *resource)
                        goto skip_unsafe_cap;
                }
 
-               if (resource->caps.configurable_cap) {
-                       res = register_rw_attrs(resource, rw_cap_attrs);
-                       if (res)
-                               goto error;
-               } else {
-                       res = register_ro_attrs(resource, ro_cap_attrs);
-                       if (res)
-                               goto error;
-               }
-               res = register_ro_attrs(resource, misc_cap_attrs);
+               if (resource->caps.configurable_cap)
+                       res = register_attrs(resource, rw_cap_attrs);
+               else
+                       res = register_attrs(resource, ro_cap_attrs);
+
+               if (res)
+                       goto error;
+
+               res = register_attrs(resource, misc_cap_attrs);
                if (res)
                        goto error;
        }
-skip_unsafe_cap:
 
+skip_unsafe_cap:
        if (resource->caps.flags & POWER_METER_CAN_TRIP) {
-               res = register_rw_attrs(resource, trip_attrs);
+               res = register_attrs(resource, trip_attrs);
                if (res)
                        goto error;
        }
 
-       res = register_ro_attrs(resource, misc_attrs);
+       res = register_attrs(resource, misc_attrs);
        if (res)
                goto error;
 
index f85ce70d96779b5dcd366983f48d4458cc782704..cfec802cf9ca949b705d24a1d862a702af223193 100644 (file)
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 
-/*
- * AD7314 power mode
- */
-#define AD7314_PD              0x2000
-
 /*
  * AD7314 temperature masks
  */
-#define AD7314_TEMP_SIGN               0x200
 #define AD7314_TEMP_MASK               0x7FE0
-#define AD7314_TEMP_OFFSET             5
+#define AD7314_TEMP_SHIFT              5
 
 /*
  * ADT7301 and ADT7302 temperature masks
  */
-#define ADT7301_TEMP_SIGN              0x2000
 #define ADT7301_TEMP_MASK              0x3FFF
 
 enum ad7314_variant {
@@ -73,7 +66,7 @@ static ssize_t ad7314_show_temperature(struct device *dev,
                return ret;
        switch (spi_get_device_id(chip->spi_dev)->driver_data) {
        case ad7314:
-               data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_OFFSET;
+               data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT;
                data = (data << 6) >> 6;
 
                return sprintf(buf, "%d\n", 250 * data);
index e8e18cab1fb8c34d63c259a64afb461833df8be7..6b13f1a4dc27c1d9fb48a6d0edc5fb46de83918b 100644 (file)
@@ -257,15 +257,4 @@ static struct pci_driver fam15h_power_driver = {
        .remove = __devexit_p(fam15h_power_remove),
 };
 
-static int __init fam15h_power_init(void)
-{
-       return pci_register_driver(&fam15h_power_driver);
-}
-
-static void __exit fam15h_power_exit(void)
-{
-       pci_unregister_driver(&fam15h_power_driver);
-}
-
-module_init(fam15h_power_init)
-module_exit(fam15h_power_exit)
+module_pci_driver(fam15h_power_driver);
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
new file mode 100644 (file)
index 0000000..7f3f4a3
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Driver for Texas Instruments INA219, INA226 power monitor chips
+ *
+ * INA219:
+ * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina219
+ *
+ * INA226:
+ * Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina226
+ *
+ * Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
+ * Thanks to Jan Volkering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <linux/platform_data/ina2xx.h>
+
+/* common register definitions */
+#define INA2XX_CONFIG                  0x00
+#define INA2XX_SHUNT_VOLTAGE           0x01 /* readonly */
+#define INA2XX_BUS_VOLTAGE             0x02 /* readonly */
+#define INA2XX_POWER                   0x03 /* readonly */
+#define INA2XX_CURRENT                 0x04 /* readonly */
+#define INA2XX_CALIBRATION             0x05
+
+/* INA226 register definitions */
+#define INA226_MASK_ENABLE             0x06
+#define INA226_ALERT_LIMIT             0x07
+#define INA226_DIE_ID                  0xFF
+
+
+/* register count */
+#define INA219_REGISTERS               6
+#define INA226_REGISTERS               8
+
+#define INA2XX_MAX_REGISTERS           8
+
+/* settings - depend on use case */
+#define INA219_CONFIG_DEFAULT          0x399F  /* PGA=8 */
+#define INA226_CONFIG_DEFAULT          0x4527  /* averages=16 */
+
+/* worst case is 68.10 ms (~14.6Hz, ina219) */
+#define INA2XX_CONVERSION_RATE         15
+
+enum ina2xx_ids { ina219, ina226 };
+
+struct ina2xx_data {
+       struct device *hwmon_dev;
+
+       struct mutex update_lock;
+       bool valid;
+       unsigned long last_updated;
+
+       int kind;
+       int registers;
+       u16 regs[INA2XX_MAX_REGISTERS];
+};
+
+int ina2xx_read_word(struct i2c_client *client, int reg)
+{
+       int val = i2c_smbus_read_word_data(client, reg);
+       if (unlikely(val < 0)) {
+               dev_dbg(&client->dev,
+                       "Failed to read register: %d\n", reg);
+               return val;
+       }
+       return be16_to_cpu(val);
+}
+
+void ina2xx_write_word(struct i2c_client *client, int reg, int data)
+{
+       i2c_smbus_write_word_data(client, reg, cpu_to_be16(data));
+}
+
+static struct ina2xx_data *ina2xx_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ina2xx_data *data = i2c_get_clientdata(client);
+       struct ina2xx_data *ret = data;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated +
+                      HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
+
+               int i;
+
+               dev_dbg(&client->dev, "Starting ina2xx update\n");
+
+               /* Read all registers */
+               for (i = 0; i < data->registers; i++) {
+                       int rv = ina2xx_read_word(client, i);
+                       if (rv < 0) {
+                               ret = ERR_PTR(rv);
+                               goto abort;
+                       }
+                       data->regs[i] = rv;
+               }
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+abort:
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static int ina219_get_value(struct ina2xx_data *data, u8 reg)
+{
+       /*
+        * calculate exact value for the given register
+        * we assume default power-on reset settings:
+        * bus voltage range 32V
+        * gain = /8
+        * adc 1 & 2 -> conversion time 532uS
+        * mode is continuous shunt and bus
+        * calibration value is INA219_CALIBRATION_VALUE
+        */
+       int val = data->regs[reg];
+
+       switch (reg) {
+       case INA2XX_SHUNT_VOLTAGE:
+               /* LSB=10uV. Convert to mV. */
+               val = DIV_ROUND_CLOSEST(val, 100);
+               break;
+       case INA2XX_BUS_VOLTAGE:
+               /* LSB=4mV. Register is not right aligned, convert to mV. */
+               val = (val >> 3) * 4;
+               break;
+       case INA2XX_POWER:
+               /* LSB=20mW. Convert to uW */
+               val = val * 20 * 1000;
+               break;
+       case INA2XX_CURRENT:
+               /* LSB=1mA (selected). Is in mA */
+               break;
+       default:
+               /* programmer goofed */
+               WARN_ON_ONCE(1);
+               val = 0;
+               break;
+       }
+
+       return val;
+}
+
+static int ina226_get_value(struct ina2xx_data *data, u8 reg)
+{
+       /*
+        * calculate exact value for the given register
+        * we assume default power-on reset settings:
+        * bus voltage range 32V
+        * gain = /8
+        * adc 1 & 2 -> conversion time 532uS
+        * mode is continuous shunt and bus
+        * calibration value is INA226_CALIBRATION_VALUE
+        */
+       int val = data->regs[reg];
+
+       switch (reg) {
+       case INA2XX_SHUNT_VOLTAGE:
+               /* LSB=2.5uV. Convert to mV. */
+               val = DIV_ROUND_CLOSEST(val, 400);
+               break;
+       case INA2XX_BUS_VOLTAGE:
+               /* LSB=1.25mV. Convert to mV. */
+               val = val + DIV_ROUND_CLOSEST(val, 4);
+               break;
+       case INA2XX_POWER:
+               /* LSB=25mW. Convert to uW */
+               val = val * 25 * 1000;
+               break;
+       case INA2XX_CURRENT:
+               /* LSB=1mA (selected). Is in mA */
+               break;
+       default:
+               /* programmer goofed */
+               WARN_ON_ONCE(1);
+               val = 0;
+               break;
+       }
+
+       return val;
+}
+
+static ssize_t ina2xx_show_value(struct device *dev,
+                                struct device_attribute *da, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct ina2xx_data *data = ina2xx_update_device(dev);
+       int value = 0;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       switch (data->kind) {
+       case ina219:
+               value = ina219_get_value(data, attr->index);
+               break;
+       case ina226:
+               value = ina226_get_value(data, attr->index);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               break;
+       }
+       return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+/* shunt voltage */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \
+       ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE);
+
+/* bus voltage */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
+       ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE);
+
+/* calculated current */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
+       ina2xx_show_value, NULL, INA2XX_CURRENT);
+
+/* calculated power */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \
+       ina2xx_show_value, NULL, INA2XX_POWER);
+
+/* pointers to created device attributes */
+static struct attribute *ina2xx_attributes[] = {
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_curr1_input.dev_attr.attr,
+       &sensor_dev_attr_power1_input.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ina2xx_group = {
+       .attrs = ina2xx_attributes,
+};
+
+static int ina2xx_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       struct ina2xx_data *data;
+       struct ina2xx_platform_data *pdata;
+       int ret = 0;
+       long shunt = 10000; /* default shunt value 10mOhms */
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+               return -ENODEV;
+
+       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       if (client->dev.platform_data) {
+               pdata =
+                 (struct ina2xx_platform_data *)client->dev.platform_data;
+               shunt = pdata->shunt_uohms;
+       }
+
+       if (shunt <= 0)
+               return -ENODEV;
+
+       /* set the device type */
+       data->kind = id->driver_data;
+
+       switch (data->kind) {
+       case ina219:
+               /* device configuration */
+               ina2xx_write_word(client, INA2XX_CONFIG, INA219_CONFIG_DEFAULT);
+
+               /* set current LSB to 1mA, shunt is in uOhms */
+               /* (equation 13 in datasheet) */
+               ina2xx_write_word(client, INA2XX_CALIBRATION, 40960000 / shunt);
+               dev_info(&client->dev,
+                        "power monitor INA219 (Rshunt = %li uOhm)\n", shunt);
+               data->registers = INA219_REGISTERS;
+               break;
+       case ina226:
+               /* device configuration */
+               ina2xx_write_word(client, INA2XX_CONFIG, INA226_CONFIG_DEFAULT);
+
+               /* set current LSB to 1mA, shunt is in uOhms */
+               /* (equation 1 in datasheet)*/
+               ina2xx_write_word(client, INA2XX_CALIBRATION, 5120000 / shunt);
+               dev_info(&client->dev,
+                        "power monitor INA226 (Rshunt = %li uOhm)\n", shunt);
+               data->registers = INA226_REGISTERS;
+               break;
+       default:
+               /* unknown device id */
+               return -ENODEV;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       ret = sysfs_create_group(&client->dev.kobj, &ina2xx_group);
+       if (ret)
+               return ret;
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               ret = PTR_ERR(data->hwmon_dev);
+               goto out_err_hwmon;
+       }
+
+       return 0;
+
+out_err_hwmon:
+       sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
+       return ret;
+}
+
+static int ina2xx_remove(struct i2c_client *client)
+{
+       struct ina2xx_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
+
+       return 0;
+}
+
+static const struct i2c_device_id ina2xx_id[] = {
+       { "ina219", ina219 },
+       { "ina226", ina226 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ina2xx_id);
+
+static struct i2c_driver ina2xx_driver = {
+       .driver = {
+               .name   = "ina2xx",
+       },
+       .probe          = ina2xx_probe,
+       .remove         = ina2xx_remove,
+       .id_table       = ina2xx_id,
+};
+
+static int __init ina2xx_init(void)
+{
+       return i2c_add_driver(&ina2xx_driver);
+}
+
+static void __exit ina2xx_exit(void)
+{
+       i2c_del_driver(&ina2xx_driver);
+}
+
+MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
+MODULE_DESCRIPTION("ina2xx driver");
+MODULE_LICENSE("GPL");
+
+module_init(ina2xx_init);
+module_exit(ina2xx_exit);
index 0b204e4cf51c5303836c9254d64f808fd8364115..e7701d99f8e8598207a18de6b6ad7f48a0796073 100644 (file)
@@ -19,6 +19,8 @@
  *            IT8726F  Super I/O chip w/LPC interface
  *            IT8728F  Super I/O chip w/LPC interface
  *            IT8758E  Super I/O chip w/LPC interface
+ *            IT8782F  Super I/O chip w/LPC interface
+ *            IT8783E/F Super I/O chip w/LPC interface
  *            Sis950   A clone of the IT8705F
  *
  *  Copyright (C) 2001 Chris Gauthron
@@ -59,7 +61,8 @@
 
 #define DRVNAME "it87"
 
-enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 };
+enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8782,
+            it8783 };
 
 static unsigned short force_id;
 module_param(force_id, ushort, 0);
@@ -137,13 +140,18 @@ static inline void superio_exit(void)
 #define IT8721F_DEVID 0x8721
 #define IT8726F_DEVID 0x8726
 #define IT8728F_DEVID 0x8728
+#define IT8782F_DEVID 0x8782
+#define IT8783E_DEVID 0x8783
 #define IT87_ACT_REG  0x30
 #define IT87_BASE_REG 0x60
 
 /* Logical device 7 registers (IT8712F and later) */
+#define IT87_SIO_GPIO1_REG     0x25
 #define IT87_SIO_GPIO3_REG     0x27
 #define IT87_SIO_GPIO5_REG     0x29
+#define IT87_SIO_PINX1_REG     0x2a    /* Pin selection */
 #define IT87_SIO_PINX2_REG     0x2c    /* Pin selection */
+#define IT87_SIO_SPI_REG       0xef    /* SPI function pin select */
 #define IT87_SIO_VID_REG       0xfc    /* VID value */
 #define IT87_SIO_BEEP_PIN_REG  0xf6    /* Beep pin mapping */
 
@@ -210,6 +218,7 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
 
 #define IT87_REG_VIN_ENABLE    0x50
 #define IT87_REG_TEMP_ENABLE   0x51
+#define IT87_REG_TEMP_EXTRA    0x55
 #define IT87_REG_BEEP_ENABLE   0x5c
 
 #define IT87_REG_CHIPID        0x58
@@ -226,9 +235,11 @@ struct it87_sio_data {
        u8 beep_pin;
        u8 internal;    /* Internal sensors can be labeled */
        /* Features skipped based on config or DMI */
+       u16 skip_in;
        u8 skip_vid;
        u8 skip_fan;
        u8 skip_pwm;
+       u8 skip_temp;
 };
 
 /*
@@ -253,6 +264,7 @@ struct it87_data {
        u8 has_fan;             /* Bitfield, fans enabled */
        u16 fan[5];             /* Register values, possibly combined */
        u16 fan_min[5];         /* Register values, possibly combined */
+       u8 has_temp;            /* Bitfield, temp sensors enabled */
        s8 temp[3];             /* Register value */
        s8 temp_high[3];        /* Register value */
        s8 temp_low[3];         /* Register value */
@@ -304,31 +316,23 @@ static inline int has_newer_autopwm(const struct it87_data *data)
            || data->type == it8728;
 }
 
-static u8 in_to_reg(const struct it87_data *data, int nr, long val)
+static int adc_lsb(const struct it87_data *data, int nr)
 {
-       long lsb;
-
-       if (has_12mv_adc(data)) {
-               if (data->in_scaled & (1 << nr))
-                       lsb = 24;
-               else
-                       lsb = 12;
-       } else
-               lsb = 16;
+       int lsb = has_12mv_adc(data) ? 12 : 16;
+       if (data->in_scaled & (1 << nr))
+               lsb <<= 1;
+       return lsb;
+}
 
-       val = DIV_ROUND_CLOSEST(val, lsb);
+static u8 in_to_reg(const struct it87_data *data, int nr, long val)
+{
+       val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr));
        return SENSORS_LIMIT(val, 0, 255);
 }
 
 static int in_from_reg(const struct it87_data *data, int nr, int val)
 {
-       if (has_12mv_adc(data)) {
-               if (data->in_scaled & (1 << nr))
-                       return val * 24;
-               else
-                       return val * 12;
-       } else
-               return val * 16;
+       return val * adc_lsb(data, nr);
 }
 
 static inline u8 FAN_TO_REG(long rpm, int div)
@@ -407,7 +411,9 @@ static inline int has_16bit_fans(const struct it87_data *data)
            || data->type == it8718
            || data->type == it8720
            || data->type == it8721
-           || data->type == it8728;
+           || data->type == it8728
+           || data->type == it8782
+           || data->type == it8783;
 }
 
 static inline int has_old_autopwm(const struct it87_data *data)
@@ -1369,57 +1375,103 @@ static ssize_t show_name(struct device *dev, struct device_attribute
 }
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
-static struct attribute *it87_attributes[] = {
+static struct attribute *it87_attributes_in[9][5] = {
+{
        &sensor_dev_attr_in0_input.dev_attr.attr,
-       &sensor_dev_attr_in1_input.dev_attr.attr,
-       &sensor_dev_attr_in2_input.dev_attr.attr,
-       &sensor_dev_attr_in3_input.dev_attr.attr,
-       &sensor_dev_attr_in4_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,
-       &sensor_dev_attr_in8_input.dev_attr.attr,
        &sensor_dev_attr_in0_min.dev_attr.attr,
-       &sensor_dev_attr_in1_min.dev_attr.attr,
-       &sensor_dev_attr_in2_min.dev_attr.attr,
-       &sensor_dev_attr_in3_min.dev_attr.attr,
-       &sensor_dev_attr_in4_min.dev_attr.attr,
-       &sensor_dev_attr_in5_min.dev_attr.attr,
-       &sensor_dev_attr_in6_min.dev_attr.attr,
-       &sensor_dev_attr_in7_min.dev_attr.attr,
        &sensor_dev_attr_in0_max.dev_attr.attr,
-       &sensor_dev_attr_in1_max.dev_attr.attr,
-       &sensor_dev_attr_in2_max.dev_attr.attr,
-       &sensor_dev_attr_in3_max.dev_attr.attr,
-       &sensor_dev_attr_in4_max.dev_attr.attr,
-       &sensor_dev_attr_in5_max.dev_attr.attr,
-       &sensor_dev_attr_in6_max.dev_attr.attr,
-       &sensor_dev_attr_in7_max.dev_attr.attr,
        &sensor_dev_attr_in0_alarm.dev_attr.attr,
+       NULL
+}, {
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in1_max.dev_attr.attr,
        &sensor_dev_attr_in1_alarm.dev_attr.attr,
+       NULL
+}, {
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in2_min.dev_attr.attr,
+       &sensor_dev_attr_in2_max.dev_attr.attr,
        &sensor_dev_attr_in2_alarm.dev_attr.attr,
+       NULL
+}, {
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in3_min.dev_attr.attr,
+       &sensor_dev_attr_in3_max.dev_attr.attr,
        &sensor_dev_attr_in3_alarm.dev_attr.attr,
+       NULL
+}, {
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in4_min.dev_attr.attr,
+       &sensor_dev_attr_in4_max.dev_attr.attr,
        &sensor_dev_attr_in4_alarm.dev_attr.attr,
+       NULL
+}, {
+       &sensor_dev_attr_in5_input.dev_attr.attr,
+       &sensor_dev_attr_in5_min.dev_attr.attr,
+       &sensor_dev_attr_in5_max.dev_attr.attr,
        &sensor_dev_attr_in5_alarm.dev_attr.attr,
+       NULL
+}, {
+       &sensor_dev_attr_in6_input.dev_attr.attr,
+       &sensor_dev_attr_in6_min.dev_attr.attr,
+       &sensor_dev_attr_in6_max.dev_attr.attr,
        &sensor_dev_attr_in6_alarm.dev_attr.attr,
+       NULL
+}, {
+       &sensor_dev_attr_in7_input.dev_attr.attr,
+       &sensor_dev_attr_in7_min.dev_attr.attr,
+       &sensor_dev_attr_in7_max.dev_attr.attr,
        &sensor_dev_attr_in7_alarm.dev_attr.attr,
+       NULL
+}, {
+       &sensor_dev_attr_in8_input.dev_attr.attr,
+       NULL
+} };
 
+static const struct attribute_group it87_group_in[9] = {
+       { .attrs = it87_attributes_in[0] },
+       { .attrs = it87_attributes_in[1] },
+       { .attrs = it87_attributes_in[2] },
+       { .attrs = it87_attributes_in[3] },
+       { .attrs = it87_attributes_in[4] },
+       { .attrs = it87_attributes_in[5] },
+       { .attrs = it87_attributes_in[6] },
+       { .attrs = it87_attributes_in[7] },
+       { .attrs = it87_attributes_in[8] },
+};
+
+static struct attribute *it87_attributes_temp[3][6] = {
+{
        &sensor_dev_attr_temp1_input.dev_attr.attr,
-       &sensor_dev_attr_temp2_input.dev_attr.attr,
-       &sensor_dev_attr_temp3_input.dev_attr.attr,
        &sensor_dev_attr_temp1_max.dev_attr.attr,
-       &sensor_dev_attr_temp2_max.dev_attr.attr,
-       &sensor_dev_attr_temp3_max.dev_attr.attr,
        &sensor_dev_attr_temp1_min.dev_attr.attr,
-       &sensor_dev_attr_temp2_min.dev_attr.attr,
-       &sensor_dev_attr_temp3_min.dev_attr.attr,
        &sensor_dev_attr_temp1_type.dev_attr.attr,
-       &sensor_dev_attr_temp2_type.dev_attr.attr,
-       &sensor_dev_attr_temp3_type.dev_attr.attr,
        &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+       NULL
+} , {
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_type.dev_attr.attr,
        &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+       NULL
+} , {
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_type.dev_attr.attr,
        &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+       NULL
+} };
+
+static const struct attribute_group it87_group_temp[3] = {
+       { .attrs = it87_attributes_temp[0] },
+       { .attrs = it87_attributes_temp[1] },
+       { .attrs = it87_attributes_temp[2] },
+};
 
+static struct attribute *it87_attributes[] = {
        &dev_attr_alarms.attr,
        &sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
        &dev_attr_name.attr,
@@ -1430,7 +1482,7 @@ static const struct attribute_group it87_group = {
        .attrs = it87_attributes,
 };
 
-static struct attribute *it87_attributes_beep[] = {
+static struct attribute *it87_attributes_in_beep[] = {
        &sensor_dev_attr_in0_beep.dev_attr.attr,
        &sensor_dev_attr_in1_beep.dev_attr.attr,
        &sensor_dev_attr_in2_beep.dev_attr.attr,
@@ -1439,15 +1491,13 @@ static struct attribute *it87_attributes_beep[] = {
        &sensor_dev_attr_in5_beep.dev_attr.attr,
        &sensor_dev_attr_in6_beep.dev_attr.attr,
        &sensor_dev_attr_in7_beep.dev_attr.attr,
+       NULL
+};
 
+static struct attribute *it87_attributes_temp_beep[] = {
        &sensor_dev_attr_temp1_beep.dev_attr.attr,
        &sensor_dev_attr_temp2_beep.dev_attr.attr,
        &sensor_dev_attr_temp3_beep.dev_attr.attr,
-       NULL
-};
-
-static const struct attribute_group it87_group_beep = {
-       .attrs = it87_attributes_beep,
 };
 
 static struct attribute *it87_attributes_fan16[5][3+1] = { {
@@ -1651,6 +1701,12 @@ static int __init it87_find(unsigned short *address,
        case IT8728F_DEVID:
                sio_data->type = it8728;
                break;
+       case IT8782F_DEVID:
+               sio_data->type = it8782;
+               break;
+       case IT8783E_DEVID:
+               sio_data->type = it8783;
+               break;
        case 0xffff:    /* No device at all */
                goto exit;
        default:
@@ -1686,16 +1742,86 @@ static int __init it87_find(unsigned short *address,
                /* The IT8705F has a different LD number for GPIO */
                superio_select(5);
                sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+       } else if (sio_data->type == it8783) {
+               int reg25, reg27, reg2A, reg2C, regEF;
+
+               sio_data->skip_vid = 1; /* No VID */
+
+               superio_select(GPIO);
+
+               reg25 = superio_inb(IT87_SIO_GPIO1_REG);
+               reg27 = superio_inb(IT87_SIO_GPIO3_REG);
+               reg2A = superio_inb(IT87_SIO_PINX1_REG);
+               reg2C = superio_inb(IT87_SIO_PINX2_REG);
+               regEF = superio_inb(IT87_SIO_SPI_REG);
+
+               /* Check if fan3 is there or not */
+               if ((reg27 & (1 << 0)) || !(reg2C & (1 << 2)))
+                       sio_data->skip_fan |= (1 << 2);
+               if ((reg25 & (1 << 4))
+                   || (!(reg2A & (1 << 1)) && (regEF & (1 << 0))))
+                       sio_data->skip_pwm |= (1 << 2);
+
+               /* Check if fan2 is there or not */
+               if (reg27 & (1 << 7))
+                       sio_data->skip_fan |= (1 << 1);
+               if (reg27 & (1 << 3))
+                       sio_data->skip_pwm |= (1 << 1);
+
+               /* VIN5 */
+               if ((reg27 & (1 << 0)) || (reg2C & (1 << 2)))
+                       sio_data->skip_in |= (1 << 5); /* No VIN5 */
+
+               /* VIN6 */
+               if (reg27 & (1 << 1))
+                       sio_data->skip_in |= (1 << 6); /* No VIN6 */
+
+               /*
+                * VIN7
+                * Does not depend on bit 2 of Reg2C, contrary to datasheet.
+                */
+               if (reg27 & (1 << 2)) {
+                       /*
+                        * The data sheet is a bit unclear regarding the
+                        * internal voltage divider for VCCH5V. It says
+                        * "This bit enables and switches VIN7 (pin 91) to the
+                        * internal voltage divider for VCCH5V".
+                        * This is different to other chips, where the internal
+                        * voltage divider would connect VIN7 to an internal
+                        * voltage source. Maybe that is the case here as well.
+                        *
+                        * Since we don't know for sure, re-route it if that is
+                        * not the case, and ask the user to report if the
+                        * resulting voltage is sane.
+                        */
+                       if (!(reg2C & (1 << 1))) {
+                               reg2C |= (1 << 1);
+                               superio_outb(IT87_SIO_PINX2_REG, reg2C);
+                               pr_notice("Routing internal VCCH5V to in7.\n");
+                       }
+                       pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
+                       pr_notice("Please report if it displays a reasonable voltage.\n");
+               }
+
+               if (reg2C & (1 << 0))
+                       sio_data->internal |= (1 << 0);
+               if (reg2C & (1 << 1))
+                       sio_data->internal |= (1 << 1);
+
+               sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+
        } else {
                int reg;
+               bool uart6;
 
                superio_select(GPIO);
 
                reg = superio_inb(IT87_SIO_GPIO3_REG);
-               if (sio_data->type == it8721 || sio_data->type == it8728) {
+               if (sio_data->type == it8721 || sio_data->type == it8728 ||
+                   sio_data->type == it8782) {
                        /*
-                        * The IT8721F/IT8758E doesn't have VID pins at all,
-                        * not sure about the IT8728F.
+                        * IT8721F/IT8758E, and IT8782F don't have VID pins
+                        * at all, not sure about the IT8728F.
                         */
                        sio_data->skip_vid = 1;
                } else {
@@ -1724,6 +1850,9 @@ static int __init it87_find(unsigned short *address,
                        sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
 
                reg = superio_inb(IT87_SIO_PINX2_REG);
+
+               uart6 = sio_data->type == it8782 && (reg & (1 << 2));
+
                /*
                 * The IT8720F has no VIN7 pin, so VCCH should always be
                 * routed internally to VIN7 with an internal divider.
@@ -1733,8 +1862,12 @@ static int __init it87_find(unsigned short *address,
                 * configured, even though the IT8720F datasheet claims
                 * that the internal routing of VCCH to VIN7 is the default
                 * setting. So we force the internal routing in this case.
+                *
+                * On IT8782F, VIN7 is multiplexed with one of the UART6 pins.
+                * If UART6 is enabled, re-route VIN7 to the internal divider
+                * if that is not already the case.
                 */
-               if (sio_data->type == it8720 && !(reg & (1 << 1))) {
+               if ((sio_data->type == it8720 || uart6) && !(reg & (1 << 1))) {
                        reg |= (1 << 1);
                        superio_outb(IT87_SIO_PINX2_REG, reg);
                        pr_notice("Routing internal VCCH to in7\n");
@@ -1745,6 +1878,20 @@ static int __init it87_find(unsigned short *address,
                    sio_data->type == it8728)
                        sio_data->internal |= (1 << 1);
 
+               /*
+                * On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7.
+                * While VIN7 can be routed to the internal voltage divider,
+                * VIN5 and VIN6 are not available if UART6 is enabled.
+                *
+                * Also, temp3 is not available if UART6 is enabled and TEMPIN3
+                * is the temperature source. Since we can not read the
+                * temperature source here, skip_temp is preliminary.
+                */
+               if (uart6) {
+                       sio_data->skip_in |= (1 << 5) | (1 << 6);
+                       sio_data->skip_temp |= (1 << 2);
+               }
+
                sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
        }
        if (sio_data->beep_pin)
@@ -1782,8 +1929,22 @@ static void it87_remove_files(struct device *dev)
        int i;
 
        sysfs_remove_group(&dev->kobj, &it87_group);
-       if (sio_data->beep_pin)
-               sysfs_remove_group(&dev->kobj, &it87_group_beep);
+       for (i = 0; i < 9; i++) {
+               if (sio_data->skip_in & (1 << i))
+                       continue;
+               sysfs_remove_group(&dev->kobj, &it87_group_in[i]);
+               if (it87_attributes_in_beep[i])
+                       sysfs_remove_file(&dev->kobj,
+                                         it87_attributes_in_beep[i]);
+       }
+       for (i = 0; i < 3; i++) {
+               if (!(data->has_temp & (1 << i)))
+                       continue;
+               sysfs_remove_group(&dev->kobj, &it87_group_temp[i]);
+               if (sio_data->beep_pin)
+                       sysfs_remove_file(&dev->kobj,
+                                         it87_attributes_temp_beep[i]);
+       }
        for (i = 0; i < 5; i++) {
                if (!(data->has_fan & (1 << i)))
                        continue;
@@ -1823,22 +1984,22 @@ static int __devinit it87_probe(struct platform_device *pdev)
                "it8720",
                "it8721",
                "it8728",
+               "it8782",
+               "it8783",
        };
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-       if (!request_region(res->start, IT87_EC_EXTENT, DRVNAME)) {
+       if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
+                                DRVNAME)) {
                dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
                        (unsigned long)res->start,
                        (unsigned long)(res->start + IT87_EC_EXTENT - 1));
-               err = -EBUSY;
-               goto ERROR0;
+               return -EBUSY;
        }
 
-       data = kzalloc(sizeof(struct it87_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto ERROR1;
-       }
+       data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        data->addr = res->start;
        data->type = sio_data->type;
@@ -1847,10 +2008,8 @@ static int __devinit it87_probe(struct platform_device *pdev)
 
        /* Now, we do the remaining detection. */
        if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
-        || it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
-               err = -ENODEV;
-               goto ERROR2;
-       }
+        || it87_read_value(data, IT87_REG_CHIPID) != 0x90)
+               return -ENODEV;
 
        platform_set_drvdata(pdev, data);
 
@@ -1867,6 +2026,18 @@ static int __devinit it87_probe(struct platform_device *pdev)
                        data->in_scaled |= (1 << 7);    /* in7 is VSB */
                if (sio_data->internal & (1 << 2))
                        data->in_scaled |= (1 << 8);    /* in8 is Vbat */
+       } else if (sio_data->type == it8782 || sio_data->type == it8783) {
+               if (sio_data->internal & (1 << 0))
+                       data->in_scaled |= (1 << 3);    /* in3 is VCC5V */
+               if (sio_data->internal & (1 << 1))
+                       data->in_scaled |= (1 << 7);    /* in7 is VCCH5V */
+       }
+
+       data->has_temp = 0x07;
+       if (sio_data->skip_temp & (1 << 2)) {
+               if (sio_data->type == it8782
+                   && !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80))
+                       data->has_temp &= ~(1 << 2);
        }
 
        /* Initialize the IT87 chip */
@@ -1875,12 +2046,34 @@ static int __devinit it87_probe(struct platform_device *pdev)
        /* Register sysfs hooks */
        err = sysfs_create_group(&dev->kobj, &it87_group);
        if (err)
-               goto ERROR2;
+               return err;
 
-       if (sio_data->beep_pin) {
-               err = sysfs_create_group(&dev->kobj, &it87_group_beep);
+       for (i = 0; i < 9; i++) {
+               if (sio_data->skip_in & (1 << i))
+                       continue;
+               err = sysfs_create_group(&dev->kobj, &it87_group_in[i]);
                if (err)
-                       goto ERROR4;
+                       goto error;
+               if (sio_data->beep_pin && it87_attributes_in_beep[i]) {
+                       err = sysfs_create_file(&dev->kobj,
+                                               it87_attributes_in_beep[i]);
+                       if (err)
+                               goto error;
+               }
+       }
+
+       for (i = 0; i < 3; i++) {
+               if (!(data->has_temp & (1 << i)))
+                       continue;
+               err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]);
+               if (err)
+                       goto error;
+               if (sio_data->beep_pin) {
+                       err = sysfs_create_file(&dev->kobj,
+                                               it87_attributes_temp_beep[i]);
+                       if (err)
+                               goto error;
+               }
        }
 
        /* Do not create fan files for disabled fans */
@@ -1891,13 +2084,13 @@ static int __devinit it87_probe(struct platform_device *pdev)
                        continue;
                err = sysfs_create_group(&dev->kobj, &fan_group[i]);
                if (err)
-                       goto ERROR4;
+                       goto error;
 
                if (sio_data->beep_pin) {
                        err = sysfs_create_file(&dev->kobj,
                                                it87_attributes_fan_beep[i]);
                        if (err)
-                               goto ERROR4;
+                               goto error;
                        if (!fan_beep_need_rw)
                                continue;
 
@@ -1922,14 +2115,14 @@ static int __devinit it87_probe(struct platform_device *pdev)
                        err = sysfs_create_group(&dev->kobj,
                                                 &it87_group_pwm[i]);
                        if (err)
-                               goto ERROR4;
+                               goto error;
 
                        if (!has_old_autopwm(data))
                                continue;
                        err = sysfs_create_group(&dev->kobj,
                                                 &it87_group_autopwm[i]);
                        if (err)
-                               goto ERROR4;
+                               goto error;
                }
        }
 
@@ -1939,7 +2132,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
                data->vid = sio_data->vid_value;
                err = sysfs_create_group(&dev->kobj, &it87_group_vid);
                if (err)
-                       goto ERROR4;
+                       goto error;
        }
 
        /* Export labels for internal sensors */
@@ -1949,25 +2142,19 @@ static int __devinit it87_probe(struct platform_device *pdev)
                err = sysfs_create_file(&dev->kobj,
                                        it87_attributes_label[i]);
                if (err)
-                       goto ERROR4;
+                       goto error;
        }
 
        data->hwmon_dev = hwmon_device_register(dev);
        if (IS_ERR(data->hwmon_dev)) {
                err = PTR_ERR(data->hwmon_dev);
-               goto ERROR4;
+               goto error;
        }
 
        return 0;
 
-ERROR4:
+error:
        it87_remove_files(dev);
-ERROR2:
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
-ERROR1:
-       release_region(res->start, IT87_EC_EXTENT);
-ERROR0:
        return err;
 }
 
@@ -1978,10 +2165,6 @@ static int __devexit it87_remove(struct platform_device *pdev)
        hwmon_device_unregister(data->hwmon_dev);
        it87_remove_files(&pdev->dev);
 
-       release_region(data->addr, IT87_EC_EXTENT);
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
-
        return 0;
 }
 
@@ -2143,8 +2326,9 @@ static void __devinit it87_init_device(struct platform_device *pdev)
                        it87_write_value(data, IT87_REG_FAN_16BIT,
                                         tmp | 0x07);
                }
-               /* IT8705F only supports three fans. */
-               if (data->type != it87) {
+               /* IT8705F, IT8782F, and IT8783E/F only support three fans. */
+               if (data->type != it87 && data->type != it8782 &&
+                   data->type != it8783) {
                        if (tmp & (1 << 4))
                                data->has_fan |= (1 << 3); /* fan4 enabled */
                        if (tmp & (1 << 5))
@@ -2233,6 +2417,8 @@ static struct it87_data *it87_update_device(struct device *dev)
                        }
                }
                for (i = 0; i < 3; i++) {
+                       if (!(data->has_temp & (1 << i)))
+                               continue;
                        data->temp[i] =
                                it87_read_value(data, IT87_REG_TEMP(i));
                        data->temp_high[i] =
index 307bb325dde952bcc6929ed39d4dd96fc9eca70d..7356b5ec8f6733bd9b4cc9a96f6f790831c60f6b 100644 (file)
@@ -225,15 +225,4 @@ static struct pci_driver k10temp_driver = {
        .remove = __devexit_p(k10temp_remove),
 };
 
-static int __init k10temp_init(void)
-{
-       return pci_register_driver(&k10temp_driver);
-}
-
-static void __exit k10temp_exit(void)
-{
-       pci_unregister_driver(&k10temp_driver);
-}
-
-module_init(k10temp_init)
-module_exit(k10temp_exit)
+module_pci_driver(k10temp_driver);
index 575101988751061eb166f962e222b70ab386ae2f..35aac82ee8eb340e726e696a98ca34a156d76607 100644 (file)
@@ -339,19 +339,8 @@ static struct pci_driver k8temp_driver = {
        .remove = __devexit_p(k8temp_remove),
 };
 
-static int __init k8temp_init(void)
-{
-       return pci_register_driver(&k8temp_driver);
-}
-
-static void __exit k8temp_exit(void)
-{
-       pci_unregister_driver(&k8temp_driver);
-}
+module_pci_driver(k8temp_driver);
 
 MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
 MODULE_DESCRIPTION("AMD K8 core temperature monitor");
 MODULE_LICENSE("GPL");
-
-module_init(k8temp_init)
-module_exit(k8temp_exit)
index 9b382ec2c3bd4de978d98a6d9f24f797684fe534..6da9696e182730ac9b7980ad356b2cc19cc01975 100644 (file)
@@ -134,8 +134,7 @@ static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
        return div64_u64(dividend, divisor);
 }
 
-static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
-               unsigned int uV)
+static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uV)
 {
        struct ntc_thermistor_platform_data *pdata = data->pdata;
        u64 mV = uV / 1000;
@@ -146,12 +145,12 @@ static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
 
        if (mV == 0) {
                if (pdata->connect == NTC_CONNECTED_POSITIVE)
-                       return UINT_MAX;
+                       return INT_MAX;
                return 0;
        }
        if (mV >= pmV)
                return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
-                       0 : UINT_MAX;
+                       0 : INT_MAX;
 
        if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0)
                N = div64_u64_safe(pdO * (pmV - mV), mV);
@@ -163,113 +162,109 @@ static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
        else
                N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV);
 
-       return (unsigned int) N;
+       if (N > INT_MAX)
+               N = INT_MAX;
+       return N;
 }
 
-static int lookup_comp(struct ntc_data *data,
-               unsigned int ohm, int *i_low, int *i_high)
+static void lookup_comp(struct ntc_data *data, unsigned int ohm,
+                       int *i_low, int *i_high)
 {
-       int start, end, mid = -1;
+       int start, end, mid;
+
+       /*
+        * Handle special cases: Resistance is higher than or equal to
+        * resistance in first table entry, or resistance is lower or equal
+        * to resistance in last table entry.
+        * In these cases, return i_low == i_high, either pointing to the
+        * beginning or to the end of the table depending on the condition.
+        */
+       if (ohm >= data->comp[0].ohm) {
+               *i_low = 0;
+               *i_high = 0;
+               return;
+       }
+       if (ohm <= data->comp[data->n_comp - 1].ohm) {
+               *i_low = data->n_comp - 1;
+               *i_high = data->n_comp - 1;
+               return;
+       }
 
        /* Do a binary search on compensation table */
        start = 0;
        end = data->n_comp;
-
-       while (end > start) {
+       while (start < end) {
                mid = start + (end - start) / 2;
-               if (data->comp[mid].ohm < ohm)
+               /*
+                * start <= mid < end
+                * data->comp[start].ohm > ohm >= data->comp[end].ohm
+                *
+                * We could check for "ohm == data->comp[mid].ohm" here, but
+                * that is a quite unlikely condition, and we would have to
+                * check again after updating start. Check it at the end instead
+                * for simplicity.
+                */
+               if (ohm >= data->comp[mid].ohm) {
                        end = mid;
-               else if (data->comp[mid].ohm > ohm)
-                       start = mid + 1;
-               else
-                       break;
-       }
-
-       if (mid == 0) {
-               if (data->comp[mid].ohm > ohm) {
-                       *i_high = mid;
-                       *i_low = mid + 1;
-                       return 0;
-               } else {
-                       *i_low = mid;
-                       *i_high = -1;
-                       return -EINVAL;
-               }
-       }
-       if (mid == (data->n_comp - 1)) {
-               if (data->comp[mid].ohm <= ohm) {
-                       *i_low = mid;
-                       *i_high = mid - 1;
-                       return 0;
                } else {
-                       *i_low = -1;
-                       *i_high = mid;
-                       return -EINVAL;
+                       start = mid + 1;
+                       /*
+                        * ohm >= data->comp[start].ohm might be true here,
+                        * since we set start to mid + 1. In that case, we are
+                        * done. We could keep going, but the condition is quite
+                        * likely to occur, so it is worth checking for it.
+                        */
+                       if (ohm >= data->comp[start].ohm)
+                               end = start;
                }
+               /*
+                * start <= end
+                * data->comp[start].ohm >= ohm >= data->comp[end].ohm
+                */
        }
-
-       if (data->comp[mid].ohm <= ohm) {
-               *i_low = mid;
-               *i_high = mid - 1;
-       } else {
-               *i_low = mid + 1;
-               *i_high = mid;
-       }
-
-       return 0;
+       /*
+        * start == end
+        * ohm >= data->comp[end].ohm
+        */
+       *i_low = end;
+       if (ohm == data->comp[end].ohm)
+               *i_high = end;
+       else
+               *i_high = end - 1;
 }
 
-static int get_temp_mC(struct ntc_data *data, unsigned int ohm, int *temp)
+static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
 {
        int low, high;
-       int ret;
+       int temp;
 
-       ret = lookup_comp(data, ohm, &low, &high);
-       if (ret) {
+       lookup_comp(data, ohm, &low, &high);
+       if (low == high) {
                /* Unable to use linear approximation */
-               if (low != -1)
-                       *temp = data->comp[low].temp_C * 1000;
-               else if (high != -1)
-                       *temp = data->comp[high].temp_C * 1000;
-               else
-                       return ret;
+               temp = data->comp[low].temp_C * 1000;
        } else {
-               *temp = data->comp[low].temp_C * 1000 +
+               temp = data->comp[low].temp_C * 1000 +
                        ((data->comp[high].temp_C - data->comp[low].temp_C) *
                         1000 * ((int)ohm - (int)data->comp[low].ohm)) /
                        ((int)data->comp[high].ohm - (int)data->comp[low].ohm);
        }
-
-       return 0;
+       return temp;
 }
 
-static int ntc_thermistor_read(struct ntc_data *data, int *temp)
+static int ntc_thermistor_get_ohm(struct ntc_data *data)
 {
-       int ret;
-       int read_ohm, read_uV;
-       unsigned int ohm = 0;
-
-       if (data->pdata->read_ohm) {
-               read_ohm = data->pdata->read_ohm();
-               if (read_ohm < 0)
-                       return read_ohm;
-               ohm = (unsigned int)read_ohm;
-       }
+       int read_uV;
+
+       if (data->pdata->read_ohm)
+               return data->pdata->read_ohm();
 
        if (data->pdata->read_uV) {
                read_uV = data->pdata->read_uV();
                if (read_uV < 0)
                        return read_uV;
-               ohm = get_ohm_of_thermistor(data, (unsigned int)read_uV);
-       }
-
-       ret = get_temp_mC(data, ohm, temp);
-       if (ret) {
-               dev_dbg(data->dev, "Sensor reading function not available.\n");
-               return ret;
+               return get_ohm_of_thermistor(data, read_uV);
        }
-
-       return 0;
+       return -EINVAL;
 }
 
 static ssize_t ntc_show_name(struct device *dev,
@@ -290,12 +285,13 @@ static ssize_t ntc_show_temp(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
        struct ntc_data *data = dev_get_drvdata(dev);
-       int temp, ret;
+       int ohm;
 
-       ret = ntc_thermistor_read(data, &temp);
-       if (ret)
-               return ret;
-       return sprintf(buf, "%d\n", temp);
+       ohm = ntc_thermistor_get_ohm(data);
+       if (ohm < 0)
+               return ohm;
+
+       return sprintf(buf, "%d\n", get_temp_mC(data, ohm));
 }
 
 static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
@@ -326,14 +322,14 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
 
        /* Either one of the two is required. */
        if (!pdata->read_uV && !pdata->read_ohm) {
-               dev_err(&pdev->dev, "Both read_uV and read_ohm missing."
-                               "Need either one of the two.\n");
+               dev_err(&pdev->dev,
+                       "Both read_uV and read_ohm missing. Need either one of the two.\n");
                return -EINVAL;
        }
 
        if (pdata->read_uV && pdata->read_ohm) {
-               dev_warn(&pdev->dev, "Only one of read_uV and read_ohm "
-                               "is needed; ignoring read_uV.\n");
+               dev_warn(&pdev->dev,
+                        "Only one of read_uV and read_ohm is needed; ignoring read_uV.\n");
                pdata->read_uV = NULL;
        }
 
@@ -344,12 +340,12 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
                                 NTC_CONNECTED_POSITIVE) ||
                                (pdata->connect != NTC_CONNECTED_POSITIVE &&
                                 pdata->connect != NTC_CONNECTED_GROUND))) {
-               dev_err(&pdev->dev, "Required data to use read_uV not "
-                               "supplied.\n");
+               dev_err(&pdev->dev,
+                       "Required data to use read_uV not supplied.\n");
                return -EINVAL;
        }
 
-       data = kzalloc(sizeof(struct ntc_data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(struct ntc_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -370,8 +366,7 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
                                pdev->id_entry->driver_data,
                                pdev->id_entry->name);
-               ret = -EINVAL;
-               goto err;
+               return -EINVAL;
        }
 
        platform_set_drvdata(pdev, data);
@@ -379,13 +374,13 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
        ret = sysfs_create_group(&data->dev->kobj, &ntc_attr_group);
        if (ret) {
                dev_err(data->dev, "unable to create sysfs files\n");
-               goto err;
+               return ret;
        }
 
        data->hwmon_dev = hwmon_device_register(data->dev);
-       if (IS_ERR_OR_NULL(data->hwmon_dev)) {
+       if (IS_ERR(data->hwmon_dev)) {
                dev_err(data->dev, "unable to register as hwmon device.\n");
-               ret = -EINVAL;
+               ret = PTR_ERR(data->hwmon_dev);
                goto err_after_sysfs;
        }
 
@@ -395,8 +390,6 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
        return 0;
 err_after_sysfs:
        sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
-err:
-       kfree(data);
        return ret;
 }
 
@@ -408,8 +401,6 @@ static int __devexit ntc_thermistor_remove(struct platform_device *pdev)
        sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
        platform_set_drvdata(pdev, NULL);
 
-       kfree(data);
-
        return 0;
 }
 
index 7b397c6f607e46e4d52dd87f127d0208dde13839..31c47e18d83c5f9fdf3bdb8927c57bc3ef12cd84 100644 (file)
@@ -227,6 +227,72 @@ static int __devexit i2c_powermac_remove(struct platform_device *dev)
        return 0;
 }
 
+static void __devinit i2c_powermac_register_devices(struct i2c_adapter *adap,
+                                                   struct pmac_i2c_bus *bus)
+{
+       struct i2c_client *newdev;
+       struct device_node *node;
+
+       for_each_child_of_node(adap->dev.of_node, node) {
+               struct i2c_board_info info = {};
+               struct dev_archdata dev_ad = {};
+               const __be32 *reg;
+               char tmp[16];
+               u32 addr;
+               int len;
+
+               /* Get address & channel */
+               reg = of_get_property(node, "reg", &len);
+               if (!reg || (len < sizeof(int))) {
+                       dev_err(&adap->dev, "i2c-powermac: invalid reg on %s\n",
+                               node->full_name);
+                       continue;
+               }
+               addr = be32_to_cpup(reg);
+
+               /* Multibus setup, check channel */
+               if (!pmac_i2c_match_adapter(node, adap))
+                       continue;
+
+               dev_dbg(&adap->dev, "i2c-powermac: register %s\n",
+                       node->full_name);
+
+               /* Make up a modalias. Note: we to _NOT_ want the standard
+                * i2c drivers to match with any of our powermac stuff
+                * unless they have been specifically modified to handle
+                * it on a case by case basis. For example, for thermal
+                * control, things like lm75 etc... shall match with their
+                * corresponding windfarm drivers, _NOT_ the generic ones,
+                * so we force a prefix of AAPL, onto the modalias to
+                * make that happen
+                */
+               if (of_modalias_node(node, tmp, sizeof(tmp)) < 0) {
+                       dev_err(&adap->dev, "i2c-powermac: modalias failure"
+                               " on %s\n", node->full_name);
+                       continue;
+               }
+               snprintf(info.type, sizeof(info.type), "MAC,%s", tmp);
+
+               /* Fill out the rest of the info structure */
+               info.addr = (addr & 0xff) >> 1;
+               info.irq = irq_of_parse_and_map(node, 0);
+               info.of_node = of_node_get(node);
+               info.archdata = &dev_ad;
+
+               newdev = i2c_new_device(adap, &info);
+               if (!newdev) {
+                       dev_err(&adap->dev, "i2c-powermac: Failure to register"
+                               " %s\n", node->full_name);
+                       of_node_put(node);
+                       /* We do not dispose of the interrupt mapping on
+                        * purpose. It's not necessary (interrupt cannot be
+                        * re-used) and somebody else might have grabbed it
+                        * via direct DT lookup so let's not bother
+                        */
+                       continue;
+               }
+       }
+}
 
 static int __devinit i2c_powermac_probe(struct platform_device *dev)
 {
@@ -272,6 +338,7 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
        adapter->algo = &i2c_powermac_algorithm;
        i2c_set_adapdata(adapter, bus);
        adapter->dev.parent = &dev->dev;
+       adapter->dev.of_node = dev->dev.of_node;
        rc = i2c_add_adapter(adapter);
        if (rc) {
                printk(KERN_ERR "i2c-powermac: Adapter %s registration "
@@ -281,33 +348,10 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
 
        printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
 
-       if (!strncmp(basename, "uni-n", 5)) {
-               struct device_node *np;
-               const u32 *prop;
-               struct i2c_board_info info;
-
-               /* Instantiate I2C motion sensor if present */
-               np = of_find_node_by_name(NULL, "accelerometer");
-               if (np && of_device_is_compatible(np, "AAPL,accelerometer_1") &&
-                   (prop = of_get_property(np, "reg", NULL))) {
-                       int i2c_bus;
-                       const char *tmp_bus;
-
-                       /* look for bus either using "reg" or by path */
-                       tmp_bus = strstr(np->full_name, "/i2c-bus@");
-                       if (tmp_bus)
-                               i2c_bus = *(tmp_bus + 9) - '0';
-                       else
-                               i2c_bus = ((*prop) >> 8) & 0x0f;
-
-                       if (pmac_i2c_get_channel(bus) == i2c_bus) {
-                               memset(&info, 0, sizeof(struct i2c_board_info));
-                               info.addr = ((*prop) & 0xff) >> 1;
-                               strlcpy(info.type, "ams", I2C_NAME_SIZE);
-                               i2c_new_device(adapter, &info);
-                       }
-               }
-       }
+       /* Cannot use of_i2c_register_devices() due to Apple device-tree
+        * funkyness
+        */
+       i2c_powermac_register_devices(adapter, bus);
 
        return rc;
 }
index fa51af11c6f1e9d927967753b86530ea45a2b600..a555da64224e09a6eb4de5a4469b0f29da279d99 100644 (file)
@@ -204,11 +204,14 @@ config THERM_ADT746X
          better fan behaviour by default, and some manual control.
 
 config THERM_PM72
-       tristate "Support for thermal management on PowerMac G5"
+       tristate "Support for thermal management on PowerMac G5 (AGP)"
        depends on I2C && I2C_POWERMAC && PPC_PMAC64
+       default n
        help
          This driver provides thermostat and fan control for the desktop
-         G5 machines. 
+         G5 machines.
+
+         This is deprecated, use windfarm instead.
 
 config WINDFARM
        tristate "New PowerMac thermal control infrastructure"
@@ -221,6 +224,22 @@ config WINDFARM_PM81
        help
          This driver provides thermal control for the iMacG5
 
+config WINDFARM_PM72
+       tristate "Support for thermal management on PowerMac G5 (AGP)"
+       depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU
+       select I2C_POWERMAC
+       help
+         This driver provides thermal control for the PowerMac G5
+         "AGP" variants (PowerMac 7,2 and 7,3)
+
+config WINDFARM_RM31
+       tristate "Support for thermal management on Xserve G5"
+       depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU
+       select I2C_POWERMAC
+       help
+         This driver provides thermal control for the Xserve G5
+         (RackMac3,1)
+
 config WINDFARM_PM91
        tristate "Support for thermal management on PowerMac9,1"
        depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
index 6652a6ebb6fa4105d3e72120546e562721619a8c..6753b65f8edeb2db67625a6fdf468b7c8b634928 100644 (file)
@@ -29,6 +29,20 @@ obj-$(CONFIG_THERM_PM72)     += therm_pm72.o
 obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o
 obj-$(CONFIG_THERM_ADT746X)    += therm_adt746x.o
 obj-$(CONFIG_WINDFARM)         += windfarm_core.o
+obj-$(CONFIG_WINDFARM_PM72)     += windfarm_fcu_controls.o \
+                                  windfarm_ad7417_sensor.o \
+                                  windfarm_lm75_sensor.o \
+                                  windfarm_max6690_sensor.o \
+                                  windfarm_pid.o \
+                                  windfarm_cpufreq_clamp.o \
+                                  windfarm_pm72.o
+obj-$(CONFIG_WINDFARM_RM31)     += windfarm_fcu_controls.o \
+                                  windfarm_ad7417_sensor.o \
+                                  windfarm_lm75_sensor.o \
+                                  windfarm_lm87_sensor.o \
+                                  windfarm_pid.o \
+                                  windfarm_cpufreq_clamp.o \
+                                  windfarm_rm31.o
 obj-$(CONFIG_WINDFARM_PM81)     += windfarm_smu_controls.o \
                                   windfarm_smu_sensors.o \
                                   windfarm_lm75_sensor.o windfarm_pid.o \
index abeecd27b484fe2345f3c01dda91b7f74f079cd6..978eda8d6678bce573b27bfa99dee94103708ce8 100644 (file)
@@ -65,7 +65,7 @@ static int ams_i2c_probe(struct i2c_client *client,
 static int ams_i2c_remove(struct i2c_client *client);
 
 static const struct i2c_device_id ams_id[] = {
-       { "ams", 0 },
+       { "MAC,accelerometer_1", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ams_id);
index fc71723cbc485a11d4eb97c7911955a5a6aa7a72..f433521a6f9d91d9ad6c5563866b3b3f30ee09ac 100644 (file)
@@ -47,7 +47,7 @@ static u8 FAN_SPD_SET[2] = {0x30, 0x31};
 
 static u8 default_limits_local[3] = {70, 50, 70};    /* local, sensor1, sensor2 */
 static u8 default_limits_chip[3] = {80, 65, 80};    /* local, sensor1, sensor2 */
-static const char *sensor_location[3];
+static const char *sensor_location[3] = { "?", "?", "?" };
 
 static int limit_adjust;
 static int fan_speed = -1;
@@ -79,18 +79,16 @@ struct thermostat {
        int                     last_speed[2];
        int                     last_var[2];
        int                     pwm_inv[2];
+       struct task_struct      *thread;
+       struct platform_device  *pdev;
+       enum {
+               ADT7460,
+               ADT7467
+       }                       type;
 };
 
-static enum {ADT7460, ADT7467} therm_type;
-static int therm_bus, therm_address;
-static struct platform_device * of_dev;
-static struct thermostat* thermostat;
-static struct task_struct *thread_therm = NULL;
-
 static void write_both_fan_speed(struct thermostat *th, int speed);
 static void write_fan_speed(struct thermostat *th, int speed, int fan);
-static void thermostat_create_files(void);
-static void thermostat_remove_files(void);
 
 static int
 write_reg(struct thermostat* th, int reg, u8 data)
@@ -126,66 +124,6 @@ read_reg(struct thermostat* th, int reg)
        return data;
 }
 
-static struct i2c_driver thermostat_driver;
-
-static int
-attach_thermostat(struct i2c_adapter *adapter)
-{
-       unsigned long bus_no;
-       struct i2c_board_info info;
-       struct i2c_client *client;
-
-       if (strncmp(adapter->name, "uni-n", 5))
-               return -ENODEV;
-       bus_no = simple_strtoul(adapter->name + 6, NULL, 10);
-       if (bus_no != therm_bus)
-               return -ENODEV;
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE);
-       info.addr = therm_address;
-       client = i2c_new_device(adapter, &info);
-       if (!client)
-               return -ENODEV;
-
-       /*
-        * Let i2c-core delete that device on driver removal.
-        * This is safe because i2c-core holds the core_lock mutex for us.
-        */
-       list_add_tail(&client->detected, &thermostat_driver.clients);
-       return 0;
-}
-
-static int
-remove_thermostat(struct i2c_client *client)
-{
-       struct thermostat *th = i2c_get_clientdata(client);
-       int i;
-       
-       thermostat_remove_files();
-
-       if (thread_therm != NULL) {
-               kthread_stop(thread_therm);
-       }
-
-       printk(KERN_INFO "adt746x: Putting max temperatures back from "
-                        "%d, %d, %d to %d, %d, %d\n",
-               th->limits[0], th->limits[1], th->limits[2],
-               th->initial_limits[0], th->initial_limits[1],
-               th->initial_limits[2]);
-
-       for (i = 0; i < 3; i++)
-               write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
-
-       write_both_fan_speed(th, -1);
-
-       thermostat = NULL;
-
-       kfree(th);
-
-       return 0;
-}
-
 static int read_fan_speed(struct thermostat *th, u8 addr)
 {
        u8 tmp[2];
@@ -203,7 +141,7 @@ static int read_fan_speed(struct thermostat *th, u8 addr)
 static void write_both_fan_speed(struct thermostat *th, int speed)
 {
        write_fan_speed(th, speed, 0);
-       if (therm_type == ADT7460)
+       if (th->type == ADT7460)
                write_fan_speed(th, speed, 1);
 }
 
@@ -216,7 +154,7 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan)
        else if (speed < -1) 
                speed = 0;
        
-       if (therm_type == ADT7467 && fan == 1)
+       if (th->type == ADT7467 && fan == 1)
                return;
        
        if (th->last_speed[fan] != speed) {
@@ -239,7 +177,7 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan)
                write_reg(th, FAN_SPD_SET[fan], speed);
        } else {
                /* back to automatic */
-               if(therm_type == ADT7460) {
+               if(th->type == ADT7460) {
                        manual = read_reg(th,
                                MANUAL_MODE[fan]) & (~MANUAL_MASK);
                        manual &= ~INVERT_MASK;
@@ -293,7 +231,7 @@ static void update_fans_speed (struct thermostat *th)
        /* we don't care about local sensor, so we start at sensor 1 */
        for (i = 1; i < 3; i++) {
                int started = 0;
-               int fan_number = (therm_type == ADT7460 && i == 2);
+               int fan_number = (th->type == ADT7460 && i == 2);
                int var = th->temps[i] - th->limits[i];
 
                if (var > -1) {
@@ -370,116 +308,22 @@ static int monitor_task(void *arg)
 
 static void set_limit(struct thermostat *th, int i)
 {
-               /* Set sensor1 limit higher to avoid powerdowns */
-               th->limits[i] = default_limits_chip[i] + limit_adjust;
-               write_reg(th, LIMIT_REG[i], th->limits[i]);
+       /* Set sensor1 limit higher to avoid powerdowns */
+       th->limits[i] = default_limits_chip[i] + limit_adjust;
+       write_reg(th, LIMIT_REG[i], th->limits[i]);
                
-               /* set our limits to normal */
-               th->limits[i] = default_limits_local[i] + limit_adjust;
+       /* set our limits to normal */
+       th->limits[i] = default_limits_local[i] + limit_adjust;
 }
 
-static int probe_thermostat(struct i2c_client *client,
-                           const struct i2c_device_id *id)
-{
-       struct thermostat* th;
-       int rc;
-       int i;
-
-       if (thermostat)
-               return 0;
-
-       th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
-       if (!th)
-               return -ENOMEM;
-
-       i2c_set_clientdata(client, th);
-       th->clt = client;
-
-       rc = read_reg(th, CONFIG_REG);
-       if (rc < 0) {
-               dev_err(&client->dev, "Thermostat failed to read config!\n");
-               kfree(th);
-               return -ENODEV;
-       }
-
-       /* force manual control to start the fan quieter */
-       if (fan_speed == -1)
-               fan_speed = 64;
-       
-       if(therm_type == ADT7460) {
-               printk(KERN_INFO "adt746x: ADT7460 initializing\n");
-               /* The 7460 needs to be started explicitly */
-               write_reg(th, CONFIG_REG, 1);
-       } else
-               printk(KERN_INFO "adt746x: ADT7467 initializing\n");
-
-       for (i = 0; i < 3; i++) {
-               th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
-               set_limit(th, i);
-       }
-
-       printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
-                        " to %d, %d, %d\n",
-                        th->initial_limits[0], th->initial_limits[1],
-                        th->initial_limits[2], th->limits[0], th->limits[1],
-                        th->limits[2]);
-
-       thermostat = th;
-
-       /* record invert bit status because fw can corrupt it after suspend */
-       th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK;
-       th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK;
-
-       /* be sure to really write fan speed the first time */
-       th->last_speed[0] = -2;
-       th->last_speed[1] = -2;
-       th->last_var[0] = -80;
-       th->last_var[1] = -80;
-
-       if (fan_speed != -1) {
-               /* manual mode, stop fans */
-               write_both_fan_speed(th, 0);
-       } else {
-               /* automatic mode */
-               write_both_fan_speed(th, -1);
-       }
-       
-       thread_therm = kthread_run(monitor_task, th, "kfand");
-
-       if (thread_therm == ERR_PTR(-ENOMEM)) {
-               printk(KERN_INFO "adt746x: Kthread creation failed\n");
-               thread_therm = NULL;
-               return -ENOMEM;
-       }
-
-       thermostat_create_files();
-
-       return 0;
+#define BUILD_SHOW_FUNC_INT(name, data)                                \
+static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)       \
+{                                                              \
+       struct thermostat *th = dev_get_drvdata(dev);           \
+       return sprintf(buf, "%d\n", data);                      \
 }
 
-static const struct i2c_device_id therm_adt746x_id[] = {
-       { "therm_adt746x", 0 },
-       { }
-};
-
-static struct i2c_driver thermostat_driver = {
-       .driver = {
-               .name   = "therm_adt746x",
-       },
-       .attach_adapter = attach_thermostat,
-       .probe = probe_thermostat,
-       .remove = remove_thermostat,
-       .id_table = therm_adt746x_id,
-};
-
-/* 
- * Now, unfortunately, sysfs doesn't give us a nice void * we could
- * pass around to the attribute functions, so we don't really have
- * choice but implement a bunch of them...
- *
- * FIXME, it does now...
- */
-#define BUILD_SHOW_FUNC_INT(name, data)                                \
+#define BUILD_SHOW_FUNC_INT_LITE(name, data)                           \
 static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)       \
 {                                                              \
        return sprintf(buf, "%d\n", data);                      \
@@ -494,22 +338,24 @@ static ssize_t show_##name(struct device *dev, struct device_attribute *attr, ch
 #define BUILD_SHOW_FUNC_FAN(name, data)                                \
 static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)       \
 {                                                              \
+       struct thermostat *th = dev_get_drvdata(dev);           \
        return sprintf(buf, "%d (%d rpm)\n",                    \
-               thermostat->last_speed[data],                   \
-               read_fan_speed(thermostat, FAN_SPEED[data])     \
+               th->last_speed[data],                           \
+               read_fan_speed(th, FAN_SPEED[data])             \
                );                                              \
 }
 
 #define BUILD_STORE_FUNC_DEG(name, data)                       \
 static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \
 {                                                              \
+       struct thermostat *th = dev_get_drvdata(dev);           \
        int val;                                                \
        int i;                                                  \
        val = simple_strtol(buf, NULL, 10);                     \
        printk(KERN_INFO "Adjusting limits by %d degrees\n", val);      \
        limit_adjust = val;                                     \
        for (i=0; i < 3; i++)                                   \
-               set_limit(thermostat, i);                       \
+               set_limit(th, i);                               \
        return n;                                               \
 }
 
@@ -525,20 +371,21 @@ static ssize_t store_##name(struct device *dev, struct device_attribute *attr, c
        return n;                                               \
 }
 
-BUILD_SHOW_FUNC_INT(sensor1_temperature,        (read_reg(thermostat, TEMP_REG[1])))
-BUILD_SHOW_FUNC_INT(sensor2_temperature,        (read_reg(thermostat, TEMP_REG[2])))
-BUILD_SHOW_FUNC_INT(sensor1_limit,              thermostat->limits[1])
-BUILD_SHOW_FUNC_INT(sensor2_limit,              thermostat->limits[2])
+BUILD_SHOW_FUNC_INT(sensor1_temperature,        (read_reg(th, TEMP_REG[1])))
+BUILD_SHOW_FUNC_INT(sensor2_temperature,        (read_reg(th, TEMP_REG[2])))
+BUILD_SHOW_FUNC_INT(sensor1_limit,              th->limits[1])
+BUILD_SHOW_FUNC_INT(sensor2_limit,              th->limits[2])
 BUILD_SHOW_FUNC_STR(sensor1_location,           sensor_location[1])
 BUILD_SHOW_FUNC_STR(sensor2_location,           sensor_location[2])
 
-BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed)
+BUILD_SHOW_FUNC_INT_LITE(specified_fan_speed, fan_speed)
+BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
+
 BUILD_SHOW_FUNC_FAN(sensor1_fan_speed,  0)
 BUILD_SHOW_FUNC_FAN(sensor2_fan_speed,  1)
 
-BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
-BUILD_SHOW_FUNC_INT(limit_adjust,       limit_adjust)
-BUILD_STORE_FUNC_DEG(limit_adjust,      thermostat)
+BUILD_SHOW_FUNC_INT_LITE(limit_adjust,  limit_adjust)
+BUILD_STORE_FUNC_DEG(limit_adjust,      th)
                
 static DEVICE_ATTR(sensor1_temperature,        S_IRUGO,
                   show_sensor1_temperature,NULL);
@@ -564,53 +411,77 @@ static DEVICE_ATTR(sensor2_fan_speed,     S_IRUGO,
 static DEVICE_ATTR(limit_adjust,       S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
                   show_limit_adjust,   store_limit_adjust);
 
-
-static int __init
-thermostat_init(void)
+static void thermostat_create_files(struct thermostat *th)
 {
-       struct device_node* np;
-       const u32 *prop;
-       int i = 0, offset = 0;
+       struct device_node *np = th->clt->dev.of_node;
+       struct device *dev;
+       int err;
 
-       np = of_find_node_by_name(NULL, "fan");
-       if (!np)
-               return -ENODEV;
-       if (of_device_is_compatible(np, "adt7460"))
-               therm_type = ADT7460;
-       else if (of_device_is_compatible(np, "adt7467"))
-               therm_type = ADT7467;
-       else {
-               of_node_put(np);
-               return -ENODEV;
-       }
+       /* To maintain ABI compatibility with userspace, create
+        * the old style platform driver and attach the attributes
+        * to it here
+        */
+       th->pdev = of_platform_device_create(np, "temperatures", NULL);
+       if (!th->pdev)
+               return;
+       dev = &th->pdev->dev;
+       dev_set_drvdata(dev, th);
+       err = device_create_file(dev, &dev_attr_sensor1_temperature);
+       err |= device_create_file(dev, &dev_attr_sensor2_temperature);
+       err |= device_create_file(dev, &dev_attr_sensor1_limit);
+       err |= device_create_file(dev, &dev_attr_sensor2_limit);
+       err |= device_create_file(dev, &dev_attr_sensor1_location);
+       err |= device_create_file(dev, &dev_attr_sensor2_location);
+       err |= device_create_file(dev, &dev_attr_limit_adjust);
+       err |= device_create_file(dev, &dev_attr_specified_fan_speed);
+       err |= device_create_file(dev, &dev_attr_sensor1_fan_speed);
+       if(th->type == ADT7460)
+               err |= device_create_file(dev, &dev_attr_sensor2_fan_speed);
+       if (err)
+               printk(KERN_WARNING
+                       "Failed to create temperature attribute file(s).\n");
+}
 
-       prop = of_get_property(np, "hwsensor-params-version", NULL);
-       printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop,
-                        (*prop == 1)?"":"un");
-       if (*prop != 1) {
-               of_node_put(np);
-               return -ENODEV;
-       }
+static void thermostat_remove_files(struct thermostat *th)
+{
+       struct device *dev;
 
-       prop = of_get_property(np, "reg", NULL);
-       if (!prop) {
-               of_node_put(np);
-               return -ENODEV;
-       }
+       if (!th->pdev)
+               return;
+       dev = &th->pdev->dev;
+       device_remove_file(dev, &dev_attr_sensor1_temperature);
+       device_remove_file(dev, &dev_attr_sensor2_temperature);
+       device_remove_file(dev, &dev_attr_sensor1_limit);
+       device_remove_file(dev, &dev_attr_sensor2_limit);
+       device_remove_file(dev, &dev_attr_sensor1_location);
+       device_remove_file(dev, &dev_attr_sensor2_location);
+       device_remove_file(dev, &dev_attr_limit_adjust);
+       device_remove_file(dev, &dev_attr_specified_fan_speed);
+       device_remove_file(dev, &dev_attr_sensor1_fan_speed);   
+       if (th->type == ADT7460)
+               device_remove_file(dev, &dev_attr_sensor2_fan_speed);
+       of_device_unregister(th->pdev);
 
-       /* look for bus either by path or using "reg" */
-       if (strstr(np->full_name, "/i2c-bus@") != NULL) {
-               const char *tmp_bus = (strstr(np->full_name, "/i2c-bus@") + 9);
-               therm_bus = tmp_bus[0]-'0';
-       } else {
-               therm_bus = ((*prop) >> 8) & 0x0f;
-       }
+}
 
-       therm_address = ((*prop) & 0xff) >> 1;
+static int probe_thermostat(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       struct device_node *np = client->dev.of_node;
+       struct thermostat* th;
+       const __be32 *prop;
+       int i, rc, vers, offset = 0;
 
-       printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, "
-                        "limit_adjust: %d, fan_speed: %d\n",
-                        therm_bus, therm_address, limit_adjust, fan_speed);
+       if (!np)
+               return -ENXIO;
+       prop = of_get_property(np, "hwsensor-params-version", NULL);
+       if (!prop)
+               return -ENXIO;
+       vers = be32_to_cpup(prop);
+       printk(KERN_INFO "adt746x: version %d (%ssupported)\n",
+              vers, vers == 1 ? "" : "un");
+       if (vers != 1)
+               return -ENXIO;
 
        if (of_get_property(np, "hwsensor-location", NULL)) {
                for (i = 0; i < 3; i++) {
@@ -623,72 +494,129 @@ thermostat_init(void)
                        printk(KERN_INFO "sensor %d: %s\n", i, sensor_location[i]);
                        offset += strlen(sensor_location[i]) + 1;
                }
-       } else {
-               sensor_location[0] = "?";
-               sensor_location[1] = "?";
-               sensor_location[2] = "?";
        }
 
-       of_dev = of_platform_device_create(np, "temperatures", NULL);
-       of_node_put(np);
+       th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
+       if (!th)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, th);
+       th->clt = client;
+       th->type = id->driver_data;
 
-       if (of_dev == NULL) {
-               printk(KERN_ERR "Can't register temperatures device !\n");
+       rc = read_reg(th, CONFIG_REG);
+       if (rc < 0) {
+               dev_err(&client->dev, "Thermostat failed to read config!\n");
+               kfree(th);
                return -ENODEV;
        }
 
-#ifndef CONFIG_I2C_POWERMAC
-       request_module("i2c-powermac");
-#endif
+       /* force manual control to start the fan quieter */
+       if (fan_speed == -1)
+               fan_speed = 64;
+       
+       if (th->type == ADT7460) {
+               printk(KERN_INFO "adt746x: ADT7460 initializing\n");
+               /* The 7460 needs to be started explicitly */
+               write_reg(th, CONFIG_REG, 1);
+       } else
+               printk(KERN_INFO "adt746x: ADT7467 initializing\n");
 
-       return i2c_add_driver(&thermostat_driver);
+       for (i = 0; i < 3; i++) {
+               th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
+               set_limit(th, i);
+       }
+
+       printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
+                        " to %d, %d, %d\n",
+                        th->initial_limits[0], th->initial_limits[1],
+                        th->initial_limits[2], th->limits[0], th->limits[1],
+                        th->limits[2]);
+
+       /* record invert bit status because fw can corrupt it after suspend */
+       th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK;
+       th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK;
+
+       /* be sure to really write fan speed the first time */
+       th->last_speed[0] = -2;
+       th->last_speed[1] = -2;
+       th->last_var[0] = -80;
+       th->last_var[1] = -80;
+
+       if (fan_speed != -1) {
+               /* manual mode, stop fans */
+               write_both_fan_speed(th, 0);
+       } else {
+               /* automatic mode */
+               write_both_fan_speed(th, -1);
+       }
+       
+       th->thread = kthread_run(monitor_task, th, "kfand");
+       if (th->thread == ERR_PTR(-ENOMEM)) {
+               printk(KERN_INFO "adt746x: Kthread creation failed\n");
+               th->thread = NULL;
+               return -ENOMEM;
+       }
+
+       thermostat_create_files(th);
+
+       return 0;
 }
 
-static void thermostat_create_files(void)
+static int remove_thermostat(struct i2c_client *client)
 {
-       int err;
+       struct thermostat *th = i2c_get_clientdata(client);
+       int i;
+       
+       thermostat_remove_files(th);
 
-       err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature);
-       err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature);
-       err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit);
-       err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_limit);
-       err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_location);
-       err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_location);
-       err |= device_create_file(&of_dev->dev, &dev_attr_limit_adjust);
-       err |= device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed);
-       err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
-       if(therm_type == ADT7460)
-               err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed);
-       if (err)
-               printk(KERN_WARNING
-                       "Failed to create temperature attribute file(s).\n");
+       if (th->thread != NULL)
+               kthread_stop(th->thread);
+
+       printk(KERN_INFO "adt746x: Putting max temperatures back from "
+                        "%d, %d, %d to %d, %d, %d\n",
+               th->limits[0], th->limits[1], th->limits[2],
+               th->initial_limits[0], th->initial_limits[1],
+               th->initial_limits[2]);
+
+       for (i = 0; i < 3; i++)
+               write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
+
+       write_both_fan_speed(th, -1);
+
+       kfree(th);
+
+       return 0;
 }
 
-static void thermostat_remove_files(void)
+static const struct i2c_device_id therm_adt746x_id[] = {
+       { "MAC,adt7460", ADT7460 },
+       { "MAC,adt7467", ADT7467 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, therm_adt746x_id);
+
+static struct i2c_driver thermostat_driver = {
+       .driver = {
+               .name   = "therm_adt746x",
+       },
+       .probe = probe_thermostat,
+       .remove = remove_thermostat,
+       .id_table = therm_adt746x_id,
+};
+
+static int __init thermostat_init(void)
 {
-       if (of_dev) {
-               device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature);
-               device_remove_file(&of_dev->dev, &dev_attr_sensor2_temperature);
-               device_remove_file(&of_dev->dev, &dev_attr_sensor1_limit);
-               device_remove_file(&of_dev->dev, &dev_attr_sensor2_limit);
-               device_remove_file(&of_dev->dev, &dev_attr_sensor1_location);
-               device_remove_file(&of_dev->dev, &dev_attr_sensor2_location);
-               device_remove_file(&of_dev->dev, &dev_attr_limit_adjust);
-               device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed);
-               device_remove_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
-
-               if(therm_type == ADT7460)
-                       device_remove_file(&of_dev->dev,
-                                          &dev_attr_sensor2_fan_speed);
+#ifndef CONFIG_I2C_POWERMAC
+       request_module("i2c-powermac");
+#endif
 
-       }
+       return i2c_add_driver(&thermostat_driver);
 }
 
-static void __exit
-thermostat_exit(void)
+static void __exit thermostat_exit(void)
 {
        i2c_del_driver(&thermostat_driver);
-       of_device_unregister(of_dev);
 }
 
 module_init(thermostat_init);
index 7a2482cc26a7a09af070916482c0bf51bee1747a..028cdac2d33d3f9bf6146dc24b329fa4237c785e 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/device.h>
 
 /* Display a 16.16 fixed point value */
-#define FIX32TOPRINT(f)        ((f) >> 16),((((f) & 0xffff) * 1000) >> 16)
+#define FIX32TOPRINT(f)        (((s32)(f)) >> 16),(((((s32)(f)) & 0xffff) * 1000) >> 16)
 
 /*
  * Control objects
@@ -35,12 +35,13 @@ struct wf_control_ops {
 };
 
 struct wf_control {
-       struct list_head        link;
-       struct wf_control_ops   *ops;
-       char                    *name;
-       int                     type;
-       struct kref             ref;
-       struct device_attribute attr;
+       struct list_head                link;
+       const struct wf_control_ops     *ops;
+       const char                      *name;
+       int                             type;
+       struct kref                     ref;
+       struct device_attribute         attr;
+       void                            *priv;
 };
 
 #define WF_CONTROL_TYPE_GENERIC                0
@@ -72,6 +73,26 @@ static inline int wf_control_set_min(struct wf_control *ct)
        return ct->ops->set_value(ct, vmin);
 }
 
+static inline int wf_control_set(struct wf_control *ct, s32 val)
+{
+       return ct->ops->set_value(ct, val);
+}
+
+static inline int wf_control_get(struct wf_control *ct, s32 *val)
+{
+       return ct->ops->get_value(ct, val);
+}
+
+static inline s32 wf_control_get_min(struct wf_control *ct)
+{
+       return ct->ops->get_min(ct);
+}
+
+static inline s32 wf_control_get_max(struct wf_control *ct)
+{
+       return ct->ops->get_max(ct);
+}
+
 /*
  * Sensor objects
  */
@@ -85,11 +106,12 @@ struct wf_sensor_ops {
 };
 
 struct wf_sensor {
-       struct list_head        link;
-       struct wf_sensor_ops    *ops;
-       char                    *name;
-       struct kref             ref;
-       struct device_attribute attr;
+       struct list_head                link;
+       const struct wf_sensor_ops      *ops;
+       const char                      *name;
+       struct kref                     ref;
+       struct device_attribute         attr;
+       void                            *priv;
 };
 
 /* Same lifetime rules as controls */
@@ -99,6 +121,11 @@ extern struct wf_sensor * wf_find_sensor(const char *name);
 extern int wf_get_sensor(struct wf_sensor *sr);
 extern void wf_put_sensor(struct wf_sensor *sr);
 
+static inline int wf_sensor_get(struct wf_sensor *sr, s32 *val)
+{
+       return sr->ops->get_value(sr, val);
+}
+
 /* For use by clients. Note that we are a bit racy here since
  * notifier_block doesn't have a module owner field. I may fix
  * it one day ...
diff --git a/drivers/macintosh/windfarm_ad7417_sensor.c b/drivers/macintosh/windfarm_ad7417_sensor.c
new file mode 100644 (file)
index 0000000..ac3f243
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * Windfarm PowerMac thermal control. AD7417 sensors
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+#include "windfarm.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+struct wf_ad7417_priv {
+       struct kref             ref;
+       struct i2c_client       *i2c;
+       u8                      config;
+       u8                      cpu;
+       const struct mpu_data   *mpu;
+       struct wf_sensor        sensors[5];
+       struct mutex            lock;
+};
+
+static int wf_ad7417_temp_get(struct wf_sensor *sr, s32 *value)
+{
+       struct wf_ad7417_priv *pv = sr->priv;
+       u8 buf[2];
+       s16 raw;
+       int rc;
+
+       *value = 0;
+       mutex_lock(&pv->lock);
+
+       /* Read temp register */
+       buf[0] = 0;
+       rc = i2c_master_send(pv->i2c, buf, 1);
+       if (rc < 0)
+               goto error;
+       rc = i2c_master_recv(pv->i2c, buf, 2);
+       if (rc < 0)
+               goto error;
+
+       /* Read a a 16-bit signed value */
+       raw = be16_to_cpup((__le16 *)buf);
+
+       /* Convert 8.8-bit to 16.16 fixed point */
+       *value = ((s32)raw) << 8;
+
+       mutex_unlock(&pv->lock);
+       return 0;
+
+error:
+       mutex_unlock(&pv->lock);
+       return -1;
+}
+
+/*
+ * Scaling factors for the AD7417 ADC converters (except
+ * for the CPU diode which is obtained from the EEPROM).
+ * Those values are obtained from the property list of
+ * the darwin driver
+ */
+#define ADC_12V_CURRENT_SCALE  0x0320  /* _AD2 */
+#define ADC_CPU_VOLTAGE_SCALE  0x00a0  /* _AD3 */
+#define ADC_CPU_CURRENT_SCALE  0x1f40  /* _AD4 */
+
+static void wf_ad7417_adc_convert(struct wf_ad7417_priv *pv,
+                                 int chan, s32 raw, s32 *value)
+{
+       switch(chan) {
+       case 1: /* Diode */
+               *value = (raw * (s32)pv->mpu->mdiode +
+                       ((s32)pv->mpu->bdiode << 12)) >> 2;
+               break;
+       case 2: /* 12v current */
+               *value = raw * ADC_12V_CURRENT_SCALE;
+               break;
+       case 3: /* core voltage */
+               *value = raw * ADC_CPU_VOLTAGE_SCALE;
+               break;
+       case 4: /* core current */
+               *value = raw * ADC_CPU_CURRENT_SCALE;
+               break;
+       }
+}
+
+static int wf_ad7417_adc_get(struct wf_sensor *sr, s32 *value)
+{
+       struct wf_ad7417_priv *pv = sr->priv;
+       int chan = sr - pv->sensors;
+       int i, rc;
+       u8 buf[2];
+       u16 raw;
+
+       *value = 0;
+       mutex_lock(&pv->lock);
+       for (i = 0; i < 10; i++) {
+               /* Set channel */
+               buf[0] = 1;
+               buf[1] = (pv->config & 0x1f) | (chan << 5);
+               rc = i2c_master_send(pv->i2c, buf, 2);
+               if (rc < 0)
+                       goto error;
+
+               /* Wait for conversion */
+               msleep(1);
+
+               /* Switch to data register */
+               buf[0] = 4;
+               rc = i2c_master_send(pv->i2c, buf, 1);
+               if (rc < 0)
+                       goto error;
+
+               /* Read result */
+               rc = i2c_master_recv(pv->i2c, buf, 2);
+               if (rc < 0)
+                       goto error;
+
+               /* Read a a 16-bit signed value */
+               raw = be16_to_cpup((__le16 *)buf) >> 6;
+               wf_ad7417_adc_convert(pv, chan, raw, value);
+
+               dev_vdbg(&pv->i2c->dev, "ADC chan %d [%s]"
+                        " raw value: 0x%x, conv to: 0x%08x\n",
+                        chan, sr->name, raw, *value);
+
+               mutex_unlock(&pv->lock);
+               return 0;
+
+       error:
+               dev_dbg(&pv->i2c->dev,
+                         "Error reading ADC, try %d...\n", i);
+               if (i < 9)
+                       msleep(10);
+       }
+       mutex_unlock(&pv->lock);
+       return -1;
+}
+
+static void wf_ad7417_release(struct kref *ref)
+{
+       struct wf_ad7417_priv *pv = container_of(ref,
+                                                struct wf_ad7417_priv, ref);
+       kfree(pv);
+}
+
+static void wf_ad7417_sensor_release(struct wf_sensor *sr)
+{
+       struct wf_ad7417_priv *pv = sr->priv;
+
+       kfree(sr->name);
+       kref_put(&pv->ref, wf_ad7417_release);
+}
+
+static const struct wf_sensor_ops wf_ad7417_temp_ops = {
+       .get_value      = wf_ad7417_temp_get,
+       .release        = wf_ad7417_sensor_release,
+       .owner          = THIS_MODULE,
+};
+
+static const struct wf_sensor_ops wf_ad7417_adc_ops = {
+       .get_value      = wf_ad7417_adc_get,
+       .release        = wf_ad7417_sensor_release,
+       .owner          = THIS_MODULE,
+};
+
+static void __devinit wf_ad7417_add_sensor(struct wf_ad7417_priv *pv,
+                                          int index, const char *name,
+                                          const struct wf_sensor_ops *ops)
+{
+       pv->sensors[index].name = kasprintf(GFP_KERNEL, "%s-%d", name, pv->cpu);
+       pv->sensors[index].priv = pv;
+       pv->sensors[index].ops = ops;
+       if (!wf_register_sensor(&pv->sensors[index]))
+               kref_get(&pv->ref);
+}
+
+static void __devinit wf_ad7417_init_chip(struct wf_ad7417_priv *pv)
+{
+       int rc;
+       u8 buf[2];
+       u8 config = 0;
+
+       /*
+        * Read ADC the configuration register and cache it. We
+        * also make sure Config2 contains proper values, I've seen
+        * cases where we got stale grabage in there, thus preventing
+        * proper reading of conv. values
+        */
+
+       /* Clear Config2 */
+       buf[0] = 5;
+       buf[1] = 0;
+       i2c_master_send(pv->i2c, buf, 2);
+
+       /* Read & cache Config1 */
+       buf[0] = 1;
+       rc = i2c_master_send(pv->i2c, buf, 1);
+       if (rc > 0) {
+               rc = i2c_master_recv(pv->i2c, buf, 1);
+               if (rc > 0) {
+                       config = buf[0];
+
+                       dev_dbg(&pv->i2c->dev, "ADC config reg: %02x\n",
+                               config);
+
+                       /* Disable shutdown mode */
+                       config &= 0xfe;
+                       buf[0] = 1;
+                       buf[1] = config;
+                       rc = i2c_master_send(pv->i2c, buf, 2);
+               }
+       }
+       if (rc <= 0)
+               dev_err(&pv->i2c->dev, "Error reading ADC config\n");
+
+       pv->config = config;
+}
+
+static int __devinit wf_ad7417_probe(struct i2c_client *client,
+                                    const struct i2c_device_id *id)
+{
+       struct wf_ad7417_priv *pv;
+       const struct mpu_data *mpu;
+       const char *loc;
+       int cpu_nr;
+
+       loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+       if (!loc) {
+               dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+               return -ENXIO;
+       }
+
+       /*
+        * Identify which CPU we belong to by looking at the first entry
+        * in the hwsensor-location list
+        */
+       if (!strncmp(loc, "CPU A", 5))
+               cpu_nr = 0;
+       else if (!strncmp(loc, "CPU B", 5))
+               cpu_nr = 1;
+       else {
+               pr_err("wf_ad7417: Can't identify location %s\n", loc);
+               return -ENXIO;
+       }
+       mpu = wf_get_mpu(cpu_nr);
+       if (!mpu) {
+               dev_err(&client->dev, "Failed to retrieve MPU data\n");
+               return -ENXIO;
+       }
+
+       pv = kzalloc(sizeof(struct wf_ad7417_priv), GFP_KERNEL);
+       if (pv == NULL)
+               return -ENODEV;
+
+       kref_init(&pv->ref);
+       mutex_init(&pv->lock);
+       pv->i2c = client;
+       pv->cpu = cpu_nr;
+       pv->mpu = mpu;
+       dev_set_drvdata(&client->dev, pv);
+
+       /* Initialize the chip */
+       wf_ad7417_init_chip(pv);
+
+       /*
+        * We cannot rely on Apple device-tree giving us child
+        * node with the names of the individual sensors so we
+        * just hard code what we know about them
+        */
+       wf_ad7417_add_sensor(pv, 0, "cpu-amb-temp", &wf_ad7417_temp_ops);
+       wf_ad7417_add_sensor(pv, 1, "cpu-diode-temp", &wf_ad7417_adc_ops);
+       wf_ad7417_add_sensor(pv, 2, "cpu-12v-current", &wf_ad7417_adc_ops);
+       wf_ad7417_add_sensor(pv, 3, "cpu-voltage", &wf_ad7417_adc_ops);
+       wf_ad7417_add_sensor(pv, 4, "cpu-current", &wf_ad7417_adc_ops);
+
+       return 0;
+}
+
+static int __devexit wf_ad7417_remove(struct i2c_client *client)
+{
+       struct wf_ad7417_priv *pv = dev_get_drvdata(&client->dev);
+       int i;
+
+       /* Mark client detached */
+       pv->i2c = NULL;
+
+       /* Release sensor */
+       for (i = 0; i < 5; i++)
+               wf_unregister_sensor(&pv->sensors[i]);
+
+       kref_put(&pv->ref, wf_ad7417_release);
+
+       return 0;
+}
+
+static const struct i2c_device_id wf_ad7417_id[] = {
+       { "MAC,ad7417", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wf_ad7417_id);
+
+static struct i2c_driver wf_ad7417_driver = {
+       .driver = {
+               .name   = "wf_ad7417",
+       },
+       .probe          = wf_ad7417_probe,
+       .remove         = wf_ad7417_remove,
+       .id_table       = wf_ad7417_id,
+};
+
+static int __devinit wf_ad7417_init(void)
+{
+       /* This is only supported on these machines */
+       if (!of_machine_is_compatible("PowerMac7,2") &&
+           !of_machine_is_compatible("PowerMac7,3") &&
+           !of_machine_is_compatible("RackMac3,1"))
+               return -ENODEV;
+
+       return i2c_add_driver(&wf_ad7417_driver);
+}
+
+static void __devexit wf_ad7417_exit(void)
+{
+       i2c_del_driver(&wf_ad7417_driver);
+}
+
+module_init(wf_ad7417_init);
+module_exit(wf_ad7417_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("ad7417 sensor driver for PowerMacs");
+MODULE_LICENSE("GPL");
+
index ce8897933a84daeccddd318438b939face4aec8f..3ee198b6584382b8051aa9be134dc625e0efb236 100644 (file)
@@ -164,13 +164,27 @@ static ssize_t wf_show_control(struct device *dev,
                               struct device_attribute *attr, char *buf)
 {
        struct wf_control *ctrl = container_of(attr, struct wf_control, attr);
+       const char *typestr;
        s32 val = 0;
        int err;
 
        err = ctrl->ops->get_value(ctrl, &val);
-       if (err < 0)
+       if (err < 0) {
+               if (err == -EFAULT)
+                       return sprintf(buf, "<HW FAULT>\n");
                return err;
-       return sprintf(buf, "%d\n", val);
+       }
+       switch(ctrl->type) {
+       case WF_CONTROL_RPM_FAN:
+               typestr = " RPM";
+               break;
+       case WF_CONTROL_PWM_FAN:
+               typestr = " %";
+               break;
+       default:
+               typestr = "";
+       }
+       return sprintf(buf, "%d%s\n", val, typestr);
 }
 
 /* This is really only for debugging... */
@@ -470,11 +484,6 @@ static int __init windfarm_core_init(void)
 {
        DBG("wf: core loaded\n");
 
-       /* Don't register on old machines that use therm_pm72 for now */
-       if (of_machine_is_compatible("PowerMac7,2") ||
-           of_machine_is_compatible("PowerMac7,3") ||
-           of_machine_is_compatible("RackMac3,1"))
-               return -ENODEV;
        platform_device_register(&wf_platform_device);
        return 0;
 }
index 1a77a7c97d0e58d3141b667b6ff2b55be0aa3f52..72d1fdfe02a5bfbffc56902eecdf7fc89ca052cb 100644 (file)
@@ -75,12 +75,6 @@ static int __init wf_cpufreq_clamp_init(void)
 {
        struct wf_control *clamp;
 
-       /* Don't register on old machines that use therm_pm72 for now */
-       if (of_machine_is_compatible("PowerMac7,2") ||
-           of_machine_is_compatible("PowerMac7,3") ||
-           of_machine_is_compatible("RackMac3,1"))
-               return -ENODEV;
-
        clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
        if (clamp == NULL)
                return -ENOMEM;
diff --git a/drivers/macintosh/windfarm_fcu_controls.c b/drivers/macintosh/windfarm_fcu_controls.c
new file mode 100644 (file)
index 0000000..b3411ed
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * Windfarm PowerMac thermal control. FCU fan control
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+#include "windfarm.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#ifdef DEBUG
+#define DBG(args...)   printk(args)
+#else
+#define DBG(args...)   do { } while(0)
+#endif
+
+/*
+ * This option is "weird" :) Basically, if you define this to 1
+ * the control loop for the RPMs fans (not PWMs) will apply the
+ * correction factor obtained from the PID to the actual RPM
+ * speed read from the FCU.
+ *
+ * If you define the below constant to 0, then it will be
+ * applied to the setpoint RPM speed, that is basically the
+ * speed we proviously "asked" for.
+ *
+ * I'm using 0 for now which is what therm_pm72 used to do and
+ * what Darwin -apparently- does based on observed behaviour.
+ */
+#define RPM_PID_USE_ACTUAL_SPEED       0
+
+/* Default min/max for pumps */
+#define CPU_PUMP_OUTPUT_MAX            3200
+#define CPU_PUMP_OUTPUT_MIN            1250
+
+#define FCU_FAN_RPM            0
+#define FCU_FAN_PWM            1
+
+struct wf_fcu_priv {
+       struct kref             ref;
+       struct i2c_client       *i2c;
+       struct mutex            lock;
+       struct list_head        fan_list;
+       int                     rpm_shift;
+};
+
+struct wf_fcu_fan {
+       struct list_head        link;
+       int                     id;
+       s32                     min, max, target;
+       struct wf_fcu_priv      *fcu_priv;
+       struct wf_control       ctrl;
+};
+
+static void wf_fcu_release(struct kref *ref)
+{
+       struct wf_fcu_priv *pv = container_of(ref, struct wf_fcu_priv, ref);
+
+       kfree(pv);
+}
+
+static void wf_fcu_fan_release(struct wf_control *ct)
+{
+       struct wf_fcu_fan *fan = ct->priv;
+
+       kref_put(&fan->fcu_priv->ref, wf_fcu_release);
+       kfree(fan);
+}
+
+static int wf_fcu_read_reg(struct wf_fcu_priv *pv, int reg,
+                          unsigned char *buf, int nb)
+{
+       int tries, nr, nw;
+
+       mutex_lock(&pv->lock);
+
+       buf[0] = reg;
+       tries = 0;
+       for (;;) {
+               nw = i2c_master_send(pv->i2c, buf, 1);
+               if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
+                       break;
+               msleep(10);
+               ++tries;
+       }
+       if (nw <= 0) {
+               pr_err("Failure writing address to FCU: %d", nw);
+               nr = nw;
+               goto bail;
+       }
+       tries = 0;
+       for (;;) {
+               nr = i2c_master_recv(pv->i2c, buf, nb);
+               if (nr > 0 || (nr < 0 && nr != -ENODEV) || tries >= 100)
+                       break;
+               msleep(10);
+               ++tries;
+       }
+       if (nr <= 0)
+               pr_err("wf_fcu: Failure reading data from FCU: %d", nw);
+ bail:
+       mutex_unlock(&pv->lock);
+       return nr;
+}
+
+static int wf_fcu_write_reg(struct wf_fcu_priv *pv, int reg,
+                           const unsigned char *ptr, int nb)
+{
+       int tries, nw;
+       unsigned char buf[16];
+
+       buf[0] = reg;
+       memcpy(buf+1, ptr, nb);
+       ++nb;
+       tries = 0;
+       for (;;) {
+               nw = i2c_master_send(pv->i2c, buf, nb);
+               if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
+                       break;
+               msleep(10);
+               ++tries;
+       }
+       if (nw < 0)
+               pr_err("wf_fcu: Failure writing to FCU: %d", nw);
+       return nw;
+}
+
+static int wf_fcu_fan_set_rpm(struct wf_control *ct, s32 value)
+{
+       struct wf_fcu_fan *fan = ct->priv;
+       struct wf_fcu_priv *pv = fan->fcu_priv;
+       int rc, shift = pv->rpm_shift;
+       unsigned char buf[2];
+
+       if (value < fan->min)
+               value = fan->min;
+       if (value > fan->max)
+               value = fan->max;
+
+       fan->target = value;
+
+       buf[0] = value >> (8 - shift);
+       buf[1] = value << shift;
+       rc = wf_fcu_write_reg(pv, 0x10 + (fan->id * 2), buf, 2);
+       if (rc < 0)
+               return -EIO;
+       return 0;
+}
+
+static int wf_fcu_fan_get_rpm(struct wf_control *ct, s32 *value)
+{
+       struct wf_fcu_fan *fan = ct->priv;
+       struct wf_fcu_priv *pv = fan->fcu_priv;
+       int rc, reg_base, shift = pv->rpm_shift;
+       unsigned char failure;
+       unsigned char active;
+       unsigned char buf[2];
+
+       rc = wf_fcu_read_reg(pv, 0xb, &failure, 1);
+       if (rc != 1)
+               return -EIO;
+       if ((failure & (1 << fan->id)) != 0)
+               return -EFAULT;
+       rc = wf_fcu_read_reg(pv, 0xd, &active, 1);
+       if (rc != 1)
+               return -EIO;
+       if ((active & (1 << fan->id)) == 0)
+               return -ENXIO;
+
+       /* Programmed value or real current speed */
+#if RPM_PID_USE_ACTUAL_SPEED
+       reg_base = 0x11;
+#else
+       reg_base = 0x10;
+#endif
+       rc = wf_fcu_read_reg(pv, reg_base + (fan->id * 2), buf, 2);
+       if (rc != 2)
+               return -EIO;
+
+       *value = (buf[0] << (8 - shift)) | buf[1] >> shift;
+
+       return 0;
+}
+
+static int wf_fcu_fan_set_pwm(struct wf_control *ct, s32 value)
+{
+       struct wf_fcu_fan *fan = ct->priv;
+       struct wf_fcu_priv *pv = fan->fcu_priv;
+       unsigned char buf[2];
+       int rc;
+
+       if (value < fan->min)
+               value = fan->min;
+       if (value > fan->max)
+               value = fan->max;
+
+       fan->target = value;
+
+       value = (value * 2559) / 1000;
+       buf[0] = value;
+       rc = wf_fcu_write_reg(pv, 0x30 + (fan->id * 2), buf, 1);
+       if (rc < 0)
+               return -EIO;
+       return 0;
+}
+
+static int wf_fcu_fan_get_pwm(struct wf_control *ct, s32 *value)
+{
+       struct wf_fcu_fan *fan = ct->priv;
+       struct wf_fcu_priv *pv = fan->fcu_priv;
+       unsigned char failure;
+       unsigned char active;
+       unsigned char buf[2];
+       int rc;
+
+       rc = wf_fcu_read_reg(pv, 0x2b, &failure, 1);
+       if (rc != 1)
+               return -EIO;
+       if ((failure & (1 << fan->id)) != 0)
+               return -EFAULT;
+       rc = wf_fcu_read_reg(pv, 0x2d, &active, 1);
+       if (rc != 1)
+               return -EIO;
+       if ((active & (1 << fan->id)) == 0)
+               return -ENXIO;
+
+       rc = wf_fcu_read_reg(pv, 0x30 + (fan->id * 2), buf, 1);
+       if (rc != 1)
+               return -EIO;
+
+       *value = (((s32)buf[0]) * 1000) / 2559;
+
+       return 0;
+}
+
+static s32 wf_fcu_fan_min(struct wf_control *ct)
+{
+       struct wf_fcu_fan *fan = ct->priv;
+
+       return fan->min;
+}
+
+static s32 wf_fcu_fan_max(struct wf_control *ct)
+{
+       struct wf_fcu_fan *fan = ct->priv;
+
+       return fan->max;
+}
+
+static const struct wf_control_ops wf_fcu_fan_rpm_ops = {
+       .set_value      = wf_fcu_fan_set_rpm,
+       .get_value      = wf_fcu_fan_get_rpm,
+       .get_min        = wf_fcu_fan_min,
+       .get_max        = wf_fcu_fan_max,
+       .release        = wf_fcu_fan_release,
+       .owner          = THIS_MODULE,
+};
+
+static const struct wf_control_ops wf_fcu_fan_pwm_ops = {
+       .set_value      = wf_fcu_fan_set_pwm,
+       .get_value      = wf_fcu_fan_get_pwm,
+       .get_min        = wf_fcu_fan_min,
+       .get_max        = wf_fcu_fan_max,
+       .release        = wf_fcu_fan_release,
+       .owner          = THIS_MODULE,
+};
+
+static void __devinit wf_fcu_get_pump_minmax(struct wf_fcu_fan *fan)
+{
+       const struct mpu_data *mpu = wf_get_mpu(0);
+       u16 pump_min = 0, pump_max = 0xffff;
+       u16 tmp[4];
+
+       /* Try to fetch pumps min/max infos from eeprom */
+       if (mpu) {
+               memcpy(&tmp, mpu->processor_part_num, 8);
+               if (tmp[0] != 0xffff && tmp[1] != 0xffff) {
+                       pump_min = max(pump_min, tmp[0]);
+                       pump_max = min(pump_max, tmp[1]);
+               }
+               if (tmp[2] != 0xffff && tmp[3] != 0xffff) {
+                       pump_min = max(pump_min, tmp[2]);
+                       pump_max = min(pump_max, tmp[3]);
+               }
+       }
+
+       /* Double check the values, this _IS_ needed as the EEPROM on
+        * some dual 2.5Ghz G5s seem, at least, to have both min & max
+        * same to the same value ... (grrrr)
+        */
+       if (pump_min == pump_max || pump_min == 0 || pump_max == 0xffff) {
+               pump_min = CPU_PUMP_OUTPUT_MIN;
+               pump_max = CPU_PUMP_OUTPUT_MAX;
+       }
+
+       fan->min = pump_min;
+       fan->max = pump_max;
+
+       DBG("wf_fcu: pump min/max for %s set to: [%d..%d] RPM\n",
+           fan->ctrl.name, pump_min, pump_max);
+}
+
+static void __devinit wf_fcu_get_rpmfan_minmax(struct wf_fcu_fan *fan)
+{
+       struct wf_fcu_priv *pv = fan->fcu_priv;
+       const struct mpu_data *mpu0 = wf_get_mpu(0);
+       const struct mpu_data *mpu1 = wf_get_mpu(1);
+
+       /* Default */
+       fan->min = 2400 >> pv->rpm_shift;
+       fan->max = 56000 >> pv->rpm_shift;
+
+       /* CPU fans have min/max in MPU */
+       if (mpu0 && !strcmp(fan->ctrl.name, "cpu-front-fan-0")) {
+               fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
+               fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan);
+               goto bail;
+       }
+       if (mpu1 && !strcmp(fan->ctrl.name, "cpu-front-fan-1")) {
+               fan->min = max(fan->min, (s32)mpu1->rminn_intake_fan);
+               fan->max = min(fan->max, (s32)mpu1->rmaxn_intake_fan);
+               goto bail;
+       }
+       if (mpu0 && !strcmp(fan->ctrl.name, "cpu-rear-fan-0")) {
+               fan->min = max(fan->min, (s32)mpu0->rminn_exhaust_fan);
+               fan->max = min(fan->max, (s32)mpu0->rmaxn_exhaust_fan);
+               goto bail;
+       }
+       if (mpu1 && !strcmp(fan->ctrl.name, "cpu-rear-fan-1")) {
+               fan->min = max(fan->min, (s32)mpu1->rminn_exhaust_fan);
+               fan->max = min(fan->max, (s32)mpu1->rmaxn_exhaust_fan);
+               goto bail;
+       }
+       /* Rackmac variants, we just use mpu0 intake */
+       if (!strncmp(fan->ctrl.name, "cpu-fan", 7)) {
+               fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
+               fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan);
+               goto bail;
+       }
+ bail:
+       DBG("wf_fcu: fan min/max for %s set to: [%d..%d] RPM\n",
+           fan->ctrl.name, fan->min, fan->max);
+}
+
+static void __devinit wf_fcu_add_fan(struct wf_fcu_priv *pv,
+                                    const char *name,
+                                    int type, int id)
+{
+       struct wf_fcu_fan *fan;
+
+       fan = kzalloc(sizeof(*fan), GFP_KERNEL);
+       if (!fan)
+               return;
+       fan->fcu_priv = pv;
+       fan->id = id;
+       fan->ctrl.name = name;
+       fan->ctrl.priv = fan;
+
+       /* min/max is oddball but the code comes from
+        * therm_pm72 which seems to work so ...
+        */
+       if (type == FCU_FAN_RPM) {
+               if (!strncmp(name, "cpu-pump", strlen("cpu-pump")))
+                       wf_fcu_get_pump_minmax(fan);
+               else
+                       wf_fcu_get_rpmfan_minmax(fan);
+               fan->ctrl.type = WF_CONTROL_RPM_FAN;
+               fan->ctrl.ops = &wf_fcu_fan_rpm_ops;
+       } else {
+               fan->min = 10;
+               fan->max = 100;
+               fan->ctrl.type = WF_CONTROL_PWM_FAN;
+               fan->ctrl.ops = &wf_fcu_fan_pwm_ops;
+       }
+
+       if (wf_register_control(&fan->ctrl)) {
+               pr_err("wf_fcu: Failed to register fan %s\n", name);
+               kfree(fan);
+               return;
+       }
+       list_add(&fan->link, &pv->fan_list);
+       kref_get(&pv->ref);
+}
+
+static void __devinit wf_fcu_lookup_fans(struct wf_fcu_priv *pv)
+{
+       /* Translation of device-tree location properties to
+        * windfarm fan names
+        */
+       static const struct {
+               const char *dt_name;    /* Device-tree name */
+               const char *ct_name;    /* Control name */
+       } loc_trans[] = {
+               { "BACKSIDE",           "backside-fan",         },
+               { "SYS CTRLR FAN",      "backside-fan",         },
+               { "DRIVE BAY",          "drive-bay-fan",        },
+               { "SLOT",               "slots-fan",            },
+               { "PCI FAN",            "slots-fan",            },
+               { "CPU A INTAKE",       "cpu-front-fan-0",      },
+               { "CPU A EXHAUST",      "cpu-rear-fan-0",       },
+               { "CPU B INTAKE",       "cpu-front-fan-1",      },
+               { "CPU B EXHAUST",      "cpu-rear-fan-1",       },
+               { "CPU A PUMP",         "cpu-pump-0",           },
+               { "CPU B PUMP",         "cpu-pump-1",           },
+               { "CPU A 1",            "cpu-fan-a-0",          },
+               { "CPU A 2",            "cpu-fan-b-0",          },
+               { "CPU A 3",            "cpu-fan-c-0",          },
+               { "CPU B 1",            "cpu-fan-a-1",          },
+               { "CPU B 2",            "cpu-fan-b-1",          },
+               { "CPU B 3",            "cpu-fan-c-1",          },
+       };
+       struct device_node *np = NULL, *fcu = pv->i2c->dev.of_node;
+       int i;
+
+       DBG("Looking up FCU controls in device-tree...\n");
+
+       while ((np = of_get_next_child(fcu, np)) != NULL) {
+               int id, type = -1;
+               const char *loc;
+               const char *name;
+               const u32 *reg;
+
+               DBG(" control: %s, type: %s\n", np->name, np->type);
+
+               /* Detect control type */
+               if (!strcmp(np->type, "fan-rpm-control") ||
+                   !strcmp(np->type, "fan-rpm"))
+                       type = FCU_FAN_RPM;
+               if (!strcmp(np->type, "fan-pwm-control") ||
+                   !strcmp(np->type, "fan-pwm"))
+                       type = FCU_FAN_PWM;
+               /* Only care about fans for now */
+               if (type == -1)
+                       continue;
+
+               /* Lookup for a matching location */
+               loc = of_get_property(np, "location", NULL);
+               reg = of_get_property(np, "reg", NULL);
+               if (loc == NULL || reg == NULL)
+                       continue;
+               DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg);
+
+               for (i = 0; i < ARRAY_SIZE(loc_trans); i++) {
+                       if (strncmp(loc, loc_trans[i].dt_name,
+                                   strlen(loc_trans[i].dt_name)))
+                               continue;
+                       name = loc_trans[i].ct_name;
+
+                       DBG(" location match, name: %s\n", name);
+
+                       if (type == FCU_FAN_RPM)
+                               id = ((*reg) - 0x10) / 2;
+                       else
+                               id = ((*reg) - 0x30) / 2;
+                       if (id > 7) {
+                               pr_warning("wf_fcu: Can't parse "
+                                      "fan ID in device-tree for %s\n",
+                                          np->full_name);
+                               break;
+                       }
+                       wf_fcu_add_fan(pv, name, type, id);
+                       break;
+               }
+       }
+}
+
+static void __devinit wf_fcu_default_fans(struct wf_fcu_priv *pv)
+{
+       /* We only support the default fans for PowerMac7,2 */
+       if (!of_machine_is_compatible("PowerMac7,2"))
+               return;
+
+       wf_fcu_add_fan(pv, "backside-fan",      FCU_FAN_PWM, 1);
+       wf_fcu_add_fan(pv, "drive-bay-fan",     FCU_FAN_RPM, 2);
+       wf_fcu_add_fan(pv, "slots-fan",         FCU_FAN_PWM, 2);
+       wf_fcu_add_fan(pv, "cpu-front-fan-0",   FCU_FAN_RPM, 3);
+       wf_fcu_add_fan(pv, "cpu-rear-fan-0",    FCU_FAN_RPM, 4);
+       wf_fcu_add_fan(pv, "cpu-front-fan-1",   FCU_FAN_RPM, 5);
+       wf_fcu_add_fan(pv, "cpu-rear-fan-1",    FCU_FAN_RPM, 6);
+}
+
+static int __devinit wf_fcu_init_chip(struct wf_fcu_priv *pv)
+{
+       unsigned char buf = 0xff;
+       int rc;
+
+       rc = wf_fcu_write_reg(pv, 0xe, &buf, 1);
+       if (rc < 0)
+               return -EIO;
+       rc = wf_fcu_write_reg(pv, 0x2e, &buf, 1);
+       if (rc < 0)
+               return -EIO;
+       rc = wf_fcu_read_reg(pv, 0, &buf, 1);
+       if (rc < 0)
+               return -EIO;
+       pv->rpm_shift = (buf == 1) ? 2 : 3;
+
+       pr_debug("wf_fcu: FCU Initialized, RPM fan shift is %d\n",
+                pv->rpm_shift);
+
+       return 0;
+}
+
+static int __devinit wf_fcu_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       struct wf_fcu_priv *pv;
+
+       pv = kzalloc(sizeof(*pv), GFP_KERNEL);
+       if (!pv)
+               return -ENOMEM;
+
+       kref_init(&pv->ref);
+       mutex_init(&pv->lock);
+       INIT_LIST_HEAD(&pv->fan_list);
+       pv->i2c = client;
+
+       /*
+        * First we must start the FCU which will query the
+        * shift value to apply to RPMs
+        */
+       if (wf_fcu_init_chip(pv)) {
+               pr_err("wf_fcu: Initialization failed !\n");
+               kfree(pv);
+               return -ENXIO;
+       }
+
+       /* First lookup fans in the device-tree */
+       wf_fcu_lookup_fans(pv);
+
+       /*
+        * Older machines don't have the device-tree entries
+        * we are looking for, just hard code the list
+        */
+       if (list_empty(&pv->fan_list))
+               wf_fcu_default_fans(pv);
+
+       /* Still no fans ? FAIL */
+       if (list_empty(&pv->fan_list)) {
+               pr_err("wf_fcu: Failed to find fans for your machine\n");
+               kfree(pv);
+               return -ENODEV;
+       }
+
+       dev_set_drvdata(&client->dev, pv);
+
+       return 0;
+}
+
+static int __devexit wf_fcu_remove(struct i2c_client *client)
+{
+       struct wf_fcu_priv *pv = dev_get_drvdata(&client->dev);
+       struct wf_fcu_fan *fan;
+
+       while (!list_empty(&pv->fan_list)) {
+               fan = list_first_entry(&pv->fan_list, struct wf_fcu_fan, link);
+               list_del(&fan->link);
+               wf_unregister_control(&fan->ctrl);
+       }
+       kref_put(&pv->ref, wf_fcu_release);
+       return 0;
+}
+
+static const struct i2c_device_id wf_fcu_id[] = {
+       { "MAC,fcu", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wf_fcu_id);
+
+static struct i2c_driver wf_fcu_driver = {
+       .driver = {
+               .name   = "wf_fcu",
+       },
+       .probe          = wf_fcu_probe,
+       .remove         = wf_fcu_remove,
+       .id_table       = wf_fcu_id,
+};
+
+static int __init wf_fcu_init(void)
+{
+       return i2c_add_driver(&wf_fcu_driver);
+}
+
+static void __exit wf_fcu_exit(void)
+{
+       i2c_del_driver(&wf_fcu_driver);
+}
+
+
+module_init(wf_fcu_init);
+module_exit(wf_fcu_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("FCU control objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
index 4d6a90a1372bf7d3c01f484dac8c24501ddd6edf..b0c2d3695b347fc1e5c8f16c22527903ecfa1630 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "windfarm.h"
 
-#define VERSION "0.2"
+#define VERSION "1.0"
 
 #undef DEBUG
 
@@ -36,8 +36,8 @@
 struct wf_lm75_sensor {
        int                     ds1775 : 1;
        int                     inited : 1;
-       struct  i2c_client      *i2c;
-       struct  wf_sensor       sens;
+       struct i2c_client       *i2c;
+       struct wf_sensor        sens;
 };
 #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
 
@@ -90,40 +90,19 @@ static struct wf_sensor_ops wf_lm75_ops = {
 
 static int wf_lm75_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
-{
+{      
        struct wf_lm75_sensor *lm;
-       int rc;
-
-       lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
-       if (lm == NULL)
-               return -ENODEV;
-
-       lm->inited = 0;
-       lm->ds1775 = id->driver_data;
-       lm->i2c = client;
-       lm->sens.name = client->dev.platform_data;
-       lm->sens.ops = &wf_lm75_ops;
-       i2c_set_clientdata(client, lm);
-
-       rc = wf_register_sensor(&lm->sens);
-       if (rc)
-               kfree(lm);
-
-       return rc;
-}
-
-static struct i2c_driver wf_lm75_driver;
-
-static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
-                                            u8 addr, int ds1775,
-                                            const char *loc)
-{
-       struct i2c_board_info info;
-       struct i2c_client *client;
-       char *name;
+       int rc, ds1775 = id->driver_data;
+       const char *name, *loc;
 
        DBG("wf_lm75: creating  %s device at address 0x%02x\n",
-           ds1775 ? "ds1775" : "lm75", addr);
+           ds1775 ? "ds1775" : "lm75", client->addr);
+
+       loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+       if (!loc) {
+               dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+               return -ENXIO;
+       }
 
        /* Usual rant about sensor names not beeing very consistent in
         * the device-tree, oh well ...
@@ -137,68 +116,31 @@ static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
                name = "optical-drive-temp";
        else if (!strcmp(loc, "HD Temp"))
                name = "hard-drive-temp";
+       else if (!strcmp(loc, "PCI SLOTS"))
+               name = "slots-temp";
+       else if (!strcmp(loc, "CPU A INLET"))
+               name = "cpu-inlet-temp-0";
+       else if (!strcmp(loc, "CPU B INLET"))
+               name = "cpu-inlet-temp-1";
        else
-               goto fail;
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = (addr >> 1) & 0x7f;
-       info.platform_data = name;
-       strlcpy(info.type, ds1775 ? "wf_ds1775" : "wf_lm75", I2C_NAME_SIZE);
-
-       client = i2c_new_device(adapter, &info);
-       if (client == NULL) {
-               printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n",
-                      ds1775 ? "ds1775" : "lm75", name);
-               goto fail;
-       }
-
-       /*
-        * Let i2c-core delete that device on driver removal.
-        * This is safe because i2c-core holds the core_lock mutex for us.
-        */
-       list_add_tail(&client->detected, &wf_lm75_driver.clients);
-       return client;
- fail:
-       return NULL;
-}
-
-static int wf_lm75_attach(struct i2c_adapter *adapter)
-{
-       struct device_node *busnode, *dev;
-       struct pmac_i2c_bus *bus;
+               return -ENXIO;
+       
 
-       DBG("wf_lm75: adapter %s detected\n", adapter->name);
-
-       bus = pmac_i2c_adapter_to_bus(adapter);
-       if (bus == NULL)
+       lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
+       if (lm == NULL)
                return -ENODEV;
-       busnode = pmac_i2c_get_bus_node(bus);
 
-       DBG("wf_lm75: bus found, looking for device...\n");
-
-       /* Now look for lm75(s) in there */
-       for (dev = NULL;
-            (dev = of_get_next_child(busnode, dev)) != NULL;) {
-               const char *loc =
-                       of_get_property(dev, "hwsensor-location", NULL);
-               u8 addr;
+       lm->inited = 0;
+       lm->ds1775 = ds1775;
+       lm->i2c = client;
+       lm->sens.name = (char *)name; /* XXX fix constness in structure */
+       lm->sens.ops = &wf_lm75_ops;
+       i2c_set_clientdata(client, lm);
 
-               /* We must re-match the adapter in order to properly check
-                * the channel on multibus setups
-                */
-               if (!pmac_i2c_match_adapter(dev, adapter))
-                       continue;
-               addr = pmac_i2c_get_dev_addr(dev);
-               if (loc == NULL || addr == 0)
-                       continue;
-               /* real lm75 */
-               if (of_device_is_compatible(dev, "lm75"))
-                       wf_lm75_create(adapter, addr, 0, loc);
-               /* ds1775 (compatible, better resolution */
-               else if (of_device_is_compatible(dev, "ds1775"))
-                       wf_lm75_create(adapter, addr, 1, loc);
-       }
-       return 0;
+       rc = wf_register_sensor(&lm->sens);
+       if (rc)
+               kfree(lm);
+       return rc;
 }
 
 static int wf_lm75_remove(struct i2c_client *client)
@@ -217,16 +159,16 @@ static int wf_lm75_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id wf_lm75_id[] = {
-       { "wf_lm75", 0 },
-       { "wf_ds1775", 1 },
+       { "MAC,lm75", 0 },
+       { "MAC,ds1775", 1 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, wf_lm75_id);
 
 static struct i2c_driver wf_lm75_driver = {
        .driver = {
                .name   = "wf_lm75",
        },
-       .attach_adapter = wf_lm75_attach,
        .probe          = wf_lm75_probe,
        .remove         = wf_lm75_remove,
        .id_table       = wf_lm75_id,
@@ -234,11 +176,6 @@ static struct i2c_driver wf_lm75_driver = {
 
 static int __init wf_lm75_sensor_init(void)
 {
-       /* Don't register on old machines that use therm_pm72 for now */
-       if (of_machine_is_compatible("PowerMac7,2") ||
-           of_machine_is_compatible("PowerMac7,3") ||
-           of_machine_is_compatible("RackMac3,1"))
-               return -ENODEV;
        return i2c_add_driver(&wf_lm75_driver);
 }
 
diff --git a/drivers/macintosh/windfarm_lm87_sensor.c b/drivers/macintosh/windfarm_lm87_sensor.c
new file mode 100644 (file)
index 0000000..c071aab
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Windfarm PowerMac thermal control. LM87 sensor
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+#include <asm/pmac_low_i2c.h>
+
+#include "windfarm.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)   printk(args)
+#else
+#define DBG(args...)   do { } while(0)
+#endif
+
+struct wf_lm87_sensor {
+       struct i2c_client       *i2c;
+       struct wf_sensor        sens;
+};
+#define wf_to_lm87(c) container_of(c, struct wf_lm87_sensor, sens)
+
+
+static int wf_lm87_read_reg(struct i2c_client *chip, int reg)
+{
+       int rc, tries = 0;
+       u8 buf;
+
+       for (;;) {
+               /* Set address */
+               buf = (u8)reg;
+               rc = i2c_master_send(chip, &buf, 1);
+               if (rc <= 0)
+                       goto error;
+               rc = i2c_master_recv(chip, &buf, 1);
+               if (rc <= 0)
+                       goto error;
+               return (int)buf;
+       error:
+               DBG("wf_lm87: Error reading LM87, retrying...\n");
+               if (++tries > 10) {
+                       printk(KERN_ERR "wf_lm87: Error reading LM87 !\n");
+                       return -EIO;
+               }
+               msleep(10);
+       }
+}
+
+static int wf_lm87_get(struct wf_sensor *sr, s32 *value)
+{
+       struct wf_lm87_sensor *lm = sr->priv;
+       s32 temp;
+
+       if (lm->i2c == NULL)
+               return -ENODEV;
+
+#define LM87_INT_TEMP          0x27
+
+       /* Read temperature register */
+       temp = wf_lm87_read_reg(lm->i2c, LM87_INT_TEMP);
+       if (temp < 0)
+               return temp;
+       *value = temp << 16;
+
+       return 0;
+}
+
+static void wf_lm87_release(struct wf_sensor *sr)
+{
+       struct wf_lm87_sensor *lm = wf_to_lm87(sr);
+
+       kfree(lm);
+}
+
+static struct wf_sensor_ops wf_lm87_ops = {
+       .get_value      = wf_lm87_get,
+       .release        = wf_lm87_release,
+       .owner          = THIS_MODULE,
+};
+
+static int wf_lm87_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{      
+       struct wf_lm87_sensor *lm;
+       const char *name = NULL, *loc;
+       struct device_node *np = NULL;
+       int rc;
+
+       /*
+        * The lm87 contains a whole pile of sensors, additionally,
+        * the Xserve G5 has several lm87's. However, for now we only
+        * care about the internal temperature sensor
+        */
+       while ((np = of_get_next_child(client->dev.of_node, np)) != NULL) {
+               if (strcmp(np->name, "int-temp"))
+                       continue;
+               loc = of_get_property(np, "location", NULL);
+               if (!loc)
+                       continue;
+               if (strstr(loc, "DIMM"))
+                       name = "dimms-temp";
+               else if (strstr(loc, "Processors"))
+                       name = "between-cpus-temp";
+               if (name) {
+                       of_node_put(np);
+                       break;
+               }
+       }
+       if (!name) {
+               pr_warning("wf_lm87: Unsupported sensor %s\n",
+                          client->dev.of_node->full_name);
+               return -ENODEV;
+       }
+
+       lm = kzalloc(sizeof(struct wf_lm87_sensor), GFP_KERNEL);
+       if (lm == NULL)
+               return -ENODEV;
+
+       lm->i2c = client;
+       lm->sens.name = name;
+       lm->sens.ops = &wf_lm87_ops;
+       lm->sens.priv = lm;
+       i2c_set_clientdata(client, lm);
+
+       rc = wf_register_sensor(&lm->sens);
+       if (rc)
+               kfree(lm);
+       return rc;
+}
+
+static int wf_lm87_remove(struct i2c_client *client)
+{
+       struct wf_lm87_sensor *lm = i2c_get_clientdata(client);
+
+       DBG("wf_lm87: i2c detatch called for %s\n", lm->sens.name);
+
+       /* Mark client detached */
+       lm->i2c = NULL;
+
+       /* release sensor */
+       wf_unregister_sensor(&lm->sens);
+
+       return 0;
+}
+
+static const struct i2c_device_id wf_lm87_id[] = {
+       { "MAC,lm87cimt", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wf_lm87_id);
+
+static struct i2c_driver wf_lm87_driver = {
+       .driver = {
+               .name   = "wf_lm87",
+       },
+       .probe          = wf_lm87_probe,
+       .remove         = wf_lm87_remove,
+       .id_table       = wf_lm87_id,
+};
+
+static int __init wf_lm87_sensor_init(void)
+{
+       /* We only support this on the Xserve */
+       if (!of_machine_is_compatible("RackMac3,1"))
+               return -ENODEV;
+
+       return i2c_add_driver(&wf_lm87_driver);
+}
+
+static void __exit wf_lm87_sensor_exit(void)
+{
+       i2c_del_driver(&wf_lm87_driver);
+}
+
+
+module_init(wf_lm87_sensor_init);
+module_exit(wf_lm87_sensor_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("LM87 sensor objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
index 8204113268f471db6021ffa7915be03272a0c40c..371b058d2f7d9565a4dada1a8bd99616ec30ec50 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "windfarm.h"
 
-#define VERSION "0.2"
+#define VERSION "1.0"
 
 /* This currently only exports the external temperature sensor,
    since that's all the control loops need. */
@@ -64,9 +64,29 @@ static struct wf_sensor_ops wf_max6690_ops = {
 static int wf_max6690_probe(struct i2c_client *client,
                            const struct i2c_device_id *id)
 {
+       const char *name, *loc;
        struct wf_6690_sensor *max;
        int rc;
 
+       loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+       if (!loc) {
+               dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+               return -ENXIO;
+       }
+
+       /*
+        * We only expose the external temperature register for
+        * now as this is all we need for our control loops
+        */
+       if (!strcmp(loc, "BACKSIDE") || !strcmp(loc, "SYS CTRLR AMBIENT"))
+               name = "backside-temp";
+       else if (!strcmp(loc, "NB Ambient"))
+               name = "north-bridge-temp";
+       else if (!strcmp(loc, "GPU Ambient"))
+               name = "gpu-temp";
+       else
+               return -ENXIO;
+
        max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
        if (max == NULL) {
                printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: "
@@ -75,90 +95,16 @@ static int wf_max6690_probe(struct i2c_client *client,
        }
 
        max->i2c = client;
-       max->sens.name = client->dev.platform_data;
+       max->sens.name = (char *)name; /* XXX fix constness in structure */
        max->sens.ops = &wf_max6690_ops;
        i2c_set_clientdata(client, max);
 
        rc = wf_register_sensor(&max->sens);
-       if (rc) {
+       if (rc)
                kfree(max);
-       }
-
        return rc;
 }
 
-static struct i2c_driver wf_max6690_driver;
-
-static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter,
-                                           u8 addr, const char *loc)
-{
-       struct i2c_board_info info;
-       struct i2c_client *client;
-       char *name;
-
-       if (!strcmp(loc, "BACKSIDE"))
-               name = "backside-temp";
-       else if (!strcmp(loc, "NB Ambient"))
-               name = "north-bridge-temp";
-       else if (!strcmp(loc, "GPU Ambient"))
-               name = "gpu-temp";
-       else
-               goto fail;
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = addr >> 1;
-       info.platform_data = name;
-       strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE);
-
-       client = i2c_new_device(adapter, &info);
-       if (client == NULL) {
-               printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n");
-               goto fail;
-       }
-
-       /*
-        * Let i2c-core delete that device on driver removal.
-        * This is safe because i2c-core holds the core_lock mutex for us.
-        */
-       list_add_tail(&client->detected, &wf_max6690_driver.clients);
-       return client;
-
- fail:
-       return NULL;
-}
-
-static int wf_max6690_attach(struct i2c_adapter *adapter)
-{
-       struct device_node *busnode, *dev = NULL;
-       struct pmac_i2c_bus *bus;
-       const char *loc;
-
-       bus = pmac_i2c_adapter_to_bus(adapter);
-       if (bus == NULL)
-               return -ENODEV;
-       busnode = pmac_i2c_get_bus_node(bus);
-
-       while ((dev = of_get_next_child(busnode, dev)) != NULL) {
-               u8 addr;
-
-               /* We must re-match the adapter in order to properly check
-                * the channel on multibus setups
-                */
-               if (!pmac_i2c_match_adapter(dev, adapter))
-                       continue;
-               if (!of_device_is_compatible(dev, "max6690"))
-                       continue;
-               addr = pmac_i2c_get_dev_addr(dev);
-               loc = of_get_property(dev, "hwsensor-location", NULL);
-               if (loc == NULL || addr == 0)
-                       continue;
-               printk("found max6690, loc=%s addr=0x%02x\n", loc, addr);
-               wf_max6690_create(adapter, addr, loc);
-       }
-
-       return 0;
-}
-
 static int wf_max6690_remove(struct i2c_client *client)
 {
        struct wf_6690_sensor *max = i2c_get_clientdata(client);
@@ -170,15 +116,15 @@ static int wf_max6690_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id wf_max6690_id[] = {
-       { "wf_max6690", 0 },
+       { "MAC,max6690", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, wf_max6690_id);
 
 static struct i2c_driver wf_max6690_driver = {
        .driver = {
                .name           = "wf_max6690",
        },
-       .attach_adapter = wf_max6690_attach,
        .probe          = wf_max6690_probe,
        .remove         = wf_max6690_remove,
        .id_table       = wf_max6690_id,
@@ -186,11 +132,6 @@ static struct i2c_driver wf_max6690_driver = {
 
 static int __init wf_max6690_sensor_init(void)
 {
-       /* Don't register on old machines that use therm_pm72 for now */
-       if (of_machine_is_compatible("PowerMac7,2") ||
-           of_machine_is_compatible("PowerMac7,3") ||
-           of_machine_is_compatible("RackMac3,1"))
-               return -ENODEV;
        return i2c_add_driver(&wf_max6690_driver);
 }
 
diff --git a/drivers/macintosh/windfarm_mpu.h b/drivers/macintosh/windfarm_mpu.h
new file mode 100644 (file)
index 0000000..046edc8
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Windfarm PowerMac thermal control
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#ifndef __WINDFARM_MPU_H
+#define __WINDFARM_MPU_H
+
+typedef unsigned short fu16;
+typedef int fs32;
+typedef short fs16;
+
+/* Definition of the MPU data structure which contains per CPU
+ * calibration information (among others) for the G5 machines
+ */
+struct mpu_data
+{
+       u8      signature;              /* 0x00 - EEPROM sig. */
+       u8      bytes_used;             /* 0x01 - Bytes used in eeprom (160 ?) */
+       u8      size;                   /* 0x02 - EEPROM size (256 ?) */
+       u8      version;                /* 0x03 - EEPROM version */
+       u32     data_revision;          /* 0x04 - Dataset revision */
+       u8      processor_bin_code[3];  /* 0x08 - Processor BIN code */
+       u8      bin_code_expansion;     /* 0x0b - ??? (padding ?) */
+       u8      processor_num;          /* 0x0c - Number of CPUs on this MPU */
+       u8      input_mul_bus_div;      /* 0x0d - Clock input multiplier/bus divider */
+       u8      reserved1[2];           /* 0x0e - */
+       u32     input_clk_freq_high;    /* 0x10 - Input clock frequency high */
+       u8      cpu_nb_target_cycles;   /* 0x14 - ??? */
+       u8      cpu_statlat;            /* 0x15 - ??? */
+       u8      cpu_snooplat;           /* 0x16 - ??? */
+       u8      cpu_snoopacc;           /* 0x17 - ??? */
+       u8      nb_paamwin;             /* 0x18 - ??? */
+       u8      nb_statlat;             /* 0x19 - ??? */
+       u8      nb_snooplat;            /* 0x1a - ??? */
+       u8      nb_snoopwin;            /* 0x1b - ??? */
+       u8      api_bus_mode;           /* 0x1c - ??? */
+       u8      reserved2[3];           /* 0x1d - */
+       u32     input_clk_freq_low;     /* 0x20 - Input clock frequency low */
+       u8      processor_card_slot;    /* 0x24 - Processor card slot number */
+       u8      reserved3[2];           /* 0x25 - */
+       u8      padjmax;                /* 0x27 - Max power adjustment (Not in OF!) */
+       u8      ttarget;                /* 0x28 - Target temperature */
+       u8      tmax;                   /* 0x29 - Max temperature */
+       u8      pmaxh;                  /* 0x2a - Max power */
+       u8      tguardband;             /* 0x2b - Guardband temp ??? Hist. len in OSX */
+       fs32    pid_gp;                 /* 0x2c - PID proportional gain */
+       fs32    pid_gr;                 /* 0x30 - PID reset gain */
+       fs32    pid_gd;                 /* 0x34 - PID derivative gain */
+       fu16    voph;                   /* 0x38 - Vop High */
+       fu16    vopl;                   /* 0x3a - Vop Low */
+       fs16    nactual_die;            /* 0x3c - nActual Die */
+       fs16    nactual_heatsink;       /* 0x3e - nActual Heatsink */
+       fs16    nactual_system;         /* 0x40 - nActual System */
+       u16     calibration_flags;      /* 0x42 - Calibration flags */
+       fu16    mdiode;                 /* 0x44 - Diode M value (scaling factor) */
+       fs16    bdiode;                 /* 0x46 - Diode B value (offset) */
+       fs32    theta_heat_sink;        /* 0x48 - Theta heat sink */
+       u16     rminn_intake_fan;       /* 0x4c - Intake fan min RPM */
+       u16     rmaxn_intake_fan;       /* 0x4e - Intake fan max RPM */
+       u16     rminn_exhaust_fan;      /* 0x50 - Exhaust fan min RPM */
+       u16     rmaxn_exhaust_fan;      /* 0x52 - Exhaust fan max RPM */
+       u8      processor_part_num[8];  /* 0x54 - Processor part number XX pumps min/max */
+       u32     processor_lot_num;      /* 0x5c - Processor lot number */
+       u8      orig_card_sernum[0x10]; /* 0x60 - Card original serial number */
+       u8      curr_card_sernum[0x10]; /* 0x70 - Card current serial number */
+       u8      mlb_sernum[0x18];       /* 0x80 - MLB serial number */
+       u32     checksum1;              /* 0x98 - */
+       u32     checksum2;              /* 0x9c - */    
+}; /* Total size = 0xa0 */
+
+static inline const struct mpu_data *wf_get_mpu(int cpu)
+{
+       struct device_node *np;
+       char nodename[64];
+       const void *data;
+       int len;
+
+       /*
+        * prom.c routine for finding a node by path is a bit brain dead
+        * and requires exact @xxx unit numbers. This is a bit ugly but
+        * will work for these machines
+        */
+       sprintf(nodename, "/u3@0,f8000000/i2c@f8001000/cpuid@a%d", cpu ? 2 : 0);
+       np = of_find_node_by_path(nodename);
+       if (!np)
+               return NULL;
+       data = of_get_property(np, "cpuid", &len);      
+       of_node_put(np);
+       if (!data)
+               return NULL;
+
+       /*
+        * We are naughty, we have dropped the reference to the device
+        * node and still return a pointer to the content. We know we
+        * can do that though as this is only ever called on PowerMac
+        * which cannot remove those nodes
+        */
+       return data;
+}
+
+#endif /*  __WINDFARM_MPU_H */
diff --git a/drivers/macintosh/windfarm_pm72.c b/drivers/macintosh/windfarm_pm72.c
new file mode 100644 (file)
index 0000000..84ac913
--- /dev/null
@@ -0,0 +1,847 @@
+/*
+ * Windfarm PowerMac thermal control.
+ * Control loops for PowerMac7,2 and 7,3
+ *
+ * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Use and redistribute under the terms of the GNU GPL v2.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <asm/prom.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+#undef LOTSA_DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)   printk(args)
+#else
+#define DBG(args...)   do { } while(0)
+#endif
+
+#ifdef LOTSA_DEBUG
+#define DBG_LOTS(args...)      printk(args)
+#else
+#define DBG_LOTS(args...)      do { } while(0)
+#endif
+
+/* define this to force CPU overtemp to 60 degree, useful for testing
+ * the overtemp code
+ */
+#undef HACKED_OVERTEMP
+
+/* We currently only handle 2 chips */
+#define NR_CHIPS       2
+#define NR_CPU_FANS    3 * NR_CHIPS
+
+/* Controls and sensors */
+static struct wf_sensor *sens_cpu_temp[NR_CHIPS];
+static struct wf_sensor *sens_cpu_volts[NR_CHIPS];
+static struct wf_sensor *sens_cpu_amps[NR_CHIPS];
+static struct wf_sensor *backside_temp;
+static struct wf_sensor *drives_temp;
+
+static struct wf_control *cpu_front_fans[NR_CHIPS];
+static struct wf_control *cpu_rear_fans[NR_CHIPS];
+static struct wf_control *cpu_pumps[NR_CHIPS];
+static struct wf_control *backside_fan;
+static struct wf_control *drives_fan;
+static struct wf_control *slots_fan;
+static struct wf_control *cpufreq_clamp;
+
+/* We keep a temperature history for average calculation of 180s */
+#define CPU_TEMP_HIST_SIZE     180
+
+/* Fixed speed for slot fan */
+#define        SLOTS_FAN_DEFAULT_PWM   40
+
+/* Scale value for CPU intake fans */
+#define CPU_INTAKE_SCALE       0x0000f852
+
+/* PID loop state */
+static const struct mpu_data *cpu_mpu_data[NR_CHIPS];
+static struct wf_cpu_pid_state cpu_pid[NR_CHIPS];
+static bool cpu_pid_combined;
+static u32 cpu_thist[CPU_TEMP_HIST_SIZE];
+static int cpu_thist_pt;
+static s64 cpu_thist_total;
+static s32 cpu_all_tmax = 100 << 16;
+static struct wf_pid_state backside_pid;
+static int backside_tick;
+static struct wf_pid_state drives_pid;
+static int drives_tick;
+
+static int nr_chips;
+static bool have_all_controls;
+static bool have_all_sensors;
+static bool started;
+
+static int failure_state;
+#define FAILURE_SENSOR         1
+#define FAILURE_FAN            2
+#define FAILURE_PERM           4
+#define FAILURE_LOW_OVERTEMP   8
+#define FAILURE_HIGH_OVERTEMP  16
+
+/* Overtemp values */
+#define LOW_OVER_AVERAGE       0
+#define LOW_OVER_IMMEDIATE     (10 << 16)
+#define LOW_OVER_CLEAR         ((-10) << 16)
+#define HIGH_OVER_IMMEDIATE    (14 << 16)
+#define HIGH_OVER_AVERAGE      (10 << 16)
+#define HIGH_OVER_IMMEDIATE    (14 << 16)
+
+
+static void cpu_max_all_fans(void)
+{
+       int i;
+
+       /* We max all CPU fans in case of a sensor error. We also do the
+        * cpufreq clamping now, even if it's supposedly done later by the
+        * generic code anyway, we do it earlier here to react faster
+        */
+       if (cpufreq_clamp)
+               wf_control_set_max(cpufreq_clamp);
+       for (i = 0; i < nr_chips; i++) {
+               if (cpu_front_fans[i])
+                       wf_control_set_max(cpu_front_fans[i]);
+               if (cpu_rear_fans[i])
+                       wf_control_set_max(cpu_rear_fans[i]);
+               if (cpu_pumps[i])
+                       wf_control_set_max(cpu_pumps[i]);
+       }
+}
+
+static int cpu_check_overtemp(s32 temp)
+{
+       int new_state = 0;
+       s32 t_avg, t_old;
+       static bool first = true;
+
+       /* First check for immediate overtemps */
+       if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) {
+               new_state |= FAILURE_LOW_OVERTEMP;
+               if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+                       printk(KERN_ERR "windfarm: Overtemp due to immediate CPU"
+                              " temperature !\n");
+       }
+       if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) {
+               new_state |= FAILURE_HIGH_OVERTEMP;
+               if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+                       printk(KERN_ERR "windfarm: Critical overtemp due to"
+                              " immediate CPU temperature !\n");
+       }
+
+       /*
+        * The first time around, initialize the array with the first
+        * temperature reading
+        */
+       if (first) {
+               int i;
+
+               cpu_thist_total = 0;
+               for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) {
+                       cpu_thist[i] = temp;
+                       cpu_thist_total += temp;
+               }
+               first = false;
+       }
+
+       /*
+        * We calculate a history of max temperatures and use that for the
+        * overtemp management
+        */
+       t_old = cpu_thist[cpu_thist_pt];
+       cpu_thist[cpu_thist_pt] = temp;
+       cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE;
+       cpu_thist_total -= t_old;
+       cpu_thist_total += temp;
+       t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE;
+
+       DBG_LOTS("  t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n",
+                FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp));
+
+       /* Now check for average overtemps */
+       if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) {
+               new_state |= FAILURE_LOW_OVERTEMP;
+               if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+                       printk(KERN_ERR "windfarm: Overtemp due to average CPU"
+                              " temperature !\n");
+       }
+       if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) {
+               new_state |= FAILURE_HIGH_OVERTEMP;
+               if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+                       printk(KERN_ERR "windfarm: Critical overtemp due to"
+                              " average CPU temperature !\n");
+       }
+
+       /* Now handle overtemp conditions. We don't currently use the windfarm
+        * overtemp handling core as it's not fully suited to the needs of those
+        * new machine. This will be fixed later.
+        */
+       if (new_state) {
+               /* High overtemp -> immediate shutdown */
+               if (new_state & FAILURE_HIGH_OVERTEMP)
+                       machine_power_off();
+               if ((failure_state & new_state) != new_state)
+                       cpu_max_all_fans();
+               failure_state |= new_state;
+       } else if ((failure_state & FAILURE_LOW_OVERTEMP) &&
+                  (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) {
+               printk(KERN_ERR "windfarm: Overtemp condition cleared !\n");
+               failure_state &= ~FAILURE_LOW_OVERTEMP;
+       }
+
+       return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP);
+}
+
+static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power)
+{
+       s32 dtemp, volts, amps;
+       int rc;
+
+       /* Get diode temperature */
+       rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp);
+       if (rc) {
+               DBG("  CPU%d: temp reading error !\n", cpu);
+               return -EIO;
+       }
+       DBG_LOTS("  CPU%d: temp   = %d.%03d\n", cpu, FIX32TOPRINT((dtemp)));
+       *temp = dtemp;
+
+       /* Get voltage */
+       rc = wf_sensor_get(sens_cpu_volts[cpu], &volts);
+       if (rc) {
+               DBG("  CPU%d, volts reading error !\n", cpu);
+               return -EIO;
+       }
+       DBG_LOTS("  CPU%d: volts  = %d.%03d\n", cpu, FIX32TOPRINT((volts)));
+
+       /* Get current */
+       rc = wf_sensor_get(sens_cpu_amps[cpu], &amps);
+       if (rc) {
+               DBG("  CPU%d, current reading error !\n", cpu);
+               return -EIO;
+       }
+       DBG_LOTS("  CPU%d: amps   = %d.%03d\n", cpu, FIX32TOPRINT((amps)));
+
+       /* Calculate power */
+
+       /* Scale voltage and current raw sensor values according to fixed scales
+        * obtained in Darwin and calculate power from I and V
+        */
+       *power = (((u64)volts) * ((u64)amps)) >> 16;
+
+       DBG_LOTS("  CPU%d: power  = %d.%03d\n", cpu, FIX32TOPRINT((*power)));
+
+       return 0;
+
+}
+
+static void cpu_fans_tick_split(void)
+{
+       int err, cpu;
+       s32 intake, temp, power, t_max = 0;
+
+       DBG_LOTS("* cpu fans_tick_split()\n");
+
+       for (cpu = 0; cpu < nr_chips; ++cpu) {
+               struct wf_cpu_pid_state *sp = &cpu_pid[cpu];
+
+               /* Read current speed */
+               wf_control_get(cpu_rear_fans[cpu], &sp->target);
+
+               DBG_LOTS("  CPU%d: cur_target = %d RPM\n", cpu, sp->target);
+
+               err = read_one_cpu_vals(cpu, &temp, &power);
+               if (err) {
+                       failure_state |= FAILURE_SENSOR;
+                       cpu_max_all_fans();
+                       return;
+               }
+
+               /* Keep track of highest temp */
+               t_max = max(t_max, temp);
+
+               /* Handle possible overtemps */
+               if (cpu_check_overtemp(t_max))
+                       return;
+
+               /* Run PID */
+               wf_cpu_pid_run(sp, power, temp);
+
+               DBG_LOTS("  CPU%d: target = %d RPM\n", cpu, sp->target);
+
+               /* Apply result directly to exhaust fan */
+               err = wf_control_set(cpu_rear_fans[cpu], sp->target);
+               if (err) {
+                       pr_warning("wf_pm72: Fan %s reports error %d\n",
+                              cpu_rear_fans[cpu]->name, err);
+                       failure_state |= FAILURE_FAN;
+                       break;
+               }
+
+               /* Scale result for intake fan */
+               intake = (sp->target * CPU_INTAKE_SCALE) >> 16;
+               DBG_LOTS("  CPU%d: intake = %d RPM\n", cpu, intake);
+               err = wf_control_set(cpu_front_fans[cpu], intake);
+               if (err) {
+                       pr_warning("wf_pm72: Fan %s reports error %d\n",
+                              cpu_front_fans[cpu]->name, err);
+                       failure_state |= FAILURE_FAN;
+                       break;
+               }
+       }
+}
+
+static void cpu_fans_tick_combined(void)
+{
+       s32 temp0, power0, temp1, power1, t_max = 0;
+       s32 temp, power, intake, pump;
+       struct wf_control *pump0, *pump1;
+       struct wf_cpu_pid_state *sp = &cpu_pid[0];
+       int err, cpu;
+
+       DBG_LOTS("* cpu fans_tick_combined()\n");
+
+       /* Read current speed from cpu 0 */
+       wf_control_get(cpu_rear_fans[0], &sp->target);
+
+       DBG_LOTS("  CPUs: cur_target = %d RPM\n", sp->target);
+
+       /* Read values for both CPUs */
+       err = read_one_cpu_vals(0, &temp0, &power0);
+       if (err) {
+               failure_state |= FAILURE_SENSOR;
+               cpu_max_all_fans();
+               return;
+       }
+       err = read_one_cpu_vals(1, &temp1, &power1);
+       if (err) {
+               failure_state |= FAILURE_SENSOR;
+               cpu_max_all_fans();
+               return;
+       }
+
+       /* Keep track of highest temp */
+       t_max = max(t_max, max(temp0, temp1));
+
+       /* Handle possible overtemps */
+       if (cpu_check_overtemp(t_max))
+               return;
+
+       /* Use the max temp & power of both */
+       temp = max(temp0, temp1);
+       power = max(power0, power1);
+
+       /* Run PID */
+       wf_cpu_pid_run(sp, power, temp);
+
+       /* Scale result for intake fan */
+       intake = (sp->target * CPU_INTAKE_SCALE) >> 16;
+
+       /* Same deal with pump speed */
+       pump0 = cpu_pumps[0];
+       pump1 = cpu_pumps[1];
+       if (!pump0) {
+               pump0 = pump1;
+               pump1 = NULL;
+       }
+       pump = (sp->target * wf_control_get_max(pump0)) /
+               cpu_mpu_data[0]->rmaxn_exhaust_fan;
+
+       DBG_LOTS("  CPUs: target = %d RPM\n", sp->target);
+       DBG_LOTS("  CPUs: intake = %d RPM\n", intake);
+       DBG_LOTS("  CPUs: pump   = %d RPM\n", pump);
+
+       for (cpu = 0; cpu < nr_chips; cpu++) {
+               err = wf_control_set(cpu_rear_fans[cpu], sp->target);
+               if (err) {
+                       pr_warning("wf_pm72: Fan %s reports error %d\n",
+                                  cpu_rear_fans[cpu]->name, err);
+                       failure_state |= FAILURE_FAN;
+               }
+               err = wf_control_set(cpu_front_fans[cpu], intake);
+               if (err) {
+                       pr_warning("wf_pm72: Fan %s reports error %d\n",
+                                  cpu_front_fans[cpu]->name, err);
+                       failure_state |= FAILURE_FAN;
+               }
+               err = 0;
+               if (cpu_pumps[cpu])
+                       err = wf_control_set(cpu_pumps[cpu], pump);
+               if (err) {
+                       pr_warning("wf_pm72: Pump %s reports error %d\n",
+                                  cpu_pumps[cpu]->name, err);
+                       failure_state |= FAILURE_FAN;
+               }
+       }
+}
+
+/* Implementation... */
+static int cpu_setup_pid(int cpu)
+{
+       struct wf_cpu_pid_param pid;
+       const struct mpu_data *mpu = cpu_mpu_data[cpu];
+       s32 tmax, ttarget, ptarget;
+       int fmin, fmax, hsize;
+
+       /* Get PID params from the appropriate MPU EEPROM */
+       tmax = mpu->tmax << 16;
+       ttarget = mpu->ttarget << 16;
+       ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16;
+
+       DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n",
+           cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax));
+
+       /* We keep a global tmax for overtemp calculations */
+       if (tmax < cpu_all_tmax)
+               cpu_all_tmax = tmax;
+
+       /* Set PID min/max by using the rear fan min/max */
+       fmin = wf_control_get_min(cpu_rear_fans[cpu]);
+       fmax = wf_control_get_max(cpu_rear_fans[cpu]);
+       DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax);
+
+       /* History size */
+       hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY);
+       DBG("wf_72: CPU%d history size = %d\n", cpu, hsize);
+
+       /* Initialize PID loop */
+       pid.interval    = 1;    /* seconds */
+       pid.history_len = hsize;
+       pid.gd          = mpu->pid_gd;
+       pid.gp          = mpu->pid_gp;
+       pid.gr          = mpu->pid_gr;
+       pid.tmax        = tmax;
+       pid.ttarget     = ttarget;
+       pid.pmaxadj     = ptarget;
+       pid.min         = fmin;
+       pid.max         = fmax;
+
+       wf_cpu_pid_init(&cpu_pid[cpu], &pid);
+       cpu_pid[cpu].target = 1000;
+
+       return 0;
+}
+
+/* Backside/U3 fan */
+static struct wf_pid_param backside_u3_param = {
+       .interval       = 5,
+       .history_len    = 2,
+       .gd             = 40 << 20,
+       .gp             = 5 << 20,
+       .gr             = 0,
+       .itarget        = 65 << 16,
+       .additive       = 1,
+       .min            = 20,
+       .max            = 100,
+};
+
+static struct wf_pid_param backside_u3h_param = {
+       .interval       = 5,
+       .history_len    = 2,
+       .gd             = 20 << 20,
+       .gp             = 5 << 20,
+       .gr             = 0,
+       .itarget        = 75 << 16,
+       .additive       = 1,
+       .min            = 20,
+       .max            = 100,
+};
+
+static void backside_fan_tick(void)
+{
+       s32 temp;
+       int speed;
+       int err;
+
+       if (!backside_fan || !backside_temp || !backside_tick)
+               return;
+       if (--backside_tick > 0)
+               return;
+       backside_tick = backside_pid.param.interval;
+
+       DBG_LOTS("* backside fans tick\n");
+
+       /* Update fan speed from actual fans */
+       err = wf_control_get(backside_fan, &speed);
+       if (!err)
+               backside_pid.target = speed;
+
+       err = wf_sensor_get(backside_temp, &temp);
+       if (err) {
+               printk(KERN_WARNING "windfarm: U4 temp sensor error %d\n",
+                      err);
+               failure_state |= FAILURE_SENSOR;
+               wf_control_set_max(backside_fan);
+               return;
+       }
+       speed = wf_pid_run(&backside_pid, temp);
+
+       DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n",
+                FIX32TOPRINT(temp), speed);
+
+       err = wf_control_set(backside_fan, speed);
+       if (err) {
+               printk(KERN_WARNING "windfarm: backside fan error %d\n", err);
+               failure_state |= FAILURE_FAN;
+       }
+}
+
+static void backside_setup_pid(void)
+{
+       /* first time initialize things */
+       s32 fmin = wf_control_get_min(backside_fan);
+       s32 fmax = wf_control_get_max(backside_fan);
+       struct wf_pid_param param;
+       struct device_node *u3;
+       int u3h = 1; /* conservative by default */
+
+       u3 = of_find_node_by_path("/u3@0,f8000000");
+       if (u3 != NULL) {
+               const u32 *vers = of_get_property(u3, "device-rev", NULL);
+               if (vers)
+                       if (((*vers) & 0x3f) < 0x34)
+                               u3h = 0;
+               of_node_put(u3);
+       }
+
+       param = u3h ? backside_u3h_param : backside_u3_param;
+
+       param.min = max(param.min, fmin);
+       param.max = min(param.max, fmax);
+       wf_pid_init(&backside_pid, &param);
+       backside_tick = 1;
+
+       pr_info("wf_pm72: Backside control loop started.\n");
+}
+
+/* Drive bay fan */
+static const struct wf_pid_param drives_param = {
+       .interval       = 5,
+       .history_len    = 2,
+       .gd             = 30 << 20,
+       .gp             = 5 << 20,
+       .gr             = 0,
+       .itarget        = 40 << 16,
+       .additive       = 1,
+       .min            = 300,
+       .max            = 4000,
+};
+
+static void drives_fan_tick(void)
+{
+       s32 temp;
+       int speed;
+       int err;
+
+       if (!drives_fan || !drives_temp || !drives_tick)
+               return;
+       if (--drives_tick > 0)
+               return;
+       drives_tick = drives_pid.param.interval;
+
+       DBG_LOTS("* drives fans tick\n");
+
+       /* Update fan speed from actual fans */
+       err = wf_control_get(drives_fan, &speed);
+       if (!err)
+               drives_pid.target = speed;
+
+       err = wf_sensor_get(drives_temp, &temp);
+       if (err) {
+               pr_warning("wf_pm72: drive bay temp sensor error %d\n", err);
+               failure_state |= FAILURE_SENSOR;
+               wf_control_set_max(drives_fan);
+               return;
+       }
+       speed = wf_pid_run(&drives_pid, temp);
+
+       DBG_LOTS("drives PID temp=%d.%.3d speed=%d\n",
+                FIX32TOPRINT(temp), speed);
+
+       err = wf_control_set(drives_fan, speed);
+       if (err) {
+               printk(KERN_WARNING "windfarm: drive bay fan error %d\n", err);
+               failure_state |= FAILURE_FAN;
+       }
+}
+
+static void drives_setup_pid(void)
+{
+       /* first time initialize things */
+       s32 fmin = wf_control_get_min(drives_fan);
+       s32 fmax = wf_control_get_max(drives_fan);
+       struct wf_pid_param param = drives_param;
+
+       param.min = max(param.min, fmin);
+       param.max = min(param.max, fmax);
+       wf_pid_init(&drives_pid, &param);
+       drives_tick = 1;
+
+       pr_info("wf_pm72: Drive bay control loop started.\n");
+}
+
+static void set_fail_state(void)
+{
+       cpu_max_all_fans();
+
+       if (backside_fan)
+               wf_control_set_max(backside_fan);
+       if (slots_fan)
+               wf_control_set_max(slots_fan);
+       if (drives_fan)
+               wf_control_set_max(drives_fan);
+}
+
+static void pm72_tick(void)
+{
+       int i, last_failure;
+
+       if (!started) {
+               started = 1;
+               printk(KERN_INFO "windfarm: CPUs control loops started.\n");
+               for (i = 0; i < nr_chips; ++i) {
+                       if (cpu_setup_pid(i) < 0) {
+                               failure_state = FAILURE_PERM;
+                               set_fail_state();
+                               break;
+                       }
+               }
+               DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax));
+
+               backside_setup_pid();
+               drives_setup_pid();
+
+               /*
+                * We don't have the right stuff to drive the PCI fan
+                * so we fix it to a default value
+                */
+               wf_control_set(slots_fan, SLOTS_FAN_DEFAULT_PWM);
+
+#ifdef HACKED_OVERTEMP
+               cpu_all_tmax = 60 << 16;
+#endif
+       }
+
+       /* Permanent failure, bail out */
+       if (failure_state & FAILURE_PERM)
+               return;
+
+       /*
+        * Clear all failure bits except low overtemp which will be eventually
+        * cleared by the control loop itself
+        */
+       last_failure = failure_state;
+       failure_state &= FAILURE_LOW_OVERTEMP;
+       if (cpu_pid_combined)
+               cpu_fans_tick_combined();
+       else
+               cpu_fans_tick_split();
+       backside_fan_tick();
+       drives_fan_tick();
+
+       DBG_LOTS("  last_failure: 0x%x, failure_state: %x\n",
+                last_failure, failure_state);
+
+       /* Check for failures. Any failure causes cpufreq clamping */
+       if (failure_state && last_failure == 0 && cpufreq_clamp)
+               wf_control_set_max(cpufreq_clamp);
+       if (failure_state == 0 && last_failure && cpufreq_clamp)
+               wf_control_set_min(cpufreq_clamp);
+
+       /* That's it for now, we might want to deal with other failures
+        * differently in the future though
+        */
+}
+
+static void pm72_new_control(struct wf_control *ct)
+{
+       bool all_controls;
+       bool had_pump = cpu_pumps[0] || cpu_pumps[1];
+
+       if (!strcmp(ct->name, "cpu-front-fan-0"))
+               cpu_front_fans[0] = ct;
+       else if (!strcmp(ct->name, "cpu-front-fan-1"))
+               cpu_front_fans[1] = ct;
+       else if (!strcmp(ct->name, "cpu-rear-fan-0"))
+               cpu_rear_fans[0] = ct;
+       else if (!strcmp(ct->name, "cpu-rear-fan-1"))
+               cpu_rear_fans[1] = ct;
+       else if (!strcmp(ct->name, "cpu-pump-0"))
+               cpu_pumps[0] = ct;
+       else if (!strcmp(ct->name, "cpu-pump-1"))
+               cpu_pumps[1] = ct;
+       else if (!strcmp(ct->name, "backside-fan"))
+               backside_fan = ct;
+       else if (!strcmp(ct->name, "slots-fan"))
+               slots_fan = ct;
+       else if (!strcmp(ct->name, "drive-bay-fan"))
+               drives_fan = ct;
+       else if (!strcmp(ct->name, "cpufreq-clamp"))
+               cpufreq_clamp = ct;
+
+       all_controls =
+               cpu_front_fans[0] &&
+               cpu_rear_fans[0] &&
+               backside_fan &&
+               slots_fan &&
+               drives_fan;
+       if (nr_chips > 1)
+               all_controls &=
+                       cpu_front_fans[1] &&
+                       cpu_rear_fans[1];
+       have_all_controls = all_controls;
+
+       if ((cpu_pumps[0] || cpu_pumps[1]) && !had_pump) {
+               pr_info("wf_pm72: Liquid cooling pump(s) detected,"
+                       " using new algorithm !\n");
+               cpu_pid_combined = true;
+       }
+}
+
+
+static void pm72_new_sensor(struct wf_sensor *sr)
+{
+       bool all_sensors;
+
+       if (!strcmp(sr->name, "cpu-diode-temp-0"))
+               sens_cpu_temp[0] = sr;
+       else if (!strcmp(sr->name, "cpu-diode-temp-1"))
+               sens_cpu_temp[1] = sr;
+       else if (!strcmp(sr->name, "cpu-voltage-0"))
+               sens_cpu_volts[0] = sr;
+       else if (!strcmp(sr->name, "cpu-voltage-1"))
+               sens_cpu_volts[1] = sr;
+       else if (!strcmp(sr->name, "cpu-current-0"))
+               sens_cpu_amps[0] = sr;
+       else if (!strcmp(sr->name, "cpu-current-1"))
+               sens_cpu_amps[1] = sr;
+       else if (!strcmp(sr->name, "backside-temp"))
+               backside_temp = sr;
+       else if (!strcmp(sr->name, "hd-temp"))
+               drives_temp = sr;
+
+       all_sensors =
+               sens_cpu_temp[0] &&
+               sens_cpu_volts[0] &&
+               sens_cpu_amps[0] &&
+               backside_temp &&
+               drives_temp;
+       if (nr_chips > 1)
+               all_sensors &=
+                       sens_cpu_temp[1] &&
+                       sens_cpu_volts[1] &&
+                       sens_cpu_amps[1];
+
+       have_all_sensors = all_sensors;
+}
+
+static int pm72_wf_notify(struct notifier_block *self,
+                         unsigned long event, void *data)
+{
+       switch (event) {
+       case WF_EVENT_NEW_SENSOR:
+               pm72_new_sensor(data);
+               break;
+       case WF_EVENT_NEW_CONTROL:
+               pm72_new_control(data);
+               break;
+       case WF_EVENT_TICK:
+               if (have_all_controls && have_all_sensors)
+                       pm72_tick();
+       }
+       return 0;
+}
+
+static struct notifier_block pm72_events = {
+       .notifier_call = pm72_wf_notify,
+};
+
+static int wf_pm72_probe(struct platform_device *dev)
+{
+       wf_register_client(&pm72_events);
+       return 0;
+}
+
+static int __devexit wf_pm72_remove(struct platform_device *dev)
+{
+       wf_unregister_client(&pm72_events);
+
+       /* should release all sensors and controls */
+       return 0;
+}
+
+static struct platform_driver wf_pm72_driver = {
+       .probe  = wf_pm72_probe,
+       .remove = wf_pm72_remove,
+       .driver = {
+               .name = "windfarm",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init wf_pm72_init(void)
+{
+       struct device_node *cpu;
+       int i;
+
+       if (!of_machine_is_compatible("PowerMac7,2") &&
+           !of_machine_is_compatible("PowerMac7,3"))
+               return -ENODEV;
+
+       /* Count the number of CPU cores */
+       nr_chips = 0;
+       for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+               ++nr_chips;
+       if (nr_chips > NR_CHIPS)
+               nr_chips = NR_CHIPS;
+
+       pr_info("windfarm: Initializing for desktop G5 with %d chips\n",
+               nr_chips);
+
+       /* Get MPU data for each CPU */
+       for (i = 0; i < nr_chips; i++) {
+               cpu_mpu_data[i] = wf_get_mpu(i);
+               if (!cpu_mpu_data[i]) {
+                       pr_err("wf_pm72: Failed to find MPU data for CPU %d\n", i);
+                       return -ENXIO;
+               }
+       }
+
+#ifdef MODULE
+       request_module("windfarm_fcu_controls");
+       request_module("windfarm_lm75_sensor");
+       request_module("windfarm_ad7417_sensor");
+       request_module("windfarm_max6690_sensor");
+       request_module("windfarm_cpufreq_clamp");
+#endif /* MODULE */
+
+       platform_driver_register(&wf_pm72_driver);
+       return 0;
+}
+
+static void __exit wf_pm72_exit(void)
+{
+       platform_driver_unregister(&wf_pm72_driver);
+}
+
+module_init(wf_pm72_init);
+module_exit(wf_pm72_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Thermal control for AGP PowerMac G5s");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:windfarm");
index fc13d0f2663bb2475ca4a97a9e43d84302a48162..990c87606be9579db02549c765a05b9ebb82ee5c 100644 (file)
@@ -302,13 +302,13 @@ static void wf_smu_create_sys_fans(void)
        pid_param.interval = WF_SMU_SYS_FANS_INTERVAL;
        pid_param.history_len = WF_SMU_SYS_FANS_HISTORY_SIZE;
        pid_param.itarget = param->itarget;
-       pid_param.min = fan_system->ops->get_min(fan_system);
-       pid_param.max = fan_system->ops->get_max(fan_system);
+       pid_param.min = wf_control_get_min(fan_system);
+       pid_param.max = wf_control_get_max(fan_system);
        if (fan_hd) {
                pid_param.min =
-                       max(pid_param.min,fan_hd->ops->get_min(fan_hd));
+                       max(pid_param.min, wf_control_get_min(fan_hd));
                pid_param.max =
-                       min(pid_param.max,fan_hd->ops->get_max(fan_hd));
+                       min(pid_param.max, wf_control_get_max(fan_hd));
        }
        wf_pid_init(&wf_smu_sys_fans->pid, &pid_param);
 
@@ -337,7 +337,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
        }
        st->ticks = WF_SMU_SYS_FANS_INTERVAL;
 
-       rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
+       rc = wf_sensor_get(sensor_hd_temp, &temp);
        if (rc) {
                printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
                       rc);
@@ -373,7 +373,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
        st->hd_setpoint = new_setpoint;
  readjust:
        if (fan_system && wf_smu_failure_state == 0) {
-               rc = fan_system->ops->set_value(fan_system, st->sys_setpoint);
+               rc = wf_control_set(fan_system, st->sys_setpoint);
                if (rc) {
                        printk(KERN_WARNING "windfarm: Sys fan error %d\n",
                               rc);
@@ -381,7 +381,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
                }
        }
        if (fan_hd && wf_smu_failure_state == 0) {
-               rc = fan_hd->ops->set_value(fan_hd, st->hd_setpoint);
+               rc = wf_control_set(fan_hd, st->hd_setpoint);
                if (rc) {
                        printk(KERN_WARNING "windfarm: HD fan error %d\n",
                               rc);
@@ -447,8 +447,8 @@ static void wf_smu_create_cpu_fans(void)
        pid_param.ttarget = tmax - tdelta;
        pid_param.pmaxadj = maxpow - powadj;
 
-       pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
-       pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
+       pid_param.min = wf_control_get_min(fan_cpu_main);
+       pid_param.max = wf_control_get_max(fan_cpu_main);
 
        wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
 
@@ -481,7 +481,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
        }
        st->ticks = WF_SMU_CPU_FANS_INTERVAL;
 
-       rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+       rc = wf_sensor_get(sensor_cpu_temp, &temp);
        if (rc) {
                printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
                       rc);
@@ -489,7 +489,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
                return;
        }
 
-       rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+       rc = wf_sensor_get(sensor_cpu_power, &power);
        if (rc) {
                printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
                       rc);
@@ -525,8 +525,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
        st->cpu_setpoint = new_setpoint;
  readjust:
        if (fan_cpu_main && wf_smu_failure_state == 0) {
-               rc = fan_cpu_main->ops->set_value(fan_cpu_main,
-                                                 st->cpu_setpoint);
+               rc = wf_control_set(fan_cpu_main, st->cpu_setpoint);
                if (rc) {
                        printk(KERN_WARNING "windfarm: CPU main fan"
                               " error %d\n", rc);
index a9430ed4f36ce1c418f5e16ab7af4519bf60281c..7653603cb00eee8069eabf10d3a022e4b54a00ce 100644 (file)
@@ -192,8 +192,8 @@ static void wf_smu_create_cpu_fans(void)
        pid_param.ttarget = tmax - tdelta;
        pid_param.pmaxadj = maxpow - powadj;
 
-       pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
-       pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
+       pid_param.min = wf_control_get_min(fan_cpu_main);
+       pid_param.max = wf_control_get_max(fan_cpu_main);
 
        wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
 
@@ -226,7 +226,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
        }
        st->ticks = WF_SMU_CPU_FANS_INTERVAL;
 
-       rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+       rc = wf_sensor_get(sensor_cpu_temp, &temp);
        if (rc) {
                printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
                       rc);
@@ -234,7 +234,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
                return;
        }
 
-       rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+       rc = wf_sensor_get(sensor_cpu_power, &power);
        if (rc) {
                printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
                       rc);
@@ -261,8 +261,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
        st->cpu_setpoint = new_setpoint;
  readjust:
        if (fan_cpu_main && wf_smu_failure_state == 0) {
-               rc = fan_cpu_main->ops->set_value(fan_cpu_main,
-                                                 st->cpu_setpoint);
+               rc = wf_control_set(fan_cpu_main, st->cpu_setpoint);
                if (rc) {
                        printk(KERN_WARNING "windfarm: CPU main fan"
                               " error %d\n", rc);
@@ -270,8 +269,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
                }
        }
        if (fan_cpu_second && wf_smu_failure_state == 0) {
-               rc = fan_cpu_second->ops->set_value(fan_cpu_second,
-                                                   st->cpu_setpoint);
+               rc = wf_control_set(fan_cpu_second, st->cpu_setpoint);
                if (rc) {
                        printk(KERN_WARNING "windfarm: CPU second fan"
                               " error %d\n", rc);
@@ -279,8 +277,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
                }
        }
        if (fan_cpu_third && wf_smu_failure_state == 0) {
-               rc = fan_cpu_main->ops->set_value(fan_cpu_third,
-                                                 st->cpu_setpoint);
+               rc = wf_control_set(fan_cpu_third, st->cpu_setpoint);
                if (rc) {
                        printk(KERN_WARNING "windfarm: CPU third fan"
                               " error %d\n", rc);
@@ -312,8 +309,8 @@ static void wf_smu_create_drive_fans(void)
 
        /* Fill PID params */
        param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN);
-       param.min = fan_hd->ops->get_min(fan_hd);
-       param.max = fan_hd->ops->get_max(fan_hd);
+       param.min = wf_control_get_min(fan_hd);
+       param.max = wf_control_get_max(fan_hd);
        wf_pid_init(&wf_smu_drive_fans->pid, &param);
 
        DBG("wf: Drive Fan control initialized.\n");
@@ -338,7 +335,7 @@ static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st)
        }
        st->ticks = st->pid.param.interval;
 
-       rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
+       rc = wf_sensor_get(sensor_hd_temp, &temp);
        if (rc) {
                printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
                       rc);
@@ -361,7 +358,7 @@ static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st)
        st->setpoint = new_setpoint;
  readjust:
        if (fan_hd && wf_smu_failure_state == 0) {
-               rc = fan_hd->ops->set_value(fan_hd, st->setpoint);
+               rc = wf_control_set(fan_hd, st->setpoint);
                if (rc) {
                        printk(KERN_WARNING "windfarm: HD fan error %d\n",
                               rc);
@@ -393,8 +390,8 @@ static void wf_smu_create_slots_fans(void)
 
        /* Fill PID params */
        param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN);
-       param.min = fan_slots->ops->get_min(fan_slots);
-       param.max = fan_slots->ops->get_max(fan_slots);
+       param.min = wf_control_get_min(fan_slots);
+       param.max = wf_control_get_max(fan_slots);
        wf_pid_init(&wf_smu_slots_fans->pid, &param);
 
        DBG("wf: Slots Fan control initialized.\n");
@@ -419,7 +416,7 @@ static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
        }
        st->ticks = st->pid.param.interval;
 
-       rc = sensor_slots_power->ops->get_value(sensor_slots_power, &power);
+       rc = wf_sensor_get(sensor_slots_power, &power);
        if (rc) {
                printk(KERN_WARNING "windfarm: Slots power sensor error %d\n",
                       rc);
@@ -444,7 +441,7 @@ static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
        st->setpoint = new_setpoint;
  readjust:
        if (fan_slots && wf_smu_failure_state == 0) {
-               rc = fan_slots->ops->set_value(fan_slots, st->setpoint);
+               rc = wf_control_set(fan_slots, st->setpoint);
                if (rc) {
                        printk(KERN_WARNING "windfarm: Slots fan error %d\n",
                               rc);
diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c
new file mode 100644 (file)
index 0000000..3eca6d4
--- /dev/null
@@ -0,0 +1,740 @@
+/*
+ * Windfarm PowerMac thermal control.
+ * Control loops for RackMack3,1 (Xserve G5)
+ *
+ * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Use and redistribute under the terms of the GNU GPL v2.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <asm/prom.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+#undef LOTSA_DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)   printk(args)
+#else
+#define DBG(args...)   do { } while(0)
+#endif
+
+#ifdef LOTSA_DEBUG
+#define DBG_LOTS(args...)      printk(args)
+#else
+#define DBG_LOTS(args...)      do { } while(0)
+#endif
+
+/* define this to force CPU overtemp to 60 degree, useful for testing
+ * the overtemp code
+ */
+#undef HACKED_OVERTEMP
+
+/* We currently only handle 2 chips */
+#define NR_CHIPS       2
+#define NR_CPU_FANS    3 * NR_CHIPS
+
+/* Controls and sensors */
+static struct wf_sensor *sens_cpu_temp[NR_CHIPS];
+static struct wf_sensor *sens_cpu_volts[NR_CHIPS];
+static struct wf_sensor *sens_cpu_amps[NR_CHIPS];
+static struct wf_sensor *backside_temp;
+static struct wf_sensor *slots_temp;
+static struct wf_sensor *dimms_temp;
+
+static struct wf_control *cpu_fans[NR_CHIPS][3];
+static struct wf_control *backside_fan;
+static struct wf_control *slots_fan;
+static struct wf_control *cpufreq_clamp;
+
+/* We keep a temperature history for average calculation of 180s */
+#define CPU_TEMP_HIST_SIZE     180
+
+/* PID loop state */
+static const struct mpu_data *cpu_mpu_data[NR_CHIPS];
+static struct wf_cpu_pid_state cpu_pid[NR_CHIPS];
+static u32 cpu_thist[CPU_TEMP_HIST_SIZE];
+static int cpu_thist_pt;
+static s64 cpu_thist_total;
+static s32 cpu_all_tmax = 100 << 16;
+static struct wf_pid_state backside_pid;
+static int backside_tick;
+static struct wf_pid_state slots_pid;
+static int slots_tick;
+static int slots_speed;
+static struct wf_pid_state dimms_pid;
+static int dimms_output_clamp;
+
+static int nr_chips;
+static bool have_all_controls;
+static bool have_all_sensors;
+static bool started;
+
+static int failure_state;
+#define FAILURE_SENSOR         1
+#define FAILURE_FAN            2
+#define FAILURE_PERM           4
+#define FAILURE_LOW_OVERTEMP   8
+#define FAILURE_HIGH_OVERTEMP  16
+
+/* Overtemp values */
+#define LOW_OVER_AVERAGE       0
+#define LOW_OVER_IMMEDIATE     (10 << 16)
+#define LOW_OVER_CLEAR         ((-10) << 16)
+#define HIGH_OVER_IMMEDIATE    (14 << 16)
+#define HIGH_OVER_AVERAGE      (10 << 16)
+#define HIGH_OVER_IMMEDIATE    (14 << 16)
+
+
+static void cpu_max_all_fans(void)
+{
+       int i;
+
+       /* We max all CPU fans in case of a sensor error. We also do the
+        * cpufreq clamping now, even if it's supposedly done later by the
+        * generic code anyway, we do it earlier here to react faster
+        */
+       if (cpufreq_clamp)
+               wf_control_set_max(cpufreq_clamp);
+       for (i = 0; i < nr_chips; i++) {
+               if (cpu_fans[i][0])
+                       wf_control_set_max(cpu_fans[i][0]);
+               if (cpu_fans[i][1])
+                       wf_control_set_max(cpu_fans[i][1]);
+               if (cpu_fans[i][2])
+                       wf_control_set_max(cpu_fans[i][2]);
+       }
+}
+
+static int cpu_check_overtemp(s32 temp)
+{
+       int new_state = 0;
+       s32 t_avg, t_old;
+       static bool first = true;
+
+       /* First check for immediate overtemps */
+       if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) {
+               new_state |= FAILURE_LOW_OVERTEMP;
+               if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+                       printk(KERN_ERR "windfarm: Overtemp due to immediate CPU"
+                              " temperature !\n");
+       }
+       if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) {
+               new_state |= FAILURE_HIGH_OVERTEMP;
+               if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+                       printk(KERN_ERR "windfarm: Critical overtemp due to"
+                              " immediate CPU temperature !\n");
+       }
+
+       /*
+        * The first time around, initialize the array with the first
+        * temperature reading
+        */
+       if (first) {
+               int i;
+
+               cpu_thist_total = 0;
+               for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) {
+                       cpu_thist[i] = temp;
+                       cpu_thist_total += temp;
+               }
+               first = false;
+       }
+
+       /*
+        * We calculate a history of max temperatures and use that for the
+        * overtemp management
+        */
+       t_old = cpu_thist[cpu_thist_pt];
+       cpu_thist[cpu_thist_pt] = temp;
+       cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE;
+       cpu_thist_total -= t_old;
+       cpu_thist_total += temp;
+       t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE;
+
+       DBG_LOTS("  t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n",
+                FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp));
+
+       /* Now check for average overtemps */
+       if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) {
+               new_state |= FAILURE_LOW_OVERTEMP;
+               if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+                       printk(KERN_ERR "windfarm: Overtemp due to average CPU"
+                              " temperature !\n");
+       }
+       if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) {
+               new_state |= FAILURE_HIGH_OVERTEMP;
+               if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+                       printk(KERN_ERR "windfarm: Critical overtemp due to"
+                              " average CPU temperature !\n");
+       }
+
+       /* Now handle overtemp conditions. We don't currently use the windfarm
+        * overtemp handling core as it's not fully suited to the needs of those
+        * new machine. This will be fixed later.
+        */
+       if (new_state) {
+               /* High overtemp -> immediate shutdown */
+               if (new_state & FAILURE_HIGH_OVERTEMP)
+                       machine_power_off();
+               if ((failure_state & new_state) != new_state)
+                       cpu_max_all_fans();
+               failure_state |= new_state;
+       } else if ((failure_state & FAILURE_LOW_OVERTEMP) &&
+                  (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) {
+               printk(KERN_ERR "windfarm: Overtemp condition cleared !\n");
+               failure_state &= ~FAILURE_LOW_OVERTEMP;
+       }
+
+       return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP);
+}
+
+static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power)
+{
+       s32 dtemp, volts, amps;
+       int rc;
+
+       /* Get diode temperature */
+       rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp);
+       if (rc) {
+               DBG("  CPU%d: temp reading error !\n", cpu);
+               return -EIO;
+       }
+       DBG_LOTS("  CPU%d: temp   = %d.%03d\n", cpu, FIX32TOPRINT((dtemp)));
+       *temp = dtemp;
+
+       /* Get voltage */
+       rc = wf_sensor_get(sens_cpu_volts[cpu], &volts);
+       if (rc) {
+               DBG("  CPU%d, volts reading error !\n", cpu);
+               return -EIO;
+       }
+       DBG_LOTS("  CPU%d: volts  = %d.%03d\n", cpu, FIX32TOPRINT((volts)));
+
+       /* Get current */
+       rc = wf_sensor_get(sens_cpu_amps[cpu], &amps);
+       if (rc) {
+               DBG("  CPU%d, current reading error !\n", cpu);
+               return -EIO;
+       }
+       DBG_LOTS("  CPU%d: amps   = %d.%03d\n", cpu, FIX32TOPRINT((amps)));
+
+       /* Calculate power */
+
+       /* Scale voltage and current raw sensor values according to fixed scales
+        * obtained in Darwin and calculate power from I and V
+        */
+       *power = (((u64)volts) * ((u64)amps)) >> 16;
+
+       DBG_LOTS("  CPU%d: power  = %d.%03d\n", cpu, FIX32TOPRINT((*power)));
+
+       return 0;
+
+}
+
+static void cpu_fans_tick(void)
+{
+       int err, cpu, i;
+       s32 speed, temp, power, t_max = 0;
+
+       DBG_LOTS("* cpu fans_tick_split()\n");
+
+       for (cpu = 0; cpu < nr_chips; ++cpu) {
+               struct wf_cpu_pid_state *sp = &cpu_pid[cpu];
+
+               /* Read current speed */
+               wf_control_get(cpu_fans[cpu][0], &sp->target);
+
+               err = read_one_cpu_vals(cpu, &temp, &power);
+               if (err) {
+                       failure_state |= FAILURE_SENSOR;
+                       cpu_max_all_fans();
+                       return;
+               }
+
+               /* Keep track of highest temp */
+               t_max = max(t_max, temp);
+
+               /* Handle possible overtemps */
+               if (cpu_check_overtemp(t_max))
+                       return;
+
+               /* Run PID */
+               wf_cpu_pid_run(sp, power, temp);
+
+               DBG_LOTS("  CPU%d: target = %d RPM\n", cpu, sp->target);
+
+               /* Apply DIMMs clamp */
+               speed = max(sp->target, dimms_output_clamp);
+
+               /* Apply result to all cpu fans */
+               for (i = 0; i < 3; i++) {
+                       err = wf_control_set(cpu_fans[cpu][i], speed);
+                       if (err) {
+                               pr_warning("wf_rm31: Fan %s reports error %d\n",
+                                          cpu_fans[cpu][i]->name, err);
+                               failure_state |= FAILURE_FAN;
+                       }
+               }
+       }
+}
+
+/* Implementation... */
+static int cpu_setup_pid(int cpu)
+{
+       struct wf_cpu_pid_param pid;
+       const struct mpu_data *mpu = cpu_mpu_data[cpu];
+       s32 tmax, ttarget, ptarget;
+       int fmin, fmax, hsize;
+
+       /* Get PID params from the appropriate MPU EEPROM */
+       tmax = mpu->tmax << 16;
+       ttarget = mpu->ttarget << 16;
+       ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16;
+
+       DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n",
+           cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax));
+
+       /* We keep a global tmax for overtemp calculations */
+       if (tmax < cpu_all_tmax)
+               cpu_all_tmax = tmax;
+
+       /* Set PID min/max by using the rear fan min/max */
+       fmin = wf_control_get_min(cpu_fans[cpu][0]);
+       fmax = wf_control_get_max(cpu_fans[cpu][0]);
+       DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax);
+
+       /* History size */
+       hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY);
+       DBG("wf_72: CPU%d history size = %d\n", cpu, hsize);
+
+       /* Initialize PID loop */
+       pid.interval    = 1;    /* seconds */
+       pid.history_len = hsize;
+       pid.gd          = mpu->pid_gd;
+       pid.gp          = mpu->pid_gp;
+       pid.gr          = mpu->pid_gr;
+       pid.tmax        = tmax;
+       pid.ttarget     = ttarget;
+       pid.pmaxadj     = ptarget;
+       pid.min         = fmin;
+       pid.max         = fmax;
+
+       wf_cpu_pid_init(&cpu_pid[cpu], &pid);
+       cpu_pid[cpu].target = 4000;
+       
+       return 0;
+}
+
+/* Backside/U3 fan */
+static struct wf_pid_param backside_param = {
+       .interval       = 1,
+       .history_len    = 2,
+       .gd             = 0x00500000,
+       .gp             = 0x0004cccc,
+       .gr             = 0,
+       .itarget        = 70 << 16,
+       .additive       = 0,
+       .min            = 20,
+       .max            = 100,
+};
+
+/* DIMMs temperature (clamp the backside fan) */
+static struct wf_pid_param dimms_param = {
+       .interval       = 1,
+       .history_len    = 20,
+       .gd             = 0,
+       .gp             = 0,
+       .gr             = 0x06553600,
+       .itarget        = 50 << 16,
+       .additive       = 0,
+       .min            = 4000,
+       .max            = 14000,
+};
+
+static void backside_fan_tick(void)
+{
+       s32 temp, dtemp;
+       int speed, dspeed, fan_min;
+       int err;
+
+       if (!backside_fan || !backside_temp || !dimms_temp || !backside_tick)
+               return;
+       if (--backside_tick > 0)
+               return;
+       backside_tick = backside_pid.param.interval;
+
+       DBG_LOTS("* backside fans tick\n");
+
+       /* Update fan speed from actual fans */
+       err = wf_control_get(backside_fan, &speed);
+       if (!err)
+               backside_pid.target = speed;
+
+       err = wf_sensor_get(backside_temp, &temp);
+       if (err) {
+               printk(KERN_WARNING "windfarm: U3 temp sensor error %d\n",
+                      err);
+               failure_state |= FAILURE_SENSOR;
+               wf_control_set_max(backside_fan);
+               return;
+       }
+       speed = wf_pid_run(&backside_pid, temp);
+
+       DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n",
+                FIX32TOPRINT(temp), speed);
+
+       err = wf_sensor_get(dimms_temp, &dtemp);
+       if (err) {
+               printk(KERN_WARNING "windfarm: DIMMs temp sensor error %d\n",
+                      err);
+               failure_state |= FAILURE_SENSOR;
+               wf_control_set_max(backside_fan);
+               return;
+       }
+       dspeed = wf_pid_run(&dimms_pid, dtemp);
+       dimms_output_clamp = dspeed;
+
+       fan_min = (dspeed * 100) / 14000;
+       fan_min = max(fan_min, backside_param.min);
+       speed = max(speed, fan_min);
+
+       err = wf_control_set(backside_fan, speed);
+       if (err) {
+               printk(KERN_WARNING "windfarm: backside fan error %d\n", err);
+               failure_state |= FAILURE_FAN;
+       }
+}
+
+static void backside_setup_pid(void)
+{
+       /* first time initialize things */
+       s32 fmin = wf_control_get_min(backside_fan);
+       s32 fmax = wf_control_get_max(backside_fan);
+       struct wf_pid_param param;
+
+       param = backside_param;
+       param.min = max(param.min, fmin);
+       param.max = min(param.max, fmax);
+       wf_pid_init(&backside_pid, &param);
+
+       param = dimms_param;
+       wf_pid_init(&dimms_pid, &param);
+
+       backside_tick = 1;
+
+       pr_info("wf_rm31: Backside control loop started.\n");
+}
+
+/* Slots fan */
+static const struct wf_pid_param slots_param = {
+       .interval       = 5,
+       .history_len    = 2,
+       .gd             = 30 << 20,
+       .gp             = 5 << 20,
+       .gr             = 0,
+       .itarget        = 40 << 16,
+       .additive       = 1,
+       .min            = 300,
+       .max            = 4000,
+};
+
+static void slots_fan_tick(void)
+{
+       s32 temp;
+       int speed;
+       int err;
+
+       if (!slots_fan || !slots_temp || !slots_tick)
+               return;
+       if (--slots_tick > 0)
+               return;
+       slots_tick = slots_pid.param.interval;
+
+       DBG_LOTS("* slots fans tick\n");
+
+       err = wf_sensor_get(slots_temp, &temp);
+       if (err) {
+               pr_warning("wf_rm31: slots temp sensor error %d\n", err);
+               failure_state |= FAILURE_SENSOR;
+               wf_control_set_max(slots_fan);
+               return;
+       }
+       speed = wf_pid_run(&slots_pid, temp);
+
+       DBG_LOTS("slots PID temp=%d.%.3d speed=%d\n",
+                FIX32TOPRINT(temp), speed);
+
+       slots_speed = speed;
+       err = wf_control_set(slots_fan, speed);
+       if (err) {
+               printk(KERN_WARNING "windfarm: slots bay fan error %d\n", err);
+               failure_state |= FAILURE_FAN;
+       }
+}
+
+static void slots_setup_pid(void)
+{
+       /* first time initialize things */
+       s32 fmin = wf_control_get_min(slots_fan);
+       s32 fmax = wf_control_get_max(slots_fan);
+       struct wf_pid_param param = slots_param;
+
+       param.min = max(param.min, fmin);
+       param.max = min(param.max, fmax);
+       wf_pid_init(&slots_pid, &param);
+       slots_tick = 1;
+
+       pr_info("wf_rm31: Slots control loop started.\n");
+}
+
+static void set_fail_state(void)
+{
+       cpu_max_all_fans();
+
+       if (backside_fan)
+               wf_control_set_max(backside_fan);
+       if (slots_fan)
+               wf_control_set_max(slots_fan);
+}
+
+static void rm31_tick(void)
+{
+       int i, last_failure;
+
+       if (!started) {
+               started = 1;
+               printk(KERN_INFO "windfarm: CPUs control loops started.\n");
+               for (i = 0; i < nr_chips; ++i) {
+                       if (cpu_setup_pid(i) < 0) {
+                               failure_state = FAILURE_PERM;
+                               set_fail_state();
+                               break;
+                       }
+               }
+               DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax));
+
+               backside_setup_pid();
+               slots_setup_pid();
+
+#ifdef HACKED_OVERTEMP
+               cpu_all_tmax = 60 << 16;
+#endif
+       }
+
+       /* Permanent failure, bail out */
+       if (failure_state & FAILURE_PERM)
+               return;
+
+       /*
+        * Clear all failure bits except low overtemp which will be eventually
+        * cleared by the control loop itself
+        */
+       last_failure = failure_state;
+       failure_state &= FAILURE_LOW_OVERTEMP;
+       backside_fan_tick();
+       slots_fan_tick();
+
+       /* We do CPUs last because they can be clamped high by
+        * DIMM temperature
+        */
+       cpu_fans_tick();
+
+       DBG_LOTS("  last_failure: 0x%x, failure_state: %x\n",
+                last_failure, failure_state);
+
+       /* Check for failures. Any failure causes cpufreq clamping */
+       if (failure_state && last_failure == 0 && cpufreq_clamp)
+               wf_control_set_max(cpufreq_clamp);
+       if (failure_state == 0 && last_failure && cpufreq_clamp)
+               wf_control_set_min(cpufreq_clamp);
+
+       /* That's it for now, we might want to deal with other failures
+        * differently in the future though
+        */
+}
+
+static void rm31_new_control(struct wf_control *ct)
+{
+       bool all_controls;
+
+       if (!strcmp(ct->name, "cpu-fan-a-0"))
+               cpu_fans[0][0] = ct;
+       else if (!strcmp(ct->name, "cpu-fan-b-0"))
+               cpu_fans[0][1] = ct;
+       else if (!strcmp(ct->name, "cpu-fan-c-0"))
+               cpu_fans[0][2] = ct;
+       else if (!strcmp(ct->name, "cpu-fan-a-1"))
+               cpu_fans[1][0] = ct;
+       else if (!strcmp(ct->name, "cpu-fan-b-1"))
+               cpu_fans[1][1] = ct;
+       else if (!strcmp(ct->name, "cpu-fan-c-1"))
+               cpu_fans[1][2] = ct;
+       else if (!strcmp(ct->name, "backside-fan"))
+               backside_fan = ct;
+       else if (!strcmp(ct->name, "slots-fan"))
+               slots_fan = ct;
+       else if (!strcmp(ct->name, "cpufreq-clamp"))
+               cpufreq_clamp = ct;
+
+       all_controls =
+               cpu_fans[0][0] &&
+               cpu_fans[0][1] &&
+               cpu_fans[0][2] &&
+               backside_fan &&
+               slots_fan;
+       if (nr_chips > 1)
+               all_controls &=
+                       cpu_fans[1][0] &&
+                       cpu_fans[1][1] &&
+                       cpu_fans[1][2];
+       have_all_controls = all_controls;
+}
+
+
+static void rm31_new_sensor(struct wf_sensor *sr)
+{
+       bool all_sensors;
+
+       if (!strcmp(sr->name, "cpu-diode-temp-0"))
+               sens_cpu_temp[0] = sr;
+       else if (!strcmp(sr->name, "cpu-diode-temp-1"))
+               sens_cpu_temp[1] = sr;
+       else if (!strcmp(sr->name, "cpu-voltage-0"))
+               sens_cpu_volts[0] = sr;
+       else if (!strcmp(sr->name, "cpu-voltage-1"))
+               sens_cpu_volts[1] = sr;
+       else if (!strcmp(sr->name, "cpu-current-0"))
+               sens_cpu_amps[0] = sr;
+       else if (!strcmp(sr->name, "cpu-current-1"))
+               sens_cpu_amps[1] = sr;
+       else if (!strcmp(sr->name, "backside-temp"))
+               backside_temp = sr;
+       else if (!strcmp(sr->name, "slots-temp"))
+               slots_temp = sr;
+       else if (!strcmp(sr->name, "dimms-temp"))
+               dimms_temp = sr;
+
+       all_sensors =
+               sens_cpu_temp[0] &&
+               sens_cpu_volts[0] &&
+               sens_cpu_amps[0] &&
+               backside_temp &&
+               slots_temp &&
+               dimms_temp;
+       if (nr_chips > 1)
+               all_sensors &=
+                       sens_cpu_temp[1] &&
+                       sens_cpu_volts[1] &&
+                       sens_cpu_amps[1];
+
+       have_all_sensors = all_sensors;
+}
+
+static int rm31_wf_notify(struct notifier_block *self,
+                         unsigned long event, void *data)
+{
+       switch (event) {
+       case WF_EVENT_NEW_SENSOR:
+               rm31_new_sensor(data);
+               break;
+       case WF_EVENT_NEW_CONTROL:
+               rm31_new_control(data);
+               break;
+       case WF_EVENT_TICK:
+               if (have_all_controls && have_all_sensors)
+                       rm31_tick();
+       }
+       return 0;
+}
+
+static struct notifier_block rm31_events = {
+       .notifier_call = rm31_wf_notify,
+};
+
+static int wf_rm31_probe(struct platform_device *dev)
+{
+       wf_register_client(&rm31_events);
+       return 0;
+}
+
+static int __devexit wf_rm31_remove(struct platform_device *dev)
+{
+       wf_unregister_client(&rm31_events);
+
+       /* should release all sensors and controls */
+       return 0;
+}
+
+static struct platform_driver wf_rm31_driver = {
+       .probe  = wf_rm31_probe,
+       .remove = wf_rm31_remove,
+       .driver = {
+               .name = "windfarm",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init wf_rm31_init(void)
+{
+       struct device_node *cpu;
+       int i;
+
+       if (!of_machine_is_compatible("RackMac3,1"))
+               return -ENODEV;
+
+       /* Count the number of CPU cores */
+       nr_chips = 0;
+       for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+               ++nr_chips;
+       if (nr_chips > NR_CHIPS)
+               nr_chips = NR_CHIPS;
+
+       pr_info("windfarm: Initializing for desktop G5 with %d chips\n",
+               nr_chips);
+
+       /* Get MPU data for each CPU */
+       for (i = 0; i < nr_chips; i++) {
+               cpu_mpu_data[i] = wf_get_mpu(i);
+               if (!cpu_mpu_data[i]) {
+                       pr_err("wf_rm31: Failed to find MPU data for CPU %d\n", i);
+                       return -ENXIO;
+               }
+       }
+
+#ifdef MODULE
+       request_module("windfarm_fcu_controls");
+       request_module("windfarm_lm75_sensor");
+       request_module("windfarm_lm87_sensor");
+       request_module("windfarm_ad7417_sensor");
+       request_module("windfarm_max6690_sensor");
+       request_module("windfarm_cpufreq_clamp");
+#endif /* MODULE */
+
+       platform_driver_register(&wf_rm31_driver);
+       return 0;
+}
+
+static void __exit wf_rm31_exit(void)
+{
+       platform_driver_unregister(&wf_rm31_driver);
+}
+
+module_init(wf_rm31_init);
+module_exit(wf_rm31_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Thermal control for Xserve G5");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:windfarm");
index 3c2be5193fd585b12810916d0feffce7754b2fef..c155a54e8638f65d5da0b1a1507f9b27bfc222a5 100644 (file)
@@ -172,7 +172,6 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
 
        fct->fan_type = pwm_fan;
        fct->ctrl.type = pwm_fan ? WF_CONTROL_PWM_FAN : WF_CONTROL_RPM_FAN;
-       sysfs_attr_init(&fct->ctrl.attr.attr);
 
        /* We use the name & location here the same way we do for SMU sensors,
         * see the comment in windfarm_smu_sensors.c. The locations are a bit
index 65a8ff3e1f8e8d4e1e73a7a7eda4bb9500fb9c82..426e810233d7403595474f2a1e1ffa810daa141f 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "windfarm.h"
 
-#define VERSION "0.2"
+#define VERSION "1.0"
 
 #define DEBUG
 
 #define MAX_AGE                msecs_to_jiffies(800)
 
 struct wf_sat {
+       struct kref             ref;
        int                     nr;
-       atomic_t                refcnt;
        struct mutex            mutex;
        unsigned long           last_read; /* jiffies when cache last updated */
        u8                      cache[16];
+       struct list_head        sensors;
        struct i2c_client       *i2c;
        struct device_node      *node;
 };
@@ -46,11 +47,12 @@ struct wf_sat {
 static struct wf_sat *sats[2];
 
 struct wf_sat_sensor {
-       int             index;
-       int             index2;         /* used for power sensors */
-       int             shift;
-       struct wf_sat   *sat;
-       struct wf_sensor sens;
+       struct list_head        link;
+       int                     index;
+       int                     index2;         /* used for power sensors */
+       int                     shift;
+       struct wf_sat           *sat;
+       struct wf_sensor        sens;
 };
 
 #define wf_to_sat(c)   container_of(c, struct wf_sat_sensor, sens)
@@ -142,7 +144,7 @@ static int wf_sat_read_cache(struct wf_sat *sat)
        return 0;
 }
 
-static int wf_sat_get(struct wf_sensor *sr, s32 *value)
+static int wf_sat_sensor_get(struct wf_sensor *sr, s32 *value)
 {
        struct wf_sat_sensor *sens = wf_to_sat(sr);
        struct wf_sat *sat = sens->sat;
@@ -175,62 +177,34 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value)
        return err;
 }
 
-static void wf_sat_release(struct wf_sensor *sr)
+static void wf_sat_release(struct kref *ref)
+{
+       struct wf_sat *sat = container_of(ref, struct wf_sat, ref);
+
+       if (sat->nr >= 0)
+               sats[sat->nr] = NULL;
+       kfree(sat);
+}
+
+static void wf_sat_sensor_release(struct wf_sensor *sr)
 {
        struct wf_sat_sensor *sens = wf_to_sat(sr);
        struct wf_sat *sat = sens->sat;
 
-       if (atomic_dec_and_test(&sat->refcnt)) {
-               if (sat->nr >= 0)
-                       sats[sat->nr] = NULL;
-               kfree(sat);
-       }
        kfree(sens);
+       kref_put(&sat->ref, wf_sat_release);
 }
 
 static struct wf_sensor_ops wf_sat_ops = {
-       .get_value      = wf_sat_get,
-       .release        = wf_sat_release,
+       .get_value      = wf_sat_sensor_get,
+       .release        = wf_sat_sensor_release,
        .owner          = THIS_MODULE,
 };
 
-static struct i2c_driver wf_sat_driver;
-
-static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
-{
-       struct i2c_board_info info;
-       struct i2c_client *client;
-       const u32 *reg;
-       u8 addr;
-
-       reg = of_get_property(dev, "reg", NULL);
-       if (reg == NULL)
-               return;
-       addr = *reg;
-       DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr);
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = (addr >> 1) & 0x7f;
-       info.platform_data = dev;
-       strlcpy(info.type, "wf_sat", I2C_NAME_SIZE);
-
-       client = i2c_new_device(adapter, &info);
-       if (client == NULL) {
-               printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n");
-               return;
-       }
-
-       /*
-        * Let i2c-core delete that device on driver removal.
-        * This is safe because i2c-core holds the core_lock mutex for us.
-        */
-       list_add_tail(&client->detected, &wf_sat_driver.clients);
-}
-
 static int wf_sat_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
-       struct device_node *dev = client->dev.platform_data;
+       struct device_node *dev = client->dev.of_node;
        struct wf_sat *sat;
        struct wf_sat_sensor *sens;
        const u32 *reg;
@@ -246,9 +220,10 @@ static int wf_sat_probe(struct i2c_client *client,
                return -ENOMEM;
        sat->nr = -1;
        sat->node = of_node_get(dev);
-       atomic_set(&sat->refcnt, 0);
+       kref_init(&sat->ref);
        mutex_init(&sat->mutex);
        sat->i2c = client;
+       INIT_LIST_HEAD(&sat->sensors);
        i2c_set_clientdata(client, sat);
 
        vsens[0] = vsens[1] = -1;
@@ -310,14 +285,15 @@ static int wf_sat_probe(struct i2c_client *client,
                sens->index2 = -1;
                sens->shift = shift;
                sens->sat = sat;
-               atomic_inc(&sat->refcnt);
                sens->sens.ops = &wf_sat_ops;
                sens->sens.name = (char *) (sens + 1);
-               snprintf(sens->sens.name, 16, "%s-%d", name, cpu);
+               snprintf((char *)sens->sens.name, 16, "%s-%d", name, cpu);
 
-               if (wf_register_sensor(&sens->sens)) {
-                       atomic_dec(&sat->refcnt);
+               if (wf_register_sensor(&sens->sens))
                        kfree(sens);
+               else {
+                       list_add(&sens->link, &sat->sensors);
+                       kref_get(&sat->ref);
                }
        }
 
@@ -336,14 +312,15 @@ static int wf_sat_probe(struct i2c_client *client,
                sens->index2 = isens[core];
                sens->shift = 0;
                sens->sat = sat;
-               atomic_inc(&sat->refcnt);
                sens->sens.ops = &wf_sat_ops;
                sens->sens.name = (char *) (sens + 1);
-               snprintf(sens->sens.name, 16, "cpu-power-%d", cpu);
+               snprintf((char *)sens->sens.name, 16, "cpu-power-%d", cpu);
 
-               if (wf_register_sensor(&sens->sens)) {
-                       atomic_dec(&sat->refcnt);
+               if (wf_register_sensor(&sens->sens))
                        kfree(sens);
+               else {
+                       list_add(&sens->link, &sat->sensors);
+                       kref_get(&sat->ref);
                }
        }
 
@@ -353,42 +330,35 @@ static int wf_sat_probe(struct i2c_client *client,
        return 0;
 }
 
-static int wf_sat_attach(struct i2c_adapter *adapter)
-{
-       struct device_node *busnode, *dev = NULL;
-       struct pmac_i2c_bus *bus;
-
-       bus = pmac_i2c_adapter_to_bus(adapter);
-       if (bus == NULL)
-               return -ENODEV;
-       busnode = pmac_i2c_get_bus_node(bus);
-
-       while ((dev = of_get_next_child(busnode, dev)) != NULL)
-               if (of_device_is_compatible(dev, "smu-sat"))
-                       wf_sat_create(adapter, dev);
-       return 0;
-}
-
 static int wf_sat_remove(struct i2c_client *client)
 {
        struct wf_sat *sat = i2c_get_clientdata(client);
+       struct wf_sat_sensor *sens;
 
-       /* XXX TODO */
-
+       /* release sensors */
+       while(!list_empty(&sat->sensors)) {
+               sens = list_first_entry(&sat->sensors,
+                                       struct wf_sat_sensor, link);
+               list_del(&sens->link);
+               wf_unregister_sensor(&sens->sens);
+       }
        sat->i2c = NULL;
+       i2c_set_clientdata(client, NULL);
+       kref_put(&sat->ref, wf_sat_release);
+
        return 0;
 }
 
 static const struct i2c_device_id wf_sat_id[] = {
-       { "wf_sat", 0 },
+       { "MAC,smu-sat", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, wf_sat_id);
 
 static struct i2c_driver wf_sat_driver = {
        .driver = {
                .name           = "wf_smu_sat",
        },
-       .attach_adapter = wf_sat_attach,
        .probe          = wf_sat_probe,
        .remove         = wf_sat_remove,
        .id_table       = wf_sat_id,
@@ -399,15 +369,13 @@ static int __init sat_sensors_init(void)
        return i2c_add_driver(&wf_sat_driver);
 }
 
-#if 0  /* uncomment when module_exit() below is uncommented */
 static void __exit sat_sensors_exit(void)
 {
        i2c_del_driver(&wf_sat_driver);
 }
-#endif
 
 module_init(sat_sensors_init);
-/*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */
+module_exit(sat_sensors_exit);
 
 MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
 MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control");
index 220686159c1586f7c70d8b70dd1fa86c25c536e9..f4b4dad77391590d02967faefc1476c5c65ac6b8 100644 (file)
@@ -377,7 +377,6 @@ config PMIC_DA9052
 
 config MFD_DA9052_SPI
        bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI"
-       select IRQ_DOMAIN
        select REGMAP_SPI
        select REGMAP_IRQ
        select PMIC_DA9052
@@ -390,7 +389,6 @@ config MFD_DA9052_SPI
 
 config MFD_DA9052_I2C
        bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C"
-       select IRQ_DOMAIN
        select REGMAP_I2C
        select REGMAP_IRQ
        select PMIC_DA9052
@@ -561,7 +559,6 @@ config MFD_WM8994
        bool "Support Wolfson Microelectronics WM8994"
        select MFD_CORE
        select REGMAP_I2C
-       select IRQ_DOMAIN
        select REGMAP_IRQ
        depends on I2C=y && GENERIC_HARDIRQS
        help
index 9fd4f63c45cc18b2e60dc41085425ff3d35f04b8..738722cdecaaa23e075b25cf2407357cea372ee7 100644 (file)
@@ -813,7 +813,8 @@ err_revision:
                mc13xxx_add_subdevice(mc13xxx, "%s-adc");
 
        if (mc13xxx->flags & MC13XXX_USE_CODEC)
-               mc13xxx_add_subdevice(mc13xxx, "%s-codec");
+               mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
+                                       pdata->codec, sizeof(*pdata->codec));
 
        if (mc13xxx->flags & MC13XXX_USE_RTC)
                mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
index a409fa050a1a910e0074ce0098e76e0868988b52..93d0a8b7718aff44f5ccd8bb24c7fff94293d95f 100644 (file)
@@ -338,7 +338,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
        mutex_unlock(&ps3av->mutex);
        return 0;
 
-      err:
+err:
        mutex_unlock(&ps3av->mutex);
        printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res);
        return res;
@@ -477,7 +477,6 @@ int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source)
 
        return 0;
 }
-
 EXPORT_SYMBOL_GPL(ps3av_set_audio_mode);
 
 static int ps3av_set_videomode(void)
@@ -501,7 +500,7 @@ static void ps3av_set_videomode_packet(u32 id)
 
        video_mode = &video_mode_table[id & PS3AV_MODE_MASK];
 
-       avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO;       /* num of head */
+       avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */
        avb_param.num_of_audio_pkt = 0;
        avb_param.num_of_av_video_pkt = ps3av->av_hw_conf.num_of_hdmi +
                                        ps3av->av_hw_conf.num_of_avmulti;
@@ -521,7 +520,7 @@ static void ps3av_set_videomode_packet(u32 id)
 #ifndef PS3AV_HDMI_YUV
                if (ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 ||
                    ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_1)
-                       av_video_cs = RGB8;     /* use RGB for HDMI */
+                       av_video_cs = RGB8; /* use RGB for HDMI */
 #endif
                len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len],
                                                 ps3av->av_port[i],
@@ -590,8 +589,8 @@ static void ps3avd(struct work_struct *work)
 #define SHIFT_VESA     8
 
 static const struct {
-       unsigned mask : 19;
-       unsigned id :  4;
+       unsigned mask:19;
+       unsigned id:4;
 } ps3av_preferred_modes[] = {
        { PS3AV_RESBIT_WUXGA      << SHIFT_VESA, PS3AV_MODE_WUXGA   },
        { PS3AV_RESBIT_1920x1080P << SHIFT_60,   PS3AV_MODE_1080P60 },
@@ -667,7 +666,8 @@ static enum ps3av_mode_num ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
        return id;
 }
 
-static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info)
+static void ps3av_monitor_info_dump(
+       const struct ps3av_pkt_av_get_monitor_info *monitor_info)
 {
        const struct ps3av_info_monitor *info = &monitor_info->info;
        const struct ps3av_info_audio *audio = info->audio;
@@ -717,8 +717,8 @@ static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *
 
        /* audio block */
        for (i = 0; i < info->num_of_audio_block; i++) {
-               pr_debug("audio[%d] type: %02x max_ch: %02x fs: %02x sbit: "
-                        "%02x\n",
+               pr_debug(
+                       "audio[%d] type: %02x max_ch: %02x fs: %02x sbit: %02x\n",
                         i, audio->type, audio->max_num_of_ch, audio->fs,
                         audio->sbit);
                audio++;
@@ -870,21 +870,18 @@ int ps3av_set_video_mode(int id)
 
        return 0;
 }
-
 EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
 
 int ps3av_get_auto_mode(void)
 {
        return ps3av_auto_videomode(&ps3av->av_hw_conf);
 }
-
 EXPORT_SYMBOL_GPL(ps3av_get_auto_mode);
 
 int ps3av_get_mode(void)
 {
        return ps3av ? ps3av->ps3av_mode : 0;
 }
-
 EXPORT_SYMBOL_GPL(ps3av_get_mode);
 
 /* get resolution by video_mode */
@@ -902,7 +899,6 @@ int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
        *yres = video_mode_table[id].y;
        return 0;
 }
-
 EXPORT_SYMBOL_GPL(ps3av_video_mode2res);
 
 /* mute */
@@ -911,7 +907,6 @@ int ps3av_video_mute(int mute)
        return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON
                                            : PS3AV_CMD_MUTE_OFF);
 }
-
 EXPORT_SYMBOL_GPL(ps3av_video_mute);
 
 /* mute analog output only */
@@ -935,7 +930,6 @@ int ps3av_audio_mute(int mute)
        return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON
                                         : PS3AV_CMD_MUTE_OFF);
 }
-
 EXPORT_SYMBOL_GPL(ps3av_audio_mute);
 
 static int __devinit ps3av_probe(struct ps3_system_bus_device *dev)
index 91b6d52f74eb76644c0f5ac2d81285a0da7719b3..f0d015dd0fef20aa2795b7c4866e00e1e2e478a2 100644 (file)
@@ -2,6 +2,7 @@
  * Helper routines for SuperH Clock Pulse Generator blocks (CPG).
  *
  *  Copyright (C) 2010  Magnus Damm
+ *  Copyright (C) 2010 - 2012  Paul Mundt
  *
  * 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
 #include <linux/io.h>
 #include <linux/sh_clk.h>
 
-static int sh_clk_mstp32_enable(struct clk *clk)
+static unsigned int sh_clk_read(struct clk *clk)
 {
-       iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
-                 clk->mapped_reg);
+       if (clk->flags & CLK_ENABLE_REG_8BIT)
+               return ioread8(clk->mapped_reg);
+       else if (clk->flags & CLK_ENABLE_REG_16BIT)
+               return ioread16(clk->mapped_reg);
+
+       return ioread32(clk->mapped_reg);
+}
+
+static void sh_clk_write(int value, struct clk *clk)
+{
+       if (clk->flags & CLK_ENABLE_REG_8BIT)
+               iowrite8(value, clk->mapped_reg);
+       else if (clk->flags & CLK_ENABLE_REG_16BIT)
+               iowrite16(value, clk->mapped_reg);
+       else
+               iowrite32(value, clk->mapped_reg);
+}
+
+static int sh_clk_mstp_enable(struct clk *clk)
+{
+       sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk);
        return 0;
 }
 
-static void sh_clk_mstp32_disable(struct clk *clk)
+static void sh_clk_mstp_disable(struct clk *clk)
 {
-       iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
-                 clk->mapped_reg);
+       sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk);
 }
 
-static struct sh_clk_ops sh_clk_mstp32_clk_ops = {
-       .enable         = sh_clk_mstp32_enable,
-       .disable        = sh_clk_mstp32_disable,
+static struct sh_clk_ops sh_clk_mstp_clk_ops = {
+       .enable         = sh_clk_mstp_enable,
+       .disable        = sh_clk_mstp_disable,
        .recalc         = followparent_recalc,
 };
 
-int __init sh_clk_mstp32_register(struct clk *clks, int nr)
+int __init sh_clk_mstp_register(struct clk *clks, int nr)
 {
        struct clk *clkp;
        int ret = 0;
@@ -40,7 +59,7 @@ int __init sh_clk_mstp32_register(struct clk *clks, int nr)
 
        for (k = 0; !ret && (k < nr); k++) {
                clkp = clks + k;
-               clkp->ops = &sh_clk_mstp32_clk_ops;
+               clkp->ops = &sh_clk_mstp_clk_ops;
                ret |= clk_register(clkp);
        }
 
@@ -72,7 +91,7 @@ static unsigned long sh_clk_div6_recalc(struct clk *clk)
        clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
                             table, NULL);
 
-       idx = ioread32(clk->mapped_reg) & 0x003f;
+       idx = sh_clk_read(clk) & 0x003f;
 
        return clk->freq_table[idx].frequency;
 }
@@ -98,10 +117,10 @@ static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
        if (ret < 0)
                return ret;
 
-       value = ioread32(clk->mapped_reg) &
+       value = sh_clk_read(clk) &
                ~(((1 << clk->src_width) - 1) << clk->src_shift);
 
-       iowrite32(value | (i << clk->src_shift), clk->mapped_reg);
+       sh_clk_write(value | (i << clk->src_shift), clk);
 
        /* Rebuild the frequency table */
        clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -119,10 +138,10 @@ static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
        if (idx < 0)
                return idx;
 
-       value = ioread32(clk->mapped_reg);
+       value = sh_clk_read(clk);
        value &= ~0x3f;
        value |= idx;
-       iowrite32(value, clk->mapped_reg);
+       sh_clk_write(value, clk);
        return 0;
 }
 
@@ -133,9 +152,9 @@ static int sh_clk_div6_enable(struct clk *clk)
 
        ret = sh_clk_div6_set_rate(clk, clk->rate);
        if (ret == 0) {
-               value = ioread32(clk->mapped_reg);
+               value = sh_clk_read(clk);
                value &= ~0x100; /* clear stop bit to enable clock */
-               iowrite32(value, clk->mapped_reg);
+               sh_clk_write(value, clk);
        }
        return ret;
 }
@@ -144,10 +163,10 @@ static void sh_clk_div6_disable(struct clk *clk)
 {
        unsigned long value;
 
-       value = ioread32(clk->mapped_reg);
+       value = sh_clk_read(clk);
        value |= 0x100; /* stop clock */
        value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
-       iowrite32(value, clk->mapped_reg);
+       sh_clk_write(value, clk);
 }
 
 static struct sh_clk_ops sh_clk_div6_clk_ops = {
@@ -182,7 +201,7 @@ static int __init sh_clk_init_parent(struct clk *clk)
                return -EINVAL;
        }
 
-       val  = (ioread32(clk->mapped_reg) >> clk->src_shift);
+       val  = (sh_clk_read(clk) >> clk->src_shift);
        val &= (1 << clk->src_width) - 1;
 
        if (val >= clk->parent_num) {
@@ -252,7 +271,7 @@ static unsigned long sh_clk_div4_recalc(struct clk *clk)
        clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
                             table, &clk->arch_flags);
 
-       idx = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0x000f;
+       idx = (sh_clk_read(clk) >> clk->enable_bit) & 0x000f;
 
        return clk->freq_table[idx].frequency;
 }
@@ -270,15 +289,15 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
         */
 
        if (parent->flags & CLK_ENABLE_ON_INIT)
-               value = ioread32(clk->mapped_reg) & ~(1 << 7);
+               value = sh_clk_read(clk) & ~(1 << 7);
        else
-               value = ioread32(clk->mapped_reg) | (1 << 7);
+               value = sh_clk_read(clk) | (1 << 7);
 
        ret = clk_reparent(clk, parent);
        if (ret < 0)
                return ret;
 
-       iowrite32(value, clk->mapped_reg);
+       sh_clk_write(value, clk);
 
        /* Rebiuld the frequency table */
        clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -295,10 +314,10 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
        if (idx < 0)
                return idx;
 
-       value = ioread32(clk->mapped_reg);
+       value = sh_clk_read(clk);
        value &= ~(0xf << clk->enable_bit);
        value |= (idx << clk->enable_bit);
-       iowrite32(value, clk->mapped_reg);
+       sh_clk_write(value, clk);
 
        if (d4t->kick)
                d4t->kick(clk);
@@ -308,13 +327,13 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
 
 static int sh_clk_div4_enable(struct clk *clk)
 {
-       iowrite32(ioread32(clk->mapped_reg) & ~(1 << 8), clk->mapped_reg);
+       sh_clk_write(sh_clk_read(clk) & ~(1 << 8), clk);
        return 0;
 }
 
 static void sh_clk_div4_disable(struct clk *clk)
 {
-       iowrite32(ioread32(clk->mapped_reg) | (1 << 8), clk->mapped_reg);
+       sh_clk_write(sh_clk_read(clk) | (1 << 8), clk);
 }
 
 static struct sh_clk_ops sh_clk_div4_clk_ops = {
index 5fea1ee8799afed9a7a028450df90e6c897060e1..14eb01ef5d723c87780e85d9664f2b2c4b31d7cf 100644 (file)
@@ -55,11 +55,3 @@ void destroy_irq(unsigned int irq)
 {
        irq_free_desc(irq);
 }
-
-void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
-{
-       int i;
-
-       for (i = 0; i < nr_vecs; i++)
-               irq_reserve_irq(evt2irq(vectors[i].vect));
-}
index 3158e17b665cc6fb1c5eb214674610bd42611235..4604153b7954b70288399bb675c373f1e16d2bf3 100644 (file)
@@ -1052,9 +1052,17 @@ static int sci_request_irq(struct sci_port *port)
                if (SCIx_IRQ_IS_MUXED(port)) {
                        i = SCIx_MUX_IRQ;
                        irq = up->irq;
-               } else
+               } else {
                        irq = port->cfg->irqs[i];
 
+                       /*
+                        * Certain port types won't support all of the
+                        * available interrupt sources.
+                        */
+                       if (unlikely(!irq))
+                               continue;
+               }
+
                desc = sci_irq_desc + i;
                port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s",
                                            dev_name(up->dev), desc->desc);
@@ -1094,6 +1102,15 @@ static void sci_free_irq(struct sci_port *port)
         * IRQ first.
         */
        for (i = 0; i < SCIx_NR_IRQS; i++) {
+               unsigned int irq = port->cfg->irqs[i];
+
+               /*
+                * Certain port types won't support all of the available
+                * interrupt sources.
+                */
+               if (unlikely(!irq))
+                       continue;
+
                free_irq(port->cfg->irqs[i], port);
                kfree(port->irqstr[i]);
 
@@ -1564,10 +1581,32 @@ static void sci_enable_ms(struct uart_port *port)
 
 static void sci_break_ctl(struct uart_port *port, int break_state)
 {
-       /*
-        * Not supported by hardware. Most parts couple break and rx
-        * interrupts together, with break detection always enabled.
-        */
+       struct sci_port *s = to_sci_port(port);
+       struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
+       unsigned short scscr, scsptr;
+
+       /* check wheter the port has SCSPTR */
+       if (!reg->size) {
+               /*
+                * Not supported by hardware. Most parts couple break and rx
+                * interrupts together, with break detection always enabled.
+                */
+               return;
+       }
+
+       scsptr = serial_port_in(port, SCSPTR);
+       scscr = serial_port_in(port, SCSCR);
+
+       if (break_state == -1) {
+               scsptr = (scsptr | SCSPTR_SPB2IO) & ~SCSPTR_SPB2DT;
+               scscr &= ~SCSCR_TE;
+       } else {
+               scsptr = (scsptr | SCSPTR_SPB2DT) & ~SCSPTR_SPB2IO;
+               scscr |= SCSCR_TE;
+       }
+
+       serial_port_out(port, SCSPTR, scsptr);
+       serial_port_out(port, SCSCR, scscr);
 }
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
index 3b0c4e32ed7b61d367d530defb11c1f24f7bb938..48cc6f25cfd39c319cea40e5d70232ca39c3c964 100644 (file)
@@ -53,17 +53,13 @@ extern void ctrl_alt_del(void);
 
 #define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
 
-/*
- * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
- * This seems a good reason to start with NumLock off. On HIL keyboards
- * of PARISC machines however there is no NumLock key and everyone expects the
- * keypad to be used for numbers.
- */
-
-#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
-#define KBD_DEFLEDS (1 << VC_NUMLOCK)
+#if defined(CONFIG_X86) || defined(CONFIG_PARISC)
+#include <asm/kbdleds.h>
 #else
-#define KBD_DEFLEDS 0
+static inline int kbd_defleds(void)
+{
+       return 0;
+}
 #endif
 
 #define KBD_DEFLOCK 0
@@ -1524,8 +1520,8 @@ int __init kbd_init(void)
        int error;
 
        for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               kbd_table[i].ledflagstate = KBD_DEFLEDS;
-               kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
+               kbd_table[i].ledflagstate = kbd_defleds();
+               kbd_table[i].default_ledflagstate = kbd_defleds();
                kbd_table[i].ledmode = LED_SHOW_FLAGS;
                kbd_table[i].lockstate = KBD_DEFLOCK;
                kbd_table[i].slockstate = 0;
index bc2ff8b8147b7708db66a62aea06e17581d6adee..a18bf6358eb89d5048ec8490985526bdf3141af1 100644 (file)
@@ -1145,6 +1145,7 @@ config ZVM_WATCHDOG
 config SH_WDT
        tristate "SuperH Watchdog"
        depends on SUPERH && (CPU_SH3 || CPU_SH4)
+       select WATCHDOG_CORE
        help
          This driver adds watchdog support for the integrated watchdog in the
          SuperH processors. If you have one of these processors and wish
index 93958a7763e69d00941fab2de25448c04cead8f9..e5b59bebcdb1a7f9da15376aa4d6a3423d27e1e7 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Watchdog driver for integrated watchdog in the SuperH processors.
  *
- * Copyright (C) 2001 - 2010  Paul Mundt <lethal@linux-sh.org>
+ * Copyright (C) 2001 - 2012  Paul Mundt <lethal@linux-sh.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
 #include <linux/platform_device.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/spinlock.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <linux/ioport.h>
+#include <linux/pm_runtime.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/io.h>
-#include <linux/uaccess.h>
+#include <linux/clk.h>
 #include <asm/watchdog.h>
 
 #define DRV_NAME "sh-wdt"
 static int clock_division_ratio = WTCSR_CKS_4096;
 #define next_ping_period(cks)  (jiffies + msecs_to_jiffies(cks - 4))
 
-static const struct watchdog_info sh_wdt_info;
-static struct platform_device *sh_wdt_dev;
-static DEFINE_SPINLOCK(shwdt_lock);
-
 #define WATCHDOG_HEARTBEAT 30                  /* 30 sec default heartbeat */
 static int heartbeat = WATCHDOG_HEARTBEAT;     /* in seconds */
 static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -81,19 +76,22 @@ static unsigned long next_heartbeat;
 struct sh_wdt {
        void __iomem            *base;
        struct device           *dev;
+       struct clk              *clk;
+       spinlock_t              lock;
 
        struct timer_list       timer;
-
-       unsigned long           enabled;
-       char                    expect_close;
 };
 
-static void sh_wdt_start(struct sh_wdt *wdt)
+static int sh_wdt_start(struct watchdog_device *wdt_dev)
 {
+       struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
        unsigned long flags;
        u8 csr;
 
-       spin_lock_irqsave(&shwdt_lock, flags);
+       pm_runtime_get_sync(wdt->dev);
+       clk_enable(wdt->clk);
+
+       spin_lock_irqsave(&wdt->lock, flags);
 
        next_heartbeat = jiffies + (heartbeat * HZ);
        mod_timer(&wdt->timer, next_ping_period(clock_division_ratio));
@@ -122,15 +120,18 @@ static void sh_wdt_start(struct sh_wdt *wdt)
        csr &= ~RSTCSR_RSTS;
        sh_wdt_write_rstcsr(csr);
 #endif
-       spin_unlock_irqrestore(&shwdt_lock, flags);
+       spin_unlock_irqrestore(&wdt->lock, flags);
+
+       return 0;
 }
 
-static void sh_wdt_stop(struct sh_wdt *wdt)
+static int sh_wdt_stop(struct watchdog_device *wdt_dev)
 {
+       struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
        unsigned long flags;
        u8 csr;
 
-       spin_lock_irqsave(&shwdt_lock, flags);
+       spin_lock_irqsave(&wdt->lock, flags);
 
        del_timer(&wdt->timer);
 
@@ -138,28 +139,39 @@ static void sh_wdt_stop(struct sh_wdt *wdt)
        csr &= ~WTCSR_TME;
        sh_wdt_write_csr(csr);
 
-       spin_unlock_irqrestore(&shwdt_lock, flags);
+       spin_unlock_irqrestore(&wdt->lock, flags);
+
+       clk_disable(wdt->clk);
+       pm_runtime_put_sync(wdt->dev);
+
+       return 0;
 }
 
-static inline void sh_wdt_keepalive(struct sh_wdt *wdt)
+static int sh_wdt_keepalive(struct watchdog_device *wdt_dev)
 {
+       struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
        unsigned long flags;
 
-       spin_lock_irqsave(&shwdt_lock, flags);
+       spin_lock_irqsave(&wdt->lock, flags);
        next_heartbeat = jiffies + (heartbeat * HZ);
-       spin_unlock_irqrestore(&shwdt_lock, flags);
+       spin_unlock_irqrestore(&wdt->lock, flags);
+
+       return 0;
 }
 
-static int sh_wdt_set_heartbeat(int t)
+static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t)
 {
+       struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
        unsigned long flags;
 
        if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */
                return -EINVAL;
 
-       spin_lock_irqsave(&shwdt_lock, flags);
+       spin_lock_irqsave(&wdt->lock, flags);
        heartbeat = t;
-       spin_unlock_irqrestore(&shwdt_lock, flags);
+       wdt_dev->timeout = t;
+       spin_unlock_irqrestore(&wdt->lock, flags);
+
        return 0;
 }
 
@@ -168,7 +180,7 @@ static void sh_wdt_ping(unsigned long data)
        struct sh_wdt *wdt = (struct sh_wdt *)data;
        unsigned long flags;
 
-       spin_lock_irqsave(&shwdt_lock, flags);
+       spin_lock_irqsave(&wdt->lock, flags);
        if (time_before(jiffies, next_heartbeat)) {
                u8 csr;
 
@@ -182,137 +194,9 @@ static void sh_wdt_ping(unsigned long data)
        } else
                dev_warn(wdt->dev, "Heartbeat lost! Will not ping "
                         "the watchdog\n");
-       spin_unlock_irqrestore(&shwdt_lock, flags);
-}
-
-static int sh_wdt_open(struct inode *inode, struct file *file)
-{
-       struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev);
-
-       if (test_and_set_bit(0, &wdt->enabled))
-               return -EBUSY;
-       if (nowayout)
-               __module_get(THIS_MODULE);
-
-       file->private_data = wdt;
-
-       sh_wdt_start(wdt);
-
-       return nonseekable_open(inode, file);
-}
-
-static int sh_wdt_close(struct inode *inode, struct file *file)
-{
-       struct sh_wdt *wdt = file->private_data;
-
-       if (wdt->expect_close == 42) {
-               sh_wdt_stop(wdt);
-       } else {
-               dev_crit(wdt->dev, "Unexpected close, not "
-                        "stopping watchdog!\n");
-               sh_wdt_keepalive(wdt);
-       }
-
-       clear_bit(0, &wdt->enabled);
-       wdt->expect_close = 0;
-
-       return 0;
-}
-
-static ssize_t sh_wdt_write(struct file *file, const char *buf,
-                           size_t count, loff_t *ppos)
-{
-       struct sh_wdt *wdt = file->private_data;
-
-       if (count) {
-               if (!nowayout) {
-                       size_t i;
-
-                       wdt->expect_close = 0;
-
-                       for (i = 0; i != count; i++) {
-                               char c;
-                               if (get_user(c, buf + i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       wdt->expect_close = 42;
-                       }
-               }
-               sh_wdt_keepalive(wdt);
-       }
-
-       return count;
+       spin_unlock_irqrestore(&wdt->lock, flags);
 }
 
-static long sh_wdt_ioctl(struct file *file, unsigned int cmd,
-                                                       unsigned long arg)
-{
-       struct sh_wdt *wdt = file->private_data;
-       int new_heartbeat;
-       int options, retval = -EINVAL;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               return copy_to_user((struct watchdog_info *)arg,
-                         &sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0;
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               return put_user(0, (int *)arg);
-       case WDIOC_SETOPTIONS:
-               if (get_user(options, (int *)arg))
-                       return -EFAULT;
-
-               if (options & WDIOS_DISABLECARD) {
-                       sh_wdt_stop(wdt);
-                       retval = 0;
-               }
-
-               if (options & WDIOS_ENABLECARD) {
-                       sh_wdt_start(wdt);
-                       retval = 0;
-               }
-
-               return retval;
-       case WDIOC_KEEPALIVE:
-               sh_wdt_keepalive(wdt);
-               return 0;
-       case WDIOC_SETTIMEOUT:
-               if (get_user(new_heartbeat, (int *)arg))
-                       return -EFAULT;
-
-               if (sh_wdt_set_heartbeat(new_heartbeat))
-                       return -EINVAL;
-
-               sh_wdt_keepalive(wdt);
-               /* Fall */
-       case WDIOC_GETTIMEOUT:
-               return put_user(heartbeat, (int *)arg);
-       default:
-               return -ENOTTY;
-       }
-       return 0;
-}
-
-static int sh_wdt_notify_sys(struct notifier_block *this,
-                            unsigned long code, void *unused)
-{
-       struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev);
-
-       if (code == SYS_DOWN || code == SYS_HALT)
-               sh_wdt_stop(wdt);
-
-       return NOTIFY_DONE;
-}
-
-static const struct file_operations sh_wdt_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .write          = sh_wdt_write,
-       .unlocked_ioctl = sh_wdt_ioctl,
-       .open           = sh_wdt_open,
-       .release        = sh_wdt_close,
-};
-
 static const struct watchdog_info sh_wdt_info = {
        .options                = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
                                  WDIOF_MAGICCLOSE,
@@ -320,14 +204,17 @@ static const struct watchdog_info sh_wdt_info = {
        .identity               = "SH WDT",
 };
 
-static struct notifier_block sh_wdt_notifier = {
-       .notifier_call          = sh_wdt_notify_sys,
+static const struct watchdog_ops sh_wdt_ops = {
+       .owner          = THIS_MODULE,
+       .start          = sh_wdt_start,
+       .stop           = sh_wdt_stop,
+       .ping           = sh_wdt_keepalive,
+       .set_timeout    = sh_wdt_set_heartbeat,
 };
 
-static struct miscdevice sh_wdt_miscdev = {
-       .minor          = WATCHDOG_MINOR,
-       .name           = "watchdog",
-       .fops           = &sh_wdt_fops,
+static struct watchdog_device sh_wdt_dev = {
+       .info   = &sh_wdt_info,
+       .ops    = &sh_wdt_ops,
 };
 
 static int __devinit sh_wdt_probe(struct platform_device *pdev)
@@ -347,39 +234,49 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev)
        if (unlikely(!res))
                return -EINVAL;
 
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res), DRV_NAME))
-               return -EBUSY;
-
        wdt = devm_kzalloc(&pdev->dev, sizeof(struct sh_wdt), GFP_KERNEL);
-       if (unlikely(!wdt)) {
-               rc = -ENOMEM;
-               goto out_release;
-       }
+       if (unlikely(!wdt))
+               return -ENOMEM;
 
        wdt->dev = &pdev->dev;
 
-       wdt->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       wdt->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(wdt->clk)) {
+               /*
+                * Clock framework support is optional, continue on
+                * anyways if we don't find a matching clock.
+                */
+               wdt->clk = NULL;
+       }
+
+       wdt->base = devm_request_and_ioremap(wdt->dev, res);
        if (unlikely(!wdt->base)) {
-               rc = -ENXIO;
-               goto out_err;
+               rc = -EADDRNOTAVAIL;
+               goto err;
        }
 
-       rc = register_reboot_notifier(&sh_wdt_notifier);
+       watchdog_set_nowayout(&sh_wdt_dev, nowayout);
+       watchdog_set_drvdata(&sh_wdt_dev, wdt);
+
+       spin_lock_init(&wdt->lock);
+
+       rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat);
        if (unlikely(rc)) {
-               dev_err(&pdev->dev,
-                       "Can't register reboot notifier (err=%d)\n", rc);
-               goto out_unmap;
+               /* Default timeout if invalid */
+               sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT);
+
+               dev_warn(&pdev->dev,
+                        "heartbeat value must be 1<=x<=3600, using %d\n",
+                        sh_wdt_dev.timeout);
        }
 
-       sh_wdt_miscdev.parent = wdt->dev;
+       dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n",
+                sh_wdt_dev.timeout, nowayout);
 
-       rc = misc_register(&sh_wdt_miscdev);
+       rc = watchdog_register_device(&sh_wdt_dev);
        if (unlikely(rc)) {
-               dev_err(&pdev->dev,
-                       "Can't register miscdev on minor=%d (err=%d)\n",
-                                               sh_wdt_miscdev.minor, rc);
-               goto out_unreg;
+               dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc);
+               goto err;
        }
 
        init_timer(&wdt->timer);
@@ -388,20 +285,15 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev)
        wdt->timer.expires      = next_ping_period(clock_division_ratio);
 
        platform_set_drvdata(pdev, wdt);
-       sh_wdt_dev = pdev;
 
        dev_info(&pdev->dev, "initialized.\n");
 
+       pm_runtime_enable(&pdev->dev);
+
        return 0;
 
-out_unreg:
-       unregister_reboot_notifier(&sh_wdt_notifier);
-out_unmap:
-       devm_iounmap(&pdev->dev, wdt->base);
-out_err:
-       devm_kfree(&pdev->dev, wdt);
-out_release:
-       devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
+err:
+       clk_put(wdt->clk);
 
        return rc;
 }
@@ -409,36 +301,35 @@ out_release:
 static int __devexit sh_wdt_remove(struct platform_device *pdev)
 {
        struct sh_wdt *wdt = platform_get_drvdata(pdev);
-       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        platform_set_drvdata(pdev, NULL);
 
-       misc_deregister(&sh_wdt_miscdev);
+       watchdog_unregister_device(&sh_wdt_dev);
 
-       sh_wdt_dev = NULL;
-
-       unregister_reboot_notifier(&sh_wdt_notifier);
-       devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
-       devm_iounmap(&pdev->dev, wdt->base);
-       devm_kfree(&pdev->dev, wdt);
+       pm_runtime_disable(&pdev->dev);
+       clk_put(wdt->clk);
 
        return 0;
 }
 
+static void sh_wdt_shutdown(struct platform_device *pdev)
+{
+       sh_wdt_stop(&sh_wdt_dev);
+}
+
 static struct platform_driver sh_wdt_driver = {
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
        },
 
-       .probe  = sh_wdt_probe,
-       .remove = __devexit_p(sh_wdt_remove),
+       .probe          = sh_wdt_probe,
+       .remove         = __devexit_p(sh_wdt_remove),
+       .shutdown       = sh_wdt_shutdown,
 };
 
 static int __init sh_wdt_init(void)
 {
-       int rc;
-
        if (unlikely(clock_division_ratio < 0x5 ||
                     clock_division_ratio > 0x7)) {
                clock_division_ratio = WTCSR_CKS_4096;
@@ -447,17 +338,6 @@ static int __init sh_wdt_init(void)
                        clock_division_ratio);
        }
 
-       rc = sh_wdt_set_heartbeat(heartbeat);
-       if (unlikely(rc)) {
-               heartbeat = WATCHDOG_HEARTBEAT;
-
-               pr_info("heartbeat value must be 1<=x<=3600, using %d\n",
-                       heartbeat);
-       }
-
-       pr_info("configured with heartbeat=%d sec (nowayout=%d)\n",
-               heartbeat, nowayout);
-
        return platform_driver_register(&sh_wdt_driver);
 }
 
index c0b3c70ee87a2b8e0e46c01a87d63ac692aecc71..079d1be65ba9e61e6f0452ecffc0cd23a6c3987d 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/bitops.h>
 #include <linux/mutex.h>
 #include <linux/anon_inodes.h>
+#include <linux/device.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/mman.h>
@@ -87,7 +88,7 @@
  */
 
 /* Epoll private bits inside the event mask */
-#define EP_PRIVATE_BITS (EPOLLONESHOT | EPOLLET)
+#define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | EPOLLET)
 
 /* Maximum number of nesting allowed inside epoll sets */
 #define EP_MAX_NESTS 4
@@ -154,6 +155,9 @@ struct epitem {
        /* List header used to link this item to the "struct file" items list */
        struct list_head fllink;
 
+       /* wakeup_source used when EPOLLWAKEUP is set */
+       struct wakeup_source *ws;
+
        /* The structure that describe the interested events and the source fd */
        struct epoll_event event;
 };
@@ -194,6 +198,9 @@ struct eventpoll {
         */
        struct epitem *ovflist;
 
+       /* wakeup_source used when ep_scan_ready_list is running */
+       struct wakeup_source *ws;
+
        /* The user that created the eventpoll descriptor */
        struct user_struct *user;
 
@@ -588,8 +595,10 @@ static int ep_scan_ready_list(struct eventpoll *ep,
                 * queued into ->ovflist but the "txlist" might already
                 * contain them, and the list_splice() below takes care of them.
                 */
-               if (!ep_is_linked(&epi->rdllink))
+               if (!ep_is_linked(&epi->rdllink)) {
                        list_add_tail(&epi->rdllink, &ep->rdllist);
+                       __pm_stay_awake(epi->ws);
+               }
        }
        /*
         * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after
@@ -602,6 +611,7 @@ static int ep_scan_ready_list(struct eventpoll *ep,
         * Quickly re-inject items left on "txlist".
         */
        list_splice(&txlist, &ep->rdllist);
+       __pm_relax(ep->ws);
 
        if (!list_empty(&ep->rdllist)) {
                /*
@@ -656,6 +666,8 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
                list_del_init(&epi->rdllink);
        spin_unlock_irqrestore(&ep->lock, flags);
 
+       wakeup_source_unregister(epi->ws);
+
        /* At this point it is safe to free the eventpoll item */
        kmem_cache_free(epi_cache, epi);
 
@@ -706,6 +718,7 @@ static void ep_free(struct eventpoll *ep)
        mutex_unlock(&epmutex);
        mutex_destroy(&ep->mtx);
        free_uid(ep->user);
+       wakeup_source_unregister(ep->ws);
        kfree(ep);
 }
 
@@ -737,6 +750,7 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
                         * callback, but it's not actually ready, as far as
                         * caller requested events goes. We can remove it here.
                         */
+                       __pm_relax(epi->ws);
                        list_del_init(&epi->rdllink);
                }
        }
@@ -927,13 +941,23 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
                if (epi->next == EP_UNACTIVE_PTR) {
                        epi->next = ep->ovflist;
                        ep->ovflist = epi;
+                       if (epi->ws) {
+                               /*
+                                * Activate ep->ws since epi->ws may get
+                                * deactivated at any time.
+                                */
+                               __pm_stay_awake(ep->ws);
+                       }
+
                }
                goto out_unlock;
        }
 
        /* If this file is already in the ready list we exit soon */
-       if (!ep_is_linked(&epi->rdllink))
+       if (!ep_is_linked(&epi->rdllink)) {
                list_add_tail(&epi->rdllink, &ep->rdllist);
+               __pm_stay_awake(epi->ws);
+       }
 
        /*
         * Wake up ( if active ) both the eventpoll wait list and the ->poll()
@@ -1091,6 +1115,30 @@ static int reverse_path_check(void)
        return error;
 }
 
+static int ep_create_wakeup_source(struct epitem *epi)
+{
+       const char *name;
+
+       if (!epi->ep->ws) {
+               epi->ep->ws = wakeup_source_register("eventpoll");
+               if (!epi->ep->ws)
+                       return -ENOMEM;
+       }
+
+       name = epi->ffd.file->f_path.dentry->d_name.name;
+       epi->ws = wakeup_source_register(name);
+       if (!epi->ws)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void ep_destroy_wakeup_source(struct epitem *epi)
+{
+       wakeup_source_unregister(epi->ws);
+       epi->ws = NULL;
+}
+
 /*
  * Must be called with "mtx" held.
  */
@@ -1118,6 +1166,13 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
        epi->event = *event;
        epi->nwait = 0;
        epi->next = EP_UNACTIVE_PTR;
+       if (epi->event.events & EPOLLWAKEUP) {
+               error = ep_create_wakeup_source(epi);
+               if (error)
+                       goto error_create_wakeup_source;
+       } else {
+               epi->ws = NULL;
+       }
 
        /* Initialize the poll table using the queue callback */
        epq.epi = epi;
@@ -1164,6 +1219,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
        /* If the file is already "ready" we drop it inside the ready list */
        if ((revents & event->events) && !ep_is_linked(&epi->rdllink)) {
                list_add_tail(&epi->rdllink, &ep->rdllist);
+               __pm_stay_awake(epi->ws);
 
                /* Notify waiting tasks that events are available */
                if (waitqueue_active(&ep->wq))
@@ -1204,6 +1260,9 @@ error_unregister:
                list_del_init(&epi->rdllink);
        spin_unlock_irqrestore(&ep->lock, flags);
 
+       wakeup_source_unregister(epi->ws);
+
+error_create_wakeup_source:
        kmem_cache_free(epi_cache, epi);
 
        return error;
@@ -1229,6 +1288,12 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
        epi->event.events = event->events;
        pt._key = event->events;
        epi->event.data = event->data; /* protected by mtx */
+       if (epi->event.events & EPOLLWAKEUP) {
+               if (!epi->ws)
+                       ep_create_wakeup_source(epi);
+       } else if (epi->ws) {
+               ep_destroy_wakeup_source(epi);
+       }
 
        /*
         * Get current event bits. We can safely use the file* here because
@@ -1244,6 +1309,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
                spin_lock_irq(&ep->lock);
                if (!ep_is_linked(&epi->rdllink)) {
                        list_add_tail(&epi->rdllink, &ep->rdllist);
+                       __pm_stay_awake(epi->ws);
 
                        /* Notify waiting tasks that events are available */
                        if (waitqueue_active(&ep->wq))
@@ -1282,6 +1348,18 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
             !list_empty(head) && eventcnt < esed->maxevents;) {
                epi = list_first_entry(head, struct epitem, rdllink);
 
+               /*
+                * Activate ep->ws before deactivating epi->ws to prevent
+                * triggering auto-suspend here (in case we reactive epi->ws
+                * below).
+                *
+                * This could be rearranged to delay the deactivation of epi->ws
+                * instead, but then epi->ws would temporarily be out of sync
+                * with ep_is_linked().
+                */
+               if (epi->ws && epi->ws->active)
+                       __pm_stay_awake(ep->ws);
+               __pm_relax(epi->ws);
                list_del_init(&epi->rdllink);
 
                pt._key = epi->event.events;
@@ -1298,6 +1376,7 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
                        if (__put_user(revents, &uevent->events) ||
                            __put_user(epi->event.data, &uevent->data)) {
                                list_add(&epi->rdllink, head);
+                               __pm_stay_awake(epi->ws);
                                return eventcnt ? eventcnt : -EFAULT;
                        }
                        eventcnt++;
@@ -1317,6 +1396,7 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
                                 * poll callback will queue them in ep->ovflist.
                                 */
                                list_add_tail(&epi->rdllink, &ep->rdllist);
+                               __pm_stay_awake(epi->ws);
                        }
                }
        }
@@ -1629,6 +1709,10 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
        if (!tfile->f_op || !tfile->f_op->poll)
                goto error_tgt_fput;
 
+       /* Check if EPOLLWAKEUP is allowed */
+       if ((epds.events & EPOLLWAKEUP) && !capable(CAP_EPOLLWAKEUP))
+               epds.events &= ~EPOLLWAKEUP;
+
        /*
         * We have to check that the file structure underneath the file descriptor
         * the user passed to us _is_ an eventpoll file. And also we do not permit
index d038968b54b420a3844c6e07f6bf25bee34d7e5c..1e8efdc80412794d0e566db69783f2a310408aa6 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1938,8 +1938,21 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
                core_waiters = zap_threads(tsk, mm, core_state, exit_code);
        up_write(&mm->mmap_sem);
 
-       if (core_waiters > 0)
+       if (core_waiters > 0) {
+               struct core_thread *ptr;
+
                wait_for_completion(&core_state->startup);
+               /*
+                * Wait for all the threads to become inactive, so that
+                * all the thread context (extended register state, like
+                * fpu etc) gets copied to the memory.
+                */
+               ptr = core_state->dumper.next;
+               while (ptr != NULL) {
+                       wait_task_inactive(ptr->task, 0);
+                       ptr = ptr->next;
+               }
+       }
 
        return core_waiters;
 }
index 12d52dedb2290f6789c7dbf621f93b3620a2fbd2..c398cff3dab7b3b2e74bedef7c5a6cf8bbf54050 100644 (file)
@@ -360,8 +360,11 @@ struct cpu_vfs_cap_data {
 
 #define CAP_WAKE_ALARM            35
 
+/* Allow preventing system suspends while epoll events are pending */
 
-#define CAP_LAST_CAP         CAP_WAKE_ALARM
+#define CAP_EPOLLWAKEUP      36
+
+#define CAP_LAST_CAP         CAP_EPOLLWAKEUP
 
 #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
 
index c077aec3a6ffed08c52d9f8f3c5cf95e9e6df061..cfe83239d7f0712e09a2766eef0ae8363ff68443 100644 (file)
@@ -95,6 +95,7 @@ static inline int cs5535_pic_unreqz_select_high(unsigned int group,
 
 /* CS5536_PM1_STS bits */
 #define CS5536_WAK_FLAG                (1 << 15)
+#define CS5536_RTC_FLAG                (1 << 10)
 #define CS5536_PWRBTN_FLAG     (1 << 8)
 
 /* CS5536_PM1_EN bits */
index 657ab55beda014c15b33833e84dc7e1496d06abf..6f8be328770abb3c11166755d9c954194cfac1ae 100644 (file)
 #define EPOLL_CTL_DEL 2
 #define EPOLL_CTL_MOD 3
 
+/*
+ * Request the handling of system wakeup events so as to prevent system suspends
+ * from happening while those events are being processed.
+ *
+ * Assuming neither EPOLLET nor EPOLLONESHOT is set, system suspends will not be
+ * re-allowed until epoll_wait is called again after consuming the wakeup
+ * event(s).
+ *
+ * Requires CAP_EPOLLWAKEUP
+ */
+#define EPOLLWAKEUP (1 << 29)
+
 /* Set the One Shot behaviour for the target file descriptor */
 #define EPOLLONESHOT (1 << 30)
 
index b27cfcfd3a59c15319488580a14de42c18174744..61f5cec031e0345bebb8e506f9727b57069dc706 100644 (file)
@@ -335,11 +335,6 @@ struct irq_chip {
        void            (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
 
        unsigned long   flags;
-
-       /* Currently used only by UML, might disappear one day.*/
-#ifdef CONFIG_IRQ_RELEASE_METHOD
-       void            (*release)(unsigned int irq, void *dev_id);
-#endif
 };
 
 /*
index e926df7b54c963745d043e1041d8876a5a7c65e6..6e887c742a278944dce4671bc0d1b8a9041bafed 100644 (file)
@@ -247,6 +247,7 @@ enum {
        ATA_HOST_SIMPLEX        = (1 << 0),     /* Host is simplex, one DMA channel per host only */
        ATA_HOST_STARTED        = (1 << 1),     /* Host started */
        ATA_HOST_PARALLEL_SCAN  = (1 << 2),     /* Ports on this host can be scanned in parallel */
+       ATA_HOST_IGNORE_ATA     = (1 << 3),     /* Ignore ATA devices on this host. */
 
        /* bits 24:31 of host->flags are reserved for LLD specific flags */
 
index 10e038bac8dd106f742dc283aa69e7f5cbc495e7..bf070755982e3c62dfdd841601d0241ad7100864 100644 (file)
@@ -170,6 +170,16 @@ struct mc13xxx_ts_platform_data {
        bool atox;
 };
 
+enum mc13783_ssi_port {
+       MC13783_SSI1_PORT,
+       MC13783_SSI2_PORT,
+};
+
+struct mc13xxx_codec_platform_data {
+       enum mc13783_ssi_port adc_ssi_port;
+       enum mc13783_ssi_port dac_ssi_port;
+};
+
 struct mc13xxx_platform_data {
 #define MC13XXX_USE_TOUCHSCREEN (1 << 0)
 #define MC13XXX_USE_CODEC      (1 << 1)
@@ -181,6 +191,7 @@ struct mc13xxx_platform_data {
        struct mc13xxx_leds_platform_data *leds;
        struct mc13xxx_buttons_platform_data *buttons;
        struct mc13xxx_ts_platform_data touch;
+       struct mc13xxx_codec_platform_data *codec;
 };
 
 #define MC13XXX_ADC_MODE_TS            1
index 8adf70e9e3cc88f9baab6927647b424ea5bdf64b..f32578634d9d1a9c195c8075c80bc981607d3452 100644 (file)
@@ -1084,8 +1084,10 @@ extern void perf_pmu_unregister(struct pmu *pmu);
 
 extern int perf_num_counters(void);
 extern const char *perf_pmu_name(void);
-extern void __perf_event_task_sched(struct task_struct *prev,
-                                   struct task_struct *next);
+extern void __perf_event_task_sched_in(struct task_struct *prev,
+                                      struct task_struct *task);
+extern void __perf_event_task_sched_out(struct task_struct *prev,
+                                       struct task_struct *next);
 extern int perf_event_init_task(struct task_struct *child);
 extern void perf_event_exit_task(struct task_struct *child);
 extern void perf_event_free_task(struct task_struct *task);
@@ -1205,13 +1207,20 @@ perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr)
 
 extern struct static_key_deferred perf_sched_events;
 
-static inline void perf_event_task_sched(struct task_struct *prev,
+static inline void perf_event_task_sched_in(struct task_struct *prev,
                                            struct task_struct *task)
+{
+       if (static_key_false(&perf_sched_events.key))
+               __perf_event_task_sched_in(prev, task);
+}
+
+static inline void perf_event_task_sched_out(struct task_struct *prev,
+                                            struct task_struct *next)
 {
        perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0);
 
        if (static_key_false(&perf_sched_events.key))
-               __perf_event_task_sched(prev, task);
+               __perf_event_task_sched_out(prev, next);
 }
 
 extern void perf_event_mmap(struct vm_area_struct *vma);
@@ -1286,8 +1295,11 @@ extern void perf_event_disable(struct perf_event *event);
 extern void perf_event_task_tick(void);
 #else
 static inline void
-perf_event_task_sched(struct task_struct *prev,
-                     struct task_struct *task)                         { }
+perf_event_task_sched_in(struct task_struct *prev,
+                        struct task_struct *task)                      { }
+static inline void
+perf_event_task_sched_out(struct task_struct *prev,
+                         struct task_struct *next)                     { }
 static inline int perf_event_init_task(struct task_struct *child)      { return 0; }
 static inline void perf_event_exit_task(struct task_struct *child)     { }
 static inline void perf_event_free_task(struct task_struct *task)      { }
diff --git a/include/linux/platform_data/ina2xx.h b/include/linux/platform_data/ina2xx.h
new file mode 100644 (file)
index 0000000..9abc0ca
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Driver for Texas Instruments INA219, INA226 power monitor chips
+ *
+ * Copyright (C) 2012 Lothar Felten <l-felten@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.
+ *
+ * For further information, see the Documentation/hwmon/ina2xx file.
+ */
+
+/**
+ * struct ina2xx_platform_data - ina2xx info
+ * @shunt_uohms                shunt resistance in microohms
+ */
+struct ina2xx_platform_data {
+       long shunt_uohms;
+};
index 715305e05123fbddfc6c886d05a0c5b2925ff508..f067e60a38322fa3a935249cc75c185a8bf522af 100644 (file)
@@ -544,8 +544,6 @@ struct dev_pm_info {
        unsigned long           active_jiffies;
        unsigned long           suspended_jiffies;
        unsigned long           accounting_timestamp;
-       ktime_t                 suspend_time;
-       s64                     max_time_suspended_ns;
        struct dev_pm_qos_request *pq_req;
 #endif
        struct pm_subsys_data   *subsys_data;  /* Owned by the subsystem. */
index 91f8286106eaed1e9b8e9acdeab5a8efe9a6f452..30f794eb382654f9017b868b4245986b4e621a31 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/pm.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/notifier.h>
 
 enum gpd_status {
        GPD_STATE_ACTIVE = 0,   /* PM domain is active */
@@ -70,9 +71,9 @@ struct generic_pm_domain {
        int (*power_on)(struct generic_pm_domain *domain);
        s64 power_on_latency_ns;
        struct gpd_dev_ops dev_ops;
-       s64 break_even_ns;      /* Power break even for the entire domain. */
        s64 max_off_time_ns;    /* Maximum allowed "suspended" time. */
-       ktime_t power_off_time;
+       bool max_off_time_changed;
+       bool cached_power_down_ok;
        struct device_node *of_node; /* Node in device tree */
 };
 
@@ -93,13 +94,17 @@ struct gpd_timing_data {
        s64 start_latency_ns;
        s64 save_state_latency_ns;
        s64 restore_state_latency_ns;
-       s64 break_even_ns;
+       s64 effective_constraint_ns;
+       bool constraint_changed;
+       bool cached_stop_ok;
 };
 
 struct generic_pm_domain_data {
        struct pm_domain_data base;
        struct gpd_dev_ops ops;
        struct gpd_timing_data td;
+       struct notifier_block nb;
+       struct mutex lock;
        bool need_restore;
        bool always_on;
 };
@@ -141,6 +146,7 @@ static inline int pm_genpd_of_add_device(struct device_node *genpd_node,
 extern int pm_genpd_remove_device(struct generic_pm_domain *genpd,
                                  struct device *dev);
 extern void pm_genpd_dev_always_on(struct device *dev, bool val);
+extern void pm_genpd_dev_need_restore(struct device *dev, bool val);
 extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
                                  struct generic_pm_domain *new_subdomain);
 extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
@@ -184,6 +190,7 @@ static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd,
        return -ENOSYS;
 }
 static inline void pm_genpd_dev_always_on(struct device *dev, bool val) {}
+static inline void pm_genpd_dev_need_restore(struct device *dev, bool val) {}
 static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
                                         struct generic_pm_domain *new_sd)
 {
index 609daae7a01450b006a3bbaf490b58af06de58c2..f271860c78d54ee4c794dcb6b7f432a9d7523a33 100644 (file)
@@ -150,9 +150,6 @@ static inline void pm_runtime_set_autosuspend_delay(struct device *dev,
 static inline unsigned long pm_runtime_autosuspend_expiration(
                                struct device *dev) { return 0; }
 
-static inline void pm_runtime_update_max_time_suspended(struct device *dev,
-                                                       s64 delta_ns) {}
-
 #endif /* !CONFIG_PM_RUNTIME */
 
 static inline int pm_runtime_idle(struct device *dev)
index d9f05113e5fb85204df5f45ee28d17e4596f31ee..569781faa5042a7930e082a74985bceac6f89786 100644 (file)
  *
  * @total_time: Total time this wakeup source has been active.
  * @max_time: Maximum time this wakeup source has been continuously active.
- * @last_time: Monotonic clock when the wakeup source's was activated last time.
+ * @last_time: Monotonic clock when the wakeup source's was touched last time.
+ * @prevent_sleep_time: Total time this source has been preventing autosleep.
  * @event_count: Number of signaled wakeup events.
  * @active_count: Number of times the wakeup sorce was activated.
  * @relax_count: Number of times the wakeup sorce was deactivated.
- * @hit_count: Number of times the wakeup sorce might abort system suspend.
+ * @expire_count: Number of times the wakeup source's timeout has expired.
+ * @wakeup_count: Number of times the wakeup source might abort suspend.
  * @active: Status of the wakeup source.
+ * @has_timeout: The wakeup source has been activated with a timeout.
  */
 struct wakeup_source {
        const char              *name;
@@ -49,11 +52,15 @@ struct wakeup_source {
        ktime_t total_time;
        ktime_t max_time;
        ktime_t last_time;
+       ktime_t start_prevent_time;
+       ktime_t prevent_sleep_time;
        unsigned long           event_count;
        unsigned long           active_count;
        unsigned long           relax_count;
-       unsigned long           hit_count;
-       unsigned int            active:1;
+       unsigned long           expire_count;
+       unsigned long           wakeup_count;
+       bool                    active:1;
+       bool                    autosleep_enabled:1;
 };
 
 #ifdef CONFIG_PM_SLEEP
index 78779074f6e8ff9b4f0d95fe9575e008eb0d1c81..eb763adf98158d113655233b21e7f9fe1ebd2cce 100644 (file)
@@ -52,6 +52,8 @@ enum {
 /* SCSPTR, optional */
 #define SCSPTR_RTSIO   (1 << 7)
 #define SCSPTR_CTSIO   (1 << 5)
+#define SCSPTR_SPB2IO  (1 << 1)
+#define SCSPTR_SPB2DT  (1 << 0)
 
 /* Offsets into the sci_port->irqs array */
 enum {
index 0a9d8f2ac51908958776115b8d1ff5d2cbbc5b6d..c513b73cd7cb8499a7ac61edb3789e7e24a8bfab 100644 (file)
@@ -59,7 +59,15 @@ struct clk {
        unsigned int            nr_freqs;
 };
 
-#define CLK_ENABLE_ON_INIT     (1 << 0)
+#define CLK_ENABLE_ON_INIT     BIT(0)
+
+#define CLK_ENABLE_REG_32BIT   BIT(1)  /* default access size */
+#define CLK_ENABLE_REG_16BIT   BIT(2)
+#define CLK_ENABLE_REG_8BIT    BIT(3)
+
+#define CLK_ENABLE_REG_MASK    (CLK_ENABLE_REG_32BIT | \
+                                CLK_ENABLE_REG_16BIT | \
+                                CLK_ENABLE_REG_8BIT)
 
 /* drivers/sh/clk.c */
 unsigned long followparent_recalc(struct clk *);
@@ -102,7 +110,7 @@ long clk_round_parent(struct clk *clk, unsigned long target,
                      unsigned long *best_freq, unsigned long *parent_freq,
                      unsigned int div_min, unsigned int div_max);
 
-#define SH_CLK_MSTP32(_parent, _enable_reg, _enable_bit, _flags)       \
+#define SH_CLK_MSTP(_parent, _enable_reg, _enable_bit, _flags)         \
 {                                                                      \
        .parent         = _parent,                                      \
        .enable_reg     = (void __iomem *)_enable_reg,                  \
@@ -110,7 +118,27 @@ long clk_round_parent(struct clk *clk, unsigned long target,
        .flags          = _flags,                                       \
 }
 
-int sh_clk_mstp32_register(struct clk *clks, int nr);
+#define SH_CLK_MSTP32(_p, _r, _b, _f)                                  \
+       SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_32BIT)
+
+#define SH_CLK_MSTP16(_p, _r, _b, _f)                                  \
+       SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_16BIT)
+
+#define SH_CLK_MSTP8(_p, _r, _b, _f)                                   \
+       SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_8BIT)
+
+int sh_clk_mstp_register(struct clk *clks, int nr);
+
+/*
+ * MSTP registration never really cared about access size, despite the
+ * original enable/disable pairs assuming a 32-bit access. Clocks are
+ * responsible for defining their access sizes either directly or via the
+ * clock definition wrappers.
+ */
+static inline int __deprecated sh_clk_mstp32_register(struct clk *clks, int nr)
+{
+       return sh_clk_mstp_register(clks, nr);
+}
 
 #define SH_CLK_DIV4(_parent, _reg, _shift, _div_bitmap, _flags)        \
 {                                                              \
index 6aed0805927f8ea608e3bce754974d53a9bc372f..32383285da68315817041a36650b9e8e94048fff 100644 (file)
@@ -133,7 +133,6 @@ struct intc_desc symbol __initdata = {                                      \
 }
 
 int register_intc_controller(struct intc_desc *desc);
-void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs);
 int intc_set_priority(unsigned int irq, unsigned int prio);
 int intc_irq_lookup(const char *chipname, intc_enum enum_id);
 void intc_finalize(void);
index ac1c114c499d088e0e9d7bed9f214abe9d924cf2..cd83059fb592c7464fc2e812d92e315fe7c77381 100644 (file)
@@ -356,8 +356,9 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
 extern bool events_check_enabled;
 
 extern bool pm_wakeup_pending(void);
-extern bool pm_get_wakeup_count(unsigned int *count);
+extern bool pm_get_wakeup_count(unsigned int *count, bool block);
 extern bool pm_save_wakeup_count(unsigned int count);
+extern void pm_wakep_autosleep_enabled(bool set);
 
 static inline void lock_system_sleep(void)
 {
@@ -407,6 +408,17 @@ static inline void unlock_system_sleep(void) {}
 
 #endif /* !CONFIG_PM_SLEEP */
 
+#ifdef CONFIG_PM_AUTOSLEEP
+
+/* kernel/power/autosleep.c */
+void queue_up_suspend_work(void);
+
+#else /* !CONFIG_PM_AUTOSLEEP */
+
+static inline void queue_up_suspend_work(void) {}
+
+#endif /* !CONFIG_PM_AUTOSLEEP */
+
 #ifdef CONFIG_ARCH_SAVE_PAGE_KEYS
 /*
  * The ARCH_SAVE_PAGE_KEYS functions can be used by an architecture
index a2e4ff5ba9e9f12be58de88d38fdf0645289ca4b..0876a1e76aefbd97dc66eb76d480e7e05573f68d 100644 (file)
@@ -68,6 +68,20 @@ struct snd_aes_iec958 {
        unsigned char dig_subframe[4];  /* AES/IEC958 subframe bits */
 };
 
+/****************************************************************************
+ *                                                                          *
+ *        CEA-861 Audio InfoFrame. Used in HDMI and DisplayPort                    *
+ *                                                                          *
+ ****************************************************************************/
+
+struct snd_cea_861_aud_if {
+       unsigned char db1_ct_cc; /* coding type and channel count */
+       unsigned char db2_sf_ss; /* sample frequency and size */
+       unsigned char db3; /* not used, all zeros */
+       unsigned char db4_ca; /* channel allocation code */
+       unsigned char db5_dminh_lsv; /* downmix inhibit & level-shit values */
+};
+
 /****************************************************************************
  *                                                                          *
  *      Section for driver hardware dependent interface - /dev/snd/hw?      *
index 20ebf3298eba56273021957b738073001e528959..bb05c02f89b0ca8845108fd3fc1306f41944bc8a 100644 (file)
 #define IEC958_AES5_CON_CGMSA_COPYNOMORE (2<<0)        /* condition not be used */
 #define IEC958_AES5_CON_CGMSA_COPYNEVER        (3<<0)  /* no copying is permitted */
 
+/****************************************************************************
+ *                                                                          *
+ *        CEA-861 Audio InfoFrame. Used in HDMI and DisplayPort                    *
+ *                                                                          *
+ ****************************************************************************/
+#define CEA861_AUDIO_INFOFRAME_DB1CC           (7<<0) /* mask - channel count */
+#define CEA861_AUDIO_INFOFRAME_DB1CT           (0xf<<4) /* mask - coding type */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM (0<<4) /* refer to stream */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_IEC60958  (1<<4) /* IEC-60958 L-PCM */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_AC3       (2<<4) /* AC-3 */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_MPEG1     (3<<4) /* MPEG1 Layers 1 & 2 */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_MP3       (4<<4) /* MPEG1 Layer 3 */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_MPEG2_MULTICH (5<<4) /* MPEG2 Multichannel */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_AAC       (6<<4) /* AAC */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_DTS       (7<<4) /* DTS */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_ATRAC     (8<<4) /* ATRAC */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_ONEBIT    (9<<4) /* One Bit Audio */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_DOLBY_DIG_PLUS (10<<4) /* Dolby Digital + */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_DTS_HD    (11<<4) /* DTS-HD */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_MAT       (12<<4) /* MAT (MLP) */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_DST       (13<<4) /* DST */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_WMA_PRO   (14<<4) /* WMA Pro */
+#define CEA861_AUDIO_INFOFRAME_DB2SF           (7<<2) /* mask - sample frequency */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM (0<<2) /* refer to stream */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_32000     (1<<2) /* 32kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_44100     (2<<2) /* 44.1kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_48000     (3<<2) /* 48kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_88200     (4<<2) /* 88.2kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_96000     (5<<2) /* 96kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_176400    (6<<2) /* 176.4kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_192000    (7<<2) /* 192kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SS           (3<<0) /* mask - sample size */
+#define CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM (0<<0) /* refer to stream */
+#define CEA861_AUDIO_INFOFRAME_DB2SS_16BIT     (1<<0) /* 16 bits */
+#define CEA861_AUDIO_INFOFRAME_DB2SS_20BIT     (2<<0) /* 20 bits */
+#define CEA861_AUDIO_INFOFRAME_DB2SS_24BIT     (3<<0) /* 24 bits */
+#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH      (1<<7) /* mask - inhibit downmixing */
+#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PERMITTED (0<<7) /* stereo downmix permitted */
+#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED (1<<7) /* stereo downmis prohibited */
+#define CEA861_AUDIO_INFOFRAME_DB5_LSV         (0xf<<3) /* mask - level-shift values */
+
 /*****************************************************************************
  *                                                                           *
  *                            MIDI v1.0 interface                            *
diff --git a/include/sound/cs42l52.h b/include/sound/cs42l52.h
new file mode 100644 (file)
index 0000000..4c68955
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * linux/sound/cs42l52.h -- Platform data for CS42L52
+ *
+ * Copyright (c) 2012 Cirrus Logic 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.
+ */
+
+#ifndef __CS42L52_H
+#define __CS42L52_H
+
+struct cs42l52_platform_data {
+
+       /* MICBIAS Level. Check datasheet Pg48 */
+       unsigned int micbias_lvl;
+
+       /* MICA mode selection 0=Single 1=Differential */
+       unsigned int mica_cfg;
+
+       /* MICB mode selection 0=Single 1=Differential */
+       unsigned int micb_cfg;
+
+       /* MICA Select 0=MIC1A 1=MIC2A */
+       unsigned int mica_sel;
+
+       /* MICB Select 0=MIC2A 1=MIC2B */
+       unsigned int micb_sel;
+
+       /* Charge Pump Freq. Check datasheet Pg73 */
+       unsigned int chgfreq;
+
+};
+
+#endif /* __CS42L52_H */
index 7513a42dd4aaa000dfb74c044dc3c3ea9a8f8dbe..e87ae67b0a553ee259d9b5724d442003fbfb5b15 100644 (file)
@@ -49,6 +49,18 @@ struct max98095_pdata {
         */
        unsigned int digmic_left_mode:1;
        unsigned int digmic_right_mode:1;
+
+       /* Pin5 is the mechanical method of sensing jack insertion
+        * but it is something that might not be supported.
+        * 0 = PIN5 not supported
+        * 1 = PIN5 supported
+        */
+       unsigned int jack_detect_pin5en:1;
+
+       /* Slew amount for jack detection. Calculated as 4 * (delay + 1).
+        * Default delay is 24 to get a time of 100ms.
+        */
+       unsigned int jack_detect_delay;
 };
 
 #endif
index b457e87fbd0849efd51fd22445cb76606c8f6d70..906010344dd7e0a227449f674d64b00a07dc1e86 100644 (file)
 /*
  * flags format
  *
- * 0x000000BA
+ * 0x00000CBA
  *
  * A:  inversion
  * B:  format mode
+ * C:  chip specific
  */
 
 /* A: clock inversion */
@@ -39,6 +40,9 @@
 #define SH_FSI_FMT_DAI         (0 << 4)
 #define SH_FSI_FMT_SPDIF       (1 << 4)
 
+/* C: chip specific */
+#define SH_FSI_OPTION_MASK     0x00000F00
+#define SH_FSI_ENABLE_STREAM_MODE      (1 << 8) /* for 16bit data */
 
 /*
  * set_rate return value
@@ -84,16 +88,4 @@ struct sh_fsi_platform_info {
        struct sh_fsi_port_info port_b;
 };
 
-/*
- * for fsi-ak4642
- */
-struct fsi_ak4642_info {
-       const char *name;
-       const char *card;
-       const char *cpu_dai;
-       const char *codec;
-       const char *platform;
-       int id;
-};
-
 #endif /* __SOUND_FSI_H */
diff --git a/include/sound/simple_card.h b/include/sound/simple_card.h
new file mode 100644 (file)
index 0000000..4b62b8d
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * ASoC simple sound card support
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SIMPLE_CARD_H
+#define __SIMPLE_CARD_H
+
+#include <sound/soc.h>
+
+struct asoc_simple_dai_init_info {
+       unsigned int fmt;
+       unsigned int cpu_daifmt;
+       unsigned int codec_daifmt;
+       unsigned int sysclk;
+};
+
+struct asoc_simple_card_info {
+       const char *name;
+       const char *card;
+       const char *cpu_dai;
+       const char *codec;
+       const char *platform;
+       const char *codec_dai;
+       struct asoc_simple_dai_init_info *init; /* for snd_link.init */
+
+       /* used in simple-card.c */
+       struct snd_soc_dai_link snd_link;
+       struct snd_soc_card snd_card;
+};
+
+#endif /* __SIMPLE_CARD_H */
index c429f248cf4e995a6a8aa20eaa1ec8af71ddfe74..1f69e0af2941803ac4452ec509baccbbd2f05f92 100644 (file)
@@ -173,6 +173,8 @@ struct snd_soc_dai_ops {
                struct snd_soc_dai *);
        int (*trigger)(struct snd_pcm_substream *, int,
                struct snd_soc_dai *);
+       int (*bespoke_trigger)(struct snd_pcm_substream *, int,
+               struct snd_soc_dai *);
        /*
         * For hardware based FIFO caused delay reporting.
         * Optional.
@@ -196,6 +198,7 @@ struct snd_soc_dai_driver {
        const char *name;
        unsigned int id;
        int ac97_control;
+       unsigned int base;
 
        /* DAI driver callbacks */
        int (*probe)(struct snd_soc_dai *dai);
@@ -241,6 +244,7 @@ struct snd_soc_dai {
 
        struct snd_soc_dapm_widget *playback_widget;
        struct snd_soc_dapm_widget *capture_widget;
+       struct snd_soc_dapm_context dapm;
 
        /* DAI DMA data */
        void *playback_dma_data;
index 8da3c2409060dc258cb5a87716fbb4fa7cdb527e..e3833d9f1914ce8d529e27c319d9038bddb8ef3b 100644 (file)
@@ -141,10 +141,6 @@ struct device;
 {       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
        .invert = winvert, .kcontrol_news = wcontrols, \
        .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
-#define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
-{      .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0, \
-       .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
 {      .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
@@ -324,6 +320,8 @@ struct snd_soc_dapm_path;
 struct snd_soc_dapm_pin;
 struct snd_soc_dapm_route;
 struct snd_soc_dapm_context;
+struct regulator;
+struct snd_soc_dapm_widget_list;
 
 int dapm_reg_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event);
@@ -359,6 +357,10 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
 int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
                                 struct snd_soc_dai *dai);
 int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
+int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
+                        const struct snd_soc_pcm_stream *params,
+                        struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink);
 
 /* dapm path setup */
 int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
@@ -369,8 +371,8 @@ int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
                             const struct snd_soc_dapm_route *route, int num);
 
 /* dapm events */
-int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
-                             struct snd_soc_dai *dai, int event);
+void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+       int event);
 void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 /* external DAPM widget events */
@@ -402,6 +404,10 @@ void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec);
 /* Mostly internal - should not normally be used */
 void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason);
 
+/* dapm path query */
+int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
+       struct snd_soc_dapm_widget_list **list);
+
 /* dapm widget types */
 enum snd_soc_dapm_type {
        snd_soc_dapm_input = 0,         /* input pin */
@@ -430,6 +436,12 @@ enum snd_soc_dapm_type {
        snd_soc_dapm_aif_out,           /* audio interface output */
        snd_soc_dapm_siggen,            /* signal generator */
        snd_soc_dapm_dai,               /* link to DAI structure */
+       snd_soc_dapm_dai_link,          /* link between two DAI structures */
+};
+
+enum snd_soc_dapm_subclass {
+       SND_SOC_DAPM_CLASS_INIT         = 0,
+       SND_SOC_DAPM_CLASS_RUNTIME      = 1,
 };
 
 /*
@@ -482,9 +494,11 @@ struct snd_soc_dapm_widget {
        struct snd_soc_dapm_context *dapm;
 
        void *priv;                             /* widget specific data */
+       struct regulator *regulator;            /* attached regulator */
+       const struct snd_soc_pcm_stream *params; /* params for dai links */
 
        /* dapm control */
-       short reg;                                              /* negative reg = no direct dapm */
+       int reg;                                /* negative reg = no direct dapm */
        unsigned char shift;                    /* bits to shift */
        unsigned int saved_value;               /* widget saved value */
        unsigned int value;                             /* widget current value */
diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h
new file mode 100644 (file)
index 0000000..04598f1
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * linux/sound/soc-dpcm.h -- ALSA SoC Dynamic PCM Support
+ *
+ * Author:             Liam Girdwood <lrg@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_SOC_DPCM_H
+#define __LINUX_SND_SOC_DPCM_H
+
+#include <linux/list.h>
+#include <sound/pcm.h>
+
+struct snd_soc_pcm_runtime;
+
+/*
+ * Types of runtime_update to perform. e.g. originated from FE PCM ops
+ * or audio route changes triggered by muxes/mixers.
+ */
+enum snd_soc_dpcm_update {
+       SND_SOC_DPCM_UPDATE_NO  = 0,
+       SND_SOC_DPCM_UPDATE_BE,
+       SND_SOC_DPCM_UPDATE_FE,
+};
+
+/*
+ * Dynamic PCM Frontend -> Backend link management states.
+ */
+enum snd_soc_dpcm_link_state {
+       SND_SOC_DPCM_LINK_STATE_NEW     = 0,    /* newly created link */
+       SND_SOC_DPCM_LINK_STATE_FREE,           /* link to be dismantled */
+};
+
+/*
+ * Dynamic PCM Frontend -> Backend link PCM states.
+ */
+enum snd_soc_dpcm_state {
+       SND_SOC_DPCM_STATE_NEW  = 0,
+       SND_SOC_DPCM_STATE_OPEN,
+       SND_SOC_DPCM_STATE_HW_PARAMS,
+       SND_SOC_DPCM_STATE_PREPARE,
+       SND_SOC_DPCM_STATE_START,
+       SND_SOC_DPCM_STATE_STOP,
+       SND_SOC_DPCM_STATE_PAUSED,
+       SND_SOC_DPCM_STATE_SUSPEND,
+       SND_SOC_DPCM_STATE_HW_FREE,
+       SND_SOC_DPCM_STATE_CLOSE,
+};
+
+/*
+ * Dynamic PCM trigger ordering. Triggering flexibility is required as some
+ * DSPs require triggering before/after their CPU platform and DAIs.
+ *
+ * i.e. some clients may want to manually order this call in their PCM
+ * trigger() whilst others will just use the regular core ordering.
+ */
+enum snd_soc_dpcm_trigger {
+       SND_SOC_DPCM_TRIGGER_PRE                = 0,
+       SND_SOC_DPCM_TRIGGER_POST,
+       SND_SOC_DPCM_TRIGGER_BESPOKE,
+};
+
+/*
+ * Dynamic PCM link
+ * This links together a FE and BE DAI at runtime and stores the link
+ * state information and the hw_params configuration.
+ */
+struct snd_soc_dpcm {
+       /* FE and BE DAIs*/
+       struct snd_soc_pcm_runtime *be;
+       struct snd_soc_pcm_runtime *fe;
+
+       /* link state */
+       enum snd_soc_dpcm_link_state state;
+
+       /* list of BE and FE for this DPCM link */
+       struct list_head list_be;
+       struct list_head list_fe;
+
+       /* hw params for this link - may be different for each link */
+       struct snd_pcm_hw_params hw_params;
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_state;
+#endif
+};
+
+/*
+ * Dynamic PCM runtime data.
+ */
+struct snd_soc_dpcm_runtime {
+       struct list_head be_clients;
+       struct list_head fe_clients;
+
+       int users;
+       struct snd_pcm_runtime *runtime;
+       struct snd_pcm_hw_params hw_params;
+
+       /* state and update */
+       enum snd_soc_dpcm_update runtime_update;
+       enum snd_soc_dpcm_state state;
+};
+
+/* can this BE stop and free */
+int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
+               struct snd_soc_pcm_runtime *be, int stream);
+
+/* can this BE perform a hw_params() */
+int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
+               struct snd_soc_pcm_runtime *be, int stream);
+
+/* is the current PCM operation for this FE ? */
+int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream);
+
+/* is the current PCM operation for this BE ? */
+int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
+               struct snd_soc_pcm_runtime *be, int stream);
+
+/* get the substream for this BE */
+struct snd_pcm_substream *
+       snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream);
+
+/* get the BE runtime state */
+enum snd_soc_dpcm_state
+       snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream);
+
+/* set the BE runtime state */
+void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream,
+       enum snd_soc_dpcm_state state);
+
+/* internal use only */
+int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute);
+int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
+int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *);
+
+#endif
index 2ebf7877c148ae717727269a1bb91cab8124b2e9..c703871f5f6556bbcf5386b3e8bb96aca35486b7 100644 (file)
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
        .put = snd_soc_put_volsw, \
        .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+#define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \
+{       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+       SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+       .tlv.p  = (tlv_array),\
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_get_volsw_sx,\
+       .put = snd_soc_put_volsw_sx, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = xreg, .rreg = xreg, \
+               .shift = xshift, .rshift = xshift, \
+               .max = xmax, .min = xmin} }
 #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
        .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
        .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
                                            xmax, xinvert) }
+#define SOC_DOUBLE_R_SX_TLV(xname, xreg, xrreg, xshift, xmin, xmax, tlv_array) \
+{       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+       SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+       .tlv.p  = (tlv_array), \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_get_volsw_sx, \
+       .put = snd_soc_put_volsw_sx, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = xreg, .rreg = xrreg, \
+               .shift = xshift, .rshift = xshift, \
+               .max = xmax, .min = xmin} }
 #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
 {      .iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
        .get = xhandler_get, .put = xhandler_put, \
        .private_value = (unsigned long)&xenum }
 
-#define SOC_DOUBLE_R_SX_TLV(xname, xreg_left, xreg_right, xshift,\
-               xmin, xmax, tlv_array) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
-                 SNDRV_CTL_ELEM_ACCESS_READWRITE, \
-       .tlv.p = (tlv_array), \
-       .info = snd_soc_info_volsw_2r_sx, \
-       .get = snd_soc_get_volsw_2r_sx, \
-       .put = snd_soc_put_volsw_2r_sx, \
-       .private_value = (unsigned long)&(struct soc_mixer_control) \
-               {.reg = xreg_left, \
-                .rreg = xreg_right, .shift = xshift, \
-                .min = xmin, .max = xmax} }
-
 #define SND_SOC_BYTES(xname, xbase, xregs)                   \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,   \
        .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
                {.base = xbase, .num_regs = xregs,            \
                 .mask = xmask }) }
 
+#define SOC_SINGLE_XR_SX(xname, xregbase, xregcount, xnbits, \
+               xmin, xmax, xinvert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .info = snd_soc_info_xr_sx, .get = snd_soc_get_xr_sx, \
+       .put = snd_soc_put_xr_sx, \
+       .private_value = (unsigned long)&(struct soc_mreg_control) \
+               {.regbase = xregbase, .regcount = xregcount, .nbits = xnbits, \
+               .invert = xinvert, .min = xmin, .max = xmax} }
+
+#define SOC_SINGLE_STROBE(xname, xreg, xshift, xinvert) \
+       SOC_SINGLE_EXT(xname, xreg, xshift, 1, xinvert, \
+               snd_soc_get_strobe, snd_soc_put_strobe)
+
 /*
  * Simplified versions of above macros, declaring a struct and calculating
  * ARRAY_SIZE internally
@@ -264,6 +287,7 @@ struct snd_soc_jack_zone;
 struct snd_soc_jack_pin;
 struct snd_soc_cache_ops;
 #include <sound/soc-dapm.h>
+#include <sound/soc-dpcm.h>
 
 #ifdef CONFIG_GPIOLIB
 struct snd_soc_jack_gpio;
@@ -288,6 +312,11 @@ enum snd_soc_pcm_subclass {
        SND_SOC_PCM_CLASS_BE    = 1,
 };
 
+enum snd_soc_card_subclass {
+       SND_SOC_CARD_CLASS_INIT         = 0,
+       SND_SOC_CARD_CLASS_RUNTIME      = 1,
+};
+
 int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                             int source, unsigned int freq, int dir);
 int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
@@ -333,6 +362,11 @@ int snd_soc_platform_write(struct snd_soc_platform *platform,
                                        unsigned int reg, unsigned int val);
 int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
 
+struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
+               const char *dai_link, int stream);
+struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
+               const char *dai_link);
+
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
 int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -343,6 +377,9 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms);
 int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
        const struct snd_pcm_hardware *hw);
 
+int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
+               int cmd, struct snd_soc_platform *platform);
+
 /* Jack reporting */
 int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
                     struct snd_soc_jack *jack);
@@ -413,6 +450,10 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 #define snd_soc_get_volsw_2r snd_soc_get_volsw
 #define snd_soc_put_volsw_2r snd_soc_put_volsw
+int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
 int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo);
 int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
@@ -421,19 +462,22 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_limit_volume(struct snd_soc_codec *codec,
        const char *name, int max);
-int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_info *uinfo);
-int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol);
-int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol);
 int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_info *uinfo);
 int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
                      struct snd_ctl_elem_value *ucontrol);
 int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
                      struct snd_ctl_elem_value *ucontrol);
-
+int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
 
 /**
  * struct snd_soc_reg_access - Describes whether a given register is
@@ -513,6 +557,7 @@ struct snd_soc_jack_gpio {
 #endif
 
 struct snd_soc_jack {
+       struct mutex mutex;
        struct snd_jack *jack;
        struct snd_soc_codec *codec;
        struct list_head pins;
@@ -711,6 +756,7 @@ struct snd_soc_platform_driver {
        /* platform IO - used for platform DAPM */
        unsigned int (*read)(struct snd_soc_platform *, unsigned int);
        int (*write)(struct snd_soc_platform *, unsigned int, unsigned int);
+       int (*bespoke_trigger)(struct snd_pcm_substream *, int);
 };
 
 struct snd_soc_platform {
@@ -746,21 +792,36 @@ struct snd_soc_dai_link {
        const char *cpu_dai_name;
        const struct device_node *cpu_dai_of_node;
        const char *codec_dai_name;
+       int be_id;      /* optional ID for machine driver BE identification */
+
+       const struct snd_soc_pcm_stream *params;
 
        unsigned int dai_fmt;           /* format to set on init */
 
+       enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
+
        /* Keep DAI active over suspend */
        unsigned int ignore_suspend:1;
 
        /* Symmetry requirements */
        unsigned int symmetric_rates:1;
 
+       /* Do not create a PCM for this DAI link (Backend link) */
+       unsigned int no_pcm:1;
+
+       /* This DAI link can route to other DAI links at runtime (Frontend)*/
+       unsigned int dynamic:1;
+
        /* pmdown_time is ignored at stop */
        unsigned int ignore_pmdown_time:1;
 
        /* codec/machine specific init - e.g. add machine controls */
        int (*init)(struct snd_soc_pcm_runtime *rtd);
 
+       /* optional hw_params re-writing for BE and FE sync */
+       int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
+                       struct snd_pcm_hw_params *params);
+
        /* machine stream operations */
        struct snd_soc_ops *ops;
 };
@@ -800,6 +861,7 @@ struct snd_soc_card {
 
        struct list_head list;
        struct mutex mutex;
+       struct mutex dapm_mutex;
 
        bool instantiated;
 
@@ -889,9 +951,11 @@ struct snd_soc_pcm_runtime {
        enum snd_soc_pcm_subclass pcm_subclass;
        struct snd_pcm_ops ops;
 
-       unsigned int complete:1;
        unsigned int dev_registered:1;
 
+       /* Dynamic PCM BE runtime data */
+       struct snd_soc_dpcm_runtime dpcm[2];
+
        long pmdown_time;
 
        /* runtime devices */
@@ -902,6 +966,10 @@ struct snd_soc_pcm_runtime {
        struct snd_soc_dai *cpu_dai;
 
        struct delayed_work delayed_work;
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_dpcm_root;
+       struct dentry *debugfs_dpcm_state;
+#endif
 };
 
 /* mixer control */
@@ -916,6 +984,12 @@ struct soc_bytes {
        u32 mask;
 };
 
+/* multi register control */
+struct soc_mreg_control {
+       long min, max;
+       unsigned int regbase, regcount, nbits, invert;
+};
+
 /* enumerated kcontrol */
 struct soc_enum {
        unsigned short reg;
index ab26f8aa3c781819ca442268acf5b9f81ff8d6c7..5fc2dcdd21cddcadc15daa9dc3e62dde7b41b5d2 100644 (file)
@@ -7,6 +7,8 @@
 #include <linux/ktime.h>
 #include <linux/tracepoint.h>
 
+#define DAPM_DIRECT "(direct)"
+
 struct snd_soc_jack;
 struct snd_soc_codec;
 struct snd_soc_platform;
@@ -241,6 +243,84 @@ TRACE_EVENT(snd_soc_dapm_walk_done,
                  (int)__entry->path_checks, (int)__entry->neighbour_checks)
 );
 
+TRACE_EVENT(snd_soc_dapm_output_path,
+
+       TP_PROTO(struct snd_soc_dapm_widget *widget,
+               struct snd_soc_dapm_path *path),
+
+       TP_ARGS(widget, path),
+
+       TP_STRUCT__entry(
+               __string(       wname,  widget->name            )
+               __string(       pname,  path->name ? path->name : DAPM_DIRECT)
+               __string(       psname, path->sink->name        )
+               __field(        int,    path_sink               )
+               __field(        int,    path_connect            )
+       ),
+
+       TP_fast_assign(
+               __assign_str(wname, widget->name);
+               __assign_str(pname, path->name ? path->name : DAPM_DIRECT);
+               __assign_str(psname, path->sink->name);
+               __entry->path_connect = path->connect;
+               __entry->path_sink = (long)path->sink;
+       ),
+
+       TP_printk("%c%s -> %s -> %s\n",
+               (int) __entry->path_sink &&
+               (int) __entry->path_connect ? '*' : ' ',
+               __get_str(wname), __get_str(pname), __get_str(psname))
+);
+
+TRACE_EVENT(snd_soc_dapm_input_path,
+
+       TP_PROTO(struct snd_soc_dapm_widget *widget,
+               struct snd_soc_dapm_path *path),
+
+       TP_ARGS(widget, path),
+
+       TP_STRUCT__entry(
+               __string(       wname,  widget->name            )
+               __string(       pname,  path->name ? path->name : DAPM_DIRECT)
+               __string(       psname, path->source->name      )
+               __field(        int,    path_source             )
+               __field(        int,    path_connect            )
+       ),
+
+       TP_fast_assign(
+               __assign_str(wname, widget->name);
+               __assign_str(pname, path->name ? path->name : DAPM_DIRECT);
+               __assign_str(psname, path->source->name);
+               __entry->path_connect = path->connect;
+               __entry->path_source = (long)path->source;
+       ),
+
+       TP_printk("%c%s <- %s <- %s\n",
+               (int) __entry->path_source &&
+               (int) __entry->path_connect ? '*' : ' ',
+               __get_str(wname), __get_str(pname), __get_str(psname))
+);
+
+TRACE_EVENT(snd_soc_dapm_connected,
+
+       TP_PROTO(int paths, int stream),
+
+       TP_ARGS(paths, stream),
+
+       TP_STRUCT__entry(
+               __field(        int,    paths           )
+               __field(        int,    stream          )
+       ),
+
+       TP_fast_assign(
+               __entry->paths = paths;
+               __entry->stream = stream;
+       ),
+
+       TP_printk("%s: found %d paths\n",
+               __entry->stream ? "capture" : "playback", __entry->paths)
+);
+
 TRACE_EVENT(snd_soc_jack_irq,
 
        TP_PROTO(const char *name),
index cae9a94f025d95ab1a6f4d927e2459d337280d23..0c9783841a3033565fa90100d6c6efd003861267 100644 (file)
@@ -65,6 +65,40 @@ TRACE_EVENT(machine_suspend,
        TP_printk("state=%lu", (unsigned long)__entry->state)
 );
 
+DECLARE_EVENT_CLASS(wakeup_source,
+
+       TP_PROTO(const char *name, unsigned int state),
+
+       TP_ARGS(name, state),
+
+       TP_STRUCT__entry(
+               __string(       name,           name            )
+               __field(        u64,            state           )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, name);
+               __entry->state = state;
+       ),
+
+       TP_printk("%s state=0x%lx", __get_str(name),
+               (unsigned long)__entry->state)
+);
+
+DEFINE_EVENT(wakeup_source, wakeup_source_activate,
+
+       TP_PROTO(const char *name, unsigned int state),
+
+       TP_ARGS(name, state)
+);
+
+DEFINE_EVENT(wakeup_source, wakeup_source_deactivate,
+
+       TP_PROTO(const char *name, unsigned int state),
+
+       TP_ARGS(name, state)
+);
+
 #ifdef CONFIG_EVENT_POWER_TRACING_DEPRECATED
 
 /*
index da2d2d2e3f07cda3346728a4b5c40b657af911b0..a30fe085940ee8a51810e3204469a12cb06f8048 100644 (file)
@@ -27,6 +27,9 @@ config IRQ_WORK
        bool
        depends on HAVE_IRQ_WORK
 
+config BUILDTIME_EXTABLE_SORT
+       bool
+
 menu "General setup"
 
 config EXPERIMENTAL
index 91a4459258558a5bc9deef879884b827c777edab..5b06cbbf6931da0ab7c4e9f1b27a76f5418d64d8 100644 (file)
@@ -2039,8 +2039,8 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
  * accessing the event control register. If a NMI hits, then it will
  * not restart the event.
  */
-static void __perf_event_task_sched_out(struct task_struct *task,
-                                       struct task_struct *next)
+void __perf_event_task_sched_out(struct task_struct *task,
+                                struct task_struct *next)
 {
        int ctxn;
 
@@ -2279,8 +2279,8 @@ static void perf_branch_stack_sched_in(struct task_struct *prev,
  * accessing the event control register. If a NMI hits, then it will
  * keep the event running.
  */
-static void __perf_event_task_sched_in(struct task_struct *prev,
-                                      struct task_struct *task)
+void __perf_event_task_sched_in(struct task_struct *prev,
+                               struct task_struct *task)
 {
        struct perf_event_context *ctx;
        int ctxn;
@@ -2305,12 +2305,6 @@ static void __perf_event_task_sched_in(struct task_struct *prev,
                perf_branch_stack_sched_in(prev, task);
 }
 
-void __perf_event_task_sched(struct task_struct *prev, struct task_struct *next)
-{
-       __perf_event_task_sched_out(prev, next);
-       __perf_event_task_sched_in(prev, next);
-}
-
 static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
 {
        u64 frequency = event->attr.sample_freq;
index 5339705b82410515dcadce220ef997930dd3247c..fe35a634bf7695efd26856cf53e5d9bd9e14c357 100644 (file)
@@ -35,10 +35,16 @@ DEFINE_MUTEX(text_mutex);
 extern struct exception_table_entry __start___ex_table[];
 extern struct exception_table_entry __stop___ex_table[];
 
+/* Cleared by build time tools if the table is already sorted. */
+u32 __initdata main_extable_sort_needed = 1;
+
 /* Sort the kernel's built-in exception table */
 void __init sort_main_extable(void)
 {
-       sort_extable(__start___ex_table, __stop___ex_table);
+       if (main_extable_sort_needed)
+               sort_extable(__start___ex_table, __stop___ex_table);
+       else
+               pr_notice("__ex_table already sorted, skipping sort\n");
 }
 
 /* Given an address, look for it in the exception tables. */
index ad54c833116a60f7c384780c31181a80b1347b5d..05c813dc9ecc50efbf9012e765dfc64b8ddf9b6b 100644 (file)
@@ -292,8 +292,6 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
        int node = tsk_fork_get_node(orig);
        int err;
 
-       prepare_to_copy(orig);
-
        tsk = alloc_task_struct_node(node);
        if (!tsk)
                return NULL;
index 585f6381f8e45367b48c321d2b183890ab3befb5..bb32326afe8796be6ebbf240fbd3ef4bb1fc8cbe 100644 (file)
@@ -1220,12 +1220,6 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
        /* Found it - now remove it from the list of entries: */
        *action_ptr = action->next;
 
-       /* Currently used only by UML, might disappear one day: */
-#ifdef CONFIG_IRQ_RELEASE_METHOD
-       if (desc->irq_data.chip->release)
-               desc->irq_data.chip->release(irq, dev_id);
-#endif
-
        /* If this was the last handler, shut down the IRQ line: */
        if (!desc->action)
                irq_shutdown(desc);
index deb5461e3216905bc6b626da168bc98321e7b21f..8f9b4eb974e0bd27e435462433a581a9b42e63b8 100644 (file)
@@ -103,6 +103,33 @@ config PM_SLEEP_SMP
        select HOTPLUG
        select HOTPLUG_CPU
 
+config PM_AUTOSLEEP
+       bool "Opportunistic sleep"
+       depends on PM_SLEEP
+       default n
+       ---help---
+       Allow the kernel to trigger a system transition into a global sleep
+       state automatically whenever there are no active wakeup sources.
+
+config PM_WAKELOCKS
+       bool "User space wakeup sources interface"
+       depends on PM_SLEEP
+       default n
+       ---help---
+       Allow user space to create, activate and deactivate wakeup source
+       objects with the help of a sysfs-based interface.
+
+config PM_WAKELOCKS_LIMIT
+       int "Maximum number of user space wakeup sources (0 = no limit)"
+       range 0 100000
+       default 100
+       depends on PM_WAKELOCKS
+
+config PM_WAKELOCKS_GC
+       bool "Garbage collector for user space wakeup sources"
+       depends on PM_WAKELOCKS
+       default y
+
 config PM_RUNTIME
        bool "Run-time PM core functionality"
        depends on !IA64_HP_SIM
index 66d808ec525234bfee1433a4df2c33ff9c399201..29472bff11ef9b1c902e71a7ae9823a9e36c06e6 100644 (file)
@@ -9,5 +9,7 @@ obj-$(CONFIG_SUSPEND)           += suspend.o
 obj-$(CONFIG_PM_TEST_SUSPEND)  += suspend_test.o
 obj-$(CONFIG_HIBERNATION)      += hibernate.o snapshot.o swap.o user.o \
                                   block_io.o
+obj-$(CONFIG_PM_AUTOSLEEP)     += autosleep.o
+obj-$(CONFIG_PM_WAKELOCKS)     += wakelock.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)      += poweroff.o
diff --git a/kernel/power/autosleep.c b/kernel/power/autosleep.c
new file mode 100644 (file)
index 0000000..ca30404
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * kernel/power/autosleep.c
+ *
+ * Opportunistic sleep support.
+ *
+ * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
+ */
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/pm_wakeup.h>
+
+#include "power.h"
+
+static suspend_state_t autosleep_state;
+static struct workqueue_struct *autosleep_wq;
+/*
+ * Note: it is only safe to mutex_lock(&autosleep_lock) if a wakeup_source
+ * is active, otherwise a deadlock with try_to_suspend() is possible.
+ * Alternatively mutex_lock_interruptible() can be used.  This will then fail
+ * if an auto_sleep cycle tries to freeze processes.
+ */
+static DEFINE_MUTEX(autosleep_lock);
+static struct wakeup_source *autosleep_ws;
+
+static void try_to_suspend(struct work_struct *work)
+{
+       unsigned int initial_count, final_count;
+
+       if (!pm_get_wakeup_count(&initial_count, true))
+               goto out;
+
+       mutex_lock(&autosleep_lock);
+
+       if (!pm_save_wakeup_count(initial_count)) {
+               mutex_unlock(&autosleep_lock);
+               goto out;
+       }
+
+       if (autosleep_state == PM_SUSPEND_ON) {
+               mutex_unlock(&autosleep_lock);
+               return;
+       }
+       if (autosleep_state >= PM_SUSPEND_MAX)
+               hibernate();
+       else
+               pm_suspend(autosleep_state);
+
+       mutex_unlock(&autosleep_lock);
+
+       if (!pm_get_wakeup_count(&final_count, false))
+               goto out;
+
+       /*
+        * If the wakeup occured for an unknown reason, wait to prevent the
+        * system from trying to suspend and waking up in a tight loop.
+        */
+       if (final_count == initial_count)
+               schedule_timeout_uninterruptible(HZ / 2);
+
+ out:
+       queue_up_suspend_work();
+}
+
+static DECLARE_WORK(suspend_work, try_to_suspend);
+
+void queue_up_suspend_work(void)
+{
+       if (!work_pending(&suspend_work) && autosleep_state > PM_SUSPEND_ON)
+               queue_work(autosleep_wq, &suspend_work);
+}
+
+suspend_state_t pm_autosleep_state(void)
+{
+       return autosleep_state;
+}
+
+int pm_autosleep_lock(void)
+{
+       return mutex_lock_interruptible(&autosleep_lock);
+}
+
+void pm_autosleep_unlock(void)
+{
+       mutex_unlock(&autosleep_lock);
+}
+
+int pm_autosleep_set_state(suspend_state_t state)
+{
+
+#ifndef CONFIG_HIBERNATION
+       if (state >= PM_SUSPEND_MAX)
+               return -EINVAL;
+#endif
+
+       __pm_stay_awake(autosleep_ws);
+
+       mutex_lock(&autosleep_lock);
+
+       autosleep_state = state;
+
+       __pm_relax(autosleep_ws);
+
+       if (state > PM_SUSPEND_ON) {
+               pm_wakep_autosleep_enabled(true);
+               queue_up_suspend_work();
+       } else {
+               pm_wakep_autosleep_enabled(false);
+       }
+
+       mutex_unlock(&autosleep_lock);
+       return 0;
+}
+
+int __init pm_autosleep_init(void)
+{
+       autosleep_ws = wakeup_source_register("autosleep");
+       if (!autosleep_ws)
+               return -ENOMEM;
+
+       autosleep_wq = alloc_ordered_workqueue("autosleep", 0);
+       if (autosleep_wq)
+               return 0;
+
+       wakeup_source_unregister(autosleep_ws);
+       return -ENOMEM;
+}
index e09dfbfeecee43ca7fff59c327f213f9605ef0f4..8b53db38a279e50a1fe3a8719752fe245201e7a0 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/freezer.h>
 #include <linux/gfp.h>
 #include <linux/syscore_ops.h>
+#include <linux/ctype.h>
+#include <linux/genhd.h>
 #include <scsi/scsi_scan.h>
 
 #include "power.h"
@@ -722,6 +724,17 @@ static int software_resume(void)
 
        /* Check if the device is there */
        swsusp_resume_device = name_to_dev_t(resume_file);
+
+       /*
+        * name_to_dev_t is ineffective to verify parition if resume_file is in
+        * integer format. (e.g. major:minor)
+        */
+       if (isdigit(resume_file[0]) && resume_wait) {
+               int partno;
+               while (!get_gendisk(swsusp_resume_device, &partno))
+                       msleep(10);
+       }
+
        if (!swsusp_resume_device) {
                /*
                 * Some device discovery might still be in progress; we need
index 1c12581f1c62ce56bfe61bae08d58745309b0b9d..428f8a034e9684c50a72f41faf71785822456bd5 100644 (file)
@@ -269,8 +269,7 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
        return (s - buf);
 }
 
-static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
-                          const char *buf, size_t n)
+static suspend_state_t decode_state(const char *buf, size_t n)
 {
 #ifdef CONFIG_SUSPEND
        suspend_state_t state = PM_SUSPEND_STANDBY;
@@ -278,27 +277,48 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
 #endif
        char *p;
        int len;
-       int error = -EINVAL;
 
        p = memchr(buf, '\n', n);
        len = p ? p - buf : n;
 
-       /* First, check if we are requested to hibernate */
-       if (len == 4 && !strncmp(buf, "disk", len)) {
-               error = hibernate();
-               goto Exit;
-       }
+       /* Check hibernation first. */
+       if (len == 4 && !strncmp(buf, "disk", len))
+               return PM_SUSPEND_MAX;
 
 #ifdef CONFIG_SUSPEND
-       for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
-               if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
-                       error = pm_suspend(state);
-                       break;
-               }
-       }
+       for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++)
+               if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
+                       return state;
 #endif
 
- Exit:
+       return PM_SUSPEND_ON;
+}
+
+static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
+                          const char *buf, size_t n)
+{
+       suspend_state_t state;
+       int error;
+
+       error = pm_autosleep_lock();
+       if (error)
+               return error;
+
+       if (pm_autosleep_state() > PM_SUSPEND_ON) {
+               error = -EBUSY;
+               goto out;
+       }
+
+       state = decode_state(buf, n);
+       if (state < PM_SUSPEND_MAX)
+               error = pm_suspend(state);
+       else if (state == PM_SUSPEND_MAX)
+               error = hibernate();
+       else
+               error = -EINVAL;
+
+ out:
+       pm_autosleep_unlock();
        return error ? error : n;
 }
 
@@ -339,7 +359,8 @@ static ssize_t wakeup_count_show(struct kobject *kobj,
 {
        unsigned int val;
 
-       return pm_get_wakeup_count(&val) ? sprintf(buf, "%u\n", val) : -EINTR;
+       return pm_get_wakeup_count(&val, true) ?
+               sprintf(buf, "%u\n", val) : -EINTR;
 }
 
 static ssize_t wakeup_count_store(struct kobject *kobj,
@@ -347,15 +368,106 @@ static ssize_t wakeup_count_store(struct kobject *kobj,
                                const char *buf, size_t n)
 {
        unsigned int val;
+       int error;
+
+       error = pm_autosleep_lock();
+       if (error)
+               return error;
+
+       if (pm_autosleep_state() > PM_SUSPEND_ON) {
+               error = -EBUSY;
+               goto out;
+       }
 
+       error = -EINVAL;
        if (sscanf(buf, "%u", &val) == 1) {
                if (pm_save_wakeup_count(val))
-                       return n;
+                       error = n;
        }
-       return -EINVAL;
+
+ out:
+       pm_autosleep_unlock();
+       return error;
 }
 
 power_attr(wakeup_count);
+
+#ifdef CONFIG_PM_AUTOSLEEP
+static ssize_t autosleep_show(struct kobject *kobj,
+                             struct kobj_attribute *attr,
+                             char *buf)
+{
+       suspend_state_t state = pm_autosleep_state();
+
+       if (state == PM_SUSPEND_ON)
+               return sprintf(buf, "off\n");
+
+#ifdef CONFIG_SUSPEND
+       if (state < PM_SUSPEND_MAX)
+               return sprintf(buf, "%s\n", valid_state(state) ?
+                                               pm_states[state] : "error");
+#endif
+#ifdef CONFIG_HIBERNATION
+       return sprintf(buf, "disk\n");
+#else
+       return sprintf(buf, "error");
+#endif
+}
+
+static ssize_t autosleep_store(struct kobject *kobj,
+                              struct kobj_attribute *attr,
+                              const char *buf, size_t n)
+{
+       suspend_state_t state = decode_state(buf, n);
+       int error;
+
+       if (state == PM_SUSPEND_ON
+           && strcmp(buf, "off") && strcmp(buf, "off\n"))
+               return -EINVAL;
+
+       error = pm_autosleep_set_state(state);
+       return error ? error : n;
+}
+
+power_attr(autosleep);
+#endif /* CONFIG_PM_AUTOSLEEP */
+
+#ifdef CONFIG_PM_WAKELOCKS
+static ssize_t wake_lock_show(struct kobject *kobj,
+                             struct kobj_attribute *attr,
+                             char *buf)
+{
+       return pm_show_wakelocks(buf, true);
+}
+
+static ssize_t wake_lock_store(struct kobject *kobj,
+                              struct kobj_attribute *attr,
+                              const char *buf, size_t n)
+{
+       int error = pm_wake_lock(buf);
+       return error ? error : n;
+}
+
+power_attr(wake_lock);
+
+static ssize_t wake_unlock_show(struct kobject *kobj,
+                               struct kobj_attribute *attr,
+                               char *buf)
+{
+       return pm_show_wakelocks(buf, false);
+}
+
+static ssize_t wake_unlock_store(struct kobject *kobj,
+                                struct kobj_attribute *attr,
+                                const char *buf, size_t n)
+{
+       int error = pm_wake_unlock(buf);
+       return error ? error : n;
+}
+
+power_attr(wake_unlock);
+
+#endif /* CONFIG_PM_WAKELOCKS */
 #endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PM_TRACE
@@ -409,6 +521,13 @@ static struct attribute * g[] = {
 #ifdef CONFIG_PM_SLEEP
        &pm_async_attr.attr,
        &wakeup_count_attr.attr,
+#ifdef CONFIG_PM_AUTOSLEEP
+       &autosleep_attr.attr,
+#endif
+#ifdef CONFIG_PM_WAKELOCKS
+       &wake_lock_attr.attr,
+       &wake_unlock_attr.attr,
+#endif
 #ifdef CONFIG_PM_DEBUG
        &pm_test_attr.attr,
 #endif
@@ -444,7 +563,10 @@ static int __init pm_init(void)
        power_kobj = kobject_create_and_add("power", NULL);
        if (!power_kobj)
                return -ENOMEM;
-       return sysfs_create_group(power_kobj, &attr_group);
+       error = sysfs_create_group(power_kobj, &attr_group);
+       if (error)
+               return error;
+       return pm_autosleep_init();
 }
 
 core_initcall(pm_init);
index 98f3622d740713dcf1b6bdfa170b00885d90f121..b0bd4beaebfe7caa84c4c3b4ded37d3e47acacd6 100644 (file)
@@ -264,3 +264,30 @@ static inline void suspend_thaw_processes(void)
 {
 }
 #endif
+
+#ifdef CONFIG_PM_AUTOSLEEP
+
+/* kernel/power/autosleep.c */
+extern int pm_autosleep_init(void);
+extern int pm_autosleep_lock(void);
+extern void pm_autosleep_unlock(void);
+extern suspend_state_t pm_autosleep_state(void);
+extern int pm_autosleep_set_state(suspend_state_t state);
+
+#else /* !CONFIG_PM_AUTOSLEEP */
+
+static inline int pm_autosleep_init(void) { return 0; }
+static inline int pm_autosleep_lock(void) { return 0; }
+static inline void pm_autosleep_unlock(void) {}
+static inline suspend_state_t pm_autosleep_state(void) { return PM_SUSPEND_ON; }
+
+#endif /* !CONFIG_PM_AUTOSLEEP */
+
+#ifdef CONFIG_PM_WAKELOCKS
+
+/* kernel/power/wakelock.c */
+extern ssize_t pm_show_wakelocks(char *buf, bool show_active);
+extern int pm_wake_lock(const char *buf);
+extern int pm_wake_unlock(const char *buf);
+
+#endif /* !CONFIG_PM_WAKELOCKS */
index eef311a58a649821f60532602a085f2a79b014bc..11e22c068e8b25ab8c6ba1127be955d2d4d33e39 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
  * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
- * Copyright (C) 2010 Bojan Smojver <bojan@rexursive.com>
+ * Copyright (C) 2010-2012 Bojan Smojver <bojan@rexursive.com>
  *
  * This file is released under the GPLv2.
  *
@@ -282,14 +282,17 @@ static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
                return -ENOSPC;
 
        if (bio_chain) {
-               src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+               src = (void *)__get_free_page(__GFP_WAIT | __GFP_NOWARN |
+                                             __GFP_NORETRY);
                if (src) {
                        copy_page(src, buf);
                } else {
                        ret = hib_wait_on_bio_chain(bio_chain); /* Free pages */
                        if (ret)
                                return ret;
-                       src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+                       src = (void *)__get_free_page(__GFP_WAIT |
+                                                     __GFP_NOWARN |
+                                                     __GFP_NORETRY);
                        if (src) {
                                copy_page(src, buf);
                        } else {
@@ -367,12 +370,17 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
                clear_page(handle->cur);
                handle->cur_swap = offset;
                handle->k = 0;
-       }
-       if (bio_chain && low_free_pages() <= handle->reqd_free_pages) {
-               error = hib_wait_on_bio_chain(bio_chain);
-               if (error)
-                       goto out;
-               handle->reqd_free_pages = reqd_free_pages();
+
+               if (bio_chain && low_free_pages() <= handle->reqd_free_pages) {
+                       error = hib_wait_on_bio_chain(bio_chain);
+                       if (error)
+                               goto out;
+                       /*
+                        * Recalculate the number of required free pages, to
+                        * make sure we never take more than half.
+                        */
+                       handle->reqd_free_pages = reqd_free_pages();
+               }
        }
  out:
        return error;
@@ -419,8 +427,9 @@ static int swap_writer_finish(struct swap_map_handle *handle,
 /* Maximum number of threads for compression/decompression. */
 #define LZO_THREADS    3
 
-/* Maximum number of pages for read buffering. */
-#define LZO_READ_PAGES (MAP_PAGE_ENTRIES * 8)
+/* Minimum/maximum number of pages for read buffering. */
+#define LZO_MIN_RD_PAGES       1024
+#define LZO_MAX_RD_PAGES       8192
 
 
 /**
@@ -630,12 +639,6 @@ static int save_image_lzo(struct swap_map_handle *handle,
                }
        }
 
-       /*
-        * Adjust number of free pages after all allocations have been done.
-        * We don't want to run out of pages when writing.
-        */
-       handle->reqd_free_pages = reqd_free_pages();
-
        /*
         * Start the CRC32 thread.
         */
@@ -657,6 +660,12 @@ static int save_image_lzo(struct swap_map_handle *handle,
                goto out_clean;
        }
 
+       /*
+        * Adjust the number of required free pages after all allocations have
+        * been done. We don't want to run out of pages when writing.
+        */
+       handle->reqd_free_pages = reqd_free_pages();
+
        printk(KERN_INFO
                "PM: Using %u thread(s) for compression.\n"
                "PM: Compressing and saving image data (%u pages) ...     ",
@@ -1067,7 +1076,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
        unsigned i, thr, run_threads, nr_threads;
        unsigned ring = 0, pg = 0, ring_size = 0,
                 have = 0, want, need, asked = 0;
-       unsigned long read_pages;
+       unsigned long read_pages = 0;
        unsigned char **page = NULL;
        struct dec_data *data = NULL;
        struct crc_data *crc = NULL;
@@ -1079,7 +1088,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
        nr_threads = num_online_cpus() - 1;
        nr_threads = clamp_val(nr_threads, 1, LZO_THREADS);
 
-       page = vmalloc(sizeof(*page) * LZO_READ_PAGES);
+       page = vmalloc(sizeof(*page) * LZO_MAX_RD_PAGES);
        if (!page) {
                printk(KERN_ERR "PM: Failed to allocate LZO page\n");
                ret = -ENOMEM;
@@ -1144,15 +1153,22 @@ static int load_image_lzo(struct swap_map_handle *handle,
        }
 
        /*
-        * Adjust number of pages for read buffering, in case we are short.
+        * Set the number of pages for read buffering.
+        * This is complete guesswork, because we'll only know the real
+        * picture once prepare_image() is called, which is much later on
+        * during the image load phase. We'll assume the worst case and
+        * say that none of the image pages are from high memory.
         */
-       read_pages = (nr_free_pages() - snapshot_get_image_size()) >> 1;
-       read_pages = clamp_val(read_pages, LZO_CMP_PAGES, LZO_READ_PAGES);
+       if (low_free_pages() > snapshot_get_image_size())
+               read_pages = (low_free_pages() - snapshot_get_image_size()) / 2;
+       read_pages = clamp_val(read_pages, LZO_MIN_RD_PAGES, LZO_MAX_RD_PAGES);
 
        for (i = 0; i < read_pages; i++) {
                page[i] = (void *)__get_free_page(i < LZO_CMP_PAGES ?
                                                  __GFP_WAIT | __GFP_HIGH :
-                                                 __GFP_WAIT);
+                                                 __GFP_WAIT | __GFP_NOWARN |
+                                                 __GFP_NORETRY);
+
                if (!page[i]) {
                        if (i < LZO_CMP_PAGES) {
                                ring_size = i;
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
new file mode 100644 (file)
index 0000000..c8fba33
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * kernel/power/wakelock.c
+ *
+ * User space wakeup sources support.
+ *
+ * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
+ *
+ * This code is based on the analogous interface allowing user space to
+ * manipulate wakelocks on Android.
+ */
+
+#include <linux/ctype.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(wakelocks_lock);
+
+struct wakelock {
+       char                    *name;
+       struct rb_node          node;
+       struct wakeup_source    ws;
+#ifdef CONFIG_PM_WAKELOCKS_GC
+       struct list_head        lru;
+#endif
+};
+
+static struct rb_root wakelocks_tree = RB_ROOT;
+
+ssize_t pm_show_wakelocks(char *buf, bool show_active)
+{
+       struct rb_node *node;
+       struct wakelock *wl;
+       char *str = buf;
+       char *end = buf + PAGE_SIZE;
+
+       mutex_lock(&wakelocks_lock);
+
+       for (node = rb_first(&wakelocks_tree); node; node = rb_next(node)) {
+               wl = rb_entry(node, struct wakelock, node);
+               if (wl->ws.active == show_active)
+                       str += scnprintf(str, end - str, "%s ", wl->name);
+       }
+       if (str > buf)
+               str--;
+
+       str += scnprintf(str, end - str, "\n");
+
+       mutex_unlock(&wakelocks_lock);
+       return (str - buf);
+}
+
+#if CONFIG_PM_WAKELOCKS_LIMIT > 0
+static unsigned int number_of_wakelocks;
+
+static inline bool wakelocks_limit_exceeded(void)
+{
+       return number_of_wakelocks > CONFIG_PM_WAKELOCKS_LIMIT;
+}
+
+static inline void increment_wakelocks_number(void)
+{
+       number_of_wakelocks++;
+}
+
+static inline void decrement_wakelocks_number(void)
+{
+       number_of_wakelocks--;
+}
+#else /* CONFIG_PM_WAKELOCKS_LIMIT = 0 */
+static inline bool wakelocks_limit_exceeded(void) { return false; }
+static inline void increment_wakelocks_number(void) {}
+static inline void decrement_wakelocks_number(void) {}
+#endif /* CONFIG_PM_WAKELOCKS_LIMIT */
+
+#ifdef CONFIG_PM_WAKELOCKS_GC
+#define WL_GC_COUNT_MAX        100
+#define WL_GC_TIME_SEC 300
+
+static LIST_HEAD(wakelocks_lru_list);
+static unsigned int wakelocks_gc_count;
+
+static inline void wakelocks_lru_add(struct wakelock *wl)
+{
+       list_add(&wl->lru, &wakelocks_lru_list);
+}
+
+static inline void wakelocks_lru_most_recent(struct wakelock *wl)
+{
+       list_move(&wl->lru, &wakelocks_lru_list);
+}
+
+static void wakelocks_gc(void)
+{
+       struct wakelock *wl, *aux;
+       ktime_t now;
+
+       if (++wakelocks_gc_count <= WL_GC_COUNT_MAX)
+               return;
+
+       now = ktime_get();
+       list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
+               u64 idle_time_ns;
+               bool active;
+
+               spin_lock_irq(&wl->ws.lock);
+               idle_time_ns = ktime_to_ns(ktime_sub(now, wl->ws.last_time));
+               active = wl->ws.active;
+               spin_unlock_irq(&wl->ws.lock);
+
+               if (idle_time_ns < ((u64)WL_GC_TIME_SEC * NSEC_PER_SEC))
+                       break;
+
+               if (!active) {
+                       wakeup_source_remove(&wl->ws);
+                       rb_erase(&wl->node, &wakelocks_tree);
+                       list_del(&wl->lru);
+                       kfree(wl->name);
+                       kfree(wl);
+                       decrement_wakelocks_number();
+               }
+       }
+       wakelocks_gc_count = 0;
+}
+#else /* !CONFIG_PM_WAKELOCKS_GC */
+static inline void wakelocks_lru_add(struct wakelock *wl) {}
+static inline void wakelocks_lru_most_recent(struct wakelock *wl) {}
+static inline void wakelocks_gc(void) {}
+#endif /* !CONFIG_PM_WAKELOCKS_GC */
+
+static struct wakelock *wakelock_lookup_add(const char *name, size_t len,
+                                           bool add_if_not_found)
+{
+       struct rb_node **node = &wakelocks_tree.rb_node;
+       struct rb_node *parent = *node;
+       struct wakelock *wl;
+
+       while (*node) {
+               int diff;
+
+               parent = *node;
+               wl = rb_entry(*node, struct wakelock, node);
+               diff = strncmp(name, wl->name, len);
+               if (diff == 0) {
+                       if (wl->name[len])
+                               diff = -1;
+                       else
+                               return wl;
+               }
+               if (diff < 0)
+                       node = &(*node)->rb_left;
+               else
+                       node = &(*node)->rb_right;
+       }
+       if (!add_if_not_found)
+               return ERR_PTR(-EINVAL);
+
+       if (wakelocks_limit_exceeded())
+               return ERR_PTR(-ENOSPC);
+
+       /* Not found, we have to add a new one. */
+       wl = kzalloc(sizeof(*wl), GFP_KERNEL);
+       if (!wl)
+               return ERR_PTR(-ENOMEM);
+
+       wl->name = kstrndup(name, len, GFP_KERNEL);
+       if (!wl->name) {
+               kfree(wl);
+               return ERR_PTR(-ENOMEM);
+       }
+       wl->ws.name = wl->name;
+       wakeup_source_add(&wl->ws);
+       rb_link_node(&wl->node, parent, node);
+       rb_insert_color(&wl->node, &wakelocks_tree);
+       wakelocks_lru_add(wl);
+       increment_wakelocks_number();
+       return wl;
+}
+
+int pm_wake_lock(const char *buf)
+{
+       const char *str = buf;
+       struct wakelock *wl;
+       u64 timeout_ns = 0;
+       size_t len;
+       int ret = 0;
+
+       while (*str && !isspace(*str))
+               str++;
+
+       len = str - buf;
+       if (!len)
+               return -EINVAL;
+
+       if (*str && *str != '\n') {
+               /* Find out if there's a valid timeout string appended. */
+               ret = kstrtou64(skip_spaces(str), 10, &timeout_ns);
+               if (ret)
+                       return -EINVAL;
+       }
+
+       mutex_lock(&wakelocks_lock);
+
+       wl = wakelock_lookup_add(buf, len, true);
+       if (IS_ERR(wl)) {
+               ret = PTR_ERR(wl);
+               goto out;
+       }
+       if (timeout_ns) {
+               u64 timeout_ms = timeout_ns + NSEC_PER_MSEC - 1;
+
+               do_div(timeout_ms, NSEC_PER_MSEC);
+               __pm_wakeup_event(&wl->ws, timeout_ms);
+       } else {
+               __pm_stay_awake(&wl->ws);
+       }
+
+       wakelocks_lru_most_recent(wl);
+
+ out:
+       mutex_unlock(&wakelocks_lock);
+       return ret;
+}
+
+int pm_wake_unlock(const char *buf)
+{
+       struct wakelock *wl;
+       size_t len;
+       int ret = 0;
+
+       len = strlen(buf);
+       if (!len)
+               return -EINVAL;
+
+       if (buf[len-1] == '\n')
+               len--;
+
+       if (!len)
+               return -EINVAL;
+
+       mutex_lock(&wakelocks_lock);
+
+       wl = wakelock_lookup_add(buf, len, false);
+       if (IS_ERR(wl)) {
+               ret = PTR_ERR(wl);
+               goto out;
+       }
+       __pm_relax(&wl->ws);
+
+       wakelocks_lru_most_recent(wl);
+       wakelocks_gc();
+
+ out:
+       mutex_unlock(&wakelocks_lock);
+       return ret;
+}
index d833cc94eedcf7599dc1d63b5809465c1ba875e2..a5a9d39b845cfaed2838a1fe1e0afd49f0609a3a 100644 (file)
@@ -1912,7 +1912,7 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
                    struct task_struct *next)
 {
        sched_info_switch(prev, next);
-       perf_event_task_sched(prev, next);
+       perf_event_task_sched_out(prev, next);
        fire_sched_out_preempt_notifiers(prev, next);
        prepare_lock_switch(rq, next);
        prepare_arch_switch(next);
@@ -1955,6 +1955,13 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)
         */
        prev_state = prev->state;
        finish_arch_switch(prev);
+#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
+       local_irq_disable();
+#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
+       perf_event_task_sched_in(prev, current);
+#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
+       local_irq_enable();
+#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
        finish_lock_switch(rq, prev);
        finish_arch_post_lock_switch();
 
index e119341770308c2341bdc59b008ce6636b4492b3..a42d3ae39648386b81a649e9844afd4e0b03bca9 100644 (file)
@@ -74,6 +74,15 @@ config STRIP_ASM_SYMS
          that look like '.Lxxx') so they don't pollute the output of
          get_wchan() and suchlike.
 
+config READABLE_ASM
+        bool "Generate readable assembler code"
+        depends on DEBUG_KERNEL
+        help
+          Disable some compiler optimizations that tend to generate human unreadable
+          assembler output. This may make the kernel slightly slower, but it helps
+          to keep kernel developers who have to stare a lot at assembler listings
+          sane.
+
 config UNUSED_SYMBOLS
        bool "Enable unused/obsolete exported symbols"
        default y if X86
index 105b21f0818597e4c881e3f1b7e4f286616cc8d9..65f362d931b59c0882f842fd824273e01049dd89 100644 (file)
@@ -9,3 +9,4 @@ unifdef
 ihex2fw
 recordmcount
 docproc
+sortextable
index 36266665dbcbb37ca9d3c3dd466268fa0dbf1265..a55b0067758a0fb5b35115dbc5f1affa35e69719 100644 (file)
@@ -15,6 +15,9 @@ hostprogs-$(CONFIG_LOGO)         += pnmtologo
 hostprogs-$(CONFIG_VT)           += conmakehash
 hostprogs-$(CONFIG_IKCONFIG)     += bin2c
 hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
+hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
+
+HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
 
 always         := $(hostprogs-y) $(hostprogs-m)
 
diff --git a/scripts/sortextable.c b/scripts/sortextable.c
new file mode 100644 (file)
index 0000000..1ca9ceb
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * sortextable.c: Sort the kernel's exception table
+ *
+ * Copyright 2011 - 2012 Cavium, Inc.
+ *
+ * Based on code taken from recortmcount.c which is:
+ *
+ * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
+ * Licensed under the GNU General Public License, version 2 (GPLv2).
+ *
+ * Restructured to fit Linux format, as well as other updates:
+ *  Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
+ */
+
+/*
+ * Strategy: alter the vmlinux file in-place.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <elf.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tools/be_byteshift.h>
+#include <tools/le_byteshift.h>
+
+static int fd_map;     /* File descriptor for file being modified. */
+static int mmap_failed; /* Boolean flag. */
+static void *ehdr_curr; /* current ElfXX_Ehdr *  for resource cleanup */
+static struct stat sb; /* Remember .st_size, etc. */
+static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
+
+/* setjmp() return values */
+enum {
+       SJ_SETJMP = 0,  /* hardwired first return */
+       SJ_FAIL,
+       SJ_SUCCEED
+};
+
+/* Per-file resource cleanup when multiple files. */
+static void
+cleanup(void)
+{
+       if (!mmap_failed)
+               munmap(ehdr_curr, sb.st_size);
+       close(fd_map);
+}
+
+static void __attribute__((noreturn))
+fail_file(void)
+{
+       cleanup();
+       longjmp(jmpenv, SJ_FAIL);
+}
+
+static void __attribute__((noreturn))
+succeed_file(void)
+{
+       cleanup();
+       longjmp(jmpenv, SJ_SUCCEED);
+}
+
+
+/*
+ * Get the whole file as a programming convenience in order to avoid
+ * malloc+lseek+read+free of many pieces.  If successful, then mmap
+ * avoids copying unused pieces; else just read the whole file.
+ * Open for both read and write.
+ */
+static void *mmap_file(char const *fname)
+{
+       void *addr;
+
+       fd_map = open(fname, O_RDWR);
+       if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
+               perror(fname);
+               fail_file();
+       }
+       if (!S_ISREG(sb.st_mode)) {
+               fprintf(stderr, "not a regular file: %s\n", fname);
+               fail_file();
+       }
+       addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED,
+                   fd_map, 0);
+       if (addr == MAP_FAILED) {
+               mmap_failed = 1;
+               fprintf(stderr, "Could not mmap file: %s\n", fname);
+               fail_file();
+       }
+       return addr;
+}
+
+static uint64_t r8be(const uint64_t *x)
+{
+       return get_unaligned_be64(x);
+}
+static uint32_t rbe(const uint32_t *x)
+{
+       return get_unaligned_be32(x);
+}
+static uint16_t r2be(const uint16_t *x)
+{
+       return get_unaligned_be16(x);
+}
+static uint64_t r8le(const uint64_t *x)
+{
+       return get_unaligned_le64(x);
+}
+static uint32_t rle(const uint32_t *x)
+{
+       return get_unaligned_le32(x);
+}
+static uint16_t r2le(const uint16_t *x)
+{
+       return get_unaligned_le16(x);
+}
+
+static void w8be(uint64_t val, uint64_t *x)
+{
+       put_unaligned_be64(val, x);
+}
+static void wbe(uint32_t val, uint32_t *x)
+{
+       put_unaligned_be32(val, x);
+}
+static void w2be(uint16_t val, uint16_t *x)
+{
+       put_unaligned_be16(val, x);
+}
+static void w8le(uint64_t val, uint64_t *x)
+{
+       put_unaligned_le64(val, x);
+}
+static void wle(uint32_t val, uint32_t *x)
+{
+       put_unaligned_le32(val, x);
+}
+static void w2le(uint16_t val, uint16_t *x)
+{
+       put_unaligned_le16(val, x);
+}
+
+static uint64_t (*r8)(const uint64_t *);
+static uint32_t (*r)(const uint32_t *);
+static uint16_t (*r2)(const uint16_t *);
+static void (*w8)(uint64_t, uint64_t *);
+static void (*w)(uint32_t, uint32_t *);
+static void (*w2)(uint16_t, uint16_t *);
+
+typedef void (*table_sort_t)(char *, int);
+
+/* 32 bit and 64 bit are very similar */
+#include "sortextable.h"
+#define SORTEXTABLE_64
+#include "sortextable.h"
+
+static int compare_x86_table(const void *a, const void *b)
+{
+       int32_t av = (int32_t)r(a);
+       int32_t bv = (int32_t)r(b);
+
+       if (av < bv)
+               return -1;
+       if (av > bv)
+               return 1;
+       return 0;
+}
+
+static void sort_x86_table(char *extab_image, int image_size)
+{
+       int i;
+
+       /*
+        * Do the same thing the runtime sort does, first normalize to
+        * being relative to the start of the section.
+        */
+       i = 0;
+       while (i < image_size) {
+               uint32_t *loc = (uint32_t *)(extab_image + i);
+               w(r(loc) + i, loc);
+               i += 4;
+       }
+
+       qsort(extab_image, image_size / 8, 8, compare_x86_table);
+
+       /* Now denormalize. */
+       i = 0;
+       while (i < image_size) {
+               uint32_t *loc = (uint32_t *)(extab_image + i);
+               w(r(loc) - i, loc);
+               i += 4;
+       }
+}
+
+static void
+do_file(char const *const fname)
+{
+       table_sort_t custom_sort;
+       Elf32_Ehdr *ehdr = mmap_file(fname);
+
+       ehdr_curr = ehdr;
+       switch (ehdr->e_ident[EI_DATA]) {
+       default:
+               fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
+                       ehdr->e_ident[EI_DATA], fname);
+               fail_file();
+               break;
+       case ELFDATA2LSB:
+               r = rle;
+               r2 = r2le;
+               r8 = r8le;
+               w = wle;
+               w2 = w2le;
+               w8 = w8le;
+               break;
+       case ELFDATA2MSB:
+               r = rbe;
+               r2 = r2be;
+               r8 = r8be;
+               w = wbe;
+               w2 = w2be;
+               w8 = w8be;
+               break;
+       }  /* end switch */
+       if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
+       ||  r2(&ehdr->e_type) != ET_EXEC
+       ||  ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
+               fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname);
+               fail_file();
+       }
+
+       custom_sort = NULL;
+       switch (r2(&ehdr->e_machine)) {
+       default:
+               fprintf(stderr, "unrecognized e_machine %d %s\n",
+                       r2(&ehdr->e_machine), fname);
+               fail_file();
+               break;
+       case EM_386:
+       case EM_X86_64:
+               custom_sort = sort_x86_table;
+               break;
+       case EM_MIPS:
+               break;
+       }  /* end switch */
+
+       switch (ehdr->e_ident[EI_CLASS]) {
+       default:
+               fprintf(stderr, "unrecognized ELF class %d %s\n",
+                       ehdr->e_ident[EI_CLASS], fname);
+               fail_file();
+               break;
+       case ELFCLASS32:
+               if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
+               ||  r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
+                       fprintf(stderr,
+                               "unrecognized ET_EXEC file: %s\n", fname);
+                       fail_file();
+               }
+               do32(ehdr, fname, custom_sort);
+               break;
+       case ELFCLASS64: {
+               Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
+               if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
+               ||  r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
+                       fprintf(stderr,
+                               "unrecognized ET_EXEC file: %s\n", fname);
+                       fail_file();
+               }
+               do64(ghdr, fname, custom_sort);
+               break;
+       }
+       }  /* end switch */
+
+       cleanup();
+}
+
+int
+main(int argc, char *argv[])
+{
+       int n_error = 0;  /* gcc-4.3.0 false positive complaint */
+       int i;
+
+       if (argc < 2) {
+               fprintf(stderr, "usage: sortextable vmlinux...\n");
+               return 0;
+       }
+
+       /* Process each file in turn, allowing deep failure. */
+       for (i = 1; i < argc; i++) {
+               char *file = argv[i];
+               int const sjval = setjmp(jmpenv);
+
+               switch (sjval) {
+               default:
+                       fprintf(stderr, "internal error: %s\n", file);
+                       exit(1);
+                       break;
+               case SJ_SETJMP:    /* normal sequence */
+                       /* Avoid problems if early cleanup() */
+                       fd_map = -1;
+                       ehdr_curr = NULL;
+                       mmap_failed = 1;
+                       do_file(file);
+                       break;
+               case SJ_FAIL:    /* error in do_file or below */
+                       ++n_error;
+                       break;
+               case SJ_SUCCEED:    /* premature success */
+                       /* do nothing */
+                       break;
+               }  /* end switch */
+       }
+       return !!n_error;
+}
diff --git a/scripts/sortextable.h b/scripts/sortextable.h
new file mode 100644 (file)
index 0000000..e4fd45b
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * sortextable.h
+ *
+ * Copyright 2011 - 2012 Cavium, Inc.
+ *
+ * Some of this code was taken out of recordmcount.h written by:
+ *
+ * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
+ * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
+ *
+ *
+ * Licensed under the GNU General Public License, version 2 (GPLv2).
+ */
+
+#undef extable_ent_size
+#undef compare_extable
+#undef do_func
+#undef Elf_Addr
+#undef Elf_Ehdr
+#undef Elf_Shdr
+#undef Elf_Rel
+#undef Elf_Rela
+#undef Elf_Sym
+#undef ELF_R_SYM
+#undef Elf_r_sym
+#undef ELF_R_INFO
+#undef Elf_r_info
+#undef ELF_ST_BIND
+#undef ELF_ST_TYPE
+#undef fn_ELF_R_SYM
+#undef fn_ELF_R_INFO
+#undef uint_t
+#undef _r
+#undef _w
+
+#ifdef SORTEXTABLE_64
+# define extable_ent_size      16
+# define compare_extable       compare_extable_64
+# define do_func               do64
+# define Elf_Addr              Elf64_Addr
+# define Elf_Ehdr              Elf64_Ehdr
+# define Elf_Shdr              Elf64_Shdr
+# define Elf_Rel               Elf64_Rel
+# define Elf_Rela              Elf64_Rela
+# define Elf_Sym               Elf64_Sym
+# define ELF_R_SYM             ELF64_R_SYM
+# define Elf_r_sym             Elf64_r_sym
+# define ELF_R_INFO            ELF64_R_INFO
+# define Elf_r_info            Elf64_r_info
+# define ELF_ST_BIND           ELF64_ST_BIND
+# define ELF_ST_TYPE           ELF64_ST_TYPE
+# define fn_ELF_R_SYM          fn_ELF64_R_SYM
+# define fn_ELF_R_INFO         fn_ELF64_R_INFO
+# define uint_t                        uint64_t
+# define _r                    r8
+# define _w                    w8
+#else
+# define extable_ent_size      8
+# define compare_extable       compare_extable_32
+# define do_func               do32
+# define Elf_Addr              Elf32_Addr
+# define Elf_Ehdr              Elf32_Ehdr
+# define Elf_Shdr              Elf32_Shdr
+# define Elf_Rel               Elf32_Rel
+# define Elf_Rela              Elf32_Rela
+# define Elf_Sym               Elf32_Sym
+# define ELF_R_SYM             ELF32_R_SYM
+# define Elf_r_sym             Elf32_r_sym
+# define ELF_R_INFO            ELF32_R_INFO
+# define Elf_r_info            Elf32_r_info
+# define ELF_ST_BIND           ELF32_ST_BIND
+# define ELF_ST_TYPE           ELF32_ST_TYPE
+# define fn_ELF_R_SYM          fn_ELF32_R_SYM
+# define fn_ELF_R_INFO         fn_ELF32_R_INFO
+# define uint_t                        uint32_t
+# define _r                    r
+# define _w                    w
+#endif
+
+static int compare_extable(const void *a, const void *b)
+{
+       Elf_Addr av = _r(a);
+       Elf_Addr bv = _r(b);
+
+       if (av < bv)
+               return -1;
+       if (av > bv)
+               return 1;
+       return 0;
+}
+
+static void
+do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort)
+{
+       Elf_Shdr *shdr;
+       Elf_Shdr *shstrtab_sec;
+       Elf_Shdr *strtab_sec = NULL;
+       Elf_Shdr *symtab_sec = NULL;
+       Elf_Shdr *extab_sec = NULL;
+       Elf_Sym *sym;
+       Elf_Sym *sort_needed_sym;
+       Elf_Shdr *sort_needed_sec;
+       Elf_Rel *relocs = NULL;
+       int relocs_size;
+       uint32_t *sort_done_location;
+       const char *secstrtab;
+       const char *strtab;
+       char *extab_image;
+       int extab_index = 0;
+       int i;
+       int idx;
+
+       shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
+       shstrtab_sec = shdr + r2(&ehdr->e_shstrndx);
+       secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset);
+       for (i = 0; i < r2(&ehdr->e_shnum); i++) {
+               idx = r(&shdr[i].sh_name);
+               if (strcmp(secstrtab + idx, "__ex_table") == 0) {
+                       extab_sec = shdr + i;
+                       extab_index = i;
+               }
+               if ((r(&shdr[i].sh_type) == SHT_REL ||
+                    r(&shdr[i].sh_type) == SHT_RELA) &&
+                   r(&shdr[i].sh_info) == extab_index) {
+                       relocs = (void *)ehdr + _r(&shdr[i].sh_offset);
+                       relocs_size = _r(&shdr[i].sh_size);
+               }
+               if (strcmp(secstrtab + idx, ".symtab") == 0)
+                       symtab_sec = shdr + i;
+               if (strcmp(secstrtab + idx, ".strtab") == 0)
+                       strtab_sec = shdr + i;
+       }
+       if (strtab_sec == NULL) {
+               fprintf(stderr, "no .strtab in  file: %s\n", fname);
+               fail_file();
+       }
+       if (symtab_sec == NULL) {
+               fprintf(stderr, "no .symtab in  file: %s\n", fname);
+               fail_file();
+       }
+       if (extab_sec == NULL) {
+               fprintf(stderr, "no __ex_table in  file: %s\n", fname);
+               fail_file();
+       }
+       strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
+
+       extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
+
+       if (custom_sort) {
+               custom_sort(extab_image, _r(&extab_sec->sh_size));
+       } else {
+               int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
+               qsort(extab_image, num_entries,
+                     extable_ent_size, compare_extable);
+       }
+       /* If there were relocations, we no longer need them. */
+       if (relocs)
+               memset(relocs, 0, relocs_size);
+
+       /* find main_extable_sort_needed */
+       sort_needed_sym = NULL;
+       for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) {
+               sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
+               sym += i;
+               if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
+                       continue;
+               idx = r(&sym->st_name);
+               if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) {
+                       sort_needed_sym = sym;
+                       break;
+               }
+       }
+       if (sort_needed_sym == NULL) {
+               fprintf(stderr,
+                       "no main_extable_sort_needed symbol in  file: %s\n",
+                       fname);
+               fail_file();
+       }
+       sort_needed_sec = &shdr[r2(&sort_needed_sym->st_shndx)];
+       sort_done_location = (void *)ehdr +
+               _r(&sort_needed_sec->sh_offset) +
+               _r(&sort_needed_sym->st_value) -
+               _r(&sort_needed_sec->sh_addr);
+
+#if 1
+       printf("sort done marker at %lx\n",
+              (unsigned long)((char *)sort_done_location - (char *)ehdr));
+#endif
+       /* We sorted it, clear the flag. */
+       w(0, sort_done_location);
+}
index 115313ef54d67e7d10cc6b6d4295a53bf49e340d..f5ded640b395312934396237299ac532ef2cb148 100644 (file)
@@ -991,6 +991,8 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
                        gpio_direction_output(pdata->reset_pin, 1);
                        chip->reset_pin = pdata->reset_pin;
                }
+       } else {
+               chip->reset_pin = -EINVAL;
        }
 
        snd_card_set_dev(card, &pdev->dev);
index 471e1e3b0a996da3fec0d21c82a55b87f3460469..a06b1651fcba02f9003f5b9a07ad2c72fb2dea14 100644 (file)
@@ -155,7 +155,7 @@ EXPORT_SYMBOL(snd_jack_new);
  * @jack:   The jack to configure
  * @parent: The device to set as parent for the jack.
  *
- * Set the parent for the jack input device in the device tree.  This
+ * Set the parent for the jack devices in the device tree.  This
  * function is only valid prior to registration of the jack.  If no
  * parent is configured then the parent device will be the sound card.
  */
@@ -179,6 +179,9 @@ EXPORT_SYMBOL(snd_jack_set_parent);
  * mapping is provided but keys are enabled in the jack type then
  * BTN_n numeric buttons will be reported.
  *
+ * If jacks are not reporting via the input API this call will have no
+ * effect.
+ *
  * Note that this is intended to be use by simple devices with small
  * numbers of keys that can be reported.  It is also possible to
  * access the input device directly - devices with complex input
index 4d18941178e6e933cb0f80f969c4d705c4777caf..faedb1481b240d9195b097f1448f98df3dcb6912 100644 (file)
@@ -1894,6 +1894,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_uframes_t xfer = 0;
        snd_pcm_uframes_t offset = 0;
+       snd_pcm_uframes_t avail;
        int err = 0;
 
        if (size == 0)
@@ -1917,13 +1918,12 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
        }
 
        runtime->twake = runtime->control->avail_min ? : 1;
+       if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+               snd_pcm_update_hw_ptr(substream);
+       avail = snd_pcm_playback_avail(runtime);
        while (size > 0) {
                snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
-               snd_pcm_uframes_t avail;
                snd_pcm_uframes_t cont;
-               if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-                       snd_pcm_update_hw_ptr(substream);
-               avail = snd_pcm_playback_avail(runtime);
                if (!avail) {
                        if (nonblock) {
                                err = -EAGAIN;
@@ -1971,6 +1971,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
                offset += frames;
                size -= frames;
                xfer += frames;
+               avail -= frames;
                if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
                    snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
                        err = snd_pcm_start(substream);
@@ -2111,6 +2112,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_uframes_t xfer = 0;
        snd_pcm_uframes_t offset = 0;
+       snd_pcm_uframes_t avail;
        int err = 0;
 
        if (size == 0)
@@ -2141,13 +2143,12 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
        }
 
        runtime->twake = runtime->control->avail_min ? : 1;
+       if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+               snd_pcm_update_hw_ptr(substream);
+       avail = snd_pcm_capture_avail(runtime);
        while (size > 0) {
                snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
-               snd_pcm_uframes_t avail;
                snd_pcm_uframes_t cont;
-               if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-                       snd_pcm_update_hw_ptr(substream);
-               avail = snd_pcm_capture_avail(runtime);
                if (!avail) {
                        if (runtime->status->state ==
                            SNDRV_PCM_STATE_DRAINING) {
@@ -2202,6 +2203,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
                offset += frames;
                size -= frames;
                xfer += frames;
+               avail -= frames;
        }
  _end_unlock:
        runtime->twake = 0;
index 3fe99e644eb838a34913f8c6870742e67c227a31..53b5ada8f7c36fd5199366662cc0ce5c5233e66c 100644 (file)
@@ -1360,7 +1360,14 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
 
 static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state)
 {
-       substream->runtime->trigger_master = substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       switch (runtime->status->state) {
+       case SNDRV_PCM_STATE_OPEN:
+       case SNDRV_PCM_STATE_DISCONNECTED:
+       case SNDRV_PCM_STATE_SUSPENDED:
+               return -EBADFD;
+       }
+       runtime->trigger_master = substream;
        return 0;
 }
 
@@ -1379,6 +1386,9 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
                case SNDRV_PCM_STATE_RUNNING:
                        runtime->status->state = SNDRV_PCM_STATE_DRAINING;
                        break;
+               case SNDRV_PCM_STATE_XRUN:
+                       runtime->status->state = SNDRV_PCM_STATE_SETUP;
+                       break;
                default:
                        break;
                }
index c700920430618f94a0dc0f7957ed75b813481507..e9528333e36d01e6e0282255639da08b7174e505 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/sound.h>
 #include <linux/mutex.h>
 
-#define SNDRV_OSS_MINORS 128
+#define SNDRV_OSS_MINORS 256
 
 static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS];
 static DEFINE_MUTEX(sound_oss_mutex);
@@ -111,7 +111,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
        int register1 = -1, register2 = -1;
        struct device *carddev = snd_card_get_device_link(card);
 
-       if (card && card->number >= 8)
+       if (card && card->number >= SNDRV_MINOR_OSS_DEVICES)
                return 0; /* ignore silently */
        if (minor < 0)
                return minor;
@@ -170,7 +170,7 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
        int track2 = -1;
        struct snd_minor *mptr;
 
-       if (card && card->number >= 8)
+       if (card && card->number >= SNDRV_MINOR_OSS_DEVICES)
                return 0;
        if (minor < 0)
                return minor;
index ad079b63b8bab170f6481112c568cfc7989b0294..8b5c36f4d30327e96a31f2e8afbd1b1dbb0f2d80 100644 (file)
@@ -117,6 +117,7 @@ struct loopback_pcm {
        /* timer stuff */
        unsigned int irq_pos;           /* fractional IRQ position */
        unsigned int period_size_frac;
+       unsigned int last_drift;
        unsigned long last_jiffies;
        struct timer_list timer;
 };
@@ -264,6 +265,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
                        return err;
                dpcm->last_jiffies = jiffies;
                dpcm->pcm_rate_shift = 0;
+               dpcm->last_drift = 0;
                spin_lock(&cable->lock);        
                cable->running |= stream;
                cable->pause &= ~stream;
@@ -444,34 +446,30 @@ static void copy_play_buf(struct loopback_pcm *play,
        }
 }
 
-#define BYTEPOS_UPDATE_POSONLY 0
-#define BYTEPOS_UPDATE_CLEAR   1
-#define BYTEPOS_UPDATE_COPY    2
-
-static void loopback_bytepos_update(struct loopback_pcm *dpcm,
-                                   unsigned int delta,
-                                   unsigned int cmd)
+static inline unsigned int bytepos_delta(struct loopback_pcm *dpcm,
+                                        unsigned int jiffies_delta)
 {
-       unsigned int count;
        unsigned long last_pos;
+       unsigned int delta;
 
        last_pos = byte_pos(dpcm, dpcm->irq_pos);
-       dpcm->irq_pos += delta * dpcm->pcm_bps;
-       count = byte_pos(dpcm, dpcm->irq_pos) - last_pos;
-       if (!count)
-               return;
-       if (cmd == BYTEPOS_UPDATE_CLEAR)
-               clear_capture_buf(dpcm, count);
-       else if (cmd == BYTEPOS_UPDATE_COPY)
-               copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
-                             dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE],
-                             count);
-       dpcm->buf_pos += count;
-       dpcm->buf_pos %= dpcm->pcm_buffer_size;
+       dpcm->irq_pos += jiffies_delta * dpcm->pcm_bps;
+       delta = byte_pos(dpcm, dpcm->irq_pos) - last_pos;
+       if (delta >= dpcm->last_drift)
+               delta -= dpcm->last_drift;
+       dpcm->last_drift = 0;
        if (dpcm->irq_pos >= dpcm->period_size_frac) {
                dpcm->irq_pos %= dpcm->period_size_frac;
                dpcm->period_update_pending = 1;
        }
+       return delta;
+}
+
+static inline void bytepos_finish(struct loopback_pcm *dpcm,
+                                 unsigned int delta)
+{
+       dpcm->buf_pos += delta;
+       dpcm->buf_pos %= dpcm->pcm_buffer_size;
 }
 
 static unsigned int loopback_pos_update(struct loopback_cable *cable)
@@ -481,7 +479,7 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable)
        struct loopback_pcm *dpcm_capt =
                        cable->streams[SNDRV_PCM_STREAM_CAPTURE];
        unsigned long delta_play = 0, delta_capt = 0;
-       unsigned int running;
+       unsigned int running, count1, count2;
        unsigned long flags;
 
        spin_lock_irqsave(&cable->lock, flags);
@@ -500,12 +498,13 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable)
                goto unlock;
                
        if (delta_play > delta_capt) {
-               loopback_bytepos_update(dpcm_play, delta_play - delta_capt,
-                                       BYTEPOS_UPDATE_POSONLY);
+               count1 = bytepos_delta(dpcm_play, delta_play - delta_capt);
+               bytepos_finish(dpcm_play, count1);
                delta_play = delta_capt;
        } else if (delta_play < delta_capt) {
-               loopback_bytepos_update(dpcm_capt, delta_capt - delta_play,
-                                       BYTEPOS_UPDATE_CLEAR);
+               count1 = bytepos_delta(dpcm_capt, delta_capt - delta_play);
+               clear_capture_buf(dpcm_capt, count1);
+               bytepos_finish(dpcm_capt, count1);
                delta_capt = delta_play;
        }
 
@@ -513,8 +512,17 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable)
                goto unlock;
 
        /* note delta_capt == delta_play at this moment */
-       loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY);
-       loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY);
+       count1 = bytepos_delta(dpcm_play, delta_play);
+       count2 = bytepos_delta(dpcm_capt, delta_capt);
+       if (count1 < count2) {
+               dpcm_capt->last_drift = count2 - count1;
+               count1 = count2;
+       } else if (count1 > count2) {
+               dpcm_play->last_drift = count1 - count2;
+       }
+       copy_play_buf(dpcm_play, dpcm_capt, count1);
+       bytepos_finish(dpcm_play, count1);
+       bytepos_finish(dpcm_capt, count1);
  unlock:
        spin_unlock_irqrestore(&cable->lock, flags);
        return running;
index 87657dd7714ccccb59f4922f12a880680b7838c8..ea995af6d049ec63b86f8fb59cf374640db9cc56 100644 (file)
@@ -31,6 +31,8 @@
 #define INTERRUPT_INTERVAL     16
 #define QUEUE_LENGTH           48
 
+static void pcm_period_tasklet(unsigned long data);
+
 /**
  * amdtp_out_stream_init - initialize an AMDTP output stream structure
  * @s: the AMDTP output stream to initialize
@@ -47,6 +49,7 @@ int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
        s->flags = flags;
        s->context = ERR_PTR(-1);
        mutex_init(&s->mutex);
+       tasklet_init(&s->period_tasklet, pcm_period_tasklet, (unsigned long)s);
        s->packet_index = 0;
 
        return 0;
@@ -164,6 +167,21 @@ void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s,
 }
 EXPORT_SYMBOL(amdtp_out_stream_set_pcm_format);
 
+/**
+ * amdtp_out_stream_pcm_prepare - prepare PCM device for running
+ * @s: the AMDTP output stream
+ *
+ * This function should be called from the PCM device's .prepare callback.
+ */
+void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s)
+{
+       tasklet_kill(&s->period_tasklet);
+       s->pcm_buffer_pointer = 0;
+       s->pcm_period_pointer = 0;
+       s->pointer_flush = true;
+}
+EXPORT_SYMBOL(amdtp_out_stream_pcm_prepare);
+
 static unsigned int calculate_data_blocks(struct amdtp_out_stream *s)
 {
        unsigned int phase, data_blocks;
@@ -376,11 +394,21 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
                s->pcm_period_pointer += data_blocks;
                if (s->pcm_period_pointer >= pcm->runtime->period_size) {
                        s->pcm_period_pointer -= pcm->runtime->period_size;
-                       snd_pcm_period_elapsed(pcm);
+                       s->pointer_flush = false;
+                       tasklet_hi_schedule(&s->period_tasklet);
                }
        }
 }
 
+static void pcm_period_tasklet(unsigned long data)
+{
+       struct amdtp_out_stream *s = (void *)data;
+       struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+
+       if (pcm)
+               snd_pcm_period_elapsed(pcm);
+}
+
 static void out_packet_callback(struct fw_iso_context *context, u32 cycle,
                                size_t header_length, void *header, void *data)
 {
@@ -505,6 +533,24 @@ err_unlock:
 }
 EXPORT_SYMBOL(amdtp_out_stream_start);
 
+/**
+ * amdtp_out_stream_pcm_pointer - get the PCM buffer position
+ * @s: the AMDTP output stream that transports the PCM data
+ *
+ * Returns the current buffer position, in frames.
+ */
+unsigned long amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s)
+{
+       /* this optimization is allowed to be racy */
+       if (s->pointer_flush)
+               fw_iso_context_flush_completions(s->context);
+       else
+               s->pointer_flush = true;
+
+       return ACCESS_ONCE(s->pcm_buffer_pointer);
+}
+EXPORT_SYMBOL(amdtp_out_stream_pcm_pointer);
+
 /**
  * amdtp_out_stream_update - update the stream after a bus reset
  * @s: the AMDTP output stream
@@ -532,6 +578,7 @@ void amdtp_out_stream_stop(struct amdtp_out_stream *s)
                return;
        }
 
+       tasklet_kill(&s->period_tasklet);
        fw_iso_context_stop(s->context);
        fw_iso_context_destroy(s->context);
        s->context = ERR_PTR(-1);
index 537a9cb83581b1b469b83914f39d3158413beb4f..b680c5ef01d694468f3b2736f357e49a09d50bf3 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED
 #define SOUND_FIREWIRE_AMDTP_H_INCLUDED
 
+#include <linux/interrupt.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include "packets-buffer.h"
@@ -55,6 +56,7 @@ struct amdtp_out_stream {
        struct iso_packets_buffer buffer;
 
        struct snd_pcm_substream *pcm;
+       struct tasklet_struct period_tasklet;
 
        int packet_index;
        unsigned int data_block_counter;
@@ -66,6 +68,7 @@ struct amdtp_out_stream {
 
        unsigned int pcm_buffer_pointer;
        unsigned int pcm_period_pointer;
+       bool pointer_flush;
 };
 
 int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
@@ -81,6 +84,8 @@ void amdtp_out_stream_stop(struct amdtp_out_stream *s);
 
 void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s,
                                     snd_pcm_format_t format);
+void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s);
+unsigned long amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s);
 void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s);
 
 /**
@@ -122,18 +127,6 @@ static inline bool amdtp_out_streaming_error(struct amdtp_out_stream *s)
        return s->packet_index < 0;
 }
 
-/**
- * amdtp_out_stream_pcm_prepare - prepare PCM device for running
- * @s: the AMDTP output stream
- *
- * This function should be called from the PCM device's .prepare callback.
- */
-static inline void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s)
-{
-       s->pcm_buffer_pointer = 0;
-       s->pcm_period_pointer = 0;
-}
-
 /**
  * amdtp_out_stream_pcm_trigger - start/stop playback from a PCM device
  * @s: the AMDTP output stream
@@ -149,18 +142,6 @@ static inline void amdtp_out_stream_pcm_trigger(struct amdtp_out_stream *s,
        ACCESS_ONCE(s->pcm) = pcm;
 }
 
-/**
- * amdtp_out_stream_pcm_pointer - get the PCM buffer position
- * @s: the AMDTP output stream that transports the PCM data
- *
- * Returns the current buffer position, in frames.
- */
-static inline unsigned long
-amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s)
-{
-       return ACCESS_ONCE(s->pcm_buffer_pointer);
-}
-
 static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
 {
        return sfc & 1;
index 5ca0939e4223b6104893fd77ccb3e1f5f982bd6c..ff3af6e77d610adc5cfba4748bdf25ac587238d7 100644 (file)
@@ -228,7 +228,7 @@ config SND_OXYGEN
          Say Y here to include support for sound cards based on the
          C-Media CMI8788 (Oxygen HD Audio) chip:
           * Asound A-8788
-          * Asus Xonar DG
+          * Asus Xonar DG/DGX
           * AuzenTech X-Meridian
           * AuzenTech X-Meridian 2G
           * Bgears b-Enspirer
index 9d91d61902b47edb7b7c8af381015653dc158d1f..e672ff4df2da15969f29a3882e541bd3ae441b7c 100644 (file)
@@ -1062,17 +1062,4 @@ static struct pci_driver ad1889_pci_driver = {
        .remove = __devexit_p(snd_ad1889_remove),
 };
 
-static int __init
-alsa_ad1889_init(void)
-{
-       return pci_register_driver(&ad1889_pci_driver);
-}
-
-static void __exit
-alsa_ad1889_fini(void)
-{
-       pci_unregister_driver(&ad1889_pci_driver);
-}
-
-module_init(alsa_ad1889_init);
-module_exit(alsa_ad1889_fini);
+module_pci_driver(ad1889_pci_driver);
index bdd6164e9c7eca267115564ad30e05e4860b18f8..9dfc27bf6cc645d5c1ecc6dd3d2d68920221a570 100644 (file)
@@ -2294,7 +2294,7 @@ static void __devexit snd_ali_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver ali5451_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_ali_ids,
        .probe = snd_ali_probe,
@@ -2305,15 +2305,4 @@ static struct pci_driver driver = {
 #endif
 };                                
 
-static int __init alsa_card_ali_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ali_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ali_init)
-module_exit(alsa_card_ali_exit)
+module_pci_driver(ali5451_driver);
index 8196e229b2dfbeb4801413b9f87bc7f3e06177aa..59d65388faf53d890d7ecd9603ac0d772a7a0e48 100644 (file)
@@ -852,7 +852,7 @@ static int __devinit snd_als300_probe(struct pci_dev *pci,
        return 0;
 }
 
-static struct pci_driver driver = {
+static struct pci_driver als300_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_als300_ids,
        .probe = snd_als300_probe,
@@ -863,15 +863,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_als300_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_als300_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_als300_init)
-module_exit(alsa_card_als300_exit)
+module_pci_driver(als300_driver);
index 3269b8011ea9692daa0068df3be024d7848fc96c..7d7f2598c7487c076cec8480f2a35c365bb5b946 100644 (file)
@@ -1036,7 +1036,7 @@ static int snd_als4000_resume(struct pci_dev *pci)
 #endif /* CONFIG_PM */
 
 
-static struct pci_driver driver = {
+static struct pci_driver als4000_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_als4000_ids,
        .probe = snd_card_als4000_probe,
@@ -1047,15 +1047,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_als4000_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_als4000_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_als4000_init)
-module_exit(alsa_card_als4000_exit)
+module_pci_driver(als4000_driver);
index 590682f115ef20f6ecf9e52423049fd28de6f06c..156a94f8a1234aa6cbd8af5f8dd2e08a322b1172 100644 (file)
@@ -1700,7 +1700,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver atiixp_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_atiixp_ids,
        .probe = snd_atiixp_probe,
@@ -1711,16 +1711,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-
-static int __init alsa_card_atiixp_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_atiixp_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_atiixp_init)
-module_exit(alsa_card_atiixp_exit)
+module_pci_driver(atiixp_driver);
index 524d35f312321145cc08461d78d9b498e4907d9f..30a4fd96ce739c937f52ecbe89d8ed3c2113248b 100644 (file)
@@ -1331,7 +1331,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver atiixp_modem_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_atiixp_ids,
        .probe = snd_atiixp_probe,
@@ -1342,16 +1342,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-
-static int __init alsa_card_atiixp_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_atiixp_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_atiixp_init)
-module_exit(alsa_card_atiixp_exit)
+module_pci_driver(atiixp_modem_driver);
index f13ad536b2d59fe19ab9826b5abc0c301d5133cf..ffc376f9f4e46f03d61aa808c48423d93e70748e 100644 (file)
@@ -375,24 +375,11 @@ static void __devexit snd_vortex_remove(struct pci_dev *pci)
 }
 
 // pci_driver definition
-static struct pci_driver driver = {
+static struct pci_driver vortex_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_vortex_ids,
        .probe = snd_vortex_probe,
        .remove = __devexit_p(snd_vortex_remove),
 };
 
-// initialization of the module
-static int __init alsa_card_vortex_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-// clean up the module
-static void __exit alsa_card_vortex_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_vortex_init)
-module_exit(alsa_card_vortex_exit)
+module_pci_driver(vortex_driver);
index 1c5231931462926f5919c57814b034f8474951d7..0f804741825f7ef9db7f18f5bb0bd358188bf3c6 100644 (file)
@@ -112,8 +112,6 @@ struct aw2 {
 /*********************************
  * FUNCTION DECLARATIONS
  ********************************/
-static int __init alsa_card_aw2_init(void);
-static void __exit alsa_card_aw2_exit(void);
 static int snd_aw2_dev_free(struct snd_device *device);
 static int __devinit snd_aw2_create(struct snd_card *card,
                                    struct pci_dev *pci, struct aw2 **rchip);
@@ -171,13 +169,15 @@ static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = {
 MODULE_DEVICE_TABLE(pci, snd_aw2_ids);
 
 /* pci_driver definition */
-static struct pci_driver driver = {
+static struct pci_driver aw2_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_aw2_ids,
        .probe = snd_aw2_probe,
        .remove = __devexit_p(snd_aw2_remove),
 };
 
+module_pci_driver(aw2_driver);
+
 /* operators for playback PCM alsa interface */
 static struct snd_pcm_ops snd_aw2_playback_ops = {
        .open = snd_aw2_pcm_playback_open,
@@ -217,23 +217,6 @@ static struct snd_kcontrol_new aw2_control __devinitdata = {
  * FUNCTION IMPLEMENTATIONS
  ********************************/
 
-/* initialization of the module */
-static int __init alsa_card_aw2_init(void)
-{
-       snd_printdd(KERN_DEBUG "aw2: Load aw2 module\n");
-       return pci_register_driver(&driver);
-}
-
-/* clean up the module */
-static void __exit alsa_card_aw2_exit(void)
-{
-       snd_printdd(KERN_DEBUG "aw2: Unload aw2 module\n");
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_aw2_init);
-module_exit(alsa_card_aw2_exit);
-
 /* component-destructor */
 static int snd_aw2_dev_free(struct snd_device *device)
 {
index 496f14c1a731e78071d30c814f6f0e08c143d85e..f0b4d7493af523083faa11422e5428d4b466bb7b 100644 (file)
@@ -2862,7 +2862,7 @@ snd_azf3328_resume(struct pci_dev *pci)
 #endif /* CONFIG_PM */
 
 
-static struct pci_driver driver = {
+static struct pci_driver azf3328_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_azf3328_ids,
        .probe = snd_azf3328_probe,
@@ -2873,23 +2873,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init
-alsa_card_azf3328_init(void)
-{
-       int err;
-       snd_azf3328_dbgcallenter();
-       err = pci_register_driver(&driver);
-       snd_azf3328_dbgcallleave();
-       return err;
-}
-
-static void __exit
-alsa_card_azf3328_exit(void)
-{
-       snd_azf3328_dbgcallenter();
-       pci_unregister_driver(&driver);
-       snd_azf3328_dbgcallleave();
-}
-
-module_init(alsa_card_azf3328_init)
-module_exit(alsa_card_azf3328_exit)
+module_pci_driver(azf3328_driver);
index 62d6163fc9d9c0bdfa2ef49ffbb230c2ea82386a..b6a95eeca095fe922d8418c4fd05ee5bcc7fe337 100644 (file)
@@ -836,8 +836,6 @@ static struct {
        {0x7063, 0x2000}, /* pcHDTV HD-2000 TV */
 };
 
-static struct pci_driver driver;
-
 /* return the id of the card, or a negative value if it's blacklisted */
 static int __devinit snd_bt87x_detect_card(struct pci_dev *pci)
 {
@@ -964,24 +962,11 @@ static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = {
        { }
 };
 
-static struct pci_driver driver = {
+static struct pci_driver bt87x_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_bt87x_ids,
        .probe = snd_bt87x_probe,
        .remove = __devexit_p(snd_bt87x_remove),
 };
 
-static int __init alsa_card_bt87x_init(void)
-{
-       if (load_all)
-               driver.id_table = snd_bt87x_default_ids;
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_bt87x_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_bt87x_init)
-module_exit(alsa_card_bt87x_exit)
+module_pci_driver(bt87x_driver);
index 08d6ebfe5a610d6b3c7a1951d43d9f44ca219838..e76d68a7081f7ec5795a4b0b6dc40b9e1564bd91 100644 (file)
@@ -1932,7 +1932,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_ca0106_ids) = {
 MODULE_DEVICE_TABLE(pci, snd_ca0106_ids);
 
 // pci_driver definition
-static struct pci_driver driver = {
+static struct pci_driver ca0106_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_ca0106_ids,
        .probe = snd_ca0106_probe,
@@ -1943,17 +1943,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-// initialization of the module
-static int __init alsa_card_ca0106_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-// clean up the module
-static void __exit alsa_card_ca0106_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ca0106_init)
-module_exit(alsa_card_ca0106_exit)
+module_pci_driver(ca0106_driver);
index 19b06269adc22df7b54bd1ad941e4a4796745423..3815bd4c67790d009776856c9d5e5cf4a0de34cb 100644 (file)
@@ -3398,7 +3398,7 @@ static int snd_cmipci_resume(struct pci_dev *pci)
 }
 #endif /* CONFIG_PM */
 
-static struct pci_driver driver = {
+static struct pci_driver cmipci_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_cmipci_ids,
        .probe = snd_cmipci_probe,
@@ -3409,15 +3409,4 @@ static struct pci_driver driver = {
 #endif
 };
        
-static int __init alsa_card_cmipci_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cmipci_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cmipci_init)
-module_exit(alsa_card_cmipci_exit)
+module_pci_driver(cmipci_driver);
index a9f368f60df6f3b7b271ce6f8e08f6a80259da35..33506ee569bd48c62411a1b014fbd5a28d69e26c 100644 (file)
@@ -2084,7 +2084,7 @@ static int cs4281_resume(struct pci_dev *pci)
 }
 #endif /* CONFIG_PM */
 
-static struct pci_driver driver = {
+static struct pci_driver cs4281_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_cs4281_ids,
        .probe = snd_cs4281_probe,
@@ -2095,15 +2095,4 @@ static struct pci_driver driver = {
 #endif
 };
        
-static int __init alsa_card_cs4281_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cs4281_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cs4281_init)
-module_exit(alsa_card_cs4281_exit)
+module_pci_driver(cs4281_driver);
index 819d79d0586de2909f308fe1094047a7b0830820..6cc7404e0e8f62991120eb5a86f835017c84cdf3 100644 (file)
@@ -161,7 +161,7 @@ static void __devexit snd_card_cs46xx_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver cs46xx_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_cs46xx_ids,
        .probe = snd_card_cs46xx_probe,
@@ -172,15 +172,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_cs46xx_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cs46xx_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cs46xx_init)
-module_exit(alsa_card_cs46xx_exit)
+module_pci_driver(cs46xx_driver);
index c47cabff2bfa2b6cbfd92755a8f5658f43ba90b5..f1e4229993af198a23afb4f33a93f1153251e9b5 100644 (file)
@@ -291,23 +291,11 @@ static int __devinit snd_cs5530_probe(struct pci_dev *pci,
        return 0;
 }
 
-static struct pci_driver driver = {
+static struct pci_driver cs5530_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_cs5530_ids,
        .probe = snd_cs5530_probe,
        .remove = __devexit_p(snd_cs5530_remove),
 };
 
-static int __init alsa_card_cs5530_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cs5530_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cs5530_init)
-module_exit(alsa_card_cs5530_exit)
-
+module_pci_driver(cs5530_driver);
index a2fb2173e980ea3697341446867d7d52a2a8350f..2c9697cf0a1a7c2f3e4dc650b9f505522e69afa2 100644 (file)
@@ -394,7 +394,7 @@ static void __devexit snd_cs5535audio_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver cs5535audio_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_cs5535audio_ids,
        .probe = snd_cs5535audio_probe,
@@ -405,18 +405,7 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_cs5535audio_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cs5535audio_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cs5535audio_init)
-module_exit(alsa_card_cs5535audio_exit)
+module_pci_driver(cs5535audio_driver);
 
 MODULE_AUTHOR("Jaya Kumar");
 MODULE_LICENSE("GPL");
index 15d95d2bacee67ff9c1c17c86a01e7aee6a44b75..75aa2c3384108c414d89d169a4a4bf8a0b8cbf7b 100644 (file)
@@ -154,15 +154,4 @@ static struct pci_driver ct_driver = {
 #endif
 };
 
-static int __init ct_card_init(void)
-{
-       return pci_register_driver(&ct_driver);
-}
-
-static void __exit ct_card_exit(void)
-{
-       pci_unregister_driver(&ct_driver);
-}
-
-module_init(ct_card_init)
-module_exit(ct_card_exit)
+module_pci_driver(ct_driver);
index 595c11f904bbf72e5cded83a807f8e8c7f9c3acd..0f8eda1dafdbb8ac11f5e570cda74c5b2373463d 100644 (file)
@@ -2328,7 +2328,7 @@ static void __devexit snd_echo_remove(struct pci_dev *pci)
 ******************************************************************************/
 
 /* pci_driver definition */
-static struct pci_driver driver = {
+static struct pci_driver echo_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_echo_ids,
        .probe = snd_echo_probe,
@@ -2339,22 +2339,4 @@ static struct pci_driver driver = {
 #endif /* CONFIG_PM */
 };
 
-
-
-/* initialization of the module */
-static int __init alsa_card_echo_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-
-
-/* clean up the module */
-static void __exit alsa_card_echo_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-
-module_init(alsa_card_echo_init)
-module_exit(alsa_card_echo_exit)
+module_pci_driver(echo_driver);
index 790c65d980c8550c828dde2baa0be1c40be40adf..7fdbbe4d9965385be9f12aa1db0fb011b1de946b 100644 (file)
@@ -263,7 +263,7 @@ static int snd_emu10k1_resume(struct pci_dev *pci)
 }
 #endif
 
-static struct pci_driver driver = {
+static struct pci_driver emu10k1_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_emu10k1_ids,
        .probe = snd_card_emu10k1_probe,
@@ -274,15 +274,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_emu10k1_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_emu10k1_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_emu10k1_init)
-module_exit(alsa_card_emu10k1_exit)
+module_pci_driver(emu10k1_driver);
index 47a651cb6e842d78c3cdc42bc3884de129a36baa..5c8978b2c4d9b1486afb26566a40b384e48106b0 100644 (file)
@@ -1612,24 +1612,11 @@ static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1x_ids) = {
 MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids);
 
 // pci_driver definition
-static struct pci_driver driver = {
+static struct pci_driver emu10k1x_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_emu10k1x_ids,
        .probe = snd_emu10k1x_probe,
        .remove = __devexit_p(snd_emu10k1x_remove),
 };
 
-// initialization of the module
-static int __init alsa_card_emu10k1x_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-// clean up the module
-static void __exit alsa_card_emu10k1x_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_emu10k1x_init)
-module_exit(alsa_card_emu10k1x_exit)
+module_pci_driver(emu10k1x_driver);
index 47a245e84190c08279075b5f14433fa1906a48a7..3821c81d1c993a24961aa4d416d70c8bbc6cd480 100644 (file)
@@ -2488,7 +2488,7 @@ static void __devexit snd_audiopci_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver ens137x_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_audiopci_ids,
        .probe = snd_audiopci_probe,
@@ -2499,15 +2499,4 @@ static struct pci_driver driver = {
 #endif
 };
        
-static int __init alsa_card_ens137x_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ens137x_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ens137x_init)
-module_exit(alsa_card_ens137x_exit)
+module_pci_driver(ens137x_driver);
index 53eb76b41108a07da237bf33af48f2cfe1da0d92..82c8d8c5c52ae724657c9bd7212fddc333d4cd5e 100644 (file)
@@ -1882,7 +1882,7 @@ static void __devexit snd_es1938_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver es1938_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_es1938_ids,
        .probe = snd_es1938_probe,
@@ -1893,15 +1893,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_es1938_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_es1938_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_es1938_init)
-module_exit(alsa_card_es1938_exit)
+module_pci_driver(es1938_driver);
index a8faae1c85e46787b8e240c3cd80fdc189da931d..67f47d891959661c326902cf5fa7803d39a09be0 100644 (file)
@@ -2898,7 +2898,7 @@ static void __devexit snd_es1968_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver es1968_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_es1968_ids,
        .probe = snd_es1968_probe,
@@ -2909,15 +2909,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_es1968_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_es1968_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_es1968_init)
-module_exit(alsa_card_es1968_exit)
+module_pci_driver(es1968_driver);
index a416ea8af3e9b3c39bef71cb92832f425217380c..f696623227503763d9996589034244314f39568c 100644 (file)
@@ -1416,7 +1416,7 @@ static int snd_fm801_resume(struct pci_dev *pci)
 }
 #endif
 
-static struct pci_driver driver = {
+static struct pci_driver fm801_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_fm801_ids,
        .probe = snd_card_fm801_probe,
@@ -1427,15 +1427,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_fm801_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_fm801_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_fm801_init)
-module_exit(alsa_card_fm801_exit)
+module_pci_driver(fm801_driver);
index ace157cc3d15c7e5b560910ca1adcfb2162d093a..bd4149f1aaf45f1f1300563c4aa469d483c2530f 100644 (file)
@@ -1,6 +1,6 @@
 snd-hda-intel-objs := hda_intel.o
 
-snd-hda-codec-y := hda_codec.o hda_jack.o
+snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o
 snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
 snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
 snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
new file mode 100644 (file)
index 0000000..6e9ef3e
--- /dev/null
@@ -0,0 +1,760 @@
+/*
+ * BIOS auto-parser helper functions for HD-audio
+ *
+ * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+
+#define SFX    "hda_codec: "
+
+/*
+ * Helper for automatic pin configuration
+ */
+
+static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list)
+{
+       for (; *list; list++)
+               if (*list == nid)
+                       return 1;
+       return 0;
+}
+
+
+/*
+ * Sort an associated group of pins according to their sequence numbers.
+ */
+static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
+                                 int num_pins)
+{
+       int i, j;
+       short seq;
+       hda_nid_t nid;
+
+       for (i = 0; i < num_pins; i++) {
+               for (j = i + 1; j < num_pins; j++) {
+                       if (sequences[i] > sequences[j]) {
+                               seq = sequences[i];
+                               sequences[i] = sequences[j];
+                               sequences[j] = seq;
+                               nid = pins[i];
+                               pins[i] = pins[j];
+                               pins[j] = nid;
+                       }
+               }
+       }
+}
+
+
+/* add the found input-pin to the cfg->inputs[] table */
+static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
+                                  int type)
+{
+       if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
+               cfg->inputs[cfg->num_inputs].pin = nid;
+               cfg->inputs[cfg->num_inputs].type = type;
+               cfg->num_inputs++;
+       }
+}
+
+/* sort inputs in the order of AUTO_PIN_* type */
+static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
+{
+       int i, j;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               for (j = i + 1; j < cfg->num_inputs; j++) {
+                       if (cfg->inputs[i].type > cfg->inputs[j].type) {
+                               struct auto_pin_cfg_item tmp;
+                               tmp = cfg->inputs[i];
+                               cfg->inputs[i] = cfg->inputs[j];
+                               cfg->inputs[j] = tmp;
+                       }
+               }
+       }
+}
+
+/* Reorder the surround channels
+ * ALSA sequence is front/surr/clfe/side
+ * HDA sequence is:
+ *    4-ch: front/surr  =>  OK as it is
+ *    6-ch: front/clfe/surr
+ *    8-ch: front/clfe/rear/side|fc
+ */
+static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
+{
+       hda_nid_t nid;
+
+       switch (nums) {
+       case 3:
+       case 4:
+               nid = pins[1];
+               pins[1] = pins[2];
+               pins[2] = nid;
+               break;
+       }
+}
+
+/*
+ * Parse all pin widgets and store the useful pin nids to cfg
+ *
+ * The number of line-outs or any primary output is stored in line_outs,
+ * and the corresponding output pins are assigned to line_out_pins[],
+ * in the order of front, rear, CLFE, side, ...
+ *
+ * If more extra outputs (speaker and headphone) are found, the pins are
+ * assisnged to hp_pins[] and speaker_pins[], respectively.  If no line-out jack
+ * is detected, one of speaker of HP pins is assigned as the primary
+ * output, i.e. to line_out_pins[0].  So, line_outs is always positive
+ * if any analog output exists.
+ *
+ * The analog input pins are assigned to inputs array.
+ * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
+ * respectively.
+ */
+int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
+                            struct auto_pin_cfg *cfg,
+                            const hda_nid_t *ignore_nids,
+                            unsigned int cond_flags)
+{
+       hda_nid_t nid, end_nid;
+       short seq, assoc_line_out;
+       short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
+       short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
+       short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
+       int i;
+
+       memset(cfg, 0, sizeof(*cfg));
+
+       memset(sequences_line_out, 0, sizeof(sequences_line_out));
+       memset(sequences_speaker, 0, sizeof(sequences_speaker));
+       memset(sequences_hp, 0, sizeof(sequences_hp));
+       assoc_line_out = 0;
+
+       codec->ignore_misc_bit = true;
+       end_nid = codec->start_nid + codec->num_nodes;
+       for (nid = codec->start_nid; nid < end_nid; nid++) {
+               unsigned int wid_caps = get_wcaps(codec, nid);
+               unsigned int wid_type = get_wcaps_type(wid_caps);
+               unsigned int def_conf;
+               short assoc, loc, conn, dev;
+
+               /* read all default configuration for pin complex */
+               if (wid_type != AC_WID_PIN)
+                       continue;
+               /* ignore the given nids (e.g. pc-beep returns error) */
+               if (ignore_nids && is_in_nid_list(nid, ignore_nids))
+                       continue;
+
+               def_conf = snd_hda_codec_get_pincfg(codec, nid);
+               if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+                     AC_DEFCFG_MISC_NO_PRESENCE))
+                       codec->ignore_misc_bit = false;
+               conn = get_defcfg_connect(def_conf);
+               if (conn == AC_JACK_PORT_NONE)
+                       continue;
+               loc = get_defcfg_location(def_conf);
+               dev = get_defcfg_device(def_conf);
+
+               /* workaround for buggy BIOS setups */
+               if (dev == AC_JACK_LINE_OUT) {
+                       if (conn == AC_JACK_PORT_FIXED)
+                               dev = AC_JACK_SPEAKER;
+               }
+
+               switch (dev) {
+               case AC_JACK_LINE_OUT:
+                       seq = get_defcfg_sequence(def_conf);
+                       assoc = get_defcfg_association(def_conf);
+
+                       if (!(wid_caps & AC_WCAP_STEREO))
+                               if (!cfg->mono_out_pin)
+                                       cfg->mono_out_pin = nid;
+                       if (!assoc)
+                               continue;
+                       if (!assoc_line_out)
+                               assoc_line_out = assoc;
+                       else if (assoc_line_out != assoc)
+                               continue;
+                       if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins))
+                               continue;
+                       cfg->line_out_pins[cfg->line_outs] = nid;
+                       sequences_line_out[cfg->line_outs] = seq;
+                       cfg->line_outs++;
+                       break;
+               case AC_JACK_SPEAKER:
+                       seq = get_defcfg_sequence(def_conf);
+                       assoc = get_defcfg_association(def_conf);
+                       if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
+                               continue;
+                       cfg->speaker_pins[cfg->speaker_outs] = nid;
+                       sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq;
+                       cfg->speaker_outs++;
+                       break;
+               case AC_JACK_HP_OUT:
+                       seq = get_defcfg_sequence(def_conf);
+                       assoc = get_defcfg_association(def_conf);
+                       if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
+                               continue;
+                       cfg->hp_pins[cfg->hp_outs] = nid;
+                       sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
+                       cfg->hp_outs++;
+                       break;
+               case AC_JACK_MIC_IN:
+                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
+                       break;
+               case AC_JACK_LINE_IN:
+                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
+                       break;
+               case AC_JACK_CD:
+                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
+                       break;
+               case AC_JACK_AUX:
+                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
+                       break;
+               case AC_JACK_SPDIF_OUT:
+               case AC_JACK_DIG_OTHER_OUT:
+                       if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins))
+                               continue;
+                       cfg->dig_out_pins[cfg->dig_outs] = nid;
+                       cfg->dig_out_type[cfg->dig_outs] =
+                               (loc == AC_JACK_LOC_HDMI) ?
+                               HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF;
+                       cfg->dig_outs++;
+                       break;
+               case AC_JACK_SPDIF_IN:
+               case AC_JACK_DIG_OTHER_IN:
+                       cfg->dig_in_pin = nid;
+                       if (loc == AC_JACK_LOC_HDMI)
+                               cfg->dig_in_type = HDA_PCM_TYPE_HDMI;
+                       else
+                               cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
+                       break;
+               }
+       }
+
+       /* FIX-UP:
+        * If no line-out is defined but multiple HPs are found,
+        * some of them might be the real line-outs.
+        */
+       if (!cfg->line_outs && cfg->hp_outs > 1 &&
+           !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) {
+               int i = 0;
+               while (i < cfg->hp_outs) {
+                       /* The real HPs should have the sequence 0x0f */
+                       if ((sequences_hp[i] & 0x0f) == 0x0f) {
+                               i++;
+                               continue;
+                       }
+                       /* Move it to the line-out table */
+                       cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i];
+                       sequences_line_out[cfg->line_outs] = sequences_hp[i];
+                       cfg->line_outs++;
+                       cfg->hp_outs--;
+                       memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1,
+                               sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i));
+                       memmove(sequences_hp + i, sequences_hp + i + 1,
+                               sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
+               }
+               memset(cfg->hp_pins + cfg->hp_outs, 0,
+                      sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
+               if (!cfg->hp_outs)
+                       cfg->line_out_type = AUTO_PIN_HP_OUT;
+
+       }
+
+       /* sort by sequence */
+       sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out,
+                             cfg->line_outs);
+       sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker,
+                             cfg->speaker_outs);
+       sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
+                             cfg->hp_outs);
+
+       /*
+        * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
+        * as a primary output
+        */
+       if (!cfg->line_outs &&
+           !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) {
+               if (cfg->speaker_outs) {
+                       cfg->line_outs = cfg->speaker_outs;
+                       memcpy(cfg->line_out_pins, cfg->speaker_pins,
+                              sizeof(cfg->speaker_pins));
+                       cfg->speaker_outs = 0;
+                       memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
+                       cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
+               } else if (cfg->hp_outs) {
+                       cfg->line_outs = cfg->hp_outs;
+                       memcpy(cfg->line_out_pins, cfg->hp_pins,
+                              sizeof(cfg->hp_pins));
+                       cfg->hp_outs = 0;
+                       memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
+                       cfg->line_out_type = AUTO_PIN_HP_OUT;
+               }
+       }
+
+       reorder_outputs(cfg->line_outs, cfg->line_out_pins);
+       reorder_outputs(cfg->hp_outs, cfg->hp_pins);
+       reorder_outputs(cfg->speaker_outs, cfg->speaker_pins);
+
+       sort_autocfg_input_pins(cfg);
+
+       /*
+        * debug prints of the parsed results
+        */
+       snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
+                  cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
+                  cfg->line_out_pins[2], cfg->line_out_pins[3],
+                  cfg->line_out_pins[4],
+                  cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
+                  (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
+                   "speaker" : "line"));
+       snd_printd("   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+                  cfg->speaker_outs, cfg->speaker_pins[0],
+                  cfg->speaker_pins[1], cfg->speaker_pins[2],
+                  cfg->speaker_pins[3], cfg->speaker_pins[4]);
+       snd_printd("   hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+                  cfg->hp_outs, cfg->hp_pins[0],
+                  cfg->hp_pins[1], cfg->hp_pins[2],
+                  cfg->hp_pins[3], cfg->hp_pins[4]);
+       snd_printd("   mono: mono_out=0x%x\n", cfg->mono_out_pin);
+       if (cfg->dig_outs)
+               snd_printd("   dig-out=0x%x/0x%x\n",
+                          cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
+       snd_printd("   inputs:");
+       for (i = 0; i < cfg->num_inputs; i++) {
+               snd_printd(" %s=0x%x",
+                           hda_get_autocfg_input_label(codec, cfg, i),
+                           cfg->inputs[i].pin);
+       }
+       snd_printd("\n");
+       if (cfg->dig_in_pin)
+               snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
+
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg);
+
+int snd_hda_get_input_pin_attr(unsigned int def_conf)
+{
+       unsigned int loc = get_defcfg_location(def_conf);
+       unsigned int conn = get_defcfg_connect(def_conf);
+       if (conn == AC_JACK_PORT_NONE)
+               return INPUT_PIN_ATTR_UNUSED;
+       /* Windows may claim the internal mic to be BOTH, too */
+       if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
+               return INPUT_PIN_ATTR_INT;
+       if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
+               return INPUT_PIN_ATTR_INT;
+       if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
+               return INPUT_PIN_ATTR_DOCK;
+       if (loc == AC_JACK_LOC_REAR)
+               return INPUT_PIN_ATTR_REAR;
+       if (loc == AC_JACK_LOC_FRONT)
+               return INPUT_PIN_ATTR_FRONT;
+       return INPUT_PIN_ATTR_NORMAL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
+
+/**
+ * hda_get_input_pin_label - Give a label for the given input pin
+ *
+ * When check_location is true, the function checks the pin location
+ * for mic and line-in pins, and set an appropriate prefix like "Front",
+ * "Rear", "Internal".
+ */
+
+static const char *hda_get_input_pin_label(struct hda_codec *codec,
+                                          hda_nid_t pin, bool check_location)
+{
+       unsigned int def_conf;
+       static const char * const mic_names[] = {
+               "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
+       };
+       int attr;
+
+       def_conf = snd_hda_codec_get_pincfg(codec, pin);
+
+       switch (get_defcfg_device(def_conf)) {
+       case AC_JACK_MIC_IN:
+               if (!check_location)
+                       return "Mic";
+               attr = snd_hda_get_input_pin_attr(def_conf);
+               if (!attr)
+                       return "None";
+               return mic_names[attr - 1];
+       case AC_JACK_LINE_IN:
+               if (!check_location)
+                       return "Line";
+               attr = snd_hda_get_input_pin_attr(def_conf);
+               if (!attr)
+                       return "None";
+               if (attr == INPUT_PIN_ATTR_DOCK)
+                       return "Dock Line";
+               return "Line";
+       case AC_JACK_AUX:
+               return "Aux";
+       case AC_JACK_CD:
+               return "CD";
+       case AC_JACK_SPDIF_IN:
+               return "SPDIF In";
+       case AC_JACK_DIG_OTHER_IN:
+               return "Digital In";
+       default:
+               return "Misc";
+       }
+}
+
+/* Check whether the location prefix needs to be added to the label.
+ * If all mic-jacks are in the same location (e.g. rear panel), we don't
+ * have to put "Front" prefix to each label.  In such a case, returns false.
+ */
+static int check_mic_location_need(struct hda_codec *codec,
+                                  const struct auto_pin_cfg *cfg,
+                                  int input)
+{
+       unsigned int defc;
+       int i, attr, attr2;
+
+       defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
+       attr = snd_hda_get_input_pin_attr(defc);
+       /* for internal or docking mics, we need locations */
+       if (attr <= INPUT_PIN_ATTR_NORMAL)
+               return 1;
+
+       attr = 0;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
+               attr2 = snd_hda_get_input_pin_attr(defc);
+               if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
+                       if (attr && attr != attr2)
+                               return 1; /* different locations found */
+                       attr = attr2;
+               }
+       }
+       return 0;
+}
+
+/**
+ * hda_get_autocfg_input_label - Get a label for the given input
+ *
+ * Get a label for the given input pin defined by the autocfg item.
+ * Unlike hda_get_input_pin_label(), this function checks all inputs
+ * defined in autocfg and avoids the redundant mic/line prefix as much as
+ * possible.
+ */
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+                                       const struct auto_pin_cfg *cfg,
+                                       int input)
+{
+       int type = cfg->inputs[input].type;
+       int has_multiple_pins = 0;
+
+       if ((input > 0 && cfg->inputs[input - 1].type == type) ||
+           (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
+               has_multiple_pins = 1;
+       if (has_multiple_pins && type == AUTO_PIN_MIC)
+               has_multiple_pins &= check_mic_location_need(codec, cfg, input);
+       return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
+                                      has_multiple_pins);
+}
+EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
+
+/* return the position of NID in the list, or -1 if not found */
+static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+       int i;
+       for (i = 0; i < nums; i++)
+               if (list[i] == nid)
+                       return i;
+       return -1;
+}
+
+/* get a unique suffix or an index number */
+static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
+                                   int num_pins, int *indexp)
+{
+       static const char * const channel_sfx[] = {
+               " Front", " Surround", " CLFE", " Side"
+       };
+       int i;
+
+       i = find_idx_in_nid_list(nid, pins, num_pins);
+       if (i < 0)
+               return NULL;
+       if (num_pins == 1)
+               return "";
+       if (num_pins > ARRAY_SIZE(channel_sfx)) {
+               if (indexp)
+                       *indexp = i;
+               return "";
+       }
+       return channel_sfx[i];
+}
+
+static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
+                              const struct auto_pin_cfg *cfg,
+                              const char *name, char *label, int maxlen,
+                              int *indexp)
+{
+       unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       int attr = snd_hda_get_input_pin_attr(def_conf);
+       const char *pfx = "", *sfx = "";
+
+       /* handle as a speaker if it's a fixed line-out */
+       if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT)
+               name = "Speaker";
+       /* check the location */
+       switch (attr) {
+       case INPUT_PIN_ATTR_DOCK:
+               pfx = "Dock ";
+               break;
+       case INPUT_PIN_ATTR_FRONT:
+               pfx = "Front ";
+               break;
+       }
+       if (cfg) {
+               /* try to give a unique suffix if needed */
+               sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs,
+                                      indexp);
+               if (!sfx)
+                       sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs,
+                                              indexp);
+               if (!sfx) {
+                       /* don't add channel suffix for Headphone controls */
+                       int idx = find_idx_in_nid_list(nid, cfg->hp_pins,
+                                                      cfg->hp_outs);
+                       if (idx >= 0)
+                               *indexp = idx;
+                       sfx = "";
+               }
+       }
+       snprintf(label, maxlen, "%s%s%s", pfx, name, sfx);
+       return 1;
+}
+
+/**
+ * snd_hda_get_pin_label - Get a label for the given I/O pin
+ *
+ * Get a label for the given pin.  This function works for both input and
+ * output pins.  When @cfg is given as non-NULL, the function tries to get
+ * an optimized label using hda_get_autocfg_input_label().
+ *
+ * This function tries to give a unique label string for the pin as much as
+ * possible.  For example, when the multiple line-outs are present, it adds
+ * the channel suffix like "Front", "Surround", etc (only when @cfg is given).
+ * If no unique name with a suffix is available and @indexp is non-NULL, the
+ * index number is stored in the pointer.
+ */
+int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
+                         const struct auto_pin_cfg *cfg,
+                         char *label, int maxlen, int *indexp)
+{
+       unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       const char *name = NULL;
+       int i;
+
+       if (indexp)
+               *indexp = 0;
+       if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
+               return 0;
+
+       switch (get_defcfg_device(def_conf)) {
+       case AC_JACK_LINE_OUT:
+               return fill_audio_out_name(codec, nid, cfg, "Line Out",
+                                          label, maxlen, indexp);
+       case AC_JACK_SPEAKER:
+               return fill_audio_out_name(codec, nid, cfg, "Speaker",
+                                          label, maxlen, indexp);
+       case AC_JACK_HP_OUT:
+               return fill_audio_out_name(codec, nid, cfg, "Headphone",
+                                          label, maxlen, indexp);
+       case AC_JACK_SPDIF_OUT:
+       case AC_JACK_DIG_OTHER_OUT:
+               if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI)
+                       name = "HDMI";
+               else
+                       name = "SPDIF";
+               if (cfg && indexp) {
+                       i = find_idx_in_nid_list(nid, cfg->dig_out_pins,
+                                                cfg->dig_outs);
+                       if (i >= 0)
+                               *indexp = i;
+               }
+               break;
+       default:
+               if (cfg) {
+                       for (i = 0; i < cfg->num_inputs; i++) {
+                               if (cfg->inputs[i].pin != nid)
+                                       continue;
+                               name = hda_get_autocfg_input_label(codec, cfg, i);
+                               if (name)
+                                       break;
+                       }
+               }
+               if (!name)
+                       name = hda_get_input_pin_label(codec, nid, true);
+               break;
+       }
+       if (!name)
+               return 0;
+       strlcpy(label, name, maxlen);
+       return 1;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_pin_label);
+
+int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
+                         const struct hda_verb *list)
+{
+       const struct hda_verb **v;
+       snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8);
+       v = snd_array_new(&spec->verbs);
+       if (!v)
+               return -ENOMEM;
+       *v = list;
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_gen_add_verbs);
+
+void snd_hda_gen_apply_verbs(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
+       for (i = 0; i < spec->verbs.used; i++) {
+               struct hda_verb **v = snd_array_elem(&spec->verbs, i);
+               snd_hda_sequence_write(codec, *v);
+       }
+}
+EXPORT_SYMBOL_HDA(snd_hda_gen_apply_verbs);
+
+void snd_hda_apply_pincfgs(struct hda_codec *codec,
+                          const struct hda_pintbl *cfg)
+{
+       for (; cfg->nid; cfg++)
+               snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+}
+EXPORT_SYMBOL_HDA(snd_hda_apply_pincfgs);
+
+void snd_hda_apply_fixup(struct hda_codec *codec, int action)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int id = spec->fixup_id;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+       const char *modelname = spec->fixup_name;
+#endif
+       int depth = 0;
+
+       if (!spec->fixup_list)
+               return;
+
+       while (id >= 0) {
+               const struct hda_fixup *fix = spec->fixup_list + id;
+
+               switch (fix->type) {
+               case HDA_FIXUP_PINS:
+                       if (action != HDA_FIXUP_ACT_PRE_PROBE || !fix->v.pins)
+                               break;
+                       snd_printdd(KERN_INFO SFX
+                                   "%s: Apply pincfg for %s\n",
+                                   codec->chip_name, modelname);
+                       snd_hda_apply_pincfgs(codec, fix->v.pins);
+                       break;
+               case HDA_FIXUP_VERBS:
+                       if (action != HDA_FIXUP_ACT_PROBE || !fix->v.verbs)
+                               break;
+                       snd_printdd(KERN_INFO SFX
+                                   "%s: Apply fix-verbs for %s\n",
+                                   codec->chip_name, modelname);
+                       snd_hda_gen_add_verbs(codec->spec, fix->v.verbs);
+                       break;
+               case HDA_FIXUP_FUNC:
+                       if (!fix->v.func)
+                               break;
+                       snd_printdd(KERN_INFO SFX
+                                   "%s: Apply fix-func for %s\n",
+                                   codec->chip_name, modelname);
+                       fix->v.func(codec, fix, action);
+                       break;
+               default:
+                       snd_printk(KERN_ERR SFX
+                                  "%s: Invalid fixup type %d\n",
+                                  codec->chip_name, fix->type);
+                       break;
+               }
+               if (!fix->chained)
+                       break;
+               if (++depth > 10)
+                       break;
+               id = fix->chain_id;
+       }
+}
+EXPORT_SYMBOL_HDA(snd_hda_apply_fixup);
+
+void snd_hda_pick_fixup(struct hda_codec *codec,
+                       const struct hda_model_fixup *models,
+                       const struct snd_pci_quirk *quirk,
+                       const struct hda_fixup *fixlist)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const struct snd_pci_quirk *q;
+       int id = -1;
+       const char *name = NULL;
+
+       /* when model=nofixup is given, don't pick up any fixups */
+       if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
+               spec->fixup_list = NULL;
+               spec->fixup_id = -1;
+               return;
+       }
+
+       if (codec->modelname && models) {
+               while (models->name) {
+                       if (!strcmp(codec->modelname, models->name)) {
+                               id = models->id;
+                               name = models->name;
+                               break;
+                       }
+                       models++;
+               }
+       }
+       if (id < 0) {
+               q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+               if (q) {
+                       id = q->value;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+                       name = q->name;
+#endif
+               }
+       }
+       if (id < 0) {
+               for (q = quirk; q->subvendor; q++) {
+                       unsigned int vendorid =
+                               q->subdevice | (q->subvendor << 16);
+                       if (vendorid == codec->subsystem_id) {
+                               id = q->value;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+                               name = q->name;
+#endif
+                               break;
+                       }
+               }
+       }
+
+       spec->fixup_id = id;
+       if (id >= 0) {
+               spec->fixup_list = fixlist;
+               spec->fixup_name = name;
+       }
+}
+EXPORT_SYMBOL_HDA(snd_hda_pick_fixup);
diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h
new file mode 100644 (file)
index 0000000..2a7889d
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * BIOS auto-parser helper functions for HD-audio
+ *
+ * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __SOUND_HDA_AUTO_PARSER_H
+#define __SOUND_HDA_AUTO_PARSER_H
+
+/*
+ * Helper for automatic pin configuration
+ */
+
+enum {
+       AUTO_PIN_MIC,
+       AUTO_PIN_LINE_IN,
+       AUTO_PIN_CD,
+       AUTO_PIN_AUX,
+       AUTO_PIN_LAST
+};
+
+enum {
+       AUTO_PIN_LINE_OUT,
+       AUTO_PIN_SPEAKER_OUT,
+       AUTO_PIN_HP_OUT
+};
+
+#define AUTO_CFG_MAX_OUTS      HDA_MAX_OUTS
+#define AUTO_CFG_MAX_INS       8
+
+struct auto_pin_cfg_item {
+       hda_nid_t pin;
+       int type;
+};
+
+struct auto_pin_cfg;
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+                                       const struct auto_pin_cfg *cfg,
+                                       int input);
+int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
+                         const struct auto_pin_cfg *cfg,
+                         char *label, int maxlen, int *indexp);
+
+enum {
+       INPUT_PIN_ATTR_UNUSED,  /* pin not connected */
+       INPUT_PIN_ATTR_INT,     /* internal mic/line-in */
+       INPUT_PIN_ATTR_DOCK,    /* docking mic/line-in */
+       INPUT_PIN_ATTR_NORMAL,  /* mic/line-in jack */
+       INPUT_PIN_ATTR_FRONT,   /* mic/line-in jack in front */
+       INPUT_PIN_ATTR_REAR,    /* mic/line-in jack in rear */
+};
+
+int snd_hda_get_input_pin_attr(unsigned int def_conf);
+
+struct auto_pin_cfg {
+       int line_outs;
+       /* sorted in the order of Front/Surr/CLFE/Side */
+       hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS];
+       int speaker_outs;
+       hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS];
+       int hp_outs;
+       int line_out_type;      /* AUTO_PIN_XXX_OUT */
+       hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
+       int num_inputs;
+       struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
+       int dig_outs;
+       hda_nid_t dig_out_pins[2];
+       hda_nid_t dig_in_pin;
+       hda_nid_t mono_out_pin;
+       int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */
+       int dig_in_type; /* HDA_PCM_TYPE_XXX */
+};
+
+/* bit-flags for snd_hda_parse_pin_def_config() behavior */
+#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */
+#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */
+
+int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
+                            struct auto_pin_cfg *cfg,
+                            const hda_nid_t *ignore_nids,
+                            unsigned int cond_flags);
+
+/* older function */
+#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
+       snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
+
+/*
+ */
+
+struct hda_gen_spec {
+       /* fix-up list */
+       int fixup_id;
+       const struct hda_fixup *fixup_list;
+       const char *fixup_name;
+
+       /* additional init verbs */
+       struct snd_array verbs;
+};
+
+
+/*
+ * Fix-up pin default configurations and add default verbs
+ */
+
+struct hda_pintbl {
+       hda_nid_t nid;
+       u32 val;
+};
+
+struct hda_model_fixup {
+       const int id;
+       const char *name;
+};
+
+struct hda_fixup {
+       int type;
+       bool chained;
+       int chain_id;
+       union {
+               const struct hda_pintbl *pins;
+               const struct hda_verb *verbs;
+               void (*func)(struct hda_codec *codec,
+                            const struct hda_fixup *fix,
+                            int action);
+       } v;
+};
+
+/* fixup types */
+enum {
+       HDA_FIXUP_INVALID,
+       HDA_FIXUP_PINS,
+       HDA_FIXUP_VERBS,
+       HDA_FIXUP_FUNC,
+};
+
+/* fixup action definitions */
+enum {
+       HDA_FIXUP_ACT_PRE_PROBE,
+       HDA_FIXUP_ACT_PROBE,
+       HDA_FIXUP_ACT_INIT,
+       HDA_FIXUP_ACT_BUILD,
+};
+
+int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
+                         const struct hda_verb *list);
+void snd_hda_gen_apply_verbs(struct hda_codec *codec);
+void snd_hda_apply_pincfgs(struct hda_codec *codec,
+                          const struct hda_pintbl *cfg);
+void snd_hda_apply_fixup(struct hda_codec *codec, int action);
+void snd_hda_pick_fixup(struct hda_codec *codec,
+                       const struct hda_model_fixup *models,
+                       const struct snd_pci_quirk *quirk,
+                       const struct hda_fixup *fixlist);
+
+#endif /* __SOUND_HDA_AUTO_PARSER_H */
index 841475cc13b657a2627e107354e4b70251fb3296..eb09a3348325358b0a741d3408d48cc4e5e8fffd 100644 (file)
@@ -334,78 +334,67 @@ static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid)
        return NULL;
 }
 
+/* read the connection and add to the cache */
+static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
+{
+       hda_nid_t list[HDA_MAX_CONNECTIONS];
+       int len;
+
+       len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(list));
+       if (len < 0)
+               return len;
+       return snd_hda_override_conn_list(codec, nid, len, list);
+}
+
 /**
- * snd_hda_get_conn_list - get connection list
+ * snd_hda_get_connections - copy connection list
  * @codec: the HDA codec
  * @nid: NID to parse
- * @listp: the pointer to store NID list
+ * @conn_list: connection list array; when NULL, checks only the size
+ * @max_conns: max. number of connections to store
  *
  * Parses the connection list of the given widget and stores the list
  * of NIDs.
  *
  * Returns the number of connections, or a negative error code.
  */
-int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
-                         const hda_nid_t **listp)
+int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
+                           hda_nid_t *conn_list, int max_conns)
 {
        struct snd_array *array = &codec->conn_lists;
-       int len, err;
-       hda_nid_t list[HDA_MAX_CONNECTIONS];
+       int len;
        hda_nid_t *p;
        bool added = false;
 
  again:
+       mutex_lock(&codec->hash_mutex);
+       len = -1;
        /* if the connection-list is already cached, read it */
        p = lookup_conn_list(array, nid);
        if (p) {
-               if (listp)
-                       *listp = p + 2;
-               return p[1];
+               len = p[1];
+               if (conn_list && len > max_conns) {
+                       snd_printk(KERN_ERR "hda_codec: "
+                                  "Too many connections %d for NID 0x%x\n",
+                                  len, nid);
+                       mutex_unlock(&codec->hash_mutex);
+                       return -EINVAL;
+               }
+               if (conn_list && len)
+                       memcpy(conn_list, p + 2, len * sizeof(hda_nid_t));
        }
+       mutex_unlock(&codec->hash_mutex);
+       if (len >= 0)
+               return len;
        if (snd_BUG_ON(added))
                return -EINVAL;
 
-       /* read the connection and add to the cache */
-       len = snd_hda_get_raw_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
+       len = read_and_add_raw_conns(codec, nid);
        if (len < 0)
                return len;
-       err = snd_hda_override_conn_list(codec, nid, len, list);
-       if (err < 0)
-               return err;
        added = true;
        goto again;
 }
-EXPORT_SYMBOL_HDA(snd_hda_get_conn_list);
-
-/**
- * snd_hda_get_connections - copy connection list
- * @codec: the HDA codec
- * @nid: NID to parse
- * @conn_list: connection list array
- * @max_conns: max. number of connections to store
- *
- * Parses the connection list of the given widget and stores the list
- * of NIDs.
- *
- * Returns the number of connections, or a negative error code.
- */
-int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
-                            hda_nid_t *conn_list, int max_conns)
-{
-       const hda_nid_t *list;
-       int len = snd_hda_get_conn_list(codec, nid, &list);
-
-       if (len <= 0)
-               return len;
-       if (len > max_conns) {
-               snd_printk(KERN_ERR "hda_codec: "
-                          "Too many connections %d for NID 0x%x\n",
-                          len, nid);
-               return -EINVAL;
-       }
-       memcpy(conn_list, list, len * sizeof(hda_nid_t));
-       return len;
-}
 EXPORT_SYMBOL_HDA(snd_hda_get_connections);
 
 /**
@@ -543,6 +532,7 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
        hda_nid_t *p;
        int i, old_used;
 
+       mutex_lock(&codec->hash_mutex);
        p = lookup_conn_list(array, nid);
        if (p)
                *p = -1; /* invalidate the old entry */
@@ -553,10 +543,12 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
        for (i = 0; i < len; i++)
                if (!add_conn_list(array, list[i]))
                        goto error_add;
+       mutex_unlock(&codec->hash_mutex);
        return 0;
 
  error_add:
        array->used = old_used;
+       mutex_unlock(&codec->hash_mutex);
        return -ENOMEM;
 }
 EXPORT_SYMBOL_HDA(snd_hda_override_conn_list);
@@ -1255,6 +1247,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
        codec->addr = codec_addr;
        mutex_init(&codec->spdif_mutex);
        mutex_init(&codec->control_mutex);
+       mutex_init(&codec->hash_mutex);
        init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
        init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
        snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
@@ -1264,15 +1257,9 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
        snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
        snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
        snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
-       if (codec->bus->modelname) {
-               codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
-               if (!codec->modelname) {
-                       snd_hda_codec_free(codec);
-                       return -ENODEV;
-               }
-       }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
+       spin_lock_init(&codec->power_lock);
        INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
        /* snd_hda_codec_new() marks the codec as power-up, and leave it as is.
         * the caller has to power down appropriatley after initialization
@@ -1281,6 +1268,14 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
        hda_keep_power_on(codec);
 #endif
 
+       if (codec->bus->modelname) {
+               codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
+               if (!codec->modelname) {
+                       snd_hda_codec_free(codec);
+                       return -ENODEV;
+               }
+       }
+
        list_add_tail(&codec->list, &bus->codec_list);
        bus->caddr_tbl[codec_addr] = codec;
 
@@ -1603,6 +1598,60 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key)
        return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key);
 }
 
+/* overwrite the value with the key in the caps hash */
+static int write_caps_hash(struct hda_codec *codec, u32 key, unsigned int val)
+{
+       struct hda_amp_info *info;
+
+       mutex_lock(&codec->hash_mutex);
+       info = get_alloc_amp_hash(codec, key);
+       if (!info) {
+               mutex_unlock(&codec->hash_mutex);
+               return -EINVAL;
+       }
+       info->amp_caps = val;
+       info->head.val |= INFO_AMP_CAPS;
+       mutex_unlock(&codec->hash_mutex);
+       return 0;
+}
+
+/* query the value from the caps hash; if not found, fetch the current
+ * value from the given function and store in the hash
+ */
+static unsigned int
+query_caps_hash(struct hda_codec *codec, hda_nid_t nid, int dir, u32 key,
+               unsigned int (*func)(struct hda_codec *, hda_nid_t, int))
+{
+       struct hda_amp_info *info;
+       unsigned int val;
+
+       mutex_lock(&codec->hash_mutex);
+       info = get_alloc_amp_hash(codec, key);
+       if (!info) {
+               mutex_unlock(&codec->hash_mutex);
+               return 0;
+       }
+       if (!(info->head.val & INFO_AMP_CAPS)) {
+               mutex_unlock(&codec->hash_mutex); /* for reentrance */
+               val = func(codec, nid, dir);
+               write_caps_hash(codec, key, val);
+       } else {
+               val = info->amp_caps;
+               mutex_unlock(&codec->hash_mutex);
+       }
+       return val;
+}
+
+static unsigned int read_amp_cap(struct hda_codec *codec, hda_nid_t nid,
+                                int direction)
+{
+       if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
+               nid = codec->afg;
+       return snd_hda_param_read(codec, nid,
+                                 direction == HDA_OUTPUT ?
+                                 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
+}
+
 /**
  * query_amp_caps - query AMP capabilities
  * @codec: the HD-auio codec
@@ -1617,22 +1666,9 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key)
  */
 u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
 {
-       struct hda_amp_info *info;
-
-       info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0));
-       if (!info)
-               return 0;
-       if (!(info->head.val & INFO_AMP_CAPS)) {
-               if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
-                       nid = codec->afg;
-               info->amp_caps = snd_hda_param_read(codec, nid,
-                                                   direction == HDA_OUTPUT ?
-                                                   AC_PAR_AMP_OUT_CAP :
-                                                   AC_PAR_AMP_IN_CAP);
-               if (info->amp_caps)
-                       info->head.val |= INFO_AMP_CAPS;
-       }
-       return info->amp_caps;
+       return query_caps_hash(codec, nid, direction,
+                              HDA_HASH_KEY(nid, direction, 0),
+                              read_amp_cap);
 }
 EXPORT_SYMBOL_HDA(query_amp_caps);
 
@@ -1652,34 +1688,12 @@ EXPORT_SYMBOL_HDA(query_amp_caps);
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
                              unsigned int caps)
 {
-       struct hda_amp_info *info;
-
-       info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, dir, 0));
-       if (!info)
-               return -EINVAL;
-       info->amp_caps = caps;
-       info->head.val |= INFO_AMP_CAPS;
-       return 0;
+       return write_caps_hash(codec, HDA_HASH_KEY(nid, dir, 0), caps);
 }
 EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
 
-static unsigned int
-query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key,
-               unsigned int (*func)(struct hda_codec *, hda_nid_t))
-{
-       struct hda_amp_info *info;
-
-       info = get_alloc_amp_hash(codec, key);
-       if (!info)
-               return 0;
-       if (!info->head.val) {
-               info->head.val |= INFO_AMP_CAPS;
-               info->amp_caps = func(codec, nid);
-       }
-       return info->amp_caps;
-}
-
-static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid,
+                                int dir)
 {
        return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
 }
@@ -1697,7 +1711,7 @@ static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid)
  */
 u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
 {
-       return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid),
+       return query_caps_hash(codec, nid, 0, HDA_HASH_PINCAP_KEY(nid),
                               read_pin_cap);
 }
 EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
@@ -1715,41 +1729,47 @@ EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
 int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
                              unsigned int caps)
 {
-       struct hda_amp_info *info;
-       info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid));
-       if (!info)
-               return -ENOMEM;
-       info->amp_caps = caps;
-       info->head.val |= INFO_AMP_CAPS;
-       return 0;
+       return write_caps_hash(codec, HDA_HASH_PINCAP_KEY(nid), caps);
 }
 EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps);
 
-/*
- * read the current volume to info
- * if the cache exists, read the cache value.
+/* read or sync the hash value with the current value;
+ * call within hash_mutex
  */
-static unsigned int get_vol_mute(struct hda_codec *codec,
-                                struct hda_amp_info *info, hda_nid_t nid,
-                                int ch, int direction, int index)
+static struct hda_amp_info *
+update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch,
+               int direction, int index)
 {
-       u32 val, parm;
-
-       if (info->head.val & INFO_AMP_VOL(ch))
-               return info->vol[ch];
+       struct hda_amp_info *info;
+       unsigned int parm, val = 0;
+       bool val_read = false;
 
-       parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
-       parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
-       parm |= index;
-       val = snd_hda_codec_read(codec, nid, 0,
+ retry:
+       info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
+       if (!info)
+               return NULL;
+       if (!(info->head.val & INFO_AMP_VOL(ch))) {
+               if (!val_read) {
+                       mutex_unlock(&codec->hash_mutex);
+                       parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
+                       parm |= direction == HDA_OUTPUT ?
+                               AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
+                       parm |= index;
+                       val = snd_hda_codec_read(codec, nid, 0,
                                 AC_VERB_GET_AMP_GAIN_MUTE, parm);
-       info->vol[ch] = val & 0xff;
-       info->head.val |= INFO_AMP_VOL(ch);
-       return info->vol[ch];
+                       val &= 0xff;
+                       val_read = true;
+                       mutex_lock(&codec->hash_mutex);
+                       goto retry;
+               }
+               info->vol[ch] = val;
+               info->head.val |= INFO_AMP_VOL(ch);
+       }
+       return info;
 }
 
 /*
- * write the current volume in info to the h/w and update the cache
+ * write the current volume in info to the h/w
  */
 static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
                         hda_nid_t nid, int ch, int direction, int index,
@@ -1766,7 +1786,6 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
        else
                parm |= val;
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm);
-       info->vol[ch] = val;
 }
 
 /**
@@ -1783,10 +1802,14 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
                           int direction, int index)
 {
        struct hda_amp_info *info;
-       info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
-       if (!info)
-               return 0;
-       return get_vol_mute(codec, info, nid, ch, direction, index);
+       unsigned int val = 0;
+
+       mutex_lock(&codec->hash_mutex);
+       info = update_amp_hash(codec, nid, ch, direction, index);
+       if (info)
+               val = info->vol[ch];
+       mutex_unlock(&codec->hash_mutex);
+       return val;
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read);
 
@@ -1808,15 +1831,23 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
 {
        struct hda_amp_info *info;
 
-       info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx));
-       if (!info)
-               return 0;
        if (snd_BUG_ON(mask & ~0xff))
                mask &= 0xff;
        val &= mask;
-       val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask;
-       if (info->vol[ch] == val)
+
+       mutex_lock(&codec->hash_mutex);
+       info = update_amp_hash(codec, nid, ch, direction, idx);
+       if (!info) {
+               mutex_unlock(&codec->hash_mutex);
+               return 0;
+       }
+       val |= info->vol[ch] & ~mask;
+       if (info->vol[ch] == val) {
+               mutex_unlock(&codec->hash_mutex);
                return 0;
+       }
+       info->vol[ch] = val;
+       mutex_unlock(&codec->hash_mutex);
        put_vol_mute(codec, info, nid, ch, direction, idx, val);
        return 1;
 }
@@ -2263,7 +2294,10 @@ int snd_hda_codec_reset(struct hda_codec *codec)
        /* OK, let it free */
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-       cancel_delayed_work(&codec->power_work);
+       cancel_delayed_work_sync(&codec->power_work);
+       codec->power_on = 0;
+       codec->power_transition = 0;
+       codec->power_jiffies = jiffies;
        flush_workqueue(codec->bus->workq);
 #endif
        snd_hda_ctls_clear(codec);
@@ -2859,12 +2893,15 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        int idx = kcontrol->private_value;
-       struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+       struct hda_spdif_out *spdif;
 
+       mutex_lock(&codec->spdif_mutex);
+       spdif = snd_array_elem(&codec->spdif_out, idx);
        ucontrol->value.iec958.status[0] = spdif->status & 0xff;
        ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff;
        ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff;
        ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff;
+       mutex_unlock(&codec->spdif_mutex);
 
        return 0;
 }
@@ -2950,12 +2987,14 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        int idx = kcontrol->private_value;
-       struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
-       hda_nid_t nid = spdif->nid;
+       struct hda_spdif_out *spdif;
+       hda_nid_t nid;
        unsigned short val;
        int change;
 
        mutex_lock(&codec->spdif_mutex);
+       spdif = snd_array_elem(&codec->spdif_out, idx);
+       nid = spdif->nid;
        spdif->status = ucontrol->value.iec958.status[0] |
                ((unsigned int)ucontrol->value.iec958.status[1] << 8) |
                ((unsigned int)ucontrol->value.iec958.status[2] << 16) |
@@ -2977,9 +3016,12 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        int idx = kcontrol->private_value;
-       struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+       struct hda_spdif_out *spdif;
 
+       mutex_lock(&codec->spdif_mutex);
+       spdif = snd_array_elem(&codec->spdif_out, idx);
        ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE;
+       mutex_unlock(&codec->spdif_mutex);
        return 0;
 }
 
@@ -2999,12 +3041,14 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        int idx = kcontrol->private_value;
-       struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
-       hda_nid_t nid = spdif->nid;
+       struct hda_spdif_out *spdif;
+       hda_nid_t nid;
        unsigned short val;
        int change;
 
        mutex_lock(&codec->spdif_mutex);
+       spdif = snd_array_elem(&codec->spdif_out, idx);
+       nid = spdif->nid;
        val = spdif->ctls & ~AC_DIG1_ENABLE;
        if (ucontrol->value.integer.value[0])
                val |= AC_DIG1_ENABLE;
@@ -3092,6 +3136,9 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls);
 
+/* get the hda_spdif_out entry from the given NID
+ * call within spdif_mutex lock
+ */
 struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
                                               hda_nid_t nid)
 {
@@ -3108,9 +3155,10 @@ EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid);
 
 void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
 {
-       struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+       struct hda_spdif_out *spdif;
 
        mutex_lock(&codec->spdif_mutex);
+       spdif = snd_array_elem(&codec->spdif_out, idx);
        spdif->nid = (u16)-1;
        mutex_unlock(&codec->spdif_mutex);
 }
@@ -3118,10 +3166,11 @@ EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign);
 
 void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
 {
-       struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+       struct hda_spdif_out *spdif;
        unsigned short val;
 
        mutex_lock(&codec->spdif_mutex);
+       spdif = snd_array_elem(&codec->spdif_out, idx);
        if (spdif->nid != nid) {
                spdif->nid = nid;
                val = spdif->ctls;
@@ -3486,11 +3535,14 @@ static void hda_call_codec_suspend(struct hda_codec *codec)
                            codec->afg ? codec->afg : codec->mfg,
                            AC_PWRST_D3);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-       snd_hda_update_power_acct(codec);
        cancel_delayed_work(&codec->power_work);
+       spin_lock(&codec->power_lock);
+       snd_hda_update_power_acct(codec);
+       trace_hda_power_down(codec);
        codec->power_on = 0;
        codec->power_transition = 0;
        codec->power_jiffies = jiffies;
+       spin_unlock(&codec->power_lock);
 #endif
 }
 
@@ -3499,6 +3551,10 @@ static void hda_call_codec_suspend(struct hda_codec *codec)
  */
 static void hda_call_codec_resume(struct hda_codec *codec)
 {
+       /* set as if powered on for avoiding re-entering the resume
+        * in the resume / power-save sequence
+        */
+       hda_keep_power_on(codec);
        hda_set_power_state(codec,
                            codec->afg ? codec->afg : codec->mfg,
                            AC_PWRST_D0);
@@ -3514,6 +3570,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
                snd_hda_codec_resume_amp(codec);
                snd_hda_codec_resume_cache(codec);
        }
+       snd_hda_power_down(codec); /* flag down before returning */
 }
 #endif /* CONFIG_PM */
 
@@ -3665,7 +3722,8 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
 }
 EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
 
-static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid,
+                                 int dir)
 {
        unsigned int val = 0;
        if (nid != codec->afg &&
@@ -3680,11 +3738,12 @@ static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid)
 
 static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
 {
-       return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid),
+       return query_caps_hash(codec, nid, 0, HDA_HASH_PARPCM_KEY(nid),
                               get_pcm_param);
 }
 
-static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid,
+                                    int dir)
 {
        unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
        if (!streams || streams == -1)
@@ -3696,7 +3755,7 @@ static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid)
 
 static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
 {
-       return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid),
+       return query_caps_hash(codec, nid, 0, HDA_HASH_PARSTR_KEY(nid),
                               get_stream_param);
 }
 
@@ -3775,11 +3834,13 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
                                        bps = 20;
                        }
                }
+#if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */
                if (streams & AC_SUPFMT_FLOAT32) {
                        formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
                        if (!bps)
                                bps = 32;
                }
+#endif
                if (streams == AC_SUPFMT_AC3) {
                        /* should be exclusive */
                        /* temporary hack: we have still no proper support
@@ -4283,12 +4344,18 @@ static void hda_power_work(struct work_struct *work)
                container_of(work, struct hda_codec, power_work.work);
        struct hda_bus *bus = codec->bus;
 
+       spin_lock(&codec->power_lock);
+       if (codec->power_transition > 0) { /* during power-up sequence? */
+               spin_unlock(&codec->power_lock);
+               return;
+       }
        if (!codec->power_on || codec->power_count) {
                codec->power_transition = 0;
+               spin_unlock(&codec->power_lock);
                return;
        }
+       spin_unlock(&codec->power_lock);
 
-       trace_hda_power_down(codec);
        hda_call_codec_suspend(codec);
        if (bus->ops.pm_notify)
                bus->ops.pm_notify(bus);
@@ -4296,9 +4363,11 @@ static void hda_power_work(struct work_struct *work)
 
 static void hda_keep_power_on(struct hda_codec *codec)
 {
+       spin_lock(&codec->power_lock);
        codec->power_count++;
        codec->power_on = 1;
        codec->power_jiffies = jiffies;
+       spin_unlock(&codec->power_lock);
 }
 
 /* update the power on/off account with the current jiffies */
@@ -4323,19 +4392,31 @@ void snd_hda_power_up(struct hda_codec *codec)
 {
        struct hda_bus *bus = codec->bus;
 
+       spin_lock(&codec->power_lock);
        codec->power_count++;
-       if (codec->power_on || codec->power_transition)
+       if (codec->power_on || codec->power_transition > 0) {
+               spin_unlock(&codec->power_lock);
                return;
+       }
+       spin_unlock(&codec->power_lock);
 
+       cancel_delayed_work_sync(&codec->power_work);
+
+       spin_lock(&codec->power_lock);
        trace_hda_power_up(codec);
        snd_hda_update_power_acct(codec);
        codec->power_on = 1;
        codec->power_jiffies = jiffies;
+       codec->power_transition = 1; /* avoid reentrance */
+       spin_unlock(&codec->power_lock);
+
        if (bus->ops.pm_notify)
                bus->ops.pm_notify(bus);
        hda_call_codec_resume(codec);
-       cancel_delayed_work(&codec->power_work);
+
+       spin_lock(&codec->power_lock);
        codec->power_transition = 0;
+       spin_unlock(&codec->power_lock);
 }
 EXPORT_SYMBOL_HDA(snd_hda_power_up);
 
@@ -4351,14 +4432,18 @@ EXPORT_SYMBOL_HDA(snd_hda_power_up);
  */
 void snd_hda_power_down(struct hda_codec *codec)
 {
+       spin_lock(&codec->power_lock);
        --codec->power_count;
-       if (!codec->power_on || codec->power_count || codec->power_transition)
+       if (!codec->power_on || codec->power_count || codec->power_transition) {
+               spin_unlock(&codec->power_lock);
                return;
+       }
        if (power_save(codec)) {
-               codec->power_transition = 1; /* avoid reentrance */
+               codec->power_transition = -1; /* avoid reentrance */
                queue_delayed_work(codec->bus->workq, &codec->power_work,
                                msecs_to_jiffies(power_save(codec) * 1000));
        }
+       spin_unlock(&codec->power_lock);
 }
 EXPORT_SYMBOL_HDA(snd_hda_power_down);
 
@@ -4710,11 +4795,11 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
 {
        const hda_nid_t *nids = mout->dac_nids;
        int chs = substream->runtime->channels;
-       struct hda_spdif_out *spdif =
-                       snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
+       struct hda_spdif_out *spdif;
        int i;
 
        mutex_lock(&codec->spdif_mutex);
+       spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
        if (mout->dig_out_nid && mout->share_spdif &&
            mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
                if (chs == 2 &&
@@ -4795,601 +4880,58 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup);
 
-/*
- * Helper for automatic pin configuration
- */
-
-static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list)
-{
-       for (; *list; list++)
-               if (*list == nid)
-                       return 1;
-       return 0;
-}
-
-
-/*
- * Sort an associated group of pins according to their sequence numbers.
- */
-static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
-                                 int num_pins)
-{
-       int i, j;
-       short seq;
-       hda_nid_t nid;
-
-       for (i = 0; i < num_pins; i++) {
-               for (j = i + 1; j < num_pins; j++) {
-                       if (sequences[i] > sequences[j]) {
-                               seq = sequences[i];
-                               sequences[i] = sequences[j];
-                               sequences[j] = seq;
-                               nid = pins[i];
-                               pins[i] = pins[j];
-                               pins[j] = nid;
-                       }
-               }
-       }
-}
-
-
-/* add the found input-pin to the cfg->inputs[] table */
-static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
-                                  int type)
-{
-       if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
-               cfg->inputs[cfg->num_inputs].pin = nid;
-               cfg->inputs[cfg->num_inputs].type = type;
-               cfg->num_inputs++;
-       }
-}
-
-/* sort inputs in the order of AUTO_PIN_* type */
-static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
-{
-       int i, j;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               for (j = i + 1; j < cfg->num_inputs; j++) {
-                       if (cfg->inputs[i].type > cfg->inputs[j].type) {
-                               struct auto_pin_cfg_item tmp;
-                               tmp = cfg->inputs[i];
-                               cfg->inputs[i] = cfg->inputs[j];
-                               cfg->inputs[j] = tmp;
-                       }
-               }
-       }
-}
-
-/* Reorder the surround channels
- * ALSA sequence is front/surr/clfe/side
- * HDA sequence is:
- *    4-ch: front/surr  =>  OK as it is
- *    6-ch: front/clfe/surr
- *    8-ch: front/clfe/rear/side|fc
- */
-static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
-{
-       hda_nid_t nid;
-
-       switch (nums) {
-       case 3:
-       case 4:
-               nid = pins[1];
-               pins[1] = pins[2];
-               pins[2] = nid;
-               break;
-       }
-}
-
-/*
- * Parse all pin widgets and store the useful pin nids to cfg
- *
- * The number of line-outs or any primary output is stored in line_outs,
- * and the corresponding output pins are assigned to line_out_pins[],
- * in the order of front, rear, CLFE, side, ...
- *
- * If more extra outputs (speaker and headphone) are found, the pins are
- * assisnged to hp_pins[] and speaker_pins[], respectively.  If no line-out jack
- * is detected, one of speaker of HP pins is assigned as the primary
- * output, i.e. to line_out_pins[0].  So, line_outs is always positive
- * if any analog output exists.
- *
- * The analog input pins are assigned to inputs array.
- * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
- * respectively.
- */
-int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
-                            struct auto_pin_cfg *cfg,
-                            const hda_nid_t *ignore_nids,
-                            unsigned int cond_flags)
-{
-       hda_nid_t nid, end_nid;
-       short seq, assoc_line_out;
-       short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
-       short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
-       short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
-       int i;
-
-       memset(cfg, 0, sizeof(*cfg));
-
-       memset(sequences_line_out, 0, sizeof(sequences_line_out));
-       memset(sequences_speaker, 0, sizeof(sequences_speaker));
-       memset(sequences_hp, 0, sizeof(sequences_hp));
-       assoc_line_out = 0;
-
-       codec->ignore_misc_bit = true;
-       end_nid = codec->start_nid + codec->num_nodes;
-       for (nid = codec->start_nid; nid < end_nid; nid++) {
-               unsigned int wid_caps = get_wcaps(codec, nid);
-               unsigned int wid_type = get_wcaps_type(wid_caps);
-               unsigned int def_conf;
-               short assoc, loc, conn, dev;
-
-               /* read all default configuration for pin complex */
-               if (wid_type != AC_WID_PIN)
-                       continue;
-               /* ignore the given nids (e.g. pc-beep returns error) */
-               if (ignore_nids && is_in_nid_list(nid, ignore_nids))
-                       continue;
-
-               def_conf = snd_hda_codec_get_pincfg(codec, nid);
-               if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
-                     AC_DEFCFG_MISC_NO_PRESENCE))
-                       codec->ignore_misc_bit = false;
-               conn = get_defcfg_connect(def_conf);
-               if (conn == AC_JACK_PORT_NONE)
-                       continue;
-               loc = get_defcfg_location(def_conf);
-               dev = get_defcfg_device(def_conf);
-
-               /* workaround for buggy BIOS setups */
-               if (dev == AC_JACK_LINE_OUT) {
-                       if (conn == AC_JACK_PORT_FIXED)
-                               dev = AC_JACK_SPEAKER;
-               }
-
-               switch (dev) {
-               case AC_JACK_LINE_OUT:
-                       seq = get_defcfg_sequence(def_conf);
-                       assoc = get_defcfg_association(def_conf);
-
-                       if (!(wid_caps & AC_WCAP_STEREO))
-                               if (!cfg->mono_out_pin)
-                                       cfg->mono_out_pin = nid;
-                       if (!assoc)
-                               continue;
-                       if (!assoc_line_out)
-                               assoc_line_out = assoc;
-                       else if (assoc_line_out != assoc)
-                               continue;
-                       if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins))
-                               continue;
-                       cfg->line_out_pins[cfg->line_outs] = nid;
-                       sequences_line_out[cfg->line_outs] = seq;
-                       cfg->line_outs++;
-                       break;
-               case AC_JACK_SPEAKER:
-                       seq = get_defcfg_sequence(def_conf);
-                       assoc = get_defcfg_association(def_conf);
-                       if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
-                               continue;
-                       cfg->speaker_pins[cfg->speaker_outs] = nid;
-                       sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq;
-                       cfg->speaker_outs++;
-                       break;
-               case AC_JACK_HP_OUT:
-                       seq = get_defcfg_sequence(def_conf);
-                       assoc = get_defcfg_association(def_conf);
-                       if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
-                               continue;
-                       cfg->hp_pins[cfg->hp_outs] = nid;
-                       sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
-                       cfg->hp_outs++;
-                       break;
-               case AC_JACK_MIC_IN:
-                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
-                       break;
-               case AC_JACK_LINE_IN:
-                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
-                       break;
-               case AC_JACK_CD:
-                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
-                       break;
-               case AC_JACK_AUX:
-                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
-                       break;
-               case AC_JACK_SPDIF_OUT:
-               case AC_JACK_DIG_OTHER_OUT:
-                       if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins))
-                               continue;
-                       cfg->dig_out_pins[cfg->dig_outs] = nid;
-                       cfg->dig_out_type[cfg->dig_outs] =
-                               (loc == AC_JACK_LOC_HDMI) ?
-                               HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF;
-                       cfg->dig_outs++;
-                       break;
-               case AC_JACK_SPDIF_IN:
-               case AC_JACK_DIG_OTHER_IN:
-                       cfg->dig_in_pin = nid;
-                       if (loc == AC_JACK_LOC_HDMI)
-                               cfg->dig_in_type = HDA_PCM_TYPE_HDMI;
-                       else
-                               cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
-                       break;
-               }
-       }
-
-       /* FIX-UP:
-        * If no line-out is defined but multiple HPs are found,
-        * some of them might be the real line-outs.
-        */
-       if (!cfg->line_outs && cfg->hp_outs > 1 &&
-           !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) {
-               int i = 0;
-               while (i < cfg->hp_outs) {
-                       /* The real HPs should have the sequence 0x0f */
-                       if ((sequences_hp[i] & 0x0f) == 0x0f) {
-                               i++;
-                               continue;
-                       }
-                       /* Move it to the line-out table */
-                       cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i];
-                       sequences_line_out[cfg->line_outs] = sequences_hp[i];
-                       cfg->line_outs++;
-                       cfg->hp_outs--;
-                       memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1,
-                               sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i));
-                       memmove(sequences_hp + i, sequences_hp + i + 1,
-                               sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
-               }
-               memset(cfg->hp_pins + cfg->hp_outs, 0,
-                      sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
-               if (!cfg->hp_outs)
-                       cfg->line_out_type = AUTO_PIN_HP_OUT;
-
-       }
-
-       /* sort by sequence */
-       sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out,
-                             cfg->line_outs);
-       sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker,
-                             cfg->speaker_outs);
-       sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
-                             cfg->hp_outs);
-
-       /*
-        * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
-        * as a primary output
-        */
-       if (!cfg->line_outs &&
-           !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) {
-               if (cfg->speaker_outs) {
-                       cfg->line_outs = cfg->speaker_outs;
-                       memcpy(cfg->line_out_pins, cfg->speaker_pins,
-                              sizeof(cfg->speaker_pins));
-                       cfg->speaker_outs = 0;
-                       memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
-                       cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
-               } else if (cfg->hp_outs) {
-                       cfg->line_outs = cfg->hp_outs;
-                       memcpy(cfg->line_out_pins, cfg->hp_pins,
-                              sizeof(cfg->hp_pins));
-                       cfg->hp_outs = 0;
-                       memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
-                       cfg->line_out_type = AUTO_PIN_HP_OUT;
-               }
-       }
-
-       reorder_outputs(cfg->line_outs, cfg->line_out_pins);
-       reorder_outputs(cfg->hp_outs, cfg->hp_pins);
-       reorder_outputs(cfg->speaker_outs, cfg->speaker_pins);
-
-       sort_autocfg_input_pins(cfg);
-
-       /*
-        * debug prints of the parsed results
-        */
-       snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
-                  cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
-                  cfg->line_out_pins[2], cfg->line_out_pins[3],
-                  cfg->line_out_pins[4],
-                  cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
-                  (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
-                   "speaker" : "line"));
-       snd_printd("   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
-                  cfg->speaker_outs, cfg->speaker_pins[0],
-                  cfg->speaker_pins[1], cfg->speaker_pins[2],
-                  cfg->speaker_pins[3], cfg->speaker_pins[4]);
-       snd_printd("   hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
-                  cfg->hp_outs, cfg->hp_pins[0],
-                  cfg->hp_pins[1], cfg->hp_pins[2],
-                  cfg->hp_pins[3], cfg->hp_pins[4]);
-       snd_printd("   mono: mono_out=0x%x\n", cfg->mono_out_pin);
-       if (cfg->dig_outs)
-               snd_printd("   dig-out=0x%x/0x%x\n",
-                          cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
-       snd_printd("   inputs:");
-       for (i = 0; i < cfg->num_inputs; i++) {
-               snd_printd(" %s=0x%x",
-                           hda_get_autocfg_input_label(codec, cfg, i),
-                           cfg->inputs[i].pin);
-       }
-       snd_printd("\n");
-       if (cfg->dig_in_pin)
-               snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
-
-       return 0;
-}
-EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg);
-
-int snd_hda_get_input_pin_attr(unsigned int def_conf)
-{
-       unsigned int loc = get_defcfg_location(def_conf);
-       unsigned int conn = get_defcfg_connect(def_conf);
-       if (conn == AC_JACK_PORT_NONE)
-               return INPUT_PIN_ATTR_UNUSED;
-       /* Windows may claim the internal mic to be BOTH, too */
-       if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
-               return INPUT_PIN_ATTR_INT;
-       if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
-               return INPUT_PIN_ATTR_INT;
-       if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
-               return INPUT_PIN_ATTR_DOCK;
-       if (loc == AC_JACK_LOC_REAR)
-               return INPUT_PIN_ATTR_REAR;
-       if (loc == AC_JACK_LOC_FRONT)
-               return INPUT_PIN_ATTR_FRONT;
-       return INPUT_PIN_ATTR_NORMAL;
-}
-EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
-
-/**
- * hda_get_input_pin_label - Give a label for the given input pin
- *
- * When check_location is true, the function checks the pin location
- * for mic and line-in pins, and set an appropriate prefix like "Front",
- * "Rear", "Internal".
- */
-
-static const char *hda_get_input_pin_label(struct hda_codec *codec,
-                                          hda_nid_t pin, bool check_location)
-{
-       unsigned int def_conf;
-       static const char * const mic_names[] = {
-               "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
-       };
-       int attr;
-
-       def_conf = snd_hda_codec_get_pincfg(codec, pin);
-
-       switch (get_defcfg_device(def_conf)) {
-       case AC_JACK_MIC_IN:
-               if (!check_location)
-                       return "Mic";
-               attr = snd_hda_get_input_pin_attr(def_conf);
-               if (!attr)
-                       return "None";
-               return mic_names[attr - 1];
-       case AC_JACK_LINE_IN:
-               if (!check_location)
-                       return "Line";
-               attr = snd_hda_get_input_pin_attr(def_conf);
-               if (!attr)
-                       return "None";
-               if (attr == INPUT_PIN_ATTR_DOCK)
-                       return "Dock Line";
-               return "Line";
-       case AC_JACK_AUX:
-               return "Aux";
-       case AC_JACK_CD:
-               return "CD";
-       case AC_JACK_SPDIF_IN:
-               return "SPDIF In";
-       case AC_JACK_DIG_OTHER_IN:
-               return "Digital In";
-       default:
-               return "Misc";
-       }
-}
-
-/* Check whether the location prefix needs to be added to the label.
- * If all mic-jacks are in the same location (e.g. rear panel), we don't
- * have to put "Front" prefix to each label.  In such a case, returns false.
- */
-static int check_mic_location_need(struct hda_codec *codec,
-                                  const struct auto_pin_cfg *cfg,
-                                  int input)
-{
-       unsigned int defc;
-       int i, attr, attr2;
-
-       defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
-       attr = snd_hda_get_input_pin_attr(defc);
-       /* for internal or docking mics, we need locations */
-       if (attr <= INPUT_PIN_ATTR_NORMAL)
-               return 1;
-
-       attr = 0;
-       for (i = 0; i < cfg->num_inputs; i++) {
-               defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
-               attr2 = snd_hda_get_input_pin_attr(defc);
-               if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
-                       if (attr && attr != attr2)
-                               return 1; /* different locations found */
-                       attr = attr2;
-               }
-       }
-       return 0;
-}
-
 /**
- * hda_get_autocfg_input_label - Get a label for the given input
+ * snd_hda_get_default_vref - Get the default (mic) VREF pin bits
  *
- * Get a label for the given input pin defined by the autocfg item.
- * Unlike hda_get_input_pin_label(), this function checks all inputs
- * defined in autocfg and avoids the redundant mic/line prefix as much as
- * possible.
- */
-const char *hda_get_autocfg_input_label(struct hda_codec *codec,
-                                       const struct auto_pin_cfg *cfg,
-                                       int input)
-{
-       int type = cfg->inputs[input].type;
-       int has_multiple_pins = 0;
-
-       if ((input > 0 && cfg->inputs[input - 1].type == type) ||
-           (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
-               has_multiple_pins = 1;
-       if (has_multiple_pins && type == AUTO_PIN_MIC)
-               has_multiple_pins &= check_mic_location_need(codec, cfg, input);
-       return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
-                                      has_multiple_pins);
-}
-EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
-
-/* return the position of NID in the list, or -1 if not found */
-static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
-       int i;
-       for (i = 0; i < nums; i++)
-               if (list[i] == nid)
-                       return i;
-       return -1;
-}
-
-/* get a unique suffix or an index number */
-static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
-                                   int num_pins, int *indexp)
-{
-       static const char * const channel_sfx[] = {
-               " Front", " Surround", " CLFE", " Side"
-       };
-       int i;
-
-       i = find_idx_in_nid_list(nid, pins, num_pins);
-       if (i < 0)
-               return NULL;
-       if (num_pins == 1)
-               return "";
-       if (num_pins > ARRAY_SIZE(channel_sfx)) {
-               if (indexp)
-                       *indexp = i;
-               return "";
-       }
-       return channel_sfx[i];
-}
-
-static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
-                              const struct auto_pin_cfg *cfg,
-                              const char *name, char *label, int maxlen,
-                              int *indexp)
-{
-       unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
-       int attr = snd_hda_get_input_pin_attr(def_conf);
-       const char *pfx = "", *sfx = "";
-
-       /* handle as a speaker if it's a fixed line-out */
-       if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT)
-               name = "Speaker";
-       /* check the location */
-       switch (attr) {
-       case INPUT_PIN_ATTR_DOCK:
-               pfx = "Dock ";
-               break;
-       case INPUT_PIN_ATTR_FRONT:
-               pfx = "Front ";
-               break;
-       }
-       if (cfg) {
-               /* try to give a unique suffix if needed */
-               sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs,
-                                      indexp);
-               if (!sfx)
-                       sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs,
-                                              indexp);
-               if (!sfx) {
-                       /* don't add channel suffix for Headphone controls */
-                       int idx = find_idx_in_nid_list(nid, cfg->hp_pins,
-                                                      cfg->hp_outs);
-                       if (idx >= 0)
-                               *indexp = idx;
-                       sfx = "";
+ * Guess the suitable VREF pin bits to be set as the pin-control value.
+ * Note: the function doesn't set the AC_PINCTL_IN_EN bit.
+ */
+unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin)
+{
+       unsigned int pincap;
+       unsigned int oldval;
+       oldval = snd_hda_codec_read(codec, pin, 0,
+                                   AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+       pincap = snd_hda_query_pin_caps(codec, pin);
+       pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+       /* Exception: if the default pin setup is vref50, we give it priority */
+       if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
+               return AC_PINCTL_VREF_80;
+       else if (pincap & AC_PINCAP_VREF_50)
+               return AC_PINCTL_VREF_50;
+       else if (pincap & AC_PINCAP_VREF_100)
+               return AC_PINCTL_VREF_100;
+       else if (pincap & AC_PINCAP_VREF_GRD)
+               return AC_PINCTL_VREF_GRD;
+       return AC_PINCTL_VREF_HIZ;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_default_vref);
+
+int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
+                        unsigned int val, bool cached)
+{
+       if (val) {
+               unsigned int cap = snd_hda_query_pin_caps(codec, pin);
+               if (cap && (val & AC_PINCTL_OUT_EN)) {
+                       if (!(cap & AC_PINCAP_OUT))
+                               val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+                       else if ((val & AC_PINCTL_HP_EN) &&
+                                !(cap & AC_PINCAP_HP_DRV))
+                               val &= ~AC_PINCTL_HP_EN;
                }
-       }
-       snprintf(label, maxlen, "%s%s%s", pfx, name, sfx);
-       return 1;
-}
-
-/**
- * snd_hda_get_pin_label - Get a label for the given I/O pin
- *
- * Get a label for the given pin.  This function works for both input and
- * output pins.  When @cfg is given as non-NULL, the function tries to get
- * an optimized label using hda_get_autocfg_input_label().
- *
- * This function tries to give a unique label string for the pin as much as
- * possible.  For example, when the multiple line-outs are present, it adds
- * the channel suffix like "Front", "Surround", etc (only when @cfg is given).
- * If no unique name with a suffix is available and @indexp is non-NULL, the
- * index number is stored in the pointer.
- */
-int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
-                         const struct auto_pin_cfg *cfg,
-                         char *label, int maxlen, int *indexp)
-{
-       unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
-       const char *name = NULL;
-       int i;
-
-       if (indexp)
-               *indexp = 0;
-       if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
-               return 0;
-
-       switch (get_defcfg_device(def_conf)) {
-       case AC_JACK_LINE_OUT:
-               return fill_audio_out_name(codec, nid, cfg, "Line Out",
-                                          label, maxlen, indexp);
-       case AC_JACK_SPEAKER:
-               return fill_audio_out_name(codec, nid, cfg, "Speaker",
-                                          label, maxlen, indexp);
-       case AC_JACK_HP_OUT:
-               return fill_audio_out_name(codec, nid, cfg, "Headphone",
-                                          label, maxlen, indexp);
-       case AC_JACK_SPDIF_OUT:
-       case AC_JACK_DIG_OTHER_OUT:
-               if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI)
-                       name = "HDMI";
-               else
-                       name = "SPDIF";
-               if (cfg && indexp) {
-                       i = find_idx_in_nid_list(nid, cfg->dig_out_pins,
-                                                cfg->dig_outs);
-                       if (i >= 0)
-                               *indexp = i;
-               }
-               break;
-       default:
-               if (cfg) {
-                       for (i = 0; i < cfg->num_inputs; i++) {
-                               if (cfg->inputs[i].pin != nid)
-                                       continue;
-                               name = hda_get_autocfg_input_label(codec, cfg, i);
-                               if (name)
-                                       break;
-                       }
+               if (cap && (val & AC_PINCTL_IN_EN)) {
+                       if (!(cap & AC_PINCAP_IN))
+                               val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN);
                }
-               if (!name)
-                       name = hda_get_input_pin_label(codec, nid, true);
-               break;
        }
-       if (!name)
-               return 0;
-       strlcpy(label, name, maxlen);
-       return 1;
+       if (cached)
+               return snd_hda_codec_update_cache(codec, pin, 0,
+                               AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+       else
+               return snd_hda_codec_write(codec, pin, 0,
+                                          AC_VERB_SET_PIN_WIDGET_CONTROL, val);
 }
-EXPORT_SYMBOL_HDA(snd_hda_get_pin_label);
+EXPORT_SYMBOL_HDA(_snd_hda_set_pin_ctl);
 
 /**
  * snd_hda_add_imux_item - Add an item to input_mux
@@ -5444,8 +4986,6 @@ int snd_hda_suspend(struct hda_bus *bus)
        list_for_each_entry(codec, &bus->codec_list, list) {
                if (hda_codec_is_power_on(codec))
                        hda_call_codec_suspend(codec);
-               if (codec->patch_ops.post_suspend)
-                       codec->patch_ops.post_suspend(codec);
        }
        return 0;
 }
@@ -5465,10 +5005,7 @@ int snd_hda_resume(struct hda_bus *bus)
        struct hda_codec *codec;
 
        list_for_each_entry(codec, &bus->codec_list, list) {
-               if (codec->patch_ops.pre_resume)
-                       codec->patch_ops.pre_resume(codec);
-               if (snd_hda_codec_needs_resume(codec))
-                       hda_call_codec_resume(codec);
+               hda_call_codec_resume(codec);
        }
        return 0;
 }
index 56b4f74c0b13a101e16e9433f76341ef7a5a7c0e..54b52819fb47acf5ef8b2342643a1ece7d9a8c57 100644 (file)
@@ -704,8 +704,6 @@ struct hda_codec_ops {
                                unsigned int power_state);
 #ifdef CONFIG_PM
        int (*suspend)(struct hda_codec *codec, pm_message_t state);
-       int (*post_suspend)(struct hda_codec *codec);
-       int (*pre_resume)(struct hda_codec *codec);
        int (*resume)(struct hda_codec *codec);
 #endif
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -829,6 +827,7 @@ struct hda_codec {
 
        struct mutex spdif_mutex;
        struct mutex control_mutex;
+       struct mutex hash_mutex;
        struct snd_array spdif_out;
        unsigned int spdif_in_enable;   /* SPDIF input enable? */
        const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
@@ -861,12 +860,13 @@ struct hda_codec {
        unsigned int no_jack_detect:1;  /* Machine has no jack-detection */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        unsigned int power_on :1;       /* current (global) power-state */
-       unsigned int power_transition :1; /* power-state in transition */
+       int power_transition;   /* power-state in transition */
        int power_count;        /* current (global) power refcount */
        struct delayed_work power_work; /* delayed task for powerdown */
        unsigned long power_on_acct;
        unsigned long power_off_acct;
        unsigned long power_jiffies;
+       spinlock_t power_lock;
 #endif
 
        /* codec-specific additional proc output */
@@ -911,10 +911,13 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
                          hda_nid_t *start_id);
 int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
                            hda_nid_t *conn_list, int max_conns);
+static inline int
+snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
+{
+       return snd_hda_get_connections(codec, nid, NULL, 0);
+}
 int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
                            hda_nid_t *conn_list, int max_conns);
-int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
-                         const hda_nid_t **listp);
 int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
                          const hda_nid_t *list);
 int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
@@ -1051,12 +1054,10 @@ const char *snd_hda_get_jack_location(u32 cfg);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 void snd_hda_power_up(struct hda_codec *codec);
 void snd_hda_power_down(struct hda_codec *codec);
-#define snd_hda_codec_needs_resume(codec) codec->power_count
 void snd_hda_update_power_acct(struct hda_codec *codec);
 #else
 static inline void snd_hda_power_up(struct hda_codec *codec) {}
 static inline void snd_hda_power_down(struct hda_codec *codec) {}
-#define snd_hda_codec_needs_resume(codec) 1
 #endif
 
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
index 1f350522bed436812b794c2544f39674ec4a868d..4ab8102f87ea63ccb83ccbb6c97df2d17fa13eb2 100644 (file)
@@ -497,6 +497,7 @@ enum {
        AZX_DRIVER_NVIDIA,
        AZX_DRIVER_TERA,
        AZX_DRIVER_CTX,
+       AZX_DRIVER_CTHDA,
        AZX_DRIVER_GENERIC,
        AZX_NUM_DRIVERS, /* keep this as last entry */
 };
@@ -518,6 +519,7 @@ enum {
 #define AZX_DCAPS_OLD_SSYNC    (1 << 20)       /* Old SSYNC reg for ICH */
 #define AZX_DCAPS_BUFSIZE      (1 << 21)       /* no buffer size alignment */
 #define AZX_DCAPS_ALIGN_BUFSIZE        (1 << 22)       /* buffer size alignment */
+#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)   /* BDLE in 4k boundary */
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
@@ -533,6 +535,9 @@ enum {
        (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\
         AZX_DCAPS_ALIGN_BUFSIZE)
 
+#define AZX_DCAPS_PRESET_CTHDA \
+       (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY)
+
 static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ICH] = "HDA Intel",
        [AZX_DRIVER_PCH] = "HDA Intel PCH",
@@ -546,6 +551,7 @@ static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_NVIDIA] = "HDA NVidia",
        [AZX_DRIVER_TERA] = "HDA Teradici", 
        [AZX_DRIVER_CTX] = "HDA Creative", 
+       [AZX_DRIVER_CTHDA] = "HDA Creative",
        [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
@@ -1285,7 +1291,8 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
 /*
  * set up a BDL entry
  */
-static int setup_bdle(struct snd_pcm_substream *substream,
+static int setup_bdle(struct azx *chip,
+                     struct snd_pcm_substream *substream,
                      struct azx_dev *azx_dev, u32 **bdlp,
                      int ofs, int size, int with_ioc)
 {
@@ -1304,6 +1311,12 @@ static int setup_bdle(struct snd_pcm_substream *substream,
                bdl[1] = cpu_to_le32(upper_32_bits(addr));
                /* program the size field of the BDL entry */
                chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
+               /* one BDLE cannot cross 4K boundary on CTHDA chips */
+               if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
+                       u32 remain = 0x1000 - (ofs & 0xfff);
+                       if (chunk > remain)
+                               chunk = remain;
+               }
                bdl[2] = cpu_to_le32(chunk);
                /* program the IOC to enable interrupt
                 * only when the whole fragment is processed
@@ -1356,7 +1369,7 @@ static int azx_setup_periods(struct azx *chip,
                                   bdl_pos_adj[chip->dev_index]);
                        pos_adj = 0;
                } else {
-                       ofs = setup_bdle(substream, azx_dev,
+                       ofs = setup_bdle(chip, substream, azx_dev,
                                         &bdl, ofs, pos_adj,
                                         !substream->runtime->no_period_wakeup);
                        if (ofs < 0)
@@ -1366,10 +1379,10 @@ static int azx_setup_periods(struct azx *chip,
                pos_adj = 0;
        for (i = 0; i < periods; i++) {
                if (i == periods - 1 && pos_adj)
-                       ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
+                       ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
                                         period_bytes - pos_adj, 0);
                else
-                       ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
+                       ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
                                         period_bytes,
                                         !substream->runtime->no_period_wakeup);
                if (ofs < 0)
@@ -2353,17 +2366,6 @@ static void azx_power_notify(struct hda_bus *bus)
  * power management
  */
 
-static int snd_hda_codecs_inuse(struct hda_bus *bus)
-{
-       struct hda_codec *codec;
-
-       list_for_each_entry(codec, &bus->codec_list, list) {
-               if (snd_hda_codec_needs_resume(codec))
-                       return 1;
-       }
-       return 0;
-}
-
 static int azx_suspend(struct pci_dev *pci, pm_message_t state)
 {
        struct snd_card *card = pci_get_drvdata(pci);
@@ -2410,8 +2412,7 @@ static int azx_resume(struct pci_dev *pci)
                return -EIO;
        azx_init_pci(chip);
 
-       if (snd_hda_codecs_inuse(chip->bus))
-               azx_init_chip(chip, 1);
+       azx_init_chip(chip, 1);
 
        snd_hda_resume(chip->bus);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
@@ -2565,6 +2566,8 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = {
        /* forced codec slots */
        SND_PCI_QUIRK(0x1043, 0x1262, "ASUS W5Fm", 0x103),
        SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103),
+       /* WinFast VP200 H (Teradici) user reported broken communication */
+       SND_PCI_QUIRK(0x3a21, 0x040d, "WinFast VP200 H", 0x101),
        {}
 };
 
@@ -3130,6 +3133,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
          .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
          AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
 #endif
+       /* CTHDA chips */
+       { PCI_DEVICE(0x1102, 0x0010),
+         .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
+       { PCI_DEVICE(0x1102, 0x0012),
+         .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
        /* Vortex86MX */
        { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
        /* VMware HDAudio */
@@ -3148,7 +3156,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
 MODULE_DEVICE_TABLE(pci, azx_ids);
 
 /* pci_driver definition */
-static struct pci_driver driver = {
+static struct pci_driver azx_driver = {
        .name = KBUILD_MODNAME,
        .id_table = azx_ids,
        .probe = azx_probe,
@@ -3159,15 +3167,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_azx_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_azx_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_azx_init)
-module_exit(alsa_card_azx_exit)
+module_pci_driver(azx_driver);
index d68948499fbc15d7342ba0c9a63675d769b95a92..2dd1c113a4c1b62248843849a5604ceb972f9f89 100644 (file)
@@ -17,6 +17,7 @@
 #include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_jack.h"
 
 bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
index c66655cf413a1bc074f62ac91e0ed6e3907e342d..8ae52465ec5df807efde3dad54c3a11fc00ca5aa 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef __SOUND_HDA_JACK_H
 #define __SOUND_HDA_JACK_H
 
+struct auto_pin_cfg;
+
 struct hda_jack_tbl {
        hda_nid_t nid;
        unsigned char action;           /* event action (0 = none) */
index 0ec9248165bca9c7f7f7d47aaffe4abc863b600c..9a096a8e0fc5b8cb01ce7620956c9bd5848eec4e 100644 (file)
@@ -262,6 +262,8 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
                          const struct hda_input_mux *imux,
                          struct snd_ctl_elem_value *ucontrol, hda_nid_t nid,
                          unsigned int *cur_val);
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+                         int index, int *type_index_ret);
 
 /*
  * Channel mode helper
@@ -393,72 +395,7 @@ struct hda_bus_unsolicited {
        struct hda_bus *bus;
 };
 
-/*
- * Helper for automatic pin configuration
- */
-
-enum {
-       AUTO_PIN_MIC,
-       AUTO_PIN_LINE_IN,
-       AUTO_PIN_CD,
-       AUTO_PIN_AUX,
-       AUTO_PIN_LAST
-};
-
-enum {
-       AUTO_PIN_LINE_OUT,
-       AUTO_PIN_SPEAKER_OUT,
-       AUTO_PIN_HP_OUT
-};
-
-#define AUTO_CFG_MAX_OUTS      HDA_MAX_OUTS
-#define AUTO_CFG_MAX_INS       8
-
-struct auto_pin_cfg_item {
-       hda_nid_t pin;
-       int type;
-};
-
-struct auto_pin_cfg;
-const char *hda_get_autocfg_input_label(struct hda_codec *codec,
-                                       const struct auto_pin_cfg *cfg,
-                                       int input);
-int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
-                         const struct auto_pin_cfg *cfg,
-                         char *label, int maxlen, int *indexp);
-int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
-                         int index, int *type_index_ret);
-
-enum {
-       INPUT_PIN_ATTR_UNUSED,  /* pin not connected */
-       INPUT_PIN_ATTR_INT,     /* internal mic/line-in */
-       INPUT_PIN_ATTR_DOCK,    /* docking mic/line-in */
-       INPUT_PIN_ATTR_NORMAL,  /* mic/line-in jack */
-       INPUT_PIN_ATTR_FRONT,   /* mic/line-in jack in front */
-       INPUT_PIN_ATTR_REAR,    /* mic/line-in jack in rear */
-};
-
-int snd_hda_get_input_pin_attr(unsigned int def_conf);
-
-struct auto_pin_cfg {
-       int line_outs;
-       /* sorted in the order of Front/Surr/CLFE/Side */
-       hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS];
-       int speaker_outs;
-       hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS];
-       int hp_outs;
-       int line_out_type;      /* AUTO_PIN_XXX_OUT */
-       hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
-       int num_inputs;
-       struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
-       int dig_outs;
-       hda_nid_t dig_out_pins[2];
-       hda_nid_t dig_in_pin;
-       hda_nid_t mono_out_pin;
-       int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */
-       int dig_in_type; /* HDA_PCM_TYPE_XXX */
-};
-
+/* helper macros to retrieve pin default-config values */
 #define get_defcfg_connect(cfg) \
        ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT)
 #define get_defcfg_association(cfg) \
@@ -472,19 +409,6 @@ struct auto_pin_cfg {
 #define get_defcfg_misc(cfg) \
        ((cfg & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT)
 
-/* bit-flags for snd_hda_parse_pin_def_config() behavior */
-#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */
-#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */
-
-int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
-                            struct auto_pin_cfg *cfg,
-                            const hda_nid_t *ignore_nids,
-                            unsigned int cond_flags);
-
-/* older function */
-#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
-       snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
-
 /* amp values */
 #define AMP_IN_MUTE(idx)       (0x7080 | ((idx)<<8))
 #define AMP_IN_UNMUTE(idx)     (0x7000 | ((idx)<<8))
@@ -502,6 +426,46 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
 #define PIN_HP                 (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
 #define PIN_HP_AMP             (AC_PINCTL_HP_EN)
 
+unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin);
+int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
+                        unsigned int val, bool cached);
+
+/**
+ * _snd_hda_set_pin_ctl - Set a pin-control value safely
+ * @codec: the codec instance
+ * @pin: the pin NID to set the control
+ * @val: the pin-control value (AC_PINCTL_* bits)
+ *
+ * This function sets the pin-control value to the given pin, but
+ * filters out the invalid pin-control bits when the pin has no such
+ * capabilities.  For example, when PIN_HP is passed but the pin has no
+ * HP-drive capability, the HP bit is omitted.
+ *
+ * The function doesn't check the input VREF capability bits, though.
+ * Use snd_hda_get_default_vref() to guess the right value.
+ * Also, this function is only for analog pins, not for HDMI pins.
+ */
+static inline int
+snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, unsigned int val)
+{
+       return _snd_hda_set_pin_ctl(codec, pin, val, false);
+}
+
+/**
+ * snd_hda_set_pin_ctl_cache - Set a pin-control value safely
+ * @codec: the codec instance
+ * @pin: the pin NID to set the control
+ * @val: the pin-control value (AC_PINCTL_* bits)
+ *
+ * Just like snd_hda_set_pin_ctl() but write to cache as well.
+ */
+static inline int
+snd_hda_set_pin_ctl_cache(struct hda_codec *codec, hda_nid_t pin,
+                         unsigned int val)
+{
+       return _snd_hda_set_pin_ctl(codec, pin, val, true);
+}
+
 /*
  * get widget capabilities
  */
index 7143393927da34ddeac2c86ce6538c669e85d16a..d8b2d6dee986b928ae0ffe98509a167e07ba639f 100644 (file)
@@ -28,6 +28,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
 
@@ -1742,9 +1743,7 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
        if (! ad198x_eapd_put(kcontrol, ucontrol))
                return 0;
        /* change speaker pin appropriately */
-       snd_hda_codec_write(codec, 0x05, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           spec->cur_eapd ? PIN_OUT : 0);
+       snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0);
        /* toggle HP mute appropriately */
        snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE,
@@ -3103,7 +3102,7 @@ static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
                                              int dac_idx)
 {
        /* set as output */
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+       snd_hda_set_pin_ctl(codec, nid, pin_type);
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
        switch (nid) {
        case 0x11: /* port-A - DAC 03 */
@@ -3157,6 +3156,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
        for (i = 0; i < cfg->num_inputs; i++) {
                hda_nid_t nid = cfg->inputs[i].pin;
                int type = cfg->inputs[i].type;
+               int val;
                switch (nid) {
                case 0x15: /* port-C */
                        snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
@@ -3165,8 +3165,10 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
                        snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
                        break;
                }
-               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   type == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
+               val = PIN_IN;
+               if (type == AUTO_PIN_MIC)
+                       val |= snd_hda_get_default_vref(codec, nid);
+               snd_hda_set_pin_ctl(codec, nid, val);
                if (nid != AD1988_PIN_CD_NID)
                        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                                            AMP_OUT_MUTE);
index 09ccfabb4a17c38a608d04d05b4a5979e6dc7ed7..19ae14f739cbbd7ad0d5c6bcff8cf945db97ff1b 100644 (file)
@@ -26,6 +26,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 
 /*
  */
@@ -341,8 +342,7 @@ static int ca0110_build_pcms(struct hda_codec *codec)
 static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
 {
        if (pin) {
-               snd_hda_codec_write(codec, pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+               snd_hda_set_pin_ctl(codec, pin, PIN_HP);
                if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
                        snd_hda_codec_write(codec, pin, 0,
                                            AC_VERB_SET_AMP_GAIN_MUTE,
@@ -356,8 +356,8 @@ static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
 static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
 {
        if (pin) {
-               snd_hda_codec_write(codec, pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80);
+               snd_hda_set_pin_ctl(codec, pin, PIN_IN |
+                                   snd_hda_get_default_vref(codec, pin));
                if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
                        snd_hda_codec_write(codec, pin, 0,
                                            AC_VERB_SET_AMP_GAIN_MUTE,
index 21d91d580da8b9e29091dca8ad5d91440b38797a..d0d3540e39e7746b1c42074257fe8194b928e09b 100644 (file)
@@ -30,6 +30,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 
 #define WIDGET_CHIP_CTRL      0x15
 #define WIDGET_DSP_CTRL       0x16
@@ -239,8 +240,7 @@ enum get_set {
 static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
 {
        if (pin) {
-               snd_hda_codec_write(codec, pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+               snd_hda_set_pin_ctl(codec, pin, PIN_HP);
                if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
                        snd_hda_codec_write(codec, pin, 0,
                                            AC_VERB_SET_AMP_GAIN_MUTE,
@@ -254,9 +254,8 @@ static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
 static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
 {
        if (pin) {
-               snd_hda_codec_write(codec, pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   PIN_VREF80);
+               snd_hda_set_pin_ctl(codec, pin, PIN_IN |
+                                   snd_hda_get_default_vref(codec, pin));
                if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
                        snd_hda_codec_write(codec, pin, 0,
                                            AC_VERB_SET_AMP_GAIN_MUTE,
index c83ccdba1e5afc1dca9715a870eedf68a8961ee8..9647ed4d7929175452ea77eee81677342264104f 100644 (file)
@@ -26,6 +26,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include <sound/tlv.h>
 
@@ -933,8 +934,7 @@ static void cs_automute(struct hda_codec *codec)
                        pin_ctl = 0;
 
                nid = cfg->speaker_pins[i];
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl);
+               snd_hda_set_pin_ctl(codec, nid, pin_ctl);
        }
        if (spec->gpio_eapd_hp) {
                unsigned int gpio = hp_present ?
@@ -948,16 +948,14 @@ static void cs_automute(struct hda_codec *codec)
                /* mute HPs if spdif jack (SENSE_B) is present */
                for (i = 0; i < cfg->hp_outs; i++) {
                        nid = cfg->hp_pins[i];
-                       snd_hda_codec_write(codec, nid, 0,
-                               AC_VERB_SET_PIN_WIDGET_CONTROL,
+                       snd_hda_set_pin_ctl(codec, nid,
                                (spdif_present && spec->sense_b) ? 0 : PIN_HP);
                }
 
                /* SPDIF TX on/off */
                if (cfg->dig_outs) {
                        nid = cfg->dig_out_pins[0];
-                       snd_hda_codec_write(codec, nid, 0,
-                               AC_VERB_SET_PIN_WIDGET_CONTROL,
+                       snd_hda_set_pin_ctl(codec, nid,
                                spdif_present ? PIN_OUT : 0);
 
                }
@@ -1024,13 +1022,11 @@ static void init_output(struct hda_codec *codec)
 
        /* set appropriate pin controls */
        for (i = 0; i < cfg->line_outs; i++)
-               snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               snd_hda_set_pin_ctl(codec, cfg->line_out_pins[i], PIN_OUT);
        /* HP */
        for (i = 0; i < cfg->hp_outs; i++) {
                hda_nid_t nid = cfg->hp_pins[i];
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+               snd_hda_set_pin_ctl(codec, nid, PIN_HP);
                if (!cfg->speaker_outs)
                        continue;
                if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
@@ -1041,8 +1037,7 @@ static void init_output(struct hda_codec *codec)
 
        /* Speaker */
        for (i = 0; i < cfg->speaker_outs; i++)
-               snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               snd_hda_set_pin_ctl(codec, cfg->speaker_pins[i], PIN_OUT);
 
        /* SPDIF is enabled on presence detect for CS421x */
        if (spec->hp_detect || spec->spdif_detect)
@@ -1063,14 +1058,9 @@ static void init_input(struct hda_codec *codec)
                        continue;
                /* set appropriate pin control and mute first */
                ctl = PIN_IN;
-               if (cfg->inputs[i].type == AUTO_PIN_MIC) {
-                       unsigned int caps = snd_hda_query_pin_caps(codec, pin);
-                       caps >>= AC_PINCAP_VREF_SHIFT;
-                       if (caps & AC_PINCAP_VREF_80)
-                               ctl = PIN_VREF80;
-               }
-               snd_hda_codec_write(codec, pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
+               if (cfg->inputs[i].type == AUTO_PIN_MIC)
+                       ctl |= snd_hda_get_default_vref(codec, pin);
+               snd_hda_set_pin_ctl(codec, pin, ctl);
                snd_hda_codec_write(codec, spec->adc_nid[i], 0,
                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                    AMP_IN_MUTE(spec->adc_idx[i]));
index b6767b4ced4478c5d1d7a0eb671d528284ef8e34..c8fdaaefe7029a403e81e03dcac96cee721ecca3 100644 (file)
@@ -29,6 +29,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #define NUM_PINS       11
 
 
index d906c5b74cf0e7b047a4e702c71ba8b6d0e5d5de..3acb5824ad39e95e354491c2336a445cd796745e 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
 
@@ -66,6 +67,7 @@ struct imux_info {
 };
 
 struct conexant_spec {
+       struct hda_gen_spec gen;
 
        const struct snd_kcontrol_new *mixers[5];
        int num_mixers;
@@ -141,6 +143,7 @@ struct conexant_spec {
        unsigned int hp_laptop:1;
        unsigned int asus:1;
        unsigned int pin_eapd_ctrls:1;
+       unsigned int fixup_stereo_dmic:1;
 
        unsigned int adc_switching:1;
 
@@ -1601,17 +1604,13 @@ static void cxt5051_update_speaker(struct hda_codec *codec)
        unsigned int pinctl;
        /* headphone pin */
        pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0;
-       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           pinctl);
+       snd_hda_set_pin_ctl(codec, 0x16, pinctl);
        /* speaker pin */
        pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
-       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           pinctl);
+       snd_hda_set_pin_ctl(codec, 0x1a, pinctl);
        /* on ideapad there is an additional speaker (subwoofer) to mute */
        if (spec->ideapad)
-               snd_hda_codec_write(codec, 0x1b, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   pinctl);
+               snd_hda_set_pin_ctl(codec, 0x1b, pinctl);
 }
 
 /* turn on/off EAPD (+ mute HP) as a master switch */
@@ -1996,8 +1995,7 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
 
        /* Port A (HP) */
        pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0;
-       snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                       pinctl);
+       snd_hda_set_pin_ctl(codec, 0x19, pinctl);
 
        /* Port D (HP/LO) */
        pinctl = spec->cur_eapd ? spec->port_d_mode : 0;
@@ -2010,13 +2008,11 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
                if (!hp_port_d_present(spec))
                        pinctl = 0;
        }
-       snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                       pinctl);
+       snd_hda_set_pin_ctl(codec, 0x1c, pinctl);
 
        /* CLASS_D AMP */
        pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
-       snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                       pinctl);
+       snd_hda_set_pin_ctl(codec, 0x1f, pinctl);
 }
 
 /* turn on/off EAPD (+ mute HP) as a master switch */
@@ -2047,8 +2043,7 @@ static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec)
        /* Even though port F is the DC input, the bias is controlled on port B.
         * we also leave that port as an active input (but unselected) in DC mode
         * just in case that is necessary to make the bias setting take effect. */
-       return snd_hda_codec_write_cache(codec, 0x1a, 0,
-               AC_VERB_SET_PIN_WIDGET_CONTROL,
+       return snd_hda_set_pin_ctl_cache(codec, 0x1a,
                cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index);
 }
 
@@ -2081,14 +2076,14 @@ static void cxt5066_olpc_select_mic(struct hda_codec *codec)
        }
 
        /* disable DC (port F) */
-       snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       snd_hda_set_pin_ctl(codec, 0x1e, 0);
 
        /* external mic, port B */
-       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+       snd_hda_set_pin_ctl(codec, 0x1a,
                spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);
 
        /* internal mic, port C */
-       snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+       snd_hda_set_pin_ctl(codec, 0x1b,
                spec->ext_mic_present ? 0 : PIN_VREF80);
 }
 
@@ -3357,9 +3352,7 @@ static void do_automute(struct hda_codec *codec, int num_pins,
        struct conexant_spec *spec = codec->spec;
        int i;
        for (i = 0; i < num_pins; i++)
-               snd_hda_codec_write(codec, pins[i], 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   on ? PIN_OUT : 0);
+               snd_hda_set_pin_ctl(codec, pins[i], on ? PIN_OUT : 0);
        if (spec->pin_eapd_ctrls)
                cx_auto_turn_eapd(codec, num_pins, pins, on);
 }
@@ -3976,8 +3969,7 @@ static void cx_auto_init_output(struct hda_codec *codec)
                if (snd_hda_query_pin_caps(codec, cfg->hp_pins[i]) &
                    AC_PINCAP_HP_DRV)
                        val |= AC_PINCTL_HP_EN;
-               snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+               snd_hda_set_pin_ctl(codec, cfg->hp_pins[i], val);
        }
        mute_outputs(codec, cfg->hp_outs, cfg->hp_pins);
        mute_outputs(codec, cfg->line_outs, cfg->line_out_pins);
@@ -4030,13 +4022,11 @@ static void cx_auto_init_input(struct hda_codec *codec)
        }
 
        for (i = 0; i < cfg->num_inputs; i++) {
-               unsigned int type;
+               hda_nid_t pin = cfg->inputs[i].pin;
+               unsigned int type = PIN_IN;
                if (cfg->inputs[i].type == AUTO_PIN_MIC)
-                       type = PIN_VREF80;
-               else
-                       type = PIN_IN;
-               snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, type);
+                       type |= snd_hda_get_default_vref(codec, pin);
+               snd_hda_set_pin_ctl(codec, pin, type);
        }
 
        if (spec->auto_mic) {
@@ -4063,11 +4053,9 @@ static void cx_auto_init_digital(struct hda_codec *codec)
        struct auto_pin_cfg *cfg = &spec->autocfg;
 
        if (spec->multiout.dig_out_nid)
-               snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               snd_hda_set_pin_ctl(codec, cfg->dig_out_pins[0], PIN_OUT);
        if (spec->dig_in_nid)
-               snd_hda_codec_write(codec, cfg->dig_in_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+               snd_hda_set_pin_ctl(codec, cfg->dig_in_pin, PIN_IN);
 }
 
 static int cx_auto_init(struct hda_codec *codec)
@@ -4084,9 +4072,9 @@ static int cx_auto_init(struct hda_codec *codec)
 
 static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
                              const char *dir, int cidx,
-                             hda_nid_t nid, int hda_dir, int amp_idx)
+                             hda_nid_t nid, int hda_dir, int amp_idx, int chs)
 {
-       static char name[32];
+       static char name[44];
        static struct snd_kcontrol_new knew[] = {
                HDA_CODEC_VOLUME(name, 0, 0, 0),
                HDA_CODEC_MUTE(name, 0, 0, 0),
@@ -4096,7 +4084,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
 
        for (i = 0; i < 2; i++) {
                struct snd_kcontrol *kctl;
-               knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx,
+               knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx,
                                                            hda_dir);
                knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
                knew[i].index = cidx;
@@ -4115,7 +4103,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
 }
 
 #define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir)                \
-       cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0)
+       cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3)
 
 #define cx_auto_add_pb_volume(codec, nid, str, idx)                    \
        cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
@@ -4185,6 +4173,36 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
        return 0;
 }
 
+/* Returns zero if this is a normal stereo channel, and non-zero if it should
+   be split in two independent channels.
+   dest_label must be at least 44 characters. */
+static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label,
+                                    char *dest_label, int nid)
+{
+       struct conexant_spec *spec = codec->spec;
+       int i;
+
+       if (!spec->fixup_stereo_dmic)
+               return 0;
+
+       for (i = 0; i < AUTO_CFG_MAX_INS; i++) {
+               int def_conf;
+               if (spec->autocfg.inputs[i].pin != nid)
+                       continue;
+
+               if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC)
+                       return 0;
+               def_conf = snd_hda_codec_get_pincfg(codec, nid);
+               if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT)
+                       return 0;
+
+               /* Finally found the inverted internal mic! */
+               snprintf(dest_label, 44, "Inverted %s", label);
+               return 1;
+       }
+       return 0;
+}
+
 static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
                                      const char *label, const char *pfx,
                                      int cidx)
@@ -4193,14 +4211,25 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
        int i;
 
        for (i = 0; i < spec->num_adc_nids; i++) {
+               char rightch_label[44];
                hda_nid_t adc_nid = spec->adc_nids[i];
                int idx = get_input_connection(codec, adc_nid, nid);
                if (idx < 0)
                        continue;
                if (codec->single_adc_amp)
                        idx = 0;
+
+               if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
+                       /* Make two independent kcontrols for left and right */
+                       int err = cx_auto_add_volume_idx(codec, label, pfx,
+                                             cidx, adc_nid, HDA_INPUT, idx, 1);
+                       if (err < 0)
+                               return err;
+                       return cx_auto_add_volume_idx(codec, rightch_label, pfx,
+                                                     cidx, adc_nid, HDA_INPUT, idx, 2);
+               }
                return cx_auto_add_volume_idx(codec, label, pfx,
-                                             cidx, adc_nid, HDA_INPUT, idx);
+                                             cidx, adc_nid, HDA_INPUT, idx, 3);
        }
        return 0;
 }
@@ -4213,9 +4242,19 @@ static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,
        int i, con;
 
        nid = spec->imux_info[idx].pin;
-       if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+       if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
+               char rightch_label[44];
+               if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
+                       int err = cx_auto_add_volume_idx(codec, label, " Boost",
+                                                        cidx, nid, HDA_INPUT, 0, 1);
+                       if (err < 0)
+                               return err;
+                       return cx_auto_add_volume_idx(codec, rightch_label, " Boost",
+                                                     cidx, nid, HDA_INPUT, 0, 2);
+               }
                return cx_auto_add_volume(codec, label, " Boost", cidx,
                                          nid, HDA_INPUT);
+       }
        con = __select_input_connection(codec, spec->imux_info[idx].adc, nid,
                                        &mux, false, 0);
        if (con < 0)
@@ -4370,37 +4409,21 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
 /*
  * pin fix-up
  */
-struct cxt_pincfg {
-       hda_nid_t nid;
-       u32 val;
-};
-
-static void apply_pincfg(struct hda_codec *codec, const struct cxt_pincfg *cfg)
-{
-       for (; cfg->nid; cfg++)
-               snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
-
-}
-
-static void apply_pin_fixup(struct hda_codec *codec,
-                           const struct snd_pci_quirk *quirk,
-                           const struct cxt_pincfg **table)
-{
-       quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
-       if (quirk) {
-               snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n",
-                           quirk->name);
-               apply_pincfg(codec, table[quirk->value]);
-       }
-}
-
 enum {
        CXT_PINCFG_LENOVO_X200,
        CXT_PINCFG_LENOVO_TP410,
+       CXT_FIXUP_STEREO_DMIC,
 };
 
+static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       struct conexant_spec *spec = codec->spec;
+       spec->fixup_stereo_dmic = 1;
+}
+
 /* ThinkPad X200 & co with cxt5051 */
-static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
+static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
        { 0x16, 0x042140ff }, /* HP (seq# overridden) */
        { 0x17, 0x21a11000 }, /* dock-mic */
        { 0x19, 0x2121103f }, /* dock-HP */
@@ -4409,16 +4432,26 @@ static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
 };
 
 /* ThinkPad 410/420/510/520, X201 & co with cxt5066 */
-static const struct cxt_pincfg cxt_pincfg_lenovo_tp410[] = {
+static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = {
        { 0x19, 0x042110ff }, /* HP (seq# overridden) */
        { 0x1a, 0x21a190f0 }, /* dock-mic */
        { 0x1c, 0x212140ff }, /* dock-HP */
        {}
 };
 
-static const struct cxt_pincfg *cxt_pincfg_tbl[] = {
-       [CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200,
-       [CXT_PINCFG_LENOVO_TP410] = cxt_pincfg_lenovo_tp410,
+static const struct hda_fixup cxt_fixups[] = {
+       [CXT_PINCFG_LENOVO_X200] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cxt_pincfg_lenovo_x200,
+       },
+       [CXT_PINCFG_LENOVO_TP410] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cxt_pincfg_lenovo_tp410,
+       },
+       [CXT_FIXUP_STEREO_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_stereo_dmic,
+       },
 };
 
 static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -4432,6 +4465,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
        {}
 };
 
@@ -4471,13 +4505,16 @@ static int patch_conexant_auto(struct hda_codec *codec)
        case 0x14f15051:
                add_cx5051_fake_mutes(codec);
                codec->pin_amp_workaround = 1;
-               apply_pin_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl);
+               snd_hda_pick_fixup(codec, NULL, cxt5051_fixups, cxt_fixups);
                break;
        default:
                codec->pin_amp_workaround = 1;
-               apply_pin_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl);
+               snd_hda_pick_fixup(codec, NULL, cxt5066_fixups, cxt_fixups);
+               break;
        }
 
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
        /* Show mute-led control only on HP laptops
         * This is a sort of white-list: on HP laptops, EAPD corresponds
         * only to the mute-LED without actualy amp function.  Meanwhile,
@@ -4556,6 +4593,12 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = {
          .patch = patch_conexant_auto },
        { .id = 0x14f150b9, .name = "CX20665",
          .patch = patch_conexant_auto },
+       { .id = 0x14f1510f, .name = "CX20751/2",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f15110, .name = "CX20751/2",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f15111, .name = "CX20753/4",
+         .patch = patch_conexant_auto },
        {} /* terminator */
 };
 
@@ -4576,6 +4619,9 @@ MODULE_ALIAS("snd-hda-codec-id:14f150ab");
 MODULE_ALIAS("snd-hda-codec-id:14f150ac");
 MODULE_ALIAS("snd-hda-codec-id:14f150b8");
 MODULE_ALIAS("snd-hda-codec-id:14f150b9");
+MODULE_ALIAS("snd-hda-codec-id:14f1510f");
+MODULE_ALIAS("snd-hda-codec-id:14f15110");
+MODULE_ALIAS("snd-hda-codec-id:14f15111");
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Conexant HD-audio codec");
index 83f345f3c961b05313a17e10d9c46d53ace138c7..ad319d4dc32f7e5d0d5265020a0f700c10bb08ab 100644 (file)
@@ -1592,10 +1592,10 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
        unsigned int dataDCC2, channel_id;
        int i;
        struct hdmi_spec *spec = codec->spec;
-       struct hda_spdif_out *spdif =
-               snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
+       struct hda_spdif_out *spdif;
 
        mutex_lock(&codec->spdif_mutex);
+       spdif = snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
 
        chs = substream->runtime->channels;
 
index 708d47c294eed0f971914f9269cdc6761c0a281c..ff71dcef08ef1c0d3b2790121fbfda1ebd989758 100644 (file)
@@ -32,6 +32,7 @@
 #include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
 
@@ -66,8 +67,6 @@ struct alc_customize_define {
        unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
 };
 
-struct alc_fixup;
-
 struct alc_multi_io {
        hda_nid_t pin;          /* multi-io widget pin NID */
        hda_nid_t dac;          /* DAC to be connected */
@@ -82,19 +81,33 @@ enum {
 
 #define MAX_VOL_NIDS   0x40
 
+/* make compatible with old code */
+#define alc_apply_pincfgs      snd_hda_apply_pincfgs
+#define alc_apply_fixup                snd_hda_apply_fixup
+#define alc_pick_fixup         snd_hda_pick_fixup
+#define alc_fixup              hda_fixup
+#define alc_pincfg             hda_pintbl
+#define alc_model_fixup                hda_model_fixup
+
+#define ALC_FIXUP_PINS HDA_FIXUP_PINS
+#define ALC_FIXUP_VERBS        HDA_FIXUP_VERBS
+#define ALC_FIXUP_FUNC HDA_FIXUP_FUNC
+
+#define ALC_FIXUP_ACT_PRE_PROBE        HDA_FIXUP_ACT_PRE_PROBE
+#define ALC_FIXUP_ACT_PROBE    HDA_FIXUP_ACT_PROBE
+#define ALC_FIXUP_ACT_INIT     HDA_FIXUP_ACT_INIT
+#define ALC_FIXUP_ACT_BUILD    HDA_FIXUP_ACT_BUILD
+
+
 struct alc_spec {
+       struct hda_gen_spec gen;
+
        /* codec parameterization */
        const struct snd_kcontrol_new *mixers[5];       /* mixer arrays */
        unsigned int num_mixers;
        const struct snd_kcontrol_new *cap_mixer;       /* capture mixer */
        unsigned int beep_amp;  /* beep amp value, set via set_beep_amp() */
 
-       const struct hda_verb *init_verbs[10];  /* initialization verbs
-                                                * don't forget NULL
-                                                * termination!
-                                                */
-       unsigned int num_init_verbs;
-
        char stream_name_analog[32];    /* analog PCM stream */
        const struct hda_pcm_stream *stream_analog_playback;
        const struct hda_pcm_stream *stream_analog_capture;
@@ -210,11 +223,6 @@ struct alc_spec {
        unsigned int pll_coef_idx, pll_coef_bit;
        unsigned int coef0;
 
-       /* fix-up list */
-       int fixup_id;
-       const struct alc_fixup *fixup_list;
-       const char *fixup_name;
-
        /* multi-io */
        int multi_ios;
        struct alc_multi_io multi_io[4];
@@ -319,13 +327,16 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
 
        /* for shared I/O, change the pin-control accordingly */
        if (spec->shared_mic_hp) {
+               unsigned int val;
+               hda_nid_t pin = spec->autocfg.inputs[1].pin;
                /* NOTE: this assumes that there are only two inputs, the
                 * first is the real internal mic and the second is HP jack.
                 */
-               snd_hda_codec_write(codec, spec->autocfg.inputs[1].pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   spec->cur_mux[adc_idx] ?
-                                   PIN_VREF80 : PIN_HP);
+               if (spec->cur_mux[adc_idx])
+                       val = snd_hda_get_default_vref(codec, pin) | PIN_IN;
+               else
+                       val = PIN_HP;
+               snd_hda_set_pin_ctl(codec, pin, val);
                spec->automute_speaker = !spec->cur_mux[adc_idx];
                call_update_outputs(codec);
        }
@@ -338,7 +349,7 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
        nid = get_capsrc(spec, adc_idx);
 
        /* no selection? */
-       num_conns = snd_hda_get_conn_list(codec, nid, NULL);
+       num_conns = snd_hda_get_num_conns(codec, nid);
        if (num_conns <= 1)
                return 1;
 
@@ -376,25 +387,9 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
                              int auto_pin_type)
 {
        unsigned int val = PIN_IN;
-
-       if (auto_pin_type == AUTO_PIN_MIC) {
-               unsigned int pincap;
-               unsigned int oldval;
-               oldval = snd_hda_codec_read(codec, nid, 0,
-                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-               pincap = snd_hda_query_pin_caps(codec, nid);
-               pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
-               /* if the default pin setup is vref50, we give it priority */
-               if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
-                       val = PIN_VREF80;
-               else if (pincap & AC_PINCAP_VREF_50)
-                       val = PIN_VREF50;
-               else if (pincap & AC_PINCAP_VREF_100)
-                       val = PIN_VREF100;
-               else if (pincap & AC_PINCAP_VREF_GRD)
-                       val = PIN_VREFGRD;
-       }
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+       if (auto_pin_type == AUTO_PIN_MIC)
+               val |= snd_hda_get_default_vref(codec, nid);
+       snd_hda_set_pin_ctl(codec, nid, val);
 }
 
 /*
@@ -409,13 +404,6 @@ static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
        spec->mixers[spec->num_mixers++] = mix;
 }
 
-static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
-{
-       if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
-               return;
-       spec->init_verbs[spec->num_init_verbs++] = verb;
-}
-
 /*
  * GPIO setup tables, used in initialization
  */
@@ -517,9 +505,7 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
                        } else
                                val = 0;
                        val |= pin_bits;
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           val);
+                       snd_hda_set_pin_ctl(codec, nid, val);
                        break;
                case ALC_AUTOMUTE_AMP:
                        snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
@@ -1200,6 +1186,16 @@ static void alc_auto_check_switches(struct hda_codec *codec)
  */
 #define ALC_FIXUP_SKU_IGNORE (2)
 
+static void alc_fixup_sku_ignore(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->cdefine.fixup = 1;
+               spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
+       }
+}
+
 static int alc_auto_parse_customize_define(struct hda_codec *codec)
 {
        unsigned int ass, tmp, i;
@@ -1402,178 +1398,6 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
        }
 }
 
-/*
- * Fix-up pin default configurations and add default verbs
- */
-
-struct alc_pincfg {
-       hda_nid_t nid;
-       u32 val;
-};
-
-struct alc_model_fixup {
-       const int id;
-       const char *name;
-};
-
-struct alc_fixup {
-       int type;
-       bool chained;
-       int chain_id;
-       union {
-               unsigned int sku;
-               const struct alc_pincfg *pins;
-               const struct hda_verb *verbs;
-               void (*func)(struct hda_codec *codec,
-                            const struct alc_fixup *fix,
-                            int action);
-       } v;
-};
-
-enum {
-       ALC_FIXUP_INVALID,
-       ALC_FIXUP_SKU,
-       ALC_FIXUP_PINS,
-       ALC_FIXUP_VERBS,
-       ALC_FIXUP_FUNC,
-};
-
-enum {
-       ALC_FIXUP_ACT_PRE_PROBE,
-       ALC_FIXUP_ACT_PROBE,
-       ALC_FIXUP_ACT_INIT,
-       ALC_FIXUP_ACT_BUILD,
-};
-
-static void alc_apply_pincfgs(struct hda_codec *codec,
-                             const struct alc_pincfg *cfg)
-{
-       for (; cfg->nid; cfg++)
-               snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
-}
-
-static void alc_apply_fixup(struct hda_codec *codec, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       int id = spec->fixup_id;
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-       const char *modelname = spec->fixup_name;
-#endif
-       int depth = 0;
-
-       if (!spec->fixup_list)
-               return;
-
-       while (id >= 0) {
-               const struct alc_fixup *fix = spec->fixup_list + id;
-               const struct alc_pincfg *cfg;
-
-               switch (fix->type) {
-               case ALC_FIXUP_SKU:
-                       if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
-                               break;
-                       snd_printdd(KERN_INFO "hda_codec: %s: "
-                                   "Apply sku override for %s\n",
-                                   codec->chip_name, modelname);
-                       spec->cdefine.sku_cfg = fix->v.sku;
-                       spec->cdefine.fixup = 1;
-                       break;
-               case ALC_FIXUP_PINS:
-                       cfg = fix->v.pins;
-                       if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
-                               break;
-                       snd_printdd(KERN_INFO "hda_codec: %s: "
-                                   "Apply pincfg for %s\n",
-                                   codec->chip_name, modelname);
-                       alc_apply_pincfgs(codec, cfg);
-                       break;
-               case ALC_FIXUP_VERBS:
-                       if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
-                               break;
-                       snd_printdd(KERN_INFO "hda_codec: %s: "
-                                   "Apply fix-verbs for %s\n",
-                                   codec->chip_name, modelname);
-                       add_verb(codec->spec, fix->v.verbs);
-                       break;
-               case ALC_FIXUP_FUNC:
-                       if (!fix->v.func)
-                               break;
-                       snd_printdd(KERN_INFO "hda_codec: %s: "
-                                   "Apply fix-func for %s\n",
-                                   codec->chip_name, modelname);
-                       fix->v.func(codec, fix, action);
-                       break;
-               default:
-                       snd_printk(KERN_ERR "hda_codec: %s: "
-                                  "Invalid fixup type %d\n",
-                                  codec->chip_name, fix->type);
-                       break;
-               }
-               if (!fix->chained)
-                       break;
-               if (++depth > 10)
-                       break;
-               id = fix->chain_id;
-       }
-}
-
-static void alc_pick_fixup(struct hda_codec *codec,
-                          const struct alc_model_fixup *models,
-                          const struct snd_pci_quirk *quirk,
-                          const struct alc_fixup *fixlist)
-{
-       struct alc_spec *spec = codec->spec;
-       const struct snd_pci_quirk *q;
-       int id = -1;
-       const char *name = NULL;
-
-       /* when model=nofixup is given, don't pick up any fixups */
-       if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
-               spec->fixup_list = NULL;
-               spec->fixup_id = -1;
-               return;
-       }
-
-       if (codec->modelname && models) {
-               while (models->name) {
-                       if (!strcmp(codec->modelname, models->name)) {
-                               id = models->id;
-                               name = models->name;
-                               break;
-                       }
-                       models++;
-               }
-       }
-       if (id < 0) {
-               q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
-               if (q) {
-                       id = q->value;
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-                       name = q->name;
-#endif
-               }
-       }
-       if (id < 0) {
-               for (q = quirk; q->subvendor; q++) {
-                       unsigned int vendorid =
-                               q->subdevice | (q->subvendor << 16);
-                       if (vendorid == codec->subsystem_id) {
-                               id = q->value;
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-                               name = q->name;
-#endif
-                               break;
-                       }
-               }
-       }
-
-       spec->fixup_id = id;
-       if (id >= 0) {
-               spec->fixup_list = fixlist;
-               spec->fixup_name = name;
-       }
-}
-
 /*
  * COEF access helper functions
  */
@@ -1621,8 +1445,7 @@ static void alc_auto_init_digital(struct hda_codec *codec)
                pin = spec->autocfg.dig_out_pins[i];
                if (!pin)
                        continue;
-               snd_hda_codec_write(codec, pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               snd_hda_set_pin_ctl(codec, pin, PIN_OUT);
                if (!i)
                        dac = spec->multiout.dig_out_nid;
                else
@@ -1635,9 +1458,7 @@ static void alc_auto_init_digital(struct hda_codec *codec)
        }
        pin = spec->autocfg.dig_in_pin;
        if (pin)
-               snd_hda_codec_write(codec, pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   PIN_IN);
+               snd_hda_set_pin_ctl(codec, pin, PIN_IN);
 }
 
 /* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
@@ -2068,7 +1889,6 @@ static void alc_auto_init_std(struct hda_codec *codec);
 static int alc_init(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int i;
 
        if (spec->init_hook)
                spec->init_hook(codec);
@@ -2076,8 +1896,6 @@ static int alc_init(struct hda_codec *codec)
        alc_fix_pll(codec);
        alc_auto_init_amp(codec, spec->init_amp);
 
-       for (i = 0; i < spec->num_init_verbs; i++)
-               snd_hda_sequence_write(codec, spec->init_verbs[i]);
        alc_init_special_input_src(codec);
        alc_auto_init_std(codec);
 
@@ -2725,7 +2543,6 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec)
        nid = codec->start_nid;
        for (i = 0; i < codec->num_nodes; i++, nid++) {
                hda_nid_t src;
-               const hda_nid_t *list;
                unsigned int caps = get_wcaps(codec, nid);
                int type = get_wcaps_type(caps);
 
@@ -2743,13 +2560,14 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec)
                                cap_nids[nums] = src;
                                break;
                        }
-                       n = snd_hda_get_conn_list(codec, src, &list);
+                       n = snd_hda_get_num_conns(codec, src);
                        if (n > 1) {
                                cap_nids[nums] = src;
                                break;
                        } else if (n != 1)
                                break;
-                       src = *list;
+                       if (snd_hda_get_connections(codec, src, &src, 1) != 1)
+                               break;
                }
                if (++nums >= max_nums)
                        break;
@@ -2856,8 +2674,7 @@ static int alc_auto_create_shared_input(struct hda_codec *codec)
 static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
                               unsigned int pin_type)
 {
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           pin_type);
+       snd_hda_set_pin_ctl(codec, nid, pin_type);
        /* unmute pin */
        if (nid_has_mute(codec, nid, HDA_OUTPUT))
                snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
@@ -2891,7 +2708,7 @@ static void alc_auto_init_analog_input(struct hda_codec *codec)
 
        /* mute all loopback inputs */
        if (spec->mixer_nid) {
-               int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL);
+               int nums = snd_hda_get_num_conns(codec, spec->mixer_nid);
                for (i = 0; i < nums; i++)
                        snd_hda_codec_write(codec, spec->mixer_nid, 0,
                                            AC_VERB_SET_AMP_GAIN_MUTE,
@@ -3521,7 +3338,7 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
        if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) {
                type = ALC_CTL_WIDGET_MUTE;
                val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
-       } else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
+       } else if (snd_hda_get_num_conns(codec, nid) == 1) {
                type = ALC_CTL_WIDGET_MUTE;
                val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
        } else {
@@ -3998,9 +3815,7 @@ static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
                        snd_hda_codec_read(codec, nid, 0,
                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
        if (output) {
-               snd_hda_codec_update_cache(codec, nid, 0,
-                                          AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                          PIN_OUT);
+               snd_hda_set_pin_ctl_cache(codec, nid, PIN_OUT);
                if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
                        snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
                                                 HDA_AMP_MUTE, 0);
@@ -4009,9 +3824,8 @@ static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
                if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
                        snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
                                                 HDA_AMP_MUTE, HDA_AMP_MUTE);
-               snd_hda_codec_update_cache(codec, nid, 0,
-                                          AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                          spec->multi_io[idx].ctl_in);
+               snd_hda_set_pin_ctl_cache(codec, nid,
+                                         spec->multi_io[idx].ctl_in);
        }
        return 0;
 }
@@ -4084,7 +3898,7 @@ static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
        nums = 0;
        for (n = 0; n < spec->num_adc_nids; n++) {
                hda_nid_t cap = spec->private_capsrc_nids[n];
-               int num_conns = snd_hda_get_conn_list(codec, cap, NULL);
+               int num_conns = snd_hda_get_num_conns(codec, cap);
                for (i = 0; i < imux->num_items; i++) {
                        hda_nid_t pin = spec->imux_pins[i];
                        if (pin) {
@@ -4213,7 +4027,7 @@ static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
        if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
                snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
                                         HDA_AMP_MUTE, 0);
-       } else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) {
+       } else if (snd_hda_get_num_conns(codec, cap) > 1) {
                snd_hda_codec_write_cache(codec, cap, 0,
                                          AC_VERB_SET_CONNECT_SEL, idx);
        }
@@ -4427,6 +4241,25 @@ static int alc_parse_auto_config(struct hda_codec *codec,
        return 1;
 }
 
+/* common preparation job for alc_spec */
+static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
+{
+       struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       int err;
+
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+       spec->mixer_nid = mixer_nid;
+
+       err = alc_codec_rename_from_preset(codec);
+       if (err < 0) {
+               kfree(spec);
+               return err;
+       }
+       return 0;
+}
+
 static int alc880_parse_auto_config(struct hda_codec *codec)
 {
        static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
@@ -4808,13 +4641,11 @@ static int patch_alc880(struct hda_codec *codec)
        struct alc_spec *spec;
        int err;
 
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
+       err = alc_alloc_spec(codec, 0x0b);
+       if (err < 0)
+               return err;
 
-       spec->mixer_nid = 0x0b;
+       spec = codec->spec;
        spec->need_dac_fix = 1;
 
        alc_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
@@ -4890,7 +4721,7 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
                spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
                snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT);
                spec->unsol_event = alc_sku_unsol_event;
-               add_verb(codec->spec, alc_gpio1_init_verbs);
+               snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs);
        }
 }
 
@@ -5001,13 +4832,11 @@ static int patch_alc260(struct hda_codec *codec)
        struct alc_spec *spec;
        int err;
 
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
+       err = alc_alloc_spec(codec, 0x07);
+       if (err < 0)
+               return err;
 
-       spec->mixer_nid = 0x07;
+       spec = codec->spec;
 
        alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -5171,8 +5000,7 @@ static void alc889_fixup_mbp_vref(struct hda_codec *codec,
                val = snd_hda_codec_read(codec, nids[i], 0,
                                         AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
                val |= AC_PINCTL_VREF_80;
-               snd_hda_codec_write(codec, nids[i], 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+               snd_hda_set_pin_ctl(codec, nids[i], val);
                spec->keep_vref_in_automute = 1;
                break;
        }
@@ -5193,8 +5021,7 @@ static void alc889_fixup_imac91_vref(struct hda_codec *codec,
                val = snd_hda_codec_read(codec, nids[i], 0,
                                         AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
                val |= AC_PINCTL_VREF_50;
-               snd_hda_codec_write(codec, nids[i], 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+               snd_hda_set_pin_ctl(codec, nids[i], val);
        }
        spec->keep_vref_in_automute = 1;
 }
@@ -5225,8 +5052,8 @@ static const struct alc_fixup alc882_fixups[] = {
                }
        },
        [ALC882_FIXUP_ACER_ASPIRE_7736] = {
-               .type = ALC_FIXUP_SKU,
-               .v.sku = ALC_FIXUP_SKU_IGNORE,
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc_fixup_sku_ignore,
        },
        [ALC882_FIXUP_ASUS_W90V] = {
                .type = ALC_FIXUP_PINS,
@@ -5476,13 +5303,11 @@ static int patch_alc882(struct hda_codec *codec)
        struct alc_spec *spec;
        int err;
 
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
+       err = alc_alloc_spec(codec, 0x0b);
+       if (err < 0)
+               return err;
 
-       spec->mixer_nid = 0x0b;
+       spec = codec->spec;
 
        switch (codec->vendor_id) {
        case 0x10ec0882:
@@ -5494,10 +5319,6 @@ static int patch_alc882(struct hda_codec *codec)
                break;
        }
 
-       err = alc_codec_rename_from_preset(codec);
-       if (err < 0)
-               goto error;
-
        alc_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
                       alc882_fixups);
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -5621,13 +5442,11 @@ static int patch_alc262(struct hda_codec *codec)
        struct alc_spec *spec;
        int err;
 
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
+       err = alc_alloc_spec(codec, 0x0b);
+       if (err < 0)
+               return err;
 
-       spec->mixer_nid = 0x0b;
+       spec = codec->spec;
 
 #if 0
        /* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
@@ -5710,7 +5529,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
        if (err > 0) {
                if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
                        add_mixer(spec, alc268_beep_mixer);
-                       add_verb(spec, alc268_beep_init_verbs);
+                       snd_hda_gen_add_verbs(&spec->gen, alc268_beep_init_verbs);
                }
        }
        return err;
@@ -5723,13 +5542,12 @@ static int patch_alc268(struct hda_codec *codec)
        struct alc_spec *spec;
        int i, has_beep, err;
 
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
        /* ALC268 has no aa-loopback mixer */
+       err = alc_alloc_spec(codec, 0);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
 
        /* automatic parse from the BIOS config */
        err = alc268_parse_auto_config(codec);
@@ -5946,9 +5764,7 @@ static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled)
 {
        struct hda_codec *codec = private_data;
        unsigned int pinval = enabled ? 0x20 : 0x24;
-       snd_hda_codec_update_cache(codec, 0x19, 0,
-                                  AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                  pinval);
+       snd_hda_set_pin_ctl_cache(codec, 0x19, pinval);
 }
 
 static void alc269_fixup_mic2_mute(struct hda_codec *codec,
@@ -6015,8 +5831,8 @@ static const struct alc_fixup alc269_fixups[] = {
                }
        },
        [ALC269_FIXUP_SKU_IGNORE] = {
-               .type = ALC_FIXUP_SKU,
-               .v.sku = ALC_FIXUP_SKU_IGNORE,
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc_fixup_sku_ignore,
        },
        [ALC269_FIXUP_ASUS_G73JW] = {
                .type = ALC_FIXUP_PINS,
@@ -6242,19 +6058,13 @@ static void alc269_fill_coef(struct hda_codec *codec)
 static int patch_alc269(struct hda_codec *codec)
 {
        struct alc_spec *spec;
-       int err = 0;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
-       spec->mixer_nid = 0x0b;
+       int err;
 
-       err = alc_codec_rename_from_preset(codec);
+       err = alc_alloc_spec(codec, 0x0b);
        if (err < 0)
-               goto error;
+               return err;
+
+       spec = codec->spec;
 
        if (codec->vendor_id == 0x10ec0269) {
                spec->codec_variant = ALC269_TYPE_ALC269VA;
@@ -6346,8 +6156,7 @@ static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
        if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
                val |= AC_PINCTL_IN_EN;
        val |= AC_PINCTL_VREF_50;
-       snd_hda_codec_write(codec, 0x0f, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+       snd_hda_set_pin_ctl(codec, 0x0f, val);
        spec->keep_vref_in_automute = 1;
 }
 
@@ -6401,13 +6210,11 @@ static int patch_alc861(struct hda_codec *codec)
        struct alc_spec *spec;
        int err;
 
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
+       err = alc_alloc_spec(codec, 0x15);
+       if (err < 0)
+               return err;
 
-       spec->mixer_nid = 0x15;
+       spec = codec->spec;
 
        alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -6504,13 +6311,11 @@ static int patch_alc861vd(struct hda_codec *codec)
        struct alc_spec *spec;
        int err;
 
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
+       err = alc_alloc_spec(codec, 0x0b);
+       if (err < 0)
+               return err;
 
-       spec->mixer_nid = 0x0b;
+       spec = codec->spec;
 
        alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -6522,7 +6327,7 @@ static int patch_alc861vd(struct hda_codec *codec)
 
        if (codec->vendor_id == 0x10ec0660) {
                /* always turn on EAPD */
-               add_verb(spec, alc660vd_eapd_verbs);
+               snd_hda_gen_add_verbs(&spec->gen, alc660vd_eapd_verbs);
        }
 
        if (!spec->no_analog) {
@@ -6635,8 +6440,8 @@ static const struct alc_fixup alc662_fixups[] = {
                }
        },
        [ALC662_FIXUP_SKU_IGNORE] = {
-               .type = ALC_FIXUP_SKU,
-               .v.sku = ALC_FIXUP_SKU_IGNORE,
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc_fixup_sku_ignore,
        },
        [ALC662_FIXUP_HP_RP5800] = {
                .type = ALC_FIXUP_PINS,
@@ -6849,25 +6654,19 @@ static const struct alc_model_fixup alc662_fixup_models[] = {
 static int patch_alc662(struct hda_codec *codec)
 {
        struct alc_spec *spec;
-       int err = 0;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
+       int err;
 
-       codec->spec = spec;
+       err = alc_alloc_spec(codec, 0x0b);
+       if (err < 0)
+               return err;
 
-       spec->mixer_nid = 0x0b;
+       spec = codec->spec;
 
        /* handle multiple HPs as is */
        spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
 
        alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
-       err = alc_codec_rename_from_preset(codec);
-       if (err < 0)
-               goto error;
-
        if ((alc_get_coef0(codec) & (1 << 14)) &&
            codec->bus->pci->subsystem_vendor == 0x1025 &&
            spec->cdefine.platform_type == 1) {
@@ -6930,16 +6729,12 @@ static int alc680_parse_auto_config(struct hda_codec *codec)
  */
 static int patch_alc680(struct hda_codec *codec)
 {
-       struct alc_spec *spec;
        int err;
 
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
        /* ALC680 has no aa-loopback mixer */
+       err = alc_alloc_spec(codec, 0);
+       if (err < 0)
+               return err;
 
        /* automatic parse from the BIOS config */
        err = alc680_parse_auto_config(codec);
index 2cb1e08f962a5edf08fd153f2d2366e48941201d..7db8228f1b882c013f4105e535af8ceaae3c1fbd 100644 (file)
@@ -36,6 +36,7 @@
 #include <sound/tlv.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
 
@@ -221,6 +222,7 @@ struct sigmatel_spec {
        unsigned char aloopback_shift;
 
        /* power management */
+       unsigned int power_map_bits;
        unsigned int num_pwrs;
        const hda_nid_t *pwr_nids;
        const hda_nid_t *dac_list;
@@ -314,6 +316,9 @@ struct sigmatel_spec {
        struct hda_vmaster_mute_hook vmaster_mute;
 };
 
+#define AC_VERB_IDT_SET_POWER_MAP      0x7ec
+#define AC_VERB_IDT_GET_POWER_MAP      0xfec
+
 static const hda_nid_t stac9200_adc_nids[1] = {
         0x03,
 };
@@ -681,8 +686,7 @@ static int stac_vrefout_set(struct hda_codec *codec,
        pinctl &= ~AC_PINCTL_VREFEN;
        pinctl |= (new_vref & AC_PINCTL_VREFEN);
 
-       error = snd_hda_codec_write_cache(codec, nid, 0,
-                                       AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
+       error = snd_hda_set_pin_ctl_cache(codec, nid, pinctl);
        if (error < 0)
                return error;
 
@@ -706,8 +710,7 @@ static unsigned int stac92xx_vref_set(struct hda_codec *codec,
        else
                pincfg |= AC_PINCTL_IN_EN;
 
-       error = snd_hda_codec_write_cache(codec, nid, 0,
-                                       AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg);
+       error = snd_hda_set_pin_ctl_cache(codec, nid, pincfg);
        if (error < 0)
                return error;
        else
@@ -2505,27 +2508,10 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
        return 0;
 }
 
-static unsigned int stac92xx_get_default_vref(struct hda_codec *codec,
-                                       hda_nid_t nid)
-{
-       unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
-       pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
-       if (pincap & AC_PINCAP_VREF_100)
-               return AC_PINCTL_VREF_100;
-       if (pincap & AC_PINCAP_VREF_80)
-               return AC_PINCTL_VREF_80;
-       if (pincap & AC_PINCAP_VREF_50)
-               return AC_PINCTL_VREF_50;
-       if (pincap & AC_PINCAP_VREF_GRD)
-               return AC_PINCTL_VREF_GRD;
-       return 0;
-}
-
 static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
 
 {
-       snd_hda_codec_write_cache(codec, nid, 0,
-                                 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+       snd_hda_set_pin_ctl_cache(codec, nid, pin_type);
 }
 
 #define stac92xx_hp_switch_info                snd_ctl_boolean_mono_info
@@ -2594,7 +2580,7 @@ static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
        hda_nid_t nid = kcontrol->private_value;
        unsigned int vref = stac92xx_vref_get(codec, nid);
 
-       if (vref == stac92xx_get_default_vref(codec, nid))
+       if (vref == snd_hda_get_default_vref(codec, nid))
                ucontrol->value.enumerated.item[0] = 0;
        else if (vref == AC_PINCTL_VREF_GRD)
                ucontrol->value.enumerated.item[0] = 1;
@@ -2613,7 +2599,7 @@ static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
        hda_nid_t nid = kcontrol->private_value;
 
        if (ucontrol->value.enumerated.item[0] == 0)
-               new_vref = stac92xx_get_default_vref(codec, nid);
+               new_vref = snd_hda_get_default_vref(codec, nid);
        else if (ucontrol->value.enumerated.item[0] == 1)
                new_vref = AC_PINCTL_VREF_GRD;
        else if (ucontrol->value.enumerated.item[0] == 2)
@@ -2679,7 +2665,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
        else {
                unsigned int pinctl = AC_PINCTL_IN_EN;
                if (io_idx) /* set VREF for mic */
-                       pinctl |= stac92xx_get_default_vref(codec, nid);
+                       pinctl |= snd_hda_get_default_vref(codec, nid);
                stac92xx_auto_set_pinctl(codec, nid, pinctl);
        }
 
@@ -2847,7 +2833,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
        char name[22];
 
        if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
-               if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
+               if (snd_hda_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
                        && nid == spec->line_switch)
                        control = STAC_CTL_WIDGET_IO_SWITCH;
                else if (snd_hda_query_pin_caps(codec, nid)
@@ -4250,13 +4236,6 @@ static void stac_store_hints(struct hda_codec *codec)
        val = snd_hda_get_bool_hint(codec, "eapd_switch");
        if (val >= 0)
                spec->eapd_switch = val;
-       get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity);
-       if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
-               spec->gpio_mask |= spec->gpio_led;
-               spec->gpio_dir |= spec->gpio_led;
-               if (spec->gpio_led_polarity)
-                       spec->gpio_data |= spec->gpio_led;
-       }
 }
 
 static void stac_issue_unsol_events(struct hda_codec *codec, int num_pins,
@@ -4354,7 +4333,7 @@ static int stac92xx_init(struct hda_codec *codec)
                unsigned int pinctl, conf;
                if (type == AUTO_PIN_MIC) {
                        /* for mic pins, force to initialize */
-                       pinctl = stac92xx_get_default_vref(codec, nid);
+                       pinctl = snd_hda_get_default_vref(codec, nid);
                        pinctl |= AC_PINCTL_IN_EN;
                        stac92xx_auto_set_pinctl(codec, nid, pinctl);
                } else {
@@ -4390,10 +4369,18 @@ static int stac92xx_init(struct hda_codec *codec)
                hda_nid_t nid = spec->pwr_nids[i];
                int pinctl, def_conf;
 
+               def_conf = snd_hda_codec_get_pincfg(codec, nid);
+               def_conf = get_defcfg_connect(def_conf);
+               if (def_conf == AC_JACK_PORT_NONE) {
+                       /* power off unused ports */
+                       stac_toggle_power_map(codec, nid, 0);
+                       continue;
+               }
                /* power on when no jack detection is available */
                /* or when the VREF is used for controlling LED */
                if (!spec->hp_detect ||
-                   spec->vref_mute_led_nid == nid) {
+                   spec->vref_mute_led_nid == nid ||
+                   !is_jack_detectable(codec, nid)) {
                        stac_toggle_power_map(codec, nid, 1);
                        continue;
                }
@@ -4411,15 +4398,6 @@ static int stac92xx_init(struct hda_codec *codec)
                        stac_toggle_power_map(codec, nid, 1);
                        continue;
                }
-               def_conf = snd_hda_codec_get_pincfg(codec, nid);
-               def_conf = get_defcfg_connect(def_conf);
-               /* skip any ports that don't have jacks since presence
-                * detection is useless */
-               if (def_conf != AC_JACK_PORT_NONE &&
-                   !is_jack_detectable(codec, nid)) {
-                       stac_toggle_power_map(codec, nid, 1);
-                       continue;
-               }
                if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) {
                        stac_issue_unsol_event(codec, nid);
                        continue;
@@ -4432,6 +4410,12 @@ static int stac92xx_init(struct hda_codec *codec)
 
        /* sync mute LED */
        snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
+
+       /* sync the power-map */
+       if (spec->num_pwrs)
+               snd_hda_codec_write(codec, codec->afg, 0,
+                                   AC_VERB_IDT_SET_POWER_MAP,
+                                   spec->power_map_bits);
        if (spec->dac_list)
                stac92xx_power_down(codec);
        return 0;
@@ -4460,8 +4444,7 @@ static void stac92xx_shutup_pins(struct hda_codec *codec)
                struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
                def_conf = snd_hda_codec_get_pincfg(codec, pin->nid);
                if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
-                       snd_hda_codec_write(codec, pin->nid, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+                       snd_hda_set_pin_ctl(codec, pin->nid, 0);
        }
 }
 
@@ -4517,9 +4500,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
        
        pin_ctl |= flag;
        if (old_ctl != pin_ctl)
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                         pin_ctl);
+               snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl);
 }
 
 static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
@@ -4528,9 +4509,7 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
        unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
                        0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
        if (pin_ctl & flag)
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                         pin_ctl & ~flag);
+               snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl & ~flag);
 }
 
 static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
@@ -4682,14 +4661,18 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
 
        idx = 1 << idx;
 
-       val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff;
+       val = spec->power_map_bits;
        if (enable)
                val &= ~idx;
        else
                val |= idx;
 
        /* power down unused output ports */
-       snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
+       if (val != spec->power_map_bits) {
+               spec->power_map_bits = val;
+               snd_hda_codec_write(codec, codec->afg, 0,
+                                   AC_VERB_IDT_SET_POWER_MAP, val);
+       }
 }
 
 static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
@@ -4866,6 +4849,11 @@ static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity)
        struct sigmatel_spec *spec = codec->spec;
        const struct dmi_device *dev = NULL;
 
+       if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
+               get_int_hint(codec, "gpio_led_polarity",
+                            &spec->gpio_led_polarity);
+               return 1;
+       }
        if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) {
                while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING,
                                                                NULL, dev))) {
@@ -4952,7 +4940,8 @@ static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
 {
        if (nid == codec->afg)
                snd_iprintf(buffer, "Power-Map: 0x%02x\n", 
-                           snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0));
+                           snd_hda_codec_read(codec, nid, 0,
+                                              AC_VERB_IDT_GET_POWER_MAP, 0));
 }
 
 static void analog_loop_proc_hook(struct snd_info_buffer *buffer,
@@ -5009,20 +4998,6 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
        return 0;
 }
 
-static int stac92xx_pre_resume(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       /* sync mute LED */
-       if (spec->vref_mute_led_nid)
-               stac_vrefout_set(codec, spec->vref_mute_led_nid,
-                                spec->vref_led);
-       else if (spec->gpio_led)
-               stac_gpio_set(codec, spec->gpio_mask,
-                             spec->gpio_dir, spec->gpio_data);
-       return 0;
-}
-
 static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
                                unsigned int power_state)
 {
@@ -5046,7 +5021,6 @@ static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
 #else
 #define stac92xx_suspend       NULL
 #define stac92xx_resume                NULL
-#define stac92xx_pre_resume    NULL
 #define stac92xx_set_power_state NULL
 #endif /* CONFIG_PM */
 
@@ -5592,9 +5566,6 @@ again:
                        codec->patch_ops.set_power_state =
                                        stac92xx_set_power_state;
                }
-#ifdef CONFIG_PM
-               codec->patch_ops.pre_resume = stac92xx_pre_resume;
-#endif
        }
 
        err = stac92xx_parse_auto_config(codec);
@@ -5901,9 +5872,6 @@ again:
                        codec->patch_ops.set_power_state =
                                        stac92xx_set_power_state;
                }
-#ifdef CONFIG_PM
-               codec->patch_ops.pre_resume = stac92xx_pre_resume;
-#endif
        }
 
        spec->multiout.dac_nids = spec->dac_nids;
index 06214fdc9486d2c5d1d6c59eca22325330c5c3f3..82b368068e08a57eb2785ca1dea23ca420b152e9 100644 (file)
@@ -54,6 +54,7 @@
 #include <sound/asoundef.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_auto_parser.h"
 #include "hda_jack.h"
 
 /* Pin Widget NID */
@@ -484,7 +485,7 @@ static void activate_output_mix(struct hda_codec *codec, struct nid_path *path,
 
        if (!path)
                return;
-       num = snd_hda_get_conn_list(codec, mix_nid, NULL);
+       num = snd_hda_get_num_conns(codec, mix_nid);
        for (i = 0; i < num; i++) {
                if (i == idx)
                        val = AMP_IN_UNMUTE(i);
@@ -532,8 +533,7 @@ static void init_output_pin(struct hda_codec *codec, hda_nid_t pin,
 {
        if (!pin)
                return;
-       snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           pin_type);
+       snd_hda_set_pin_ctl(codec, pin, pin_type);
        if (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)
                snd_hda_codec_write(codec, pin, 0,
                                    AC_VERB_SET_EAPD_BTLENABLE, 0x02);
@@ -662,12 +662,12 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
                hda_nid_t nid = cfg->inputs[i].pin;
                if (spec->smart51_enabled && is_smart51_pins(codec, nid))
                        ctl = PIN_OUT;
-               else if (cfg->inputs[i].type == AUTO_PIN_MIC)
-                       ctl = PIN_VREF50;
-               else
+               else {
                        ctl = PIN_IN;
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
+                       if (cfg->inputs[i].type == AUTO_PIN_MIC)
+                               ctl |= snd_hda_get_default_vref(codec, nid);
+               }
+               snd_hda_set_pin_ctl(codec, nid, ctl);
        }
 
        /* init input-src */
@@ -1006,9 +1006,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
                                          AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
                parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
                parm |= out_in;
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   parm);
+               snd_hda_set_pin_ctl(codec, nid, parm);
                if (out_in == AC_PINCTL_OUT_EN) {
                        mute_aa_path(codec, 1);
                        notify_aa_path_ctls(codec);
@@ -1647,8 +1645,7 @@ static void toggle_output_mutes(struct hda_codec *codec, int num_pins,
                        parm &= ~AC_PINCTL_OUT_EN;
                else
                        parm |= AC_PINCTL_OUT_EN;
-               snd_hda_codec_write(codec, pins[i], 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, parm);
+               snd_hda_set_pin_ctl(codec, pins[i], parm);
        }
 }
 
@@ -1709,8 +1706,7 @@ static void via_gpio_control(struct hda_codec *codec)
 
        if (gpio_data == 0x02) {
                /* unmute line out */
-               snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+               snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0],
                                    PIN_OUT);
                if (vol_counter & 0x20) {
                        /* decrease volume */
@@ -1728,9 +1724,7 @@ static void via_gpio_control(struct hda_codec *codec)
                }
        } else if (!(gpio_data & 0x02)) {
                /* mute line out */
-               snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   0);
+               snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0], 0);
        }
 }
 
@@ -2757,8 +2751,7 @@ static void via_auto_init_dig_in(struct hda_codec *codec)
        struct via_spec *spec = codec->spec;
        if (!spec->dig_in_nid)
                return;
-       snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+       snd_hda_set_pin_ctl(codec, spec->autocfg.dig_in_pin, PIN_IN);
 }
 
 /* initialize the unsolicited events */
index 132a86e09d07d69adb6f7e5c7516207205f44c13..5be2e120a14e25a03744b873e690f765eecb9545 100644 (file)
@@ -2803,22 +2803,11 @@ static void __devexit snd_ice1712_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver ice1712_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_ice1712_ids,
        .probe = snd_ice1712_probe,
        .remove = __devexit_p(snd_ice1712_remove),
 };
 
-static int __init alsa_card_ice1712_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ice1712_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ice1712_init)
-module_exit(alsa_card_ice1712_exit)
+module_pci_driver(ice1712_driver);
index 812d10e43ae0aa270517b9204be80a2c64200ff6..a01a00d1cf4db3ab1184beba254a3f20cb4e3634 100644 (file)
@@ -2873,7 +2873,7 @@ static int snd_vt1724_resume(struct pci_dev *pci)
 }
 #endif
 
-static struct pci_driver driver = {
+static struct pci_driver vt1724_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_vt1724_ids,
        .probe = snd_vt1724_probe,
@@ -2884,15 +2884,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_ice1724_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ice1724_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ice1724_init)
-module_exit(alsa_card_ice1724_exit)
+module_pci_driver(vt1724_driver);
index e0a4263baa2028f995b45741745dd703e2191875..f4e2dd4da8cf6e2c5e72b45d88e143a9d19783bb 100644 (file)
@@ -3338,7 +3338,7 @@ static void __devexit snd_intel8x0_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver intel8x0_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_intel8x0_ids,
        .probe = snd_intel8x0_probe,
@@ -3349,16 +3349,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-
-static int __init alsa_card_intel8x0_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_intel8x0_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_intel8x0_init)
-module_exit(alsa_card_intel8x0_exit)
+module_pci_driver(intel8x0_driver);
index d689913a61be11ba1a2462ab11b8c4e54aac0735..fc27a6a69e77d8aeb45a9a46fda2d319fa1c19fc 100644 (file)
@@ -1324,7 +1324,7 @@ static void __devexit snd_intel8x0m_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver intel8x0m_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_intel8x0m_ids,
        .probe = snd_intel8x0m_probe,
@@ -1335,16 +1335,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-
-static int __init alsa_card_intel8x0m_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_intel8x0m_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_intel8x0m_init)
-module_exit(alsa_card_intel8x0m_exit)
+module_pci_driver(intel8x0m_driver);
index 8fea45ab5882b241237bdc834205e687b651666b..e69ce5f9c31e036a9f4229d76fe9d8c21d9cefe8 100644 (file)
@@ -2476,22 +2476,11 @@ static void __devexit snd_korg1212_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver korg1212_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_korg1212_ids,
        .probe = snd_korg1212_probe,
        .remove = __devexit_p(snd_korg1212_remove),
 };
 
-static int __init alsa_card_korg1212_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_korg1212_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_korg1212_init)
-module_exit(alsa_card_korg1212_exit)
+module_pci_driver(korg1212_driver);
index 375982736858fed1d27f3a848abce3498d581a25..ac15166bee6889477d5cc4c005adc8979c6b7ee5 100644 (file)
@@ -770,22 +770,11 @@ static DEFINE_PCI_DEVICE_TABLE(lola_ids) = {
 MODULE_DEVICE_TABLE(pci, lola_ids);
 
 /* pci_driver definition */
-static struct pci_driver driver = {
+static struct pci_driver lola_driver = {
        .name = KBUILD_MODNAME,
        .id_table = lola_ids,
        .probe = lola_probe,
        .remove = __devexit_p(lola_remove),
 };
 
-static int __init alsa_card_lola_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_lola_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_lola_init)
-module_exit(alsa_card_lola_exit)
+module_pci_driver(lola_driver);
index d94c0c292bd08c2753f4dabc714bd31c5bbf9239..d1ab43706735fb42d12cc8514b48b9add557b5c2 100644 (file)
@@ -1141,24 +1141,11 @@ static void __devexit snd_lx6464es_remove(struct pci_dev *pci)
 }
 
 
-static struct pci_driver driver = {
+static struct pci_driver lx6464es_driver = {
        .name =     KBUILD_MODNAME,
        .id_table = snd_lx6464es_ids,
        .probe =    snd_lx6464es_probe,
        .remove = __devexit_p(snd_lx6464es_remove),
 };
 
-
-/* module initialization */
-static int __init mod_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit mod_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(mod_init);
-module_exit(mod_exit);
+module_pci_driver(lx6464es_driver);
index 78229b0dad2bcbfcfdcafd4f18c40b775a133498..deef213995869964791ddf53d03198019cfb1db0 100644 (file)
@@ -2837,7 +2837,7 @@ static void __devexit snd_m3_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver m3_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_m3_ids,
        .probe = snd_m3_probe,
@@ -2848,15 +2848,4 @@ static struct pci_driver driver = {
 #endif
 };
        
-static int __init alsa_card_m3_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_m3_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_m3_init)
-module_exit(alsa_card_m3_exit)
+module_pci_driver(m3_driver);
index 487837c01c9ff3ae206e30cbd804e02c5de1725e..0762610c99c0e7046f490d0d71e9a304a9e940c7 100644 (file)
@@ -1380,22 +1380,11 @@ static void __devexit snd_mixart_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver mixart_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_mixart_ids,
        .probe = snd_mixart_probe,
        .remove = __devexit_p(snd_mixart_remove),
 };
 
-static int __init alsa_card_mixart_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_mixart_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_mixart_init)
-module_exit(alsa_card_mixart_exit)
+module_pci_driver(mixart_driver);
index ade2c64bd606f9ba84eab2c84ab0ebb841f7b146..8159b05ee94d4a10a41988597891c8765ba50c2f 100644 (file)
@@ -1742,7 +1742,7 @@ static void __devexit snd_nm256_remove(struct pci_dev *pci)
 }
 
 
-static struct pci_driver driver = {
+static struct pci_driver nm256_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_nm256_ids,
        .probe = snd_nm256_probe,
@@ -1753,16 +1753,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-
-static int __init alsa_card_nm256_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_nm256_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_nm256_init)
-module_exit(alsa_card_nm256_exit)
+module_pci_driver(nm256_driver);
index eab663eef1170dd22f508c6f589a2f17f82f35de..610275bfbaeb2c2bae48f620f1232b7e12f027ed 100644 (file)
@@ -94,6 +94,7 @@ enum {
        MODEL_2CH_OUTPUT,
        MODEL_HG2PCI,
        MODEL_XONAR_DG,
+       MODEL_XONAR_DGX,
 };
 
 static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
@@ -109,6 +110,8 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
        { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
        /* Asus Xonar DG */
        { OXYGEN_PCI_SUBID(0x1043, 0x8467), .driver_data = MODEL_XONAR_DG },
+       /* Asus Xonar DGX */
+       { OXYGEN_PCI_SUBID(0x1043, 0x8521), .driver_data = MODEL_XONAR_DGX },
        /* PCI 2.0 HD Audio */
        { OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT },
        /* Kuroutoshikou CMI8787-HG2PCI */
@@ -827,6 +830,11 @@ static int __devinit get_oxygen_model(struct oxygen *chip,
                break;
        case MODEL_XONAR_DG:
                chip->model = model_xonar_dg;
+               chip->model.shortname = "Xonar DG";
+               break;
+       case MODEL_XONAR_DGX:
+               chip->model = model_xonar_dg;
+               chip->model.shortname = "Xonar DGX";
                break;
        }
        if (id->driver_data == MODEL_MERIDIAN ||
@@ -870,15 +878,4 @@ static struct pci_driver oxygen_driver = {
 #endif
 };
 
-static int __init alsa_card_oxygen_init(void)
-{
-       return pci_register_driver(&oxygen_driver);
-}
-
-static void __exit alsa_card_oxygen_exit(void)
-{
-       pci_unregister_driver(&oxygen_driver);
-}
-
-module_init(alsa_card_oxygen_init)
-module_exit(alsa_card_oxygen_exit)
+module_pci_driver(oxygen_driver);
index 3fdee4950174597db4abaf93e11192e95e2d2f65..19962c6d38c3caf3850d5a71d4bb70307d301276 100644 (file)
@@ -100,15 +100,4 @@ static struct pci_driver xonar_driver = {
        .shutdown = oxygen_pci_shutdown,
 };
 
-static int __init alsa_card_xonar_init(void)
-{
-       return pci_register_driver(&xonar_driver);
-}
-
-static void __exit alsa_card_xonar_exit(void)
-{
-       pci_unregister_driver(&xonar_driver);
-}
-
-module_init(alsa_card_xonar_init)
-module_exit(alsa_card_xonar_exit)
+module_pci_driver(xonar_driver);
index 793bdf03d7e07cdc700c93915356896936993806..77acd790ea4796b94c779fd72c1a8be861c4aa9e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * card driver for the Xonar DG
+ * card driver for the Xonar DG/DGX
  *
  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
  *
@@ -17,8 +17,8 @@
  */
 
 /*
- * Xonar DG
- * --------
+ * Xonar DG/DGX
+ * ------------
  *
  * CMI8788:
  *
@@ -581,7 +581,6 @@ static void dump_cs4245_registers(struct oxygen *chip,
 }
 
 struct oxygen_model model_xonar_dg = {
-       .shortname = "Xonar DG",
        .longname = "C-Media Oxygen HD Audio",
        .chip = "CMI8786",
        .init = dg_init,
index fd1809ab73b4e4c3a934e895a4039a32f8cc2ba6..0435f45e95132d59583a09c9d72a25f19d536408 100644 (file)
@@ -1607,22 +1607,11 @@ static void __devexit pcxhr_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver pcxhr_driver = {
        .name = KBUILD_MODNAME,
        .id_table = pcxhr_ids,
        .probe = pcxhr_probe,
        .remove = __devexit_p(pcxhr_remove),
 };
 
-static int __init pcxhr_module_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit pcxhr_module_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(pcxhr_module_init)
-module_exit(pcxhr_module_exit)
+module_pci_driver(pcxhr_driver);
index 0481d94aac9b9e3027467aa744861d947c5373cc..cbeb3f77350c6e42ff8861c7304a3b5b4957920c 100644 (file)
@@ -1837,8 +1837,7 @@ static int snd_riptide_free(struct snd_riptide *chip)
        }
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
-       if (chip->fw_entry)
-               release_firmware(chip->fw_entry);
+       release_firmware(chip->fw_entry);
        release_and_free_resource(chip->res_port);
        kfree(chip);
        return 0;
index b4819d5e41dbe04be2f707ead5f7daecb015a281..46b3629dda22d3d9fbd33f281b2dc13c79815f56 100644 (file)
@@ -1984,22 +1984,11 @@ static void __devexit snd_rme32_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver rme32_driver = {
        .name =         KBUILD_MODNAME,
        .id_table =     snd_rme32_ids,
        .probe =        snd_rme32_probe,
        .remove =       __devexit_p(snd_rme32_remove),
 };
 
-static int __init alsa_card_rme32_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_rme32_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_rme32_init)
-module_exit(alsa_card_rme32_exit)
+module_pci_driver(rme32_driver);
index ba894158e76ceaa62fc335ae8a30a69d28de1b16..9b98dc406988386b62a6c9f07e31181f98d2bb29 100644 (file)
@@ -2395,22 +2395,11 @@ static void __devexit snd_rme96_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver rme96_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_rme96_ids,
        .probe = snd_rme96_probe,
        .remove = __devexit_p(snd_rme96_remove),
 };
 
-static int __init alsa_card_rme96_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_rme96_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_rme96_init)
-module_exit(alsa_card_rme96_exit)
+module_pci_driver(rme96_driver);
index 0b2aea2ce1729086db78b38b134777935d04fb00..0d6930c4f4b7bc4c2d4cecd0a074cbd30b3305bb 100644 (file)
@@ -5636,22 +5636,11 @@ static void __devexit snd_hdsp_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver hdsp_driver = {
        .name =     KBUILD_MODNAME,
        .id_table = snd_hdsp_ids,
        .probe =    snd_hdsp_probe,
        .remove = __devexit_p(snd_hdsp_remove),
 };
 
-static int __init alsa_card_hdsp_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_hdsp_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_hdsp_init)
-module_exit(alsa_card_hdsp_exit)
+module_pci_driver(hdsp_driver);
index bc030a2088da7928d0b9ebc5830fbeb743c59a37..0a5027b94714afb9600b94922f6d89140271492d 100644 (file)
@@ -6918,23 +6918,11 @@ static void __devexit snd_hdspm_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver hdspm_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_hdspm_ids,
        .probe = snd_hdspm_probe,
        .remove = __devexit_p(snd_hdspm_remove),
 };
 
-
-static int __init alsa_card_hdspm_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_hdspm_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_hdspm_init)
-module_exit(alsa_card_hdspm_exit)
+module_pci_driver(hdspm_driver);
index b737d1619cc764ce00137b71db68709363ae2d0b..a15fc100ab0c320808229729d00c4a55eb1d7da4 100644 (file)
@@ -2631,22 +2631,11 @@ static void __devexit snd_rme9652_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver rme9652_driver = {
        .name     = KBUILD_MODNAME,
        .id_table = snd_rme9652_ids,
        .probe    = snd_rme9652_probe,
        .remove   = __devexit_p(snd_rme9652_remove),
 };
 
-static int __init alsa_card_hammerfall_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_hammerfall_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_hammerfall_init)
-module_exit(alsa_card_hammerfall_exit)
+module_pci_driver(rme9652_driver);
index ff500a87f7694f09578d032965bdc4815c039d1c..1552642765d6eea4896da26bc715024764c49eaa 100644 (file)
@@ -1488,15 +1488,4 @@ static struct pci_driver sis7019_driver = {
 #endif
 };
 
-static int __init sis7019_init(void)
-{
-       return pci_register_driver(&sis7019_driver);
-}
-
-static void __exit sis7019_exit(void)
-{
-       pci_unregister_driver(&sis7019_driver);
-}
-
-module_init(sis7019_init);
-module_exit(sis7019_exit);
+module_pci_driver(sis7019_driver);
index 54cc802050f705b55b6675be122f7b649ed9b2c3..baa9946bedf019cb098032be10ee5df4c233cc05 100644 (file)
@@ -1530,22 +1530,11 @@ static void __devexit snd_sonic_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver sonicvibes_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_sonic_ids,
        .probe = snd_sonic_probe,
        .remove = __devexit_p(snd_sonic_remove),
 };
 
-static int __init alsa_card_sonicvibes_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_sonicvibes_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_sonicvibes_init)
-module_exit(alsa_card_sonicvibes_exit)
+module_pci_driver(sonicvibes_driver);
index 5f1def7f45e550949e547ea4fffcbded6051503b..611983ec73211f35e8ca761073a9c15803f65d96 100644 (file)
@@ -172,7 +172,7 @@ static void __devexit snd_trident_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver trident_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_trident_ids,
        .probe = snd_trident_probe,
@@ -183,15 +183,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_trident_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_trident_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_trident_init)
-module_exit(alsa_card_trident_exit)
+module_pci_driver(trident_driver);
index 75630408c6db495bf9c124a84738f57eb92c64b5..b5afab48943eeca6bcb8a6aac3836c83cafd7de8 100644 (file)
@@ -2619,7 +2619,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver via82xx_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_via82xx_ids,
        .probe = snd_via82xx_probe,
@@ -2630,15 +2630,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_via82xx_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_via82xx_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_via82xx_init)
-module_exit(alsa_card_via82xx_exit)
+module_pci_driver(via82xx_driver);
index 5efcbcac506a16f0e392551faa9f1d559dade231..59fd47ed0a31238e2aeb37e412cdfba591feafc5 100644 (file)
@@ -1223,7 +1223,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver via82xx_modem_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_via82xx_modem_ids,
        .probe = snd_via82xx_probe,
@@ -1234,15 +1234,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_via82xx_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_via82xx_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_via82xx_init)
-module_exit(alsa_card_via82xx_exit)
+module_pci_driver(via82xx_modem_driver);
index 6a534bfe127408b6fe08d4045413508f1d0bec13..1ea1f656a5dc2e300fa48a757052e450dac6485d 100644 (file)
@@ -289,7 +289,7 @@ static int snd_vx222_resume(struct pci_dev *pci)
 }
 #endif
 
-static struct pci_driver driver = {
+static struct pci_driver vx222_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_vx222_ids,
        .probe = snd_vx222_probe,
@@ -300,15 +300,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_vx222_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_vx222_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_vx222_init)
-module_exit(alsa_card_vx222_exit)
+module_pci_driver(vx222_driver);
index 94ab728f5ca8b5a28b5a11ef9f36a723e3ebb707..9a1d01d653a7cff03b68fc64b572fb9e32376516 100644 (file)
@@ -350,7 +350,7 @@ static void __devexit snd_card_ymfpci_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-static struct pci_driver driver = {
+static struct pci_driver ymfpci_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_ymfpci_ids,
        .probe = snd_card_ymfpci_probe,
@@ -361,15 +361,4 @@ static struct pci_driver driver = {
 #endif
 };
 
-static int __init alsa_card_ymfpci_init(void)
-{
-       return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ymfpci_exit(void)
-{
-       pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ymfpci_init)
-module_exit(alsa_card_ymfpci_exit)
+module_pci_driver(ymfpci_driver);
index b11f82b5718fdb1c49eec15d034bad31c9fd9e6f..f8b01c77b298dd2da058e049c2738d396e6b6892 100644 (file)
@@ -433,7 +433,7 @@ probe_error:
 /*
  * "driver" definition
  */
-static struct platform_driver driver = {
+static struct platform_driver sh_dac_driver = {
        .probe  = snd_sh_dac_probe,
        .remove = snd_sh_dac_remove,
        .driver = {
@@ -441,4 +441,4 @@ static struct platform_driver driver = {
        },
 };
 
-module_platform_driver(driver);
+module_platform_driver(sh_dac_driver);
index 91c985599d32c782c9b42029ccb409bb9afec429..40b2ad1bb1cd8b14cb401d60f096f07ee5cf0f3b 100644 (file)
@@ -35,7 +35,6 @@ source "sound/soc/blackfin/Kconfig"
 source "sound/soc/davinci/Kconfig"
 source "sound/soc/ep93xx/Kconfig"
 source "sound/soc/fsl/Kconfig"
-source "sound/soc/imx/Kconfig"
 source "sound/soc/jz4740/Kconfig"
 source "sound/soc/nuc900/Kconfig"
 source "sound/soc/omap/Kconfig"
@@ -48,9 +47,13 @@ source "sound/soc/s6000/Kconfig"
 source "sound/soc/sh/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
+source "sound/soc/ux500/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
 
+# generic frame-work
+source "sound/soc/generic/Kconfig"
+
 endif  # SND_SOC
 
index 2feaf376e94b2fc4ab06ca821e4ac328d3d423bb..70990f4017f4952b2f311a77c7c61dbe03332fba 100644 (file)
@@ -6,13 +6,13 @@ obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o
 
 obj-$(CONFIG_SND_SOC)  += snd-soc-core.o
 obj-$(CONFIG_SND_SOC)  += codecs/
+obj-$(CONFIG_SND_SOC)  += generic/
 obj-$(CONFIG_SND_SOC)  += atmel/
 obj-$(CONFIG_SND_SOC)  += au1x/
 obj-$(CONFIG_SND_SOC)  += blackfin/
 obj-$(CONFIG_SND_SOC)  += davinci/
 obj-$(CONFIG_SND_SOC)  += ep93xx/
 obj-$(CONFIG_SND_SOC)  += fsl/
-obj-$(CONFIG_SND_SOC)   += imx/
 obj-$(CONFIG_SND_SOC)  += jz4740/
 obj-$(CONFIG_SND_SOC)  += mid-x86/
 obj-$(CONFIG_SND_SOC)  += mxs/
@@ -25,3 +25,4 @@ obj-$(CONFIG_SND_SOC) += s6000/
 obj-$(CONFIG_SND_SOC)  += sh/
 obj-$(CONFIG_SND_SOC)  += tegra/
 obj-$(CONFIG_SND_SOC)  += txx9/
+obj-$(CONFIG_SND_SOC)  += ux500/
index b39ad356b92b84e2d649c0ea986c2ba23aecbac9..7dbeef1099b48de868d3fd724c93db45a64a0206 100644 (file)
 
 static struct snd_soc_card bf5xx_ssm2602;
 
-static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
+static int bf5xx_ssm2602_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       unsigned int clk = 0;
-       int ret = 0;
-
-       pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
-               params_format(params));
        /*
         * If you are using a crystal source which frequency is not 12MHz
         * then modify the below case statement with frequency of the crystal.
@@ -61,31 +53,10 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
         * If you are using the SPORT to generate clocking then this is
         * where to do it.
         */
-
-       switch (params_rate(params)) {
-       case 8000:
-       case 16000:
-       case 48000:
-       case 96000:
-       case 11025:
-       case 22050:
-       case 44100:
-               clk = 12000000;
-               break;
-       }
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, SSM2602_SYSCLK, clk,
+       return snd_soc_dai_set_sysclk(rtd->codec_dai, SSM2602_SYSCLK, 12000000,
                SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       return 0;
 }
 
-static struct snd_soc_ops bf5xx_ssm2602_ops = {
-       .hw_params = bf5xx_ssm2602_hw_params,
-};
-
 /* CODEC is master for BCLK and LRC in this configuration. */
 #define BF5XX_SSM2602_DAIFMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
                                SND_SOC_DAIFMT_CBM_CFM)
@@ -98,7 +69,7 @@ static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
                .codec_dai_name = "ssm2602-hifi",
                .platform_name = "bfin-i2s-pcm-audio",
                .codec_name = "ssm2602.0-001b",
-               .ops = &bf5xx_ssm2602_ops,
+               .init = bf5xx_ssm2602_dai_init,
                .dai_fmt = BF5XX_SSM2602_DAIFMT,
        },
        {
@@ -108,7 +79,7 @@ static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
                .codec_dai_name = "ssm2602-hifi",
                .platform_name = "bfin-i2s-pcm-audio",
                .codec_name = "ssm2602.0-001b",
-               .ops = &bf5xx_ssm2602_ops,
+               .init = bf5xx_ssm2602_dai_init,
                .dai_fmt = BF5XX_SSM2602_DAIFMT,
        },
 };
index 59d8efaa17e96eec921774fad61fd149884f2241..1e1613a438ddbf5a0eb42ab81a72020a792fb074 100644 (file)
@@ -29,6 +29,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_ALC5632 if I2C
        select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
        select SND_SOC_CS42L51 if I2C
+       select SND_SOC_CS42L52 if I2C
        select SND_SOC_CS42L73 if I2C
        select SND_SOC_CS4270 if I2C
        select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
@@ -37,11 +38,15 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_DFBMCS320
        select SND_SOC_JZ4740_CODEC
        select SND_SOC_LM4857 if I2C
+       select SND_SOC_LM49453 if I2C
        select SND_SOC_MAX98088 if I2C
        select SND_SOC_MAX98095 if I2C
        select SND_SOC_MAX9850 if I2C
        select SND_SOC_MAX9768 if I2C
        select SND_SOC_MAX9877 if I2C
+       select SND_SOC_MC13783 if MFD_MC13XXX
+       select SND_SOC_ML26124 if I2C
+       select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI
        select SND_SOC_PCM3008
        select SND_SOC_RT5631 if I2C
        select SND_SOC_SGTL5000 if I2C
@@ -181,6 +186,9 @@ config SND_SOC_CQ0093VC
 config SND_SOC_CS42L51
        tristate
 
+config SND_SOC_CS42L52
+       tristate
+
 config SND_SOC_CS42L73
        tristate
 
@@ -217,6 +225,9 @@ config SND_SOC_DFBMCS320
 config SND_SOC_DMIC
        tristate
 
+config SND_SOC_LM49453
+       tristate
+
 config SND_SOC_MAX98088
        tristate
 
@@ -226,6 +237,9 @@ config SND_SOC_MAX98095
 config SND_SOC_MAX9850
        tristate
 
+config SND_SOC_OMAP_HDMI_CODEC
+       tristate
+
 config SND_SOC_PCM3008
        tristate
 
@@ -435,5 +449,11 @@ config SND_SOC_MAX9768
 config SND_SOC_MAX9877
        tristate
 
+config SND_SOC_MC13783
+       tristate
+
+config SND_SOC_ML26124
+       tristate
+
 config SND_SOC_TPA6130A2
        tristate
index 6662eb0cdcc0724f2364760a15730346278267ab..fc27fec39487bf1bd9e9e8a9fd4551d45777a159 100644 (file)
@@ -15,6 +15,7 @@ snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cs42l51-objs := cs42l51.o
+snd-soc-cs42l52-objs := cs42l52.o
 snd-soc-cs42l73-objs := cs42l73.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cs4271-objs := cs4271.o
@@ -25,10 +26,14 @@ snd-soc-dmic-objs := dmic.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
 snd-soc-lm4857-objs := lm4857.o
+snd-soc-lm49453-objs := lm49453.o
 snd-soc-max9768-objs := max9768.o
 snd-soc-max98088-objs := max98088.o
 snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
+snd-soc-mc13783-objs := mc13783.o
+snd-soc-ml26124-objs := ml26124.o
+snd-soc-omap-hdmi-codec-objs := omap-hdmi.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-sgtl5000-objs := sgtl5000.o
@@ -121,6 +126,7 @@ obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5632)  += snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
 obj-$(CONFIG_SND_SOC_CS42L51)  += snd-soc-cs42l51.o
+obj-$(CONFIG_SND_SOC_CS42L52)  += snd-soc-cs42l52.o
 obj-$(CONFIG_SND_SOC_CS42L73)  += snd-soc-cs42l73.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CS4271)   += snd-soc-cs4271.o
@@ -128,13 +134,17 @@ obj-$(CONFIG_SND_SOC_CX20442)     += snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)   += snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DFBMCS320)        += snd-soc-dfbmcs320.o
 obj-$(CONFIG_SND_SOC_DMIC)     += snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_JZ4740_CODEC)     += snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_LM4857)   += snd-soc-lm4857.o
-obj-$(CONFIG_SND_SOC_JZ4740_CODEC)     += snd-soc-jz4740-codec.o
+obj-$(CONFIG_SND_SOC_LM49453)   += snd-soc-lm49453.o
 obj-$(CONFIG_SND_SOC_MAX9768)  += snd-soc-max9768.o
 obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX9850)  += snd-soc-max9850.o
+obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
+obj-$(CONFIG_SND_SOC_ML26124)  += snd-soc-ml26124.o
+obj-$(CONFIG_SND_SOC_OMAP_HDMI_CODEC) += snd-soc-omap-hdmi-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_RT5631)   += snd-soc-rt5631.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
index 1bbad4c16d289fe29f7c20702138db81f4f093d5..2023c749f23278e77dacee56feb5df139c43a47f 100644 (file)
 static int ac97_prepare(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
 
        int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
                  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
-       return snd_ac97_set_rate(codec->ac97, reg, runtime->rate);
+       return snd_ac97_set_rate(codec->ac97, reg, substream->runtime->rate);
 }
 
 #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
index 12e3b4118557388b5cbb1a62fc0dea3264ba082f..c67b50d8b3170cd388a1279516a186c9a23e9a99 100644 (file)
@@ -162,9 +162,7 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
        int word_len = 0;
-
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
 
        /* bit size */
        switch (params_format(params)) {
index a4a6bef2c0bbd1372fafe48bde8129687138dc85..13e62be4f9903eac8560819d751b0edbcf9e4555 100644 (file)
@@ -245,9 +245,7 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
        int word_len = 0, master_rate = 0;
-
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
 
        /* bit size */
index 78e9ce48bb99e6402987a0083d124219bd3400f7..3d50fc8646b672fd87eb82c21abb72b4699ec368 100644 (file)
@@ -258,8 +258,7 @@ static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,
 static int adau1701_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        snd_pcm_format_t format;
        unsigned int val;
 
index ceb96ecf5588994f1d8c3797a7d4ed9048f83417..31d4483245d0db951584a0e1619b91c8ac8fa726 100644 (file)
@@ -88,8 +88,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        int val = 0;
 
        /* set the IEC958 bits: consumer mode, no copyright bit */
index 838ae8b22b500f8461f2baa151f4164d303ec85d..618fdc30f73eb3889f2372e4bba9033d3675270d 100644 (file)
@@ -262,8 +262,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
        u8 mode2 = snd_soc_read(codec, AK4535_MODE2) & ~(0x3 << 5);
        int rate = params_rate(params), fs = 256;
index c4d165a4bddf522f3557d86d111ccbfc1bc9148e..543a12f471be65a70c9b88a529c9d2dd42f8b7ed 100644 (file)
@@ -296,8 +296,7 @@ static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
        int rate = params_rate(params), fs = 256;
        u8 mode2;
@@ -517,67 +516,24 @@ static int ak4641_resume(struct snd_soc_codec *codec)
 
 static int ak4641_probe(struct snd_soc_codec *codec)
 {
-       struct ak4641_platform_data *pdata = codec->dev->platform_data;
        int ret;
 
-
-       if (pdata) {
-               if (gpio_is_valid(pdata->gpio_power)) {
-                       ret = gpio_request_one(pdata->gpio_power,
-                                       GPIOF_OUT_INIT_LOW, "ak4641 power");
-                       if (ret)
-                               goto err_out;
-               }
-               if (gpio_is_valid(pdata->gpio_npdn)) {
-                       ret = gpio_request_one(pdata->gpio_npdn,
-                                       GPIOF_OUT_INIT_LOW, "ak4641 npdn");
-                       if (ret)
-                               goto err_gpio;
-
-                       udelay(1); /* > 150 ns */
-                       gpio_set_value(pdata->gpio_npdn, 1);
-               }
-       }
-
        ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err_register;
+               return ret;
        }
 
        /* power on device */
        ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
-
-err_register:
-       if (pdata) {
-               if (gpio_is_valid(pdata->gpio_power))
-                       gpio_set_value(pdata->gpio_power, 0);
-               if (gpio_is_valid(pdata->gpio_npdn))
-                       gpio_free(pdata->gpio_npdn);
-       }
-err_gpio:
-       if (pdata && gpio_is_valid(pdata->gpio_power))
-               gpio_free(pdata->gpio_power);
-err_out:
-       return ret;
 }
 
 static int ak4641_remove(struct snd_soc_codec *codec)
 {
-       struct ak4641_platform_data *pdata = codec->dev->platform_data;
-
        ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-       if (pdata) {
-               if (gpio_is_valid(pdata->gpio_power)) {
-                       gpio_set_value(pdata->gpio_power, 0);
-                       gpio_free(pdata->gpio_power);
-               }
-               if (gpio_is_valid(pdata->gpio_npdn))
-                       gpio_free(pdata->gpio_npdn);
-       }
        return 0;
 }
 
@@ -604,6 +560,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
 static int __devinit ak4641_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
+       struct ak4641_platform_data *pdata = i2c->dev.platform_data;
        struct ak4641_priv *ak4641;
        int ret;
 
@@ -612,16 +569,62 @@ static int __devinit ak4641_i2c_probe(struct i2c_client *i2c,
        if (!ak4641)
                return -ENOMEM;
 
+       if (pdata) {
+               if (gpio_is_valid(pdata->gpio_power)) {
+                       ret = gpio_request_one(pdata->gpio_power,
+                                       GPIOF_OUT_INIT_LOW, "ak4641 power");
+                       if (ret)
+                               goto err_out;
+               }
+               if (gpio_is_valid(pdata->gpio_npdn)) {
+                       ret = gpio_request_one(pdata->gpio_npdn,
+                                       GPIOF_OUT_INIT_LOW, "ak4641 npdn");
+                       if (ret)
+                               goto err_gpio;
+
+                       udelay(1); /* > 150 ns */
+                       gpio_set_value(pdata->gpio_npdn, 1);
+               }
+       }
+
        i2c_set_clientdata(i2c, ak4641);
 
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4641,
                                ak4641_dai, ARRAY_SIZE(ak4641_dai));
+       if (ret != 0)
+               goto err_gpio2;
+
+       return 0;
+
+err_gpio2:
+       if (pdata) {
+               if (gpio_is_valid(pdata->gpio_power))
+                       gpio_set_value(pdata->gpio_power, 0);
+               if (gpio_is_valid(pdata->gpio_npdn))
+                       gpio_free(pdata->gpio_npdn);
+       }
+err_gpio:
+       if (pdata && gpio_is_valid(pdata->gpio_power))
+               gpio_free(pdata->gpio_power);
+err_out:
        return ret;
 }
 
 static int __devexit ak4641_i2c_remove(struct i2c_client *i2c)
 {
+       struct ak4641_platform_data *pdata = i2c->dev.platform_data;
+
        snd_soc_unregister_codec(&i2c->dev);
+
+       if (pdata) {
+               if (gpio_is_valid(pdata->gpio_power)) {
+                       gpio_set_value(pdata->gpio_power, 0);
+                       gpio_free(pdata->gpio_power);
+               }
+               if (gpio_is_valid(pdata->gpio_npdn))
+                       gpio_free(pdata->gpio_npdn);
+       }
+
        return 0;
 }
 
@@ -641,23 +644,7 @@ static struct i2c_driver ak4641_i2c_driver = {
        .id_table = ak4641_i2c_id,
 };
 
-static int __init ak4641_modinit(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&ak4641_i2c_driver);
-       if (ret != 0)
-               pr_err("Failed to register AK4641 I2C driver: %d\n", ret);
-
-       return ret;
-}
-module_init(ak4641_modinit);
-
-static void __exit ak4641_exit(void)
-{
-       i2c_del_driver(&ak4641_i2c_driver);
-}
-module_exit(ak4641_exit);
+module_i2c_driver(ak4641_i2c_driver);
 
 MODULE_DESCRIPTION("SoC AK4641 driver");
 MODULE_AUTHOR("Harald Welte <laforge@gnufiish.org>");
index d47b62ddb210dbf68b5eeb4b4e0dc4abadc5556d..1960478ce6bb883dbf02af92e242e2b538ea8823 100644 (file)
@@ -705,8 +705,7 @@ static int alc5623_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int alc5623_pcm_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
        int coeff, rate;
        u16 iface;
@@ -1084,25 +1083,7 @@ static struct i2c_driver alc5623_i2c_driver = {
        .id_table = alc5623_i2c_table,
 };
 
-static int __init alc5623_modinit(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&alc5623_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "%s: can't add i2c driver", __func__);
-               return ret;
-       }
-
-       return ret;
-}
-module_init(alc5623_modinit);
-
-static void __exit alc5623_modexit(void)
-{
-       i2c_del_driver(&alc5623_i2c_driver);
-}
-module_exit(alc5623_modexit);
+module_i2c_driver(alc5623_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC alc5621/2/3 driver");
 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
index e2111e0ccad7eedad086e5bc791d690f86388a15..7dd02420b36d3976f21b86ac8e50f0af0372a36f 100644 (file)
@@ -861,8 +861,7 @@ static int alc5632_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int alc5632_pcm_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        int coeff, rate;
        u16 iface;
 
@@ -1131,7 +1130,7 @@ static __devinit int alc5632_i2c_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, alc5632);
 
-       alc5632->regmap = regmap_init_i2c(client, &alc5632_regmap);
+       alc5632->regmap = devm_regmap_init_i2c(client, &alc5632_regmap);
        if (IS_ERR(alc5632->regmap)) {
                ret = PTR_ERR(alc5632->regmap);
                dev_err(&client->dev, "regmap_init() failed: %d\n", ret);
@@ -1143,7 +1142,6 @@ static __devinit int alc5632_i2c_probe(struct i2c_client *client,
        if (ret1 != 0 || ret2 != 0) {
                dev_err(&client->dev,
                "Failed to read chip ID: ret1=%d, ret2=%d\n", ret1, ret2);
-               regmap_exit(alc5632->regmap);
                return -EIO;
        }
 
@@ -1152,14 +1150,12 @@ static __devinit int alc5632_i2c_probe(struct i2c_client *client,
        if ((vid1 != 0x10EC) || (vid2 != id->driver_data)) {
                dev_err(&client->dev,
                "Device is not a ALC5632: VID1=0x%x, VID2=0x%x\n", vid1, vid2);
-               regmap_exit(alc5632->regmap);
                return -EINVAL;
        }
 
        ret = alc5632_reset(alc5632->regmap);
        if (ret < 0) {
                dev_err(&client->dev, "Failed to issue reset\n");
-               regmap_exit(alc5632->regmap);
                return ret;
        }
 
@@ -1177,7 +1173,6 @@ static __devinit int alc5632_i2c_probe(struct i2c_client *client,
 
        if (ret < 0) {
                dev_err(&client->dev, "Failed to register codec: %d\n", ret);
-               regmap_exit(alc5632->regmap);
                return ret;
        }
 
@@ -1186,9 +1181,7 @@ static __devinit int alc5632_i2c_probe(struct i2c_client *client,
 
 static __devexit int alc5632_i2c_remove(struct i2c_client *client)
 {
-       struct alc5632_priv *alc5632 = i2c_get_clientdata(client);
        snd_soc_unregister_codec(&client->dev);
-       regmap_exit(alc5632->regmap);
        return 0;
 }
 
@@ -1209,25 +1202,7 @@ static struct i2c_driver alc5632_i2c_driver = {
        .id_table = alc5632_i2c_table,
 };
 
-static int __init alc5632_modinit(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&alc5632_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "%s: can't add i2c driver", __func__);
-               return ret;
-       }
-
-       return ret;
-}
-module_init(alc5632_modinit);
-
-static void __exit alc5632_modexit(void)
-{
-       i2c_del_driver(&alc5632_i2c_driver);
-}
-module_exit(alc5632_modexit);
+module_i2c_driver(alc5632_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC ALC5632 driver");
 MODULE_AUTHOR("Leon Romanovsky <leon@leon.nu>");
index 1d672f528662cb162fc99a36b6946026a2dfdb09..047917f0b8aef6c54d82f618db30b706fe72636f 100644 (file)
@@ -307,8 +307,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
        int ret;
        unsigned int i;
@@ -600,10 +599,12 @@ static int cs4270_soc_suspend(struct snd_soc_codec *codec)
 static int cs4270_soc_resume(struct snd_soc_codec *codec)
 {
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
-       int reg;
+       int reg, ret;
 
-       regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
-                             cs4270->supplies);
+       ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
+                                   cs4270->supplies);
+       if (ret != 0)
+               return ret;
 
        /* In case the device was put to hard reset during sleep, we need to
         * wait 500ns here before any I2C communication. */
index bf7141280a747ab25b311c083b06b82bc8e7ad9e..9eb01d7d58a36f44c001b88556a466758c0eba49 100644 (file)
@@ -318,8 +318,7 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
        int i, ret;
        unsigned int ratio, val;
index a8bf588e8740ee248e039bf4028f346383bd9f4a..091d0193f507df21553be5515efc5f6836cd88d9 100644 (file)
@@ -141,15 +141,15 @@ static const struct soc_enum cs42l51_chan_mix =
 static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
        SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
                        CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
-                       7, 0xffffff99, 0x18, adc_pcm_tlv),
+                       6, 0x19, 0x7F, adc_pcm_tlv),
        SOC_DOUBLE_R("PCM Playback Switch",
                        CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
        SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
                        CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
-                       8, 0xffffff19, 0x18, aout_tlv),
+                       0, 0x34, 0xE4, aout_tlv),
        SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
                        CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
-                       7, 0xffffff99, 0x18, adc_pcm_tlv),
+                       6, 0x19, 0x7F, adc_pcm_tlv),
        SOC_DOUBLE_R("ADC Mixer Switch",
                        CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
        SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
@@ -356,8 +356,7 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params,
                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
        int ret;
        unsigned int i;
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
new file mode 100644 (file)
index 0000000..a710941
--- /dev/null
@@ -0,0 +1,1295 @@
+/*
+ * cs42l52.c -- CS42L52 ALSA SoC audio driver
+ *
+ * Copyright 2012 CirrusLogic, Inc.
+ *
+ * Author: Georgi Vlaev <joe@nucleusys.com>
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/cs42l52.h>
+#include "cs42l52.h"
+
+struct sp_config {
+       u8 spc, format, spfs;
+       u32 srate;
+};
+
+struct  cs42l52_private {
+       struct regmap *regmap;
+       struct snd_soc_codec *codec;
+       struct device *dev;
+       struct sp_config config;
+       struct cs42l52_platform_data pdata;
+       u32 sysclk;
+       u8 mclksel;
+       u32 mclk;
+       u8 flags;
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+       struct input_dev *beep;
+       struct work_struct beep_work;
+       int beep_rate;
+#endif
+};
+
+static const struct reg_default cs42l52_reg_defaults[] = {
+       { CS42L52_PWRCTL1, 0x9F },      /* r02 PWRCTL 1 */
+       { CS42L52_PWRCTL2, 0x07 },      /* r03 PWRCTL 2 */
+       { CS42L52_PWRCTL3, 0xFF },      /* r04 PWRCTL 3 */
+       { CS42L52_CLK_CTL, 0xA0 },      /* r05 Clocking Ctl */
+       { CS42L52_IFACE_CTL1, 0x00 },   /* r06 Interface Ctl 1 */
+       { CS42L52_ADC_PGA_A, 0x80 },    /* r08 Input A Select */
+       { CS42L52_ADC_PGA_B, 0x80 },    /* r09 Input B Select */
+       { CS42L52_ANALOG_HPF_CTL, 0xA5 },       /* r0A Analog HPF Ctl */
+       { CS42L52_ADC_HPF_FREQ, 0x00 }, /* r0B ADC HPF Corner Freq */
+       { CS42L52_ADC_MISC_CTL, 0x00 }, /* r0C Misc. ADC Ctl */
+       { CS42L52_PB_CTL1, 0x60 },      /* r0D Playback Ctl 1 */
+       { CS42L52_MISC_CTL, 0x02 },     /* r0E Misc. Ctl */
+       { CS42L52_PB_CTL2, 0x00 },      /* r0F Playback Ctl 2 */
+       { CS42L52_MICA_CTL, 0x00 },     /* r10 MICA Amp Ctl */
+       { CS42L52_MICB_CTL, 0x00 },     /* r11 MICB Amp Ctl */
+       { CS42L52_PGAA_CTL, 0x00 },     /* r12 PGAA Vol, Misc. */
+       { CS42L52_PGAB_CTL, 0x00 },     /* r13 PGAB Vol, Misc. */
+       { CS42L52_PASSTHRUA_VOL, 0x00 },        /* r14 Bypass A Vol */
+       { CS42L52_PASSTHRUB_VOL, 0x00 },        /* r15 Bypass B Vol */
+       { CS42L52_ADCA_VOL, 0x00 },     /* r16 ADCA Volume */
+       { CS42L52_ADCB_VOL, 0x00 },     /* r17 ADCB Volume */
+       { CS42L52_ADCA_MIXER_VOL, 0x80 },       /* r18 ADCA Mixer Volume */
+       { CS42L52_ADCB_MIXER_VOL, 0x80 },       /* r19 ADCB Mixer Volume */
+       { CS42L52_PCMA_MIXER_VOL, 0x00 },       /* r1A PCMA Mixer Volume */
+       { CS42L52_PCMB_MIXER_VOL, 0x00 },       /* r1B PCMB Mixer Volume */
+       { CS42L52_BEEP_FREQ, 0x00 },    /* r1C Beep Freq on Time */
+       { CS42L52_BEEP_VOL, 0x00 },     /* r1D Beep Volume off Time */
+       { CS42L52_BEEP_TONE_CTL, 0x00 },        /* r1E Beep Tone Cfg. */
+       { CS42L52_TONE_CTL, 0x00 },     /* r1F Tone Ctl */
+       { CS42L52_MASTERA_VOL, 0x88 },  /* r20 Master A Volume */
+       { CS42L52_MASTERB_VOL, 0x00 },  /* r21 Master B Volume */
+       { CS42L52_HPA_VOL, 0x00 },      /* r22 Headphone A Volume */
+       { CS42L52_HPB_VOL, 0x00 },      /* r23 Headphone B Volume */
+       { CS42L52_SPKA_VOL, 0x00 },     /* r24 Speaker A Volume */
+       { CS42L52_SPKB_VOL, 0x00 },     /* r25 Speaker B Volume */
+       { CS42L52_ADC_PCM_MIXER, 0x00 },        /* r26 Channel Mixer and Swap */
+       { CS42L52_LIMITER_CTL1, 0x00 }, /* r27 Limit Ctl 1 Thresholds */
+       { CS42L52_LIMITER_CTL2, 0x7F }, /* r28 Limit Ctl 2 Release Rate */
+       { CS42L52_LIMITER_AT_RATE, 0xC0 },      /* r29 Limiter Attack Rate */
+       { CS42L52_ALC_CTL, 0x00 },      /* r2A ALC Ctl 1 Attack Rate */
+       { CS42L52_ALC_RATE, 0x3F },     /* r2B ALC Release Rate */
+       { CS42L52_ALC_THRESHOLD, 0x3f },        /* r2C ALC Thresholds */
+       { CS42L52_NOISE_GATE_CTL, 0x00 },       /* r2D Noise Gate Ctl */
+       { CS42L52_CLK_STATUS, 0x00 },   /* r2E Overflow and Clock Status */
+       { CS42L52_BATT_COMPEN, 0x00 },  /* r2F battery Compensation */
+       { CS42L52_BATT_LEVEL, 0x00 },   /* r30 VP Battery Level */
+       { CS42L52_SPK_STATUS, 0x00 },   /* r31 Speaker Status */
+       { CS42L52_TEM_CTL, 0x3B },      /* r32 Temp Ctl */
+       { CS42L52_THE_FOLDBACK, 0x00 }, /* r33 Foldback */
+};
+
+static bool cs42l52_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS42L52_CHIP:
+       case CS42L52_PWRCTL1:
+       case CS42L52_PWRCTL2:
+       case CS42L52_PWRCTL3:
+       case CS42L52_CLK_CTL:
+       case CS42L52_IFACE_CTL1:
+       case CS42L52_IFACE_CTL2:
+       case CS42L52_ADC_PGA_A:
+       case CS42L52_ADC_PGA_B:
+       case CS42L52_ANALOG_HPF_CTL:
+       case CS42L52_ADC_HPF_FREQ:
+       case CS42L52_ADC_MISC_CTL:
+       case CS42L52_PB_CTL1:
+       case CS42L52_MISC_CTL:
+       case CS42L52_PB_CTL2:
+       case CS42L52_MICA_CTL:
+       case CS42L52_MICB_CTL:
+       case CS42L52_PGAA_CTL:
+       case CS42L52_PGAB_CTL:
+       case CS42L52_PASSTHRUA_VOL:
+       case CS42L52_PASSTHRUB_VOL:
+       case CS42L52_ADCA_VOL:
+       case CS42L52_ADCB_VOL:
+       case CS42L52_ADCA_MIXER_VOL:
+       case CS42L52_ADCB_MIXER_VOL:
+       case CS42L52_PCMA_MIXER_VOL:
+       case CS42L52_PCMB_MIXER_VOL:
+       case CS42L52_BEEP_FREQ:
+       case CS42L52_BEEP_VOL:
+       case CS42L52_BEEP_TONE_CTL:
+       case CS42L52_TONE_CTL:
+       case CS42L52_MASTERA_VOL:
+       case CS42L52_MASTERB_VOL:
+       case CS42L52_HPA_VOL:
+       case CS42L52_HPB_VOL:
+       case CS42L52_SPKA_VOL:
+       case CS42L52_SPKB_VOL:
+       case CS42L52_ADC_PCM_MIXER:
+       case CS42L52_LIMITER_CTL1:
+       case CS42L52_LIMITER_CTL2:
+       case CS42L52_LIMITER_AT_RATE:
+       case CS42L52_ALC_CTL:
+       case CS42L52_ALC_RATE:
+       case CS42L52_ALC_THRESHOLD:
+       case CS42L52_NOISE_GATE_CTL:
+       case CS42L52_CLK_STATUS:
+       case CS42L52_BATT_COMPEN:
+       case CS42L52_BATT_LEVEL:
+       case CS42L52_SPK_STATUS:
+       case CS42L52_TEM_CTL:
+       case CS42L52_THE_FOLDBACK:
+       case CS42L52_CHARGE_PUMP:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool cs42l52_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS42L52_IFACE_CTL2:
+       case CS42L52_CLK_STATUS:
+       case CS42L52_BATT_LEVEL:
+       case CS42L52_SPK_STATUS:
+       case CS42L52_CHARGE_PUMP:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static DECLARE_TLV_DB_SCALE(hl_tlv, -10200, 50, 0);
+
+static DECLARE_TLV_DB_SCALE(hpd_tlv, -9600, 50, 1);
+
+static DECLARE_TLV_DB_SCALE(ipd_tlv, -9600, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(mic_tlv, 1600, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
+
+static const unsigned int limiter_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
+       3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0),
+};
+
+static const char * const cs42l52_adca_text[] = {
+       "Input1A", "Input2A", "Input3A", "Input4A", "PGA Input Left"};
+
+static const char * const cs42l52_adcb_text[] = {
+       "Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"};
+
+static const struct soc_enum adca_enum =
+       SOC_ENUM_SINGLE(CS42L52_ADC_PGA_A, 5,
+               ARRAY_SIZE(cs42l52_adca_text), cs42l52_adca_text);
+
+static const struct soc_enum adcb_enum =
+       SOC_ENUM_SINGLE(CS42L52_ADC_PGA_B, 5,
+               ARRAY_SIZE(cs42l52_adcb_text), cs42l52_adcb_text);
+
+static const struct snd_kcontrol_new adca_mux =
+       SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum);
+
+static const struct snd_kcontrol_new adcb_mux =
+       SOC_DAPM_ENUM("Right ADC Input Capture Mux", adcb_enum);
+
+static const char * const mic_bias_level_text[] = {
+       "0.5 +VA", "0.6 +VA", "0.7 +VA",
+       "0.8 +VA", "0.83 +VA", "0.91 +VA"
+};
+
+static const struct soc_enum mic_bias_level_enum =
+       SOC_ENUM_SINGLE(CS42L52_IFACE_CTL1, 0,
+                       ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text);
+
+static const char * const cs42l52_mic_text[] = { "Single", "Differential" };
+
+static const struct soc_enum mica_enum =
+       SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5,
+                       ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
+
+static const struct soc_enum micb_enum =
+       SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5,
+                       ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
+
+static const struct snd_kcontrol_new mica_mux =
+       SOC_DAPM_ENUM("Left Mic Input Capture Mux", mica_enum);
+
+static const struct snd_kcontrol_new micb_mux =
+       SOC_DAPM_ENUM("Right Mic Input Capture Mux", micb_enum);
+
+static const char * const digital_output_mux_text[] = {"ADC", "DSP"};
+
+static const struct soc_enum digital_output_mux_enum =
+       SOC_ENUM_SINGLE(CS42L52_ADC_MISC_CTL, 6,
+                       ARRAY_SIZE(digital_output_mux_text),
+                       digital_output_mux_text);
+
+static const struct snd_kcontrol_new digital_output_mux =
+       SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum);
+
+static const char * const hp_gain_num_text[] = {
+       "0.3959", "0.4571", "0.5111", "0.6047",
+       "0.7099", "0.8399", "1.000", "1.1430"
+};
+
+static const struct soc_enum hp_gain_enum =
+       SOC_ENUM_SINGLE(CS42L52_PB_CTL1, 4,
+               ARRAY_SIZE(hp_gain_num_text), hp_gain_num_text);
+
+static const char * const beep_pitch_text[] = {
+       "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
+       "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
+};
+
+static const struct soc_enum beep_pitch_enum =
+       SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 4,
+                       ARRAY_SIZE(beep_pitch_text), beep_pitch_text);
+
+static const char * const beep_ontime_text[] = {
+       "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
+       "1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s",
+       "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
+};
+
+static const struct soc_enum beep_ontime_enum =
+       SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 0,
+                       ARRAY_SIZE(beep_ontime_text), beep_ontime_text);
+
+static const char * const beep_offtime_text[] = {
+       "1.23 s", "2.58 s", "3.90 s", "5.20 s",
+       "6.60 s", "8.05 s", "9.35 s", "10.80 s"
+};
+
+static const struct soc_enum beep_offtime_enum =
+       SOC_ENUM_SINGLE(CS42L52_BEEP_VOL, 5,
+                       ARRAY_SIZE(beep_offtime_text), beep_offtime_text);
+
+static const char * const beep_config_text[] = {
+       "Off", "Single", "Multiple", "Continuous"
+};
+
+static const struct soc_enum beep_config_enum =
+       SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 6,
+                       ARRAY_SIZE(beep_config_text), beep_config_text);
+
+static const char * const beep_bass_text[] = {
+       "50 Hz", "100 Hz", "200 Hz", "250 Hz"
+};
+
+static const struct soc_enum beep_bass_enum =
+       SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 1,
+                       ARRAY_SIZE(beep_bass_text), beep_bass_text);
+
+static const char * const beep_treble_text[] = {
+       "5 kHz", "7 kHz", "10 kHz", " 15 kHz"
+};
+
+static const struct soc_enum beep_treble_enum =
+       SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 3,
+                       ARRAY_SIZE(beep_treble_text), beep_treble_text);
+
+static const char * const ng_threshold_text[] = {
+       "-34dB", "-37dB", "-40dB", "-43dB",
+       "-46dB", "-52dB", "-58dB", "-64dB"
+};
+
+static const struct soc_enum ng_threshold_enum =
+       SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 2,
+               ARRAY_SIZE(ng_threshold_text), ng_threshold_text);
+
+static const char * const cs42l52_ng_delay_text[] = {
+       "50ms", "100ms", "150ms", "200ms"};
+
+static const struct soc_enum ng_delay_enum =
+       SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 0,
+               ARRAY_SIZE(cs42l52_ng_delay_text), cs42l52_ng_delay_text);
+
+static const char * const cs42l52_ng_type_text[] = {
+       "Apply Specific", "Apply All"
+};
+
+static const struct soc_enum ng_type_enum =
+       SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 6,
+               ARRAY_SIZE(cs42l52_ng_type_text), cs42l52_ng_type_text);
+
+static const char * const left_swap_text[] = {
+       "Left", "LR 2", "Right"};
+
+static const char * const right_swap_text[] = {
+       "Right", "LR 2", "Left"};
+
+static const unsigned int swap_values[] = { 0, 1, 3 };
+
+static const struct soc_enum adca_swap_enum =
+       SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 1,
+                             ARRAY_SIZE(left_swap_text),
+                             left_swap_text,
+                             swap_values);
+
+static const struct snd_kcontrol_new adca_mixer =
+       SOC_DAPM_ENUM("Route", adca_swap_enum);
+
+static const struct soc_enum pcma_swap_enum =
+       SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 1,
+                             ARRAY_SIZE(left_swap_text),
+                             left_swap_text,
+                             swap_values);
+
+static const struct snd_kcontrol_new pcma_mixer =
+       SOC_DAPM_ENUM("Route", pcma_swap_enum);
+
+static const struct soc_enum adcb_swap_enum =
+       SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 1,
+                             ARRAY_SIZE(right_swap_text),
+                             right_swap_text,
+                             swap_values);
+
+static const struct snd_kcontrol_new adcb_mixer =
+       SOC_DAPM_ENUM("Route", adcb_swap_enum);
+
+static const struct soc_enum pcmb_swap_enum =
+       SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 1,
+                             ARRAY_SIZE(right_swap_text),
+                             right_swap_text,
+                             swap_values);
+
+static const struct snd_kcontrol_new pcmb_mixer =
+       SOC_DAPM_ENUM("Route", pcmb_swap_enum);
+
+
+static const struct snd_kcontrol_new passthrul_ctl =
+       SOC_DAPM_SINGLE("Switch", CS42L52_MISC_CTL, 6, 1, 0);
+
+static const struct snd_kcontrol_new passthrur_ctl =
+       SOC_DAPM_SINGLE("Switch", CS42L52_MISC_CTL, 7, 1, 0);
+
+static const struct snd_kcontrol_new spkl_ctl =
+       SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 0, 1, 1);
+
+static const struct snd_kcontrol_new spkr_ctl =
+       SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 2, 1, 1);
+
+static const struct snd_kcontrol_new hpl_ctl =
+       SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 4, 1, 1);
+
+static const struct snd_kcontrol_new hpr_ctl =
+       SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 6, 1, 1);
+
+static const struct snd_kcontrol_new cs42l52_snd_controls[] = {
+
+       SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L52_MASTERA_VOL,
+                             CS42L52_MASTERB_VOL, 0, 0x34, 0xE4, hl_tlv),
+
+       SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L52_HPA_VOL,
+                             CS42L52_HPB_VOL, 0, 0x34, 0xCC, hpd_tlv),
+
+       SOC_ENUM("Headphone Analog Gain", hp_gain_enum),
+
+       SOC_DOUBLE_R_SX_TLV("Speaker Volume", CS42L52_SPKA_VOL,
+                             CS42L52_SPKB_VOL, 7, 0x1, 0xff, hl_tlv),
+
+       SOC_DOUBLE_R_SX_TLV("Bypass Volume", CS42L52_PASSTHRUA_VOL,
+                             CS42L52_PASSTHRUB_VOL, 6, 0x18, 0x90, pga_tlv),
+
+       SOC_DOUBLE("Bypass Mute", CS42L52_MISC_CTL, 4, 5, 1, 0),
+
+       SOC_DOUBLE_R_TLV("MIC Gain Volume", CS42L52_MICA_CTL,
+                             CS42L52_MICB_CTL, 0, 0x10, 0, mic_tlv),
+
+       SOC_ENUM("MIC Bias Level", mic_bias_level_enum),
+
+       SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L52_ADCA_VOL,
+                             CS42L52_ADCB_VOL, 7, 0x80, 0xA0, ipd_tlv),
+       SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
+                            CS42L52_ADCA_MIXER_VOL, CS42L52_ADCB_MIXER_VOL,
+                               6, 0x7f, 0x19, ipd_tlv),
+
+       SOC_DOUBLE("ADC Switch", CS42L52_ADC_MISC_CTL, 0, 1, 1, 0),
+
+       SOC_DOUBLE_R("ADC Mixer Switch", CS42L52_ADCA_MIXER_VOL,
+                    CS42L52_ADCB_MIXER_VOL, 7, 1, 1),
+
+       SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L52_PGAA_CTL,
+                           CS42L52_PGAB_CTL, 0, 0x28, 0x30, pga_tlv),
+
+       SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume",
+                           CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL,
+                               6, 0x7f, 0x19, hl_tlv),
+       SOC_DOUBLE_R("PCM Mixer Switch",
+                    CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL, 7, 1, 1),
+
+       SOC_ENUM("Beep Config", beep_config_enum),
+       SOC_ENUM("Beep Pitch", beep_pitch_enum),
+       SOC_ENUM("Beep on Time", beep_ontime_enum),
+       SOC_ENUM("Beep off Time", beep_offtime_enum),
+       SOC_SINGLE_TLV("Beep Volume", CS42L52_BEEP_VOL, 0, 0x1f, 0x07, hl_tlv),
+       SOC_SINGLE("Beep Mixer Switch", CS42L52_BEEP_TONE_CTL, 5, 1, 1),
+       SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
+       SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
+
+       SOC_SINGLE("Tone Control Switch", CS42L52_BEEP_TONE_CTL, 0, 1, 1),
+       SOC_SINGLE_TLV("Treble Gain Volume",
+                           CS42L52_TONE_CTL, 4, 15, 1, hl_tlv),
+       SOC_SINGLE_TLV("Bass Gain Volume",
+                           CS42L52_TONE_CTL, 0, 15, 1, hl_tlv),
+
+       /* Limiter */
+       SOC_SINGLE_TLV("Limiter Max Threshold Volume",
+                      CS42L52_LIMITER_CTL1, 5, 7, 0, limiter_tlv),
+       SOC_SINGLE_TLV("Limiter Cushion Threshold Volume",
+                      CS42L52_LIMITER_CTL1, 2, 7, 0, limiter_tlv),
+       SOC_SINGLE_TLV("Limiter Release Rate Volume",
+                      CS42L52_LIMITER_CTL2, 0, 63, 0, limiter_tlv),
+       SOC_SINGLE_TLV("Limiter Attack Rate Volume",
+                      CS42L52_LIMITER_AT_RATE, 0, 63, 0, limiter_tlv),
+
+       SOC_SINGLE("Limiter SR Switch", CS42L52_LIMITER_CTL1, 1, 1, 0),
+       SOC_SINGLE("Limiter ZC Switch", CS42L52_LIMITER_CTL1, 0, 1, 0),
+       SOC_SINGLE("Limiter Switch", CS42L52_LIMITER_CTL2, 7, 1, 0),
+
+       /* ALC */
+       SOC_SINGLE_TLV("ALC Attack Rate Volume", CS42L52_ALC_CTL,
+                      0, 63, 0, limiter_tlv),
+       SOC_SINGLE_TLV("ALC Release Rate Volume", CS42L52_ALC_RATE,
+                      0, 63, 0, limiter_tlv),
+       SOC_SINGLE_TLV("ALC Max Threshold Volume", CS42L52_ALC_THRESHOLD,
+                      5, 7, 0, limiter_tlv),
+       SOC_SINGLE_TLV("ALC Min Threshold Volume", CS42L52_ALC_THRESHOLD,
+                      2, 7, 0, limiter_tlv),
+
+       SOC_DOUBLE_R("ALC SR Capture Switch", CS42L52_PGAA_CTL,
+                    CS42L52_PGAB_CTL, 7, 1, 1),
+       SOC_DOUBLE_R("ALC ZC Capture Switch", CS42L52_PGAA_CTL,
+                    CS42L52_PGAB_CTL, 6, 1, 1),
+       SOC_DOUBLE("ALC Capture Switch", CS42L52_ALC_CTL, 6, 7, 1, 0),
+
+       /* Noise gate */
+       SOC_ENUM("NG Type Switch", ng_type_enum),
+       SOC_SINGLE("NG Enable Switch", CS42L52_NOISE_GATE_CTL, 6, 1, 0),
+       SOC_SINGLE("NG Boost Switch", CS42L52_NOISE_GATE_CTL, 5, 1, 1),
+       SOC_ENUM("NG Threshold", ng_threshold_enum),
+       SOC_ENUM("NG Delay", ng_delay_enum),
+
+       SOC_DOUBLE("HPF Switch", CS42L52_ANALOG_HPF_CTL, 5, 7, 1, 0),
+
+       SOC_DOUBLE("Analog SR Switch", CS42L52_ANALOG_HPF_CTL, 1, 3, 1, 1),
+       SOC_DOUBLE("Analog ZC Switch", CS42L52_ANALOG_HPF_CTL, 0, 2, 1, 1),
+       SOC_SINGLE("Digital SR Switch", CS42L52_MISC_CTL, 1, 1, 0),
+       SOC_SINGLE("Digital ZC Switch", CS42L52_MISC_CTL, 0, 1, 0),
+       SOC_SINGLE("Deemphasis Switch", CS42L52_MISC_CTL, 2, 1, 0),
+
+       SOC_SINGLE("Batt Compensation Switch", CS42L52_BATT_COMPEN, 7, 1, 0),
+       SOC_SINGLE("Batt VP Monitor Switch", CS42L52_BATT_COMPEN, 6, 1, 0),
+       SOC_SINGLE("Batt VP ref", CS42L52_BATT_COMPEN, 0, 0x0f, 0),
+
+       SOC_SINGLE("PGA AIN1L Switch", CS42L52_ADC_PGA_A, 0, 1, 0),
+       SOC_SINGLE("PGA AIN1R Switch", CS42L52_ADC_PGA_B, 0, 1, 0),
+       SOC_SINGLE("PGA AIN2L Switch", CS42L52_ADC_PGA_A, 1, 1, 0),
+       SOC_SINGLE("PGA AIN2R Switch", CS42L52_ADC_PGA_B, 1, 1, 0),
+
+       SOC_SINGLE("PGA AIN3L Switch", CS42L52_ADC_PGA_A, 2, 1, 0),
+       SOC_SINGLE("PGA AIN3R Switch", CS42L52_ADC_PGA_B, 2, 1, 0),
+
+       SOC_SINGLE("PGA AIN4L Switch", CS42L52_ADC_PGA_A, 3, 1, 0),
+       SOC_SINGLE("PGA AIN4R Switch", CS42L52_ADC_PGA_B, 3, 1, 0),
+
+       SOC_SINGLE("PGA MICA Switch", CS42L52_ADC_PGA_A, 4, 1, 0),
+       SOC_SINGLE("PGA MICB Switch", CS42L52_ADC_PGA_B, 4, 1, 0),
+
+};
+
+static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
+
+       SND_SOC_DAPM_INPUT("AIN1L"),
+       SND_SOC_DAPM_INPUT("AIN1R"),
+       SND_SOC_DAPM_INPUT("AIN2L"),
+       SND_SOC_DAPM_INPUT("AIN2R"),
+       SND_SOC_DAPM_INPUT("AIN3L"),
+       SND_SOC_DAPM_INPUT("AIN3R"),
+       SND_SOC_DAPM_INPUT("AIN4L"),
+       SND_SOC_DAPM_INPUT("AIN4R"),
+       SND_SOC_DAPM_INPUT("MICA"),
+       SND_SOC_DAPM_INPUT("MICB"),
+       SND_SOC_DAPM_SIGGEN("Beep"),
+
+       SND_SOC_DAPM_AIF_OUT("AIFOUTL", NULL,  0,
+                       SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIFOUTR", NULL,  0,
+                       SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_MUX("MICA Mux", SND_SOC_NOPM, 0, 0, &mica_mux),
+       SND_SOC_DAPM_MUX("MICB Mux", SND_SOC_NOPM, 0, 0, &micb_mux),
+
+       SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L52_PWRCTL1, 1, 1),
+       SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L52_PWRCTL1, 2, 1),
+       SND_SOC_DAPM_PGA("PGA Left", CS42L52_PWRCTL1, 3, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("PGA Right", CS42L52_PWRCTL1, 4, 1, NULL, 0),
+
+       SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adca_mux),
+       SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcb_mux),
+
+       SND_SOC_DAPM_MUX("ADC Left Swap", SND_SOC_NOPM,
+                        0, 0, &adca_mixer),
+       SND_SOC_DAPM_MUX("ADC Right Swap", SND_SOC_NOPM,
+                        0, 0, &adcb_mixer),
+
+       SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM,
+                        0, 0, &digital_output_mux),
+
+       SND_SOC_DAPM_PGA("PGA MICA", CS42L52_PWRCTL2, 1, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("PGA MICB", CS42L52_PWRCTL2, 2, 1, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("Mic Bias", CS42L52_PWRCTL2, 0, 1, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L52_PWRCTL1, 7, 1, NULL, 0),
+
+       SND_SOC_DAPM_AIF_IN("AIFINL", NULL,  0,
+                       SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIFINR", NULL,  0,
+                       SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_DAC("DAC Left", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC Right", NULL, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_SWITCH("Bypass Left", CS42L52_MISC_CTL,
+                           6, 0, &passthrul_ctl),
+       SND_SOC_DAPM_SWITCH("Bypass Right", CS42L52_MISC_CTL,
+                           7, 0, &passthrur_ctl),
+
+       SND_SOC_DAPM_MUX("PCM Left Swap", SND_SOC_NOPM,
+                        0, 0, &pcma_mixer),
+       SND_SOC_DAPM_MUX("PCM Right Swap", SND_SOC_NOPM,
+                        0, 0, &pcmb_mixer),
+
+       SND_SOC_DAPM_SWITCH("HP Left Amp", SND_SOC_NOPM, 0, 0, &hpl_ctl),
+       SND_SOC_DAPM_SWITCH("HP Right Amp", SND_SOC_NOPM, 0, 0, &hpr_ctl),
+
+       SND_SOC_DAPM_SWITCH("SPK Left Amp", SND_SOC_NOPM, 0, 0, &spkl_ctl),
+       SND_SOC_DAPM_SWITCH("SPK Right Amp", SND_SOC_NOPM, 0, 0, &spkr_ctl),
+
+       SND_SOC_DAPM_OUTPUT("HPOUTA"),
+       SND_SOC_DAPM_OUTPUT("HPOUTB"),
+       SND_SOC_DAPM_OUTPUT("SPKOUTA"),
+       SND_SOC_DAPM_OUTPUT("SPKOUTB"),
+
+};
+
+static const struct snd_soc_dapm_route cs42l52_audio_map[] = {
+
+       {"Capture", NULL, "AIFOUTL"},
+       {"Capture", NULL, "AIFOUTL"},
+
+       {"AIFOUTL", NULL, "Output Mux"},
+       {"AIFOUTR", NULL, "Output Mux"},
+
+       {"Output Mux", "ADC", "ADC Left"},
+       {"Output Mux", "ADC", "ADC Right"},
+
+       {"ADC Left", NULL, "Charge Pump"},
+       {"ADC Right", NULL, "Charge Pump"},
+
+       {"Charge Pump", NULL, "ADC Left Mux"},
+       {"Charge Pump", NULL, "ADC Right Mux"},
+
+       {"ADC Left Mux", "Input1A", "AIN1L"},
+       {"ADC Right Mux", "Input1B", "AIN1R"},
+       {"ADC Left Mux", "Input2A", "AIN2L"},
+       {"ADC Right Mux", "Input2B", "AIN2R"},
+       {"ADC Left Mux", "Input3A", "AIN3L"},
+       {"ADC Right Mux", "Input3B", "AIN3R"},
+       {"ADC Left Mux", "Input4A", "AIN4L"},
+       {"ADC Right Mux", "Input4B", "AIN4R"},
+       {"ADC Left Mux", "PGA Input Left", "PGA Left"},
+       {"ADC Right Mux", "PGA Input Right" , "PGA Right"},
+
+       {"PGA Left", "Switch", "AIN1L"},
+       {"PGA Right", "Switch", "AIN1R"},
+       {"PGA Left", "Switch", "AIN2L"},
+       {"PGA Right", "Switch", "AIN2R"},
+       {"PGA Left", "Switch", "AIN3L"},
+       {"PGA Right", "Switch", "AIN3R"},
+       {"PGA Left", "Switch", "AIN4L"},
+       {"PGA Right", "Switch", "AIN4R"},
+
+       {"PGA Left", "Switch", "PGA MICA"},
+       {"PGA MICA", NULL, "MICA"},
+
+       {"PGA Right", "Switch", "PGA MICB"},
+       {"PGA MICB", NULL, "MICB"},
+
+       {"HPOUTA", NULL, "HP Left Amp"},
+       {"HPOUTB", NULL, "HP Right Amp"},
+       {"HP Left Amp", NULL, "Bypass Left"},
+       {"HP Right Amp", NULL, "Bypass Right"},
+       {"Bypass Left", "Switch", "PGA Left"},
+       {"Bypass Right", "Switch", "PGA Right"},
+       {"HP Left Amp", "Switch", "DAC Left"},
+       {"HP Right Amp", "Switch", "DAC Right"},
+
+       {"SPKOUTA", NULL, "SPK Left Amp"},
+       {"SPKOUTB", NULL, "SPK Right Amp"},
+
+       {"SPK Left Amp", NULL, "Beep"},
+       {"SPK Right Amp", NULL, "Beep"},
+       {"SPK Left Amp", "Switch", "Playback"},
+       {"SPK Right Amp", "Switch", "Playback"},
+
+       {"DAC Left", NULL, "Beep"},
+       {"DAC Right", NULL, "Beep"},
+       {"DAC Left", NULL, "Playback"},
+       {"DAC Right", NULL, "Playback"},
+
+       {"Output Mux", "DSP", "Playback"},
+       {"Output Mux", "DSP", "Playback"},
+
+       {"AIFINL", NULL, "Playback"},
+       {"AIFINR", NULL, "Playback"},
+
+};
+
+struct cs42l52_clk_para {
+       u32 mclk;
+       u32 rate;
+       u8 speed;
+       u8 group;
+       u8 videoclk;
+       u8 ratio;
+       u8 mclkdiv2;
+};
+
+static const struct cs42l52_clk_para clk_map_table[] = {
+       /*8k*/
+       {12288000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+       {18432000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+       {12000000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
+       {24000000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
+       {27000000, 8000, CLK_QS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 0},
+
+       /*11.025k*/
+       {11289600, 11025, CLK_QS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+       {16934400, 11025, CLK_QS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+       /*16k*/
+       {12288000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+       {18432000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+       {12000000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
+       {24000000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
+       {27000000, 16000, CLK_HS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 1},
+
+       /*22.05k*/
+       {11289600, 22050, CLK_HS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+       {16934400, 22050, CLK_HS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+       /* 32k */
+       {12288000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+       {18432000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+       {12000000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
+       {24000000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
+       {27000000, 32000, CLK_SS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 0},
+
+       /* 44.1k */
+       {11289600, 44100, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+       {16934400, 44100, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+       /* 48k */
+       {12288000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+       {18432000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+       {12000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 0},
+       {24000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 1},
+       {27000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_27M_MCLK, CLK_R_125, 1},
+
+       /* 88.2k */
+       {11289600, 88200, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+       {16934400, 88200, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+       /* 96k */
+       {12288000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+       {18432000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+       {12000000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 0},
+       {24000000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 1},
+};
+
+static int cs42l52_get_clk(int mclk, int rate)
+{
+       int i, ret = 0;
+       u_int mclk1, mclk2 = 0;
+
+       for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
+               if (clk_map_table[i].rate == rate) {
+                       mclk1 = clk_map_table[i].mclk;
+                       if (abs(mclk - mclk1) < abs(mclk - mclk2)) {
+                               mclk2 = mclk1;
+                               ret = i;
+                       }
+               }
+       }
+       if (ret > ARRAY_SIZE(clk_map_table))
+               return -EINVAL;
+       return ret;
+}
+
+static int cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
+                       int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+
+       if ((freq >= CS42L52_MIN_CLK) && (freq <= CS42L52_MAX_CLK)) {
+               cs42l52->sysclk = freq;
+       } else {
+               dev_err(codec->dev, "Invalid freq paramter\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int cs42l52_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+       u8 iface = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               iface = CS42L52_IFACE_CTL1_MASTER;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               iface = CS42L52_IFACE_CTL1_SLAVE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+        /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= CS42L52_IFACE_CTL1_ADC_FMT_I2S |
+                               CS42L52_IFACE_CTL1_DAC_FMT_I2S;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               iface |= CS42L52_IFACE_CTL1_DAC_FMT_RIGHT_J;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface |= CS42L52_IFACE_CTL1_ADC_FMT_LEFT_J |
+                               CS42L52_IFACE_CTL1_DAC_FMT_LEFT_J;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface |= CS42L52_IFACE_CTL1_DSP_MODE_EN;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               iface |= CS42L52_IFACE_CTL1_INV_SCLK;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               iface |= CS42L52_IFACE_CTL1_INV_SCLK;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       cs42l52->config.format = iface;
+       snd_soc_write(codec, CS42L52_IFACE_CTL1, cs42l52->config.format);
+
+       return 0;
+}
+
+static int cs42l52_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       if (mute)
+               snd_soc_update_bits(codec, CS42L52_PB_CTL1,
+                                   CS42L52_PB_CTL1_MUTE_MASK,
+                               CS42L52_PB_CTL1_MUTE);
+       else
+               snd_soc_update_bits(codec, CS42L52_PB_CTL1,
+                                   CS42L52_PB_CTL1_MUTE_MASK,
+                               CS42L52_PB_CTL1_UNMUTE);
+
+       return 0;
+}
+
+static int cs42l52_pcm_hw_params(struct snd_pcm_substream *substream,
+                                    struct snd_pcm_hw_params *params,
+                                    struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+       u32 clk = 0;
+       int index;
+
+       index = cs42l52_get_clk(cs42l52->sysclk, params_rate(params));
+       if (index >= 0) {
+               cs42l52->sysclk = clk_map_table[index].mclk;
+
+               clk |= (clk_map_table[index].speed << CLK_SPEED_SHIFT) |
+               (clk_map_table[index].group << CLK_32K_SR_SHIFT) |
+               (clk_map_table[index].videoclk << CLK_27M_MCLK_SHIFT) |
+               (clk_map_table[index].ratio << CLK_RATIO_SHIFT) |
+               clk_map_table[index].mclkdiv2;
+
+               snd_soc_write(codec, CS42L52_CLK_CTL, clk);
+       } else {
+               dev_err(codec->dev, "can't get correct mclk\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cs42l52_set_bias_level(struct snd_soc_codec *codec,
+                                       enum snd_soc_bias_level level)
+{
+       struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               snd_soc_update_bits(codec, CS42L52_PWRCTL1,
+                                   CS42L52_PWRCTL1_PDN_CODEC, 0);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       regcache_cache_only(cs42l52->regmap, false);
+                       regcache_sync(cs42l52->regmap);
+               }
+               snd_soc_write(codec, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
+               break;
+       case SND_SOC_BIAS_OFF:
+               snd_soc_write(codec, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
+               regcache_cache_only(cs42l52->regmap, true);
+               break;
+       }
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+#define CS42L52_RATES (SNDRV_PCM_RATE_8000_96000)
+
+#define CS42L52_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
+                       SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \
+                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
+
+static struct snd_soc_dai_ops cs42l52_ops = {
+       .hw_params      = cs42l52_pcm_hw_params,
+       .digital_mute   = cs42l52_digital_mute,
+       .set_fmt        = cs42l52_set_fmt,
+       .set_sysclk     = cs42l52_set_sysclk,
+};
+
+static struct snd_soc_dai_driver cs42l52_dai = {
+               .name = "cs42l52",
+               .playback = {
+                       .stream_name = "Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = CS42L52_RATES,
+                       .formats = CS42L52_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = CS42L52_RATES,
+                       .formats = CS42L52_FORMATS,
+               },
+               .ops = &cs42l52_ops,
+};
+
+static int cs42l52_suspend(struct snd_soc_codec *codec)
+{
+       cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int cs42l52_resume(struct snd_soc_codec *codec)
+{
+       cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+static int beep_rates[] = {
+       261, 522, 585, 667, 706, 774, 889, 1000,
+       1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
+};
+
+static void cs42l52_beep_work(struct work_struct *work)
+{
+       struct cs42l52_private *cs42l52 =
+               container_of(work, struct cs42l52_private, beep_work);
+       struct snd_soc_codec *codec = cs42l52->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int i;
+       int val = 0;
+       int best = 0;
+
+       if (cs42l52->beep_rate) {
+               for (i = 0; i < ARRAY_SIZE(beep_rates); i++) {
+                       if (abs(cs42l52->beep_rate - beep_rates[i]) <
+                           abs(cs42l52->beep_rate - beep_rates[best]))
+                               best = i;
+               }
+
+               dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
+                       beep_rates[best], cs42l52->beep_rate);
+
+               val = (best << CS42L52_BEEP_RATE_SHIFT);
+
+               snd_soc_dapm_enable_pin(dapm, "Beep");
+       } else {
+               dev_dbg(codec->dev, "Disabling beep\n");
+               snd_soc_dapm_disable_pin(dapm, "Beep");
+       }
+
+       snd_soc_update_bits(codec, CS42L52_BEEP_FREQ,
+                           CS42L52_BEEP_RATE_MASK, val);
+
+       snd_soc_dapm_sync(dapm);
+}
+
+/* For usability define a way of injecting beep events for the device -
+ * many systems will not have a keyboard.
+ */
+static int cs42l52_beep_event(struct input_dev *dev, unsigned int type,
+                            unsigned int code, int hz)
+{
+       struct snd_soc_codec *codec = input_get_drvdata(dev);
+       struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
+
+       switch (code) {
+       case SND_BELL:
+               if (hz)
+                       hz = 261;
+       case SND_TONE:
+               break;
+       default:
+               return -1;
+       }
+
+       /* Kick the beep from a workqueue */
+       cs42l52->beep_rate = hz;
+       schedule_work(&cs42l52->beep_work);
+       return 0;
+}
+
+static ssize_t cs42l52_beep_set(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct cs42l52_private *cs42l52 = dev_get_drvdata(dev);
+       long int time;
+       int ret;
+
+       ret = kstrtol(buf, 10, &time);
+       if (ret != 0)
+               return ret;
+
+       input_event(cs42l52->beep, EV_SND, SND_TONE, time);
+
+       return count;
+}
+
+static DEVICE_ATTR(beep, 0200, NULL, cs42l52_beep_set);
+
+static void cs42l52_init_beep(struct snd_soc_codec *codec)
+{
+       struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       cs42l52->beep = input_allocate_device();
+       if (!cs42l52->beep) {
+               dev_err(codec->dev, "Failed to allocate beep device\n");
+               return;
+       }
+
+       INIT_WORK(&cs42l52->beep_work, cs42l52_beep_work);
+       cs42l52->beep_rate = 0;
+
+       cs42l52->beep->name = "CS42L52 Beep Generator";
+       cs42l52->beep->phys = dev_name(codec->dev);
+       cs42l52->beep->id.bustype = BUS_I2C;
+
+       cs42l52->beep->evbit[0] = BIT_MASK(EV_SND);
+       cs42l52->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+       cs42l52->beep->event = cs42l52_beep_event;
+       cs42l52->beep->dev.parent = codec->dev;
+       input_set_drvdata(cs42l52->beep, codec);
+
+       ret = input_register_device(cs42l52->beep);
+       if (ret != 0) {
+               input_free_device(cs42l52->beep);
+               cs42l52->beep = NULL;
+               dev_err(codec->dev, "Failed to register beep device\n");
+       }
+
+       ret = device_create_file(codec->dev, &dev_attr_beep);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to create keyclick file: %d\n",
+                       ret);
+       }
+}
+
+static void cs42l52_free_beep(struct snd_soc_codec *codec)
+{
+       struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+
+       device_remove_file(codec->dev, &dev_attr_beep);
+       input_unregister_device(cs42l52->beep);
+       cancel_work_sync(&cs42l52->beep_work);
+       cs42l52->beep = NULL;
+
+       snd_soc_update_bits(codec, CS42L52_BEEP_TONE_CTL,
+                           CS42L52_BEEP_EN_MASK, 0);
+}
+#else
+static void cs42l52_init_beep(struct snd_soc_codec *codec)
+{
+}
+
+static void cs42l52_free_beep(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+static int cs42l52_probe(struct snd_soc_codec *codec)
+{
+       struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       codec->control_data = cs42l52->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+       regcache_cache_only(cs42l52->regmap, true);
+
+       cs42l52_init_beep(codec);
+
+       cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       cs42l52->sysclk = CS42L52_DEFAULT_CLK;
+       cs42l52->config.format = CS42L52_DEFAULT_FORMAT;
+
+       /* Set Platform MICx CFG */
+       snd_soc_update_bits(codec, CS42L52_MICA_CTL,
+                           CS42L52_MIC_CTL_TYPE_MASK,
+                               cs42l52->pdata.mica_cfg <<
+                               CS42L52_MIC_CTL_TYPE_SHIFT);
+
+       snd_soc_update_bits(codec, CS42L52_MICB_CTL,
+                           CS42L52_MIC_CTL_TYPE_MASK,
+                               cs42l52->pdata.micb_cfg <<
+                               CS42L52_MIC_CTL_TYPE_SHIFT);
+
+       /* if Single Ended, Get Mic_Select */
+       if (cs42l52->pdata.mica_cfg)
+               snd_soc_update_bits(codec, CS42L52_MICA_CTL,
+                                   CS42L52_MIC_CTL_MIC_SEL_MASK,
+                               cs42l52->pdata.mica_sel <<
+                               CS42L52_MIC_CTL_MIC_SEL_SHIFT);
+       if (cs42l52->pdata.micb_cfg)
+               snd_soc_update_bits(codec, CS42L52_MICB_CTL,
+                                   CS42L52_MIC_CTL_MIC_SEL_MASK,
+                               cs42l52->pdata.micb_sel <<
+                               CS42L52_MIC_CTL_MIC_SEL_SHIFT);
+
+       /* Set Platform Charge Pump Freq */
+       snd_soc_update_bits(codec, CS42L52_CHARGE_PUMP,
+                           CS42L52_CHARGE_PUMP_MASK,
+                               cs42l52->pdata.chgfreq <<
+                               CS42L52_CHARGE_PUMP_SHIFT);
+
+       /* Set Platform Bias Level */
+       snd_soc_update_bits(codec, CS42L52_IFACE_CTL2,
+                           CS42L52_IFACE_CTL2_BIAS_LVL,
+                               cs42l52->pdata.micbias_lvl);
+
+       return ret;
+}
+
+static int cs42l52_remove(struct snd_soc_codec *codec)
+{
+       cs42l52_free_beep(codec);
+       cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
+       .probe = cs42l52_probe,
+       .remove = cs42l52_remove,
+       .suspend = cs42l52_suspend,
+       .resume = cs42l52_resume,
+       .set_bias_level = cs42l52_set_bias_level,
+
+       .dapm_widgets = cs42l52_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets),
+       .dapm_routes = cs42l52_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(cs42l52_audio_map),
+
+       .controls = cs42l52_snd_controls,
+       .num_controls = ARRAY_SIZE(cs42l52_snd_controls),
+};
+
+/* Current and threshold powerup sequence Pg37 */
+static const struct reg_default cs42l52_threshold_patch[] = {
+
+       { 0x00, 0x99 },
+       { 0x3E, 0xBA },
+       { 0x47, 0x80 },
+       { 0x32, 0xBB },
+       { 0x32, 0x3B },
+       { 0x00, 0x00 },
+
+};
+
+static struct regmap_config cs42l52_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = CS42L52_MAX_REGISTER,
+       .reg_defaults = cs42l52_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(cs42l52_reg_defaults),
+       .readable_reg = cs42l52_readable_register,
+       .volatile_reg = cs42l52_volatile_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
+                            const struct i2c_device_id *id)
+{
+       struct cs42l52_private *cs42l52;
+       int ret;
+       unsigned int devid = 0;
+       unsigned int reg;
+
+       cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l52_private),
+                              GFP_KERNEL);
+       if (cs42l52 == NULL)
+               return -ENOMEM;
+       cs42l52->dev = &i2c_client->dev;
+
+       cs42l52->regmap = regmap_init_i2c(i2c_client, &cs42l52_regmap);
+       if (IS_ERR(cs42l52->regmap)) {
+               ret = PTR_ERR(cs42l52->regmap);
+               dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+               goto err;
+       }
+
+       i2c_set_clientdata(i2c_client, cs42l52);
+
+       if (dev_get_platdata(&i2c_client->dev))
+               memcpy(&cs42l52->pdata, dev_get_platdata(&i2c_client->dev),
+                      sizeof(cs42l52->pdata));
+
+       ret = regmap_register_patch(cs42l52->regmap, cs42l52_threshold_patch,
+                                   ARRAY_SIZE(cs42l52_threshold_patch));
+       if (ret != 0)
+               dev_warn(cs42l52->dev, "Failed to apply regmap patch: %d\n",
+                        ret);
+
+       ret = regmap_read(cs42l52->regmap, CS42L52_CHIP, &reg);
+       devid = reg & CS42L52_CHIP_ID_MASK;
+       if (devid != CS42L52_CHIP_ID) {
+               ret = -ENODEV;
+               dev_err(&i2c_client->dev,
+                       "CS42L52 Device ID (%X). Expected %X\n",
+                       devid, CS42L52_CHIP_ID);
+               goto err_regmap;
+       }
+
+       regcache_cache_only(cs42l52->regmap, true);
+
+       ret =  snd_soc_register_codec(&i2c_client->dev,
+                       &soc_codec_dev_cs42l52, &cs42l52_dai, 1);
+       if (ret < 0)
+               goto err_regmap;
+       return 0;
+
+err_regmap:
+       regmap_exit(cs42l52->regmap);
+
+err:
+       return ret;
+}
+
+static int cs42l52_i2c_remove(struct i2c_client *client)
+{
+       struct cs42l52_private *cs42l52 = i2c_get_clientdata(client);
+
+       snd_soc_unregister_codec(&client->dev);
+       regmap_exit(cs42l52->regmap);
+
+       return 0;
+}
+
+static const struct i2c_device_id cs42l52_id[] = {
+       { "cs42l52", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, cs42l52_id);
+
+static struct i2c_driver cs42l52_i2c_driver = {
+       .driver = {
+               .name = "cs42l52",
+               .owner = THIS_MODULE,
+       },
+       .id_table = cs42l52_id,
+       .probe =    cs42l52_i2c_probe,
+       .remove =   __devexit_p(cs42l52_i2c_remove),
+};
+
+module_i2c_driver(cs42l52_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L52 driver");
+MODULE_AUTHOR("Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l52.h b/sound/soc/codecs/cs42l52.h
new file mode 100644 (file)
index 0000000..60985c0
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * cs42l52.h -- CS42L52 ALSA SoC audio driver
+ *
+ * Copyright 2012 CirrusLogic, Inc.
+ *
+ * Author: Georgi Vlaev <joe@nucleusys.com>
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS42L52_H__
+#define __CS42L52_H__
+
+#define CS42L52_NAME                           "CS42L52"
+#define CS42L52_DEFAULT_CLK                    12000000
+#define CS42L52_MIN_CLK                                11000000
+#define CS42L52_MAX_CLK                                27000000
+#define CS42L52_DEFAULT_FORMAT                 SNDRV_PCM_FMTBIT_S16_LE
+#define CS42L52_DEFAULT_MAX_CHANS              2
+#define CS42L52_SYSCLK                         1
+
+#define CS42L52_CHIP_SWICTH                    (1 << 17)
+#define CS42L52_ALL_IN_ONE                     (1 << 16)
+#define CS42L52_CHIP_ONE                       0x00
+#define CS42L52_CHIP_TWO                       0x01
+#define CS42L52_CHIP_THR                       0x02
+#define CS42L52_CHIP_MASK                      0x0f
+
+#define CS42L52_FIX_BITS_CTL                   0x00
+#define CS42L52_CHIP                           0x01
+#define CS42L52_CHIP_ID                                0xE0
+#define CS42L52_CHIP_ID_MASK                   0xF8
+#define CS42L52_CHIP_REV_A0                    0x00
+#define CS42L52_CHIP_REV_A1                    0x01
+#define CS42L52_CHIP_REV_B0                    0x02
+#define CS42L52_CHIP_REV_MASK                  0x03
+
+#define CS42L52_PWRCTL1                                0x02
+#define CS42L52_PWRCTL1_PDN_ALL                        0x9F
+#define CS42L52_PWRCTL1_PDN_CHRG               0x80
+#define CS42L52_PWRCTL1_PDN_PGAB               0x10
+#define CS42L52_PWRCTL1_PDN_PGAA               0x08
+#define CS42L52_PWRCTL1_PDN_ADCB               0x04
+#define CS42L52_PWRCTL1_PDN_ADCA               0x02
+#define CS42L52_PWRCTL1_PDN_CODEC              0x01
+
+#define CS42L52_PWRCTL2                                0x03
+#define CS42L52_PWRCTL2_OVRDB                  (1 << 4)
+#define CS42L52_PWRCTL2_OVRDA                  (1 << 3)
+#define        CS42L52_PWRCTL2_PDN_MICB                (1 << 2)
+#define CS42L52_PWRCTL2_PDN_MICB_SHIFT         2
+#define CS42L52_PWRCTL2_PDN_MICA               (1 << 1)
+#define CS42L52_PWRCTL2_PDN_MICA_SHIFT         1
+#define CS42L52_PWRCTL2_PDN_MICBIAS            (1 << 0)
+#define CS42L52_PWRCTL2_PDN_MICBIAS_SHIFT      0
+
+#define CS42L52_PWRCTL3                                0x04
+#define CS42L52_PWRCTL3_HPB_PDN_SHIFT          6
+#define CS42L52_PWRCTL3_HPB_ON_LOW             0x00
+#define CS42L52_PWRCTL3_HPB_ON_HIGH            0x01
+#define CS42L52_PWRCTL3_HPB_ALWAYS_ON          0x02
+#define CS42L52_PWRCTL3_HPB_ALWAYS_OFF         0x03
+#define CS42L52_PWRCTL3_HPA_PDN_SHIFT          4
+#define CS42L52_PWRCTL3_HPA_ON_LOW             0x00
+#define CS42L52_PWRCTL3_HPA_ON_HIGH            0x01
+#define CS42L52_PWRCTL3_HPA_ALWAYS_ON          0x02
+#define CS42L52_PWRCTL3_HPA_ALWAYS_OFF         0x03
+#define CS42L52_PWRCTL3_SPKB_PDN_SHIFT         2
+#define CS42L52_PWRCTL3_SPKB_ON_LOW            0x00
+#define CS42L52_PWRCTL3_SPKB_ON_HIGH           0x01
+#define CS42L52_PWRCTL3_SPKB_ALWAYS_ON         0x02
+#define CS42L52_PWRCTL3_PDN_SPKB               (1 << 2)
+#define CS42L52_PWRCTL3_PDN_SPKA               (1 << 0)
+#define CS42L52_PWRCTL3_SPKA_PDN_SHIFT         0
+#define CS42L52_PWRCTL3_SPKA_ON_LOW            0x00
+#define CS42L52_PWRCTL3_SPKA_ON_HIGH           0x01
+#define CS42L52_PWRCTL3_SPKA_ALWAYS_ON         0x02
+
+#define CS42L52_DEFAULT_OUTPUT_STATE           0x05
+#define CS42L52_PWRCTL3_CONF_MASK              0x03
+
+#define CS42L52_CLK_CTL                                0x05
+#define CLK_AUTODECT_ENABLE                    (1 << 7)
+#define CLK_SPEED_SHIFT                                5
+#define CLK_DS_MODE                            0x00
+#define CLK_SS_MODE                            0x01
+#define CLK_HS_MODE                            0x02
+#define CLK_QS_MODE                            0x03
+#define CLK_32K_SR_SHIFT                       4
+#define CLK_32K                                        0x01
+#define CLK_NO_32K                             0x00
+#define CLK_27M_MCLK_SHIFT                     3
+#define CLK_27M_MCLK                           0x01
+#define CLK_NO_27M                             0x00
+#define CLK_RATIO_SHIFT                                1
+#define CLK_R_128                              0x00
+#define CLK_R_125                              0x01
+#define CLK_R_132                              0x02
+#define CLK_R_136                              0x03
+
+#define CS42L52_IFACE_CTL1                     0x06
+#define CS42L52_IFACE_CTL1_MASTER              (1 << 7)
+#define CS42L52_IFACE_CTL1_SLAVE               (0 << 7)
+#define CS42L52_IFACE_CTL1_INV_SCLK            (1 << 6)
+#define CS42L52_IFACE_CTL1_ADC_FMT_I2S         (1 << 5)
+#define CS42L52_IFACE_CTL1_ADC_FMT_LEFT_J      (0 << 5)
+#define CS42L52_IFACE_CTL1_DSP_MODE_EN         (1 << 4)
+#define CS42L52_IFACE_CTL1_DAC_FMT_LEFT_J      (0 << 2)
+#define CS42L52_IFACE_CTL1_DAC_FMT_I2S         (1 << 2)
+#define CS42L52_IFACE_CTL1_DAC_FMT_RIGHT_J     (2 << 2)
+#define CS42L52_IFACE_CTL1_WL_32BIT            (0x00)
+#define CS42L52_IFACE_CTL1_WL_24BIT            (0x01)
+#define CS42L52_IFACE_CTL1_WL_20BIT            (0x02)
+#define CS42L52_IFACE_CTL1_WL_16BIT            (0x03)
+#define CS42L52_IFACE_CTL1_WL_MASK             0xFFFF
+
+#define CS42L52_IFACE_CTL2                     0x07
+#define CS42L52_IFACE_CTL2_SC_MC_EQ            (1 << 6)
+#define CS42L52_IFACE_CTL2_LOOPBACK            (1 << 5)
+#define CS42L52_IFACE_CTL2_S_MODE_OUTPUT_EN    (0 << 4)
+#define CS42L52_IFACE_CTL2_S_MODE_OUTPUT_HIZ   (1 << 4)
+#define CS42L52_IFACE_CTL2_HP_SW_INV           (1 << 3)
+#define CS42L52_IFACE_CTL2_BIAS_LVL            0x07
+
+#define CS42L52_ADC_PGA_A                      0x08
+#define CS42L52_ADC_PGA_B                      0x09
+#define CS42L52_ADC_SEL_SHIFT                  5
+#define CS42L52_ADC_SEL_AIN1                   0x00
+#define CS42L52_ADC_SEL_AIN2                   0x01
+#define CS42L52_ADC_SEL_AIN3                   0x02
+#define CS42L52_ADC_SEL_AIN4                   0x03
+#define CS42L52_ADC_SEL_PGA                    0x04
+
+#define CS42L52_ANALOG_HPF_CTL                 0x0A
+#define CS42L52_HPF_CTL_ANLGSFTB               (1 << 3)
+#define CS42L52_HPF_CTL_ANLGSFTA                (1 << 0)
+
+#define CS42L52_ADC_HPF_FREQ                   0x0B
+#define CS42L52_ADC_MISC_CTL                   0x0C
+#define CS42L52_ADC_MISC_CTL_SOURCE_DSP                (1 << 6)
+
+#define CS42L52_PB_CTL1                                0x0D
+#define CS42L52_PB_CTL1_HP_GAIN_SHIFT          5
+#define CS42L52_PB_CTL1_HP_GAIN_03959          0x00
+#define CS42L52_PB_CTL1_HP_GAIN_04571          0x01
+#define CS42L52_PB_CTL1_HP_GAIN_05111          0x02
+#define CS42L52_PB_CTL1_HP_GAIN_06047          0x03
+#define CS42L52_PB_CTL1_HP_GAIN_07099          0x04
+#define CS42L52_PB_CTL1_HP_GAIN_08399          0x05
+#define CS42L52_PB_CTL1_HP_GAIN_10000          0x06
+#define CS42L52_PB_CTL1_HP_GAIN_11430          0x07
+#define CS42L52_PB_CTL1_INV_PCMB               (1 << 3)
+#define CS42L52_PB_CTL1_INV_PCMA               (1 << 2)
+#define CS42L52_PB_CTL1_MSTB_MUTE              (1 << 1)
+#define CS42L52_PB_CTL1_MSTA_MUTE              (1 << 0)
+#define CS42L52_PB_CTL1_MUTE_MASK              0xFFFD
+#define CS42L52_PB_CTL1_MUTE                   3
+#define CS42L52_PB_CTL1_UNMUTE                 0
+
+#define CS42L52_MISC_CTL                       0x0E
+#define CS42L52_MISC_CTL_DEEMPH                        (1 << 2)
+#define CS42L52_MISC_CTL_DIGSFT                        (1 << 1)
+#define CS42L52_MISC_CTL_DIGZC                 (1 << 0)
+
+#define CS42L52_PB_CTL2                                0x0F
+#define CS42L52_PB_CTL2_HPB_MUTE               (1 << 7)
+#define CS42L52_PB_CTL2_HPA_MUTE               (1 << 6)
+#define CS42L52_PB_CTL2_SPKB_MUTE              (1 << 5)
+#define CS42L52_PB_CTL2_SPKA_MUTE              (1 << 4)
+#define CS42L52_PB_CTL2_SPK_SWAP               (1 << 2)
+#define CS42L52_PB_CTL2_SPK_MONO               (1 << 1)
+#define CS42L52_PB_CTL2_SPK_MUTE50             (1 << 0)
+
+#define        CS42L52_MICA_CTL                        0x10
+#define CS42L52_MICB_CTL                       0x11
+#define        CS42L52_MIC_CTL_MIC_SEL_MASK            0xBF
+#define        CS42L52_MIC_CTL_MIC_SEL_SHIFT           6
+#define CS42L52_MIC_CTL_TYPE_MASK              0xDF
+#define CS42L52_MIC_CTL_TYPE_SHIFT             5
+
+
+#define CS42L52_PGAA_CTL                       0x12
+#define CS42L52_PGAB_CTL                       0x13
+#define CS42L52_PGAX_CTL_VOL_12DB              24
+#define CS42L52_PGAX_CTL_VOL_6DB               12 /*step size 0.5db*/
+
+#define CS42L52_PASSTHRUA_VOL                  0x14
+#define CS42L52_PASSTHRUB_VOL                  0x15
+
+#define CS42L52_ADCA_VOL                       0x16
+#define CS42L52_ADCB_VOL                       0x17
+#define CS42L52_ADCX_VOL_24DB                  24 /*step size 1db*/
+#define CS42L52_ADCX_VOL_12DB                  12
+#define CS42L52_ADCX_VOL_6DB                   6
+
+#define CS42L52_ADCA_MIXER_VOL                 0x18
+#define CS42L52_ADCB_MIXER_VOL                 0x19
+#define CS42L52_ADC_MIXER_VOL_12DB             0x18
+
+#define CS42L52_PCMA_MIXER_VOL                 0x1A
+#define CS42L52_PCMB_MIXER_VOL                 0x1B
+
+#define CS42L52_BEEP_FREQ                      0x1C
+#define CS42L52_BEEP_VOL                       0x1D
+#define CS42L52_BEEP_TONE_CTL                  0x1E
+#define CS42L52_BEEP_RATE_SHIFT                        4
+#define CS42L52_BEEP_RATE_MASK                 0x0F
+
+#define CS42L52_TONE_CTL                       0x1F
+#define CS42L52_BEEP_EN_MASK                   0x3F
+
+#define CS42L52_MASTERA_VOL                    0x20
+#define CS42L52_MASTERB_VOL                    0x21
+
+#define CS42L52_HPA_VOL                                0x22
+#define CS42L52_HPB_VOL                                0x23
+#define CS42L52_DEFAULT_HP_VOL                 0xF0
+
+#define CS42L52_SPKA_VOL                       0x24
+#define CS42L52_SPKB_VOL                       0x25
+#define CS42L52_DEFAULT_SPK_VOL                        0xF0
+
+#define CS42L52_ADC_PCM_MIXER                  0x26
+
+#define CS42L52_LIMITER_CTL1                   0x27
+#define CS42L52_LIMITER_CTL2                   0x28
+#define CS42L52_LIMITER_AT_RATE                        0x29
+
+#define CS42L52_ALC_CTL                                0x2A
+#define CS42L52_ALC_CTL_ALCB_ENABLE_SHIFT      7
+#define CS42L52_ALC_CTL_ALCA_ENABLE_SHIFT      6
+#define CS42L52_ALC_CTL_FASTEST_ATTACK         0
+
+#define CS42L52_ALC_RATE                       0x2B
+#define CS42L52_ALC_SLOWEST_RELEASE            0x3F
+
+#define CS42L52_ALC_THRESHOLD                  0x2C
+#define CS42L52_ALC_MAX_RATE_SHIFT             5
+#define CS42L52_ALC_MIN_RATE_SHIFT             2
+#define CS42L52_ALC_RATE_0DB                   0
+#define CS42L52_ALC_RATE_3DB                   1
+#define CS42L52_ALC_RATE_6DB                   2
+
+#define CS42L52_NOISE_GATE_CTL                 0x2D
+#define CS42L52_NG_ENABLE_SHIFT                        6
+#define CS42L52_NG_THRESHOLD_SHIFT             2
+#define CS42L52_NG_MIN_70DB                    2
+#define CS42L52_NG_DELAY_SHIFT                 0
+#define CS42L52_NG_DELAY_100MS                 1
+
+#define CS42L52_CLK_STATUS                     0x2E
+#define CS42L52_BATT_COMPEN                    0x2F
+
+#define CS42L52_BATT_LEVEL                     0x30
+#define CS42L52_SPK_STATUS                     0x31
+#define CS42L52_SPK_STATUS_PIN_SHIFT           3
+#define CS42L52_SPK_STATUS_PIN_HIGH            1
+
+#define CS42L52_TEM_CTL                                0x32
+#define CS42L52_TEM_CTL_SET                    0x80
+#define CS42L52_THE_FOLDBACK                   0x33
+#define CS42L52_CHARGE_PUMP                    0x34
+#define CS42L52_CHARGE_PUMP_MASK               0xF0
+#define CS42L52_CHARGE_PUMP_SHIFT              4
+#define CS42L52_FIX_BITS1                      0x3E
+#define CS42L52_FIX_BITS2                      0x47
+
+#define CS42L52_MAX_REGISTER                   0x34
+
+#endif
index 3686417f5ea54b5222cd6190174a7b08176aa6f7..e0d45fdaa750842eb342dc9ced8116ff1a21e212 100644 (file)
@@ -43,9 +43,6 @@ struct  cs42l73_private {
 };
 
 static const struct reg_default cs42l73_reg_defaults[] = {
-       { 1, 0x42 },    /* r01  - Device ID A&B */
-       { 2, 0xA7 },    /* r02  - Device ID C&D */
-       { 3, 0x30 },    /* r03  - Device ID E */
        { 6, 0xF1 },    /* r06  - Power Ctl 1 */
        { 7, 0xDF },    /* r07  - Power Ctl 2 */
        { 8, 0x3F },    /* r08  - Power Ctl 3 */
@@ -402,37 +399,37 @@ static const struct snd_kcontrol_new ear_amp_ctl =
 
 static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
        SOC_DOUBLE_R_SX_TLV("Headphone Analog Playback Volume",
-                       CS42L73_HPAAVOL, CS42L73_HPBAVOL, 7,
-                       0xffffffC1, 0x0C, hpaloa_tlv),
+                       CS42L73_HPAAVOL, CS42L73_HPBAVOL, 0,
+                       0x41, 0x4B, hpaloa_tlv),
 
        SOC_DOUBLE_R_SX_TLV("LineOut Analog Playback Volume", CS42L73_LOAAVOL,
-                       CS42L73_LOBAVOL, 7, 0xffffffC1, 0x0C, hpaloa_tlv),
+                       CS42L73_LOBAVOL, 0, 0x41, 0x4B, hpaloa_tlv),
 
        SOC_DOUBLE_R_SX_TLV("Input PGA Analog Volume", CS42L73_MICAPREPGAAVOL,
-                       CS42L73_MICBPREPGABVOL, 5, 0xffffff35,
-                       0x34, micpga_tlv),
+                       CS42L73_MICBPREPGABVOL, 5, 0x34,
+                       0x24, micpga_tlv),
 
        SOC_DOUBLE_R("MIC Preamp Switch", CS42L73_MICAPREPGAAVOL,
                        CS42L73_MICBPREPGABVOL, 6, 1, 1),
 
        SOC_DOUBLE_R_SX_TLV("Input Path Digital Volume", CS42L73_IPADVOL,
-                       CS42L73_IPBDVOL, 7, 0xffffffA0, 0xA0, ipd_tlv),
+                       CS42L73_IPBDVOL, 0, 0xA0, 0x6C, ipd_tlv),
 
        SOC_DOUBLE_R_SX_TLV("HL Digital Playback Volume",
-                       CS42L73_HLADVOL, CS42L73_HLBDVOL, 7, 0xffffffE5,
-                       0xE4, hl_tlv),
+                       CS42L73_HLADVOL, CS42L73_HLBDVOL,
+                       0, 0x34, 0xE4, hl_tlv),
 
        SOC_SINGLE_TLV("ADC A Boost Volume",
                        CS42L73_ADCIPC, 2, 0x01, 1, adc_boost_tlv),
 
        SOC_SINGLE_TLV("ADC B Boost Volume",
-                       CS42L73_ADCIPC, 6, 0x01, 1, adc_boost_tlv),
+                      CS42L73_ADCIPC, 6, 0x01, 1, adc_boost_tlv),
 
-       SOC_SINGLE_TLV("Speakerphone Digital Playback Volume",
-                       CS42L73_SPKDVOL, 0, 0xE4, 1, hl_tlv),
+       SOC_SINGLE_SX_TLV("Speakerphone Digital Volume",
+                           CS42L73_SPKDVOL, 0, 0x34, 0xE4, hl_tlv),
 
-       SOC_SINGLE_TLV("Ear Speaker Digital Playback Volume",
-                       CS42L73_ESLDVOL, 0, 0xE4, 1, hl_tlv),
+       SOC_SINGLE_SX_TLV("Ear Speaker Digital Volume",
+                           CS42L73_ESLDVOL, 0, 0x34, 0xE4, hl_tlv),
 
        SOC_DOUBLE_R("Headphone Analog Playback Switch", CS42L73_HPAAVOL,
                        CS42L73_HPBAVOL, 7, 1, 1),
@@ -599,17 +596,17 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("MIC2"),
        SND_SOC_DAPM_SUPPLY("MIC2 Bias", CS42L73_PWRCTL2, 7, 1, NULL, 0),
 
-       SND_SOC_DAPM_AIF_OUT("XSPOUTL", "XSP Capture",  0,
+       SND_SOC_DAPM_AIF_OUT("XSPOUTL", NULL,  0,
                        CS42L73_PWRCTL2, 1, 1),
-       SND_SOC_DAPM_AIF_OUT("XSPOUTR", "XSP Capture",  0,
+       SND_SOC_DAPM_AIF_OUT("XSPOUTR", NULL,  0,
                        CS42L73_PWRCTL2, 1, 1),
-       SND_SOC_DAPM_AIF_OUT("ASPOUTL", "ASP Capture",  0,
+       SND_SOC_DAPM_AIF_OUT("ASPOUTL", NULL,  0,
                        CS42L73_PWRCTL2, 3, 1),
-       SND_SOC_DAPM_AIF_OUT("ASPOUTR", "ASP Capture",  0,
+       SND_SOC_DAPM_AIF_OUT("ASPOUTR", NULL,  0,
                        CS42L73_PWRCTL2, 3, 1),
-       SND_SOC_DAPM_AIF_OUT("VSPOUTL", "VSP Capture",  0,
+       SND_SOC_DAPM_AIF_OUT("VSPOUTL", NULL,  0,
                        CS42L73_PWRCTL2, 4, 1),
-       SND_SOC_DAPM_AIF_OUT("VSPOUTR", "VSP Capture",  0,
+       SND_SOC_DAPM_AIF_OUT("VSPOUTR", NULL,  0,
                        CS42L73_PWRCTL2, 4, 1),
 
        SND_SOC_DAPM_PGA("PGA Left", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -638,21 +635,21 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
        SND_SOC_DAPM_MIXER("VSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_MIXER("VSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 
-       SND_SOC_DAPM_AIF_IN("XSPINL", "XSP Playback", 0,
+       SND_SOC_DAPM_AIF_IN("XSPINL", NULL, 0,
                                CS42L73_PWRCTL2, 0, 1),
-       SND_SOC_DAPM_AIF_IN("XSPINR", "XSP Playback", 0,
+       SND_SOC_DAPM_AIF_IN("XSPINR", NULL, 0,
                                CS42L73_PWRCTL2, 0, 1),
-       SND_SOC_DAPM_AIF_IN("XSPINM", "XSP Playback", 0,
+       SND_SOC_DAPM_AIF_IN("XSPINM", NULL, 0,
                                CS42L73_PWRCTL2, 0, 1),
 
-       SND_SOC_DAPM_AIF_IN("ASPINL", "ASP Playback", 0,
+       SND_SOC_DAPM_AIF_IN("ASPINL", NULL, 0,
                                CS42L73_PWRCTL2, 2, 1),
-       SND_SOC_DAPM_AIF_IN("ASPINR", "ASP Playback", 0,
+       SND_SOC_DAPM_AIF_IN("ASPINR", NULL, 0,
                                CS42L73_PWRCTL2, 2, 1),
-       SND_SOC_DAPM_AIF_IN("ASPINM", "ASP Playback", 0,
+       SND_SOC_DAPM_AIF_IN("ASPINM", NULL, 0,
                                CS42L73_PWRCTL2, 2, 1),
 
-       SND_SOC_DAPM_AIF_IN("VSPIN", "VSP Playback", 0,
+       SND_SOC_DAPM_AIF_IN("VSPIN", NULL, 0,
                                CS42L73_PWRCTL2, 4, 1),
 
        SND_SOC_DAPM_MIXER("HL Left Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -776,6 +773,14 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
        {"HL Left Mixer", NULL, "VSPIN"},
        {"HL Right Mixer", NULL, "VSPIN"},
 
+       {"ASPINL", NULL, "ASP Playback"},
+       {"ASPINM", NULL, "ASP Playback"},
+       {"ASPINR", NULL, "ASP Playback"},
+       {"XSPINL", NULL, "XSP Playback"},
+       {"XSPINM", NULL, "XSP Playback"},
+       {"XSPINR", NULL, "XSP Playback"},
+       {"VSPIN", NULL, "VSP Playback"},
+
        /* Capture Paths */
        {"MIC1", NULL, "MIC1 Bias"},
        {"PGA Left Mux", "Mic 1", "MIC1"},
@@ -822,6 +827,13 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
 
        {"VSPOUTL", NULL, "VSPL Output Mixer"},
        {"VSPOUTR", NULL, "VSPR Output Mixer"},
+
+       {"ASP Capture", NULL, "ASPOUTL"},
+       {"ASP Capture", NULL, "ASPOUTR"},
+       {"XSP Capture", NULL, "XSPOUTL"},
+       {"XSP Capture", NULL, "XSPOUTR"},
+       {"VSP Capture", NULL, "VSPOUTL"},
+       {"VSP Capture", NULL, "VSPOUTR"},
 };
 
 struct cs42l73_mclk_div {
@@ -1091,8 +1103,7 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
        int id = dai->id;
        int mclk_coeff;
@@ -1429,25 +1440,7 @@ static struct i2c_driver cs42l73_i2c_driver = {
 
 };
 
-static int __init cs42l73_modinit(void)
-{
-       int ret;
-       ret = i2c_add_driver(&cs42l73_i2c_driver);
-       if (ret != 0) {
-               pr_err("Failed to register CS42L73 I2C driver: %d\n", ret);
-               return ret;
-       }
-       return 0;
-}
-
-module_init(cs42l73_modinit);
-
-static void __exit cs42l73_exit(void)
-{
-       i2c_del_driver(&cs42l73_i2c_driver);
-}
-
-module_exit(cs42l73_exit);
+module_i2c_driver(cs42l73_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC CS42L73 driver");
 MODULE_AUTHOR("Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>");
index 7843711729bcd79ce0f9d8938904199d7c056dd9..af5db70805199e81b06e7d48a8e844ae504489b2 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/delay.h>
 #include <linux/i2c.h>
+#include <linux/spi/spi.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -27,6 +28,7 @@
 #include <sound/tlv.h>
 
 /* DA7210 register space */
+#define DA7210_PAGE_CONTROL            0x00
 #define DA7210_CONTROL                 0x01
 #define DA7210_STATUS                  0x02
 #define DA7210_STARTUP1                        0x03
 #define DA7210_DAI_EN                  (1 << 7)
 
 /*PLL_DIV3 bit fields */
+#define DA7210_PLL_DIV_L_MASK          (0xF << 0)
 #define DA7210_MCLK_RANGE_10_20_MHZ    (1 << 4)
 #define DA7210_PLL_BYP                 (1 << 6)
 
 #define DA7210_PLL_FS_48000            (0xB << 0)
 #define DA7210_PLL_FS_88200            (0xE << 0)
 #define DA7210_PLL_FS_96000            (0xF << 0)
+#define DA7210_MCLK_DET_EN             (0x1 << 5)
+#define DA7210_MCLK_SRM_EN             (0x1 << 6)
 #define DA7210_PLL_EN                  (0x1 << 7)
 
 /* SOFTMUTE bit fields */
 #define DA7210_RAMP_EN                 (1 << 6)
 
 /* CONTROL bit fields */
+#define DA7210_REG_EN                  (1 << 0)
+#define DA7210_BIAS_EN                 (1 << 2)
 #define DA7210_NOISE_SUP_EN            (1 << 3)
 
 /* IN_GAIN bit fields */
 #define DA7210_OUT2_OUTMIX_L           (1 << 6)
 #define DA7210_OUT2_EN                 (1 << 7)
 
+struct pll_div {
+       int fref;
+       int fout;
+       u8 div1;
+       u8 div2;
+       u8 div3;
+       u8 mode;        /* 0 = slave, 1 = master */
+};
+
+/* PLL dividers table */
+static const struct pll_div da7210_pll_div[] = {
+       /* for MASTER mode, fs = 44.1Khz */
+       { 12000000, 2822400, 0xE8, 0x6C, 0x2, 1},       /* MCLK=12Mhz */
+       { 13000000, 2822400, 0xDF, 0x28, 0xC, 1},       /* MCLK=13Mhz */
+       { 13500000, 2822400, 0xDB, 0x0A, 0xD, 1},       /* MCLK=13.5Mhz */
+       { 14400000, 2822400, 0xD4, 0x5A, 0x2, 1},       /* MCLK=14.4Mhz */
+       { 19200000, 2822400, 0xBB, 0x43, 0x9, 1},       /* MCLK=19.2Mhz */
+       { 19680000, 2822400, 0xB9, 0x6D, 0xA, 1},       /* MCLK=19.68Mhz */
+       { 19800000, 2822400, 0xB8, 0xFB, 0xB, 1},       /* MCLK=19.8Mhz */
+       /* for MASTER mode, fs = 48Khz */
+       { 12000000, 3072000, 0xF3, 0x12, 0x7, 1},       /* MCLK=12Mhz */
+       { 13000000, 3072000, 0xE8, 0xFD, 0x5, 1},       /* MCLK=13Mhz */
+       { 13500000, 3072000, 0xE4, 0x82, 0x3, 1},       /* MCLK=13.5Mhz */
+       { 14400000, 3072000, 0xDD, 0x3A, 0x0, 1},       /* MCLK=14.4Mhz */
+       { 19200000, 3072000, 0xC1, 0xEB, 0x8, 1},       /* MCLK=19.2Mhz */
+       { 19680000, 3072000, 0xBF, 0xEC, 0x0, 1},       /* MCLK=19.68Mhz */
+       { 19800000, 3072000, 0xBF, 0x70, 0x0, 1},       /* MCLK=19.8Mhz */
+       /* for SLAVE mode with SRM */
+       { 12000000, 2822400, 0xED, 0xBF, 0x5, 0},       /* MCLK=12Mhz */
+       { 13000000, 2822400, 0xE4, 0x13, 0x0, 0},       /* MCLK=13Mhz */
+       { 13500000, 2822400, 0xDF, 0xC6, 0x8, 0},       /* MCLK=13.5Mhz */
+       { 14400000, 2822400, 0xD8, 0xCA, 0x1, 0},       /* MCLK=14.4Mhz */
+       { 19200000, 2822400, 0xBE, 0x97, 0x9, 0},       /* MCLK=19.2Mhz */
+       { 19680000, 2822400, 0xBC, 0xAC, 0xD, 0},       /* MCLK=19.68Mhz */
+       { 19800000, 2822400, 0xBC, 0x35, 0xE, 0},       /* MCLK=19.8Mhz  */
+};
+
+enum clk_src {
+       DA7210_CLKSRC_MCLK
+};
+
 #define DA7210_VERSION "0.0.1"
 
 /*
@@ -628,9 +676,12 @@ static const struct snd_soc_dapm_route da7210_audio_map[] = {
 /* Codec private data */
 struct da7210_priv {
        struct regmap *regmap;
+       unsigned int mclk_rate;
+       int master;
 };
 
 static struct reg_default da7210_reg_defaults[] = {
+       { 0x00, 0x00 },
        { 0x01, 0x11 },
        { 0x03, 0x00 },
        { 0x04, 0x00 },
@@ -713,10 +764,10 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
+       struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
        u32 dai_cfg1;
-       u32 fs, bypass;
+       u32 fs, sysclk;
 
        /* set DAI source to Left and Right ADC */
        snd_soc_write(codec, DA7210_DAI_SRC_SEL,
@@ -749,43 +800,43 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
        switch (params_rate(params)) {
        case 8000:
                fs              = DA7210_PLL_FS_8000;
-               bypass          = DA7210_PLL_BYP;
+               sysclk          = 3072000;
                break;
        case 11025:
                fs              = DA7210_PLL_FS_11025;
-               bypass          = 0;
+               sysclk          = 2822400;
                break;
        case 12000:
                fs              = DA7210_PLL_FS_12000;
-               bypass          = DA7210_PLL_BYP;
+               sysclk          = 3072000;
                break;
        case 16000:
                fs              = DA7210_PLL_FS_16000;
-               bypass          = DA7210_PLL_BYP;
+               sysclk          = 3072000;
                break;
        case 22050:
                fs              = DA7210_PLL_FS_22050;
-               bypass          = 0;
+               sysclk          = 2822400;
                break;
        case 32000:
                fs              = DA7210_PLL_FS_32000;
-               bypass          = DA7210_PLL_BYP;
+               sysclk          = 3072000;
                break;
        case 44100:
                fs              = DA7210_PLL_FS_44100;
-               bypass          = 0;
+               sysclk          = 2822400;
                break;
        case 48000:
                fs              = DA7210_PLL_FS_48000;
-               bypass          = DA7210_PLL_BYP;
+               sysclk          = 3072000;
                break;
        case 88200:
                fs              = DA7210_PLL_FS_88200;
-               bypass          = 0;
+               sysclk          = 2822400;
                break;
        case 96000:
                fs              = DA7210_PLL_FS_96000;
-               bypass          = DA7210_PLL_BYP;
+               sysclk          = 3072000;
                break;
        default:
                return -EINVAL;
@@ -795,8 +846,26 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
        snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
 
        snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_FS_MASK, fs);
-       snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, bypass);
 
+       if (da7210->mclk_rate && (da7210->mclk_rate != sysclk)) {
+               /* PLL mode, disable PLL bypass */
+               snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, 0);
+
+               if (!da7210->master) {
+                       /* PLL slave mode, also enable SRM */
+                       snd_soc_update_bits(codec, DA7210_PLL,
+                                                  (DA7210_MCLK_SRM_EN |
+                                                   DA7210_MCLK_DET_EN),
+                                                  (DA7210_MCLK_SRM_EN |
+                                                   DA7210_MCLK_DET_EN));
+               }
+       } else {
+               /* PLL bypass mode, enable PLL bypass and Auto Detection */
+               snd_soc_update_bits(codec, DA7210_PLL, DA7210_MCLK_DET_EN,
+                                                      DA7210_MCLK_DET_EN);
+               snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP,
+                                                           DA7210_PLL_BYP);
+       }
        /* Enable active mode */
        snd_soc_update_bits(codec, DA7210_STARTUP1,
                            DA7210_SC_MST_EN, DA7210_SC_MST_EN);
@@ -810,17 +879,24 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
 static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
+       struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
        u32 dai_cfg1;
        u32 dai_cfg3;
 
        dai_cfg1 = 0x7f & snd_soc_read(codec, DA7210_DAI_CFG1);
        dai_cfg3 = 0xfc & snd_soc_read(codec, DA7210_DAI_CFG3);
 
+       if ((snd_soc_read(codec, DA7210_PLL) & DA7210_PLL_EN) &&
+               (!(snd_soc_read(codec, DA7210_PLL_DIV3) & DA7210_PLL_BYP)))
+               return -EINVAL;
+
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
+               da7210->master = 1;
                dai_cfg1 |= DA7210_DAI_MODE_MASTER;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
+               da7210->master = 0;
                dai_cfg1 |= DA7210_DAI_MODE_SLAVE;
                break;
        default:
@@ -872,10 +948,101 @@ static int da7210_mute(struct snd_soc_dai *dai, int mute)
 #define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
                        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static int da7210_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
+
+       switch (clk_id) {
+       case DA7210_CLKSRC_MCLK:
+               switch (freq) {
+               case 12000000:
+               case 13000000:
+               case 13500000:
+               case 14400000:
+               case 19200000:
+               case 19680000:
+               case 19800000:
+                       da7210->mclk_rate = freq;
+                       return 0;
+               default:
+                       dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+                               freq);
+                       return -EINVAL;
+               }
+               break;
+       default:
+               dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+               return -EINVAL;
+       }
+}
+
+/**
+ * da7210_set_dai_pll  :Configure the codec PLL
+ * @param codec_dai    : pointer to codec DAI
+ * @param pll_id       : da7210 has only one pll, so pll_id is always zero
+ * @param fref         : MCLK frequency, should be < 20MHz
+ * @param fout         : FsDM value, Refer page 44 & 45 of datasheet
+ * @return int         : Zero for success, negative error code for error
+ *
+ * Note: Supported PLL input frequencies are 12MHz, 13MHz, 13.5MHz, 14.4MHz,
+ *       19.2MHz, 19.6MHz and 19.8MHz
+ */
+static int da7210_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+                             int source, unsigned int fref, unsigned int fout)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
+
+       u8 pll_div1, pll_div2, pll_div3, cnt;
+
+       /* In slave mode, there is only one set of divisors */
+       if (!da7210->master)
+               fout = 2822400;
+
+       /* Search pll div array for correct divisors */
+       for (cnt = 0; cnt < ARRAY_SIZE(da7210_pll_div); cnt++) {
+               /* check fref, mode  and fout */
+               if ((fref == da7210_pll_div[cnt].fref) &&
+                   (da7210->master ==  da7210_pll_div[cnt].mode) &&
+                   (fout == da7210_pll_div[cnt].fout)) {
+                       /* all match, pick up divisors */
+                       pll_div1 = da7210_pll_div[cnt].div1;
+                       pll_div2 = da7210_pll_div[cnt].div2;
+                       pll_div3 = da7210_pll_div[cnt].div3;
+                       break;
+               }
+       }
+       if (cnt >= ARRAY_SIZE(da7210_pll_div))
+               goto err;
+
+       /* Disable active mode */
+       snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
+       /* Write PLL dividers */
+       snd_soc_write(codec, DA7210_PLL_DIV1, pll_div1);
+       snd_soc_write(codec, DA7210_PLL_DIV2, pll_div2);
+       snd_soc_update_bits(codec, DA7210_PLL_DIV3,
+                                  DA7210_PLL_DIV_L_MASK, pll_div3);
+
+       /* Enable PLL */
+       snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
+
+       /* Enable active mode */
+       snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN,
+                                                   DA7210_SC_MST_EN);
+       return 0;
+err:
+       dev_err(codec_dai->dev, "Unsupported PLL input frequency %d\n", fref);
+       return -EINVAL;
+}
+
 /* DAI operations */
 static const struct snd_soc_dai_ops da7210_dai_ops = {
        .hw_params      = da7210_hw_params,
        .set_fmt        = da7210_set_dai_fmt,
+       .set_sysclk     = da7210_set_dai_sysclk,
+       .set_pll        = da7210_set_dai_pll,
        .digital_mute   = da7210_mute,
 };
 
@@ -915,24 +1082,11 @@ static int da7210_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       /* FIXME
-        *
-        * This driver use fixed value here
-        * And below settings expects MCLK = 12.288MHz
-        *
-        * When you select different MCLK, please check...
-        *      DA7210_PLL_DIV1 val
-        *      DA7210_PLL_DIV2 val
-        *      DA7210_PLL_DIV3 val
-        *      DA7210_PLL_DIV3 :: DA7210_MCLK_RANGExxx
-        */
+       da7210->mclk_rate       = 0;    /* This will be set from set_sysclk() */
+       da7210->master          = 0;    /* This will be set from set_fmt() */
 
-       /*
-        * make sure that DA7210 use bypass mode before start up
-        */
-       snd_soc_write(codec, DA7210_STARTUP1, 0);
-       snd_soc_write(codec, DA7210_PLL_DIV3,
-                    DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
+       /* Enable internal regulator & bias current */
+       snd_soc_write(codec, DA7210_CONTROL, DA7210_REG_EN | DA7210_BIAS_EN);
 
        /*
         * ADC settings
@@ -1007,34 +1161,13 @@ static int da7210_probe(struct snd_soc_codec *codec)
        /* Enable Aux2 */
        snd_soc_write(codec, DA7210_AUX2, DA7210_AUX2_EN);
 
+       /* Set PLL Master clock range 10-20 MHz, enable PLL bypass */
+       snd_soc_write(codec, DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ |
+                                             DA7210_PLL_BYP);
+
        /* Diable PLL and bypass it */
        snd_soc_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
 
-       /*
-        * If 48kHz sound came, it use bypass mode,
-        * and when it is 44.1kHz, it use PLL.
-        *
-        * This time, this driver sets PLL always ON
-        * and controls bypass/PLL mode by switching
-        * DA7210_PLL_DIV3 :: DA7210_PLL_BYP bit.
-        *   see da7210_hw_params
-        */
-       snd_soc_write(codec, DA7210_PLL_DIV1, 0xE5); /* MCLK = 12.288MHz */
-       snd_soc_write(codec, DA7210_PLL_DIV2, 0x99);
-       snd_soc_write(codec, DA7210_PLL_DIV3, 0x0A |
-                    DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
-       snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
-
-       /* As suggested by Dialog */
-       /* unlock */
-       regmap_write(da7210->regmap, DA7210_A_HID_UNLOCK,       0x8B);
-       regmap_write(da7210->regmap, DA7210_A_TEST_UNLOCK,      0xB4);
-       regmap_write(da7210->regmap, DA7210_A_PLL1,             0x01);
-       regmap_write(da7210->regmap, DA7210_A_CP_MODE,          0x7C);
-       /* re-lock */
-       regmap_write(da7210->regmap, DA7210_A_HID_UNLOCK,       0x00);
-       regmap_write(da7210->regmap, DA7210_A_TEST_UNLOCK,      0x00);
-
        /* Activate all enabled subsystem */
        snd_soc_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
 
@@ -1055,7 +1188,26 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
        .num_dapm_routes        = ARRAY_SIZE(da7210_audio_map),
 };
 
-static struct regmap_config da7210_regmap = {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+static struct reg_default da7210_regmap_i2c_patch[] = {
+
+       /* System controller master disable */
+       { DA7210_STARTUP1, 0x00 },
+       /* Set PLL Master clock range 10-20 MHz */
+       { DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ },
+
+       /* to unlock */
+       { DA7210_A_HID_UNLOCK, 0x8B},
+       { DA7210_A_TEST_UNLOCK, 0xB4},
+       { DA7210_A_PLL1, 0x01},
+       { DA7210_A_CP_MODE, 0x7C},
+       /* to re-lock */
+       { DA7210_A_HID_UNLOCK, 0x00},
+       { DA7210_A_TEST_UNLOCK, 0x00},
+};
+
+static const struct regmap_config da7210_regmap_config_i2c = {
        .reg_bits = 8,
        .val_bits = 8,
 
@@ -1066,7 +1218,6 @@ static struct regmap_config da7210_regmap = {
        .cache_type = REGCACHE_RBTREE,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
@@ -1080,13 +1231,18 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, da7210);
 
-       da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap);
+       da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap_config_i2c);
        if (IS_ERR(da7210->regmap)) {
                ret = PTR_ERR(da7210->regmap);
                dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
                return ret;
        }
 
+       ret = regmap_register_patch(da7210->regmap, da7210_regmap_i2c_patch,
+                                   ARRAY_SIZE(da7210_regmap_i2c_patch));
+       if (ret != 0)
+               dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_da7210, &da7210_dai, 1);
        if (ret < 0) {
@@ -1119,7 +1275,7 @@ MODULE_DEVICE_TABLE(i2c, da7210_i2c_id);
 /* I2C codec control layer */
 static struct i2c_driver da7210_i2c_driver = {
        .driver = {
-               .name = "da7210-codec",
+               .name = "da7210",
                .owner = THIS_MODULE,
        },
        .probe          = da7210_i2c_probe,
@@ -1128,11 +1284,111 @@ static struct i2c_driver da7210_i2c_driver = {
 };
 #endif
 
+#if defined(CONFIG_SPI_MASTER)
+
+static struct reg_default da7210_regmap_spi_patch[] = {
+       /* Dummy read to give two pulses over nCS for SPI */
+       { DA7210_AUX2, 0x00 },
+       { DA7210_AUX2, 0x00 },
+
+       /* System controller master disable */
+       { DA7210_STARTUP1, 0x00 },
+       /* Set PLL Master clock range 10-20 MHz */
+       { DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ },
+
+       /* to set PAGE1 of SPI register space */
+       { DA7210_PAGE_CONTROL, 0x80 },
+       /* to unlock */
+       { DA7210_A_HID_UNLOCK, 0x8B},
+       { DA7210_A_TEST_UNLOCK, 0xB4},
+       { DA7210_A_PLL1, 0x01},
+       { DA7210_A_CP_MODE, 0x7C},
+       /* to re-lock */
+       { DA7210_A_HID_UNLOCK, 0x00},
+       { DA7210_A_TEST_UNLOCK, 0x00},
+       /* to set back PAGE0 of SPI register space */
+       { DA7210_PAGE_CONTROL, 0x00 },
+};
+
+static const struct regmap_config da7210_regmap_config_spi = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .read_flag_mask = 0x01,
+       .write_flag_mask = 0x00,
+
+       .reg_defaults = da7210_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(da7210_reg_defaults),
+       .volatile_reg = da7210_volatile_register,
+       .readable_reg = da7210_readable_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit da7210_spi_probe(struct spi_device *spi)
+{
+       struct da7210_priv *da7210;
+       int ret;
+
+       da7210 = devm_kzalloc(&spi->dev, sizeof(struct da7210_priv),
+                             GFP_KERNEL);
+       if (!da7210)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, da7210);
+       da7210->regmap = devm_regmap_init_spi(spi, &da7210_regmap_config_spi);
+       if (IS_ERR(da7210->regmap)) {
+               ret = PTR_ERR(da7210->regmap);
+               dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_register_patch(da7210->regmap, da7210_regmap_spi_patch,
+                                   ARRAY_SIZE(da7210_regmap_spi_patch));
+       if (ret != 0)
+               dev_warn(&spi->dev, "Failed to apply regmap patch: %d\n", ret);
+
+       ret =  snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_da7210, &da7210_dai, 1);
+       if (ret < 0)
+               goto err_regmap;
+
+       return ret;
+
+err_regmap:
+       regmap_exit(da7210->regmap);
+
+       return ret;
+}
+
+static int __devexit da7210_spi_remove(struct spi_device *spi)
+{
+       struct da7210_priv *da7210 = spi_get_drvdata(spi);
+       snd_soc_unregister_codec(&spi->dev);
+       regmap_exit(da7210->regmap);
+       return 0;
+}
+
+static struct spi_driver da7210_spi_driver = {
+       .driver = {
+               .name = "da7210",
+               .owner = THIS_MODULE,
+       },
+       .probe = da7210_spi_probe,
+       .remove = __devexit_p(da7210_spi_remove)
+};
+#endif
+
 static int __init da7210_modinit(void)
 {
        int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&da7210_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&da7210_spi_driver);
+       if (ret) {
+               printk(KERN_ERR "Failed to register da7210 SPI driver: %d\n",
+                      ret);
+       }
 #endif
        return ret;
 }
@@ -1143,6 +1399,9 @@ static void __exit da7210_exit(void)
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&da7210_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&da7210_spi_driver);
+#endif
 }
 module_exit(da7210_exit);
 
index 4624e752a188cdc13689fc3b29bacfd1d5e4bf84..85d9cabe6d555d9e28e3812f1d97f631434ff461 100644 (file)
@@ -164,8 +164,7 @@ static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
        uint32_t val;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec =rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
 
        switch (params_rate(params)) {
        case 8000:
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
new file mode 100644 (file)
index 0000000..802b9f1
--- /dev/null
@@ -0,0 +1,1550 @@
+/*
+ * lm49453.c  -  LM49453 ALSA Soc Audio driver
+ *
+ * Copyright (c) 2012 Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * Initially based on sound/soc/codecs/wm8350.c
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <asm/div64.h>
+#include "lm49453.h"
+
+static struct reg_default lm49453_reg_defs[] = {
+       { 0, 0x00 },
+       { 1, 0x00 },
+       { 2, 0x00 },
+       { 3, 0x00 },
+       { 4, 0x00 },
+       { 5, 0x00 },
+       { 6, 0x00 },
+       { 7, 0x00 },
+       { 8, 0x00 },
+       { 9, 0x00 },
+       { 10, 0x00 },
+       { 11, 0x00 },
+       { 12, 0x00 },
+       { 13, 0x00 },
+       { 14, 0x00 },
+       { 15, 0x00 },
+       { 16, 0x00 },
+       { 17, 0x00 },
+       { 18, 0x00 },
+       { 19, 0x00 },
+       { 20, 0x00 },
+       { 21, 0x00 },
+       { 22, 0x00 },
+       { 23, 0x00 },
+       { 32, 0x00 },
+       { 33, 0x00 },
+       { 35, 0x00 },
+       { 36, 0x00 },
+       { 37, 0x00 },
+       { 46, 0x00 },
+       { 48, 0x00 },
+       { 49, 0x00 },
+       { 51, 0x00 },
+       { 56, 0x00 },
+       { 58, 0x00 },
+       { 59, 0x00 },
+       { 60, 0x00 },
+       { 61, 0x00 },
+       { 62, 0x00 },
+       { 63, 0x00 },
+       { 64, 0x00 },
+       { 65, 0x00 },
+       { 66, 0x00 },
+       { 67, 0x00 },
+       { 68, 0x00 },
+       { 69, 0x00 },
+       { 70, 0x00 },
+       { 71, 0x00 },
+       { 72, 0x00 },
+       { 73, 0x00 },
+       { 74, 0x00 },
+       { 75, 0x00 },
+       { 76, 0x00 },
+       { 77, 0x00 },
+       { 78, 0x00 },
+       { 79, 0x00 },
+       { 80, 0x00 },
+       { 81, 0x00 },
+       { 82, 0x00 },
+       { 83, 0x00 },
+       { 85, 0x00 },
+       { 85, 0x00 },
+       { 86, 0x00 },
+       { 87, 0x00 },
+       { 88, 0x00 },
+       { 89, 0x00 },
+       { 90, 0x00 },
+       { 91, 0x00 },
+       { 92, 0x00 },
+       { 93, 0x00 },
+       { 94, 0x00 },
+       { 95, 0x00 },
+       { 96, 0x01 },
+       { 97, 0x00 },
+       { 98, 0x00 },
+       { 99, 0x00 },
+       { 100, 0x00 },
+       { 101, 0x00 },
+       { 102, 0x00 },
+       { 103, 0x01 },
+       { 105, 0x01 },
+       { 106, 0x00 },
+       { 107, 0x01 },
+       { 107, 0x00 },
+       { 108, 0x00 },
+       { 109, 0x00 },
+       { 110, 0x00 },
+       { 111, 0x02 },
+       { 112, 0x02 },
+       { 113, 0x00 },
+       { 121, 0x80 },
+       { 122, 0xBB },
+       { 123, 0x80 },
+       { 124, 0xBB },
+       { 128, 0x00 },
+       { 130, 0x00 },
+       { 131, 0x00 },
+       { 132, 0x00 },
+       { 133, 0x0A },
+       { 134, 0x0A },
+       { 135, 0x0A },
+       { 136, 0x0F },
+       { 137, 0x00 },
+       { 138, 0x73 },
+       { 139, 0x33 },
+       { 140, 0x73 },
+       { 141, 0x33 },
+       { 142, 0x73 },
+       { 143, 0x33 },
+       { 144, 0x73 },
+       { 145, 0x33 },
+       { 146, 0x73 },
+       { 147, 0x33 },
+       { 148, 0x73 },
+       { 149, 0x33 },
+       { 150, 0x73 },
+       { 151, 0x33 },
+       { 152, 0x00 },
+       { 153, 0x00 },
+       { 154, 0x00 },
+       { 155, 0x00 },
+       { 176, 0x00 },
+       { 177, 0x00 },
+       { 178, 0x00 },
+       { 179, 0x00 },
+       { 180, 0x00 },
+       { 181, 0x00 },
+       { 182, 0x00 },
+       { 183, 0x00 },
+       { 184, 0x00 },
+       { 185, 0x00 },
+       { 186, 0x00 },
+       { 189, 0x00 },
+       { 188, 0x00 },
+       { 194, 0x00 },
+       { 195, 0x00 },
+       { 196, 0x00 },
+       { 197, 0x00 },
+       { 200, 0x00 },
+       { 201, 0x00 },
+       { 202, 0x00 },
+       { 203, 0x00 },
+       { 204, 0x00 },
+       { 205, 0x00 },
+       { 208, 0x00 },
+       { 209, 0x00 },
+       { 210, 0x00 },
+       { 211, 0x00 },
+       { 213, 0x00 },
+       { 214, 0x00 },
+       { 215, 0x00 },
+       { 216, 0x00 },
+       { 217, 0x00 },
+       { 218, 0x00 },
+       { 219, 0x00 },
+       { 221, 0x00 },
+       { 222, 0x00 },
+       { 224, 0x00 },
+       { 225, 0x00 },
+       { 226, 0x00 },
+       { 227, 0x00 },
+       { 228, 0x00 },
+       { 229, 0x00 },
+       { 230, 0x13 },
+       { 231, 0x00 },
+       { 232, 0x80 },
+       { 233, 0x0C },
+       { 234, 0xDD },
+       { 235, 0x00 },
+       { 236, 0x04 },
+       { 237, 0x00 },
+       { 238, 0x00 },
+       { 239, 0x00 },
+       { 240, 0x00 },
+       { 241, 0x00 },
+       { 242, 0x00 },
+       { 243, 0x00 },
+       { 244, 0x00 },
+       { 245, 0x00 },
+       { 248, 0x00 },
+       { 249, 0x00 },
+       { 254, 0x00 },
+       { 255, 0x00 },
+};
+
+/* codec private data */
+struct lm49453_priv {
+       struct regmap *regmap;
+       int fs_rate;
+};
+
+/* capture path controls */
+
+static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"};
+
+static const SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5,
+                                 lm49453_mic2mode_text);
+
+static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"};
+
+static const SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum,
+                                 LM49453_P0_DIGITAL_MIC1_CONFIG_REG,
+                                 7, lm49453_dmic_cfg_text);
+
+static const SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum,
+                                 LM49453_P0_DIGITAL_MIC2_CONFIG_REG,
+                                 7, lm49453_dmic_cfg_text);
+
+/* MUX Controls */
+static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" };
+
+static const char *lm49453_adcr_mux_text[] = { "MIC2", "Aux_R" };
+
+static const struct soc_enum lm49453_adcl_enum =
+       SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 0,
+                       ARRAY_SIZE(lm49453_adcl_mux_text),
+                       lm49453_adcl_mux_text);
+
+static const struct soc_enum lm49453_adcr_enum =
+       SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 1,
+                       ARRAY_SIZE(lm49453_adcr_mux_text),
+                       lm49453_adcr_mux_text);
+
+static const struct snd_kcontrol_new lm49453_adcl_mux_control =
+       SOC_DAPM_ENUM("ADC Left Mux", lm49453_adcl_enum);
+
+static const struct snd_kcontrol_new lm49453_adcr_mux_control =
+       SOC_DAPM_ENUM("ADC Right Mux", lm49453_adcr_enum);
+
+static const struct snd_kcontrol_new lm49453_headset_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHPL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHPL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHPL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHPL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHPL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHPL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHPL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHPL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHPL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHPL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHPL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHPL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHPL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHPL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHPL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHPL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 0, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_headset_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHPR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHPR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHPR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHPR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHPR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHPR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHPR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHPR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHPR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHPR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHPR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHPR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHPR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHPR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHPR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHPR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 1, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_speaker_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLSL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLSL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLSL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLSL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLSL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLSL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLSL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLSL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLSL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLSL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLSL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLSL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLSL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLSL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLSL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLSL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 2, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_speaker_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLSR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLSR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLSR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLSR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLSR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLSR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLSR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLSR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLSR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLSR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLSR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLSR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLSR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLSR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLSR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLSR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 3, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_haptic_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHAL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHAL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHAL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHAL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHAL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHAL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHAL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHAL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHAL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHAL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHAL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHAL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHAL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHAL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHAL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHAL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 4, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_haptic_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHAR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHAR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHAR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHAR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHAR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHAR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHAR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHAR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHAR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHAR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHAR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHAR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHAR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHAR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHAR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHAR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 5, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_lineout_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLOL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLOL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLOL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLOL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLOL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLOL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLOL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLOL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLOL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLOL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLOL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLOL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLOL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLOL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLOL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLOL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 6, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_lineout_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLOR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLOR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLOR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLOR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLOR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLOR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLOR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLOR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLOR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLOR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLOR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLOR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLOR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLOR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLOR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLOR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 7, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx1_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_PORT1_TX1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_PORT1_TX1_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx2_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_PORT1_TX2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT1_TX2_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx3_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX3_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX3_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX3_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX3_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX3_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX3_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_PORT1_TX3_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx4_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX4_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX4_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX4_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX4_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX4_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX4_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_PORT1_TX4_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx5_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX5_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX5_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX5_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX5_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX5_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX5_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_PORT1_TX5_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx6_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX6_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX6_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX6_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX6_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX6_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX6_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_PORT1_TX6_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx7_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX7_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX7_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX7_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX7_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX7_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX7_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_PORT1_TX7_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx8_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX8_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX8_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX8_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX8_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX8_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX8_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_PORT1_TX8_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port2_tx1_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT2_TX1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT2_TX1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT2_TX1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT2_TX1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT2_TX1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT2_TX1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_PORT2_TX1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_PORT2_TX1_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port2_tx2_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT2_TX2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT2_TX2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT2_TX2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT2_TX2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT2_TX2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT2_TX2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_PORT2_TX2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT2_TX2_REG, 7, 1, 0),
+};
+
+/* TLV Declarations */
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7650, 150, 1);
+static const DECLARE_TLV_DB_SCALE(port_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new lm49453_sidetone_mixer_controls[] = {
+/* Sidetone supports mono only */
+SOC_DAPM_SINGLE_TLV("Sidetone ADCL Volume", LM49453_P0_STN_VOL_ADCL_REG,
+                    0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone ADCR Volume", LM49453_P0_STN_VOL_ADCR_REG,
+                    0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC1L Volume", LM49453_P0_STN_VOL_DMIC1L_REG,
+                    0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC1R Volume", LM49453_P0_STN_VOL_DMIC1R_REG,
+                    0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC2L Volume", LM49453_P0_STN_VOL_DMIC2L_REG,
+                    0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC2R Volume", LM49453_P0_STN_VOL_DMIC2R_REG,
+                    0, 0x3F, 0, digital_tlv),
+};
+
+static const struct snd_kcontrol_new lm49453_snd_controls[] = {
+       /* mic1 and mic2 supports mono only */
+       SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_ADC_LEVELL_REG, 0, 6,
+                       0, digital_tlv),
+       SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_ADC_LEVELR_REG, 0, 6,
+                       0, digital_tlv),
+
+       SOC_DOUBLE_R_TLV("DMIC1 Volume", LM49453_P0_DMIC1_LEVELL_REG,
+                         LM49453_P0_DMIC1_LEVELR_REG, 0, 6, 0, digital_tlv),
+       SOC_DOUBLE_R_TLV("DMIC2 Volume", LM49453_P0_DMIC2_LEVELL_REG,
+                         LM49453_P0_DMIC2_LEVELR_REG, 0, 6, 0, digital_tlv),
+
+       SOC_DAPM_ENUM("Mic2Mode", lm49453_mic2mode_enum),
+       SOC_DAPM_ENUM("DMIC12 SRC", lm49453_dmic12_cfg_enum),
+       SOC_DAPM_ENUM("DMIC34 SRC", lm49453_dmic34_cfg_enum),
+
+       /* Capture path filter enable */
+       SOC_SINGLE("DMIC1 HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+                                           0, 1, 0),
+       SOC_SINGLE("DMIC2 HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+                                           1, 1, 0),
+       SOC_SINGLE("ADC HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+                                         2, 1, 0),
+
+       SOC_DOUBLE_R_TLV("DAC HP Volume", LM49453_P0_DAC_HP_LEVELL_REG,
+                         LM49453_P0_DAC_HP_LEVELR_REG, 0, 6, 0, digital_tlv),
+       SOC_DOUBLE_R_TLV("DAC LO Volume", LM49453_P0_DAC_LO_LEVELL_REG,
+                         LM49453_P0_DAC_LO_LEVELR_REG, 0, 6, 0, digital_tlv),
+       SOC_DOUBLE_R_TLV("DAC LS Volume", LM49453_P0_DAC_LS_LEVELL_REG,
+                         LM49453_P0_DAC_LS_LEVELR_REG, 0, 6, 0, digital_tlv),
+       SOC_DOUBLE_R_TLV("DAC HA Volume", LM49453_P0_DAC_HA_LEVELL_REG,
+                         LM49453_P0_DAC_HA_LEVELR_REG, 0, 6, 0, digital_tlv),
+
+       SOC_SINGLE_TLV("EP Volume", LM49453_P0_DAC_LS_LEVELL_REG,
+                       0, 6, 0, digital_tlv),
+
+       SOC_SINGLE_TLV("PORT1_1_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+                       0, 3, 0, port_tlv),
+       SOC_SINGLE_TLV("PORT1_2_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+                       2, 3, 0, port_tlv),
+       SOC_SINGLE_TLV("PORT1_3_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+                       4, 3, 0, port_tlv),
+       SOC_SINGLE_TLV("PORT1_4_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+                       6, 3, 0, port_tlv),
+       SOC_SINGLE_TLV("PORT1_5_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+                       0, 3, 0, port_tlv),
+       SOC_SINGLE_TLV("PORT1_6_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+                       2, 3, 0, port_tlv),
+       SOC_SINGLE_TLV("PORT1_7_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+                       4, 3, 0, port_tlv),
+       SOC_SINGLE_TLV("PORT1_8_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+                       6, 3, 0, port_tlv),
+
+       SOC_SINGLE_TLV("PORT2_1_RX_LVL Volume", LM49453_P0_PORT2_RX_LVL_REG,
+                       0, 3, 0, port_tlv),
+       SOC_SINGLE_TLV("PORT2_2_RX_LVL Volume", LM49453_P0_PORT2_RX_LVL_REG,
+                       2, 3, 0, port_tlv),
+
+       SOC_SINGLE("Port1 Playback Switch", LM49453_P0_AUDIO_PORT1_BASIC_REG,
+                   1, 1, 0),
+       SOC_SINGLE("Port2 Playback Switch", LM49453_P0_AUDIO_PORT2_BASIC_REG,
+                   1, 1, 0),
+       SOC_SINGLE("Port1 Capture Switch", LM49453_P0_AUDIO_PORT1_BASIC_REG,
+                   2, 1, 0),
+       SOC_SINGLE("Port2 Capture Switch", LM49453_P0_AUDIO_PORT2_BASIC_REG,
+                   2, 1, 0)
+
+};
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget lm49453_dapm_widgets[] = {
+
+       /* All end points HP,EP, LS, Lineout and Haptic */
+       SND_SOC_DAPM_OUTPUT("HPOUTL"),
+       SND_SOC_DAPM_OUTPUT("HPOUTR"),
+       SND_SOC_DAPM_OUTPUT("EPOUT"),
+       SND_SOC_DAPM_OUTPUT("LSOUTL"),
+       SND_SOC_DAPM_OUTPUT("LSOUTR"),
+       SND_SOC_DAPM_OUTPUT("LOOUTR"),
+       SND_SOC_DAPM_OUTPUT("LOOUTL"),
+       SND_SOC_DAPM_OUTPUT("HAOUTL"),
+       SND_SOC_DAPM_OUTPUT("HAOUTR"),
+
+       SND_SOC_DAPM_INPUT("AMIC1"),
+       SND_SOC_DAPM_INPUT("AMIC2"),
+       SND_SOC_DAPM_INPUT("DMIC1DAT"),
+       SND_SOC_DAPM_INPUT("DMIC2DAT"),
+       SND_SOC_DAPM_INPUT("AUXL"),
+       SND_SOC_DAPM_INPUT("AUXR"),
+
+       SND_SOC_DAPM_PGA("PORT1_1_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PORT1_2_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PORT1_3_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PORT1_4_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PORT1_5_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PORT1_6_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PORT1_7_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PORT1_8_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PORT2_1_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PORT2_2_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("AMIC1Bias", LM49453_P0_MICL_REG, 6, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("AMIC2Bias", LM49453_P0_MICR_REG, 6, 0, NULL, 0),
+
+       /* playback path driver enables */
+       SND_SOC_DAPM_OUT_DRV("Headset Switch",
+                       LM49453_P0_PMC_SETUP_REG, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("Earpiece Switch",
+                       LM49453_P0_EP_REG, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("Speaker Left Switch",
+                       LM49453_P0_DIS_PKVL_FB_REG, 0, 1, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("Speaker Right Switch",
+                       LM49453_P0_DIS_PKVL_FB_REG, 1, 1, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("Haptic Left Switch",
+                       LM49453_P0_DIS_PKVL_FB_REG, 2, 1, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("Haptic Right Switch",
+                       LM49453_P0_DIS_PKVL_FB_REG, 3, 1, NULL, 0),
+
+       /* DAC */
+       SND_SOC_DAPM_DAC("HPL DAC", "Headset", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("HPR DAC", "Headset", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("LSL DAC", "Speaker", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("LSR DAC", "Speaker", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("HAL DAC", "Haptic", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("HAR DAC", "Haptic", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("LOL DAC", "Lineout", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("LOR DAC", "Lineout", SND_SOC_NOPM, 0, 0),
+
+
+       SND_SOC_DAPM_PGA("AUXL Input",
+                       LM49453_P0_ANALOG_MIXER_ADC_REG, 2, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("AUXR Input",
+                       LM49453_P0_ANALOG_MIXER_ADC_REG, 3, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Sidetone", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* ADC */
+       SND_SOC_DAPM_ADC("DMIC1 Left", "Capture", SND_SOC_NOPM, 1, 0),
+       SND_SOC_DAPM_ADC("DMIC1 Right", "Capture", SND_SOC_NOPM, 1, 0),
+       SND_SOC_DAPM_ADC("DMIC2 Left", "Capture", SND_SOC_NOPM, 1, 0),
+       SND_SOC_DAPM_ADC("DMIC2 Right", "Capture", SND_SOC_NOPM, 1, 0),
+
+       SND_SOC_DAPM_ADC("ADC Left", "Capture", SND_SOC_NOPM, 1, 0),
+       SND_SOC_DAPM_ADC("ADC Right", "Capture", SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_MUX("ADCL Mux", SND_SOC_NOPM, 0, 0,
+                         &lm49453_adcl_mux_control),
+       SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0,
+                         &lm49453_adcr_mux_control),
+
+       SND_SOC_DAPM_MUX("Mic1 Input",
+                       SND_SOC_NOPM, 0, 0, &lm49453_adcl_mux_control),
+
+       SND_SOC_DAPM_MUX("Mic2 Input",
+                       SND_SOC_NOPM, 0, 0, &lm49453_adcr_mux_control),
+
+       /* AIF */
+       SND_SOC_DAPM_AIF_IN("PORT1_SDI", NULL, 0,
+                           LM49453_P0_PULL_CONFIG1_REG, 2, 0),
+       SND_SOC_DAPM_AIF_IN("PORT2_SDI", NULL, 0,
+                           LM49453_P0_PULL_CONFIG1_REG, 6, 0),
+
+       SND_SOC_DAPM_AIF_OUT("PORT1_SDO", NULL, 0,
+                            LM49453_P0_PULL_CONFIG1_REG, 3, 0),
+       SND_SOC_DAPM_AIF_OUT("PORT2_SDO", NULL, 0,
+                             LM49453_P0_PULL_CONFIG1_REG, 7, 0),
+
+       /* Port1 TX controls */
+       SND_SOC_DAPM_OUT_DRV("P1_1_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("P1_2_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("P1_3_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("P1_4_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("P1_5_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("P1_6_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("P1_7_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("P1_8_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Port2 TX controls */
+       SND_SOC_DAPM_OUT_DRV("P2_1_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("P2_2_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Sidetone Mixer */
+       SND_SOC_DAPM_MIXER("Sidetone Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_sidetone_mixer_controls,
+                           ARRAY_SIZE(lm49453_sidetone_mixer_controls)),
+
+       /* DAC MIXERS */
+       SND_SOC_DAPM_MIXER("HPL Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_headset_left_mixer,
+                           ARRAY_SIZE(lm49453_headset_left_mixer)),
+       SND_SOC_DAPM_MIXER("HPR Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_headset_right_mixer,
+                           ARRAY_SIZE(lm49453_headset_right_mixer)),
+       SND_SOC_DAPM_MIXER("LOL Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_lineout_left_mixer,
+                           ARRAY_SIZE(lm49453_lineout_left_mixer)),
+       SND_SOC_DAPM_MIXER("LOR Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_lineout_right_mixer,
+                           ARRAY_SIZE(lm49453_lineout_right_mixer)),
+       SND_SOC_DAPM_MIXER("LSL Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_speaker_left_mixer,
+                           ARRAY_SIZE(lm49453_speaker_left_mixer)),
+       SND_SOC_DAPM_MIXER("LSR Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_speaker_right_mixer,
+                           ARRAY_SIZE(lm49453_speaker_right_mixer)),
+       SND_SOC_DAPM_MIXER("HAL Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_haptic_left_mixer,
+                           ARRAY_SIZE(lm49453_haptic_left_mixer)),
+       SND_SOC_DAPM_MIXER("HAR Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_haptic_right_mixer,
+                           ARRAY_SIZE(lm49453_haptic_right_mixer)),
+
+       /* Capture Mixer */
+       SND_SOC_DAPM_MIXER("Port1_1 Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_port1_tx1_mixer,
+                           ARRAY_SIZE(lm49453_port1_tx1_mixer)),
+       SND_SOC_DAPM_MIXER("Port1_2 Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_port1_tx2_mixer,
+                           ARRAY_SIZE(lm49453_port1_tx2_mixer)),
+       SND_SOC_DAPM_MIXER("Port1_3 Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_port1_tx3_mixer,
+                           ARRAY_SIZE(lm49453_port1_tx3_mixer)),
+       SND_SOC_DAPM_MIXER("Port1_4 Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_port1_tx4_mixer,
+                           ARRAY_SIZE(lm49453_port1_tx4_mixer)),
+       SND_SOC_DAPM_MIXER("Port1_5 Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_port1_tx5_mixer,
+                           ARRAY_SIZE(lm49453_port1_tx5_mixer)),
+       SND_SOC_DAPM_MIXER("Port1_6 Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_port1_tx6_mixer,
+                           ARRAY_SIZE(lm49453_port1_tx6_mixer)),
+       SND_SOC_DAPM_MIXER("Port1_7 Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_port1_tx7_mixer,
+                           ARRAY_SIZE(lm49453_port1_tx7_mixer)),
+       SND_SOC_DAPM_MIXER("Port1_8 Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_port1_tx8_mixer,
+                           ARRAY_SIZE(lm49453_port1_tx8_mixer)),
+
+       SND_SOC_DAPM_MIXER("Port2_1 Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_port2_tx1_mixer,
+                           ARRAY_SIZE(lm49453_port2_tx1_mixer)),
+       SND_SOC_DAPM_MIXER("Port2_2 Mixer", SND_SOC_NOPM, 0, 0,
+                           lm49453_port2_tx2_mixer,
+                           ARRAY_SIZE(lm49453_port2_tx2_mixer)),
+};
+
+static const struct snd_soc_dapm_route lm49453_audio_map[] = {
+       /* Port SDI mapping */
+       { "PORT1_1_RX", "Port1 Playback Switch", "PORT1_SDI" },
+       { "PORT1_2_RX", "Port1 Playback Switch", "PORT1_SDI" },
+       { "PORT1_3_RX", "Port1 Playback Switch", "PORT1_SDI" },
+       { "PORT1_4_RX", "Port1 Playback Switch", "PORT1_SDI" },
+       { "PORT1_5_RX", "Port1 Playback Switch", "PORT1_SDI" },
+       { "PORT1_6_RX", "Port1 Playback Switch", "PORT1_SDI" },
+       { "PORT1_7_RX", "Port1 Playback Switch", "PORT1_SDI" },
+       { "PORT1_8_RX", "Port1 Playback Switch", "PORT1_SDI" },
+
+       { "PORT2_1_RX", "Port2 Playback Switch", "PORT2_SDI" },
+       { "PORT2_2_RX", "Port2 Playback Switch", "PORT2_SDI" },
+
+       /* HP mapping */
+       { "HPL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+       { "HPL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+       { "HPL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+       { "HPL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+       { "HPL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+       { "HPL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+       { "HPL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+       { "HPL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+       { "HPL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+       { "HPL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+       { "HPL Mixer", "ADCL Switch", "ADC Left" },
+       { "HPL Mixer", "ADCR Switch", "ADC Right" },
+       { "HPL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "HPL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "HPL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "HPL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+       { "HPL Mixer", "Sidetone Switch", "Sidetone" },
+
+       { "HPL DAC", NULL, "HPL Mixer" },
+
+       { "HPR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+       { "HPR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+       { "HPR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+       { "HPR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+       { "HPR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+       { "HPR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+       { "HPR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+       { "HPR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+       /* Port 2 */
+       { "HPR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+       { "HPR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+       { "HPR Mixer", "ADCL Switch", "ADC Left" },
+       { "HPR Mixer", "ADCR Switch", "ADC Right" },
+       { "HPR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "HPR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "HPR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "HPR Mixer", "DMIC2L Switch", "DMIC2 Right" },
+       { "HPR Mixer", "Sidetone Switch", "Sidetone" },
+
+       { "HPR DAC", NULL, "HPR Mixer" },
+
+       { "HPOUTL", "Headset Switch", "HPL DAC"},
+       { "HPOUTR", "Headset Switch", "HPR DAC"},
+
+       /* EP map */
+       { "EPOUT", "Earpiece Switch", "HPL DAC" },
+
+       /* Speaker map */
+       { "LSL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+       { "LSL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+       { "LSL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+       { "LSL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+       { "LSL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+       { "LSL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+       { "LSL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+       { "LSL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+       /* Port 2 */
+       { "LSL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+       { "LSL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+       { "LSL Mixer", "ADCL Switch", "ADC Left" },
+       { "LSL Mixer", "ADCR Switch", "ADC Right" },
+       { "LSL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "LSL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "LSL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "LSL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+       { "LSL Mixer", "Sidetone Switch", "Sidetone" },
+
+       { "LSL DAC", NULL, "LSL Mixer" },
+
+       { "LSR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+       { "LSR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+       { "LSR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+       { "LSR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+       { "LSR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+       { "LSR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+       { "LSR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+       { "LSR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+       /* Port 2 */
+       { "LSR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+       { "LSR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+       { "LSR Mixer", "ADCL Switch", "ADC Left" },
+       { "LSR Mixer", "ADCR Switch", "ADC Right" },
+       { "LSR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "LSR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "LSR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "LSR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+       { "LSR Mixer", "Sidetone Switch", "Sidetone" },
+
+       { "LSR DAC", NULL, "LSR Mixer" },
+
+       { "LSOUTL", "Speaker Left Switch", "LSL DAC"},
+       { "LSOUTR", "Speaker Left Switch", "LSR DAC"},
+
+       /* Haptic map */
+       { "HAL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+       { "HAL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+       { "HAL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+       { "HAL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+       { "HAL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+       { "HAL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+       { "HAL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+       { "HAL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+       /* Port 2 */
+       { "HAL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+       { "HAL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+       { "HAL Mixer", "ADCL Switch", "ADC Left" },
+       { "HAL Mixer", "ADCR Switch", "ADC Right" },
+       { "HAL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "HAL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "HAL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "HAL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+       { "HAL Mixer", "Sidetone Switch", "Sidetone" },
+
+       { "HAL DAC", NULL, "HAL Mixer" },
+
+       { "HAR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+       { "HAR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+       { "HAR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+       { "HAR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+       { "HAR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+       { "HAR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+       { "HAR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+       { "HAR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+       /* Port 2 */
+       { "HAR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+       { "HAR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+       { "HAR Mixer", "ADCL Switch", "ADC Left" },
+       { "HAR Mixer", "ADCR Switch", "ADC Right" },
+       { "HAR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "HAR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "HAR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "HAR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+       { "HAR Mixer", "Sideton Switch", "Sidetone" },
+
+       { "HAR DAC", NULL, "HAR Mixer" },
+
+       { "HAOUTL", "Haptic Left Switch", "HAL DAC" },
+       { "HAOUTR", "Haptic Right Switch", "HAR DAC" },
+
+       /* Lineout map */
+       { "LOL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+       { "LOL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+       { "LOL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+       { "LOL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+       { "LOL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+       { "LOL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+       { "LOL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+       { "LOL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+       /* Port 2 */
+       { "LOL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+       { "LOL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+       { "LOL Mixer", "ADCL Switch", "ADC Left" },
+       { "LOL Mixer", "ADCR Switch", "ADC Right" },
+       { "LOL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "LOL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "LOL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "LOL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+       { "LOL Mixer", "Sidetone Switch", "Sidetone" },
+
+       { "LOL DAC", NULL, "LOL Mixer" },
+
+       { "LOR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+       { "LOR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+       { "LOR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+       { "LOR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+       { "LOR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+       { "LOR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+       { "LOR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+       { "LOR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+       /* Port 2 */
+       { "LOR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+       { "LOR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+       { "LOR Mixer", "ADCL Switch", "ADC Left" },
+       { "LOR Mixer", "ADCR Switch", "ADC Right" },
+       { "LOR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "LOR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "LOR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "LOR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+       { "LOR Mixer", "Sidetone Switch", "Sidetone" },
+
+       { "LOR DAC", NULL, "LOR Mixer" },
+
+       { "LOOUTL", NULL, "LOL DAC" },
+       { "LOOUTR", NULL, "LOR DAC" },
+
+       /* TX map */
+       /* Port1 mappings */
+       { "Port1_1 Mixer", "ADCL Switch", "ADC Left" },
+       { "Port1_1 Mixer", "ADCR Switch", "ADC Right" },
+       { "Port1_1 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "Port1_1 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "Port1_1 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "Port1_1 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+       { "Port1_2 Mixer", "ADCL Switch", "ADC Left" },
+       { "Port1_2 Mixer", "ADCR Switch", "ADC Right" },
+       { "Port1_2 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "Port1_2 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "Port1_2 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "Port1_2 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+       { "Port1_3 Mixer", "ADCL Switch", "ADC Left" },
+       { "Port1_3 Mixer", "ADCR Switch", "ADC Right" },
+       { "Port1_3 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "Port1_3 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "Port1_3 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "Port1_3 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+       { "Port1_4 Mixer", "ADCL Switch", "ADC Left" },
+       { "Port1_4 Mixer", "ADCR Switch", "ADC Right" },
+       { "Port1_4 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "Port1_4 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "Port1_4 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "Port1_4 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+       { "Port1_5 Mixer", "ADCL Switch", "ADC Left" },
+       { "Port1_5 Mixer", "ADCR Switch", "ADC Right" },
+       { "Port1_5 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "Port1_5 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "Port1_5 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "Port1_5 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+       { "Port1_6 Mixer", "ADCL Switch", "ADC Left" },
+       { "Port1_6 Mixer", "ADCR Switch", "ADC Right" },
+       { "Port1_6 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "Port1_6 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "Port1_6 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "Port1_6 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+       { "Port1_7 Mixer", "ADCL Switch", "ADC Left" },
+       { "Port1_7 Mixer", "ADCR Switch", "ADC Right" },
+       { "Port1_7 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "Port1_7 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "Port1_7 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "Port1_7 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+       { "Port1_8 Mixer", "ADCL Switch", "ADC Left" },
+       { "Port1_8 Mixer", "ADCR Switch", "ADC Right" },
+       { "Port1_8 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "Port1_8 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "Port1_8 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "Port1_8 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+       { "Port2_1 Mixer", "ADCL Switch", "ADC Left" },
+       { "Port2_1 Mixer", "ADCR Switch", "ADC Right" },
+       { "Port2_1 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "Port2_1 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "Port2_1 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "Port2_1 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+       { "Port2_2 Mixer", "ADCL Switch", "ADC Left" },
+       { "Port2_2 Mixer", "ADCR Switch", "ADC Right" },
+       { "Port2_2 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+       { "Port2_2 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+       { "Port2_2 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+       { "Port2_2 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+       { "P1_1_TX", NULL, "Port1_1 Mixer" },
+       { "P1_2_TX", NULL, "Port1_2 Mixer" },
+       { "P1_3_TX", NULL, "Port1_3 Mixer" },
+       { "P1_4_TX", NULL, "Port1_4 Mixer" },
+       { "P1_5_TX", NULL, "Port1_5 Mixer" },
+       { "P1_6_TX", NULL, "Port1_6 Mixer" },
+       { "P1_7_TX", NULL, "Port1_7 Mixer" },
+       { "P1_8_TX", NULL, "Port1_8 Mixer" },
+
+       { "P2_1_TX", NULL, "Port2_1 Mixer" },
+       { "P2_2_TX", NULL, "Port2_2 Mixer" },
+
+       { "PORT1_SDO", "Port1 Capture Switch", "P1_1_TX"},
+       { "PORT1_SDO", "Port1 Capture Switch", "P1_2_TX"},
+       { "PORT1_SDO", "Port1 Capture Switch", "P1_3_TX"},
+       { "PORT1_SDO", "Port1 Capture Switch", "P1_4_TX"},
+       { "PORT1_SDO", "Port1 Capture Switch", "P1_5_TX"},
+       { "PORT1_SDO", "Port1 Capture Switch", "P1_6_TX"},
+       { "PORT1_SDO", "Port1 Capture Switch", "P1_7_TX"},
+       { "PORT1_SDO", "Port1 Capture Switch", "P1_8_TX"},
+
+       { "PORT2_SDO", "Port2 Capture Switch", "P2_1_TX"},
+       { "PORT2_SDO", "Port2 Capture Switch", "P2_2_TX"},
+
+       { "Mic1 Input", NULL, "AMIC1" },
+       { "Mic2 Input", NULL, "AMIC2" },
+
+       { "AUXL Input", NULL, "AUXL" },
+       { "AUXR Input", NULL, "AUXR" },
+
+       /* AUX connections */
+       { "ADCL Mux", "Aux_L", "AUXL Input" },
+       { "ADCL Mux", "MIC1", "Mic1 Input" },
+
+       { "ADCR Mux", "Aux_R", "AUXR Input" },
+       { "ADCR Mux", "MIC2", "Mic2 Input" },
+
+       /* ADC connection */
+       { "ADC Left", NULL, "ADCL Mux"},
+       { "ADC Right", NULL, "ADCR Mux"},
+
+       { "DMIC1 Left", NULL, "DMIC1DAT"},
+       { "DMIC1 Right", NULL, "DMIC1DAT"},
+       { "DMIC2 Left", NULL, "DMIC2DAT"},
+       { "DMIC2 Right", NULL, "DMIC2DAT"},
+
+       /* Sidetone map */
+       { "Sidetone Mixer", NULL, "ADC Left" },
+       { "Sidetone Mixer", NULL, "ADC Right" },
+       { "Sidetone Mixer", NULL, "DMIC1 Left" },
+       { "Sidetone Mixer", NULL, "DMIC1 Right" },
+       { "Sidetone Mixer", NULL, "DMIC2 Left" },
+       { "Sidetone Mixer", NULL, "DMIC2 Right" },
+
+       { "Sidetone", "Sidetone Switch", "Sidetone Mixer" },
+};
+
+static int lm49453_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+       u16 clk_div = 0;
+
+       lm49453->fs_rate = params_rate(params);
+
+       /* Setting DAC clock dividers based on substream sample rate. */
+       switch (lm49453->fs_rate) {
+       case 8000:
+       case 16000:
+       case 32000:
+       case 24000:
+       case 48000:
+               clk_div = 256;
+               break;
+       case 11025:
+       case 22050:
+       case 44100:
+               clk_div = 216;
+               break;
+       case 96000:
+               clk_div = 127;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_write(codec, LM49453_P0_ADC_CLK_DIV_REG, clk_div);
+       snd_soc_write(codec, LM49453_P0_DAC_HP_CLK_DIV_REG, clk_div);
+
+       return 0;
+}
+
+static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+
+       u16 aif_val;
+       int mode = 0;
+       int clk_phase = 0;
+       int clk_shift = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               aif_val = 0;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               aif_val = LM49453_AUDIO_PORT1_BASIC_SYNC_MS;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               aif_val = LM49453_AUDIO_PORT1_BASIC_CLK_MS;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               aif_val = LM49453_AUDIO_PORT1_BASIC_CLK_MS |
+                         LM49453_AUDIO_PORT1_BASIC_SYNC_MS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               mode = 1;
+               clk_phase = (1 << 5);
+               clk_shift = 1;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               mode = 1;
+               clk_phase = (1 << 5);
+               clk_shift = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, LM49453_P0_AUDIO_PORT1_BASIC_REG,
+                           LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(1)|BIT(5),
+                           (aif_val | mode | clk_phase));
+
+       snd_soc_write(codec, LM49453_P0_AUDIO_PORT1_RX_MSB_REG, clk_shift);
+
+       return 0;
+}
+
+static int lm49453_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+                                 unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 pll_clk = 0;
+
+       switch (freq) {
+       case 12288000:
+       case 26000000:
+       case 19200000:
+               /* pll clk slection */
+               pll_clk = 0;
+               break;
+       case 48000:
+       case 32576:
+               /* fll clk slection */
+               pll_clk = BIT(4);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG, BIT(4), pll_clk);
+
+       return 0;
+}
+
+static int lm49453_hp_mute(struct snd_soc_dai *dai, int mute)
+{
+       snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(1)|BIT(0),
+                           (mute ? (BIT(1)|BIT(0)) : 0));
+       return 0;
+}
+
+static int lm49453_lo_mute(struct snd_soc_dai *dai, int mute)
+{
+       snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(3)|BIT(2),
+                           (mute ? (BIT(3)|BIT(2)) : 0));
+       return 0;
+}
+
+static int lm49453_ls_mute(struct snd_soc_dai *dai, int mute)
+{
+       snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(5)|BIT(4),
+                           (mute ? (BIT(5)|BIT(4)) : 0));
+       return 0;
+}
+
+static int lm49453_ep_mute(struct snd_soc_dai *dai, int mute)
+{
+       snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(4),
+                           (mute ? BIT(4) : 0));
+       return 0;
+}
+
+static int lm49453_ha_mute(struct snd_soc_dai *dai, int mute)
+{
+       snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(7)|BIT(6),
+                           (mute ? (BIT(7)|BIT(6)) : 0));
+       return 0;
+}
+
+static int lm49453_set_bias_level(struct snd_soc_codec *codec,
+                                 enum snd_soc_bias_level level)
+{
+       struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+                       regcache_sync(lm49453->regmap);
+
+               snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
+                                   LM49453_PMC_SETUP_CHIP_EN, LM49453_CHIP_EN);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
+                                   LM49453_PMC_SETUP_CHIP_EN, 0);
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+/* Formates supported by LM49453 driver. */
+#define LM49453_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops lm49453_headset_dai_ops = {
+       .hw_params      = lm49453_hw_params,
+       .set_sysclk     = lm49453_set_dai_sysclk,
+       .set_fmt        = lm49453_set_dai_fmt,
+       .digital_mute   = lm49453_hp_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_speaker_dai_ops = {
+       .hw_params      = lm49453_hw_params,
+       .set_sysclk     = lm49453_set_dai_sysclk,
+       .set_fmt        = lm49453_set_dai_fmt,
+       .digital_mute   = lm49453_ls_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_haptic_dai_ops = {
+       .hw_params      = lm49453_hw_params,
+       .set_sysclk     = lm49453_set_dai_sysclk,
+       .set_fmt        = lm49453_set_dai_fmt,
+       .digital_mute   = lm49453_ha_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_ep_dai_ops = {
+       .hw_params      = lm49453_hw_params,
+       .set_sysclk     = lm49453_set_dai_sysclk,
+       .set_fmt        = lm49453_set_dai_fmt,
+       .digital_mute   = lm49453_ep_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_lineout_dai_ops = {
+       .hw_params      = lm49453_hw_params,
+       .set_sysclk     = lm49453_set_dai_sysclk,
+       .set_fmt        = lm49453_set_dai_fmt,
+       .digital_mute   = lm49453_lo_mute,
+};
+
+/* LM49453 dai structure. */
+static const struct snd_soc_dai_driver lm49453_dai[] = {
+       {
+               .name = "LM49453 Headset",
+               .playback = {
+                       .stream_name = "Headset",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = LM49453_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 1,
+                       .channels_max = 5,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = LM49453_FORMATS,
+               },
+               .ops = &lm49453_headset_dai_ops,
+               .symmetric_rates = 1,
+       },
+       {
+               .name = "LM49453 Speaker",
+               .playback = {
+                       .stream_name = "Speaker",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = LM49453_FORMATS,
+               },
+               .ops = &lm49453_speaker_dai_ops,
+       },
+       {
+               .name = "LM49453 Haptic",
+               .playback = {
+                       .stream_name = "Haptic",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = LM49453_FORMATS,
+               },
+               .ops = &lm49453_haptic_dai_ops,
+       },
+       {
+               .name = "LM49453 Earpiece",
+               .playback = {
+                       .stream_name = "Earpiece",
+                       .channels_min = 1,
+                       .channels_max = 1,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = LM49453_FORMATS,
+               },
+               .ops = &lm49453_ep_dai_ops,
+       },
+       {
+               .name = "LM49453 line out",
+               .playback = {
+                       .stream_name = "Lineout",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = LM49453_FORMATS,
+               },
+               .ops = &lm49453_lineout_dai_ops,
+       },
+};
+
+static int lm49453_suspend(struct snd_soc_codec *codec)
+{
+       lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int lm49453_resume(struct snd_soc_codec *codec)
+{
+       lm49453_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+
+static int lm49453_probe(struct snd_soc_codec *codec)
+{
+       struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+
+       codec->control_data = lm49453->regmap;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/* power down chip */
+static int lm49453_remove(struct snd_soc_codec *codec)
+{
+       lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
+       .probe = lm49453_probe,
+       .remove = lm49453_remove,
+       .suspend = lm49453_suspend,
+       .resume = lm49453_resume,
+       .set_bias_level = lm49453_set_bias_level,
+       .controls = lm49453_snd_controls,
+       .num_controls = ARRAY_SIZE(lm49453_snd_controls),
+       .dapm_widgets = lm49453_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(lm49453_dapm_widgets),
+       .dapm_routes = lm49453_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(lm49453_audio_map),
+       .idle_bias_off = true,
+};
+
+static const struct regmap_config lm49453_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = LM49453_MAX_REGISTER,
+       .reg_defaults = lm49453_reg_defs,
+       .num_reg_defaults = ARRAY_SIZE(lm49453_reg_defs),
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int lm49453_i2c_probe(struct i2c_client *i2c,
+                                      const struct i2c_device_id *id)
+{
+       struct lm49453_priv *lm49453;
+       int ret = 0;
+
+       lm49453 = devm_kzalloc(&i2c->dev, sizeof(struct lm49453_priv),
+                               GFP_KERNEL);
+
+       if (lm49453 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, lm49453);
+
+       lm49453->regmap = regmap_init_i2c(i2c, &lm49453_regmap_config);
+       if (IS_ERR(lm49453->regmap)) {
+               ret = PTR_ERR(lm49453->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       ret =  snd_soc_register_codec(&i2c->dev,
+                                     &soc_codec_dev_lm49453,
+                                     lm49453_dai, ARRAY_SIZE(lm49453_dai));
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+               regmap_exit(lm49453->regmap);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int __devexit lm49453_i2c_remove(struct i2c_client *client)
+{
+       struct lm49453_priv *lm49453 = i2c_get_clientdata(client);
+
+       snd_soc_unregister_codec(&client->dev);
+       regmap_exit(lm49453->regmap);
+       return 0;
+}
+
+static const struct i2c_device_id lm49453_i2c_id[] = {
+       { "lm49453", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lm49453_i2c_id);
+
+static struct i2c_driver lm49453_i2c_driver = {
+       .driver = {
+               .name = "lm49453",
+               .owner = THIS_MODULE,
+       },
+       .probe = lm49453_i2c_probe,
+       .remove = __devexit_p(lm49453_i2c_remove),
+       .id_table = lm49453_i2c_id,
+};
+
+module_i2c_driver(lm49453_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC LM49453 driver");
+MODULE_AUTHOR("M R Swami Reddy <MR.Swami.Reddy@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/lm49453.h b/sound/soc/codecs/lm49453.h
new file mode 100644 (file)
index 0000000..a63cfa5
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * lm49453.h  -  LM49453 ALSA Soc Audio drive
+ *
+ * Copyright (c) 2012  Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ */
+
+#ifndef _LM49453_H
+#define _LM49453_H
+
+#include <linux/bitops.h>
+
+/* LM49453_P0 register space for page0 */
+#define LM49453_P0_PMC_SETUP_REG                       0x00
+#define LM49453_P0_PLL_CLK_SEL1_REG                    0x01
+#define LM49453_P0_PLL_CLK_SEL2_REG                    0x02
+#define LM49453_P0_PMC_CLK_DIV_REG                     0x03
+#define LM49453_P0_HSDET_CLK_DIV_REG                   0x04
+#define LM49453_P0_DMIC_CLK_DIV_REG                    0x05
+#define LM49453_P0_ADC_CLK_DIV_REG                     0x06
+#define LM49453_P0_DAC_OT_CLK_DIV_REG                  0x07
+#define LM49453_P0_PLL_HF_M_REG                                0x08
+#define LM49453_P0_PLL_LF_M_REG                                0x09
+#define LM49453_P0_PLL_NL_REG                          0x0A
+#define LM49453_P0_PLL_N_MODL_REG                      0x0B
+#define LM49453_P0_PLL_N_MODH_REG                      0x0C
+#define LM49453_P0_PLL_P1_REG                          0x0D
+#define LM49453_P0_PLL_P2_REG                          0x0E
+#define LM49453_P0_FLL_REF_FREQL_REG                   0x0F
+#define LM49453_P0_FLL_REF_FREQH_REG                   0x10
+#define LM49453_P0_VCO_TARGETLL_REG                    0x11
+#define LM49453_P0_VCO_TARGETLH_REG                    0x12
+#define LM49453_P0_VCO_TARGETHL_REG                    0x13
+#define LM49453_P0_VCO_TARGETHH_REG                    0x14
+#define LM49453_P0_PLL_CONFIG_REG                      0x15
+#define LM49453_P0_DAC_CLK_SEL_REG                     0x16
+#define LM49453_P0_DAC_HP_CLK_DIV_REG                  0x17
+
+/* Analog Mixer Input Stages */
+#define LM49453_P0_MICL_REG                            0x20
+#define LM49453_P0_MICR_REG                            0x21
+#define LM49453_P0_EP_REG                              0x24
+#define LM49453_P0_DIS_PKVL_FB_REG                     0x25
+
+/* Analog Mixer Output Stages */
+#define LM49453_P0_ANALOG_MIXER_ADC_REG                        0x2E
+
+/*ADC or DAC */
+#define LM49453_P0_ADC_DSP_REG                         0x30
+#define LM49453_P0_DAC_DSP_REG                         0x31
+
+/* EFFECTS ENABLES */
+#define LM49453_P0_ADC_FX_ENABLES_REG                  0x33
+
+/* GPIO */
+#define LM49453_P0_GPIO1_REG                           0x38
+#define LM49453_P0_GPIO2_REG                           0x39
+#define LM49453_P0_GPIO3_REG                           0x3A
+#define LM49453_P0_HAP_CTL_REG                         0x3B
+#define LM49453_P0_HAP_FREQ_PROG_LEFTL_REG             0x3C
+#define LM49453_P0_HAP_FREQ_PROG_LEFTH_REG             0x3D
+#define LM49453_P0_HAP_FREQ_PROG_RIGHTL_REG            0x3E
+#define LM49453_P0_HAP_FREQ_PROG_RIGHTH_REG            0x3F
+
+/* DIGITAL MIXER */
+#define LM49453_P0_DMIX_CLK_SEL_REG                    0x40
+#define LM49453_P0_PORT1_RX_LVL1_REG                   0x41
+#define LM49453_P0_PORT1_RX_LVL2_REG                   0x42
+#define LM49453_P0_PORT2_RX_LVL_REG                    0x43
+#define LM49453_P0_PORT1_TX1_REG                       0x44
+#define LM49453_P0_PORT1_TX2_REG                       0x45
+#define LM49453_P0_PORT1_TX3_REG                       0x46
+#define LM49453_P0_PORT1_TX4_REG                       0x47
+#define LM49453_P0_PORT1_TX5_REG                       0x48
+#define LM49453_P0_PORT1_TX6_REG                       0x49
+#define LM49453_P0_PORT1_TX7_REG                       0x4A
+#define LM49453_P0_PORT1_TX8_REG                       0x4B
+#define LM49453_P0_PORT2_TX1_REG                       0x4C
+#define LM49453_P0_PORT2_TX2_REG                       0x4D
+#define LM49453_P0_STN_SEL_REG                         0x4F
+#define LM49453_P0_DACHPL1_REG                         0x50
+#define LM49453_P0_DACHPL2_REG                         0x51
+#define LM49453_P0_DACHPR1_REG                         0x52
+#define LM49453_P0_DACHPR2_REG                         0x53
+#define LM49453_P0_DACLOL1_REG                         0x54
+#define LM49453_P0_DACLOL2_REG                         0x55
+#define LM49453_P0_DACLOR1_REG                         0x56
+#define LM49453_P0_DACLOR2_REG                         0x57
+#define LM49453_P0_DACLSL1_REG                         0x58
+#define LM49453_P0_DACLSL2_REG                         0x59
+#define LM49453_P0_DACLSR1_REG                         0x5A
+#define LM49453_P0_DACLSR2_REG                         0x5B
+#define LM49453_P0_DACHAL1_REG                         0x5C
+#define LM49453_P0_DACHAL2_REG                         0x5D
+#define LM49453_P0_DACHAR1_REG                         0x5E
+#define LM49453_P0_DACHAR2_REG                         0x5F
+
+/* AUDIO PORT 1 (TDM) */
+#define LM49453_P0_AUDIO_PORT1_BASIC_REG               0x60
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN1_REG            0x61
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN2_REG            0x62
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN3_REG            0x63
+#define LM49453_P0_AUDIO_PORT1_SYNC_RATE_REG           0x64
+#define LM49453_P0_AUDIO_PORT1_SYNC_SDO_SETUP_REG      0x65
+#define LM49453_P0_AUDIO_PORT1_DATA_WIDTH_REG          0x66
+#define LM49453_P0_AUDIO_PORT1_RX_MSB_REG              0x67
+#define LM49453_P0_AUDIO_PORT1_TX_MSB_REG              0x68
+#define LM49453_P0_AUDIO_PORT1_TDM_CHANNELS_REG                0x69
+
+/* AUDIO PORT 2 */
+#define LM49453_P0_AUDIO_PORT2_BASIC_REG               0x6A
+#define LM49453_P0_AUDIO_PORT2_CLK_GEN1_REG            0x6B
+#define LM49453_P0_AUDIO_PORT2_CLK_GEN2_REG            0x6C
+#define LM49453_P0_AUDIO_PORT2_SYNC_GEN_REG            0x6D
+#define LM49453_P0_AUDIO_PORT2_DATA_WIDTH_REG          0x6E
+#define LM49453_P0_AUDIO_PORT2_RX_MODE_REG             0x6F
+#define LM49453_P0_AUDIO_PORT2_TX_MODE_REG             0x70
+
+/* SAMPLE RATE */
+#define LM49453_P0_PORT1_SR_LSB_REG                    0x79
+#define LM49453_P0_PORT1_SR_MSB_REG                    0x7A
+#define LM49453_P0_PORT2_SR_LSB_REG                    0x7B
+#define LM49453_P0_PORT2_SR_MSB_REG                    0x7C
+
+/* EFFECTS - HPFs */
+#define LM49453_P0_HPF_REG                             0x80
+
+/* EFFECTS ADC ALC */
+#define LM49453_P0_ADC_ALC1_REG                                0x82
+#define LM49453_P0_ADC_ALC2_REG                                0x83
+#define LM49453_P0_ADC_ALC3_REG                                0x84
+#define LM49453_P0_ADC_ALC4_REG                                0x85
+#define LM49453_P0_ADC_ALC5_REG                                0x86
+#define LM49453_P0_ADC_ALC6_REG                                0x87
+#define LM49453_P0_ADC_ALC7_REG                                0x88
+#define LM49453_P0_ADC_ALC8_REG                                0x89
+#define LM49453_P0_DMIC1_LEVELL_REG                    0x8A
+#define LM49453_P0_DMIC1_LEVELR_REG                    0x8B
+#define LM49453_P0_DMIC2_LEVELL_REG                    0x8C
+#define LM49453_P0_DMIC2_LEVELR_REG                    0x8D
+#define LM49453_P0_ADC_LEVELL_REG                      0x8E
+#define LM49453_P0_ADC_LEVELR_REG                      0x8F
+#define LM49453_P0_DAC_HP_LEVELL_REG                   0x90
+#define LM49453_P0_DAC_HP_LEVELR_REG                   0x91
+#define LM49453_P0_DAC_LO_LEVELL_REG                   0x92
+#define LM49453_P0_DAC_LO_LEVELR_REG                   0x93
+#define LM49453_P0_DAC_LS_LEVELL_REG                   0x94
+#define LM49453_P0_DAC_LS_LEVELR_REG                   0x95
+#define LM49453_P0_DAC_HA_LEVELL_REG                   0x96
+#define LM49453_P0_DAC_HA_LEVELR_REG                   0x97
+#define LM49453_P0_SOFT_MUTE_REG                       0x98
+#define LM49453_P0_DMIC_MUTE_CFG_REG                   0x99
+#define LM49453_P0_ADC_MUTE_CFG_REG                    0x9A
+#define LM49453_P0_DAC_MUTE_CFG_REG                    0x9B
+
+/*DIGITAL MIC1 */
+#define LM49453_P0_DIGITAL_MIC1_CONFIG_REG             0xB0
+#define LM49453_P0_DIGITAL_MIC1_DATA_DELAYL_REG                0xB1
+#define LM49453_P0_DIGITAL_MIC1_DATA_DELAYR_REG                0xB2
+
+/*DIGITAL MIC2 */
+#define LM49453_P0_DIGITAL_MIC2_CONFIG_REG             0xB3
+#define LM49453_P0_DIGITAL_MIC2_DATA_DELAYL_REG                0xB4
+#define LM49453_P0_DIGITAL_MIC2_DATA_DELAYR_REG                0xB5
+
+/* ADC DECIMATOR */
+#define LM49453_P0_ADC_DECIMATOR_REG                   0xB6
+
+/* DAC CONFIGURE */
+#define LM49453_P0_DAC_CONFIG_REG                      0xB7
+
+/* SIDETONE */
+#define LM49453_P0_STN_VOL_ADCL_REG                    0xB8
+#define LM49453_P0_STN_VOL_ADCR_REG                    0xB9
+#define LM49453_P0_STN_VOL_DMIC1L_REG                  0xBA
+#define LM49453_P0_STN_VOL_DMIC1R_REG                  0xBB
+#define LM49453_P0_STN_VOL_DMIC2L_REG                  0xBC
+#define LM49453_P0_STN_VOL_DMIC2R_REG                  0xBD
+
+/* ADC/DAC CLIPPING MONITORS (Read Only/Write to Clear) */
+#define LM49453_P0_ADC_DEC_CLIP_REG                    0xC2
+#define LM49453_P0_ADC_HPF_CLIP_REG                    0xC3
+#define LM49453_P0_ADC_LVL_CLIP_REG                    0xC4
+#define LM49453_P0_DAC_LVL_CLIP_REG                    0xC5
+
+/* ADC ALC EFFECT MONITORS (Read Only) */
+#define LM49453_P0_ADC_LVLMONL_REG                     0xC8
+#define LM49453_P0_ADC_LVLMONR_REG                     0xC9
+#define LM49453_P0_ADC_ALCMONL_REG                     0xCA
+#define LM49453_P0_ADC_ALCMONR_REG                     0xCB
+#define LM49453_P0_ADC_MUTED_REG                       0xCC
+#define LM49453_P0_DAC_MUTED_REG                       0xCD
+
+/* HEADSET DETECT */
+#define LM49453_P0_HSD_PPB_LONG_CNT_LIMITL_REG         0xD0
+#define LM49453_P0_HSD_PPB_LONG_CNT_LIMITR_REG         0xD1
+#define LM49453_P0_HSD_PIN3_4_EX_LOOP_CNT_LIMITL_REG   0xD2
+#define LM49453_P0_HSD_PIN3_4_EX_LOOP_CNT_LIMITH_REG   0xD3
+#define LM49453_P0_HSD_TIMEOUT1_REG                    0xD4
+#define LM49453_P0_HSD_TIMEOUT2_REG                    0xD5
+#define LM49453_P0_HSD_TIMEOUT3_REG                    0xD6
+#define LM49453_P0_HSD_PIN3_4_CFG_REG                  0xD7
+#define LM49453_P0_HSD_IRQ1_REG                                0xD8
+#define LM49453_P0_HSD_IRQ2_REG                                0xD9
+#define LM49453_P0_HSD_IRQ3_REG                                0xDA
+#define LM49453_P0_HSD_IRQ4_REG                                0xDB
+#define LM49453_P0_HSD_IRQ_MASK1_REG                   0xDC
+#define LM49453_P0_HSD_IRQ_MASK2_REG                   0xDD
+#define LM49453_P0_HSD_IRQ_MASK3_REG                   0xDE
+#define LM49453_P0_HSD_R_HPLL_REG                      0xE0
+#define LM49453_P0_HSD_R_HPLH_REG                      0xE1
+#define LM49453_P0_HSD_R_HPLU_REG                      0xE2
+#define LM49453_P0_HSD_R_HPRL_REG                      0xE3
+#define LM49453_P0_HSD_R_HPRH_REG                      0xE4
+#define LM49453_P0_HSD_R_HPRU_REG                      0xE5
+#define LM49453_P0_HSD_VEL_L_FINALL_REG                        0xE6
+#define LM49453_P0_HSD_VEL_L_FINALH_REG                        0xE7
+#define LM49453_P0_HSD_VEL_L_FINALU_REG                        0xE8
+#define LM49453_P0_HSD_RO_FINALL_REG                   0xE9
+#define LM49453_P0_HSD_RO_FINALH_REG                   0xEA
+#define LM49453_P0_HSD_RO_FINALU_REG                   0xEB
+#define LM49453_P0_HSD_VMIC_BIAS_FINALL_REG            0xEC
+#define LM49453_P0_HSD_VMIC_BIAS_FINALH_REG            0xED
+#define LM49453_P0_HSD_VMIC_BIAS_FINALU_REG            0xEE
+#define LM49453_P0_HSD_PIN_CONFIG_REG                  0xEF
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS1_REG  0xF1
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS2_REG  0xF2
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS3_REG  0xF3
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATEL_REG   0xF4
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATEH_REG   0xF5
+
+/* I/O PULLDOWN CONFIG */
+#define LM49453_P0_PULL_CONFIG1_REG                    0xF8
+#define LM49453_P0_PULL_CONFIG2_REG                    0xF9
+#define LM49453_P0_PULL_CONFIG3_REG                    0xFA
+
+/* RESET */
+#define LM49453_P0_RESET_REG                           0xFE
+
+/* PAGE */
+#define LM49453_PAGE_REG                               0xFF
+
+#define LM49453_MAX_REGISTER                           (0xFF+1)
+
+/* LM49453_P0_PMC_SETUP_REG (0x00h) */
+#define LM49453_PMC_SETUP_CHIP_EN                      (BIT(1)|BIT(0))
+#define LM49453_PMC_SETUP_PLL_EN                       BIT(2)
+#define LM49453_PMC_SETUP_PLL_P2_EN                    BIT(3)
+#define LM49453_PMC_SETUP_PLL_FLL                      BIT(4)
+#define LM49453_PMC_SETUP_MCLK_OVER                    BIT(5)
+#define LM49453_PMC_SETUP_RTC_CLK_OVER                 BIT(6)
+#define LM49453_PMC_SETUP_CHIP_ACTIVE                  BIT(7)
+
+/* Chip Enable bits */
+#define LM49453_CHIP_EN_SHUTDOWN                       0x00
+#define LM49453_CHIP_EN                                        0x01
+#define LM49453_CHIP_EN_HSD_DETECT                     0x02
+#define LM49453_CHIP_EN_INVALID_HSD                    0x03
+
+/* LM49453_P0_PLL_CLK_SEL1_REG (0x01h) */
+#define LM49453_CLK_SEL1_MCLK_SEL                      0x11
+#define LM49453_CLK_SEL1_RTC_SEL                       0x11
+#define LM49453_CLK_SEL1_PORT1_SEL                     0x10
+#define LM49453_CLK_SEL1_PORT2_SEL                     0x11
+
+/* LM49453_P0_PLL_CLK_SEL2_REG (0x02h) */
+#define LM49453_CLK_SEL2_ADC_CLK_SEL                   0x38
+
+/* LM49453_P0_FLL_REF_FREQL_REG (0x0F) */
+#define LM49453_FLL_REF_FREQ_VAL                       0x8ca0001
+
+/* LM49453_P0_VCO_TARGETLL_REG (0x11) */
+#define LM49453_VCO_TARGET_VAL                         0x8ca0001
+
+/* LM49453_P0_ADC_DSP_REG (0x30h) */
+#define LM49453_ADC_DSP_ADC_MUTEL                      BIT(0)
+#define LM49453_ADC_DSP_ADC_MUTER                      BIT(1)
+#define LM49453_ADC_DSP_DMIC1_MUTEL                    BIT(2)
+#define LM49453_ADC_DSP_DMIC1_MUTER                    BIT(3)
+#define LM49453_ADC_DSP_DMIC2_MUTEL                    BIT(4)
+#define LM49453_ADC_DSP_DMIC2_MUTER                    BIT(5)
+#define LM49453_ADC_DSP_MUTE_ALL                       0x3F
+
+/* LM49453_P0_DAC_DSP_REG (0x31h) */
+#define LM49453_DAC_DSP_MUTE_ALL                       0xFF
+
+/* LM49453_P0_AUDIO_PORT1_BASIC_REG (0x60h) */
+#define LM49453_AUDIO_PORT1_BASIC_FMT_MASK             (BIT(4)|BIT(3))
+#define LM49453_AUDIO_PORT1_BASIC_CLK_MS               BIT(3)
+#define LM49453_AUDIO_PORT1_BASIC_SYNC_MS              BIT(4)
+
+/* LM49453_P0_RESET_REG (0xFEh) */
+#define LM49453_RESET_REG_RST                          BIT(0)
+
+/* Page select register bits (0xFF) */
+#define LM49453_PAGE0_SELECT                           0x0
+#define LM49453_PAGE1_SELECT                           0x1
+
+/* LM49453_P0_HSD_PIN3_4_CFG_REG (Jack Pin config - 0xD7) */
+#define LM49453_JACK_DISABLE                           0x00
+#define LM49453_JACK_CONFIG1                           0x01
+#define LM49453_JACK_CONFIG2                           0x02
+#define LM49453_JACK_CONFIG3                           0x03
+#define LM49453_JACK_CONFIG4                           0x04
+#define LM49453_JACK_CONFIG5                           0x05
+
+/* Page 1 REGISTERS */
+
+/* SIDETONE */
+#define LM49453_P1_SIDETONE_SA0L_REG                   0x80
+#define LM49453_P1_SIDETONE_SA0H_REG                   0x81
+#define LM49453_P1_SIDETONE_SAB0U_REG                  0x82
+#define LM49453_P1_SIDETONE_SB0L_REG                   0x83
+#define LM49453_P1_SIDETONE_SB0H_REG                   0x84
+#define LM49453_P1_SIDETONE_SH0L_REG                   0x85
+#define LM49453_P1_SIDETONE_SH0H_REG                   0x86
+#define LM49453_P1_SIDETONE_SH0U_REG                   0x87
+#define LM49453_P1_SIDETONE_SA1L_REG                   0x88
+#define LM49453_P1_SIDETONE_SA1H_REG                   0x89
+#define LM49453_P1_SIDETONE_SAB1U_REG                  0x8A
+#define LM49453_P1_SIDETONE_SB1L_REG                   0x8B
+#define LM49453_P1_SIDETONE_SB1H_REG                   0x8C
+#define LM49453_P1_SIDETONE_SH1L_REG                   0x8D
+#define LM49453_P1_SIDETONE_SH1H_REG                   0x8E
+#define LM49453_P1_SIDETONE_SH1U_REG                   0x8F
+#define LM49453_P1_SIDETONE_SA2L_REG                   0x90
+#define LM49453_P1_SIDETONE_SA2H_REG                   0x91
+#define LM49453_P1_SIDETONE_SAB2U_REG                  0x92
+#define LM49453_P1_SIDETONE_SB2L_REG                   0x93
+#define LM49453_P1_SIDETONE_SB2H_REG                   0x94
+#define LM49453_P1_SIDETONE_SH2L_REG                   0x95
+#define LM49453_P1_SIDETONE_SH2H_REG                   0x96
+#define LM49453_P1_SIDETONE_SH2U_REG                   0x97
+#define LM49453_P1_SIDETONE_SA3L_REG                   0x98
+#define LM49453_P1_SIDETONE_SA3H_REG                   0x99
+#define LM49453_P1_SIDETONE_SAB3U_REG                  0x9A
+#define LM49453_P1_SIDETONE_SB3L_REG                   0x9B
+#define LM49453_P1_SIDETONE_SB3H_REG                   0x9C
+#define LM49453_P1_SIDETONE_SH3L_REG                   0x9D
+#define LM49453_P1_SIDETONE_SH3H_REG                   0x9E
+#define LM49453_P1_SIDETONE_SH3U_REG                   0x9F
+#define LM49453_P1_SIDETONE_SA4L_REG                   0xA0
+#define LM49453_P1_SIDETONE_SA4H_REG                   0xA1
+#define LM49453_P1_SIDETONE_SAB4U_REG                  0xA2
+#define LM49453_P1_SIDETONE_SB4L_REG                   0xA3
+#define LM49453_P1_SIDETONE_SB4H_REG                   0xA4
+#define LM49453_P1_SIDETONE_SH4L_REG                   0xA5
+#define LM49453_P1_SIDETONE_SH4H_REG                   0xA6
+#define LM49453_P1_SIDETONE_SH4U_REG                   0xA7
+#define LM49453_P1_SIDETONE_SA5L_REG                   0xA8
+#define LM49453_P1_SIDETONE_SA5H_REG                   0xA9
+#define LM49453_P1_SIDETONE_SAB5U_REG                  0xAA
+#define LM49453_P1_SIDETONE_SB5L_REG                   0xAB
+#define LM49453_P1_SIDETONE_SB5H_REG                   0xAC
+#define LM49453_P1_SIDETONE_SH5L_REG                   0xAD
+#define LM49453_P1_SIDETONE_SH5H_REG                   0xAE
+#define LM49453_P1_SIDETONE_SH5U_REG                   0xAF
+
+/* CHARGE PUMP CONFIG */
+#define LM49453_P1_CP_CONFIG1_REG                      0xB0
+#define LM49453_P1_CP_CONFIG2_REG                      0xB1
+#define LM49453_P1_CP_CONFIG3_REG                      0xB2
+#define LM49453_P1_CP_CONFIG4_REG                      0xB3
+#define LM49453_P1_CP_LA_VTH1L_REG                     0xB4
+#define LM49453_P1_CP_LA_VTH1M_REG                     0xB5
+#define LM49453_P1_CP_LA_VTH2L_REG                     0xB6
+#define LM49453_P1_CP_LA_VTH2M_REG                     0xB7
+#define LM49453_P1_CP_LA_VTH3L_REG                     0xB8
+#define LM49453_P1_CP_LA_VTH3H_REG                     0xB9
+#define LM49453_P1_CP_CLK_DIV_REG                      0xBA
+
+/* DAC */
+#define LM49453_P1_DAC_CHOP_REG                                0xC0
+
+#define        LM49453_CLK_SRC_MCLK                            1
+#endif
index 0bb511a0388de84cfec32f1794dd0a77be63ba1d..35179e2c23c92a31665fef50563c06e295b7a201 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <asm/div64.h>
 #include <sound/max98095.h>
+#include <sound/jack.h>
 #include "max98095.h"
 
 enum max98095_type {
@@ -51,6 +52,8 @@ struct max98095_priv {
        u8 lin_state;
        unsigned int mic1pre;
        unsigned int mic2pre;
+       struct snd_soc_jack *headphone_jack;
+       struct snd_soc_jack *mic_jack;
 };
 
 static const u8 max98095_reg_def[M98095_REG_CNT] = {
@@ -2173,9 +2176,125 @@ static void max98095_handle_pdata(struct snd_soc_codec *codec)
                max98095_handle_bq_pdata(codec);
 }
 
+static irqreturn_t max98095_report_jack(int irq, void *data)
+{
+       struct snd_soc_codec *codec = data;
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       unsigned int value;
+       int hp_report = 0;
+       int mic_report = 0;
+
+       /* Read the Jack Status Register */
+       value = snd_soc_read(codec, M98095_007_JACK_AUTO_STS);
+
+       /* If ddone is not set, then detection isn't finished yet */
+       if ((value & M98095_DDONE) == 0)
+               return IRQ_NONE;
+
+       /* if hp, check its bit, and if set, clear it */
+       if ((value & M98095_HP_IN || value & M98095_LO_IN) &&
+               max98095->headphone_jack)
+               hp_report |= SND_JACK_HEADPHONE;
+
+       /* if mic, check its bit, and if set, clear it */
+       if ((value & M98095_MIC_IN) && max98095->mic_jack)
+               mic_report |= SND_JACK_MICROPHONE;
+
+       if (max98095->headphone_jack == max98095->mic_jack) {
+               snd_soc_jack_report(max98095->headphone_jack,
+                                       hp_report | mic_report,
+                                       SND_JACK_HEADSET);
+       } else {
+               if (max98095->headphone_jack)
+                       snd_soc_jack_report(max98095->headphone_jack,
+                                       hp_report, SND_JACK_HEADPHONE);
+               if (max98095->mic_jack)
+                       snd_soc_jack_report(max98095->mic_jack,
+                                       mic_report, SND_JACK_MICROPHONE);
+       }
+
+       return IRQ_HANDLED;
+}
+
+int max98095_jack_detect_enable(struct snd_soc_codec *codec)
+{
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+       int detect_enable = M98095_JDEN;
+       unsigned int slew = M98095_DEFAULT_SLEW_DELAY;
+
+       if (max98095->pdata->jack_detect_pin5en)
+               detect_enable |= M98095_PIN5EN;
+
+       if (max98095->pdata->jack_detect_delay)
+               slew = max98095->pdata->jack_detect_delay;
+
+       ret = snd_soc_write(codec, M98095_08E_JACK_DC_SLEW, slew);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+               return ret;
+       }
+
+       /* configure auto detection to be enabled */
+       ret = snd_soc_write(codec, M98095_089_JACK_DET_AUTO, detect_enable);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+int max98095_jack_detect_disable(struct snd_soc_codec *codec)
+{
+       int ret = 0;
+
+       /* configure auto detection to be disabled */
+       ret = snd_soc_write(codec, M98095_089_JACK_DET_AUTO, 0x0);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+int max98095_jack_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
+{
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *client = to_i2c_client(codec->dev);
+       int ret = 0;
+
+       max98095->headphone_jack = hp_jack;
+       max98095->mic_jack = mic_jack;
+
+       /* only progress if we have at least 1 jack pointer */
+       if (!hp_jack && !mic_jack)
+               return -EINVAL;
+
+       max98095_jack_detect_enable(codec);
+
+       /* enable interrupts for headphone jack detection */
+       ret = snd_soc_update_bits(codec, M98095_013_JACK_INT_EN,
+               M98095_IDDONE, M98095_IDDONE);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to cfg jack irqs %d\n", ret);
+               return ret;
+       }
+
+       max98095_report_jack(client->irq, codec);
+       return 0;
+}
+
 #ifdef CONFIG_PM
 static int max98095_suspend(struct snd_soc_codec *codec)
 {
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+       if (max98095->headphone_jack || max98095->mic_jack)
+               max98095_jack_detect_disable(codec);
+
        max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
@@ -2183,8 +2302,16 @@ static int max98095_suspend(struct snd_soc_codec *codec)
 
 static int max98095_resume(struct snd_soc_codec *codec)
 {
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *client = to_i2c_client(codec->dev);
+
        max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
+       if (max98095->headphone_jack || max98095->mic_jack) {
+               max98095_jack_detect_enable(codec);
+               max98095_report_jack(client->irq, codec);
+       }
+
        return 0;
 }
 #else
@@ -2227,6 +2354,7 @@ static int max98095_probe(struct snd_soc_codec *codec)
 {
        struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
        struct max98095_cdata *cdata;
+       struct i2c_client *client;
        int ret = 0;
 
        ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
@@ -2238,6 +2366,8 @@ static int max98095_probe(struct snd_soc_codec *codec)
        /* reset the codec, the DSP core, and disable all interrupts */
        max98095_reset(codec);
 
+       client = to_i2c_client(codec->dev);
+
        /* initialize private data */
 
        max98095->sysclk = (unsigned)-1;
@@ -2266,11 +2396,23 @@ static int max98095_probe(struct snd_soc_codec *codec)
        max98095->mic1pre = 0;
        max98095->mic2pre = 0;
 
+       if (client->irq) {
+               /* register an audio interrupt */
+               ret = request_threaded_irq(client->irq, NULL,
+                       max98095_report_jack,
+                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+                       "max98095", codec);
+               if (ret) {
+                       dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
+                       goto err_access;
+               }
+       }
+
        ret = snd_soc_read(codec, M98095_0FF_REV_ID);
        if (ret < 0) {
                dev_err(codec->dev, "Failure reading hardware revision: %d\n",
                        ret);
-               goto err_access;
+               goto err_irq;
        }
        dev_info(codec->dev, "Hardware revision: %c\n", ret - 0x40 + 'A');
 
@@ -2306,14 +2448,28 @@ static int max98095_probe(struct snd_soc_codec *codec)
 
        max98095_add_widgets(codec);
 
+       return 0;
+
+err_irq:
+       if (client->irq)
+               free_irq(client->irq, codec);
 err_access:
        return ret;
 }
 
 static int max98095_remove(struct snd_soc_codec *codec)
 {
+       struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *client = to_i2c_client(codec->dev);
+
        max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
+       if (max98095->headphone_jack || max98095->mic_jack)
+               max98095_jack_detect_disable(codec);
+
+       if (client->irq)
+               free_irq(client->irq, codec);
+
        return 0;
 }
 
index 891584a0eb03b9ddc2a4a6d9b15184b61233fc59..2ebbe4e894bf090636a641ee704849a5f25e7068 100644 (file)
 
 /* MAX98095 Registers Bit Fields */
 
+/* M98095_007_JACK_AUTO_STS */
+       #define M98095_MIC_IN                   (1<<3)
+       #define M98095_LO_IN                    (1<<5)
+       #define M98095_HP_IN                    (1<<6)
+       #define M98095_DDONE                    (1<<7)
+
 /* M98095_00F_HOST_CFG */
        #define M98095_SEG                      (1<<0)
        #define M98095_XTEN                     (1<<1)
        #define M98095_MDLLEN                   (1<<2)
 
+/* M98095_013_JACK_INT_EN */
+       #define M98095_IMIC_IN                  (1<<3)
+       #define M98095_ILO_IN                   (1<<5)
+       #define M98095_IHP_IN                   (1<<6)
+       #define M98095_IDDONE                   (1<<7)
+
 /* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */
        #define M98095_CLKMODE_MASK             0xFF
 
        #define M98095_EQ2EN                    (1<<1)
        #define M98095_EQ1EN                    (1<<0)
 
+/* M98095_089_JACK_DET_AUTO */
+       #define M98095_PIN5EN                   (1<<2)
+       #define M98095_JDEN                     (1<<7)
+
 /* M98095_090_PWR_EN_IN */
        #define M98095_INEN                     (1<<7)
        #define M98095_MB2EN                    (1<<3)
 #define M98095_174_DAI1_BQ_BASE             0x74
 #define M98095_17E_DAI2_BQ_BASE             0x7E
 
+/* Default Delay used in Slew Rate Calculation for Jack detection */
+#define M98095_DEFAULT_SLEW_DELAY              0x18
+
+extern int max98095_jack_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
+
 #endif
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
new file mode 100644 (file)
index 0000000..6276e35
--- /dev/null
@@ -0,0 +1,786 @@
+/*
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ * Copyright 2009 Sascha Hauer, s.hauer@pengutronix.de
+ * Copyright 2012 Philippe Retornaz, philippe.retornaz@epfl.ch
+ *
+ * Initial development of this code was funded by
+ * Phytec Messtechnik GmbH, http://www.phytec.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mfd/mc13xxx.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/soc-dapm.h>
+
+#include "mc13783.h"
+
+#define MC13783_AUDIO_RX0      36
+#define MC13783_AUDIO_RX1      37
+#define MC13783_AUDIO_TX       38
+#define MC13783_SSI_NETWORK    39
+#define MC13783_AUDIO_CODEC    40
+#define MC13783_AUDIO_DAC      41
+
+#define AUDIO_RX0_ALSPEN               (1 << 5)
+#define AUDIO_RX0_ALSPSEL              (1 << 7)
+#define AUDIO_RX0_ADDCDC               (1 << 21)
+#define AUDIO_RX0_ADDSTDC              (1 << 22)
+#define AUDIO_RX0_ADDRXIN              (1 << 23)
+
+#define AUDIO_RX1_PGARXEN              (1 << 0);
+#define AUDIO_RX1_PGASTEN              (1 << 5)
+#define AUDIO_RX1_ARXINEN              (1 << 10)
+
+#define AUDIO_TX_AMC1REN               (1 << 5)
+#define AUDIO_TX_AMC1LEN               (1 << 7)
+#define AUDIO_TX_AMC2EN                        (1 << 9)
+#define AUDIO_TX_ATXINEN               (1 << 11)
+#define AUDIO_TX_RXINREC               (1 << 13)
+
+#define SSI_NETWORK_CDCTXRXSLOT(x)     (((x) & 0x3) << 2)
+#define SSI_NETWORK_CDCTXSECSLOT(x)    (((x) & 0x3) << 4)
+#define SSI_NETWORK_CDCRXSECSLOT(x)    (((x) & 0x3) << 6)
+#define SSI_NETWORK_CDCRXSECGAIN(x)    (((x) & 0x3) << 8)
+#define SSI_NETWORK_CDCSUMGAIN(x)      (1 << 10)
+#define SSI_NETWORK_CDCFSDLY(x)                (1 << 11)
+#define SSI_NETWORK_DAC_SLOTS_8                (1 << 12)
+#define SSI_NETWORK_DAC_SLOTS_4                (2 << 12)
+#define SSI_NETWORK_DAC_SLOTS_2                (3 << 12)
+#define SSI_NETWORK_DAC_SLOT_MASK      (3 << 12)
+#define SSI_NETWORK_DAC_RXSLOT_0_1     (0 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_2_3     (1 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_4_5     (2 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_6_7     (3 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_MASK    (3 << 14)
+#define SSI_NETWORK_STDCRXSECSLOT(x)   (((x) & 0x3) << 16)
+#define SSI_NETWORK_STDCRXSECGAIN(x)   (((x) & 0x3) << 18)
+#define SSI_NETWORK_STDCSUMGAIN                (1 << 20)
+
+/*
+ * MC13783_AUDIO_CODEC and MC13783_AUDIO_DAC mostly share the same
+ * register layout
+ */
+#define AUDIO_SSI_SEL                  (1 << 0)
+#define AUDIO_CLK_SEL                  (1 << 1)
+#define AUDIO_CSM                      (1 << 2)
+#define AUDIO_BCL_INV                  (1 << 3)
+#define AUDIO_CFS_INV                  (1 << 4)
+#define AUDIO_CFS(x)                   (((x) & 0x3) << 5)
+#define AUDIO_CLK(x)                   (((x) & 0x7) << 7)
+#define AUDIO_C_EN                     (1 << 11)
+#define AUDIO_C_CLK_EN                 (1 << 12)
+#define AUDIO_C_RESET                  (1 << 15)
+
+#define AUDIO_CODEC_CDCFS8K16K         (1 << 10)
+#define AUDIO_DAC_CFS_DLY_B            (1 << 10)
+
+struct mc13783_priv {
+       struct snd_soc_codec codec;
+       struct mc13xxx *mc13xxx;
+
+       enum mc13783_ssi_port adc_ssi_port;
+       enum mc13783_ssi_port dac_ssi_port;
+};
+
+static unsigned int mc13783_read(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+       unsigned int value = 0;
+
+       mc13xxx_lock(priv->mc13xxx);
+
+       mc13xxx_reg_read(priv->mc13xxx, reg, &value);
+
+       mc13xxx_unlock(priv->mc13xxx);
+
+       return value;
+}
+
+static int mc13783_write(struct snd_soc_codec *codec,
+       unsigned int reg, unsigned int value)
+{
+       struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       mc13xxx_lock(priv->mc13xxx);
+
+       ret = mc13xxx_reg_write(priv->mc13xxx, reg, value);
+
+       mc13xxx_unlock(priv->mc13xxx);
+
+       return ret;
+}
+
+/* Mapping between sample rates and register value */
+static unsigned int mc13783_rates[] = {
+       8000, 11025, 12000, 16000,
+       22050, 24000, 32000, 44100,
+       48000, 64000, 96000
+};
+
+static int mc13783_pcm_hw_params_dac(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       unsigned int rate = params_rate(params);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mc13783_rates); i++) {
+               if (rate == mc13783_rates[i]) {
+                       snd_soc_update_bits(codec, MC13783_AUDIO_DAC,
+                                       0xf << 17, i << 17);
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int mc13783_pcm_hw_params_codec(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       unsigned int rate = params_rate(params);
+       unsigned int val;
+
+       switch (rate) {
+       case 8000:
+               val = 0;
+               break;
+       case 16000:
+               val = AUDIO_CODEC_CDCFS8K16K;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, MC13783_AUDIO_CODEC, AUDIO_CODEC_CDCFS8K16K,
+                       val);
+
+       return 0;
+}
+
+static int mc13783_pcm_hw_params_sync(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return mc13783_pcm_hw_params_dac(substream, params, dai);
+       else
+               return mc13783_pcm_hw_params_codec(substream, params, dai);
+}
+
+static int mc13783_set_fmt(struct snd_soc_dai *dai, unsigned int fmt,
+                       unsigned int reg)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int val = 0;
+       unsigned int mask = AUDIO_CFS(3) | AUDIO_BCL_INV | AUDIO_CFS_INV |
+                               AUDIO_CSM | AUDIO_C_CLK_EN | AUDIO_C_RESET;
+
+
+       /* DAI mode */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               val |= AUDIO_CFS(2);
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               val |= AUDIO_CFS(1);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* DAI clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               val |= AUDIO_BCL_INV;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               val |= AUDIO_BCL_INV | AUDIO_CFS_INV;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               val |= AUDIO_CFS_INV;
+               break;
+       }
+
+       /* DAI clock master masks */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               val |= AUDIO_C_CLK_EN;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               val |= AUDIO_CSM;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_CBS_CFM:
+               return -EINVAL;
+       }
+
+       val |= AUDIO_C_RESET;
+
+       snd_soc_update_bits(codec, reg, mask, val);
+
+       return 0;
+}
+
+static int mc13783_set_fmt_async(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       if (dai->id == MC13783_ID_STEREO_DAC)
+               return mc13783_set_fmt(dai, fmt, MC13783_AUDIO_DAC);
+       else
+               return mc13783_set_fmt(dai, fmt, MC13783_AUDIO_CODEC);
+}
+
+static int mc13783_set_fmt_sync(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       int ret;
+
+       ret = mc13783_set_fmt(dai, fmt, MC13783_AUDIO_DAC);
+       if (ret)
+               return ret;
+
+       /*
+        * In synchronous mode force the voice codec into slave mode
+        * so that the clock / framesync from the stereo DAC is used
+        */
+       fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+       fmt |= SND_SOC_DAIFMT_CBS_CFS;
+       ret = mc13783_set_fmt(dai, fmt, MC13783_AUDIO_CODEC);
+
+       return ret;
+}
+
+static int mc13783_sysclk[] = {
+       13000000,
+       15360000,
+       16800000,
+       -1,
+       26000000,
+       -1, /* 12000000, invalid for voice codec */
+       -1, /* 3686400, invalid for voice codec */
+       33600000,
+};
+
+static int mc13783_set_sysclk(struct snd_soc_dai *dai,
+                                 int clk_id, unsigned int freq, int dir,
+                                 unsigned int reg)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int clk;
+       unsigned int val = 0;
+       unsigned int mask = AUDIO_CLK(0x7) | AUDIO_CLK_SEL;
+
+       for (clk = 0; clk < ARRAY_SIZE(mc13783_sysclk); clk++) {
+               if (mc13783_sysclk[clk] < 0)
+                       continue;
+               if (mc13783_sysclk[clk] == freq)
+                       break;
+       }
+
+       if (clk == ARRAY_SIZE(mc13783_sysclk))
+               return -EINVAL;
+
+       if (clk_id == MC13783_CLK_CLIB)
+               val |= AUDIO_CLK_SEL;
+
+       val |= AUDIO_CLK(clk);
+
+       snd_soc_update_bits(codec, reg, mask, val);
+
+       return 0;
+}
+
+static int mc13783_set_sysclk_dac(struct snd_soc_dai *dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_DAC);
+}
+
+static int mc13783_set_sysclk_codec(struct snd_soc_dai *dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_CODEC);
+}
+
+static int mc13783_set_sysclk_sync(struct snd_soc_dai *dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       int ret;
+
+       ret = mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_DAC);
+       if (ret)
+               return ret;
+
+       return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_CODEC);
+}
+
+static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,
+       unsigned int tx_mask, unsigned int rx_mask, int slots,
+       int slot_width)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int val = 0;
+       unsigned int mask = SSI_NETWORK_DAC_SLOT_MASK |
+                               SSI_NETWORK_DAC_RXSLOT_MASK;
+
+       switch (slots) {
+       case 2:
+               val |= SSI_NETWORK_DAC_SLOTS_2;
+               break;
+       case 4:
+               val |= SSI_NETWORK_DAC_SLOTS_4;
+               break;
+       case 8:
+               val |= SSI_NETWORK_DAC_SLOTS_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (rx_mask) {
+       case 0xfffffffc:
+               val |= SSI_NETWORK_DAC_RXSLOT_0_1;
+               break;
+       case 0xfffffff3:
+               val |= SSI_NETWORK_DAC_RXSLOT_2_3;
+               break;
+       case 0xffffffcf:
+               val |= SSI_NETWORK_DAC_RXSLOT_4_5;
+               break;
+       case 0xffffff3f:
+               val |= SSI_NETWORK_DAC_RXSLOT_6_7;
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       snd_soc_update_bits(codec, MC13783_SSI_NETWORK, mask, val);
+
+       return 0;
+}
+
+static int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai,
+       unsigned int tx_mask, unsigned int rx_mask, int slots,
+       int slot_width)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int val = 0;
+       unsigned int mask = 0x3f;
+
+       if (slots != 4)
+               return -EINVAL;
+
+       if (tx_mask != 0xfffffffc)
+               return -EINVAL;
+
+       val |= (0x00 << 2);     /* primary timeslot RX/TX(?) is 0 */
+       val |= (0x01 << 4);     /* secondary timeslot TX is 1 */
+
+       snd_soc_update_bits(codec, MC13783_SSI_NETWORK, mask, val);
+
+       return 0;
+}
+
+static int mc13783_set_tdm_slot_sync(struct snd_soc_dai *dai,
+       unsigned int tx_mask, unsigned int rx_mask, int slots,
+       int slot_width)
+{
+       int ret;
+
+       ret = mc13783_set_tdm_slot_dac(dai, tx_mask, rx_mask, slots,
+                       slot_width);
+       if (ret)
+               return ret;
+
+       ret = mc13783_set_tdm_slot_codec(dai, tx_mask, rx_mask, slots,
+                       slot_width);
+
+       return ret;
+}
+
+static const struct snd_kcontrol_new mc1l_amp_ctl =
+       SOC_DAPM_SINGLE("Switch", 38, 7, 1, 0);
+
+static const struct snd_kcontrol_new mc1r_amp_ctl =
+       SOC_DAPM_SINGLE("Switch", 38, 5, 1, 0);
+
+static const struct snd_kcontrol_new mc2_amp_ctl =
+       SOC_DAPM_SINGLE("Switch", 38, 9, 1, 0);
+
+static const struct snd_kcontrol_new atx_amp_ctl =
+       SOC_DAPM_SINGLE("Switch", 38, 11, 1, 0);
+
+
+/* Virtual mux. The chip does the input selection automatically
+ * as soon as we enable one input. */
+static const char * const adcl_enum_text[] = {
+       "MC1L", "RXINL",
+};
+
+static const struct soc_enum adcl_enum =
+       SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcl_enum_text), adcl_enum_text);
+
+static const struct snd_kcontrol_new left_input_mux =
+       SOC_DAPM_ENUM_VIRT("Route", adcl_enum);
+
+static const char * const adcr_enum_text[] = {
+       "MC1R", "MC2", "RXINR", "TXIN",
+};
+
+static const struct soc_enum adcr_enum =
+       SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcr_enum_text), adcr_enum_text);
+
+static const struct snd_kcontrol_new right_input_mux =
+       SOC_DAPM_ENUM_VIRT("Route", adcr_enum);
+
+static const struct snd_kcontrol_new samp_ctl =
+       SOC_DAPM_SINGLE("Switch", 36, 3, 1, 0);
+
+static const struct snd_kcontrol_new lamp_ctl =
+       SOC_DAPM_SINGLE("Switch", 36, 5, 1, 0);
+
+static const struct snd_kcontrol_new hlamp_ctl =
+       SOC_DAPM_SINGLE("Switch", 36, 10, 1, 0);
+
+static const struct snd_kcontrol_new hramp_ctl =
+       SOC_DAPM_SINGLE("Switch", 36, 9, 1, 0);
+
+static const struct snd_kcontrol_new llamp_ctl =
+       SOC_DAPM_SINGLE("Switch", 36, 16, 1, 0);
+
+static const struct snd_kcontrol_new lramp_ctl =
+       SOC_DAPM_SINGLE("Switch", 36, 15, 1, 0);
+
+static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
+/* Input */
+       SND_SOC_DAPM_INPUT("MC1LIN"),
+       SND_SOC_DAPM_INPUT("MC1RIN"),
+       SND_SOC_DAPM_INPUT("MC2IN"),
+       SND_SOC_DAPM_INPUT("RXINR"),
+       SND_SOC_DAPM_INPUT("RXINL"),
+       SND_SOC_DAPM_INPUT("TXIN"),
+
+       SND_SOC_DAPM_SUPPLY("MC1 Bias", 38, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MC2 Bias", 38, 1, 0, NULL, 0),
+
+       SND_SOC_DAPM_SWITCH("MC1L Amp", 38, 7, 0, &mc1l_amp_ctl),
+       SND_SOC_DAPM_SWITCH("MC1R Amp", 38, 5, 0, &mc1r_amp_ctl),
+       SND_SOC_DAPM_SWITCH("MC2 Amp", 38, 9, 0, &mc2_amp_ctl),
+       SND_SOC_DAPM_SWITCH("TXIN Amp", 38, 11, 0, &atx_amp_ctl),
+
+       SND_SOC_DAPM_VIRT_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,
+                             &left_input_mux),
+       SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,
+                             &right_input_mux),
+
+       SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_ADC("ADC", "Capture", 40, 11, 0),
+       SND_SOC_DAPM_SUPPLY("ADC_Reset", 40, 15, 0, NULL, 0),
+
+/* Output */
+       SND_SOC_DAPM_SUPPLY("DAC_E", 41, 11, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC_Reset", 41, 15, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("RXOUTL"),
+       SND_SOC_DAPM_OUTPUT("RXOUTR"),
+       SND_SOC_DAPM_OUTPUT("HSL"),
+       SND_SOC_DAPM_OUTPUT("HSR"),
+       SND_SOC_DAPM_OUTPUT("LSP"),
+       SND_SOC_DAPM_OUTPUT("SP"),
+
+       SND_SOC_DAPM_SWITCH("Speaker Amp", 36, 3, 0, &samp_ctl),
+       SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl),
+       SND_SOC_DAPM_SWITCH("Headset Amp Left", 36, 10, 0, &hlamp_ctl),
+       SND_SOC_DAPM_SWITCH("Headset Amp Right", 36, 9, 0, &hramp_ctl),
+       SND_SOC_DAPM_SWITCH("Line out Amp Left", 36, 16, 0, &llamp_ctl),
+       SND_SOC_DAPM_SWITCH("Line out Amp Right", 36, 15, 0, &lramp_ctl),
+       SND_SOC_DAPM_DAC("DAC", "Playback", 36, 22, 0),
+       SND_SOC_DAPM_PGA("DAC PGA", 37, 5, 0, NULL, 0),
+};
+
+static struct snd_soc_dapm_route mc13783_routes[] = {
+/* Input */
+       { "MC1L Amp", NULL, "MC1LIN"},
+       { "MC1R Amp", NULL, "MC1RIN" },
+       { "MC2 Amp", NULL, "MC2IN" },
+       { "TXIN Amp", NULL, "TXIN"},
+
+       { "PGA Left Input Mux", "MC1L", "MC1L Amp" },
+       { "PGA Left Input Mux", "RXINL", "RXINL"},
+       { "PGA Right Input Mux", "MC1R", "MC1R Amp" },
+       { "PGA Right Input Mux", "MC2",  "MC2 Amp"},
+       { "PGA Right Input Mux", "TXIN", "TXIN Amp"},
+       { "PGA Right Input Mux", "RXINR", "RXINR"},
+
+       { "PGA Left Input", NULL, "PGA Left Input Mux"},
+       { "PGA Right Input", NULL, "PGA Right Input Mux"},
+
+       { "ADC", NULL, "PGA Left Input"},
+       { "ADC", NULL, "PGA Right Input"},
+       { "ADC", NULL, "ADC_Reset"},
+
+/* Output */
+       { "HSL", NULL, "Headset Amp Left" },
+       { "HSR", NULL, "Headset Amp Right"},
+       { "RXOUTL", NULL, "Line out Amp Left"},
+       { "RXOUTR", NULL, "Line out Amp Right"},
+       { "SP", NULL, "Speaker Amp"},
+       { "Speaker Amp", NULL, "DAC PGA"},
+       { "LSP", NULL, "DAC PGA"},
+       { "Headset Amp Left", NULL, "DAC PGA"},
+       { "Headset Amp Right", NULL, "DAC PGA"},
+       { "Line out Amp Left", NULL, "DAC PGA"},
+       { "Line out Amp Right", NULL, "DAC PGA"},
+       { "DAC PGA", NULL, "DAC"},
+       { "DAC", NULL, "DAC_E"},
+};
+
+static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix",
+                                               "Mono", "Mono Mix"};
+
+static const struct soc_enum mc13783_enum_3d_mixer =
+       SOC_ENUM_SINGLE(MC13783_AUDIO_RX1, 16, ARRAY_SIZE(mc13783_3d_mixer),
+                       mc13783_3d_mixer);
+
+static struct snd_kcontrol_new mc13783_control_list[] = {
+       SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0),
+       SOC_SINGLE("PCM Playback Volume", MC13783_AUDIO_RX1, 6, 15, 0),
+       SOC_DOUBLE("PCM Capture Volume", MC13783_AUDIO_TX, 19, 14, 31, 0),
+       SOC_ENUM("3D Control", mc13783_enum_3d_mixer),
+};
+
+static int mc13783_probe(struct snd_soc_codec *codec)
+{
+       struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       mc13xxx_lock(priv->mc13xxx);
+
+       /* these are the reset values */
+       mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);
+       mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX1, 0x00d35A);
+       mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_TX, 0x420000);
+       mc13xxx_reg_write(priv->mc13xxx, MC13783_SSI_NETWORK, 0x013060);
+       mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_CODEC, 0x180027);
+       mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_DAC, 0x0e0004);
+
+       if (priv->adc_ssi_port == MC13783_SSI1_PORT)
+               mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC,
+                               AUDIO_SSI_SEL, 0);
+       else
+               mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC,
+                               0, AUDIO_SSI_SEL);
+
+       if (priv->dac_ssi_port == MC13783_SSI1_PORT)
+               mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
+                               AUDIO_SSI_SEL, 0);
+       else
+               mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
+                               0, AUDIO_SSI_SEL);
+
+       mc13xxx_unlock(priv->mc13xxx);
+
+       return 0;
+}
+
+static int mc13783_remove(struct snd_soc_codec *codec)
+{
+       struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       mc13xxx_lock(priv->mc13xxx);
+
+       /* Make sure VAUDIOON is off */
+       mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_RX0, 0x3, 0);
+
+       mc13xxx_unlock(priv->mc13xxx);
+
+       return 0;
+}
+
+#define MC13783_RATES_RECORD (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
+
+#define MC13783_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+       SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops mc13783_ops_dac = {
+       .hw_params      = mc13783_pcm_hw_params_dac,
+       .set_fmt        = mc13783_set_fmt_async,
+       .set_sysclk     = mc13783_set_sysclk_dac,
+       .set_tdm_slot   = mc13783_set_tdm_slot_dac,
+};
+
+static struct snd_soc_dai_ops mc13783_ops_codec = {
+       .hw_params      = mc13783_pcm_hw_params_codec,
+       .set_fmt        = mc13783_set_fmt_async,
+       .set_sysclk     = mc13783_set_sysclk_codec,
+       .set_tdm_slot   = mc13783_set_tdm_slot_codec,
+};
+
+/*
+ * The mc13783 has two SSI ports, both of them can be routed either
+ * to the voice codec or the stereo DAC. When two different SSI ports
+ * are used for the voice codec and the stereo DAC we can do different
+ * formats and sysclock settings for playback and capture
+ * (mc13783-hifi-playback and mc13783-hifi-capture). Using the same port
+ * forces us to use symmetric rates (mc13783-hifi).
+ */
+static struct snd_soc_dai_driver mc13783_dai_async[] = {
+       {
+               .name = "mc13783-hifi-playback",
+               .id = MC13783_ID_STEREO_DAC,
+               .playback = {
+                       .stream_name = "Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_96000,
+                       .formats = MC13783_FORMATS,
+               },
+               .ops = &mc13783_ops_dac,
+       }, {
+               .name = "mc13783-hifi-capture",
+               .id = MC13783_ID_STEREO_CODEC,
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MC13783_RATES_RECORD,
+                       .formats = MC13783_FORMATS,
+               },
+               .ops = &mc13783_ops_codec,
+       },
+};
+
+static struct snd_soc_dai_ops mc13783_ops_sync = {
+       .hw_params      = mc13783_pcm_hw_params_sync,
+       .set_fmt        = mc13783_set_fmt_sync,
+       .set_sysclk     = mc13783_set_sysclk_sync,
+       .set_tdm_slot   = mc13783_set_tdm_slot_sync,
+};
+
+static struct snd_soc_dai_driver mc13783_dai_sync[] = {
+       {
+               .name = "mc13783-hifi",
+               .id = MC13783_ID_SYNC,
+               .playback = {
+                       .stream_name = "Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_96000,
+                       .formats = MC13783_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MC13783_RATES_RECORD,
+                       .formats = MC13783_FORMATS,
+               },
+               .ops = &mc13783_ops_sync,
+               .symmetric_rates = 1,
+       }
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
+       .probe          = mc13783_probe,
+       .remove         = mc13783_remove,
+       .read           = mc13783_read,
+       .write          = mc13783_write,
+       .controls       = mc13783_control_list,
+       .num_controls   = ARRAY_SIZE(mc13783_control_list),
+       .dapm_widgets   = mc13783_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mc13783_dapm_widgets),
+       .dapm_routes    = mc13783_routes,
+       .num_dapm_routes = ARRAY_SIZE(mc13783_routes),
+};
+
+static int mc13783_codec_probe(struct platform_device *pdev)
+{
+       struct mc13xxx *mc13xxx;
+       struct mc13783_priv *priv;
+       struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
+       int ret;
+
+       mc13xxx = dev_get_drvdata(pdev->dev.parent);
+
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+
+       dev_set_drvdata(&pdev->dev, priv);
+       priv->mc13xxx = mc13xxx;
+       if (pdata) {
+               priv->adc_ssi_port = pdata->adc_ssi_port;
+               priv->dac_ssi_port = pdata->dac_ssi_port;
+       } else {
+               priv->adc_ssi_port = MC13783_SSI1_PORT;
+               priv->dac_ssi_port = MC13783_SSI2_PORT;
+       }
+
+       if (priv->adc_ssi_port == priv->dac_ssi_port)
+               ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
+                       mc13783_dai_sync, ARRAY_SIZE(mc13783_dai_sync));
+       else
+               ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
+                       mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async));
+
+       if (ret)
+               goto err_register_codec;
+
+       return 0;
+
+err_register_codec:
+       dev_err(&pdev->dev, "register codec failed with %d\n", ret);
+
+       return ret;
+}
+
+static int mc13783_codec_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+
+       return 0;
+}
+
+static struct platform_driver mc13783_codec_driver = {
+       .driver = {
+                  .name = "mc13783-codec",
+                  .owner = THIS_MODULE,
+                  },
+       .probe = mc13783_codec_probe,
+       .remove = __devexit_p(mc13783_codec_remove),
+};
+
+module_platform_driver(mc13783_codec_driver);
+
+MODULE_DESCRIPTION("ASoC MC13783 driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/mc13783.h b/sound/soc/codecs/mc13783.h
new file mode 100644 (file)
index 0000000..3a6d199
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2008 Juergen Beisert, 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 MC13783_MIXER_H
+#define MC13783_MIXER_H
+
+#define MC13783_CLK_CLIA       1
+#define MC13783_CLK_CLIB       2
+
+#define MC13783_ID_STEREO_DAC  1
+#define MC13783_ID_STEREO_CODEC        2
+#define MC13783_ID_SYNC                3
+
+#endif /* MC13783_MIXER_H */
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
new file mode 100644 (file)
index 0000000..22cb5bf
--- /dev/null
@@ -0,0 +1,681 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor Co., 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; 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "ml26124.h"
+
+#define DVOL_CTL_DVMUTE_ON             BIT(4)  /* Digital volume MUTE On */
+#define DVOL_CTL_DVMUTE_OFF            0       /* Digital volume MUTE Off */
+#define ML26124_SAI_NO_DELAY   BIT(1)
+#define ML26124_SAI_FRAME_SYNC (BIT(5) | BIT(0)) /* For mono (Telecodec) */
+#define ML26134_CACHESIZE 212
+#define ML26124_VMID   BIT(1)
+#define ML26124_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 |\
+                      SNDRV_PCM_RATE_48000)
+#define ML26124_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE)
+#define ML26124_NUM_REGISTER ML26134_CACHESIZE
+
+struct ml26124_priv {
+       u32 mclk;
+       u32 rate;
+       struct regmap *regmap;
+       int clk_in;
+       struct snd_pcm_substream *substream;
+};
+
+struct clk_coeff {
+       u32 mclk;
+       u32 rate;
+       u8 pllnl;
+       u8 pllnh;
+       u8 pllml;
+       u8 pllmh;
+       u8 plldiv;
+};
+
+/* ML26124 configuration */
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7150, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(alclvl, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mingain, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(maxgain, -675, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_vol, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0);
+
+static const char * const ml26124_companding[] = {"16bit PCM", "u-law",
+                                                 "A-law"};
+
+static const struct soc_enum ml26124_adc_companding_enum
+       = SOC_ENUM_SINGLE(ML26124_SAI_TRANS_CTL, 6, 3, ml26124_companding);
+
+static const struct soc_enum ml26124_dac_companding_enum
+       = SOC_ENUM_SINGLE(ML26124_SAI_RCV_CTL, 6, 3, ml26124_companding);
+
+static const struct snd_kcontrol_new ml26124_snd_controls[] = {
+       SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0,
+                       0xff, 1, digital_tlv),
+       SOC_SINGLE_TLV("Playback Digital Volume", ML26124_PLBAK_DIG_VOL, 0,
+                       0xff, 1, digital_tlv),
+       SOC_SINGLE_TLV("Digital Boost Volume", ML26124_DIGI_BOOST_VOL, 0,
+                       0x3f, 0, boost_vol),
+       SOC_SINGLE_TLV("EQ Band0 Volume", ML26124_EQ_GAIN_BRAND0, 0,
+                       0xff, 1, digital_tlv),
+       SOC_SINGLE_TLV("EQ Band1 Volume", ML26124_EQ_GAIN_BRAND1, 0,
+                       0xff, 1, digital_tlv),
+       SOC_SINGLE_TLV("EQ Band2 Volume", ML26124_EQ_GAIN_BRAND2, 0,
+                       0xff, 1, digital_tlv),
+       SOC_SINGLE_TLV("EQ Band3 Volume", ML26124_EQ_GAIN_BRAND3, 0,
+                       0xff, 1, digital_tlv),
+       SOC_SINGLE_TLV("EQ Band4 Volume", ML26124_EQ_GAIN_BRAND4, 0,
+                       0xff, 1, digital_tlv),
+       SOC_SINGLE_TLV("ALC Target Level", ML26124_ALC_TARGET_LEV, 0,
+                       0xf, 1, alclvl),
+       SOC_SINGLE_TLV("ALC Min Input Volume", ML26124_ALC_MAXMIN_GAIN, 0,
+                       7, 0, mingain),
+       SOC_SINGLE_TLV("ALC Max Input Volume", ML26124_ALC_MAXMIN_GAIN, 4,
+                       7, 1, maxgain),
+       SOC_SINGLE_TLV("Playback Limiter Min Input Volume",
+                       ML26124_PL_MAXMIN_GAIN, 0, 7, 0, mingain),
+       SOC_SINGLE_TLV("Playback Limiter Max Input Volume",
+                       ML26124_PL_MAXMIN_GAIN, 4, 7, 1, maxgain),
+       SOC_SINGLE_TLV("Playback Boost Volume", ML26124_PLYBAK_BOST_VOL, 0,
+                       0x3f, 0, boost_vol),
+       SOC_SINGLE("DC High Pass Filter Switch", ML26124_FILTER_EN, 0, 1, 0),
+       SOC_SINGLE("Noise High Pass Filter Switch", ML26124_FILTER_EN, 1, 1, 0),
+       SOC_SINGLE("ZC Switch", ML26124_PW_ZCCMP_PW_MNG, 1,
+                   1, 0),
+       SOC_SINGLE("EQ Band0 Switch", ML26124_FILTER_EN, 2, 1, 0),
+       SOC_SINGLE("EQ Band1 Switch", ML26124_FILTER_EN, 3, 1, 0),
+       SOC_SINGLE("EQ Band2 Switch", ML26124_FILTER_EN, 4, 1, 0),
+       SOC_SINGLE("EQ Band3 Switch", ML26124_FILTER_EN, 5, 1, 0),
+       SOC_SINGLE("EQ Band4 Switch", ML26124_FILTER_EN, 6, 1, 0),
+       SOC_SINGLE("Play Limiter", ML26124_DVOL_CTL, 0, 1, 0),
+       SOC_SINGLE("Capture Limiter", ML26124_DVOL_CTL, 1, 1, 0),
+       SOC_SINGLE("Digital Volume Fade Switch", ML26124_DVOL_CTL, 3, 1, 0),
+       SOC_SINGLE("Digital Switch", ML26124_DVOL_CTL, 4, 1, 0),
+       SOC_ENUM("DAC Companding", ml26124_dac_companding_enum),
+       SOC_ENUM("ADC Companding", ml26124_adc_companding_enum),
+};
+
+static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DAC Switch", ML26124_SPK_AMP_OUT, 1, 1, 0),
+       SOC_DAPM_SINGLE("Line in loopback Switch", ML26124_SPK_AMP_OUT, 3, 1,
+                        0),
+       SOC_DAPM_SINGLE("PGA Switch", ML26124_SPK_AMP_OUT, 5, 1, 0),
+};
+
+/* Input mux */
+static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in",
+                               "Digital MIC in", "Analog MIC Differential in"};
+
+static const struct soc_enum ml26124_insel_enum =
+       SOC_ENUM_SINGLE(ML26124_MIC_IF_CTL, 0, 3, ml26124_input_select);
+
+static const struct snd_kcontrol_new ml26124_input_mux_controls =
+       SOC_DAPM_ENUM("Input Select", ml26124_insel_enum);
+
+static const struct snd_kcontrol_new ml26124_line_control =
+       SOC_DAPM_SINGLE("Switch", ML26124_PW_LOUT_PW_MNG, 1, 1, 0);
+
+static const struct snd_soc_dapm_widget ml26124_dapm_widgets[] = {
+       SND_SOC_DAPM_SUPPLY("MCLKEN", ML26124_CLK_EN, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("PLLEN", ML26124_CLK_EN, 1, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("PLLOE", ML26124_CLK_EN, 2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS", ML26124_PW_REF_PW_MNG, 2, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
+                          &ml26124_output_mixer_controls[0],
+                          ARRAY_SIZE(ml26124_output_mixer_controls)),
+       SND_SOC_DAPM_DAC("DAC", "Playback", ML26124_PW_DAC_PW_MNG, 1, 0),
+       SND_SOC_DAPM_ADC("ADC", "Capture", ML26124_PW_IN_PW_MNG, 1, 0),
+       SND_SOC_DAPM_PGA("PGA", ML26124_PW_IN_PW_MNG, 3, 0, NULL, 0),
+       SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+                         &ml26124_input_mux_controls),
+       SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0,
+                            &ml26124_line_control),
+       SND_SOC_DAPM_INPUT("MDIN"),
+       SND_SOC_DAPM_INPUT("MIN"),
+       SND_SOC_DAPM_INPUT("LIN"),
+       SND_SOC_DAPM_OUTPUT("SPOUT"),
+       SND_SOC_DAPM_OUTPUT("LOUT"),
+};
+
+static const struct snd_soc_dapm_route ml26124_intercon[] = {
+       /* Supply */
+       {"DAC", NULL, "MCLKEN"},
+       {"ADC", NULL, "MCLKEN"},
+       {"DAC", NULL, "PLLEN"},
+       {"ADC", NULL, "PLLEN"},
+       {"DAC", NULL, "PLLOE"},
+       {"ADC", NULL, "PLLOE"},
+
+       /* output mixer */
+       {"Output Mixer", "DAC Switch", "DAC"},
+       {"Output Mixer", "Line in loopback Switch", "LIN"},
+
+       /* outputs */
+       {"LOUT", NULL, "Output Mixer"},
+       {"SPOUT", NULL, "Output Mixer"},
+       {"Line Out Enable", NULL, "LOUT"},
+
+       /* input */
+       {"ADC", NULL, "Input Mux"},
+       {"Input Mux", "Analog MIC SingleEnded in", "PGA"},
+       {"Input Mux", "Analog MIC Differential in", "PGA"},
+       {"PGA", NULL, "MIN"},
+};
+
+/* PLLOutputFreq(Hz) = InputMclkFreq(Hz) * PLLM / (PLLN * PLLDIV) */
+static const struct clk_coeff coeff_div[] = {
+       {12288000, 16000, 0xc, 0x0, 0x20, 0x0, 0x4},
+       {12288000, 32000, 0xc, 0x0, 0x20, 0x0, 0x4},
+       {12288000, 48000, 0xc, 0x0, 0x30, 0x0, 0x4},
+};
+
+static struct reg_default ml26124_reg[] = {
+       /* CLOCK control Register */
+       {0x00, 0x00 },  /* Sampling Rate */
+       {0x02, 0x00},   /* PLL NL */
+       {0x04, 0x00},   /* PLLNH */
+       {0x06, 0x00},   /* PLLML */
+       {0x08, 0x00},   /* MLLMH */
+       {0x0a, 0x00},   /* PLLDIV */
+       {0x0c, 0x00},   /* Clock Enable */
+       {0x0e, 0x00},   /* CLK Input/Output Control */
+
+       /* System Control Register */
+       {0x10, 0x00},   /* Software RESET */
+       {0x12, 0x00},   /* Record/Playback Run */
+       {0x14, 0x00},   /* Mic Input/Output control */
+
+       /* Power Management Register */
+       {0x20, 0x00},   /* Reference Power Management */
+       {0x22, 0x00},   /* Input Power Management */
+       {0x24, 0x00},   /* DAC Power Management */
+       {0x26, 0x00},   /* SP-AMP Power Management */
+       {0x28, 0x00},   /* LINEOUT Power Management */
+       {0x2a, 0x00},   /* VIDEO Power Management */
+       {0x2e, 0x00},   /* AC-CMP Power Management */
+
+       /* Analog reference Control Register */
+       {0x30, 0x04},   /* MICBIAS Voltage Control */
+
+       /* Input/Output Amplifier Control Register */
+       {0x32, 0x10},   /* MIC Input Volume */
+       {0x38, 0x00},   /* Mic Boost Volume */
+       {0x3a, 0x33},   /* Speaker AMP Volume */
+       {0x48, 0x00},   /* AMP Volume Control Function Enable */
+       {0x4a, 0x00},   /* Amplifier Volume Fader Control */
+
+       /* Analog Path Control Register */
+       {0x54, 0x00},   /* Speaker AMP Output Control */
+       {0x5a, 0x00},   /* Mic IF Control */
+       {0xe8, 0x01},   /* Mic Select Control */
+
+       /* Audio Interface Control Register */
+       {0x60, 0x00},   /* SAI-Trans Control */
+       {0x62, 0x00},   /* SAI-Receive Control */
+       {0x64, 0x00},   /* SAI Mode select */
+
+       /* DSP Control Register */
+       {0x66, 0x01},   /* Filter Func Enable */
+       {0x68, 0x00},   /* Volume Control Func Enable */
+       {0x6A, 0x00},   /* Mixer & Volume Control*/
+       {0x6C, 0xff},   /* Record Digital Volume */
+       {0x70, 0xff},   /* Playback Digital Volume */
+       {0x72, 0x10},   /* Digital Boost Volume */
+       {0x74, 0xe7},   /* EQ gain Band0 */
+       {0x76, 0xe7},   /* EQ gain Band1 */
+       {0x78, 0xe7},   /* EQ gain Band2 */
+       {0x7A, 0xe7},   /* EQ gain Band3 */
+       {0x7C, 0xe7},   /* EQ gain Band4 */
+       {0x7E, 0x00},   /* HPF2 CutOff*/
+       {0x80, 0x00},   /* EQ Band0 Coef0L */
+       {0x82, 0x00},   /* EQ Band0 Coef0H */
+       {0x84, 0x00},   /* EQ Band0 Coef0L */
+       {0x86, 0x00},   /* EQ Band0 Coef0H */
+       {0x88, 0x00},   /* EQ Band1 Coef0L */
+       {0x8A, 0x00},   /* EQ Band1 Coef0H */
+       {0x8C, 0x00},   /* EQ Band1 Coef0L */
+       {0x8E, 0x00},   /* EQ Band1 Coef0H */
+       {0x90, 0x00},   /* EQ Band2 Coef0L */
+       {0x92, 0x00},   /* EQ Band2 Coef0H */
+       {0x94, 0x00},   /* EQ Band2 Coef0L */
+       {0x96, 0x00},   /* EQ Band2 Coef0H */
+       {0x98, 0x00},   /* EQ Band3 Coef0L */
+       {0x9A, 0x00},   /* EQ Band3 Coef0H */
+       {0x9C, 0x00},   /* EQ Band3 Coef0L */
+       {0x9E, 0x00},   /* EQ Band3 Coef0H */
+       {0xA0, 0x00},   /* EQ Band4 Coef0L */
+       {0xA2, 0x00},   /* EQ Band4 Coef0H */
+       {0xA4, 0x00},   /* EQ Band4 Coef0L */
+       {0xA6, 0x00},   /* EQ Band4 Coef0H */
+
+       /* ALC Control Register */
+       {0xb0, 0x00},   /* ALC Mode */
+       {0xb2, 0x02},   /* ALC Attack Time */
+       {0xb4, 0x03},   /* ALC Decay Time */
+       {0xb6, 0x00},   /* ALC Hold Time */
+       {0xb8, 0x0b},   /* ALC Target Level */
+       {0xba, 0x70},   /* ALC Max/Min Gain */
+       {0xbc, 0x00},   /* Noise Gate Threshold */
+       {0xbe, 0x00},   /* ALC ZeroCross TimeOut */
+
+       /* Playback Limiter Control Register */
+       {0xc0, 0x04},   /* PL Attack Time */
+       {0xc2, 0x05},   /* PL Decay Time */
+       {0xc4, 0x0d},   /* PL Target Level */
+       {0xc6, 0x70},   /* PL Max/Min Gain */
+       {0xc8, 0x10},   /* Playback Boost Volume */
+       {0xca, 0x00},   /* PL ZeroCross TimeOut */
+
+       /* Video Amplifier Control Register */
+       {0xd0, 0x01},   /* VIDEO AMP Gain Control */
+       {0xd2, 0x01},   /* VIDEO AMP Setup 1 */
+       {0xd4, 0x01},   /* VIDEO AMP Control2 */
+};
+
+/* Get sampling rate value of sampling rate setting register (0x0) */
+static inline int get_srate(int rate)
+{
+       int srate;
+
+       switch (rate) {
+       case 16000:
+               srate = 3;
+               break;
+       case 32000:
+               srate = 6;
+               break;
+       case 48000:
+               srate = 8;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return srate;
+}
+
+static inline int get_coeff(int mclk, int rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+               if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+                       return i;
+       }
+       return -EINVAL;
+}
+
+static int ml26124_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *hw_params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+       int i = get_coeff(priv->mclk, params_rate(hw_params));
+
+       priv->substream = substream;
+       priv->rate = params_rate(hw_params);
+
+       if (priv->clk_in) {
+               switch (priv->mclk / params_rate(hw_params)) {
+               case 256:
+                       snd_soc_update_bits(codec, ML26124_CLK_CTL,
+                                           BIT(0) | BIT(1), 1);
+                       break;
+               case 512:
+                       snd_soc_update_bits(codec, ML26124_CLK_CTL,
+                                           BIT(0) | BIT(1), 2);
+                       break;
+               case 1024:
+                       snd_soc_update_bits(codec, ML26124_CLK_CTL,
+                                           BIT(0) | BIT(1), 3);
+                       break;
+               default:
+                       dev_err(codec->dev, "Unsupported MCLKI\n");
+                       break;
+               }
+       } else {
+               snd_soc_update_bits(codec, ML26124_CLK_CTL,
+                                   BIT(0) | BIT(1), 0);
+       }
+
+       switch (params_rate(hw_params)) {
+       case 16000:
+               snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
+                                   get_srate(params_rate(hw_params)));
+               snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
+                                   coeff_div[i].pllnl);
+               snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
+                                   coeff_div[i].pllnh);
+               snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
+                                   coeff_div[i].pllml);
+               snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
+                                   coeff_div[i].pllmh);
+               snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
+                                   coeff_div[i].plldiv);
+               break;
+       case 32000:
+               snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
+                                   get_srate(params_rate(hw_params)));
+               snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
+                                   coeff_div[i].pllnl);
+               snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
+                                   coeff_div[i].pllnh);
+               snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
+                                   coeff_div[i].pllml);
+               snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
+                                   coeff_div[i].pllmh);
+               snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
+                                   coeff_div[i].plldiv);
+               break;
+       case 48000:
+               snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
+                                   get_srate(params_rate(hw_params)));
+               snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
+                                   coeff_div[i].pllnl);
+               snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
+                                   coeff_div[i].pllnh);
+               snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
+                                   coeff_div[i].pllml);
+               snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
+                                   coeff_div[i].pllmh);
+               snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
+                                   coeff_div[i].plldiv);
+               break;
+       default:
+               pr_err("%s:this rate is no support for ml26124\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ml26124_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       switch (priv->substream->stream) {
+       case SNDRV_PCM_STREAM_CAPTURE:
+               snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, BIT(0), 1);
+               break;
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, BIT(1), 2);
+               break;
+       }
+
+       if (mute)
+               snd_soc_update_bits(codec, ML26124_DVOL_CTL, BIT(4),
+                                   DVOL_CTL_DVMUTE_ON);
+       else
+               snd_soc_update_bits(codec, ML26124_DVOL_CTL, BIT(4),
+                                   DVOL_CTL_DVMUTE_OFF);
+
+       return 0;
+}
+
+static int ml26124_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       unsigned char mode;
+       struct snd_soc_codec *codec = codec_dai->codec;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               mode = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               mode = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, ML26124_SAI_MODE_SEL, BIT(0), mode);
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ml26124_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       switch (clk_id) {
+       case ML26124_USE_PLLOUT:
+               priv->clk_in = ML26124_USE_PLLOUT;
+               break;
+       case ML26124_USE_MCLKI:
+               priv->clk_in = ML26124_USE_MCLKI;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       priv->mclk = freq;
+
+       return 0;
+}
+
+static int ml26124_set_bias_level(struct snd_soc_codec *codec,
+               enum snd_soc_bias_level level)
+{
+       struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               snd_soc_update_bits(codec, ML26124_PW_SPAMP_PW_MNG,
+                                   ML26124_R26_MASK, ML26124_BLT_PREAMP_ON);
+               msleep(100);
+               snd_soc_update_bits(codec, ML26124_PW_SPAMP_PW_MNG,
+                                   ML26124_R26_MASK,
+                                   ML26124_MICBEN_ON | ML26124_BLT_ALL_ON);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               /* VMID ON */
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
+                                           ML26124_VMID, ML26124_VMID);
+                       msleep(500);
+                       regcache_sync(priv->regmap);
+               }
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* VMID OFF */
+               snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
+                                   ML26124_VMID, 0);
+               break;
+       }
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+static const struct snd_soc_dai_ops ml26124_dai_ops = {
+       .hw_params      = ml26124_hw_params,
+       .digital_mute   = ml26124_mute,
+       .set_fmt        = ml26124_set_dai_fmt,
+       .set_sysclk     = ml26124_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver ml26124_dai = {
+       .name = "ml26124-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = ML26124_RATES,
+               .formats = ML26124_FORMATS,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = ML26124_RATES,
+               .formats = ML26124_FORMATS,},
+       .ops = &ml26124_dai_ops,
+       .symmetric_rates = 1,
+};
+
+#ifdef CONFIG_PM
+static int ml26124_suspend(struct snd_soc_codec *codec)
+{
+       ml26124_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int ml26124_resume(struct snd_soc_codec *codec)
+{
+       ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+#else
+#define ml26124_suspend NULL
+#define ml26124_resume NULL
+#endif
+
+static int ml26124_probe(struct snd_soc_codec *codec)
+{
+       int ret;
+       struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+       codec->control_data = priv->regmap;
+
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       /* Software Reset */
+       snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1);
+       snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0);
+
+       ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
+       .probe =        ml26124_probe,
+       .suspend =      ml26124_suspend,
+       .resume =       ml26124_resume,
+       .set_bias_level = ml26124_set_bias_level,
+       .dapm_widgets = ml26124_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets),
+       .dapm_routes = ml26124_intercon,
+       .num_dapm_routes = ARRAY_SIZE(ml26124_intercon),
+       .controls = ml26124_snd_controls,
+       .num_controls = ARRAY_SIZE(ml26124_snd_controls),
+};
+
+static const struct regmap_config ml26124_i2c_regmap = {
+       .val_bits = 8,
+       .reg_bits = 8,
+       .max_register = ML26124_NUM_REGISTER,
+       .reg_defaults = ml26124_reg,
+       .num_reg_defaults = ARRAY_SIZE(ml26124_reg),
+       .cache_type = REGCACHE_RBTREE,
+       .write_flag_mask = 0x01,
+};
+
+static __devinit int ml26124_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct ml26124_priv *priv;
+       int ret;
+
+       priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, priv);
+
+       priv->regmap = regmap_init_i2c(i2c, &ml26124_i2c_regmap);
+       if (IS_ERR(priv->regmap)) {
+               ret = PTR_ERR(priv->regmap);
+               dev_err(&i2c->dev, "regmap_init_i2c() failed: %d\n", ret);
+               return ret;
+       }
+
+       return snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_ml26124, &ml26124_dai, 1);
+}
+
+static __devexit int ml26124_i2c_remove(struct i2c_client *client)
+{
+       struct ml26124_priv *priv = i2c_get_clientdata(client);
+
+       snd_soc_unregister_codec(&client->dev);
+       regmap_exit(priv->regmap);
+       return 0;
+}
+
+static const struct i2c_device_id ml26124_i2c_id[] = {
+       { "ml26124", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ml26124_i2c_id);
+
+static struct i2c_driver ml26124_i2c_driver = {
+       .driver = {
+               .name = "ml26124",
+               .owner = THIS_MODULE,
+       },
+       .probe = ml26124_i2c_probe,
+       .remove = __devexit_p(ml26124_i2c_remove),
+       .id_table = ml26124_i2c_id,
+};
+
+module_i2c_driver(ml26124_i2c_driver);
+
+MODULE_AUTHOR("Tomoya MORINAGA <tomoya.rohm@gmail.com>");
+MODULE_DESCRIPTION("LAPIS Semiconductor ML26124 ALSA SoC codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ml26124.h b/sound/soc/codecs/ml26124.h
new file mode 100644 (file)
index 0000000..5ea0cbb
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor Co., 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef ML26124_H
+#define ML26124_H
+
+/* Clock Control Register */
+#define ML26124_SMPLING_RATE           0x00
+#define ML26124_PLLNL                  0x02
+#define ML26124_PLLNH                  0x04
+#define ML26124_PLLML                  0x06
+#define ML26124_PLLMH                  0x08
+#define ML26124_PLLDIV                 0x0a
+#define ML26124_CLK_EN                 0x0c
+#define ML26124_CLK_CTL                        0x0e
+
+/* System Control Register */
+#define ML26124_SW_RST                 0x10
+#define ML26124_REC_PLYBAK_RUN         0x12
+#define ML26124_MIC_TIM                        0x14
+
+/* Power Mnagement Register */
+#define ML26124_PW_REF_PW_MNG          0x20
+#define ML26124_PW_IN_PW_MNG           0x22
+#define ML26124_PW_DAC_PW_MNG          0x24
+#define ML26124_PW_SPAMP_PW_MNG                0x26
+#define ML26124_PW_LOUT_PW_MNG         0x28
+#define ML26124_PW_VOUT_PW_MNG         0x2a
+#define ML26124_PW_ZCCMP_PW_MNG                0x2e
+
+/* Analog Reference Control Register */
+#define ML26124_PW_MICBIAS_VOL         0x30
+
+/* Input/Output Amplifier Control Register */
+#define ML26124_PW_MIC_IN_VOL          0x32
+#define ML26124_PW_MIC_BOST_VOL                0x38
+#define ML26124_PW_SPK_AMP_VOL         0x3a
+#define ML26124_PW_AMP_VOL_FUNC                0x48
+#define ML26124_PW_AMP_VOL_FADE                0x4a
+
+/* Analog Path Control Register */
+#define ML26124_SPK_AMP_OUT            0x54
+#define ML26124_MIC_IF_CTL             0x5a
+#define ML26124_MIC_SELECT             0xe8
+
+/* Audio Interface Control Register */
+#define ML26124_SAI_TRANS_CTL          0x60
+#define ML26124_SAI_RCV_CTL            0x62
+#define ML26124_SAI_MODE_SEL           0x64
+
+/* DSP Control Register */
+#define ML26124_FILTER_EN              0x66
+#define ML26124_DVOL_CTL               0x68
+#define ML26124_MIXER_VOL_CTL          0x6a
+#define ML26124_RECORD_DIG_VOL         0x6c
+#define ML26124_PLBAK_DIG_VOL          0x70
+#define ML26124_DIGI_BOOST_VOL         0x72
+#define ML26124_EQ_GAIN_BRAND0         0x74
+#define ML26124_EQ_GAIN_BRAND1         0x76
+#define ML26124_EQ_GAIN_BRAND2         0x78
+#define ML26124_EQ_GAIN_BRAND3         0x7a
+#define ML26124_EQ_GAIN_BRAND4         0x7c
+#define ML26124_HPF2_CUTOFF            0x7e
+#define ML26124_EQBRAND0_F0L           0x80
+#define ML26124_EQBRAND0_F0H           0x82
+#define ML26124_EQBRAND0_F1L           0x84
+#define ML26124_EQBRAND0_F1H           0x86
+#define ML26124_EQBRAND1_F0L           0x88
+#define ML26124_EQBRAND1_F0H           0x8a
+#define ML26124_EQBRAND1_F1L           0x8c
+#define ML26124_EQBRAND1_F1H           0x8e
+#define ML26124_EQBRAND2_F0L           0x90
+#define ML26124_EQBRAND2_F0H           0x92
+#define ML26124_EQBRAND2_F1L           0x94
+#define ML26124_EQBRAND2_F1H           0x96
+#define ML26124_EQBRAND3_F0L           0x98
+#define ML26124_EQBRAND3_F0H           0x9a
+#define ML26124_EQBRAND3_F1L           0x9c
+#define ML26124_EQBRAND3_F1H           0x9e
+#define ML26124_EQBRAND4_F0L           0xa0
+#define ML26124_EQBRAND4_F0H           0xa2
+#define ML26124_EQBRAND4_F1L           0xa4
+#define ML26124_EQBRAND4_F1H           0xa6
+
+/* ALC Control Register */
+#define ML26124_ALC_MODE               0xb0
+#define ML26124_ALC_ATTACK_TIM         0xb2
+#define ML26124_ALC_DECAY_TIM          0xb4
+#define ML26124_ALC_HOLD_TIM           0xb6
+#define ML26124_ALC_TARGET_LEV         0xb8
+#define ML26124_ALC_MAXMIN_GAIN                0xba
+#define ML26124_NOIS_GATE_THRSH                0xbc
+#define ML26124_ALC_ZERO_TIMOUT                0xbe
+
+/* Playback Limiter Control Register */
+#define ML26124_PL_ATTACKTIME          0xc0
+#define ML26124_PL_DECAYTIME           0xc2
+#define ML26124_PL_TARGETTIME          0xc4
+#define ML26124_PL_MAXMIN_GAIN         0xc6
+#define ML26124_PLYBAK_BOST_VOL                0xc8
+#define ML26124_PL_0CROSS_TIMOUT       0xca
+
+/* Video Amplifer Control Register */
+#define ML26124_VIDEO_AMP_GAIN_CTL     0xd0
+#define ML26124_VIDEO_AMP_SETUP1       0xd2
+#define ML26124_VIDEO_AMP_CTL2         0xd4
+
+/* Clock select for machine driver */
+#define ML26124_USE_PLL                        0
+#define ML26124_USE_MCLKI_256FS                1
+#define ML26124_USE_MCLKI_512FS                2
+#define ML26124_USE_MCLKI_1024FS       3
+
+/* Register Mask */
+#define ML26124_R0_MASK        0xf
+#define ML26124_R2_MASK        0xff
+#define ML26124_R4_MASK        0x1
+#define ML26124_R6_MASK        0xf
+#define ML26124_R8_MASK        0x3f
+#define ML26124_Ra_MASK        0x1f
+#define ML26124_Rc_MASK        0x1f
+#define ML26124_Re_MASK        0x7
+#define ML26124_R10_MASK       0x1
+#define ML26124_R12_MASK       0x17
+#define ML26124_R14_MASK       0x3f
+#define ML26124_R20_MASK       0x47
+#define ML26124_R22_MASK       0xa
+#define ML26124_R24_MASK       0x2
+#define ML26124_R26_MASK       0x1f
+#define ML26124_R28_MASK       0x2
+#define ML26124_R2a_MASK       0x2
+#define ML26124_R2e_MASK       0x2
+#define ML26124_R30_MASK       0x7
+#define ML26124_R32_MASK       0x3f
+#define ML26124_R38_MASK       0x38
+#define ML26124_R3a_MASK       0x3f
+#define ML26124_R48_MASK       0x3
+#define ML26124_R4a_MASK       0x7
+#define ML26124_R54_MASK       0x2a
+#define ML26124_R5a_MASK       0x3
+#define ML26124_Re8_MASK       0x3
+#define ML26124_R60_MASK       0xff
+#define ML26124_R62_MASK       0xff
+#define ML26124_R64_MASK       0x1
+#define ML26124_R66_MASK       0xff
+#define ML26124_R68_MASK       0x3b
+#define ML26124_R6a_MASK       0xf3
+#define ML26124_R6c_MASK       0xff
+#define ML26124_R70_MASK       0xff
+
+#define ML26124_MCLKEN         BIT(0)
+#define ML26124_PLLEN          BIT(1)
+#define ML26124_PLLOE          BIT(2)
+#define ML26124_MCLKOE         BIT(3)
+
+#define ML26124_BLT_ALL_ON     0x1f
+#define ML26124_BLT_PREAMP_ON  0x13
+
+#define ML26124_MICBEN_ON      BIT(2)
+
+enum ml26124_regs {
+       ML26124_MCLK = 0,
+};
+
+enum ml26124_clk_in {
+       ML26124_USE_PLLOUT = 0,
+       ML26124_USE_MCLKI,
+};
+
+#endif
diff --git a/sound/soc/codecs/omap-hdmi.c b/sound/soc/codecs/omap-hdmi.c
new file mode 100644 (file)
index 0000000..1bf5c74
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * ALSA SoC codec driver for HDMI audio on OMAP processors.
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Ricardo Neri <ricardo.neri@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "hdmi-audio-codec"
+
+static struct snd_soc_codec_driver omap_hdmi_codec;
+
+static struct snd_soc_dai_driver omap_hdmi_codec_dai = {
+       .name = "omap-hdmi-hifi",
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 8,
+               .rates = SNDRV_PCM_RATE_32000 |
+                       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                       SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+                       SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_LE,
+       },
+};
+
+static __devinit int omap_hdmi_codec_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev, &omap_hdmi_codec,
+                       &omap_hdmi_codec_dai, 1);
+}
+
+static __devexit int omap_hdmi_codec_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver omap_hdmi_codec_driver = {
+       .driver         = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+
+       .probe          = omap_hdmi_codec_probe,
+       .remove         = __devexit_p(omap_hdmi_codec_remove),
+};
+
+module_platform_driver(omap_hdmi_codec_driver);
+
+MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
+MODULE_DESCRIPTION("ASoC OMAP HDMI codec driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index 20c324c7c3492814a803130cbbc80a8ab75380d0..960d0e93cce9463a3592c17d74de0f9d5ad4bf19 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/spi/spi.h>
+#include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -30,6 +30,7 @@
 #include "rt5631.h"
 
 struct rt5631_priv {
+       struct regmap *regmap;
        int codec_version;
        int master;
        int sysclk;
@@ -38,33 +39,33 @@ struct rt5631_priv {
        int dmic_used_flag;
 };
 
-static const u16 rt5631_reg[RT5631_VENDOR_ID2 + 1] = {
-       [RT5631_SPK_OUT_VOL] = 0x8888,
-       [RT5631_HP_OUT_VOL] = 0x8080,
-       [RT5631_MONO_AXO_1_2_VOL] = 0xa080,
-       [RT5631_AUX_IN_VOL] = 0x0808,
-       [RT5631_ADC_REC_MIXER] = 0xf0f0,
-       [RT5631_VDAC_DIG_VOL] = 0x0010,
-       [RT5631_OUTMIXER_L_CTRL] = 0xffc0,
-       [RT5631_OUTMIXER_R_CTRL] = 0xffc0,
-       [RT5631_AXO1MIXER_CTRL] = 0x88c0,
-       [RT5631_AXO2MIXER_CTRL] = 0x88c0,
-       [RT5631_DIG_MIC_CTRL] = 0x3000,
-       [RT5631_MONO_INPUT_VOL] = 0x8808,
-       [RT5631_SPK_MIXER_CTRL] = 0xf8f8,
-       [RT5631_SPK_MONO_OUT_CTRL] = 0xfc00,
-       [RT5631_SPK_MONO_HP_OUT_CTRL] = 0x4440,
-       [RT5631_SDP_CTRL] = 0x8000,
-       [RT5631_MONO_SDP_CTRL] = 0x8000,
-       [RT5631_STEREO_AD_DA_CLK_CTRL] = 0x2010,
-       [RT5631_GEN_PUR_CTRL_REG] = 0x0e00,
-       [RT5631_INT_ST_IRQ_CTRL_2] = 0x071a,
-       [RT5631_MISC_CTRL] = 0x2040,
-       [RT5631_DEPOP_FUN_CTRL_2] = 0x8000,
-       [RT5631_SOFT_VOL_CTRL] = 0x07e0,
-       [RT5631_ALC_CTRL_1] = 0x0206,
-       [RT5631_ALC_CTRL_3] = 0x2000,
-       [RT5631_PSEUDO_SPATL_CTRL] = 0x0553,
+static const struct reg_default rt5631_reg[] = {
+       { RT5631_SPK_OUT_VOL, 0x8888 },
+       { RT5631_HP_OUT_VOL, 0x8080 },
+       { RT5631_MONO_AXO_1_2_VOL, 0xa080 },
+       { RT5631_AUX_IN_VOL, 0x0808 },
+       { RT5631_ADC_REC_MIXER, 0xf0f0 },
+       { RT5631_VDAC_DIG_VOL, 0x0010 },
+       { RT5631_OUTMIXER_L_CTRL, 0xffc0 },
+       { RT5631_OUTMIXER_R_CTRL, 0xffc0 },
+       { RT5631_AXO1MIXER_CTRL, 0x88c0 },
+       { RT5631_AXO2MIXER_CTRL, 0x88c0 },
+       { RT5631_DIG_MIC_CTRL, 0x3000 },
+       { RT5631_MONO_INPUT_VOL, 0x8808 },
+       { RT5631_SPK_MIXER_CTRL, 0xf8f8 },
+       { RT5631_SPK_MONO_OUT_CTRL, 0xfc00 },
+       { RT5631_SPK_MONO_HP_OUT_CTRL, 0x4440 },
+       { RT5631_SDP_CTRL, 0x8000 },
+       { RT5631_MONO_SDP_CTRL, 0x8000 },
+       { RT5631_STEREO_AD_DA_CLK_CTRL, 0x2010 },
+       { RT5631_GEN_PUR_CTRL_REG, 0x0e00 },
+       { RT5631_INT_ST_IRQ_CTRL_2, 0x071a },
+       { RT5631_MISC_CTRL, 0x2040 },
+       { RT5631_DEPOP_FUN_CTRL_2, 0x8000 },
+       { RT5631_SOFT_VOL_CTRL, 0x07e0 },
+       { RT5631_ALC_CTRL_1, 0x0206 },
+       { RT5631_ALC_CTRL_3, 0x2000 },
+       { RT5631_PSEUDO_SPATL_CTRL, 0x0553 },
 };
 
 /**
@@ -96,8 +97,7 @@ static int rt5631_reset(struct snd_soc_codec *codec)
        return snd_soc_write(codec, RT5631_RESET, 0);
 }
 
-static int rt5631_volatile_register(struct snd_soc_codec *codec,
-                                   unsigned int reg)
+static bool rt5631_volatile_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case RT5631_RESET:
@@ -111,8 +111,7 @@ static int rt5631_volatile_register(struct snd_soc_codec *codec,
        }
 }
 
-static int rt5631_readable_register(struct snd_soc_codec *codec,
-                                   unsigned int reg)
+static bool rt5631_readable_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case RT5631_RESET:
@@ -1361,8 +1360,7 @@ static int get_coeff(int mclk, int rate, int timesofbclk)
 static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
        int timesofbclk = 32, coeff;
        unsigned int iface = 0;
@@ -1544,6 +1542,8 @@ static int rt5631_codec_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 static int rt5631_set_bias_level(struct snd_soc_codec *codec,
                        enum snd_soc_bias_level level)
 {
+       struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+
        switch (level) {
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
@@ -1561,8 +1561,8 @@ static int rt5631_set_bias_level(struct snd_soc_codec *codec,
                        snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
                                RT5631_PWR_FAST_VREF_CTRL,
                                RT5631_PWR_FAST_VREF_CTRL);
-                       codec->cache_only = false;
-                       snd_soc_cache_sync(codec);
+                       regcache_cache_only(rt5631->regmap, false);
+                       regcache_sync(rt5631->regmap);
                }
                break;
 
@@ -1587,7 +1587,9 @@ static int rt5631_probe(struct snd_soc_codec *codec)
        unsigned int val;
        int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+       codec->control_data = rt5631->regmap;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
@@ -1698,12 +1700,6 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
        .suspend = rt5631_suspend,
        .resume = rt5631_resume,
        .set_bias_level = rt5631_set_bias_level,
-       .reg_cache_size = RT5631_VENDOR_ID2 + 1,
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = rt5631_reg,
-       .volatile_register = rt5631_volatile_register,
-       .readable_register = rt5631_readable_register,
-       .reg_cache_step = 1,
        .controls = rt5631_snd_controls,
        .num_controls = ARRAY_SIZE(rt5631_snd_controls),
        .dapm_widgets = rt5631_dapm_widgets,
@@ -1718,6 +1714,18 @@ static const struct i2c_device_id rt5631_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
 
+static const struct regmap_config rt5631_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 16,
+
+       .readable_reg = rt5631_readable_register,
+       .volatile_reg = rt5631_volatile_register,
+       .max_register = RT5631_VENDOR_ID2,
+       .reg_defaults = rt5631_reg,
+       .num_reg_defaults = ARRAY_SIZE(rt5631_reg),
+       .cache_type = REGCACHE_RBTREE,
+};
+
 static int rt5631_i2c_probe(struct i2c_client *i2c,
                    const struct i2c_device_id *id)
 {
@@ -1731,6 +1739,10 @@ static int rt5631_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, rt5631);
 
+       rt5631->regmap = devm_regmap_init_i2c(i2c, &rt5631_regmap_config);
+       if (IS_ERR(rt5631->regmap))
+               return PTR_ERR(rt5631->regmap);
+
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5631,
                        rt5631_dai, ARRAY_SIZE(rt5631_dai));
        return ret;
@@ -1752,17 +1764,7 @@ static struct i2c_driver rt5631_i2c_driver = {
        .id_table = rt5631_i2c_id,
 };
 
-static int __init rt5631_modinit(void)
-{
-       return i2c_add_driver(&rt5631_i2c_driver);
-}
-module_init(rt5631_modinit);
-
-static void __exit rt5631_modexit(void)
-{
-       i2c_del_driver(&rt5631_i2c_driver);
-}
-module_exit(rt5631_modexit);
+module_i2c_driver(rt5631_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC RT5631 driver");
 MODULE_AUTHOR("flove <flove@realtek.com>");
index c395ec370445d61bfa7ce766331f8dd47a7b6139..8af6a5245b18acbfefe5fa1ca8ecbec8fd9068be 100644 (file)
@@ -84,8 +84,8 @@ static struct regulator_consumer_supply ldo_consumer[] = {
 
 static struct regulator_init_data ldo_init_data = {
        .constraints = {
-               .min_uV                 = 850000,
-               .max_uV                 = 1600000,
+               .min_uV                 = 1200000,
+               .max_uV                 = 1200000,
                .valid_modes_mask       = REGULATOR_MODE_NORMAL,
                .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
        },
@@ -197,9 +197,9 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("HP_OUT"),
        SND_SOC_DAPM_OUTPUT("LINE_OUT"),
 
-       SND_SOC_DAPM_MICBIAS_E("Mic Bias", SGTL5000_CHIP_MIC_CTRL, 8, 0,
-                               mic_bias_event,
-                               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_SUPPLY("Mic Bias", SGTL5000_CHIP_MIC_CTRL, 8, 0,
+                           mic_bias_event,
+                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
        SND_SOC_DAPM_PGA("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0),
        SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0),
@@ -665,8 +665,7 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *params,
                                  struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
        int channels = params_channels(params);
        int i2s_ctl = 0;
@@ -1455,17 +1454,7 @@ static struct i2c_driver sgtl5000_i2c_driver = {
        .id_table = sgtl5000_id,
 };
 
-static int __init sgtl5000_modinit(void)
-{
-       return i2c_add_driver(&sgtl5000_i2c_driver);
-}
-module_init(sgtl5000_modinit);
-
-static void __exit sgtl5000_exit(void)
-{
-       i2c_del_driver(&sgtl5000_i2c_driver);
-}
-module_exit(sgtl5000_exit);
+module_i2c_driver(sgtl5000_i2c_driver);
 
 MODULE_DESCRIPTION("Freescale SGTL5000 ALSA SoC Codec Driver");
 MODULE_AUTHOR("Zeng Zhaoming <zengzm.kernel@gmail.com>");
index de2b20544ceb01cb8ecbecaae507d6b33826e53f..079066fef4255217adce5319e58be0d15acdcb91 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -43,8 +44,6 @@
 
 #include "ssm2602.h"
 
-#define SSM2602_VERSION "0.1"
-
 enum ssm2602_type {
        SSM2602,
        SSM2604,
@@ -53,10 +52,12 @@ enum ssm2602_type {
 /* codec private data */
 struct ssm2602_priv {
        unsigned int sysclk;
-       enum snd_soc_control_type control_type;
+       struct snd_pcm_hw_constraint_list *sysclk_constraints;
        struct snd_pcm_substream *master_substream;
        struct snd_pcm_substream *slave_substream;
 
+       struct regmap *regmap;
+
        enum ssm2602_type type;
        unsigned int clk_out_pwr;
 };
@@ -73,7 +74,6 @@ static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
        0x0000, 0x0000
 };
 
-#define ssm2602_reset(c)       snd_soc_write(c, SSM2602_RESET, 0)
 
 /*Appending several "None"s just for OSS mixer use*/
 static const char *ssm2602_input_select[] = {
@@ -195,6 +195,24 @@ static const struct snd_soc_dapm_route ssm2604_routes[] = {
        {"ADC", NULL, "Line Input"},
 };
 
+static const unsigned int ssm2602_rates_12288000[] = {
+       8000, 32000, 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
+       .list = ssm2602_rates_12288000,
+       .count = ARRAY_SIZE(ssm2602_rates_12288000),
+};
+
+static const unsigned int ssm2602_rates_11289600[] = {
+       8000, 44100, 88200,
+};
+
+static struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {
+       .list = ssm2602_rates_11289600,
+       .count = ARRAY_SIZE(ssm2602_rates_11289600),
+};
+
 struct ssm2602_coeff {
        u32 mclk;
        u32 rate;
@@ -254,11 +272,10 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-       u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3;
        int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
+       unsigned int iface;
 
        if (substream == ssm2602->slave_substream) {
                dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
@@ -268,31 +285,34 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
        if (srate < 0)
                return srate;
 
-       snd_soc_write(codec, SSM2602_SRATE, srate);
+       regmap_write(ssm2602->regmap, SSM2602_SRATE, srate);
 
        /* bit size */
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
+               iface = 0x0;
                break;
        case SNDRV_PCM_FORMAT_S20_3LE:
-               iface |= 0x0004;
+               iface = 0x4;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
-               iface |= 0x0008;
+               iface = 0x8;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
-               iface |= 0x000c;
+               iface = 0xc;
                break;
+       default:
+               return -EINVAL;
        }
-       snd_soc_write(codec, SSM2602_IFACE, iface);
+       regmap_update_bits(ssm2602->regmap, SSM2602_IFACE,
+               IFACE_AUDIO_DATA_LEN, iface);
        return 0;
 }
 
 static int ssm2602_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
        struct snd_pcm_runtime *master_runtime;
 
@@ -322,14 +342,19 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
        } else
                ssm2602->master_substream = substream;
 
+       if (ssm2602->sysclk_constraints) {
+               snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_RATE,
+                                  ssm2602->sysclk_constraints);
+       }
+
        return 0;
 }
 
 static void ssm2602_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
        if (ssm2602->master_substream == substream)
@@ -341,14 +366,14 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
 
 static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
 {
-       struct snd_soc_codec *codec = dai->codec;
+       struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(dai->codec);
 
        if (mute)
-               snd_soc_update_bits(codec, SSM2602_APDIGI,
+               regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
                                    APDIGI_ENABLE_DAC_MUTE,
                                    APDIGI_ENABLE_DAC_MUTE);
        else
-               snd_soc_update_bits(codec, SSM2602_APDIGI,
+               regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
                                    APDIGI_ENABLE_DAC_MUTE, 0);
        return 0;
 }
@@ -364,16 +389,21 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                        return -EINVAL;
 
                switch (freq) {
-               case 11289600:
-               case 12000000:
                case 12288000:
-               case 16934400:
                case 18432000:
-                       ssm2602->sysclk = freq;
+                       ssm2602->sysclk_constraints = &ssm2602_constraints_12288000;
+                       break;
+               case 11289600:
+               case 16934400:
+                       ssm2602->sysclk_constraints = &ssm2602_constraints_11289600;
+                       break;
+               case 12000000:
+                       ssm2602->sysclk_constraints = NULL;
                        break;
                default:
                        return -EINVAL;
                }
+               ssm2602->sysclk = freq;
        } else {
                unsigned int mask;
 
@@ -393,7 +423,7 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                else
                        ssm2602->clk_out_pwr &= ~mask;
 
-               snd_soc_update_bits(codec, SSM2602_PWR,
+               regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
                        PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr);
        }
 
@@ -403,8 +433,8 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
-       struct snd_soc_codec *codec = codec_dai->codec;
-       u16 iface = 0;
+       struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec_dai->codec);
+       unsigned int iface = 0;
 
        /* set master/slave audio interface */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -455,7 +485,7 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
        }
 
        /* set iface */
-       snd_soc_write(codec, SSM2602_IFACE, iface);
+       regmap_write(ssm2602->regmap, SSM2602_IFACE, iface);
        return 0;
 }
 
@@ -467,7 +497,7 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
        switch (level) {
        case SND_SOC_BIAS_ON:
                /* vref/mid on, osc and clkout on if enabled */
-               snd_soc_update_bits(codec, SSM2602_PWR,
+               regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
                        PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
                        ssm2602->clk_out_pwr);
                break;
@@ -475,13 +505,13 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
                break;
        case SND_SOC_BIAS_STANDBY:
                /* everything off except vref/vmid, */
-               snd_soc_update_bits(codec, SSM2602_PWR,
+               regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
                        PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
                        PWR_CLK_OUT_PDN | PWR_OSC_PDN);
                break;
        case SND_SOC_BIAS_OFF:
                /* everything off */
-               snd_soc_update_bits(codec, SSM2602_PWR,
+               regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
                        PWR_POWER_OFF, PWR_POWER_OFF);
                break;
 
@@ -540,12 +570,13 @@ static int ssm2602_resume(struct snd_soc_codec *codec)
 
 static int ssm2602_probe(struct snd_soc_codec *codec)
 {
+       struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
-       snd_soc_update_bits(codec, SSM2602_LOUT1V,
+       regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V,
                            LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH);
-       snd_soc_update_bits(codec, SSM2602_ROUT1V,
+       regmap_update_bits(ssm2602->regmap, SSM2602_ROUT1V,
                            ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);
 
        ret = snd_soc_add_codec_controls(codec, ssm2602_snd_controls,
@@ -581,27 +612,26 @@ static int ssm260x_probe(struct snd_soc_codec *codec)
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, ssm2602->control_type);
+       codec->control_data = ssm2602->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       ret = ssm2602_reset(codec);
+       ret = regmap_write(ssm2602->regmap, SSM2602_RESET, 0);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
                return ret;
        }
 
        /* set the update bits */
-       snd_soc_update_bits(codec, SSM2602_LINVOL,
+       regmap_update_bits(ssm2602->regmap, SSM2602_LINVOL,
                            LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH);
-       snd_soc_update_bits(codec, SSM2602_RINVOL,
+       regmap_update_bits(ssm2602->regmap, SSM2602_RINVOL,
                            RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH);
        /*select Line in as default input*/
-       snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
+       regmap_write(ssm2602->regmap, SSM2602_APANA, APANA_SELECT_DAC |
                        APANA_ENABLE_MIC_BOOST);
 
        switch (ssm2602->type) {
@@ -634,9 +664,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
        .suspend =      ssm2602_suspend,
        .resume =       ssm2602_resume,
        .set_bias_level = ssm2602_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(ssm2602_reg),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = ssm2602_reg,
 
        .controls = ssm260x_snd_controls,
        .num_controls = ARRAY_SIZE(ssm260x_snd_controls),
@@ -646,6 +673,23 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
        .num_dapm_routes = ARRAY_SIZE(ssm260x_routes),
 };
 
+static bool ssm2602_register_volatile(struct device *dev, unsigned int reg)
+{
+       return reg == SSM2602_RESET;
+}
+
+static const struct regmap_config ssm2602_regmap_config = {
+       .val_bits = 9,
+       .reg_bits = 7,
+
+       .max_register = SSM2602_RESET,
+       .volatile_reg = ssm2602_register_volatile,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults_raw = ssm2602_reg,
+       .num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg),
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit ssm2602_spi_probe(struct spi_device *spi)
 {
@@ -658,9 +702,12 @@ static int __devinit ssm2602_spi_probe(struct spi_device *spi)
                return -ENOMEM;
 
        spi_set_drvdata(spi, ssm2602);
-       ssm2602->control_type = SND_SOC_SPI;
        ssm2602->type = SSM2602;
 
+       ssm2602->regmap = devm_regmap_init_spi(spi, &ssm2602_regmap_config);
+       if (IS_ERR(ssm2602->regmap))
+               return PTR_ERR(ssm2602->regmap);
+
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
        return ret;
@@ -701,9 +748,12 @@ static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c,
                return -ENOMEM;
 
        i2c_set_clientdata(i2c, ssm2602);
-       ssm2602->control_type = SND_SOC_I2C;
        ssm2602->type = id->driver_data;
 
+       ssm2602->regmap = devm_regmap_init_i2c(i2c, &ssm2602_regmap_config);
+       if (IS_ERR(ssm2602->regmap))
+               return PTR_ERR(ssm2602->regmap);
+
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
        return ret;
index 7db6fa515028d566cfd75c5ee048db8b52f2ca54..8d717f4b5a875d5efb4bcdf283f3604366a07dea 100644 (file)
@@ -609,8 +609,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
        unsigned int rate;
        int i, mcs = -1, ir = -1;
index df1e07ffac32f6057f1e94d2a9421b14a8a89c9b..31762ebdd774d1947c115542eb4041144345b1b9 100644 (file)
@@ -34,8 +34,6 @@
 
 #include "tlv320aic23.h"
 
-#define AIC23_VERSION "0.1"
-
 /*
  * AIC23 register cache
  */
@@ -325,8 +323,7 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        u16 iface_reg;
        int ret;
        struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
@@ -371,8 +368,7 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
 static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
                                   struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
 
        /* set active */
        snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0001);
@@ -383,8 +379,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
 static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
 
        /* deactivate */
@@ -548,8 +543,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec)
        struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
-
        ret = snd_soc_codec_set_cache_io(codec, 7, 9, aic23->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
index 802064b5030d0b910736ae05d5365941a9d0b74c..85944e95357834c5e7c5584c9998d1947a42e905 100644 (file)
@@ -126,8 +126,7 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
                           struct snd_pcm_hw_params *params,
                           struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
        int fsref, divisor, wlen, pval, jval, dval, qval;
        u16 reg;
index 8d20f6ec20f35853b98e13735f5e540ef9c27c47..64d2a4fa34b27d81ad84d0e64ed625e04e293b7a 100644 (file)
@@ -802,8 +802,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
                           struct snd_pcm_hw_params *params,
                           struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec =rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
        int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
        u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
@@ -1161,24 +1160,6 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
-                                int headset_debounce, int button_debounce)
-{
-       u8 val;
-
-       val = ((detect & AIC3X_HEADSET_DETECT_MASK)
-               << AIC3X_HEADSET_DETECT_SHIFT) |
-             ((headset_debounce & AIC3X_HEADSET_DEBOUNCE_MASK)
-               << AIC3X_HEADSET_DEBOUNCE_SHIFT) |
-             ((button_debounce & AIC3X_BUTTON_DEBOUNCE_MASK)
-               << AIC3X_BUTTON_DEBOUNCE_SHIFT);
-
-       if (detect & AIC3X_HEADSET_DETECT_MASK)
-               val |= AIC3X_HEADSET_DETECT_ENABLED;
-
-       snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
-}
-
 #define AIC3X_RATES    SNDRV_PCM_RATE_8000_96000
 #define AIC3X_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
                         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
index 4587ddd0fbf8c2e30fa01600dcbd17aed9545e90..0dd41077ab79eab0daf001111a5248ac17ee98f2 100644 (file)
 #define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \
        (((samples)*5000) / (((burstrate)*5000) / ((burstrate) - (playrate))))
 
-static void dac33_calculate_times(struct snd_pcm_substream *substream);
-static int dac33_prepare_chip(struct snd_pcm_substream *substream);
+static void dac33_calculate_times(struct snd_pcm_substream *substream,
+                                 struct snd_soc_codec *codec);
+static int dac33_prepare_chip(struct snd_pcm_substream *substream,
+                             struct snd_soc_codec *codec);
 
 enum dac33_state {
        DAC33_IDLE = 0,
@@ -427,8 +429,8 @@ static int dac33_playback_event(struct snd_soc_dapm_widget *w,
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                if (likely(dac33->substream)) {
-                       dac33_calculate_times(dac33->substream);
-                       dac33_prepare_chip(dac33->substream);
+                       dac33_calculate_times(dac33->substream, w->codec);
+                       dac33_prepare_chip(dac33->substream, w->codec);
                }
                break;
        case SND_SOC_DAPM_POST_PMD:
@@ -799,8 +801,7 @@ static void dac33_oscwait(struct snd_soc_codec *codec)
 static int dac33_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        /* Stream started, save the substream pointer */
@@ -812,8 +813,7 @@ static int dac33_startup(struct snd_pcm_substream *substream,
 static void dac33_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        dac33->substream = NULL;
@@ -825,8 +825,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
                           struct snd_pcm_hw_params *params,
                           struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        /* Check parameters for validity */
@@ -868,10 +867,9 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
  * writes happens in different order, than dac33 might end up in unknown state.
  * Use the known, working sequence of register writes to initialize the dac33.
  */
-static int dac33_prepare_chip(struct snd_pcm_substream *substream)
+static int dac33_prepare_chip(struct snd_pcm_substream *substream,
+                             struct snd_soc_codec *codec)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
        u8 aictrl_a, aictrl_b, fifoctrl_a;
@@ -1067,10 +1065,9 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static void dac33_calculate_times(struct snd_pcm_substream *substream)
+static void dac33_calculate_times(struct snd_pcm_substream *substream,
+                                 struct snd_soc_codec *codec)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        unsigned int period_size = substream->runtime->period_size;
        unsigned int rate = substream->runtime->rate;
@@ -1128,8 +1125,7 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
 static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
                             struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
@@ -1161,8 +1157,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
                        struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        unsigned long long t0, t1, t_now;
        unsigned int time_delta, uthr;
index 170cf9a8fc796c40925c24d594ed36d20181721b..391fcfc7b63b16838257c43326362621f61a3368 100644 (file)
@@ -1685,8 +1685,7 @@ static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction,
 static int twl4030_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
        if (twl4030->master_substream) {
@@ -1715,8 +1714,7 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
 static void twl4030_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
        if (twl4030->master_substream == substream)
@@ -1740,8 +1738,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
                           struct snd_pcm_hw_params *params,
                           struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 mode, old_mode, format, old_format;
 
@@ -1974,8 +1971,7 @@ static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
 static int twl4030_voice_startup(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 mode;
 
@@ -2007,8 +2003,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
 static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
 
        /* Enable voice digital filters */
        twl4030_voice_enable(codec, substream->stream, 0);
@@ -2017,8 +2012,7 @@ static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
 static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 old_mode, mode;
 
index dc7509b9d53aa27f4580c923bfe81b2baa7fbff6..a36e9fcdf184f9d9a4774937063d6b622ea616bb 100644 (file)
 #define TWL6040_OUTHF_0dB 0x03
 #define TWL6040_OUTHF_M52dB 0x1D
 
-#define TWL6040_RAMP_NONE      0
-#define TWL6040_RAMP_UP                1
-#define TWL6040_RAMP_DOWN      2
-
-#define TWL6040_HSL_VOL_MASK   0x0F
-#define TWL6040_HSL_VOL_SHIFT  0
-#define TWL6040_HSR_VOL_MASK   0xF0
-#define TWL6040_HSR_VOL_SHIFT  4
-#define TWL6040_HF_VOL_MASK    0x1F
-#define TWL6040_HF_VOL_SHIFT   0
-
 /* Shadow register used by the driver */
 #define TWL6040_REG_SW_SHADOW  0x2F
 #define TWL6040_CACHEREGNUM    (TWL6040_REG_SW_SHADOW + 1)
 /* TWL6040_REG_SW_SHADOW (0x2F) fields */
 #define TWL6040_EAR_PATH_ENABLE        0x01
 
-struct twl6040_output {
-       u16 active;
-       u16 left_vol;
-       u16 right_vol;
-       u16 left_step;
-       u16 right_step;
-       unsigned int step_delay;
-       u16 ramp;
-       struct delayed_work work;
-       struct completion ramp_done;
-};
-
 struct twl6040_jack_data {
        struct snd_soc_jack *jack;
        struct delayed_work work;
@@ -100,8 +77,6 @@ struct twl6040_data {
        struct snd_soc_codec *codec;
        struct workqueue_struct *workqueue;
        struct mutex mutex;
-       struct twl6040_output headset;
-       struct twl6040_output handsfree;
 };
 
 /*
@@ -311,318 +286,6 @@ static void twl6040_restore_regs(struct snd_soc_codec *codec)
        }
 }
 
-/*
- * Ramp HS PGA volume to minimise pops at stream startup and shutdown.
- */
-static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
-                       unsigned int left_step, unsigned int right_step)
-{
-
-       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
-       struct twl6040_output *headset = &priv->headset;
-       int left_complete = 0, right_complete = 0;
-       u8 reg, val;
-
-       /* left channel */
-       left_step = (left_step > 0xF) ? 0xF : left_step;
-       reg = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);
-       val = (~reg & TWL6040_HSL_VOL_MASK);
-
-       if (headset->ramp == TWL6040_RAMP_UP) {
-               /* ramp step up */
-               if (val < headset->left_vol) {
-                       if (val + left_step > headset->left_vol)
-                               val = headset->left_vol;
-                       else
-                               val += left_step;
-
-                       reg &= ~TWL6040_HSL_VOL_MASK;
-                       twl6040_write(codec, TWL6040_REG_HSGAIN,
-                                       (reg | (~val & TWL6040_HSL_VOL_MASK)));
-               } else {
-                       left_complete = 1;
-               }
-       } else if (headset->ramp == TWL6040_RAMP_DOWN) {
-               /* ramp step down */
-               if (val > 0x0) {
-                       if ((int)val - (int)left_step < 0)
-                               val = 0;
-                       else
-                               val -= left_step;
-
-                       reg &= ~TWL6040_HSL_VOL_MASK;
-                       twl6040_write(codec, TWL6040_REG_HSGAIN, reg |
-                                               (~val & TWL6040_HSL_VOL_MASK));
-               } else {
-                       left_complete = 1;
-               }
-       }
-
-       /* right channel */
-       right_step = (right_step > 0xF) ? 0xF : right_step;
-       reg = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);
-       val = (~reg & TWL6040_HSR_VOL_MASK) >> TWL6040_HSR_VOL_SHIFT;
-
-       if (headset->ramp == TWL6040_RAMP_UP) {
-               /* ramp step up */
-               if (val < headset->right_vol) {
-                       if (val + right_step > headset->right_vol)
-                               val = headset->right_vol;
-                       else
-                               val += right_step;
-
-                       reg &= ~TWL6040_HSR_VOL_MASK;
-                       twl6040_write(codec, TWL6040_REG_HSGAIN,
-                               (reg | (~val << TWL6040_HSR_VOL_SHIFT)));
-               } else {
-                       right_complete = 1;
-               }
-       } else if (headset->ramp == TWL6040_RAMP_DOWN) {
-               /* ramp step down */
-               if (val > 0x0) {
-                       if ((int)val - (int)right_step < 0)
-                               val = 0;
-                       else
-                               val -= right_step;
-
-                       reg &= ~TWL6040_HSR_VOL_MASK;
-                       twl6040_write(codec, TWL6040_REG_HSGAIN,
-                                        reg | (~val << TWL6040_HSR_VOL_SHIFT));
-               } else {
-                       right_complete = 1;
-               }
-       }
-
-       return left_complete & right_complete;
-}
-
-/*
- * Ramp HF PGA volume to minimise pops at stream startup and shutdown.
- */
-static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
-                       unsigned int left_step, unsigned int right_step)
-{
-       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
-       struct twl6040_output *handsfree = &priv->handsfree;
-       int left_complete = 0, right_complete = 0;
-       u16 reg, val;
-
-       /* left channel */
-       left_step = (left_step > 0x1D) ? 0x1D : left_step;
-       reg = twl6040_read_reg_cache(codec, TWL6040_REG_HFLGAIN);
-       reg = 0x1D - reg;
-       val = (reg & TWL6040_HF_VOL_MASK);
-       if (handsfree->ramp == TWL6040_RAMP_UP) {
-               /* ramp step up */
-               if (val < handsfree->left_vol) {
-                       if (val + left_step > handsfree->left_vol)
-                               val = handsfree->left_vol;
-                       else
-                               val += left_step;
-
-                       reg &= ~TWL6040_HF_VOL_MASK;
-                       twl6040_write(codec, TWL6040_REG_HFLGAIN,
-                                               reg | (0x1D - val));
-               } else {
-                       left_complete = 1;
-               }
-       } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
-               /* ramp step down */
-               if (val > 0) {
-                       if ((int)val - (int)left_step < 0)
-                               val = 0;
-                       else
-                               val -= left_step;
-
-                       reg &= ~TWL6040_HF_VOL_MASK;
-                       twl6040_write(codec, TWL6040_REG_HFLGAIN,
-                                               reg | (0x1D - val));
-               } else {
-                       left_complete = 1;
-               }
-       }
-
-       /* right channel */
-       right_step = (right_step > 0x1D) ? 0x1D : right_step;
-       reg = twl6040_read_reg_cache(codec, TWL6040_REG_HFRGAIN);
-       reg = 0x1D - reg;
-       val = (reg & TWL6040_HF_VOL_MASK);
-       if (handsfree->ramp == TWL6040_RAMP_UP) {
-               /* ramp step up */
-               if (val < handsfree->right_vol) {
-                       if (val + right_step > handsfree->right_vol)
-                               val = handsfree->right_vol;
-                       else
-                               val += right_step;
-
-                       reg &= ~TWL6040_HF_VOL_MASK;
-                       twl6040_write(codec, TWL6040_REG_HFRGAIN,
-                                               reg | (0x1D - val));
-               } else {
-                       right_complete = 1;
-               }
-       } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
-               /* ramp step down */
-               if (val > 0) {
-                       if ((int)val - (int)right_step < 0)
-                               val = 0;
-                       else
-                               val -= right_step;
-
-                       reg &= ~TWL6040_HF_VOL_MASK;
-                       twl6040_write(codec, TWL6040_REG_HFRGAIN,
-                                               reg | (0x1D - val));
-               }
-       }
-
-       return left_complete & right_complete;
-}
-
-/*
- * This work ramps both output PGAs at stream start/stop time to
- * minimise pop associated with DAPM power switching.
- */
-static void twl6040_pga_hs_work(struct work_struct *work)
-{
-       struct twl6040_data *priv =
-               container_of(work, struct twl6040_data, headset.work.work);
-       struct snd_soc_codec *codec = priv->codec;
-       struct twl6040_output *headset = &priv->headset;
-       int i, headset_complete;
-
-       /* do we need to ramp at all ? */
-       if (headset->ramp == TWL6040_RAMP_NONE)
-               return;
-
-       /* HS PGA gain range: 0x0 - 0xf (0 - 15) */
-       for (i = 0; i < 16; i++) {
-               headset_complete = twl6040_hs_ramp_step(codec,
-                                               headset->left_step,
-                                               headset->right_step);
-
-               /* ramp finished ? */
-               if (headset_complete)
-                       break;
-
-               schedule_timeout_interruptible(
-                               msecs_to_jiffies(headset->step_delay));
-       }
-
-       if (headset->ramp == TWL6040_RAMP_DOWN) {
-               headset->active = 0;
-               complete(&headset->ramp_done);
-       } else {
-               headset->active = 1;
-       }
-       headset->ramp = TWL6040_RAMP_NONE;
-}
-
-static void twl6040_pga_hf_work(struct work_struct *work)
-{
-       struct twl6040_data *priv =
-               container_of(work, struct twl6040_data, handsfree.work.work);
-       struct snd_soc_codec *codec = priv->codec;
-       struct twl6040_output *handsfree = &priv->handsfree;
-       int i, handsfree_complete;
-
-       /* do we need to ramp at all ? */
-       if (handsfree->ramp == TWL6040_RAMP_NONE)
-               return;
-
-       /*
-        * HF PGA gain range: 0x00 - 0x1d (0 - 29) */
-       for (i = 0; i < 30; i++) {
-               handsfree_complete = twl6040_hf_ramp_step(codec,
-                                               handsfree->left_step,
-                                               handsfree->right_step);
-
-               /* ramp finished ? */
-               if (handsfree_complete)
-                       break;
-
-               schedule_timeout_interruptible(
-                               msecs_to_jiffies(handsfree->step_delay));
-       }
-
-
-       if (handsfree->ramp == TWL6040_RAMP_DOWN) {
-               handsfree->active = 0;
-               complete(&handsfree->ramp_done);
-       } else
-               handsfree->active = 1;
-       handsfree->ramp = TWL6040_RAMP_NONE;
-}
-
-static int out_drv_event(struct snd_soc_dapm_widget *w,
-                       struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = w->codec;
-       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
-       struct twl6040_output *out;
-       struct delayed_work *work;
-
-       switch (w->shift) {
-       case 2: /* Headset output driver */
-               out = &priv->headset;
-               work = &out->work;
-               /*
-                * Make sure, that we do not mess up variables for already
-                * executing work.
-                */
-               cancel_delayed_work_sync(work);
-
-               out->left_step = priv->hs_left_step;
-               out->right_step = priv->hs_right_step;
-               out->step_delay = 5;    /* 5 ms between volume ramp steps */
-               break;
-       case 4: /* Handsfree output driver */
-               out = &priv->handsfree;
-               work = &out->work;
-               /*
-                * Make sure, that we do not mess up variables for already
-                * executing work.
-                */
-               cancel_delayed_work_sync(work);
-
-               out->left_step = priv->hf_left_step;
-               out->right_step = priv->hf_right_step;
-               out->step_delay = 5;    /* 5 ms between volume ramp steps */
-               break;
-       default:
-               return -1;
-       }
-
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               if (out->active)
-                       break;
-
-               /* don't use volume ramp for power-up */
-               out->ramp = TWL6040_RAMP_UP;
-               out->left_step = out->left_vol;
-               out->right_step = out->right_vol;
-
-               queue_delayed_work(priv->workqueue, work, msecs_to_jiffies(1));
-               break;
-
-       case SND_SOC_DAPM_PRE_PMD:
-               if (!out->active)
-                       break;
-
-               /* use volume ramp for power-down */
-               out->ramp = TWL6040_RAMP_DOWN;
-               INIT_COMPLETION(out->ramp_done);
-
-               queue_delayed_work(priv->workqueue, work, msecs_to_jiffies(1));
-
-               wait_for_completion_timeout(&out->ramp_done,
-                                           msecs_to_jiffies(2000));
-               break;
-       }
-
-       return 0;
-}
-
 /* set headset dac and driver power mode */
 static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
 {
@@ -747,71 +410,6 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int twl6040_put_volsw(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
-       struct twl6040_output *out = NULL;
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       int ret;
-
-       /* For HS and HF we shadow the values and only actually write
-        * them out when active in order to ensure the amplifier comes on
-        * as quietly as possible. */
-       switch (mc->reg) {
-       case TWL6040_REG_HSGAIN:
-               out = &twl6040_priv->headset;
-               break;
-       case TWL6040_REG_HFLGAIN:
-               out = &twl6040_priv->handsfree;
-               break;
-       default:
-               dev_warn(codec->dev, "%s: Unexpected register: 0x%02x\n",
-                                       __func__, mc->reg);
-               return -EINVAL;
-       }
-
-       out->left_vol = ucontrol->value.integer.value[0];
-       out->right_vol = ucontrol->value.integer.value[1];
-       if (!out->active)
-               return 1;
-
-       ret = snd_soc_put_volsw(kcontrol, ucontrol);
-       if (ret < 0)
-               return ret;
-
-       return 1;
-}
-
-static int twl6040_get_volsw(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
-       struct twl6040_output *out = &twl6040_priv->headset;
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-
-       switch (mc->reg) {
-       case TWL6040_REG_HSGAIN:
-               out = &twl6040_priv->headset;
-               break;
-       case TWL6040_REG_HFLGAIN:
-               out = &twl6040_priv->handsfree;
-               break;
-       default:
-               dev_warn(codec->dev, "%s: Unexpected register: 0x%02x\n",
-                                       __func__, mc->reg);
-               return -EINVAL;
-       }
-
-       ucontrol->value.integer.value[0] = out->left_vol;
-       ucontrol->value.integer.value[1] = out->right_vol;
-       return 0;
-}
-
 static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
@@ -1076,12 +674,10 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
                TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv),
 
        /* Playback gains */
-       SOC_DOUBLE_EXT_TLV("Headset Playback Volume",
-               TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, twl6040_get_volsw,
-               twl6040_put_volsw, hs_tlv),
-       SOC_DOUBLE_R_EXT_TLV("Handsfree Playback Volume",
-               TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1,
-               twl6040_get_volsw, twl6040_put_volsw, hf_tlv),
+       SOC_DOUBLE_TLV("Headset Playback Volume",
+               TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, hs_tlv),
+       SOC_DOUBLE_R_TLV("Handsfree Playback Volume",
+               TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
        SOC_SINGLE_TLV("Earphone Playback Volume",
                TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
 
@@ -1180,22 +776,14 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
                        &auxr_switch_control),
 
        /* Analog playback drivers */
-       SND_SOC_DAPM_OUT_DRV_E("HF Left Driver",
-                       TWL6040_REG_HFLCTL, 4, 0, NULL, 0,
-                       out_drv_event,
-                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-       SND_SOC_DAPM_OUT_DRV_E("HF Right Driver",
-                       TWL6040_REG_HFRCTL, 4, 0, NULL, 0,
-                       out_drv_event,
-                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-       SND_SOC_DAPM_OUT_DRV_E("HS Left Driver",
-                       TWL6040_REG_HSLCTL, 2, 0, NULL, 0,
-                       out_drv_event,
-                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-       SND_SOC_DAPM_OUT_DRV_E("HS Right Driver",
-                       TWL6040_REG_HSRCTL, 2, 0, NULL, 0,
-                       out_drv_event,
-                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_OUT_DRV("HF Left Driver",
+                       TWL6040_REG_HFLCTL, 4, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("HF Right Driver",
+                       TWL6040_REG_HFRCTL, 4, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("HS Left Driver",
+                       TWL6040_REG_HSLCTL, 2, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("HS Right Driver",
+                       TWL6040_REG_HSRCTL, 2, 0, NULL, 0),
        SND_SOC_DAPM_OUT_DRV_E("Earphone Driver",
                        TWL6040_REG_EARCTL, 0, 0, NULL, 0,
                        twl6040_ep_drv_event,
@@ -1339,8 +927,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
 static int twl6040_startup(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
        snd_pcm_hw_constraint_list(substream->runtime, 0,
@@ -1354,8 +941,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
                        struct snd_pcm_hw_params *params,
                        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
        int rate;
 
@@ -1391,8 +977,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
 static int twl6040_prepare(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct twl6040 *twl6040 = codec->control_data;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
        int ret;
@@ -1570,14 +1155,9 @@ static int twl6040_probe(struct snd_soc_codec *codec)
        }
 
        INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work);
-       INIT_DELAYED_WORK(&priv->headset.work, twl6040_pga_hs_work);
-       INIT_DELAYED_WORK(&priv->handsfree.work, twl6040_pga_hf_work);
 
        mutex_init(&priv->mutex);
 
-       init_completion(&priv->headset.ramp_done);
-       init_completion(&priv->handsfree.ramp_done);
-
        ret = request_threaded_irq(priv->plug_irq, NULL, twl6040_audio_handler,
                                   0, "twl6040_irq_plug", codec);
        if (ret) {
index 797b0dde2c68620910a5870f7e341731aaf3380b..6c3d43b8ee858538346565ec5915f4b2acf004d9 100644 (file)
@@ -159,8 +159,7 @@ static int uda134x_mute(struct snd_soc_dai *dai, int mute)
 static int uda134x_startup(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec =rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
        struct snd_pcm_runtime *master_runtime;
 
@@ -191,8 +190,7 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
 static void uda134x_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
 
        if (uda134x->master_substream == substream)
index 4f1b23d7e4043eb28789133bd707298aa613e090..2502214b84abe918514f9462039ef1f941bb3f59 100644 (file)
@@ -502,8 +502,7 @@ static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
 static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
        int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
 
@@ -528,8 +527,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
 
        /* set WSPLL power and divider if running from this clock */
index 3d868dc400921cc22d21ef1ede114fb643dcd6e1..7b24d6d192e17d8cd5b61ade0d59988dde07c924 100644 (file)
@@ -293,8 +293,7 @@ static const struct snd_kcontrol_new wl1273_controls[] = {
 static int wl1273_startup(struct snd_pcm_substream *substream,
                          struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
 
        switch (wl1273->mode) {
@@ -329,8 +328,7 @@ static int wl1273_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(rtd->codec);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(dai->codec);
        struct wl1273_core *core = wl1273->core;
        unsigned int rate, width, r;
 
index aefb4f89be0eb23b108e01581e86a52299961904..e0b51e9f8b121c8a146e9582665cc413a94b7ae1 100644 (file)
@@ -79,22 +79,65 @@ static const struct snd_soc_dapm_route wm1250_ev1_dapm_routes[] = {
        { "WM1250 Output", NULL, "DAC" },
 };
 
+static int wm1250_ev1_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct wm1250_priv *wm1250 = snd_soc_codec_get_drvdata(dai->codec);
+
+       switch (params_rate(params)) {
+       case 8000:
+               gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+                              1);
+               gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+                              1);
+               break;
+       case 16000:
+               gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+                              0);
+               gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+                              1);
+               break;
+       case 32000:
+               gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+                              1);
+               gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+                              0);
+               break;
+       case 64000:
+               gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+                              0);
+               gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+                              0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops wm1250_ev1_ops = {
+       .hw_params = wm1250_ev1_hw_params,
+};
+
 static struct snd_soc_dai_driver wm1250_ev1_dai = {
        .name = "wm1250-ev1",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
-               .channels_max = 1,
+               .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
-               .channels_max = 1,
+               .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
+       .ops = &wm1250_ev1_ops,
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
@@ -215,23 +258,7 @@ static struct i2c_driver wm1250_ev1_i2c_driver = {
        .id_table = wm1250_ev1_i2c_id,
 };
 
-static int __init wm1250_ev1_modinit(void)
-{
-       int ret = 0;
-
-       ret = i2c_add_driver(&wm1250_ev1_i2c_driver);
-       if (ret != 0)
-               pr_err("Failed to register WM1250-EV1 I2C driver: %d\n", ret);
-
-       return ret;
-}
-module_init(wm1250_ev1_modinit);
-
-static void __exit wm1250_ev1_exit(void)
-{
-       i2c_del_driver(&wm1250_ev1_i2c_driver);
-}
-module_exit(wm1250_ev1_exit);
+module_i2c_driver(wm1250_ev1_i2c_driver);
 
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_DESCRIPTION("WM1250-EV1 audio I/O module driver");
index 9a18fae68204f790a19c75e7fc527e1b25d3a1f5..e167207a19cc357250fe65c5376b2248e6866d1e 100644 (file)
@@ -32,7 +32,18 @@ bool wm5100_volatile_register(struct device *dev, unsigned int reg)
        case WM5100_MIC_DETECT_3:
                return 1;
        default:
-               return 0;
+               if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
+                   (reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
+                   (reg >= WM5100_DSP1_DM_0 && reg <= WM5100_DSP1_DM_511) ||
+                   (reg >= WM5100_DSP2_PM_0 && reg <= WM5100_DSP2_PM_1535) ||
+                   (reg >= WM5100_DSP2_ZM_0 && reg <= WM5100_DSP2_ZM_2047) ||
+                   (reg >= WM5100_DSP2_DM_0 && reg <= WM5100_DSP2_DM_511) ||
+                   (reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
+                   (reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
+                   (reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
+                       return 1;
+               else
+                       return 0;
        }
 }
 
@@ -697,9 +708,110 @@ bool wm5100_readable_register(struct device *dev, unsigned int reg)
        case WM5100_HPLPF3_2:
        case WM5100_HPLPF4_1:
        case WM5100_HPLPF4_2:
+       case WM5100_DSP1_CONTROL_1:
+       case WM5100_DSP1_CONTROL_2:
+       case WM5100_DSP1_CONTROL_3:
+       case WM5100_DSP1_CONTROL_4:
+       case WM5100_DSP1_CONTROL_5:
+       case WM5100_DSP1_CONTROL_6:
+       case WM5100_DSP1_CONTROL_7:
+       case WM5100_DSP1_CONTROL_8:
+       case WM5100_DSP1_CONTROL_9:
+       case WM5100_DSP1_CONTROL_10:
+       case WM5100_DSP1_CONTROL_11:
+       case WM5100_DSP1_CONTROL_12:
+       case WM5100_DSP1_CONTROL_13:
+       case WM5100_DSP1_CONTROL_14:
+       case WM5100_DSP1_CONTROL_15:
+       case WM5100_DSP1_CONTROL_16:
+       case WM5100_DSP1_CONTROL_17:
+       case WM5100_DSP1_CONTROL_18:
+       case WM5100_DSP1_CONTROL_19:
+       case WM5100_DSP1_CONTROL_20:
+       case WM5100_DSP1_CONTROL_21:
+       case WM5100_DSP1_CONTROL_22:
+       case WM5100_DSP1_CONTROL_23:
+       case WM5100_DSP1_CONTROL_24:
+       case WM5100_DSP1_CONTROL_25:
+       case WM5100_DSP1_CONTROL_26:
+       case WM5100_DSP1_CONTROL_27:
+       case WM5100_DSP1_CONTROL_28:
+       case WM5100_DSP1_CONTROL_29:
+       case WM5100_DSP1_CONTROL_30:
+       case WM5100_DSP2_CONTROL_1:
+       case WM5100_DSP2_CONTROL_2:
+       case WM5100_DSP2_CONTROL_3:
+       case WM5100_DSP2_CONTROL_4:
+       case WM5100_DSP2_CONTROL_5:
+       case WM5100_DSP2_CONTROL_6:
+       case WM5100_DSP2_CONTROL_7:
+       case WM5100_DSP2_CONTROL_8:
+       case WM5100_DSP2_CONTROL_9:
+       case WM5100_DSP2_CONTROL_10:
+       case WM5100_DSP2_CONTROL_11:
+       case WM5100_DSP2_CONTROL_12:
+       case WM5100_DSP2_CONTROL_13:
+       case WM5100_DSP2_CONTROL_14:
+       case WM5100_DSP2_CONTROL_15:
+       case WM5100_DSP2_CONTROL_16:
+       case WM5100_DSP2_CONTROL_17:
+       case WM5100_DSP2_CONTROL_18:
+       case WM5100_DSP2_CONTROL_19:
+       case WM5100_DSP2_CONTROL_20:
+       case WM5100_DSP2_CONTROL_21:
+       case WM5100_DSP2_CONTROL_22:
+       case WM5100_DSP2_CONTROL_23:
+       case WM5100_DSP2_CONTROL_24:
+       case WM5100_DSP2_CONTROL_25:
+       case WM5100_DSP2_CONTROL_26:
+       case WM5100_DSP2_CONTROL_27:
+       case WM5100_DSP2_CONTROL_28:
+       case WM5100_DSP2_CONTROL_29:
+       case WM5100_DSP2_CONTROL_30:
+       case WM5100_DSP3_CONTROL_1:
+       case WM5100_DSP3_CONTROL_2:
+       case WM5100_DSP3_CONTROL_3:
+       case WM5100_DSP3_CONTROL_4:
+       case WM5100_DSP3_CONTROL_5:
+       case WM5100_DSP3_CONTROL_6:
+       case WM5100_DSP3_CONTROL_7:
+       case WM5100_DSP3_CONTROL_8:
+       case WM5100_DSP3_CONTROL_9:
+       case WM5100_DSP3_CONTROL_10:
+       case WM5100_DSP3_CONTROL_11:
+       case WM5100_DSP3_CONTROL_12:
+       case WM5100_DSP3_CONTROL_13:
+       case WM5100_DSP3_CONTROL_14:
+       case WM5100_DSP3_CONTROL_15:
+       case WM5100_DSP3_CONTROL_16:
+       case WM5100_DSP3_CONTROL_17:
+       case WM5100_DSP3_CONTROL_18:
+       case WM5100_DSP3_CONTROL_19:
+       case WM5100_DSP3_CONTROL_20:
+       case WM5100_DSP3_CONTROL_21:
+       case WM5100_DSP3_CONTROL_22:
+       case WM5100_DSP3_CONTROL_23:
+       case WM5100_DSP3_CONTROL_24:
+       case WM5100_DSP3_CONTROL_25:
+       case WM5100_DSP3_CONTROL_26:
+       case WM5100_DSP3_CONTROL_27:
+       case WM5100_DSP3_CONTROL_28:
+       case WM5100_DSP3_CONTROL_29:
+       case WM5100_DSP3_CONTROL_30:
                return 1;
        default:
-               return 0;
+               if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
+                   (reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
+                   (reg >= WM5100_DSP1_DM_0 && reg <= WM5100_DSP1_DM_511) ||
+                   (reg >= WM5100_DSP2_PM_0 && reg <= WM5100_DSP2_PM_1535) ||
+                   (reg >= WM5100_DSP2_ZM_0 && reg <= WM5100_DSP2_ZM_2047) ||
+                   (reg >= WM5100_DSP2_DM_0 && reg <= WM5100_DSP2_DM_511) ||
+                   (reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
+                   (reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
+                   (reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
+                       return 1;
+               else
+                       return 0;
        }
 }
 
@@ -1361,4 +1473,13 @@ struct reg_default wm5100_reg_defaults[WM5100_REGISTER_COUNT] = {
        { 0x0EC9, 0x0000 },  /* R3785  - HPLPF3_2 */
        { 0x0ECC, 0x0000 },  /* R3788  - HPLPF4_1 */
        { 0x0ECD, 0x0000 },  /* R3789  - HPLPF4_2 */
+       { 0x0F02, 0x0000 },  /* R3842  - DSP1 Control 2 */
+       { 0x0F03, 0x0000 },  /* R3843  - DSP1 Control 3 */
+       { 0x0F04, 0x0000 },  /* R3844  - DSP1 Control 4 */
+       { 0x1002, 0x0000 },  /* R4098  - DSP2 Control 2 */
+       { 0x1003, 0x0000 },  /* R4099  - DSP2 Control 3 */
+       { 0x1004, 0x0000 },  /* R4100  - DSP2 Control 4 */
+       { 0x1102, 0x0000 },  /* R4354  - DSP3 Control 2 */
+       { 0x1103, 0x0000 },  /* R4355  - DSP3 Control 3 */
+       { 0x1104, 0x0000 },  /* R4356  - DSP3 Control 4 */
 };
index b9c185ce64e46e04b0500416d70ba8bc0206701f..cb6d5372103a56290fafc84f3c917cdb8362cb0f 100644 (file)
@@ -1265,29 +1265,12 @@ static const __devinitdata struct reg_default wm5100_reva_patches[] = {
        { WM5100_AUDIO_IF_3_19, 1 },
 };
 
-static int wm5100_dai_to_base(struct snd_soc_dai *dai)
-{
-       switch (dai->id) {
-       case 0:
-               return WM5100_AUDIO_IF_1_1 - 1;
-       case 1:
-               return WM5100_AUDIO_IF_2_1 - 1;
-       case 2:
-               return WM5100_AUDIO_IF_3_1 - 1;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-}
-
 static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct snd_soc_codec *codec = dai->codec;
        int lrclk, bclk, mask, base;
 
-       base = wm5100_dai_to_base(dai);
-       if (base < 0)
-               return base;
+       base = dai->driver->base;
 
        lrclk = 0;
        bclk = 0;
@@ -1414,9 +1397,7 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream,
        int i, base, bclk, aif_rate, lrclk, wl, fl, sr;
        int *bclk_rates;
 
-       base = wm5100_dai_to_base(dai);
-       if (base < 0)
-               return base;
+       base = dai->driver->base;
 
        /* Data sizes if not using TDM */
        wl = snd_pcm_format_width(params_format(params));
@@ -1897,6 +1878,7 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 static struct snd_soc_dai_driver wm5100_dai[] = {
        {
                .name = "wm5100-aif1",
+               .base = WM5100_AUDIO_IF_1_1 - 1,
                .playback = {
                        .stream_name = "AIF1 Playback",
                        .channels_min = 2,
@@ -1916,6 +1898,7 @@ static struct snd_soc_dai_driver wm5100_dai[] = {
        {
                .name = "wm5100-aif2",
                .id = 1,
+               .base = WM5100_AUDIO_IF_2_1 - 1,
                .playback = {
                        .stream_name = "AIF2 Playback",
                        .channels_min = 2,
@@ -1935,6 +1918,7 @@ static struct snd_soc_dai_driver wm5100_dai[] = {
        {
                .name = "wm5100-aif3",
                .id = 2,
+               .base = WM5100_AUDIO_IF_3_1 - 1,
                .playback = {
                        .stream_name = "AIF3 Playback",
                        .channels_min = 2,
@@ -2454,7 +2438,7 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
 
        wm5100->dev = &i2c->dev;
 
-       wm5100->regmap = regmap_init_i2c(i2c, &wm5100_regmap);
+       wm5100->regmap = devm_regmap_init_i2c(i2c, &wm5100_regmap);
        if (IS_ERR(wm5100->regmap)) {
                ret = PTR_ERR(wm5100->regmap);
                dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -2479,7 +2463,7 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
        if (ret != 0) {
                dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
                        ret);
-               goto err_regmap;
+               goto err;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
@@ -2487,7 +2471,7 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
        if (ret != 0) {
                dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
                        ret);
-               goto err_regmap;
+               goto err;
        }
 
        if (wm5100->pdata.ldo_ena) {
@@ -2660,8 +2644,6 @@ err_ldo:
 err_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
                               wm5100->core_supplies);
-err_regmap:
-       regmap_exit(wm5100->regmap);
 err:
        return ret;
 }
@@ -2682,7 +2664,6 @@ static __devexit int wm5100_i2c_remove(struct i2c_client *i2c)
                gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
                gpio_free(wm5100->pdata.ldo_ena);
        }
-       regmap_exit(wm5100->regmap);
 
        return 0;
 }
@@ -2749,17 +2730,7 @@ static struct i2c_driver wm5100_i2c_driver = {
        .id_table = wm5100_i2c_id,
 };
 
-static int __init wm5100_modinit(void)
-{
-       return i2c_add_driver(&wm5100_i2c_driver);
-}
-module_init(wm5100_modinit);
-
-static void __exit wm5100_exit(void)
-{
-       i2c_del_driver(&wm5100_i2c_driver);
-}
-module_exit(wm5100_exit);
+module_i2c_driver(wm5100_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM5100 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index 25cb6016f9d7f37ce7eb855c66930ba27f06bd90..935a9b7fb27457e5e91987442df2b6d89ddc423c 100644 (file)
@@ -709,6 +709,96 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
 #define WM5100_HPLPF3_2                         0xEC9
 #define WM5100_HPLPF4_1                         0xECC
 #define WM5100_HPLPF4_2                         0xECD
+#define WM5100_DSP1_CONTROL_1                   0xF00
+#define WM5100_DSP1_CONTROL_2                   0xF02
+#define WM5100_DSP1_CONTROL_3                   0xF03
+#define WM5100_DSP1_CONTROL_4                   0xF04
+#define WM5100_DSP1_CONTROL_5                   0xF06
+#define WM5100_DSP1_CONTROL_6                   0xF07
+#define WM5100_DSP1_CONTROL_7                   0xF08
+#define WM5100_DSP1_CONTROL_8                   0xF09
+#define WM5100_DSP1_CONTROL_9                   0xF0A
+#define WM5100_DSP1_CONTROL_10                  0xF0B
+#define WM5100_DSP1_CONTROL_11                  0xF0C
+#define WM5100_DSP1_CONTROL_12                  0xF0D
+#define WM5100_DSP1_CONTROL_13                  0xF0F
+#define WM5100_DSP1_CONTROL_14                  0xF10
+#define WM5100_DSP1_CONTROL_15                  0xF11
+#define WM5100_DSP1_CONTROL_16                  0xF12
+#define WM5100_DSP1_CONTROL_17                  0xF13
+#define WM5100_DSP1_CONTROL_18                  0xF14
+#define WM5100_DSP1_CONTROL_19                  0xF16
+#define WM5100_DSP1_CONTROL_20                  0xF17
+#define WM5100_DSP1_CONTROL_21                  0xF18
+#define WM5100_DSP1_CONTROL_22                  0xF1A
+#define WM5100_DSP1_CONTROL_23                  0xF1B
+#define WM5100_DSP1_CONTROL_24                  0xF1C
+#define WM5100_DSP1_CONTROL_25                  0xF1E
+#define WM5100_DSP1_CONTROL_26                  0xF20
+#define WM5100_DSP1_CONTROL_27                  0xF21
+#define WM5100_DSP1_CONTROL_28                  0xF22
+#define WM5100_DSP1_CONTROL_29                  0xF23
+#define WM5100_DSP1_CONTROL_30                  0xF24
+#define WM5100_DSP2_CONTROL_1                   0x1000
+#define WM5100_DSP2_CONTROL_2                   0x1002
+#define WM5100_DSP2_CONTROL_3                   0x1003
+#define WM5100_DSP2_CONTROL_4                   0x1004
+#define WM5100_DSP2_CONTROL_5                   0x1006
+#define WM5100_DSP2_CONTROL_6                   0x1007
+#define WM5100_DSP2_CONTROL_7                   0x1008
+#define WM5100_DSP2_CONTROL_8                   0x1009
+#define WM5100_DSP2_CONTROL_9                   0x100A
+#define WM5100_DSP2_CONTROL_10                  0x100B
+#define WM5100_DSP2_CONTROL_11                  0x100C
+#define WM5100_DSP2_CONTROL_12                  0x100D
+#define WM5100_DSP2_CONTROL_13                  0x100F
+#define WM5100_DSP2_CONTROL_14                  0x1010
+#define WM5100_DSP2_CONTROL_15                  0x1011
+#define WM5100_DSP2_CONTROL_16                  0x1012
+#define WM5100_DSP2_CONTROL_17                  0x1013
+#define WM5100_DSP2_CONTROL_18                  0x1014
+#define WM5100_DSP2_CONTROL_19                  0x1016
+#define WM5100_DSP2_CONTROL_20                  0x1017
+#define WM5100_DSP2_CONTROL_21                  0x1018
+#define WM5100_DSP2_CONTROL_22                  0x101A
+#define WM5100_DSP2_CONTROL_23                  0x101B
+#define WM5100_DSP2_CONTROL_24                  0x101C
+#define WM5100_DSP2_CONTROL_25                  0x101E
+#define WM5100_DSP2_CONTROL_26                  0x1020
+#define WM5100_DSP2_CONTROL_27                  0x1021
+#define WM5100_DSP2_CONTROL_28                  0x1022
+#define WM5100_DSP2_CONTROL_29                  0x1023
+#define WM5100_DSP2_CONTROL_30                  0x1024
+#define WM5100_DSP3_CONTROL_1                   0x1100
+#define WM5100_DSP3_CONTROL_2                   0x1102
+#define WM5100_DSP3_CONTROL_3                   0x1103
+#define WM5100_DSP3_CONTROL_4                   0x1104
+#define WM5100_DSP3_CONTROL_5                   0x1106
+#define WM5100_DSP3_CONTROL_6                   0x1107
+#define WM5100_DSP3_CONTROL_7                   0x1108
+#define WM5100_DSP3_CONTROL_8                   0x1109
+#define WM5100_DSP3_CONTROL_9                   0x110A
+#define WM5100_DSP3_CONTROL_10                  0x110B
+#define WM5100_DSP3_CONTROL_11                  0x110C
+#define WM5100_DSP3_CONTROL_12                  0x110D
+#define WM5100_DSP3_CONTROL_13                  0x110F
+#define WM5100_DSP3_CONTROL_14                  0x1110
+#define WM5100_DSP3_CONTROL_15                  0x1111
+#define WM5100_DSP3_CONTROL_16                  0x1112
+#define WM5100_DSP3_CONTROL_17                  0x1113
+#define WM5100_DSP3_CONTROL_18                  0x1114
+#define WM5100_DSP3_CONTROL_19                  0x1116
+#define WM5100_DSP3_CONTROL_20                  0x1117
+#define WM5100_DSP3_CONTROL_21                  0x1118
+#define WM5100_DSP3_CONTROL_22                  0x111A
+#define WM5100_DSP3_CONTROL_23                  0x111B
+#define WM5100_DSP3_CONTROL_24                  0x111C
+#define WM5100_DSP3_CONTROL_25                  0x111E
+#define WM5100_DSP3_CONTROL_26                  0x1120
+#define WM5100_DSP3_CONTROL_27                  0x1121
+#define WM5100_DSP3_CONTROL_28                  0x1122
+#define WM5100_DSP3_CONTROL_29                  0x1123
+#define WM5100_DSP3_CONTROL_30                  0x1124
 #define WM5100_DSP1_DM_0                        0x4000
 #define WM5100_DSP1_DM_1                        0x4001
 #define WM5100_DSP1_DM_2                        0x4002
@@ -4560,6 +4650,75 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
 #define WM5100_LHPF4_COEFF_SHIFT                     0  /* LHPF4_COEFF - [15:0] */
 #define WM5100_LHPF4_COEFF_WIDTH                    16  /* LHPF4_COEFF - [15:0] */
 
+/*
+ * R4132 (0x1024) - DSP2 Control 30
+ */
+#define WM5100_DSP2_RATE_MASK                   0xC000  /* DSP2_RATE - [15:14] */
+#define WM5100_DSP2_RATE_SHIFT                      14  /* DSP2_RATE - [15:14] */
+#define WM5100_DSP2_RATE_WIDTH                       2  /* DSP2_RATE - [15:14] */
+#define WM5100_DSP2_DBG_CLK_ENA                 0x0008  /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_DBG_CLK_ENA_MASK            0x0008  /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_DBG_CLK_ENA_SHIFT                3  /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_DBG_CLK_ENA_WIDTH                1  /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_SYS_ENA                     0x0004  /* DSP2_SYS_ENA */
+#define WM5100_DSP2_SYS_ENA_MASK                0x0004  /* DSP2_SYS_ENA */
+#define WM5100_DSP2_SYS_ENA_SHIFT                    2  /* DSP2_SYS_ENA */
+#define WM5100_DSP2_SYS_ENA_WIDTH                    1  /* DSP2_SYS_ENA */
+#define WM5100_DSP2_CORE_ENA                    0x0002  /* DSP2_CORE_ENA */
+#define WM5100_DSP2_CORE_ENA_MASK               0x0002  /* DSP2_CORE_ENA */
+#define WM5100_DSP2_CORE_ENA_SHIFT                   1  /* DSP2_CORE_ENA */
+#define WM5100_DSP2_CORE_ENA_WIDTH                   1  /* DSP2_CORE_ENA */
+#define WM5100_DSP2_START                       0x0001  /* DSP2_START */
+#define WM5100_DSP2_START_MASK                  0x0001  /* DSP2_START */
+#define WM5100_DSP2_START_SHIFT                      0  /* DSP2_START */
+#define WM5100_DSP2_START_WIDTH                      1  /* DSP2_START */
+
+/*
+ * R3876 (0xF24) - DSP1 Control 30
+ */
+#define WM5100_DSP1_RATE_MASK                   0xC000  /* DSP1_RATE - [15:14] */
+#define WM5100_DSP1_RATE_SHIFT                      14  /* DSP1_RATE - [15:14] */
+#define WM5100_DSP1_RATE_WIDTH                       2  /* DSP1_RATE - [15:14] */
+#define WM5100_DSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
+#define WM5100_DSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
+#define WM5100_DSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
+#define WM5100_DSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
+#define WM5100_DSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
+#define WM5100_DSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
+#define WM5100_DSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
+#define WM5100_DSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
+#define WM5100_DSP1_START                       0x0001  /* DSP1_START */
+#define WM5100_DSP1_START_MASK                  0x0001  /* DSP1_START */
+#define WM5100_DSP1_START_SHIFT                      0  /* DSP1_START */
+#define WM5100_DSP1_START_WIDTH                      1  /* DSP1_START */
+
+/*
+ * R4388 (0x1124) - DSP3 Control 30
+ */
+#define WM5100_DSP3_RATE_MASK                   0xC000  /* DSP3_RATE - [15:14] */
+#define WM5100_DSP3_RATE_SHIFT                      14  /* DSP3_RATE - [15:14] */
+#define WM5100_DSP3_RATE_WIDTH                       2  /* DSP3_RATE - [15:14] */
+#define WM5100_DSP3_DBG_CLK_ENA                 0x0008  /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_DBG_CLK_ENA_MASK            0x0008  /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_DBG_CLK_ENA_SHIFT                3  /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_DBG_CLK_ENA_WIDTH                1  /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_SYS_ENA                     0x0004  /* DSP3_SYS_ENA */
+#define WM5100_DSP3_SYS_ENA_MASK                0x0004  /* DSP3_SYS_ENA */
+#define WM5100_DSP3_SYS_ENA_SHIFT                    2  /* DSP3_SYS_ENA */
+#define WM5100_DSP3_SYS_ENA_WIDTH                    1  /* DSP3_SYS_ENA */
+#define WM5100_DSP3_CORE_ENA                    0x0002  /* DSP3_CORE_ENA */
+#define WM5100_DSP3_CORE_ENA_MASK               0x0002  /* DSP3_CORE_ENA */
+#define WM5100_DSP3_CORE_ENA_SHIFT                   1  /* DSP3_CORE_ENA */
+#define WM5100_DSP3_CORE_ENA_WIDTH                   1  /* DSP3_CORE_ENA */
+#define WM5100_DSP3_START                       0x0001  /* DSP3_START */
+#define WM5100_DSP3_START_MASK                  0x0001  /* DSP3_START */
+#define WM5100_DSP3_START_SHIFT                      0  /* DSP3_START */
+#define WM5100_DSP3_START_WIDTH                      1  /* DSP3_START */
+
 /*
  * R16384 (0x4000) - DSP1 DM 0
  */
index aa12c6b6beeb40c0cb80580772739259b1e9f27a..555ee146ae0d00bc4c36a8a006580c1d01fc75d3 100644 (file)
@@ -71,13 +71,6 @@ struct wm8350_data {
        int fll_freq_in;
 };
 
-static unsigned int wm8350_codec_cache_read(struct snd_soc_codec *codec,
-                                           unsigned int reg)
-{
-       struct wm8350 *wm8350 = codec->control_data;
-       return wm8350->reg_cache[reg];
-}
-
 static unsigned int wm8350_codec_read(struct snd_soc_codec *codec,
                                      unsigned int reg)
 {
@@ -99,7 +92,7 @@ static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec)
 {
        struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
        struct wm8350_output *out1 = &wm8350_data->out1;
-       struct wm8350 *wm8350 = codec->control_data;
+       struct wm8350 *wm8350 = wm8350_data->wm8350;
        int left_complete = 0, right_complete = 0;
        u16 reg, val;
 
@@ -165,7 +158,7 @@ static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec)
 {
        struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
        struct wm8350_output *out2 = &wm8350_data->out2;
-       struct wm8350 *wm8350 = codec->control_data;
+       struct wm8350 *wm8350 = wm8350_data->wm8350;
        int left_complete = 0, right_complete = 0;
        u16 reg, val;
 
@@ -360,8 +353,8 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
                return ret;
 
        /* now hit the volume update bits (always bit 8) */
-       val = wm8350_codec_read(codec, reg);
-       wm8350_codec_write(codec, reg, val | WM8350_OUT1_VU);
+       val = snd_soc_read(codec, reg);
+       snd_soc_write(codec, reg, val | WM8350_OUT1_VU);
        return 1;
 }
 
@@ -781,7 +774,8 @@ static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                                 int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
-       struct wm8350 *wm8350 = codec->control_data;
+       struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
+       struct wm8350 *wm8350 = wm8350_data->wm8350;
        u16 fll_4;
 
        switch (clk_id) {
@@ -795,9 +789,9 @@ static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        case WM8350_MCLK_SEL_PLL_32K:
                wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_1,
                                WM8350_MCLK_SEL);
-               fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) &
+               fll_4 = snd_soc_read(codec, WM8350_FLL_CONTROL_4) &
                    ~WM8350_FLL_CLK_SRC_MASK;
-               wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, fll_4 | clk_id);
+               snd_soc_write(codec, WM8350_FLL_CONTROL_4, fll_4 | clk_id);
                break;
        }
 
@@ -819,39 +813,39 @@ static int wm8350_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div)
 
        switch (div_id) {
        case WM8350_ADC_CLKDIV:
-               val = wm8350_codec_read(codec, WM8350_ADC_DIVIDER) &
+               val = snd_soc_read(codec, WM8350_ADC_DIVIDER) &
                    ~WM8350_ADC_CLKDIV_MASK;
-               wm8350_codec_write(codec, WM8350_ADC_DIVIDER, val | div);
+               snd_soc_write(codec, WM8350_ADC_DIVIDER, val | div);
                break;
        case WM8350_DAC_CLKDIV:
-               val = wm8350_codec_read(codec, WM8350_DAC_CLOCK_CONTROL) &
+               val = snd_soc_read(codec, WM8350_DAC_CLOCK_CONTROL) &
                    ~WM8350_DAC_CLKDIV_MASK;
-               wm8350_codec_write(codec, WM8350_DAC_CLOCK_CONTROL, val | div);
+               snd_soc_write(codec, WM8350_DAC_CLOCK_CONTROL, val | div);
                break;
        case WM8350_BCLK_CLKDIV:
-               val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) &
+               val = snd_soc_read(codec, WM8350_CLOCK_CONTROL_1) &
                    ~WM8350_BCLK_DIV_MASK;
-               wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+               snd_soc_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
                break;
        case WM8350_OPCLK_CLKDIV:
-               val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) &
+               val = snd_soc_read(codec, WM8350_CLOCK_CONTROL_1) &
                    ~WM8350_OPCLK_DIV_MASK;
-               wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+               snd_soc_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
                break;
        case WM8350_SYS_CLKDIV:
-               val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) &
+               val = snd_soc_read(codec, WM8350_CLOCK_CONTROL_1) &
                    ~WM8350_MCLK_DIV_MASK;
-               wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+               snd_soc_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
                break;
        case WM8350_DACLR_CLKDIV:
-               val = wm8350_codec_read(codec, WM8350_DAC_LR_RATE) &
+               val = snd_soc_read(codec, WM8350_DAC_LR_RATE) &
                    ~WM8350_DACLRC_RATE_MASK;
-               wm8350_codec_write(codec, WM8350_DAC_LR_RATE, val | div);
+               snd_soc_write(codec, WM8350_DAC_LR_RATE, val | div);
                break;
        case WM8350_ADCLR_CLKDIV:
-               val = wm8350_codec_read(codec, WM8350_ADC_LR_RATE) &
+               val = snd_soc_read(codec, WM8350_ADC_LR_RATE) &
                    ~WM8350_ADCLRC_RATE_MASK;
-               wm8350_codec_write(codec, WM8350_ADC_LR_RATE, val | div);
+               snd_soc_write(codec, WM8350_ADC_LR_RATE, val | div);
                break;
        default:
                return -EINVAL;
@@ -863,13 +857,13 @@ static int wm8350_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div)
 static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
-       u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) &
+       u16 iface = snd_soc_read(codec, WM8350_AI_FORMATING) &
            ~(WM8350_AIF_BCLK_INV | WM8350_AIF_LRCLK_INV | WM8350_AIF_FMT_MASK);
-       u16 master = wm8350_codec_read(codec, WM8350_AI_DAC_CONTROL) &
+       u16 master = snd_soc_read(codec, WM8350_AI_DAC_CONTROL) &
            ~WM8350_BCLK_MSTR;
-       u16 dac_lrc = wm8350_codec_read(codec, WM8350_DAC_LR_RATE) &
+       u16 dac_lrc = snd_soc_read(codec, WM8350_DAC_LR_RATE) &
            ~WM8350_DACLRC_ENA;
-       u16 adc_lrc = wm8350_codec_read(codec, WM8350_ADC_LR_RATE) &
+       u16 adc_lrc = snd_soc_read(codec, WM8350_ADC_LR_RATE) &
            ~WM8350_ADCLRC_ENA;
 
        /* set master/slave audio interface */
@@ -922,42 +916,10 @@ static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       wm8350_codec_write(codec, WM8350_AI_FORMATING, iface);
-       wm8350_codec_write(codec, WM8350_AI_DAC_CONTROL, master);
-       wm8350_codec_write(codec, WM8350_DAC_LR_RATE, dac_lrc);
-       wm8350_codec_write(codec, WM8350_ADC_LR_RATE, adc_lrc);
-       return 0;
-}
-
-static int wm8350_pcm_trigger(struct snd_pcm_substream *substream,
-                             int cmd, struct snd_soc_dai *codec_dai)
-{
-       struct snd_soc_codec *codec = codec_dai->codec;
-       int master = wm8350_codec_cache_read(codec, WM8350_AI_DAC_CONTROL) &
-           WM8350_BCLK_MSTR;
-       int enabled = 0;
-
-       /* Check that the DACs or ADCs are enabled since they are
-        * required for LRC in master mode. The DACs or ADCs need a
-        * valid audio path i.e. pin -> ADC or DAC -> pin before
-        * the LRC will be enabled in master mode. */
-       if (!master || cmd != SNDRV_PCM_TRIGGER_START)
-               return 0;
-
-       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               enabled = wm8350_codec_cache_read(codec, WM8350_POWER_MGMT_4) &
-                   (WM8350_ADCR_ENA | WM8350_ADCL_ENA);
-       } else {
-               enabled = wm8350_codec_cache_read(codec, WM8350_POWER_MGMT_4) &
-                   (WM8350_DACR_ENA | WM8350_DACL_ENA);
-       }
-
-       if (!enabled) {
-               dev_err(codec->dev,
-                      "%s: invalid audio path - no clocks available\n",
-                      __func__);
-               return -EINVAL;
-       }
+       snd_soc_write(codec, WM8350_AI_FORMATING, iface);
+       snd_soc_write(codec, WM8350_AI_DAC_CONTROL, master);
+       snd_soc_write(codec, WM8350_DAC_LR_RATE, dac_lrc);
+       snd_soc_write(codec, WM8350_ADC_LR_RATE, adc_lrc);
        return 0;
 }
 
@@ -966,8 +928,9 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *codec_dai)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
-       struct wm8350 *wm8350 = codec->control_data;
-       u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) &
+       struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
+       struct wm8350 *wm8350 = wm8350_data->wm8350;
+       u16 iface = snd_soc_read(codec, WM8350_AI_FORMATING) &
            ~WM8350_AIF_WL_MASK;
 
        /* bit size */
@@ -985,7 +948,7 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       wm8350_codec_write(codec, WM8350_AI_FORMATING, iface);
+       snd_soc_write(codec, WM8350_AI_FORMATING, iface);
 
        /* The sloping stopband filter is recommended for use with
         * lower sample rates to improve performance.
@@ -1005,12 +968,15 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
 static int wm8350_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
-       struct wm8350 *wm8350 = codec->control_data;
+       unsigned int val;
 
        if (mute)
-               wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
+               val = WM8350_DAC_MUTE_ENA;
        else
-               wm8350_clear_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
+               val = 0;
+
+       snd_soc_update_bits(codec, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA, val);
+
        return 0;
 }
 
@@ -1079,8 +1045,8 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
                          unsigned int freq_out)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
-       struct wm8350 *wm8350 = codec->control_data;
        struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+       struct wm8350 *wm8350 = priv->wm8350;
        struct _fll_div fll_div;
        int ret = 0;
        u16 fll_1, fll_4;
@@ -1104,17 +1070,17 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
                fll_div.ratio);
 
        /* set up N.K & dividers */
-       fll_1 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_1) &
+       fll_1 = snd_soc_read(codec, WM8350_FLL_CONTROL_1) &
            ~(WM8350_FLL_OUTDIV_MASK | WM8350_FLL_RSP_RATE_MASK | 0xc000);
-       wm8350_codec_write(codec, WM8350_FLL_CONTROL_1,
+       snd_soc_write(codec, WM8350_FLL_CONTROL_1,
                           fll_1 | (fll_div.div << 8) | 0x50);
-       wm8350_codec_write(codec, WM8350_FLL_CONTROL_2,
+       snd_soc_write(codec, WM8350_FLL_CONTROL_2,
                           (fll_div.ratio << 11) | (fll_div.
                                                    n & WM8350_FLL_N_MASK));
-       wm8350_codec_write(codec, WM8350_FLL_CONTROL_3, fll_div.k);
-       fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) &
+       snd_soc_write(codec, WM8350_FLL_CONTROL_3, fll_div.k);
+       fll_4 = snd_soc_read(codec, WM8350_FLL_CONTROL_4) &
            ~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF);
-       wm8350_codec_write(codec, WM8350_FLL_CONTROL_4,
+       snd_soc_write(codec, WM8350_FLL_CONTROL_4,
                           fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) |
                           (fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0));
 
@@ -1131,8 +1097,8 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
 static int wm8350_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
-       struct wm8350 *wm8350 = codec->control_data;
        struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+       struct wm8350 *wm8350 = priv->wm8350;
        struct wm8350_audio_platform_data *platform =
                wm8350->codec.platform_data;
        u16 pm1;
@@ -1339,35 +1305,36 @@ static void wm8350_hpr_work(struct work_struct *work)
        wm8350_hp_work(priv, &priv->hpr, WM8350_JACK_R_LVL);
 }
 
-static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
+static irqreturn_t wm8350_hpl_jack_handler(int irq, void *data)
 {
        struct wm8350_data *priv = data;
        struct wm8350 *wm8350 = priv->wm8350;
-       struct wm8350_jack_data *jack = NULL;
 
-       switch (irq - wm8350->irq_base) {
-       case WM8350_IRQ_CODEC_JCK_DET_L:
 #ifndef CONFIG_SND_SOC_WM8350_MODULE
-               trace_snd_soc_jack_irq("WM8350 HPL");
+       trace_snd_soc_jack_irq("WM8350 HPL");
 #endif
-               jack = &priv->hpl;
-               break;
 
-       case WM8350_IRQ_CODEC_JCK_DET_R:
+       if (device_may_wakeup(wm8350->dev))
+               pm_wakeup_event(wm8350->dev, 250);
+
+       schedule_delayed_work(&priv->hpl.work, 200);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wm8350_hpr_jack_handler(int irq, void *data)
+{
+       struct wm8350_data *priv = data;
+       struct wm8350 *wm8350 = priv->wm8350;
+
 #ifndef CONFIG_SND_SOC_WM8350_MODULE
-               trace_snd_soc_jack_irq("WM8350 HPR");
+       trace_snd_soc_jack_irq("WM8350 HPR");
 #endif
-               jack = &priv->hpr;
-               break;
-
-       default:
-               BUG();
-       }
 
        if (device_may_wakeup(wm8350->dev))
                pm_wakeup_event(wm8350->dev, 250);
 
-       schedule_delayed_work(&jack->work, 200);
+       schedule_delayed_work(&priv->hpr.work, 200);
 
        return IRQ_HANDLED;
 }
@@ -1387,7 +1354,7 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
                          struct snd_soc_jack *jack, int report)
 {
        struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
-       struct wm8350 *wm8350 = codec->control_data;
+       struct wm8350 *wm8350 = priv->wm8350;
        int irq;
        int ena;
 
@@ -1418,7 +1385,14 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
        }
 
        /* Sync status */
-       wm8350_hp_jack_handler(irq + wm8350->irq_base, priv);
+       switch (which) {
+       case WM8350_JDL:
+               wm8350_hpl_jack_handler(0, priv);
+               break;
+       case WM8350_JDR:
+               wm8350_hpr_jack_handler(0, priv);
+               break;
+       }
 
        return 0;
 }
@@ -1463,7 +1437,7 @@ int wm8350_mic_jack_detect(struct snd_soc_codec *codec,
                           int detect_report, int short_report)
 {
        struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
-       struct wm8350 *wm8350 = codec->control_data;
+       struct wm8350 *wm8350 = priv->wm8350;
 
        priv->mic.jack = jack;
        priv->mic.report = detect_report;
@@ -1491,7 +1465,6 @@ EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
 static const struct snd_soc_dai_ops wm8350_dai_ops = {
         .hw_params     = wm8350_pcm_hw_params,
         .digital_mute  = wm8350_mute,
-        .trigger       = wm8350_pcm_trigger,
         .set_fmt       = wm8350_set_dai_fmt,
         .set_sysclk    = wm8350_set_dai_sysclk,
         .set_pll       = wm8350_set_fll,
@@ -1559,9 +1532,9 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
        wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
 
        /* Enable robust clocking mode in ADC */
-       wm8350_codec_write(codec, WM8350_SECURITY, 0xa7);
-       wm8350_codec_write(codec, 0xde, 0x13);
-       wm8350_codec_write(codec, WM8350_SECURITY, 0);
+       snd_soc_write(codec, WM8350_SECURITY, 0xa7);
+       snd_soc_write(codec, 0xde, 0x13);
+       snd_soc_write(codec, WM8350_SECURITY, 0);
 
        /* read OUT1 & OUT2 volumes */
        out1 = &priv->out1;
@@ -1601,10 +1574,10 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
                          WM8350_JDL_ENA | WM8350_JDR_ENA);
 
        wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L,
-                           wm8350_hp_jack_handler, 0, "Left jack detect",
+                           wm8350_hpl_jack_handler, 0, "Left jack detect",
                            priv);
        wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R,
-                           wm8350_hp_jack_handler, 0, "Right jack detect",
+                           wm8350_hpr_jack_handler, 0, "Right jack detect",
                            priv);
        wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD,
                            wm8350_mic_handler, 0, "Microphone short", priv);
index 898979d23010e3f5f50cc00070c4d6d56b92b58f..5dc31ebcd0e7ca5ffe2f1b545788f894c11a2080 100644 (file)
@@ -138,8 +138,8 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
                 return ret;
 
         /* now hit the volume update bits (always bit 8) */
-        val = wm8400_read(codec, reg);
-        return wm8400_write(codec, reg, val | 0x0100);
+        val = snd_soc_read(codec, reg);
+        return snd_soc_write(codec, reg, val | 0x0100);
 }
 
 #define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \
@@ -362,8 +362,8 @@ static int inmixer_event (struct snd_soc_dapm_widget *w,
 {
        u16 reg, fakepower;
 
-       reg = wm8400_read(w->codec, WM8400_POWER_MANAGEMENT_2);
-       fakepower = wm8400_read(w->codec, WM8400_INTDRIVBITS);
+       reg = snd_soc_read(w->codec, WM8400_POWER_MANAGEMENT_2);
+       fakepower = snd_soc_read(w->codec, WM8400_INTDRIVBITS);
 
        if (fakepower & ((1 << WM8400_INMIXL_PWR) |
                (1 << WM8400_AINLMUX_PWR))) {
@@ -378,7 +378,7 @@ static int inmixer_event (struct snd_soc_dapm_widget *w,
        } else {
                reg &= ~WM8400_AINR_ENA;
        }
-       wm8400_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
+       snd_soc_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
 
        return 0;
 }
@@ -394,7 +394,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 
        switch (reg_shift) {
        case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
-               reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER1);
+               reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER1);
                if (reg & WM8400_LDLO) {
                        printk(KERN_WARNING
                        "Cannot set as Output Mixer 1 LDLO Set\n");
@@ -402,7 +402,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
-               reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER2);
+               reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER2);
                if (reg & WM8400_RDRO) {
                        printk(KERN_WARNING
                        "Cannot set as Output Mixer 2 RDRO Set\n");
@@ -410,7 +410,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
-               reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
+               reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
                if (reg & WM8400_LDSPK) {
                        printk(KERN_WARNING
                        "Cannot set as Speaker Mixer LDSPK Set\n");
@@ -418,7 +418,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
-               reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
+               reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
                if (reg & WM8400_RDSPK) {
                        printk(KERN_WARNING
                        "Cannot set as Speaker Mixer RDSPK Set\n");
@@ -1021,13 +1021,13 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
        wm8400->fll_in = freq_in;
 
        /* We *must* disable the FLL before any changes */
-       reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_2);
+       reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_2);
        reg &= ~WM8400_FLL_ENA;
-       wm8400_write(codec, WM8400_POWER_MANAGEMENT_2, reg);
+       snd_soc_write(codec, WM8400_POWER_MANAGEMENT_2, reg);
 
-       reg = wm8400_read(codec, WM8400_FLL_CONTROL_1);
+       reg = snd_soc_read(codec, WM8400_FLL_CONTROL_1);
        reg &= ~WM8400_FLL_OSC_ENA;
-       wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
+       snd_soc_write(codec, WM8400_FLL_CONTROL_1, reg);
 
        if (!freq_out)
                return 0;
@@ -1035,15 +1035,15 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
        reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK);
        reg |= WM8400_FLL_FRAC | factors.fratio;
        reg |= factors.freq_ref << WM8400_FLL_REF_FREQ_SHIFT;
-       wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
+       snd_soc_write(codec, WM8400_FLL_CONTROL_1, reg);
 
-       wm8400_write(codec, WM8400_FLL_CONTROL_2, factors.k);
-       wm8400_write(codec, WM8400_FLL_CONTROL_3, factors.n);
+       snd_soc_write(codec, WM8400_FLL_CONTROL_2, factors.k);
+       snd_soc_write(codec, WM8400_FLL_CONTROL_3, factors.n);
 
-       reg = wm8400_read(codec, WM8400_FLL_CONTROL_4);
+       reg = snd_soc_read(codec, WM8400_FLL_CONTROL_4);
        reg &= ~WM8400_FLL_OUTDIV_MASK;
        reg |= factors.outdiv;
-       wm8400_write(codec, WM8400_FLL_CONTROL_4, reg);
+       snd_soc_write(codec, WM8400_FLL_CONTROL_4, reg);
 
        return 0;
 }
@@ -1057,8 +1057,8 @@ static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai,
        struct snd_soc_codec *codec = codec_dai->codec;
        u16 audio1, audio3;
 
-       audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
-       audio3 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_3);
+       audio1 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_1);
+       audio3 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_3);
 
        /* set master/slave audio interface */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1099,8 +1099,8 @@ static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
-       wm8400_write(codec, WM8400_AUDIO_INTERFACE_3, audio3);
+       snd_soc_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+       snd_soc_write(codec, WM8400_AUDIO_INTERFACE_3, audio3);
        return 0;
 }
 
@@ -1112,24 +1112,24 @@ static int wm8400_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 
        switch (div_id) {
        case WM8400_MCLK_DIV:
-               reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+               reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
                        ~WM8400_MCLK_DIV_MASK;
-               wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+               snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
                break;
        case WM8400_DACCLK_DIV:
-               reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+               reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
                        ~WM8400_DAC_CLKDIV_MASK;
-               wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+               snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
                break;
        case WM8400_ADCCLK_DIV:
-               reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+               reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
                        ~WM8400_ADC_CLKDIV_MASK;
-               wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+               snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
                break;
        case WM8400_BCLK_DIV:
-               reg = wm8400_read(codec, WM8400_CLOCKING_1) &
+               reg = snd_soc_read(codec, WM8400_CLOCKING_1) &
                        ~WM8400_BCLK_DIV_MASK;
-               wm8400_write(codec, WM8400_CLOCKING_1, reg | div);
+               snd_soc_write(codec, WM8400_CLOCKING_1, reg | div);
                break;
        default:
                return -EINVAL;
@@ -1145,9 +1145,8 @@ static int wm8400_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
-       u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
+       struct snd_soc_codec *codec = dai->codec;
+       u16 audio1 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_1);
 
        audio1 &= ~WM8400_AIF_WL_MASK;
        /* bit size */
@@ -1165,19 +1164,19 @@ static int wm8400_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+       snd_soc_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
        return 0;
 }
 
 static int wm8400_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
-       u16 val = wm8400_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
+       u16 val = snd_soc_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
 
        if (mute)
-               wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+               snd_soc_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
        else
-               wm8400_write(codec, WM8400_DAC_CTRL, val);
+               snd_soc_write(codec, WM8400_DAC_CTRL, val);
 
        return 0;
 }
@@ -1196,9 +1195,9 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
 
        case SND_SOC_BIAS_PREPARE:
                /* VMID=2*50k */
-               val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
+               val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1) &
                        ~WM8400_VMID_MODE_MASK;
-               wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2);
+               snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2);
                break;
 
        case SND_SOC_BIAS_STANDBY:
@@ -1212,74 +1211,74 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
                                return ret;
                        }
 
-                       wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
+                       snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1,
                                     WM8400_CODEC_ENA | WM8400_SYSCLK_ENA);
 
                        /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
-                       wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+                       snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
                                     WM8400_BUFDCOPEN | WM8400_POBCTRL);
 
                        msleep(50);
 
                        /* Enable VREF & VMID at 2x50k */
-                       val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+                       val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
                        val |= 0x2 | WM8400_VREF_ENA;
-                       wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+                       snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
 
                        /* Enable BUFIOEN */
-                       wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+                       snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
                                     WM8400_BUFDCOPEN | WM8400_POBCTRL |
                                     WM8400_BUFIOEN);
 
                        /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-                       wm8400_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN);
+                       snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN);
                }
 
                /* VMID=2*300k */
-               val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
+               val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1) &
                        ~WM8400_VMID_MODE_MASK;
-               wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4);
+               snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4);
                break;
 
        case SND_SOC_BIAS_OFF:
                /* Enable POBCTRL and SOFT_ST */
-               wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+               snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
                        WM8400_POBCTRL | WM8400_BUFIOEN);
 
                /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
-               wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+               snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
                        WM8400_BUFDCOPEN | WM8400_POBCTRL |
                        WM8400_BUFIOEN);
 
                /* mute DAC */
-               val = wm8400_read(codec, WM8400_DAC_CTRL);
-               wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+               val = snd_soc_read(codec, WM8400_DAC_CTRL);
+               snd_soc_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
 
                /* Enable any disabled outputs */
-               val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+               val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
                val |= WM8400_SPK_ENA | WM8400_OUT3_ENA |
                        WM8400_OUT4_ENA | WM8400_LOUT_ENA |
                        WM8400_ROUT_ENA;
-               wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+               snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
 
                /* Disable VMID */
                val &= ~WM8400_VMID_MODE_MASK;
-               wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+               snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
 
                msleep(300);
 
                /* Enable all output discharge bits */
-               wm8400_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
+               snd_soc_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
                        WM8400_DIS_RLINE | WM8400_DIS_OUT3 |
                        WM8400_DIS_OUT4 | WM8400_DIS_LOUT |
                        WM8400_DIS_ROUT);
 
                /* Disable VREF */
                val &= ~WM8400_VREF_ENA;
-               wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+               snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
 
                /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-               wm8400_write(codec, WM8400_ANTIPOP2, 0x0);
+               snd_soc_write(codec, WM8400_ANTIPOP2, 0x0);
 
                ret = regulator_bulk_disable(ARRAY_SIZE(power),
                                             &power[0]);
@@ -1385,19 +1384,19 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
 
        wm8400_codec_reset(codec);
 
-       reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
-       wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
+       reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
+       snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
 
        /* Latch volume update bits */
-       reg = wm8400_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
-       wm8400_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+       reg = snd_soc_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
+       snd_soc_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
                     reg & WM8400_IPVU);
-       reg = wm8400_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
-       wm8400_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+       reg = snd_soc_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
+       snd_soc_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
                     reg & WM8400_IPVU);
 
-       wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
-       wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+       snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+       snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
 
        if (!schedule_work(&priv->work)) {
                ret = -EINVAL;
@@ -1414,8 +1413,8 @@ static int  wm8400_codec_remove(struct snd_soc_codec *codec)
 {
        u16 reg;
 
-       reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
-       wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
+       reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
+       snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1,
                     reg & (~WM8400_CODEC_ENA));
 
        regulator_bulk_free(ARRAY_SIZE(power), power);
@@ -1428,7 +1427,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
        .remove =       wm8400_codec_remove,
        .suspend =      wm8400_suspend,
        .resume =       wm8400_resume,
-       .read = wm8400_read,
+       .read = snd_soc_read,
        .write = wm8400_write,
        .set_bias_level = wm8400_set_bias_level,
 
index 9166126bd31259f10fa56c7b224029e7f7a7b0cc..56a049555e2c1de782b82b2fc7e947539076c1a3 100644 (file)
@@ -392,8 +392,7 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
        u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
 
index 7fea2c3bf7e77dbf16096709df41004cf88ffdbf..1c3ffb290cdcdb00651ef5c31db835394ae35421 100644 (file)
@@ -145,8 +145,7 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
        int i;
        u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
index fc3d59e4908404491a1801765f29bbacabb3c15c..1467f97dce21efa668b005a531faf3a64bfd78c2 100644 (file)
@@ -88,8 +88,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        u16 dac = snd_soc_read(codec, WM8728_DACCTL);
 
        dac &= ~0x18;
index a32caa72bd7d727e4e94737e50650d647da1e2db..9d1b9b0271f18671bf50cdfb77c448b40d46db8b 100644 (file)
@@ -635,16 +635,17 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi)
        struct wm8731_priv *wm8731;
        int ret;
 
-       wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
+       wm8731 = devm_kzalloc(&spi->dev, sizeof(struct wm8731_priv),
+                             GFP_KERNEL);
        if (wm8731 == NULL)
                return -ENOMEM;
 
-       wm8731->regmap = regmap_init_spi(spi, &wm8731_regmap);
+       wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap);
        if (IS_ERR(wm8731->regmap)) {
                ret = PTR_ERR(wm8731->regmap);
                dev_err(&spi->dev, "Failed to allocate register map: %d\n",
                        ret);
-               goto err;
+               return ret;
        }
 
        spi_set_drvdata(spi, wm8731);
@@ -653,25 +654,15 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi)
                        &soc_codec_dev_wm8731, &wm8731_dai, 1);
        if (ret != 0) {
                dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret);
-               goto err_regmap;
+               return ret;
        }
 
        return 0;
-
-err_regmap:
-       regmap_exit(wm8731->regmap);
-err:
-       kfree(wm8731);
-       return ret;
 }
 
 static int __devexit wm8731_spi_remove(struct spi_device *spi)
 {
-       struct wm8731_priv *wm8731 = spi_get_drvdata(spi);
-
        snd_soc_unregister_codec(&spi->dev);
-       regmap_exit(wm8731->regmap);
-       kfree(wm8731);
        return 0;
 }
 
@@ -693,16 +684,17 @@ static __devinit int wm8731_i2c_probe(struct i2c_client *i2c,
        struct wm8731_priv *wm8731;
        int ret;
 
-       wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
+       wm8731 = devm_kzalloc(&i2c->dev, sizeof(struct wm8731_priv),
+                             GFP_KERNEL);
        if (wm8731 == NULL)
                return -ENOMEM;
 
-       wm8731->regmap = regmap_init_i2c(i2c, &wm8731_regmap);
+       wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap);
        if (IS_ERR(wm8731->regmap)) {
                ret = PTR_ERR(wm8731->regmap);
                dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
                        ret);
-               goto err;
+               return ret;
        }
 
        i2c_set_clientdata(i2c, wm8731);
@@ -711,24 +703,15 @@ static __devinit int wm8731_i2c_probe(struct i2c_client *i2c,
                        &soc_codec_dev_wm8731, &wm8731_dai, 1);
        if (ret != 0) {
                dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
-               goto err_regmap;
+               return ret;
        }
 
        return 0;
-
-err_regmap:
-       regmap_exit(wm8731->regmap);
-err:
-       kfree(wm8731);
-       return ret;
 }
 
 static __devexit int wm8731_i2c_remove(struct i2c_client *client)
 {
-       struct wm8731_priv *wm8731 = i2c_get_clientdata(client);
        snd_soc_unregister_codec(&client->dev);
-       regmap_exit(wm8731->regmap);
-       kfree(wm8731);
        return 0;
 }
 
index 4fe9d191e2774ab7fad2e00a5ba7542b51580669..d0520124616d1831d2d4cf419a9d11ecbd23c40a 100644 (file)
@@ -329,8 +329,7 @@ static int wm8737_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
        int i;
        u16 clocking = 0;
index 3941f50bf18787b57a9e99555c7f67a28b00eedc..6e849cb042430dc5ca22df08c1bb1708a36ec238 100644 (file)
@@ -203,8 +203,7 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
        int i;
index e4c50ce7d9c0852bce267e0e13b41a759a810ae3..89151ca5e7766b69cd57447e611fcf1301fd301f 100644 (file)
@@ -547,8 +547,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3;
        u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0;
index e27e7b62b365a0a79942956455d95d40dd4f2e5d..a26482cd7654fbfcbccd64ef7a86bbb7faaaa619 100644 (file)
@@ -931,8 +931,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
        u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01f3;
        u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x017f;
@@ -1161,8 +1160,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
        u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x01c0;
        u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01f3;
index f18c554efc984832ec6b538cf896cfce5ae2d925..077c9628c70d7870f0a29a517f20cd92c6bce66d 100644 (file)
@@ -610,8 +610,7 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        u16 reg;
 
        reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60;
index c91fb2f99c13b5ac978191ecff133302989ea5ce..86b8a2926591e15bf487ec96cb1c3e5125c45770 100644 (file)
@@ -1432,8 +1432,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec =rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        int fs = params_rate(params);
        int bclk;
index d2883affea3b2421508c474732d3fdf92192bdb2..481a3d9cfe4852958047cec3f83be88cd17a365d 100644 (file)
@@ -371,8 +371,7 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
        u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
        u16 companding =  snd_soc_read(codec,
index 840d72086d04c7c3cf8dcf7d813c9a4f8ee149d7..8bc659d8dd2e2d5bda0936a37bd694ee33ed10c4 100644 (file)
@@ -505,8 +505,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
        int i;
index 15d467ff91b496b6bb72dfbdd5eb4c9bfb5500fa..0cfce9999c894b83bef22d09ae6320c7ce88e8b8 100644 (file)
@@ -1478,7 +1478,8 @@ static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
 
 static int wm8962_dsp2_write_config(struct snd_soc_codec *codec)
 {
-       return 0;
+       return regcache_sync_region(codec->control_data,
+                                   WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER);
 }
 
 static int wm8962_dsp2_set_enable(struct snd_soc_codec *codec, u16 val)
@@ -1755,10 +1756,22 @@ SOC_DOUBLE_R_TLV("EQ4 Volume", WM8962_EQ3, WM8962_EQ23,
 SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23,
                 WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv),
 
+SOC_SINGLE("3D Switch", WM8962_THREED1, 0, 1, 0),
+SND_SOC_BYTES_MASK("3D Coefficients", WM8962_THREED1, 4, WM8962_THREED_ENA),
+
+SOC_SINGLE("DF1 Switch", WM8962_DF1, 0, 1, 0),
+SND_SOC_BYTES_MASK("DF1 Coefficients", WM8962_DF1, 7, WM8962_DF1_ENA),
+
+SOC_SINGLE("DRC Switch", WM8962_DRC_1, 0, 1, 0),
+SND_SOC_BYTES_MASK("DRC Coefficients", WM8962_DRC_1, 5, WM8962_DRC_ENA),
+
 WM8962_DSP2_ENABLE("VSS Switch", WM8962_VSS_ENA_SHIFT),
+SND_SOC_BYTES("VSS Coefficients", WM8962_VSS_XHD2_1, 148),
 WM8962_DSP2_ENABLE("HPF1 Switch", WM8962_HPF1_ENA_SHIFT),
 WM8962_DSP2_ENABLE("HPF2 Switch", WM8962_HPF2_ENA_SHIFT),
+SND_SOC_BYTES("HPF Coefficients", WM8962_LHPF2, 1),
 WM8962_DSP2_ENABLE("HD Bass Switch", WM8962_HDBASS_ENA_SHIFT),
+SND_SOC_BYTES("HD Bass Coefficients", WM8962_HDBASS_AI_1, 30),
 };
 
 static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
@@ -2519,8 +2532,7 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
        int i;
        int aif0 = 0;
index 28fe59e3ce011c4d96eac242276214b91d3d9c86..eef783f6b6d6849aa014296a9afea6b5743adfca 100644 (file)
@@ -478,8 +478,7 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
        u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
index 72d5fdcd3cc2b8b1eb6453f847eea219cb920b35..a5be3adecf7572bed47d4ed99b59f6fbf87fbed8 100644 (file)
@@ -723,8 +723,7 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
        /* Word length mask = 0x60 */
        u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60;
index 6cdf6a2bc28304db51b59128584689bfcc29139c..1d4c5cf47b06ba24d49509d904b5460e3ad22891 100644 (file)
@@ -668,8 +668,7 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3;
        u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180;
index 9d242351e6e837211c70ffb37033874830ccb8b3..db63c97ddf5160afe74c8b2bcd9f9f1d28c27273 100644 (file)
@@ -1112,8 +1112,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
 
        audio1 &= ~WM8990_AIF_WL_MASK;
index d256a934064490abb621b738020463e30490610b..36acfccab99986fa7ee5e3bd3f770d4212c2d29a 100644 (file)
@@ -218,7 +218,6 @@ struct wm8993_priv {
        unsigned int sysclk_rate;
        unsigned int fs;
        unsigned int bclk;
-       int class_w_users;
        unsigned int fll_fref;
        unsigned int fll_fout;
        int fll_src;
@@ -824,84 +823,6 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-/*
- * When used with DAC outputs only the WM8993 charge pump supports
- * operation in class W mode, providing very low power consumption
- * when used with digital sources.  Enable and disable this mode
- * automatically depending on the mixer configuration.
- *
- * Currently the only supported paths are the direct DAC->headphone
- * paths (which provide minimum power consumption anyway).
- */
-static int class_w_put(struct snd_kcontrol *kcontrol,
-                      struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
-       struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       /* Turn it off if we're using the main output mixer */
-       if (ucontrol->value.integer.value[0] == 0) {
-               if (wm8993->class_w_users == 0) {
-                       dev_dbg(codec->dev, "Disabling Class W\n");
-                       snd_soc_update_bits(codec, WM8993_CLASS_W_0,
-                                           WM8993_CP_DYN_FREQ |
-                                           WM8993_CP_DYN_V,
-                                           0);
-               }
-               wm8993->class_w_users++;
-               wm8993->hubs_data.class_w = true;
-       }
-
-       /* Implement the change */
-       ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
-
-       /* Enable it if we're using the direct DAC path */
-       if (ucontrol->value.integer.value[0] == 1) {
-               if (wm8993->class_w_users == 1) {
-                       dev_dbg(codec->dev, "Enabling Class W\n");
-                       snd_soc_update_bits(codec, WM8993_CLASS_W_0,
-                                           WM8993_CP_DYN_FREQ |
-                                           WM8993_CP_DYN_V,
-                                           WM8993_CP_DYN_FREQ |
-                                           WM8993_CP_DYN_V);
-               }
-               wm8993->class_w_users--;
-               wm8993->hubs_data.class_w = false;
-       }
-
-       dev_dbg(codec->dev, "Indirect DAC use count now %d\n",
-               wm8993->class_w_users);
-
-       return ret;
-}
-
-#define SOC_DAPM_ENUM_W(xname, xenum) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_enum_double, \
-       .get = snd_soc_dapm_get_enum_double, \
-       .put = class_w_put, \
-       .private_value = (unsigned long)&xenum }
-
-static const char *hp_mux_text[] = {
-       "Mixer",
-       "DAC",
-};
-
-static const struct soc_enum hpl_enum =
-       SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpl_mux =
-       SOC_DAPM_ENUM_W("Left Headphone Mux", hpl_enum);
-
-static const struct soc_enum hpr_enum =
-       SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpr_mux =
-       SOC_DAPM_ENUM_W("Right Headphone Mux", hpr_enum);
-
 static const struct snd_kcontrol_new left_speaker_mixer[] = {
 SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 7, 1, 0),
 SOC_DAPM_SINGLE("IN1LP Switch", WM8993_SPEAKER_MIXER, 5, 1, 0),
@@ -988,8 +909,8 @@ SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &sidetoner_mux),
 SND_SOC_DAPM_DAC("DACL", NULL, WM8993_POWER_MANAGEMENT_3, 1, 0),
 SND_SOC_DAPM_DAC("DACR", NULL, WM8993_POWER_MANAGEMENT_3, 0, 0),
 
-SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
-SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux),
 
 SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0,
                   left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
@@ -1579,9 +1500,6 @@ static int wm8993_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       /* By default we're using the output mixers */
-       wm8993->class_w_users = 2;
-
        /* Latch volume update bits and default ZC on */
        snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
                            WM8993_DAC_VU, WM8993_DAC_VU);
index 2de12ebe43b5f8c8a423cc1a26d071f063777469..993639d694ce308aed067cea3003fcbf6ad2ee2b 100644 (file)
@@ -70,8 +70,8 @@ static const struct wm8958_micd_rate micdet_rates[] = {
 static const struct wm8958_micd_rate jackdet_rates[] = {
        { 32768,       true,  0, 1 },
        { 32768,       false, 0, 1 },
-       { 44100 * 256, true,  7, 10 },
-       { 44100 * 256, false, 7, 10 },
+       { 44100 * 256, true,  10, 10 },
+       { 44100 * 256, false, 7, 8 },
 };
 
 static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
@@ -82,7 +82,8 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
        const struct wm8958_micd_rate *rates;
        int num_rates;
 
-       if (wm8994->jack_cb != wm8958_default_micdet)
+       if (!(wm8994->pdata && wm8994->pdata->micd_rates) &&
+           wm8994->jack_cb != wm8958_default_micdet)
                return;
 
        idle = !wm8994->jack_mic;
@@ -118,6 +119,10 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
        val = rates[best].start << WM8958_MICD_BIAS_STARTTIME_SHIFT
                | rates[best].rate << WM8958_MICD_RATE_SHIFT;
 
+       dev_dbg(codec->dev, "MICD rate %d,%d for %dHz %s\n",
+               rates[best].start, rates[best].rate, sysclk,
+               idle ? "idle" : "active");
+
        snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
                            WM8958_MICD_BIAS_STARTTIME_MASK |
                            WM8958_MICD_RATE_MASK, val);
@@ -398,7 +403,7 @@ static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block)
                wm8994->dac_rates[iface]);
 
        /* The EQ will be disabled while reconfiguring it, remember the
-        * current configuration. 
+        * current configuration.
         */
        save = snd_soc_read(codec, base);
        save &= WM8994_AIF1DAC1_EQ_ENA;
@@ -686,6 +691,9 @@ static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
+       if (!wm8994->jackdet || !wm8994->jack_cb)
+               return;
+
        if (!wm8994->jackdet || !wm8994->jack_cb)
                return;
 
@@ -784,7 +792,7 @@ static void vmid_reference(struct snd_soc_codec *codec)
 
                switch (wm8994->vmid_mode) {
                default:
-                       WARN_ON(0 == "Invalid VMID mode");
+                       WARN_ON(NULL == "Invalid VMID mode");
                case WM8994_VMID_NORMAL:
                        /* Startup bias, VMID ramp & buffer */
                        snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
@@ -937,27 +945,12 @@ static int vmid_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static void wm8994_update_class_w(struct snd_soc_codec *codec)
+static bool wm8994_check_class_w_digital(struct snd_soc_codec *codec)
 {
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       int enable = 1;
        int source = 0;  /* GCC flow analysis can't track enable */
        int reg, reg_r;
 
-       /* Only support direct DAC->headphone paths */
-       reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_1);
-       if (!(reg & WM8994_DAC1L_TO_HPOUT1L)) {
-               dev_vdbg(codec->dev, "HPL connected to output mixer\n");
-               enable = 0;
-       }
-
-       reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_2);
-       if (!(reg & WM8994_DAC1R_TO_HPOUT1R)) {
-               dev_vdbg(codec->dev, "HPR connected to output mixer\n");
-               enable = 0;
-       }
-
-       /* We also need the same setting for L/R and only one path */
+       /* We also need the same AIF source for L/R and only one path */
        reg = snd_soc_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING);
        switch (reg) {
        case WM8994_AIF2DACL_TO_DAC1L:
@@ -974,30 +967,20 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec)
                break;
        default:
                dev_vdbg(codec->dev, "DAC mixer setting: %x\n", reg);
-               enable = 0;
-               break;
+               return false;
        }
 
        reg_r = snd_soc_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING);
        if (reg_r != reg) {
                dev_vdbg(codec->dev, "Left and right DAC mixers different\n");
-               enable = 0;
+               return false;
        }
 
-       if (enable) {
-               dev_dbg(codec->dev, "Class W enabled\n");
-               snd_soc_update_bits(codec, WM8994_CLASS_W_1,
-                                   WM8994_CP_DYN_PWR |
-                                   WM8994_CP_DYN_SRC_SEL_MASK,
-                                   source | WM8994_CP_DYN_PWR);
-               wm8994->hubs.class_w = true;
-               
-       } else {
-               dev_dbg(codec->dev, "Class W disabled\n");
-               snd_soc_update_bits(codec, WM8994_CLASS_W_1,
-                                   WM8994_CP_DYN_PWR, 0);
-               wm8994->hubs.class_w = false;
-       }
+       /* Set the source up */
+       snd_soc_update_bits(codec, WM8994_CLASS_W_1,
+                           WM8994_CP_DYN_SRC_SEL_MASK, source);
+
+       return true;
 }
 
 static int aif1clk_ev(struct snd_soc_dapm_widget *w,
@@ -1280,45 +1263,6 @@ static int dac_ev(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static const char *hp_mux_text[] = {
-       "Mixer",
-       "DAC",
-};
-
-#define WM8994_HP_ENUM(xname, xenum) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_enum_double, \
-       .get = snd_soc_dapm_get_enum_double, \
-       .put = wm8994_put_hp_enum, \
-       .private_value = (unsigned long)&xenum }
-
-static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *w = wlist->widgets[0];
-       struct snd_soc_codec *codec = w->codec;
-       int ret;
-
-       ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
-
-       wm8994_update_class_w(codec);
-
-       return ret;
-}
-
-static const struct soc_enum hpl_enum =
-       SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_1, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpl_mux =
-       WM8994_HP_ENUM("Left Headphone Mux", hpl_enum);
-
-static const struct soc_enum hpr_enum =
-       SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_2, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpr_mux =
-       WM8994_HP_ENUM("Right Headphone Mux", hpr_enum);
-
 static const char *adc_mux_text[] = {
        "ADC",
        "DMIC",
@@ -1430,7 +1374,7 @@ static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
 
        ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
 
-       wm8994_update_class_w(codec);
+       wm_hubs_update_class_w(codec);
 
        return ret;
 }
@@ -1524,7 +1468,7 @@ static const struct snd_kcontrol_new wm8958_aif3adc_mux =
        SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum);
 
 static const char *mono_pcm_out_text[] = {
-       "None", "AIF2ADCL", "AIF2ADCR", 
+       "None", "AIF2ADCL", "AIF2ADCR",
 };
 
 static const struct soc_enum mono_pcm_out_enum =
@@ -1573,9 +1517,9 @@ SND_SOC_DAPM_MIXER_E("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
 SND_SOC_DAPM_MIXER_E("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
                     right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer),
                     late_enable_ev, SND_SOC_DAPM_PRE_PMU),
-SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux,
+SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux,
                   late_enable_ev, SND_SOC_DAPM_PRE_PMU),
-SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux,
+SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux,
                   late_enable_ev, SND_SOC_DAPM_PRE_PMU),
 
 SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
@@ -1591,8 +1535,8 @@ SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
                   left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
 SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
                   right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
-SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
-SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux),
 };
 
 static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = {
@@ -1732,6 +1676,7 @@ SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8994_aif3adc_mux),
 };
 
 static const struct snd_soc_dapm_widget wm8958_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("AIF3", WM8994_POWER_MANAGEMENT_6, 5, 1, NULL, 0),
 SND_SOC_DAPM_MUX("Mono PCM Out Mux", SND_SOC_NOPM, 0, 0, &mono_pcm_out_mux),
 SND_SOC_DAPM_MUX("AIF2DACL Mux", SND_SOC_NOPM, 0, 0, &aif2dacl_src_mux),
 SND_SOC_DAPM_MUX("AIF2DACR Mux", SND_SOC_NOPM, 0, 0, &aif2dacr_src_mux),
@@ -1972,6 +1917,9 @@ static const struct snd_soc_dapm_route wm8958_intercon[] = {
        { "AIF2DACR Mux", "AIF2", "AIF2DAC Mux" },
        { "AIF2DACR Mux", "AIF3", "AIF3DACDAT" },
 
+       { "AIF3DACDAT", NULL, "AIF3" },
+       { "AIF3ADCDAT", NULL, "AIF3" },
+
        { "Mono PCM Out Mux", "AIF2ADCL", "AIF2ADCL" },
        { "Mono PCM Out Mux", "AIF2ADCR", "AIF2ADCR" },
 
@@ -2068,24 +2016,20 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
        struct wm8994 *control = wm8994->wm8994;
        int reg_offset, ret;
        struct fll_div fll;
-       u16 reg, aif1, aif2;
+       u16 reg, clk1, aif_reg, aif_src;
        unsigned long timeout;
        bool was_enabled;
 
-       aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
-               & WM8994_AIF1CLK_ENA;
-
-       aif2 = snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
-               & WM8994_AIF2CLK_ENA;
-
        switch (id) {
        case WM8994_FLL1:
                reg_offset = 0;
                id = 0;
+               aif_src = 0x10;
                break;
        case WM8994_FLL2:
                reg_offset = 0x20;
                id = 1;
+               aif_src = 0x18;
                break;
        default:
                return -EINVAL;
@@ -2127,16 +2071,33 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
        if (ret < 0)
                return ret;
 
-       /* Gate the AIF clocks while we reclock */
-       snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
-                           WM8994_AIF1CLK_ENA, 0);
-       snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
-                           WM8994_AIF2CLK_ENA, 0);
+       /* Make sure that we're not providing SYSCLK right now */
+       clk1 = snd_soc_read(codec, WM8994_CLOCKING_1);
+       if (clk1 & WM8994_SYSCLK_SRC)
+               aif_reg = WM8994_AIF2_CLOCKING_1;
+       else
+               aif_reg = WM8994_AIF1_CLOCKING_1;
+       reg = snd_soc_read(codec, aif_reg);
+
+       if ((reg & WM8994_AIF1CLK_ENA) &&
+           (reg & WM8994_AIF1CLK_SRC_MASK) == aif_src) {
+               dev_err(codec->dev, "FLL%d is currently providing SYSCLK\n",
+                       id + 1);
+               return -EBUSY;
+       }
 
        /* We always need to disable the FLL while reconfiguring */
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
                            WM8994_FLL1_ENA, 0);
 
+       if (wm8994->fll_byp && src == WM8994_FLL_SRC_BCLK &&
+           freq_in == freq_out && freq_out) {
+               dev_dbg(codec->dev, "Bypassing FLL%d\n", id + 1);
+               snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
+                                   WM8958_FLL1_BYP, WM8958_FLL1_BYP);
+               goto out;
+       }
+
        reg = (fll.outdiv << WM8994_FLL1_OUTDIV_SHIFT) |
                (fll.fll_fratio << WM8994_FLL1_FRATIO_SHIFT);
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_2 + reg_offset,
@@ -2151,6 +2112,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                                    fll.n << WM8994_FLL1_N_SHIFT);
 
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
+                           WM8958_FLL1_BYP |
                            WM8994_FLL1_REFCLK_DIV_MASK |
                            WM8994_FLL1_REFCLK_SRC_MASK,
                            (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
@@ -2213,16 +2175,11 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                }
        }
 
+out:
        wm8994->fll[id].in = freq_in;
        wm8994->fll[id].out = freq_out;
        wm8994->fll[id].src = src;
 
-       /* Enable any gated AIF clocks */
-       snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
-                           WM8994_AIF1CLK_ENA, aif1);
-       snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
-                           WM8994_AIF2CLK_ENA, aif2);
-
        configure_clock(codec);
 
        return 0;
@@ -2290,7 +2247,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 
        case WM8994_SYSCLK_OPCLK:
                /* Special case - a division (times 10) is given and
-                * no effect on main clocking. 
+                * no effect on main clocking.
                 */
                if (freq) {
                        for (i = 0; i < ARRAY_SIZE(opclk_divs); i++)
@@ -2792,33 +2749,6 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream,
        return snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
 }
 
-static void wm8994_aif_shutdown(struct snd_pcm_substream *substream,
-                               struct snd_soc_dai *dai)
-{
-       struct snd_soc_codec *codec = dai->codec;
-       int rate_reg = 0;
-
-       switch (dai->id) {
-       case 1:
-               rate_reg = WM8994_AIF1_RATE;
-               break;
-       case 2:
-               rate_reg = WM8994_AIF2_RATE;
-               break;
-       default:
-               break;
-       }
-
-       /* If the DAI is idle then configure the divider tree for the
-        * lowest output rate to save a little power if the clock is
-        * still active (eg, because it is system clock).
-        */
-       if (rate_reg && !dai->playback_active && !dai->capture_active)
-               snd_soc_update_bits(codec, rate_reg,
-                                   WM8994_AIF1_SR_MASK |
-                                   WM8994_AIF1CLK_RATE_MASK, 0x9);
-}
-
 static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -2860,10 +2790,6 @@ static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
                reg = WM8994_AIF2_MASTER_SLAVE;
                mask = WM8994_AIF2_TRI;
                break;
-       case 3:
-               reg = WM8994_POWER_MANAGEMENT_6;
-               mask = WM8994_AIF3_TRI;
-               break;
        default:
                return -EINVAL;
        }
@@ -2900,7 +2826,6 @@ static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
        .set_sysclk     = wm8994_set_dai_sysclk,
        .set_fmt        = wm8994_set_dai_fmt,
        .hw_params      = wm8994_hw_params,
-       .shutdown       = wm8994_aif_shutdown,
        .digital_mute   = wm8994_aif_mute,
        .set_pll        = wm8994_set_fll,
        .set_tristate   = wm8994_set_tristate,
@@ -2910,7 +2835,6 @@ static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
        .set_sysclk     = wm8994_set_dai_sysclk,
        .set_fmt        = wm8994_set_dai_fmt,
        .hw_params      = wm8994_hw_params,
-       .shutdown       = wm8994_aif_shutdown,
        .digital_mute   = wm8994_aif_mute,
        .set_pll        = wm8994_set_fll,
        .set_tristate   = wm8994_set_tristate,
@@ -2918,7 +2842,6 @@ static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
 
 static const struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
        .hw_params      = wm8994_aif3_hw_params,
-       .set_tristate   = wm8994_set_tristate,
 };
 
 static struct snd_soc_dai_driver wm8994_dai[] = {
@@ -3126,14 +3049,14 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
 
                /* Expand the array... */
                t = krealloc(wm8994->retune_mobile_texts,
-                            sizeof(char *) * 
+                            sizeof(char *) *
                             (wm8994->num_retune_mobile_texts + 1),
                             GFP_KERNEL);
                if (t == NULL)
                        continue;
 
                /* ...store the new entry... */
-               t[wm8994->num_retune_mobile_texts] = 
+               t[wm8994->num_retune_mobile_texts] =
                        pdata->retune_mobile_cfgs[i].name;
 
                /* ...and remember the new version. */
@@ -3304,25 +3227,25 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 }
 EXPORT_SYMBOL_GPL(wm8994_mic_detect);
 
-static irqreturn_t wm8994_mic_irq(int irq, void *data)
+static void wm8994_mic_work(struct work_struct *work)
 {
-       struct wm8994_priv *priv = data;
-       struct snd_soc_codec *codec = priv->codec;
-       int reg;
+       struct wm8994_priv *priv = container_of(work,
+                                               struct wm8994_priv,
+                                               mic_work.work);
+       struct regmap *regmap = priv->wm8994->regmap;
+       struct device *dev = priv->wm8994->dev;
+       unsigned int reg;
+       int ret;
        int report;
 
-#ifndef CONFIG_SND_SOC_WM8994_MODULE
-       trace_snd_soc_jack_irq(dev_name(codec->dev));
-#endif
-
-       reg = snd_soc_read(codec, WM8994_INTERRUPT_RAW_STATUS_2);
-       if (reg < 0) {
-               dev_err(codec->dev, "Failed to read microphone status: %d\n",
-                       reg);
-               return IRQ_HANDLED;
+       ret = regmap_read(regmap, WM8994_INTERRUPT_RAW_STATUS_2, &reg);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read microphone status: %d\n",
+                       ret);
+               return;
        }
 
-       dev_dbg(codec->dev, "Microphone status: %x\n", reg);
+       dev_dbg(dev, "Microphone status: %x\n", reg);
 
        report = 0;
        if (reg & WM8994_MIC1_DET_STS) {
@@ -3361,6 +3284,20 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
 
        snd_soc_jack_report(priv->micdet[1].jack, report,
                            SND_JACK_HEADSET | SND_JACK_BTN_0);
+}
+
+static irqreturn_t wm8994_mic_irq(int irq, void *data)
+{
+       struct wm8994_priv *priv = data;
+       struct snd_soc_codec *codec = priv->codec;
+
+#ifndef CONFIG_SND_SOC_WM8994_MODULE
+       trace_snd_soc_jack_irq(dev_name(codec->dev));
+#endif
+
+       pm_wakeup_event(codec->dev, 300);
+
+       schedule_delayed_work(&priv->mic_work, msecs_to_jiffies(250));
 
        return IRQ_HANDLED;
 }
@@ -3415,9 +3352,6 @@ static void wm8958_default_micdet(u16 status, void *data)
 
                wm8958_micd_set_rate(codec);
 
-               snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
-                                   SND_JACK_HEADSET);
-
                /* If we have jackdet that will detect removal */
                if (wm8994->jackdet) {
                        mutex_lock(&wm8994->accdet_lock);
@@ -3430,14 +3364,13 @@ static void wm8958_default_micdet(u16 status, void *data)
 
                        mutex_unlock(&wm8994->accdet_lock);
 
-                       if (wm8994->pdata->jd_ext_cap) {
-                               mutex_lock(&codec->mutex);
+                       if (wm8994->pdata->jd_ext_cap)
                                snd_soc_dapm_disable_pin(&codec->dapm,
                                                         "MICBIAS2");
-                               snd_soc_dapm_sync(&codec->dapm);
-                               mutex_unlock(&codec->mutex);
-                       }
                }
+
+               snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
+                                   SND_JACK_HEADSET);
        }
 
        /* Report short circuit as a button */
@@ -3489,6 +3422,8 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
        if (present) {
                dev_dbg(codec->dev, "Jack detected\n");
 
+               wm8958_micd_set_rate(codec);
+
                snd_soc_update_bits(codec, WM8958_MICBIAS2,
                                    WM8958_MICB2_DISCH, 0);
 
@@ -3526,16 +3461,11 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
 
        /* If required for an external cap force MICBIAS on */
        if (wm8994->pdata->jd_ext_cap) {
-               mutex_lock(&codec->mutex);
-
                if (present)
                        snd_soc_dapm_force_enable_pin(&codec->dapm,
                                                      "MICBIAS2");
                else
                        snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
-
-               snd_soc_dapm_sync(&codec->dapm);
-               mutex_unlock(&codec->mutex);
        }
 
        if (present)
@@ -3740,6 +3670,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        wm8994->codec = codec;
 
        mutex_init(&wm8994->accdet_lock);
+       INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work);
 
        for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
                init_completion(&wm8994->fll_locked[i]);
@@ -3783,13 +3714,22 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        case WM8958:
                wm8994->hubs.dcs_readback_mode = 1;
                wm8994->hubs.hp_startup_mode = 1;
+
+               switch (wm8994->revision) {
+               case 0:
+                       break;
+               default:
+                       wm8994->fll_byp = true;
+                       break;
+               }
                break;
 
        case WM1811:
                wm8994->hubs.dcs_readback_mode = 2;
                wm8994->hubs.no_series_update = 1;
                wm8994->hubs.hp_startup_mode = 1;
-               wm8994->hubs.no_cache_class_w = true;
+               wm8994->hubs.no_cache_dac_hp_direct = true;
+               wm8994->fll_byp = true;
 
                switch (wm8994->revision) {
                case 0:
@@ -4010,7 +3950,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                break;
        }
 
-       wm8994_update_class_w(codec);
+       wm8994->hubs.check_class_w_digital = wm8994_check_class_w_digital;
+       wm_hubs_update_class_w(codec);
 
        wm8994_handle_pdata(wm8994);
 
@@ -4075,7 +4016,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                                          ARRAY_SIZE(wm8994_dac_widgets));
                break;
        }
-               
 
        wm_hubs_add_analogue_routes(codec, 0, 0);
        snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
@@ -4140,7 +4080,7 @@ err_irq:
        return ret;
 }
 
-static int  wm8994_codec_remove(struct snd_soc_codec *codec)
+static int wm8994_codec_remove(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = wm8994->wm8994;
@@ -4181,14 +4121,10 @@ static int  wm8994_codec_remove(struct snd_soc_codec *codec)
                        free_irq(wm8994->micdet_irq, wm8994);
                break;
        }
-       if (wm8994->mbc)
-               release_firmware(wm8994->mbc);
-       if (wm8994->mbc_vss)
-               release_firmware(wm8994->mbc_vss);
-       if (wm8994->enh_eq)
-               release_firmware(wm8994->enh_eq);
+       release_firmware(wm8994->mbc);
+       release_firmware(wm8994->mbc_vss);
+       release_firmware(wm8994->enh_eq);
        kfree(wm8994->retune_mobile_texts);
-
        return 0;
 }
 
index c724112998d87038fc55a219ae9b3eea66e1032f..d77e06f0a6751f7a1d4394b90324916b6085a34d 100644 (file)
@@ -12,6 +12,7 @@
 #include <sound/soc.h>
 #include <linux/firmware.h>
 #include <linux/completion.h>
+#include <linux/workqueue.h>
 
 #include "wm_hubs.h"
 
@@ -79,6 +80,7 @@ struct wm8994_priv {
        struct wm8994_fll_config fll[2], fll_suspend[2];
        struct completion fll_locked[2];
        bool fll_locked_irq;
+       bool fll_byp;
 
        int vmid_refcount;
        int active_refcount;
@@ -126,6 +128,7 @@ struct wm8994_priv {
 
        struct mutex accdet_lock;
        struct wm8994_micdet micdet[2];
+       struct delayed_work mic_work;
        bool mic_detecting;
        bool jack_mic;
        int btn_mask;
index 1fd635494045f71e44731e1abe7959b980a33b45..8af422e38fd060118968eb6f3bf62d707b32584e 100644 (file)
@@ -1770,7 +1770,13 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
+               break;
        case SND_SOC_BIAS_PREPARE:
+               /* Put the MICBIASes into regulating mode */
+               snd_soc_update_bits(codec, WM8996_MICBIAS_1,
+                                   WM8996_MICB1_MODE, 0);
+               snd_soc_update_bits(codec, WM8996_MICBIAS_2,
+                                   WM8996_MICB2_MODE, 0);
                break;
 
        case SND_SOC_BIAS_STANDBY:
@@ -1793,6 +1799,12 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
                        regcache_cache_only(codec->control_data, false);
                        regcache_sync(codec->control_data);
                }
+
+               /* Bypass the MICBIASes for lowest power */
+               snd_soc_update_bits(codec, WM8996_MICBIAS_1,
+                                   WM8996_MICB1_MODE, WM8996_MICB1_MODE);
+               snd_soc_update_bits(codec, WM8996_MICBIAS_2,
+                                   WM8996_MICB2_MODE, WM8996_MICB2_MODE);
                break;
 
        case SND_SOC_BIAS_OFF:
index 076c126ed9b1812b63cc186138859a43832a8b9e..9328270df16cfcc91cb758b65effa6c9607ea9c3 100644 (file)
@@ -774,7 +774,7 @@ static const struct snd_soc_dapm_widget wm9081_dapm_widgets[] = {
 SND_SOC_DAPM_INPUT("IN1"),
 SND_SOC_DAPM_INPUT("IN2"),
 
-SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM9081_POWER_MANAGEMENT, 0, 0),
+SND_SOC_DAPM_DAC("DAC", NULL, WM9081_POWER_MANAGEMENT, 0, 0),
 
 SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0,
                             mixer, ARRAY_SIZE(mixer)),
@@ -799,6 +799,7 @@ SND_SOC_DAPM_SUPPLY("TSENSE", WM9081_POWER_MANAGEMENT, 7, 0, NULL, 0),
 static const struct snd_soc_dapm_route wm9081_audio_paths[] = {
        { "DAC", NULL, "CLK_SYS" },
        { "DAC", NULL, "CLK_DSP" },
+       { "DAC", NULL, "AIF" },
 
        { "Mixer", "IN1 Switch", "IN1" },
        { "Mixer", "IN2 Switch", "IN2" },
@@ -1252,7 +1253,7 @@ static const struct snd_soc_dai_ops wm9081_dai_ops = {
 static struct snd_soc_dai_driver wm9081_dai = {
        .name = "wm9081-hifi",
        .playback = {
-               .stream_name = "HiFi Playback",
+               .stream_name = "AIF",
                .channels_min = 1,
                .channels_max = 2,
                .rates = WM9081_RATES,
index cacc6a86b46f05b1fd5ea54b08fae3d4ad7eb4be..e8e782a0c78d0791b88d509ae5fa33c9e6a77840 100644 (file)
@@ -236,9 +236,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
 static int ac97_prepare(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        int reg;
        u16 vra;
 
@@ -250,7 +248,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
        else
                reg = AC97_PCM_LR_ADC_RATE;
 
-       return ac97_write(codec, reg, runtime->rate);
+       return ac97_write(codec, reg, substream->runtime->rate);
 }
 
 #define WM9705_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
index b342ae50bcd6e294b5fe017f2bb7cdb77f4440ab..a1541414d904d0ac96dd5d9715d6205b941ad614 100644 (file)
@@ -467,11 +467,10 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
 static int ac97_prepare(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec =rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        int reg;
        u16 vra;
+       struct snd_pcm_runtime *runtime = substream->runtime;
 
        vra = ac97_read(codec, AC97_EXTENDED_STATUS);
        ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
@@ -487,10 +486,9 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
 static int ac97_aux_prepare(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        u16 vra, xsle;
+       struct snd_pcm_runtime *runtime = substream->runtime;
 
        vra = ac97_read(codec, AC97_EXTENDED_STATUS);
        ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
index 6c028c4706016e1f56bb36114d6ee9108e597736..dfe957a47f29b02073de0de666de9cfab51c96e4 100644 (file)
@@ -109,12 +109,103 @@ irqreturn_t wm_hubs_dcs_done(int irq, void *data)
 }
 EXPORT_SYMBOL_GPL(wm_hubs_dcs_done);
 
+static bool wm_hubs_dac_hp_direct(struct snd_soc_codec *codec)
+{
+       int reg;
+
+       /* If we're going via the mixer we'll need to do additional checks */
+       reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER1);
+       if (!(reg & WM8993_DACL_TO_HPOUT1L)) {
+               if (reg & ~WM8993_DACL_TO_MIXOUTL) {
+                       dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
+                                reg & ~WM8993_DACL_TO_HPOUT1L);
+                       return false;
+               } else {
+                       dev_vdbg(codec->dev, "HPL connected to mixer\n");
+               }
+       } else {
+               dev_vdbg(codec->dev, "HPL connected to DAC\n");
+       }
+
+       reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER2);
+       if (!(reg & WM8993_DACR_TO_HPOUT1R)) {
+               if (reg & ~WM8993_DACR_TO_MIXOUTR) {
+                       dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
+                                reg & ~WM8993_DACR_TO_HPOUT1R);
+                       return false;
+               } else {
+                       dev_vdbg(codec->dev, "HPR connected to mixer\n");
+               }
+       } else {
+               dev_vdbg(codec->dev, "HPR connected to DAC\n");
+       }
+
+       return true;
+}
+
+struct wm_hubs_dcs_cache {
+       struct list_head list;
+       unsigned int left;
+       unsigned int right;
+       u16 dcs_cfg;
+};
+
+static bool wm_hubs_dcs_cache_get(struct snd_soc_codec *codec,
+                                 struct wm_hubs_dcs_cache **entry)
+{
+       struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+       struct wm_hubs_dcs_cache *cache;
+       unsigned int left, right;
+
+       left = snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME);
+       left &= WM8993_HPOUT1L_VOL_MASK;
+
+       right = snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME);
+       right &= WM8993_HPOUT1R_VOL_MASK;
+
+       list_for_each_entry(cache, &hubs->dcs_cache, list) {
+               if (cache->left != left || cache->right != right)
+                       continue;
+
+               *entry = cache;
+               return true;
+       }
+
+       return false;
+}
+
+static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
+{
+       struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+       struct wm_hubs_dcs_cache *cache;
+
+       if (hubs->no_cache_dac_hp_direct)
+               return;
+
+       cache = devm_kzalloc(codec->dev, sizeof(*cache), GFP_KERNEL);
+       if (!cache) {
+               dev_err(codec->dev, "Failed to allocate DCS cache entry\n");
+               return;
+       }
+
+       cache->left = snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME);
+       cache->left &= WM8993_HPOUT1L_VOL_MASK;
+
+       cache->right = snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME);
+       cache->right &= WM8993_HPOUT1R_VOL_MASK;
+
+       cache->dcs_cfg = dcs_cfg;
+
+       list_add_tail(&cache->list, &hubs->dcs_cache);
+}
+
 /*
  * Startup calibration of the DC servo
  */
 static void calibrate_dc_servo(struct snd_soc_codec *codec)
 {
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+       struct wm_hubs_dcs_cache *cache;
        s8 offset;
        u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg;
 
@@ -129,10 +220,11 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
 
        /* If we're using a digital only path and have a previously
         * callibrated DC servo offset stored then use that. */
-       if (hubs->class_w && hubs->class_w_dcs) {
-               dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
-                       hubs->class_w_dcs);
-               snd_soc_write(codec, dcs_reg, hubs->class_w_dcs);
+       if (wm_hubs_dac_hp_direct(codec) &&
+           wm_hubs_dcs_cache_get(codec, &cache)) {
+               dev_dbg(codec->dev, "Using cached DCS offset %x for %d,%d\n",
+                       cache->dcs_cfg, cache->left, cache->right);
+               snd_soc_write(codec, dcs_reg, cache->dcs_cfg);
                wait_for_dc_servo(codec,
                                  WM8993_DCS_TRIG_DAC_WR_0 |
                                  WM8993_DCS_TRIG_DAC_WR_1);
@@ -207,8 +299,8 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
 
        /* Save the callibrated offset if we're in class W mode and
         * therefore don't have any analogue signal mixed in. */
-       if (hubs->class_w && !hubs->no_cache_class_w)
-               hubs->class_w_dcs = dcs_cfg;
+       if (wm_hubs_dac_hp_direct(codec))
+               wm_hubs_dcs_cache_set(codec, dcs_cfg);
 }
 
 /*
@@ -223,9 +315,6 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
 
        ret = snd_soc_put_volsw(kcontrol, ucontrol);
 
-       /* Updating the analogue gains invalidates the DC servo cache */
-       hubs->class_w_dcs = 0;
-
        /* If we're applying an offset correction then updating the
         * callibration would be likely to introduce further offsets. */
        if (hubs->dcs_codes_l || hubs->dcs_codes_r || hubs->no_series_update)
@@ -530,6 +619,86 @@ static int lineout_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+void wm_hubs_update_class_w(struct snd_soc_codec *codec)
+{
+       struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+       int enable = WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ;
+
+       if (!wm_hubs_dac_hp_direct(codec))
+               enable = false;
+
+       if (hubs->check_class_w_digital && !hubs->check_class_w_digital(codec))
+               enable = false;
+
+       dev_vdbg(codec->dev, "Class W %s\n", enable ? "enabled" : "disabled");
+
+       snd_soc_update_bits(codec, WM8993_CLASS_W_0,
+                           WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
+}
+EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
+
+#define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_dapm_get_volsw, .put = class_w_put_volsw, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = widget->codec;
+       int ret;
+
+       ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+       wm_hubs_update_class_w(codec);
+
+       return ret;
+}
+
+#define WM_HUBS_ENUM_W(xname, xenum) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_enum_double, \
+       .get = snd_soc_dapm_get_enum_double, \
+       .put = class_w_put_double, \
+       .private_value = (unsigned long)&xenum }
+
+static int class_w_put_double(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = widget->codec;
+       int ret;
+
+       ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+       wm_hubs_update_class_w(codec);
+
+       return ret;
+}
+
+static const char *hp_mux_text[] = {
+       "Mixer",
+       "DAC",
+};
+
+static const struct soc_enum hpl_enum =
+       SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text);
+
+const struct snd_kcontrol_new wm_hubs_hpl_mux =
+       WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum);
+EXPORT_SYMBOL_GPL(wm_hubs_hpl_mux);
+
+static const struct soc_enum hpr_enum =
+       SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text);
+
+const struct snd_kcontrol_new wm_hubs_hpr_mux =
+       WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum);
+EXPORT_SYMBOL_GPL(wm_hubs_hpr_mux);
+
 static const struct snd_kcontrol_new in1l_pga[] = {
 SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
 SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
@@ -561,25 +730,25 @@ SOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0),
 };
 
 static const struct snd_kcontrol_new left_output_mixer[] = {
-SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
-SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
-SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
-SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
-SOC_DAPM_SINGLE("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
-SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
-SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
+WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
+WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
+WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
+WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
+WM_HUBS_SINGLE_W("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
+WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
+WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
+WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
 };
 
 static const struct snd_kcontrol_new right_output_mixer[] = {
-SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
-SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
-SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
-SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
-SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
-SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
-SOC_DAPM_SINGLE("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
+WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
+WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
+WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
+WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
+WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
+WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
+WM_HUBS_SINGLE_W("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
+WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
 };
 
 static const struct snd_kcontrol_new earpiece_mixer[] = {
@@ -943,6 +1112,7 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
+       INIT_LIST_HEAD(&hubs->dcs_cache);
        init_completion(&hubs->dcs_done);
 
        snd_soc_dapm_add_routes(dapm, analogue_routes,
index 5705276f49438f396eb5252b8bb65514cdfb8498..da2dc899ce6d58df7a4f34bd6f589ead6e4b2f3f 100644 (file)
@@ -16,6 +16,8 @@
 
 #include <linux/completion.h>
 #include <linux/interrupt.h>
+#include <linux/list.h>
+#include <sound/control.h>
 
 struct snd_soc_codec;
 
@@ -30,9 +32,9 @@ struct wm_hubs_data {
        int series_startup;
        int no_series_update;
 
-       bool no_cache_class_w;
-       bool class_w;
-       u16 class_w_dcs;
+       bool no_cache_dac_hp_direct;
+       struct list_head dcs_cache;
+       bool (*check_class_w_digital)(struct snd_soc_codec *);
 
        bool lineout1_se;
        bool lineout1n_ena;
@@ -58,5 +60,9 @@ extern irqreturn_t wm_hubs_dcs_done(int irq, void *data);
 extern void wm_hubs_vmid_ena(struct snd_soc_codec *codec);
 extern void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
                                   enum snd_soc_bias_level level);
+extern void wm_hubs_update_class_w(struct snd_soc_codec *codec);
+
+extern const struct snd_kcontrol_new wm_hubs_hpl_mux;
+extern const struct snd_kcontrol_new wm_hubs_hpr_mux;
 
 #endif
index 0678637abd66c6110524fa7bd3ee17d8e4abf8d9..bdffab33e1609c6648a0c5c3bdd33629ee852cee 100644 (file)
  * struct ep93xx_ac97_info - EP93xx AC97 controller info structure
  * @lock: mutex serializing access to the bus (slot 1 & 2 ops)
  * @dev: pointer to the platform device dev structure
- * @mem: physical memory resource for the registers
  * @regs: mapped AC97 controller registers
- * @irq: AC97 interrupt number
  * @done: bus ops wait here for an interrupt
  */
 struct ep93xx_ac97_info {
        struct mutex            lock;
        struct device           *dev;
-       struct resource         *mem;
        void __iomem            *regs;
-       int                     irq;
        struct completion       done;
 };
 
@@ -359,66 +355,50 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = {
 static int __devinit ep93xx_ac97_probe(struct platform_device *pdev)
 {
        struct ep93xx_ac97_info *info;
+       struct resource *res;
+       unsigned int irq;
        int ret;
 
-       info = kzalloc(sizeof(struct ep93xx_ac97_info), GFP_KERNEL);
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
-       dev_set_drvdata(&pdev->dev, info);
-
-       mutex_init(&info->lock);
-       init_completion(&info->done);
-       info->dev = &pdev->dev;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
 
-       info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!info->mem) {
-               ret = -ENXIO;
-               goto fail_free_info;
-       }
+       info->regs = devm_request_and_ioremap(&pdev->dev, res);
+       if (!info->regs)
+               return -ENXIO;
 
-       info->irq = platform_get_irq(pdev, 0);
-       if (!info->irq) {
-               ret = -ENXIO;
-               goto fail_free_info;
-       }
+       irq = platform_get_irq(pdev, 0);
+       if (!irq)
+               return -ENODEV;
 
-       if (!request_mem_region(info->mem->start, resource_size(info->mem),
-                               pdev->name)) {
-               ret = -EBUSY;
-               goto fail_free_info;
-       }
+       ret = devm_request_irq(&pdev->dev, irq, ep93xx_ac97_interrupt,
+                              IRQF_TRIGGER_HIGH, pdev->name, info);
+       if (ret)
+               goto fail;
 
-       info->regs = ioremap(info->mem->start, resource_size(info->mem));
-       if (!info->regs) {
-               ret = -ENOMEM;
-               goto fail_release_mem;
-       }
+       dev_set_drvdata(&pdev->dev, info);
 
-       ret = request_irq(info->irq, ep93xx_ac97_interrupt, IRQF_TRIGGER_HIGH,
-                         pdev->name, info);
-       if (ret)
-               goto fail_unmap_mem;
+       mutex_init(&info->lock);
+       init_completion(&info->done);
+       info->dev = &pdev->dev;
 
        ep93xx_ac97_info = info;
        platform_set_drvdata(pdev, info);
 
        ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
        if (ret)
-               goto fail_free_irq;
+               goto fail;
 
        return 0;
 
-fail_free_irq:
+fail:
        platform_set_drvdata(pdev, NULL);
-       free_irq(info->irq, info);
-fail_unmap_mem:
-       iounmap(info->regs);
-fail_release_mem:
-       release_mem_region(info->mem->start, resource_size(info->mem));
-fail_free_info:
-       kfree(info);
-
+       ep93xx_ac97_info = NULL;
+       dev_set_drvdata(&pdev->dev, NULL);
        return ret;
 }
 
@@ -431,11 +411,9 @@ static int __devexit ep93xx_ac97_remove(struct platform_device *pdev)
        /* disable the AC97 controller */
        ep93xx_ac97_write_reg(info, AC97GCR, 0);
 
-       free_irq(info->irq, info);
-       iounmap(info->regs);
-       release_mem_region(info->mem->start, resource_size(info->mem));
        platform_set_drvdata(pdev, NULL);
-       kfree(info);
+       ep93xx_ac97_info = NULL;
+       dev_set_drvdata(&pdev->dev, NULL);
 
        return 0;
 }
index f7a62348e3fe022a3bc7ba4faa06b9e19f5c23a0..8df8f6dc474fc9bdfb0a70672b8121c201f247ef 100644 (file)
@@ -63,7 +63,6 @@ struct ep93xx_i2s_info {
        struct clk                      *sclk;
        struct clk                      *lrclk;
        struct ep93xx_pcm_dma_params    *dma_params;
-       struct resource                 *mem;
        void __iomem                    *regs;
 };
 
@@ -373,38 +372,22 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
        struct resource *res;
        int err;
 
-       info = kzalloc(sizeof(struct ep93xx_i2s_info), GFP_KERNEL);
-       if (!info) {
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       dev_set_drvdata(&pdev->dev, info);
-       info->dma_params = ep93xx_i2s_dma_params;
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               err = -ENODEV;
-               goto fail_free_info;
-       }
+       if (!res)
+               return -ENODEV;
 
-       info->mem = request_mem_region(res->start, resource_size(res),
-                                      pdev->name);
-       if (!info->mem) {
-               err = -EBUSY;
-               goto fail_free_info;
-       }
-
-       info->regs = ioremap(info->mem->start, resource_size(info->mem));
-       if (!info->regs) {
-               err = -ENXIO;
-               goto fail_release_mem;
-       }
+       info->regs = devm_request_and_ioremap(&pdev->dev, res);
+       if (!info->regs)
+               return -ENXIO;
 
        info->mclk = clk_get(&pdev->dev, "mclk");
        if (IS_ERR(info->mclk)) {
                err = PTR_ERR(info->mclk);
-               goto fail_unmap_mem;
+               goto fail;
        }
 
        info->sclk = clk_get(&pdev->dev, "sclk");
@@ -419,6 +402,9 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
                goto fail_put_sclk;
        }
 
+       dev_set_drvdata(&pdev->dev, info);
+       info->dma_params = ep93xx_i2s_dma_params;
+
        err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
        if (err)
                goto fail_put_lrclk;
@@ -426,17 +412,12 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
        return 0;
 
 fail_put_lrclk:
+       dev_set_drvdata(&pdev->dev, NULL);
        clk_put(info->lrclk);
 fail_put_sclk:
        clk_put(info->sclk);
 fail_put_mclk:
        clk_put(info->mclk);
-fail_unmap_mem:
-       iounmap(info->regs);
-fail_release_mem:
-       release_mem_region(info->mem->start, resource_size(info->mem));
-fail_free_info:
-       kfree(info);
 fail:
        return err;
 }
@@ -446,12 +427,10 @@ static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
        struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
 
        snd_soc_unregister_dai(&pdev->dev);
+       dev_set_drvdata(&pdev->dev, NULL);
        clk_put(info->lrclk);
        clk_put(info->sclk);
        clk_put(info->mclk);
-       iounmap(info->regs);
-       release_mem_region(info->mem->start, resource_size(info->mem));
-       kfree(info);
        return 0;
 }
 
index d754d34d68a68a83b95b080ee9bf0baebeaea0ce..d70133086ac330456ec931b74afce38dd36a3b54 100644 (file)
@@ -1,18 +1,31 @@
-config SND_MPC52xx_DMA
+config SND_SOC_FSL_SSI
        tristate
 
-# ASoC platform support for the Freescale PowerPC SOCs that have an SSI and
-# an Elo DMA controller, such as the MPC8610 and P1022.  You will still need to
-# select a platform driver and a codec driver.
-config SND_SOC_POWERPC_SSI
+config SND_SOC_FSL_UTILS
        tristate
+
+menuconfig SND_POWERPC_SOC
+       tristate "SoC Audio for Freescale PowerPC CPUs"
        depends on FSL_SOC
+       help
+         Say Y or M if you want to add support for codecs attached to
+         the PowerPC CPUs.
+
+if SND_POWERPC_SOC
+
+config SND_MPC52xx_DMA
+       tristate
+
+config SND_SOC_POWERPC_DMA
+       tristate
 
 config SND_SOC_MPC8610_HPCD
        tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
        # I2C is necessary for the CS4270 driver
        depends on MPC8610_HPCD && I2C
-       select SND_SOC_POWERPC_SSI
+       select SND_SOC_FSL_SSI
+       select SND_SOC_FSL_UTILS
+       select SND_SOC_POWERPC_DMA
        select SND_SOC_CS4270
        select SND_SOC_CS4270_VD33_ERRATA
        default y if MPC8610_HPCD
@@ -23,7 +36,9 @@ config SND_SOC_P1022_DS
        tristate "ALSA SoC support for the Freescale P1022 DS board"
        # I2C is necessary for the WM8776 driver
        depends on P1022_DS && I2C
-       select SND_SOC_POWERPC_SSI
+       select SND_SOC_FSL_SSI
+       select SND_SOC_FSL_UTILS
+       select SND_SOC_POWERPC_DMA
        select SND_SOC_WM8776
        default y if P1022_DS
        help
@@ -65,3 +80,103 @@ config SND_MPC52xx_SOC_EFIKA
        help
          Say Y if you want to add support for sound on the Efika.
 
+endif # SND_POWERPC_SOC
+
+menuconfig SND_IMX_SOC
+       tristate "SoC Audio for Freescale i.MX CPUs"
+       depends on ARCH_MXC
+       help
+         Say Y or M if you want to add support for codecs attached to
+         the i.MX CPUs.
+
+if SND_IMX_SOC
+
+config SND_SOC_IMX_SSI
+       tristate
+
+config SND_SOC_IMX_PCM
+       tristate
+
+config SND_SOC_IMX_PCM_FIQ
+       tristate
+       select FIQ
+       select SND_SOC_IMX_PCM
+
+config SND_SOC_IMX_PCM_DMA
+       tristate
+       select SND_SOC_DMAENGINE_PCM
+       select SND_SOC_IMX_PCM
+
+config SND_SOC_IMX_AUDMUX
+       tristate
+
+config SND_MXC_SOC_WM1133_EV1
+       tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted"
+       depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
+       select SND_SOC_WM8350
+       select SND_SOC_IMX_PCM_FIQ
+       select SND_SOC_IMX_AUDMUX
+       select SND_SOC_IMX_SSI
+       help
+         Enable support for audio on the i.MX31ADS with the WM1133-EV1
+         PMIC board with WM8835x fitted.
+
+config SND_SOC_MX27VIS_AIC32X4
+       tristate "SoC audio support for Visstrim M10 boards"
+       depends on MACH_IMX27_VISSTRIM_M10 && I2C
+       select SND_SOC_TLV320AIC32X4
+       select SND_SOC_IMX_PCM_DMA
+       select SND_SOC_IMX_AUDMUX
+       select SND_SOC_IMX_SSI
+       help
+         Say Y if you want to add support for SoC audio on Visstrim SM10
+         board with TLV320AIC32X4 codec.
+
+config SND_SOC_PHYCORE_AC97
+       tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
+       depends on MACH_PCM043 || MACH_PCA100
+       select SND_SOC_AC97_BUS
+       select SND_SOC_WM9712
+       select SND_SOC_IMX_PCM_FIQ
+       select SND_SOC_IMX_AUDMUX
+       select SND_SOC_IMX_SSI
+       help
+         Say Y if you want to add support for SoC audio on Phytec phyCORE
+         and phyCARD boards in AC97 mode
+
+config SND_SOC_EUKREA_TLV320
+       tristate "Eukrea TLV320"
+       depends on MACH_EUKREA_MBIMX27_BASEBOARD \
+               || MACH_EUKREA_MBIMXSD25_BASEBOARD \
+               || MACH_EUKREA_MBIMXSD35_BASEBOARD \
+               || MACH_EUKREA_MBIMXSD51_BASEBOARD
+       depends on I2C
+       select SND_SOC_TLV320AIC23
+       select SND_SOC_IMX_PCM_FIQ
+       select SND_SOC_IMX_AUDMUX
+       select SND_SOC_IMX_SSI
+       help
+         Enable I2S based access to the TLV320AIC23B codec attached
+         to the SSI interface
+
+config SND_SOC_IMX_SGTL5000
+       tristate "SoC Audio support for i.MX boards with sgtl5000"
+       depends on OF && I2C
+       select SND_SOC_SGTL5000
+       select SND_SOC_IMX_PCM_DMA
+       select SND_SOC_IMX_AUDMUX
+       select SND_SOC_FSL_SSI
+       select SND_SOC_FSL_UTILS
+       help
+         Say Y if you want to add support for SoC audio on an i.MX board with
+         a sgtl5000 codec.
+
+config SND_SOC_IMX_MC13783
+       tristate "SoC Audio support for I.MX boards with mc13783"
+       depends on MFD_MC13783
+       select SND_SOC_IMX_SSI
+       select SND_SOC_IMX_AUDMUX
+       select SND_SOC_MC13783
+       select SND_SOC_IMX_PCM_DMA
+
+endif # SND_IMX_SOC
index b4a38c0ac58c35445e8efb91b66cf4f8c7a92cde..5f3cf3f52ea03e16a1a374ca530f6daec7a2ed35 100644 (file)
@@ -8,8 +8,11 @@ obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o
 
 # Freescale PowerPC SSI/DMA Platform Support
 snd-soc-fsl-ssi-objs := fsl_ssi.o
+snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
-obj-$(CONFIG_SND_SOC_POWERPC_SSI) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
+obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
+obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
+obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
@@ -20,3 +23,29 @@ obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o
 obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
 obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
 
+# i.MX Platform Support
+snd-soc-imx-ssi-objs := imx-ssi.o
+snd-soc-imx-audmux-objs := imx-audmux.o
+
+obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
+obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
+
+obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o
+snd-soc-imx-pcm-y := imx-pcm.o
+snd-soc-imx-pcm-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o
+snd-soc-imx-pcm-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o
+
+# i.MX Machine Support
+snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
+snd-soc-phycore-ac97-objs := phycore-ac97.o
+snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
+snd-soc-wm1133-ev1-objs := wm1133-ev1.o
+snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
+snd-soc-imx-mc13783-objs := imx-mc13783.o
+
+obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
+obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
+obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
+obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
+obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
+obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
similarity index 99%
rename from sound/soc/imx/eukrea-tlv320.c
rename to sound/soc/fsl/eukrea-tlv320.c
index 7d4475cfdb242bf6da4a74393a45c7b80b053d33..efb9ede01208f8cbe6f66b597f1253ecd780e96f 100644 (file)
@@ -7,7 +7,7 @@
  * which is Copyright 2009 Simtec Electronics
  * and on sound/soc/imx/phycore-ac97.c which is
  * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
- * 
+ *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
  *  Free Software Foundation;  either version 2 of the  License, or (at your
index 2eb407fa3b4893e2a43c5adbf7ba7f3bcc1762a7..4ed2afd47782cba1667cf109d3c63c6d501ba2a1 100644 (file)
  */
 
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 
 #include <sound/core.h>
 #include <sound/soc.h>
 
 #include "fsl_ssi.h"
+#include "imx-pcm.h"
+
+#ifdef PPC
+#define read_ssi(addr)                  in_be32(addr)
+#define write_ssi(val, addr)            out_be32(addr, val)
+#define write_ssi_mask(addr, clear, set) clrsetbits_be32(addr, clear, set)
+#elif defined ARM
+#define read_ssi(addr)                  readl(addr)
+#define write_ssi(val, addr)            writel(val, addr)
+/*
+ * FIXME: Proper locking should be added at write_ssi_mask caller level
+ * to ensure this register read/modify/write sequence is race free.
+ */
+static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
+{
+       u32 val = readl(addr);
+       val = (val & ~clear) | set;
+       writel(val, addr);
+}
+#endif
 
 /**
  * FSLSSI_I2S_RATES: sample rates supported by the I2S
@@ -94,6 +118,13 @@ struct fsl_ssi_private {
        struct device_attribute dev_attr;
        struct platform_device *pdev;
 
+       bool new_binding;
+       bool ssi_on_imx;
+       struct clk *clk;
+       struct platform_device *imx_pcm_pdev;
+       struct imx_pcm_dma_params dma_params_tx;
+       struct imx_pcm_dma_params dma_params_rx;
+
        struct {
                unsigned int rfrc;
                unsigned int tfrc;
@@ -145,7 +176,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
           were interrupted for.  We mask it with the Interrupt Enable register
           so that we only check for events that we're interested in.
         */
-       sisr = in_be32(&ssi->sisr) & SIER_FLAGS;
+       sisr = read_ssi(&ssi->sisr) & SIER_FLAGS;
 
        if (sisr & CCSR_SSI_SISR_RFRC) {
                ssi_private->stats.rfrc++;
@@ -260,7 +291,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
 
        /* Clear the bits that we set */
        if (sisr2)
-               out_be32(&ssi->sisr, sisr2);
+               write_ssi(sisr2, &ssi->sisr);
 
        return ret;
 }
@@ -295,7 +326,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                 * SSI needs to be disabled before updating the registers we set
                 * here.
                 */
-               clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+               write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
 
                /*
                 * Program the SSI into I2S Slave Non-Network Synchronous mode.
@@ -303,20 +334,18 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                 *
                 * FIXME: Little-endian samples require a different shift dir
                 */
-               clrsetbits_be32(&ssi->scr,
+               write_ssi_mask(&ssi->scr,
                        CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
                        CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
                        | (synchronous ? CCSR_SSI_SCR_SYN : 0));
 
-               out_be32(&ssi->stcr,
-                        CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
+               write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
                         CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
-                        CCSR_SSI_STCR_TSCKP);
+                        CCSR_SSI_STCR_TSCKP, &ssi->stcr);
 
-               out_be32(&ssi->srcr,
-                        CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
+               write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
                         CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
-                        CCSR_SSI_SRCR_RSCKP);
+                        CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
 
                /*
                 * The DC and PM bits are only used if the SSI is the clock
@@ -324,7 +353,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                 */
 
                /* Enable the interrupts and DMA requests */
-               out_be32(&ssi->sier, SIER_FLAGS);
+               write_ssi(SIER_FLAGS, &ssi->sier);
 
                /*
                 * Set the watermark for transmit FIFI 0 and receive FIFO 0. We
@@ -339,9 +368,9 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                 * make this value larger (and maybe we should), but this way
                 * data will be written to memory as soon as it's available.
                 */
-               out_be32(&ssi->sfcsr,
-                       CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
-                       CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2));
+               write_ssi(CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
+                       CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2),
+                       &ssi->sfcsr);
 
                /*
                 * We keep the SSI disabled because if we enable it, then the
@@ -393,6 +422,12 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                ssi_private->second_stream = substream;
        }
 
+       if (ssi_private->ssi_on_imx)
+               snd_soc_dai_set_dma_data(dai, substream,
+                       (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+                               &ssi_private->dma_params_tx :
+                               &ssi_private->dma_params_rx);
+
        return 0;
 }
 
@@ -417,7 +452,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
        unsigned int sample_size =
                snd_pcm_format_width(params_format(hw_params));
        u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
-       int enabled = in_be32(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
+       int enabled = read_ssi(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
 
        /*
         * If we're in synchronous mode, and the SSI is already enabled,
@@ -439,9 +474,9 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
        /* In synchronous mode, the SSI uses STCCR for capture */
        if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
            ssi_private->cpu_dai_drv.symmetric_rates)
-               clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+               write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
        else
-               clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+               write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
 
        return 0;
 }
@@ -466,19 +501,19 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       setbits32(&ssi->scr,
+                       write_ssi_mask(&ssi->scr, 0,
                                CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
                else
-                       setbits32(&ssi->scr,
+                       write_ssi_mask(&ssi->scr, 0,
                                CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
+                       write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0);
                else
-                       clrbits32(&ssi->scr, CCSR_SSI_SCR_RE);
+                       write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0);
                break;
 
        default:
@@ -510,7 +545,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
        if (!ssi_private->first_stream) {
                struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
 
-               clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+               write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
        }
 }
 
@@ -622,12 +657,6 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
        if (!of_device_is_available(np))
                return -ENODEV;
 
-       /* Check for a codec-handle property. */
-       if (!of_get_property(np, "codec-handle", NULL)) {
-               dev_err(&pdev->dev, "missing codec-handle property\n");
-               return -ENODEV;
-       }
-
        /* We only support the SSI in "I2S Slave" mode */
        sprop = of_get_property(np, "fsl,mode", NULL);
        if (!sprop || strcmp(sprop, "i2s-slave")) {
@@ -692,6 +721,50 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
                 /* Older 8610 DTs didn't have the fifo-depth property */
                ssi_private->fifo_depth = 8;
 
+       if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
+               u32 dma_events[2];
+               ssi_private->ssi_on_imx = true;
+
+               ssi_private->clk = clk_get(&pdev->dev, NULL);
+               if (IS_ERR(ssi_private->clk)) {
+                       ret = PTR_ERR(ssi_private->clk);
+                       dev_err(&pdev->dev, "could not get clock: %d\n", ret);
+                       goto error_irq;
+               }
+               clk_prepare_enable(ssi_private->clk);
+
+               /*
+                * We have burstsize be "fifo_depth - 2" to match the SSI
+                * watermark setting in fsl_ssi_startup().
+                */
+               ssi_private->dma_params_tx.burstsize =
+                       ssi_private->fifo_depth - 2;
+               ssi_private->dma_params_rx.burstsize =
+                       ssi_private->fifo_depth - 2;
+               ssi_private->dma_params_tx.dma_addr =
+                       ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0);
+               ssi_private->dma_params_rx.dma_addr =
+                       ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0);
+               /*
+                * TODO: This is a temporary solution and should be changed
+                * to use generic DMA binding later when the helplers get in.
+                */
+               ret = of_property_read_u32_array(pdev->dev.of_node,
+                                       "fsl,ssi-dma-events", dma_events, 2);
+               if (ret) {
+                       dev_err(&pdev->dev, "could not get dma events\n");
+                       goto error_clk;
+               }
+               ssi_private->dma_params_tx.dma = dma_events[0];
+               ssi_private->dma_params_rx.dma = dma_events[1];
+
+               ssi_private->dma_params_tx.shared_peripheral =
+                               of_device_is_compatible(of_get_parent(np),
+                                                       "fsl,spba-bus");
+               ssi_private->dma_params_rx.shared_peripheral =
+                               ssi_private->dma_params_tx.shared_peripheral;
+       }
+
        /* Initialize the the device_attribute structure */
        dev_attr = &ssi_private->dev_attr;
        sysfs_attr_init(&dev_attr->attr);
@@ -715,6 +788,26 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
                goto error_dev;
        }
 
+       if (ssi_private->ssi_on_imx) {
+               ssi_private->imx_pcm_pdev =
+                       platform_device_register_simple("imx-pcm-audio",
+                                                       -1, NULL, 0);
+               if (IS_ERR(ssi_private->imx_pcm_pdev)) {
+                       ret = PTR_ERR(ssi_private->imx_pcm_pdev);
+                       goto error_dev;
+               }
+       }
+
+       /*
+        * If codec-handle property is missing from SSI node, we assume
+        * that the machine driver uses new binding which does not require
+        * SSI driver to trigger machine driver's probe.
+        */
+       if (!of_get_property(np, "codec-handle", NULL)) {
+               ssi_private->new_binding = true;
+               goto done;
+       }
+
        /* Trigger the machine driver's probe function.  The platform driver
         * name of the machine driver is taken from /compatible property of the
         * device tree.  We also pass the address of the CPU DAI driver
@@ -736,15 +829,24 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
                goto error_dai;
        }
 
+done:
        return 0;
 
 error_dai:
+       if (ssi_private->ssi_on_imx)
+               platform_device_unregister(ssi_private->imx_pcm_pdev);
        snd_soc_unregister_dai(&pdev->dev);
 
 error_dev:
        dev_set_drvdata(&pdev->dev, NULL);
        device_remove_file(&pdev->dev, dev_attr);
 
+error_clk:
+       if (ssi_private->ssi_on_imx) {
+               clk_disable_unprepare(ssi_private->clk);
+               clk_put(ssi_private->clk);
+       }
+
 error_irq:
        free_irq(ssi_private->irq, ssi_private);
 
@@ -764,7 +866,13 @@ static int fsl_ssi_remove(struct platform_device *pdev)
 {
        struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
 
-       platform_device_unregister(ssi_private->pdev);
+       if (!ssi_private->new_binding)
+               platform_device_unregister(ssi_private->pdev);
+       if (ssi_private->ssi_on_imx) {
+               platform_device_unregister(ssi_private->imx_pcm_pdev);
+               clk_disable_unprepare(ssi_private->clk);
+               clk_put(ssi_private->clk);
+       }
        snd_soc_unregister_dai(&pdev->dev);
        device_remove_file(&pdev->dev, &ssi_private->dev_attr);
 
@@ -779,6 +887,7 @@ static int fsl_ssi_remove(struct platform_device *pdev)
 
 static const struct of_device_id fsl_ssi_ids[] = {
        { .compatible = "fsl,mpc8610-ssi", },
+       { .compatible = "fsl,imx21-ssi", },
        {}
 };
 MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c
new file mode 100644 (file)
index 0000000..b9e42b5
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * Freescale ALSA SoC Machine driver utility
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, 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.
+ */
+
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <sound/soc.h>
+
+#include "fsl_utils.h"
+
+/**
+ * fsl_asoc_get_dma_channel - determine the dma channel for a SSI node
+ *
+ * @ssi_np: pointer to the SSI device tree node
+ * @name: name of the phandle pointing to the dma channel
+ * @dai: ASoC DAI link pointer to be filled with platform_name
+ * @dma_channel_id: dma channel id to be returned
+ * @dma_id: dma id to be returned
+ *
+ * This function determines the dma and channel id for given SSI node.  It
+ * also discovers the platform_name for the ASoC DAI link.
+ */
+int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
+                            const char *name,
+                            struct snd_soc_dai_link *dai,
+                            unsigned int *dma_channel_id,
+                            unsigned int *dma_id)
+{
+       struct resource res;
+       struct device_node *dma_channel_np, *dma_np;
+       const u32 *iprop;
+       int ret;
+
+       dma_channel_np = of_parse_phandle(ssi_np, name, 0);
+       if (!dma_channel_np)
+               return -EINVAL;
+
+       if (!of_device_is_compatible(dma_channel_np, "fsl,ssi-dma-channel")) {
+               of_node_put(dma_channel_np);
+               return -EINVAL;
+       }
+
+       /* Determine the dev_name for the device_node.  This code mimics the
+        * behavior of of_device_make_bus_id(). We need this because ASoC uses
+        * the dev_name() of the device to match the platform (DMA) device with
+        * the CPU (SSI) device.  It's all ugly and hackish, but it works (for
+        * now).
+        *
+        * dai->platform name should already point to an allocated buffer.
+        */
+       ret = of_address_to_resource(dma_channel_np, 0, &res);
+       if (ret) {
+               of_node_put(dma_channel_np);
+               return ret;
+       }
+       snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
+                (unsigned long long) res.start, dma_channel_np->name);
+
+       iprop = of_get_property(dma_channel_np, "cell-index", NULL);
+       if (!iprop) {
+               of_node_put(dma_channel_np);
+               return -EINVAL;
+       }
+       *dma_channel_id = be32_to_cpup(iprop);
+
+       dma_np = of_get_parent(dma_channel_np);
+       iprop = of_get_property(dma_np, "cell-index", NULL);
+       if (!iprop) {
+               of_node_put(dma_np);
+               return -EINVAL;
+       }
+       *dma_id = be32_to_cpup(iprop);
+
+       of_node_put(dma_np);
+       of_node_put(dma_channel_np);
+
+       return 0;
+}
+EXPORT_SYMBOL(fsl_asoc_get_dma_channel);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Freescale ASoC utility code");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_utils.h b/sound/soc/fsl/fsl_utils.h
new file mode 100644 (file)
index 0000000..b295112
--- /dev/null
@@ -0,0 +1,26 @@
+/**
+ * Freescale ALSA SoC Machine driver utility
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, 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 _FSL_UTILS_H
+#define _FSL_UTILS_H
+
+#define DAI_NAME_SIZE  32
+
+struct snd_soc_dai_link;
+struct device_node;
+
+int fsl_asoc_get_dma_channel(struct device_node *ssi_np, const char *name,
+                            struct snd_soc_dai_link *dai,
+                            unsigned int *dma_channel_id,
+                            unsigned int *dma_id);
+
+#endif /* _FSL_UTILS_H */
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c
new file mode 100644 (file)
index 0000000..f59c349
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * imx-mc13783.c  --  SoC audio for imx based boards with mc13783 codec
+ *
+ * Copyright 2012 Philippe Retornaz, <philippe.retornaz@epfl.ch>
+ *
+ * Heavly based on phycore-mc13783:
+ * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
+
+#include "../codecs/mc13783.h"
+#include "imx-ssi.h"
+#include "imx-audmux.h"
+
+#define FMT_SSI (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \
+               SND_SOC_DAIFMT_CBM_CFM)
+
+static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xfffffffc, 0xfffffffc,
+                                       4, 16);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, MC13783_CLK_CLIA, 26000000, 0);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x0, 0xfffffffc, 2, 16);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops imx_mc13783_hifi_ops = {
+       .hw_params = imx_mc13783_hifi_hw_params,
+};
+
+static struct snd_soc_dai_link imx_mc13783_dai_mc13783[] = {
+       {
+               .name = "MC13783",
+               .stream_name     = "Sound",
+               .codec_dai_name  = "mc13783-hifi",
+               .codec_name      = "mc13783-codec",
+               .cpu_dai_name    = "imx-ssi.0",
+               .platform_name   = "imx-pcm-audio.0",
+               .ops             = &imx_mc13783_hifi_ops,
+               .symmetric_rates = 1,
+               .dai_fmt         = FMT_SSI,
+       },
+};
+
+static const struct snd_soc_dapm_widget imx_mc13783_widget[] = {
+       SND_SOC_DAPM_MIC("Mic", NULL),
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route imx_mc13783_routes[] = {
+       {"Speaker", NULL, "LSP"},
+       {"Headphone", NULL, "HSL"},
+       {"Headphone", NULL, "HSR"},
+
+       {"MC1LIN", NULL, "MC1 Bias"},
+       {"MC2IN", NULL, "MC2 Bias"},
+       {"MC1 Bias", NULL, "Mic"},
+       {"MC2 Bias", NULL, "Mic"},
+};
+
+static struct snd_soc_card imx_mc13783 = {
+       .name           = "imx_mc13783",
+       .dai_link       = imx_mc13783_dai_mc13783,
+       .num_links      = ARRAY_SIZE(imx_mc13783_dai_mc13783),
+       .dapm_widgets   = imx_mc13783_widget,
+       .num_dapm_widgets = ARRAY_SIZE(imx_mc13783_widget),
+       .dapm_routes    = imx_mc13783_routes,
+       .num_dapm_routes = ARRAY_SIZE(imx_mc13783_routes),
+};
+
+static int __devinit imx_mc13783_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       imx_mc13783.dev = &pdev->dev;
+
+       ret = snd_soc_register_card(&imx_mc13783);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+                       ret);
+               return ret;
+       }
+
+       imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4,
+               IMX_AUDMUX_V2_PTCR_SYN,
+               IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) |
+               IMX_AUDMUX_V2_PDCR_MODE(1) |
+               IMX_AUDMUX_V2_PDCR_INMMASK(0xfc));
+       imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0,
+               IMX_AUDMUX_V2_PTCR_SYN |
+               IMX_AUDMUX_V2_PTCR_TFSDIR |
+               IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
+               IMX_AUDMUX_V2_PTCR_TCLKDIR |
+               IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
+               IMX_AUDMUX_V2_PTCR_RFSDIR |
+               IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
+               IMX_AUDMUX_V2_PTCR_RCLKDIR |
+               IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4),
+               IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4));
+
+       return ret;
+}
+
+static int __devexit imx_mc13783_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_card(&imx_mc13783);
+
+       return 0;
+}
+
+static struct platform_driver imx_mc13783_audio_driver = {
+       .driver = {
+               .name = "imx_mc13783",
+               .owner = THIS_MODULE,
+       },
+       .probe = imx_mc13783_probe,
+       .remove = __devexit_p(imx_mc13783_remove)
+};
+
+module_platform_driver(imx_mc13783_audio_driver);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch");
+MODULE_DESCRIPTION("imx with mc13783 codec ALSA SoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx_mc13783");
similarity index 97%
rename from sound/soc/imx/imx-pcm-dma-mx2.c
rename to sound/soc/fsl/imx-pcm-dma.c
index 6b818de2fc03344e6c532067b252655b32c99819..f3c0a5ef35c8afc08a2fb8c48775285985ec421d 100644 (file)
@@ -109,7 +109,8 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
        dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
-       dma_data->peripheral_type = IMX_DMATYPE_SSI;
+       dma_data->peripheral_type = dma_params->shared_peripheral ?
+                                       IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI;
        dma_data->priority = DMA_PRIO_HIGH;
        dma_data->dma_request = dma_params->dma;
 
similarity index 93%
rename from sound/soc/imx/imx-pcm.h
rename to sound/soc/fsl/imx-pcm.h
index b5f5c3acf34d30348342e4ebad2abc4cdf2e214e..83c0ed7d55c9a4710b75846bb0bd5569d257ed0f 100644 (file)
@@ -22,6 +22,7 @@ struct imx_pcm_dma_params {
        int dma;
        unsigned long dma_addr;
        int burstsize;
+       bool shared_peripheral; /* The peripheral is on SPBA bus */
 };
 
 int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
new file mode 100644 (file)
index 0000000..3a729ca
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * 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 <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h>
+#include <linux/clk.h>
+#include <sound/soc.h>
+
+#include "../codecs/sgtl5000.h"
+#include "imx-audmux.h"
+
+#define DAI_NAME_SIZE  32
+
+struct imx_sgtl5000_data {
+       struct snd_soc_dai_link dai;
+       struct snd_soc_card card;
+       char codec_dai_name[DAI_NAME_SIZE];
+       char platform_name[DAI_NAME_SIZE];
+       struct clk *codec_clk;
+       unsigned int clk_frequency;
+};
+
+static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct imx_sgtl5000_data *data = container_of(rtd->card,
+                                       struct imx_sgtl5000_data, card);
+       struct device *dev = rtd->card->dev;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(rtd->codec_dai, SGTL5000_SYSCLK,
+                                    data->clk_frequency, SND_SOC_CLOCK_IN);
+       if (ret) {
+               dev_err(dev, "could not set codec driver clock params\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget imx_sgtl5000_dapm_widgets[] = {
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_LINE("Line In Jack", NULL),
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Line Out Jack", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static int __devinit imx_sgtl5000_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *ssi_np, *codec_np;
+       struct platform_device *ssi_pdev;
+       struct i2c_client *codec_dev;
+       struct imx_sgtl5000_data *data;
+       int int_port, ext_port;
+       int ret;
+
+       ret = of_property_read_u32(np, "mux-int-port", &int_port);
+       if (ret) {
+               dev_err(&pdev->dev, "mux-int-port missing or invalid\n");
+               return ret;
+       }
+       ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
+       if (ret) {
+               dev_err(&pdev->dev, "mux-ext-port missing or invalid\n");
+               return ret;
+       }
+
+       /*
+        * The port numbering in the hardware manual starts at 1, while
+        * the audmux API expects it starts at 0.
+        */
+       int_port--;
+       ext_port--;
+       ret = imx_audmux_v2_configure_port(int_port,
+                       IMX_AUDMUX_V2_PTCR_SYN |
+                       IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+                       IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+                       IMX_AUDMUX_V2_PTCR_TFSDIR |
+                       IMX_AUDMUX_V2_PTCR_TCLKDIR,
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
+       if (ret) {
+               dev_err(&pdev->dev, "audmux internal port setup failed\n");
+               return ret;
+       }
+       imx_audmux_v2_configure_port(ext_port,
+                       IMX_AUDMUX_V2_PTCR_SYN |
+                       IMX_AUDMUX_V2_PTCR_TCSEL(int_port),
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
+       if (ret) {
+               dev_err(&pdev->dev, "audmux external port setup failed\n");
+               return ret;
+       }
+
+       ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
+       codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
+       if (!ssi_np || !codec_np) {
+               dev_err(&pdev->dev, "phandle missing or invalid\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       ssi_pdev = of_find_device_by_node(ssi_np);
+       if (!ssi_pdev) {
+               dev_err(&pdev->dev, "failed to find SSI platform device\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+       codec_dev = of_find_i2c_device_by_node(codec_np);
+       if (!codec_dev) {
+               dev_err(&pdev->dev, "failed to find codec platform device\n");
+               return -EINVAL;
+       }
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       data->codec_clk = clk_get(&codec_dev->dev, NULL);
+       if (IS_ERR(data->codec_clk)) {
+               /* assuming clock enabled by default */
+               data->codec_clk = NULL;
+               ret = of_property_read_u32(codec_np, "clock-frequency",
+                                       &data->clk_frequency);
+               if (ret) {
+                       dev_err(&codec_dev->dev,
+                               "clock-frequency missing or invalid\n");
+                       goto fail;
+               }
+       } else {
+               data->clk_frequency = clk_get_rate(data->codec_clk);
+               clk_prepare_enable(data->codec_clk);
+       }
+
+       data->dai.name = "HiFi";
+       data->dai.stream_name = "HiFi";
+       data->dai.codec_dai_name = "sgtl5000";
+       data->dai.codec_of_node = codec_np;
+       data->dai.cpu_dai_name = dev_name(&ssi_pdev->dev);
+       data->dai.platform_name = "imx-pcm-audio";
+       data->dai.init = &imx_sgtl5000_dai_init;
+       data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                           SND_SOC_DAIFMT_CBM_CFM;
+
+       data->card.dev = &pdev->dev;
+       ret = snd_soc_of_parse_card_name(&data->card, "model");
+       if (ret)
+               goto clk_fail;
+       ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
+       if (ret)
+               goto clk_fail;
+       data->card.num_links = 1;
+       data->card.dai_link = &data->dai;
+       data->card.dapm_widgets = imx_sgtl5000_dapm_widgets;
+       data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets);
+
+       ret = snd_soc_register_card(&data->card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+               goto clk_fail;
+       }
+
+       platform_set_drvdata(pdev, data);
+clk_fail:
+       clk_put(data->codec_clk);
+fail:
+       if (ssi_np)
+               of_node_put(ssi_np);
+       if (codec_np)
+               of_node_put(codec_np);
+
+       return ret;
+}
+
+static int __devexit imx_sgtl5000_remove(struct platform_device *pdev)
+{
+       struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
+
+       if (data->codec_clk) {
+               clk_disable_unprepare(data->codec_clk);
+               clk_put(data->codec_clk);
+       }
+       snd_soc_unregister_card(&data->card);
+
+       return 0;
+}
+
+static const struct of_device_id imx_sgtl5000_dt_ids[] = {
+       { .compatible = "fsl,imx-audio-sgtl5000", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_sgtl5000_dt_ids);
+
+static struct platform_driver imx_sgtl5000_driver = {
+       .driver = {
+               .name = "imx-sgtl5000",
+               .owner = THIS_MODULE,
+               .of_match_table = imx_sgtl5000_dt_ids,
+       },
+       .probe = imx_sgtl5000_probe,
+       .remove = __devexit_p(imx_sgtl5000_remove),
+};
+module_platform_driver(imx_sgtl5000_driver);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("Freescale i.MX SGTL5000 ASoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-sgtl5000");
similarity index 99%
rename from sound/soc/imx/imx-ssi.c
rename to sound/soc/fsl/imx-ssi.c
index 4f81ed456325c044e1dc9f0781de9b4dc4d46310..cf3ed0362c9ccf76cbbdc975c8788b33725b70f7 100644 (file)
@@ -28,7 +28,7 @@
  * value. When we read the same register two times (and the register still
  * contains the same value) these status bits are not set. We work
  * around this by not polling these bits but only wait a fixed delay.
- * 
+ *
  */
 
 #include <linux/clk.h>
index 3fea5a15ffe8c6c64e6d86b9587f7cf776f4fedd..60bcba1bc30e550d34fc97500efb31b1a890e259 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
-#include <linux/of_i2c.h>
 #include <sound/soc.h>
 #include <asm/fsl_guts.h>
 
 #include "fsl_dma.h"
 #include "fsl_ssi.h"
+#include "fsl_utils.h"
 
 /* There's only one global utilities register */
 static phys_addr_t guts_phys;
 
-#define DAI_NAME_SIZE  32
-
 /**
  * mpc8610_hpcd_data: machine-specific ASoC device data
  *
@@ -43,7 +41,6 @@ struct mpc8610_hpcd_data {
        unsigned int dma_id[2];         /* 0 = DMA1, 1 = DMA2, etc */
        unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
        char codec_dai_name[DAI_NAME_SIZE];
-       char codec_name[DAI_NAME_SIZE];
        char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
 };
 
@@ -180,141 +177,6 @@ static struct snd_soc_ops mpc8610_hpcd_ops = {
        .startup = mpc8610_hpcd_startup,
 };
 
-/**
- * get_node_by_phandle_name - get a node by its phandle name
- *
- * This function takes a node, the name of a property in that node, and a
- * compatible string.  Assuming the property is a phandle to another node,
- * it returns that node, (optionally) if that node is compatible.
- *
- * If the property is not a phandle, or the node it points to is not compatible
- * with the specific string, then NULL is returned.
- */
-static struct device_node *get_node_by_phandle_name(struct device_node *np,
-                                              const char *name,
-                                              const char *compatible)
-{
-       const phandle *ph;
-       int len;
-
-       ph = of_get_property(np, name, &len);
-       if (!ph || (len != sizeof(phandle)))
-               return NULL;
-
-       np = of_find_node_by_phandle(*ph);
-       if (!np)
-               return NULL;
-
-       if (compatible && !of_device_is_compatible(np, compatible)) {
-               of_node_put(np);
-               return NULL;
-       }
-
-       return np;
-}
-
-/**
- * get_parent_cell_index -- return the cell-index of the parent of a node
- *
- * Return the value of the cell-index property of the parent of the given
- * node.  This is used for DMA channel nodes that need to know the DMA ID
- * of the controller they are on.
- */
-static int get_parent_cell_index(struct device_node *np)
-{
-       struct device_node *parent = of_get_parent(np);
-       const u32 *iprop;
-
-       if (!parent)
-               return -1;
-
-       iprop = of_get_property(parent, "cell-index", NULL);
-       of_node_put(parent);
-
-       if (!iprop)
-               return -1;
-
-       return be32_to_cpup(iprop);
-}
-
-/**
- * codec_node_dev_name - determine the dev_name for a codec node
- *
- * This function determines the dev_name for an I2C node.  This is the name
- * that would be returned by dev_name() if this device_node were part of a
- * 'struct device'  It's ugly and hackish, but it works.
- *
- * The dev_name for such devices include the bus number and I2C address. For
- * example, "cs4270.0-004f".
- */
-static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
-{
-       const u32 *iprop;
-       int addr;
-       char temp[DAI_NAME_SIZE];
-       struct i2c_client *i2c;
-
-       of_modalias_node(np, temp, DAI_NAME_SIZE);
-
-       iprop = of_get_property(np, "reg", NULL);
-       if (!iprop)
-               return -EINVAL;
-
-       addr = be32_to_cpup(iprop);
-
-       /* We need the adapter number */
-       i2c = of_find_i2c_device_by_node(np);
-       if (!i2c)
-               return -ENODEV;
-
-       snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr);
-
-       return 0;
-}
-
-static int get_dma_channel(struct device_node *ssi_np,
-                          const char *name,
-                          struct snd_soc_dai_link *dai,
-                          unsigned int *dma_channel_id,
-                          unsigned int *dma_id)
-{
-       struct resource res;
-       struct device_node *dma_channel_np;
-       const u32 *iprop;
-       int ret;
-
-       dma_channel_np = get_node_by_phandle_name(ssi_np, name,
-                                                 "fsl,ssi-dma-channel");
-       if (!dma_channel_np)
-               return -EINVAL;
-
-       /* Determine the dev_name for the device_node.  This code mimics the
-        * behavior of of_device_make_bus_id(). We need this because ASoC uses
-        * the dev_name() of the device to match the platform (DMA) device with
-        * the CPU (SSI) device.  It's all ugly and hackish, but it works (for
-        * now).
-        *
-        * dai->platform name should already point to an allocated buffer.
-        */
-       ret = of_address_to_resource(dma_channel_np, 0, &res);
-       if (ret)
-               return ret;
-       snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
-                (unsigned long long) res.start, dma_channel_np->name);
-
-       iprop = of_get_property(dma_channel_np, "cell-index", NULL);
-       if (!iprop) {
-               of_node_put(dma_channel_np);
-               return -EINVAL;
-       }
-
-       *dma_channel_id = be32_to_cpup(iprop);
-       *dma_id = get_parent_cell_index(dma_channel_np);
-       of_node_put(dma_channel_np);
-
-       return 0;
-}
-
 /**
  * mpc8610_hpcd_probe: platform probe function for the machine driver
  *
@@ -352,16 +214,8 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
        machine_data->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
        machine_data->dai[0].ops = &mpc8610_hpcd_ops;
 
-       /* Determine the codec name, it will be used as the codec DAI name */
-       ret = codec_node_dev_name(codec_np, machine_data->codec_name,
-                                 DAI_NAME_SIZE);
-       if (ret) {
-               dev_err(&pdev->dev, "invalid codec node %s\n",
-                       codec_np->full_name);
-               ret = -EINVAL;
-               goto error;
-       }
-       machine_data->dai[0].codec_name = machine_data->codec_name;
+       /* ASoC core can match codec with device node */
+       machine_data->dai[0].codec_of_node = codec_np;
 
        /* The DAI name from the codec (snd_soc_dai_driver.name) */
        machine_data->dai[0].codec_dai_name = "cs4270-hifi";
@@ -458,9 +312,10 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
 
        /* Find the playback DMA channel to use. */
        machine_data->dai[0].platform_name = machine_data->platform_name[0];
-       ret = get_dma_channel(np, "fsl,playback-dma", &machine_data->dai[0],
-                             &machine_data->dma_channel_id[0],
-                             &machine_data->dma_id[0]);
+       ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma",
+                                      &machine_data->dai[0],
+                                      &machine_data->dma_channel_id[0],
+                                      &machine_data->dma_id[0]);
        if (ret) {
                dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
                goto error;
@@ -468,9 +323,10 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
 
        /* Find the capture DMA channel to use. */
        machine_data->dai[1].platform_name = machine_data->platform_name[1];
-       ret = get_dma_channel(np, "fsl,capture-dma", &machine_data->dai[1],
-                             &machine_data->dma_channel_id[1],
-                             &machine_data->dma_id[1]);
+       ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma",
+                                      &machine_data->dai[1],
+                                      &machine_data->dma_channel_id[1],
+                                      &machine_data->dma_id[1]);
        if (ret) {
                dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
                goto error;
index 982a1c94498344af320b3ce18798f24215474a9a..50adf4032bcceee4a1ac4085baed835b46c27c6f 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
-#include <linux/of_i2c.h>
 #include <sound/soc.h>
 #include <asm/fsl_guts.h>
 
 #include "fsl_dma.h"
 #include "fsl_ssi.h"
+#include "fsl_utils.h"
 
 /* P1022-specific PMUXCR and DMUXCR bit definitions */
 
@@ -57,8 +57,6 @@ static inline void guts_set_dmuxcr(struct ccsr_guts __iomem *guts,
 /* There's only one global utilities register */
 static phys_addr_t guts_phys;
 
-#define DAI_NAME_SIZE  32
-
 /**
  * machine_data: machine-specific ASoC device data
  *
@@ -75,7 +73,6 @@ struct machine_data {
        unsigned int ssi_id;            /* 0 = SSI1, 1 = SSI2, etc */
        unsigned int dma_id[2];         /* 0 = DMA1, 1 = DMA2, etc */
        unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
-       char codec_name[DAI_NAME_SIZE];
        char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
 };
 
@@ -190,136 +187,6 @@ static struct snd_soc_ops p1022_ds_ops = {
        .startup = p1022_ds_startup,
 };
 
-/**
- * get_node_by_phandle_name - get a node by its phandle name
- *
- * This function takes a node, the name of a property in that node, and a
- * compatible string.  Assuming the property is a phandle to another node,
- * it returns that node, (optionally) if that node is compatible.
- *
- * If the property is not a phandle, or the node it points to is not compatible
- * with the specific string, then NULL is returned.
- */
-static struct device_node *get_node_by_phandle_name(struct device_node *np,
-       const char *name, const char *compatible)
-{
-       np = of_parse_phandle(np, name, 0);
-       if (!np)
-               return NULL;
-
-       if (!of_device_is_compatible(np, compatible)) {
-               of_node_put(np);
-               return NULL;
-       }
-
-       return np;
-}
-
-/**
- * get_parent_cell_index -- return the cell-index of the parent of a node
- *
- * Return the value of the cell-index property of the parent of the given
- * node.  This is used for DMA channel nodes that need to know the DMA ID
- * of the controller they are on.
- */
-static int get_parent_cell_index(struct device_node *np)
-{
-       struct device_node *parent = of_get_parent(np);
-       const u32 *iprop;
-       int ret = -1;
-
-       if (!parent)
-               return -1;
-
-       iprop = of_get_property(parent, "cell-index", NULL);
-       if (iprop)
-               ret = be32_to_cpup(iprop);
-
-       of_node_put(parent);
-
-       return ret;
-}
-
-/**
- * codec_node_dev_name - determine the dev_name for a codec node
- *
- * This function determines the dev_name for an I2C node.  This is the name
- * that would be returned by dev_name() if this device_node were part of a
- * 'struct device'  It's ugly and hackish, but it works.
- *
- * The dev_name for such devices include the bus number and I2C address. For
- * example, "cs4270-codec.0-004f".
- */
-static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
-{
-       const u32 *iprop;
-       int addr;
-       char temp[DAI_NAME_SIZE];
-       struct i2c_client *i2c;
-
-       of_modalias_node(np, temp, DAI_NAME_SIZE);
-
-       iprop = of_get_property(np, "reg", NULL);
-       if (!iprop)
-               return -EINVAL;
-
-       addr = be32_to_cpup(iprop);
-
-       /* We need the adapter number */
-       i2c = of_find_i2c_device_by_node(np);
-       if (!i2c)
-               return -ENODEV;
-
-       snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr);
-
-       return 0;
-}
-
-static int get_dma_channel(struct device_node *ssi_np,
-                          const char *name,
-                          struct snd_soc_dai_link *dai,
-                          unsigned int *dma_channel_id,
-                          unsigned int *dma_id)
-{
-       struct resource res;
-       struct device_node *dma_channel_np;
-       const u32 *iprop;
-       int ret;
-
-       dma_channel_np = get_node_by_phandle_name(ssi_np, name,
-                                                 "fsl,ssi-dma-channel");
-       if (!dma_channel_np)
-               return -EINVAL;
-
-       /* Determine the dev_name for the device_node.  This code mimics the
-        * behavior of of_device_make_bus_id(). We need this because ASoC uses
-        * the dev_name() of the device to match the platform (DMA) device with
-        * the CPU (SSI) device.  It's all ugly and hackish, but it works (for
-        * now).
-        *
-        * dai->platform name should already point to an allocated buffer.
-        */
-       ret = of_address_to_resource(dma_channel_np, 0, &res);
-       if (ret) {
-               of_node_put(dma_channel_np);
-               return ret;
-       }
-       snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
-                (unsigned long long) res.start, dma_channel_np->name);
-
-       iprop = of_get_property(dma_channel_np, "cell-index", NULL);
-       if (!iprop) {
-               of_node_put(dma_channel_np);
-               return -EINVAL;
-       }
-
-       *dma_channel_id = be32_to_cpup(iprop);
-       *dma_id = get_parent_cell_index(dma_channel_np);
-       of_node_put(dma_channel_np);
-
-       return 0;
-}
-
 /**
  * p1022_ds_probe: platform probe function for the machine driver
  *
@@ -357,15 +224,8 @@ static int p1022_ds_probe(struct platform_device *pdev)
        mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
        mdata->dai[0].ops = &p1022_ds_ops;
 
-       /* Determine the codec name, it will be used as the codec DAI name */
-       ret = codec_node_dev_name(codec_np, mdata->codec_name, DAI_NAME_SIZE);
-       if (ret) {
-               dev_err(&pdev->dev, "invalid codec node %s\n",
-                       codec_np->full_name);
-               ret = -EINVAL;
-               goto error;
-       }
-       mdata->dai[0].codec_name = mdata->codec_name;
+       /* ASoC core can match codec with device node */
+       mdata->dai[0].codec_of_node = codec_np;
 
        /* We register two DAIs per SSI, one for playback and the other for
         * capture.  We support codecs that have separate DAIs for both playback
@@ -462,9 +322,9 @@ static int p1022_ds_probe(struct platform_device *pdev)
 
        /* Find the playback DMA channel to use. */
        mdata->dai[0].platform_name = mdata->platform_name[0];
-       ret = get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0],
-                             &mdata->dma_channel_id[0],
-                             &mdata->dma_id[0]);
+       ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0],
+                                      &mdata->dma_channel_id[0],
+                                      &mdata->dma_id[0]);
        if (ret) {
                dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
                goto error;
@@ -472,9 +332,9 @@ static int p1022_ds_probe(struct platform_device *pdev)
 
        /* Find the capture DMA channel to use. */
        mdata->dai[1].platform_name = mdata->platform_name[1];
-       ret = get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1],
-                             &mdata->dma_channel_id[1],
-                             &mdata->dma_id[1]);
+       ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1],
+                                      &mdata->dma_channel_id[1],
+                                      &mdata->dma_id[1]);
        if (ret) {
                dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
                goto error;
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
new file mode 100644 (file)
index 0000000..610f612
--- /dev/null
@@ -0,0 +1,4 @@
+config SND_SIMPLE_CARD
+       tristate "ASoC Simple sound card support"
+       help
+         This option enables generic simple sound card support
diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile
new file mode 100644 (file)
index 0000000..9c3b246
--- /dev/null
@@ -0,0 +1,3 @@
+snd-soc-simple-card-objs       := simple-card.o
+
+obj-$(CONFIG_SND_SIMPLE_CARD)  += snd-soc-simple-card.o
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
new file mode 100644 (file)
index 0000000..b4b4cab
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * ASoC simple sound card support
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <sound/simple_card.h>
+
+#define asoc_simple_get_card_info(p) \
+       container_of(p->dai_link, struct asoc_simple_card_info, snd_link)
+
+static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct asoc_simple_card_info *cinfo = asoc_simple_get_card_info(rtd);
+       struct asoc_simple_dai_init_info *iinfo = cinfo->init;
+       struct snd_soc_dai *codec = rtd->codec_dai;
+       struct snd_soc_dai *cpu = rtd->cpu_dai;
+       unsigned int cpu_daifmt = iinfo->fmt | iinfo->cpu_daifmt;
+       unsigned int codec_daifmt = iinfo->fmt | iinfo->codec_daifmt;
+       int ret;
+
+       if (codec_daifmt) {
+               ret = snd_soc_dai_set_fmt(codec, codec_daifmt);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (iinfo->sysclk) {
+               ret = snd_soc_dai_set_sysclk(codec, 0, iinfo->sysclk, 0);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (cpu_daifmt) {
+               ret = snd_soc_dai_set_fmt(cpu, cpu_daifmt);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int asoc_simple_card_probe(struct platform_device *pdev)
+{
+       struct asoc_simple_card_info *cinfo = pdev->dev.platform_data;
+
+       if (!cinfo) {
+               dev_err(&pdev->dev, "no info for asoc-simple-card\n");
+               return -EINVAL;
+       }
+
+       if (!cinfo->name        ||
+           !cinfo->card        ||
+           !cinfo->cpu_dai     ||
+           !cinfo->codec       ||
+           !cinfo->platform    ||
+           !cinfo->codec_dai) {
+               dev_err(&pdev->dev, "insufficient asoc_simple_card_info settings\n");
+               return -EINVAL;
+       }
+
+       /*
+        * init snd_soc_dai_link
+        */
+       cinfo->snd_link.name            = cinfo->name;
+       cinfo->snd_link.stream_name     = cinfo->name;
+       cinfo->snd_link.cpu_dai_name    = cinfo->cpu_dai;
+       cinfo->snd_link.platform_name   = cinfo->platform;
+       cinfo->snd_link.codec_name      = cinfo->codec;
+       cinfo->snd_link.codec_dai_name  = cinfo->codec_dai;
+
+       /* enable snd_link.init if cinfo has settings */
+       if (cinfo->init)
+               cinfo->snd_link.init    = asoc_simple_card_dai_init;
+
+       /*
+        * init snd_soc_card
+        */
+       cinfo->snd_card.name            = cinfo->card;
+       cinfo->snd_card.owner           = THIS_MODULE;
+       cinfo->snd_card.dai_link        = &cinfo->snd_link;
+       cinfo->snd_card.num_links       = 1;
+       cinfo->snd_card.dev             = &pdev->dev;
+
+       return snd_soc_register_card(&cinfo->snd_card);
+}
+
+static int asoc_simple_card_remove(struct platform_device *pdev)
+{
+       struct asoc_simple_card_info *cinfo = pdev->dev.platform_data;
+
+       return snd_soc_unregister_card(&cinfo->snd_card);
+}
+
+static struct platform_driver asoc_simple_card = {
+       .driver = {
+               .name   = "asoc-simple-card",
+       },
+       .probe          = asoc_simple_card_probe,
+       .remove         = asoc_simple_card_remove,
+};
+
+module_platform_driver(asoc_simple_card);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ASoC Simple Sound Card");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
deleted file mode 100644 (file)
index d83e5d0..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-menuconfig SND_IMX_SOC
-       tristate "SoC Audio for Freescale i.MX CPUs"
-       depends on ARCH_MXC
-       help
-         Say Y or M if you want to add support for codecs attached to
-         the i.MX SSI interface.
-
-
-if SND_IMX_SOC
-
-config SND_SOC_IMX_SSI
-       tristate
-
-config SND_SOC_IMX_PCM
-       tristate
-
-config SND_MXC_SOC_FIQ
-       tristate
-       select FIQ
-       select SND_SOC_IMX_PCM
-
-config SND_MXC_SOC_MX2
-       select SND_SOC_DMAENGINE_PCM
-       tristate
-       select SND_SOC_IMX_PCM
-
-config SND_SOC_IMX_AUDMUX
-       tristate
-
-config SND_MXC_SOC_WM1133_EV1
-       tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted"
-       depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
-       select SND_SOC_WM8350
-       select SND_MXC_SOC_FIQ
-       select SND_SOC_IMX_AUDMUX
-       select SND_SOC_IMX_SSI
-       help
-         Enable support for audio on the i.MX31ADS with the WM1133-EV1
-         PMIC board with WM8835x fitted.
-
-config SND_SOC_MX27VIS_AIC32X4
-       tristate "SoC audio support for Visstrim M10 boards"
-       depends on MACH_IMX27_VISSTRIM_M10 && I2C
-       select SND_SOC_TLV320AIC32X4
-       select SND_MXC_SOC_MX2
-       select SND_SOC_IMX_AUDMUX
-       select SND_SOC_IMX_SSI
-       help
-         Say Y if you want to add support for SoC audio on Visstrim SM10
-         board with TLV320AIC32X4 codec.
-
-config SND_SOC_PHYCORE_AC97
-       tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
-       depends on MACH_PCM043 || MACH_PCA100
-       select SND_SOC_AC97_BUS
-       select SND_SOC_WM9712
-       select SND_MXC_SOC_FIQ
-       select SND_SOC_IMX_AUDMUX
-       select SND_SOC_IMX_SSI
-       help
-         Say Y if you want to add support for SoC audio on Phytec phyCORE
-         and phyCARD boards in AC97 mode
-
-config SND_SOC_EUKREA_TLV320
-       tristate "Eukrea TLV320"
-       depends on MACH_EUKREA_MBIMX27_BASEBOARD \
-               || MACH_EUKREA_MBIMXSD25_BASEBOARD \
-               || MACH_EUKREA_MBIMXSD35_BASEBOARD \
-               || MACH_EUKREA_MBIMXSD51_BASEBOARD
-       depends on I2C
-       select SND_SOC_TLV320AIC23
-       select SND_MXC_SOC_FIQ
-       select SND_SOC_IMX_AUDMUX
-       select SND_SOC_IMX_SSI
-       help
-         Enable I2S based access to the TLV320AIC23B codec attached
-         to the SSI interface
-
-endif  # SND_IMX_SOC
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
deleted file mode 100644 (file)
index f5db3e9..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# i.MX Platform Support
-snd-soc-imx-ssi-objs := imx-ssi.o
-snd-soc-imx-audmux-objs := imx-audmux.o
-
-obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
-obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
-
-obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o
-snd-soc-imx-pcm-y := imx-pcm.o
-snd-soc-imx-pcm-$(CONFIG_SND_MXC_SOC_FIQ) += imx-pcm-fiq.o
-snd-soc-imx-pcm-$(CONFIG_SND_MXC_SOC_MX2) += imx-pcm-dma-mx2.o
-
-# i.MX Machine Support
-snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
-snd-soc-phycore-ac97-objs := phycore-ac97.o
-snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
-snd-soc-wm1133-ev1-objs := wm1133-ev1.o
-
-obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
-obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
-obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
-obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
index a5af7c42e62bb7ce641e13d3635c3c5312fc167b..41349670adab8ab18c00ef9bc696b2826e4fcf87 100644 (file)
@@ -346,7 +346,7 @@ static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
 
        /* Playback */
        dma_config = &i2s->pcm_config_playback.dma_config;
-       dma_config->src_width = JZ4740_DMA_WIDTH_32BIT,
+       dma_config->src_width = JZ4740_DMA_WIDTH_32BIT;
        dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
        dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
        dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
@@ -355,7 +355,7 @@ static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
 
        /* Capture */
        dma_config = &i2s->pcm_config_capture.dma_config;
-       dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT,
+       dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT;
        dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
        dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
        dma_config->flags = JZ4740_DMA_DST_AUTOINC;
index e373fbbc97a0eb7edeb06bb99dfee274a129249c..373dec90579f5e7860e4dbeab8e00645942eb648 100644 (file)
@@ -220,28 +220,16 @@ static struct snd_soc_platform_driver mxs_soc_platform = {
        .pcm_free       = mxs_pcm_free,
 };
 
-static int __devinit mxs_soc_platform_probe(struct platform_device *pdev)
+int __devinit mxs_pcm_platform_register(struct device *dev)
 {
-       return snd_soc_register_platform(&pdev->dev, &mxs_soc_platform);
+       return snd_soc_register_platform(dev, &mxs_soc_platform);
 }
+EXPORT_SYMBOL_GPL(mxs_pcm_platform_register);
 
-static int __devexit mxs_soc_platform_remove(struct platform_device *pdev)
+void __devexit mxs_pcm_platform_unregister(struct device *dev)
 {
-       snd_soc_unregister_platform(&pdev->dev);
-
-       return 0;
+       snd_soc_unregister_platform(dev);
 }
-
-static struct platform_driver mxs_pcm_driver = {
-       .driver = {
-               .name = "mxs-pcm-audio",
-               .owner = THIS_MODULE,
-       },
-       .probe = mxs_soc_platform_probe,
-       .remove = __devexit_p(mxs_soc_platform_remove),
-};
-
-module_platform_driver(mxs_pcm_driver);
+EXPORT_SYMBOL_GPL(mxs_pcm_platform_unregister);
 
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mxs-pcm-audio");
index 5f01a9124b3ddcdbbb103f871a6cdd8c8fe293c8..35ba2ca423843c7c191625d9b0ff7df36e6d7797 100644 (file)
@@ -24,4 +24,7 @@ struct mxs_pcm_dma_params {
        int chan_num;
 };
 
+int mxs_pcm_platform_register(struct device *dev);
+void mxs_pcm_platform_unregister(struct device *dev);
+
 #endif
index 7fd224bb732408bd52fbd267f0f8f97efbc24006..aba71bfa33b15f0813f48a7a236bb61c5b5968b9 100644 (file)
@@ -18,6 +18,8 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
@@ -621,37 +623,57 @@ static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int mxs_saif_probe(struct platform_device *pdev)
+static int __devinit mxs_saif_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        struct resource *iores, *dmares;
        struct mxs_saif *saif;
        struct mxs_saif_platform_data *pdata;
        struct pinctrl *pinctrl;
        int ret = 0;
 
-       if (pdev->id >= ARRAY_SIZE(mxs_saif))
+
+       if (!np && pdev->id >= ARRAY_SIZE(mxs_saif))
                return -EINVAL;
 
        saif = devm_kzalloc(&pdev->dev, sizeof(*saif), GFP_KERNEL);
        if (!saif)
                return -ENOMEM;
 
-       mxs_saif[pdev->id] = saif;
-       saif->id = pdev->id;
-
-       pdata = pdev->dev.platform_data;
-       if (pdata && !pdata->master_mode) {
-               saif->master_id = pdata->master_id;
-               if (saif->master_id < 0 ||
-                       saif->master_id >= ARRAY_SIZE(mxs_saif) ||
-                       saif->master_id == saif->id) {
-                       dev_err(&pdev->dev, "get wrong master id\n");
-                       return -EINVAL;
+       if (np) {
+               struct device_node *master;
+               saif->id = of_alias_get_id(np, "saif");
+               if (saif->id < 0)
+                       return saif->id;
+               /*
+                * If there is no "fsl,saif-master" phandle, it's a saif
+                * master.  Otherwise, it's a slave and its phandle points
+                * to the master.
+                */
+               master = of_parse_phandle(np, "fsl,saif-master", 0);
+               if (!master) {
+                       saif->master_id = saif->id;
+               } else {
+                       saif->master_id = of_alias_get_id(master, "saif");
+                       if (saif->master_id < 0)
+                               return saif->master_id;
                }
        } else {
-               saif->master_id = saif->id;
+               saif->id = pdev->id;
+               pdata = pdev->dev.platform_data;
+               if (pdata && !pdata->master_mode)
+                       saif->master_id = pdata->master_id;
+               else
+                       saif->master_id = saif->id;
+       }
+
+       if (saif->master_id < 0 || saif->master_id >= ARRAY_SIZE(mxs_saif)) {
+               dev_err(&pdev->dev, "get wrong master id\n");
+               return -EINVAL;
        }
 
+       mxs_saif[saif->id] = saif;
+
        pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
        if (IS_ERR(pinctrl)) {
                ret = PTR_ERR(pinctrl);
@@ -677,12 +699,19 @@ static int mxs_saif_probe(struct platform_device *pdev)
 
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!dmares) {
-               ret = -ENODEV;
-               dev_err(&pdev->dev, "failed to get dma resource: %d\n",
-                       ret);
-               goto failed_get_resource;
+               /*
+                * TODO: This is a temporary solution and should be changed
+                * to use generic DMA binding later when the helplers get in.
+                */
+               ret = of_property_read_u32(np, "fsl,saif-dma-channel",
+                                          &saif->dma_param.chan_num);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to get dma channel\n");
+                       goto failed_get_resource;
+               }
+       } else {
+               saif->dma_param.chan_num = dmares->start;
        }
-       saif->dma_param.chan_num = dmares->start;
 
        saif->irq = platform_get_irq(pdev, 0);
        if (saif->irq < 0) {
@@ -716,24 +745,14 @@ static int mxs_saif_probe(struct platform_device *pdev)
                goto failed_get_resource;
        }
 
-       saif->soc_platform_pdev = platform_device_alloc(
-                                       "mxs-pcm-audio", pdev->id);
-       if (!saif->soc_platform_pdev) {
-               ret = -ENOMEM;
-               goto failed_pdev_alloc;
-       }
-
-       platform_set_drvdata(saif->soc_platform_pdev, saif);
-       ret = platform_device_add(saif->soc_platform_pdev);
+       ret = mxs_pcm_platform_register(&pdev->dev);
        if (ret) {
-               dev_err(&pdev->dev, "failed to add soc platform device\n");
-               goto failed_pdev_add;
+               dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+               goto failed_pdev_alloc;
        }
 
        return 0;
 
-failed_pdev_add:
-       platform_device_put(saif->soc_platform_pdev);
 failed_pdev_alloc:
        snd_soc_unregister_dai(&pdev->dev);
 failed_get_resource:
@@ -746,13 +765,19 @@ static int __devexit mxs_saif_remove(struct platform_device *pdev)
 {
        struct mxs_saif *saif = platform_get_drvdata(pdev);
 
-       platform_device_unregister(saif->soc_platform_pdev);
+       mxs_pcm_platform_unregister(&pdev->dev);
        snd_soc_unregister_dai(&pdev->dev);
        clk_put(saif->clk);
 
        return 0;
 }
 
+static const struct of_device_id mxs_saif_dt_ids[] = {
+       { .compatible = "fsl,imx28-saif", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_saif_dt_ids);
+
 static struct platform_driver mxs_saif_driver = {
        .probe = mxs_saif_probe,
        .remove = __devexit_p(mxs_saif_remove),
@@ -760,6 +785,7 @@ static struct platform_driver mxs_saif_driver = {
        .driver = {
                .name = "mxs-saif",
                .owner = THIS_MODULE,
+               .of_match_table = mxs_saif_dt_ids,
        },
 };
 
index 12c91e4eb941029c5c6510ab3d0e95818efaa070..3cb342e5bc902b2c9b39eff62023015a43c7fe70 100644 (file)
@@ -123,7 +123,6 @@ struct mxs_saif {
        unsigned int cur_rate;
        unsigned int ongoing;
 
-       struct platform_device *soc_platform_pdev;
        u32 fifo_underrun;
        u32 fifo_overrun;
 };
index 60f052b7cf223b6573a1116153552acb76849f0a..3e6e8764b2e67674ad9ba3f571cd162a13cad509 100644 (file)
@@ -18,6 +18,8 @@
 
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
@@ -90,7 +92,7 @@ static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
                .codec_dai_name = "sgtl5000",
                .codec_name     = "sgtl5000.0-000a",
                .cpu_dai_name   = "mxs-saif.0",
-               .platform_name  = "mxs-pcm-audio.0",
+               .platform_name  = "mxs-saif.0",
                .ops            = &mxs_sgtl5000_hifi_ops,
        }, {
                .name           = "HiFi Rx",
@@ -98,7 +100,7 @@ static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
                .codec_dai_name = "sgtl5000",
                .codec_name     = "sgtl5000.0-000a",
                .cpu_dai_name   = "mxs-saif.1",
-               .platform_name  = "mxs-pcm-audio.1",
+               .platform_name  = "mxs-saif.1",
                .ops            = &mxs_sgtl5000_hifi_ops,
        },
 };
@@ -110,11 +112,48 @@ static struct snd_soc_card mxs_sgtl5000 = {
        .num_links      = ARRAY_SIZE(mxs_sgtl5000_dai),
 };
 
+static int __devinit mxs_sgtl5000_probe_dt(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *saif_np[2], *codec_np;
+       int i, ret = 0;
+
+       if (!np)
+               return 1; /* no device tree */
+
+       saif_np[0] = of_parse_phandle(np, "saif-controllers", 0);
+       saif_np[1] = of_parse_phandle(np, "saif-controllers", 1);
+       codec_np = of_parse_phandle(np, "audio-codec", 0);
+       if (!saif_np[0] || !saif_np[1] || !codec_np) {
+               dev_err(&pdev->dev, "phandle missing or invalid\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < 2; i++) {
+               mxs_sgtl5000_dai[i].codec_name = NULL;
+               mxs_sgtl5000_dai[i].codec_of_node = codec_np;
+               mxs_sgtl5000_dai[i].cpu_dai_name = NULL;
+               mxs_sgtl5000_dai[i].cpu_dai_of_node = saif_np[i];
+               mxs_sgtl5000_dai[i].platform_name = NULL;
+               mxs_sgtl5000_dai[i].platform_of_node = saif_np[i];
+       }
+
+       of_node_put(codec_np);
+       of_node_put(saif_np[0]);
+       of_node_put(saif_np[1]);
+
+       return ret;
+}
+
 static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &mxs_sgtl5000;
        int ret;
 
+       ret = mxs_sgtl5000_probe_dt(pdev);
+       if (ret < 0)
+               return ret;
+
        /*
         * Set an init clock(11.28Mhz) for sgtl5000 initialization(i2c r/w).
         * The Sgtl5000 sysclk is derived from saif0 mclk and it's range
@@ -148,10 +187,17 @@ static int __devexit mxs_sgtl5000_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id mxs_sgtl5000_dt_ids[] = {
+       { .compatible = "fsl,mxs-audio-sgtl5000", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_sgtl5000_dt_ids);
+
 static struct platform_driver mxs_sgtl5000_audio_driver = {
        .driver = {
                .name = "mxs-sgtl5000",
                .owner = THIS_MODULE,
+               .of_match_table = mxs_sgtl5000_dt_ids,
        },
        .probe = mxs_sgtl5000_probe,
        .remove = __devexit_p(mxs_sgtl5000_remove),
index deafbfaacdbf13644d72009ddeadd18c5eb81eea..9ccfa5e1c11b4f236128663b4cfaca8bae197a75 100644 (file)
@@ -113,6 +113,7 @@ config SND_OMAP_SOC_OMAP4_HDMI
        tristate "SoC Audio support for Texas Instruments OMAP4 HDMI"
        depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4
        select SND_OMAP_SOC_HDMI
+       select SND_SOC_OMAP_HDMI_CODEC
        help
          Say Y if you want to add support for SoC HDMI audio on Texas Instruments
          OMAP4 chips
index fd04ce139031d56b99800a8e0c6a7e6faeb4d662..1c2aa7fab3fd1f2beed5232187e959e69f38e7bc 100644 (file)
@@ -85,14 +85,12 @@ struct pxa2xx_pcm_dma_data {
        char name[20];
 };
 
-static struct pxa2xx_pcm_dma_params *
-pxa_ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
+static void pxa_ssp_set_dma_params(struct ssp_device *ssp, int width4,
+                       int out, struct pxa2xx_pcm_dma_params *dma_data)
 {
        struct pxa2xx_pcm_dma_data *dma;
 
-       dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL);
-       if (dma == NULL)
-               return NULL;
+       dma = container_of(dma_data, struct pxa2xx_pcm_dma_data, params);
 
        snprintf(dma->name, 20, "SSP%d PCM %s %s", ssp->port_id,
                        width4 ? "32-bit" : "16-bit", out ? "out" : "in");
@@ -103,8 +101,6 @@ pxa_ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
                                  (DCMD_INCTRGADDR | DCMD_FLOWSRC)) |
                        (width4 ? DCMD_WIDTH4 : DCMD_WIDTH2) | DCMD_BURST16;
        dma->params.dev_addr = ssp->phys_base + SSDR;
-
-       return &dma->params;
 }
 
 static int pxa_ssp_startup(struct snd_pcm_substream *substream,
@@ -112,6 +108,7 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
 {
        struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
+       struct pxa2xx_pcm_dma_data *dma;
        int ret = 0;
 
        if (!cpu_dai->active) {
@@ -119,8 +116,10 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
                pxa_ssp_disable(ssp);
        }
 
-       kfree(snd_soc_dai_get_dma_data(cpu_dai, substream));
-       snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
+       dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL);
+       if (!dma)
+               return -ENOMEM;
+       snd_soc_dai_set_dma_data(cpu_dai, substream, &dma->params);
 
        return ret;
 }
@@ -573,18 +572,13 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
 
        dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
 
-       /* generate correct DMA params */
-       kfree(dma_data);
-
        /* Network mode with one active slot (ttsa == 1) can be used
         * to force 16-bit frame width on the wire (for S16_LE), even
         * with two channels. Use 16-bit DMA transfers for this case.
         */
-       dma_data = pxa_ssp_get_dma_params(ssp,
-                       ((chn == 2) && (ttsa != 1)) || (width == 32),
-                       substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-
-       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+       pxa_ssp_set_dma_params(ssp,
+               ((chn == 2) && (ttsa != 1)) || (width == 32),
+               substream->stream == SNDRV_PCM_STREAM_PLAYBACK, dma_data);
 
        /* we can only change the settings if the port is not in use */
        if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
index d08583790d231192fd2b11ac4cfcf8a50477b042..3075a426124cc119cfc43355c2403fba835ec4b4 100644 (file)
@@ -166,7 +166,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
        struct pxa2xx_pcm_dma_params *dma_data;
 
        BUG_ON(IS_ERR(clk_i2s));
-       clk_enable(clk_i2s);
+       clk_prepare_enable(clk_i2s);
        clk_ena = 1;
        pxa_i2s_wait();
 
@@ -259,7 +259,7 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
                SACR0 &= ~SACR0_ENB;
                pxa_i2s_wait();
                if (clk_ena) {
-                       clk_disable(clk_i2s);
+                       clk_disable_unprepare(clk_i2s);
                        clk_ena = 0;
                }
        }
index e7416851bf7d0237e97f33fd58b60886ab3ec4f0..c82c646b8a0897308c8288b96f62f5b4df10a801 100644 (file)
@@ -23,10 +23,10 @@ static int littlemill_set_bias_level(struct snd_soc_card *card,
                                          struct snd_soc_dapm_context *dapm,
                                          enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
        int ret;
 
-       if (dapm->dev != codec_dai->dev)
+       if (dapm->dev != aif1_dai->dev)
                return 0;
 
        switch (level) {
@@ -36,7 +36,7 @@ static int littlemill_set_bias_level(struct snd_soc_card *card,
                 * then do so now, otherwise these are noops.
                 */
                if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
-                       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1,
+                       ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1,
                                                  WM8994_FLL_SRC_MCLK2, 32768,
                                                  sample_rate * 512);
                        if (ret < 0) {
@@ -44,7 +44,7 @@ static int littlemill_set_bias_level(struct snd_soc_card *card,
                                return ret;
                        }
 
-                       ret = snd_soc_dai_set_sysclk(codec_dai,
+                       ret = snd_soc_dai_set_sysclk(aif1_dai,
                                                     WM8994_SYSCLK_FLL1,
                                                     sample_rate * 512,
                                                     SND_SOC_CLOCK_IN);
@@ -66,25 +66,25 @@ static int littlemill_set_bias_level_post(struct snd_soc_card *card,
                                               struct snd_soc_dapm_context *dapm,
                                               enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
        int ret;
 
-       if (dapm->dev != codec_dai->dev)
+       if (dapm->dev != aif1_dai->dev)
                return 0;
 
        switch (level) {
        case SND_SOC_BIAS_STANDBY:
-               ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK2,
+               ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
                                             32768, SND_SOC_CLOCK_IN);
                if (ret < 0) {
-                       pr_err("Failed to switch away from FLL: %d\n", ret);
+                       pr_err("Failed to switch away from FLL1: %d\n", ret);
                        return ret;
                }
 
-               ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1,
+               ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1,
                                          0, 0, 0);
                if (ret < 0) {
-                       pr_err("Failed to stop FLL: %d\n", ret);
+                       pr_err("Failed to stop FLL1: %d\n", ret);
                        return ret;
                }
                break;
@@ -131,6 +131,14 @@ static struct snd_soc_ops littlemill_ops = {
        .hw_params = littlemill_hw_params,
 };
 
+static const struct snd_soc_pcm_stream baseband_params = {
+       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+       .rate_min = 8000,
+       .rate_max = 8000,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
 static struct snd_soc_dai_link littlemill_dai[] = {
        {
                .name = "CPU",
@@ -143,13 +151,75 @@ static struct snd_soc_dai_link littlemill_dai[] = {
                                | SND_SOC_DAIFMT_CBM_CFM,
                .ops = &littlemill_ops,
        },
+       {
+               .name = "Baseband",
+               .stream_name = "Baseband",
+               .cpu_dai_name = "wm8994-aif2",
+               .codec_dai_name = "wm1250-ev1",
+               .codec_name = "wm1250-ev1.1-0027",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+               .ignore_suspend = 1,
+               .params = &baseband_params,
+       },
 };
 
+static int bbclk_ev(struct snd_soc_dapm_widget *w,
+                   struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_card *card = w->dapm->card;
+       struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
+       int ret;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2,
+                                         WM8994_FLL_SRC_BCLK, 64 * 8000,
+                                         8000 * 256);
+               if (ret < 0) {
+                       pr_err("Failed to start FLL: %d\n", ret);
+                       return ret;
+               }
+
+               ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_FLL2,
+                                            8000 * 256,
+                                            SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       pr_err("Failed to set SYSCLK: %d\n", ret);
+                       return ret;
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_MCLK2,
+                                            32768, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       pr_err("Failed to switch away from FLL2: %d\n", ret);
+                       return ret;
+               }
+
+               ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2,
+                                         0, 0, 0);
+               if (ret < 0) {
+                       pr_err("Failed to stop FLL2: %d\n", ret);
+                       return ret;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static struct snd_soc_dapm_widget widgets[] = {
        SND_SOC_DAPM_HP("Headphone", NULL),
 
        SND_SOC_DAPM_MIC("AMIC", NULL),
        SND_SOC_DAPM_MIC("DMIC", NULL),
+
+       SND_SOC_DAPM_SUPPLY_S("Baseband Clock", -1, SND_SOC_NOPM, 0, 0,
+                             bbclk_ev,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 };
 
 static struct snd_soc_dapm_route audio_paths[] = {
@@ -162,6 +232,8 @@ static struct snd_soc_dapm_route audio_paths[] = {
        { "DMIC", NULL, "MICBIAS2" },   /* Default for DMICBIAS jumper */
        { "DMIC1DAT", NULL, "DMIC" },
        { "DMIC2DAT", NULL, "DMIC" },
+
+       { "AIF2CLK", NULL, "Baseband Clock" },
 };
 
 static struct snd_soc_jack littlemill_headset;
@@ -169,10 +241,16 @@ static struct snd_soc_jack littlemill_headset;
 static int littlemill_late_probe(struct snd_soc_card *card)
 {
        struct snd_soc_codec *codec = card->rtd[0].codec;
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
+       struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
        int ret;
 
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK2,
+       ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
+                                    32768, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_MCLK2,
                                     32768, SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
index 4adff934f771e8ef18741e8b009c4b7eb25628b5..6abf341c4a2ab3f4a224f1161770228dc07da93a 100644 (file)
 #define MCLK1_RATE (44100 * 512)
 #define CLKOUT_RATE (44100 * 256)
 
-static int lowland_hw_params(struct snd_pcm_substream *substream,
-                            struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_ops lowland_ops = {
-       .hw_params = lowland_hw_params,
-};
-
 static struct snd_soc_jack lowland_headset;
 
 /* Headset jack detection DAPM pins */
@@ -101,6 +74,25 @@ static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
+static int lowland_wm9081_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+
+       snd_soc_dapm_nc_pin(&codec->dapm, "LINEOUT");
+
+       /* At any time the WM9081 is active it will have this clock */
+       return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0,
+                                       CLKOUT_RATE, 0);
+}
+
+static const struct snd_soc_pcm_stream sub_params = {
+       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+       .rate_min = 44100,
+       .rate_max = 44100,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
 static struct snd_soc_dai_link lowland_dai[] = {
        {
                .name = "CPU",
@@ -109,7 +101,8 @@ static struct snd_soc_dai_link lowland_dai[] = {
                .codec_dai_name = "wm5100-aif1",
                .platform_name = "samsung-audio",
                .codec_name = "wm5100.1-001a",
-               .ops = &lowland_ops,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                               SND_SOC_DAIFMT_CBM_CFM,
                .init = lowland_wm5100_init,
        },
        {
@@ -118,24 +111,20 @@ static struct snd_soc_dai_link lowland_dai[] = {
                .cpu_dai_name = "wm5100-aif2",
                .codec_dai_name = "wm1250-ev1",
                .codec_name = "wm1250-ev1.1-0027",
-               .ops = &lowland_ops,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                               SND_SOC_DAIFMT_CBM_CFM,
                .ignore_suspend = 1,
        },
-};
-
-static int lowland_wm9081_init(struct snd_soc_dapm_context *dapm)
-{
-       snd_soc_dapm_nc_pin(dapm, "LINEOUT");
-
-       /* At any time the WM9081 is active it will have this clock */
-       return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0,
-                                       CLKOUT_RATE, 0);
-}
-
-static struct snd_soc_aux_dev lowland_aux_dev[] = {
        {
-               .name = "wm9081",
+               .name = "Sub Speaker",
+               .stream_name = "Sub Speaker",
+               .cpu_dai_name = "wm5100-aif3",
+               .codec_dai_name = "wm9081-hifi",
                .codec_name = "wm9081.1-006c",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                               SND_SOC_DAIFMT_CBM_CFM,
+               .ignore_suspend = 1,
+               .params = &sub_params,
                .init = lowland_wm9081_init,
        },
 };
@@ -180,8 +169,6 @@ static struct snd_soc_card lowland = {
        .owner = THIS_MODULE,
        .dai_link = lowland_dai,
        .num_links = ARRAY_SIZE(lowland_dai),
-       .aux_dev = lowland_aux_dev,
-       .num_aux_devs = ARRAY_SIZE(lowland_aux_dev),
        .codec_conf = lowland_codec_conf,
        .num_configs = ARRAY_SIZE(lowland_codec_conf),
 
index f9ab7707a3e46674d464be23f36e9775df82169d..a4a9fc7e8c762c610f8f1f616fc516894e8506da 100644 (file)
@@ -92,33 +92,6 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
        return 0;
 }
 
-static int speyside_hw_params(struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_ops speyside_ops = {
-       .hw_params = speyside_hw_params,
-};
-
 static struct snd_soc_jack speyside_headset;
 
 /* Headset jack detection DAPM pins */
@@ -208,7 +181,8 @@ static struct snd_soc_dai_link speyside_dai[] = {
                .platform_name = "samsung-audio",
                .codec_name = "wm8996.1-001a",
                .init = speyside_wm8996_init,
-               .ops = &speyside_ops,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
        },
        {
                .name = "Baseband",
@@ -216,7 +190,8 @@ static struct snd_soc_dai_link speyside_dai[] = {
                .cpu_dai_name = "wm8996-aif2",
                .codec_dai_name = "wm1250-ev1",
                .codec_name = "wm1250-ev1.1-0027",
-               .ops = &speyside_ops,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
                .ignore_suspend = 1,
        },
 };
index d8e06a607a22990fe41f312123b628a3231366e4..6bcb1164d599d61bec029fdb94d3f00495b8f66c 100644 (file)
@@ -22,6 +22,7 @@ config SND_SOC_SH4_SSI
 
 config SND_SOC_SH4_FSI
        tristate "SH4 FSI support"
+       select SND_SIMPLE_CARD
        help
          This option enables FSI sound support
 
@@ -46,29 +47,6 @@ config SND_SH7760_AC97
          This option enables generic sound support for the first
          AC97 unit of the SH7760.
 
-config SND_FSI_AK4642
-       tristate "FSI-AK4642 sound support"
-       depends on SND_SOC_SH4_FSI && I2C
-       select SND_SOC_AK4642
-       help
-         This option enables generic sound support for the
-         FSI - AK4642 unit
-
-config SND_FSI_DA7210
-       tristate "FSI-DA7210 sound support"
-       depends on SND_SOC_SH4_FSI && I2C
-       select SND_SOC_DA7210
-       help
-         This option enables generic sound support for the
-         FSI - DA7210 unit
-
-config SND_FSI_HDMI
-       tristate "FSI-HDMI sound support"
-       depends on SND_SOC_SH4_FSI && FB_SH_MOBILE_HDMI
-       help
-         This option enables generic sound support for the
-         FSI - HDMI unit
-
 config SND_SIU_MIGOR
        tristate "SIU sound support on Migo-R"
        depends on SH_MIGOR
index 94476d4c0fd58f01b9ae46691f9b6621b66cac95..849b387d17d99a7d91b21bd1f64adc228341cfb9 100644 (file)
@@ -14,13 +14,7 @@ obj-$(CONFIG_SND_SOC_SH4_SIU)        += snd-soc-siu.o
 
 ## boards
 snd-soc-sh7760-ac97-objs       := sh7760-ac97.o
-snd-soc-fsi-ak4642-objs                := fsi-ak4642.o
-snd-soc-fsi-da7210-objs                := fsi-da7210.o
-snd-soc-fsi-hdmi-objs          := fsi-hdmi.o
 snd-soc-migor-objs             := migor.o
 
 obj-$(CONFIG_SND_SH7760_AC97)  += snd-soc-sh7760-ac97.o
-obj-$(CONFIG_SND_FSI_AK4642)   += snd-soc-fsi-ak4642.o
-obj-$(CONFIG_SND_FSI_DA7210)   += snd-soc-fsi-da7210.o
-obj-$(CONFIG_SND_FSI_HDMI)     += snd-soc-fsi-hdmi.o
 obj-$(CONFIG_SND_SIU_MIGOR)    += snd-soc-migor.o
diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c
deleted file mode 100644 (file)
index 97f540a..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * FSI-AK464x sound support for ms7724se
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/sh_fsi.h>
-
-struct fsi_ak4642_data {
-       const char *name;
-       const char *card;
-       const char *cpu_dai;
-       const char *codec;
-       const char *platform;
-       int id;
-};
-
-static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_dai *codec = rtd->codec_dai;
-       struct snd_soc_dai *cpu = rtd->cpu_dai;
-       int ret;
-
-       ret = snd_soc_dai_set_fmt(codec, SND_SOC_DAIFMT_LEFT_J |
-                                        SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_sysclk(codec, 0, 11289600, 0);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_LEFT_J |
-                                      SND_SOC_DAIFMT_CBS_CFS);
-
-       return ret;
-}
-
-static struct snd_soc_dai_link fsi_dai_link = {
-       .codec_dai_name = "ak4642-hifi",
-       .init           = fsi_ak4642_dai_init,
-};
-
-static struct snd_soc_card fsi_soc_card  = {
-       .owner          = THIS_MODULE,
-       .dai_link       = &fsi_dai_link,
-       .num_links      = 1,
-};
-
-static struct platform_device *fsi_snd_device;
-
-static int fsi_ak4642_probe(struct platform_device *pdev)
-{
-       int ret = -ENOMEM;
-       struct fsi_ak4642_info *pinfo = pdev->dev.platform_data;
-
-       if (!pinfo) {
-               dev_err(&pdev->dev, "no info for fsi ak4642\n");
-               goto out;
-       }
-
-       fsi_snd_device = platform_device_alloc("soc-audio", pinfo->id);
-       if (!fsi_snd_device)
-               goto out;
-
-       fsi_dai_link.name               = pinfo->name;
-       fsi_dai_link.stream_name        = pinfo->name;
-       fsi_dai_link.cpu_dai_name       = pinfo->cpu_dai;
-       fsi_dai_link.platform_name      = pinfo->platform;
-       fsi_dai_link.codec_name         = pinfo->codec;
-       fsi_soc_card.name               = pinfo->card;
-
-       platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
-       ret = platform_device_add(fsi_snd_device);
-
-       if (ret)
-               platform_device_put(fsi_snd_device);
-
-out:
-       return ret;
-}
-
-static int fsi_ak4642_remove(struct platform_device *pdev)
-{
-       platform_device_unregister(fsi_snd_device);
-       return 0;
-}
-
-static struct platform_driver fsi_ak4642 = {
-       .driver = {
-               .name   = "fsi-ak4642-audio",
-       },
-       .probe          = fsi_ak4642_probe,
-       .remove         = fsi_ak4642_remove,
-};
-
-module_platform_driver(fsi_ak4642);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic SH4 FSI-AK4642 sound card");
-MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
deleted file mode 100644 (file)
index 1dd3354..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * fsi-da7210.c
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/sh_fsi.h>
-
-static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_dai *codec = rtd->codec_dai;
-       struct snd_soc_dai *cpu = rtd->cpu_dai;
-       int ret;
-
-       ret = snd_soc_dai_set_fmt(codec,
-                                  SND_SOC_DAIFMT_I2S |
-                                  SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_I2S |
-                                      SND_SOC_DAIFMT_CBS_CFS);
-
-       return ret;
-}
-
-static struct snd_soc_dai_link fsi_da7210_dai = {
-       .name           = "DA7210",
-       .stream_name    = "DA7210",
-       .cpu_dai_name   = "fsib-dai", /* FSI B */
-       .codec_dai_name = "da7210-hifi",
-       .platform_name  = "sh_fsi.0",
-       .codec_name     = "da7210-codec.0-001a",
-       .init           = fsi_da7210_init,
-};
-
-static struct snd_soc_card fsi_soc_card = {
-       .name           = "FSI-DA7210",
-       .owner          = THIS_MODULE,
-       .dai_link       = &fsi_da7210_dai,
-       .num_links      = 1,
-};
-
-static struct platform_device *fsi_da7210_snd_device;
-
-static int __init fsi_da7210_sound_init(void)
-{
-       int ret;
-
-       fsi_da7210_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B);
-       if (!fsi_da7210_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(fsi_da7210_snd_device, &fsi_soc_card);
-       ret = platform_device_add(fsi_da7210_snd_device);
-       if (ret)
-               platform_device_put(fsi_da7210_snd_device);
-
-       return ret;
-}
-
-static void __exit fsi_da7210_sound_exit(void)
-{
-       platform_device_unregister(fsi_da7210_snd_device);
-}
-
-module_init(fsi_da7210_sound_init);
-module_exit(fsi_da7210_sound_exit);
-
-/* Module information */
-MODULE_DESCRIPTION("ALSA SoC FSI DA2710");
-MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c
deleted file mode 100644 (file)
index 6e41908..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * FSI - HDMI sound support
- *
- * Copyright (C) 2010 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/sh_fsi.h>
-
-struct fsi_hdmi_data {
-       const char *cpu_dai;
-       const char *card;
-       int id;
-};
-
-static int fsi_hdmi_dai_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_dai *cpu = rtd->cpu_dai;
-       int ret;
-
-       ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_CBM_CFM);
-
-       return ret;
-}
-
-static struct snd_soc_dai_link fsi_dai_link = {
-       .name           = "HDMI",
-       .stream_name    = "HDMI",
-       .codec_dai_name = "sh_mobile_hdmi-hifi",
-       .platform_name  = "sh_fsi2",
-       .codec_name     = "sh-mobile-hdmi",
-       .init           = fsi_hdmi_dai_init,
-};
-
-static struct snd_soc_card fsi_soc_card  = {
-       .owner          = THIS_MODULE,
-       .dai_link       = &fsi_dai_link,
-       .num_links      = 1,
-};
-
-static struct platform_device *fsi_snd_device;
-
-static int fsi_hdmi_probe(struct platform_device *pdev)
-{
-       int ret = -ENOMEM;
-       const struct platform_device_id *id_entry;
-       struct fsi_hdmi_data *pdata;
-
-       id_entry = pdev->id_entry;
-       if (!id_entry) {
-               dev_err(&pdev->dev, "unknown fsi hdmi\n");
-               return -ENODEV;
-       }
-
-       pdata = (struct fsi_hdmi_data *)id_entry->driver_data;
-
-       fsi_snd_device = platform_device_alloc("soc-audio", pdata->id);
-       if (!fsi_snd_device)
-               goto out;
-
-       fsi_dai_link.cpu_dai_name       = pdata->cpu_dai;
-       fsi_soc_card.name               = pdata->card;
-
-       platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
-       ret = platform_device_add(fsi_snd_device);
-
-       if (ret)
-               platform_device_put(fsi_snd_device);
-
-out:
-       return ret;
-}
-
-static int fsi_hdmi_remove(struct platform_device *pdev)
-{
-       platform_device_unregister(fsi_snd_device);
-       return 0;
-}
-
-static struct fsi_hdmi_data fsi2_a_hdmi = {
-       .cpu_dai        = "fsia-dai",
-       .card           = "FSI2A-HDMI",
-       .id             = FSI_PORT_A,
-};
-
-static struct fsi_hdmi_data fsi2_b_hdmi = {
-       .cpu_dai        = "fsib-dai",
-       .card           = "FSI2B-HDMI",
-       .id             = FSI_PORT_B,
-};
-
-static struct platform_device_id fsi_id_table[] = {
-       /* FSI 2 */
-       { "sh_fsi2_a_hdmi",     (kernel_ulong_t)&fsi2_a_hdmi },
-       { "sh_fsi2_b_hdmi",     (kernel_ulong_t)&fsi2_b_hdmi },
-       {},
-};
-
-static struct platform_driver fsi_hdmi = {
-       .driver = {
-               .name   = "fsi-hdmi-audio",
-       },
-       .probe          = fsi_hdmi_probe,
-       .remove         = fsi_hdmi_remove,
-       .id_table       = fsi_id_table,
-};
-
-module_platform_driver(fsi_hdmi);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic SH4 FSI-HDMI sound card");
-MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
index 74ed2dffbffda4313401793b72bde4b6b2224eeb..7cee22515d9de55c505eae1dd460107b1eacee3a 100644 (file)
 
 typedef int (*set_rate_func)(struct device *dev, int rate, int enable);
 
+/*
+ * bus options
+ *
+ * 0x000000BA
+ *
+ * A : sample widtht 16bit setting
+ * B : sample widtht 24bit setting
+ */
+
+#define SHIFT_16DATA           0
+#define SHIFT_24DATA           4
+
+#define PACKAGE_24BITBUS_BACK          0
+#define PACKAGE_24BITBUS_FRONT         1
+#define PACKAGE_16BITBUS_STREAM                2
+
+#define BUSOP_SET(s, a)        ((a) << SHIFT_ ## s ## DATA)
+#define BUSOP_GET(s, a)        (((a) >> SHIFT_ ## s ## DATA) & 0xF)
+
 /*
  * FSI driver use below type name for variable
  *
@@ -188,6 +207,11 @@ struct fsi_stream {
        int uerr_num;
        int oerr_num;
 
+       /*
+        * bus options
+        */
+       u32 bus_option;
+
        /*
         * thse are initialized by fsi_handler_init()
         */
@@ -211,8 +235,7 @@ struct fsi_priv {
        struct fsi_stream playback;
        struct fsi_stream capture;
 
-       u32 do_fmt;
-       u32 di_fmt;
+       u32 fmt;
 
        int chan_num:16;
        int clk_master:1;
@@ -321,6 +344,10 @@ static void _fsi_master_mask_set(struct fsi_master *master,
 /*
  *             basic function
  */
+static int fsi_version(struct fsi_master *master)
+{
+       return master->core->ver;
+}
 
 static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
 {
@@ -495,6 +522,7 @@ static void fsi_stream_init(struct fsi_priv *fsi,
        io->period_samples      = fsi_frame2sample(fsi, runtime->period_size);
        io->period_pos          = 0;
        io->sample_width        = samples_to_bytes(runtime, 1);
+       io->bus_option          = 0;
        io->oerr_num    = -1; /* ignore 1st err */
        io->uerr_num    = -1; /* ignore 1st err */
        fsi_stream_handler_call(io, init, fsi, io);
@@ -522,6 +550,7 @@ static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io)
        io->period_samples      = 0;
        io->period_pos          = 0;
        io->sample_width        = 0;
+       io->bus_option          = 0;
        io->oerr_num    = 0;
        io->uerr_num    = 0;
        spin_unlock_irqrestore(&master->lock, flags);
@@ -580,6 +609,53 @@ static int fsi_stream_remove(struct fsi_priv *fsi)
        return 0;
 }
 
+/*
+ *     format/bus/dma setting
+ */
+static void fsi_format_bus_setup(struct fsi_priv *fsi, struct fsi_stream *io,
+                                u32 bus, struct device *dev)
+{
+       struct fsi_master *master = fsi_get_master(fsi);
+       int is_play = fsi_stream_is_play(fsi, io);
+       u32 fmt = fsi->fmt;
+
+       if (fsi_version(master) >= 2) {
+               u32 dma = 0;
+
+               /*
+                * FSI2 needs DMA/Bus setting
+                */
+               switch (bus) {
+               case PACKAGE_24BITBUS_FRONT:
+                       fmt |= CR_BWS_24;
+                       dma |= VDMD_FRONT;
+                       dev_dbg(dev, "24bit bus / package in front\n");
+                       break;
+               case PACKAGE_16BITBUS_STREAM:
+                       fmt |= CR_BWS_16;
+                       dma |= VDMD_STREAM;
+                       dev_dbg(dev, "16bit bus / stream mode\n");
+                       break;
+               case PACKAGE_24BITBUS_BACK:
+               default:
+                       fmt |= CR_BWS_24;
+                       dma |= VDMD_BACK;
+                       dev_dbg(dev, "24bit bus / package in back\n");
+                       break;
+               }
+
+               if (is_play)
+                       fsi_reg_write(fsi, OUT_DMAC,    dma);
+               else
+                       fsi_reg_write(fsi, IN_DMAC,     dma);
+       }
+
+       if (is_play)
+               fsi_reg_write(fsi, DO_FMT, fmt);
+       else
+               fsi_reg_write(fsi, DI_FMT, fmt);
+}
+
 /*
  *             irq function
  */
@@ -629,11 +705,6 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
        struct fsi_master *master = fsi_get_master(fsi);
        u32 mask, val;
 
-       if (master->core->ver < 2) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return;
-       }
-
        mask = BP | SE;
        val = enable ? mask : 0;
 
@@ -648,9 +719,7 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
 static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
                              long rate, int enable)
 {
-       struct fsi_master *master = fsi_get_master(fsi);
        set_rate_func set_rate = fsi_get_info_set_rate(fsi);
-       int fsi_ver = master->core->ver;
        int ret;
 
        if (!set_rate)
@@ -682,10 +751,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
                        data |= (0x3 << 12);
                        break;
                case SH_FSI_ACKMD_32:
-                       if (fsi_ver < 2)
-                               dev_err(dev, "unsupported ACKMD\n");
-                       else
-                               data |= (0x4 << 12);
+                       data |= (0x4 << 12);
                        break;
                }
 
@@ -708,10 +774,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
                        data |= (0x4 << 8);
                        break;
                case SH_FSI_BPFMD_16:
-                       if (fsi_ver < 2)
-                               dev_err(dev, "unsupported ACKMD\n");
-                       else
-                               data |= (0x7 << 8);
+                       data |= (0x7 << 8);
                        break;
                }
 
@@ -728,11 +791,26 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
  */
 static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples)
 {
-       u16 *buf = (u16 *)_buf;
+       u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE;
        int i;
 
-       for (i = 0; i < samples; i++)
-               fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
+       if (enable_stream) {
+               /*
+                * stream mode
+                * see
+                *      fsi_pio_push_init()
+                */
+               u32 *buf = (u32 *)_buf;
+
+               for (i = 0; i < samples / 2; i++)
+                       fsi_reg_write(fsi, DODT, buf[i]);
+       } else {
+               /* normal mode */
+               u16 *buf = (u16 *)_buf;
+
+               for (i = 0; i < samples; i++)
+                       fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
+       }
 }
 
 static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples)
@@ -872,12 +950,44 @@ static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
                fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
 }
 
+static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE;
+
+       /*
+        * we can use 16bit stream mode
+        * when "playback" and "16bit data"
+        * and platform allows "stream mode"
+        * see
+        *      fsi_pio_push16()
+        */
+       if (enable_stream)
+               io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+                                BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
+       else
+               io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+                                BUSOP_SET(16, PACKAGE_24BITBUS_BACK);
+       return 0;
+}
+
+static int fsi_pio_pop_init(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       /*
+        * always 24bit bus, package back when "capture"
+        */
+       io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+                        BUSOP_SET(16, PACKAGE_24BITBUS_BACK);
+       return 0;
+}
+
 static struct fsi_stream_handler fsi_pio_push_handler = {
+       .init           = fsi_pio_push_init,
        .transfer       = fsi_pio_push,
        .start_stop     = fsi_pio_start_stop,
 };
 
 static struct fsi_stream_handler fsi_pio_pop_handler = {
+       .init           = fsi_pio_pop_init,
        .transfer       = fsi_pio_pop,
        .start_stop     = fsi_pio_start_stop,
 };
@@ -919,6 +1029,13 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io)
        enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
                                DMA_TO_DEVICE : DMA_FROM_DEVICE;
 
+       /*
+        * 24bit data : 24bit bus / package in back
+        * 16bit data : 16bit bus / stream mode
+        */
+       io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+                        BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
+
        io->dma = dma_map_single(dai->dev, runtime->dma_area,
                                 snd_pcm_lib_buffer_bytes(io->substream), dir);
        return 0;
@@ -1055,25 +1172,9 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
 static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
                                 int start)
 {
-       u32 bws;
-       u32 dma;
+       u32 enable = start ? DMA_ON : 0;
 
-       switch (io->sample_width * start) {
-       case 2:
-               bws = CR_BWS_16;
-               dma = VDMD_STREAM | DMA_ON;
-               break;
-       case 4:
-               bws = CR_BWS_24;
-               dma = VDMD_BACK | DMA_ON;
-               break;
-       default:
-               bws = 0;
-               dma = 0;
-       }
-
-       fsi_reg_mask_set(fsi, DO_FMT, CR_BWS_MASK, bws);
-       fsi_reg_write(fsi, OUT_DMAC, dma);
+       fsi_reg_mask_set(fsi, OUT_DMAC, DMA_ON, enable);
 }
 
 static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
@@ -1176,8 +1277,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
                          struct fsi_stream *io,
                          struct device *dev)
 {
-       struct fsi_master *master = fsi_get_master(fsi);
-       int fsi_ver = master->core->ver;
        u32 flags = fsi_get_info_flags(fsi);
        u32 data = 0;
 
@@ -1200,10 +1299,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
 
        fsi_reg_write(fsi, CKG2, data);
 
-       /* set format */
-       fsi_reg_write(fsi, DO_FMT, fsi->do_fmt);
-       fsi_reg_write(fsi, DI_FMT, fsi->di_fmt);
-
        /* spdif ? */
        if (fsi_is_spdif(fsi)) {
                fsi_spdif_clk_ctrl(fsi, 1);
@@ -1211,15 +1306,18 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
        }
 
        /*
-        * FIXME
-        *
-        * FSI driver assumed that data package is in-back.
-        * FSI2 chip can select it.
+        * get bus settings
         */
-       if (fsi_ver >= 2) {
-               fsi_reg_write(fsi, OUT_DMAC,    (1 << 4));
-               fsi_reg_write(fsi, IN_DMAC,     (1 << 4));
+       data = 0;
+       switch (io->sample_width) {
+       case 2:
+               data = BUSOP_GET(16, io->bus_option);
+               break;
+       case 4:
+               data = BUSOP_GET(24, io->bus_option);
+               break;
        }
+       fsi_format_bus_setup(fsi, io, data, dev);
 
        /* irq clear */
        fsi_irq_disable(fsi, io);
@@ -1243,7 +1341,9 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
 
-       return fsi_hw_startup(fsi, fsi_stream_get(fsi, substream), dai->dev);
+       fsi->rate = 0;
+
+       return 0;
 }
 
 static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
@@ -1251,7 +1351,6 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
 
-       fsi_hw_shutdown(fsi, dai->dev);
        fsi->rate = 0;
 }
 
@@ -1265,11 +1364,13 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
                fsi_stream_init(fsi, io, substream);
+               fsi_hw_startup(fsi, io, dai->dev);
                ret = fsi_stream_transfer(io);
                if (0 == ret)
                        fsi_stream_start(fsi, io);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
+               fsi_hw_shutdown(fsi, dai->dev);
                fsi_stream_stop(fsi, io);
                fsi_stream_quit(fsi, io);
                break;
@@ -1280,42 +1381,33 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 
 static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt)
 {
-       u32 data = 0;
-
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
-               data = CR_I2S;
+               fsi->fmt = CR_I2S;
                fsi->chan_num = 2;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
-               data = CR_PCM;
+               fsi->fmt = CR_PCM;
                fsi->chan_num = 2;
                break;
        default:
                return -EINVAL;
        }
 
-       fsi->do_fmt = data;
-       fsi->di_fmt = data;
-
        return 0;
 }
 
 static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
 {
        struct fsi_master *master = fsi_get_master(fsi);
-       u32 data = 0;
 
-       if (master->core->ver < 2)
+       if (fsi_version(master) < 2)
                return -EINVAL;
 
-       data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM;
+       fsi->fmt = CR_DTMD_SPDIF_PCM | CR_PCM;
        fsi->chan_num = 2;
        fsi->spdif = 1;
 
-       fsi->do_fmt = data;
-       fsi->di_fmt = data;
-
        return 0;
 }
 
index c88d9741b9e7942e60ba17e3d98231136b607dc9..b37ee8077ed148613419ae37a4427ddb227ec095 100644 (file)
@@ -39,6 +39,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/soc-dpcm.h>
 #include <sound/initval.h>
 
 #define CREATE_TRACE_POINTS
@@ -54,7 +55,6 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
 #endif
 
 static DEFINE_MUTEX(client_mutex);
-static LIST_HEAD(card_list);
 static LIST_HEAD(dai_list);
 static LIST_HEAD(platform_list);
 static LIST_HEAD(codec_list);
@@ -465,6 +465,35 @@ static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card)
 }
 #endif
 
+struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
+               const char *dai_link, int stream)
+{
+       int i;
+
+       for (i = 0; i < card->num_links; i++) {
+               if (card->rtd[i].dai_link->no_pcm &&
+                       !strcmp(card->rtd[i].dai_link->name, dai_link))
+                       return card->rtd[i].pcm->streams[stream].substream;
+       }
+       dev_dbg(card->dev, "failed to find dai link %s\n", dai_link);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream);
+
+struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
+               const char *dai_link)
+{
+       int i;
+
+       for (i = 0; i < card->num_links; i++) {
+               if (!strcmp(card->rtd[i].dai_link->name, dai_link))
+                       return &card->rtd[i];
+       }
+       dev_dbg(card->dev, "failed to find rtd %s\n", dai_link);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
+
 #ifdef CONFIG_SND_SOC_AC97_BUS
 /* unregister ac97 codec */
 static int soc_ac97_dev_unregister(struct snd_soc_codec *codec)
@@ -567,19 +596,16 @@ int snd_soc_suspend(struct device *dev)
        }
 
        for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
 
                if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
                snd_soc_dapm_stream_event(&card->rtd[i],
                                          SNDRV_PCM_STREAM_PLAYBACK,
-                                         codec_dai,
                                          SND_SOC_DAPM_STREAM_SUSPEND);
 
                snd_soc_dapm_stream_event(&card->rtd[i],
                                          SNDRV_PCM_STREAM_CAPTURE,
-                                         codec_dai,
                                          SND_SOC_DAPM_STREAM_SUSPEND);
        }
 
@@ -683,17 +709,16 @@ static void soc_resume_deferred(struct work_struct *work)
        }
 
        for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
 
                if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
                snd_soc_dapm_stream_event(&card->rtd[i],
-                                         SNDRV_PCM_STREAM_PLAYBACK, codec_dai,
+                                         SNDRV_PCM_STREAM_PLAYBACK,
                                          SND_SOC_DAPM_STREAM_RESUME);
 
                snd_soc_dapm_stream_event(&card->rtd[i],
-                                         SNDRV_PCM_STREAM_CAPTURE, codec_dai,
+                                         SNDRV_PCM_STREAM_CAPTURE,
                                          SND_SOC_DAPM_STREAM_RESUME);
        }
 
@@ -783,15 +808,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
        struct snd_soc_dai *codec_dai, *cpu_dai;
        const char *platform_name;
 
-       if (rtd->complete)
-               return 1;
        dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num);
 
-       /* do we already have the CPU DAI for this link ? */
-       if (rtd->cpu_dai) {
-               goto find_codec;
-       }
-       /* no, then find CPU DAI from registered DAIs*/
+       /* Find CPU DAI from registered DAIs*/
        list_for_each_entry(cpu_dai, &dai_list, list) {
                if (dai_link->cpu_dai_of_node) {
                        if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
@@ -802,18 +821,15 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
                }
 
                rtd->cpu_dai = cpu_dai;
-               goto find_codec;
        }
-       dev_dbg(card->dev, "CPU DAI %s not registered\n",
-                       dai_link->cpu_dai_name);
 
-find_codec:
-       /* do we already have the CODEC for this link ? */
-       if (rtd->codec) {
-               goto find_platform;
+       if (!rtd->cpu_dai) {
+               dev_dbg(card->dev, "CPU DAI %s not registered\n",
+                       dai_link->cpu_dai_name);
+               return -EPROBE_DEFER;
        }
 
-       /* no, then find CODEC from registered CODECs*/
+       /* Find CODEC from registered CODECs */
        list_for_each_entry(codec, &codec_list, list) {
                if (dai_link->codec_of_node) {
                        if (codec->dev->of_node != dai_link->codec_of_node)
@@ -835,28 +851,28 @@ find_codec:
                                        dai_link->codec_dai_name)) {
 
                                rtd->codec_dai = codec_dai;
-                               goto find_platform;
                        }
                }
-               dev_dbg(card->dev, "CODEC DAI %s not registered\n",
-                               dai_link->codec_dai_name);
 
-               goto find_platform;
+               if (!rtd->codec_dai) {
+                       dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+                               dai_link->codec_dai_name);
+                       return -EPROBE_DEFER;
+               }
        }
-       dev_dbg(card->dev, "CODEC %s not registered\n",
-                       dai_link->codec_name);
 
-find_platform:
-       /* do we need a platform? */
-       if (rtd->platform)
-               goto out;
+       if (!rtd->codec) {
+               dev_dbg(card->dev, "CODEC %s not registered\n",
+                       dai_link->codec_name);
+               return -EPROBE_DEFER;
+       }
 
        /* if there's no platform we match on the empty platform */
        platform_name = dai_link->platform_name;
        if (!platform_name && !dai_link->platform_of_node)
                platform_name = "snd-soc-dummy";
 
-       /* no, then find one from the set of registered platforms */
+       /* find one from the set of registered platforms */
        list_for_each_entry(platform, &platform_list, list) {
                if (dai_link->platform_of_node) {
                        if (platform->dev->of_node !=
@@ -868,20 +884,16 @@ find_platform:
                }
 
                rtd->platform = platform;
-               goto out;
        }
-
-       dev_dbg(card->dev, "platform %s not registered\n",
+       if (!rtd->platform) {
+               dev_dbg(card->dev, "platform %s not registered\n",
                        dai_link->platform_name);
-       return 0;
-
-out:
-       /* mark rtd as complete if we found all 4 of our client devices */
-       if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) {
-               rtd->complete = 1;
-               card->num_rtd++;
+               return -EPROBE_DEFER;
        }
-       return 1;
+
+       card->num_rtd++;
+
+       return 0;
 }
 
 static void soc_remove_codec(struct snd_soc_codec *codec)
@@ -1068,6 +1080,7 @@ static int soc_probe_platform(struct snd_soc_card *card,
 {
        int ret = 0;
        const struct snd_soc_platform_driver *driver = platform->driver;
+       struct snd_soc_dai *dai;
 
        platform->card = card;
        platform->dapm.card = card;
@@ -1081,6 +1094,14 @@ static int soc_probe_platform(struct snd_soc_card *card,
                snd_soc_dapm_new_controls(&platform->dapm,
                        driver->dapm_widgets, driver->num_dapm_widgets);
 
+       /* Create DAPM widgets for each DAI stream */
+       list_for_each_entry(dai, &dai_list, list) {
+               if (dai->dev != platform->dev)
+                       continue;
+
+               snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);
+       }
+
        platform->dapm.idle_bias_off = 1;
 
        if (driver->probe) {
@@ -1170,6 +1191,10 @@ static int soc_post_component_init(struct snd_soc_card *card,
        rtd->dev->init_name = name;
        dev_set_drvdata(rtd->dev, rtd);
        mutex_init(&rtd->pcm_mutex);
+       INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients);
+       INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients);
+       INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients);
+       INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients);
        ret = device_add(rtd->dev);
        if (ret < 0) {
                dev_err(card->dev,
@@ -1191,6 +1216,17 @@ static int soc_post_component_init(struct snd_soc_card *card,
                dev_err(codec->dev,
                        "asoc: failed to add codec sysfs files: %d\n", ret);
 
+#ifdef CONFIG_DEBUG_FS
+       /* add DPCM sysfs entries */
+       if (!dailess && !dai_link->dynamic)
+               goto out;
+
+       ret = soc_dpcm_debugfs_add(rtd);
+       if (ret < 0)
+               dev_err(rtd->dev, "asoc: failed to add dpcm sysfs entries: %d\n", ret);
+
+out:
+#endif
        return 0;
 }
 
@@ -1200,14 +1236,15 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
        struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_platform *platform = rtd->platform;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dapm_widget *play_w, *capture_w;
        int ret;
 
        dev_dbg(card->dev, "probe %s dai link %d late %d\n",
                        card->name, num, order);
 
        /* config components */
-       codec_dai->codec = codec;
        cpu_dai->platform = platform;
        codec_dai->card = card;
        cpu_dai->card = card;
@@ -1218,9 +1255,12 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
        /* probe the cpu_dai */
        if (!cpu_dai->probed &&
                        cpu_dai->driver->probe_order == order) {
+               cpu_dai->dapm.card = card;
                if (!try_module_get(cpu_dai->dev->driver->owner))
                        return -ENODEV;
 
+               snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai);
+
                if (cpu_dai->driver->probe) {
                        ret = cpu_dai->driver->probe(cpu_dai);
                        if (ret < 0) {
@@ -1279,12 +1319,39 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
        if (ret < 0)
                pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret);
 
-       /* create the pcm */
-       ret = soc_new_pcm(rtd, num);
-       if (ret < 0) {
-               pr_err("asoc: can't create pcm %s :%d\n",
-                               dai_link->stream_name, ret);
-               return ret;
+       if (!dai_link->params) {
+               /* create the pcm */
+               ret = soc_new_pcm(rtd, num);
+               if (ret < 0) {
+                       pr_err("asoc: can't create pcm %s :%d\n",
+                              dai_link->stream_name, ret);
+                       return ret;
+               }
+       } else {
+               /* link the DAI widgets */
+               play_w = codec_dai->playback_widget;
+               capture_w = cpu_dai->capture_widget;
+               if (play_w && capture_w) {
+                       ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+                                                  capture_w, play_w);
+                       if (ret != 0) {
+                               dev_err(card->dev, "Can't link %s to %s: %d\n",
+                                       play_w->name, capture_w->name, ret);
+                               return ret;
+                       }
+               }
+
+               play_w = cpu_dai->playback_widget;
+               capture_w = codec_dai->capture_widget;
+               if (play_w && capture_w) {
+                       ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+                                                  capture_w, play_w);
+                       if (ret != 0) {
+                               dev_err(card->dev, "Can't link %s to %s: %d\n",
+                                       play_w->name, capture_w->name, ret);
+                               return ret;
+                       }
+               }
        }
 
        /* add platform data for AC97 devices */
@@ -1334,6 +1401,20 @@ static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
 }
 #endif
 
+static int soc_check_aux_dev(struct snd_soc_card *card, int num)
+{
+       struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+       struct snd_soc_codec *codec;
+
+       /* find CODEC from registered CODECs*/
+       list_for_each_entry(codec, &codec_list, list) {
+               if (!strcmp(codec->name, aux_dev->codec_name))
+                       return 0;
+       }
+
+       return -EPROBE_DEFER;
+}
+
 static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
 {
        struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
@@ -1354,7 +1435,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
        }
        /* codec not found */
        dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name);
-       goto out;
+       return -EPROBE_DEFER;
 
 found:
        ret = soc_probe_codec(card, codec);
@@ -1404,29 +1485,28 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,
        return 0;
 }
 
-static void snd_soc_instantiate_card(struct snd_soc_card *card)
+static int snd_soc_instantiate_card(struct snd_soc_card *card)
 {
        struct snd_soc_codec *codec;
        struct snd_soc_codec_conf *codec_conf;
        enum snd_soc_compress_type compress_type;
        struct snd_soc_dai_link *dai_link;
-       int ret, i, order;
+       int ret, i, order, dai_fmt;
 
-       mutex_lock(&card->mutex);
-
-       if (card->instantiated) {
-               mutex_unlock(&card->mutex);
-               return;
-       }
+       mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
 
        /* bind DAIs */
-       for (i = 0; i < card->num_links; i++)
-               soc_bind_dai_link(card, i);
+       for (i = 0; i < card->num_links; i++) {
+               ret = soc_bind_dai_link(card, i);
+               if (ret != 0)
+                       goto base_error;
+       }
 
-       /* bind completed ? */
-       if (card->num_rtd != card->num_links) {
-               mutex_unlock(&card->mutex);
-               return;
+       /* check aux_devs too */
+       for (i = 0; i < card->num_aux_devs; i++) {
+               ret = soc_check_aux_dev(card, i);
+               if (ret != 0)
+                       goto base_error;
        }
 
        /* initialize the register cache for each available codec */
@@ -1446,10 +1526,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
                        }
                }
                ret = snd_soc_init_codec_cache(codec, compress_type);
-               if (ret < 0) {
-                       mutex_unlock(&card->mutex);
-                       return;
-               }
+               if (ret < 0)
+                       goto base_error;
        }
 
        /* card bind complete so register a sound card */
@@ -1458,8 +1536,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        if (ret < 0) {
                pr_err("asoc: can't create sound card for card %s: %d\n",
                        card->name, ret);
-               mutex_unlock(&card->mutex);
-               return;
+               goto base_error;
        }
        card->snd_card->dev = card->dev;
 
@@ -1523,17 +1600,47 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
 
        for (i = 0; i < card->num_links; i++) {
                dai_link = &card->dai_link[i];
+               dai_fmt = dai_link->dai_fmt;
 
-               if (dai_link->dai_fmt) {
+               if (dai_fmt) {
                        ret = snd_soc_dai_set_fmt(card->rtd[i].codec_dai,
-                                                 dai_link->dai_fmt);
+                                                 dai_fmt);
                        if (ret != 0 && ret != -ENOTSUPP)
                                dev_warn(card->rtd[i].codec_dai->dev,
                                         "Failed to set DAI format: %d\n",
                                         ret);
+               }
 
+               /* If this is a regular CPU link there will be a platform */
+               if (dai_fmt &&
+                   (dai_link->platform_name || dai_link->platform_of_node)) {
                        ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
-                                                 dai_link->dai_fmt);
+                                                 dai_fmt);
+                       if (ret != 0 && ret != -ENOTSUPP)
+                               dev_warn(card->rtd[i].cpu_dai->dev,
+                                        "Failed to set DAI format: %d\n",
+                                        ret);
+               } else if (dai_fmt) {
+                       /* Flip the polarity for the "CPU" end */
+                       dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+                       switch (dai_link->dai_fmt &
+                               SND_SOC_DAIFMT_MASTER_MASK) {
+                       case SND_SOC_DAIFMT_CBM_CFM:
+                               dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+                               break;
+                       case SND_SOC_DAIFMT_CBM_CFS:
+                               dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
+                               break;
+                       case SND_SOC_DAIFMT_CBS_CFM:
+                               dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
+                               break;
+                       case SND_SOC_DAIFMT_CBS_CFS:
+                               dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+                               break;
+                       }
+
+                       ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
+                                                 dai_fmt);
                        if (ret != 0 && ret != -ENOTSUPP)
                                dev_warn(card->rtd[i].cpu_dai->dev,
                                         "Failed to set DAI format: %d\n",
@@ -1599,7 +1706,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        card->instantiated = 1;
        snd_soc_dapm_sync(&card->dapm);
        mutex_unlock(&card->mutex);
-       return;
+
+       return 0;
 
 probe_aux_dev_err:
        for (i = 0; i < card->num_aux_devs; i++)
@@ -1614,18 +1722,10 @@ card_probe_error:
 
        snd_card_free(card->snd_card);
 
+base_error:
        mutex_unlock(&card->mutex);
-}
 
-/*
- * Attempt to initialise any uninitialised cards.  Must be called with
- * client_mutex.
- */
-static void snd_soc_instantiate_cards(void)
-{
-       struct snd_soc_card *card;
-       list_for_each_entry(card, &card_list, list)
-               snd_soc_instantiate_card(card);
+       return ret;
 }
 
 /* probes a new socdev */
@@ -2526,6 +2626,87 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
 
+/**
+ * snd_soc_get_volsw_sx - single mixer get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a single mixer control, or a double mixer
+ * control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+           (struct soc_mixer_control *)kcontrol->private_value;
+
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       unsigned int rshift = mc->rshift;
+       int max = mc->max;
+       int min = mc->min;
+       int mask = (1 << (fls(min + max) - 1)) - 1;
+
+       ucontrol->value.integer.value[0] =
+           ((snd_soc_read(codec, reg) >> shift) - min) & mask;
+
+       if (snd_soc_volsw_is_stereo(mc))
+               ucontrol->value.integer.value[1] =
+                       ((snd_soc_read(codec, reg2) >> rshift) - min) & mask;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
+
+/**
+ * snd_soc_put_volsw_sx - double mixer set callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a double mixer control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+           (struct soc_mixer_control *)kcontrol->private_value;
+
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       unsigned int rshift = mc->rshift;
+       int max = mc->max;
+       int min = mc->min;
+       int mask = (1 << (fls(min + max) - 1)) - 1;
+       int err = 0;
+       unsigned short val, val_mask, val2 = 0;
+
+       val_mask = mask << shift;
+       val = (ucontrol->value.integer.value[0] + min) & mask;
+       val = val << shift;
+
+       if (snd_soc_update_bits_locked(codec, reg, val_mask, val))
+                       return err;
+
+       if (snd_soc_volsw_is_stereo(mc)) {
+               val_mask = mask << rshift;
+               val2 = (ucontrol->value.integer.value[1] + min) & mask;
+               val2 = val2 << rshift;
+
+               if (snd_soc_update_bits_locked(codec, reg2, val_mask, val2))
+                       return err;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx);
+
 /**
  * snd_soc_info_volsw_s8 - signed mixer info callback
  * @kcontrol: mixer control
@@ -2647,99 +2828,6 @@ int snd_soc_limit_volume(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
 
-/**
- * snd_soc_info_volsw_2r_sx - double with tlv and variable data size
- *  mixer info callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_info *uinfo)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       int max = mc->max;
-       int min = mc->min;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 2;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = max-min;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx);
-
-/**
- * snd_soc_get_volsw_2r_sx - double with tlv and variable data size
- *  mixer get callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int mask = (1<<mc->shift)-1;
-       int min = mc->min;
-       int val = snd_soc_read(codec, mc->reg) & mask;
-       int valr = snd_soc_read(codec, mc->rreg) & mask;
-
-       ucontrol->value.integer.value[0] = ((val & 0xff)-min) & mask;
-       ucontrol->value.integer.value[1] = ((valr & 0xff)-min) & mask;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx);
-
-/**
- * snd_soc_put_volsw_2r_sx - double with tlv and variable data size
- *  mixer put callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int mask = (1<<mc->shift)-1;
-       int min = mc->min;
-       int ret;
-       unsigned int val, valr, oval, ovalr;
-
-       val = ((ucontrol->value.integer.value[0]+min) & 0xff);
-       val &= mask;
-       valr = ((ucontrol->value.integer.value[1]+min) & 0xff);
-       valr &= mask;
-
-       oval = snd_soc_read(codec, mc->reg) & mask;
-       ovalr = snd_soc_read(codec, mc->rreg) & mask;
-
-       ret = 0;
-       if (oval != val) {
-               ret = snd_soc_write(codec, mc->reg, val);
-               if (ret < 0)
-                       return ret;
-       }
-       if (ovalr != valr) {
-               ret = snd_soc_write(codec, mc->rreg, valr);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
-
 int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
                       struct snd_ctl_elem_info *uinfo)
 {
@@ -2849,6 +2937,186 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_GPL(snd_soc_bytes_put);
 
+/**
+ * snd_soc_info_xr_sx - signed multi register info callback
+ * @kcontrol: mreg control
+ * @uinfo: control element information
+ *
+ * Callback to provide information of a control that can
+ * span multiple codec registers which together
+ * forms a single signed value in a MSB/LSB manner.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       struct soc_mreg_control *mc =
+               (struct soc_mreg_control *)kcontrol->private_value;
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = mc->min;
+       uinfo->value.integer.max = mc->max;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx);
+
+/**
+ * snd_soc_get_xr_sx - signed multi register get callback
+ * @kcontrol: mreg control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a control that can span
+ * multiple codec registers which together forms a single
+ * signed value in a MSB/LSB manner. The control supports
+ * specifying total no of bits used to allow for bitfields
+ * across the multiple codec registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mreg_control *mc =
+               (struct soc_mreg_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int regbase = mc->regbase;
+       unsigned int regcount = mc->regcount;
+       unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE;
+       unsigned int regwmask = (1<<regwshift)-1;
+       unsigned int invert = mc->invert;
+       unsigned long mask = (1UL<<mc->nbits)-1;
+       long min = mc->min;
+       long max = mc->max;
+       long val = 0;
+       unsigned long regval;
+       unsigned int i;
+
+       for (i = 0; i < regcount; i++) {
+               regval = snd_soc_read(codec, regbase+i) & regwmask;
+               val |= regval << (regwshift*(regcount-i-1));
+       }
+       val &= mask;
+       if (min < 0 && val > max)
+               val |= ~mask;
+       if (invert)
+               val = max - val;
+       ucontrol->value.integer.value[0] = val;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx);
+
+/**
+ * snd_soc_put_xr_sx - signed multi register get callback
+ * @kcontrol: mreg control
+ * @ucontrol: control element information
+ *
+ * Callback to set the value of a control that can span
+ * multiple codec registers which together forms a single
+ * signed value in a MSB/LSB manner. The control supports
+ * specifying total no of bits used to allow for bitfields
+ * across the multiple codec registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mreg_control *mc =
+               (struct soc_mreg_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int regbase = mc->regbase;
+       unsigned int regcount = mc->regcount;
+       unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE;
+       unsigned int regwmask = (1<<regwshift)-1;
+       unsigned int invert = mc->invert;
+       unsigned long mask = (1UL<<mc->nbits)-1;
+       long max = mc->max;
+       long val = ucontrol->value.integer.value[0];
+       unsigned int i, regval, regmask;
+       int err;
+
+       if (invert)
+               val = max - val;
+       val &= mask;
+       for (i = 0; i < regcount; i++) {
+               regval = (val >> (regwshift*(regcount-i-1))) & regwmask;
+               regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask;
+               err = snd_soc_update_bits_locked(codec, regbase+i,
+                               regmask, regval);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx);
+
+/**
+ * snd_soc_get_strobe - strobe get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback get the value of a strobe mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int shift = mc->shift;
+       unsigned int mask = 1 << shift;
+       unsigned int invert = mc->invert != 0;
+       unsigned int val = snd_soc_read(codec, reg) & mask;
+
+       if (shift != 0 && val != 0)
+               val = val >> shift;
+       ucontrol->value.enumerated.item[0] = val ^ invert;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_strobe);
+
+/**
+ * snd_soc_put_strobe - strobe put callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback strobe a register bit to high then low (or the inverse)
+ * in one pass of a single mixer enum control.
+ *
+ * Returns 1 for success.
+ */
+int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int shift = mc->shift;
+       unsigned int mask = 1 << shift;
+       unsigned int invert = mc->invert != 0;
+       unsigned int strobe = ucontrol->value.enumerated.item[0] != 0;
+       unsigned int val1 = (strobe ^ invert) ? mask : 0;
+       unsigned int val2 = (strobe ^ invert) ? 0 : mask;
+       int err;
+
+       err = snd_soc_update_bits_locked(codec, reg, mask, val1);
+       if (err < 0)
+               return err;
+
+       err = snd_soc_update_bits_locked(codec, reg, mask, val2);
+       return err;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_strobe);
+
 /**
  * snd_soc_dai_set_sysclk - configure DAI system or master clock.
  * @dai: DAI
@@ -3048,7 +3316,7 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
        if (dai->driver && dai->driver->ops->digital_mute)
                return dai->driver->ops->digital_mute(dai, mute);
        else
-               return -EINVAL;
+               return -ENOTSUPP;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
 
@@ -3060,7 +3328,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
  */
 int snd_soc_register_card(struct snd_soc_card *card)
 {
-       int i;
+       int i, ret;
 
        if (!card->name || !card->dev)
                return -EINVAL;
@@ -3123,15 +3391,13 @@ int snd_soc_register_card(struct snd_soc_card *card)
        INIT_LIST_HEAD(&card->dapm_dirty);
        card->instantiated = 0;
        mutex_init(&card->mutex);
+       mutex_init(&card->dapm_mutex);
 
-       mutex_lock(&client_mutex);
-       list_add(&card->list, &card_list);
-       snd_soc_instantiate_cards();
-       mutex_unlock(&client_mutex);
-
-       dev_dbg(card->dev, "Registered card '%s'\n", card->name);
+       ret = snd_soc_instantiate_card(card);
+       if (ret != 0)
+               soc_cleanup_card_debugfs(card);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_register_card);
 
@@ -3145,9 +3411,6 @@ int snd_soc_unregister_card(struct snd_soc_card *card)
 {
        if (card->instantiated)
                soc_cleanup_card_resources(card);
-       mutex_lock(&client_mutex);
-       list_del(&card->list);
-       mutex_unlock(&client_mutex);
        dev_dbg(card->dev, "Unregistered card '%s'\n", card->name);
 
        return 0;
@@ -3221,6 +3484,7 @@ static inline char *fmt_multiple_name(struct device *dev,
 int snd_soc_register_dai(struct device *dev,
                struct snd_soc_dai_driver *dai_drv)
 {
+       struct snd_soc_codec *codec;
        struct snd_soc_dai *dai;
 
        dev_dbg(dev, "dai register %s\n", dev_name(dev));
@@ -3238,12 +3502,23 @@ int snd_soc_register_dai(struct device *dev,
 
        dai->dev = dev;
        dai->driver = dai_drv;
+       dai->dapm.dev = dev;
        if (!dai->driver->ops)
                dai->driver->ops = &null_dai_ops;
 
        mutex_lock(&client_mutex);
+
+       list_for_each_entry(codec, &codec_list, list) {
+               if (codec->dev == dev) {
+                       dev_dbg(dev, "Mapped DAI %s to CODEC %s\n",
+                               dai->name, codec->name);
+                       dai->codec = codec;
+                       break;
+               }
+       }
+
        list_add(&dai->list, &dai_list);
-       snd_soc_instantiate_cards();
+
        mutex_unlock(&client_mutex);
 
        pr_debug("Registered DAI '%s'\n", dai->name);
@@ -3287,6 +3562,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
 int snd_soc_register_dais(struct device *dev,
                struct snd_soc_dai_driver *dai_drv, size_t count)
 {
+       struct snd_soc_codec *codec;
        struct snd_soc_dai *dai;
        int i, ret = 0;
 
@@ -3314,19 +3590,28 @@ int snd_soc_register_dais(struct device *dev,
                        dai->id = dai->driver->id;
                else
                        dai->id = i;
+               dai->dapm.dev = dev;
                if (!dai->driver->ops)
                        dai->driver->ops = &null_dai_ops;
 
                mutex_lock(&client_mutex);
+
+               list_for_each_entry(codec, &codec_list, list) {
+                       if (codec->dev == dev) {
+                               dev_dbg(dev, "Mapped DAI %s to CODEC %s\n",
+                                       dai->name, codec->name);
+                               dai->codec = codec;
+                               break;
+                       }
+               }
+
                list_add(&dai->list, &dai_list);
+
                mutex_unlock(&client_mutex);
 
                pr_debug("Registered DAI '%s'\n", dai->name);
        }
 
-       mutex_lock(&client_mutex);
-       snd_soc_instantiate_cards();
-       mutex_unlock(&client_mutex);
        return 0;
 
 err:
@@ -3384,7 +3669,6 @@ int snd_soc_register_platform(struct device *dev,
 
        mutex_lock(&client_mutex);
        list_add(&platform->list, &platform_list);
-       snd_soc_instantiate_cards();
        mutex_unlock(&client_mutex);
 
        pr_debug("Registered platform '%s'\n", platform->name);
@@ -3534,18 +3818,18 @@ int snd_soc_register_codec(struct device *dev,
                fixup_codec_formats(&dai_drv[i].capture);
        }
 
+       mutex_lock(&client_mutex);
+       list_add(&codec->list, &codec_list);
+       mutex_unlock(&client_mutex);
+
        /* register any DAIs */
        if (num_dai) {
                ret = snd_soc_register_dais(dev, dai_drv, num_dai);
                if (ret < 0)
-                       goto fail;
+                       dev_err(codec->dev, "Failed to regster DAIs: %d\n",
+                               ret);
        }
 
-       mutex_lock(&client_mutex);
-       list_add(&codec->list, &codec_list);
-       snd_soc_instantiate_cards();
-       mutex_unlock(&client_mutex);
-
        pr_debug("Registered codec '%s'\n", codec->name);
        return 0;
 
index 1bb6d4a63cd8630854ae2b82f47a70057cdd753a..90ee77d2409da8402ea58026b788a624f850a25a 100644 (file)
@@ -52,6 +52,7 @@ static int dapm_up_seq[] = {
        [snd_soc_dapm_supply] = 1,
        [snd_soc_dapm_regulator_supply] = 1,
        [snd_soc_dapm_micbias] = 2,
+       [snd_soc_dapm_dai_link] = 2,
        [snd_soc_dapm_dai] = 3,
        [snd_soc_dapm_aif_in] = 3,
        [snd_soc_dapm_aif_out] = 3,
@@ -90,9 +91,10 @@ static int dapm_down_seq[] = {
        [snd_soc_dapm_aif_in] = 10,
        [snd_soc_dapm_aif_out] = 10,
        [snd_soc_dapm_dai] = 10,
-       [snd_soc_dapm_regulator_supply] = 11,
-       [snd_soc_dapm_supply] = 11,
-       [snd_soc_dapm_post] = 12,
+       [snd_soc_dapm_dai_link] = 11,
+       [snd_soc_dapm_regulator_supply] = 12,
+       [snd_soc_dapm_supply] = 12,
+       [snd_soc_dapm_post] = 13,
 };
 
 static void pop_wait(u32 pop_time)
@@ -208,7 +210,23 @@ static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val)
        return -1;
 }
 
-static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
+static inline void soc_widget_lock(struct snd_soc_dapm_widget *w)
+{
+       if (w->codec && !w->codec->using_regmap)
+               mutex_lock(&w->codec->mutex);
+       else if (w->platform)
+               mutex_lock(&w->platform->mutex);
+}
+
+static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w)
+{
+       if (w->codec && !w->codec->using_regmap)
+               mutex_unlock(&w->codec->mutex);
+       else if (w->platform)
+               mutex_unlock(&w->platform->mutex);
+}
+
+static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
        unsigned short reg, unsigned int mask, unsigned int value)
 {
        bool change;
@@ -221,18 +239,24 @@ static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
                if (ret != 0)
                        return ret;
        } else {
+               soc_widget_lock(w);
                ret = soc_widget_read(w, reg);
-               if (ret < 0)
+               if (ret < 0) {
+                       soc_widget_unlock(w);
                        return ret;
+               }
 
                old = ret;
                new = (old & ~mask) | (value & mask);
                change = old != new;
                if (change) {
                        ret = soc_widget_write(w, reg, new);
-                       if (ret < 0)
+                       if (ret < 0) {
+                               soc_widget_unlock(w);
                                return ret;
+                       }
                }
+               soc_widget_unlock(w);
        }
 
        return change;
@@ -374,6 +398,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        case snd_soc_dapm_mic:
        case snd_soc_dapm_spk:
        case snd_soc_dapm_line:
+       case snd_soc_dapm_dai_link:
                p->connect = 1;
        break;
        /* does affect routing - dynamically connected */
@@ -682,11 +707,51 @@ static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
        }
 }
 
+/* add widget to list if it's not already in the list */
+static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list,
+       struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_dapm_widget_list *wlist;
+       int wlistsize, wlistentries, i;
+
+       if (*list == NULL)
+               return -EINVAL;
+
+       wlist = *list;
+
+       /* is this widget already in the list */
+       for (i = 0; i < wlist->num_widgets; i++) {
+               if (wlist->widgets[i] == w)
+                       return 0;
+       }
+
+       /* allocate some new space */
+       wlistentries = wlist->num_widgets + 1;
+       wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+                       wlistentries * sizeof(struct snd_soc_dapm_widget *);
+       *list = krealloc(wlist, wlistsize, GFP_KERNEL);
+       if (*list == NULL) {
+               dev_err(w->dapm->dev, "can't allocate widget list for %s\n",
+                       w->name);
+               return -ENOMEM;
+       }
+       wlist = *list;
+
+       /* insert the widget */
+       dev_dbg(w->dapm->dev, "added %s in widget list pos %d\n",
+                       w->name, wlist->num_widgets);
+
+       wlist->widgets[wlist->num_widgets] = w;
+       wlist->num_widgets++;
+       return 1;
+}
+
 /*
  * Recursively check for a completed path to an active or physically connected
  * output widget. Returns number of complete paths.
  */
-static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
+static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
+       struct snd_soc_dapm_widget_list **list)
 {
        struct snd_soc_dapm_path *path;
        int con = 0;
@@ -742,9 +807,23 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
                if (path->walked)
                        continue;
 
+               trace_snd_soc_dapm_output_path(widget, path);
+
                if (path->sink && path->connect) {
                        path->walked = 1;
-                       con += is_connected_output_ep(path->sink);
+
+                       /* do we need to add this widget to the list ? */
+                       if (list) {
+                               int err;
+                               err = dapm_list_add_widget(list, path->sink);
+                               if (err < 0) {
+                                       dev_err(widget->dapm->dev, "could not add widget %s\n",
+                                               widget->name);
+                                       return con;
+                               }
+                       }
+
+                       con += is_connected_output_ep(path->sink, list);
                }
        }
 
@@ -757,7 +836,8 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
  * Recursively check for a completed path to an active or physically connected
  * input widget. Returns number of complete paths.
  */
-static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
+static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
+       struct snd_soc_dapm_widget_list **list)
 {
        struct snd_soc_dapm_path *path;
        int con = 0;
@@ -825,9 +905,23 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
                if (path->walked)
                        continue;
 
+               trace_snd_soc_dapm_input_path(widget, path);
+
                if (path->source && path->connect) {
                        path->walked = 1;
-                       con += is_connected_input_ep(path->source);
+
+                       /* do we need to add this widget to the list ? */
+                       if (list) {
+                               int err;
+                               err = dapm_list_add_widget(list, path->sink);
+                               if (err < 0) {
+                                       dev_err(widget->dapm->dev, "could not add widget %s\n",
+                                               widget->name);
+                                       return con;
+                               }
+                       }
+
+                       con += is_connected_input_ep(path->source, list);
                }
        }
 
@@ -836,6 +930,39 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
        return con;
 }
 
+/**
+ * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
+ * @dai: the soc DAI.
+ * @stream: stream direction.
+ * @list: list of active widgets for this stream.
+ *
+ * Queries DAPM graph as to whether an valid audio stream path exists for
+ * the initial stream specified by name. This takes into account
+ * current mixer and mux kcontrol settings. Creates list of valid widgets.
+ *
+ * Returns the number of valid paths or negative error.
+ */
+int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
+       struct snd_soc_dapm_widget_list **list)
+{
+       struct snd_soc_card *card = dai->card;
+       int paths;
+
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       dapm_reset(card);
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               paths = is_connected_output_ep(dai->playback_widget, list);
+       else
+               paths = is_connected_input_ep(dai->playback_widget, list);
+
+       trace_snd_soc_dapm_connected(paths, stream);
+       dapm_clear_walk(&card->dapm);
+       mutex_unlock(&card->dapm_mutex);
+
+       return paths;
+}
+
 /*
  * Handler for generic register modifier widget.
  */
@@ -849,7 +976,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
        else
                val = w->off_val;
 
-       soc_widget_update_bits(w, -(w->reg + 1),
+       soc_widget_update_bits_locked(w, -(w->reg + 1),
                            w->mask << w->shift, val << w->shift);
 
        return 0;
@@ -863,9 +990,9 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event)
 {
        if (SND_SOC_DAPM_EVENT_ON(event))
-               return regulator_enable(w->priv);
+               return regulator_enable(w->regulator);
        else
-               return regulator_disable_deferred(w->priv, w->shift);
+               return regulator_disable_deferred(w->regulator, w->shift);
 }
 EXPORT_SYMBOL_GPL(dapm_regulator_event);
 
@@ -892,9 +1019,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
 
        DAPM_UPDATE_STAT(w, power_checks);
 
-       in = is_connected_input_ep(w);
+       in = is_connected_input_ep(w, NULL);
        dapm_clear_walk(w->dapm);
-       out = is_connected_output_ep(w);
+       out = is_connected_output_ep(w, NULL);
        dapm_clear_walk(w->dapm);
        return out != 0 && in != 0;
 }
@@ -903,7 +1030,10 @@ static int dapm_dai_check_power(struct snd_soc_dapm_widget *w)
 {
        DAPM_UPDATE_STAT(w, power_checks);
 
-       return w->active;
+       if (w->active)
+               return w->active;
+
+       return dapm_generic_check_power(w);
 }
 
 /* Check to see if an ADC has power */
@@ -914,7 +1044,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
        DAPM_UPDATE_STAT(w, power_checks);
 
        if (w->active) {
-               in = is_connected_input_ep(w);
+               in = is_connected_input_ep(w, NULL);
                dapm_clear_walk(w->dapm);
                return in != 0;
        } else {
@@ -930,7 +1060,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
        DAPM_UPDATE_STAT(w, power_checks);
 
        if (w->active) {
-               out = is_connected_output_ep(w);
+               out = is_connected_output_ep(w, NULL);
                dapm_clear_walk(w->dapm);
                return out != 0;
        } else {
@@ -1107,7 +1237,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
                        "pop test : Applying 0x%x/0x%x to %x in %dms\n",
                        value, mask, reg, card->pop_time);
                pop_wait(card->pop_time);
-               soc_widget_update_bits(w, reg, mask, value);
+               soc_widget_update_bits_locked(w, reg, mask, value);
        }
 
        list_for_each_entry(w, pending, power_list) {
@@ -1237,7 +1367,7 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
                               w->name, ret);
        }
 
-       ret = snd_soc_update_bits(w->codec, update->reg, update->mask,
+       ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
                                  update->val);
        if (ret < 0)
                pr_err("%s DAPM update failed: %d\n", w->name, ret);
@@ -1421,12 +1551,10 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
        trace_snd_soc_dapm_start(card);
 
        list_for_each_entry(d, &card->dapm_list, list) {
-               if (d->n_widgets || d->codec == NULL) {
-                       if (d->idle_bias_off)
-                               d->target_bias_level = SND_SOC_BIAS_OFF;
-                       else
-                               d->target_bias_level = SND_SOC_BIAS_STANDBY;
-               }
+               if (d->idle_bias_off)
+                       d->target_bias_level = SND_SOC_BIAS_OFF;
+               else
+                       d->target_bias_level = SND_SOC_BIAS_STANDBY;
        }
 
        dapm_reset(card);
@@ -1471,32 +1599,6 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
 
        }
 
-       /* If there are no DAPM widgets then try to figure out power from the
-        * event type.
-        */
-       if (!dapm->n_widgets) {
-               switch (event) {
-               case SND_SOC_DAPM_STREAM_START:
-               case SND_SOC_DAPM_STREAM_RESUME:
-                       dapm->target_bias_level = SND_SOC_BIAS_ON;
-                       break;
-               case SND_SOC_DAPM_STREAM_STOP:
-                       if (dapm->codec && dapm->codec->active)
-                               dapm->target_bias_level = SND_SOC_BIAS_ON;
-                       else
-                               dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
-                       break;
-               case SND_SOC_DAPM_STREAM_SUSPEND:
-                       dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
-                       break;
-               case SND_SOC_DAPM_STREAM_NOP:
-                       dapm->target_bias_level = dapm->bias_level;
-                       break;
-               default:
-                       break;
-               }
-       }
-
        /* Force all contexts in the card to the same bias state if
         * they're not ground referenced.
         */
@@ -1560,9 +1662,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
        if (!buf)
                return -ENOMEM;
 
-       in = is_connected_input_ep(w);
+       in = is_connected_input_ep(w, NULL);
        dapm_clear_walk(w->dapm);
-       out = is_connected_output_ep(w);
+       out = is_connected_output_ep(w, NULL);
        dapm_clear_walk(w->dapm);
 
        ret = snprintf(buf, PAGE_SIZE, "%s: %s%s  in %d out %d",
@@ -1709,7 +1811,7 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
 #endif
 
 /* test and update the power status of a mux widget */
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
                                 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
 {
        struct snd_soc_dapm_path *path;
@@ -1746,12 +1848,26 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
                dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
        }
 
-       return 0;
+       return found;
+}
+
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+               struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
+{
+       struct snd_soc_card *card = widget->dapm->card;
+       int ret;
+
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+       mutex_unlock(&card->dapm_mutex);
+       if (ret > 0)
+               soc_dpcm_runtime_update(widget);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
 
 /* test and update the power status of a mixer or switch widget */
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
                                   struct snd_kcontrol *kcontrol, int connect)
 {
        struct snd_soc_dapm_path *path;
@@ -1778,7 +1894,21 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
                dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
        }
 
-       return 0;
+       return found;
+}
+
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+                               struct snd_kcontrol *kcontrol, int connect)
+{
+       struct snd_soc_card *card = widget->dapm->card;
+       int ret;
+
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
+       mutex_unlock(&card->dapm_mutex);
+       if (ret > 0)
+               soc_dpcm_runtime_update(widget);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
 
@@ -1939,6 +2069,8 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
  */
 int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
 {
+       int ret;
+
        /*
         * Suppress early reports (eg, jacks syncing their state) to avoid
         * silly DAPM runs during card startup.
@@ -1946,7 +2078,10 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
        if (!dapm->card || !dapm->card->instantiated)
                return 0;
 
-       return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+       mutex_unlock(&dapm->card->dapm_mutex);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
 
@@ -2055,6 +2190,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
        case snd_soc_dapm_aif_in:
        case snd_soc_dapm_aif_out:
        case snd_soc_dapm_dai:
+       case snd_soc_dapm_dai_link:
                list_add(&path->list, &dapm->card->paths);
                list_add(&path->list_sink, &wsink->sources);
                list_add(&path->list_source, &wsource->sinks);
@@ -2110,19 +2246,21 @@ err:
 int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
                            const struct snd_soc_dapm_route *route, int num)
 {
-       int i, ret;
+       int i, ret = 0;
 
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
        for (i = 0; i < num; i++) {
                ret = snd_soc_dapm_add_route(dapm, route);
                if (ret < 0) {
                        dev_err(dapm->dev, "Failed to add route %s->%s\n",
                                route->source, route->sink);
-                       return ret;
+                       break;
                }
                route++;
        }
+       mutex_unlock(&dapm->card->dapm_mutex);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
 
@@ -2193,12 +2331,14 @@ int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
        int i, err;
        int ret = 0;
 
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
        for (i = 0; i < num; i++) {
                err = snd_soc_dapm_weak_route(dapm, route);
                if (err)
                        ret = err;
                route++;
        }
+       mutex_unlock(&dapm->card->dapm_mutex);
 
        return ret;
 }
@@ -2217,6 +2357,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
        struct snd_soc_dapm_widget *w;
        unsigned int val;
 
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+
        list_for_each_entry(w, &dapm->card->widgets, list)
        {
                if (w->new)
@@ -2226,8 +2368,10 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
                        w->kcontrols = kzalloc(w->num_kcontrols *
                                                sizeof(struct snd_kcontrol *),
                                                GFP_KERNEL);
-                       if (!w->kcontrols)
+                       if (!w->kcontrols) {
+                               mutex_unlock(&dapm->card->dapm_mutex);
                                return -ENOMEM;
+                       }
                }
 
                switch(w->id) {
@@ -2267,6 +2411,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
        }
 
        dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+       mutex_unlock(&dapm->card->dapm_mutex);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -2326,6 +2471,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
        struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_card *card = codec->card;
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int reg = mc->reg;
@@ -2352,7 +2498,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
                /* old connection must be powered down */
                connect = invert ? 1 : 0;
 
-       mutex_lock(&codec->mutex);
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
        change = snd_soc_test_bits(widget->codec, reg, mask, val);
        if (change) {
@@ -2368,13 +2514,13 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
                        update.val = val;
                        widget->dapm->update = &update;
 
-                       snd_soc_dapm_mixer_update_power(widget, kcontrol, connect);
+                       soc_dapm_mixer_update_power(widget, kcontrol, connect);
 
                        widget->dapm->update = NULL;
                }
        }
 
-       mutex_unlock(&codec->mutex);
+       mutex_unlock(&card->dapm_mutex);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
@@ -2423,6 +2569,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
        struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_card *card = codec->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, mux, change;
        unsigned int mask, bitmask;
@@ -2443,7 +2590,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
                mask |= (bitmask - 1) << e->shift_r;
        }
 
-       mutex_lock(&codec->mutex);
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
        change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
        if (change) {
@@ -2459,13 +2606,13 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
                        update.val = val;
                        widget->dapm->update = &update;
 
-                       snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+                       soc_dapm_mux_update_power(widget, kcontrol, mux, e);
 
                        widget->dapm->update = NULL;
                }
        }
 
-       mutex_unlock(&codec->mutex);
+       mutex_unlock(&card->dapm_mutex);
        return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
@@ -2502,6 +2649,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
        struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_card *card = codec->card;
        struct soc_enum *e =
                (struct soc_enum *)kcontrol->private_value;
        int change;
@@ -2511,7 +2659,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
        if (ucontrol->value.enumerated.item[0] >= e->max)
                return -EINVAL;
 
-       mutex_lock(&codec->mutex);
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
        change = widget->value != ucontrol->value.enumerated.item[0];
        if (change) {
@@ -2520,11 +2668,11 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
 
                        widget->value = ucontrol->value.enumerated.item[0];
 
-                       snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
+                       soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
                }
        }
 
-       mutex_unlock(&codec->mutex);
+       mutex_unlock(&card->dapm_mutex);
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
@@ -2589,6 +2737,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
        struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_card *card = codec->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, mux, change;
        unsigned int mask;
@@ -2607,7 +2756,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
                mask |= e->mask << e->shift_r;
        }
 
-       mutex_lock(&codec->mutex);
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
        change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
        if (change) {
@@ -2623,13 +2772,13 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
                        update.val = val;
                        widget->dapm->update = &update;
 
-                       snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+                       soc_dapm_mux_update_power(widget, kcontrol, mux, e);
 
                        widget->dapm->update = NULL;
                }
        }
 
-       mutex_unlock(&codec->mutex);
+       mutex_unlock(&card->dapm_mutex);
        return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
@@ -2666,12 +2815,12 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
        struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
        const char *pin = (const char *)kcontrol->private_value;
 
-       mutex_lock(&card->mutex);
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
        ucontrol->value.integer.value[0] =
                snd_soc_dapm_get_pin_status(&card->dapm, pin);
 
-       mutex_unlock(&card->mutex);
+       mutex_unlock(&card->dapm_mutex);
 
        return 0;
 }
@@ -2689,17 +2838,16 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
        struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
        const char *pin = (const char *)kcontrol->private_value;
 
-       mutex_lock(&card->mutex);
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
        if (ucontrol->value.integer.value[0])
                snd_soc_dapm_enable_pin(&card->dapm, pin);
        else
                snd_soc_dapm_disable_pin(&card->dapm, pin);
 
-       snd_soc_dapm_sync(&card->dapm);
-
-       mutex_unlock(&card->mutex);
+       mutex_unlock(&card->dapm_mutex);
 
+       snd_soc_dapm_sync(&card->dapm);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
@@ -2717,9 +2865,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 
        switch (w->id) {
        case snd_soc_dapm_regulator_supply:
-               w->priv = devm_regulator_get(dapm->dev, w->name);
-               if (IS_ERR(w->priv)) {
-                       ret = PTR_ERR(w->priv);
+               w->regulator = devm_regulator_get(dapm->dev, w->name);
+               if (IS_ERR(w->regulator)) {
+                       ret = PTR_ERR(w->regulator);
                        dev_err(dapm->dev, "Failed to request %s: %d\n",
                                w->name, ret);
                        return NULL;
@@ -2771,6 +2919,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
        case snd_soc_dapm_hp:
        case snd_soc_dapm_mic:
        case snd_soc_dapm_line:
+       case snd_soc_dapm_dai_link:
                w->power_check = dapm_generic_check_power;
                break;
        case snd_soc_dapm_supply:
@@ -2816,21 +2965,177 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
 {
        struct snd_soc_dapm_widget *w;
        int i;
+       int ret = 0;
 
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
        for (i = 0; i < num; i++) {
                w = snd_soc_dapm_new_control(dapm, widget);
                if (!w) {
                        dev_err(dapm->dev,
                                "ASoC: Failed to create DAPM control %s\n",
                                widget->name);
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       break;
                }
                widget++;
        }
-       return 0;
+       mutex_unlock(&dapm->card->dapm_mutex);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
 
+static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
+                                 struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_dapm_path *source_p, *sink_p;
+       struct snd_soc_dai *source, *sink;
+       const struct snd_soc_pcm_stream *config = w->params;
+       struct snd_pcm_substream substream;
+       struct snd_pcm_hw_params *params = NULL;
+       u64 fmt;
+       int ret;
+
+       BUG_ON(!config);
+       BUG_ON(list_empty(&w->sources) || list_empty(&w->sinks));
+
+       /* We only support a single source and sink, pick the first */
+       source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path,
+                                   list_sink);
+       sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path,
+                                 list_source);
+
+       BUG_ON(!source_p || !sink_p);
+       BUG_ON(!sink_p->source || !source_p->sink);
+       BUG_ON(!source_p->source || !sink_p->sink);
+
+       source = source_p->source->priv;
+       sink = sink_p->sink->priv;
+
+       /* Be a little careful as we don't want to overflow the mask array */
+       if (config->formats) {
+               fmt = ffs(config->formats) - 1;
+       } else {
+               dev_warn(w->dapm->dev, "Invalid format %llx specified\n",
+                        config->formats);
+               fmt = 0;
+       }
+
+       /* Currently very limited parameter selection */
+       params = kzalloc(sizeof(*params), GFP_KERNEL);
+       if (!params) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
+
+       hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
+               config->rate_min;
+       hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
+               config->rate_max;
+
+       hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
+               = config->channels_min;
+       hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
+               = config->channels_max;
+
+       memset(&substream, 0, sizeof(substream));
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (source->driver->ops && source->driver->ops->hw_params) {
+                       substream.stream = SNDRV_PCM_STREAM_CAPTURE;
+                       ret = source->driver->ops->hw_params(&substream,
+                                                            params, source);
+                       if (ret != 0) {
+                               dev_err(source->dev,
+                                       "hw_params() failed: %d\n", ret);
+                               goto out;
+                       }
+               }
+
+               if (sink->driver->ops && sink->driver->ops->hw_params) {
+                       substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
+                       ret = sink->driver->ops->hw_params(&substream, params,
+                                                          sink);
+                       if (ret != 0) {
+                               dev_err(sink->dev,
+                                       "hw_params() failed: %d\n", ret);
+                               goto out;
+                       }
+               }
+               break;
+
+       case SND_SOC_DAPM_POST_PMU:
+               ret = snd_soc_dai_digital_mute(sink, 0);
+               if (ret != 0 && ret != -ENOTSUPP)
+                       dev_warn(sink->dev, "Failed to unmute: %d\n", ret);
+               ret = 0;
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               ret = snd_soc_dai_digital_mute(sink, 1);
+               if (ret != 0 && ret != -ENOTSUPP)
+                       dev_warn(sink->dev, "Failed to mute: %d\n", ret);
+               ret = 0;
+               break;
+
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+out:
+       kfree(params);
+       return ret;
+}
+
+int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
+                        const struct snd_soc_pcm_stream *params,
+                        struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_route routes[2];
+       struct snd_soc_dapm_widget template;
+       struct snd_soc_dapm_widget *w;
+       size_t len;
+       char *link_name;
+
+       len = strlen(source->name) + strlen(sink->name) + 2;
+       link_name = devm_kzalloc(card->dev, len, GFP_KERNEL);
+       if (!link_name)
+               return -ENOMEM;
+       snprintf(link_name, len, "%s-%s", source->name, sink->name);
+
+       memset(&template, 0, sizeof(template));
+       template.reg = SND_SOC_NOPM;
+       template.id = snd_soc_dapm_dai_link;
+       template.name = link_name;
+       template.event = snd_soc_dai_link_event;
+       template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+               SND_SOC_DAPM_PRE_PMD;
+
+       dev_dbg(card->dev, "adding %s widget\n", link_name);
+
+       w = snd_soc_dapm_new_control(&card->dapm, &template);
+       if (!w) {
+               dev_err(card->dev, "Failed to create %s widget\n",
+                       link_name);
+               return -ENOMEM;
+       }
+
+       w->params = params;
+
+       memset(&routes, 0, sizeof(routes));
+
+       routes[0].source = source->name;
+       routes[0].sink = link_name;
+       routes[1].source = link_name;
+       routes[1].sink = sink->name;
+
+       return snd_soc_dapm_add_routes(&card->dapm, routes,
+                                      ARRAY_SIZE(routes));
+}
+
 int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
                                 struct snd_soc_dai *dai)
 {
@@ -2934,37 +3239,61 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
        return 0;
 }
 
-static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
-                                 int stream, struct snd_soc_dai *dai,
-                                 int event)
+static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+       int event)
 {
-       struct snd_soc_dapm_widget *w;
 
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-               w = dai->playback_widget;
-       else
-               w = dai->capture_widget;
+       struct snd_soc_dapm_widget *w_cpu, *w_codec;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
-       if (!w)
-               return;
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               w_cpu = cpu_dai->playback_widget;
+               w_codec = codec_dai->playback_widget;
+       } else {
+               w_cpu = cpu_dai->capture_widget;
+               w_codec = codec_dai->capture_widget;
+       }
 
-       dapm_mark_dirty(w, "stream event");
+       if (w_cpu) {
 
-       switch (event) {
-       case SND_SOC_DAPM_STREAM_START:
-               w->active = 1;
-               break;
-       case SND_SOC_DAPM_STREAM_STOP:
-               w->active = 0;
-               break;
-       case SND_SOC_DAPM_STREAM_SUSPEND:
-       case SND_SOC_DAPM_STREAM_RESUME:
-       case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
-       case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
-               break;
+               dapm_mark_dirty(w_cpu, "stream event");
+
+               switch (event) {
+               case SND_SOC_DAPM_STREAM_START:
+                       w_cpu->active = 1;
+                       break;
+               case SND_SOC_DAPM_STREAM_STOP:
+                       w_cpu->active = 0;
+                       break;
+               case SND_SOC_DAPM_STREAM_SUSPEND:
+               case SND_SOC_DAPM_STREAM_RESUME:
+               case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
+               case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
+                       break;
+               }
+       }
+
+       if (w_codec) {
+
+               dapm_mark_dirty(w_codec, "stream event");
+
+               switch (event) {
+               case SND_SOC_DAPM_STREAM_START:
+                       w_codec->active = 1;
+                       break;
+               case SND_SOC_DAPM_STREAM_STOP:
+                       w_codec->active = 0;
+                       break;
+               case SND_SOC_DAPM_STREAM_SUSPEND:
+               case SND_SOC_DAPM_STREAM_RESUME:
+               case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
+               case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
+                       break;
+               }
        }
 
-       dapm_power_widgets(dapm, event);
+       dapm_power_widgets(&rtd->card->dapm, event);
 }
 
 /**
@@ -2978,15 +3307,14 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
  *
  * Returns 0 for success else error.
  */
-int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
-                             struct snd_soc_dai *dai, int event)
+void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+                             int event)
 {
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_card *card = rtd->card;
 
-       mutex_lock(&codec->mutex);
-       soc_dapm_stream_event(&codec->dapm, stream, dai, event);
-       mutex_unlock(&codec->mutex);
-       return 0;
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       soc_dapm_stream_event(rtd, stream, event);
+       mutex_unlock(&card->dapm_mutex);
 }
 
 /**
index ee4353f843eae07a82b7358004d9defb63ae5e96..7f8b3b7428bbf12c60f603fff8fbb8d3989fa254 100644 (file)
@@ -36,6 +36,7 @@
 int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
                     struct snd_soc_jack *jack)
 {
+       mutex_init(&jack->mutex);
        jack->codec = codec;
        INIT_LIST_HEAD(&jack->pins);
        INIT_LIST_HEAD(&jack->jack_zones);
@@ -75,7 +76,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
        codec = jack->codec;
        dapm =  &codec->dapm;
 
-       mutex_lock(&codec->mutex);
+       mutex_lock(&jack->mutex);
 
        oldstatus = jack->status;
 
@@ -109,7 +110,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
        snd_jack_report(jack->jack, jack->status);
 
 out:
-       mutex_unlock(&codec->mutex);
+       mutex_unlock(&jack->mutex);
 }
 EXPORT_SYMBOL_GPL(snd_soc_jack_report);
 
index 0ad8dcacd2f39eefbdc434ac8bed0a4a56e3ea6f..bedd1717a37381376e6084a5e631d739dbb06cb3 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/export.h>
+#include <linux/debugfs.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/soc-dpcm.h>
 #include <sound/initval.h>
 
+#define DPCM_MAX_BE_USERS      8
+
+/* DPCM stream event, send event to FE and all active BEs. */
+static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
+       int event)
+{
+       struct snd_soc_dpcm *dpcm;
+
+       list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) {
+
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+
+               dev_dbg(be->dev, "pm: BE %s event %d dir %d\n",
+                               be->dai_link->name, event, dir);
+
+               snd_soc_dapm_stream_event(be, dir, event);
+       }
+
+       snd_soc_dapm_stream_event(fe, dir, event);
+
+       return 0;
+}
+
 static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
                                        struct snd_soc_dai *soc_dai)
 {
@@ -156,6 +182,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                }
        }
 
+       /* Dynamic PCM DAI links compat checks use dynamic capabilities */
+       if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
+               goto dynamic;
+
        /* Check that the codec and cpu DAIs are compatible */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                runtime->hw.rate_min =
@@ -248,6 +278,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
                 runtime->hw.rate_max);
 
+dynamic:
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                cpu_dai->playback_active++;
                codec_dai->playback_active++;
@@ -308,7 +339,7 @@ static void close_delayed_work(struct work_struct *work)
        if (codec_dai->pop_wait == 1) {
                codec_dai->pop_wait = 0;
                snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
-                                         codec_dai, SND_SOC_DAPM_STREAM_STOP);
+                                         SND_SOC_DAPM_STREAM_STOP);
        }
 
        mutex_unlock(&rtd->pcm_mutex);
@@ -373,7 +404,6 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
                        /* powered down playback stream now */
                        snd_soc_dapm_stream_event(rtd,
                                                  SNDRV_PCM_STREAM_PLAYBACK,
-                                                 codec_dai,
                                                  SND_SOC_DAPM_STREAM_STOP);
                } else {
                        /* start delayed pop wq here for playback streams */
@@ -384,7 +414,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
        } else {
                /* capture streams can be powered down now */
                snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
-                                         codec_dai, SND_SOC_DAPM_STREAM_STOP);
+                                         SND_SOC_DAPM_STREAM_STOP);
        }
 
        mutex_unlock(&rtd->pcm_mutex);
@@ -453,8 +483,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
                cancel_delayed_work(&rtd->delayed_work);
        }
 
-       snd_soc_dapm_stream_event(rtd, substream->stream, codec_dai,
-                                 SND_SOC_DAPM_STREAM_START);
+       snd_soc_dapm_stream_event(rtd, substream->stream,
+                       SND_SOC_DAPM_STREAM_START);
 
        snd_soc_dai_digital_mute(codec_dai, 0);
 
@@ -602,6 +632,34 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        return 0;
 }
 
+static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
+                                  int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       if (codec_dai->driver->ops->bespoke_trigger) {
+               ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (platform->driver->bespoke_trigger) {
+               ret = platform->driver->bespoke_trigger(substream, cmd);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (cpu_dai->driver->ops->bespoke_trigger) {
+               ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
 /*
  * soc level wrapper for pointer callback
  * If cpu_dai, codec_dai, platform driver has the delay callback, than
@@ -634,74 +692,1664 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
        return offset;
 }
 
-/* create a new pcm */
-int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
+/* connect a FE and BE */
+static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
+               struct snd_soc_pcm_runtime *be, int stream)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_platform *platform = rtd->platform;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_pcm_ops *soc_pcm_ops = &rtd->ops;
-       struct snd_pcm *pcm;
-       char new_name[64];
-       int ret = 0, playback = 0, capture = 0;
+       struct snd_soc_dpcm *dpcm;
 
-       soc_pcm_ops->open       = soc_pcm_open;
-       soc_pcm_ops->close      = soc_pcm_close;
-       soc_pcm_ops->hw_params  = soc_pcm_hw_params;
-       soc_pcm_ops->hw_free    = soc_pcm_hw_free;
-       soc_pcm_ops->prepare    = soc_pcm_prepare;
-       soc_pcm_ops->trigger    = soc_pcm_trigger;
-       soc_pcm_ops->pointer    = soc_pcm_pointer;
-
-       /* check client and interface hw capabilities */
-       snprintf(new_name, sizeof(new_name), "%s %s-%d",
-                       rtd->dai_link->stream_name, codec_dai->name, num);
-
-       if (codec_dai->driver->playback.channels_min)
-               playback = 1;
-       if (codec_dai->driver->capture.channels_min)
-               capture = 1;
-
-       dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
-       ret = snd_pcm_new(rtd->card->snd_card, new_name,
-                       num, playback, capture, &pcm);
-       if (ret < 0) {
-               printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
-               return ret;
+       /* only add new dpcms */
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+               if (dpcm->be == be && dpcm->fe == fe)
+                       return 0;
        }
 
-       /* DAPM dai link stream work */
-       INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+       dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
+       if (!dpcm)
+               return -ENOMEM;
+
+       dpcm->be = be;
+       dpcm->fe = fe;
+       be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
+       dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
+       list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
+       list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
+
+       dev_dbg(fe->dev, "  connected new DPCM %s path %s %s %s\n",
+                       stream ? "capture" : "playback",  fe->dai_link->name,
+                       stream ? "<-" : "->", be->dai_link->name);
+
+#ifdef CONFIG_DEBUG_FS
+       dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644,
+                       fe->debugfs_dpcm_root, &dpcm->state);
+#endif
+       return 1;
+}
 
-       rtd->pcm = pcm;
-       pcm->private_data = rtd;
-       if (platform->driver->ops) {
-               soc_pcm_ops->mmap = platform->driver->ops->mmap;
-               soc_pcm_ops->pointer = platform->driver->ops->pointer;
-               soc_pcm_ops->ioctl = platform->driver->ops->ioctl;
-               soc_pcm_ops->copy = platform->driver->ops->copy;
-               soc_pcm_ops->silence = platform->driver->ops->silence;
-               soc_pcm_ops->ack = platform->driver->ops->ack;
-               soc_pcm_ops->page = platform->driver->ops->page;
+/* reparent a BE onto another FE */
+static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
+                       struct snd_soc_pcm_runtime *be, int stream)
+{
+       struct snd_soc_dpcm *dpcm;
+       struct snd_pcm_substream *fe_substream, *be_substream;
+
+       /* reparent if BE is connected to other FEs */
+       if (!be->dpcm[stream].users)
+               return;
+
+       be_substream = snd_soc_dpcm_get_substream(be, stream);
+
+       list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
+               if (dpcm->fe == fe)
+                       continue;
+
+               dev_dbg(fe->dev, "  reparent %s path %s %s %s\n",
+                       stream ? "capture" : "playback",
+                       dpcm->fe->dai_link->name,
+                       stream ? "<-" : "->", dpcm->be->dai_link->name);
+
+               fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
+               be_substream->runtime = fe_substream->runtime;
+               break;
        }
+}
 
-       if (playback)
-               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, soc_pcm_ops);
+/* disconnect a BE and FE */
+static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
+{
+       struct snd_soc_dpcm *dpcm, *d;
 
-       if (capture)
-               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, soc_pcm_ops);
+       list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) {
+               dev_dbg(fe->dev, "BE %s disconnect check for %s\n",
+                               stream ? "capture" : "playback",
+                               dpcm->be->dai_link->name);
 
-       if (platform->driver->pcm_new) {
-               ret = platform->driver->pcm_new(rtd);
-               if (ret < 0) {
-                       pr_err("asoc: platform pcm constructor failed\n");
-                       return ret;
+               if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
+                       continue;
+
+               dev_dbg(fe->dev, "  freed DSP %s path %s %s %s\n",
+                       stream ? "capture" : "playback", fe->dai_link->name,
+                       stream ? "<-" : "->", dpcm->be->dai_link->name);
+
+               /* BEs still alive need new FE */
+               dpcm_be_reparent(fe, dpcm->be, stream);
+
+#ifdef CONFIG_DEBUG_FS
+               debugfs_remove(dpcm->debugfs_state);
+#endif
+               list_del(&dpcm->list_be);
+               list_del(&dpcm->list_fe);
+               kfree(dpcm);
+       }
+}
+
+/* get BE for DAI widget and stream */
+static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
+               struct snd_soc_dapm_widget *widget, int stream)
+{
+       struct snd_soc_pcm_runtime *be;
+       int i;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               for (i = 0; i < card->num_links; i++) {
+                       be = &card->rtd[i];
+
+                       if (be->cpu_dai->playback_widget == widget ||
+                               be->codec_dai->playback_widget == widget)
+                               return be;
+               }
+       } else {
+
+               for (i = 0; i < card->num_links; i++) {
+                       be = &card->rtd[i];
+
+                       if (be->cpu_dai->capture_widget == widget ||
+                               be->codec_dai->capture_widget == widget)
+                               return be;
                }
        }
 
-       pcm->private_free = platform->driver->pcm_free;
-       printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
-               cpu_dai->name);
+       dev_err(card->dev, "can't get %s BE for %s\n",
+               stream ? "capture" : "playback", widget->name);
+       return NULL;
+}
+
+static inline struct snd_soc_dapm_widget *
+       rtd_get_cpu_widget(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return rtd->cpu_dai->playback_widget;
+       else
+               return rtd->cpu_dai->capture_widget;
+}
+
+static inline struct snd_soc_dapm_widget *
+       rtd_get_codec_widget(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return rtd->codec_dai->playback_widget;
+       else
+               return rtd->codec_dai->capture_widget;
+}
+
+static int widget_in_list(struct snd_soc_dapm_widget_list *list,
+               struct snd_soc_dapm_widget *widget)
+{
+       int i;
+
+       for (i = 0; i < list->num_widgets; i++) {
+               if (widget == list->widgets[i])
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
+       int stream, struct snd_soc_dapm_widget_list **list_)
+{
+       struct snd_soc_dai *cpu_dai = fe->cpu_dai;
+       struct snd_soc_dapm_widget_list *list;
+       int paths;
+
+       list = kzalloc(sizeof(struct snd_soc_dapm_widget_list) +
+                       sizeof(struct snd_soc_dapm_widget *), GFP_KERNEL);
+       if (list == NULL)
+               return -ENOMEM;
+
+       /* get number of valid DAI paths and their widgets */
+       paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list);
+
+       dev_dbg(fe->dev, "found %d audio %s paths\n", paths,
+                       stream ? "capture" : "playback");
+
+       *list_ = list;
+       return paths;
+}
+
+static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
+{
+       kfree(*list);
+}
+
+static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
+       struct snd_soc_dapm_widget_list **list_)
+{
+       struct snd_soc_dpcm *dpcm;
+       struct snd_soc_dapm_widget_list *list = *list_;
+       struct snd_soc_dapm_widget *widget;
+       int prune = 0;
+
+       /* Destroy any old FE <--> BE connections */
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+               /* is there a valid CPU DAI widget for this BE */
+               widget = rtd_get_cpu_widget(dpcm->be, stream);
+
+               /* prune the BE if it's no longer in our active list */
+               if (widget && widget_in_list(list, widget))
+                       continue;
+
+               /* is there a valid CODEC DAI widget for this BE */
+               widget = rtd_get_codec_widget(dpcm->be, stream);
+
+               /* prune the BE if it's no longer in our active list */
+               if (widget && widget_in_list(list, widget))
+                       continue;
+
+               dev_dbg(fe->dev, "pruning %s BE %s for %s\n",
+                       stream ? "capture" : "playback",
+                       dpcm->be->dai_link->name, fe->dai_link->name);
+               dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+               dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+               prune++;
+       }
+
+       dev_dbg(fe->dev, "found %d old BE paths for pruning\n", prune);
+       return prune;
+}
+
+static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
+       struct snd_soc_dapm_widget_list **list_)
+{
+       struct snd_soc_card *card = fe->card;
+       struct snd_soc_dapm_widget_list *list = *list_;
+       struct snd_soc_pcm_runtime *be;
+       int i, new = 0, err;
+
+       /* Create any new FE <--> BE connections */
+       for (i = 0; i < list->num_widgets; i++) {
+
+               if (list->widgets[i]->id != snd_soc_dapm_dai)
+                       continue;
+
+               /* is there a valid BE rtd for this widget */
+               be = dpcm_get_be(card, list->widgets[i], stream);
+               if (!be) {
+                       dev_err(fe->dev, "no BE found for %s\n",
+                                       list->widgets[i]->name);
+                       continue;
+               }
+
+               /* make sure BE is a real BE */
+               if (!be->dai_link->no_pcm)
+                       continue;
+
+               /* don't connect if FE is not running */
+               if (!fe->dpcm[stream].runtime)
+                       continue;
+
+               /* newly connected FE and BE */
+               err = dpcm_be_connect(fe, be, stream);
+               if (err < 0) {
+                       dev_err(fe->dev, "can't connect %s\n",
+                               list->widgets[i]->name);
+                       break;
+               } else if (err == 0) /* already connected */
+                       continue;
+
+               /* new */
+               be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+               new++;
+       }
+
+       dev_dbg(fe->dev, "found %d new BE paths\n", new);
+       return new;
+}
+
+/*
+ * Find the corresponding BE DAIs that source or sink audio to this
+ * FE substream.
+ */
+static int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
+       int stream, struct snd_soc_dapm_widget_list **list, int new)
+{
+       if (new)
+               return dpcm_add_paths(fe, stream, list);
+       else
+               return dpcm_prune_paths(fe, stream, list);
+}
+
+static void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
+{
+       struct snd_soc_dpcm *dpcm;
+
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+               dpcm->be->dpcm[stream].runtime_update =
+                                               SND_SOC_DPCM_UPDATE_NO;
+}
+
+static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
+       int stream)
+{
+       struct snd_soc_dpcm *dpcm;
+
+       /* disable any enabled and non active backends */
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_pcm_substream *be_substream =
+                       snd_soc_dpcm_get_substream(be, stream);
+
+               if (be->dpcm[stream].users == 0)
+                       dev_err(be->dev, "no users %s at close - state %d\n",
+                               stream ? "capture" : "playback",
+                               be->dpcm[stream].state);
+
+               if (--be->dpcm[stream].users != 0)
+                       continue;
+
+               if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
+                       continue;
+
+               soc_pcm_close(be_substream);
+               be_substream->runtime = NULL;
+               be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+       }
+}
+
+static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
+{
+       struct snd_soc_dpcm *dpcm;
+       int err, count = 0;
+
+       /* only startup BE DAIs that are either sinks or sources to this FE DAI */
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_pcm_substream *be_substream =
+                       snd_soc_dpcm_get_substream(be, stream);
+
+               /* is this op for this BE ? */
+               if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+                       continue;
+
+               /* first time the dpcm is open ? */
+               if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
+                       dev_err(be->dev, "too many users %s at open %d\n",
+                               stream ? "capture" : "playback",
+                               be->dpcm[stream].state);
+
+               if (be->dpcm[stream].users++ != 0)
+                       continue;
+
+               if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
+                       continue;
+
+               dev_dbg(be->dev, "dpcm: open BE %s\n", be->dai_link->name);
+
+               be_substream->runtime = be->dpcm[stream].runtime;
+               err = soc_pcm_open(be_substream);
+               if (err < 0) {
+                       dev_err(be->dev, "BE open failed %d\n", err);
+                       be->dpcm[stream].users--;
+                       if (be->dpcm[stream].users < 0)
+                               dev_err(be->dev, "no users %s at unwind %d\n",
+                                       stream ? "capture" : "playback",
+                                       be->dpcm[stream].state);
+
+                       be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+                       goto unwind;
+               }
+
+               be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
+               count++;
+       }
+
+       return count;
+
+unwind:
+       /* disable any enabled and non active backends */
+       list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_pcm_substream *be_substream =
+                       snd_soc_dpcm_get_substream(be, stream);
+
+               if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+                       continue;
+
+               if (be->dpcm[stream].users == 0)
+                       dev_err(be->dev, "no users %s at close %d\n",
+                               stream ? "capture" : "playback",
+                               be->dpcm[stream].state);
+
+               if (--be->dpcm[stream].users != 0)
+                       continue;
+
+               if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
+                       continue;
+
+               soc_pcm_close(be_substream);
+               be_substream->runtime = NULL;
+               be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+       }
+
+       return err;
+}
+
+static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               runtime->hw.rate_min = cpu_dai_drv->playback.rate_min;
+               runtime->hw.rate_max = cpu_dai_drv->playback.rate_max;
+               runtime->hw.channels_min = cpu_dai_drv->playback.channels_min;
+               runtime->hw.channels_max = cpu_dai_drv->playback.channels_max;
+               runtime->hw.formats &= cpu_dai_drv->playback.formats;
+               runtime->hw.rates = cpu_dai_drv->playback.rates;
+       } else {
+               runtime->hw.rate_min = cpu_dai_drv->capture.rate_min;
+               runtime->hw.rate_max = cpu_dai_drv->capture.rate_max;
+               runtime->hw.channels_min = cpu_dai_drv->capture.channels_min;
+               runtime->hw.channels_max = cpu_dai_drv->capture.channels_max;
+               runtime->hw.formats &= cpu_dai_drv->capture.formats;
+               runtime->hw.rates = cpu_dai_drv->capture.rates;
+       }
+}
+
+static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
+{
+       struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
+       struct snd_pcm_runtime *runtime = fe_substream->runtime;
+       int stream = fe_substream->stream, ret = 0;
+
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+       ret = dpcm_be_dai_startup(fe, fe_substream->stream);
+       if (ret < 0) {
+               dev_err(fe->dev,"dpcm: failed to start some BEs %d\n", ret);
+               goto be_err;
+       }
+
+       dev_dbg(fe->dev, "dpcm: open FE %s\n", fe->dai_link->name);
+
+       /* start the DAI frontend */
+       ret = soc_pcm_open(fe_substream);
+       if (ret < 0) {
+               dev_err(fe->dev,"dpcm: failed to start FE %d\n", ret);
+               goto unwind;
+       }
+
+       fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
+
+       dpcm_set_fe_runtime(fe_substream);
+       snd_pcm_limit_hw_rates(runtime);
+
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       return 0;
+
+unwind:
+       dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
+be_err:
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
        return ret;
 }
+
+static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
+{
+       struct snd_soc_dpcm *dpcm;
+
+       /* only shutdown BEs that are either sinks or sources to this FE DAI */
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_pcm_substream *be_substream =
+                       snd_soc_dpcm_get_substream(be, stream);
+
+               /* is this op for this BE ? */
+               if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+                       continue;
+
+               if (be->dpcm[stream].users == 0)
+                       dev_err(be->dev, "no users %s at close - state %d\n",
+                               stream ? "capture" : "playback",
+                               be->dpcm[stream].state);
+
+               if (--be->dpcm[stream].users != 0)
+                       continue;
+
+               if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN))
+                       continue;
+
+               dev_dbg(be->dev, "dpcm: close BE %s\n",
+                       dpcm->fe->dai_link->name);
+
+               soc_pcm_close(be_substream);
+               be_substream->runtime = NULL;
+
+               be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+       }
+       return 0;
+}
+
+static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *fe = substream->private_data;
+       int stream = substream->stream;
+
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+       /* shutdown the BEs */
+       dpcm_be_dai_shutdown(fe, substream->stream);
+
+       dev_dbg(fe->dev, "dpcm: close FE %s\n", fe->dai_link->name);
+
+       /* now shutdown the frontend */
+       soc_pcm_close(substream);
+
+       /* run the stream event for each BE */
+       dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
+
+       fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       return 0;
+}
+
+static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
+{
+       struct snd_soc_dpcm *dpcm;
+
+       /* only hw_params backends that are either sinks or sources
+        * to this frontend DAI */
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_pcm_substream *be_substream =
+                       snd_soc_dpcm_get_substream(be, stream);
+
+               /* is this op for this BE ? */
+               if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+                       continue;
+
+               /* only free hw when no longer used - check all FEs */
+               if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+                               continue;
+
+               if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+                       continue;
+
+               dev_dbg(be->dev, "dpcm: hw_free BE %s\n",
+                       dpcm->fe->dai_link->name);
+
+               soc_pcm_hw_free(be_substream);
+
+               be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
+       }
+
+       return 0;
+}
+
+static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *fe = substream->private_data;
+       int err, stream = substream->stream;
+
+       mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+       dev_dbg(fe->dev, "dpcm: hw_free FE %s\n", fe->dai_link->name);
+
+       /* call hw_free on the frontend */
+       err = soc_pcm_hw_free(substream);
+       if (err < 0)
+               dev_err(fe->dev,"dpcm: hw_free FE %s failed\n",
+                       fe->dai_link->name);
+
+       /* only hw_params backends that are either sinks or sources
+        * to this frontend DAI */
+       err = dpcm_be_dai_hw_free(fe, stream);
+
+       fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+
+       mutex_unlock(&fe->card->mutex);
+       return 0;
+}
+
+static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
+{
+       struct snd_soc_dpcm *dpcm;
+       int ret;
+
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_pcm_substream *be_substream =
+                       snd_soc_dpcm_get_substream(be, stream);
+
+               /* is this op for this BE ? */
+               if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+                       continue;
+
+               /* only allow hw_params() if no connected FEs are running */
+               if (!snd_soc_dpcm_can_be_params(fe, be, stream))
+                       continue;
+
+               if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
+                       continue;
+
+               dev_dbg(be->dev, "dpcm: hw_params BE %s\n",
+                       dpcm->fe->dai_link->name);
+
+               /* copy params for each dpcm */
+               memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
+                               sizeof(struct snd_pcm_hw_params));
+
+               /* perform any hw_params fixups */
+               if (be->dai_link->be_hw_params_fixup) {
+                       ret = be->dai_link->be_hw_params_fixup(be,
+                                       &dpcm->hw_params);
+                       if (ret < 0) {
+                               dev_err(be->dev,
+                                       "dpcm: hw_params BE fixup failed %d\n",
+                                       ret);
+                               goto unwind;
+                       }
+               }
+
+               ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
+               if (ret < 0) {
+                       dev_err(dpcm->be->dev,
+                               "dpcm: hw_params BE failed %d\n", ret);
+                       goto unwind;
+               }
+
+               be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
+       }
+       return 0;
+
+unwind:
+       /* disable any enabled and non active backends */
+       list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_pcm_substream *be_substream =
+                       snd_soc_dpcm_get_substream(be, stream);
+
+               if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+                       continue;
+
+               /* only allow hw_free() if no connected FEs are running */
+               if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+                       continue;
+
+               if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
+                  (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+                  (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+                  (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+                       continue;
+
+               soc_pcm_hw_free(be_substream);
+       }
+
+       return ret;
+}
+
+static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *fe = substream->private_data;
+       int ret, stream = substream->stream;
+
+       mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+       memcpy(&fe->dpcm[substream->stream].hw_params, params,
+                       sizeof(struct snd_pcm_hw_params));
+       ret = dpcm_be_dai_hw_params(fe, substream->stream);
+       if (ret < 0) {
+               dev_err(fe->dev,"dpcm: hw_params BE failed %d\n", ret);
+               goto out;
+       }
+
+       dev_dbg(fe->dev, "dpcm: hw_params FE %s rate %d chan %x fmt %d\n",
+                       fe->dai_link->name, params_rate(params),
+                       params_channels(params), params_format(params));
+
+       /* call hw_params on the frontend */
+       ret = soc_pcm_hw_params(substream, params);
+       if (ret < 0) {
+               dev_err(fe->dev,"dpcm: hw_params FE failed %d\n", ret);
+               dpcm_be_dai_hw_free(fe, stream);
+        } else
+               fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
+
+out:
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       mutex_unlock(&fe->card->mutex);
+       return ret;
+}
+
+static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
+               struct snd_pcm_substream *substream, int cmd)
+{
+       int ret;
+
+       dev_dbg(dpcm->be->dev, "dpcm: trigger BE %s cmd %d\n",
+                       dpcm->fe->dai_link->name, cmd);
+
+       ret = soc_pcm_trigger(substream, cmd);
+       if (ret < 0)
+               dev_err(dpcm->be->dev,"dpcm: trigger BE failed %d\n", ret);
+
+       return ret;
+}
+
+static int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
+                              int cmd)
+{
+       struct snd_soc_dpcm *dpcm;
+       int ret = 0;
+
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_pcm_substream *be_substream =
+                       snd_soc_dpcm_get_substream(be, stream);
+
+               /* is this op for this BE ? */
+               if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+                       continue;
+
+               switch (cmd) {
+               case SNDRV_PCM_TRIGGER_START:
+                       if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
+                           (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+                               continue;
+
+                       ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+                       if (ret)
+                               return ret;
+
+                       be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+                       break;
+               case SNDRV_PCM_TRIGGER_RESUME:
+                       if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
+                               continue;
+
+                       ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+                       if (ret)
+                               return ret;
+
+                       be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+                       break;
+               case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+                       if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
+                               continue;
+
+                       ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+                       if (ret)
+                               return ret;
+
+                       be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+                       break;
+               case SNDRV_PCM_TRIGGER_STOP:
+                       if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
+                               continue;
+
+                       if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+                               continue;
+
+                       ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+                       if (ret)
+                               return ret;
+
+                       be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
+                       break;
+               case SNDRV_PCM_TRIGGER_SUSPEND:
+                       if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)
+                               continue;
+
+                       if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+                               continue;
+
+                       ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+                       if (ret)
+                               return ret;
+
+                       be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
+                       break;
+               case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+                       if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
+                               continue;
+
+                       if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+                               continue;
+
+                       ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+                       if (ret)
+                               return ret;
+
+                       be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
+                       break;
+               }
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
+
+static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *fe = substream->private_data;
+       int stream = substream->stream, ret;
+       enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
+
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+       switch (trigger) {
+       case SND_SOC_DPCM_TRIGGER_PRE:
+               /* call trigger on the frontend before the backend. */
+
+               dev_dbg(fe->dev, "dpcm: pre trigger FE %s cmd %d\n",
+                               fe->dai_link->name, cmd);
+
+               ret = soc_pcm_trigger(substream, cmd);
+               if (ret < 0) {
+                       dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
+                       goto out;
+               }
+
+               ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
+               break;
+       case SND_SOC_DPCM_TRIGGER_POST:
+               /* call trigger on the frontend after the backend. */
+
+               ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
+               if (ret < 0) {
+                       dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
+                       goto out;
+               }
+
+               dev_dbg(fe->dev, "dpcm: post trigger FE %s cmd %d\n",
+                               fe->dai_link->name, cmd);
+
+               ret = soc_pcm_trigger(substream, cmd);
+               break;
+       case SND_SOC_DPCM_TRIGGER_BESPOKE:
+               /* bespoke trigger() - handles both FE and BEs */
+
+               dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd %d\n",
+                               fe->dai_link->name, cmd);
+
+               ret = soc_pcm_bespoke_trigger(substream, cmd);
+               if (ret < 0) {
+                       dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
+                       goto out;
+               }
+               break;
+       default:
+               dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd,
+                               fe->dai_link->name);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
+               break;
+       }
+
+out:
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       return ret;
+}
+
+static int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
+{
+       struct snd_soc_dpcm *dpcm;
+       int ret = 0;
+
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_pcm_substream *be_substream =
+                       snd_soc_dpcm_get_substream(be, stream);
+
+               /* is this op for this BE ? */
+               if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+                       continue;
+
+               if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+                       continue;
+
+               dev_dbg(be->dev, "dpcm: prepare BE %s\n",
+                       dpcm->fe->dai_link->name);
+
+               ret = soc_pcm_prepare(be_substream);
+               if (ret < 0) {
+                       dev_err(be->dev, "dpcm: backend prepare failed %d\n",
+                               ret);
+                       break;
+               }
+
+               be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
+       }
+       return ret;
+}
+
+static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *fe = substream->private_data;
+       int stream = substream->stream, ret = 0;
+
+       mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+
+       dev_dbg(fe->dev, "dpcm: prepare FE %s\n", fe->dai_link->name);
+
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+       /* there is no point preparing this FE if there are no BEs */
+       if (list_empty(&fe->dpcm[stream].be_clients)) {
+               dev_err(fe->dev, "dpcm: no backend DAIs enabled for %s\n",
+                               fe->dai_link->name);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = dpcm_be_dai_prepare(fe, substream->stream);
+       if (ret < 0)
+               goto out;
+
+       /* call prepare on the frontend */
+       ret = soc_pcm_prepare(substream);
+       if (ret < 0) {
+               dev_err(fe->dev,"dpcm: prepare FE %s failed\n",
+                       fe->dai_link->name);
+               goto out;
+       }
+
+       /* run the stream event for each BE */
+       dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
+       fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
+
+out:
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       mutex_unlock(&fe->card->mutex);
+
+       return ret;
+}
+
+static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
+                    unsigned int cmd, void *arg)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+
+       if (platform->driver->ops->ioctl)
+               return platform->driver->ops->ioctl(substream, cmd, arg);
+       return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
+{
+       struct snd_pcm_substream *substream =
+               snd_soc_dpcm_get_substream(fe, stream);
+       enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
+       int err;
+
+       dev_dbg(fe->dev, "runtime %s close on FE %s\n",
+                       stream ? "capture" : "playback", fe->dai_link->name);
+
+       if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
+               /* call bespoke trigger - FE takes care of all BE triggers */
+               dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd stop\n",
+                               fe->dai_link->name);
+
+               err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
+               if (err < 0)
+                       dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err);
+       } else {
+               dev_dbg(fe->dev, "dpcm: trigger FE %s cmd stop\n",
+                       fe->dai_link->name);
+
+               err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
+               if (err < 0)
+                       dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err);
+       }
+
+       err = dpcm_be_dai_hw_free(fe, stream);
+       if (err < 0)
+               dev_err(fe->dev,"dpcm: hw_free FE failed %d\n", err);
+
+       err = dpcm_be_dai_shutdown(fe, stream);
+       if (err < 0)
+               dev_err(fe->dev,"dpcm: shutdown FE failed %d\n", err);
+
+       /* run the stream event for each BE */
+       dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
+
+       return 0;
+}
+
+static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
+{
+       struct snd_pcm_substream *substream =
+               snd_soc_dpcm_get_substream(fe, stream);
+       struct snd_soc_dpcm *dpcm;
+       enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
+       int ret;
+
+       dev_dbg(fe->dev, "runtime %s open on FE %s\n",
+                       stream ? "capture" : "playback", fe->dai_link->name);
+
+       /* Only start the BE if the FE is ready */
+       if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
+               fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
+               return -EINVAL;
+
+       /* startup must always be called for new BEs */
+       ret = dpcm_be_dai_startup(fe, stream);
+       if (ret < 0) {
+               goto disconnect;
+               return ret;
+       }
+
+       /* keep going if FE state is > open */
+       if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
+               return 0;
+
+       ret = dpcm_be_dai_hw_params(fe, stream);
+       if (ret < 0) {
+               goto close;
+               return ret;
+       }
+
+       /* keep going if FE state is > hw_params */
+       if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
+               return 0;
+
+
+       ret = dpcm_be_dai_prepare(fe, stream);
+       if (ret < 0) {
+               goto hw_free;
+               return ret;
+       }
+
+       /* run the stream event for each BE */
+       dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
+
+       /* keep going if FE state is > prepare */
+       if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
+               fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
+               return 0;
+
+       if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
+               /* call trigger on the frontend - FE takes care of all BE triggers */
+               dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd start\n",
+                               fe->dai_link->name);
+
+               ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
+               if (ret < 0) {
+                       dev_err(fe->dev,"dpcm: bespoke trigger FE failed %d\n", ret);
+                       goto hw_free;
+               }
+       } else {
+               dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n",
+                       fe->dai_link->name);
+
+               ret = dpcm_be_dai_trigger(fe, stream,
+                                       SNDRV_PCM_TRIGGER_START);
+               if (ret < 0) {
+                       dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
+                       goto hw_free;
+               }
+       }
+
+       return 0;
+
+hw_free:
+       dpcm_be_dai_hw_free(fe, stream);
+close:
+       dpcm_be_dai_shutdown(fe, stream);
+disconnect:
+       /* disconnect any non started BEs */
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
+                               dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+       }
+
+       return ret;
+}
+
+static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
+{
+       int ret;
+
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+       ret = dpcm_run_update_startup(fe, stream);
+       if (ret < 0)
+               dev_err(fe->dev, "failed to startup some BEs\n");
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+
+       return ret;
+}
+
+static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
+{
+       int ret;
+
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+       ret = dpcm_run_update_shutdown(fe, stream);
+       if (ret < 0)
+               dev_err(fe->dev, "failed to shutdown some BEs\n");
+       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+
+       return ret;
+}
+
+/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
+ * any DAI links.
+ */
+int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget)
+{
+       struct snd_soc_card *card;
+       int i, old, new, paths;
+
+       if (widget->codec)
+               card = widget->codec->card;
+       else if (widget->platform)
+               card = widget->platform->card;
+       else
+               return -EINVAL;
+
+       mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dapm_widget_list *list;
+               struct snd_soc_pcm_runtime *fe = &card->rtd[i];
+
+               /* make sure link is FE */
+               if (!fe->dai_link->dynamic)
+                       continue;
+
+               /* only check active links */
+               if (!fe->cpu_dai->active)
+                       continue;
+
+               /* DAPM sync will call this to update DSP paths */
+               dev_dbg(fe->dev, "DPCM runtime update for FE %s\n",
+                       fe->dai_link->name);
+
+               /* skip if FE doesn't have playback capability */
+               if (!fe->cpu_dai->driver->playback.channels_min)
+                       goto capture;
+
+               paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
+               if (paths < 0) {
+                       dev_warn(fe->dev, "%s no valid %s path\n",
+                                       fe->dai_link->name,  "playback");
+                       mutex_unlock(&card->mutex);
+                       return paths;
+               }
+
+               /* update any new playback paths */
+               new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1);
+               if (new) {
+                       dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
+                       dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
+                       dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
+               }
+
+               /* update any old playback paths */
+               old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0);
+               if (old) {
+                       dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
+                       dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
+                       dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
+               }
+
+capture:
+               /* skip if FE doesn't have capture capability */
+               if (!fe->cpu_dai->driver->capture.channels_min)
+                       continue;
+
+               paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
+               if (paths < 0) {
+                       dev_warn(fe->dev, "%s no valid %s path\n",
+                                       fe->dai_link->name,  "capture");
+                       mutex_unlock(&card->mutex);
+                       return paths;
+               }
+
+               /* update any new capture paths */
+               new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1);
+               if (new) {
+                       dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
+                       dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
+                       dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
+               }
+
+               /* update any old capture paths */
+               old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0);
+               if (old) {
+                       dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
+                       dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
+                       dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
+               }
+
+               dpcm_path_put(&list);
+       }
+
+       mutex_unlock(&card->mutex);
+       return 0;
+}
+int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
+{
+       struct snd_soc_dpcm *dpcm;
+       struct list_head *clients =
+               &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients;
+
+       list_for_each_entry(dpcm, clients, list_be) {
+
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               struct snd_soc_dai *dai = be->codec_dai;
+               struct snd_soc_dai_driver *drv = dai->driver;
+
+               if (be->dai_link->ignore_suspend)
+                       continue;
+
+               dev_dbg(be->dev, "BE digital mute %s\n", be->dai_link->name);
+
+               if (drv->ops->digital_mute && dai->playback_active)
+                               drv->ops->digital_mute(dai, mute);
+       }
+
+       return 0;
+}
+
+static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
+{
+       struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
+       struct snd_soc_dpcm *dpcm;
+       struct snd_soc_dapm_widget_list *list;
+       int ret;
+       int stream = fe_substream->stream;
+
+       mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+       fe->dpcm[stream].runtime = fe_substream->runtime;
+
+       if (dpcm_path_get(fe, stream, &list) <= 0) {
+               dev_warn(fe->dev, "asoc: %s no valid %s route\n",
+                       fe->dai_link->name, stream ? "capture" : "playback");
+                       mutex_unlock(&fe->card->mutex);
+                       return -EINVAL;
+       }
+
+       /* calculate valid and active FE <-> BE dpcms */
+       dpcm_process_paths(fe, stream, &list, 1);
+
+       ret = dpcm_fe_dai_startup(fe_substream);
+       if (ret < 0) {
+               /* clean up all links */
+               list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+                       dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+
+               dpcm_be_disconnect(fe, stream);
+               fe->dpcm[stream].runtime = NULL;
+       }
+
+       dpcm_clear_pending_state(fe, stream);
+       dpcm_path_put(&list);
+       mutex_unlock(&fe->card->mutex);
+       return ret;
+}
+
+static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
+{
+       struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
+       struct snd_soc_dpcm *dpcm;
+       int stream = fe_substream->stream, ret;
+
+       mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+       ret = dpcm_fe_dai_shutdown(fe_substream);
+
+       /* mark FE's links ready to prune */
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+               dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+
+       dpcm_be_disconnect(fe, stream);
+
+       fe->dpcm[stream].runtime = NULL;
+       mutex_unlock(&fe->card->mutex);
+       return ret;
+}
+
+/* create a new pcm */
+int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_pcm *pcm;
+       char new_name[64];
+       int ret = 0, playback = 0, capture = 0;
+
+       if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
+               if (cpu_dai->driver->playback.channels_min)
+                       playback = 1;
+               if (cpu_dai->driver->capture.channels_min)
+                       capture = 1;
+       } else {
+               if (codec_dai->driver->playback.channels_min)
+                       playback = 1;
+               if (codec_dai->driver->capture.channels_min)
+                       capture = 1;
+       }
+
+       /* create the PCM */
+       if (rtd->dai_link->no_pcm) {
+               snprintf(new_name, sizeof(new_name), "(%s)",
+                       rtd->dai_link->stream_name);
+
+               ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
+                               playback, capture, &pcm);
+       } else {
+               if (rtd->dai_link->dynamic)
+                       snprintf(new_name, sizeof(new_name), "%s (*)",
+                               rtd->dai_link->stream_name);
+               else
+                       snprintf(new_name, sizeof(new_name), "%s %s-%d",
+                               rtd->dai_link->stream_name, codec_dai->name, num);
+
+               ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
+                       capture, &pcm);
+       }
+       if (ret < 0) {
+               printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
+               return ret;
+       }
+       dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name);
+
+       /* DAPM dai link stream work */
+       INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+
+       rtd->pcm = pcm;
+       pcm->private_data = rtd;
+
+       if (rtd->dai_link->no_pcm) {
+               if (playback)
+                       pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
+               if (capture)
+                       pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
+               goto out;
+       }
+
+       /* ASoC PCM operations */
+       if (rtd->dai_link->dynamic) {
+               rtd->ops.open           = dpcm_fe_dai_open;
+               rtd->ops.hw_params      = dpcm_fe_dai_hw_params;
+               rtd->ops.prepare        = dpcm_fe_dai_prepare;
+               rtd->ops.trigger        = dpcm_fe_dai_trigger;
+               rtd->ops.hw_free        = dpcm_fe_dai_hw_free;
+               rtd->ops.close          = dpcm_fe_dai_close;
+               rtd->ops.pointer        = soc_pcm_pointer;
+               rtd->ops.ioctl          = soc_pcm_ioctl;
+       } else {
+               rtd->ops.open           = soc_pcm_open;
+               rtd->ops.hw_params      = soc_pcm_hw_params;
+               rtd->ops.prepare        = soc_pcm_prepare;
+               rtd->ops.trigger        = soc_pcm_trigger;
+               rtd->ops.hw_free        = soc_pcm_hw_free;
+               rtd->ops.close          = soc_pcm_close;
+               rtd->ops.pointer        = soc_pcm_pointer;
+               rtd->ops.ioctl          = soc_pcm_ioctl;
+       }
+
+       if (platform->driver->ops) {
+               rtd->ops.ack            = platform->driver->ops->ack;
+               rtd->ops.copy           = platform->driver->ops->copy;
+               rtd->ops.silence        = platform->driver->ops->silence;
+               rtd->ops.page           = platform->driver->ops->page;
+               rtd->ops.mmap           = platform->driver->ops->mmap;
+       }
+
+       if (playback)
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
+
+       if (capture)
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
+
+       if (platform->driver->pcm_new) {
+               ret = platform->driver->pcm_new(rtd);
+               if (ret < 0) {
+                       pr_err("asoc: platform pcm constructor failed\n");
+                       return ret;
+               }
+       }
+
+       pcm->private_free = platform->driver->pcm_free;
+out:
+       printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
+               cpu_dai->name);
+       return ret;
+}
+
+/* is the current PCM operation for this FE ? */
+int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
+{
+       if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
+
+/* is the current PCM operation for this BE ? */
+int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
+               struct snd_soc_pcm_runtime *be, int stream)
+{
+       if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
+          ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
+                 be->dpcm[stream].runtime_update))
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
+
+/* get the substream for this BE */
+struct snd_pcm_substream *
+       snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
+{
+       return be->pcm->streams[stream].substream;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
+
+/* get the BE runtime state */
+enum snd_soc_dpcm_state
+       snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream)
+{
+       return be->dpcm[stream].state;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state);
+
+/* set the BE runtime state */
+void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be,
+               int stream, enum snd_soc_dpcm_state state)
+{
+       be->dpcm[stream].state = state;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state);
+
+/*
+ * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
+ * are not running, paused or suspended for the specified stream direction.
+ */
+int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
+               struct snd_soc_pcm_runtime *be, int stream)
+{
+       struct snd_soc_dpcm *dpcm;
+       int state;
+
+       list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
+
+               if (dpcm->fe == fe)
+                       continue;
+
+               state = dpcm->fe->dpcm[stream].state;
+               if (state == SND_SOC_DPCM_STATE_START ||
+                       state == SND_SOC_DPCM_STATE_PAUSED ||
+                       state == SND_SOC_DPCM_STATE_SUSPEND)
+                       return 0;
+       }
+
+       /* it's safe to free/stop this BE DAI */
+       return 1;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
+
+/*
+ * We can only change hw params a BE DAI if any of it's FE are not prepared,
+ * running, paused or suspended for the specified stream direction.
+ */
+int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
+               struct snd_soc_pcm_runtime *be, int stream)
+{
+       struct snd_soc_dpcm *dpcm;
+       int state;
+
+       list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
+
+               if (dpcm->fe == fe)
+                       continue;
+
+               state = dpcm->fe->dpcm[stream].state;
+               if (state == SND_SOC_DPCM_STATE_START ||
+                       state == SND_SOC_DPCM_STATE_PAUSED ||
+                       state == SND_SOC_DPCM_STATE_SUSPEND ||
+                       state == SND_SOC_DPCM_STATE_PREPARE)
+                       return 0;
+       }
+
+       /* it's safe to change hw_params */
+       return 1;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
+
+int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
+               int cmd, struct snd_soc_platform *platform)
+{
+       if (platform->driver->ops->trigger)
+               return platform->driver->ops->trigger(substream, cmd);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_platform_trigger);
+
+#ifdef CONFIG_DEBUG_FS
+static char *dpcm_state_string(enum snd_soc_dpcm_state state)
+{
+       switch (state) {
+       case SND_SOC_DPCM_STATE_NEW:
+               return "new";
+       case SND_SOC_DPCM_STATE_OPEN:
+               return "open";
+       case SND_SOC_DPCM_STATE_HW_PARAMS:
+               return "hw_params";
+       case SND_SOC_DPCM_STATE_PREPARE:
+               return "prepare";
+       case SND_SOC_DPCM_STATE_START:
+               return "start";
+       case SND_SOC_DPCM_STATE_STOP:
+               return "stop";
+       case SND_SOC_DPCM_STATE_SUSPEND:
+               return "suspend";
+       case SND_SOC_DPCM_STATE_PAUSED:
+               return "paused";
+       case SND_SOC_DPCM_STATE_HW_FREE:
+               return "hw_free";
+       case SND_SOC_DPCM_STATE_CLOSE:
+               return "close";
+       }
+
+       return "unknown";
+}
+
+static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
+                               int stream, char *buf, size_t size)
+{
+       struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
+       struct snd_soc_dpcm *dpcm;
+       ssize_t offset = 0;
+
+       /* FE state */
+       offset += snprintf(buf + offset, size - offset,
+                       "[%s - %s]\n", fe->dai_link->name,
+                       stream ? "Capture" : "Playback");
+
+       offset += snprintf(buf + offset, size - offset, "State: %s\n",
+                       dpcm_state_string(fe->dpcm[stream].state));
+
+       if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
+           (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
+               offset += snprintf(buf + offset, size - offset,
+                               "Hardware Params: "
+                               "Format = %s, Channels = %d, Rate = %d\n",
+                               snd_pcm_format_name(params_format(params)),
+                               params_channels(params),
+                               params_rate(params));
+
+       /* BEs state */
+       offset += snprintf(buf + offset, size - offset, "Backends:\n");
+
+       if (list_empty(&fe->dpcm[stream].be_clients)) {
+               offset += snprintf(buf + offset, size - offset,
+                               " No active DSP links\n");
+               goto out;
+       }
+
+       list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+               struct snd_soc_pcm_runtime *be = dpcm->be;
+               params = &dpcm->hw_params;
+
+               offset += snprintf(buf + offset, size - offset,
+                               "- %s\n", be->dai_link->name);
+
+               offset += snprintf(buf + offset, size - offset,
+                               "   State: %s\n",
+                               dpcm_state_string(be->dpcm[stream].state));
+
+               if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
+                   (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
+                       offset += snprintf(buf + offset, size - offset,
+                               "   Hardware Params: "
+                               "Format = %s, Channels = %d, Rate = %d\n",
+                               snd_pcm_format_name(params_format(params)),
+                               params_channels(params),
+                               params_rate(params));
+       }
+
+out:
+       return offset;
+}
+
+static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct snd_soc_pcm_runtime *fe = file->private_data;
+       ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
+       char *buf;
+
+       buf = kmalloc(out_count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       if (fe->cpu_dai->driver->playback.channels_min)
+               offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK,
+                                       buf + offset, out_count - offset);
+
+       if (fe->cpu_dai->driver->capture.channels_min)
+               offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE,
+                                       buf + offset, out_count - offset);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
+
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations dpcm_state_fops = {
+       .open = simple_open,
+       .read = dpcm_state_read_file,
+       .llseek = default_llseek,
+};
+
+int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
+{
+       if (!rtd->dai_link)
+               return 0;
+
+       rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
+                       rtd->card->debugfs_card_root);
+       if (!rtd->debugfs_dpcm_root) {
+               dev_dbg(rtd->dev,
+                        "ASoC: Failed to create dpcm debugfs directory %s\n",
+                        rtd->dai_link->name);
+               return -EINVAL;
+       }
+
+       rtd->debugfs_dpcm_state = debugfs_create_file("state", 0444,
+                                               rtd->debugfs_dpcm_root,
+                                               rtd, &dpcm_state_fops);
+
+       return 0;
+}
+#endif
index ce1b773c351fd00772b5fccdf98688594d099c91..c1c8e955f4d31b2a79be704d7dda736bd1e24010 100644 (file)
@@ -1,26 +1,63 @@
 config SND_SOC_TEGRA
        tristate "SoC Audio for the Tegra System-on-Chip"
        depends on ARCH_TEGRA && TEGRA_SYSTEM_DMA
+       select REGMAP_MMIO
        help
          Say Y or M here if you want support for SoC audio on Tegra.
 
-config SND_SOC_TEGRA_I2S
+config SND_SOC_TEGRA20_DAS
        tristate
-       depends on SND_SOC_TEGRA
+       depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+       help
+         Say Y or M if you want to add support for the Tegra20 DAS module.
+         You will also need to select the individual machine drivers to
+         support below.
+
+config SND_SOC_TEGRA20_I2S
+       tristate
+       depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+       select SND_SOC_TEGRA20_DAS
        help
          Say Y or M if you want to add support for codecs attached to the
-         Tegra I2S interface. You will also need to select the individual
+         Tegra20 I2S interface. You will also need to select the individual
          machine drivers to support below.
 
-config SND_SOC_TEGRA_SPDIF
+config SND_SOC_TEGRA20_SPDIF
        tristate
-       depends on SND_SOC_TEGRA
+       depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
        default m
        help
-         Say Y or M if you want to add support for the SPDIF interface.
+         Say Y or M if you want to add support for the Tegra20 SPDIF interface.
          You will also need to select the individual machine drivers to support
          below.
 
+config SND_SOC_TEGRA30_AHUB
+       tristate
+       depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC
+       help
+         Say Y or M if you want to add support for the Tegra20 AHUB module.
+         You will also need to select the individual machine drivers to
+         support below.
+
+config SND_SOC_TEGRA30_I2S
+       tristate
+       depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC
+       select SND_SOC_TEGRA30_AHUB
+       help
+         Say Y or M if you want to add support for codecs attached to the
+         Tegra30 I2S interface. You will also need to select the individual
+         machine drivers to support below.
+
+config SND_SOC_TEGRA_WM8753
+       tristate "SoC Audio support for Tegra boards using a WM8753 codec"
+       depends on SND_SOC_TEGRA && I2C
+       select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+       select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
+       select SND_SOC_WM8753
+       help
+         Say Y or M here if you want to add support for SoC audio on Tegra
+         boards using the WM8753 codec, such as Whistler.
+
 config MACH_HAS_SND_SOC_TEGRA_WM8903
        bool
        help
@@ -32,7 +69,8 @@ config SND_SOC_TEGRA_WM8903
        tristate "SoC Audio support for Tegra boards using a WM8903 codec"
        depends on SND_SOC_TEGRA && I2C
        depends on MACH_HAS_SND_SOC_TEGRA_WM8903
-       select SND_SOC_TEGRA_I2S
+       select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+       select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
        select SND_SOC_WM8903
        help
          Say Y or M here if you want to add support for SoC audio on Tegra
@@ -42,17 +80,17 @@ config SND_SOC_TEGRA_WM8903
 config SND_SOC_TEGRA_TRIMSLICE
        tristate "SoC Audio support for TrimSlice board"
        depends on SND_SOC_TEGRA && MACH_TRIMSLICE && I2C
-       select SND_SOC_TEGRA_I2S
+       select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
        select SND_SOC_TLV320AIC23
        help
          Say Y or M here if you want to add support for SoC audio on the
          TrimSlice platform.
 
 config SND_SOC_TEGRA_ALC5632
-       tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
-       depends on SND_SOC_TEGRA && I2C
-       select SND_SOC_TEGRA_I2S
-       select SND_SOC_ALC5632
-       help
-         Say Y or M here if you want to add support for SoC audio on the
-         Toshiba AC100 netbook.
+       tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
+       depends on SND_SOC_TEGRA && I2C
+       select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+       select SND_SOC_ALC5632
+       help
+         Say Y or M here if you want to add support for SoC audio on the
+         Toshiba AC100 netbook.
index 8e584b8fcfba2e5a1c5a5a286bdfd1dda1c714b5..391e78a34c0602b3dfdb6867dcd0fdd48441c219 100644 (file)
@@ -1,21 +1,27 @@
 # Tegra platform Support
-snd-soc-tegra-das-objs := tegra_das.o
 snd-soc-tegra-pcm-objs := tegra_pcm.o
-snd-soc-tegra-i2s-objs := tegra_i2s.o
-snd-soc-tegra-spdif-objs := tegra_spdif.o
 snd-soc-tegra-utils-objs += tegra_asoc_utils.o
+snd-soc-tegra20-das-objs := tegra20_das.o
+snd-soc-tegra20-i2s-objs := tegra20_i2s.o
+snd-soc-tegra20-spdif-objs := tegra20_spdif.o
+snd-soc-tegra30-ahub-objs := tegra30_ahub.o
+snd-soc-tegra30-i2s-objs := tegra30_i2s.o
 
-obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
-obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-das.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
-obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o
-obj-$(CONFIG_SND_SOC_TEGRA_SPDIF) += snd-soc-tegra-spdif.o
+obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
+obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o
+obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
+obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
+obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 
 # Tegra machine Support
+snd-soc-tegra-wm8753-objs := tegra_wm8753.o
 snd-soc-tegra-wm8903-objs := tegra_wm8903.o
 snd-soc-tegra-trimslice-objs := trimslice.o
 snd-soc-tegra-alc5632-objs := tegra_alc5632.o
 
+obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
 obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
 obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c
new file mode 100644 (file)
index 0000000..bf99296
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * tegra20_das.c - Tegra20 DAS driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include "tegra20_das.h"
+
+#define DRV_NAME "tegra20-das"
+
+static struct tegra20_das *das;
+
+static inline void tegra20_das_write(u32 reg, u32 val)
+{
+       regmap_write(das->regmap, reg, val);
+}
+
+static inline u32 tegra20_das_read(u32 reg)
+{
+       u32 val;
+       regmap_read(das->regmap, reg, &val);
+       return val;
+}
+
+int tegra20_das_connect_dap_to_dac(int dap, int dac)
+{
+       u32 addr;
+       u32 reg;
+
+       if (!das)
+               return -ENODEV;
+
+       addr = TEGRA20_DAS_DAP_CTRL_SEL +
+               (dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
+       reg = dac << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
+
+       tegra20_das_write(addr, reg);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dac);
+
+int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master,
+                                  int sdata1rx, int sdata2rx)
+{
+       u32 addr;
+       u32 reg;
+
+       if (!das)
+               return -ENODEV;
+
+       addr = TEGRA20_DAS_DAP_CTRL_SEL +
+               (dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
+       reg = otherdap << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P |
+               !!sdata2rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P |
+               !!sdata1rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P |
+               !!master << TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P;
+
+       tegra20_das_write(addr, reg);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dap);
+
+int tegra20_das_connect_dac_to_dap(int dac, int dap)
+{
+       u32 addr;
+       u32 reg;
+
+       if (!das)
+               return -ENODEV;
+
+       addr = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL +
+               (dac * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
+       reg = dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
+               dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
+               dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
+
+       tegra20_das_write(addr, reg);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra20_das_connect_dac_to_dap);
+
+#define LAST_REG(name) \
+       (TEGRA20_DAS_##name + \
+        (TEGRA20_DAS_##name##_STRIDE * (TEGRA20_DAS_##name##_COUNT - 1)))
+
+static bool tegra20_das_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+       if ((reg >= TEGRA20_DAS_DAP_CTRL_SEL) &&
+           (reg <= LAST_REG(DAP_CTRL_SEL)))
+               return true;
+       if ((reg >= TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL) &&
+           (reg <= LAST_REG(DAC_INPUT_DATA_CLK_SEL)))
+               return true;
+
+       return false;
+}
+
+static const struct regmap_config tegra20_das_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = LAST_REG(DAC_INPUT_DATA_CLK_SEL),
+       .writeable_reg = tegra20_das_wr_rd_reg,
+       .readable_reg = tegra20_das_wr_rd_reg,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit tegra20_das_probe(struct platform_device *pdev)
+{
+       struct resource *res, *region;
+       void __iomem *regs;
+       int ret = 0;
+
+       if (das)
+               return -ENODEV;
+
+       das = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_das), GFP_KERNEL);
+       if (!das) {
+               dev_err(&pdev->dev, "Can't allocate tegra20_das\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+       das->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "No memory resource\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       region = devm_request_mem_region(&pdev->dev, res->start,
+                                        resource_size(res), pdev->name);
+       if (!region) {
+               dev_err(&pdev->dev, "Memory region already claimed\n");
+               ret = -EBUSY;
+               goto err;
+       }
+
+       regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!regs) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       das->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+                                           &tegra20_das_regmap_config);
+       if (IS_ERR(das->regmap)) {
+               dev_err(&pdev->dev, "regmap init failed\n");
+               ret = PTR_ERR(das->regmap);
+               goto err;
+       }
+
+       ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_1,
+                                            TEGRA20_DAS_DAP_SEL_DAC1);
+       if (ret) {
+               dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
+               goto err;
+       }
+       ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_1,
+                                            TEGRA20_DAS_DAC_SEL_DAP1);
+       if (ret) {
+               dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, das);
+
+       return 0;
+
+err:
+       das = NULL;
+       return ret;
+}
+
+static int __devexit tegra20_das_remove(struct platform_device *pdev)
+{
+       if (!das)
+               return -ENODEV;
+
+       das = NULL;
+
+       return 0;
+}
+
+static const struct of_device_id tegra20_das_of_match[] __devinitconst = {
+       { .compatible = "nvidia,tegra20-das", },
+       {},
+};
+
+static struct platform_driver tegra20_das_driver = {
+       .probe = tegra20_das_probe,
+       .remove = __devexit_p(tegra20_das_remove),
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = tegra20_das_of_match,
+       },
+};
+module_platform_driver(tegra20_das_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 DAS driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra20_das_of_match);
diff --git a/sound/soc/tegra/tegra20_das.h b/sound/soc/tegra/tegra20_das.h
new file mode 100644 (file)
index 0000000..be217f3
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * tegra20_das.h - Definitions for Tegra20 DAS driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TEGRA20_DAS_H__
+#define __TEGRA20_DAS_H__
+
+/* Register TEGRA20_DAS_DAP_CTRL_SEL */
+#define TEGRA20_DAS_DAP_CTRL_SEL                       0x00
+#define TEGRA20_DAS_DAP_CTRL_SEL_COUNT                 5
+#define TEGRA20_DAS_DAP_CTRL_SEL_STRIDE                        4
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P          31
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S          1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P    30
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S    1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P    29
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S    1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P                0
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S                5
+
+/* Values for field TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
+#define TEGRA20_DAS_DAP_SEL_DAC1       0
+#define TEGRA20_DAS_DAP_SEL_DAC2       1
+#define TEGRA20_DAS_DAP_SEL_DAC3       2
+#define TEGRA20_DAS_DAP_SEL_DAP1       16
+#define TEGRA20_DAS_DAP_SEL_DAP2       17
+#define TEGRA20_DAS_DAP_SEL_DAP3       18
+#define TEGRA20_DAS_DAP_SEL_DAP4       19
+#define TEGRA20_DAS_DAP_SEL_DAP5       20
+
+/* Register TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL */
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL                     0x40
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT               3
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE              4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P    28
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S    4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P    24
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S    4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P       0
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S       4
+
+/*
+ * Values for:
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
+ */
+#define TEGRA20_DAS_DAC_SEL_DAP1       0
+#define TEGRA20_DAS_DAC_SEL_DAP2       1
+#define TEGRA20_DAS_DAC_SEL_DAP3       2
+#define TEGRA20_DAS_DAC_SEL_DAP4       3
+#define TEGRA20_DAS_DAC_SEL_DAP5       4
+
+/*
+ * Names/IDs of the DACs/DAPs.
+ */
+
+#define TEGRA20_DAS_DAP_ID_1 0
+#define TEGRA20_DAS_DAP_ID_2 1
+#define TEGRA20_DAS_DAP_ID_3 2
+#define TEGRA20_DAS_DAP_ID_4 3
+#define TEGRA20_DAS_DAP_ID_5 4
+
+#define TEGRA20_DAS_DAC_ID_1 0
+#define TEGRA20_DAS_DAC_ID_2 1
+#define TEGRA20_DAS_DAC_ID_3 2
+
+struct tegra20_das {
+       struct device *dev;
+       struct regmap *regmap;
+};
+
+/*
+ * Terminology:
+ * DAS: Digital audio switch (HW module controlled by this driver)
+ * DAP: Digital audio port (port/pins on Tegra device)
+ * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
+ *
+ * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
+ * DAC, or another DAP. When DAPs are connected, one must be the master and
+ * one the slave. Each DAC allows selection of a specific DAP for input, to
+ * cater for the case where N DAPs are connected to 1 DAC for broadcast
+ * output.
+ *
+ * This driver is dumb; no attempt is made to ensure that a valid routing
+ * configuration is programmed.
+ */
+
+/*
+ * Connect a DAP to to a DAC
+ * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_*
+ * dac_sel: DAC to connect to: TEGRA20_DAS_DAP_SEL_DAC*
+ */
+extern int tegra20_das_connect_dap_to_dac(int dap_id, int dac_sel);
+
+/*
+ * Connect a DAP to to another DAP
+ * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_*
+ * other_dap_sel: DAP to connect to: TEGRA20_DAS_DAP_SEL_DAP*
+ * master: Is this DAP the master (1) or slave (0)
+ * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0)
+ * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0)
+ */
+extern int tegra20_das_connect_dap_to_dap(int dap_id, int other_dap_sel,
+                                         int master, int sdata1rx,
+                                         int sdata2rx);
+
+/*
+ * Connect a DAC's input to a DAP
+ * (DAC outputs are selected by the DAP)
+ * dac_id: DAC ID to connect: TEGRA20_DAS_DAC_ID_*
+ * dap_sel: DAP to receive input from: TEGRA20_DAS_DAC_SEL_DAP*
+ */
+extern int tegra20_das_connect_dac_to_dap(int dac_id, int dap_sel);
+
+#endif
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
new file mode 100644 (file)
index 0000000..0c7af63
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * tegra20_i2s.c - Tegra20 I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.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/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra20_i2s.h"
+
+#define DRV_NAME "tegra20-i2s"
+
+static inline void tegra20_i2s_write(struct tegra20_i2s *i2s, u32 reg, u32 val)
+{
+       regmap_write(i2s->regmap, reg, val);
+}
+
+static inline u32 tegra20_i2s_read(struct tegra20_i2s *i2s, u32 reg)
+{
+       u32 val;
+       regmap_read(i2s->regmap, reg, &val);
+       return val;
+}
+
+static int tegra20_i2s_runtime_suspend(struct device *dev)
+{
+       struct tegra20_i2s *i2s = dev_get_drvdata(dev);
+
+       clk_disable(i2s->clk_i2s);
+
+       return 0;
+}
+
+static int tegra20_i2s_runtime_resume(struct device *dev)
+{
+       struct tegra20_i2s *i2s = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_enable(i2s->clk_i2s);
+       if (ret) {
+               dev_err(dev, "clk_enable failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
+                               unsigned int fmt)
+{
+       struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_MASTER_ENABLE;
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       i2s->reg_ctrl &= ~(TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
+                          TEGRA20_I2S_CTRL_LRCK_MASK);
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct device *dev = substream->pcm->card->dev;
+       struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+       u32 reg;
+       int ret, sample_size, srate, i2sclock, bitcnt;
+
+       i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_16;
+               sample_size = 16;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_24;
+               sample_size = 24;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_32;
+               sample_size = 32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       srate = params_rate(params);
+
+       /* Final "* 2" required by Tegra hardware */
+       i2sclock = srate * params_channels(params) * sample_size * 2;
+
+       ret = clk_set_rate(i2s->clk_i2s, i2sclock);
+       if (ret) {
+               dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
+               return ret;
+       }
+
+       bitcnt = (i2sclock / (2 * srate)) - 1;
+       if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
+               return -EINVAL;
+       reg = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
+
+       if (i2sclock % (2 * srate))
+               reg |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
+
+       tegra20_i2s_write(i2s, TEGRA20_I2S_TIMING, reg);
+
+       tegra20_i2s_write(i2s, TEGRA20_I2S_FIFO_SCR,
+               TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
+               TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
+
+       return 0;
+}
+
+static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s)
+{
+       i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO1_ENABLE;
+       tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s)
+{
+       i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO1_ENABLE;
+       tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s)
+{
+       i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO2_ENABLE;
+       tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s)
+{
+       i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO2_ENABLE;
+       tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
+{
+       struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       tegra20_i2s_start_playback(i2s);
+               else
+                       tegra20_i2s_start_capture(i2s);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       tegra20_i2s_stop_playback(i2s);
+               else
+                       tegra20_i2s_stop_capture(i2s);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int tegra20_i2s_probe(struct snd_soc_dai *dai)
+{
+       struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       dai->capture_dma_data = &i2s->capture_dma_data;
+       dai->playback_dma_data = &i2s->playback_dma_data;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
+       .set_fmt        = tegra20_i2s_set_fmt,
+       .hw_params      = tegra20_i2s_hw_params,
+       .trigger        = tegra20_i2s_trigger,
+};
+
+static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
+       .probe = tegra20_i2s_probe,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &tegra20_i2s_dai_ops,
+       .symmetric_rates = 1,
+};
+
+static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA20_I2S_CTRL:
+       case TEGRA20_I2S_STATUS:
+       case TEGRA20_I2S_TIMING:
+       case TEGRA20_I2S_FIFO_SCR:
+       case TEGRA20_I2S_PCM_CTRL:
+       case TEGRA20_I2S_NW_CTRL:
+       case TEGRA20_I2S_TDM_CTRL:
+       case TEGRA20_I2S_TDM_TX_RX_CTRL:
+       case TEGRA20_I2S_FIFO1:
+       case TEGRA20_I2S_FIFO2:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static bool tegra20_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA20_I2S_STATUS:
+       case TEGRA20_I2S_FIFO_SCR:
+       case TEGRA20_I2S_FIFO1:
+       case TEGRA20_I2S_FIFO2:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static bool tegra20_i2s_precious_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA20_I2S_FIFO1:
+       case TEGRA20_I2S_FIFO2:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static const struct regmap_config tegra20_i2s_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = TEGRA20_I2S_FIFO2,
+       .writeable_reg = tegra20_i2s_wr_rd_reg,
+       .readable_reg = tegra20_i2s_wr_rd_reg,
+       .volatile_reg = tegra20_i2s_volatile_reg,
+       .precious_reg = tegra20_i2s_precious_reg,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
+{
+       struct tegra20_i2s *i2s;
+       struct resource *mem, *memregion, *dmareq;
+       u32 of_dma[2];
+       u32 dma_ch;
+       void __iomem *regs;
+       int ret;
+
+       i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_i2s), GFP_KERNEL);
+       if (!i2s) {
+               dev_err(&pdev->dev, "Can't allocate tegra20_i2s\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+       dev_set_drvdata(&pdev->dev, i2s);
+
+       i2s->dai = tegra20_i2s_dai_template;
+       i2s->dai.name = dev_name(&pdev->dev);
+
+       i2s->clk_i2s = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(i2s->clk_i2s)) {
+               dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
+               ret = PTR_ERR(i2s->clk_i2s);
+               goto err;
+       }
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "No memory resource\n");
+               ret = -ENODEV;
+               goto err_clk_put;
+       }
+
+       dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!dmareq) {
+               if (of_property_read_u32_array(pdev->dev.of_node,
+                                       "nvidia,dma-request-selector",
+                                       of_dma, 2) < 0) {
+                       dev_err(&pdev->dev, "No DMA resource\n");
+                       ret = -ENODEV;
+                       goto err_clk_put;
+               }
+               dma_ch = of_dma[1];
+       } else {
+               dma_ch = dmareq->start;
+       }
+
+       memregion = devm_request_mem_region(&pdev->dev, mem->start,
+                                           resource_size(mem), DRV_NAME);
+       if (!memregion) {
+               dev_err(&pdev->dev, "Memory region already claimed\n");
+               ret = -EBUSY;
+               goto err_clk_put;
+       }
+
+       regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+       if (!regs) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -ENOMEM;
+               goto err_clk_put;
+       }
+
+       i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+                                           &tegra20_i2s_regmap_config);
+       if (IS_ERR(i2s->regmap)) {
+               dev_err(&pdev->dev, "regmap init failed\n");
+               ret = PTR_ERR(i2s->regmap);
+               goto err_clk_put;
+       }
+
+       i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
+       i2s->capture_dma_data.wrap = 4;
+       i2s->capture_dma_data.width = 32;
+       i2s->capture_dma_data.req_sel = dma_ch;
+
+       i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
+       i2s->playback_dma_data.wrap = 4;
+       i2s->playback_dma_data.width = 32;
+       i2s->playback_dma_data.req_sel = dma_ch;
+
+       i2s->reg_ctrl = TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
+
+       pm_runtime_enable(&pdev->dev);
+       if (!pm_runtime_enabled(&pdev->dev)) {
+               ret = tegra20_i2s_runtime_resume(&pdev->dev);
+               if (ret)
+                       goto err_pm_disable;
+       }
+
+       ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+               ret = -ENOMEM;
+               goto err_suspend;
+       }
+
+       ret = tegra_pcm_platform_register(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+               goto err_unregister_dai;
+       }
+
+       return 0;
+
+err_unregister_dai:
+       snd_soc_unregister_dai(&pdev->dev);
+err_suspend:
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               tegra20_i2s_runtime_suspend(&pdev->dev);
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
+err_clk_put:
+       clk_put(i2s->clk_i2s);
+err:
+       return ret;
+}
+
+static int __devexit tegra20_i2s_platform_remove(struct platform_device *pdev)
+{
+       struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev);
+
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               tegra20_i2s_runtime_suspend(&pdev->dev);
+
+       tegra_pcm_platform_unregister(&pdev->dev);
+       snd_soc_unregister_dai(&pdev->dev);
+
+       clk_put(i2s->clk_i2s);
+
+       return 0;
+}
+
+static const struct of_device_id tegra20_i2s_of_match[] __devinitconst = {
+       { .compatible = "nvidia,tegra20-i2s", },
+       {},
+};
+
+static const struct dev_pm_ops tegra20_i2s_pm_ops __devinitconst = {
+       SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend,
+                          tegra20_i2s_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra20_i2s_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = tegra20_i2s_of_match,
+               .pm = &tegra20_i2s_pm_ops,
+       },
+       .probe = tegra20_i2s_platform_probe,
+       .remove = __devexit_p(tegra20_i2s_platform_remove),
+};
+module_platform_driver(tegra20_i2s_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 I2S ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra20_i2s_of_match);
diff --git a/sound/soc/tegra/tegra20_i2s.h b/sound/soc/tegra/tegra20_i2s.h
new file mode 100644 (file)
index 0000000..a57efc6
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * tegra20_i2s.h - Definitions for Tegra20 I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.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 __TEGRA20_I2S_H__
+#define __TEGRA20_I2S_H__
+
+#include "tegra_pcm.h"
+
+/* Register offsets from TEGRA20_I2S1_BASE and TEGRA20_I2S2_BASE */
+
+#define TEGRA20_I2S_CTRL                               0x00
+#define TEGRA20_I2S_STATUS                             0x04
+#define TEGRA20_I2S_TIMING                             0x08
+#define TEGRA20_I2S_FIFO_SCR                           0x0c
+#define TEGRA20_I2S_PCM_CTRL                           0x10
+#define TEGRA20_I2S_NW_CTRL                            0x14
+#define TEGRA20_I2S_TDM_CTRL                           0x20
+#define TEGRA20_I2S_TDM_TX_RX_CTRL                     0x24
+#define TEGRA20_I2S_FIFO1                              0x40
+#define TEGRA20_I2S_FIFO2                              0x80
+
+/* Fields in TEGRA20_I2S_CTRL */
+
+#define TEGRA20_I2S_CTRL_FIFO2_TX_ENABLE               (1 << 30)
+#define TEGRA20_I2S_CTRL_FIFO1_ENABLE                  (1 << 29)
+#define TEGRA20_I2S_CTRL_FIFO2_ENABLE                  (1 << 28)
+#define TEGRA20_I2S_CTRL_FIFO1_RX_ENABLE               (1 << 27)
+#define TEGRA20_I2S_CTRL_FIFO_LPBK_ENABLE              (1 << 26)
+#define TEGRA20_I2S_CTRL_MASTER_ENABLE                 (1 << 25)
+
+#define TEGRA20_I2S_LRCK_LEFT_LOW                              0
+#define TEGRA20_I2S_LRCK_RIGHT_LOW                     1
+
+#define TEGRA20_I2S_CTRL_LRCK_SHIFT                    24
+#define TEGRA20_I2S_CTRL_LRCK_MASK                     (1                          << TEGRA20_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA20_I2S_CTRL_LRCK_L_LOW                    (TEGRA20_I2S_LRCK_LEFT_LOW  << TEGRA20_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA20_I2S_CTRL_LRCK_R_LOW                    (TEGRA20_I2S_LRCK_RIGHT_LOW << TEGRA20_I2S_CTRL_LRCK_SHIFT)
+
+#define TEGRA20_I2S_BIT_FORMAT_I2S                     0
+#define TEGRA20_I2S_BIT_FORMAT_RJM                     1
+#define TEGRA20_I2S_BIT_FORMAT_LJM                     2
+#define TEGRA20_I2S_BIT_FORMAT_DSP                     3
+
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT              10
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_MASK               (3                          << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_I2S                        (TEGRA20_I2S_BIT_FORMAT_I2S << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_RJM                        (TEGRA20_I2S_BIT_FORMAT_RJM << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_LJM                        (TEGRA20_I2S_BIT_FORMAT_LJM << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_DSP                        (TEGRA20_I2S_BIT_FORMAT_DSP << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+
+#define TEGRA20_I2S_BIT_SIZE_16                                0
+#define TEGRA20_I2S_BIT_SIZE_20                                1
+#define TEGRA20_I2S_BIT_SIZE_24                                2
+#define TEGRA20_I2S_BIT_SIZE_32                                3
+
+#define TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT                        8
+#define TEGRA20_I2S_CTRL_BIT_SIZE_MASK                 (3                       << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_16                   (TEGRA20_I2S_BIT_SIZE_16 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_20                   (TEGRA20_I2S_BIT_SIZE_20 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_24                   (TEGRA20_I2S_BIT_SIZE_24 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_32                   (TEGRA20_I2S_BIT_SIZE_32 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+
+#define TEGRA20_I2S_FIFO_16_LSB                                0
+#define TEGRA20_I2S_FIFO_20_LSB                                1
+#define TEGRA20_I2S_FIFO_24_LSB                                2
+#define TEGRA20_I2S_FIFO_32                            3
+#define TEGRA20_I2S_FIFO_PACKED                                7
+
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT             4
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK              (7                       << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_16_LSB            (TEGRA20_I2S_FIFO_16_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_20_LSB            (TEGRA20_I2S_FIFO_20_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_24_LSB            (TEGRA20_I2S_FIFO_24_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_32                        (TEGRA20_I2S_FIFO_32     << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED            (TEGRA20_I2S_FIFO_PACKED << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+
+#define TEGRA20_I2S_CTRL_IE_FIFO1_ERR                  (1 << 3)
+#define TEGRA20_I2S_CTRL_IE_FIFO2_ERR                  (1 << 2)
+#define TEGRA20_I2S_CTRL_QE_FIFO1                      (1 << 1)
+#define TEGRA20_I2S_CTRL_QE_FIFO2                      (1 << 0)
+
+/* Fields in TEGRA20_I2S_STATUS */
+
+#define TEGRA20_I2S_STATUS_FIFO1_RDY                   (1 << 31)
+#define TEGRA20_I2S_STATUS_FIFO2_RDY                   (1 << 30)
+#define TEGRA20_I2S_STATUS_FIFO1_BSY                   (1 << 29)
+#define TEGRA20_I2S_STATUS_FIFO2_BSY                   (1 << 28)
+#define TEGRA20_I2S_STATUS_FIFO1_ERR                   (1 << 3)
+#define TEGRA20_I2S_STATUS_FIFO2_ERR                   (1 << 2)
+#define TEGRA20_I2S_STATUS_QS_FIFO1                    (1 << 1)
+#define TEGRA20_I2S_STATUS_QS_FIFO2                    (1 << 0)
+
+/* Fields in TEGRA20_I2S_TIMING */
+
+#define TEGRA20_I2S_TIMING_NON_SYM_ENABLE              (1 << 12)
+#define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT     0
+#define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US   0x7fff
+#define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK      (TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT)
+
+/* Fields in TEGRA20_I2S_FIFO_SCR */
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT      24
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT      16
+#define TEGRA20_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK                0x3f
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_CLR                 (1 << 12)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_CLR                 (1 << 8)
+
+#define TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT              0
+#define TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS            1
+#define TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS           2
+#define TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS          3
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT       4
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK                (3 << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT    (TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT     << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS  (TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS   << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS  << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS        (TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT       0
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK                (3 << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT    (TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT     << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS  (TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS   << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS  << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS        (TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+
+struct tegra20_i2s {
+       struct snd_soc_dai_driver dai;
+       struct clk *clk_i2s;
+       struct tegra_pcm_dma_params capture_dma_data;
+       struct tegra_pcm_dma_params playback_dma_data;
+       struct regmap *regmap;
+       u32 reg_ctrl;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
new file mode 100644 (file)
index 0000000..f9b5741
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * tegra20_spdif.c - Tegra20 SPDIF driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2011-2012 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra20_spdif.h"
+
+#define DRV_NAME "tegra20-spdif"
+
+static inline void tegra20_spdif_write(struct tegra20_spdif *spdif, u32 reg,
+                                       u32 val)
+{
+       regmap_write(spdif->regmap, reg, val);
+}
+
+static inline u32 tegra20_spdif_read(struct tegra20_spdif *spdif, u32 reg)
+{
+       u32 val;
+       regmap_read(spdif->regmap, reg, &val);
+       return val;
+}
+
+static int tegra20_spdif_runtime_suspend(struct device *dev)
+{
+       struct tegra20_spdif *spdif = dev_get_drvdata(dev);
+
+       clk_disable(spdif->clk_spdif_out);
+
+       return 0;
+}
+
+static int tegra20_spdif_runtime_resume(struct device *dev)
+{
+       struct tegra20_spdif *spdif = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_enable(spdif->clk_spdif_out);
+       if (ret) {
+               dev_err(dev, "clk_enable failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct device *dev = substream->pcm->card->dev;
+       struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+       int ret, spdifclock;
+
+       spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_PACK;
+       spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_PACK;
+               spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params_rate(params)) {
+       case 32000:
+               spdifclock = 4096000;
+               break;
+       case 44100:
+               spdifclock = 5644800;
+               break;
+       case 48000:
+               spdifclock = 6144000;
+               break;
+       case 88200:
+               spdifclock = 11289600;
+               break;
+       case 96000:
+               spdifclock = 12288000;
+               break;
+       case 176400:
+               spdifclock = 22579200;
+               break;
+       case 192000:
+               spdifclock = 24576000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);
+       if (ret) {
+               dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void tegra20_spdif_start_playback(struct tegra20_spdif *spdif)
+{
+       spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_TX_EN;
+       tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl);
+}
+
+static void tegra20_spdif_stop_playback(struct tegra20_spdif *spdif)
+{
+       spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_TX_EN;
+       tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl);
+}
+
+static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               tegra20_spdif_start_playback(spdif);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               tegra20_spdif_stop_playback(spdif);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int tegra20_spdif_probe(struct snd_soc_dai *dai)
+{
+       struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+       dai->capture_dma_data = NULL;
+       dai->playback_dma_data = &spdif->playback_dma_data;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = {
+       .hw_params      = tegra20_spdif_hw_params,
+       .trigger        = tegra20_spdif_trigger,
+};
+
+static struct snd_soc_dai_driver tegra20_spdif_dai = {
+       .name = DRV_NAME,
+       .probe = tegra20_spdif_probe,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+                               SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &tegra20_spdif_dai_ops,
+};
+
+static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA20_SPDIF_CTRL:
+       case TEGRA20_SPDIF_STATUS:
+       case TEGRA20_SPDIF_STROBE_CTRL:
+       case TEGRA20_SPDIF_DATA_FIFO_CSR:
+       case TEGRA20_SPDIF_DATA_OUT:
+       case TEGRA20_SPDIF_DATA_IN:
+       case TEGRA20_SPDIF_CH_STA_RX_A:
+       case TEGRA20_SPDIF_CH_STA_RX_B:
+       case TEGRA20_SPDIF_CH_STA_RX_C:
+       case TEGRA20_SPDIF_CH_STA_RX_D:
+       case TEGRA20_SPDIF_CH_STA_RX_E:
+       case TEGRA20_SPDIF_CH_STA_RX_F:
+       case TEGRA20_SPDIF_CH_STA_TX_A:
+       case TEGRA20_SPDIF_CH_STA_TX_B:
+       case TEGRA20_SPDIF_CH_STA_TX_C:
+       case TEGRA20_SPDIF_CH_STA_TX_D:
+       case TEGRA20_SPDIF_CH_STA_TX_E:
+       case TEGRA20_SPDIF_CH_STA_TX_F:
+       case TEGRA20_SPDIF_USR_STA_RX_A:
+       case TEGRA20_SPDIF_USR_DAT_TX_A:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static bool tegra20_spdif_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA20_SPDIF_STATUS:
+       case TEGRA20_SPDIF_DATA_FIFO_CSR:
+       case TEGRA20_SPDIF_DATA_OUT:
+       case TEGRA20_SPDIF_DATA_IN:
+       case TEGRA20_SPDIF_CH_STA_RX_A:
+       case TEGRA20_SPDIF_CH_STA_RX_B:
+       case TEGRA20_SPDIF_CH_STA_RX_C:
+       case TEGRA20_SPDIF_CH_STA_RX_D:
+       case TEGRA20_SPDIF_CH_STA_RX_E:
+       case TEGRA20_SPDIF_CH_STA_RX_F:
+       case TEGRA20_SPDIF_USR_STA_RX_A:
+       case TEGRA20_SPDIF_USR_DAT_TX_A:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static bool tegra20_spdif_precious_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA20_SPDIF_DATA_OUT:
+       case TEGRA20_SPDIF_DATA_IN:
+       case TEGRA20_SPDIF_USR_STA_RX_A:
+       case TEGRA20_SPDIF_USR_DAT_TX_A:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static const struct regmap_config tegra20_spdif_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = TEGRA20_SPDIF_USR_DAT_TX_A,
+       .writeable_reg = tegra20_spdif_wr_rd_reg,
+       .readable_reg = tegra20_spdif_wr_rd_reg,
+       .volatile_reg = tegra20_spdif_volatile_reg,
+       .precious_reg = tegra20_spdif_precious_reg,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev)
+{
+       struct tegra20_spdif *spdif;
+       struct resource *mem, *memregion, *dmareq;
+       void __iomem *regs;
+       int ret;
+
+       spdif = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_spdif),
+                            GFP_KERNEL);
+       if (!spdif) {
+               dev_err(&pdev->dev, "Can't allocate tegra20_spdif\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+       dev_set_drvdata(&pdev->dev, spdif);
+
+       spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out");
+       if (IS_ERR(spdif->clk_spdif_out)) {
+               pr_err("Can't retrieve spdif clock\n");
+               ret = PTR_ERR(spdif->clk_spdif_out);
+               goto err;
+       }
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "No memory resource\n");
+               ret = -ENODEV;
+               goto err_clk_put;
+       }
+
+       dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!dmareq) {
+               dev_err(&pdev->dev, "No DMA resource\n");
+               ret = -ENODEV;
+               goto err_clk_put;
+       }
+
+       memregion = devm_request_mem_region(&pdev->dev, mem->start,
+                                           resource_size(mem), DRV_NAME);
+       if (!memregion) {
+               dev_err(&pdev->dev, "Memory region already claimed\n");
+               ret = -EBUSY;
+               goto err_clk_put;
+       }
+
+       regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+       if (!regs) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -ENOMEM;
+               goto err_clk_put;
+       }
+
+       spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+                                           &tegra20_spdif_regmap_config);
+       if (IS_ERR(spdif->regmap)) {
+               dev_err(&pdev->dev, "regmap init failed\n");
+               ret = PTR_ERR(spdif->regmap);
+               goto err_clk_put;
+       }
+
+       spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT;
+       spdif->playback_dma_data.wrap = 4;
+       spdif->playback_dma_data.width = 32;
+       spdif->playback_dma_data.req_sel = dmareq->start;
+
+       pm_runtime_enable(&pdev->dev);
+       if (!pm_runtime_enabled(&pdev->dev)) {
+               ret = tegra20_spdif_runtime_resume(&pdev->dev);
+               if (ret)
+                       goto err_pm_disable;
+       }
+
+       ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+               ret = -ENOMEM;
+               goto err_suspend;
+       }
+
+       ret = tegra_pcm_platform_register(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+               goto err_unregister_dai;
+       }
+
+       return 0;
+
+err_unregister_dai:
+       snd_soc_unregister_dai(&pdev->dev);
+err_suspend:
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               tegra20_spdif_runtime_suspend(&pdev->dev);
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
+err_clk_put:
+       clk_put(spdif->clk_spdif_out);
+err:
+       return ret;
+}
+
+static int __devexit tegra20_spdif_platform_remove(struct platform_device *pdev)
+{
+       struct tegra20_spdif *spdif = dev_get_drvdata(&pdev->dev);
+
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               tegra20_spdif_runtime_suspend(&pdev->dev);
+
+       tegra_pcm_platform_unregister(&pdev->dev);
+       snd_soc_unregister_dai(&pdev->dev);
+
+       clk_put(spdif->clk_spdif_out);
+
+       return 0;
+}
+
+static const struct dev_pm_ops tegra20_spdif_pm_ops __devinitconst = {
+       SET_RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend,
+                          tegra20_spdif_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra20_spdif_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .pm = &tegra20_spdif_pm_ops,
+       },
+       .probe = tegra20_spdif_platform_probe,
+       .remove = __devexit_p(tegra20_spdif_platform_remove),
+};
+
+module_platform_driver(tegra20_spdif_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 SPDIF ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h
new file mode 100644 (file)
index 0000000..ed75652
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ * tegra20_spdif.h - Definitions for Tegra20 SPDIF driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2011 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ * Copyright (c) 2008-2009, NVIDIA 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.
+ *
+ * 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 __TEGRA20_SPDIF_H__
+#define __TEGRA20_SPDIF_H__
+
+#include "tegra_pcm.h"
+
+/* Offsets from TEGRA20_SPDIF_BASE */
+
+#define TEGRA20_SPDIF_CTRL                                     0x0
+#define TEGRA20_SPDIF_STATUS                                   0x4
+#define TEGRA20_SPDIF_STROBE_CTRL                              0x8
+#define TEGRA20_SPDIF_DATA_FIFO_CSR                            0x0C
+#define TEGRA20_SPDIF_DATA_OUT                                 0x40
+#define TEGRA20_SPDIF_DATA_IN                                  0x80
+#define TEGRA20_SPDIF_CH_STA_RX_A                              0x100
+#define TEGRA20_SPDIF_CH_STA_RX_B                              0x104
+#define TEGRA20_SPDIF_CH_STA_RX_C                              0x108
+#define TEGRA20_SPDIF_CH_STA_RX_D                              0x10C
+#define TEGRA20_SPDIF_CH_STA_RX_E                              0x110
+#define TEGRA20_SPDIF_CH_STA_RX_F                              0x114
+#define TEGRA20_SPDIF_CH_STA_TX_A                              0x140
+#define TEGRA20_SPDIF_CH_STA_TX_B                              0x144
+#define TEGRA20_SPDIF_CH_STA_TX_C                              0x148
+#define TEGRA20_SPDIF_CH_STA_TX_D                              0x14C
+#define TEGRA20_SPDIF_CH_STA_TX_E                              0x150
+#define TEGRA20_SPDIF_CH_STA_TX_F                              0x154
+#define TEGRA20_SPDIF_USR_STA_RX_A                             0x180
+#define TEGRA20_SPDIF_USR_DAT_TX_A                             0x1C0
+
+/* Fields in TEGRA20_SPDIF_CTRL */
+
+/* Start capturing from 0=right, 1=left channel */
+#define TEGRA20_SPDIF_CTRL_CAP_LC                              (1 << 30)
+
+/* SPDIF receiver(RX) enable */
+#define TEGRA20_SPDIF_CTRL_RX_EN                               (1 << 29)
+
+/* SPDIF Transmitter(TX) enable */
+#define TEGRA20_SPDIF_CTRL_TX_EN                               (1 << 28)
+
+/* Transmit Channel status */
+#define TEGRA20_SPDIF_CTRL_TC_EN                               (1 << 27)
+
+/* Transmit user Data */
+#define TEGRA20_SPDIF_CTRL_TU_EN                               (1 << 26)
+
+/* Interrupt on transmit error */
+#define TEGRA20_SPDIF_CTRL_IE_TXE                              (1 << 25)
+
+/* Interrupt on receive error */
+#define TEGRA20_SPDIF_CTRL_IE_RXE                              (1 << 24)
+
+/* Interrupt on invalid preamble */
+#define TEGRA20_SPDIF_CTRL_IE_P                                        (1 << 23)
+
+/* Interrupt on "B" preamble */
+#define TEGRA20_SPDIF_CTRL_IE_B                                        (1 << 22)
+
+/* Interrupt when block of channel status received */
+#define TEGRA20_SPDIF_CTRL_IE_C                                        (1 << 21)
+
+/* Interrupt when a valid information unit (IU) is received */
+#define TEGRA20_SPDIF_CTRL_IE_U                                        (1 << 20)
+
+/* Interrupt when RX user FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_RU                               (1 << 19)
+
+/* Interrupt when TX user FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_TU                               (1 << 18)
+
+/* Interrupt when RX data FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_RX                               (1 << 17)
+
+/* Interrupt when TX data FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_TX                               (1 << 16)
+
+/* Loopback test mode enable */
+#define TEGRA20_SPDIF_CTRL_LBK_EN                              (1 << 15)
+
+/*
+ * Pack data mode:
+ * 0 = Single data (16 bit needs to be  padded to match the
+ *     interface data bit size).
+ * 1 = Packeted left/right channel data into a single word.
+ */
+#define TEGRA20_SPDIF_CTRL_PACK                                        (1 << 14)
+
+/*
+ * 00 = 16bit data
+ * 01 = 20bit data
+ * 10 = 24bit data
+ * 11 = raw data
+ */
+#define TEGRA20_SPDIF_BIT_MODE_16BIT                           0
+#define TEGRA20_SPDIF_BIT_MODE_20BIT                           1
+#define TEGRA20_SPDIF_BIT_MODE_24BIT                           2
+#define TEGRA20_SPDIF_BIT_MODE_RAW                             3
+
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT                      12
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_MASK                       (3                            << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT                      (TEGRA20_SPDIF_BIT_MODE_16BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_20BIT                      (TEGRA20_SPDIF_BIT_MODE_20BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_24BIT                      (TEGRA20_SPDIF_BIT_MODE_24BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_RAW                                (TEGRA20_SPDIF_BIT_MODE_RAW   << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_STATUS */
+
+/*
+ * Note: IS_P, IS_B, IS_C, and IS_U are sticky bits. Software must
+ * write a 1 to the corresponding bit location to clear the status.
+ */
+
+/*
+ * Receiver(RX) shifter is busy receiving data.
+ * This bit is asserted when the receiver first locked onto the
+ * preamble of the data stream after RX_EN is asserted. This bit is
+ * deasserted when either,
+ * (a) the end of a frame is reached after RX_EN is deeasserted, or
+ * (b) the SPDIF data stream becomes inactive.
+ */
+#define TEGRA20_SPDIF_STATUS_RX_BSY                            (1 << 29)
+
+/*
+ * Transmitter(TX) shifter is busy transmitting data.
+ * This bit is asserted when TX_EN is asserted.
+ * This bit is deasserted when the end of a frame is reached after
+ * TX_EN is deasserted.
+ */
+#define TEGRA20_SPDIF_STATUS_TX_BSY                            (1 << 28)
+
+/*
+ * TX is busy shifting out channel status.
+ * This bit is asserted when both TX_EN and TC_EN are asserted and
+ * data from CH_STA_TX_A register is loaded into the internal shifter.
+ * This bit is deasserted when either,
+ * (a) the end of a frame is reached after TX_EN is deasserted, or
+ * (b) CH_STA_TX_F register is loaded into the internal shifter.
+ */
+#define TEGRA20_SPDIF_STATUS_TC_BSY                            (1 << 27)
+
+/*
+ * TX User data FIFO busy.
+ * This bit is asserted when TX_EN and TXU_EN are asserted and
+ * there's data in the TX user FIFO.  This bit is deassert when either,
+ * (a) the end of a frame is reached after TX_EN is deasserted, or
+ * (b) there's no data left in the TX user FIFO.
+ */
+#define TEGRA20_SPDIF_STATUS_TU_BSY                            (1 << 26)
+
+/* TX FIFO Underrun error status */
+#define TEGRA20_SPDIF_STATUS_TX_ERR                            (1 << 25)
+
+/* RX FIFO Overrun error status */
+#define TEGRA20_SPDIF_STATUS_RX_ERR                            (1 << 24)
+
+/* Preamble status: 0=Preamble OK, 1=bad/missing preamble */
+#define TEGRA20_SPDIF_STATUS_IS_P                              (1 << 23)
+
+/* B-preamble detection status: 0=not detected, 1=B-preamble detected */
+#define TEGRA20_SPDIF_STATUS_IS_B                              (1 << 22)
+
+/*
+ * RX channel block data receive status:
+ * 0=entire block not recieved yet.
+ * 1=received entire block of channel status,
+ */
+#define TEGRA20_SPDIF_STATUS_IS_C                              (1 << 21)
+
+/* RX User Data Valid flag:  1=valid IU detected, 0 = no IU detected. */
+#define TEGRA20_SPDIF_STATUS_IS_U                              (1 << 20)
+
+/*
+ * RX User FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_RU                             (1 << 19)
+
+/*
+ * TX User FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_TU                             (1 << 18)
+
+/*
+ * RX Data FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_RX                             (1 << 17)
+
+/*
+ * TX Data FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_TX                             (1 << 16)
+
+/* Fields in TEGRA20_SPDIF_STROBE_CTRL */
+
+/*
+ * Indicates the approximate number of detected SPDIFIN clocks within a
+ * bi-phase period.
+ */
+#define TEGRA20_SPDIF_STROBE_CTRL_PERIOD_SHIFT                 16
+#define TEGRA20_SPDIF_STROBE_CTRL_PERIOD_MASK                  (0xff << TEGRA20_SPDIF_STROBE_CTRL_PERIOD_SHIFT)
+
+/* Data strobe mode: 0=Auto-locked 1=Manual locked */
+#define TEGRA20_SPDIF_STROBE_CTRL_STROBE                       (1 << 15)
+
+/*
+ * Manual data strobe time within the bi-phase clock period (in terms of
+ * the number of over-sampling clocks).
+ */
+#define TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT           8
+#define TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_MASK            (0x1f << TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT)
+
+/*
+ * Manual SPDIFIN bi-phase clock period (in terms of the number of
+ * over-sampling clocks).
+ */
+#define TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT           0
+#define TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK            (0x3f << TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT)
+
+/* Fields in SPDIF_DATA_FIFO_CSR */
+
+/* Clear Receiver User FIFO (RX USR.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_CLR                     (1 << 31)
+
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT                  0
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS                 1
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS               2
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS                        3
+
+/* RU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT           29
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_MASK            \
+               (0x3                                      << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU1_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU2_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU3_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU4_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+
+/* Number of RX USR.FIFO levels with valid data. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT                24
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_MASK         (0x1f << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT)
+
+/* Clear Transmitter User FIFO (TX USR.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_CLR                     (1 << 23)
+
+/* TU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT           21
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_MASK            \
+               (0x3                                      << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU1_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU2_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU3_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU4_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+
+/* Number of TX USR.FIFO levels that could be filled. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT       16
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_MASK                (0x1f << SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT)
+
+/* Clear Receiver Data FIFO (RX DATA.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_CLR                     (1 << 15)
+
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT                  0
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS                        1
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS               2
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS              3
+
+/* RU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT           13
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_MASK            \
+               (0x3                                       << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU1_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU4_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU8_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU12_WORD_FULL  \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+
+/* Number of RX DATA.FIFO levels with valid data. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT                8
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_MASK         (0x1f << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT)
+
+/* Clear Transmitter Data FIFO (TX DATA.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_CLR                     (1 << 7)
+
+/* TU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT           5
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK            \
+               (0x3                                       << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU1_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU8_WORD_FULL   \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU12_WORD_FULL  \
+               (TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+
+/* Number of TX DATA.FIFO levels that could be filled. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT       0
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_MASK                (0x1f << SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_DATA_OUT */
+
+/*
+ * This register has 5 different formats:
+ * 16-bit        (BIT_MODE=00, PACK=0)
+ * 20-bit        (BIT_MODE=01, PACK=0)
+ * 24-bit        (BIT_MODE=10, PACK=0)
+ * raw           (BIT_MODE=11, PACK=0)
+ * 16-bit packed (BIT_MODE=00, PACK=1)
+ */
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_SHIFT                   0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_MASK                    (0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_20_SHIFT                   0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_20_MASK                    (0xfffff << TEGRA20_SPDIF_DATA_OUT_DATA_20_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_24_SHIFT                   0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_24_MASK                    (0xffffff << TEGRA20_SPDIF_DATA_OUT_DATA_24_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_P                      (1 << 31)
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_C                      (1 << 30)
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_U                      (1 << 29)
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_V                      (1 << 28)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT             8
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_MASK              (0xfffff << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT              4
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_MASK               (0xf << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT         0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_MASK          (0xf << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT      16
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_MASK       (0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT       0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_MASK                (0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_DATA_IN */
+
+/*
+ * This register has 5 different formats:
+ * 16-bit        (BIT_MODE=00, PACK=0)
+ * 20-bit        (BIT_MODE=01, PACK=0)
+ * 24-bit        (BIT_MODE=10, PACK=0)
+ * raw           (BIT_MODE=11, PACK=0)
+ * 16-bit packed (BIT_MODE=00, PACK=1)
+ *
+ * Bits 31:24 are common to all modes except 16-bit packed
+ */
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_P                           (1 << 31)
+#define TEGRA20_SPDIF_DATA_IN_DATA_C                           (1 << 30)
+#define TEGRA20_SPDIF_DATA_IN_DATA_U                           (1 << 29)
+#define TEGRA20_SPDIF_DATA_IN_DATA_V                           (1 << 28)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT              24
+#define TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_MASK               (0xf << TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_SHIFT                    0
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_MASK                     (0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_20_SHIFT                    0
+#define TEGRA20_SPDIF_DATA_IN_DATA_20_MASK                     (0xfffff << TEGRA20_SPDIF_DATA_IN_DATA_20_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_24_SHIFT                    0
+#define TEGRA20_SPDIF_DATA_IN_DATA_24_MASK                     (0xffffff << TEGRA20_SPDIF_DATA_IN_DATA_24_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT              8
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_MASK               (0xfffff << TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT               4
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_MASK                        (0xf << TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT          0
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_MASK           (0xf << TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT       16
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_MASK                (0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT                0
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_MASK         (0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_A */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_B */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_C */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_D */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_E */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_F */
+
+/*
+ * The 6-word receive channel data page buffer holds a block (192 frames) of
+ * channel status information. The order of receive is from LSB to MSB
+ * bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A.
+ */
+
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_A */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_B */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_C */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_D */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_E */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_F */
+
+/*
+ * The 6-word transmit channel data page buffer holds a block (192 frames) of
+ * channel status information. The order of transmission is from LSB to MSB
+ * bit, and from CH_STA_TX_A to CH_STA_TX_F then back to CH_STA_TX_A.
+ */
+
+/* Fields in TEGRA20_SPDIF_USR_STA_RX_A */
+
+/*
+ * This 4-word deep FIFO receives user FIFO field information. The order of
+ * receive is from LSB to MSB bit.
+ */
+
+/* Fields in TEGRA20_SPDIF_USR_DAT_TX_A */
+
+/*
+ * This 4-word deep FIFO transmits user FIFO field information. The order of
+ * transmission is from LSB to MSB bit.
+ */
+
+struct tegra20_spdif {
+       struct clk *clk_spdif_out;
+       struct tegra_pcm_dma_params capture_dma_data;
+       struct tegra_pcm_dma_params playback_dma_data;
+       struct regmap *regmap;
+       u32 reg_ctrl;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
new file mode 100644 (file)
index 0000000..57cd419
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ * tegra30_ahub.c - Tegra30 AHUB driver
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <mach/clk.h>
+#include <mach/dma.h>
+#include <sound/soc.h>
+#include "tegra30_ahub.h"
+
+#define DRV_NAME "tegra30-ahub"
+
+static struct tegra30_ahub *ahub;
+
+static inline void tegra30_apbif_write(u32 reg, u32 val)
+{
+       regmap_write(ahub->regmap_apbif, reg, val);
+}
+
+static inline u32 tegra30_apbif_read(u32 reg)
+{
+       u32 val;
+       regmap_read(ahub->regmap_apbif, reg, &val);
+       return val;
+}
+
+static inline void tegra30_audio_write(u32 reg, u32 val)
+{
+       regmap_write(ahub->regmap_ahub, reg, val);
+}
+
+static int tegra30_ahub_runtime_suspend(struct device *dev)
+{
+       regcache_cache_only(ahub->regmap_apbif, true);
+       regcache_cache_only(ahub->regmap_ahub, true);
+
+       clk_disable(ahub->clk_apbif);
+       clk_disable(ahub->clk_d_audio);
+
+       return 0;
+}
+
+/*
+ * clk_apbif isn't required for an I2S<->I2S configuration where no PCM data
+ * is read from or sent to memory. However, that's not something the rest of
+ * the driver supports right now, so we'll just treat the two clocks as one
+ * for now.
+ *
+ * These functions should not be a plain ref-count. Instead, each active stream
+ * contributes some requirement to the minimum clock rate, so starting or
+ * stopping streams should dynamically adjust the clock as required.  However,
+ * this is not yet implemented.
+ */
+static int tegra30_ahub_runtime_resume(struct device *dev)
+{
+       int ret;
+
+       ret = clk_enable(ahub->clk_d_audio);
+       if (ret) {
+               dev_err(dev, "clk_enable d_audio failed: %d\n", ret);
+               return ret;
+       }
+       ret = clk_enable(ahub->clk_apbif);
+       if (ret) {
+               dev_err(dev, "clk_enable apbif failed: %d\n", ret);
+               clk_disable(ahub->clk_d_audio);
+               return ret;
+       }
+
+       regcache_cache_only(ahub->regmap_apbif, false);
+       regcache_cache_only(ahub->regmap_ahub, false);
+
+       return 0;
+}
+
+int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
+                                 unsigned long *fiforeg,
+                                 unsigned long *reqsel)
+{
+       int channel;
+       u32 reg, val;
+
+       channel = find_first_zero_bit(ahub->rx_usage,
+                                     TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
+       if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
+               return -EBUSY;
+
+       __set_bit(channel, ahub->rx_usage);
+
+       *rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel;
+       *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO +
+                  (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE);
+       *reqsel = ahub->dma_sel + channel;
+
+       reg = TEGRA30_AHUB_CHANNEL_CTRL +
+             (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+       val = tegra30_apbif_read(reg);
+       val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK |
+                TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK);
+       val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) |
+              TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN |
+              TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16;
+       tegra30_apbif_write(reg, val);
+
+       reg = TEGRA30_AHUB_CIF_RX_CTRL +
+             (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
+       val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+             (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+             (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+             TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
+             TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 |
+             TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
+       tegra30_apbif_write(reg, val);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo);
+
+int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
+{
+       int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+       int reg, val;
+
+       reg = TEGRA30_AHUB_CHANNEL_CTRL +
+             (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+       val = tegra30_apbif_read(reg);
+       val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
+       tegra30_apbif_write(reg, val);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo);
+
+int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
+{
+       int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+       int reg, val;
+
+       reg = TEGRA30_AHUB_CHANNEL_CTRL +
+             (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+       val = tegra30_apbif_read(reg);
+       val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
+       tegra30_apbif_write(reg, val);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo);
+
+int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
+{
+       int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+
+       __clear_bit(channel, ahub->rx_usage);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
+
+int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
+                                 unsigned long *fiforeg,
+                                 unsigned long *reqsel)
+{
+       int channel;
+       u32 reg, val;
+
+       channel = find_first_zero_bit(ahub->tx_usage,
+                                     TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
+       if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
+               return -EBUSY;
+
+       __set_bit(channel, ahub->tx_usage);
+
+       *txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel;
+       *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO +
+                  (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE);
+       *reqsel = ahub->dma_sel + channel;
+
+       reg = TEGRA30_AHUB_CHANNEL_CTRL +
+             (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+       val = tegra30_apbif_read(reg);
+       val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK |
+                TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK);
+       val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) |
+              TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN |
+              TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16;
+       tegra30_apbif_write(reg, val);
+
+       reg = TEGRA30_AHUB_CIF_TX_CTRL +
+             (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
+       val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+             (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+             (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+             TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
+             TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 |
+             TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
+       tegra30_apbif_write(reg, val);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo);
+
+int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif)
+{
+       int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
+       int reg, val;
+
+       reg = TEGRA30_AHUB_CHANNEL_CTRL +
+             (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+       val = tegra30_apbif_read(reg);
+       val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
+       tegra30_apbif_write(reg, val);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo);
+
+int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif)
+{
+       int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
+       int reg, val;
+
+       reg = TEGRA30_AHUB_CHANNEL_CTRL +
+             (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+       val = tegra30_apbif_read(reg);
+       val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
+       tegra30_apbif_write(reg, val);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo);
+
+int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif)
+{
+       int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
+
+       __clear_bit(channel, ahub->tx_usage);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_free_tx_fifo);
+
+int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
+                                  enum tegra30_ahub_txcif txcif)
+{
+       int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+       int reg;
+
+       reg = TEGRA30_AHUB_AUDIO_RX +
+             (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
+       tegra30_audio_write(reg, 1 << txcif);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source);
+
+int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
+{
+       int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+       int reg;
+
+       reg = TEGRA30_AHUB_AUDIO_RX +
+             (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
+       tegra30_audio_write(reg, 0);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
+
+static const char * const configlink_clocks[] __devinitconst = {
+       "i2s0",
+       "i2s1",
+       "i2s2",
+       "i2s3",
+       "i2s4",
+       "dam0",
+       "dam1",
+       "dam2",
+       "spdif_in",
+};
+
+struct of_dev_auxdata ahub_auxdata[] __devinitdata = {
+       OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080300, "tegra30-i2s.0", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080400, "tegra30-i2s.1", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080500, "tegra30-i2s.2", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080600, "tegra30-i2s.3", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080700, "tegra30-i2s.4", NULL),
+       {}
+};
+
+#define LAST_REG(name) \
+       (TEGRA30_AHUB_##name + \
+        (TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4)
+
+#define REG_IN_ARRAY(reg, name) \
+       ((reg >= TEGRA30_AHUB_##name) && \
+        (reg <= LAST_REG(name) && \
+        (!((reg - TEGRA30_AHUB_##name) % TEGRA30_AHUB_##name##_STRIDE))))
+
+static bool tegra30_ahub_apbif_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA30_AHUB_CONFIG_LINK_CTRL:
+       case TEGRA30_AHUB_MISC_CTRL:
+       case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
+       case TEGRA30_AHUB_I2S_LIVE_STATUS:
+       case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
+       case TEGRA30_AHUB_I2S_INT_MASK:
+       case TEGRA30_AHUB_DAM_INT_MASK:
+       case TEGRA30_AHUB_SPDIF_INT_MASK:
+       case TEGRA30_AHUB_APBIF_INT_MASK:
+       case TEGRA30_AHUB_I2S_INT_STATUS:
+       case TEGRA30_AHUB_DAM_INT_STATUS:
+       case TEGRA30_AHUB_SPDIF_INT_STATUS:
+       case TEGRA30_AHUB_APBIF_INT_STATUS:
+       case TEGRA30_AHUB_I2S_INT_SOURCE:
+       case TEGRA30_AHUB_DAM_INT_SOURCE:
+       case TEGRA30_AHUB_SPDIF_INT_SOURCE:
+       case TEGRA30_AHUB_APBIF_INT_SOURCE:
+       case TEGRA30_AHUB_I2S_INT_SET:
+       case TEGRA30_AHUB_DAM_INT_SET:
+       case TEGRA30_AHUB_SPDIF_INT_SET:
+       case TEGRA30_AHUB_APBIF_INT_SET:
+               return true;
+       default:
+               break;
+       };
+
+       if (REG_IN_ARRAY(reg, CHANNEL_CTRL) ||
+           REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
+           REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
+           REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
+           REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
+           REG_IN_ARRAY(reg, CIF_TX_CTRL) ||
+           REG_IN_ARRAY(reg, CIF_RX_CTRL) ||
+           REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
+               return true;
+
+       return false;
+}
+
+static bool tegra30_ahub_apbif_volatile_reg(struct device *dev,
+                                           unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA30_AHUB_CONFIG_LINK_CTRL:
+       case TEGRA30_AHUB_MISC_CTRL:
+       case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
+       case TEGRA30_AHUB_I2S_LIVE_STATUS:
+       case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
+       case TEGRA30_AHUB_I2S_INT_STATUS:
+       case TEGRA30_AHUB_DAM_INT_STATUS:
+       case TEGRA30_AHUB_SPDIF_INT_STATUS:
+       case TEGRA30_AHUB_APBIF_INT_STATUS:
+       case TEGRA30_AHUB_I2S_INT_SET:
+       case TEGRA30_AHUB_DAM_INT_SET:
+       case TEGRA30_AHUB_SPDIF_INT_SET:
+       case TEGRA30_AHUB_APBIF_INT_SET:
+               return true;
+       default:
+               break;
+       };
+
+       if (REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
+           REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
+           REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
+           REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
+           REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
+               return true;
+
+       return false;
+}
+
+static bool tegra30_ahub_apbif_precious_reg(struct device *dev,
+                                           unsigned int reg)
+{
+       if (REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
+           REG_IN_ARRAY(reg, CHANNEL_RXFIFO))
+               return true;
+
+       return false;
+}
+
+static const struct regmap_config tegra30_ahub_apbif_regmap_config = {
+       .name = "apbif",
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = TEGRA30_AHUB_APBIF_INT_SET,
+       .writeable_reg = tegra30_ahub_apbif_wr_rd_reg,
+       .readable_reg = tegra30_ahub_apbif_wr_rd_reg,
+       .volatile_reg = tegra30_ahub_apbif_volatile_reg,
+       .precious_reg = tegra30_ahub_apbif_precious_reg,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+       if (REG_IN_ARRAY(reg, AUDIO_RX))
+               return true;
+
+       return false;
+}
+
+static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
+       .name = "ahub",
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = LAST_REG(AUDIO_RX),
+       .writeable_reg = tegra30_ahub_ahub_wr_rd_reg,
+       .readable_reg = tegra30_ahub_ahub_wr_rd_reg,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit tegra30_ahub_probe(struct platform_device *pdev)
+{
+       struct clk *clk;
+       int i;
+       struct resource *res0, *res1, *region;
+       u32 of_dma[2];
+       void __iomem *regs_apbif, *regs_ahub;
+       int ret = 0;
+
+       if (ahub)
+               return -ENODEV;
+
+       /*
+        * The AHUB hosts a register bus: the "configlink". For this to
+        * operate correctly, all devices on this bus must be out of reset.
+        * Ensure that here.
+        */
+       for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) {
+               clk = clk_get_sys(NULL, configlink_clocks[i]);
+               if (IS_ERR(clk)) {
+                       dev_err(&pdev->dev, "Can't get clock %s\n",
+                               configlink_clocks[i]);
+                       ret = PTR_ERR(clk);
+                       goto err;
+               }
+               tegra_periph_reset_deassert(clk);
+               clk_put(clk);
+       }
+
+       ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
+                           GFP_KERNEL);
+       if (!ahub) {
+               dev_err(&pdev->dev, "Can't allocate tegra30_ahub\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+       dev_set_drvdata(&pdev->dev, ahub);
+
+       ahub->dev = &pdev->dev;
+
+       ahub->clk_d_audio = clk_get(&pdev->dev, "d_audio");
+       if (IS_ERR(ahub->clk_d_audio)) {
+               dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n");
+               ret = PTR_ERR(ahub->clk_d_audio);
+               goto err;
+       }
+
+       ahub->clk_apbif = clk_get(&pdev->dev, "apbif");
+       if (IS_ERR(ahub->clk_apbif)) {
+               dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n");
+               ret = PTR_ERR(ahub->clk_apbif);
+               goto err_clk_put_d_audio;
+       }
+
+       if (of_property_read_u32_array(pdev->dev.of_node,
+                               "nvidia,dma-request-selector",
+                               of_dma, 2) < 0) {
+               dev_err(&pdev->dev,
+                       "Missing property nvidia,dma-request-selector\n");
+               ret = -ENODEV;
+               goto err_clk_put_d_audio;
+       }
+       ahub->dma_sel = of_dma[1];
+
+       res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res0) {
+               dev_err(&pdev->dev, "No apbif memory resource\n");
+               ret = -ENODEV;
+               goto err_clk_put_apbif;
+       }
+
+       region = devm_request_mem_region(&pdev->dev, res0->start,
+                                        resource_size(res0), DRV_NAME);
+       if (!region) {
+               dev_err(&pdev->dev, "request region apbif failed\n");
+               ret = -EBUSY;
+               goto err_clk_put_apbif;
+       }
+       ahub->apbif_addr = res0->start;
+
+       regs_apbif = devm_ioremap(&pdev->dev, res0->start,
+                                 resource_size(res0));
+       if (!regs_apbif) {
+               dev_err(&pdev->dev, "ioremap apbif failed\n");
+               ret = -ENOMEM;
+               goto err_clk_put_apbif;
+       }
+
+       ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif,
+                                       &tegra30_ahub_apbif_regmap_config);
+       if (IS_ERR(ahub->regmap_apbif)) {
+               dev_err(&pdev->dev, "apbif regmap init failed\n");
+               ret = PTR_ERR(ahub->regmap_apbif);
+               goto err_clk_put_apbif;
+       }
+       regcache_cache_only(ahub->regmap_apbif, true);
+
+       res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res1) {
+               dev_err(&pdev->dev, "No ahub memory resource\n");
+               ret = -ENODEV;
+               goto err_clk_put_apbif;
+       }
+
+       region = devm_request_mem_region(&pdev->dev, res1->start,
+                                        resource_size(res1), DRV_NAME);
+       if (!region) {
+               dev_err(&pdev->dev, "request region ahub failed\n");
+               ret = -EBUSY;
+               goto err_clk_put_apbif;
+       }
+
+       regs_ahub = devm_ioremap(&pdev->dev, res1->start,
+                                resource_size(res1));
+       if (!regs_ahub) {
+               dev_err(&pdev->dev, "ioremap ahub failed\n");
+               ret = -ENOMEM;
+               goto err_clk_put_apbif;
+       }
+
+       ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub,
+                                       &tegra30_ahub_ahub_regmap_config);
+       if (IS_ERR(ahub->regmap_ahub)) {
+               dev_err(&pdev->dev, "ahub regmap init failed\n");
+               ret = PTR_ERR(ahub->regmap_ahub);
+               goto err_clk_put_apbif;
+       }
+       regcache_cache_only(ahub->regmap_ahub, true);
+
+       pm_runtime_enable(&pdev->dev);
+       if (!pm_runtime_enabled(&pdev->dev)) {
+               ret = tegra30_ahub_runtime_resume(&pdev->dev);
+               if (ret)
+                       goto err_pm_disable;
+       }
+
+       of_platform_populate(pdev->dev.of_node, NULL, ahub_auxdata,
+                            &pdev->dev);
+
+       return 0;
+
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
+err_clk_put_apbif:
+       clk_put(ahub->clk_apbif);
+err_clk_put_d_audio:
+       clk_put(ahub->clk_d_audio);
+       ahub = 0;
+err:
+       return ret;
+}
+
+static int __devexit tegra30_ahub_remove(struct platform_device *pdev)
+{
+       if (!ahub)
+               return -ENODEV;
+
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               tegra30_ahub_runtime_suspend(&pdev->dev);
+
+       clk_put(ahub->clk_apbif);
+       clk_put(ahub->clk_d_audio);
+
+       ahub = 0;
+
+       return 0;
+}
+
+static const struct of_device_id tegra30_ahub_of_match[] __devinitconst = {
+       { .compatible = "nvidia,tegra30-ahub", },
+       {},
+};
+
+static const struct dev_pm_ops tegra30_ahub_pm_ops __devinitconst = {
+       SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
+                          tegra30_ahub_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra30_ahub_driver = {
+       .probe = tegra30_ahub_probe,
+       .remove = __devexit_p(tegra30_ahub_remove),
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = tegra30_ahub_of_match,
+               .pm = &tegra30_ahub_pm_ops,
+       },
+};
+module_platform_driver(tegra30_ahub_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra30 AHUB driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
new file mode 100644 (file)
index 0000000..e690e2e
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * tegra30_ahub.h - Definitions for Tegra30 AHUB driver
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TEGRA30_AHUB_H__
+#define __TEGRA30_AHUB_H__
+
+/* Fields in *_CIF_RX/TX_CTRL; used by AHUB FIFOs, and all other audio modules */
+
+#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT     28
+#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US   0xf
+#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK      (TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT)
+
+/* Channel count minus 1 */
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT     24
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US   7
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK      (TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT)
+
+/* Channel count minus 1 */
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT    16
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US  7
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK     (TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT)
+
+#define TEGRA30_AUDIOCIF_BITS_4                                0
+#define TEGRA30_AUDIOCIF_BITS_8                                1
+#define TEGRA30_AUDIOCIF_BITS_12                       2
+#define TEGRA30_AUDIOCIF_BITS_16                       3
+#define TEGRA30_AUDIOCIF_BITS_20                       4
+#define TEGRA30_AUDIOCIF_BITS_24                       5
+#define TEGRA30_AUDIOCIF_BITS_28                       6
+#define TEGRA30_AUDIOCIF_BITS_32                       7
+
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT         12
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK          (7                        << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_4             (TEGRA30_AUDIOCIF_BITS_4  << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_8             (TEGRA30_AUDIOCIF_BITS_8  << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_12            (TEGRA30_AUDIOCIF_BITS_12 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16            (TEGRA30_AUDIOCIF_BITS_16 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_20            (TEGRA30_AUDIOCIF_BITS_20 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_24            (TEGRA30_AUDIOCIF_BITS_24 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_28            (TEGRA30_AUDIOCIF_BITS_28 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_32            (TEGRA30_AUDIOCIF_BITS_32 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT                8
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK         (7                        << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_4            (TEGRA30_AUDIOCIF_BITS_4  << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_8            (TEGRA30_AUDIOCIF_BITS_8  << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_12           (TEGRA30_AUDIOCIF_BITS_12 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16           (TEGRA30_AUDIOCIF_BITS_16 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_20           (TEGRA30_AUDIOCIF_BITS_20 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_24           (TEGRA30_AUDIOCIF_BITS_24 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_28           (TEGRA30_AUDIOCIF_BITS_28 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_32           (TEGRA30_AUDIOCIF_BITS_32 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+
+#define TEGRA30_AUDIOCIF_EXPAND_ZERO                   0
+#define TEGRA30_AUDIOCIF_EXPAND_ONE                    1
+#define TEGRA30_AUDIOCIF_EXPAND_LFSR                   2
+
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT             6
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_MASK              (3                            << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_ZERO              (TEGRA30_AUDIOCIF_EXPAND_ZERO << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_ONE               (TEGRA30_AUDIOCIF_EXPAND_ONE  << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_LFSR              (TEGRA30_AUDIOCIF_EXPAND_LFSR << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
+
+#define TEGRA30_AUDIOCIF_STEREO_CONV_CH0               0
+#define TEGRA30_AUDIOCIF_STEREO_CONV_CH1               1
+#define TEGRA30_AUDIOCIF_STEREO_CONV_AVG               2
+
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT                4
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_MASK         (3                                << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_CH0          (TEGRA30_AUDIOCIF_STEREO_CONV_CH0 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_CH1          (TEGRA30_AUDIOCIF_STEREO_CONV_CH1 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_AVG          (TEGRA30_AUDIOCIF_STEREO_CONV_AVG << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
+
+#define TEGRA30_AUDIOCIF_CTRL_REPLICATE                        3
+
+#define TEGRA30_AUDIOCIF_DIRECTION_TX                  0
+#define TEGRA30_AUDIOCIF_DIRECTION_RX                  1
+
+#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT          2
+#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_MASK           (1                             << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX             (TEGRA30_AUDIOCIF_DIRECTION_TX << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX             (TEGRA30_AUDIOCIF_DIRECTION_RX << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT)
+
+#define TEGRA30_AUDIOCIF_TRUNCATE_ROUND                        0
+#define TEGRA30_AUDIOCIF_TRUNCATE_CHOP                 1
+
+#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT           1
+#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_MASK            (1                               << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_ROUND           (TEGRA30_AUDIOCIF_TRUNCATE_ROUND << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_CHOP            (TEGRA30_AUDIOCIF_TRUNCATE_CHOP  << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT)
+
+#define TEGRA30_AUDIOCIF_MONO_CONV_ZERO                        0
+#define TEGRA30_AUDIOCIF_MONO_CONV_COPY                        1
+
+#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT          0
+#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_MASK           (1                               << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_ZERO           (TEGRA30_AUDIOCIF_MONO_CONV_ZERO << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_COPY           (TEGRA30_AUDIOCIF_MONO_CONV_COPY << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT)
+
+/* Registers within TEGRA30_AUDIO_CLUSTER_BASE */
+
+/* TEGRA30_AHUB_CHANNEL_CTRL */
+
+#define TEGRA30_AHUB_CHANNEL_CTRL                      0x0
+#define TEGRA30_AHUB_CHANNEL_CTRL_STRIDE               0x20
+#define TEGRA30_AHUB_CHANNEL_CTRL_COUNT                        4
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_EN                        (1 << 31)
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_EN                        (1 << 30)
+#define TEGRA30_AHUB_CHANNEL_CTRL_LOOPBACK             (1 << 29)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT   16
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK_US 0xff
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK    (TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT   8
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK_US 0xff
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK    (TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN           (1 << 6)
+
+#define TEGRA30_PACK_8_4                               2
+#define TEGRA30_PACK_16                                        3
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT                4
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK_US      3
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK         (TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_8_4          (TEGRA30_PACK_8_4                          << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16           (TEGRA30_PACK_16                           << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN           (1 << 2)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT                0
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK_US      3
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK         (TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_8_4          (TEGRA30_PACK_8_4                          << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16           (TEGRA30_PACK_16                           << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT)
+
+/* TEGRA30_AHUB_CHANNEL_CLEAR */
+
+#define TEGRA30_AHUB_CHANNEL_CLEAR                     0x4
+#define TEGRA30_AHUB_CHANNEL_CLEAR_STRIDE              0x20
+#define TEGRA30_AHUB_CHANNEL_CLEAR_COUNT               4
+#define TEGRA30_AHUB_CHANNEL_CLEAR_TX_SOFT_RESET       (1 << 31)
+#define TEGRA30_AHUB_CHANNEL_CLEAR_RX_SOFT_RESET       (1 << 30)
+
+/* TEGRA30_AHUB_CHANNEL_STATUS */
+
+#define TEGRA30_AHUB_CHANNEL_STATUS                    0x8
+#define TEGRA30_AHUB_CHANNEL_STATUS_STRIDE             0x20
+#define TEGRA30_AHUB_CHANNEL_STATUS_COUNT              4
+#define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_SHIFT      24
+#define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK_US    0xff
+#define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK       (TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK_US << TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_SHIFT      16
+#define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK_US    0xff
+#define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK       (TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK_US << TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_STATUS_TX_TRIG            (1 << 1)
+#define TEGRA30_AHUB_CHANNEL_STATUS_RX_TRIG            (1 << 0)
+
+/* TEGRA30_AHUB_CHANNEL_TXFIFO */
+
+#define TEGRA30_AHUB_CHANNEL_TXFIFO                    0xc
+#define TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE             0x20
+#define TEGRA30_AHUB_CHANNEL_TXFIFO_COUNT              4
+
+/* TEGRA30_AHUB_CHANNEL_RXFIFO */
+
+#define TEGRA30_AHUB_CHANNEL_RXFIFO                    0x10
+#define TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE             0x20
+#define TEGRA30_AHUB_CHANNEL_RXFIFO_COUNT              4
+
+/* TEGRA30_AHUB_CIF_TX_CTRL */
+
+#define TEGRA30_AHUB_CIF_TX_CTRL                       0x14
+#define TEGRA30_AHUB_CIF_TX_CTRL_STRIDE                        0x20
+#define TEGRA30_AHUB_CIF_TX_CTRL_COUNT                 4
+/* Uses field from TEGRA30_AUDIOCIF_CTRL_* */
+
+/* TEGRA30_AHUB_CIF_RX_CTRL */
+
+#define TEGRA30_AHUB_CIF_RX_CTRL                       0x18
+#define TEGRA30_AHUB_CIF_RX_CTRL_STRIDE                        0x20
+#define TEGRA30_AHUB_CIF_RX_CTRL_COUNT                 4
+/* Uses field from TEGRA30_AUDIOCIF_CTRL_* */
+
+/* TEGRA30_AHUB_CONFIG_LINK_CTRL */
+
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL                                  0x80
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_SHIFT       28
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK_US     0xf
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK                (TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_SHIFT)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_SHIFT                        16
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK_US              0xfff
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK                 (TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_SHIFT)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT                   4
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK_US                 0xfff
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK                    (TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_CG_EN                            (1 << 2)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_CLEAR_TIMEOUT_CNTR               (1 << 1)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_SOFT_RESET                       (1 << 0)
+
+/* TEGRA30_AHUB_MISC_CTRL */
+
+#define TEGRA30_AHUB_MISC_CTRL                         0x84
+#define TEGRA30_AHUB_MISC_CTRL_AUDIO_ACTIVE            (1 << 31)
+#define TEGRA30_AHUB_MISC_CTRL_AUDIO_CG_EN             (1 << 8)
+#define TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_SHIFT     0
+#define TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_MASK      (0x1f << TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_SHIFT)
+
+/* TEGRA30_AHUB_APBDMA_LIVE_STATUS */
+
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS                                0x88
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_CIF_FIFO_FULL   (1 << 31)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_CIF_FIFO_FULL   (1 << 30)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_CIF_FIFO_FULL   (1 << 29)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_CIF_FIFO_FULL   (1 << 28)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_CIF_FIFO_FULL   (1 << 27)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_CIF_FIFO_FULL   (1 << 26)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_CIF_FIFO_FULL   (1 << 25)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_CIF_FIFO_FULL   (1 << 24)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_CIF_FIFO_EMPTY  (1 << 23)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_CIF_FIFO_EMPTY  (1 << 22)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_CIF_FIFO_EMPTY  (1 << 21)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_CIF_FIFO_EMPTY  (1 << 20)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_CIF_FIFO_EMPTY  (1 << 19)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_CIF_FIFO_EMPTY  (1 << 18)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_CIF_FIFO_EMPTY  (1 << 17)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_CIF_FIFO_EMPTY  (1 << 16)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_DMA_FIFO_FULL   (1 << 15)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_DMA_FIFO_FULL   (1 << 14)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_DMA_FIFO_FULL   (1 << 13)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_DMA_FIFO_FULL   (1 << 12)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_DMA_FIFO_FULL   (1 << 11)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_DMA_FIFO_FULL   (1 << 10)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_DMA_FIFO_FULL   (1 << 9)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_DMA_FIFO_FULL   (1 << 8)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_DMA_FIFO_EMPTY  (1 << 7)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_DMA_FIFO_EMPTY  (1 << 6)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_DMA_FIFO_EMPTY  (1 << 5)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_DMA_FIFO_EMPTY  (1 << 4)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_DMA_FIFO_EMPTY  (1 << 3)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_DMA_FIFO_EMPTY  (1 << 2)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_DMA_FIFO_EMPTY  (1 << 1)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_DMA_FIFO_EMPTY  (1 << 0)
+
+/* TEGRA30_AHUB_I2S_LIVE_STATUS */
+
+#define TEGRA30_AHUB_I2S_LIVE_STATUS                           0x8c
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_FULL         (1 << 29)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_FULL         (1 << 28)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_FULL         (1 << 27)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_FULL         (1 << 26)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_FULL         (1 << 25)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_FULL         (1 << 24)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_FULL         (1 << 23)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_FULL         (1 << 22)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_FULL         (1 << 21)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_FULL         (1 << 20)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_ENABLED      (1 << 19)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_ENABLED      (1 << 18)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_ENABLED      (1 << 17)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_ENABLED      (1 << 16)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_ENABLED      (1 << 15)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_ENABLED      (1 << 14)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_ENABLED      (1 << 13)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_ENABLED      (1 << 12)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_ENABLED      (1 << 11)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_ENABLED      (1 << 10)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_EMPTY                (1 << 9)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_EMPTY                (1 << 8)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_EMPTY                (1 << 7)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_EMPTY                (1 << 6)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_EMPTY                (1 << 5)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_EMPTY                (1 << 4)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_EMPTY                (1 << 3)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_EMPTY                (1 << 2)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_EMPTY                (1 << 1)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_EMPTY                (1 << 0)
+
+/* TEGRA30_AHUB_DAM0_LIVE_STATUS */
+
+#define TEGRA30_AHUB_DAM_LIVE_STATUS                           0x90
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_STRIDE                    0x8
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_COUNT                     3
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_TX_ENABLED                        (1 << 26)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1_ENABLED               (1 << 25)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0_ENABLED               (1 << 24)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_TXFIFO_FULL               (1 << 15)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1FIFO_FULL              (1 << 9)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0FIFO_FULL              (1 << 8)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_TXFIFO_EMPTY              (1 << 7)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1FIFO_EMPTY             (1 << 1)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0FIFO_EMPTY             (1 << 0)
+
+/* TEGRA30_AHUB_SPDIF_LIVE_STATUS */
+
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS                         0xa8
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TX_ENABLED         (1 << 11)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RX_ENABLED         (1 << 10)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TX_ENABLED         (1 << 9)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RX_ENABLED         (1 << 8)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TXFIFO_FULL                (1 << 7)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RXFIFO_FULL                (1 << 6)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TXFIFO_FULL                (1 << 5)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RXFIFO_FULL                (1 << 4)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TXFIFO_EMPTY       (1 << 3)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RXFIFO_EMPTY       (1 << 2)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TXFIFO_EMPTY       (1 << 1)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RXFIFO_EMPTY       (1 << 0)
+
+/* TEGRA30_AHUB_I2S_INT_MASK */
+
+#define TEGRA30_AHUB_I2S_INT_MASK                              0xb0
+
+/* TEGRA30_AHUB_DAM_INT_MASK */
+
+#define TEGRA30_AHUB_DAM_INT_MASK                              0xb4
+
+/* TEGRA30_AHUB_SPDIF_INT_MASK */
+
+#define TEGRA30_AHUB_SPDIF_INT_MASK                            0xbc
+
+/* TEGRA30_AHUB_APBIF_INT_MASK */
+
+#define TEGRA30_AHUB_APBIF_INT_MASK                            0xc0
+
+/* TEGRA30_AHUB_I2S_INT_STATUS */
+
+#define TEGRA30_AHUB_I2S_INT_STATUS                            0xc8
+
+/* TEGRA30_AHUB_DAM_INT_STATUS */
+
+#define TEGRA30_AHUB_DAM_INT_STATUS                            0xcc
+
+/* TEGRA30_AHUB_SPDIF_INT_STATUS */
+
+#define TEGRA30_AHUB_SPDIF_INT_STATUS                          0xd4
+
+/* TEGRA30_AHUB_APBIF_INT_STATUS */
+
+#define TEGRA30_AHUB_APBIF_INT_STATUS                          0xd8
+
+/* TEGRA30_AHUB_I2S_INT_SOURCE */
+
+#define TEGRA30_AHUB_I2S_INT_SOURCE                            0xe0
+
+/* TEGRA30_AHUB_DAM_INT_SOURCE */
+
+#define TEGRA30_AHUB_DAM_INT_SOURCE                            0xe4
+
+/* TEGRA30_AHUB_SPDIF_INT_SOURCE */
+
+#define TEGRA30_AHUB_SPDIF_INT_SOURCE                          0xec
+
+/* TEGRA30_AHUB_APBIF_INT_SOURCE */
+
+#define TEGRA30_AHUB_APBIF_INT_SOURCE                          0xf0
+
+/* TEGRA30_AHUB_I2S_INT_SET */
+
+#define TEGRA30_AHUB_I2S_INT_SET                               0xf8
+
+/* TEGRA30_AHUB_DAM_INT_SET */
+
+#define TEGRA30_AHUB_DAM_INT_SET                               0xfc
+
+/* TEGRA30_AHUB_SPDIF_INT_SET */
+
+#define TEGRA30_AHUB_SPDIF_INT_SET                             0x100
+
+/* TEGRA30_AHUB_APBIF_INT_SET */
+
+#define TEGRA30_AHUB_APBIF_INT_SET                             0x104
+
+/* Registers within TEGRA30_AHUB_BASE */
+
+#define TEGRA30_AHUB_AUDIO_RX                                  0x0
+#define TEGRA30_AHUB_AUDIO_RX_STRIDE                           0x4
+#define TEGRA30_AHUB_AUDIO_RX_COUNT                            17
+/* This register repeats once for each entry in enum tegra30_ahub_rxcif */
+/* The fields in this register are 1 bit per entry in tegra30_ahub_txcif */
+
+/*
+ * Terminology:
+ * AHUB: Audio Hub; a cross-bar switch between the audio devices: DMA FIFOs,
+ *       I2S controllers, SPDIF controllers, and DAMs.
+ * XBAR: The core cross-bar component of the AHUB.
+ * CIF:  Client Interface; the HW module connecting an audio device to the
+ *       XBAR.
+ * DAM:  Digital Audio Mixer: A HW module that mixes multiple audio streams,
+ *       possibly including sample-rate conversion.
+ *
+ * Each TX CIF transmits data into the XBAR. Each RX CIF can receive audio
+ * transmitted by a particular TX CIF.
+ *
+ * This driver is currently very simplistic; many HW features are not
+ * exposed; DAMs are not supported, only 16-bit stereo audio is supported,
+ * etc.
+ */
+
+enum tegra30_ahub_txcif {
+       TEGRA30_AHUB_TXCIF_APBIF_TX0,
+       TEGRA30_AHUB_TXCIF_APBIF_TX1,
+       TEGRA30_AHUB_TXCIF_APBIF_TX2,
+       TEGRA30_AHUB_TXCIF_APBIF_TX3,
+       TEGRA30_AHUB_TXCIF_I2S0_TX0,
+       TEGRA30_AHUB_TXCIF_I2S1_TX0,
+       TEGRA30_AHUB_TXCIF_I2S2_TX0,
+       TEGRA30_AHUB_TXCIF_I2S3_TX0,
+       TEGRA30_AHUB_TXCIF_I2S4_TX0,
+       TEGRA30_AHUB_TXCIF_DAM0_TX0,
+       TEGRA30_AHUB_TXCIF_DAM1_TX0,
+       TEGRA30_AHUB_TXCIF_DAM2_TX0,
+       TEGRA30_AHUB_TXCIF_SPDIF_TX0,
+       TEGRA30_AHUB_TXCIF_SPDIF_TX1,
+};
+
+enum tegra30_ahub_rxcif {
+       TEGRA30_AHUB_RXCIF_APBIF_RX0,
+       TEGRA30_AHUB_RXCIF_APBIF_RX1,
+       TEGRA30_AHUB_RXcIF_APBIF_RX2,
+       TEGRA30_AHUB_RXCIF_APBIF_RX3,
+       TEGRA30_AHUB_RXCIF_I2S0_RX0,
+       TEGRA30_AHUB_RXCIF_I2S1_RX0,
+       TEGRA30_AHUB_RXCIF_I2S2_RX0,
+       TEGRA30_AHUB_RXCIF_I2S3_RX0,
+       TEGRA30_AHUB_RXCIF_I2S4_RX0,
+       TEGRA30_AHUB_RXCIF_DAM0_RX0,
+       TEGRA30_AHUB_RXCIF_DAM0_RX1,
+       TEGRA30_AHUB_RXCIF_DAM1_RX0,
+       TEGRA30_AHUB_RXCIF_DAM2_RX1,
+       TEGRA30_AHUB_RXCIF_DAM3_RX0,
+       TEGRA30_AHUB_RXCIF_DAM3_RX1,
+       TEGRA30_AHUB_RXCIF_SPDIF_RX0,
+       TEGRA30_AHUB_RXCIF_SPDIF_RX1,
+};
+
+extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
+                                        unsigned long *fiforeg,
+                                        unsigned long *reqsel);
+extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
+extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
+extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif);
+
+extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
+                                        unsigned long *fiforeg,
+                                        unsigned long *reqsel);
+extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif);
+extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif);
+extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif);
+
+extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
+                                         enum tegra30_ahub_txcif txcif);
+extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif);
+
+struct tegra30_ahub {
+       struct device *dev;
+       struct clk *clk_d_audio;
+       struct clk *clk_apbif;
+       int dma_sel;
+       resource_size_t apbif_addr;
+       struct regmap *regmap_apbif;
+       struct regmap *regmap_ahub;
+       DECLARE_BITMAP(rx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
+       DECLARE_BITMAP(tx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
new file mode 100644 (file)
index 0000000..8596032
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * tegra30_i2s.c - Tegra30 I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.com>
+ *
+ * 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/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra30_ahub.h"
+#include "tegra30_i2s.h"
+
+#define DRV_NAME "tegra30-i2s"
+
+static inline void tegra30_i2s_write(struct tegra30_i2s *i2s, u32 reg, u32 val)
+{
+       regmap_write(i2s->regmap, reg, val);
+}
+
+static inline u32 tegra30_i2s_read(struct tegra30_i2s *i2s, u32 reg)
+{
+       u32 val;
+       regmap_read(i2s->regmap, reg, &val);
+       return val;
+}
+
+static int tegra30_i2s_runtime_suspend(struct device *dev)
+{
+       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+
+       regcache_cache_only(i2s->regmap, true);
+
+       clk_disable(i2s->clk_i2s);
+
+       return 0;
+}
+
+static int tegra30_i2s_runtime_resume(struct device *dev)
+{
+       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_enable(i2s->clk_i2s);
+       if (ret) {
+               dev_err(dev, "clk_enable failed: %d\n", ret);
+               return ret;
+       }
+
+       regcache_cache_only(i2s->regmap, false);
+
+       return 0;
+}
+
+int tegra30_i2s_startup(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *dai)
+{
+       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+       int ret;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif,
+                                       &i2s->playback_dma_data.addr,
+                                       &i2s->playback_dma_data.req_sel);
+               i2s->playback_dma_data.wrap = 4;
+               i2s->playback_dma_data.width = 32;
+               tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif,
+                                              i2s->playback_fifo_cif);
+       } else {
+               ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif,
+                                       &i2s->capture_dma_data.addr,
+                                       &i2s->capture_dma_data.req_sel);
+               i2s->capture_dma_data.wrap = 4;
+               i2s->capture_dma_data.width = 32;
+               tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif,
+                                              i2s->capture_i2s_cif);
+       }
+
+       return ret;
+}
+
+void tegra30_i2s_shutdown(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *dai)
+{
+       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif);
+               tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif);
+       } else {
+               tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif);
+               tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif);
+       }
+}
+
+static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
+                               unsigned int fmt)
+{
+       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_MASTER_ENABLE;
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       i2s->reg_ctrl &= ~(TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK |
+                          TEGRA30_I2S_CTRL_LRCK_MASK);
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
+               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
+               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct device *dev = substream->pcm->card->dev;
+       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+       u32 val;
+       int ret, sample_size, srate, i2sclock, bitcnt;
+
+       if (params_channels(params) != 2)
+               return -EINVAL;
+
+       i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16;
+               sample_size = 16;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       srate = params_rate(params);
+
+       /* Final "* 2" required by Tegra hardware */
+       i2sclock = srate * params_channels(params) * sample_size * 2;
+
+       bitcnt = (i2sclock / (2 * srate)) - 1;
+       if (bitcnt < 0 || bitcnt > TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
+               return -EINVAL;
+
+       ret = clk_set_rate(i2s->clk_i2s, i2sclock);
+       if (ret) {
+               dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
+               return ret;
+       }
+
+       val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
+
+       if (i2sclock % (2 * srate))
+               val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE;
+
+       tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val);
+
+       val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+             (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+             (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+             TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
+             TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
+               tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val);
+       } else {
+               val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
+               tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val);
+       }
+
+       val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) |
+             (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT);
+       tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val);
+
+       return 0;
+}
+
+static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s)
+{
+       tegra30_ahub_enable_tx_fifo(i2s->playback_fifo_cif);
+       i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX;
+       tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s)
+{
+       tegra30_ahub_disable_tx_fifo(i2s->playback_fifo_cif);
+       i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX;
+       tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s)
+{
+       tegra30_ahub_enable_rx_fifo(i2s->capture_fifo_cif);
+       i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX;
+       tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s)
+{
+       tegra30_ahub_disable_rx_fifo(i2s->capture_fifo_cif);
+       i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX;
+       tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       tegra30_i2s_start_playback(i2s);
+               else
+                       tegra30_i2s_start_capture(i2s);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       tegra30_i2s_stop_playback(i2s);
+               else
+                       tegra30_i2s_stop_capture(i2s);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int tegra30_i2s_probe(struct snd_soc_dai *dai)
+{
+       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       dai->capture_dma_data = &i2s->capture_dma_data;
+       dai->playback_dma_data = &i2s->playback_dma_data;
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
+       .startup        = tegra30_i2s_startup,
+       .shutdown       = tegra30_i2s_shutdown,
+       .set_fmt        = tegra30_i2s_set_fmt,
+       .hw_params      = tegra30_i2s_hw_params,
+       .trigger        = tegra30_i2s_trigger,
+};
+
+static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
+       .probe = tegra30_i2s_probe,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &tegra30_i2s_dai_ops,
+       .symmetric_rates = 1,
+};
+
+static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA30_I2S_CTRL:
+       case TEGRA30_I2S_TIMING:
+       case TEGRA30_I2S_OFFSET:
+       case TEGRA30_I2S_CH_CTRL:
+       case TEGRA30_I2S_SLOT_CTRL:
+       case TEGRA30_I2S_CIF_RX_CTRL:
+       case TEGRA30_I2S_CIF_TX_CTRL:
+       case TEGRA30_I2S_FLOWCTL:
+       case TEGRA30_I2S_TX_STEP:
+       case TEGRA30_I2S_FLOW_STATUS:
+       case TEGRA30_I2S_FLOW_TOTAL:
+       case TEGRA30_I2S_FLOW_OVER:
+       case TEGRA30_I2S_FLOW_UNDER:
+       case TEGRA30_I2S_LCOEF_1_4_0:
+       case TEGRA30_I2S_LCOEF_1_4_1:
+       case TEGRA30_I2S_LCOEF_1_4_2:
+       case TEGRA30_I2S_LCOEF_1_4_3:
+       case TEGRA30_I2S_LCOEF_1_4_4:
+       case TEGRA30_I2S_LCOEF_1_4_5:
+       case TEGRA30_I2S_LCOEF_2_4_0:
+       case TEGRA30_I2S_LCOEF_2_4_1:
+       case TEGRA30_I2S_LCOEF_2_4_2:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static bool tegra30_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA30_I2S_FLOW_STATUS:
+       case TEGRA30_I2S_FLOW_TOTAL:
+       case TEGRA30_I2S_FLOW_OVER:
+       case TEGRA30_I2S_FLOW_UNDER:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static const struct regmap_config tegra30_i2s_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = TEGRA30_I2S_LCOEF_2_4_2,
+       .writeable_reg = tegra30_i2s_wr_rd_reg,
+       .readable_reg = tegra30_i2s_wr_rd_reg,
+       .volatile_reg = tegra30_i2s_volatile_reg,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int tegra30_i2s_platform_probe(struct platform_device *pdev)
+{
+       struct tegra30_i2s *i2s;
+       u32 cif_ids[2];
+       struct resource *mem, *memregion;
+       void __iomem *regs;
+       int ret;
+
+       i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_i2s), GFP_KERNEL);
+       if (!i2s) {
+               dev_err(&pdev->dev, "Can't allocate tegra30_i2s\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+       dev_set_drvdata(&pdev->dev, i2s);
+
+       i2s->dai = tegra30_i2s_dai_template;
+       i2s->dai.name = dev_name(&pdev->dev);
+
+       ret = of_property_read_u32_array(pdev->dev.of_node,
+                                        "nvidia,ahub-cif-ids", cif_ids,
+                                        ARRAY_SIZE(cif_ids));
+       if (ret < 0)
+               goto err;
+
+       i2s->playback_i2s_cif = cif_ids[0];
+       i2s->capture_i2s_cif = cif_ids[1];
+
+       i2s->clk_i2s = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(i2s->clk_i2s)) {
+               dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
+               ret = PTR_ERR(i2s->clk_i2s);
+               goto err;
+       }
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "No memory resource\n");
+               ret = -ENODEV;
+               goto err_clk_put;
+       }
+
+       memregion = devm_request_mem_region(&pdev->dev, mem->start,
+                                           resource_size(mem), DRV_NAME);
+       if (!memregion) {
+               dev_err(&pdev->dev, "Memory region already claimed\n");
+               ret = -EBUSY;
+               goto err_clk_put;
+       }
+
+       regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+       if (!regs) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -ENOMEM;
+               goto err_clk_put;
+       }
+
+       i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+                                           &tegra30_i2s_regmap_config);
+       if (IS_ERR(i2s->regmap)) {
+               dev_err(&pdev->dev, "regmap init failed\n");
+               ret = PTR_ERR(i2s->regmap);
+               goto err_clk_put;
+       }
+       regcache_cache_only(i2s->regmap, true);
+
+       pm_runtime_enable(&pdev->dev);
+       if (!pm_runtime_enabled(&pdev->dev)) {
+               ret = tegra30_i2s_runtime_resume(&pdev->dev);
+               if (ret)
+                       goto err_pm_disable;
+       }
+
+       ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+               ret = -ENOMEM;
+               goto err_suspend;
+       }
+
+       ret = tegra_pcm_platform_register(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+               goto err_unregister_dai;
+       }
+
+       return 0;
+
+err_unregister_dai:
+       snd_soc_unregister_dai(&pdev->dev);
+err_suspend:
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               tegra30_i2s_runtime_suspend(&pdev->dev);
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
+err_clk_put:
+       clk_put(i2s->clk_i2s);
+err:
+       return ret;
+}
+
+static int __devexit tegra30_i2s_platform_remove(struct platform_device *pdev)
+{
+       struct tegra30_i2s *i2s = dev_get_drvdata(&pdev->dev);
+
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               tegra30_i2s_runtime_suspend(&pdev->dev);
+
+       tegra_pcm_platform_unregister(&pdev->dev);
+       snd_soc_unregister_dai(&pdev->dev);
+
+       clk_put(i2s->clk_i2s);
+
+       return 0;
+}
+
+static const struct of_device_id tegra30_i2s_of_match[] __devinitconst = {
+       { .compatible = "nvidia,tegra30-i2s", },
+       {},
+};
+
+static const struct dev_pm_ops tegra30_i2s_pm_ops __devinitconst = {
+       SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend,
+                          tegra30_i2s_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra30_i2s_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = tegra30_i2s_of_match,
+               .pm = &tegra30_i2s_pm_ops,
+       },
+       .probe = tegra30_i2s_platform_probe,
+       .remove = __devexit_p(tegra30_i2s_platform_remove),
+};
+module_platform_driver(tegra30_i2s_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra30 I2S ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra30_i2s_of_match);
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h
new file mode 100644 (file)
index 0000000..91adf29
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * tegra30_i2s.h - Definitions for Tegra30 I2S driver
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TEGRA30_I2S_H__
+#define __TEGRA30_I2S_H__
+
+#include "tegra_pcm.h"
+
+/* Register offsets from TEGRA30_I2S*_BASE */
+
+#define TEGRA30_I2S_CTRL                               0x0
+#define TEGRA30_I2S_TIMING                             0x4
+#define TEGRA30_I2S_OFFSET                             0x08
+#define TEGRA30_I2S_CH_CTRL                            0x0c
+#define TEGRA30_I2S_SLOT_CTRL                          0x10
+#define TEGRA30_I2S_CIF_RX_CTRL                                0x14
+#define TEGRA30_I2S_CIF_TX_CTRL                                0x18
+#define TEGRA30_I2S_FLOWCTL                            0x1c
+#define TEGRA30_I2S_TX_STEP                            0x20
+#define TEGRA30_I2S_FLOW_STATUS                                0x24
+#define TEGRA30_I2S_FLOW_TOTAL                         0x28
+#define TEGRA30_I2S_FLOW_OVER                          0x2c
+#define TEGRA30_I2S_FLOW_UNDER                         0x30
+#define TEGRA30_I2S_LCOEF_1_4_0                                0x34
+#define TEGRA30_I2S_LCOEF_1_4_1                                0x38
+#define TEGRA30_I2S_LCOEF_1_4_2                                0x3c
+#define TEGRA30_I2S_LCOEF_1_4_3                                0x40
+#define TEGRA30_I2S_LCOEF_1_4_4                                0x44
+#define TEGRA30_I2S_LCOEF_1_4_5                                0x48
+#define TEGRA30_I2S_LCOEF_2_4_0                                0x4c
+#define TEGRA30_I2S_LCOEF_2_4_1                                0x50
+#define TEGRA30_I2S_LCOEF_2_4_2                                0x54
+
+/* Fields in TEGRA30_I2S_CTRL */
+
+#define TEGRA30_I2S_CTRL_XFER_EN_TX                    (1 << 31)
+#define TEGRA30_I2S_CTRL_XFER_EN_RX                    (1 << 30)
+#define TEGRA30_I2S_CTRL_CG_EN                         (1 << 29)
+#define TEGRA30_I2S_CTRL_SOFT_RESET                    (1 << 28)
+#define TEGRA30_I2S_CTRL_TX_FLOWCTL_EN                 (1 << 27)
+
+#define TEGRA30_I2S_CTRL_OBS_SEL_SHIFT                 24
+#define TEGRA30_I2S_CTRL_OBS_SEL_MASK                  (7 << TEGRA30_I2S_CTRL_OBS_SEL_SHIFT)
+
+#define TEGRA30_I2S_FRAME_FORMAT_LRCK                  0
+#define TEGRA30_I2S_FRAME_FORMAT_FSYNC                 1
+
+#define TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT            12
+#define TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK             (7                              << TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT)
+#define TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK             (TEGRA30_I2S_FRAME_FORMAT_LRCK  << TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT)
+#define TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC            (TEGRA30_I2S_FRAME_FORMAT_FSYNC << TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT)
+
+#define TEGRA30_I2S_CTRL_MASTER_ENABLE                 (1 << 10)
+
+#define TEGRA30_I2S_LRCK_LEFT_LOW                      0
+#define TEGRA30_I2S_LRCK_RIGHT_LOW                     1
+
+#define TEGRA30_I2S_CTRL_LRCK_SHIFT                    9
+#define TEGRA30_I2S_CTRL_LRCK_MASK                     (1                          << TEGRA30_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA30_I2S_CTRL_LRCK_L_LOW                    (TEGRA30_I2S_LRCK_LEFT_LOW  << TEGRA30_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA30_I2S_CTRL_LRCK_R_LOW                    (TEGRA30_I2S_LRCK_RIGHT_LOW << TEGRA30_I2S_CTRL_LRCK_SHIFT)
+
+#define TEGRA30_I2S_CTRL_LPBK_ENABLE                   (1 << 8)
+
+#define TEGRA30_I2S_BIT_CODE_LINEAR                    0
+#define TEGRA30_I2S_BIT_CODE_ULAW                      1
+#define TEGRA30_I2S_BIT_CODE_ALAW                      2
+
+#define TEGRA30_I2S_CTRL_BIT_CODE_SHIFT                        4
+#define TEGRA30_I2S_CTRL_BIT_CODE_MASK                 (3                           << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_CODE_LINEAR               (TEGRA30_I2S_BIT_CODE_LINEAR << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_CODE_ULAW                 (TEGRA30_I2S_BIT_CODE_ULAW   << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_CODE_ALAW                 (TEGRA30_I2S_BIT_CODE_ALAW   << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT)
+
+#define TEGRA30_I2S_BITS_8                             1
+#define TEGRA30_I2S_BITS_12                            2
+#define TEGRA30_I2S_BITS_16                            3
+#define TEGRA30_I2S_BITS_20                            4
+#define TEGRA30_I2S_BITS_24                            5
+#define TEGRA30_I2S_BITS_28                            6
+#define TEGRA30_I2S_BITS_32                            7
+
+/* Sample container size; see {RX,TX}_MASK field in CH_CTRL below */
+#define TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT                        0
+#define TEGRA30_I2S_CTRL_BIT_SIZE_MASK                 (7                   << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_8                    (TEGRA30_I2S_BITS_8  << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_12                   (TEGRA30_I2S_BITS_12 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_16                   (TEGRA30_I2S_BITS_16 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_20                   (TEGRA30_I2S_BITS_20 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_24                   (TEGRA30_I2S_BITS_24 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_28                   (TEGRA30_I2S_BITS_28 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_32                   (TEGRA30_I2S_BITS_32 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+
+/* Fields in TEGRA30_I2S_TIMING */
+
+#define TEGRA30_I2S_TIMING_NON_SYM_ENABLE              (1 << 12)
+#define TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT     0
+#define TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US   0x7fff
+#define TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK      (TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT)
+
+/* Fields in TEGRA30_I2S_OFFSET */
+
+#define TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT                16
+#define TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK_US      0x7ff
+#define TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK         (TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK_US << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT)
+#define TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT                0
+#define TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK_US      0x7ff
+#define TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK         (TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK_US << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT)
+
+/* Fields in TEGRA30_I2S_CH_CTRL */
+
+/* (FSYNC width - 1) in bit clocks */
+#define TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT          24
+#define TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK_US                0xff
+#define TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK           (TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK_US << TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT)
+
+#define TEGRA30_I2S_HIGHZ_NO                           0
+#define TEGRA30_I2S_HIGHZ_YES                          1
+#define TEGRA30_I2S_HIGHZ_ON_HALF_BIT_CLK              2
+
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT           12
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_MASK            (3                                 << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_NO              (TEGRA30_I2S_HIGHZ_NO              << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_YES             (TEGRA30_I2S_HIGHZ_YES             << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_ON_HALF_BIT_CLK (TEGRA30_I2S_HIGHZ_ON_HALF_BIT_CLK << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT)
+
+#define TEGRA30_I2S_MSB_FIRST                          0
+#define TEGRA30_I2S_LSB_FIRST                          1
+
+#define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT         10
+#define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_MASK          (1                     << TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_MSB_FIRST     (TEGRA30_I2S_MSB_FIRST << TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_LSB_FIRST     (TEGRA30_I2S_LSB_FIRST << TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT         9
+#define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_MASK          (1                     << TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_MSB_FIRST     (TEGRA30_I2S_MSB_FIRST << TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_LSB_FIRST     (TEGRA30_I2S_LSB_FIRST << TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT)
+
+#define TEGRA30_I2S_POS_EDGE                           0
+#define TEGRA30_I2S_NEG_EDGE                           1
+
+#define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT            8
+#define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_MASK             (1                    << TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE         (TEGRA30_I2S_POS_EDGE << TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_NEG_EDGE         (TEGRA30_I2S_NEG_EDGE << TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT)
+
+/* Sample size is # bits from BIT_SIZE minus this field */
+#define TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_SHIFT         4
+#define TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_MASK_US       7
+#define TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_MASK          (TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_MASK_US << TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_SHIFT)
+
+#define TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_SHIFT         0
+#define TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_MASK_US       7
+#define TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_MASK          (TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_MASK_US << TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_SHIFT)
+
+/* Fields in TEGRA30_I2S_SLOT_CTRL */
+
+/* Number of slots in frame, minus 1 */
+#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT                16
+#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US      7
+#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK         (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_SHIFT)
+
+/* TDM mode slot enable bitmask */
+#define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT    8
+#define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK     (0xff << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT)
+
+#define TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT    0
+#define TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK     (0xff << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT)
+
+/* Fields in TEGRA30_I2S_CIF_RX_CTRL */
+/* Uses field from TEGRA30_AUDIOCIF_CTRL_* in tegra30_ahub.h */
+
+/* Fields in TEGRA30_I2S_CIF_TX_CTRL */
+/* Uses field from TEGRA30_AUDIOCIF_CTRL_* in tegra30_ahub.h */
+
+/* Fields in TEGRA30_I2S_FLOWCTL */
+
+#define TEGRA30_I2S_FILTER_LINEAR                      0
+#define TEGRA30_I2S_FILTER_QUAD                                1
+
+#define TEGRA30_I2S_FLOWCTL_FILTER_SHIFT               31
+#define TEGRA30_I2S_FLOWCTL_FILTER_MASK                        (1                         << TEGRA30_I2S_FLOWCTL_FILTER_SHIFT)
+#define TEGRA30_I2S_FLOWCTL_FILTER_LINEAR              (TEGRA30_I2S_FILTER_LINEAR << TEGRA30_I2S_FLOWCTL_FILTER_SHIFT)
+#define TEGRA30_I2S_FLOWCTL_FILTER_QUAD                        (TEGRA30_I2S_FILTER_QUAD   << TEGRA30_I2S_FLOWCTL_FILTER_SHIFT)
+
+/* Fields in TEGRA30_I2S_TX_STEP */
+
+#define TEGRA30_I2S_TX_STEP_SHIFT                      0
+#define TEGRA30_I2S_TX_STEP_MASK_US                    0xffff
+#define TEGRA30_I2S_TX_STEP_MASK                       (TEGRA30_I2S_TX_STEP_MASK_US << TEGRA30_I2S_TX_STEP_SHIFT)
+
+/* Fields in TEGRA30_I2S_FLOW_STATUS */
+
+#define TEGRA30_I2S_FLOW_STATUS_UNDERFLOW              (1 << 31)
+#define TEGRA30_I2S_FLOW_STATUS_OVERFLOW               (1 << 30)
+#define TEGRA30_I2S_FLOW_STATUS_MONITOR_INT_EN         (1 << 4)
+#define TEGRA30_I2S_FLOW_STATUS_COUNTER_CLR            (1 << 3)
+#define TEGRA30_I2S_FLOW_STATUS_MONITOR_CLR            (1 << 2)
+#define TEGRA30_I2S_FLOW_STATUS_COUNTER_EN             (1 << 1)
+#define TEGRA30_I2S_FLOW_STATUS_MONITOR_EN             (1 << 0)
+
+/*
+ * There are no fields in TEGRA30_I2S_FLOW_TOTAL, TEGRA30_I2S_FLOW_OVER,
+ * TEGRA30_I2S_FLOW_UNDER; they are counters taking the whole register.
+ */
+
+/* Fields in TEGRA30_I2S_LCOEF_* */
+
+#define TEGRA30_I2S_LCOEF_COEF_SHIFT                   0
+#define TEGRA30_I2S_LCOEF_COEF_MASK_US                 0xffff
+#define TEGRA30_I2S_LCOEF_COEF_MASK                    (TEGRA30_I2S_LCOEF_COEF_MASK_US << TEGRA30_I2S_LCOEF_COEF_SHIFT)
+
+struct tegra30_i2s {
+       struct snd_soc_dai_driver dai;
+       int cif_id;
+       struct clk *clk_i2s;
+       enum tegra30_ahub_txcif capture_i2s_cif;
+       enum tegra30_ahub_rxcif capture_fifo_cif;
+       struct tegra_pcm_dma_params capture_dma_data;
+       enum tegra30_ahub_rxcif playback_i2s_cif;
+       enum tegra30_ahub_txcif playback_fifo_cif;
+       struct tegra_pcm_dma_params playback_dma_data;
+       struct regmap *regmap;
+       u32 reg_ctrl;
+};
+
+#endif
index e45ccd851f6a9133065303ab8c04c6737f53e0ec..32de7006daf08975e5a3edb4e4e8b9bfe029b572 100644 (file)
@@ -1,16 +1,17 @@
 /*
-* tegra_alc5632.c  --  Toshiba AC100(PAZ00) machine ASoC driver
-*
-* Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
-*
-* Authors:  Leon Romanovsky <leon@leon.nu>
-*           Andrey Danin <danindrey@mail.ru>
-*           Marc Dietrich <marvin24@gmx.de>
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License version 2 as
-* published by the Free Software Foundation.
-*/
+ * tegra_alc5632.c  --  Toshiba AC100(PAZ00) machine ASoC driver
+ *
+ * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+ * Copyright (C) 2012 - NVIDIA, Inc.
+ *
+ * Authors:  Leon Romanovsky <leon@leon.nu>
+ *           Andrey Danin <danindrey@mail.ru>
+ *           Marc Dietrich <marvin24@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
 
 #include <asm/mach-types.h>
 
@@ -28,9 +29,6 @@
 
 #include "../codecs/alc5632.h"
 
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
 #include "tegra_asoc_utils.h"
 
 #define DRV_NAME "tegra-alc5632"
@@ -39,7 +37,6 @@
 
 struct tegra_alc5632 {
        struct tegra_asoc_utils_data util_data;
-       struct platform_device *pcm_dev;
        int gpio_requested;
        int gpio_hp_det;
 };
@@ -140,7 +137,6 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link tegra_alc5632_dai = {
        .name = "ALC5632",
        .stream_name = "ALC5632 PCM",
-       .platform_name = "tegra-pcm-audio",
        .codec_dai_name = "alc5632-hifi",
        .init = tegra_alc5632_asoc_init,
        .ops = &tegra_alc5632_asoc_ops,
@@ -179,8 +175,6 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, card);
        snd_soc_card_set_drvdata(card, alc5632);
 
-       alc5632->pcm_dev = ERR_PTR(-EINVAL);
-
        if (!(pdev->dev.of_node)) {
                dev_err(&pdev->dev, "Must be instantiated using device tree\n");
                ret = -EINVAL;
@@ -214,18 +208,11 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
                goto err;
        }
 
-       alc5632->pcm_dev = platform_device_register_simple(
-               "tegra-pcm-audio", -1, NULL, 0);
-       if (IS_ERR(alc5632->pcm_dev)) {
-               dev_err(&pdev->dev,
-                       "Can't instantiate tegra-pcm-audio\n");
-               ret = PTR_ERR(alc5632->pcm_dev);
-               goto err;
-       }
+       tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_dai_of_node;
 
        ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev);
        if (ret)
-               goto err_unregister;
+               goto err;
 
        ret = snd_soc_register_card(card);
        if (ret) {
@@ -238,9 +225,6 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
 
 err_fini_utils:
        tegra_asoc_utils_fini(&alc5632->util_data);
-err_unregister:
-       if (!IS_ERR(alc5632->pcm_dev))
-               platform_device_unregister(alc5632->pcm_dev);
 err:
        return ret;
 }
@@ -259,8 +243,6 @@ static int __devexit tegra_alc5632_remove(struct platform_device *pdev)
        snd_soc_unregister_card(card);
 
        tegra_asoc_utils_fini(&machine->util_data);
-       if (!IS_ERR(machine->pcm_dev))
-               platform_device_unregister(machine->pcm_dev);
 
        return 0;
 }
index f8428e410e050bb4649d235038cd835284a660ab..9515ce58ea022a11f059edd9f7163ca1b95a1a04 100644 (file)
@@ -2,7 +2,7 @@
  * tegra_asoc_utils.c - Harmony machine ASoC driver
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -25,6 +25,7 @@
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
 
 #include "tegra_asoc_utils.h"
 
@@ -40,7 +41,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
        case 22050:
        case 44100:
        case 88200:
-               new_baseclock = 56448000;
+               if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+                       new_baseclock = 56448000;
+               else
+                       new_baseclock = 564480000;
                break;
        case 8000:
        case 16000:
@@ -48,7 +52,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
        case 48000:
        case 64000:
        case 96000:
-               new_baseclock = 73728000;
+               if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+                       new_baseclock = 73728000;
+               else
+                       new_baseclock = 552960000;
                break;
        default:
                return -EINVAL;
@@ -78,7 +85,7 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
                return err;
        }
 
-       /* Don't set cdev1 rate; its locked to pll_a_out0 */
+       /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
 
        err = clk_enable(data->clk_pll_a);
        if (err) {
@@ -112,6 +119,17 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
 
        data->dev = dev;
 
+       if (of_machine_is_compatible("nvidia,tegra20"))
+               data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
+       else if (of_machine_is_compatible("nvidia,tegra30"))
+               data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30;
+       else if (!dev->of_node)
+               /* non-DT is always Tegra20 */
+               data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
+       else
+               /* DT boot, but unknown SoC */
+               return -EINVAL;
+
        data->clk_pll_a = clk_get_sys(NULL, "pll_a");
        if (IS_ERR(data->clk_pll_a)) {
                dev_err(data->dev, "Can't retrieve clk pll_a\n");
@@ -126,15 +144,24 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
                goto err_put_pll_a;
        }
 
-       data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
+       if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+               data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
+       else
+               data->clk_cdev1 = clk_get_sys("extern1", NULL);
        if (IS_ERR(data->clk_cdev1)) {
                dev_err(data->dev, "Can't retrieve clk cdev1\n");
                ret = PTR_ERR(data->clk_cdev1);
                goto err_put_pll_a_out0;
        }
 
+       ret = tegra_asoc_utils_set_rate(data, 44100, 256 * 44100);
+       if (ret)
+               goto err_put_cdev1;
+
        return 0;
 
+err_put_cdev1:
+       clk_put(data->clk_cdev1);
 err_put_pll_a_out0:
        clk_put(data->clk_pll_a_out0);
 err_put_pll_a:
index 4818195da25c3be3542b403112aa7d68e742122d..44db1dbb8f210bebca2e0305fd8bc087e0c0820b 100644 (file)
@@ -2,7 +2,7 @@
  * tegra_asoc_utils.h - Definitions for Tegra DAS driver
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 struct clk;
 struct device;
 
+enum tegra_asoc_utils_soc {
+       TEGRA_ASOC_UTILS_SOC_TEGRA20,
+       TEGRA_ASOC_UTILS_SOC_TEGRA30,
+};
+
 struct tegra_asoc_utils_data {
        struct device *dev;
+       enum tegra_asoc_utils_soc soc;
        struct clk *clk_pll_a;
        struct clk *clk_pll_a_out0;
        struct clk *clk_cdev1;
@@ -42,4 +48,3 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
 void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data);
 
 #endif
-
diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c
deleted file mode 100644 (file)
index 3b3c1ba..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * tegra_das.c - Tegra DAS driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <mach/iomap.h>
-#include <sound/soc.h>
-#include "tegra_das.h"
-
-#define DRV_NAME "tegra-das"
-
-static struct tegra_das *das;
-
-static inline void tegra_das_write(u32 reg, u32 val)
-{
-       __raw_writel(val, das->regs + reg);
-}
-
-static inline u32 tegra_das_read(u32 reg)
-{
-       return __raw_readl(das->regs + reg);
-}
-
-int tegra_das_connect_dap_to_dac(int dap, int dac)
-{
-       u32 addr;
-       u32 reg;
-
-       if (!das)
-               return -ENODEV;
-
-       addr = TEGRA_DAS_DAP_CTRL_SEL +
-               (dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
-       reg = dac << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
-
-       tegra_das_write(addr, reg);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dac);
-
-int tegra_das_connect_dap_to_dap(int dap, int otherdap, int master,
-                                       int sdata1rx, int sdata2rx)
-{
-       u32 addr;
-       u32 reg;
-
-       if (!das)
-               return -ENODEV;
-
-       addr = TEGRA_DAS_DAP_CTRL_SEL +
-               (dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
-       reg = otherdap << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P |
-               !!sdata2rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P |
-               !!sdata1rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P |
-               !!master << TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P;
-
-       tegra_das_write(addr, reg);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dap);
-
-int tegra_das_connect_dac_to_dap(int dac, int dap)
-{
-       u32 addr;
-       u32 reg;
-
-       if (!das)
-               return -ENODEV;
-
-       addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL +
-               (dac * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
-       reg = dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
-               dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
-               dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
-
-       tegra_das_write(addr, reg);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(tegra_das_connect_dac_to_dap);
-
-#ifdef CONFIG_DEBUG_FS
-static int tegra_das_show(struct seq_file *s, void *unused)
-{
-       int i;
-       u32 addr;
-       u32 reg;
-
-       for (i = 0; i < TEGRA_DAS_DAP_CTRL_SEL_COUNT; i++) {
-               addr = TEGRA_DAS_DAP_CTRL_SEL +
-                       (i * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
-               reg = tegra_das_read(addr);
-               seq_printf(s, "TEGRA_DAS_DAP_CTRL_SEL[%d] = %08x\n", i, reg);
-       }
-
-       for (i = 0; i < TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT; i++) {
-               addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL +
-                       (i * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
-               reg = tegra_das_read(addr);
-               seq_printf(s, "TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL[%d] = %08x\n",
-                                i, reg);
-       }
-
-       return 0;
-}
-
-static int tegra_das_debug_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, tegra_das_show, inode->i_private);
-}
-
-static const struct file_operations tegra_das_debug_fops = {
-       .open    = tegra_das_debug_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = single_release,
-};
-
-static void tegra_das_debug_add(struct tegra_das *das)
-{
-       das->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
-                                        snd_soc_debugfs_root, das,
-                                        &tegra_das_debug_fops);
-}
-
-static void tegra_das_debug_remove(struct tegra_das *das)
-{
-       if (das->debug)
-               debugfs_remove(das->debug);
-}
-#else
-static inline void tegra_das_debug_add(struct tegra_das *das)
-{
-}
-
-static inline void tegra_das_debug_remove(struct tegra_das *das)
-{
-}
-#endif
-
-static int __devinit tegra_das_probe(struct platform_device *pdev)
-{
-       struct resource *res, *region;
-       int ret = 0;
-
-       if (das)
-               return -ENODEV;
-
-       das = devm_kzalloc(&pdev->dev, sizeof(struct tegra_das), GFP_KERNEL);
-       if (!das) {
-               dev_err(&pdev->dev, "Can't allocate tegra_das\n");
-               ret = -ENOMEM;
-               goto err;
-       }
-       das->dev = &pdev->dev;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "No memory resource\n");
-               ret = -ENODEV;
-               goto err;
-       }
-
-       region = devm_request_mem_region(&pdev->dev, res->start,
-                                        resource_size(res), pdev->name);
-       if (!region) {
-               dev_err(&pdev->dev, "Memory region already claimed\n");
-               ret = -EBUSY;
-               goto err;
-       }
-
-       das->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-       if (!das->regs) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1,
-                                          TEGRA_DAS_DAP_SEL_DAC1);
-       if (ret) {
-               dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
-               goto err;
-       }
-       ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1,
-                                          TEGRA_DAS_DAC_SEL_DAP1);
-       if (ret) {
-               dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
-               goto err;
-       }
-
-       tegra_das_debug_add(das);
-
-       platform_set_drvdata(pdev, das);
-
-       return 0;
-
-err:
-       das = NULL;
-       return ret;
-}
-
-static int __devexit tegra_das_remove(struct platform_device *pdev)
-{
-       if (!das)
-               return -ENODEV;
-
-       tegra_das_debug_remove(das);
-
-       das = NULL;
-
-       return 0;
-}
-
-static const struct of_device_id tegra_das_of_match[] __devinitconst = {
-       { .compatible = "nvidia,tegra20-das", },
-       {},
-};
-
-static struct platform_driver tegra_das_driver = {
-       .probe = tegra_das_probe,
-       .remove = __devexit_p(tegra_das_remove),
-       .driver = {
-               .name = DRV_NAME,
-               .owner = THIS_MODULE,
-               .of_match_table = tegra_das_of_match,
-       },
-};
-module_platform_driver(tegra_das_driver);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Tegra DAS driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, tegra_das_of_match);
diff --git a/sound/soc/tegra/tegra_das.h b/sound/soc/tegra/tegra_das.h
deleted file mode 100644 (file)
index 2c96c7b..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * tegra_das.h - Definitions for Tegra DAS driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __TEGRA_DAS_H__
-#define __TEGRA_DAS_H__
-
-/* Register TEGRA_DAS_DAP_CTRL_SEL */
-#define TEGRA_DAS_DAP_CTRL_SEL                         0x00
-#define TEGRA_DAS_DAP_CTRL_SEL_COUNT                   5
-#define TEGRA_DAS_DAP_CTRL_SEL_STRIDE                  4
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P            31
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S            1
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P      30
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S      1
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P      29
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S      1
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P          0
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S          5
-
-/* Values for field TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
-#define TEGRA_DAS_DAP_SEL_DAC1 0
-#define TEGRA_DAS_DAP_SEL_DAC2 1
-#define TEGRA_DAS_DAP_SEL_DAC3 2
-#define TEGRA_DAS_DAP_SEL_DAP1 16
-#define TEGRA_DAS_DAP_SEL_DAP2 17
-#define TEGRA_DAS_DAP_SEL_DAP3 18
-#define TEGRA_DAS_DAP_SEL_DAP4 19
-#define TEGRA_DAS_DAP_SEL_DAP5 20
-
-/* Register TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL */
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL                       0x40
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT                 3
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE                        4
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P      28
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S      4
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P      24
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S      4
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P         0
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S         4
-
-/*
- * Values for:
- * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
- * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
- * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
- */
-#define TEGRA_DAS_DAC_SEL_DAP1 0
-#define TEGRA_DAS_DAC_SEL_DAP2 1
-#define TEGRA_DAS_DAC_SEL_DAP3 2
-#define TEGRA_DAS_DAC_SEL_DAP4 3
-#define TEGRA_DAS_DAC_SEL_DAP5 4
-
-/*
- * Names/IDs of the DACs/DAPs.
- */
-
-#define TEGRA_DAS_DAP_ID_1 0
-#define TEGRA_DAS_DAP_ID_2 1
-#define TEGRA_DAS_DAP_ID_3 2
-#define TEGRA_DAS_DAP_ID_4 3
-#define TEGRA_DAS_DAP_ID_5 4
-
-#define TEGRA_DAS_DAC_ID_1 0
-#define TEGRA_DAS_DAC_ID_2 1
-#define TEGRA_DAS_DAC_ID_3 2
-
-struct tegra_das {
-       struct device *dev;
-       void __iomem *regs;
-       struct dentry *debug;
-};
-
-/*
- * Terminology:
- * DAS: Digital audio switch (HW module controlled by this driver)
- * DAP: Digital audio port (port/pins on Tegra device)
- * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
- * 
- * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
- * DAC, or another DAP. When DAPs are connected, one must be the master and
- * one the slave. Each DAC allows selection of a specific DAP for input, to
- * cater for the case where N DAPs are connected to 1 DAC for broadcast
- * output.
- *
- * This driver is dumb; no attempt is made to ensure that a valid routing
- * configuration is programmed.
- */
-
-/*
- * Connect a DAP to to a DAC
- * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_*
- * dac_sel: DAC to connect to: TEGRA_DAS_DAP_SEL_DAC*
- */
-extern int tegra_das_connect_dap_to_dac(int dap_id, int dac_sel);
-
-/*
- * Connect a DAP to to another DAP
- * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_*
- * other_dap_sel: DAP to connect to: TEGRA_DAS_DAP_SEL_DAP*
- * master: Is this DAP the master (1) or slave (0)
- * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0)
- * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0)
- */
-extern int tegra_das_connect_dap_to_dap(int dap_id, int other_dap_sel,
-                                       int master, int sdata1rx,
-                                       int sdata2rx);
-
-/*
- * Connect a DAC's input to a DAP
- * (DAC outputs are selected by the DAP)
- * dac_id: DAC ID to connect: TEGRA_DAS_DAC_ID_*
- * dap_sel: DAP to receive input from: TEGRA_DAS_DAC_SEL_DAP*
- */
-extern int tegra_das_connect_dac_to_dap(int dac_id, int dap_sel);
-
-#endif
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c
deleted file mode 100644 (file)
index e533499..0000000
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * tegra_i2s.c - Tegra I2S driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- *
- * Copyright (c) 2009-2010, NVIDIA Corporation.
- * Scott Peterson <speterson@nvidia.com>
- *
- * Copyright (C) 2010 Google, Inc.
- * Iliyan Malchev <malchev@google.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/clk.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <mach/iomap.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "tegra_i2s.h"
-
-#define DRV_NAME "tegra-i2s"
-
-static inline void tegra_i2s_write(struct tegra_i2s *i2s, u32 reg, u32 val)
-{
-       __raw_writel(val, i2s->regs + reg);
-}
-
-static inline u32 tegra_i2s_read(struct tegra_i2s *i2s, u32 reg)
-{
-       return __raw_readl(i2s->regs + reg);
-}
-
-#ifdef CONFIG_DEBUG_FS
-static int tegra_i2s_show(struct seq_file *s, void *unused)
-{
-#define REG(r) { r, #r }
-       static const struct {
-               int offset;
-               const char *name;
-       } regs[] = {
-               REG(TEGRA_I2S_CTRL),
-               REG(TEGRA_I2S_STATUS),
-               REG(TEGRA_I2S_TIMING),
-               REG(TEGRA_I2S_FIFO_SCR),
-               REG(TEGRA_I2S_PCM_CTRL),
-               REG(TEGRA_I2S_NW_CTRL),
-               REG(TEGRA_I2S_TDM_CTRL),
-               REG(TEGRA_I2S_TDM_TX_RX_CTRL),
-       };
-#undef REG
-
-       struct tegra_i2s *i2s = s->private;
-       int i;
-
-       clk_enable(i2s->clk_i2s);
-
-       for (i = 0; i < ARRAY_SIZE(regs); i++) {
-               u32 val = tegra_i2s_read(i2s, regs[i].offset);
-               seq_printf(s, "%s = %08x\n", regs[i].name, val);
-       }
-
-       clk_disable(i2s->clk_i2s);
-
-       return 0;
-}
-
-static int tegra_i2s_debug_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, tegra_i2s_show, inode->i_private);
-}
-
-static const struct file_operations tegra_i2s_debug_fops = {
-       .open    = tegra_i2s_debug_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = single_release,
-};
-
-static void tegra_i2s_debug_add(struct tegra_i2s *i2s)
-{
-       i2s->debug = debugfs_create_file(i2s->dai.name, S_IRUGO,
-                                        snd_soc_debugfs_root, i2s,
-                                        &tegra_i2s_debug_fops);
-}
-
-static void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
-{
-       if (i2s->debug)
-               debugfs_remove(i2s->debug);
-}
-#else
-static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s)
-{
-}
-
-static inline void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
-{
-}
-#endif
-
-static int tegra_i2s_set_fmt(struct snd_soc_dai *dai,
-                               unsigned int fmt)
-{
-       struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_NF:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_MASTER_ENABLE;
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_MASTER_ENABLE;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFM:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       i2s->reg_ctrl &= ~(TEGRA_I2S_CTRL_BIT_FORMAT_MASK | 
-                               TEGRA_I2S_CTRL_LRCK_MASK);
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_DSP_A:
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP;
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
-               break;
-       case SND_SOC_DAIFMT_DSP_B:
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP;
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_R_LOW;
-               break;
-       case SND_SOC_DAIFMT_I2S:
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_I2S;
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
-               break;
-       case SND_SOC_DAIFMT_RIGHT_J:
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_RJM;
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_LJM;
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int tegra_i2s_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params,
-                               struct snd_soc_dai *dai)
-{
-        struct device *dev = substream->pcm->card->dev;
-       struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-       u32 reg;
-       int ret, sample_size, srate, i2sclock, bitcnt;
-
-       i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_BIT_SIZE_MASK;
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_16;
-               sample_size = 16;
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_24;
-               sample_size = 24;
-               break;
-       case SNDRV_PCM_FORMAT_S32_LE:
-               i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_32;
-               sample_size = 32;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       srate = params_rate(params);
-
-       /* Final "* 2" required by Tegra hardware */
-       i2sclock = srate * params_channels(params) * sample_size * 2;
-
-       ret = clk_set_rate(i2s->clk_i2s, i2sclock);
-       if (ret) {
-               dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
-               return ret;
-       }
-
-       bitcnt = (i2sclock / (2 * srate)) - 1;
-       if (bitcnt < 0 || bitcnt > TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
-               return -EINVAL;
-       reg = bitcnt << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
-
-       if (i2sclock % (2 * srate))
-               reg |= TEGRA_I2S_TIMING_NON_SYM_ENABLE;
-
-       if (!i2s->clk_refs)
-               clk_enable(i2s->clk_i2s);
-
-       tegra_i2s_write(i2s, TEGRA_I2S_TIMING, reg);
-
-       tegra_i2s_write(i2s, TEGRA_I2S_FIFO_SCR,
-               TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
-               TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
-
-       if (!i2s->clk_refs)
-               clk_disable(i2s->clk_i2s);
-
-       return 0;
-}
-
-static void tegra_i2s_start_playback(struct tegra_i2s *i2s)
-{
-       i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO1_ENABLE;
-       tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static void tegra_i2s_stop_playback(struct tegra_i2s *i2s)
-{
-       i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO1_ENABLE;
-       tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static void tegra_i2s_start_capture(struct tegra_i2s *i2s)
-{
-       i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO2_ENABLE;
-       tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static void tegra_i2s_stop_capture(struct tegra_i2s *i2s)
-{
-       i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO2_ENABLE;
-       tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static int tegra_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-                               struct snd_soc_dai *dai)
-{
-       struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-       case SNDRV_PCM_TRIGGER_RESUME:
-               if (!i2s->clk_refs)
-                       clk_enable(i2s->clk_i2s);
-               i2s->clk_refs++;
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       tegra_i2s_start_playback(i2s);
-               else
-                       tegra_i2s_start_capture(i2s);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       tegra_i2s_stop_playback(i2s);
-               else
-                       tegra_i2s_stop_capture(i2s);
-               i2s->clk_refs--;
-               if (!i2s->clk_refs)
-                       clk_disable(i2s->clk_i2s);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int tegra_i2s_probe(struct snd_soc_dai *dai)
-{
-       struct tegra_i2s * i2s = snd_soc_dai_get_drvdata(dai);
-
-       dai->capture_dma_data = &i2s->capture_dma_data;
-       dai->playback_dma_data = &i2s->playback_dma_data;
-
-       return 0;
-}
-
-static const struct snd_soc_dai_ops tegra_i2s_dai_ops = {
-       .set_fmt        = tegra_i2s_set_fmt,
-       .hw_params      = tegra_i2s_hw_params,
-       .trigger        = tegra_i2s_trigger,
-};
-
-static const struct snd_soc_dai_driver tegra_i2s_dai_template = {
-       .probe = tegra_i2s_probe,
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_96000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_96000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .ops = &tegra_i2s_dai_ops,
-       .symmetric_rates = 1,
-};
-
-static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
-{
-       struct tegra_i2s * i2s;
-       struct resource *mem, *memregion, *dmareq;
-       u32 of_dma[2];
-       u32 dma_ch;
-       int ret;
-
-       i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2s), GFP_KERNEL);
-       if (!i2s) {
-               dev_err(&pdev->dev, "Can't allocate tegra_i2s\n");
-               ret = -ENOMEM;
-               goto err;
-       }
-       dev_set_drvdata(&pdev->dev, i2s);
-
-       i2s->dai = tegra_i2s_dai_template;
-       i2s->dai.name = dev_name(&pdev->dev);
-
-       i2s->clk_i2s = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(i2s->clk_i2s)) {
-               dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
-               ret = PTR_ERR(i2s->clk_i2s);
-               goto err;
-       }
-
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem) {
-               dev_err(&pdev->dev, "No memory resource\n");
-               ret = -ENODEV;
-               goto err_clk_put;
-       }
-
-       dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dmareq) {
-               if (of_property_read_u32_array(pdev->dev.of_node,
-                                       "nvidia,dma-request-selector",
-                                       of_dma, 2) < 0) {
-                       dev_err(&pdev->dev, "No DMA resource\n");
-                       ret = -ENODEV;
-                       goto err_clk_put;
-               }
-               dma_ch = of_dma[1];
-       } else {
-               dma_ch = dmareq->start;
-       }
-
-       memregion = devm_request_mem_region(&pdev->dev, mem->start,
-                                           resource_size(mem), DRV_NAME);
-       if (!memregion) {
-               dev_err(&pdev->dev, "Memory region already claimed\n");
-               ret = -EBUSY;
-               goto err_clk_put;
-       }
-
-       i2s->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
-       if (!i2s->regs) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -ENOMEM;
-               goto err_clk_put;
-       }
-
-       i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2;
-       i2s->capture_dma_data.wrap = 4;
-       i2s->capture_dma_data.width = 32;
-       i2s->capture_dma_data.req_sel = dma_ch;
-
-       i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1;
-       i2s->playback_dma_data.wrap = 4;
-       i2s->playback_dma_data.width = 32;
-       i2s->playback_dma_data.req_sel = dma_ch;
-
-       i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED;
-
-       ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
-       if (ret) {
-               dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
-               ret = -ENOMEM;
-               goto err_clk_put;
-       }
-
-       tegra_i2s_debug_add(i2s);
-
-       return 0;
-
-err_clk_put:
-       clk_put(i2s->clk_i2s);
-err:
-       return ret;
-}
-
-static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev)
-{
-       struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev);
-
-       snd_soc_unregister_dai(&pdev->dev);
-
-       tegra_i2s_debug_remove(i2s);
-
-       clk_put(i2s->clk_i2s);
-
-       return 0;
-}
-
-static const struct of_device_id tegra_i2s_of_match[] __devinitconst = {
-       { .compatible = "nvidia,tegra20-i2s", },
-       {},
-};
-
-static struct platform_driver tegra_i2s_driver = {
-       .driver = {
-               .name = DRV_NAME,
-               .owner = THIS_MODULE,
-               .of_match_table = tegra_i2s_of_match,
-       },
-       .probe = tegra_i2s_platform_probe,
-       .remove = __devexit_p(tegra_i2s_platform_remove),
-};
-module_platform_driver(tegra_i2s_driver);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Tegra I2S ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, tegra_i2s_of_match);
diff --git a/sound/soc/tegra/tegra_i2s.h b/sound/soc/tegra/tegra_i2s.h
deleted file mode 100644 (file)
index 15ce1e2..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * tegra_i2s.h - Definitions for Tegra I2S driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- *
- * Copyright (c) 2009-2010, NVIDIA Corporation.
- * Scott Peterson <speterson@nvidia.com>
- *
- * Copyright (C) 2010 Google, Inc.
- * Iliyan Malchev <malchev@google.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 __TEGRA_I2S_H__
-#define __TEGRA_I2S_H__
-
-#include "tegra_pcm.h"
-
-/* Register offsets from TEGRA_I2S1_BASE and TEGRA_I2S2_BASE */
-
-#define TEGRA_I2S_CTRL                                 0x00
-#define TEGRA_I2S_STATUS                               0x04
-#define TEGRA_I2S_TIMING                               0x08
-#define TEGRA_I2S_FIFO_SCR                             0x0c
-#define TEGRA_I2S_PCM_CTRL                             0x10
-#define TEGRA_I2S_NW_CTRL                              0x14
-#define TEGRA_I2S_TDM_CTRL                             0x20
-#define TEGRA_I2S_TDM_TX_RX_CTRL                       0x24
-#define TEGRA_I2S_FIFO1                                        0x40
-#define TEGRA_I2S_FIFO2                                        0x80
-
-/* Fields in TEGRA_I2S_CTRL */
-
-#define TEGRA_I2S_CTRL_FIFO2_TX_ENABLE                 (1 << 30)
-#define TEGRA_I2S_CTRL_FIFO1_ENABLE                    (1 << 29)
-#define TEGRA_I2S_CTRL_FIFO2_ENABLE                    (1 << 28)
-#define TEGRA_I2S_CTRL_FIFO1_RX_ENABLE                 (1 << 27)
-#define TEGRA_I2S_CTRL_FIFO_LPBK_ENABLE                        (1 << 26)
-#define TEGRA_I2S_CTRL_MASTER_ENABLE                   (1 << 25)
-
-#define TEGRA_I2S_LRCK_LEFT_LOW                                0
-#define TEGRA_I2S_LRCK_RIGHT_LOW                       1
-
-#define TEGRA_I2S_CTRL_LRCK_SHIFT                      24
-#define TEGRA_I2S_CTRL_LRCK_MASK                       (1                        << TEGRA_I2S_CTRL_LRCK_SHIFT)
-#define TEGRA_I2S_CTRL_LRCK_L_LOW                      (TEGRA_I2S_LRCK_LEFT_LOW  << TEGRA_I2S_CTRL_LRCK_SHIFT)
-#define TEGRA_I2S_CTRL_LRCK_R_LOW                      (TEGRA_I2S_LRCK_RIGHT_LOW << TEGRA_I2S_CTRL_LRCK_SHIFT)
-
-#define TEGRA_I2S_BIT_FORMAT_I2S                       0
-#define TEGRA_I2S_BIT_FORMAT_RJM                       1
-#define TEGRA_I2S_BIT_FORMAT_LJM                       2
-#define TEGRA_I2S_BIT_FORMAT_DSP                       3
-
-#define TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT                        10
-#define TEGRA_I2S_CTRL_BIT_FORMAT_MASK                 (3                        << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_I2S                  (TEGRA_I2S_BIT_FORMAT_I2S << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_RJM                  (TEGRA_I2S_BIT_FORMAT_RJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_LJM                  (TEGRA_I2S_BIT_FORMAT_LJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_DSP                  (TEGRA_I2S_BIT_FORMAT_DSP << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-
-#define TEGRA_I2S_BIT_SIZE_16                          0
-#define TEGRA_I2S_BIT_SIZE_20                          1
-#define TEGRA_I2S_BIT_SIZE_24                          2
-#define TEGRA_I2S_BIT_SIZE_32                          3
-
-#define TEGRA_I2S_CTRL_BIT_SIZE_SHIFT                  8
-#define TEGRA_I2S_CTRL_BIT_SIZE_MASK                   (3                     << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_16                     (TEGRA_I2S_BIT_SIZE_16 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_20                     (TEGRA_I2S_BIT_SIZE_20 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_24                     (TEGRA_I2S_BIT_SIZE_24 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_32                     (TEGRA_I2S_BIT_SIZE_32 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-
-#define TEGRA_I2S_FIFO_16_LSB                          0
-#define TEGRA_I2S_FIFO_20_LSB                          1
-#define TEGRA_I2S_FIFO_24_LSB                          2
-#define TEGRA_I2S_FIFO_32                              3
-#define TEGRA_I2S_FIFO_PACKED                          7
-
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT               4
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_MASK                        (7                     << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_16_LSB              (TEGRA_I2S_FIFO_16_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_20_LSB              (TEGRA_I2S_FIFO_20_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_24_LSB              (TEGRA_I2S_FIFO_24_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_32                  (TEGRA_I2S_FIFO_32     << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED              (TEGRA_I2S_FIFO_PACKED << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-
-#define TEGRA_I2S_CTRL_IE_FIFO1_ERR                    (1 << 3)
-#define TEGRA_I2S_CTRL_IE_FIFO2_ERR                    (1 << 2)
-#define TEGRA_I2S_CTRL_QE_FIFO1                                (1 << 1)
-#define TEGRA_I2S_CTRL_QE_FIFO2                                (1 << 0)
-
-/* Fields in TEGRA_I2S_STATUS */
-
-#define TEGRA_I2S_STATUS_FIFO1_RDY                     (1 << 31)
-#define TEGRA_I2S_STATUS_FIFO2_RDY                     (1 << 30)
-#define TEGRA_I2S_STATUS_FIFO1_BSY                     (1 << 29)
-#define TEGRA_I2S_STATUS_FIFO2_BSY                     (1 << 28)
-#define TEGRA_I2S_STATUS_FIFO1_ERR                     (1 << 3)
-#define TEGRA_I2S_STATUS_FIFO2_ERR                     (1 << 2)
-#define TEGRA_I2S_STATUS_QS_FIFO1                      (1 << 1)
-#define TEGRA_I2S_STATUS_QS_FIFO2                      (1 << 0)
-
-/* Fields in TEGRA_I2S_TIMING */
-
-#define TEGRA_I2S_TIMING_NON_SYM_ENABLE                        (1 << 12)
-#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT       0
-#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US     0x7fff
-#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK                (TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT)
-
-/* Fields in TEGRA_I2S_FIFO_SCR */
-
-#define TEGRA_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT        24
-#define TEGRA_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT        16
-#define TEGRA_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK  0x3f
-
-#define TEGRA_I2S_FIFO_SCR_FIFO2_CLR                   (1 << 12)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_CLR                   (1 << 8)
-
-#define TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT                        0
-#define TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS              1
-#define TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS             2
-#define TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS            3
-
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT         4
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK          (3 << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT      (TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT     << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS    (TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS   << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS   (TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS  << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS  (TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT         0
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK          (3 << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT      (TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT     << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS    (TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS   << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS   (TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS  << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS  (TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-
-struct tegra_i2s {
-       struct snd_soc_dai_driver dai;
-       struct clk *clk_i2s;
-       int clk_refs;
-       struct tegra_pcm_dma_params capture_dma_data;
-       struct tegra_pcm_dma_params playback_dma_data;
-       void __iomem *regs;
-       struct dentry *debug;
-       u32 reg_ctrl;
-};
-
-#endif
index 8b4457137c7ca7a451cad16e41fb274010a2d380..127348dc09b10d36782f5e3538bbefd02f494612 100644 (file)
@@ -2,7 +2,7 @@
  * tegra_pcm.c - Tegra PCM driver
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
  *
  * Based on code copyright/by:
  *
@@ -29,8 +29,8 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/dma-mapping.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -39,8 +39,6 @@
 
 #include "tegra_pcm.h"
 
-#define DRV_NAME "tegra-pcm-audio"
-
 static const struct snd_pcm_hardware tegra_pcm_hardware = {
        .info                   = SNDRV_PCM_INFO_MMAP |
                                  SNDRV_PCM_INFO_MMAP_VALID |
@@ -372,28 +370,18 @@ static struct snd_soc_platform_driver tegra_pcm_platform = {
        .pcm_free       = tegra_pcm_free,
 };
 
-static int __devinit tegra_pcm_platform_probe(struct platform_device *pdev)
+int __devinit tegra_pcm_platform_register(struct device *dev)
 {
-       return snd_soc_register_platform(&pdev->dev, &tegra_pcm_platform);
+       return snd_soc_register_platform(dev, &tegra_pcm_platform);
 }
+EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
 
-static int __devexit tegra_pcm_platform_remove(struct platform_device *pdev)
+void __devexit tegra_pcm_platform_unregister(struct device *dev)
 {
-       snd_soc_unregister_platform(&pdev->dev);
-       return 0;
+       snd_soc_unregister_platform(dev);
 }
-
-static struct platform_driver tegra_pcm_driver = {
-       .driver = {
-               .name = DRV_NAME,
-               .owner = THIS_MODULE,
-       },
-       .probe = tegra_pcm_platform_probe,
-       .remove = __devexit_p(tegra_pcm_platform_remove),
-};
-module_platform_driver(tegra_pcm_driver);
+EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
 
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("Tegra PCM ASoC driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
index dbb90339fe0de21a8df6d9b9d70dbccc1db912f1..985d418a35e7a7e5e092ddd6b0eac36f8c73cf5b 100644 (file)
@@ -2,7 +2,7 @@
  * tegra_pcm.h - Definitions for Tegra PCM driver
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
  *
  * Based on code copyright/by:
  *
@@ -52,4 +52,7 @@ struct tegra_runtime_data {
        struct tegra_dma_channel *dma_chan;
 };
 
+int tegra_pcm_platform_register(struct device *dev);
+void tegra_pcm_platform_unregister(struct device *dev);
+
 #endif
diff --git a/sound/soc/tegra/tegra_spdif.c b/sound/soc/tegra/tegra_spdif.c
deleted file mode 100644 (file)
index 9ff2c60..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * tegra_spdif.c - Tegra SPDIF driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2011 - NVIDIA, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <mach/iomap.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "tegra_spdif.h"
-
-#define DRV_NAME "tegra-spdif"
-
-static inline void tegra_spdif_write(struct tegra_spdif *spdif, u32 reg,
-                                       u32 val)
-{
-       __raw_writel(val, spdif->regs + reg);
-}
-
-static inline u32 tegra_spdif_read(struct tegra_spdif *spdif, u32 reg)
-{
-       return __raw_readl(spdif->regs + reg);
-}
-
-#ifdef CONFIG_DEBUG_FS
-static int tegra_spdif_show(struct seq_file *s, void *unused)
-{
-#define REG(r) { r, #r }
-       static const struct {
-               int offset;
-               const char *name;
-       } regs[] = {
-               REG(TEGRA_SPDIF_CTRL),
-               REG(TEGRA_SPDIF_STATUS),
-               REG(TEGRA_SPDIF_STROBE_CTRL),
-               REG(TEGRA_SPDIF_DATA_FIFO_CSR),
-               REG(TEGRA_SPDIF_CH_STA_RX_A),
-               REG(TEGRA_SPDIF_CH_STA_RX_B),
-               REG(TEGRA_SPDIF_CH_STA_RX_C),
-               REG(TEGRA_SPDIF_CH_STA_RX_D),
-               REG(TEGRA_SPDIF_CH_STA_RX_E),
-               REG(TEGRA_SPDIF_CH_STA_RX_F),
-               REG(TEGRA_SPDIF_CH_STA_TX_A),
-               REG(TEGRA_SPDIF_CH_STA_TX_B),
-               REG(TEGRA_SPDIF_CH_STA_TX_C),
-               REG(TEGRA_SPDIF_CH_STA_TX_D),
-               REG(TEGRA_SPDIF_CH_STA_TX_E),
-               REG(TEGRA_SPDIF_CH_STA_TX_F),
-       };
-#undef REG
-
-       struct tegra_spdif *spdif = s->private;
-       int i;
-
-       clk_enable(spdif->clk_spdif_out);
-
-       for (i = 0; i < ARRAY_SIZE(regs); i++) {
-               u32 val = tegra_spdif_read(spdif, regs[i].offset);
-               seq_printf(s, "%s = %08x\n", regs[i].name, val);
-       }
-
-       clk_disable(spdif->clk_spdif_out);
-
-       return 0;
-}
-
-static int tegra_spdif_debug_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, tegra_spdif_show, inode->i_private);
-}
-
-static const struct file_operations tegra_spdif_debug_fops = {
-       .open    = tegra_spdif_debug_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = single_release,
-};
-
-static void tegra_spdif_debug_add(struct tegra_spdif *spdif)
-{
-       spdif->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
-                                               snd_soc_debugfs_root, spdif,
-                                               &tegra_spdif_debug_fops);
-}
-
-static void tegra_spdif_debug_remove(struct tegra_spdif *spdif)
-{
-       if (spdif->debug)
-               debugfs_remove(spdif->debug);
-}
-#else
-static inline void tegra_spdif_debug_add(struct tegra_spdif *spdif)
-{
-}
-
-static inline void tegra_spdif_debug_remove(struct tegra_spdif *spdif)
-{
-}
-#endif
-
-static int tegra_spdif_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params,
-                               struct snd_soc_dai *dai)
-{
-       struct device *dev = substream->pcm->card->dev;
-       struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
-       int ret, spdifclock;
-
-       spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_PACK;
-       spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_BIT_MODE_MASK;
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_PACK;
-               spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_BIT_MODE_16BIT;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (params_rate(params)) {
-       case 32000:
-               spdifclock = 4096000;
-               break;
-       case 44100:
-               spdifclock = 5644800;
-               break;
-       case 48000:
-               spdifclock = 6144000;
-               break;
-       case 88200:
-               spdifclock = 11289600;
-               break;
-       case 96000:
-               spdifclock = 12288000;
-               break;
-       case 176400:
-               spdifclock = 22579200;
-               break;
-       case 192000:
-               spdifclock = 24576000;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);
-       if (ret) {
-               dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static void tegra_spdif_start_playback(struct tegra_spdif *spdif)
-{
-       spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_TX_EN;
-       tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl);
-}
-
-static void tegra_spdif_stop_playback(struct tegra_spdif *spdif)
-{
-       spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_TX_EN;
-       tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl);
-}
-
-static int tegra_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
-                               struct snd_soc_dai *dai)
-{
-       struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-       case SNDRV_PCM_TRIGGER_RESUME:
-               if (!spdif->clk_refs)
-                       clk_enable(spdif->clk_spdif_out);
-               spdif->clk_refs++;
-               tegra_spdif_start_playback(spdif);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-               tegra_spdif_stop_playback(spdif);
-               spdif->clk_refs--;
-               if (!spdif->clk_refs)
-                       clk_disable(spdif->clk_spdif_out);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int tegra_spdif_probe(struct snd_soc_dai *dai)
-{
-       struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
-
-       dai->capture_dma_data = NULL;
-       dai->playback_dma_data = &spdif->playback_dma_data;
-
-       return 0;
-}
-
-static const struct snd_soc_dai_ops tegra_spdif_dai_ops = {
-       .hw_params      = tegra_spdif_hw_params,
-       .trigger        = tegra_spdif_trigger,
-};
-
-static struct snd_soc_dai_driver tegra_spdif_dai = {
-       .name = DRV_NAME,
-       .probe = tegra_spdif_probe,
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
-                               SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .ops = &tegra_spdif_dai_ops,
-};
-
-static __devinit int tegra_spdif_platform_probe(struct platform_device *pdev)
-{
-       struct tegra_spdif *spdif;
-       struct resource *mem, *memregion, *dmareq;
-       int ret;
-
-       spdif = kzalloc(sizeof(struct tegra_spdif), GFP_KERNEL);
-       if (!spdif) {
-               dev_err(&pdev->dev, "Can't allocate tegra_spdif\n");
-               ret = -ENOMEM;
-               goto exit;
-       }
-       dev_set_drvdata(&pdev->dev, spdif);
-
-       spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out");
-       if (IS_ERR(spdif->clk_spdif_out)) {
-               pr_err("Can't retrieve spdif clock\n");
-               ret = PTR_ERR(spdif->clk_spdif_out);
-               goto err_free;
-       }
-
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem) {
-               dev_err(&pdev->dev, "No memory resource\n");
-               ret = -ENODEV;
-               goto err_clk_put;
-       }
-
-       dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dmareq) {
-               dev_err(&pdev->dev, "No DMA resource\n");
-               ret = -ENODEV;
-               goto err_clk_put;
-       }
-
-       memregion = request_mem_region(mem->start, resource_size(mem),
-                                       DRV_NAME);
-       if (!memregion) {
-               dev_err(&pdev->dev, "Memory region already claimed\n");
-               ret = -EBUSY;
-               goto err_clk_put;
-       }
-
-       spdif->regs = ioremap(mem->start, resource_size(mem));
-       if (!spdif->regs) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -ENOMEM;
-               goto err_release;
-       }
-
-       spdif->playback_dma_data.addr = mem->start + TEGRA_SPDIF_DATA_OUT;
-       spdif->playback_dma_data.wrap = 4;
-       spdif->playback_dma_data.width = 32;
-       spdif->playback_dma_data.req_sel = dmareq->start;
-
-       ret = snd_soc_register_dai(&pdev->dev, &tegra_spdif_dai);
-       if (ret) {
-               dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
-               ret = -ENOMEM;
-               goto err_unmap;
-       }
-
-       tegra_spdif_debug_add(spdif);
-
-       return 0;
-
-err_unmap:
-       iounmap(spdif->regs);
-err_release:
-       release_mem_region(mem->start, resource_size(mem));
-err_clk_put:
-       clk_put(spdif->clk_spdif_out);
-err_free:
-       kfree(spdif);
-exit:
-       return ret;
-}
-
-static int __devexit tegra_spdif_platform_remove(struct platform_device *pdev)
-{
-       struct tegra_spdif *spdif = dev_get_drvdata(&pdev->dev);
-       struct resource *res;
-
-       snd_soc_unregister_dai(&pdev->dev);
-
-       tegra_spdif_debug_remove(spdif);
-
-       iounmap(spdif->regs);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-
-       clk_put(spdif->clk_spdif_out);
-
-       kfree(spdif);
-
-       return 0;
-}
-
-static struct platform_driver tegra_spdif_driver = {
-       .driver = {
-               .name = DRV_NAME,
-               .owner = THIS_MODULE,
-       },
-       .probe = tegra_spdif_platform_probe,
-       .remove = __devexit_p(tegra_spdif_platform_remove),
-};
-
-module_platform_driver(tegra_spdif_driver);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Tegra SPDIF ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_spdif.h b/sound/soc/tegra/tegra_spdif.h
deleted file mode 100644 (file)
index 2e03db4..0000000
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * tegra_spdif.h - Definitions for Tegra SPDIF driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2011 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- * Copyright (c) 2008-2009, NVIDIA 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.
- *
- * 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 __TEGRA_SPDIF_H__
-#define __TEGRA_SPDIF_H__
-
-#include "tegra_pcm.h"
-
-/* Offsets from TEGRA_SPDIF_BASE */
-
-#define TEGRA_SPDIF_CTRL                                       0x0
-#define TEGRA_SPDIF_STATUS                                     0x4
-#define TEGRA_SPDIF_STROBE_CTRL                                        0x8
-#define TEGRA_SPDIF_DATA_FIFO_CSR                              0x0C
-#define TEGRA_SPDIF_DATA_OUT                                   0x40
-#define TEGRA_SPDIF_DATA_IN                                    0x80
-#define TEGRA_SPDIF_CH_STA_RX_A                                        0x100
-#define TEGRA_SPDIF_CH_STA_RX_B                                        0x104
-#define TEGRA_SPDIF_CH_STA_RX_C                                        0x108
-#define TEGRA_SPDIF_CH_STA_RX_D                                        0x10C
-#define TEGRA_SPDIF_CH_STA_RX_E                                        0x110
-#define TEGRA_SPDIF_CH_STA_RX_F                                        0x114
-#define TEGRA_SPDIF_CH_STA_TX_A                                        0x140
-#define TEGRA_SPDIF_CH_STA_TX_B                                        0x144
-#define TEGRA_SPDIF_CH_STA_TX_C                                        0x148
-#define TEGRA_SPDIF_CH_STA_TX_D                                        0x14C
-#define TEGRA_SPDIF_CH_STA_TX_E                                        0x150
-#define TEGRA_SPDIF_CH_STA_TX_F                                        0x154
-#define TEGRA_SPDIF_USR_STA_RX_A                               0x180
-#define TEGRA_SPDIF_USR_DAT_TX_A                               0x1C0
-
-/* Fields in TEGRA_SPDIF_CTRL */
-
-/* Start capturing from 0=right, 1=left channel */
-#define TEGRA_SPDIF_CTRL_CAP_LC                                        (1 << 30)
-
-/* SPDIF receiver(RX) enable */
-#define TEGRA_SPDIF_CTRL_RX_EN                                 (1 << 29)
-
-/* SPDIF Transmitter(TX) enable */
-#define TEGRA_SPDIF_CTRL_TX_EN                                 (1 << 28)
-
-/* Transmit Channel status */
-#define TEGRA_SPDIF_CTRL_TC_EN                                 (1 << 27)
-
-/* Transmit user Data */
-#define TEGRA_SPDIF_CTRL_TU_EN                                 (1 << 26)
-
-/* Interrupt on transmit error */
-#define TEGRA_SPDIF_CTRL_IE_TXE                                        (1 << 25)
-
-/* Interrupt on receive error */
-#define TEGRA_SPDIF_CTRL_IE_RXE                                        (1 << 24)
-
-/* Interrupt on invalid preamble */
-#define TEGRA_SPDIF_CTRL_IE_P                                  (1 << 23)
-
-/* Interrupt on "B" preamble */
-#define TEGRA_SPDIF_CTRL_IE_B                                  (1 << 22)
-
-/* Interrupt when block of channel status received */
-#define TEGRA_SPDIF_CTRL_IE_C                                  (1 << 21)
-
-/* Interrupt when a valid information unit (IU) is received */
-#define TEGRA_SPDIF_CTRL_IE_U                                  (1 << 20)
-
-/* Interrupt when RX user FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_RU                                 (1 << 19)
-
-/* Interrupt when TX user FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_TU                                 (1 << 18)
-
-/* Interrupt when RX data FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_RX                                 (1 << 17)
-
-/* Interrupt when TX data FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_TX                                 (1 << 16)
-
-/* Loopback test mode enable */
-#define TEGRA_SPDIF_CTRL_LBK_EN                                        (1 << 15)
-
-/*
- * Pack data mode:
- * 0 = Single data (16 bit needs to be  padded to match the
- *     interface data bit size).
- * 1 = Packeted left/right channel data into a single word.
- */
-#define TEGRA_SPDIF_CTRL_PACK                                  (1 << 14)
-
-/*
- * 00 = 16bit data
- * 01 = 20bit data
- * 10 = 24bit data
- * 11 = raw data
- */
-#define TEGRA_SPDIF_BIT_MODE_16BIT                             0
-#define TEGRA_SPDIF_BIT_MODE_20BIT                             1
-#define TEGRA_SPDIF_BIT_MODE_24BIT                             2
-#define TEGRA_SPDIF_BIT_MODE_RAW                               3
-
-#define TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT                                12
-#define TEGRA_SPDIF_CTRL_BIT_MODE_MASK                         (3                          << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_16BIT                                (TEGRA_SPDIF_BIT_MODE_16BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_20BIT                                (TEGRA_SPDIF_BIT_MODE_20BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_24BIT                                (TEGRA_SPDIF_BIT_MODE_24BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_RAW                          (TEGRA_SPDIF_BIT_MODE_RAW   << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-
-/* Fields in TEGRA_SPDIF_STATUS */
-
-/*
- * Note: IS_P, IS_B, IS_C, and IS_U are sticky bits. Software must
- * write a 1 to the corresponding bit location to clear the status.
- */
-
-/*
- * Receiver(RX) shifter is busy receiving data.
- * This bit is asserted when the receiver first locked onto the
- * preamble of the data stream after RX_EN is asserted. This bit is
- * deasserted when either,
- * (a) the end of a frame is reached after RX_EN is deeasserted, or
- * (b) the SPDIF data stream becomes inactive.
- */
-#define TEGRA_SPDIF_STATUS_RX_BSY                              (1 << 29)
-
-/*
- * Transmitter(TX) shifter is busy transmitting data.
- * This bit is asserted when TX_EN is asserted.
- * This bit is deasserted when the end of a frame is reached after
- * TX_EN is deasserted.
- */
-#define TEGRA_SPDIF_STATUS_TX_BSY                              (1 << 28)
-
-/*
- * TX is busy shifting out channel status.
- * This bit is asserted when both TX_EN and TC_EN are asserted and
- * data from CH_STA_TX_A register is loaded into the internal shifter.
- * This bit is deasserted when either,
- * (a) the end of a frame is reached after TX_EN is deasserted, or
- * (b) CH_STA_TX_F register is loaded into the internal shifter.
- */
-#define TEGRA_SPDIF_STATUS_TC_BSY                              (1 << 27)
-
-/*
- * TX User data FIFO busy.
- * This bit is asserted when TX_EN and TXU_EN are asserted and
- * there's data in the TX user FIFO.  This bit is deassert when either,
- * (a) the end of a frame is reached after TX_EN is deasserted, or
- * (b) there's no data left in the TX user FIFO.
- */
-#define TEGRA_SPDIF_STATUS_TU_BSY                              (1 << 26)
-
-/* TX FIFO Underrun error status */
-#define TEGRA_SPDIF_STATUS_TX_ERR                              (1 << 25)
-
-/* RX FIFO Overrun error status */
-#define TEGRA_SPDIF_STATUS_RX_ERR                              (1 << 24)
-
-/* Preamble status: 0=Preamble OK, 1=bad/missing preamble */
-#define TEGRA_SPDIF_STATUS_IS_P                                        (1 << 23)
-
-/* B-preamble detection status: 0=not detected, 1=B-preamble detected */
-#define TEGRA_SPDIF_STATUS_IS_B                                        (1 << 22)
-
-/*
- * RX channel block data receive status:
- * 0=entire block not recieved yet.
- * 1=received entire block of channel status,
- */
-#define TEGRA_SPDIF_STATUS_IS_C                                        (1 << 21)
-
-/* RX User Data Valid flag:  1=valid IU detected, 0 = no IU detected. */
-#define TEGRA_SPDIF_STATUS_IS_U                                        (1 << 20)
-
-/*
- * RX User FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_RU                               (1 << 19)
-
-/*
- * TX User FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_TU                               (1 << 18)
-
-/*
- * RX Data FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_RX                               (1 << 17)
-
-/*
- * TX Data FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_TX                               (1 << 16)
-
-/* Fields in TEGRA_SPDIF_STROBE_CTRL */
-
-/*
- * Indicates the approximate number of detected SPDIFIN clocks within a
- * bi-phase period.
- */
-#define TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT                   16
-#define TEGRA_SPDIF_STROBE_CTRL_PERIOD_MASK                    (0xff << TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT)
-
-/* Data strobe mode: 0=Auto-locked 1=Manual locked */
-#define TEGRA_SPDIF_STROBE_CTRL_STROBE                         (1 << 15)
-
-/*
- * Manual data strobe time within the bi-phase clock period (in terms of
- * the number of over-sampling clocks).
- */
-#define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT             8
-#define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_MASK              (0x1f << TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT)
-
-/*
- * Manual SPDIFIN bi-phase clock period (in terms of the number of
- * over-sampling clocks).
- */
-#define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT             0
-#define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK              (0x3f << TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT)
-
-/* Fields in SPDIF_DATA_FIFO_CSR */
-
-/* Clear Receiver User FIFO (RX USR.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_CLR                       (1 << 31)
-
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT                    0
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS                   1
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS                 2
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS                  3
-
-/* RU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT             29
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_MASK              \
-               (0x3                                    << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU1_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU2_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU3_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU4_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-
-/* Number of RX USR.FIFO levels with valid data. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT          24
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_MASK           (0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT)
-
-/* Clear Transmitter User FIFO (TX USR.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_CLR                       (1 << 23)
-
-/* TU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT             21
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_MASK              \
-               (0x3                                   << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU1_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT    << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU2_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU3_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU4_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-
-/* Number of TX USR.FIFO levels that could be filled. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT         16
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_MASK          (0x1f << SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT)
-
-/* Clear Receiver Data FIFO (RX DATA.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_CLR                       (1 << 15)
-
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT                    0
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS                  1
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS                 2
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS                        3
-
-/* RU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT             13
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_MASK              \
-               (0x3                                     << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU1_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU4_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU8_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU12_WORD_FULL    \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-
-/* Number of RX DATA.FIFO levels with valid data. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT          8
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_MASK           (0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT)
-
-/* Clear Transmitter Data FIFO (TX DATA.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_CLR                       (1 << 7)
-
-/* TU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT             5
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK              \
-               (0x3                                     << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU1_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT     << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS   << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU8_WORD_FULL     \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS  << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU12_WORD_FULL    \
-               (TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-
-/* Number of TX DATA.FIFO levels that could be filled. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT         0
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_MASK          (0x1f << SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT)
-
-/* Fields in TEGRA_SPDIF_DATA_OUT */
-
-/*
- * This register has 5 different formats:
- * 16-bit        (BIT_MODE=00, PACK=0)
- * 20-bit        (BIT_MODE=01, PACK=0)
- * 24-bit        (BIT_MODE=10, PACK=0)
- * raw           (BIT_MODE=11, PACK=0)
- * 16-bit packed (BIT_MODE=00, PACK=1)
- */
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT                     0
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_MASK                      (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT                     0
-#define TEGRA_SPDIF_DATA_OUT_DATA_20_MASK                      (0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT                     0
-#define TEGRA_SPDIF_DATA_OUT_DATA_24_MASK                      (0xffffff << TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_P                                (1 << 31)
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_C                                (1 << 30)
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_U                                (1 << 29)
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_V                                (1 << 28)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT               8
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_MASK                        (0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT                        4
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_MASK                 (0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT           0
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_MASK            (0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT                16
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_MASK         (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT         0
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_MASK          (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT)
-
-/* Fields in TEGRA_SPDIF_DATA_IN */
-
-/*
- * This register has 5 different formats:
- * 16-bit        (BIT_MODE=00, PACK=0)
- * 20-bit        (BIT_MODE=01, PACK=0)
- * 24-bit        (BIT_MODE=10, PACK=0)
- * raw           (BIT_MODE=11, PACK=0)
- * 16-bit packed (BIT_MODE=00, PACK=1)
- *
- * Bits 31:24 are common to all modes except 16-bit packed
- */
-
-#define TEGRA_SPDIF_DATA_IN_DATA_P                             (1 << 31)
-#define TEGRA_SPDIF_DATA_IN_DATA_C                             (1 << 30)
-#define TEGRA_SPDIF_DATA_IN_DATA_U                             (1 << 29)
-#define TEGRA_SPDIF_DATA_IN_DATA_V                             (1 << 28)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT                        24
-#define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_MASK                 (0xf << TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT                      0
-#define TEGRA_SPDIF_DATA_IN_DATA_16_MASK                       (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT                      0
-#define TEGRA_SPDIF_DATA_IN_DATA_20_MASK                       (0xfffff << TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT                      0
-#define TEGRA_SPDIF_DATA_IN_DATA_24_MASK                       (0xffffff << TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT                        8
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_MASK                 (0xfffff << TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT                 4
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_MASK                  (0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT            0
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_MASK             (0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT         16
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_MASK          (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT          0
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_MASK           (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT)
-
-/* Fields in TEGRA_SPDIF_CH_STA_RX_A */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_B */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_C */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_D */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_E */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_F */
-
-/*
- * The 6-word receive channel data page buffer holds a block (192 frames) of
- * channel status information. The order of receive is from LSB to MSB
- * bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A.
- */
-
-/* Fields in TEGRA_SPDIF_CH_STA_TX_A */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_B */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_C */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_D */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_E */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_F */
-
-/*
- * The 6-word transmit channel data page buffer holds a block (192 frames) of
- * channel status information. The order of transmission is from LSB to MSB
- * bit, and from CH_STA_TX_A to CH_STA_TX_F then back to CH_STA_TX_A.
- */
-
-/* Fields in TEGRA_SPDIF_USR_STA_RX_A */
-
-/*
- * This 4-word deep FIFO receives user FIFO field information. The order of
- * receive is from LSB to MSB bit.
- */
-
-/* Fields in TEGRA_SPDIF_USR_DAT_TX_A */
-
-/*
- * This 4-word deep FIFO transmits user FIFO field information. The order of
- * transmission is from LSB to MSB bit.
- */
-
-struct tegra_spdif {
-       struct clk *clk_spdif_out;
-       int clk_refs;
-       struct tegra_pcm_dma_params capture_dma_data;
-       struct tegra_pcm_dma_params playback_dma_data;
-       void __iomem *regs;
-       struct dentry *debug;
-       u32 reg_ctrl;
-};
-
-#endif
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
new file mode 100644 (file)
index 0000000..4e77026
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * tegra_wm8753.c - Tegra machine ASoC driver for boards using WM8753 codec.
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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 <asm/mach-types.h>
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/wm8753.h"
+
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-wm8753"
+
+struct tegra_wm8753 {
+       struct tegra_asoc_utils_data util_data;
+};
+
+static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_card *card = codec->card;
+       struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
+       int srate, mclk;
+       int err;
+
+       srate = params_rate(params);
+       switch (srate) {
+       case 11025:
+       case 22050:
+       case 44100:
+       case 88200:
+               mclk = 11289600;
+               break;
+       default:
+               mclk = 12288000;
+               break;
+       }
+
+       err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+       if (err < 0) {
+               dev_err(card->dev, "Can't configure clocks\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, mclk,
+                                       SND_SOC_CLOCK_IN);
+       if (err < 0) {
+               dev_err(card->dev, "codec_dai clock not set\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops tegra_wm8753_ops = {
+       .hw_params = tegra_wm8753_hw_params,
+};
+
+static const struct snd_soc_dapm_widget tegra_wm8753_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static struct snd_soc_dai_link tegra_wm8753_dai = {
+       .name = "WM8753",
+       .stream_name = "WM8753 PCM",
+       .codec_dai_name = "wm8753-hifi",
+       .ops = &tegra_wm8753_ops,
+       .dai_fmt = SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_tegra_wm8753 = {
+       .name = "tegra-wm8753",
+       .owner = THIS_MODULE,
+       .dai_link = &tegra_wm8753_dai,
+       .num_links = 1,
+
+       .dapm_widgets = tegra_wm8753_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tegra_wm8753_dapm_widgets),
+       .fully_routed = true,
+};
+
+static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &snd_soc_tegra_wm8753;
+       struct tegra_wm8753 *machine;
+       int ret;
+
+       machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8753),
+                              GFP_KERNEL);
+       if (!machine) {
+               dev_err(&pdev->dev, "Can't allocate tegra_wm8753 struct\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, machine);
+
+       ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+       if (ret)
+               goto err;
+
+       ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+       if (ret)
+               goto err;
+
+       tegra_wm8753_dai.codec_of_node = of_parse_phandle(
+                       pdev->dev.of_node, "nvidia,audio-codec", 0);
+       if (!tegra_wm8753_dai.codec_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,audio-codec' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_wm8753_dai.cpu_dai_of_node = of_parse_phandle(
+                       pdev->dev.of_node, "nvidia,i2s-controller", 0);
+       if (!tegra_wm8753_dai.cpu_dai_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,i2s-controller' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_wm8753_dai.platform_of_node =
+                               tegra_wm8753_dai.cpu_dai_of_node;
+
+       ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+       if (ret)
+               goto err;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+                       ret);
+               goto err_fini_utils;
+       }
+
+       return 0;
+
+err_fini_utils:
+       tegra_asoc_utils_fini(&machine->util_data);
+err:
+       return ret;
+}
+
+static int __devexit tegra_wm8753_driver_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
+
+       snd_soc_unregister_card(card);
+
+       tegra_asoc_utils_fini(&machine->util_data);
+
+       return 0;
+}
+
+static const struct of_device_id tegra_wm8753_of_match[] __devinitconst = {
+       { .compatible = "nvidia,tegra-audio-wm8753", },
+       {},
+};
+
+static struct platform_driver tegra_wm8753_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = tegra_wm8753_of_match,
+       },
+       .probe = tegra_wm8753_driver_probe,
+       .remove = __devexit_p(tegra_wm8753_driver_remove),
+};
+module_platform_driver(tegra_wm8753_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra+WM8753 machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_wm8753_of_match);
index 566655e23b7d18063f8e2e337647eec023fead2a..0b0df49d9d33b071118576c340b69366f212663f 100644 (file)
@@ -2,7 +2,7 @@
  * tegra_wm8903.c - Tegra machine ASoC driver for boards using WM8903 codec.
  *
  * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010-2011 - NVIDIA, Inc.
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
  *
  * Based on code copyright/by:
  *
@@ -46,9 +46,6 @@
 
 #include "../codecs/wm8903.h"
 
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
 #include "tegra_asoc_utils.h"
 
 #define DRV_NAME "tegra-snd-wm8903"
@@ -61,7 +58,6 @@
 
 struct tegra_wm8903 {
        struct tegra_wm8903_platform_data pdata;
-       struct platform_device *pcm_dev;
        struct tegra_asoc_utils_data util_data;
        int gpio_requested;
 };
@@ -354,8 +350,8 @@ static struct snd_soc_dai_link tegra_wm8903_dai = {
        .name = "WM8903",
        .stream_name = "WM8903 PCM",
        .codec_name = "wm8903.0-001a",
-       .platform_name = "tegra-pcm-audio",
-       .cpu_dai_name = "tegra-i2s.0",
+       .platform_name = "tegra20-i2s.0",
+       .cpu_dai_name = "tegra20-i2s.0",
        .codec_dai_name = "wm8903-hifi",
        .init = tegra_wm8903_init,
        .ops = &tegra_wm8903_ops,
@@ -392,7 +388,6 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto err;
        }
-       machine->pcm_dev = ERR_PTR(-EINVAL);
 
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
@@ -428,14 +423,9 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
                        goto err;
                }
 
-               machine->pcm_dev = platform_device_register_simple(
-                                       "tegra-pcm-audio", -1, NULL, 0);
-               if (IS_ERR(machine->pcm_dev)) {
-                       dev_err(&pdev->dev,
-                               "Can't instantiate tegra-pcm-audio\n");
-                       ret = PTR_ERR(machine->pcm_dev);
-                       goto err;
-               }
+               tegra_wm8903_dai.platform_name = NULL;
+               tegra_wm8903_dai.platform_of_node =
+                                       tegra_wm8903_dai.cpu_dai_of_node;
        } else {
                if (machine_is_harmony()) {
                        card->dapm_routes = harmony_audio_map;
@@ -454,7 +444,7 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
 
        ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
        if (ret)
-               goto err_unregister;
+               goto err;
 
        ret = snd_soc_register_card(card);
        if (ret) {
@@ -467,9 +457,6 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
 
 err_fini_utils:
        tegra_asoc_utils_fini(&machine->util_data);
-err_unregister:
-       if (!IS_ERR(machine->pcm_dev))
-               platform_device_unregister(machine->pcm_dev);
 err:
        return ret;
 }
@@ -497,8 +484,6 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
        snd_soc_unregister_card(card);
 
        tegra_asoc_utils_fini(&machine->util_data);
-       if (!IS_ERR(machine->pcm_dev))
-               platform_device_unregister(machine->pcm_dev);
 
        return 0;
 }
index 2bdfc550cff8a482958042b8d7151d8118d436b1..4a8d5b672c9ff5a018bd81c88a94167ea928e0b1 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/mach-types.h>
 
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
@@ -38,9 +39,6 @@
 
 #include "../codecs/tlv320aic23.h"
 
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
 #include "tegra_asoc_utils.h"
 
 #define DRV_NAME "tegra-snd-trimslice"
@@ -119,8 +117,8 @@ static struct snd_soc_dai_link trimslice_tlv320aic23_dai = {
        .name = "TLV320AIC23",
        .stream_name = "AIC23",
        .codec_name = "tlv320aic23-codec.2-001a",
-       .platform_name = "tegra-pcm-audio",
-       .cpu_dai_name = "tegra-i2s.0",
+       .platform_name = "tegra20-i2s.0",
+       .cpu_dai_name = "tegra20-i2s.0",
        .codec_dai_name = "tlv320aic23-hifi",
        .ops = &trimslice_asoc_ops,
 };
@@ -152,6 +150,32 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
                goto err;
        }
 
+       if (pdev->dev.of_node) {
+               trimslice_tlv320aic23_dai.codec_name = NULL;
+               trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle(
+                               pdev->dev.of_node, "nvidia,audio-codec", 0);
+               if (!trimslice_tlv320aic23_dai.codec_of_node) {
+                       dev_err(&pdev->dev,
+                               "Property 'nvidia,audio-codec' missing or invalid\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               trimslice_tlv320aic23_dai.cpu_dai_name = NULL;
+               trimslice_tlv320aic23_dai.cpu_dai_of_node = of_parse_phandle(
+                               pdev->dev.of_node, "nvidia,i2s-controller", 0);
+               if (!trimslice_tlv320aic23_dai.cpu_dai_of_node) {
+                       dev_err(&pdev->dev,
+                               "Property 'nvidia,i2s-controller' missing or invalid\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               trimslice_tlv320aic23_dai.platform_name = NULL;
+               trimslice_tlv320aic23_dai.platform_of_node =
+                               trimslice_tlv320aic23_dai.cpu_dai_of_node;
+       }
+
        ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
        if (ret)
                goto err;
@@ -187,10 +211,17 @@ static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id trimslice_of_match[] __devinitconst = {
+       { .compatible = "nvidia,tegra-audio-trimslice", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, trimslice_of_match);
+
 static struct platform_driver tegra_snd_trimslice_driver = {
        .driver = {
                .name = DRV_NAME,
                .owner = THIS_MODULE,
+               .of_match_table = trimslice_of_match,
        },
        .probe = tegra_snd_trimslice_probe,
        .remove = __devexit_p(tegra_snd_trimslice_remove),
diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig
new file mode 100644 (file)
index 0000000..44cf434
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Ux500 SoC audio configuration
+#
+menuconfig SND_SOC_UX500
+       tristate "SoC Audio support for Ux500 platform"
+       depends on SND_SOC
+       depends on MFD_DB8500_PRCMU
+       help
+               Say Y if you want to enable ASoC-support for
+               any of the Ux500 platforms (e.g. U8500).
+
+config SND_SOC_UX500_PLAT_MSP_I2S
+       tristate
+       depends on SND_SOC_UX500
diff --git a/sound/soc/ux500/Makefile b/sound/soc/ux500/Makefile
new file mode 100644 (file)
index 0000000..19974c5
--- /dev/null
@@ -0,0 +1,4 @@
+# Ux500 Platform Support
+
+snd-soc-ux500-plat-msp-i2s-objs := ux500_msp_dai.o ux500_msp_i2s.o
+obj-$(CONFIG_SND_SOC_UX500_PLAT_MSP_I2S) += snd-soc-ux500-plat-msp-i2s.o
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
new file mode 100644 (file)
index 0000000..93c6c40
--- /dev/null
@@ -0,0 +1,843 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can 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/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/dbx500-prcmu.h>
+
+#include <mach/hardware.h>
+#include <mach/board-mop500-msp.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "ux500_msp_i2s.h"
+#include "ux500_msp_dai.h"
+
+static int setup_pcm_multichan(struct snd_soc_dai *dai,
+                       struct ux500_msp_config *msp_config)
+{
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+       struct msp_multichannel_config *multi =
+                                       &msp_config->multichannel_config;
+
+       if (drvdata->slots > 1) {
+               msp_config->multichannel_configured = 1;
+
+               multi->tx_multichannel_enable = true;
+               multi->rx_multichannel_enable = true;
+               multi->rx_comparison_enable_mode = MSP_COMPARISON_DISABLED;
+
+               multi->tx_channel_0_enable = drvdata->tx_mask;
+               multi->tx_channel_1_enable = 0;
+               multi->tx_channel_2_enable = 0;
+               multi->tx_channel_3_enable = 0;
+
+               multi->rx_channel_0_enable = drvdata->rx_mask;
+               multi->rx_channel_1_enable = 0;
+               multi->rx_channel_2_enable = 0;
+               multi->rx_channel_3_enable = 0;
+
+               dev_dbg(dai->dev,
+                       "%s: Multichannel enabled. Slots: %d, TX: %u, RX: %u\n",
+                       __func__, drvdata->slots, multi->tx_channel_0_enable,
+                       multi->rx_channel_0_enable);
+       }
+
+       return 0;
+}
+
+static int setup_frameper(struct snd_soc_dai *dai, unsigned int rate,
+                       struct msp_protdesc *prot_desc)
+{
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+       switch (drvdata->slots) {
+       case 1:
+               switch (rate) {
+               case 8000:
+                       prot_desc->frame_period =
+                               FRAME_PER_SINGLE_SLOT_8_KHZ;
+                       break;
+
+               case 16000:
+                       prot_desc->frame_period =
+                               FRAME_PER_SINGLE_SLOT_16_KHZ;
+                       break;
+
+               case 44100:
+                       prot_desc->frame_period =
+                               FRAME_PER_SINGLE_SLOT_44_1_KHZ;
+                       break;
+
+               case 48000:
+                       prot_desc->frame_period =
+                               FRAME_PER_SINGLE_SLOT_48_KHZ;
+                       break;
+
+               default:
+                       dev_err(dai->dev,
+                               "%s: Error: Unsupported sample-rate (freq = %d)!\n",
+                               __func__, rate);
+                       return -EINVAL;
+               }
+               break;
+
+       case 2:
+               prot_desc->frame_period = FRAME_PER_2_SLOTS;
+               break;
+
+       case 8:
+               prot_desc->frame_period = FRAME_PER_8_SLOTS;
+               break;
+
+       case 16:
+               prot_desc->frame_period = FRAME_PER_16_SLOTS;
+               break;
+       default:
+               dev_err(dai->dev,
+                       "%s: Error: Unsupported slot-count (slots = %d)!\n",
+                       __func__, drvdata->slots);
+               return -EINVAL;
+       }
+
+       prot_desc->clocks_per_frame =
+                       prot_desc->frame_period+1;
+
+       dev_dbg(dai->dev, "%s: Clocks per frame: %u\n",
+               __func__,
+               prot_desc->clocks_per_frame);
+
+       return 0;
+}
+
+static int setup_pcm_framing(struct snd_soc_dai *dai, unsigned int rate,
+                       struct msp_protdesc *prot_desc)
+{
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+       u32 frame_length = MSP_FRAME_LEN_1;
+       prot_desc->frame_width = 0;
+
+       switch (drvdata->slots) {
+       case 1:
+               frame_length = MSP_FRAME_LEN_1;
+               break;
+
+       case 2:
+               frame_length = MSP_FRAME_LEN_2;
+               break;
+
+       case 8:
+               frame_length = MSP_FRAME_LEN_8;
+               break;
+
+       case 16:
+               frame_length = MSP_FRAME_LEN_16;
+               break;
+       default:
+               dev_err(dai->dev,
+                       "%s: Error: Unsupported slot-count (slots = %d)!\n",
+                       __func__, drvdata->slots);
+               return -EINVAL;
+       }
+
+       prot_desc->tx_frame_len_1 = frame_length;
+       prot_desc->rx_frame_len_1 = frame_length;
+       prot_desc->tx_frame_len_2 = frame_length;
+       prot_desc->rx_frame_len_2 = frame_length;
+
+       prot_desc->tx_elem_len_1 = MSP_ELEM_LEN_16;
+       prot_desc->rx_elem_len_1 = MSP_ELEM_LEN_16;
+       prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16;
+       prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16;
+
+       return setup_frameper(dai, rate, prot_desc);
+}
+
+static int setup_clocking(struct snd_soc_dai *dai,
+                       unsigned int fmt,
+                       struct ux500_msp_config *msp_config)
+{
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+
+       case SND_SOC_DAIFMT_NB_IF:
+               msp_config->tx_fsync_pol ^= 1 << TFSPOL_SHIFT;
+               msp_config->rx_fsync_pol ^= 1 << RFSPOL_SHIFT;
+
+               break;
+
+       default:
+               dev_err(dai->dev,
+                       "%s: Error: Unsopported inversion (fmt = 0x%x)!\n",
+                       __func__, fmt);
+
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               dev_dbg(dai->dev, "%s: Codec is master.\n", __func__);
+
+               msp_config->iodelay = 0x20;
+               msp_config->rx_fsync_sel = 0;
+               msp_config->tx_fsync_sel = 1 << TFSSEL_SHIFT;
+               msp_config->tx_clk_sel = 0;
+               msp_config->rx_clk_sel = 0;
+               msp_config->srg_clk_sel = 0x2 << SCKSEL_SHIFT;
+
+               break;
+
+       case SND_SOC_DAIFMT_CBS_CFS:
+               dev_dbg(dai->dev, "%s: Codec is slave.\n", __func__);
+
+               msp_config->tx_clk_sel = TX_CLK_SEL_SRG;
+               msp_config->tx_fsync_sel = TX_SYNC_SRG_PROG;
+               msp_config->rx_clk_sel = RX_CLK_SEL_SRG;
+               msp_config->rx_fsync_sel = RX_SYNC_SRG;
+               msp_config->srg_clk_sel = 1 << SCKSEL_SHIFT;
+
+               break;
+
+       default:
+               dev_err(dai->dev, "%s: Error: Unsopported master (fmt = 0x%x)!\n",
+                       __func__, fmt);
+
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int setup_pcm_protdesc(struct snd_soc_dai *dai,
+                               unsigned int fmt,
+                               struct msp_protdesc *prot_desc)
+{
+       prot_desc->rx_phase_mode = MSP_SINGLE_PHASE;
+       prot_desc->tx_phase_mode = MSP_SINGLE_PHASE;
+       prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE;
+       prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE;
+       prot_desc->rx_byte_order = MSP_BTF_MS_BIT_FIRST;
+       prot_desc->tx_byte_order = MSP_BTF_MS_BIT_FIRST;
+       prot_desc->tx_fsync_pol = MSP_FSYNC_POL(MSP_FSYNC_POL_ACT_HI);
+       prot_desc->rx_fsync_pol = MSP_FSYNC_POL_ACT_HI << RFSPOL_SHIFT;
+
+       if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A) {
+               dev_dbg(dai->dev, "%s: DSP_A.\n", __func__);
+               prot_desc->rx_clk_pol = MSP_RISING_EDGE;
+               prot_desc->tx_clk_pol = MSP_FALLING_EDGE;
+
+               prot_desc->rx_data_delay = MSP_DELAY_1;
+               prot_desc->tx_data_delay = MSP_DELAY_1;
+       } else {
+               dev_dbg(dai->dev, "%s: DSP_B.\n", __func__);
+               prot_desc->rx_clk_pol = MSP_FALLING_EDGE;
+               prot_desc->tx_clk_pol = MSP_RISING_EDGE;
+
+               prot_desc->rx_data_delay = MSP_DELAY_0;
+               prot_desc->tx_data_delay = MSP_DELAY_0;
+       }
+
+       prot_desc->rx_half_word_swap = MSP_SWAP_NONE;
+       prot_desc->tx_half_word_swap = MSP_SWAP_NONE;
+       prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR;
+       prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR;
+       prot_desc->frame_sync_ignore = MSP_FSYNC_IGNORE;
+
+       return 0;
+}
+
+static int setup_i2s_protdesc(struct msp_protdesc *prot_desc)
+{
+       prot_desc->rx_phase_mode = MSP_DUAL_PHASE;
+       prot_desc->tx_phase_mode = MSP_DUAL_PHASE;
+       prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_FSYNC;
+       prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_FSYNC;
+       prot_desc->rx_byte_order = MSP_BTF_MS_BIT_FIRST;
+       prot_desc->tx_byte_order = MSP_BTF_MS_BIT_FIRST;
+       prot_desc->tx_fsync_pol = MSP_FSYNC_POL(MSP_FSYNC_POL_ACT_LO);
+       prot_desc->rx_fsync_pol = MSP_FSYNC_POL_ACT_LO << RFSPOL_SHIFT;
+
+       prot_desc->rx_frame_len_1 = MSP_FRAME_LEN_1;
+       prot_desc->rx_frame_len_2 = MSP_FRAME_LEN_1;
+       prot_desc->tx_frame_len_1 = MSP_FRAME_LEN_1;
+       prot_desc->tx_frame_len_2 = MSP_FRAME_LEN_1;
+       prot_desc->rx_elem_len_1 = MSP_ELEM_LEN_16;
+       prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16;
+       prot_desc->tx_elem_len_1 = MSP_ELEM_LEN_16;
+       prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16;
+
+       prot_desc->rx_clk_pol = MSP_RISING_EDGE;
+       prot_desc->tx_clk_pol = MSP_FALLING_EDGE;
+
+       prot_desc->rx_data_delay = MSP_DELAY_0;
+       prot_desc->tx_data_delay = MSP_DELAY_0;
+
+       prot_desc->tx_half_word_swap = MSP_SWAP_NONE;
+       prot_desc->rx_half_word_swap = MSP_SWAP_NONE;
+       prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR;
+       prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR;
+       prot_desc->frame_sync_ignore = MSP_FSYNC_IGNORE;
+
+       return 0;
+}
+
+static int setup_msp_config(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *dai,
+                       struct ux500_msp_config *msp_config)
+{
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+       struct msp_protdesc *prot_desc = &msp_config->protdesc;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned int fmt = drvdata->fmt;
+       int ret;
+
+       memset(msp_config, 0, sizeof(*msp_config));
+
+       msp_config->f_inputclk = drvdata->master_clk;
+
+       msp_config->tx_fifo_config = TX_FIFO_ENABLE;
+       msp_config->rx_fifo_config = RX_FIFO_ENABLE;
+       msp_config->def_elem_len = 1;
+       msp_config->direction = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+                               MSP_DIR_TX : MSP_DIR_RX;
+       msp_config->data_size = MSP_DATA_BITS_32;
+       msp_config->frame_freq = runtime->rate;
+
+       dev_dbg(dai->dev, "%s: f_inputclk = %u, frame_freq = %u.\n",
+              __func__, msp_config->f_inputclk, msp_config->frame_freq);
+       /* To avoid division by zero */
+       prot_desc->clocks_per_frame = 1;
+
+       dev_dbg(dai->dev, "%s: rate: %u, channels: %d.\n", __func__,
+               runtime->rate, runtime->channels);
+       switch (fmt &
+               (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+               dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);
+
+               msp_config->default_protdesc = 1;
+               msp_config->protocol = MSP_I2S_PROTOCOL;
+               break;
+
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+               dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);
+
+               msp_config->data_size = MSP_DATA_BITS_16;
+               msp_config->protocol = MSP_I2S_PROTOCOL;
+
+               ret = setup_i2s_protdesc(prot_desc);
+               if (ret < 0)
+                       return ret;
+
+               break;
+
+       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
+               dev_dbg(dai->dev, "%s: PCM format.\n", __func__);
+
+               msp_config->data_size = MSP_DATA_BITS_16;
+               msp_config->protocol = MSP_PCM_PROTOCOL;
+
+               ret = setup_pcm_protdesc(dai, fmt, prot_desc);
+               if (ret < 0)
+                       return ret;
+
+               ret = setup_pcm_multichan(dai, msp_config);
+               if (ret < 0)
+                       return ret;
+
+               ret = setup_pcm_framing(dai, runtime->rate, prot_desc);
+               if (ret < 0)
+                       return ret;
+
+               break;
+
+       default:
+               dev_err(dai->dev, "%s: Error: Unsopported format (%d)!\n",
+                       __func__, fmt);
+               return -EINVAL;
+       }
+
+       return setup_clocking(dai, fmt, msp_config);
+}
+
+static int ux500_msp_dai_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       int ret = 0;
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+       dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
+               snd_pcm_stream_str(substream));
+
+       /* Enable regulator */
+       ret = regulator_enable(drvdata->reg_vape);
+       if (ret != 0) {
+               dev_err(drvdata->msp->dev,
+                       "%s: Failed to enable regulator!\n", __func__);
+               return ret;
+       }
+
+       /* Enable clock */
+       dev_dbg(dai->dev, "%s: Enabling MSP-clock.\n", __func__);
+       clk_enable(drvdata->clk);
+
+       return 0;
+}
+
+static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       int ret;
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+       bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+
+       dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
+               snd_pcm_stream_str(substream));
+
+       if (drvdata->vape_opp_constraint == 1) {
+               prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
+                                       "ux500_msp_i2s", 50);
+               drvdata->vape_opp_constraint = 0;
+       }
+
+       if (ux500_msp_i2s_close(drvdata->msp,
+                               is_playback ? MSP_DIR_TX : MSP_DIR_RX)) {
+               dev_err(dai->dev,
+                       "%s: Error: MSP %d (%s): Unable to close i2s.\n",
+                       __func__, dai->id, snd_pcm_stream_str(substream));
+       }
+
+       /* Disable clock */
+       clk_disable(drvdata->clk);
+
+       /* Disable regulator */
+       ret = regulator_disable(drvdata->reg_vape);
+       if (ret < 0)
+               dev_err(dai->dev,
+                       "%s: ERROR: Failed to disable regulator (%d)!\n",
+                       __func__, ret);
+}
+
+static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       int ret = 0;
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ux500_msp_config msp_config;
+
+       dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (rate = %d).\n", __func__,
+               dai->id, snd_pcm_stream_str(substream), runtime->rate);
+
+       setup_msp_config(substream, dai, &msp_config);
+
+       ret = ux500_msp_i2s_open(drvdata->msp, &msp_config);
+       if (ret < 0) {
+               dev_err(dai->dev, "%s: Error: msp_setup failed (ret = %d)!\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       /* Set OPP-level */
+       if ((drvdata->fmt & SND_SOC_DAIFMT_MASTER_MASK) &&
+               (drvdata->msp->f_bitclk > 19200000)) {
+               /* If the bit-clock is higher than 19.2MHz, Vape should be
+                * run in 100% OPP. Only when bit-clock is used (MSP master) */
+               prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
+                                       "ux500-msp-i2s", 100);
+               drvdata->vape_opp_constraint = 1;
+       } else {
+               prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
+                                       "ux500-msp-i2s", 50);
+               drvdata->vape_opp_constraint = 0;
+       }
+
+       return ret;
+}
+
+static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       unsigned int mask, slots_active;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+       dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n",
+                       __func__, dai->id, snd_pcm_stream_str(substream));
+
+       switch (drvdata->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               snd_pcm_hw_constraint_minmax(runtime,
+                               SNDRV_PCM_HW_PARAM_CHANNELS,
+                               1, 2);
+               break;
+
+       case SND_SOC_DAIFMT_DSP_B:
+       case SND_SOC_DAIFMT_DSP_A:
+               mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+                       drvdata->tx_mask :
+                       drvdata->rx_mask;
+
+               slots_active = hweight32(mask);
+               dev_dbg(dai->dev, "TDM-slots active: %d", slots_active);
+
+               snd_pcm_hw_constraint_minmax(runtime,
+                               SNDRV_PCM_HW_PARAM_CHANNELS,
+                               slots_active, slots_active);
+               break;
+
+       default:
+               dev_err(dai->dev,
+                       "%s: Error: Unsupported protocol (fmt = 0x%x)!\n",
+                       __func__, drvdata->fmt);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai,
+                               unsigned int fmt)
+{
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+       dev_dbg(dai->dev, "%s: MSP %d: Enter.\n", __func__, dai->id);
+
+       switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
+               SND_SOC_DAIFMT_MASTER_MASK)) {
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+               break;
+
+       default:
+               dev_err(dai->dev,
+                       "%s: Error: Unsupported protocol/master (fmt = 0x%x)!\n",
+                       __func__, drvdata->fmt);
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+       case SND_SOC_DAIFMT_NB_IF:
+       case SND_SOC_DAIFMT_IB_IF:
+               break;
+
+       default:
+               dev_err(dai->dev,
+                       "%s: Error: Unsupported inversion (fmt = 0x%x)!\n",
+                       __func__, drvdata->fmt);
+               return -EINVAL;
+       }
+
+       drvdata->fmt = fmt;
+       return 0;
+}
+
+static int ux500_msp_dai_set_tdm_slot(struct snd_soc_dai *dai,
+                               unsigned int tx_mask,
+                               unsigned int rx_mask,
+                               int slots, int slot_width)
+{
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+       unsigned int cap;
+
+       switch (slots) {
+       case 1:
+               cap = 0x01;
+               break;
+       case 2:
+               cap = 0x03;
+               break;
+       case 8:
+               cap = 0xFF;
+               break;
+       case 16:
+               cap = 0xFFFF;
+               break;
+       default:
+               dev_err(dai->dev, "%s: Error: Unsupported slot-count (%d)!\n",
+                       __func__, slots);
+               return -EINVAL;
+       }
+       drvdata->slots = slots;
+
+       if (!(slot_width == 16)) {
+               dev_err(dai->dev, "%s: Error: Unsupported slot-width (%d)!\n",
+                       __func__, slot_width);
+               return -EINVAL;
+       }
+       drvdata->slot_width = slot_width;
+
+       drvdata->tx_mask = tx_mask & cap;
+       drvdata->rx_mask = rx_mask & cap;
+
+       return 0;
+}
+
+static int ux500_msp_dai_set_dai_sysclk(struct snd_soc_dai *dai,
+                                       int clk_id, unsigned int freq, int dir)
+{
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+       dev_dbg(dai->dev, "%s: MSP %d: Enter. clk-id: %d, freq: %u.\n",
+               __func__, dai->id, clk_id, freq);
+
+       switch (clk_id) {
+       case UX500_MSP_MASTER_CLOCK:
+               drvdata->master_clk = freq;
+               break;
+
+       default:
+               dev_err(dai->dev, "%s: MSP %d: Invalid clk-id (%d)!\n",
+                       __func__, dai->id, clk_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream,
+                               int cmd, struct snd_soc_dai *dai)
+{
+       int ret = 0;
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+       dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (msp->id = %d, cmd = %d).\n",
+               __func__, dai->id, snd_pcm_stream_str(substream),
+               (int)drvdata->msp->id, cmd);
+
+       ret = ux500_msp_i2s_trigger(drvdata->msp, cmd, substream->stream);
+
+       return ret;
+}
+
+static int ux500_msp_dai_probe(struct snd_soc_dai *dai)
+{
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+       drvdata->playback_dma_data.dma_cfg = drvdata->msp->dma_cfg_tx;
+       drvdata->capture_dma_data.dma_cfg = drvdata->msp->dma_cfg_rx;
+
+       dai->playback_dma_data = &drvdata->playback_dma_data;
+       dai->capture_dma_data = &drvdata->capture_dma_data;
+
+       drvdata->playback_dma_data.data_size = drvdata->slot_width;
+       drvdata->capture_dma_data.data_size = drvdata->slot_width;
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
+       {
+               .set_sysclk = ux500_msp_dai_set_dai_sysclk,
+               .set_fmt = ux500_msp_dai_set_dai_fmt,
+               .set_tdm_slot = ux500_msp_dai_set_tdm_slot,
+               .startup = ux500_msp_dai_startup,
+               .shutdown = ux500_msp_dai_shutdown,
+               .prepare = ux500_msp_dai_prepare,
+               .trigger = ux500_msp_dai_trigger,
+               .hw_params = ux500_msp_dai_hw_params,
+       }
+};
+
+static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
+       {
+               .name = "ux500-msp-i2s.0",
+               .probe = ux500_msp_dai_probe,
+               .id = 0,
+               .suspend = NULL,
+               .resume = NULL,
+               .playback = {
+                       .channels_min = UX500_MSP_MIN_CHANNELS,
+                       .channels_max = UX500_MSP_MAX_CHANNELS,
+                       .rates = UX500_I2S_RATES,
+                       .formats = UX500_I2S_FORMATS,
+               },
+               .capture = {
+                       .channels_min = UX500_MSP_MIN_CHANNELS,
+                       .channels_max = UX500_MSP_MAX_CHANNELS,
+                       .rates = UX500_I2S_RATES,
+                       .formats = UX500_I2S_FORMATS,
+               },
+               .ops = ux500_msp_dai_ops,
+       },
+       {
+               .name = "ux500-msp-i2s.1",
+               .probe = ux500_msp_dai_probe,
+               .id = 1,
+               .suspend = NULL,
+               .resume = NULL,
+               .playback = {
+                       .channels_min = UX500_MSP_MIN_CHANNELS,
+                       .channels_max = UX500_MSP_MAX_CHANNELS,
+                       .rates = UX500_I2S_RATES,
+                       .formats = UX500_I2S_FORMATS,
+               },
+               .capture = {
+                       .channels_min = UX500_MSP_MIN_CHANNELS,
+                       .channels_max = UX500_MSP_MAX_CHANNELS,
+                       .rates = UX500_I2S_RATES,
+                       .formats = UX500_I2S_FORMATS,
+               },
+               .ops = ux500_msp_dai_ops,
+       },
+       {
+               .name = "ux500-msp-i2s.2",
+               .id = 2,
+               .probe = ux500_msp_dai_probe,
+               .suspend = NULL,
+               .resume = NULL,
+               .playback = {
+                       .channels_min = UX500_MSP_MIN_CHANNELS,
+                       .channels_max = UX500_MSP_MAX_CHANNELS,
+                       .rates = UX500_I2S_RATES,
+                       .formats = UX500_I2S_FORMATS,
+               },
+               .capture = {
+                       .channels_min = UX500_MSP_MIN_CHANNELS,
+                       .channels_max = UX500_MSP_MAX_CHANNELS,
+                       .rates = UX500_I2S_RATES,
+                       .formats = UX500_I2S_FORMATS,
+               },
+               .ops = ux500_msp_dai_ops,
+       },
+       {
+               .name = "ux500-msp-i2s.3",
+               .probe = ux500_msp_dai_probe,
+               .id = 3,
+               .suspend = NULL,
+               .resume = NULL,
+               .playback = {
+                       .channels_min = UX500_MSP_MIN_CHANNELS,
+                       .channels_max = UX500_MSP_MAX_CHANNELS,
+                       .rates = UX500_I2S_RATES,
+                       .formats = UX500_I2S_FORMATS,
+               },
+               .capture = {
+                       .channels_min = UX500_MSP_MIN_CHANNELS,
+                       .channels_max = UX500_MSP_MAX_CHANNELS,
+                       .rates = UX500_I2S_RATES,
+                       .formats = UX500_I2S_FORMATS,
+               },
+               .ops = ux500_msp_dai_ops,
+       },
+};
+
+static int __devinit ux500_msp_drv_probe(struct platform_device *pdev)
+{
+       struct ux500_msp_i2s_drvdata *drvdata;
+       int ret = 0;
+
+       dev_dbg(&pdev->dev, "%s: Enter (pdev->name = %s).\n", __func__,
+               pdev->name);
+
+       drvdata = devm_kzalloc(&pdev->dev,
+                               sizeof(struct ux500_msp_i2s_drvdata),
+                               GFP_KERNEL);
+       drvdata->fmt = 0;
+       drvdata->slots = 1;
+       drvdata->tx_mask = 0x01;
+       drvdata->rx_mask = 0x01;
+       drvdata->slot_width = 16;
+       drvdata->master_clk = MSP_INPUT_FREQ_APB;
+
+       drvdata->reg_vape = devm_regulator_get(&pdev->dev, "v-ape");
+       if (IS_ERR(drvdata->reg_vape)) {
+               ret = (int)PTR_ERR(drvdata->reg_vape);
+               dev_err(&pdev->dev,
+                       "%s: ERROR: Failed to get Vape supply (%d)!\n",
+                       __func__, ret);
+               return ret;
+       }
+       prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50);
+
+       drvdata->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(drvdata->clk)) {
+               ret = (int)PTR_ERR(drvdata->clk);
+               dev_err(&pdev->dev, "%s: ERROR: clk_get failed (%d)!\n",
+                       __func__, ret);
+               goto err_clk;
+       }
+
+       ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp,
+                               pdev->dev.platform_data);
+       if (!drvdata->msp) {
+               dev_err(&pdev->dev,
+                       "%s: ERROR: Failed to init MSP-struct (%d)!",
+                       __func__, ret);
+               goto err_init_msp;
+       }
+       dev_set_drvdata(&pdev->dev, drvdata);
+
+       ret = snd_soc_register_dai(&pdev->dev,
+                               &ux500_msp_dai_drv[drvdata->msp->id]);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n",
+                       __func__, drvdata->msp->id);
+               goto err_init_msp;
+       }
+
+       return 0;
+
+err_init_msp:
+       clk_put(drvdata->clk);
+
+err_clk:
+       devm_regulator_put(drvdata->reg_vape);
+
+       return ret;
+}
+
+static int __devexit ux500_msp_drv_remove(struct platform_device *pdev)
+{
+       struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
+
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv));
+
+       devm_regulator_put(drvdata->reg_vape);
+       prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");
+
+       clk_put(drvdata->clk);
+
+       ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp);
+
+       return 0;
+}
+
+static struct platform_driver msp_i2s_driver = {
+       .driver = {
+               .name = "ux500-msp-i2s",
+               .owner = THIS_MODULE,
+       },
+       .probe = ux500_msp_drv_probe,
+       .remove = ux500_msp_drv_remove,
+};
+module_platform_driver(msp_i2s_driver);
+
+MODULE_LICENSE("GPLv2");
diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h
new file mode 100644 (file)
index 0000000..98202a3
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can 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 UX500_msp_dai_H
+#define UX500_msp_dai_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+#include "ux500_msp_i2s.h"
+
+#define UX500_NBR_OF_DAI       4
+
+#define UX500_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |  \
+                       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define UX500_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+#define FRAME_PER_SINGLE_SLOT_8_KHZ            31
+#define FRAME_PER_SINGLE_SLOT_16_KHZ   124
+#define FRAME_PER_SINGLE_SLOT_44_1_KHZ 63
+#define FRAME_PER_SINGLE_SLOT_48_KHZ   49
+#define FRAME_PER_2_SLOTS                              31
+#define FRAME_PER_8_SLOTS                              138
+#define FRAME_PER_16_SLOTS                             277
+
+#ifndef CONFIG_SND_SOC_UX500_AB5500
+#define UX500_MSP_INTERNAL_CLOCK_FREQ  40000000
+#define UX500_MSP1_INTERNAL_CLOCK_FREQ UX500_MSP_INTERNAL_CLOCK_FREQ
+#else
+#define UX500_MSP_INTERNAL_CLOCK_FREQ 13000000
+#define UX500_MSP1_INTERNAL_CLOCK_FREQ (UX500_MSP_INTERNAL_CLOCK_FREQ * 2)
+#endif
+
+#define UX500_MSP_MIN_CHANNELS         1
+#define UX500_MSP_MAX_CHANNELS         8
+
+#define PLAYBACK_CONFIGURED            1
+#define CAPTURE_CONFIGURED             2
+
+enum ux500_msp_clock_id {
+       UX500_MSP_MASTER_CLOCK,
+};
+
+struct ux500_msp_i2s_drvdata {
+       struct ux500_msp *msp;
+       struct regulator *reg_vape;
+       struct ux500_msp_dma_params playback_dma_data;
+       struct ux500_msp_dma_params capture_dma_data;
+       unsigned int fmt;
+       unsigned int tx_mask;
+       unsigned int rx_mask;
+       int slots;
+       int slot_width;
+       u8 configured;
+       int data_delay;
+
+       /* Clocks */
+       unsigned int master_clk;
+       struct clk *clk;
+
+       /* Regulators */
+       int vape_opp_constraint;
+};
+
+int ux500_msp_dai_set_data_delay(struct snd_soc_dai *dai, int delay);
+
+#endif
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c
new file mode 100644 (file)
index 0000000..496dec1
--- /dev/null
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>,
+ *         Sandeep Kaushik <sandeep.kaushik@st.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can 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/platform_device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+#include <mach/board-mop500-msp.h>
+
+#include <sound/soc.h>
+
+#include "ux500_msp_i2s.h"
+
+ /* Protocol desciptors */
+static const struct msp_protdesc prot_descs[] = {
+       { /* I2S */
+               MSP_SINGLE_PHASE,
+               MSP_SINGLE_PHASE,
+               MSP_PHASE2_START_MODE_IMEDIATE,
+               MSP_PHASE2_START_MODE_IMEDIATE,
+               MSP_BTF_MS_BIT_FIRST,
+               MSP_BTF_MS_BIT_FIRST,
+               MSP_FRAME_LEN_1,
+               MSP_FRAME_LEN_1,
+               MSP_FRAME_LEN_1,
+               MSP_FRAME_LEN_1,
+               MSP_ELEM_LEN_32,
+               MSP_ELEM_LEN_32,
+               MSP_ELEM_LEN_32,
+               MSP_ELEM_LEN_32,
+               MSP_DELAY_1,
+               MSP_DELAY_1,
+               MSP_RISING_EDGE,
+               MSP_FALLING_EDGE,
+               MSP_FSYNC_POL_ACT_LO,
+               MSP_FSYNC_POL_ACT_LO,
+               MSP_SWAP_NONE,
+               MSP_SWAP_NONE,
+               MSP_COMPRESS_MODE_LINEAR,
+               MSP_EXPAND_MODE_LINEAR,
+               MSP_FSYNC_IGNORE,
+               31,
+               15,
+               32,
+       }, { /* PCM */
+               MSP_DUAL_PHASE,
+               MSP_DUAL_PHASE,
+               MSP_PHASE2_START_MODE_FSYNC,
+               MSP_PHASE2_START_MODE_FSYNC,
+               MSP_BTF_MS_BIT_FIRST,
+               MSP_BTF_MS_BIT_FIRST,
+               MSP_FRAME_LEN_1,
+               MSP_FRAME_LEN_1,
+               MSP_FRAME_LEN_1,
+               MSP_FRAME_LEN_1,
+               MSP_ELEM_LEN_16,
+               MSP_ELEM_LEN_16,
+               MSP_ELEM_LEN_16,
+               MSP_ELEM_LEN_16,
+               MSP_DELAY_0,
+               MSP_DELAY_0,
+               MSP_RISING_EDGE,
+               MSP_FALLING_EDGE,
+               MSP_FSYNC_POL_ACT_HI,
+               MSP_FSYNC_POL_ACT_HI,
+               MSP_SWAP_NONE,
+               MSP_SWAP_NONE,
+               MSP_COMPRESS_MODE_LINEAR,
+               MSP_EXPAND_MODE_LINEAR,
+               MSP_FSYNC_IGNORE,
+               255,
+               0,
+               256,
+       }, { /* Companded PCM */
+               MSP_SINGLE_PHASE,
+               MSP_SINGLE_PHASE,
+               MSP_PHASE2_START_MODE_FSYNC,
+               MSP_PHASE2_START_MODE_FSYNC,
+               MSP_BTF_MS_BIT_FIRST,
+               MSP_BTF_MS_BIT_FIRST,
+               MSP_FRAME_LEN_1,
+               MSP_FRAME_LEN_1,
+               MSP_FRAME_LEN_1,
+               MSP_FRAME_LEN_1,
+               MSP_ELEM_LEN_8,
+               MSP_ELEM_LEN_8,
+               MSP_ELEM_LEN_8,
+               MSP_ELEM_LEN_8,
+               MSP_DELAY_0,
+               MSP_DELAY_0,
+               MSP_RISING_EDGE,
+               MSP_RISING_EDGE,
+               MSP_FSYNC_POL_ACT_HI,
+               MSP_FSYNC_POL_ACT_HI,
+               MSP_SWAP_NONE,
+               MSP_SWAP_NONE,
+               MSP_COMPRESS_MODE_LINEAR,
+               MSP_EXPAND_MODE_LINEAR,
+               MSP_FSYNC_IGNORE,
+               255,
+               0,
+               256,
+       },
+};
+
+static void set_prot_desc_tx(struct ux500_msp *msp,
+                       struct msp_protdesc *protdesc,
+                       enum msp_data_size data_size)
+{
+       u32 temp_reg = 0;
+
+       temp_reg |= MSP_P2_ENABLE_BIT(protdesc->tx_phase_mode);
+       temp_reg |= MSP_P2_START_MODE_BIT(protdesc->tx_phase2_start_mode);
+       temp_reg |= MSP_P1_FRAME_LEN_BITS(protdesc->tx_frame_len_1);
+       temp_reg |= MSP_P2_FRAME_LEN_BITS(protdesc->tx_frame_len_2);
+       if (msp->def_elem_len) {
+               temp_reg |= MSP_P1_ELEM_LEN_BITS(protdesc->tx_elem_len_1);
+               temp_reg |= MSP_P2_ELEM_LEN_BITS(protdesc->tx_elem_len_2);
+       } else {
+               temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
+               temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
+       }
+       temp_reg |= MSP_DATA_DELAY_BITS(protdesc->tx_data_delay);
+       temp_reg |= MSP_SET_ENDIANNES_BIT(protdesc->tx_byte_order);
+       temp_reg |= MSP_FSYNC_POL(protdesc->tx_fsync_pol);
+       temp_reg |= MSP_DATA_WORD_SWAP(protdesc->tx_half_word_swap);
+       temp_reg |= MSP_SET_COMPANDING_MODE(protdesc->compression_mode);
+       temp_reg |= MSP_SET_FSYNC_IGNORE(protdesc->frame_sync_ignore);
+
+       writel(temp_reg, msp->registers + MSP_TCF);
+}
+
+static void set_prot_desc_rx(struct ux500_msp *msp,
+                       struct msp_protdesc *protdesc,
+                       enum msp_data_size data_size)
+{
+       u32 temp_reg = 0;
+
+       temp_reg |= MSP_P2_ENABLE_BIT(protdesc->rx_phase_mode);
+       temp_reg |= MSP_P2_START_MODE_BIT(protdesc->rx_phase2_start_mode);
+       temp_reg |= MSP_P1_FRAME_LEN_BITS(protdesc->rx_frame_len_1);
+       temp_reg |= MSP_P2_FRAME_LEN_BITS(protdesc->rx_frame_len_2);
+       if (msp->def_elem_len) {
+               temp_reg |= MSP_P1_ELEM_LEN_BITS(protdesc->rx_elem_len_1);
+               temp_reg |= MSP_P2_ELEM_LEN_BITS(protdesc->rx_elem_len_2);
+       } else {
+               temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
+               temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
+       }
+
+       temp_reg |= MSP_DATA_DELAY_BITS(protdesc->rx_data_delay);
+       temp_reg |= MSP_SET_ENDIANNES_BIT(protdesc->rx_byte_order);
+       temp_reg |= MSP_FSYNC_POL(protdesc->rx_fsync_pol);
+       temp_reg |= MSP_DATA_WORD_SWAP(protdesc->rx_half_word_swap);
+       temp_reg |= MSP_SET_COMPANDING_MODE(protdesc->expansion_mode);
+       temp_reg |= MSP_SET_FSYNC_IGNORE(protdesc->frame_sync_ignore);
+
+       writel(temp_reg, msp->registers + MSP_RCF);
+}
+
+static int configure_protocol(struct ux500_msp *msp,
+                       struct ux500_msp_config *config)
+{
+       struct msp_protdesc *protdesc;
+       enum msp_data_size data_size;
+       u32 temp_reg = 0;
+
+       data_size = config->data_size;
+       msp->def_elem_len = config->def_elem_len;
+       if (config->default_protdesc == 1) {
+               if (config->protocol >= MSP_INVALID_PROTOCOL) {
+                       dev_err(msp->dev, "%s: ERROR: Invalid protocol!\n",
+                               __func__);
+                       return -EINVAL;
+               }
+               protdesc =
+                   (struct msp_protdesc *)&prot_descs[config->protocol];
+       } else {
+               protdesc = (struct msp_protdesc *)&config->protdesc;
+       }
+
+       if (data_size < MSP_DATA_BITS_DEFAULT || data_size > MSP_DATA_BITS_32) {
+               dev_err(msp->dev,
+                       "%s: ERROR: Invalid data-size requested (data_size = %d)!\n",
+                       __func__, data_size);
+               return -EINVAL;
+       }
+
+       if (config->direction & MSP_DIR_TX)
+               set_prot_desc_tx(msp, protdesc, data_size);
+       if (config->direction & MSP_DIR_RX)
+               set_prot_desc_rx(msp, protdesc, data_size);
+
+       /* The code below should not be separated. */
+       temp_reg = readl(msp->registers + MSP_GCR) & ~TX_CLK_POL_RISING;
+       temp_reg |= MSP_TX_CLKPOL_BIT(~protdesc->tx_clk_pol);
+       writel(temp_reg, msp->registers + MSP_GCR);
+       temp_reg = readl(msp->registers + MSP_GCR) & ~RX_CLK_POL_RISING;
+       temp_reg |= MSP_RX_CLKPOL_BIT(protdesc->rx_clk_pol);
+       writel(temp_reg, msp->registers + MSP_GCR);
+
+       return 0;
+}
+
+static int setup_bitclk(struct ux500_msp *msp, struct ux500_msp_config *config)
+{
+       u32 reg_val_GCR;
+       u32 frame_per = 0;
+       u32 sck_div = 0;
+       u32 frame_width = 0;
+       u32 temp_reg = 0;
+       struct msp_protdesc *protdesc = NULL;
+
+       reg_val_GCR = readl(msp->registers + MSP_GCR);
+       writel(reg_val_GCR & ~SRG_ENABLE, msp->registers + MSP_GCR);
+
+       if (config->default_protdesc)
+               protdesc =
+                       (struct msp_protdesc *)&prot_descs[config->protocol];
+       else
+               protdesc = (struct msp_protdesc *)&config->protdesc;
+
+       switch (config->protocol) {
+       case MSP_PCM_PROTOCOL:
+       case MSP_PCM_COMPAND_PROTOCOL:
+               frame_width = protdesc->frame_width;
+               sck_div = config->f_inputclk / (config->frame_freq *
+                       (protdesc->clocks_per_frame));
+               frame_per = protdesc->frame_period;
+               break;
+       case MSP_I2S_PROTOCOL:
+               frame_width = protdesc->frame_width;
+               sck_div = config->f_inputclk / (config->frame_freq *
+                       (protdesc->clocks_per_frame));
+               frame_per = protdesc->frame_period;
+               break;
+       default:
+               dev_err(msp->dev, "%s: ERROR: Unknown protocol (%d)!\n",
+                       __func__,
+                       config->protocol);
+               return -EINVAL;
+       }
+
+       temp_reg = (sck_div - 1) & SCK_DIV_MASK;
+       temp_reg |= FRAME_WIDTH_BITS(frame_width);
+       temp_reg |= FRAME_PERIOD_BITS(frame_per);
+       writel(temp_reg, msp->registers + MSP_SRG);
+
+       msp->f_bitclk = (config->f_inputclk)/(sck_div + 1);
+
+       /* Enable bit-clock */
+       udelay(100);
+       reg_val_GCR = readl(msp->registers + MSP_GCR);
+       writel(reg_val_GCR | SRG_ENABLE, msp->registers + MSP_GCR);
+       udelay(100);
+
+       return 0;
+}
+
+static int configure_multichannel(struct ux500_msp *msp,
+                               struct ux500_msp_config *config)
+{
+       struct msp_protdesc *protdesc;
+       struct msp_multichannel_config *mcfg;
+       u32 reg_val_MCR;
+
+       if (config->default_protdesc == 1) {
+               if (config->protocol >= MSP_INVALID_PROTOCOL) {
+                       dev_err(msp->dev,
+                               "%s: ERROR: Invalid protocol (%d)!\n",
+                               __func__, config->protocol);
+                       return -EINVAL;
+               }
+               protdesc = (struct msp_protdesc *)
+                               &prot_descs[config->protocol];
+       } else {
+               protdesc = (struct msp_protdesc *)&config->protdesc;
+       }
+
+       mcfg = &config->multichannel_config;
+       if (mcfg->tx_multichannel_enable) {
+               if (protdesc->tx_phase_mode == MSP_SINGLE_PHASE) {
+                       reg_val_MCR = readl(msp->registers + MSP_MCR);
+                       writel(reg_val_MCR | (mcfg->tx_multichannel_enable ?
+                                               1 << TMCEN_BIT : 0),
+                               msp->registers + MSP_MCR);
+                       writel(mcfg->tx_channel_0_enable,
+                               msp->registers + MSP_TCE0);
+                       writel(mcfg->tx_channel_1_enable,
+                               msp->registers + MSP_TCE1);
+                       writel(mcfg->tx_channel_2_enable,
+                               msp->registers + MSP_TCE2);
+                       writel(mcfg->tx_channel_3_enable,
+                               msp->registers + MSP_TCE3);
+               } else {
+                       dev_err(msp->dev,
+                               "%s: ERROR: Only single-phase supported (TX-mode: %d)!\n",
+                               __func__, protdesc->tx_phase_mode);
+                       return -EINVAL;
+               }
+       }
+       if (mcfg->rx_multichannel_enable) {
+               if (protdesc->rx_phase_mode == MSP_SINGLE_PHASE) {
+                       reg_val_MCR = readl(msp->registers + MSP_MCR);
+                       writel(reg_val_MCR | (mcfg->rx_multichannel_enable ?
+                                               1 << RMCEN_BIT : 0),
+                               msp->registers + MSP_MCR);
+                       writel(mcfg->rx_channel_0_enable,
+                                       msp->registers + MSP_RCE0);
+                       writel(mcfg->rx_channel_1_enable,
+                                       msp->registers + MSP_RCE1);
+                       writel(mcfg->rx_channel_2_enable,
+                                       msp->registers + MSP_RCE2);
+                       writel(mcfg->rx_channel_3_enable,
+                                       msp->registers + MSP_RCE3);
+               } else {
+                       dev_err(msp->dev,
+                               "%s: ERROR: Only single-phase supported (RX-mode: %d)!\n",
+                               __func__, protdesc->rx_phase_mode);
+                       return -EINVAL;
+               }
+               if (mcfg->rx_comparison_enable_mode) {
+                       reg_val_MCR = readl(msp->registers + MSP_MCR);
+                       writel(reg_val_MCR |
+                               (mcfg->rx_comparison_enable_mode << RCMPM_BIT),
+                               msp->registers + MSP_MCR);
+
+                       writel(mcfg->comparison_mask,
+                                       msp->registers + MSP_RCM);
+                       writel(mcfg->comparison_value,
+                                       msp->registers + MSP_RCV);
+
+               }
+       }
+
+       return 0;
+}
+
+static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
+{
+       int status = 0;
+       u32 reg_val_DMACR, reg_val_GCR;
+
+       /* Check msp state whether in RUN or CONFIGURED Mode */
+       if ((msp->msp_state == MSP_STATE_IDLE) && (msp->plat_init)) {
+               status = msp->plat_init();
+               if (status) {
+                       dev_err(msp->dev, "%s: ERROR: Failed to init MSP (%d)!\n",
+                               __func__, status);
+                       return status;
+               }
+       }
+
+       /* Configure msp with protocol dependent settings */
+       configure_protocol(msp, config);
+       setup_bitclk(msp, config);
+       if (config->multichannel_configured == 1) {
+               status = configure_multichannel(msp, config);
+               if (status)
+                       dev_warn(msp->dev,
+                               "%s: WARN: configure_multichannel failed (%d)!\n",
+                               __func__, status);
+       }
+
+       /* Make sure the correct DMA-directions are configured */
+       if ((config->direction & MSP_DIR_RX) && (!msp->dma_cfg_rx)) {
+               dev_err(msp->dev, "%s: ERROR: MSP RX-mode is not configured!",
+                       __func__);
+               return -EINVAL;
+       }
+       if ((config->direction == MSP_DIR_TX) && (!msp->dma_cfg_tx)) {
+               dev_err(msp->dev, "%s: ERROR: MSP TX-mode is not configured!",
+                       __func__);
+               return -EINVAL;
+       }
+
+       reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+       if (config->direction & MSP_DIR_RX)
+               reg_val_DMACR |= RX_DMA_ENABLE;
+       if (config->direction & MSP_DIR_TX)
+               reg_val_DMACR |= TX_DMA_ENABLE;
+       writel(reg_val_DMACR, msp->registers + MSP_DMACR);
+
+       writel(config->iodelay, msp->registers + MSP_IODLY);
+
+       /* Enable frame generation logic */
+       reg_val_GCR = readl(msp->registers + MSP_GCR);
+       writel(reg_val_GCR | FRAME_GEN_ENABLE, msp->registers + MSP_GCR);
+
+       return status;
+}
+
+static void flush_fifo_rx(struct ux500_msp *msp)
+{
+       u32 reg_val_DR, reg_val_GCR, reg_val_FLR;
+       u32 limit = 32;
+
+       reg_val_GCR = readl(msp->registers + MSP_GCR);
+       writel(reg_val_GCR | RX_ENABLE, msp->registers + MSP_GCR);
+
+       reg_val_FLR = readl(msp->registers + MSP_FLR);
+       while (!(reg_val_FLR & RX_FIFO_EMPTY) && limit--) {
+               reg_val_DR = readl(msp->registers + MSP_DR);
+               reg_val_FLR = readl(msp->registers + MSP_FLR);
+       }
+
+       writel(reg_val_GCR, msp->registers + MSP_GCR);
+}
+
+static void flush_fifo_tx(struct ux500_msp *msp)
+{
+       u32 reg_val_TSTDR, reg_val_GCR, reg_val_FLR;
+       u32 limit = 32;
+
+       reg_val_GCR = readl(msp->registers + MSP_GCR);
+       writel(reg_val_GCR | TX_ENABLE, msp->registers + MSP_GCR);
+       writel(MSP_ITCR_ITEN | MSP_ITCR_TESTFIFO, msp->registers + MSP_ITCR);
+
+       reg_val_FLR = readl(msp->registers + MSP_FLR);
+       while (!(reg_val_FLR & TX_FIFO_EMPTY) && limit--) {
+               reg_val_TSTDR = readl(msp->registers + MSP_TSTDR);
+               reg_val_FLR = readl(msp->registers + MSP_FLR);
+       }
+       writel(0x0, msp->registers + MSP_ITCR);
+       writel(reg_val_GCR, msp->registers + MSP_GCR);
+}
+
+int ux500_msp_i2s_open(struct ux500_msp *msp,
+               struct ux500_msp_config *config)
+{
+       u32 old_reg, new_reg, mask;
+       int res;
+       unsigned int tx_sel, rx_sel, tx_busy, rx_busy;
+
+       if (in_interrupt()) {
+               dev_err(msp->dev,
+                       "%s: ERROR: Open called in interrupt context!\n",
+                       __func__);
+               return -1;
+       }
+
+       tx_sel = (config->direction & MSP_DIR_TX) > 0;
+       rx_sel = (config->direction & MSP_DIR_RX) > 0;
+       if (!tx_sel && !rx_sel) {
+               dev_err(msp->dev, "%s: Error: No direction selected!\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       tx_busy = (msp->dir_busy & MSP_DIR_TX) > 0;
+       rx_busy = (msp->dir_busy & MSP_DIR_RX) > 0;
+       if (tx_busy && tx_sel) {
+               dev_err(msp->dev, "%s: Error: TX is in use!\n", __func__);
+               return -EBUSY;
+       }
+       if (rx_busy && rx_sel) {
+               dev_err(msp->dev, "%s: Error: RX is in use!\n", __func__);
+               return -EBUSY;
+       }
+
+       msp->dir_busy |= (tx_sel ? MSP_DIR_TX : 0) | (rx_sel ? MSP_DIR_RX : 0);
+
+       /* First do the global config register */
+       mask = RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FSYNC_MASK |
+           TX_FSYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK |
+           RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK | SRG_CLK_SEL_MASK |
+           LOOPBACK_MASK | TX_EXTRA_DELAY_MASK;
+
+       new_reg = (config->tx_clk_sel | config->rx_clk_sel |
+               config->rx_fsync_pol | config->tx_fsync_pol |
+               config->rx_fsync_sel | config->tx_fsync_sel |
+               config->rx_fifo_config | config->tx_fifo_config |
+               config->srg_clk_sel | config->loopback_enable |
+               config->tx_data_enable);
+
+       old_reg = readl(msp->registers + MSP_GCR);
+       old_reg &= ~mask;
+       new_reg |= old_reg;
+       writel(new_reg, msp->registers + MSP_GCR);
+
+       res = enable_msp(msp, config);
+       if (res < 0) {
+               dev_err(msp->dev, "%s: ERROR: enable_msp failed (%d)!\n",
+                       __func__, res);
+               return -EBUSY;
+       }
+       if (config->loopback_enable & 0x80)
+               msp->loopback_enable = 1;
+
+       /* Flush FIFOs */
+       flush_fifo_tx(msp);
+       flush_fifo_rx(msp);
+
+       msp->msp_state = MSP_STATE_CONFIGURED;
+       return 0;
+}
+
+static void disable_msp_rx(struct ux500_msp *msp)
+{
+       u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC;
+
+       reg_val_GCR = readl(msp->registers + MSP_GCR);
+       writel(reg_val_GCR & ~RX_ENABLE, msp->registers + MSP_GCR);
+       reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+       writel(reg_val_DMACR & ~RX_DMA_ENABLE, msp->registers + MSP_DMACR);
+       reg_val_IMSC = readl(msp->registers + MSP_IMSC);
+       writel(reg_val_IMSC &
+                       ~(RX_SERVICE_INT | RX_OVERRUN_ERROR_INT),
+                       msp->registers + MSP_IMSC);
+
+       msp->dir_busy &= ~MSP_DIR_RX;
+}
+
+static void disable_msp_tx(struct ux500_msp *msp)
+{
+       u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC;
+
+       reg_val_GCR = readl(msp->registers + MSP_GCR);
+       writel(reg_val_GCR & ~TX_ENABLE, msp->registers + MSP_GCR);
+       reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+       writel(reg_val_DMACR & ~TX_DMA_ENABLE, msp->registers + MSP_DMACR);
+       reg_val_IMSC = readl(msp->registers + MSP_IMSC);
+       writel(reg_val_IMSC &
+                       ~(TX_SERVICE_INT | TX_UNDERRUN_ERR_INT),
+                       msp->registers + MSP_IMSC);
+
+       msp->dir_busy &= ~MSP_DIR_TX;
+}
+
+static int disable_msp(struct ux500_msp *msp, unsigned int dir)
+{
+       u32 reg_val_GCR;
+       int status = 0;
+       unsigned int disable_tx, disable_rx;
+
+       reg_val_GCR = readl(msp->registers + MSP_GCR);
+       disable_tx = dir & MSP_DIR_TX;
+       disable_rx = dir & MSP_DIR_TX;
+       if (disable_tx && disable_rx) {
+               reg_val_GCR = readl(msp->registers + MSP_GCR);
+               writel(reg_val_GCR | LOOPBACK_MASK,
+                               msp->registers + MSP_GCR);
+
+               /* Flush TX-FIFO */
+               flush_fifo_tx(msp);
+
+               /* Disable TX-channel */
+               writel((readl(msp->registers + MSP_GCR) &
+                              (~TX_ENABLE)), msp->registers + MSP_GCR);
+
+               /* Flush RX-FIFO */
+               flush_fifo_rx(msp);
+
+               /* Disable Loopback and Receive channel */
+               writel((readl(msp->registers + MSP_GCR) &
+                               (~(RX_ENABLE | LOOPBACK_MASK))),
+                               msp->registers + MSP_GCR);
+
+               disable_msp_tx(msp);
+               disable_msp_rx(msp);
+       } else if (disable_tx)
+               disable_msp_tx(msp);
+       else if (disable_rx)
+               disable_msp_rx(msp);
+
+       return status;
+}
+
+int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
+{
+       u32 reg_val_GCR, enable_bit;
+
+       if (msp->msp_state == MSP_STATE_IDLE) {
+               dev_err(msp->dev, "%s: ERROR: MSP is not configured!\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+                       enable_bit = TX_ENABLE;
+               else
+                       enable_bit = RX_ENABLE;
+               reg_val_GCR = readl(msp->registers + MSP_GCR);
+               writel(reg_val_GCR | enable_bit, msp->registers + MSP_GCR);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+                       disable_msp_tx(msp);
+               else
+                       disable_msp_rx(msp);
+               break;
+       default:
+               return -EINVAL;
+               break;
+       }
+
+       return 0;
+}
+
+int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
+{
+       int status = 0;
+
+       dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);
+
+       status = disable_msp(msp, dir);
+       if (msp->dir_busy == 0) {
+               /* disable sample rate and frame generators */
+               msp->msp_state = MSP_STATE_IDLE;
+               writel((readl(msp->registers + MSP_GCR) &
+                              (~(FRAME_GEN_ENABLE | SRG_ENABLE))),
+                             msp->registers + MSP_GCR);
+               if (msp->plat_exit)
+                       status = msp->plat_exit();
+                       if (status)
+                               dev_warn(msp->dev,
+                                       "%s: WARN: ux500_msp_i2s_exit failed (%d)!\n",
+                                       __func__, status);
+               writel(0, msp->registers + MSP_GCR);
+               writel(0, msp->registers + MSP_TCF);
+               writel(0, msp->registers + MSP_RCF);
+               writel(0, msp->registers + MSP_DMACR);
+               writel(0, msp->registers + MSP_SRG);
+               writel(0, msp->registers + MSP_MCR);
+               writel(0, msp->registers + MSP_RCM);
+               writel(0, msp->registers + MSP_RCV);
+               writel(0, msp->registers + MSP_TCE0);
+               writel(0, msp->registers + MSP_TCE1);
+               writel(0, msp->registers + MSP_TCE2);
+               writel(0, msp->registers + MSP_TCE3);
+               writel(0, msp->registers + MSP_RCE0);
+               writel(0, msp->registers + MSP_RCE1);
+               writel(0, msp->registers + MSP_RCE2);
+               writel(0, msp->registers + MSP_RCE3);
+       }
+
+       return status;
+
+}
+
+int ux500_msp_i2s_init_msp(struct platform_device *pdev,
+                       struct ux500_msp **msp_p,
+                       struct msp_i2s_platform_data *platform_data)
+{
+       int ret = 0;
+       struct resource *res = NULL;
+       struct i2s_controller *i2s_cont;
+       struct ux500_msp *msp;
+
+       dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
+               pdev->name, platform_data->id);
+
+       *msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
+       msp = *msp_p;
+
+       msp->id = platform_data->id;
+       msp->dev = &pdev->dev;
+       msp->plat_init = platform_data->msp_i2s_init;
+       msp->plat_exit = platform_data->msp_i2s_exit;
+       msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
+       msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "%s: ERROR: Unable to get resource!\n",
+                       __func__);
+               ret = -ENOMEM;
+               goto err_res;
+       }
+
+       msp->registers = ioremap(res->start, (res->end - res->start + 1));
+       if (msp->registers == NULL) {
+               dev_err(&pdev->dev, "%s: ERROR: ioremap failed!\n", __func__);
+               ret = -ENOMEM;
+               goto err_res;
+       }
+
+       msp->msp_state = MSP_STATE_IDLE;
+       msp->loopback_enable = 0;
+
+       /* I2S-controller is allocated and added in I2S controller class. */
+       i2s_cont = devm_kzalloc(&pdev->dev, sizeof(*i2s_cont), GFP_KERNEL);
+       if (!i2s_cont) {
+               dev_err(&pdev->dev,
+                       "%s: ERROR: Failed to allocate I2S-controller!\n",
+                       __func__);
+               goto err_i2s_cont;
+       }
+       i2s_cont->dev.parent = &pdev->dev;
+       i2s_cont->data = (void *)msp;
+       i2s_cont->id = (s16)msp->id;
+       snprintf(i2s_cont->name, sizeof(i2s_cont->name), "ux500-msp-i2s.%04x",
+               msp->id);
+       dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name);
+       msp->i2s_cont = i2s_cont;
+
+       return 0;
+
+err_i2s_cont:
+       iounmap(msp->registers);
+
+err_res:
+       devm_kfree(&pdev->dev, msp);
+
+       return ret;
+}
+
+void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,
+                       struct ux500_msp *msp)
+{
+       dev_dbg(msp->dev, "%s: Enter (id = %d).\n", __func__, msp->id);
+
+       device_unregister(&msp->i2s_cont->dev);
+       devm_kfree(&pdev->dev, msp->i2s_cont);
+
+       iounmap(msp->registers);
+
+       devm_kfree(&pdev->dev, msp);
+}
+
+MODULE_LICENSE("GPLv2");
diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h
new file mode 100644 (file)
index 0000000..7f71b4a
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can 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 UX500_MSP_I2S_H
+#define UX500_MSP_I2S_H
+
+#include <linux/platform_device.h>
+
+#include <mach/board-mop500-msp.h>
+
+#define MSP_INPUT_FREQ_APB 48000000
+
+/*** Stereo mode. Used for APB data accesses as 16 bits accesses (mono),
+ *   32 bits accesses (stereo).
+ ***/
+enum msp_stereo_mode {
+       MSP_MONO,
+       MSP_STEREO
+};
+
+/* Direction (Transmit/Receive mode) */
+enum msp_direction {
+       MSP_TX = 1,
+       MSP_RX = 2
+};
+
+/* Transmit and receive configuration register */
+#define MSP_BIG_ENDIAN           0x00000000
+#define MSP_LITTLE_ENDIAN        0x00001000
+#define MSP_UNEXPECTED_FS_ABORT  0x00000000
+#define MSP_UNEXPECTED_FS_IGNORE 0x00008000
+#define MSP_NON_MODE_BIT_MASK    0x00009000
+
+/* Global configuration register */
+#define RX_ENABLE             0x00000001
+#define RX_FIFO_ENABLE        0x00000002
+#define RX_SYNC_SRG           0x00000010
+#define RX_CLK_POL_RISING     0x00000020
+#define RX_CLK_SEL_SRG        0x00000040
+#define TX_ENABLE             0x00000100
+#define TX_FIFO_ENABLE        0x00000200
+#define TX_SYNC_SRG_PROG      0x00001800
+#define TX_SYNC_SRG_AUTO      0x00001000
+#define TX_CLK_POL_RISING     0x00002000
+#define TX_CLK_SEL_SRG        0x00004000
+#define TX_EXTRA_DELAY_ENABLE 0x00008000
+#define SRG_ENABLE            0x00010000
+#define FRAME_GEN_ENABLE      0x00100000
+#define SRG_CLK_SEL_APB       0x00000000
+#define RX_FIFO_SYNC_HI       0x00000000
+#define TX_FIFO_SYNC_HI       0x00000000
+#define SPI_CLK_MODE_NORMAL   0x00000000
+
+#define MSP_FRAME_SIZE_AUTO -1
+
+#define MSP_DR         0x00
+#define MSP_GCR                0x04
+#define MSP_TCF                0x08
+#define MSP_RCF                0x0c
+#define MSP_SRG                0x10
+#define MSP_FLR                0x14
+#define MSP_DMACR      0x18
+
+#define MSP_IMSC       0x20
+#define MSP_RIS                0x24
+#define MSP_MIS                0x28
+#define MSP_ICR                0x2c
+#define MSP_MCR                0x30
+#define MSP_RCV                0x34
+#define MSP_RCM                0x38
+
+#define MSP_TCE0       0x40
+#define MSP_TCE1       0x44
+#define MSP_TCE2       0x48
+#define MSP_TCE3       0x4c
+
+#define MSP_RCE0       0x60
+#define MSP_RCE1       0x64
+#define MSP_RCE2       0x68
+#define MSP_RCE3       0x6c
+#define MSP_IODLY      0x70
+
+#define MSP_ITCR       0x80
+#define MSP_ITIP       0x84
+#define MSP_ITOP       0x88
+#define MSP_TSTDR      0x8c
+
+#define MSP_PID0       0xfe0
+#define MSP_PID1       0xfe4
+#define MSP_PID2       0xfe8
+#define MSP_PID3       0xfec
+
+#define MSP_CID0       0xff0
+#define MSP_CID1       0xff4
+#define MSP_CID2       0xff8
+#define MSP_CID3       0xffc
+
+/* Protocol dependant parameters list */
+#define RX_ENABLE_MASK         BIT(0)
+#define RX_FIFO_ENABLE_MASK    BIT(1)
+#define RX_FSYNC_MASK          BIT(2)
+#define DIRECT_COMPANDING_MASK BIT(3)
+#define RX_SYNC_SEL_MASK       BIT(4)
+#define RX_CLK_POL_MASK                BIT(5)
+#define RX_CLK_SEL_MASK                BIT(6)
+#define LOOPBACK_MASK          BIT(7)
+#define TX_ENABLE_MASK         BIT(8)
+#define TX_FIFO_ENABLE_MASK    BIT(9)
+#define TX_FSYNC_MASK          BIT(10)
+#define TX_MSP_TDR_TSR         BIT(11)
+#define TX_SYNC_SEL_MASK       (BIT(12) | BIT(11))
+#define TX_CLK_POL_MASK                BIT(13)
+#define TX_CLK_SEL_MASK                BIT(14)
+#define TX_EXTRA_DELAY_MASK    BIT(15)
+#define SRG_ENABLE_MASK                BIT(16)
+#define SRG_CLK_POL_MASK       BIT(17)
+#define SRG_CLK_SEL_MASK       (BIT(19) | BIT(18))
+#define FRAME_GEN_EN_MASK      BIT(20)
+#define SPI_CLK_MODE_MASK      (BIT(22) | BIT(21))
+#define SPI_BURST_MODE_MASK    BIT(23)
+
+#define RXEN_SHIFT             0
+#define RFFEN_SHIFT            1
+#define RFSPOL_SHIFT           2
+#define DCM_SHIFT              3
+#define RFSSEL_SHIFT           4
+#define RCKPOL_SHIFT           5
+#define RCKSEL_SHIFT           6
+#define LBM_SHIFT              7
+#define TXEN_SHIFT             8
+#define TFFEN_SHIFT            9
+#define TFSPOL_SHIFT           10
+#define TFSSEL_SHIFT           11
+#define TCKPOL_SHIFT           13
+#define TCKSEL_SHIFT           14
+#define TXDDL_SHIFT            15
+#define SGEN_SHIFT             16
+#define SCKPOL_SHIFT           17
+#define SCKSEL_SHIFT           18
+#define FGEN_SHIFT             20
+#define SPICKM_SHIFT           21
+#define TBSWAP_SHIFT           28
+
+#define RCKPOL_MASK            BIT(0)
+#define TCKPOL_MASK            BIT(0)
+#define SPICKM_MASK            (BIT(1) | BIT(0))
+#define MSP_RX_CLKPOL_BIT(n)     ((n & RCKPOL_MASK) << RCKPOL_SHIFT)
+#define MSP_TX_CLKPOL_BIT(n)     ((n & TCKPOL_MASK) << TCKPOL_SHIFT)
+
+#define P1ELEN_SHIFT           0
+#define P1FLEN_SHIFT           3
+#define DTYP_SHIFT             10
+#define ENDN_SHIFT             12
+#define DDLY_SHIFT             13
+#define FSIG_SHIFT             15
+#define P2ELEN_SHIFT           16
+#define P2FLEN_SHIFT           19
+#define P2SM_SHIFT             26
+#define P2EN_SHIFT             27
+#define FSYNC_SHIFT            15
+
+#define P1ELEN_MASK            0x00000007
+#define P2ELEN_MASK            0x00070000
+#define P1FLEN_MASK            0x00000378
+#define P2FLEN_MASK            0x03780000
+#define DDLY_MASK              0x00003000
+#define DTYP_MASK              0x00000600
+#define P2SM_MASK              0x04000000
+#define P2EN_MASK              0x08000000
+#define ENDN_MASK              0x00001000
+#define TFSPOL_MASK            0x00000400
+#define TBSWAP_MASK            0x30000000
+#define COMPANDING_MODE_MASK   0x00000c00
+#define FSYNC_MASK             0x00008000
+
+#define MSP_P1_ELEM_LEN_BITS(n)                (n & P1ELEN_MASK)
+#define MSP_P2_ELEM_LEN_BITS(n)                (((n) << P2ELEN_SHIFT) & P2ELEN_MASK)
+#define MSP_P1_FRAME_LEN_BITS(n)       (((n) << P1FLEN_SHIFT) & P1FLEN_MASK)
+#define MSP_P2_FRAME_LEN_BITS(n)       (((n) << P2FLEN_SHIFT) & P2FLEN_MASK)
+#define MSP_DATA_DELAY_BITS(n)         (((n) << DDLY_SHIFT) & DDLY_MASK)
+#define MSP_DATA_TYPE_BITS(n)          (((n) << DTYP_SHIFT) & DTYP_MASK)
+#define MSP_P2_START_MODE_BIT(n)       ((n << P2SM_SHIFT) & P2SM_MASK)
+#define MSP_P2_ENABLE_BIT(n)           ((n << P2EN_SHIFT) & P2EN_MASK)
+#define MSP_SET_ENDIANNES_BIT(n)       ((n << ENDN_SHIFT) & ENDN_MASK)
+#define MSP_FSYNC_POL(n)               ((n << TFSPOL_SHIFT) & TFSPOL_MASK)
+#define MSP_DATA_WORD_SWAP(n)          ((n << TBSWAP_SHIFT) & TBSWAP_MASK)
+#define MSP_SET_COMPANDING_MODE(n)     ((n << DTYP_SHIFT) & \
+                                               COMPANDING_MODE_MASK)
+#define MSP_SET_FSYNC_IGNORE(n)                ((n << FSYNC_SHIFT) & FSYNC_MASK)
+
+/* Flag register */
+#define RX_BUSY                        BIT(0)
+#define RX_FIFO_EMPTY          BIT(1)
+#define RX_FIFO_FULL           BIT(2)
+#define TX_BUSY                        BIT(3)
+#define TX_FIFO_EMPTY          BIT(4)
+#define TX_FIFO_FULL           BIT(5)
+
+#define RBUSY_SHIFT            0
+#define RFE_SHIFT              1
+#define RFU_SHIFT              2
+#define TBUSY_SHIFT            3
+#define TFE_SHIFT              4
+#define TFU_SHIFT              5
+
+/* Multichannel control register */
+#define RMCEN_SHIFT            0
+#define RMCSF_SHIFT            1
+#define RCMPM_SHIFT            3
+#define TMCEN_SHIFT            5
+#define TNCSF_SHIFT            6
+
+/* Sample rate generator register */
+#define SCKDIV_SHIFT           0
+#define FRWID_SHIFT            10
+#define FRPER_SHIFT            16
+
+#define SCK_DIV_MASK           0x0000003FF
+#define FRAME_WIDTH_BITS(n)    (((n) << FRWID_SHIFT)  & 0x0000FC00)
+#define FRAME_PERIOD_BITS(n)   (((n) << FRPER_SHIFT) & 0x1FFF0000)
+
+/* DMA controller register */
+#define RX_DMA_ENABLE          BIT(0)
+#define TX_DMA_ENABLE          BIT(1)
+
+#define RDMAE_SHIFT            0
+#define TDMAE_SHIFT            1
+
+/* Interrupt Register */
+#define RX_SERVICE_INT         BIT(0)
+#define RX_OVERRUN_ERROR_INT   BIT(1)
+#define RX_FSYNC_ERR_INT       BIT(2)
+#define RX_FSYNC_INT           BIT(3)
+#define TX_SERVICE_INT         BIT(4)
+#define TX_UNDERRUN_ERR_INT    BIT(5)
+#define TX_FSYNC_ERR_INT       BIT(6)
+#define TX_FSYNC_INT           BIT(7)
+#define ALL_INT                        0x000000ff
+
+/* MSP test control register */
+#define MSP_ITCR_ITEN          BIT(0)
+#define MSP_ITCR_TESTFIFO      BIT(1)
+
+#define RMCEN_BIT   0
+#define RMCSF_BIT   1
+#define RCMPM_BIT   3
+#define TMCEN_BIT   5
+#define TNCSF_BIT   6
+
+/* Single or dual phase mode */
+enum msp_phase_mode {
+       MSP_SINGLE_PHASE,
+       MSP_DUAL_PHASE
+};
+
+/* Frame length */
+enum msp_frame_length {
+       MSP_FRAME_LEN_1 = 0,
+       MSP_FRAME_LEN_2 = 1,
+       MSP_FRAME_LEN_4 = 3,
+       MSP_FRAME_LEN_8 = 7,
+       MSP_FRAME_LEN_12 = 11,
+       MSP_FRAME_LEN_16 = 15,
+       MSP_FRAME_LEN_20 = 19,
+       MSP_FRAME_LEN_32 = 31,
+       MSP_FRAME_LEN_48 = 47,
+       MSP_FRAME_LEN_64 = 63
+};
+
+/* Element length */
+enum msp_elem_length {
+       MSP_ELEM_LEN_8 = 0,
+       MSP_ELEM_LEN_10 = 1,
+       MSP_ELEM_LEN_12 = 2,
+       MSP_ELEM_LEN_14 = 3,
+       MSP_ELEM_LEN_16 = 4,
+       MSP_ELEM_LEN_20 = 5,
+       MSP_ELEM_LEN_24 = 6,
+       MSP_ELEM_LEN_32 = 7
+};
+
+enum msp_data_xfer_width {
+       MSP_DATA_TRANSFER_WIDTH_BYTE,
+       MSP_DATA_TRANSFER_WIDTH_HALFWORD,
+       MSP_DATA_TRANSFER_WIDTH_WORD
+};
+
+enum msp_frame_sync {
+       MSP_FSYNC_UNIGNORE = 0,
+       MSP_FSYNC_IGNORE = 1,
+};
+
+enum msp_phase2_start_mode {
+       MSP_PHASE2_START_MODE_IMEDIATE,
+       MSP_PHASE2_START_MODE_FSYNC
+};
+
+enum msp_btf {
+       MSP_BTF_MS_BIT_FIRST = 0,
+       MSP_BTF_LS_BIT_FIRST = 1
+};
+
+enum msp_fsync_pol {
+       MSP_FSYNC_POL_ACT_HI = 0,
+       MSP_FSYNC_POL_ACT_LO = 1
+};
+
+/* Data delay (in bit clock cycles) */
+enum msp_delay {
+       MSP_DELAY_0 = 0,
+       MSP_DELAY_1 = 1,
+       MSP_DELAY_2 = 2,
+       MSP_DELAY_3 = 3
+};
+
+/* Configurations of clocks (transmit, receive or sample rate generator) */
+enum msp_edge {
+       MSP_FALLING_EDGE = 0,
+       MSP_RISING_EDGE = 1,
+};
+
+enum msp_hws {
+       MSP_SWAP_NONE = 0,
+       MSP_SWAP_BYTE_PER_WORD = 1,
+       MSP_SWAP_BYTE_PER_HALF_WORD = 2,
+       MSP_SWAP_HALF_WORD_PER_WORD = 3
+};
+
+enum msp_compress_mode {
+       MSP_COMPRESS_MODE_LINEAR = 0,
+       MSP_COMPRESS_MODE_MU_LAW = 2,
+       MSP_COMPRESS_MODE_A_LAW = 3
+};
+
+enum msp_spi_burst_mode {
+       MSP_SPI_BURST_MODE_DISABLE = 0,
+       MSP_SPI_BURST_MODE_ENABLE = 1
+};
+
+enum msp_expand_mode {
+       MSP_EXPAND_MODE_LINEAR = 0,
+       MSP_EXPAND_MODE_LINEAR_SIGNED = 1,
+       MSP_EXPAND_MODE_MU_LAW = 2,
+       MSP_EXPAND_MODE_A_LAW = 3
+};
+
+#define MSP_FRAME_PERIOD_IN_MONO_MODE 256
+#define MSP_FRAME_PERIOD_IN_STEREO_MODE 32
+#define MSP_FRAME_WIDTH_IN_STEREO_MODE 16
+
+enum msp_protocol {
+       MSP_I2S_PROTOCOL,
+       MSP_PCM_PROTOCOL,
+       MSP_PCM_COMPAND_PROTOCOL,
+       MSP_INVALID_PROTOCOL
+};
+
+/*
+ * No of registers to backup during
+ * suspend resume
+ */
+#define MAX_MSP_BACKUP_REGS 36
+
+enum enum_i2s_controller {
+       MSP_0_I2S_CONTROLLER = 0,
+       MSP_1_I2S_CONTROLLER,
+       MSP_2_I2S_CONTROLLER,
+       MSP_3_I2S_CONTROLLER,
+};
+
+enum i2s_direction_t {
+       MSP_DIR_TX = 0x01,
+       MSP_DIR_RX = 0x02,
+};
+
+enum msp_data_size {
+       MSP_DATA_BITS_DEFAULT = -1,
+       MSP_DATA_BITS_8 = 0x00,
+       MSP_DATA_BITS_10,
+       MSP_DATA_BITS_12,
+       MSP_DATA_BITS_14,
+       MSP_DATA_BITS_16,
+       MSP_DATA_BITS_20,
+       MSP_DATA_BITS_24,
+       MSP_DATA_BITS_32,
+};
+
+enum msp_state {
+       MSP_STATE_IDLE = 0,
+       MSP_STATE_CONFIGURED = 1,
+       MSP_STATE_RUNNING = 2,
+};
+
+enum msp_rx_comparison_enable_mode {
+       MSP_COMPARISON_DISABLED = 0,
+       MSP_COMPARISON_NONEQUAL_ENABLED = 2,
+       MSP_COMPARISON_EQUAL_ENABLED = 3
+};
+
+struct msp_multichannel_config {
+       bool rx_multichannel_enable;
+       bool tx_multichannel_enable;
+       enum msp_rx_comparison_enable_mode rx_comparison_enable_mode;
+       u8 padding;
+       u32 comparison_value;
+       u32 comparison_mask;
+       u32 rx_channel_0_enable;
+       u32 rx_channel_1_enable;
+       u32 rx_channel_2_enable;
+       u32 rx_channel_3_enable;
+       u32 tx_channel_0_enable;
+       u32 tx_channel_1_enable;
+       u32 tx_channel_2_enable;
+       u32 tx_channel_3_enable;
+};
+
+struct msp_protdesc {
+       u32 rx_phase_mode;
+       u32 tx_phase_mode;
+       u32 rx_phase2_start_mode;
+       u32 tx_phase2_start_mode;
+       u32 rx_byte_order;
+       u32 tx_byte_order;
+       u32 rx_frame_len_1;
+       u32 rx_frame_len_2;
+       u32 tx_frame_len_1;
+       u32 tx_frame_len_2;
+       u32 rx_elem_len_1;
+       u32 rx_elem_len_2;
+       u32 tx_elem_len_1;
+       u32 tx_elem_len_2;
+       u32 rx_data_delay;
+       u32 tx_data_delay;
+       u32 rx_clk_pol;
+       u32 tx_clk_pol;
+       u32 rx_fsync_pol;
+       u32 tx_fsync_pol;
+       u32 rx_half_word_swap;
+       u32 tx_half_word_swap;
+       u32 compression_mode;
+       u32 expansion_mode;
+       u32 frame_sync_ignore;
+       u32 frame_period;
+       u32 frame_width;
+       u32 clocks_per_frame;
+};
+
+struct i2s_message {
+       enum i2s_direction_t i2s_direction;
+       void *txdata;
+       void *rxdata;
+       size_t txbytes;
+       size_t rxbytes;
+       int dma_flag;
+       int tx_offset;
+       int rx_offset;
+       bool cyclic_dma;
+       dma_addr_t buf_addr;
+       size_t buf_len;
+       size_t period_len;
+};
+
+struct i2s_controller {
+       struct module *owner;
+       unsigned int id;
+       unsigned int class;
+       const struct i2s_algorithm *algo; /* the algorithm to access the bus */
+       void *data;
+       struct mutex bus_lock;
+       struct device dev; /* the controller device */
+       char name[48];
+};
+
+struct ux500_msp_config {
+       unsigned int f_inputclk;
+       unsigned int rx_clk_sel;
+       unsigned int tx_clk_sel;
+       unsigned int srg_clk_sel;
+       unsigned int rx_fsync_pol;
+       unsigned int tx_fsync_pol;
+       unsigned int rx_fsync_sel;
+       unsigned int tx_fsync_sel;
+       unsigned int rx_fifo_config;
+       unsigned int tx_fifo_config;
+       unsigned int spi_clk_mode;
+       unsigned int spi_burst_mode;
+       unsigned int loopback_enable;
+       unsigned int tx_data_enable;
+       unsigned int default_protdesc;
+       struct msp_protdesc protdesc;
+       int multichannel_configured;
+       struct msp_multichannel_config multichannel_config;
+       unsigned int direction;
+       unsigned int protocol;
+       unsigned int frame_freq;
+       unsigned int frame_size;
+       enum msp_data_size data_size;
+       unsigned int def_elem_len;
+       unsigned int iodelay;
+       void (*handler) (void *data);
+       void *tx_callback_data;
+       void *rx_callback_data;
+};
+
+struct ux500_msp {
+       enum enum_i2s_controller id;
+       void __iomem *registers;
+       struct device *dev;
+       struct i2s_controller *i2s_cont;
+       struct stedma40_chan_cfg *dma_cfg_rx;
+       struct stedma40_chan_cfg *dma_cfg_tx;
+       struct dma_chan *tx_pipeid;
+       struct dma_chan *rx_pipeid;
+       enum msp_state msp_state;
+       int (*transfer) (struct ux500_msp *msp, struct i2s_message *message);
+       int (*plat_init) (void);
+       int (*plat_exit) (void);
+       struct timer_list notify_timer;
+       int def_elem_len;
+       unsigned int dir_busy;
+       int loopback_enable;
+       u32 backup_regs[MAX_MSP_BACKUP_REGS];
+       unsigned int f_bitclk;
+};
+
+struct ux500_msp_dma_params {
+       unsigned int data_size;
+       struct stedma40_chan_cfg *dma_cfg;
+};
+
+int ux500_msp_i2s_init_msp(struct platform_device *pdev,
+                       struct ux500_msp **msp_p,
+                       struct msp_i2s_platform_data *platform_data);
+void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,
+                       struct ux500_msp *msp);
+int ux500_msp_i2s_open(struct ux500_msp *msp, struct ux500_msp_config *config);
+int ux500_msp_i2s_close(struct ux500_msp *msp,
+                       unsigned int dir);
+int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd,
+                       int direction);
+
+#endif
index c6e81fb928e9acda430945fe7b0bf329f5760074..fb9255cca2146dd866496841b7784e89d690597d 100644 (file)
@@ -361,7 +361,7 @@ int register_sound_special_device(const struct file_operations *fops, int unit,
                                  struct device *dev)
 {
        const int chain = unit % SOUND_STEP;
-       int max_unit = 128 + chain;
+       int max_unit = 256;
        const char *name;
        char _name[16];
 
index 4a7be7b98331538228a49e13c81faf6b7f8243b7..d5b5c3388e28ced3cb7c287399755b56d90e1aed 100644 (file)
@@ -131,8 +131,9 @@ static void snd_usb_stream_disconnect(struct list_head *head)
                subs = &as->substream[idx];
                if (!subs->num_formats)
                        continue;
-               snd_usb_release_substream_urbs(subs, 1);
                subs->interface = -1;
+               subs->data_endpoint = NULL;
+               subs->sync_endpoint = NULL;
        }
 }
 
@@ -276,6 +277,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
 
 static int snd_usb_audio_free(struct snd_usb_audio *chip)
 {
+       mutex_destroy(&chip->mutex);
        kfree(chip);
        return 0;
 }
@@ -336,6 +338,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
                return -ENOMEM;
        }
 
+       mutex_init(&chip->mutex);
        mutex_init(&chip->shutdown_mutex);
        chip->index = idx;
        chip->dev = dev;
@@ -348,6 +351,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
        chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
                              le16_to_cpu(dev->descriptor.idProduct));
        INIT_LIST_HEAD(&chip->pcm_list);
+       INIT_LIST_HEAD(&chip->ep_list);
        INIT_LIST_HEAD(&chip->midi_list);
        INIT_LIST_HEAD(&chip->mixer_list);
 
@@ -565,6 +569,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
                list_for_each(p, &chip->pcm_list) {
                        snd_usb_stream_disconnect(p);
                }
+               /* release the endpoint resources */
+               list_for_each(p, &chip->ep_list) {
+                       snd_usb_endpoint_free(p);
+               }
                /* release the midi resources */
                list_for_each(p, &chip->midi_list) {
                        snd_usbmidi_disconnect(p);
index da5fa1ac4edaf3608c7811dea5194b98a8bab37c..0d37238b84572fed54cef1c89ee23e1d44d8ae00 100644 (file)
@@ -30,20 +30,71 @@ struct audioformat {
 };
 
 struct snd_usb_substream;
+struct snd_usb_endpoint;
 
 struct snd_urb_ctx {
        struct urb *urb;
        unsigned int buffer_size;       /* size of data buffer, if data URB */
        struct snd_usb_substream *subs;
+       struct snd_usb_endpoint *ep;
        int index;      /* index for urb array */
        int packets;    /* number of packets per urb */
+       int packet_size[MAX_PACKS_HS]; /* size of packets for next submission */
+       struct list_head ready_list;
 };
 
-struct snd_urb_ops {
-       int (*prepare)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
-       int (*retire)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
-       int (*prepare_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
-       int (*retire_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
+struct snd_usb_endpoint {
+       struct snd_usb_audio *chip;
+
+       int use_count;
+       int ep_num;             /* the referenced endpoint number */
+       int type;               /* SND_USB_ENDPOINT_TYPE_* */
+       unsigned long flags;
+
+       void (*prepare_data_urb) (struct snd_usb_substream *subs,
+                                 struct urb *urb);
+       void (*retire_data_urb) (struct snd_usb_substream *subs,
+                                struct urb *urb);
+
+       struct snd_usb_substream *data_subs;
+       struct snd_usb_endpoint *sync_master;
+       struct snd_usb_endpoint *sync_slave;
+
+       struct snd_urb_ctx urb[MAX_URBS];
+
+       struct snd_usb_packet_info {
+               uint32_t packet_size[MAX_PACKS_HS];
+               int packets;
+       } next_packet[MAX_URBS];
+       int next_packet_read_pos, next_packet_write_pos;
+       struct list_head ready_playback_urbs;
+
+       unsigned int nurbs;             /* # urbs */
+       unsigned long active_mask;      /* bitmask of active urbs */
+       unsigned long unlink_mask;      /* bitmask of unlinked urbs */
+       char *syncbuf;                  /* sync buffer for all sync URBs */
+       dma_addr_t sync_dma;            /* DMA address of syncbuf */
+
+       unsigned int pipe;              /* the data i/o pipe */
+       unsigned int freqn;             /* nominal sampling rate in fs/fps in Q16.16 format */
+       unsigned int freqm;             /* momentary sampling rate in fs/fps in Q16.16 format */
+       int        freqshift;           /* how much to shift the feedback value to get Q16.16 */
+       unsigned int freqmax;           /* maximum sampling rate, used for buffer management */
+       unsigned int phase;             /* phase accumulator */
+       unsigned int maxpacksize;       /* max packet size in bytes */
+       unsigned int maxframesize;      /* max packet size in frames */
+       unsigned int curpacksize;       /* current packet size in bytes (for capture) */
+       unsigned int curframesize;      /* current packet size in frames (for capture) */
+       unsigned int syncmaxsize;       /* sync endpoint packet size */
+       unsigned int fill_max:1;        /* fill max packet size always */
+       unsigned int datainterval;      /* log_2 of data packet interval */
+       unsigned int syncinterval;      /* P for adaptive mode, 0 otherwise */
+       unsigned char silence_value;
+       unsigned int stride;
+       int iface, alt_idx;
+
+       spinlock_t lock;
+       struct list_head list;
 };
 
 struct snd_usb_substream {
@@ -57,21 +108,6 @@ struct snd_usb_substream {
        unsigned int cur_rate;          /* current rate (for hw_params callback) */
        unsigned int period_bytes;      /* current period bytes (for hw_params callback) */
        unsigned int altset_idx;     /* USB data format: index of alternate setting */
-       unsigned int datapipe;   /* the data i/o pipe */
-       unsigned int syncpipe;   /* 1 - async out or adaptive in */
-       unsigned int datainterval;      /* log_2 of data packet interval */
-       unsigned int syncinterval;  /* P for adaptive mode, 0 otherwise */
-       unsigned int freqn;      /* nominal sampling rate in fs/fps in Q16.16 format */
-       unsigned int freqm;      /* momentary sampling rate in fs/fps in Q16.16 format */
-       int          freqshift;  /* how much to shift the feedback value to get Q16.16 */
-       unsigned int freqmax;    /* maximum sampling rate, used for buffer management */
-       unsigned int phase;      /* phase accumulator */
-       unsigned int maxpacksize;       /* max packet size in bytes */
-       unsigned int maxframesize;      /* max packet size in frames */
-       unsigned int curpacksize;       /* current packet size in bytes (for capture) */
-       unsigned int curframesize;      /* current packet size in frames (for capture) */
-       unsigned int syncmaxsize;       /* sync endpoint packet size */
-       unsigned int fill_max: 1;       /* fill max packet size always */
        unsigned int txfr_quirk:1;      /* allow sub-frame alignment */
        unsigned int fmt_type;          /* USB audio format type (1-3) */
 
@@ -82,11 +118,10 @@ struct snd_usb_substream {
        unsigned long active_mask;      /* bitmask of active urbs */
        unsigned long unlink_mask;      /* bitmask of unlinked urbs */
 
-       unsigned int nurbs;                     /* # urbs */
-       struct snd_urb_ctx dataurb[MAX_URBS];   /* data urb table */
-       struct snd_urb_ctx syncurb[SYNC_URBS];  /* sync urb table */
-       char *syncbuf;                          /* sync buffer for all sync URBs */
-       dma_addr_t sync_dma;                    /* DMA address of syncbuf */
+       /* data and sync endpoints for this stream */
+       struct snd_usb_endpoint *data_endpoint;
+       struct snd_usb_endpoint *sync_endpoint;
+       unsigned long flags;
 
        u64 formats;                    /* format bitmasks (all or'ed) */
        unsigned int num_formats;               /* number of supported audio formats (list) */
@@ -94,7 +129,6 @@ struct snd_usb_substream {
        struct snd_pcm_hw_constraint_list rate_list;    /* limited rates */
        spinlock_t lock;
 
-       struct snd_urb_ops ops;         /* callbacks (must be filled at init) */
        int last_frame_number;          /* stored frame number */
        int last_delay;                 /* stored delay */
 };
index 08dcce53720bad66499f48709c553b04e6ea6821..e6906901debbc2aaa71c40621fbd4241d8d15663 100644 (file)
 #include <linux/ratelimit.h>
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
+#include <linux/slab.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 
 #include "usbaudio.h"
 #include "helper.h"
 #include "endpoint.h"
 #include "pcm.h"
 
+#define EP_FLAG_ACTIVATED      0
+#define EP_FLAG_RUNNING                1
+
+/*
+ * snd_usb_endpoint is a model that abstracts everything related to an
+ * USB endpoint and its streaming.
+ *
+ * There are functions to activate and deactivate the streaming URBs and
+ * optional callbacks to let the pcm logic handle the actual content of the
+ * packets for playback and record. Thus, the bus streaming and the audio
+ * handlers are fully decoupled.
+ *
+ * There are two different types of endpoints in audio applications.
+ *
+ * SND_USB_ENDPOINT_TYPE_DATA handles full audio data payload for both
+ * inbound and outbound traffic.
+ *
+ * SND_USB_ENDPOINT_TYPE_SYNC endpoints are for inbound traffic only and
+ * expect the payload to carry Q10.14 / Q16.16 formatted sync information
+ * (3 or 4 bytes).
+ *
+ * Each endpoint has to be configured prior to being used by calling
+ * snd_usb_endpoint_set_params().
+ *
+ * The model incorporates a reference counting, so that multiple users
+ * can call snd_usb_endpoint_start() and snd_usb_endpoint_stop(), and
+ * only the first user will effectively start the URBs, and only the last
+ * one to stop it will tear the URBs down again.
+ */
+
 /*
  * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
  * this will overflow at approx 524 kHz
@@ -49,71 +81,415 @@ static inline unsigned get_usb_high_speed_rate(unsigned int rate)
 }
 
 /*
- * unlink active urbs.
+ * release a urb data
  */
-static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep)
+static void release_urb_ctx(struct snd_urb_ctx *u)
 {
-       struct snd_usb_audio *chip = subs->stream->chip;
-       unsigned int i;
-       int async;
+       if (u->buffer_size)
+               usb_free_coherent(u->ep->chip->dev, u->buffer_size,
+                                 u->urb->transfer_buffer,
+                                 u->urb->transfer_dma);
+       usb_free_urb(u->urb);
+       u->urb = NULL;
+}
+
+static const char *usb_error_string(int err)
+{
+       switch (err) {
+       case -ENODEV:
+               return "no device";
+       case -ENOENT:
+               return "endpoint not enabled";
+       case -EPIPE:
+               return "endpoint stalled";
+       case -ENOSPC:
+               return "not enough bandwidth";
+       case -ESHUTDOWN:
+               return "device disabled";
+       case -EHOSTUNREACH:
+               return "device suspended";
+       case -EINVAL:
+       case -EAGAIN:
+       case -EFBIG:
+       case -EMSGSIZE:
+               return "internal error";
+       default:
+               return "unknown error";
+       }
+}
+
+/**
+ * snd_usb_endpoint_implicit_feedback_sink: Report endpoint usage type
+ *
+ * @ep: The snd_usb_endpoint
+ *
+ * Determine whether an endpoint is driven by an implicit feedback
+ * data endpoint source.
+ */
+int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep)
+{
+       return  ep->sync_master &&
+               ep->sync_master->type == SND_USB_ENDPOINT_TYPE_DATA &&
+               ep->type == SND_USB_ENDPOINT_TYPE_DATA &&
+               usb_pipeout(ep->pipe);
+}
 
-       subs->running = 0;
+/*
+ * For streaming based on information derived from sync endpoints,
+ * prepare_outbound_urb_sizes() will call next_packet_size() to
+ * determine the number of samples to be sent in the next packet.
+ *
+ * For implicit feedback, next_packet_size() is unused.
+ */
+static int next_packet_size(struct snd_usb_endpoint *ep)
+{
+       unsigned long flags;
+       int ret;
 
-       if (!force && subs->stream->chip->shutdown) /* to be sure... */
-               return -EBADFD;
+       if (ep->fill_max)
+               return ep->maxframesize;
 
-       async = !can_sleep && chip->async_unlink;
+       spin_lock_irqsave(&ep->lock, flags);
+       ep->phase = (ep->phase & 0xffff)
+               + (ep->freqm << ep->datainterval);
+       ret = min(ep->phase >> 16, ep->maxframesize);
+       spin_unlock_irqrestore(&ep->lock, flags);
 
-       if (!async && in_interrupt())
-               return 0;
+       return ret;
+}
 
-       for (i = 0; i < subs->nurbs; i++) {
-               if (test_bit(i, &subs->active_mask)) {
-                       if (!test_and_set_bit(i, &subs->unlink_mask)) {
-                               struct urb *u = subs->dataurb[i].urb;
-                               if (async)
-                                       usb_unlink_urb(u);
-                               else
-                                       usb_kill_urb(u);
+static void retire_outbound_urb(struct snd_usb_endpoint *ep,
+                               struct snd_urb_ctx *urb_ctx)
+{
+       if (ep->retire_data_urb)
+               ep->retire_data_urb(ep->data_subs, urb_ctx->urb);
+}
+
+static void retire_inbound_urb(struct snd_usb_endpoint *ep,
+                              struct snd_urb_ctx *urb_ctx)
+{
+       struct urb *urb = urb_ctx->urb;
+
+       if (ep->sync_slave)
+               snd_usb_handle_sync_urb(ep->sync_slave, ep, urb);
+
+       if (ep->retire_data_urb)
+               ep->retire_data_urb(ep->data_subs, urb);
+}
+
+static void prepare_outbound_urb_sizes(struct snd_usb_endpoint *ep,
+                                      struct snd_urb_ctx *ctx)
+{
+       int i;
+
+       for (i = 0; i < ctx->packets; ++i)
+               ctx->packet_size[i] = next_packet_size(ep);
+}
+
+/*
+ * Prepare a PLAYBACK urb for submission to the bus.
+ */
+static void prepare_outbound_urb(struct snd_usb_endpoint *ep,
+                                struct snd_urb_ctx *ctx)
+{
+       int i;
+       struct urb *urb = ctx->urb;
+       unsigned char *cp = urb->transfer_buffer;
+
+       urb->dev = ep->chip->dev; /* we need to set this at each time */
+
+       switch (ep->type) {
+       case SND_USB_ENDPOINT_TYPE_DATA:
+               if (ep->prepare_data_urb) {
+                       ep->prepare_data_urb(ep->data_subs, urb);
+               } else {
+                       /* no data provider, so send silence */
+                       unsigned int offs = 0;
+                       for (i = 0; i < ctx->packets; ++i) {
+                               int counts = ctx->packet_size[i];
+                               urb->iso_frame_desc[i].offset = offs * ep->stride;
+                               urb->iso_frame_desc[i].length = counts * ep->stride;
+                               offs += counts;
                        }
+
+                       urb->number_of_packets = ctx->packets;
+                       urb->transfer_buffer_length = offs * ep->stride;
+                       memset(urb->transfer_buffer, ep->silence_value,
+                              offs * ep->stride);
                }
+               break;
+
+       case SND_USB_ENDPOINT_TYPE_SYNC:
+               if (snd_usb_get_speed(ep->chip->dev) >= USB_SPEED_HIGH) {
+                       /*
+                        * fill the length and offset of each urb descriptor.
+                        * the fixed 12.13 frequency is passed as 16.16 through the pipe.
+                        */
+                       urb->iso_frame_desc[0].length = 4;
+                       urb->iso_frame_desc[0].offset = 0;
+                       cp[0] = ep->freqn;
+                       cp[1] = ep->freqn >> 8;
+                       cp[2] = ep->freqn >> 16;
+                       cp[3] = ep->freqn >> 24;
+               } else {
+                       /*
+                        * fill the length and offset of each urb descriptor.
+                        * the fixed 10.14 frequency is passed through the pipe.
+                        */
+                       urb->iso_frame_desc[0].length = 3;
+                       urb->iso_frame_desc[0].offset = 0;
+                       cp[0] = ep->freqn >> 2;
+                       cp[1] = ep->freqn >> 10;
+                       cp[2] = ep->freqn >> 18;
+               }
+
+               break;
        }
-       if (subs->syncpipe) {
-               for (i = 0; i < SYNC_URBS; i++) {
-                       if (test_bit(i+16, &subs->active_mask)) {
-                               if (!test_and_set_bit(i+16, &subs->unlink_mask)) {
-                                       struct urb *u = subs->syncurb[i].urb;
-                                       if (async)
-                                               usb_unlink_urb(u);
-                                       else
-                                               usb_kill_urb(u);
-                               }
-                       }
+}
+
+/*
+ * Prepare a CAPTURE or SYNC urb for submission to the bus.
+ */
+static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep,
+                                      struct snd_urb_ctx *urb_ctx)
+{
+       int i, offs;
+       struct urb *urb = urb_ctx->urb;
+
+       urb->dev = ep->chip->dev; /* we need to set this at each time */
+
+       switch (ep->type) {
+       case SND_USB_ENDPOINT_TYPE_DATA:
+               offs = 0;
+               for (i = 0; i < urb_ctx->packets; i++) {
+                       urb->iso_frame_desc[i].offset = offs;
+                       urb->iso_frame_desc[i].length = ep->curpacksize;
+                       offs += ep->curpacksize;
                }
+
+               urb->transfer_buffer_length = offs;
+               urb->number_of_packets = urb_ctx->packets;
+               break;
+
+       case SND_USB_ENDPOINT_TYPE_SYNC:
+               urb->iso_frame_desc[0].length = min(4u, ep->syncmaxsize);
+               urb->iso_frame_desc[0].offset = 0;
+               break;
        }
-       return 0;
 }
 
+/*
+ * Send output urbs that have been prepared previously. URBs are dequeued
+ * from ep->ready_playback_urbs and in case there there aren't any available
+ * or there are no packets that have been prepared, this function does
+ * nothing.
+ *
+ * The reason why the functionality of sending and preparing URBs is separated
+ * is that host controllers don't guarantee the order in which they return
+ * inbound and outbound packets to their submitters.
+ *
+ * This function is only used for implicit feedback endpoints. For endpoints
+ * driven by dedicated sync endpoints, URBs are immediately re-submitted
+ * from their completion handler.
+ */
+static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
+{
+       while (test_bit(EP_FLAG_RUNNING, &ep->flags)) {
+
+               unsigned long flags;
+               struct snd_usb_packet_info *uninitialized_var(packet);
+               struct snd_urb_ctx *ctx = NULL;
+               struct urb *urb;
+               int err, i;
+
+               spin_lock_irqsave(&ep->lock, flags);
+               if (ep->next_packet_read_pos != ep->next_packet_write_pos) {
+                       packet = ep->next_packet + ep->next_packet_read_pos;
+                       ep->next_packet_read_pos++;
+                       ep->next_packet_read_pos %= MAX_URBS;
+
+                       /* take URB out of FIFO */
+                       if (!list_empty(&ep->ready_playback_urbs))
+                               ctx = list_first_entry(&ep->ready_playback_urbs,
+                                              struct snd_urb_ctx, ready_list);
+               }
+               spin_unlock_irqrestore(&ep->lock, flags);
+
+               if (ctx == NULL)
+                       return;
+
+               list_del_init(&ctx->ready_list);
+               urb = ctx->urb;
+
+               /* copy over the length information */
+               for (i = 0; i < packet->packets; i++)
+                       ctx->packet_size[i] = packet->packet_size[i];
+
+               /* call the data handler to fill in playback data */
+               prepare_outbound_urb(ep, ctx);
+
+               err = usb_submit_urb(ctx->urb, GFP_ATOMIC);
+               if (err < 0)
+                       snd_printk(KERN_ERR "Unable to submit urb #%d: %d (urb %p)\n",
+                                  ctx->index, err, ctx->urb);
+               else
+                       set_bit(ctx->index, &ep->active_mask);
+       }
+}
 
 /*
- * release a urb data
+ * complete callback for urbs
  */
-static void release_urb_ctx(struct snd_urb_ctx *u)
+static void snd_complete_urb(struct urb *urb)
+{
+       struct snd_urb_ctx *ctx = urb->context;
+       struct snd_usb_endpoint *ep = ctx->ep;
+       int err;
+
+       if (unlikely(urb->status == -ENOENT ||          /* unlinked */
+                    urb->status == -ENODEV ||          /* device removed */
+                    urb->status == -ECONNRESET ||      /* unlinked */
+                    urb->status == -ESHUTDOWN ||       /* device disabled */
+                    ep->chip->shutdown))               /* device disconnected */
+               goto exit_clear;
+
+       if (usb_pipeout(ep->pipe)) {
+               retire_outbound_urb(ep, ctx);
+               /* can be stopped during retire callback */
+               if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+                       goto exit_clear;
+
+               if (snd_usb_endpoint_implict_feedback_sink(ep)) {
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&ep->lock, flags);
+                       list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
+                       spin_unlock_irqrestore(&ep->lock, flags);
+                       queue_pending_output_urbs(ep);
+
+                       goto exit_clear;
+               }
+
+               prepare_outbound_urb_sizes(ep, ctx);
+               prepare_outbound_urb(ep, ctx);
+       } else {
+               retire_inbound_urb(ep, ctx);
+               /* can be stopped during retire callback */
+               if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+                       goto exit_clear;
+
+               prepare_inbound_urb(ep, ctx);
+       }
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err == 0)
+               return;
+
+       snd_printk(KERN_ERR "cannot submit urb (err = %d)\n", err);
+       //snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+
+exit_clear:
+       clear_bit(ctx->index, &ep->active_mask);
+}
+
+/**
+ * snd_usb_add_endpoint: Add an endpoint to an USB audio chip
+ *
+ * @chip: The chip
+ * @alts: The USB host interface
+ * @ep_num: The number of the endpoint to use
+ * @direction: SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE
+ * @type: SND_USB_ENDPOINT_TYPE_DATA or SND_USB_ENDPOINT_TYPE_SYNC
+ *
+ * If the requested endpoint has not been added to the given chip before,
+ * a new instance is created. Otherwise, a pointer to the previoulsy
+ * created instance is returned. In case of any error, NULL is returned.
+ *
+ * New endpoints will be added to chip->ep_list and must be freed by
+ * calling snd_usb_endpoint_free().
+ */
+struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
+                                             struct usb_host_interface *alts,
+                                             int ep_num, int direction, int type)
 {
-       if (u->urb) {
-               if (u->buffer_size)
-                       usb_free_coherent(u->subs->dev, u->buffer_size,
-                                       u->urb->transfer_buffer,
-                                       u->urb->transfer_dma);
-               usb_free_urb(u->urb);
-               u->urb = NULL;
+       struct list_head *p;
+       struct snd_usb_endpoint *ep;
+       int ret, is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
+
+       mutex_lock(&chip->mutex);
+
+       list_for_each(p, &chip->ep_list) {
+               ep = list_entry(p, struct snd_usb_endpoint, list);
+               if (ep->ep_num == ep_num &&
+                   ep->iface == alts->desc.bInterfaceNumber &&
+                   ep->alt_idx == alts->desc.bAlternateSetting) {
+                       snd_printdd(KERN_DEBUG "Re-using EP %x in iface %d,%d @%p\n",
+                                       ep_num, ep->iface, ep->alt_idx, ep);
+                       goto __exit_unlock;
+               }
+       }
+
+       snd_printdd(KERN_DEBUG "Creating new %s %s endpoint #%x\n",
+                   is_playback ? "playback" : "capture",
+                   type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync",
+                   ep_num);
+
+       /* select the alt setting once so the endpoints become valid */
+       ret = usb_set_interface(chip->dev, alts->desc.bInterfaceNumber,
+                               alts->desc.bAlternateSetting);
+       if (ret < 0) {
+               snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n",
+                                       __func__, ret);
+               ep = NULL;
+               goto __exit_unlock;
        }
+
+       ep = kzalloc(sizeof(*ep), GFP_KERNEL);
+       if (!ep)
+               goto __exit_unlock;
+
+       ep->chip = chip;
+       spin_lock_init(&ep->lock);
+       ep->type = type;
+       ep->ep_num = ep_num;
+       ep->iface = alts->desc.bInterfaceNumber;
+       ep->alt_idx = alts->desc.bAlternateSetting;
+       INIT_LIST_HEAD(&ep->ready_playback_urbs);
+       ep_num &= USB_ENDPOINT_NUMBER_MASK;
+
+       if (is_playback)
+               ep->pipe = usb_sndisocpipe(chip->dev, ep_num);
+       else
+               ep->pipe = usb_rcvisocpipe(chip->dev, ep_num);
+
+       if (type == SND_USB_ENDPOINT_TYPE_SYNC) {
+               if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
+                   get_endpoint(alts, 1)->bRefresh >= 1 &&
+                   get_endpoint(alts, 1)->bRefresh <= 9)
+                       ep->syncinterval = get_endpoint(alts, 1)->bRefresh;
+               else if (snd_usb_get_speed(chip->dev) == USB_SPEED_FULL)
+                       ep->syncinterval = 1;
+               else if (get_endpoint(alts, 1)->bInterval >= 1 &&
+                        get_endpoint(alts, 1)->bInterval <= 16)
+                       ep->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
+               else
+                       ep->syncinterval = 3;
+
+               ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
+       }
+
+       list_add_tail(&ep->list, &chip->ep_list);
+
+__exit_unlock:
+       mutex_unlock(&chip->mutex);
+
+       return ep;
 }
 
 /*
  *  wait until all urbs are processed.
  */
-static int wait_clear_urbs(struct snd_usb_substream *subs)
+static int wait_clear_urbs(struct snd_usb_endpoint *ep)
 {
        unsigned long end_time = jiffies + msecs_to_jiffies(1000);
        unsigned int i;
@@ -121,153 +497,148 @@ static int wait_clear_urbs(struct snd_usb_substream *subs)
 
        do {
                alive = 0;
-               for (i = 0; i < subs->nurbs; i++) {
-                       if (test_bit(i, &subs->active_mask))
+               for (i = 0; i < ep->nurbs; i++)
+                       if (test_bit(i, &ep->active_mask))
                                alive++;
-               }
-               if (subs->syncpipe) {
-                       for (i = 0; i < SYNC_URBS; i++) {
-                               if (test_bit(i + 16, &subs->active_mask))
-                                       alive++;
-                       }
-               }
-               if (! alive)
+
+               if (!alive)
                        break;
+
                schedule_timeout_uninterruptible(1);
        } while (time_before(jiffies, end_time));
+
        if (alive)
-               snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
+               snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n",
+                                       alive, ep->ep_num);
+
        return 0;
 }
 
 /*
- * release a substream
+ * unlink active urbs.
  */
-void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force)
+static int deactivate_urbs(struct snd_usb_endpoint *ep, int force, int can_sleep)
 {
-       int i;
+       unsigned int i;
+       int async;
 
-       /* stop urbs (to be sure) */
-       deactivate_urbs(subs, force, 1);
-       wait_clear_urbs(subs);
-
-       for (i = 0; i < MAX_URBS; i++)
-               release_urb_ctx(&subs->dataurb[i]);
-       for (i = 0; i < SYNC_URBS; i++)
-               release_urb_ctx(&subs->syncurb[i]);
-       usb_free_coherent(subs->dev, SYNC_URBS * 4,
-                       subs->syncbuf, subs->sync_dma);
-       subs->syncbuf = NULL;
-       subs->nurbs = 0;
-}
+       if (!force && ep->chip->shutdown) /* to be sure... */
+               return -EBADFD;
 
-/*
- * complete callback from data urb
- */
-static void snd_complete_urb(struct urb *urb)
-{
-       struct snd_urb_ctx *ctx = urb->context;
-       struct snd_usb_substream *subs = ctx->subs;
-       struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
-       int err = 0;
-
-       if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) ||
-           !subs->running || /* can be stopped during retire callback */
-           (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 ||
-           (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
-               clear_bit(ctx->index, &subs->active_mask);
-               if (err < 0) {
-                       snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
-                       snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+       async = !can_sleep && ep->chip->async_unlink;
+
+       clear_bit(EP_FLAG_RUNNING, &ep->flags);
+
+       INIT_LIST_HEAD(&ep->ready_playback_urbs);
+       ep->next_packet_read_pos = 0;
+       ep->next_packet_write_pos = 0;
+
+       if (!async && in_interrupt())
+               return 0;
+
+       for (i = 0; i < ep->nurbs; i++) {
+               if (test_bit(i, &ep->active_mask)) {
+                       if (!test_and_set_bit(i, &ep->unlink_mask)) {
+                               struct urb *u = ep->urb[i].urb;
+                               if (async)
+                                       usb_unlink_urb(u);
+                               else
+                                       usb_kill_urb(u);
+                       }
                }
        }
-}
 
+       return 0;
+}
 
 /*
- * complete callback from sync urb
+ * release an endpoint's urbs
  */
-static void snd_complete_sync_urb(struct urb *urb)
+static void release_urbs(struct snd_usb_endpoint *ep, int force)
 {
-       struct snd_urb_ctx *ctx = urb->context;
-       struct snd_usb_substream *subs = ctx->subs;
-       struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
-       int err = 0;
-
-       if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) ||
-           !subs->running || /* can be stopped during retire callback */
-           (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 ||
-           (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
-               clear_bit(ctx->index + 16, &subs->active_mask);
-               if (err < 0) {
-                       snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err);
-                       snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-               }
-       }
-}
+       int i;
 
+       /* route incoming urbs to nirvana */
+       ep->retire_data_urb = NULL;
+       ep->prepare_data_urb = NULL;
+
+       /* stop urbs */
+       deactivate_urbs(ep, force, 1);
+       wait_clear_urbs(ep);
+
+       for (i = 0; i < ep->nurbs; i++)
+               release_urb_ctx(&ep->urb[i]);
+
+       if (ep->syncbuf)
+               usb_free_coherent(ep->chip->dev, SYNC_URBS * 4,
+                                 ep->syncbuf, ep->sync_dma);
+
+       ep->syncbuf = NULL;
+       ep->nurbs = 0;
+}
 
 /*
- * initialize a substream for plaback/capture
+ * configure a data endpoint
  */
-int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
-                               unsigned int period_bytes,
-                               unsigned int rate,
-                               unsigned int frame_bits)
+static int data_ep_set_params(struct snd_usb_endpoint *ep,
+                             struct snd_pcm_hw_params *hw_params,
+                             struct audioformat *fmt,
+                             struct snd_usb_endpoint *sync_ep)
 {
-       unsigned int maxsize, i;
-       int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
-       unsigned int urb_packs, total_packs, packs_per_ms;
-       struct snd_usb_audio *chip = subs->stream->chip;
+       unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
+       int period_bytes = params_period_bytes(hw_params);
+       int format = params_format(hw_params);
+       int is_playback = usb_pipeout(ep->pipe);
+       int frame_bits = snd_pcm_format_physical_width(params_format(hw_params)) *
+                                                       params_channels(hw_params);
+
+       ep->datainterval = fmt->datainterval;
+       ep->stride = frame_bits >> 3;
+       ep->silence_value = format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
 
-       /* calculate the frequency in 16.16 format */
-       if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
-               subs->freqn = get_usb_full_speed_rate(rate);
-       else
-               subs->freqn = get_usb_high_speed_rate(rate);
-       subs->freqm = subs->freqn;
-       subs->freqshift = INT_MIN;
        /* calculate max. frequency */
-       if (subs->maxpacksize) {
+       if (ep->maxpacksize) {
                /* whatever fits into a max. size packet */
-               maxsize = subs->maxpacksize;
-               subs->freqmax = (maxsize / (frame_bits >> 3))
-                               << (16 - subs->datainterval);
+               maxsize = ep->maxpacksize;
+               ep->freqmax = (maxsize / (frame_bits >> 3))
+                               << (16 - ep->datainterval);
        } else {
                /* no max. packet size: just take 25% higher than nominal */
-               subs->freqmax = subs->freqn + (subs->freqn >> 2);
-               maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3))
-                               >> (16 - subs->datainterval);
+               ep->freqmax = ep->freqn + (ep->freqn >> 2);
+               maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3))
+                               >> (16 - ep->datainterval);
        }
-       subs->phase = 0;
 
-       if (subs->fill_max)
-               subs->curpacksize = subs->maxpacksize;
+       if (ep->fill_max)
+               ep->curpacksize = ep->maxpacksize;
        else
-               subs->curpacksize = maxsize;
+               ep->curpacksize = maxsize;
 
-       if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
-               packs_per_ms = 8 >> subs->datainterval;
+       if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL)
+               packs_per_ms = 8 >> ep->datainterval;
        else
                packs_per_ms = 1;
 
-       if (is_playback) {
-               urb_packs = max(chip->nrpacks, 1);
-               urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
-       } else
+       if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
+               urb_packs = max(ep->chip->nrpacks, 1);
+               urb_packs = min(urb_packs, (unsigned int) MAX_PACKS);
+       } else {
                urb_packs = 1;
+       }
+
        urb_packs *= packs_per_ms;
-       if (subs->syncpipe)
-               urb_packs = min(urb_packs, 1U << subs->syncinterval);
+
+       if (sync_ep && !snd_usb_endpoint_implict_feedback_sink(ep))
+               urb_packs = min(urb_packs, 1U << sync_ep->syncinterval);
 
        /* decide how many packets to be used */
-       if (is_playback) {
+       if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
                unsigned int minsize, maxpacks;
                /* determine how small a packet can be */
-               minsize = (subs->freqn >> (16 - subs->datainterval))
+               minsize = (ep->freqn >> (16 - ep->datainterval))
                          * (frame_bits >> 3);
                /* with sync from device, assume it can be 12% lower */
-               if (subs->syncpipe)
+               if (sync_ep)
                        minsize -= minsize >> 3;
                minsize = max(minsize, 1u);
                total_packs = (period_bytes + minsize - 1) / minsize;
@@ -284,284 +655,472 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
                        urb_packs >>= 1;
                total_packs = MAX_URBS * urb_packs;
        }
-       subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
-       if (subs->nurbs > MAX_URBS) {
+
+       ep->nurbs = (total_packs + urb_packs - 1) / urb_packs;
+       if (ep->nurbs > MAX_URBS) {
                /* too much... */
-               subs->nurbs = MAX_URBS;
+               ep->nurbs = MAX_URBS;
                total_packs = MAX_URBS * urb_packs;
-       } else if (subs->nurbs < 2) {
+       } else if (ep->nurbs < 2) {
                /* too little - we need at least two packets
                 * to ensure contiguous playback/capture
                 */
-               subs->nurbs = 2;
+               ep->nurbs = 2;
        }
 
        /* allocate and initialize data urbs */
-       for (i = 0; i < subs->nurbs; i++) {
-               struct snd_urb_ctx *u = &subs->dataurb[i];
+       for (i = 0; i < ep->nurbs; i++) {
+               struct snd_urb_ctx *u = &ep->urb[i];
                u->index = i;
-               u->subs = subs;
-               u->packets = (i + 1) * total_packs / subs->nurbs
-                       - i * total_packs / subs->nurbs;
+               u->ep = ep;
+               u->packets = (i + 1) * total_packs / ep->nurbs
+                       - i * total_packs / ep->nurbs;
                u->buffer_size = maxsize * u->packets;
-               if (subs->fmt_type == UAC_FORMAT_TYPE_II)
+
+               if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
                        u->packets++; /* for transfer delimiter */
                u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
                if (!u->urb)
                        goto out_of_memory;
+
                u->urb->transfer_buffer =
-                       usb_alloc_coherent(subs->dev, u->buffer_size,
+                       usb_alloc_coherent(ep->chip->dev, u->buffer_size,
                                           GFP_KERNEL, &u->urb->transfer_dma);
                if (!u->urb->transfer_buffer)
                        goto out_of_memory;
-               u->urb->pipe = subs->datapipe;
+               u->urb->pipe = ep->pipe;
                u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-               u->urb->interval = 1 << subs->datainterval;
+               u->urb->interval = 1 << ep->datainterval;
                u->urb->context = u;
                u->urb->complete = snd_complete_urb;
+               INIT_LIST_HEAD(&u->ready_list);
        }
 
-       if (subs->syncpipe) {
-               /* allocate and initialize sync urbs */
-               subs->syncbuf = usb_alloc_coherent(subs->dev, SYNC_URBS * 4,
-                                                GFP_KERNEL, &subs->sync_dma);
-               if (!subs->syncbuf)
-                       goto out_of_memory;
-               for (i = 0; i < SYNC_URBS; i++) {
-                       struct snd_urb_ctx *u = &subs->syncurb[i];
-                       u->index = i;
-                       u->subs = subs;
-                       u->packets = 1;
-                       u->urb = usb_alloc_urb(1, GFP_KERNEL);
-                       if (!u->urb)
-                               goto out_of_memory;
-                       u->urb->transfer_buffer = subs->syncbuf + i * 4;
-                       u->urb->transfer_dma = subs->sync_dma + i * 4;
-                       u->urb->transfer_buffer_length = 4;
-                       u->urb->pipe = subs->syncpipe;
-                       u->urb->transfer_flags = URB_ISO_ASAP |
-                                                URB_NO_TRANSFER_DMA_MAP;
-                       u->urb->number_of_packets = 1;
-                       u->urb->interval = 1 << subs->syncinterval;
-                       u->urb->context = u;
-                       u->urb->complete = snd_complete_sync_urb;
-               }
-       }
        return 0;
 
 out_of_memory:
-       snd_usb_release_substream_urbs(subs, 0);
+       release_urbs(ep, 0);
        return -ENOMEM;
 }
 
 /*
- * prepare urb for full speed capture sync pipe
- *
- * fill the length and offset of each urb descriptor.
- * the fixed 10.14 frequency is passed through the pipe.
+ * configure a sync endpoint
  */
-static int prepare_capture_sync_urb(struct snd_usb_substream *subs,
-                                   struct snd_pcm_runtime *runtime,
-                                   struct urb *urb)
+static int sync_ep_set_params(struct snd_usb_endpoint *ep,
+                             struct snd_pcm_hw_params *hw_params,
+                             struct audioformat *fmt)
 {
-       unsigned char *cp = urb->transfer_buffer;
-       struct snd_urb_ctx *ctx = urb->context;
+       int i;
+
+       ep->syncbuf = usb_alloc_coherent(ep->chip->dev, SYNC_URBS * 4,
+                                        GFP_KERNEL, &ep->sync_dma);
+       if (!ep->syncbuf)
+               return -ENOMEM;
+
+       for (i = 0; i < SYNC_URBS; i++) {
+               struct snd_urb_ctx *u = &ep->urb[i];
+               u->index = i;
+               u->ep = ep;
+               u->packets = 1;
+               u->urb = usb_alloc_urb(1, GFP_KERNEL);
+               if (!u->urb)
+                       goto out_of_memory;
+               u->urb->transfer_buffer = ep->syncbuf + i * 4;
+               u->urb->transfer_dma = ep->sync_dma + i * 4;
+               u->urb->transfer_buffer_length = 4;
+               u->urb->pipe = ep->pipe;
+               u->urb->transfer_flags = URB_ISO_ASAP |
+                                        URB_NO_TRANSFER_DMA_MAP;
+               u->urb->number_of_packets = 1;
+               u->urb->interval = 1 << ep->syncinterval;
+               u->urb->context = u;
+               u->urb->complete = snd_complete_urb;
+       }
+
+       ep->nurbs = SYNC_URBS;
 
-       urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       urb->iso_frame_desc[0].length = 3;
-       urb->iso_frame_desc[0].offset = 0;
-       cp[0] = subs->freqn >> 2;
-       cp[1] = subs->freqn >> 10;
-       cp[2] = subs->freqn >> 18;
        return 0;
+
+out_of_memory:
+       release_urbs(ep, 0);
+       return -ENOMEM;
 }
 
-/*
- * prepare urb for high speed capture sync pipe
+/**
+ * snd_usb_endpoint_set_params: configure an snd_usb_endpoint
+ *
+ * @ep: the snd_usb_endpoint to configure
+ * @hw_params: the hardware parameters
+ * @fmt: the USB audio format information
+ * @sync_ep: the sync endpoint to use, if any
  *
- * fill the length and offset of each urb descriptor.
- * the fixed 12.13 frequency is passed as 16.16 through the pipe.
+ * Determine the number of URBs to be used on this endpoint.
+ * An endpoint must be configured before it can be started.
+ * An endpoint that is already running can not be reconfigured.
  */
-static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs,
-                                      struct snd_pcm_runtime *runtime,
-                                      struct urb *urb)
+int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
+                               struct snd_pcm_hw_params *hw_params,
+                               struct audioformat *fmt,
+                               struct snd_usb_endpoint *sync_ep)
 {
-       unsigned char *cp = urb->transfer_buffer;
-       struct snd_urb_ctx *ctx = urb->context;
+       int err;
 
-       urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       urb->iso_frame_desc[0].length = 4;
-       urb->iso_frame_desc[0].offset = 0;
-       cp[0] = subs->freqn;
-       cp[1] = subs->freqn >> 8;
-       cp[2] = subs->freqn >> 16;
-       cp[3] = subs->freqn >> 24;
-       return 0;
+       if (ep->use_count != 0) {
+               snd_printk(KERN_WARNING "Unable to change format on ep #%x: already in use\n",
+                          ep->ep_num);
+               return -EBUSY;
+       }
+
+       /* release old buffers, if any */
+       release_urbs(ep, 0);
+
+       ep->datainterval = fmt->datainterval;
+       ep->maxpacksize = fmt->maxpacksize;
+       ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX);
+
+       if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL)
+               ep->freqn = get_usb_full_speed_rate(params_rate(hw_params));
+       else
+               ep->freqn = get_usb_high_speed_rate(params_rate(hw_params));
+
+       /* calculate the frequency in 16.16 format */
+       ep->freqm = ep->freqn;
+       ep->freqshift = INT_MIN;
+
+       ep->phase = 0;
+
+       switch (ep->type) {
+       case  SND_USB_ENDPOINT_TYPE_DATA:
+               err = data_ep_set_params(ep, hw_params, fmt, sync_ep);
+               break;
+       case  SND_USB_ENDPOINT_TYPE_SYNC:
+               err = sync_ep_set_params(ep, hw_params, fmt);
+               break;
+       default:
+               err = -EINVAL;
+       }
+
+       snd_printdd(KERN_DEBUG "Setting params for ep #%x (type %d, %d urbs), ret=%d\n",
+                  ep->ep_num, ep->type, ep->nurbs, err);
+
+       return err;
 }
 
-/*
- * process after capture sync complete
- * - nothing to do
+/**
+ * snd_usb_endpoint_start: start an snd_usb_endpoint
+ *
+ * @ep: the endpoint to start
+ *
+ * A call to this function will increment the use count of the endpoint.
+ * In case it is not already running, the URBs for this endpoint will be
+ * submitted. Otherwise, this function does nothing.
+ *
+ * Must be balanced to calls of snd_usb_endpoint_stop().
+ *
+ * Returns an error if the URB submission failed, 0 in all other cases.
  */
-static int retire_capture_sync_urb(struct snd_usb_substream *subs,
-                                  struct snd_pcm_runtime *runtime,
-                                  struct urb *urb)
+int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
 {
+       int err;
+       unsigned int i;
+
+       if (ep->chip->shutdown)
+               return -EBADFD;
+
+       /* already running? */
+       if (++ep->use_count != 1)
+               return 0;
+
+       if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
+               return -EINVAL;
+
+       /* just to be sure */
+       deactivate_urbs(ep, 0, 1);
+       wait_clear_urbs(ep);
+
+       ep->active_mask = 0;
+       ep->unlink_mask = 0;
+       ep->phase = 0;
+
+       /*
+        * If this endpoint has a data endpoint as implicit feedback source,
+        * don't start the urbs here. Instead, mark them all as available,
+        * wait for the record urbs to return and queue the playback urbs
+        * from that context.
+        */
+
+       set_bit(EP_FLAG_RUNNING, &ep->flags);
+
+       if (snd_usb_endpoint_implict_feedback_sink(ep)) {
+               for (i = 0; i < ep->nurbs; i++) {
+                       struct snd_urb_ctx *ctx = ep->urb + i;
+                       list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
+               }
+
+               return 0;
+       }
+
+       for (i = 0; i < ep->nurbs; i++) {
+               struct urb *urb = ep->urb[i].urb;
+
+               if (snd_BUG_ON(!urb))
+                       goto __error;
+
+               if (usb_pipeout(ep->pipe)) {
+                       prepare_outbound_urb_sizes(ep, urb->context);
+                       prepare_outbound_urb(ep, urb->context);
+               } else {
+                       prepare_inbound_urb(ep, urb->context);
+               }
+
+               err = usb_submit_urb(urb, GFP_ATOMIC);
+               if (err < 0) {
+                       snd_printk(KERN_ERR "cannot submit urb %d, error %d: %s\n",
+                                  i, err, usb_error_string(err));
+                       goto __error;
+               }
+               set_bit(i, &ep->active_mask);
+       }
+
        return 0;
+
+__error:
+       clear_bit(EP_FLAG_RUNNING, &ep->flags);
+       ep->use_count--;
+       deactivate_urbs(ep, 0, 0);
+       return -EPIPE;
 }
 
-/*
- * prepare urb for capture data pipe
+/**
+ * snd_usb_endpoint_stop: stop an snd_usb_endpoint
+ *
+ * @ep: the endpoint to stop (may be NULL)
  *
- * fill the offset and length of each descriptor.
+ * A call to this function will decrement the use count of the endpoint.
+ * In case the last user has requested the endpoint stop, the URBs will
+ * actually be deactivated.
  *
- * we use a temporary buffer to write the captured data.
- * since the length of written data is determined by host, we cannot
- * write onto the pcm buffer directly...  the data is thus copied
- * later at complete callback to the global buffer.
+ * Must be balanced to calls of snd_usb_endpoint_start().
  */
-static int prepare_capture_urb(struct snd_usb_substream *subs,
-                              struct snd_pcm_runtime *runtime,
-                              struct urb *urb)
+void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
+                          int force, int can_sleep, int wait)
 {
-       int i, offs;
-       struct snd_urb_ctx *ctx = urb->context;
+       if (!ep)
+               return;
 
-       offs = 0;
-       urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       for (i = 0; i < ctx->packets; i++) {
-               urb->iso_frame_desc[i].offset = offs;
-               urb->iso_frame_desc[i].length = subs->curpacksize;
-               offs += subs->curpacksize;
+       if (snd_BUG_ON(ep->use_count == 0))
+               return;
+
+       if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
+               return;
+
+       if (--ep->use_count == 0) {
+               deactivate_urbs(ep, force, can_sleep);
+               ep->data_subs = NULL;
+               ep->sync_slave = NULL;
+               ep->retire_data_urb = NULL;
+               ep->prepare_data_urb = NULL;
+
+               if (wait)
+                       wait_clear_urbs(ep);
        }
-       urb->transfer_buffer_length = offs;
-       urb->number_of_packets = ctx->packets;
-       return 0;
 }
 
-/*
- * process after capture complete
+/**
+ * snd_usb_endpoint_activate: activate an snd_usb_endpoint
+ *
+ * @ep: the endpoint to activate
+ *
+ * If the endpoint is not currently in use, this functions will select the
+ * correct alternate interface setting for the interface of this endpoint.
  *
- * copy the data from each desctiptor to the pcm buffer, and
- * update the current position.
+ * In case of any active users, this functions does nothing.
+ *
+ * Returns an error if usb_set_interface() failed, 0 in all other
+ * cases.
  */
-static int retire_capture_urb(struct snd_usb_substream *subs,
-                             struct snd_pcm_runtime *runtime,
-                             struct urb *urb)
+int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep)
 {
-       unsigned long flags;
-       unsigned char *cp;
-       int i;
-       unsigned int stride, frames, bytes, oldptr;
-       int period_elapsed = 0;
+       if (ep->use_count != 0)
+               return 0;
 
-       stride = runtime->frame_bits >> 3;
+       if (!ep->chip->shutdown &&
+           !test_and_set_bit(EP_FLAG_ACTIVATED, &ep->flags)) {
+               int ret;
 
-       for (i = 0; i < urb->number_of_packets; i++) {
-               cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-               if (urb->iso_frame_desc[i].status && printk_ratelimit()) {
-                       snd_printdd("frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
-                       // continue;
-               }
-               bytes = urb->iso_frame_desc[i].actual_length;
-               frames = bytes / stride;
-               if (!subs->txfr_quirk)
-                       bytes = frames * stride;
-               if (bytes % (runtime->sample_bits >> 3) != 0) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-                       int oldbytes = bytes;
-#endif
-                       bytes = frames * stride;
-                       snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
-                                                       oldbytes, bytes);
-               }
-               /* update the current pointer */
-               spin_lock_irqsave(&subs->lock, flags);
-               oldptr = subs->hwptr_done;
-               subs->hwptr_done += bytes;
-               if (subs->hwptr_done >= runtime->buffer_size * stride)
-                       subs->hwptr_done -= runtime->buffer_size * stride;
-               frames = (bytes + (oldptr % stride)) / stride;
-               subs->transfer_done += frames;
-               if (subs->transfer_done >= runtime->period_size) {
-                       subs->transfer_done -= runtime->period_size;
-                       period_elapsed = 1;
-               }
-               spin_unlock_irqrestore(&subs->lock, flags);
-               /* copy a data chunk */
-               if (oldptr + bytes > runtime->buffer_size * stride) {
-                       unsigned int bytes1 =
-                                       runtime->buffer_size * stride - oldptr;
-                       memcpy(runtime->dma_area + oldptr, cp, bytes1);
-                       memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
-               } else {
-                       memcpy(runtime->dma_area + oldptr, cp, bytes);
+               ret = usb_set_interface(ep->chip->dev, ep->iface, ep->alt_idx);
+               if (ret < 0) {
+                       snd_printk(KERN_ERR "%s() usb_set_interface() failed, ret = %d\n",
+                                               __func__, ret);
+                       clear_bit(EP_FLAG_ACTIVATED, &ep->flags);
+                       return ret;
                }
+
+               return 0;
        }
-       if (period_elapsed)
-               snd_pcm_period_elapsed(subs->pcm_substream);
-       return 0;
+
+       return -EBUSY;
 }
 
-/*
- * Process after capture complete when paused.  Nothing to do.
+/**
+ * snd_usb_endpoint_deactivate: deactivate an snd_usb_endpoint
+ *
+ * @ep: the endpoint to deactivate
+ *
+ * If the endpoint is not currently in use, this functions will select the
+ * alternate interface setting 0 for the interface of this endpoint.
+ *
+ * In case of any active users, this functions does nothing.
+ *
+ * Returns an error if usb_set_interface() failed, 0 in all other
+ * cases.
  */
-static int retire_paused_capture_urb(struct snd_usb_substream *subs,
-                                    struct snd_pcm_runtime *runtime,
-                                    struct urb *urb)
+int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)
 {
-       return 0;
-}
+       if (!ep)
+               return -EINVAL;
 
+       if (ep->use_count != 0)
+               return 0;
 
-/*
- * prepare urb for playback sync pipe
+       if (!ep->chip->shutdown &&
+           test_and_clear_bit(EP_FLAG_ACTIVATED, &ep->flags)) {
+               int ret;
+
+               ret = usb_set_interface(ep->chip->dev, ep->iface, 0);
+               if (ret < 0) {
+                       snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n",
+                                               __func__, ret);
+                       return ret;
+               }
+
+               return 0;
+       }
+
+       return -EBUSY;
+}
+
+/**
+ * snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint
+ *
+ * @ep: the list header of the endpoint to free
  *
- * set up the offset and length to receive the current frequency.
+ * This function does not care for the endpoint's use count but will tear
+ * down all the streaming URBs immediately and free all resources.
  */
-static int prepare_playback_sync_urb(struct snd_usb_substream *subs,
-                                    struct snd_pcm_runtime *runtime,
-                                    struct urb *urb)
+void snd_usb_endpoint_free(struct list_head *head)
 {
-       struct snd_urb_ctx *ctx = urb->context;
+       struct snd_usb_endpoint *ep;
 
-       urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       urb->iso_frame_desc[0].length = min(4u, ctx->subs->syncmaxsize);
-       urb->iso_frame_desc[0].offset = 0;
-       return 0;
+       ep = list_entry(head, struct snd_usb_endpoint, list);
+       release_urbs(ep, 1);
+       kfree(ep);
 }
 
-/*
- * process after playback sync complete
- *
- * Full speed devices report feedback values in 10.14 format as samples per
- * frame, high speed devices in 16.16 format as samples per microframe.
- * Because the Audio Class 1 spec was written before USB 2.0, many high speed
- * devices use a wrong interpretation, some others use an entirely different
- * format.  Therefore, we cannot predict what format any particular device uses
- * and must detect it automatically.
+/**
+ * snd_usb_handle_sync_urb: parse an USB sync packet
+ *
+ * @ep: the endpoint to handle the packet
+ * @sender: the sending endpoint
+ * @urb: the received packet
+ *
+ * This function is called from the context of an endpoint that received
+ * the packet and is used to let another endpoint object handle the payload.
  */
-static int retire_playback_sync_urb(struct snd_usb_substream *subs,
-                                   struct snd_pcm_runtime *runtime,
-                                   struct urb *urb)
+void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
+                            struct snd_usb_endpoint *sender,
+                            const struct urb *urb)
 {
-       unsigned int f;
        int shift;
+       unsigned int f;
        unsigned long flags;
 
+       snd_BUG_ON(ep == sender);
+
+       /*
+        * In case the endpoint is operating in implicit feedback mode, prepare
+        * a new outbound URB that has the same layout as the received packet
+        * and add it to the list of pending urbs. queue_pending_output_urbs()
+        * will take care of them later.
+        */
+       if (snd_usb_endpoint_implict_feedback_sink(ep) &&
+           ep->use_count != 0) {
+
+               /* implicit feedback case */
+               int i, bytes = 0;
+               struct snd_urb_ctx *in_ctx;
+               struct snd_usb_packet_info *out_packet;
+
+               in_ctx = urb->context;
+
+               /* Count overall packet size */
+               for (i = 0; i < in_ctx->packets; i++)
+                       if (urb->iso_frame_desc[i].status == 0)
+                               bytes += urb->iso_frame_desc[i].actual_length;
+
+               /*
+                * skip empty packets. At least M-Audio's Fast Track Ultra stops
+                * streaming once it received a 0-byte OUT URB
+                */
+               if (bytes == 0)
+                       return;
+
+               spin_lock_irqsave(&ep->lock, flags);
+               out_packet = ep->next_packet + ep->next_packet_write_pos;
+
+               /*
+                * Iterate through the inbound packet and prepare the lengths
+                * for the output packet. The OUT packet we are about to send
+                * will have the same amount of payload bytes than the IN
+                * packet we just received.
+                */
+
+               out_packet->packets = in_ctx->packets;
+               for (i = 0; i < in_ctx->packets; i++) {
+                       if (urb->iso_frame_desc[i].status == 0)
+                               out_packet->packet_size[i] =
+                                       urb->iso_frame_desc[i].actual_length / ep->stride;
+                       else
+                               out_packet->packet_size[i] = 0;
+               }
+
+               ep->next_packet_write_pos++;
+               ep->next_packet_write_pos %= MAX_URBS;
+               spin_unlock_irqrestore(&ep->lock, flags);
+               queue_pending_output_urbs(ep);
+
+               return;
+       }
+
+       /*
+        * process after playback sync complete
+        *
+        * Full speed devices report feedback values in 10.14 format as samples
+        * per frame, high speed devices in 16.16 format as samples per
+        * microframe.
+        *
+        * Because the Audio Class 1 spec was written before USB 2.0, many high
+        * speed devices use a wrong interpretation, some others use an
+        * entirely different format.
+        *
+        * Therefore, we cannot predict what format any particular device uses
+        * and must detect it automatically.
+        */
+
        if (urb->iso_frame_desc[0].status != 0 ||
            urb->iso_frame_desc[0].actual_length < 3)
-               return 0;
+               return;
 
        f = le32_to_cpup(urb->transfer_buffer);
        if (urb->iso_frame_desc[0].actual_length == 3)
                f &= 0x00ffffff;
        else
                f &= 0x0fffffff;
+
        if (f == 0)
-               return 0;
+               return;
 
-       if (unlikely(subs->freqshift == INT_MIN)) {
+       if (unlikely(ep->freqshift == INT_MIN)) {
                /*
                 * The first time we see a feedback value, determine its format
                 * by shifting it left or right until it matches the nominal
@@ -569,398 +1128,34 @@ static int retire_playback_sync_urb(struct snd_usb_substream *subs,
                 * differ from the nominal value more than +50% or -25%.
                 */
                shift = 0;
-               while (f < subs->freqn - subs->freqn / 4) {
+               while (f < ep->freqn - ep->freqn / 4) {
                        f <<= 1;
                        shift++;
                }
-               while (f > subs->freqn + subs->freqn / 2) {
+               while (f > ep->freqn + ep->freqn / 2) {
                        f >>= 1;
                        shift--;
                }
-               subs->freqshift = shift;
-       }
-       else if (subs->freqshift >= 0)
-               f <<= subs->freqshift;
+               ep->freqshift = shift;
+       } else if (ep->freqshift >= 0)
+               f <<= ep->freqshift;
        else
-               f >>= -subs->freqshift;
+               f >>= -ep->freqshift;
 
-       if (likely(f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax)) {
+       if (likely(f >= ep->freqn - ep->freqn / 8 && f <= ep->freqmax)) {
                /*
                 * If the frequency looks valid, set it.
                 * This value is referred to in prepare_playback_urb().
                 */
-               spin_lock_irqsave(&subs->lock, flags);
-               subs->freqm = f;
-               spin_unlock_irqrestore(&subs->lock, flags);
+               spin_lock_irqsave(&ep->lock, flags);
+               ep->freqm = f;
+               spin_unlock_irqrestore(&ep->lock, flags);
        } else {
                /*
                 * Out of range; maybe the shift value is wrong.
                 * Reset it so that we autodetect again the next time.
                 */
-               subs->freqshift = INT_MIN;
-       }
-
-       return 0;
-}
-
-/* determine the number of frames in the next packet */
-static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
-{
-       if (subs->fill_max)
-               return subs->maxframesize;
-       else {
-               subs->phase = (subs->phase & 0xffff)
-                       + (subs->freqm << subs->datainterval);
-               return min(subs->phase >> 16, subs->maxframesize);
+               ep->freqshift = INT_MIN;
        }
 }
 
-/*
- * Prepare urb for streaming before playback starts or when paused.
- *
- * We don't have any data, so we send silence.
- */
-static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
-                                      struct snd_pcm_runtime *runtime,
-                                      struct urb *urb)
-{
-       unsigned int i, offs, counts;
-       struct snd_urb_ctx *ctx = urb->context;
-       int stride = runtime->frame_bits >> 3;
-
-       offs = 0;
-       urb->dev = ctx->subs->dev;
-       for (i = 0; i < ctx->packets; ++i) {
-               counts = snd_usb_audio_next_packet_size(subs);
-               urb->iso_frame_desc[i].offset = offs * stride;
-               urb->iso_frame_desc[i].length = counts * stride;
-               offs += counts;
-       }
-       urb->number_of_packets = ctx->packets;
-       urb->transfer_buffer_length = offs * stride;
-       memset(urb->transfer_buffer,
-              runtime->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0,
-              offs * stride);
-       return 0;
-}
-
-/*
- * prepare urb for playback data pipe
- *
- * Since a URB can handle only a single linear buffer, we must use double
- * buffering when the data to be transferred overflows the buffer boundary.
- * To avoid inconsistencies when updating hwptr_done, we use double buffering
- * for all URBs.
- */
-static int prepare_playback_urb(struct snd_usb_substream *subs,
-                               struct snd_pcm_runtime *runtime,
-                               struct urb *urb)
-{
-       int i, stride;
-       unsigned int counts, frames, bytes;
-       unsigned long flags;
-       int period_elapsed = 0;
-       struct snd_urb_ctx *ctx = urb->context;
-
-       stride = runtime->frame_bits >> 3;
-
-       frames = 0;
-       urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       urb->number_of_packets = 0;
-       spin_lock_irqsave(&subs->lock, flags);
-       for (i = 0; i < ctx->packets; i++) {
-               counts = snd_usb_audio_next_packet_size(subs);
-               /* set up descriptor */
-               urb->iso_frame_desc[i].offset = frames * stride;
-               urb->iso_frame_desc[i].length = counts * stride;
-               frames += counts;
-               urb->number_of_packets++;
-               subs->transfer_done += counts;
-               if (subs->transfer_done >= runtime->period_size) {
-                       subs->transfer_done -= runtime->period_size;
-                       period_elapsed = 1;
-                       if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
-                               if (subs->transfer_done > 0) {
-                                       /* FIXME: fill-max mode is not
-                                        * supported yet */
-                                       frames -= subs->transfer_done;
-                                       counts -= subs->transfer_done;
-                                       urb->iso_frame_desc[i].length =
-                                               counts * stride;
-                                       subs->transfer_done = 0;
-                               }
-                               i++;
-                               if (i < ctx->packets) {
-                                       /* add a transfer delimiter */
-                                       urb->iso_frame_desc[i].offset =
-                                               frames * stride;
-                                       urb->iso_frame_desc[i].length = 0;
-                                       urb->number_of_packets++;
-                               }
-                               break;
-                       }
-               }
-               if (period_elapsed) /* finish at the period boundary */
-                       break;
-       }
-       bytes = frames * stride;
-       if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
-               /* err, the transferred area goes over buffer boundary. */
-               unsigned int bytes1 =
-                       runtime->buffer_size * stride - subs->hwptr_done;
-               memcpy(urb->transfer_buffer,
-                      runtime->dma_area + subs->hwptr_done, bytes1);
-               memcpy(urb->transfer_buffer + bytes1,
-                      runtime->dma_area, bytes - bytes1);
-       } else {
-               memcpy(urb->transfer_buffer,
-                      runtime->dma_area + subs->hwptr_done, bytes);
-       }
-       subs->hwptr_done += bytes;
-       if (subs->hwptr_done >= runtime->buffer_size * stride)
-               subs->hwptr_done -= runtime->buffer_size * stride;
-
-       /* update delay with exact number of samples queued */
-       runtime->delay = subs->last_delay;
-       runtime->delay += frames;
-       subs->last_delay = runtime->delay;
-
-       /* realign last_frame_number */
-       subs->last_frame_number = usb_get_current_frame_number(subs->dev);
-       subs->last_frame_number &= 0xFF; /* keep 8 LSBs */
-
-       spin_unlock_irqrestore(&subs->lock, flags);
-       urb->transfer_buffer_length = bytes;
-       if (period_elapsed)
-               snd_pcm_period_elapsed(subs->pcm_substream);
-       return 0;
-}
-
-/*
- * process after playback data complete
- * - decrease the delay count again
- */
-static int retire_playback_urb(struct snd_usb_substream *subs,
-                              struct snd_pcm_runtime *runtime,
-                              struct urb *urb)
-{
-       unsigned long flags;
-       int stride = runtime->frame_bits >> 3;
-       int processed = urb->transfer_buffer_length / stride;
-       int est_delay;
-
-       spin_lock_irqsave(&subs->lock, flags);
-
-       est_delay = snd_usb_pcm_delay(subs, runtime->rate);
-       /* update delay with exact number of samples played */
-       if (processed > subs->last_delay)
-               subs->last_delay = 0;
-       else
-               subs->last_delay -= processed;
-       runtime->delay = subs->last_delay;
-
-       /*
-        * Report when delay estimate is off by more than 2ms.
-        * The error should be lower than 2ms since the estimate relies
-        * on two reads of a counter updated every ms.
-        */
-       if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
-               snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n",
-                       est_delay, subs->last_delay);
-
-       spin_unlock_irqrestore(&subs->lock, flags);
-       return 0;
-}
-
-static const char *usb_error_string(int err)
-{
-       switch (err) {
-       case -ENODEV:
-               return "no device";
-       case -ENOENT:
-               return "endpoint not enabled";
-       case -EPIPE:
-               return "endpoint stalled";
-       case -ENOSPC:
-               return "not enough bandwidth";
-       case -ESHUTDOWN:
-               return "device disabled";
-       case -EHOSTUNREACH:
-               return "device suspended";
-       case -EINVAL:
-       case -EAGAIN:
-       case -EFBIG:
-       case -EMSGSIZE:
-               return "internal error";
-       default:
-               return "unknown error";
-       }
-}
-
-/*
- * set up and start data/sync urbs
- */
-static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime)
-{
-       unsigned int i;
-       int err;
-
-       if (subs->stream->chip->shutdown)
-               return -EBADFD;
-
-       for (i = 0; i < subs->nurbs; i++) {
-               if (snd_BUG_ON(!subs->dataurb[i].urb))
-                       return -EINVAL;
-               if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
-                       snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
-                       goto __error;
-               }
-       }
-       if (subs->syncpipe) {
-               for (i = 0; i < SYNC_URBS; i++) {
-                       if (snd_BUG_ON(!subs->syncurb[i].urb))
-                               return -EINVAL;
-                       if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) {
-                               snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i);
-                               goto __error;
-                       }
-               }
-       }
-
-       subs->active_mask = 0;
-       subs->unlink_mask = 0;
-       subs->running = 1;
-       for (i = 0; i < subs->nurbs; i++) {
-               err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC);
-               if (err < 0) {
-                       snd_printk(KERN_ERR "cannot submit datapipe "
-                                  "for urb %d, error %d: %s\n",
-                                  i, err, usb_error_string(err));
-                       goto __error;
-               }
-               set_bit(i, &subs->active_mask);
-       }
-       if (subs->syncpipe) {
-               for (i = 0; i < SYNC_URBS; i++) {
-                       err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC);
-                       if (err < 0) {
-                               snd_printk(KERN_ERR "cannot submit syncpipe "
-                                          "for urb %d, error %d: %s\n",
-                                          i, err, usb_error_string(err));
-                               goto __error;
-                       }
-                       set_bit(i + 16, &subs->active_mask);
-               }
-       }
-       return 0;
-
- __error:
-       // snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
-       deactivate_urbs(subs, 0, 0);
-       return -EPIPE;
-}
-
-
-/*
- */
-static struct snd_urb_ops audio_urb_ops[2] = {
-       {
-               .prepare =      prepare_nodata_playback_urb,
-               .retire =       retire_playback_urb,
-               .prepare_sync = prepare_playback_sync_urb,
-               .retire_sync =  retire_playback_sync_urb,
-       },
-       {
-               .prepare =      prepare_capture_urb,
-               .retire =       retire_capture_urb,
-               .prepare_sync = prepare_capture_sync_urb,
-               .retire_sync =  retire_capture_sync_urb,
-       },
-};
-
-/*
- * initialize the substream instance.
- */
-
-void snd_usb_init_substream(struct snd_usb_stream *as,
-                           int stream, struct audioformat *fp)
-{
-       struct snd_usb_substream *subs = &as->substream[stream];
-
-       INIT_LIST_HEAD(&subs->fmt_list);
-       spin_lock_init(&subs->lock);
-
-       subs->stream = as;
-       subs->direction = stream;
-       subs->dev = as->chip->dev;
-       subs->txfr_quirk = as->chip->txfr_quirk;
-       subs->ops = audio_urb_ops[stream];
-       if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH)
-               subs->ops.prepare_sync = prepare_capture_sync_urb_hs;
-
-       snd_usb_set_pcm_ops(as->pcm, stream);
-
-       list_add_tail(&fp->list, &subs->fmt_list);
-       subs->formats |= fp->formats;
-       subs->endpoint = fp->endpoint;
-       subs->num_formats++;
-       subs->fmt_type = fp->fmt_type;
-}
-
-int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_usb_substream *subs = substream->runtime->private_data;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               subs->ops.prepare = prepare_playback_urb;
-               return 0;
-       case SNDRV_PCM_TRIGGER_STOP:
-               return deactivate_urbs(subs, 0, 0);
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               subs->ops.prepare = prepare_nodata_playback_urb;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_usb_substream *subs = substream->runtime->private_data;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               subs->ops.retire = retire_capture_urb;
-               return start_urbs(subs, substream->runtime);
-       case SNDRV_PCM_TRIGGER_STOP:
-               return deactivate_urbs(subs, 0, 0);
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               subs->ops.retire = retire_paused_capture_urb;
-               return 0;
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               subs->ops.retire = retire_capture_urb;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-int snd_usb_substream_prepare(struct snd_usb_substream *subs,
-                             struct snd_pcm_runtime *runtime)
-{
-       /* clear urbs (to be sure) */
-       deactivate_urbs(subs, 0, 1);
-       wait_clear_urbs(subs);
-
-       /* for playback, submit the URBs now; otherwise, the first hwptr_done
-        * updates for all URBs would happen at the same time when starting */
-       if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
-               subs->ops.prepare = prepare_nodata_playback_urb;
-               return start_urbs(subs, runtime);
-       }
-
-       return 0;
-}
-
index 88eb63a636eb28fa3b0fc56e05340d4be581cd72..ee2723fb174f61ddb9a3c0c0224bc065b36ba173 100644 (file)
@@ -1,21 +1,29 @@
 #ifndef __USBAUDIO_ENDPOINT_H
 #define __USBAUDIO_ENDPOINT_H
 
-void snd_usb_init_substream(struct snd_usb_stream *as,
-                           int stream,
-                           struct audioformat *fp);
+#define SND_USB_ENDPOINT_TYPE_DATA     0
+#define SND_USB_ENDPOINT_TYPE_SYNC     1
 
-int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
-                               unsigned int period_bytes,
-                               unsigned int rate,
-                               unsigned int frame_bits);
+struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
+                                             struct usb_host_interface *alts,
+                                             int ep_num, int direction, int type);
 
-void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force);
+int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
+                               struct snd_pcm_hw_params *hw_params,
+                               struct audioformat *fmt,
+                               struct snd_usb_endpoint *sync_ep);
 
-int snd_usb_substream_prepare(struct snd_usb_substream *subs,
-                             struct snd_pcm_runtime *runtime);
+int  snd_usb_endpoint_start(struct snd_usb_endpoint *ep);
+void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
+                          int force, int can_sleep, int wait);
+int  snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
+int  snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
+void snd_usb_endpoint_free(struct list_head *head);
 
-int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd);
-int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
+int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep);
+
+void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
+                            struct snd_usb_endpoint *sender,
+                            const struct urb *urb);
 
 #endif /* __USBAUDIO_ENDPOINT_H */
index ab23869c01bb6734073b65c6c397fe177224c217..4f40ba82316316fdad18839c1bc906af2a2af66f 100644 (file)
@@ -486,7 +486,7 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
 /*
  * TLV callback for mixer volume controls
  */
-static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
                         unsigned int size, unsigned int __user *_tlv)
 {
        struct usb_mixer_elem_info *cval = kcontrol->private_data;
@@ -770,6 +770,26 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
                                  struct snd_kcontrol *kctl)
 {
        switch (cval->mixer->chip->usb_id) {
+       case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
+       case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
+               if (strcmp(kctl->id.name, "Effect Duration") == 0) {
+                       snd_printk(KERN_INFO
+                               "usb-audio: set quirk for FTU Effect Duration\n");
+                       cval->min = 0x0000;
+                       cval->max = 0x7f00;
+                       cval->res = 0x0100;
+                       break;
+               }
+               if (strcmp(kctl->id.name, "Effect Volume") == 0 ||
+                   strcmp(kctl->id.name, "Effect Feedback Volume") == 0) {
+                       snd_printk(KERN_INFO
+                               "usb-audio: set quirks for FTU Effect Feedback/Volume\n");
+                       cval->min = 0x00;
+                       cval->max = 0x7f;
+                       break;
+               }
+               break;
+
        case USB_ID(0x0471, 0x0101):
        case USB_ID(0x0471, 0x0104):
        case USB_ID(0x0471, 0x0105):
@@ -1121,9 +1141,6 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                len = snd_usb_copy_string_desc(state, nameid,
                                kctl->id.name, sizeof(kctl->id.name));
 
-       /* get min/max values */
-       get_min_max_with_quirks(cval, 0, kctl);
-
        switch (control) {
        case UAC_FU_MUTE:
        case UAC_FU_VOLUME:
@@ -1155,17 +1172,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                }
                append_ctl_name(kctl, control == UAC_FU_MUTE ?
                                " Switch" : " Volume");
-               if (control == UAC_FU_VOLUME) {
-                       check_mapped_dB(map, cval);
-                       if (cval->dBmin < cval->dBmax || !cval->initialized) {
-                               kctl->tlv.c = mixer_vol_tlv;
-                               kctl->vd[0].access |= 
-                                       SNDRV_CTL_ELEM_ACCESS_TLV_READ |
-                                       SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
-                       }
-               }
                break;
-
        default:
                if (! len)
                        strlcpy(kctl->id.name, audio_feature_info[control-1].name,
@@ -1173,6 +1180,19 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                break;
        }
 
+       /* get min/max values */
+       get_min_max_with_quirks(cval, 0, kctl);
+
+       if (control == UAC_FU_VOLUME) {
+               check_mapped_dB(map, cval);
+               if (cval->dBmin < cval->dBmax || !cval->initialized) {
+                       kctl->tlv.c = snd_usb_mixer_vol_tlv;
+                       kctl->vd[0].access |=
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+                               SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+               }
+       }
+
        range = (cval->max - cval->min) / cval->res;
        /* Are there devices with volume range more than 255? I use a bit more
         * to be sure. 384 is a resolution magic number found on Logitech
@@ -1388,7 +1408,7 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *r
        for (pin = 0; pin < input_pins; pin++) {
                err = parse_audio_unit(state, desc->baSourceID[pin]);
                if (err < 0)
-                       return err;
+                       continue;
                err = check_input_term(state, desc->baSourceID[pin], &iterm);
                if (err < 0)
                        return err;
index 81b2d8a32fb0f82e33475fabf6aa890ca7a675f4..a7f3d45a8acf1f6255a86f88038ca64012069137 100644 (file)
@@ -68,4 +68,7 @@ int snd_usb_mixer_activate(struct usb_mixer_interface *mixer);
 int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
                              struct snd_kcontrol *kctl);
 
+int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+                         unsigned int size, unsigned int __user *_tlv);
+
 #endif /* __USBMIXER_H */
index f1324c423835c8ade54cdb30730e7999b3cec853..41daaa24c25f465e6ff209118d4a24f6f68ec220 100644 (file)
@@ -288,6 +288,15 @@ static struct usbmix_name_map scratch_live_map[] = {
        { 0 } /* terminator */
 };
 
+static struct usbmix_name_map ebox44_map[] = {
+       { 4, NULL }, /* FU */
+       { 6, NULL }, /* MU */
+       { 7, NULL }, /* FU */
+       { 10, NULL }, /* FU */
+       { 11, NULL }, /* MU */
+       { 0 }
+};
+
 /* "Gamesurround Muse Pocket LT" looks same like "Sound Blaster MP3+"
  *  most importand difference is SU[8], it should be set to "Capture Source"
  *  to make alsamixer and PA working properly.
@@ -371,6 +380,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .map = scratch_live_map,
                .ignore_ctl_error = 1,
        },
+       {
+               .id = USB_ID(0x200c, 0x1018),
+               .map = ebox44_map,
+       },
        { 0 } /* terminator */
 };
 
index ab125ee0b0f0e20091a13a7b354fc9f9abb69590..41f4b69119205d04f9b50e1e6ccc3bd5d16d980f 100644 (file)
 
 extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
 
+/* private_free callback */
+static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
+{
+       kfree(kctl->private_data);
+       kctl->private_data = NULL;
+}
+
+/* This function allows for the creation of standard UAC controls.
+ * See the quirks for M-Audio FTUs or Ebox-44.
+ * If you don't want to set a TLV callback pass NULL.
+ *
+ * Since there doesn't seem to be a devices that needs a multichannel
+ * version, we keep it mono for simplicity.
+ */
+static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
+                               unsigned int unitid,
+                               unsigned int control,
+                               unsigned int cmask,
+                               int val_type,
+                               const char *name,
+                               snd_kcontrol_tlv_rw_t *tlv_callback)
+{
+       int err;
+       struct usb_mixer_elem_info *cval;
+       struct snd_kcontrol *kctl;
+
+       cval = kzalloc(sizeof(*cval), GFP_KERNEL);
+       if (!cval)
+               return -ENOMEM;
+
+       cval->id = unitid;
+       cval->mixer = mixer;
+       cval->val_type = val_type;
+       cval->channels = 1;
+       cval->control = control;
+       cval->cmask = cmask;
+
+       /* get_min_max() is called only for integer volumes later,
+        * so provide a short-cut for booleans */
+       cval->min = 0;
+       cval->max = 1;
+       cval->res = 0;
+       cval->dBmin = 0;
+       cval->dBmax = 0;
+
+       /* Create control */
+       kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
+       if (!kctl) {
+               kfree(cval);
+               return -ENOMEM;
+       }
+
+       /* Set name */
+       snprintf(kctl->id.name, sizeof(kctl->id.name), name);
+       kctl->private_free = usb_mixer_elem_free;
+
+       /* set TLV */
+       if (tlv_callback) {
+               kctl->tlv.c = tlv_callback;
+               kctl->vd[0].access |=
+                       SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+                       SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+       }
+       /* Add control to mixer */
+       err = snd_usb_mixer_add_control(mixer, kctl);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
 /*
  * Sound Blaster remote control configuration
  *
@@ -495,60 +566,218 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
 }
 
 /* M-Audio FastTrack Ultra quirks */
+/* FTU Effect switch */
+struct snd_ftu_eff_switch_priv_val {
+       struct usb_mixer_interface *mixer;
+       int cached_value;
+       int is_cached;
+};
 
-/* private_free callback */
-static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
+static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
 {
-       kfree(kctl->private_data);
-       kctl->private_data = NULL;
+       static const char *texts[8] = {"Room 1",
+                                      "Room 2",
+                                      "Room 3",
+                                      "Hall 1",
+                                      "Hall 2",
+                                      "Plate",
+                                      "Delay",
+                                      "Echo"
+       };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 8;
+       if (uinfo->value.enumerated.item > 7)
+               uinfo->value.enumerated.item = 7;
+       strcpy(uinfo->value.enumerated.name,
+               texts[uinfo->value.enumerated.item]);
+
+       return 0;
 }
 
-static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer,
-                                    int in, int out, const char *name)
+static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
+                                       struct snd_ctl_elem_value *ucontrol)
 {
-       struct usb_mixer_elem_info *cval;
+       struct snd_usb_audio *chip;
+       struct usb_mixer_interface *mixer;
+       struct snd_ftu_eff_switch_priv_val *pval;
+       int err;
+       unsigned char value[2];
+
+       const int id = 6;
+       const int validx = 1;
+       const int val_len = 2;
+
+       value[0] = 0x00;
+       value[1] = 0x00;
+
+       pval = (struct snd_ftu_eff_switch_priv_val *)
+               kctl->private_value;
+
+       if (pval->is_cached) {
+               ucontrol->value.enumerated.item[0] = pval->cached_value;
+               return 0;
+       }
+
+       mixer = (struct usb_mixer_interface *) pval->mixer;
+       if (snd_BUG_ON(!mixer))
+               return -EINVAL;
+
+       chip = (struct snd_usb_audio *) mixer->chip;
+       if (snd_BUG_ON(!chip))
+               return -EINVAL;
+
+
+       err = snd_usb_ctl_msg(chip->dev,
+                       usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
+                       USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+                       validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
+                       value, val_len);
+       if (err < 0)
+               return err;
+
+       ucontrol->value.enumerated.item[0] = value[0];
+       pval->cached_value = value[0];
+       pval->is_cached = 1;
+
+       return 0;
+}
+
+static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_usb_audio *chip;
+       struct snd_ftu_eff_switch_priv_val *pval;
+
+       struct usb_mixer_interface *mixer;
+       int changed, cur_val, err, new_val;
+       unsigned char value[2];
+
+
+       const int id = 6;
+       const int validx = 1;
+       const int val_len = 2;
+
+       changed = 0;
+
+       pval = (struct snd_ftu_eff_switch_priv_val *)
+               kctl->private_value;
+       cur_val = pval->cached_value;
+       new_val = ucontrol->value.enumerated.item[0];
+
+       mixer = (struct usb_mixer_interface *) pval->mixer;
+       if (snd_BUG_ON(!mixer))
+               return -EINVAL;
+
+       chip = (struct snd_usb_audio *) mixer->chip;
+       if (snd_BUG_ON(!chip))
+               return -EINVAL;
+
+       if (!pval->is_cached) {
+               /* Read current value */
+               err = snd_usb_ctl_msg(chip->dev,
+                               usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
+                               USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+                               validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
+                               value, val_len);
+               if (err < 0)
+                       return err;
+
+               cur_val = value[0];
+               pval->cached_value = cur_val;
+               pval->is_cached = 1;
+       }
+       /* update value if needed */
+       if (cur_val != new_val) {
+               value[0] = new_val;
+               value[1] = 0;
+               err = snd_usb_ctl_msg(chip->dev,
+                               usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
+                               USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+                               validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
+                               value, val_len);
+               if (err < 0)
+                       return err;
+
+               pval->cached_value = new_val;
+               pval->is_cached = 1;
+               changed = 1;
+       }
+
+       return changed;
+}
+
+static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer)
+{
+       static struct snd_kcontrol_new template = {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Effect Program Switch",
+               .index = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = snd_ftu_eff_switch_info,
+               .get = snd_ftu_eff_switch_get,
+               .put = snd_ftu_eff_switch_put
+       };
+
+       int err;
        struct snd_kcontrol *kctl;
+       struct snd_ftu_eff_switch_priv_val *pval;
 
-       cval = kzalloc(sizeof(*cval), GFP_KERNEL);
-       if (!cval)
+       pval = kzalloc(sizeof(*pval), GFP_KERNEL);
+       if (!pval)
                return -ENOMEM;
 
-       cval->id = 5;
-       cval->mixer = mixer;
-       cval->val_type = USB_MIXER_S16;
-       cval->channels = 1;
-       cval->control = out + 1;
-       cval->cmask = 1 << in;
+       pval->cached_value = 0;
+       pval->is_cached = 0;
+       pval->mixer = mixer;
 
-       kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
+       template.private_value = (unsigned long) pval;
+       kctl = snd_ctl_new1(&template, mixer->chip);
        if (!kctl) {
-               kfree(cval);
+               kfree(pval);
                return -ENOMEM;
        }
 
-       snprintf(kctl->id.name, sizeof(kctl->id.name), name);
-       kctl->private_free = usb_mixer_elem_free;
-       return snd_usb_mixer_add_control(mixer, kctl);
+       err = snd_ctl_add(mixer->chip->card, kctl);
+       if (err < 0)
+               return err;
+
+       return 0;
 }
 
-static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+/* Create volume controls for FTU devices*/
+static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
 {
        char name[64];
+       unsigned int control, cmask;
        int in, out, err;
 
+       const unsigned int id = 5;
+       const int val_type = USB_MIXER_S16;
+
        for (out = 0; out < 8; out++) {
+               control = out + 1;
                for (in = 0; in < 8; in++) {
+                       cmask = 1 << in;
                        snprintf(name, sizeof(name),
-                                "AIn%d - Out%d Capture Volume", in  + 1, out + 1);
-                       err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+                               "AIn%d - Out%d Capture Volume",
+                               in  + 1, out + 1);
+                       err = snd_create_std_mono_ctl(mixer, id, control,
+                                                       cmask, val_type, name,
+                                                       &snd_usb_mixer_vol_tlv);
                        if (err < 0)
                                return err;
                }
-
                for (in = 8; in < 16; in++) {
+                       cmask = 1 << in;
                        snprintf(name, sizeof(name),
-                                "DIn%d - Out%d Playback Volume", in - 7, out + 1);
-                       err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+                               "DIn%d - Out%d Playback Volume",
+                               in - 7, out + 1);
+                       err = snd_create_std_mono_ctl(mixer, id, control,
+                                                       cmask, val_type, name,
+                                                       &snd_usb_mixer_vol_tlv);
                        if (err < 0)
                                return err;
                }
@@ -557,6 +786,191 @@ static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
        return 0;
 }
 
+/* This control needs a volume quirk, see mixer.c */
+static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
+{
+       static const char name[] = "Effect Volume";
+       const unsigned int id = 6;
+       const int val_type = USB_MIXER_U8;
+       const unsigned int control = 2;
+       const unsigned int cmask = 0;
+
+       return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
+                                       name, snd_usb_mixer_vol_tlv);
+}
+
+/* This control needs a volume quirk, see mixer.c */
+static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
+{
+       static const char name[] = "Effect Duration";
+       const unsigned int id = 6;
+       const int val_type = USB_MIXER_S16;
+       const unsigned int control = 3;
+       const unsigned int cmask = 0;
+
+       return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
+                                       name, snd_usb_mixer_vol_tlv);
+}
+
+/* This control needs a volume quirk, see mixer.c */
+static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
+{
+       static const char name[] = "Effect Feedback Volume";
+       const unsigned int id = 6;
+       const int val_type = USB_MIXER_U8;
+       const unsigned int control = 4;
+       const unsigned int cmask = 0;
+
+       return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
+                                       name, NULL);
+}
+
+static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer)
+{
+       unsigned int cmask;
+       int err, ch;
+       char name[48];
+
+       const unsigned int id = 7;
+       const int val_type = USB_MIXER_S16;
+       const unsigned int control = 7;
+
+       for (ch = 0; ch < 4; ++ch) {
+               cmask = 1 << ch;
+               snprintf(name, sizeof(name),
+                       "Effect Return %d Volume", ch + 1);
+               err = snd_create_std_mono_ctl(mixer, id, control,
+                                               cmask, val_type, name,
+                                               snd_usb_mixer_vol_tlv);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer)
+{
+       unsigned int  cmask;
+       int err, ch;
+       char name[48];
+
+       const unsigned int id = 5;
+       const int val_type = USB_MIXER_S16;
+       const unsigned int control = 9;
+
+       for (ch = 0; ch < 8; ++ch) {
+               cmask = 1 << ch;
+               snprintf(name, sizeof(name),
+                       "Effect Send AIn%d Volume", ch + 1);
+               err = snd_create_std_mono_ctl(mixer, id, control, cmask,
+                                               val_type, name,
+                                               snd_usb_mixer_vol_tlv);
+               if (err < 0)
+                       return err;
+       }
+       for (ch = 8; ch < 16; ++ch) {
+               cmask = 1 << ch;
+               snprintf(name, sizeof(name),
+                       "Effect Send DIn%d Volume", ch - 7);
+               err = snd_create_std_mono_ctl(mixer, id, control, cmask,
+                                               val_type, name,
+                                               snd_usb_mixer_vol_tlv);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer)
+{
+       int err;
+
+       err = snd_ftu_create_volume_ctls(mixer);
+       if (err < 0)
+               return err;
+
+       err = snd_ftu_create_effect_switch(mixer);
+       if (err < 0)
+               return err;
+       err = snd_ftu_create_effect_volume_ctl(mixer);
+       if (err < 0)
+               return err;
+
+       err = snd_ftu_create_effect_duration_ctl(mixer);
+       if (err < 0)
+               return err;
+
+       err = snd_ftu_create_effect_feedback_ctl(mixer);
+       if (err < 0)
+               return err;
+
+       err = snd_ftu_create_effect_return_ctls(mixer);
+       if (err < 0)
+               return err;
+
+       err = snd_ftu_create_effect_send_ctls(mixer);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+
+/*
+ * Create mixer for Electrix Ebox-44
+ *
+ * The mixer units from this device are corrupt, and even where they
+ * are valid they presents mono controls as L and R channels of
+ * stereo. So we create a good mixer in code.
+ */
+
+static int snd_ebox44_create_mixer(struct usb_mixer_interface *mixer)
+{
+       int err;
+
+       err = snd_create_std_mono_ctl(mixer, 4, 1, 0x0, USB_MIXER_INV_BOOLEAN,
+                               "Headphone Playback Switch", NULL);
+       if (err < 0)
+               return err;
+       err = snd_create_std_mono_ctl(mixer, 4, 2, 0x1, USB_MIXER_S16,
+                               "Headphone A Mix Playback Volume", NULL);
+       if (err < 0)
+               return err;
+       err = snd_create_std_mono_ctl(mixer, 4, 2, 0x2, USB_MIXER_S16,
+                               "Headphone B Mix Playback Volume", NULL);
+       if (err < 0)
+               return err;
+
+       err = snd_create_std_mono_ctl(mixer, 7, 1, 0x0, USB_MIXER_INV_BOOLEAN,
+                               "Output Playback Switch", NULL);
+       if (err < 0)
+               return err;
+       err = snd_create_std_mono_ctl(mixer, 7, 2, 0x1, USB_MIXER_S16,
+                               "Output A Playback Volume", NULL);
+       if (err < 0)
+               return err;
+       err = snd_create_std_mono_ctl(mixer, 7, 2, 0x2, USB_MIXER_S16,
+                               "Output B Playback Volume", NULL);
+       if (err < 0)
+               return err;
+
+       err = snd_create_std_mono_ctl(mixer, 10, 1, 0x0, USB_MIXER_INV_BOOLEAN,
+                               "Input Capture Switch", NULL);
+       if (err < 0)
+               return err;
+       err = snd_create_std_mono_ctl(mixer, 10, 2, 0x1, USB_MIXER_S16,
+                               "Input A Capture Volume", NULL);
+       if (err < 0)
+               return err;
+       err = snd_create_std_mono_ctl(mixer, 10, 2, 0x2, USB_MIXER_S16,
+                               "Input B Capture Volume", NULL);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
 void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
                               unsigned char samplerate_id)
 {
@@ -600,7 +1014,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 
        case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
        case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
-               err = snd_maudio_ftu_create_mixer(mixer);
+               err = snd_ftu_create_mixer(mixer);
                break;
 
        case USB_ID(0x0b05, 0x1739):
@@ -619,6 +1033,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
                                snd_nativeinstruments_ta10_mixers,
                                ARRAY_SIZE(snd_nativeinstruments_ta10_mixers));
                break;
+
+       case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */
+               err = snd_ebox44_create_mixer(mixer);
+               break;
        }
 
        return err;
index 0eed6115c2d444e166d770008238d5e11e4800fb..24839d932648c81849ecfe63214a8124d914dd0e 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/ratelimit.h>
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/audio-v2.h>
@@ -34,6 +35,9 @@
 #include "clock.h"
 #include "power.h"
 
+#define SUBSTREAM_FLAG_DATA_EP_STARTED 0
+#define SUBSTREAM_FLAG_SYNC_EP_STARTED 1
+
 /* return the estimated delay based on USB frame counters */
 snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
                                    unsigned int rate)
@@ -208,6 +212,84 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
        }
 }
 
+static int start_endpoints(struct snd_usb_substream *subs)
+{
+       int err;
+
+       if (!subs->data_endpoint)
+               return -EINVAL;
+
+       if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) {
+               struct snd_usb_endpoint *ep = subs->data_endpoint;
+
+               snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep);
+
+               ep->data_subs = subs;
+               err = snd_usb_endpoint_start(ep);
+               if (err < 0) {
+                       clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags);
+                       return err;
+               }
+       }
+
+       if (subs->sync_endpoint &&
+           !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {
+               struct snd_usb_endpoint *ep = subs->sync_endpoint;
+
+               snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep);
+
+               ep->sync_slave = subs->data_endpoint;
+               err = snd_usb_endpoint_start(ep);
+               if (err < 0) {
+                       clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static void stop_endpoints(struct snd_usb_substream *subs,
+                          int force, int can_sleep, int wait)
+{
+       if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags))
+               snd_usb_endpoint_stop(subs->sync_endpoint,
+                                     force, can_sleep, wait);
+
+       if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags))
+               snd_usb_endpoint_stop(subs->data_endpoint,
+                                     force, can_sleep, wait);
+}
+
+static int activate_endpoints(struct snd_usb_substream *subs)
+{
+       if (subs->sync_endpoint) {
+               int ret;
+
+               ret = snd_usb_endpoint_activate(subs->sync_endpoint);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return snd_usb_endpoint_activate(subs->data_endpoint);
+}
+
+static int deactivate_endpoints(struct snd_usb_substream *subs)
+{
+       int reta, retb;
+
+       reta = snd_usb_endpoint_deactivate(subs->sync_endpoint);
+       retb = snd_usb_endpoint_deactivate(subs->data_endpoint);
+
+       if (reta < 0)
+               return reta;
+
+       if (retb < 0)
+               return retb;
+
+       return 0;
+}
+
 /*
  * find a matching format and set up the interface
  */
@@ -219,7 +301,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
        struct usb_interface *iface;
        unsigned int ep, attr;
        int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
-       int err;
+       int err, implicit_fb = 0;
 
        iface = usb_ifnum_to_if(dev, fmt->iface);
        if (WARN_ON(!iface))
@@ -232,40 +314,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
        if (fmt == subs->cur_audiofmt)
                return 0;
 
-       /* close the old interface */
-       if (subs->interface >= 0 && subs->interface != fmt->iface) {
-               if (usb_set_interface(subs->dev, subs->interface, 0) < 0) {
-                       snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed\n",
-                               dev->devnum, fmt->iface, fmt->altsetting);
-                       return -EIO;
-               }
-               subs->interface = -1;
-               subs->altset_idx = 0;
-       }
-
-       /* set interface */
-       if (subs->interface != fmt->iface || subs->altset_idx != fmt->altset_idx) {
-               if (usb_set_interface(dev, fmt->iface, fmt->altsetting) < 0) {
-                       snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n",
-                                  dev->devnum, fmt->iface, fmt->altsetting);
-                       return -EIO;
-               }
-               snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting);
-               subs->interface = fmt->iface;
-               subs->altset_idx = fmt->altset_idx;
-       }
-
-       /* create a data pipe */
-       ep = fmt->endpoint & USB_ENDPOINT_NUMBER_MASK;
-       if (is_playback)
-               subs->datapipe = usb_sndisocpipe(dev, ep);
-       else
-               subs->datapipe = usb_rcvisocpipe(dev, ep);
-       subs->datainterval = fmt->datainterval;
-       subs->syncpipe = subs->syncinterval = 0;
-       subs->maxpacksize = fmt->maxpacksize;
-       subs->syncmaxsize = 0;
-       subs->fill_max = 0;
+       subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
+                                                  alts, fmt->endpoint, subs->direction,
+                                                  SND_USB_ENDPOINT_TYPE_DATA);
+       if (!subs->data_endpoint)
+               return -EINVAL;
 
        /* we need a sync pipe in async OUT or adaptive IN mode */
        /* check the number of EP, since some devices have broken
@@ -273,8 +326,25 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
         * assume it as adaptive-out or sync-in.
         */
        attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
+
+       switch (subs->stream->chip->usb_id) {
+       case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
+       case USB_ID(0x0763, 0x2081):
+               if (is_playback) {
+                       implicit_fb = 1;
+                       ep = 0x81;
+                       iface = usb_ifnum_to_if(dev, 2);
+
+                       if (!iface || iface->num_altsetting == 0)
+                               return -EINVAL;
+
+                       alts = &iface->altsetting[1];
+                       goto add_sync_ep;
+               }
+       }
+
        if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
-            (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
+            (!is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
            altsd->bNumEndpoints >= 2) {
                /* check sync-pipe endpoint */
                /* ... and check descriptor size before accessing bSynchAddress
@@ -282,7 +352,8 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
                   the audio fields in the endpoint descriptors */
                if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 ||
                    (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
-                    get_endpoint(alts, 1)->bSynchAddress != 0)) {
+                    get_endpoint(alts, 1)->bSynchAddress != 0 &&
+                    !implicit_fb)) {
                        snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
                                   dev->devnum, fmt->iface, fmt->altsetting);
                        return -EINVAL;
@@ -290,33 +361,27 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
                ep = get_endpoint(alts, 1)->bEndpointAddress;
                if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
                    (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
-                    (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
+                    (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)) ||
+                    ( is_playback && !implicit_fb))) {
                        snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
                                   dev->devnum, fmt->iface, fmt->altsetting);
                        return -EINVAL;
                }
-               ep &= USB_ENDPOINT_NUMBER_MASK;
-               if (is_playback)
-                       subs->syncpipe = usb_rcvisocpipe(dev, ep);
-               else
-                       subs->syncpipe = usb_sndisocpipe(dev, ep);
-               if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
-                   get_endpoint(alts, 1)->bRefresh >= 1 &&
-                   get_endpoint(alts, 1)->bRefresh <= 9)
-                       subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
-               else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
-                       subs->syncinterval = 1;
-               else if (get_endpoint(alts, 1)->bInterval >= 1 &&
-                        get_endpoint(alts, 1)->bInterval <= 16)
-                       subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
-               else
-                       subs->syncinterval = 3;
-               subs->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
-       }
-
-       /* always fill max packet size */
-       if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX)
-               subs->fill_max = 1;
+
+               implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK)
+                               == USB_ENDPOINT_USAGE_IMPLICIT_FB;
+
+add_sync_ep:
+               subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
+                                                          alts, ep, !subs->direction,
+                                                          implicit_fb ?
+                                                               SND_USB_ENDPOINT_TYPE_DATA :
+                                                               SND_USB_ENDPOINT_TYPE_SYNC);
+               if (!subs->sync_endpoint)
+                       return -EINVAL;
+
+               subs->data_endpoint->sync_master = subs->sync_endpoint;
+       }
 
        if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0)
                return err;
@@ -390,15 +455,30 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
        if (changed) {
                mutex_lock(&subs->stream->chip->shutdown_mutex);
                /* format changed */
-               snd_usb_release_substream_urbs(subs, 0);
-               /* influenced: period_bytes, channels, rate, format, */
-               ret = snd_usb_init_substream_urbs(subs, params_period_bytes(hw_params),
-                                                 params_rate(hw_params),
-                                                 snd_pcm_format_physical_width(params_format(hw_params)) *
-                                                       params_channels(hw_params));
+               stop_endpoints(subs, 0, 0, 0);
+               deactivate_endpoints(subs);
+
+               ret = activate_endpoints(subs);
+               if (ret < 0)
+                       goto unlock;
+
+               ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt,
+                                                 subs->sync_endpoint);
+               if (ret < 0)
+                       goto unlock;
+
+               if (subs->sync_endpoint)
+                       ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
+                                                         hw_params, fmt, NULL);
+unlock:
                mutex_unlock(&subs->stream->chip->shutdown_mutex);
        }
 
+       if (ret == 0) {
+               subs->interface = fmt->iface;
+               subs->altset_idx = fmt->altset_idx;
+       }
+
        return ret;
 }
 
@@ -415,7 +495,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
        subs->cur_rate = 0;
        subs->period_bytes = 0;
        mutex_lock(&subs->stream->chip->shutdown_mutex);
-       snd_usb_release_substream_urbs(subs, 0);
+       stop_endpoints(subs, 0, 1, 1);
        mutex_unlock(&subs->stream->chip->shutdown_mutex);
        return snd_pcm_lib_free_vmalloc_buffer(substream);
 }
@@ -435,19 +515,28 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
                return -ENXIO;
        }
 
+       if (snd_BUG_ON(!subs->data_endpoint))
+               return -EIO;
+
        /* some unit conversions in runtime */
-       subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
-       subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
+       subs->data_endpoint->maxframesize =
+               bytes_to_frames(runtime, subs->data_endpoint->maxpacksize);
+       subs->data_endpoint->curframesize =
+               bytes_to_frames(runtime, subs->data_endpoint->curpacksize);
 
        /* reset the pointer */
        subs->hwptr_done = 0;
        subs->transfer_done = 0;
-       subs->phase = 0;
        subs->last_delay = 0;
        subs->last_frame_number = 0;
        runtime->delay = 0;
 
-       return snd_usb_substream_prepare(subs, runtime);
+       /* for playback, submit the URBs now; otherwise, the first hwptr_done
+        * updates for all URBs would happen at the same time when starting */
+       if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
+               return start_endpoints(subs);
+
+       return 0;
 }
 
 static struct snd_pcm_hardware snd_usb_hardware =
@@ -842,16 +931,171 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
 
 static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
 {
+       int ret;
        struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
        struct snd_usb_substream *subs = &as->substream[direction];
 
-       if (!as->chip->shutdown && subs->interface >= 0) {
-               usb_set_interface(subs->dev, subs->interface, 0);
-               subs->interface = -1;
-       }
+       stop_endpoints(subs, 0, 0, 0);
+       ret = deactivate_endpoints(subs);
        subs->pcm_substream = NULL;
        snd_usb_autosuspend(subs->stream->chip);
-       return 0;
+
+       return ret;
+}
+
+/* Since a URB can handle only a single linear buffer, we must use double
+ * buffering when the data to be transferred overflows the buffer boundary.
+ * To avoid inconsistencies when updating hwptr_done, we use double buffering
+ * for all URBs.
+ */
+static void retire_capture_urb(struct snd_usb_substream *subs,
+                              struct urb *urb)
+{
+       struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+       unsigned int stride, frames, bytes, oldptr;
+       int i, period_elapsed = 0;
+       unsigned long flags;
+       unsigned char *cp;
+
+       stride = runtime->frame_bits >> 3;
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+               if (urb->iso_frame_desc[i].status && printk_ratelimit()) {
+                       snd_printdd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
+                       // continue;
+               }
+               bytes = urb->iso_frame_desc[i].actual_length;
+               frames = bytes / stride;
+               if (!subs->txfr_quirk)
+                       bytes = frames * stride;
+               if (bytes % (runtime->sample_bits >> 3) != 0) {
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+                       int oldbytes = bytes;
+#endif
+                       bytes = frames * stride;
+                       snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
+                                                       oldbytes, bytes);
+               }
+               /* update the current pointer */
+               spin_lock_irqsave(&subs->lock, flags);
+               oldptr = subs->hwptr_done;
+               subs->hwptr_done += bytes;
+               if (subs->hwptr_done >= runtime->buffer_size * stride)
+                       subs->hwptr_done -= runtime->buffer_size * stride;
+               frames = (bytes + (oldptr % stride)) / stride;
+               subs->transfer_done += frames;
+               if (subs->transfer_done >= runtime->period_size) {
+                       subs->transfer_done -= runtime->period_size;
+                       period_elapsed = 1;
+               }
+               spin_unlock_irqrestore(&subs->lock, flags);
+               /* copy a data chunk */
+               if (oldptr + bytes > runtime->buffer_size * stride) {
+                       unsigned int bytes1 =
+                                       runtime->buffer_size * stride - oldptr;
+                       memcpy(runtime->dma_area + oldptr, cp, bytes1);
+                       memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
+               } else {
+                       memcpy(runtime->dma_area + oldptr, cp, bytes);
+               }
+       }
+
+       if (period_elapsed)
+               snd_pcm_period_elapsed(subs->pcm_substream);
+}
+
+static void prepare_playback_urb(struct snd_usb_substream *subs,
+                                struct urb *urb)
+{
+       struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+       struct snd_urb_ctx *ctx = urb->context;
+       unsigned int counts, frames, bytes;
+       int i, stride, period_elapsed = 0;
+       unsigned long flags;
+
+       stride = runtime->frame_bits >> 3;
+
+       frames = 0;
+       urb->number_of_packets = 0;
+       spin_lock_irqsave(&subs->lock, flags);
+       for (i = 0; i < ctx->packets; i++) {
+               counts = ctx->packet_size[i];
+               /* set up descriptor */
+               urb->iso_frame_desc[i].offset = frames * stride;
+               urb->iso_frame_desc[i].length = counts * stride;
+               frames += counts;
+               urb->number_of_packets++;
+               subs->transfer_done += counts;
+               if (subs->transfer_done >= runtime->period_size) {
+                       subs->transfer_done -= runtime->period_size;
+                       period_elapsed = 1;
+                       if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
+                               if (subs->transfer_done > 0) {
+                                       /* FIXME: fill-max mode is not
+                                        * supported yet */
+                                       frames -= subs->transfer_done;
+                                       counts -= subs->transfer_done;
+                                       urb->iso_frame_desc[i].length =
+                                               counts * stride;
+                                       subs->transfer_done = 0;
+                               }
+                               i++;
+                               if (i < ctx->packets) {
+                                       /* add a transfer delimiter */
+                                       urb->iso_frame_desc[i].offset =
+                                               frames * stride;
+                                       urb->iso_frame_desc[i].length = 0;
+                                       urb->number_of_packets++;
+                               }
+                               break;
+                       }
+               }
+               if (period_elapsed &&
+                   !snd_usb_endpoint_implict_feedback_sink(subs->data_endpoint)) /* finish at the period boundary */
+                       break;
+       }
+       bytes = frames * stride;
+       if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
+               /* err, the transferred area goes over buffer boundary. */
+               unsigned int bytes1 =
+                       runtime->buffer_size * stride - subs->hwptr_done;
+               memcpy(urb->transfer_buffer,
+                      runtime->dma_area + subs->hwptr_done, bytes1);
+               memcpy(urb->transfer_buffer + bytes1,
+                      runtime->dma_area, bytes - bytes1);
+       } else {
+               memcpy(urb->transfer_buffer,
+                      runtime->dma_area + subs->hwptr_done, bytes);
+       }
+       subs->hwptr_done += bytes;
+       if (subs->hwptr_done >= runtime->buffer_size * stride)
+               subs->hwptr_done -= runtime->buffer_size * stride;
+       runtime->delay += frames;
+       spin_unlock_irqrestore(&subs->lock, flags);
+       urb->transfer_buffer_length = bytes;
+       if (period_elapsed)
+               snd_pcm_period_elapsed(subs->pcm_substream);
+}
+
+/*
+ * process after playback data complete
+ * - decrease the delay count again
+ */
+static void retire_playback_urb(struct snd_usb_substream *subs,
+                              struct urb *urb)
+{
+       unsigned long flags;
+       struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+       int stride = runtime->frame_bits >> 3;
+       int processed = urb->transfer_buffer_length / stride;
+
+       spin_lock_irqsave(&subs->lock, flags);
+       if (processed > runtime->delay)
+               runtime->delay = 0;
+       else
+               runtime->delay -= processed;
+       spin_unlock_irqrestore(&subs->lock, flags);
 }
 
 static int snd_usb_playback_open(struct snd_pcm_substream *substream)
@@ -874,6 +1118,63 @@ static int snd_usb_capture_close(struct snd_pcm_substream *substream)
        return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE);
 }
 
+static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream,
+                                             int cmd)
+{
+       struct snd_usb_substream *subs = substream->runtime->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               subs->data_endpoint->prepare_data_urb = prepare_playback_urb;
+               subs->data_endpoint->retire_data_urb = retire_playback_urb;
+               subs->running = 1;
+               return 0;
+       case SNDRV_PCM_TRIGGER_STOP:
+               stop_endpoints(subs, 0, 0, 0);
+               subs->running = 0;
+               return 0;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               subs->data_endpoint->prepare_data_urb = NULL;
+               subs->data_endpoint->retire_data_urb = NULL;
+               subs->running = 0;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       int err;
+       struct snd_usb_substream *subs = substream->runtime->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               err = start_endpoints(subs);
+               if (err < 0)
+                       return err;
+
+               subs->data_endpoint->retire_data_urb = retire_capture_urb;
+               subs->running = 1;
+               return 0;
+       case SNDRV_PCM_TRIGGER_STOP:
+               stop_endpoints(subs, 0, 0, 0);
+               subs->running = 0;
+               return 0;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               subs->data_endpoint->retire_data_urb = NULL;
+               subs->running = 0;
+               return 0;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               subs->data_endpoint->retire_data_urb = retire_capture_urb;
+               subs->running = 1;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
 static struct snd_pcm_ops snd_usb_playback_ops = {
        .open =         snd_usb_playback_open,
        .close =        snd_usb_playback_close,
index 961c9a2506865b9a84cb337606e80b21705f2b04..ebc1a5b5b3f1ba79c4c25ea66aadd34fd053e6d6 100644 (file)
@@ -25,6 +25,7 @@
 #include "usbaudio.h"
 #include "helper.h"
 #include "card.h"
+#include "endpoint.h"
 #include "proc.h"
 
 /* convert our full speed USB rate into sampling rate in Hz */
@@ -115,28 +116,33 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
        }
 }
 
+static void proc_dump_ep_status(struct snd_usb_substream *subs,
+                               struct snd_usb_endpoint *ep,
+                               struct snd_info_buffer *buffer)
+{
+       if (!ep)
+               return;
+       snd_iprintf(buffer, "    Packet Size = %d\n", ep->curpacksize);
+       snd_iprintf(buffer, "    Momentary freq = %u Hz (%#x.%04x)\n",
+                   snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
+                   ? get_full_speed_hz(ep->freqm)
+                   : get_high_speed_hz(ep->freqm),
+                   ep->freqm >> 16, ep->freqm & 0xffff);
+       if (ep->freqshift != INT_MIN) {
+               int res = 16 - ep->freqshift;
+               snd_iprintf(buffer, "    Feedback Format = %d.%d\n",
+                           (ep->syncmaxsize > 3 ? 32 : 24) - res, res);
+       }
+}
+
 static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)
 {
        if (subs->running) {
-               unsigned int i;
                snd_iprintf(buffer, "  Status: Running\n");
                snd_iprintf(buffer, "    Interface = %d\n", subs->interface);
                snd_iprintf(buffer, "    Altset = %d\n", subs->altset_idx);
-               snd_iprintf(buffer, "    URBs = %d [ ", subs->nurbs);
-               for (i = 0; i < subs->nurbs; i++)
-                       snd_iprintf(buffer, "%d ", subs->dataurb[i].packets);
-               snd_iprintf(buffer, "]\n");
-               snd_iprintf(buffer, "    Packet Size = %d\n", subs->curpacksize);
-               snd_iprintf(buffer, "    Momentary freq = %u Hz (%#x.%04x)\n",
-                           snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
-                           ? get_full_speed_hz(subs->freqm)
-                           : get_high_speed_hz(subs->freqm),
-                           subs->freqm >> 16, subs->freqm & 0xffff);
-               if (subs->freqshift != INT_MIN)
-                       snd_iprintf(buffer, "    Feedback Format = %d.%d\n",
-                                   (subs->syncmaxsize > 3 ? 32 : 24)
-                                               - (16 - subs->freqshift),
-                                   16 - subs->freqshift);
+               proc_dump_ep_status(subs, subs->data_endpoint, buffer);
+               proc_dump_ep_status(subs, subs->sync_endpoint, buffer);
        } else {
                snd_iprintf(buffer, "  Status: Stop\n");
        }
index 5ff8010b2d6f593080060fcba47fd6017dfabd5a..6b7d7a2b7baa3a83c68e35917d95515a3caa482a 100644 (file)
@@ -73,6 +73,31 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
        }
 }
 
+/*
+ * initialize the substream instance.
+ */
+
+static void snd_usb_init_substream(struct snd_usb_stream *as,
+                                  int stream,
+                                  struct audioformat *fp)
+{
+       struct snd_usb_substream *subs = &as->substream[stream];
+
+       INIT_LIST_HEAD(&subs->fmt_list);
+       spin_lock_init(&subs->lock);
+
+       subs->stream = as;
+       subs->direction = stream;
+       subs->dev = as->chip->dev;
+       subs->txfr_quirk = as->chip->txfr_quirk;
+
+       snd_usb_set_pcm_ops(as->pcm, stream);
+
+       list_add_tail(&fp->list, &subs->fmt_list);
+       subs->formats |= fp->formats;
+       subs->num_formats++;
+       subs->fmt_type = fp->fmt_type;
+}
 
 /*
  * add this endpoint to the chip instance.
@@ -94,9 +119,9 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
                if (as->fmt_type != fp->fmt_type)
                        continue;
                subs = &as->substream[stream];
-               if (!subs->endpoint)
+               if (!subs->data_endpoint)
                        continue;
-               if (subs->endpoint == fp->endpoint) {
+               if (subs->data_endpoint->ep_num == fp->endpoint) {
                        list_add_tail(&fp->list, &subs->fmt_list);
                        subs->num_formats++;
                        subs->formats |= fp->formats;
@@ -109,7 +134,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
                if (as->fmt_type != fp->fmt_type)
                        continue;
                subs = &as->substream[stream];
-               if (subs->endpoint)
+               if (subs->data_endpoint)
                        continue;
                err = snd_pcm_new_stream(as->pcm, stream, 1);
                if (err < 0)
index 3e2b035779362d6adc733ba5fa8396590e98e8d6..b8233ebe250f88648cc0baf2f6cfcfd13aa6de8f 100644 (file)
@@ -36,6 +36,7 @@ struct snd_usb_audio {
        struct snd_card *card;
        struct usb_interface *pm_intf;
        u32 usb_id;
+       struct mutex mutex;
        struct mutex shutdown_mutex;
        unsigned int shutdown:1;
        unsigned int probing:1;
@@ -46,6 +47,7 @@ struct snd_usb_audio {
        int num_suspended_intf;
 
        struct list_head pcm_list;      /* list of pcm streams */
+       struct list_head ep_list;       /* list of audio-related endpoints */
        int pcm_devs;
 
        struct list_head midi_list;     /* list of midi interfaces */
index 0507ec7bad717a5e869abc4b549efe30da033d2b..15217345c2fab7d13a451ff08473d5faf29d7171 100644 (file)
@@ -20,6 +20,14 @@ OPTIONS
 --input=::
         Input file name. (default: perf.data unless stdin is a fifo)
 
+-F::
+--freq=::
+       Show just the sample frequency used for each event.
+
+-v::
+--verbose=::
+       Show all fields.
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-list[1],
index a1386b2fff00f4b7876967bd89b646dbf4b09a49..b38a1f9ad4606db6e8544ee5908789eaae0ac0f0 100644 (file)
@@ -168,7 +168,7 @@ following filters are defined:
         - any:  any type of branches
         - any_call: any function call or system call
         - any_ret: any function return or system call return
-        - any_ind: any indirect branch
+        - ind_call: any indirect branch
         - u:  only when the branch target is at the user level
         - k: only when the branch target is in the kernel
         - hv: only when the target is at the hypervisor level
index fa37cd53e9b9f7b538641e2e8666657fd99ca9ac..1d3d513beb9b1083c60531f349d5d0c06af64dfa 100644 (file)
@@ -83,7 +83,13 @@ ifndef PERF_DEBUG
   CFLAGS_OPTIMIZE = -O6
 endif
 
-CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
+ifdef PARSER_DEBUG
+       PARSER_DEBUG_BISON  := -t
+       PARSER_DEBUG_FLEX   := -d
+       PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
+endif
+
+CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS)
 EXTLIBS = -lpthread -lrt -lelf -lm
 ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 ALL_LDFLAGS = $(LDFLAGS)
@@ -149,7 +155,7 @@ endif
 
 ### --- END CONFIGURATION SECTION ---
 
-BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -I$(EVENT_PARSE_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 BASIC_LDFLAGS =
 
 # Guard against environment variables
@@ -178,16 +184,16 @@ $(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
 
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
 
-EVENT_PARSE_DIR = ../lib/traceevent/
+TRACE_EVENT_DIR = ../lib/traceevent/
 
 ifeq ("$(origin O)", "command line")
-       EP_PATH=$(OUTPUT)/
+       TE_PATH=$(OUTPUT)/
 else
-       EP_PATH=$(EVENT_PARSE_DIR)/
+       TE_PATH=$(TRACE_EVENT_DIR)/
 endif
 
-LIBPARSEVENT = $(EP_PATH)libtraceevent.a
-EP_LIB := -L$(EP_PATH) -ltraceevent
+LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
+TE_LIB := -L$(TE_PATH) -ltraceevent
 
 #
 # Single 'perf' binary right now:
@@ -216,10 +222,10 @@ FLEX = flex
 BISON= bison
 
 $(OUTPUT)util/parse-events-flex.c: util/parse-events.l
-       $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
+       $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
 
 $(OUTPUT)util/parse-events-bison.c: util/parse-events.y
-       $(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c
+       $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c
 
 $(OUTPUT)util/pmu-flex.c: util/pmu.l
        $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
@@ -311,7 +317,7 @@ LIB_H += util/cpumap.h
 LIB_H += util/top.h
 LIB_H += $(ARCH_INCLUDE)
 LIB_H += util/cgroup.h
-LIB_H += $(EVENT_PARSE_DIR)event-parse.h
+LIB_H += $(TRACE_EVENT_DIR)event-parse.h
 LIB_H += util/target.h
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
@@ -332,6 +338,7 @@ LIB_OBJS += $(OUTPUT)util/help.o
 LIB_OBJS += $(OUTPUT)util/levenshtein.o
 LIB_OBJS += $(OUTPUT)util/parse-options.o
 LIB_OBJS += $(OUTPUT)util/parse-events.o
+LIB_OBJS += $(OUTPUT)util/parse-events-test.o
 LIB_OBJS += $(OUTPUT)util/path.o
 LIB_OBJS += $(OUTPUT)util/rbtree.o
 LIB_OBJS += $(OUTPUT)util/bitmap.o
@@ -410,7 +417,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
 BUILTIN_OBJS += $(OUTPUT)builtin-test.o
 BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
 
-PERFLIBS = $(LIB_FILE) $(LIBPARSEVENT)
+PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)
 
 # Files needed for the python binding, perf.so
 # pyrf is just an internal name needed for all those wrappers.
@@ -819,9 +826,9 @@ $(sort $(dir $(DIRECTORY_DEPS))):
 $(LIB_FILE): $(LIB_OBJS)
        $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
 
-# libparsevent.a
-$(LIBPARSEVENT):
-       make -C $(EVENT_PARSE_DIR) $(COMMAND_O) libtraceevent.a
+# libtraceevent.a
+$(LIBTRACEEVENT):
+       $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) $(COMMAND_O) libtraceevent.a
 
 help:
        @echo 'Perf make targets:'
@@ -969,6 +976,6 @@ clean:
        $(RM) $(OUTPUT)util/*-{bison,flex}*
        $(python-clean)
 
-.PHONY: all install clean strip
+.PHONY: all install clean strip $(LIBTRACEEVENT)
 .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
 .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
index 52480467e9ffeebe8d48e69f9ae47eeef57954ec..6b2bcfbde150870ce25de5d037de00246caa2730 100644 (file)
@@ -84,7 +84,11 @@ static int perf_session__list_build_ids(void)
        if (filename__fprintf_build_id(session->filename, stdout))
                goto out;
 
-       if (with_hits)
+       /*
+        * in pipe-mode, the only way to get the buildids is to parse
+        * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
+        */
+       if (with_hits || session->fd_pipe)
                perf_session__process_events(session, &build_id__mark_dso_hit_ops);
 
        perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
index 26760322c4f4178a91a1edb1f35e5e0ce6d8a2b7..e52d77ec7084e02e4fa318e873ff2cf1679a222d 100644 (file)
 #include "util/parse-options.h"
 #include "util/session.h"
 
-static const char *input_name;
+struct perf_attr_details {
+       bool freq;
+       bool verbose;
+};
+
+static int comma_printf(bool *first, const char *fmt, ...)
+{
+       va_list args;
+       int ret = 0;
+
+       if (!*first) {
+               ret += printf(",");
+       } else {
+               ret += printf(":");
+               *first = false;
+       }
+
+       va_start(args, fmt);
+       ret += vprintf(fmt, args);
+       va_end(args);
+       return ret;
+}
+
+static int __if_print(bool *first, const char *field, u64 value)
+{
+       if (value == 0)
+               return 0;
+
+       return comma_printf(first, " %s: %" PRIu64, field, value);
+}
+
+#define if_print(field) __if_print(&first, #field, pos->attr.field)
 
-static int __cmd_evlist(void)
+static int __cmd_evlist(const char *input_name, struct perf_attr_details *details)
 {
        struct perf_session *session;
        struct perf_evsel *pos;
@@ -26,8 +57,52 @@ static int __cmd_evlist(void)
        if (session == NULL)
                return -ENOMEM;
 
-       list_for_each_entry(pos, &session->evlist->entries, node)
-               printf("%s\n", event_name(pos));
+       list_for_each_entry(pos, &session->evlist->entries, node) {
+               bool first = true;
+
+               printf("%s", event_name(pos));
+
+               if (details->verbose || details->freq) {
+                       comma_printf(&first, " sample_freq=%" PRIu64,
+                                    (u64)pos->attr.sample_freq);
+               }
+
+               if (details->verbose) {
+                       if_print(type);
+                       if_print(config);
+                       if_print(config1);
+                       if_print(config2);
+                       if_print(size);
+                       if_print(sample_type);
+                       if_print(read_format);
+                       if_print(disabled);
+                       if_print(inherit);
+                       if_print(pinned);
+                       if_print(exclusive);
+                       if_print(exclude_user);
+                       if_print(exclude_kernel);
+                       if_print(exclude_hv);
+                       if_print(exclude_idle);
+                       if_print(mmap);
+                       if_print(comm);
+                       if_print(freq);
+                       if_print(inherit_stat);
+                       if_print(enable_on_exec);
+                       if_print(task);
+                       if_print(watermark);
+                       if_print(precise_ip);
+                       if_print(mmap_data);
+                       if_print(sample_id_all);
+                       if_print(exclude_host);
+                       if_print(exclude_guest);
+                       if_print(__reserved_1);
+                       if_print(wakeup_events);
+                       if_print(bp_type);
+                       if_print(branch_sample_type);
+               }
+
+               putchar('\n');
+       }
 
        perf_session__delete(session);
        return 0;
@@ -38,17 +113,23 @@ static const char * const evlist_usage[] = {
        NULL
 };
 
-static const struct option options[] = {
-       OPT_STRING('i', "input", &input_name, "file",
-                   "input file name"),
-       OPT_END()
-};
-
 int cmd_evlist(int argc, const char **argv, const char *prefix __used)
 {
+       struct perf_attr_details details = { .verbose = false, };
+       const char *input_name;
+       const struct option options[] = {
+               OPT_STRING('i', "input", &input_name, "file",
+                           "Input file name"),
+               OPT_BOOLEAN('F', "freq", &details.freq,
+                           "Show the sample frequency"),
+               OPT_BOOLEAN('v', "verbose", &details.verbose,
+                           "Show all event attr details"),
+               OPT_END()
+       };
+
        argc = parse_options(argc, argv, options, evlist_usage, 0);
        if (argc)
                usage_with_options(evlist_usage, options);
 
-       return __cmd_evlist();
+       return __cmd_evlist(input_name, &details);
 }
index 09c106193e65df339dccfc788bcc75c1ff83ef82..3beab489afc5c69446c5ce37fefe5fa40cfde9b2 100644 (file)
@@ -60,6 +60,11 @@ static int perf_event__repipe_tracing_data_synth(union perf_event *event,
 static int perf_event__repipe_attr(union perf_event *event,
                                   struct perf_evlist **pevlist __used)
 {
+       int ret;
+       ret = perf_event__process_attr(event, pevlist);
+       if (ret)
+               return ret;
+
        return perf_event__repipe_synth(NULL, event, NULL);
 }
 
index 8a3dfac161e298bbab7f0912fd7429a52fbb1dd6..e5cb08427e13f56ed7f9223d520a954ef0fc1cf2 100644 (file)
@@ -396,7 +396,7 @@ static void perf_record__mmap_read_all(struct perf_record *rec)
                        perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
        }
 
-       if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
+       if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
                write_output(rec, &finished_round_event, sizeof(finished_round_event));
 }
 
@@ -478,7 +478,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
                perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
 
        if (!have_tracepoints(&evsel_list->entries))
-               perf_header__clear_feat(&session->header, HEADER_TRACE_INFO);
+               perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
 
        if (!rec->opts.branch_stack)
                perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
@@ -753,7 +753,7 @@ static struct perf_record record = {
                .mmap_pages          = UINT_MAX,
                .user_freq           = UINT_MAX,
                .user_interval       = ULLONG_MAX,
-               .freq                = 1000,
+               .freq                = 4000,
                .target              = {
                        .uses_mmap   = true,
                },
index 6c47376e29d81b93983ae5fd6d8cbafa47f293f2..5a8727c0875772c9c37c3fc381b1812161c3b983 100644 (file)
@@ -604,556 +604,6 @@ out_free_threads:
 #undef nsyscalls
 }
 
-#define TEST_ASSERT_VAL(text, cond) \
-do { \
-       if (!(cond)) { \
-               pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
-               return -1; \
-       } \
-} while (0)
-
-static int test__checkevent_tracepoint(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-       TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong sample_type",
-               (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
-               evsel->attr.sample_type);
-       TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
-       return 0;
-}
-
-static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel;
-
-       TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
-
-       list_for_each_entry(evsel, &evlist->entries, node) {
-               TEST_ASSERT_VAL("wrong type",
-                       PERF_TYPE_TRACEPOINT == evsel->attr.type);
-               TEST_ASSERT_VAL("wrong sample_type",
-                       (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
-                       == evsel->attr.sample_type);
-               TEST_ASSERT_VAL("wrong sample_period",
-                       1 == evsel->attr.sample_period);
-       }
-       return 0;
-}
-
-static int test__checkevent_raw(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-       TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
-       return 0;
-}
-
-static int test__checkevent_numeric(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-       TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
-       return 0;
-}
-
-static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config",
-                       PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
-       return 0;
-}
-
-static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config",
-                       PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
-       TEST_ASSERT_VAL("wrong period",
-                       100000 == evsel->attr.sample_period);
-       TEST_ASSERT_VAL("wrong config1",
-                       0 == evsel->attr.config1);
-       TEST_ASSERT_VAL("wrong config2",
-                       1 == evsel->attr.config2);
-       return 0;
-}
-
-static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-       TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config",
-                       PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
-       return 0;
-}
-
-static int test__checkevent_genhw(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
-       return 0;
-}
-
-static int test__checkevent_breakpoint(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-       TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
-       TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
-                                        evsel->attr.bp_type);
-       TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
-                                       evsel->attr.bp_len);
-       return 0;
-}
-
-static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-       TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
-       TEST_ASSERT_VAL("wrong bp_type",
-                       HW_BREAKPOINT_X == evsel->attr.bp_type);
-       TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
-       return 0;
-}
-
-static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-       TEST_ASSERT_VAL("wrong type",
-                       PERF_TYPE_BREAKPOINT == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
-       TEST_ASSERT_VAL("wrong bp_type",
-                       HW_BREAKPOINT_R == evsel->attr.bp_type);
-       TEST_ASSERT_VAL("wrong bp_len",
-                       HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
-       return 0;
-}
-
-static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-       TEST_ASSERT_VAL("wrong type",
-                       PERF_TYPE_BREAKPOINT == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
-       TEST_ASSERT_VAL("wrong bp_type",
-                       HW_BREAKPOINT_W == evsel->attr.bp_type);
-       TEST_ASSERT_VAL("wrong bp_len",
-                       HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
-       return 0;
-}
-
-static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-       return test__checkevent_tracepoint(evlist);
-}
-
-static int
-test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel;
-
-       TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
-
-       list_for_each_entry(evsel, &evlist->entries, node) {
-               TEST_ASSERT_VAL("wrong exclude_user",
-                               !evsel->attr.exclude_user);
-               TEST_ASSERT_VAL("wrong exclude_kernel",
-                               evsel->attr.exclude_kernel);
-               TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-               TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-       }
-
-       return test__checkevent_tracepoint_multi(evlist);
-}
-
-static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-       return test__checkevent_raw(evlist);
-}
-
-static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-       return test__checkevent_numeric(evlist);
-}
-
-static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-       return test__checkevent_symbolic_name(evlist);
-}
-
-static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
-       TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
-
-       return test__checkevent_symbolic_name(evlist);
-}
-
-static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
-       TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
-
-       return test__checkevent_symbolic_name(evlist);
-}
-
-static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-       return test__checkevent_symbolic_alias(evlist);
-}
-
-static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-       return test__checkevent_genhw(evlist);
-}
-
-static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-       return test__checkevent_breakpoint(evlist);
-}
-
-static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-       return test__checkevent_breakpoint_x(evlist);
-}
-
-static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-       return test__checkevent_breakpoint_r(evlist);
-}
-
-static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-       return test__checkevent_breakpoint_w(evlist);
-}
-
-static int test__checkevent_pmu(struct perf_evlist *evlist)
-{
-
-       struct perf_evsel *evsel = list_entry(evlist->entries.next,
-                                             struct perf_evsel, node);
-
-       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
-       TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config",    10 == evsel->attr.config);
-       TEST_ASSERT_VAL("wrong config1",    1 == evsel->attr.config1);
-       TEST_ASSERT_VAL("wrong config2",    3 == evsel->attr.config2);
-       TEST_ASSERT_VAL("wrong period",  1000 == evsel->attr.sample_period);
-
-       return 0;
-}
-
-static int test__checkevent_list(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel;
-
-       TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
-
-       /* r1 */
-       evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
-       TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
-       TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
-       TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
-       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-       /* syscalls:sys_enter_open:k */
-       evsel = list_entry(evsel->node.next, struct perf_evsel, node);
-       TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong sample_type",
-               (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
-               evsel->attr.sample_type);
-       TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
-       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
-       /* 1:1:hp */
-       evsel = list_entry(evsel->node.next, struct perf_evsel, node);
-       TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
-       TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
-       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
-       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
-       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
-       return 0;
-}
-
-static struct test__event_st {
-       const char *name;
-       __u32 type;
-       int (*check)(struct perf_evlist *evlist);
-} test__events[] = {
-       {
-               .name  = "syscalls:sys_enter_open",
-               .check = test__checkevent_tracepoint,
-       },
-       {
-               .name  = "syscalls:*",
-               .check = test__checkevent_tracepoint_multi,
-       },
-       {
-               .name  = "r1a",
-               .check = test__checkevent_raw,
-       },
-       {
-               .name  = "1:1",
-               .check = test__checkevent_numeric,
-       },
-       {
-               .name  = "instructions",
-               .check = test__checkevent_symbolic_name,
-       },
-       {
-               .name  = "cycles/period=100000,config2/",
-               .check = test__checkevent_symbolic_name_config,
-       },
-       {
-               .name  = "faults",
-               .check = test__checkevent_symbolic_alias,
-       },
-       {
-               .name  = "L1-dcache-load-miss",
-               .check = test__checkevent_genhw,
-       },
-       {
-               .name  = "mem:0",
-               .check = test__checkevent_breakpoint,
-       },
-       {
-               .name  = "mem:0:x",
-               .check = test__checkevent_breakpoint_x,
-       },
-       {
-               .name  = "mem:0:r",
-               .check = test__checkevent_breakpoint_r,
-       },
-       {
-               .name  = "mem:0:w",
-               .check = test__checkevent_breakpoint_w,
-       },
-       {
-               .name  = "syscalls:sys_enter_open:k",
-               .check = test__checkevent_tracepoint_modifier,
-       },
-       {
-               .name  = "syscalls:*:u",
-               .check = test__checkevent_tracepoint_multi_modifier,
-       },
-       {
-               .name  = "r1a:kp",
-               .check = test__checkevent_raw_modifier,
-       },
-       {
-               .name  = "1:1:hp",
-               .check = test__checkevent_numeric_modifier,
-       },
-       {
-               .name  = "instructions:h",
-               .check = test__checkevent_symbolic_name_modifier,
-       },
-       {
-               .name  = "faults:u",
-               .check = test__checkevent_symbolic_alias_modifier,
-       },
-       {
-               .name  = "L1-dcache-load-miss:kp",
-               .check = test__checkevent_genhw_modifier,
-       },
-       {
-               .name  = "mem:0:u",
-               .check = test__checkevent_breakpoint_modifier,
-       },
-       {
-               .name  = "mem:0:x:k",
-               .check = test__checkevent_breakpoint_x_modifier,
-       },
-       {
-               .name  = "mem:0:r:hp",
-               .check = test__checkevent_breakpoint_r_modifier,
-       },
-       {
-               .name  = "mem:0:w:up",
-               .check = test__checkevent_breakpoint_w_modifier,
-       },
-       {
-               .name  = "cpu/config=10,config1,config2=3,period=1000/u",
-               .check = test__checkevent_pmu,
-       },
-       {
-               .name  = "r1,syscalls:sys_enter_open:k,1:1:hp",
-               .check = test__checkevent_list,
-       },
-       {
-               .name  = "instructions:G",
-               .check = test__checkevent_exclude_host_modifier,
-       },
-       {
-               .name  = "instructions:H",
-               .check = test__checkevent_exclude_guest_modifier,
-       },
-};
-
-#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
-
-static int test__parse_events(void)
-{
-       struct perf_evlist *evlist;
-       u_int i;
-       int ret = 0;
-
-       for (i = 0; i < TEST__EVENTS_CNT; i++) {
-               struct test__event_st *e = &test__events[i];
-
-               evlist = perf_evlist__new(NULL, NULL);
-               if (evlist == NULL)
-                       break;
-
-               ret = parse_events(evlist, e->name, 0);
-               if (ret) {
-                       pr_debug("failed to parse event '%s', err %d\n",
-                                e->name, ret);
-                       break;
-               }
-
-               ret = e->check(evlist);
-               perf_evlist__delete(evlist);
-               if (ret)
-                       break;
-       }
-
-       return ret;
-}
-
 static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
                                         size_t *sizep)
 {
@@ -1675,7 +1125,7 @@ static struct test {
        },
        {
                .desc = "parse events tests",
-               .func = test__parse_events,
+               .func = parse_events__test,
        },
 #if defined(__x86_64__) || defined(__i386__)
        {
index 3e981a710c4d2f9323317d34ae128e2f29a6c826..6031dce0429f8f93e267d530e9a91fec3ddaf74b 100644 (file)
@@ -900,6 +900,9 @@ static void perf_top__start_counters(struct perf_top *top)
                        attr->read_format |= PERF_FORMAT_ID;
                }
 
+               if (perf_target__has_cpu(&top->target))
+                       attr->sample_type |= PERF_SAMPLE_CPU;
+
                if (symbol_conf.use_callchain)
                        attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
 
@@ -1159,7 +1162,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
        struct perf_top top = {
                .count_filter        = 5,
                .delay_secs          = 2,
-               .freq                = 1000, /* 1 KHz */
+               .freq                = 4000, /* 4 KHz */
                .mmap_pages          = 128,
                .sym_pcnt_filter     = 5,
                .target              = {
index dff9c7a725f40c47330bed9d2df338f77e711124..fd9a5944b62764f6317834323160276c7b1c7270 100644 (file)
@@ -65,6 +65,8 @@ struct perf_tool build_id__mark_dso_hit_ops = {
        .mmap   = perf_event__process_mmap,
        .fork   = perf_event__process_task,
        .exit   = perf_event__exit_del_thread,
+       .attr            = perf_event__process_attr,
+       .build_id        = perf_event__process_build_id,
 };
 
 char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
index f4f427ce4d641446747bfa196c333020ef22644f..57e4ce57bbcc03faf7245f40a0ba3e20b43851d8 100644 (file)
@@ -108,7 +108,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
        if (opts->call_graph)
                attr->sample_type       |= PERF_SAMPLE_CALLCHAIN;
 
-       if (opts->target.system_wide)
+       if (perf_target__has_cpu(&opts->target))
                attr->sample_type       |= PERF_SAMPLE_CPU;
 
        if (opts->period)
@@ -462,10 +462,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
         * used for cross-endian analysis. See git commit 65014ab3
         * for why this goofiness is needed.
         */
-       union {
-               u64 val64;
-               u32 val32[2];
-       } u;
+       union u64_swap u;
 
        memset(data, 0, sizeof(*data));
        data->cpu = data->pid = data->tid = -1;
@@ -608,10 +605,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
         * used for cross-endian analysis. See git commit 65014ab3
         * for why this goofiness is needed.
         */
-       union {
-               u64 val64;
-               u32 val32[2];
-       } u;
+       union u64_swap u;
 
        array = event->sample.array;
 
index 538598012139cad703b063e7dd75607358c8bb2c..2dd5edf161b731ae1be22b9530e25e59fd444f47 100644 (file)
@@ -437,7 +437,7 @@ static bool perf_session__read_build_ids(struct perf_session *session, bool with
        return ret;
 }
 
-static int write_trace_info(int fd, struct perf_header *h __used,
+static int write_tracing_data(int fd, struct perf_header *h __used,
                            struct perf_evlist *evlist)
 {
        return read_tracing_data(fd, &evlist->entries);
@@ -1472,7 +1472,7 @@ out:
        return err;
 }
 
-static int process_trace_info(struct perf_file_section *section __unused,
+static int process_tracing_data(struct perf_file_section *section __unused,
                              struct perf_header *ph __unused,
                              int feat __unused, int fd)
 {
@@ -1508,11 +1508,11 @@ struct feature_ops {
                .full_only = true }
 
 /* feature_ops not implemented: */
-#define print_trace_info               NULL
-#define print_build_id                 NULL
+#define print_tracing_data     NULL
+#define print_build_id         NULL
 
 static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
-       FEAT_OPP(HEADER_TRACE_INFO,     trace_info),
+       FEAT_OPP(HEADER_TRACING_DATA,   tracing_data),
        FEAT_OPP(HEADER_BUILD_ID,       build_id),
        FEAT_OPA(HEADER_HOSTNAME,       hostname),
        FEAT_OPA(HEADER_OSRELEASE,      osrelease),
index 21a6be09c129dd63747bca64707a17d9eec13cb9..2d42b3e1826ff998534b3f949b48fc7c902bc0a1 100644 (file)
@@ -12,7 +12,7 @@
 enum {
        HEADER_RESERVED         = 0,    /* always cleared */
        HEADER_FIRST_FEATURE    = 1,
-       HEADER_TRACE_INFO       = 1,
+       HEADER_TRACING_DATA     = 1,
        HEADER_BUILD_ID,
 
        HEADER_HOSTNAME,
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
new file mode 100644 (file)
index 0000000..76b98e2
--- /dev/null
@@ -0,0 +1,625 @@
+
+#include "parse-events.h"
+#include "evsel.h"
+#include "evlist.h"
+#include "sysfs.h"
+#include "../../../include/linux/hw_breakpoint.h"
+
+#define TEST_ASSERT_VAL(text, cond) \
+do { \
+       if (!(cond)) { \
+               pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
+               return -1; \
+       } \
+} while (0)
+
+static int test__checkevent_tracepoint(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong sample_type",
+               (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
+               evsel->attr.sample_type);
+       TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
+       return 0;
+}
+
+static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel;
+
+       TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
+
+       list_for_each_entry(evsel, &evlist->entries, node) {
+               TEST_ASSERT_VAL("wrong type",
+                       PERF_TYPE_TRACEPOINT == evsel->attr.type);
+               TEST_ASSERT_VAL("wrong sample_type",
+                       (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
+                       == evsel->attr.sample_type);
+               TEST_ASSERT_VAL("wrong sample_period",
+                       1 == evsel->attr.sample_period);
+       }
+       return 0;
+}
+
+static int test__checkevent_raw(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
+       return 0;
+}
+
+static int test__checkevent_numeric(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+       return 0;
+}
+
+static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",
+                       PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
+       return 0;
+}
+
+static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",
+                       PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong period",
+                       100000 == evsel->attr.sample_period);
+       TEST_ASSERT_VAL("wrong config1",
+                       0 == evsel->attr.config1);
+       TEST_ASSERT_VAL("wrong config2",
+                       1 == evsel->attr.config2);
+       return 0;
+}
+
+static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",
+                       PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
+       return 0;
+}
+
+static int test__checkevent_genhw(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
+       return 0;
+}
+
+static int test__checkevent_breakpoint(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
+                                        evsel->attr.bp_type);
+       TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
+                                       evsel->attr.bp_len);
+       return 0;
+}
+
+static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong bp_type",
+                       HW_BREAKPOINT_X == evsel->attr.bp_type);
+       TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
+       return 0;
+}
+
+static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type",
+                       PERF_TYPE_BREAKPOINT == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong bp_type",
+                       HW_BREAKPOINT_R == evsel->attr.bp_type);
+       TEST_ASSERT_VAL("wrong bp_len",
+                       HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
+       return 0;
+}
+
+static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type",
+                       PERF_TYPE_BREAKPOINT == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong bp_type",
+                       HW_BREAKPOINT_W == evsel->attr.bp_type);
+       TEST_ASSERT_VAL("wrong bp_len",
+                       HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
+       return 0;
+}
+
+static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+       return test__checkevent_tracepoint(evlist);
+}
+
+static int
+test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel;
+
+       TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
+
+       list_for_each_entry(evsel, &evlist->entries, node) {
+               TEST_ASSERT_VAL("wrong exclude_user",
+                               !evsel->attr.exclude_user);
+               TEST_ASSERT_VAL("wrong exclude_kernel",
+                               evsel->attr.exclude_kernel);
+               TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+               TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+       }
+
+       return test__checkevent_tracepoint_multi(evlist);
+}
+
+static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+       return test__checkevent_raw(evlist);
+}
+
+static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+       return test__checkevent_numeric(evlist);
+}
+
+static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+       return test__checkevent_symbolic_name(evlist);
+}
+
+static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
+
+       return test__checkevent_symbolic_name(evlist);
+}
+
+static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+
+       return test__checkevent_symbolic_name(evlist);
+}
+
+static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+       return test__checkevent_symbolic_alias(evlist);
+}
+
+static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+       return test__checkevent_genhw(evlist);
+}
+
+static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+       return test__checkevent_breakpoint(evlist);
+}
+
+static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+       return test__checkevent_breakpoint_x(evlist);
+}
+
+static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+       return test__checkevent_breakpoint_r(evlist);
+}
+
+static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+       return test__checkevent_breakpoint_w(evlist);
+}
+
+static int test__checkevent_pmu(struct perf_evlist *evlist)
+{
+
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",    10 == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong config1",    1 == evsel->attr.config1);
+       TEST_ASSERT_VAL("wrong config2",    3 == evsel->attr.config2);
+       TEST_ASSERT_VAL("wrong period",  1000 == evsel->attr.sample_period);
+
+       return 0;
+}
+
+static int test__checkevent_list(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel;
+
+       TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
+
+       /* r1 */
+       evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
+       TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+       /* syscalls:sys_enter_open:k */
+       evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong sample_type",
+               (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
+               evsel->attr.sample_type);
+       TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
+       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+       /* 1:1:hp */
+       evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+       TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+       return 0;
+}
+
+static int test__checkevent_pmu_name(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel;
+
+       /* cpu/config=1,name=krava1/u */
+       evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+       TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava"));
+
+       /* cpu/config=2/" */
+       evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+       TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",  2 == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2"));
+
+       return 0;
+}
+
+struct test__event_st {
+       const char *name;
+       __u32 type;
+       int (*check)(struct perf_evlist *evlist);
+};
+
+static struct test__event_st test__events[] = {
+       [0] = {
+               .name  = "syscalls:sys_enter_open",
+               .check = test__checkevent_tracepoint,
+       },
+       [1] = {
+               .name  = "syscalls:*",
+               .check = test__checkevent_tracepoint_multi,
+       },
+       [2] = {
+               .name  = "r1a",
+               .check = test__checkevent_raw,
+       },
+       [3] = {
+               .name  = "1:1",
+               .check = test__checkevent_numeric,
+       },
+       [4] = {
+               .name  = "instructions",
+               .check = test__checkevent_symbolic_name,
+       },
+       [5] = {
+               .name  = "cycles/period=100000,config2/",
+               .check = test__checkevent_symbolic_name_config,
+       },
+       [6] = {
+               .name  = "faults",
+               .check = test__checkevent_symbolic_alias,
+       },
+       [7] = {
+               .name  = "L1-dcache-load-miss",
+               .check = test__checkevent_genhw,
+       },
+       [8] = {
+               .name  = "mem:0",
+               .check = test__checkevent_breakpoint,
+       },
+       [9] = {
+               .name  = "mem:0:x",
+               .check = test__checkevent_breakpoint_x,
+       },
+       [10] = {
+               .name  = "mem:0:r",
+               .check = test__checkevent_breakpoint_r,
+       },
+       [11] = {
+               .name  = "mem:0:w",
+               .check = test__checkevent_breakpoint_w,
+       },
+       [12] = {
+               .name  = "syscalls:sys_enter_open:k",
+               .check = test__checkevent_tracepoint_modifier,
+       },
+       [13] = {
+               .name  = "syscalls:*:u",
+               .check = test__checkevent_tracepoint_multi_modifier,
+       },
+       [14] = {
+               .name  = "r1a:kp",
+               .check = test__checkevent_raw_modifier,
+       },
+       [15] = {
+               .name  = "1:1:hp",
+               .check = test__checkevent_numeric_modifier,
+       },
+       [16] = {
+               .name  = "instructions:h",
+               .check = test__checkevent_symbolic_name_modifier,
+       },
+       [17] = {
+               .name  = "faults:u",
+               .check = test__checkevent_symbolic_alias_modifier,
+       },
+       [18] = {
+               .name  = "L1-dcache-load-miss:kp",
+               .check = test__checkevent_genhw_modifier,
+       },
+       [19] = {
+               .name  = "mem:0:u",
+               .check = test__checkevent_breakpoint_modifier,
+       },
+       [20] = {
+               .name  = "mem:0:x:k",
+               .check = test__checkevent_breakpoint_x_modifier,
+       },
+       [21] = {
+               .name  = "mem:0:r:hp",
+               .check = test__checkevent_breakpoint_r_modifier,
+       },
+       [22] = {
+               .name  = "mem:0:w:up",
+               .check = test__checkevent_breakpoint_w_modifier,
+       },
+       [23] = {
+               .name  = "r1,syscalls:sys_enter_open:k,1:1:hp",
+               .check = test__checkevent_list,
+       },
+       [24] = {
+               .name  = "instructions:G",
+               .check = test__checkevent_exclude_host_modifier,
+       },
+       [25] = {
+               .name  = "instructions:H",
+               .check = test__checkevent_exclude_guest_modifier,
+       },
+};
+
+#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
+
+static struct test__event_st test__events_pmu[] = {
+       [0] = {
+               .name  = "cpu/config=10,config1,config2=3,period=1000/u",
+               .check = test__checkevent_pmu,
+       },
+       [1] = {
+               .name  = "cpu/config=1,name=krava/u,cpu/config=2/u",
+               .check = test__checkevent_pmu_name,
+       },
+};
+
+#define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \
+                             sizeof(struct test__event_st))
+
+static int test(struct test__event_st *e)
+{
+       struct perf_evlist *evlist;
+       int ret;
+
+       evlist = perf_evlist__new(NULL, NULL);
+       if (evlist == NULL)
+               return -ENOMEM;
+
+       ret = parse_events(evlist, e->name, 0);
+       if (ret) {
+               pr_debug("failed to parse event '%s', err %d\n",
+                        e->name, ret);
+               return ret;
+       }
+
+       ret = e->check(evlist);
+       perf_evlist__delete(evlist);
+
+       return ret;
+}
+
+static int test_events(struct test__event_st *events, unsigned cnt)
+{
+       int ret = 0;
+       unsigned i;
+
+       for (i = 0; i < cnt; i++) {
+               struct test__event_st *e = &events[i];
+
+               pr_debug("running test %d '%s'\n", i, e->name);
+               ret = test(e);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static int test_pmu(void)
+{
+       struct stat st;
+       char path[PATH_MAX];
+       int ret;
+
+       snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/format/",
+                sysfs_find_mountpoint());
+
+       ret = stat(path, &st);
+       if (ret)
+               pr_debug("ommiting PMU cpu tests\n");
+       return !ret;
+}
+
+int parse_events__test(void)
+{
+       int ret;
+
+       ret = test_events(test__events, TEST__EVENTS_CNT);
+       if (!ret && test_pmu())
+               ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT);
+
+       return ret;
+}
index c7fc18a33d54503b3a05347dd11b5a7d66b148f4..fac7d59309b83698cf22829936e86e1c511eb31e 100644 (file)
@@ -23,8 +23,10 @@ struct event_symbol {
        const char      *alias;
 };
 
-int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
-                      int *idx);
+#ifdef PARSER_DEBUG
+extern int parse_events_debug;
+#endif
+int parse_events_parse(struct list_head *list, int *idx);
 
 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -355,20 +357,30 @@ const char *__event_name(int type, u64 config)
        return "unknown";
 }
 
-static int add_event(struct list_head *list, int *idx,
+static int add_event(struct list_head **_list, int *idx,
                     struct perf_event_attr *attr, char *name)
 {
        struct perf_evsel *evsel;
+       struct list_head *list = *_list;
+
+       if (!list) {
+               list = malloc(sizeof(*list));
+               if (!list)
+                       return -ENOMEM;
+               INIT_LIST_HEAD(list);
+       }
 
        event_attr_init(attr);
 
        evsel = perf_evsel__new(attr, (*idx)++);
-       if (!evsel)
+       if (!evsel) {
+               free(list);
                return -ENOMEM;
-
-       list_add_tail(&evsel->node, list);
+       }
 
        evsel->name = strdup(name);
+       list_add_tail(&evsel->node, list);
+       *_list = list;
        return 0;
 }
 
@@ -390,7 +402,7 @@ static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
        return -1;
 }
 
-int parse_events_add_cache(struct list_head *list, int *idx,
+int parse_events_add_cache(struct list_head **list, int *idx,
                           char *type, char *op_result1, char *op_result2)
 {
        struct perf_event_attr attr;
@@ -451,7 +463,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
        return add_event(list, idx, &attr, name);
 }
 
-static int add_tracepoint(struct list_head *list, int *idx,
+static int add_tracepoint(struct list_head **list, int *idx,
                          char *sys_name, char *evt_name)
 {
        struct perf_event_attr attr;
@@ -488,7 +500,7 @@ static int add_tracepoint(struct list_head *list, int *idx,
        return add_event(list, idx, &attr, name);
 }
 
-static int add_tracepoint_multi(struct list_head *list, int *idx,
+static int add_tracepoint_multi(struct list_head **list, int *idx,
                                char *sys_name, char *evt_name)
 {
        char evt_path[MAXPATHLEN];
@@ -519,7 +531,7 @@ static int add_tracepoint_multi(struct list_head *list, int *idx,
        return ret;
 }
 
-int parse_events_add_tracepoint(struct list_head *list, int *idx,
+int parse_events_add_tracepoint(struct list_head **list, int *idx,
                                char *sys, char *event)
 {
        int ret;
@@ -563,7 +575,7 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
        return 0;
 }
 
-int parse_events_add_breakpoint(struct list_head *list, int *idx,
+int parse_events_add_breakpoint(struct list_head **list, int *idx,
                                void *ptr, char *type)
 {
        struct perf_event_attr attr;
@@ -622,6 +634,9 @@ do {                                                                \
                 * attr->branch_sample_type = term->val.num;
                 */
                break;
+       case PARSE_EVENTS__TERM_TYPE_NAME:
+               CHECK_TYPE_VAL(STR);
+               break;
        default:
                return -EINVAL;
        }
@@ -642,7 +657,7 @@ static int config_attr(struct perf_event_attr *attr,
        return 0;
 }
 
-int parse_events_add_numeric(struct list_head *list, int *idx,
+int parse_events_add_numeric(struct list_head **list, int *idx,
                             unsigned long type, unsigned long config,
                             struct list_head *head_config)
 {
@@ -660,7 +675,24 @@ int parse_events_add_numeric(struct list_head *list, int *idx,
                         (char *) __event_name(type, config));
 }
 
-int parse_events_add_pmu(struct list_head *list, int *idx,
+static int parse_events__is_name_term(struct parse_events__term *term)
+{
+       return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
+}
+
+static char *pmu_event_name(struct perf_event_attr *attr,
+                           struct list_head *head_terms)
+{
+       struct parse_events__term *term;
+
+       list_for_each_entry(term, head_terms, list)
+               if (parse_events__is_name_term(term))
+                       return term->val.str;
+
+       return (char *) __event_name(PERF_TYPE_RAW, attr->config);
+}
+
+int parse_events_add_pmu(struct list_head **list, int *idx,
                         char *name, struct list_head *head_config)
 {
        struct perf_event_attr attr;
@@ -681,7 +713,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
        if (perf_pmu__config(pmu, &attr, head_config))
                return -EINVAL;
 
-       return add_event(list, idx, &attr, (char *) "pmu");
+       return add_event(list, idx, &attr,
+                        pmu_event_name(&attr, head_config));
 }
 
 void parse_events_update_lists(struct list_head *list_event,
@@ -693,7 +726,7 @@ void parse_events_update_lists(struct list_head *list_event,
         * list, for next event definition.
         */
        list_splice_tail(list_event, list_all);
-       INIT_LIST_HEAD(list_event);
+       free(list_event);
 }
 
 int parse_events_modifier(struct list_head *list, char *str)
@@ -768,10 +801,14 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 
        buffer = parse_events__scan_string(str);
 
-       ret = parse_events_parse(&list, &list_tmp, &idx);
+#ifdef PARSER_DEBUG
+       parse_events_debug = 1;
+#endif
+       ret = parse_events_parse(&list, &idx);
 
        parse_events__flush_buffer(buffer);
        parse_events__delete_buffer(buffer);
+       parse_events_lex_destroy();
 
        if (!ret) {
                int entries = idx - evlist->nr_entries;
index 3fddd610d35097896ce6e2327b445b1e095424fe..8cac57ab4ee6b396549a4ee857486effedb9343b 100644 (file)
@@ -4,7 +4,9 @@
  * Parse symbolic events/counts passed in as options:
  */
 
+#include <linux/list.h>
 #include <stdbool.h>
+#include "types.h"
 #include "../../../include/linux/perf_event.h"
 #include "types.h"
 
@@ -45,6 +47,7 @@ enum {
        PARSE_EVENTS__TERM_TYPE_CONFIG,
        PARSE_EVENTS__TERM_TYPE_CONFIG1,
        PARSE_EVENTS__TERM_TYPE_CONFIG2,
+       PARSE_EVENTS__TERM_TYPE_NAME,
        PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
        PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
 };
@@ -66,26 +69,23 @@ int parse_events__term_num(struct parse_events__term **_term,
 int parse_events__term_str(struct parse_events__term **_term,
                           int type_term, char *config, char *str);
 void parse_events__free_terms(struct list_head *terms);
-int parse_events_modifier(struct list_head *list __used, char *str __used);
-int parse_events_add_tracepoint(struct list_head *list, int *idx,
+int parse_events_modifier(struct list_head *list, char *str);
+int parse_events_add_tracepoint(struct list_head **list, int *idx,
                                char *sys, char *event);
-int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config,
-                        unsigned long config1, unsigned long config2,
-                        char *mod);
-int parse_events_add_numeric(struct list_head *list, int *idx,
+int parse_events_add_numeric(struct list_head **list, int *idx,
                             unsigned long type, unsigned long config,
                             struct list_head *head_config);
-int parse_events_add_cache(struct list_head *list, int *idx,
+int parse_events_add_cache(struct list_head **list, int *idx,
                           char *type, char *op_result1, char *op_result2);
-int parse_events_add_breakpoint(struct list_head *list, int *idx,
+int parse_events_add_breakpoint(struct list_head **list, int *idx,
                                void *ptr, char *type);
-int parse_events_add_pmu(struct list_head *list, int *idx,
+int parse_events_add_pmu(struct list_head **list, int *idx,
                         char *pmu , struct list_head *head_config);
 void parse_events_update_lists(struct list_head *list_event,
                               struct list_head *list_all);
 void parse_events_error(struct list_head *list_all,
-                       struct list_head *list_event,
                        int *idx, char const *msg);
+int parse_events__test(void);
 
 void print_events(const char *event_glob);
 void print_events_type(u8 type);
index 1fcf1bbc5458e4a8d626f671a6455348a2225f1f..618a8e7883995bbee72f4b90c6d5e55a012f05f1 100644 (file)
@@ -1,5 +1,6 @@
 
 %option prefix="parse_events_"
+%option stack
 
 %{
 #include <errno.h>
@@ -50,6 +51,8 @@ static int term(int type)
 
 %}
 
+%x mem
+
 num_dec                [0-9]+
 num_hex                0x[a-fA-F0-9]+
 num_raw_hex    [a-fA-F0-9]+
@@ -102,16 +105,16 @@ misses|miss                               { return str(PE_NAME_CACHE_OP_RESULT); }
 config                 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
 config1                        { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
 config2                        { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
+name                   { return term(PARSE_EVENTS__TERM_TYPE_NAME); }
 period                 { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
 branch_type            { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
 
-mem:                   { return PE_PREFIX_MEM; }
+mem:                   { BEGIN(mem); return PE_PREFIX_MEM; }
 r{num_raw_hex}         { return raw(); }
 {num_dec}              { return value(10); }
 {num_hex}              { return value(16); }
 
 {modifier_event}       { return str(PE_MODIFIER_EVENT); }
-{modifier_bp}          { return str(PE_MODIFIER_BP); }
 {name}                 { return str(PE_NAME); }
 "/"                    { return '/'; }
 -                      { return '-'; }
@@ -119,6 +122,25 @@ r{num_raw_hex}             { return raw(); }
 :                      { return ':'; }
 =                      { return '='; }
 
+<mem>{
+{modifier_bp}          { return str(PE_MODIFIER_BP); }
+:                      { return ':'; }
+{num_dec}              { return value(10); }
+{num_hex}              { return value(16); }
+       /*
+        * We need to separate 'mem:' scanner part, in order to get specific
+        * modifier bits parsed out. Otherwise we would need to handle PE_NAME
+        * and we'd need to parse it manually. During the escape from <mem>
+        * state we need to put the escaping char back, so we dont miss it.
+        */
+.                      { unput(*parse_events_text); BEGIN(INITIAL); }
+       /*
+        * We destroy the scanner after reaching EOF,
+        * but anyway just to be sure get back to INIT state.
+        */
+<<EOF>>                        { BEGIN(INITIAL); }
+}
+
 %%
 
 int parse_events_wrap(void)
index 936913ea0ab6a67344aa56a59900b35fd569e4fb..362cc59332ae78e0774fed92e3f20a2f751fa211 100644 (file)
@@ -1,7 +1,6 @@
 
 %name-prefix "parse_events_"
 %parse-param {struct list_head *list_all}
-%parse-param {struct list_head *list_event}
 %parse-param {int *idx}
 
 %{
@@ -41,6 +40,14 @@ do { \
 %type <str> PE_MODIFIER_BP
 %type <head> event_config
 %type <term> event_term
+%type <head> event_pmu
+%type <head> event_legacy_symbol
+%type <head> event_legacy_cache
+%type <head> event_legacy_mem
+%type <head> event_legacy_tracepoint
+%type <head> event_legacy_numeric
+%type <head> event_legacy_raw
+%type <head> event_def
 
 %union
 {
@@ -62,13 +69,13 @@ event_def PE_MODIFIER_EVENT
         * (there could be more events added for multiple tracepoint
         * definitions via '*?'.
         */
-       ABORT_ON(parse_events_modifier(list_event, $2));
-       parse_events_update_lists(list_event, list_all);
+       ABORT_ON(parse_events_modifier($1, $2));
+       parse_events_update_lists($1, list_all);
 }
 |
 event_def
 {
-       parse_events_update_lists(list_event, list_all);
+       parse_events_update_lists($1, list_all);
 }
 
 event_def: event_pmu |
@@ -82,71 +89,102 @@ event_def: event_pmu |
 event_pmu:
 PE_NAME '/' event_config '/'
 {
-       ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3));
+       struct list_head *list = NULL;
+
+       ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3));
        parse_events__free_terms($3);
+       $$ = list;
 }
 
 event_legacy_symbol:
 PE_VALUE_SYM '/' event_config '/'
 {
+       struct list_head *list = NULL;
        int type = $1 >> 16;
        int config = $1 & 255;
 
-       ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3));
+       ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3));
        parse_events__free_terms($3);
+       $$ = list;
 }
 |
 PE_VALUE_SYM sep_slash_dc
 {
+       struct list_head *list = NULL;
        int type = $1 >> 16;
        int config = $1 & 255;
 
-       ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL));
+       ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL));
+       $$ = list;
 }
 
 event_legacy_cache:
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
 {
-       ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5));
+       struct list_head *list = NULL;
+
+       ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5));
+       $$ = list;
 }
 |
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 {
-       ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL));
+       struct list_head *list = NULL;
+
+       ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL));
+       $$ = list;
 }
 |
 PE_NAME_CACHE_TYPE
 {
-       ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL));
+       struct list_head *list = NULL;
+
+       ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL));
+       $$ = list;
 }
 
 event_legacy_mem:
 PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 {
-       ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4));
+       struct list_head *list = NULL;
+
+       ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4));
+       $$ = list;
 }
 |
 PE_PREFIX_MEM PE_VALUE sep_dc
 {
-       ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL));
+       struct list_head *list = NULL;
+
+       ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL));
+       $$ = list;
 }
 
 event_legacy_tracepoint:
 PE_NAME ':' PE_NAME
 {
-       ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3));
+       struct list_head *list = NULL;
+
+       ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3));
+       $$ = list;
 }
 
 event_legacy_numeric:
 PE_VALUE ':' PE_VALUE
 {
-       ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL));
+       struct list_head *list = NULL;
+
+       ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL));
+       $$ = list;
 }
 
 event_legacy_raw:
 PE_RAW
 {
-       ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL));
+       struct list_head *list = NULL;
+
+       ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL));
+       $$ = list;
 }
 
 event_config:
@@ -199,6 +237,14 @@ PE_NAME
        $$ = term;
 }
 |
+PE_TERM '=' PE_NAME
+{
+       struct parse_events__term *term;
+
+       ABORT_ON(parse_events__term_str(&term, $1, NULL, $3));
+       $$ = term;
+}
+|
 PE_TERM '=' PE_VALUE
 {
        struct parse_events__term *term;
@@ -222,7 +268,6 @@ sep_slash_dc: '/' | ':' |
 %%
 
 void parse_events_error(struct list_head *list_all __used,
-                       struct list_head *list_event __used,
                        int *idx __used,
                        char const *msg __used)
 {
index 8ee219b7285b95e6d90c8eb1b5b7db9d8c9e72f1..a119a5371699bd1c89575ce02de0d47655548e52 100644 (file)
@@ -258,9 +258,9 @@ static int pmu_config_term(struct list_head *formats,
 static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
                      struct list_head *head_terms)
 {
-       struct parse_events__term *term, *h;
+       struct parse_events__term *term;
 
-       list_for_each_entry_safe(term, h, head_terms, list)
+       list_for_each_entry(term, head_terms, list)
                if (pmu_config_term(formats, attr, term))
                        return -EINVAL;
 
index e30749e38a9b72d30d86486cc91924e10f6f15dc..4c1b3d72a1d2d24093733018674024e42723a548 100644 (file)
@@ -56,7 +56,7 @@ INTERP my_perl;
 #define FTRACE_MAX_EVENT                               \
        ((1 << (sizeof(unsigned short) * 8)) - 1)
 
-struct event *events[FTRACE_MAX_EVENT];
+struct event_format *events[FTRACE_MAX_EVENT];
 
 extern struct scripting_context *scripting_context;
 
@@ -181,7 +181,7 @@ static void define_flag_field(const char *ev_name,
        LEAVE;
 }
 
-static void define_event_symbols(struct event *event,
+static void define_event_symbols(struct event_format *event,
                                 const char *ev_name,
                                 struct print_arg *args)
 {
@@ -209,6 +209,8 @@ static void define_event_symbols(struct event *event,
                define_symbolic_values(args->symbol.symbols, ev_name,
                                       cur_field_name);
                break;
+       case PRINT_BSTRING:
+       case PRINT_DYNAMIC_ARRAY:
        case PRINT_STRING:
                break;
        case PRINT_TYPE:
@@ -220,7 +222,9 @@ static void define_event_symbols(struct event *event,
                define_event_symbols(event, ev_name, args->op.left);
                define_event_symbols(event, ev_name, args->op.right);
                break;
+       case PRINT_FUNC:
        default:
+               pr_err("Unsupported print arg type\n");
                /* we should warn... */
                return;
        }
@@ -229,10 +233,10 @@ static void define_event_symbols(struct event *event,
                define_event_symbols(event, ev_name, args->next);
 }
 
-static inline struct event *find_cache_event(int type)
+static inline struct event_format *find_cache_event(int type)
 {
        static char ev_name[256];
-       struct event *event;
+       struct event_format *event;
 
        if (events[type])
                return events[type];
@@ -258,7 +262,7 @@ static void perl_process_tracepoint(union perf_event *pevent __unused,
        static char handler[256];
        unsigned long long val;
        unsigned long s, ns;
-       struct event *event;
+       struct event_format *event;
        int type;
        int pid;
        int cpu = sample->cpu;
@@ -446,7 +450,7 @@ static int perl_stop_script(void)
 
 static int perl_generate_script(const char *outfile)
 {
-       struct event *event = NULL;
+       struct event_format *event = NULL;
        struct format_field *f;
        char fname[PATH_MAX];
        int not_first, count;
index 4dcc8f3190cf2802a1afc459a638ee61a3622969..93d355d2710989d784f5a796e02f58c2d4938888 100644 (file)
@@ -481,6 +481,38 @@ static void perf_event__read_swap(union perf_event *event)
        event->read.id           = bswap_64(event->read.id);
 }
 
+static u8 revbyte(u8 b)
+{
+       int rev = (b >> 4) | ((b & 0xf) << 4);
+       rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2);
+       rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1);
+       return (u8) rev;
+}
+
+/*
+ * XXX this is hack in attempt to carry flags bitfield
+ * throught endian village. ABI says:
+ *
+ * Bit-fields are allocated from right to left (least to most significant)
+ * on little-endian implementations and from left to right (most to least
+ * significant) on big-endian implementations.
+ *
+ * The above seems to be byte specific, so we need to reverse each
+ * byte of the bitfield. 'Internet' also says this might be implementation
+ * specific and we probably need proper fix and carry perf_event_attr
+ * bitfield flags in separate data file FEAT_ section. Thought this seems
+ * to work for now.
+ */
+static void swap_bitfield(u8 *p, unsigned len)
+{
+       unsigned i;
+
+       for (i = 0; i < len; i++) {
+               *p = revbyte(*p);
+               p++;
+       }
+}
+
 /* exported for swapping attributes in file header */
 void perf_event__attr_swap(struct perf_event_attr *attr)
 {
@@ -494,6 +526,8 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
        attr->bp_type           = bswap_32(attr->bp_type);
        attr->bp_addr           = bswap_64(attr->bp_addr);
        attr->bp_len            = bswap_64(attr->bp_len);
+
+       swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
 }
 
 static void perf_event__hdr_attr_swap(union perf_event *event)
@@ -1064,8 +1098,9 @@ volatile int session_done;
 static int __perf_session__process_pipe_events(struct perf_session *self,
                                               struct perf_tool *tool)
 {
-       union perf_event event;
-       uint32_t size;
+       union perf_event *event;
+       uint32_t size, cur_size = 0;
+       void *buf = NULL;
        int skip = 0;
        u64 head;
        int err;
@@ -1074,8 +1109,14 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
        perf_tool__fill_defaults(tool);
 
        head = 0;
+       cur_size = sizeof(union perf_event);
+
+       buf = malloc(cur_size);
+       if (!buf)
+               return -errno;
 more:
-       err = readn(self->fd, &event, sizeof(struct perf_event_header));
+       event = buf;
+       err = readn(self->fd, event, sizeof(struct perf_event_header));
        if (err <= 0) {
                if (err == 0)
                        goto done;
@@ -1085,13 +1126,23 @@ more:
        }
 
        if (self->header.needs_swap)
-               perf_event_header__bswap(&event.header);
+               perf_event_header__bswap(&event->header);
 
-       size = event.header.size;
+       size = event->header.size;
        if (size == 0)
                size = 8;
 
-       p = &event;
+       if (size > cur_size) {
+               void *new = realloc(buf, size);
+               if (!new) {
+                       pr_err("failed to allocate memory to read event\n");
+                       goto out_err;
+               }
+               buf = new;
+               cur_size = size;
+               event = buf;
+       }
+       p = event;
        p += sizeof(struct perf_event_header);
 
        if (size - sizeof(struct perf_event_header)) {
@@ -1107,9 +1158,9 @@ more:
                }
        }
 
-       if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) {
+       if ((skip = perf_session__process_event(self, event, tool, head)) < 0) {
                pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
-                      head, event.header.size, event.header.type);
+                      head, event->header.size, event->header.type);
                err = -EINVAL;
                goto out_err;
        }
@@ -1124,6 +1175,7 @@ more:
 done:
        err = 0;
 out_err:
+       free(buf);
        perf_session__warn_about_errors(self, tool);
        perf_session_free_sample_buffers(self);
        return err;
index 5f3689a3d0857be7431f8ed06eac3eb5e9707e18..c51fa6b70a2854c3befeb82af0bf3307b7e8c6c4 100644 (file)
@@ -16,4 +16,9 @@ typedef signed short     s16;
 typedef unsigned char     u8;
 typedef signed char       s8;
 
+union u64_swap {
+       u64 val64;
+       u32 val32[2];
+};
+
 #endif /* __PERF_TYPES_H */
index 0e8191b6c5e38a82f4a849e68cece085ec3755b7..cf362b3d1ec959322af01e650b4eb0912084e5e9 100644 (file)
 #
 # TEST_START IF (DEFINED ALL_TESTS || ${MYTEST} == boottest) && ${MACHINE} == gandalf
 #
-# Notice the use of paranthesis. Without any paranthesis the above would be
+# Notice the use of parentheses. Without any parentheses the above would be
 # processed the same as:
 #
 # TEST_START IF DEFINED ALL_TESTS || (${MYTEST} == boottest && ${MACHINE} == gandalf)