From 8a555760572a6a96cbf2d4bd2fe8bc322249a525 Mon Sep 17 00:00:00 2001 From: Ola Lilja Date: Thu, 7 Jun 2012 14:00:46 +0200 Subject: [PATCH] --- yaml --- r: 316235 b: refs/heads/master c: f242e50eee1ec7692c4854d94e8cd543991cce71 h: refs/heads/master i: 316233: 606f15cbc91f73c83fd2b902c98c804527733b17 316231: 5181e95f59f657b36e263880d49bdea09bf06ebf v: v3 --- [refs] | 2 +- .../bindings/i2c/i2c-mux-pinctrl.txt | 93 + trunk/Documentation/kernel-parameters.txt | 9 + trunk/Documentation/vm/frontswap.txt | 278 ++ trunk/MAINTAINERS | 52 +- trunk/Makefile | 2 +- trunk/arch/arm/Kconfig | 1 - trunk/arch/arm/mach-shmobile/Kconfig | 6 + trunk/arch/arm/mach-ux500/board-mop500.c | 14 + trunk/arch/arm/mm/dma-mapping.c | 10 +- trunk/arch/avr32/kernel/signal.c | 2 +- trunk/arch/blackfin/kernel/process.c | 2 +- trunk/arch/parisc/Makefile | 3 +- trunk/arch/parisc/include/asm/Kbuild | 1 + trunk/arch/parisc/include/asm/bug.h | 2 + trunk/arch/powerpc/kernel/module_32.c | 11 +- trunk/arch/powerpc/kernel/time.c | 14 +- trunk/arch/tile/include/asm/thread_info.h | 5 - trunk/arch/tile/kernel/entry.S | 14 - trunk/arch/tile/kernel/setup.c | 1 + trunk/arch/x86/boot/header.S | 42 +- trunk/arch/x86/boot/tools/build.c | 172 +- trunk/arch/x86/include/asm/nmi.h | 14 + trunk/arch/x86/include/asm/uaccess.h | 12 +- trunk/arch/x86/include/asm/uv/uv_bau.h | 1 - trunk/arch/x86/kernel/aperture_64.c | 6 - trunk/arch/x86/kernel/apic/io_apic.c | 4 +- trunk/arch/x86/kernel/cpu/mcheck/mce.c | 4 +- trunk/arch/x86/kernel/cpu/perf_event.c | 11 +- trunk/arch/x86/kernel/cpu/perf_event.h | 2 + trunk/arch/x86/kernel/cpu/perf_event_intel.c | 145 +- .../arch/x86/kernel/cpu/perf_event_intel_ds.c | 9 +- trunk/arch/x86/kernel/nmi_selftest.c | 4 +- trunk/arch/x86/kernel/reboot.c | 6 +- trunk/arch/x86/kernel/smpboot.c | 19 +- trunk/arch/x86/lib/usercopy.c | 4 + trunk/arch/x86/lib/x86-opcode-map.txt | 8 +- trunk/arch/x86/mm/init.c | 3 +- trunk/arch/x86/mm/srat.c | 2 + trunk/arch/x86/platform/mrst/mrst.c | 2 +- trunk/arch/x86/platform/uv/tlb_uv.c | 1 - trunk/arch/x86/tools/gen-insn-attr-x86.awk | 14 +- trunk/arch/xtensa/include/asm/syscall.h | 4 +- trunk/arch/xtensa/kernel/signal.c | 2 +- trunk/drivers/acpi/Kconfig | 2 +- trunk/drivers/acpi/battery.c | 10 +- trunk/drivers/acpi/bus.c | 88 +- trunk/drivers/acpi/power.c | 2 +- trunk/drivers/acpi/processor_perflib.c | 30 +- trunk/drivers/acpi/scan.c | 1 + trunk/drivers/acpi/sleep.c | 49 +- trunk/drivers/acpi/video.c | 33 +- trunk/drivers/char/agp/intel-agp.c | 1 + trunk/drivers/char/agp/intel-agp.h | 1 + trunk/drivers/clocksource/Makefile | 1 + trunk/drivers/clocksource/em_sti.c | 406 +++ trunk/drivers/gpio/gpio-samsung.c | 2 +- trunk/drivers/gpu/drm/exynos/exynos_drm_drv.c | 4 +- .../gpu/drm/exynos/exynos_drm_encoder.c | 7 - trunk/drivers/gpu/drm/exynos/exynos_drm_fb.c | 19 +- trunk/drivers/gpu/drm/exynos/exynos_drm_fb.h | 4 +- trunk/drivers/gpu/drm/exynos/exynos_drm_gem.c | 9 +- trunk/drivers/gpu/drm/exynos/exynos_mixer.c | 12 +- trunk/drivers/gpu/drm/i915/i915_drv.c | 13 +- trunk/drivers/gpu/drm/i915/i915_drv.h | 3 + trunk/drivers/gpu/drm/i915/i915_irq.c | 38 +- trunk/drivers/gpu/drm/i915/i915_reg.h | 43 +- trunk/drivers/gpu/drm/i915/intel_display.c | 19 +- trunk/drivers/gpu/drm/i915/intel_ringbuffer.c | 21 +- trunk/drivers/gpu/drm/radeon/ni.c | 21 +- trunk/drivers/gpu/drm/radeon/r600.c | 15 +- trunk/drivers/gpu/drm/radeon/r600_audio.c | 5 +- trunk/drivers/gpu/drm/radeon/r600_hdmi.c | 1 - trunk/drivers/gpu/drm/radeon/radeon.h | 5 +- trunk/drivers/gpu/drm/radeon/radeon_gart.c | 19 +- trunk/drivers/gpu/drm/radeon/radeon_kms.c | 2 +- trunk/drivers/gpu/drm/radeon/rs600.c | 12 +- trunk/drivers/gpu/drm/radeon/rs690.c | 12 +- trunk/drivers/gpu/drm/radeon/rv770.c | 18 +- trunk/drivers/gpu/drm/radeon/si.c | 477 ++-- trunk/drivers/gpu/drm/radeon/sid.h | 19 + trunk/drivers/i2c/muxes/Kconfig | 12 + trunk/drivers/i2c/muxes/Makefile | 1 + trunk/drivers/i2c/muxes/i2c-mux-pinctrl.c | 279 ++ trunk/drivers/infiniband/hw/cxgb4/cm.c | 4 + trunk/drivers/infiniband/hw/mlx4/main.c | 21 +- trunk/drivers/infiniband/hw/mlx4/mlx4_ib.h | 8 + trunk/drivers/infiniband/hw/mlx4/qp.c | 21 +- trunk/drivers/infiniband/hw/ocrdma/ocrdma.h | 1 - .../drivers/infiniband/hw/ocrdma/ocrdma_abi.h | 5 +- .../drivers/infiniband/hw/ocrdma/ocrdma_hw.c | 9 +- .../infiniband/hw/ocrdma/ocrdma_main.c | 1 - .../infiniband/hw/ocrdma/ocrdma_verbs.c | 5 - .../infiniband/hw/ocrdma/ocrdma_verbs.h | 1 - trunk/drivers/iommu/amd_iommu.c | 71 +- trunk/drivers/iommu/amd_iommu_init.c | 13 +- trunk/drivers/iommu/amd_iommu_types.h | 3 + trunk/drivers/md/raid1.c | 4 + trunk/drivers/md/raid10.c | 4 + trunk/drivers/mtd/ubi/debug.c | 12 +- trunk/drivers/mtd/ubi/wl.c | 17 +- .../drivers/net/ethernet/mellanox/mlx4/port.c | 4 +- trunk/drivers/platform/x86/acerhdf.c | 2 +- trunk/drivers/rtc/rtc-cmos.c | 9 +- trunk/drivers/staging/ramster/zcache-main.c | 8 +- trunk/drivers/staging/zcache/zcache-main.c | 10 +- trunk/drivers/target/sbp/sbp_target.c | 8 +- trunk/drivers/target/target_core_file.c | 70 +- trunk/drivers/target/target_core_file.h | 1 - trunk/drivers/xen/tmem.c | 8 +- trunk/fs/cifs/cifsglob.h | 7 + trunk/fs/cifs/cifsproto.h | 1 - trunk/fs/cifs/cifssmb.c | 8 +- trunk/fs/cifs/connect.c | 8 +- trunk/fs/cifs/file.c | 106 +- trunk/fs/cifs/misc.c | 89 +- trunk/fs/cifs/smb1ops.c | 89 + trunk/fs/cifs/transport.c | 2 +- trunk/fs/dcache.c | 16 +- trunk/fs/ext4/balloc.c | 8 +- trunk/fs/ext4/ioctl.c | 1 - trunk/fs/fuse/control.c | 10 +- trunk/fs/fuse/dir.c | 11 +- trunk/fs/fuse/file.c | 40 + trunk/fs/fuse/fuse_i.h | 6 + trunk/fs/fuse/inode.c | 17 +- trunk/fs/proc/base.c | 17 +- trunk/fs/ubifs/debug.c | 12 +- trunk/include/acpi/acpi_bus.h | 4 +- trunk/include/drm/drm_pciids.h | 17 +- trunk/include/drm/exynos_drm.h | 4 +- trunk/include/linux/clockchips.h | 1 + trunk/include/linux/compaction.h | 19 - trunk/include/linux/frontswap.h | 127 + trunk/include/linux/fs.h | 6 +- trunk/include/linux/fuse.h | 14 +- trunk/include/linux/i2c-mux-pinctrl.h | 41 + trunk/include/linux/init_task.h | 2 +- trunk/include/linux/mfd/abx500/ab8500-codec.h | 52 + trunk/include/linux/mfd/abx500/ab8500.h | 2 + trunk/include/linux/moduleparam.h | 10 +- trunk/include/linux/perf_event.h | 4 +- trunk/include/linux/prctl.h | 10 +- trunk/include/linux/radix-tree.h | 5 +- trunk/include/linux/sched.h | 15 +- trunk/include/linux/swap.h | 4 + trunk/include/linux/swapfile.h | 13 + trunk/include/sound/pcm.h | 11 - trunk/include/sound/soc-dapm.h | 10 - trunk/include/sound/soc.h | 56 +- trunk/init/main.c | 9 +- trunk/ipc/shm.c | 12 + trunk/kernel/cgroup.c | 17 +- trunk/kernel/events/core.c | 1 - trunk/kernel/irq/chip.c | 8 +- trunk/kernel/irq/internals.h | 3 + trunk/kernel/irq/manage.c | 39 +- trunk/kernel/irq/migration.c | 13 +- trunk/kernel/sched/core.c | 249 +- trunk/kernel/sched/fair.c | 71 +- trunk/kernel/sched/rt.c | 53 +- trunk/kernel/sched/sched.h | 2 + trunk/kernel/smpboot.c | 17 +- trunk/kernel/sys.c | 60 +- trunk/kernel/time/clockevents.c | 3 +- trunk/kernel/time/tick-sched.c | 19 + trunk/kernel/time/timekeeping.c | 2 + trunk/lib/btree.c | 5 +- trunk/lib/radix-tree.c | 3 + trunk/lib/raid6/recov.c | 7 +- trunk/lib/raid6/recov_ssse3.c | 7 +- trunk/mm/Kconfig | 17 + trunk/mm/Makefile | 1 + trunk/mm/compaction.c | 142 +- trunk/mm/frontswap.c | 314 ++ trunk/mm/internal.h | 9 +- trunk/mm/migrate.c | 5 +- trunk/mm/nommu.c | 2 +- trunk/mm/oom_kill.c | 4 +- trunk/mm/page_alloc.c | 8 +- trunk/mm/page_io.c | 12 + trunk/mm/shmem.c | 57 +- trunk/mm/swapfile.c | 54 +- trunk/sound/soc/codecs/Kconfig | 12 - trunk/sound/soc/codecs/Makefile | 6 - trunk/sound/soc/codecs/ab8500-codec.c | 2521 ----------------- trunk/sound/soc/codecs/ab8500-codec.h | 590 ---- trunk/sound/soc/codecs/ac97.c | 6 + trunk/sound/soc/codecs/cs42l52.c | 19 +- trunk/sound/soc/codecs/cs42l73.c | 20 +- trunk/sound/soc/codecs/da732x.c | 1627 ----------- trunk/sound/soc/codecs/da732x.h | 133 - trunk/sound/soc/codecs/da732x_reg.h | 654 ----- trunk/sound/soc/codecs/isabelle.c | 1176 -------- trunk/sound/soc/codecs/isabelle.h | 143 - trunk/sound/soc/codecs/lm49453.c | 3 +- trunk/sound/soc/codecs/max98095.c | 5 +- trunk/sound/soc/codecs/tlv320aic3x.c | 2 +- trunk/sound/soc/codecs/wm2000.c | 32 +- trunk/sound/soc/codecs/wm5100-tables.c | 2 +- trunk/sound/soc/codecs/wm5100.c | 2 +- trunk/sound/soc/codecs/wm8350.c | 22 +- trunk/sound/soc/codecs/wm8400.c | 2 +- trunk/sound/soc/codecs/wm8580.c | 2 +- trunk/sound/soc/codecs/wm8731.c | 1 - trunk/sound/soc/codecs/wm8741.c | 2 +- trunk/sound/soc/codecs/wm8753.c | 2 +- trunk/sound/soc/codecs/wm8776.c | 2 +- trunk/sound/soc/codecs/wm8804.c | 2 +- trunk/sound/soc/codecs/wm8903.c | 316 +-- trunk/sound/soc/codecs/wm8904.c | 25 +- trunk/sound/soc/codecs/wm8960.c | 2 - trunk/sound/soc/codecs/wm8961.c | 2 - trunk/sound/soc/codecs/wm8962.c | 2 +- trunk/sound/soc/codecs/wm8993.c | 2 +- trunk/sound/soc/codecs/wm8994.c | 2 +- trunk/sound/soc/codecs/wm8996.c | 184 +- trunk/sound/soc/codecs/wm9081.c | 2 +- trunk/sound/soc/codecs/wm9090.c | 2 +- trunk/sound/soc/codecs/wm9712.c | 2 +- trunk/sound/soc/codecs/wm9713.c | 2 +- trunk/sound/soc/codecs/wm_hubs.c | 2 +- trunk/sound/soc/mxs/mxs-sgtl5000.c | 2 +- trunk/sound/soc/sh/fsi.c | 48 +- trunk/sound/soc/soc-core.c | 140 +- trunk/sound/soc/soc-dapm.c | 44 - trunk/sound/soc/soc-io.c | 2 - trunk/sound/soc/tegra/tegra20_i2s.c | 94 +- trunk/sound/soc/tegra/tegra20_i2s.h | 1 + trunk/sound/soc/tegra/tegra20_spdif.c | 36 +- trunk/sound/soc/tegra/tegra20_spdif.h | 1 + trunk/sound/soc/tegra/tegra30_i2s.c | 85 +- trunk/sound/soc/tegra/tegra30_i2s.h | 1 + trunk/sound/soc/tegra/tegra_alc5632.c | 32 +- trunk/sound/soc/tegra/tegra_wm8753.c | 8 +- trunk/sound/soc/tegra/tegra_wm8903.c | 259 +- trunk/sound/soc/tegra/trimslice.c | 30 +- trunk/sound/soc/ux500/Kconfig | 7 - trunk/sound/soc/ux500/Makefile | 3 - trunk/sound/soc/ux500/ux500_pcm.c | 318 --- trunk/sound/soc/ux500/ux500_pcm.h | 35 - trunk/tools/perf/MANIFEST | 2 + trunk/tools/perf/builtin-report.c | 4 +- trunk/tools/perf/builtin-stat.c | 8 +- trunk/tools/perf/builtin-top.c | 2 +- trunk/tools/perf/design.txt | 7 +- trunk/tools/perf/ui/browsers/annotate.c | 2 +- trunk/tools/perf/util/PERF-VERSION-GEN | 2 +- trunk/tools/perf/util/callchain.c | 2 + trunk/tools/perf/util/callchain.h | 2 + trunk/tools/perf/util/evlist.c | 17 +- trunk/tools/perf/util/evlist.h | 4 + trunk/tools/perf/util/evsel.c | 29 +- trunk/tools/perf/util/hist.c | 7 +- trunk/tools/perf/util/hist.h | 2 - trunk/tools/perf/util/pager.c | 4 + trunk/tools/perf/util/probe-event.c | 8 +- trunk/tools/perf/util/session.c | 97 +- trunk/tools/perf/util/symbol.c | 38 +- trunk/tools/perf/util/symbol.h | 30 + trunk/tools/power/x86/turbostat/turbostat.c | 30 +- trunk/virt/kvm/irq_comm.c | 1 + 262 files changed, 4709 insertions(+), 9417 deletions(-) create mode 100644 trunk/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt create mode 100644 trunk/Documentation/vm/frontswap.txt create mode 100644 trunk/drivers/clocksource/em_sti.c create mode 100644 trunk/drivers/i2c/muxes/i2c-mux-pinctrl.c create mode 100644 trunk/include/linux/frontswap.h create mode 100644 trunk/include/linux/i2c-mux-pinctrl.h create mode 100644 trunk/include/linux/mfd/abx500/ab8500-codec.h create mode 100644 trunk/include/linux/swapfile.h create mode 100644 trunk/mm/frontswap.c delete mode 100644 trunk/sound/soc/codecs/ab8500-codec.c delete mode 100644 trunk/sound/soc/codecs/ab8500-codec.h delete mode 100644 trunk/sound/soc/codecs/da732x.c delete mode 100644 trunk/sound/soc/codecs/da732x.h delete mode 100644 trunk/sound/soc/codecs/da732x_reg.h delete mode 100644 trunk/sound/soc/codecs/isabelle.c delete mode 100644 trunk/sound/soc/codecs/isabelle.h delete mode 100644 trunk/sound/soc/ux500/ux500_pcm.c delete mode 100644 trunk/sound/soc/ux500/ux500_pcm.h diff --git a/[refs] b/[refs] index 00608b10ad2c..aecb8ebeb9ab 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: a89c3e956ae78cec8926b92f2d61b7a5b675e787 +refs/heads/master: f242e50eee1ec7692c4854d94e8cd543991cce71 diff --git a/trunk/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt b/trunk/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt new file mode 100644 index 000000000000..ae8af1694e95 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt @@ -0,0 +1,93 @@ +Pinctrl-based I2C Bus Mux + +This binding describes an I2C bus multiplexer that uses pin multiplexing to +route the I2C signals, and represents the pin multiplexing configuration +using the pinctrl device tree bindings. + + +-----+ +-----+ + | dev | | dev | + +------------------------+ +-----+ +-----+ + | SoC | | | + | /----|------+--------+ + | +---+ +------+ | child bus A, on first set of pins + | |I2C|---|Pinmux| | + | +---+ +------+ | child bus B, on second set of pins + | \----|------+--------+--------+ + | | | | | + +------------------------+ +-----+ +-----+ +-----+ + | dev | | dev | | dev | + +-----+ +-----+ +-----+ + +Required properties: +- compatible: i2c-mux-pinctrl +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side + port is connected to. + +Also required are: + +* Standard pinctrl properties that specify the pin mux state for each child + bus. See ../pinctrl/pinctrl-bindings.txt. + +* Standard I2C mux properties. See mux.txt in this directory. + +* I2C child bus nodes. See mux.txt in this directory. + +For each named state defined in the pinctrl-names property, an I2C child bus +will be created. I2C child bus numbers are assigned based on the index into +the pinctrl-names property. + +The only exception is that no bus will be created for a state named "idle". If +such a state is defined, it must be the last entry in pinctrl-names. For +example: + + pinctrl-names = "ddc", "pta", "idle" -> ddc = bus 0, pta = bus 1 + pinctrl-names = "ddc", "idle", "pta" -> Invalid ("idle" not last) + pinctrl-names = "idle", "ddc", "pta" -> Invalid ("idle" not last) + +Whenever an access is made to a device on a child bus, the relevant pinctrl +state will be programmed into hardware. + +If an idle state is defined, whenever an access is not being made to a device +on a child bus, the idle pinctrl state will be programmed into hardware. + +If an idle state is not defined, the most recently used pinctrl state will be +left programmed into hardware whenever no access is being made of a device on +a child bus. + +Example: + + i2cmux { + compatible = "i2c-mux-pinctrl"; + #address-cells = <1>; + #size-cells = <0>; + + i2c-parent = <&i2c1>; + + pinctrl-names = "ddc", "pta", "idle"; + pinctrl-0 = <&state_i2cmux_ddc>; + pinctrl-1 = <&state_i2cmux_pta>; + pinctrl-2 = <&state_i2cmux_idle>; + + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom { + compatible = "eeprom"; + reg = <0x50>; + }; + }; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom { + compatible = "eeprom"; + reg = <0x50>; + }; + }; + }; + diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index c45513d806ab..a92c5ebf373e 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -2543,6 +2543,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. sched_debug [KNL] Enables verbose scheduler debug messages. + skew_tick= [KNL] Offset the periodic timer tick per cpu to mitigate + xtime_lock contention on larger systems, and/or RCU lock + contention on all systems with CONFIG_MAXSMP set. + Format: { "0" | "1" } + 0 -- disable. (may be 1 via CONFIG_CMDLINE="skew_tick=1" + 1 -- enable. + Note: increases power consumption, thus should only be + enabled if running jitter sensitive (HPC/RT) workloads. + security= [SECURITY] Choose a security module to enable at boot. If this boot parameter is not specified, only the first security module asking for security registration will be diff --git a/trunk/Documentation/vm/frontswap.txt b/trunk/Documentation/vm/frontswap.txt new file mode 100644 index 000000000000..37067cf455f4 --- /dev/null +++ b/trunk/Documentation/vm/frontswap.txt @@ -0,0 +1,278 @@ +Frontswap provides a "transcendent memory" interface for swap pages. +In some environments, dramatic performance savings may be obtained because +swapped pages are saved in RAM (or a RAM-like device) instead of a swap disk. + +(Note, frontswap -- and cleancache (merged at 3.0) -- are the "frontends" +and the only necessary changes to the core kernel for transcendent memory; +all other supporting code -- the "backends" -- is implemented as drivers. +See the LWN.net article "Transcendent memory in a nutshell" for a detailed +overview of frontswap and related kernel parts: +https://lwn.net/Articles/454795/ ) + +Frontswap is so named because it can be thought of as the opposite of +a "backing" store for a swap device. The storage is assumed to be +a synchronous concurrency-safe page-oriented "pseudo-RAM device" conforming +to the requirements of transcendent memory (such as Xen's "tmem", or +in-kernel compressed memory, aka "zcache", or future RAM-like devices); +this pseudo-RAM device is not directly accessible or addressable by the +kernel and is of unknown and possibly time-varying size. The driver +links itself to frontswap by calling frontswap_register_ops to set the +frontswap_ops funcs appropriately and the functions it provides must +conform to certain policies as follows: + +An "init" prepares the device to receive frontswap pages associated +with the specified swap device number (aka "type"). A "store" will +copy the page to transcendent memory and associate it with the type and +offset associated with the page. A "load" will copy the page, if found, +from transcendent memory into kernel memory, but will NOT remove the page +from from transcendent memory. An "invalidate_page" will remove the page +from transcendent memory and an "invalidate_area" will remove ALL pages +associated with the swap type (e.g., like swapoff) and notify the "device" +to refuse further stores with that swap type. + +Once a page is successfully stored, a matching load on the page will normally +succeed. So when the kernel finds itself in a situation where it needs +to swap out a page, it first attempts to use frontswap. If the store returns +success, the data has been successfully saved to transcendent memory and +a disk write and, if the data is later read back, a disk read are avoided. +If a store returns failure, transcendent memory has rejected the data, and the +page can be written to swap as usual. + +If a backend chooses, frontswap can be configured as a "writethrough +cache" by calling frontswap_writethrough(). In this mode, the reduction +in swap device writes is lost (and also a non-trivial performance advantage) +in order to allow the backend to arbitrarily "reclaim" space used to +store frontswap pages to more completely manage its memory usage. + +Note that if a page is stored and the page already exists in transcendent memory +(a "duplicate" store), either the store succeeds and the data is overwritten, +or the store fails AND the page is invalidated. This ensures stale data may +never be obtained from frontswap. + +If properly configured, monitoring of frontswap is done via debugfs in +the /sys/kernel/debug/frontswap directory. The effectiveness of +frontswap can be measured (across all swap devices) with: + +failed_stores - how many store attempts have failed +loads - how many loads were attempted (all should succeed) +succ_stores - how many store attempts have succeeded +invalidates - how many invalidates were attempted + +A backend implementation may provide additional metrics. + +FAQ + +1) Where's the value? + +When a workload starts swapping, performance falls through the floor. +Frontswap significantly increases performance in many such workloads by +providing a clean, dynamic interface to read and write swap pages to +"transcendent memory" that is otherwise not directly addressable to the kernel. +This interface is ideal when data is transformed to a different form +and size (such as with compression) or secretly moved (as might be +useful for write-balancing for some RAM-like devices). Swap pages (and +evicted page-cache pages) are a great use for this kind of slower-than-RAM- +but-much-faster-than-disk "pseudo-RAM device" and the frontswap (and +cleancache) interface to transcendent memory provides a nice way to read +and write -- and indirectly "name" -- the pages. + +Frontswap -- and cleancache -- with a fairly small impact on the kernel, +provides a huge amount of flexibility for more dynamic, flexible RAM +utilization in various system configurations: + +In the single kernel case, aka "zcache", pages are compressed and +stored in local memory, thus increasing the total anonymous pages +that can be safely kept in RAM. Zcache essentially trades off CPU +cycles used in compression/decompression for better memory utilization. +Benchmarks have shown little or no impact when memory pressure is +low while providing a significant performance improvement (25%+) +on some workloads under high memory pressure. + +"RAMster" builds on zcache by adding "peer-to-peer" transcendent memory +support for clustered systems. Frontswap pages are locally compressed +as in zcache, but then "remotified" to another system's RAM. This +allows RAM to be dynamically load-balanced back-and-forth as needed, +i.e. when system A is overcommitted, it can swap to system B, and +vice versa. RAMster can also be configured as a memory server so +many servers in a cluster can swap, dynamically as needed, to a single +server configured with a large amount of RAM... without pre-configuring +how much of the RAM is available for each of the clients! + +In the virtual case, the whole point of virtualization is to statistically +multiplex physical resources acrosst the varying demands of multiple +virtual machines. This is really hard to do with RAM and efforts to do +it well with no kernel changes have essentially failed (except in some +well-publicized special-case workloads). +Specifically, the Xen Transcendent Memory backend allows otherwise +"fallow" hypervisor-owned RAM to not only be "time-shared" between multiple +virtual machines, but the pages can be compressed and deduplicated to +optimize RAM utilization. And when guest OS's are induced to surrender +underutilized RAM (e.g. with "selfballooning"), sudden unexpected +memory pressure may result in swapping; frontswap allows those pages +to be swapped to and from hypervisor RAM (if overall host system memory +conditions allow), thus mitigating the potentially awful performance impact +of unplanned swapping. + +A KVM implementation is underway and has been RFC'ed to lkml. And, +using frontswap, investigation is also underway on the use of NVM as +a memory extension technology. + +2) Sure there may be performance advantages in some situations, but + what's the space/time overhead of frontswap? + +If CONFIG_FRONTSWAP is disabled, every frontswap hook compiles into +nothingness and the only overhead is a few extra bytes per swapon'ed +swap device. If CONFIG_FRONTSWAP is enabled but no frontswap "backend" +registers, there is one extra global variable compared to zero for +every swap page read or written. If CONFIG_FRONTSWAP is enabled +AND a frontswap backend registers AND the backend fails every "store" +request (i.e. provides no memory despite claiming it might), +CPU overhead is still negligible -- and since every frontswap fail +precedes a swap page write-to-disk, the system is highly likely +to be I/O bound and using a small fraction of a percent of a CPU +will be irrelevant anyway. + +As for space, if CONFIG_FRONTSWAP is enabled AND a frontswap backend +registers, one bit is allocated for every swap page for every swap +device that is swapon'd. This is added to the EIGHT bits (which +was sixteen until about 2.6.34) that the kernel already allocates +for every swap page for every swap device that is swapon'd. (Hugh +Dickins has observed that frontswap could probably steal one of +the existing eight bits, but let's worry about that minor optimization +later.) For very large swap disks (which are rare) on a standard +4K pagesize, this is 1MB per 32GB swap. + +When swap pages are stored in transcendent memory instead of written +out to disk, there is a side effect that this may create more memory +pressure that can potentially outweigh the other advantages. A +backend, such as zcache, must implement policies to carefully (but +dynamically) manage memory limits to ensure this doesn't happen. + +3) OK, how about a quick overview of what this frontswap patch does + in terms that a kernel hacker can grok? + +Let's assume that a frontswap "backend" has registered during +kernel initialization; this registration indicates that this +frontswap backend has access to some "memory" that is not directly +accessible by the kernel. Exactly how much memory it provides is +entirely dynamic and random. + +Whenever a swap-device is swapon'd frontswap_init() is called, +passing the swap device number (aka "type") as a parameter. +This notifies frontswap to expect attempts to "store" swap pages +associated with that number. + +Whenever the swap subsystem is readying a page to write to a swap +device (c.f swap_writepage()), frontswap_store is called. Frontswap +consults with the frontswap backend and if the backend says it does NOT +have room, frontswap_store returns -1 and the kernel swaps the page +to the swap device as normal. Note that the response from the frontswap +backend is unpredictable to the kernel; it may choose to never accept a +page, it could accept every ninth page, or it might accept every +page. But if the backend does accept a page, the data from the page +has already been copied and associated with the type and offset, +and the backend guarantees the persistence of the data. In this case, +frontswap sets a bit in the "frontswap_map" for the swap device +corresponding to the page offset on the swap device to which it would +otherwise have written the data. + +When the swap subsystem needs to swap-in a page (swap_readpage()), +it first calls frontswap_load() which checks the frontswap_map to +see if the page was earlier accepted by the frontswap backend. If +it was, the page of data is filled from the frontswap backend and +the swap-in is complete. If not, the normal swap-in code is +executed to obtain the page of data from the real swap device. + +So every time the frontswap backend accepts a page, a swap device read +and (potentially) a swap device write are replaced by a "frontswap backend +store" and (possibly) a "frontswap backend loads", which are presumably much +faster. + +4) Can't frontswap be configured as a "special" swap device that is + just higher priority than any real swap device (e.g. like zswap, + or maybe swap-over-nbd/NFS)? + +No. First, the existing swap subsystem doesn't allow for any kind of +swap hierarchy. Perhaps it could be rewritten to accomodate a hierarchy, +but this would require fairly drastic changes. Even if it were +rewritten, the existing swap subsystem uses the block I/O layer which +assumes a swap device is fixed size and any page in it is linearly +addressable. Frontswap barely touches the existing swap subsystem, +and works around the constraints of the block I/O subsystem to provide +a great deal of flexibility and dynamicity. + +For example, the acceptance of any swap page by the frontswap backend is +entirely unpredictable. This is critical to the definition of frontswap +backends because it grants completely dynamic discretion to the +backend. In zcache, one cannot know a priori how compressible a page is. +"Poorly" compressible pages can be rejected, and "poorly" can itself be +defined dynamically depending on current memory constraints. + +Further, frontswap is entirely synchronous whereas a real swap +device is, by definition, asynchronous and uses block I/O. The +block I/O layer is not only unnecessary, but may perform "optimizations" +that are inappropriate for a RAM-oriented device including delaying +the write of some pages for a significant amount of time. Synchrony is +required to ensure the dynamicity of the backend and to avoid thorny race +conditions that would unnecessarily and greatly complicate frontswap +and/or the block I/O subsystem. That said, only the initial "store" +and "load" operations need be synchronous. A separate asynchronous thread +is free to manipulate the pages stored by frontswap. For example, +the "remotification" thread in RAMster uses standard asynchronous +kernel sockets to move compressed frontswap pages to a remote machine. +Similarly, a KVM guest-side implementation could do in-guest compression +and use "batched" hypercalls. + +In a virtualized environment, the dynamicity allows the hypervisor +(or host OS) to do "intelligent overcommit". For example, it can +choose to accept pages only until host-swapping might be imminent, +then force guests to do their own swapping. + +There is a downside to the transcendent memory specifications for +frontswap: Since any "store" might fail, there must always be a real +slot on a real swap device to swap the page. Thus frontswap must be +implemented as a "shadow" to every swapon'd device with the potential +capability of holding every page that the swap device might have held +and the possibility that it might hold no pages at all. This means +that frontswap cannot contain more pages than the total of swapon'd +swap devices. For example, if NO swap device is configured on some +installation, frontswap is useless. Swapless portable devices +can still use frontswap but a backend for such devices must configure +some kind of "ghost" swap device and ensure that it is never used. + +5) Why this weird definition about "duplicate stores"? If a page + has been previously successfully stored, can't it always be + successfully overwritten? + +Nearly always it can, but no, sometimes it cannot. Consider an example +where data is compressed and the original 4K page has been compressed +to 1K. Now an attempt is made to overwrite the page with data that +is non-compressible and so would take the entire 4K. But the backend +has no more space. In this case, the store must be rejected. Whenever +frontswap rejects a store that would overwrite, it also must invalidate +the old data and ensure that it is no longer accessible. Since the +swap subsystem then writes the new data to the read swap device, +this is the correct course of action to ensure coherency. + +6) What is frontswap_shrink for? + +When the (non-frontswap) swap subsystem swaps out a page to a real +swap device, that page is only taking up low-value pre-allocated disk +space. But if frontswap has placed a page in transcendent memory, that +page may be taking up valuable real estate. The frontswap_shrink +routine allows code outside of the swap subsystem to force pages out +of the memory managed by frontswap and back into kernel-addressable memory. +For example, in RAMster, a "suction driver" thread will attempt +to "repatriate" pages sent to a remote machine back to the local machine; +this is driven using the frontswap_shrink mechanism when memory pressure +subsides. + +7) Why does the frontswap patch create the new include file swapfile.h? + +The frontswap code depends on some swap-subsystem-internal data +structures that have, over the years, moved back and forth between +static and global. This seemed a reasonable compromise: Define +them as global but declare them in a new include file that isn't +included by the large number of source files that include swap.h. + +Dan Magenheimer, last updated April 9, 2012 diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index d0526640f717..14bc7071f9df 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -1077,7 +1077,7 @@ F: drivers/media/video/s5p-fimc/ ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT M: Kyungmin Park M: Kamil Debski -M: Jeongtae Park +M: Jeongtae Park L: linux-arm-kernel@lists.infradead.org L: linux-media@vger.kernel.org S: Maintained @@ -1743,10 +1743,10 @@ F: include/linux/can/platform/ CAPABILITIES M: Serge Hallyn L: linux-security-module@vger.kernel.org -S: Supported +S: Supported F: include/linux/capability.h F: security/capability.c -F: security/commoncap.c +F: security/commoncap.c F: kernel/capability.c CELL BROADBAND ENGINE ARCHITECTURE @@ -2146,11 +2146,11 @@ S: Orphan F: drivers/net/wan/pc300* CYTTSP TOUCHSCREEN DRIVER -M: Javier Martinez Canillas -L: linux-input@vger.kernel.org -S: Maintained -F: drivers/input/touchscreen/cyttsp* -F: include/linux/input/cyttsp.h +M: Javier Martinez Canillas +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/input/touchscreen/cyttsp* +F: include/linux/input/cyttsp.h DAMA SLAVE for AX.25 M: Joerg Reuter @@ -2270,7 +2270,7 @@ F: include/linux/device-mapper.h F: include/linux/dm-*.h DIOLAN U2C-12 I2C DRIVER -M: Guenter Roeck +M: Guenter Roeck L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/busses/i2c-diolan-u2c.c @@ -2930,6 +2930,13 @@ F: Documentation/power/freezing-of-tasks.txt F: include/linux/freezer.h F: kernel/freezer.c +FRONTSWAP API +M: Konrad Rzeszutek Wilk +L: linux-kernel@vger.kernel.org +S: Maintained +F: mm/frontswap.c +F: include/linux/frontswap.h + FS-CACHE: LOCAL CACHING FOR NETWORK FILESYSTEMS M: David Howells L: linux-cachefs@redhat.com @@ -3138,7 +3145,7 @@ F: drivers/tty/hvc/ HARDWARE MONITORING M: Jean Delvare -M: Guenter Roeck +M: Guenter Roeck L: lm-sensors@lm-sensors.org W: http://www.lm-sensors.org/ T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-hwmon/ @@ -4096,6 +4103,8 @@ F: drivers/scsi/53c700* LED SUBSYSTEM M: Bryan Wu M: Richard Purdie +L: linux-leds@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git S: Maintained F: drivers/leds/ F: include/linux/leds.h @@ -4411,6 +4420,13 @@ S: Orphan F: drivers/video/matrox/matroxfb_* F: include/linux/matroxfb.h +MAX16065 HARDWARE MONITOR DRIVER +M: Guenter Roeck +L: lm-sensors@lm-sensors.org +S: Maintained +F: Documentation/hwmon/max16065 +F: drivers/hwmon/max16065.c + MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER M: "Hans J. Koch" L: lm-sensors@lm-sensors.org @@ -5149,7 +5165,7 @@ F: drivers/leds/leds-pca9532.c F: include/linux/leds-pca9532.h PCA9541 I2C BUS MASTER SELECTOR DRIVER -M: Guenter Roeck +M: Guenter Roeck L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/muxes/i2c-mux-pca9541.c @@ -5169,7 +5185,7 @@ S: Maintained F: drivers/firmware/pcdp.* PCI ERROR RECOVERY -M: Linas Vepstas +M: Linas Vepstas L: linux-pci@vger.kernel.org S: Supported F: Documentation/PCI/pci-error-recovery.txt @@ -5299,7 +5315,7 @@ F: drivers/video/fb-puv3.c F: drivers/rtc/rtc-puv3.c PMBUS HARDWARE MONITORING DRIVERS -M: Guenter Roeck +M: Guenter Roeck L: lm-sensors@lm-sensors.org W: http://www.lm-sensors.org/ W: http://www.roeck-us.net/linux/drivers/ @@ -6723,11 +6739,9 @@ F: include/linux/tifm.h TI LM49xxx FAMILY ASoC CODEC DRIVERS M: M R Swami Reddy -M: Vishwas A Deshpande L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained F: sound/soc/codecs/lm49453* -F: sound/soc/codecs/isabelle* TI TWL4030 SERIES SOC CODEC DRIVER M: Peter Ujfalusi @@ -7293,11 +7307,11 @@ F: Documentation/DocBook/uio-howto.tmpl F: drivers/uio/ F: include/linux/uio*.h -UTIL-LINUX-NG PACKAGE +UTIL-LINUX PACKAGE M: Karel Zak -L: util-linux-ng@vger.kernel.org -W: http://kernel.org/~kzak/util-linux-ng/ -T: git git://git.kernel.org/pub/scm/utils/util-linux-ng/util-linux-ng.git +L: util-linux@vger.kernel.org +W: http://en.wikipedia.org/wiki/Util-linux +T: git git://git.kernel.org/pub/scm/utils/util-linux/util-linux.git S: Maintained UVESAFB DRIVER diff --git a/trunk/Makefile b/trunk/Makefile index 0d718ede9ea5..d845c2a1aa68 100644 --- a/trunk/Makefile +++ b/trunk/Makefile @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 5 SUBLEVEL = 0 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = Saber-toothed Squirrel # *DOCUMENTATION* diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig index b649c5904a4f..84449dd8f031 100644 --- a/trunk/arch/arm/Kconfig +++ b/trunk/arch/arm/Kconfig @@ -7,7 +7,6 @@ config ARM select HAVE_IDE if PCI || ISA || PCMCIA select HAVE_DMA_ATTRS select HAVE_DMA_CONTIGUOUS if (CPU_V6 || CPU_V6K || CPU_V7) - select CMA if (CPU_V6 || CPU_V6K || CPU_V7) select HAVE_MEMBLOCK select RTC_LIB select SYS_SUPPORTS_APM_EMULATION diff --git a/trunk/arch/arm/mach-shmobile/Kconfig b/trunk/arch/arm/mach-shmobile/Kconfig index f31383c32f9c..df33909205e2 100644 --- a/trunk/arch/arm/mach-shmobile/Kconfig +++ b/trunk/arch/arm/mach-shmobile/Kconfig @@ -186,6 +186,12 @@ config SH_TIMER_TMU help This enables build of the TMU timer driver. +config EM_TIMER_STI + bool "STI timer driver" + default y + help + This enables build of the STI timer driver. + endmenu config SH_CLK_CPG diff --git a/trunk/arch/arm/mach-ux500/board-mop500.c b/trunk/arch/arm/mach-ux500/board-mop500.c index 9c74ac545849..c8a8fde777bb 100644 --- a/trunk/arch/arm/mach-ux500/board-mop500.c +++ b/trunk/arch/arm/mach-ux500/board-mop500.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +98,18 @@ static struct ab8500_gpio_platform_data ab8500_gpio_pdata = { 0x7A, 0x00, 0x00}, }; +/* ab8500-codec */ +static struct ab8500_codec_platform_data ab8500_codec_pdata = { + .amics = { + .mic1_type = AMIC_TYPE_DIFFERENTIAL, + .mic2_type = AMIC_TYPE_DIFFERENTIAL, + .mic1a_micbias = AMIC_MICBIAS_VAMIC1, + .mic1b_micbias = AMIC_MICBIAS_VAMIC1, + .mic2_micbias = AMIC_MICBIAS_VAMIC2 + }, + .ear_cmv = EAR_CMV_0_95V +}; + static struct gpio_keys_button snowball_key_array[] = { { .gpio = 32, @@ -195,6 +208,7 @@ static struct ab8500_platform_data ab8500_platdata = { .regulator = ab8500_regulators, .num_regulator = ARRAY_SIZE(ab8500_regulators), .gpio = &ab8500_gpio_pdata, + .codec = &ab8500_codec_pdata, }; static struct resource ab8500_resources[] = { diff --git a/trunk/arch/arm/mm/dma-mapping.c b/trunk/arch/arm/mm/dma-mapping.c index ea6b43154090..106c4c0ebccd 100644 --- a/trunk/arch/arm/mm/dma-mapping.c +++ b/trunk/arch/arm/mm/dma-mapping.c @@ -268,10 +268,8 @@ static int __init consistent_init(void) unsigned long base = consistent_base; unsigned long num_ptes = (CONSISTENT_END - base) >> PMD_SHIFT; -#ifndef CONFIG_ARM_DMA_USE_IOMMU - if (cpu_architecture() >= CPU_ARCH_ARMv6) + if (IS_ENABLED(CONFIG_CMA) && !IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) return 0; -#endif consistent_pte = kmalloc(num_ptes * sizeof(pte_t), GFP_KERNEL); if (!consistent_pte) { @@ -342,7 +340,7 @@ static int __init coherent_init(void) struct page *page; void *ptr; - if (cpu_architecture() < CPU_ARCH_ARMv6) + if (!IS_ENABLED(CONFIG_CMA)) return 0; ptr = __alloc_from_contiguous(NULL, size, prot, &page); @@ -704,7 +702,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, if (arch_is_coherent() || nommu()) addr = __alloc_simple_buffer(dev, size, gfp, &page); - else if (cpu_architecture() < CPU_ARCH_ARMv6) + else if (!IS_ENABLED(CONFIG_CMA)) addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller); else if (gfp & GFP_ATOMIC) addr = __alloc_from_pool(dev, size, &page, caller); @@ -773,7 +771,7 @@ void arm_dma_free(struct device *dev, size_t size, void *cpu_addr, if (arch_is_coherent() || nommu()) { __dma_free_buffer(page, size); - } else if (cpu_architecture() < CPU_ARCH_ARMv6) { + } else if (!IS_ENABLED(CONFIG_CMA)) { __dma_free_remap(cpu_addr, size); __dma_free_buffer(page, size); } else { diff --git a/trunk/arch/avr32/kernel/signal.c b/trunk/arch/avr32/kernel/signal.c index c140f9b41dce..d552a854dacc 100644 --- a/trunk/arch/avr32/kernel/signal.c +++ b/trunk/arch/avr32/kernel/signal.c @@ -300,7 +300,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti) if ((sysreg_read(SR) & MODE_MASK) == MODE_SUPERVISOR) syscall = 1; - if (ti->flags & _TIF_SIGPENDING)) + if (ti->flags & _TIF_SIGPENDING) do_signal(regs, syscall); if (ti->flags & _TIF_NOTIFY_RESUME) { diff --git a/trunk/arch/blackfin/kernel/process.c b/trunk/arch/blackfin/kernel/process.c index 2e3994b20169..62bcea7dcc6d 100644 --- a/trunk/arch/blackfin/kernel/process.c +++ b/trunk/arch/blackfin/kernel/process.c @@ -173,7 +173,7 @@ asmlinkage int bfin_clone(struct pt_regs *regs) unsigned long newsp; #ifdef __ARCH_SYNC_CORE_DCACHE - if (current->rt.nr_cpus_allowed == num_possible_cpus()) + if (current->nr_cpus_allowed == num_possible_cpus()) set_cpus_allowed_ptr(current, cpumask_of(smp_processor_id())); #endif diff --git a/trunk/arch/parisc/Makefile b/trunk/arch/parisc/Makefile index dbc3850b1d0d..5707f1a62341 100644 --- a/trunk/arch/parisc/Makefile +++ b/trunk/arch/parisc/Makefile @@ -21,6 +21,7 @@ KBUILD_DEFCONFIG := default_defconfig NM = sh $(srctree)/arch/parisc/nm CHECKFLAGS += -D__hppa__=1 +LIBGCC = $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) MACHINE := $(shell uname -m) ifeq ($(MACHINE),parisc*) @@ -79,7 +80,7 @@ kernel-y := mm/ kernel/ math-emu/ kernel-$(CONFIG_HPUX) += hpux/ core-y += $(addprefix arch/parisc/, $(kernel-y)) -libs-y += arch/parisc/lib/ `$(CC) -print-libgcc-file-name` +libs-y += arch/parisc/lib/ $(LIBGCC) drivers-$(CONFIG_OPROFILE) += arch/parisc/oprofile/ diff --git a/trunk/arch/parisc/include/asm/Kbuild b/trunk/arch/parisc/include/asm/Kbuild index 19a434f55059..4383707d9801 100644 --- a/trunk/arch/parisc/include/asm/Kbuild +++ b/trunk/arch/parisc/include/asm/Kbuild @@ -1,3 +1,4 @@ include include/asm-generic/Kbuild.asm header-y += pdc.h +generic-y += word-at-a-time.h diff --git a/trunk/arch/parisc/include/asm/bug.h b/trunk/arch/parisc/include/asm/bug.h index 72cfdb0cfdd1..62a33338549c 100644 --- a/trunk/arch/parisc/include/asm/bug.h +++ b/trunk/arch/parisc/include/asm/bug.h @@ -1,6 +1,8 @@ #ifndef _PARISC_BUG_H #define _PARISC_BUG_H +#include /* for BUGFLAG_TAINT */ + /* * Tell the user there is some problem. * The offending file and line are encoded in the __bug_table section. diff --git a/trunk/arch/powerpc/kernel/module_32.c b/trunk/arch/powerpc/kernel/module_32.c index 0b6d79617d7b..2e3200ca485f 100644 --- a/trunk/arch/powerpc/kernel/module_32.c +++ b/trunk/arch/powerpc/kernel/module_32.c @@ -176,8 +176,8 @@ int module_frob_arch_sections(Elf32_Ehdr *hdr, static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val) { - if (entry->jump[0] == 0x3d600000 + ((val + 0x8000) >> 16) - && entry->jump[1] == 0x396b0000 + (val & 0xffff)) + if (entry->jump[0] == 0x3d800000 + ((val + 0x8000) >> 16) + && entry->jump[1] == 0x398c0000 + (val & 0xffff)) return 1; return 0; } @@ -204,10 +204,9 @@ static uint32_t do_plt_call(void *location, entry++; } - /* Stolen from Paul Mackerras as well... */ - entry->jump[0] = 0x3d600000+((val+0x8000)>>16); /* lis r11,sym@ha */ - entry->jump[1] = 0x396b0000 + (val&0xffff); /* addi r11,r11,sym@l*/ - entry->jump[2] = 0x7d6903a6; /* mtctr r11 */ + entry->jump[0] = 0x3d800000+((val+0x8000)>>16); /* lis r12,sym@ha */ + entry->jump[1] = 0x398c0000 + (val&0xffff); /* addi r12,r12,sym@l*/ + entry->jump[2] = 0x7d8903a6; /* mtctr r12 */ entry->jump[3] = 0x4e800420; /* bctr */ DEBUGP("Initialized plt for 0x%x at %p\n", val, entry); diff --git a/trunk/arch/powerpc/kernel/time.c b/trunk/arch/powerpc/kernel/time.c index 99a995c2a3f2..be171ee73bf8 100644 --- a/trunk/arch/powerpc/kernel/time.c +++ b/trunk/arch/powerpc/kernel/time.c @@ -475,6 +475,7 @@ void timer_interrupt(struct pt_regs * regs) struct pt_regs *old_regs; u64 *next_tb = &__get_cpu_var(decrementers_next_tb); struct clock_event_device *evt = &__get_cpu_var(decrementers); + u64 now; /* Ensure a positive value is written to the decrementer, or else * some CPUs will continue to take decrementer exceptions. @@ -509,9 +510,16 @@ void timer_interrupt(struct pt_regs * regs) irq_work_run(); } - *next_tb = ~(u64)0; - if (evt->event_handler) - evt->event_handler(evt); + now = get_tb_or_rtc(); + if (now >= *next_tb) { + *next_tb = ~(u64)0; + if (evt->event_handler) + evt->event_handler(evt); + } else { + now = *next_tb - now; + if (now <= DECREMENTER_MAX) + set_dec((int)now); + } #ifdef CONFIG_PPC64 /* collect purr register values often, for accurate calculations */ diff --git a/trunk/arch/tile/include/asm/thread_info.h b/trunk/arch/tile/include/asm/thread_info.h index 7e1fef36bde6..e9c670d7a7fe 100644 --- a/trunk/arch/tile/include/asm/thread_info.h +++ b/trunk/arch/tile/include/asm/thread_info.h @@ -91,11 +91,6 @@ extern void smp_nap(void); /* Enable interrupts racelessly and nap forever: helper for cpu_idle(). */ extern void _cpu_idle(void); -/* Switch boot idle thread to a freshly-allocated stack and free old stack. */ -extern void cpu_idle_on_new_stack(struct thread_info *old_ti, - unsigned long new_sp, - unsigned long new_ss10); - #else /* __ASSEMBLY__ */ /* diff --git a/trunk/arch/tile/kernel/entry.S b/trunk/arch/tile/kernel/entry.S index 133c4b56a99e..c31637baff28 100644 --- a/trunk/arch/tile/kernel/entry.S +++ b/trunk/arch/tile/kernel/entry.S @@ -68,20 +68,6 @@ STD_ENTRY(KBacktraceIterator_init_current) jrp lr /* keep backtracer happy */ STD_ENDPROC(KBacktraceIterator_init_current) -/* - * Reset our stack to r1/r2 (sp and ksp0+cpu respectively), then - * free the old stack (passed in r0) and re-invoke cpu_idle(). - * We update sp and ksp0 simultaneously to avoid backtracer warnings. - */ -STD_ENTRY(cpu_idle_on_new_stack) - { - move sp, r1 - mtspr SPR_SYSTEM_SAVE_K_0, r2 - } - jal free_thread_info - j cpu_idle - STD_ENDPROC(cpu_idle_on_new_stack) - /* Loop forever on a nap during SMP boot. */ STD_ENTRY(smp_nap) nap diff --git a/trunk/arch/tile/kernel/setup.c b/trunk/arch/tile/kernel/setup.c index 6098ccc59be2..dd87f3420390 100644 --- a/trunk/arch/tile/kernel/setup.c +++ b/trunk/arch/tile/kernel/setup.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/x86/boot/header.S b/trunk/arch/x86/boot/header.S index 8bbea6aa40d9..efe5acfc79c3 100644 --- a/trunk/arch/x86/boot/header.S +++ b/trunk/arch/x86/boot/header.S @@ -94,10 +94,10 @@ bs_die: .section ".bsdata", "a" bugger_off_msg: - .ascii "Direct booting from floppy is no longer supported.\r\n" - .ascii "Please use a boot loader program instead.\r\n" + .ascii "Direct floppy boot is not supported. " + .ascii "Use a boot loader program instead.\r\n" .ascii "\n" - .ascii "Remove disk and press any key to reboot . . .\r\n" + .ascii "Remove disk and press any key to reboot ...\r\n" .byte 0 #ifdef CONFIG_EFI_STUB @@ -111,7 +111,7 @@ coff_header: #else .word 0x8664 # x86-64 #endif - .word 2 # nr_sections + .word 3 # nr_sections .long 0 # TimeDateStamp .long 0 # PointerToSymbolTable .long 1 # NumberOfSymbols @@ -158,8 +158,8 @@ extra_header_fields: #else .quad 0 # ImageBase #endif - .long 0x1000 # SectionAlignment - .long 0x200 # FileAlignment + .long 0x20 # SectionAlignment + .long 0x20 # FileAlignment .word 0 # MajorOperatingSystemVersion .word 0 # MinorOperatingSystemVersion .word 0 # MajorImageVersion @@ -200,8 +200,10 @@ extra_header_fields: # Section table section_table: - .ascii ".text" - .byte 0 + # + # The offset & size fields are filled in by build.c. + # + .ascii ".setup" .byte 0 .byte 0 .long 0 @@ -217,9 +219,8 @@ section_table: # # The EFI application loader requires a relocation section - # 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. + # because EFI applications must be relocatable. The .reloc + # offset & size fields are filled in by build.c. # .ascii ".reloc" .byte 0 @@ -233,6 +234,25 @@ section_table: .word 0 # NumberOfRelocations .word 0 # NumberOfLineNumbers .long 0x42100040 # Characteristics (section flags) + + # + # The offset & size fields are filled in by build.c. + # + .ascii ".text" + .byte 0 + .byte 0 + .byte 0 + .long 0 + .long 0x0 # startup_{32,64} + .long 0 # Size of initialized data + # on disk + .long 0x0 # startup_{32,64} + .long 0 # PointerToRelocations + .long 0 # PointerToLineNumbers + .word 0 # NumberOfRelocations + .word 0 # NumberOfLineNumbers + .long 0x60500020 # Characteristics (section flags) + #endif /* CONFIG_EFI_STUB */ # Kernel attributes; used by setup. This is part 1 of the diff --git a/trunk/arch/x86/boot/tools/build.c b/trunk/arch/x86/boot/tools/build.c index 3f61f6e2b46f..4b8e165ee572 100644 --- a/trunk/arch/x86/boot/tools/build.c +++ b/trunk/arch/x86/boot/tools/build.c @@ -50,6 +50,8 @@ typedef unsigned int u32; u8 buf[SETUP_SECT_MAX*512]; int is_big_kernel; +#define PECOFF_RELOC_RESERVE 0x20 + /*----------------------------------------------------------------------*/ static const u32 crctab32[] = { @@ -133,11 +135,103 @@ static void usage(void) die("Usage: build setup system [> image]"); } -int main(int argc, char ** argv) -{ #ifdef CONFIG_EFI_STUB - unsigned int file_sz, pe_header; + +static void update_pecoff_section_header(char *section_name, u32 offset, u32 size) +{ + unsigned int pe_header; + unsigned short num_sections; + u8 *section; + + pe_header = get_unaligned_le32(&buf[0x3c]); + num_sections = get_unaligned_le16(&buf[pe_header + 6]); + +#ifdef CONFIG_X86_32 + section = &buf[pe_header + 0xa8]; +#else + section = &buf[pe_header + 0xb8]; #endif + + while (num_sections > 0) { + if (strncmp((char*)section, section_name, 8) == 0) { + /* section header size field */ + put_unaligned_le32(size, section + 0x8); + + /* section header vma field */ + put_unaligned_le32(offset, section + 0xc); + + /* section header 'size of initialised data' field */ + put_unaligned_le32(size, section + 0x10); + + /* section header 'file offset' field */ + put_unaligned_le32(offset, section + 0x14); + + break; + } + section += 0x28; + num_sections--; + } +} + +static void update_pecoff_setup_and_reloc(unsigned int size) +{ + u32 setup_offset = 0x200; + u32 reloc_offset = size - PECOFF_RELOC_RESERVE; + u32 setup_size = reloc_offset - setup_offset; + + update_pecoff_section_header(".setup", setup_offset, setup_size); + update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE); + + /* + * Modify .reloc section contents with a single entry. The + * relocation is applied to offset 10 of the relocation section. + */ + put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]); + put_unaligned_le32(10, &buf[reloc_offset + 4]); +} + +static void update_pecoff_text(unsigned int text_start, unsigned int file_sz) +{ + unsigned int pe_header; + unsigned int text_sz = file_sz - text_start; + + pe_header = get_unaligned_le32(&buf[0x3c]); + + /* Size of image */ + put_unaligned_le32(file_sz, &buf[pe_header + 0x50]); + + /* + * Size of code: Subtract the size of the first sector (512 bytes) + * which includes the header. + */ + put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]); + +#ifdef CONFIG_X86_32 + /* + * Address of entry point. + * + * The EFI stub entry point is +16 bytes from the start of + * the .text section. + */ + put_unaligned_le32(text_start + 16, &buf[pe_header + 0x28]); +#else + /* + * Address of entry point. startup_32 is at the beginning and + * the 64-bit entry point (startup_64) is always 512 bytes + * after. The EFI stub entry point is 16 bytes after that, as + * the first instruction allows legacy loaders to jump over + * the EFI stub initialisation + */ + put_unaligned_le32(text_start + 528, &buf[pe_header + 0x28]); +#endif /* CONFIG_X86_32 */ + + update_pecoff_section_header(".text", text_start, text_sz); +} + +#endif /* CONFIG_EFI_STUB */ + +int main(int argc, char ** argv) +{ unsigned int i, sz, setup_sectors; int c; u32 sys_size; @@ -163,6 +257,12 @@ int main(int argc, char ** argv) die("Boot block hasn't got boot flag (0xAA55)"); fclose(file); +#ifdef CONFIG_EFI_STUB + /* Reserve 0x20 bytes for .reloc section */ + memset(buf+c, 0, PECOFF_RELOC_RESERVE); + c += PECOFF_RELOC_RESERVE; +#endif + /* Pad unused space with zeros */ setup_sectors = (c + 511) / 512; if (setup_sectors < SETUP_SECT_MIN) @@ -170,6 +270,10 @@ int main(int argc, char ** argv) i = setup_sectors*512; memset(buf+c, 0, i-c); +#ifdef CONFIG_EFI_STUB + update_pecoff_setup_and_reloc(i); +#endif + /* Set the default root device */ put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]); @@ -194,66 +298,8 @@ int main(int argc, char ** argv) put_unaligned_le32(sys_size, &buf[0x1f4]); #ifdef CONFIG_EFI_STUB - file_sz = sz + i + ((sys_size * 16) - sz); - - pe_header = get_unaligned_le32(&buf[0x3c]); - - /* 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. - * - * The EFI stub entry point is +16 bytes from the start of - * the .text section. - */ - put_unaligned_le32(i + 16, &buf[pe_header + 0x28]); - - /* .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 - * the 64-bit entry point (startup_64) is always 512 bytes - * after. The EFI stub entry point is 16 bytes after that, as - * the first instruction allows legacy loaders to jump over - * the EFI stub initialisation - */ - put_unaligned_le32(i + 528, &buf[pe_header + 0x28]); - - /* .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 */ + update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz)); +#endif crc = partial_crc32(buf, i, crc); if (fwrite(buf, 1, i, stdout) != i) diff --git a/trunk/arch/x86/include/asm/nmi.h b/trunk/arch/x86/include/asm/nmi.h index 0e3793b821ef..dc580c42851c 100644 --- a/trunk/arch/x86/include/asm/nmi.h +++ b/trunk/arch/x86/include/asm/nmi.h @@ -54,6 +54,20 @@ struct nmiaction { __register_nmi_handler((t), &fn##_na); \ }) +/* + * For special handlers that register/unregister in the + * init section only. This should be considered rare. + */ +#define register_nmi_handler_initonly(t, fn, fg, n) \ +({ \ + static struct nmiaction fn##_na __initdata = { \ + .handler = (fn), \ + .name = (n), \ + .flags = (fg), \ + }; \ + __register_nmi_handler((t), &fn##_na); \ +}) + int __register_nmi_handler(unsigned int, struct nmiaction *); void unregister_nmi_handler(unsigned int, const char *); diff --git a/trunk/arch/x86/include/asm/uaccess.h b/trunk/arch/x86/include/asm/uaccess.h index 04cd6882308e..e1f3a17034fc 100644 --- a/trunk/arch/x86/include/asm/uaccess.h +++ b/trunk/arch/x86/include/asm/uaccess.h @@ -33,9 +33,8 @@ #define segment_eq(a, b) ((a).seg == (b).seg) #define user_addr_max() (current_thread_info()->addr_limit.seg) -#define __addr_ok(addr) \ - ((unsigned long __force)(addr) < \ - (current_thread_info()->addr_limit.seg)) +#define __addr_ok(addr) \ + ((unsigned long __force)(addr) < user_addr_max()) /* * Test whether a block of memory is a valid user space address. @@ -47,14 +46,14 @@ * This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry... */ -#define __range_not_ok(addr, size) \ +#define __range_not_ok(addr, size, limit) \ ({ \ unsigned long flag, roksum; \ __chk_user_ptr(addr); \ asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \ : "=&r" (flag), "=r" (roksum) \ : "1" (addr), "g" ((long)(size)), \ - "rm" (current_thread_info()->addr_limit.seg)); \ + "rm" (limit)); \ flag; \ }) @@ -77,7 +76,8 @@ * checks that the pointer is in the user space range - after calling * this function, memory access functions may still return -EFAULT. */ -#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0)) +#define access_ok(type, addr, size) \ + (likely(__range_not_ok(addr, size, user_addr_max()) == 0)) /* * The exception table consists of pairs of addresses relative to the diff --git a/trunk/arch/x86/include/asm/uv/uv_bau.h b/trunk/arch/x86/include/asm/uv/uv_bau.h index becf47b81735..6149b476d9df 100644 --- a/trunk/arch/x86/include/asm/uv/uv_bau.h +++ b/trunk/arch/x86/include/asm/uv/uv_bau.h @@ -149,7 +149,6 @@ /* 4 bits of software ack period */ #define UV2_ACK_MASK 0x7UL #define UV2_ACK_UNITS_SHFT 3 -#define UV2_LEG_SHFT UV2H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT #define UV2_EXT_SHFT UV2H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT /* diff --git a/trunk/arch/x86/kernel/aperture_64.c b/trunk/arch/x86/kernel/aperture_64.c index 6e76c191a835..d5fd66f0d4cd 100644 --- a/trunk/arch/x86/kernel/aperture_64.c +++ b/trunk/arch/x86/kernel/aperture_64.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -95,11 +94,6 @@ static u32 __init allocate_aperture(void) return 0; } memblock_reserve(addr, aper_size); - /* - * Kmemleak should not scan this block as it may not be mapped via the - * kernel direct mapping. - */ - kmemleak_ignore(phys_to_virt(addr)); printk(KERN_INFO "Mapping aperture over %d KB of RAM @ %lx\n", aper_size >> 10, addr); insert_aperture_resource((u32)addr, aper_size); diff --git a/trunk/arch/x86/kernel/apic/io_apic.c b/trunk/arch/x86/kernel/apic/io_apic.c index ac96561d1a99..5f0ff597437c 100644 --- a/trunk/arch/x86/kernel/apic/io_apic.c +++ b/trunk/arch/x86/kernel/apic/io_apic.c @@ -1195,7 +1195,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg) BUG_ON(!cfg->vector); vector = cfg->vector; - for_each_cpu_and(cpu, cfg->domain, cpu_online_mask) + for_each_cpu(cpu, cfg->domain) per_cpu(vector_irq, cpu)[vector] = -1; cfg->vector = 0; @@ -1203,7 +1203,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg) if (likely(!cfg->move_in_progress)) return; - for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) { + for_each_cpu(cpu, cfg->old_domain) { for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { if (per_cpu(vector_irq, cpu)[vector] != irq) diff --git a/trunk/arch/x86/kernel/cpu/mcheck/mce.c b/trunk/arch/x86/kernel/cpu/mcheck/mce.c index 0a687fd185e6..da27c5d2168a 100644 --- a/trunk/arch/x86/kernel/cpu/mcheck/mce.c +++ b/trunk/arch/x86/kernel/cpu/mcheck/mce.c @@ -1274,7 +1274,7 @@ static void mce_timer_fn(unsigned long data) */ iv = __this_cpu_read(mce_next_interval); if (mce_notify_irq()) - iv = max(iv, (unsigned long) HZ/100); + iv = max(iv / 2, (unsigned long) HZ/100); else iv = min(iv * 2, round_jiffies_relative(check_interval * HZ)); __this_cpu_write(mce_next_interval, iv); @@ -1557,7 +1557,7 @@ static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) static void __mcheck_cpu_init_timer(void) { struct timer_list *t = &__get_cpu_var(mce_timer); - unsigned long iv = __this_cpu_read(mce_next_interval); + unsigned long iv = check_interval * HZ; setup_timer(t, mce_timer_fn, smp_processor_id()); diff --git a/trunk/arch/x86/kernel/cpu/perf_event.c b/trunk/arch/x86/kernel/cpu/perf_event.c index e049d6da0183..c4706cf9c011 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event.c +++ b/trunk/arch/x86/kernel/cpu/perf_event.c @@ -1496,6 +1496,7 @@ static struct cpu_hw_events *allocate_fake_cpuc(void) if (!cpuc->shared_regs) goto error; } + cpuc->is_fake = 1; return cpuc; error: free_fake_cpuc(cpuc); @@ -1756,6 +1757,12 @@ perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs) dump_trace(NULL, regs, NULL, 0, &backtrace_ops, entry); } +static inline int +valid_user_frame(const void __user *fp, unsigned long size) +{ + return (__range_not_ok(fp, size, TASK_SIZE) == 0); +} + #ifdef CONFIG_COMPAT #include @@ -1780,7 +1787,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry) if (bytes != sizeof(frame)) break; - if (fp < compat_ptr(regs->sp)) + if (!valid_user_frame(fp, sizeof(frame))) break; perf_callchain_store(entry, frame.return_address); @@ -1826,7 +1833,7 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) if (bytes != sizeof(frame)) break; - if ((unsigned long)fp < regs->sp) + if (!valid_user_frame(fp, sizeof(frame))) break; perf_callchain_store(entry, frame.return_address); diff --git a/trunk/arch/x86/kernel/cpu/perf_event.h b/trunk/arch/x86/kernel/cpu/perf_event.h index 6638aaf54493..7241e2fc3c17 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event.h +++ b/trunk/arch/x86/kernel/cpu/perf_event.h @@ -117,6 +117,7 @@ struct cpu_hw_events { struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */ unsigned int group_flag; + int is_fake; /* * Intel DebugStore bits @@ -364,6 +365,7 @@ struct x86_pmu { int pebs_record_size; void (*drain_pebs)(struct pt_regs *regs); struct event_constraint *pebs_constraints; + void (*pebs_aliases)(struct perf_event *event); /* * Intel LBR diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel.c b/trunk/arch/x86/kernel/cpu/perf_event_intel.c index 166546ec6aef..187c294bc658 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_intel.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_intel.c @@ -1119,27 +1119,33 @@ intel_bts_constraints(struct perf_event *event) return NULL; } -static bool intel_try_alt_er(struct perf_event *event, int orig_idx) +static int intel_alt_er(int idx) { if (!(x86_pmu.er_flags & ERF_HAS_RSP_1)) - return false; + return idx; - if (event->hw.extra_reg.idx == EXTRA_REG_RSP_0) { - event->hw.config &= ~INTEL_ARCH_EVENT_MASK; - event->hw.config |= 0x01bb; - event->hw.extra_reg.idx = EXTRA_REG_RSP_1; - event->hw.extra_reg.reg = MSR_OFFCORE_RSP_1; - } else if (event->hw.extra_reg.idx == EXTRA_REG_RSP_1) { + if (idx == EXTRA_REG_RSP_0) + return EXTRA_REG_RSP_1; + + if (idx == EXTRA_REG_RSP_1) + return EXTRA_REG_RSP_0; + + return idx; +} + +static void intel_fixup_er(struct perf_event *event, int idx) +{ + event->hw.extra_reg.idx = idx; + + if (idx == EXTRA_REG_RSP_0) { event->hw.config &= ~INTEL_ARCH_EVENT_MASK; event->hw.config |= 0x01b7; - event->hw.extra_reg.idx = EXTRA_REG_RSP_0; event->hw.extra_reg.reg = MSR_OFFCORE_RSP_0; + } else if (idx == EXTRA_REG_RSP_1) { + event->hw.config &= ~INTEL_ARCH_EVENT_MASK; + event->hw.config |= 0x01bb; + event->hw.extra_reg.reg = MSR_OFFCORE_RSP_1; } - - if (event->hw.extra_reg.idx == orig_idx) - return false; - - return true; } /* @@ -1157,14 +1163,18 @@ __intel_shared_reg_get_constraints(struct cpu_hw_events *cpuc, struct event_constraint *c = &emptyconstraint; struct er_account *era; unsigned long flags; - int orig_idx = reg->idx; + int idx = reg->idx; - /* already allocated shared msr */ - if (reg->alloc) + /* + * reg->alloc can be set due to existing state, so for fake cpuc we + * need to ignore this, otherwise we might fail to allocate proper fake + * state for this extra reg constraint. Also see the comment below. + */ + if (reg->alloc && !cpuc->is_fake) return NULL; /* call x86_get_event_constraint() */ again: - era = &cpuc->shared_regs->regs[reg->idx]; + era = &cpuc->shared_regs->regs[idx]; /* * we use spin_lock_irqsave() to avoid lockdep issues when * passing a fake cpuc @@ -1173,6 +1183,29 @@ __intel_shared_reg_get_constraints(struct cpu_hw_events *cpuc, if (!atomic_read(&era->ref) || era->config == reg->config) { + /* + * If its a fake cpuc -- as per validate_{group,event}() we + * shouldn't touch event state and we can avoid doing so + * since both will only call get_event_constraints() once + * on each event, this avoids the need for reg->alloc. + * + * Not doing the ER fixup will only result in era->reg being + * wrong, but since we won't actually try and program hardware + * this isn't a problem either. + */ + if (!cpuc->is_fake) { + if (idx != reg->idx) + intel_fixup_er(event, idx); + + /* + * x86_schedule_events() can call get_event_constraints() + * multiple times on events in the case of incremental + * scheduling(). reg->alloc ensures we only do the ER + * allocation once. + */ + reg->alloc = 1; + } + /* lock in msr value */ era->config = reg->config; era->reg = reg->reg; @@ -1180,17 +1213,17 @@ __intel_shared_reg_get_constraints(struct cpu_hw_events *cpuc, /* one more user */ atomic_inc(&era->ref); - /* no need to reallocate during incremental event scheduling */ - reg->alloc = 1; - /* * need to call x86_get_event_constraint() * to check if associated event has constraints */ c = NULL; - } else if (intel_try_alt_er(event, orig_idx)) { - raw_spin_unlock_irqrestore(&era->lock, flags); - goto again; + } else { + idx = intel_alt_er(idx); + if (idx != reg->idx) { + raw_spin_unlock_irqrestore(&era->lock, flags); + goto again; + } } raw_spin_unlock_irqrestore(&era->lock, flags); @@ -1204,11 +1237,14 @@ __intel_shared_reg_put_constraints(struct cpu_hw_events *cpuc, struct er_account *era; /* - * only put constraint if extra reg was actually - * allocated. Also takes care of event which do - * not use an extra shared reg + * Only put constraint if extra reg was actually allocated. Also takes + * care of event which do not use an extra shared reg. + * + * Also, if this is a fake cpuc we shouldn't touch any event state + * (reg->alloc) and we don't care about leaving inconsistent cpuc state + * either since it'll be thrown out. */ - if (!reg->alloc) + if (!reg->alloc || cpuc->is_fake) return; era = &cpuc->shared_regs->regs[reg->idx]; @@ -1300,15 +1336,9 @@ static void intel_put_event_constraints(struct cpu_hw_events *cpuc, intel_put_shared_regs_event_constraints(cpuc, event); } -static int intel_pmu_hw_config(struct perf_event *event) +static void intel_pebs_aliases_core2(struct perf_event *event) { - int ret = x86_pmu_hw_config(event); - - if (ret) - return ret; - - if (event->attr.precise_ip && - (event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) { + if ((event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) { /* * Use an alternative encoding for CPU_CLK_UNHALTED.THREAD_P * (0x003c) so that we can use it with PEBS. @@ -1329,10 +1359,48 @@ static int intel_pmu_hw_config(struct perf_event *event) */ u64 alt_config = X86_CONFIG(.event=0xc0, .inv=1, .cmask=16); + alt_config |= (event->hw.config & ~X86_RAW_EVENT_MASK); + event->hw.config = alt_config; + } +} + +static void intel_pebs_aliases_snb(struct perf_event *event) +{ + if ((event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) { + /* + * Use an alternative encoding for CPU_CLK_UNHALTED.THREAD_P + * (0x003c) so that we can use it with PEBS. + * + * The regular CPU_CLK_UNHALTED.THREAD_P event (0x003c) isn't + * PEBS capable. However we can use UOPS_RETIRED.ALL + * (0x01c2), which is a PEBS capable event, to get the same + * count. + * + * UOPS_RETIRED.ALL counts the number of cycles that retires + * CNTMASK micro-ops. By setting CNTMASK to a value (16) + * larger than the maximum number of micro-ops that can be + * retired per cycle (4) and then inverting the condition, we + * count all cycles that retire 16 or less micro-ops, which + * is every cycle. + * + * Thereby we gain a PEBS capable cycle counter. + */ + u64 alt_config = X86_CONFIG(.event=0xc2, .umask=0x01, .inv=1, .cmask=16); alt_config |= (event->hw.config & ~X86_RAW_EVENT_MASK); event->hw.config = alt_config; } +} + +static int intel_pmu_hw_config(struct perf_event *event) +{ + int ret = x86_pmu_hw_config(event); + + if (ret) + return ret; + + if (event->attr.precise_ip && x86_pmu.pebs_aliases) + x86_pmu.pebs_aliases(event); if (intel_pmu_needs_lbr_smpl(event)) { ret = intel_pmu_setup_lbr_filter(event); @@ -1607,6 +1675,7 @@ static __initconst const struct x86_pmu intel_pmu = { .max_period = (1ULL << 31) - 1, .get_event_constraints = intel_get_event_constraints, .put_event_constraints = intel_put_event_constraints, + .pebs_aliases = intel_pebs_aliases_core2, .format_attrs = intel_arch3_formats_attr, @@ -1840,8 +1909,9 @@ __init int intel_pmu_init(void) break; case 42: /* SandyBridge */ - x86_add_quirk(intel_sandybridge_quirk); case 45: /* SandyBridge, "Romely-EP" */ + x86_add_quirk(intel_sandybridge_quirk); + case 58: /* IvyBridge */ memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -1849,6 +1919,7 @@ __init int intel_pmu_init(void) x86_pmu.event_constraints = intel_snb_event_constraints; x86_pmu.pebs_constraints = intel_snb_pebs_event_constraints; + x86_pmu.pebs_aliases = intel_pebs_aliases_snb; x86_pmu.extra_regs = intel_snb_extra_regs; /* all extra regs are per-cpu when HT is on */ x86_pmu.er_flags |= ERF_HAS_RSP_1; diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c b/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c index 5a3edc27f6e5..35e2192df9f4 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -400,14 +400,7 @@ struct event_constraint intel_snb_pebs_event_constraints[] = { INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */ INTEL_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */ INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.* */ - INTEL_UEVENT_CONSTRAINT(0x11d0, 0xf), /* MEM_UOP_RETIRED.STLB_MISS_LOADS */ - INTEL_UEVENT_CONSTRAINT(0x12d0, 0xf), /* MEM_UOP_RETIRED.STLB_MISS_STORES */ - INTEL_UEVENT_CONSTRAINT(0x21d0, 0xf), /* MEM_UOP_RETIRED.LOCK_LOADS */ - INTEL_UEVENT_CONSTRAINT(0x22d0, 0xf), /* MEM_UOP_RETIRED.LOCK_STORES */ - INTEL_UEVENT_CONSTRAINT(0x41d0, 0xf), /* MEM_UOP_RETIRED.SPLIT_LOADS */ - INTEL_UEVENT_CONSTRAINT(0x42d0, 0xf), /* MEM_UOP_RETIRED.SPLIT_STORES */ - INTEL_UEVENT_CONSTRAINT(0x81d0, 0xf), /* MEM_UOP_RETIRED.ANY_LOADS */ - INTEL_UEVENT_CONSTRAINT(0x82d0, 0xf), /* MEM_UOP_RETIRED.ANY_STORES */ + INTEL_EVENT_CONSTRAINT(0xd0, 0xf), /* MEM_UOP_RETIRED.* */ INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ INTEL_UEVENT_CONSTRAINT(0x02d4, 0xf), /* MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS */ diff --git a/trunk/arch/x86/kernel/nmi_selftest.c b/trunk/arch/x86/kernel/nmi_selftest.c index e31bf8d5c4d2..149b8d9c6ad4 100644 --- a/trunk/arch/x86/kernel/nmi_selftest.c +++ b/trunk/arch/x86/kernel/nmi_selftest.c @@ -42,7 +42,7 @@ static int __init nmi_unk_cb(unsigned int val, struct pt_regs *regs) static void __init init_nmi_testsuite(void) { /* trap all the unknown NMIs we may generate */ - register_nmi_handler(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk"); + register_nmi_handler_initonly(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk"); } static void __init cleanup_nmi_testsuite(void) @@ -64,7 +64,7 @@ static void __init test_nmi_ipi(struct cpumask *mask) { unsigned long timeout; - if (register_nmi_handler(NMI_LOCAL, test_nmi_ipi_callback, + if (register_nmi_handler_initonly(NMI_LOCAL, test_nmi_ipi_callback, NMI_FLAG_FIRST, "nmi_selftest")) { nmi_fail = FAILURE; return; diff --git a/trunk/arch/x86/kernel/reboot.c b/trunk/arch/x86/kernel/reboot.c index 79c45af81604..25b48edb847c 100644 --- a/trunk/arch/x86/kernel/reboot.c +++ b/trunk/arch/x86/kernel/reboot.c @@ -639,9 +639,11 @@ void native_machine_shutdown(void) set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id)); /* - * O.K Now that I'm on the appropriate processor, - * stop all of the others. + * O.K Now that I'm on the appropriate processor, stop all of the + * others. Also disable the local irq to not receive the per-cpu + * timer interrupt which may trigger scheduler's load balance. */ + local_irq_disable(); stop_other_cpus(); #endif diff --git a/trunk/arch/x86/kernel/smpboot.c b/trunk/arch/x86/kernel/smpboot.c index f56f96da77f5..3fab55bea29b 100644 --- a/trunk/arch/x86/kernel/smpboot.c +++ b/trunk/arch/x86/kernel/smpboot.c @@ -382,6 +382,15 @@ void __cpuinit set_cpu_sibling_map(int cpu) if ((i == cpu) || (has_mc && match_llc(c, o))) link_mask(llc_shared, cpu, i); + } + + /* + * This needs a separate iteration over the cpus because we rely on all + * cpu_sibling_mask links to be set-up. + */ + for_each_cpu(i, cpu_sibling_setup_mask) { + o = &cpu_data(i); + if ((i == cpu) || (has_mc && match_mc(c, o))) { link_mask(core, cpu, i); @@ -410,15 +419,7 @@ void __cpuinit set_cpu_sibling_map(int cpu) /* maps the cpu to the sched domain representing multi-core */ const struct cpumask *cpu_coregroup_mask(int cpu) { - struct cpuinfo_x86 *c = &cpu_data(cpu); - /* - * For perf, we return last level cache shared map. - * And for power savings, we return cpu_core_map - */ - if (!(cpu_has(c, X86_FEATURE_AMD_DCM))) - return cpu_core_mask(cpu); - else - return cpu_llc_shared_mask(cpu); + return cpu_llc_shared_mask(cpu); } static void impress_friends(void) diff --git a/trunk/arch/x86/lib/usercopy.c b/trunk/arch/x86/lib/usercopy.c index f61ee67ec00f..677b1ed184c9 100644 --- a/trunk/arch/x86/lib/usercopy.c +++ b/trunk/arch/x86/lib/usercopy.c @@ -8,6 +8,7 @@ #include #include +#include /* * best effort, GUP based copy_from_user() that is NMI-safe @@ -21,6 +22,9 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n) void *map; int ret; + if (__range_not_ok(from, n, TASK_SIZE) == 0) + return len; + do { ret = __get_user_pages_fast(addr, 1, 0, &page); if (!ret) diff --git a/trunk/arch/x86/lib/x86-opcode-map.txt b/trunk/arch/x86/lib/x86-opcode-map.txt index 819137904428..5d7e51f3fd28 100644 --- a/trunk/arch/x86/lib/x86-opcode-map.txt +++ b/trunk/arch/x86/lib/x86-opcode-map.txt @@ -28,7 +28,7 @@ # - (66): the last prefix is 0x66 # - (F3): the last prefix is 0xF3 # - (F2): the last prefix is 0xF2 -# +# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case) Table: one byte opcode Referrer: @@ -515,12 +515,12 @@ b4: LFS Gv,Mp b5: LGS Gv,Mp b6: MOVZX Gv,Eb b7: MOVZX Gv,Ew -b8: JMPE | POPCNT Gv,Ev (F3) +b8: JMPE (!F3) | POPCNT Gv,Ev (F3) b9: Grp10 (1A) ba: Grp8 Ev,Ib (1A) bb: BTC Ev,Gv -bc: BSF Gv,Ev | TZCNT Gv,Ev (F3) -bd: BSR Gv,Ev | LZCNT Gv,Ev (F3) +bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3) +bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3) be: MOVSX Gv,Eb bf: MOVSX Gv,Ew # 0x0f 0xc0-0xcf diff --git a/trunk/arch/x86/mm/init.c b/trunk/arch/x86/mm/init.c index 97141c26a13a..bc4e9d84157f 100644 --- a/trunk/arch/x86/mm/init.c +++ b/trunk/arch/x86/mm/init.c @@ -62,7 +62,8 @@ static void __init find_early_table_space(struct map_range *mr, unsigned long en extra += PMD_SIZE; #endif /* The first 2/4M doesn't use large pages. */ - extra += mr->end - mr->start; + if (mr->start < PMD_SIZE) + extra += mr->end - mr->start; ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT; } else diff --git a/trunk/arch/x86/mm/srat.c b/trunk/arch/x86/mm/srat.c index 732af3a96183..4599c3e8bcb6 100644 --- a/trunk/arch/x86/mm/srat.c +++ b/trunk/arch/x86/mm/srat.c @@ -176,6 +176,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) return; } + node_set(node, numa_nodes_parsed); + printk(KERN_INFO "SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]\n", node, pxm, (unsigned long long) start, (unsigned long long) end - 1); diff --git a/trunk/arch/x86/platform/mrst/mrst.c b/trunk/arch/x86/platform/mrst/mrst.c index e31bcd8f2eee..fd41a9262d65 100644 --- a/trunk/arch/x86/platform/mrst/mrst.c +++ b/trunk/arch/x86/platform/mrst/mrst.c @@ -782,7 +782,7 @@ BLOCKING_NOTIFIER_HEAD(intel_scu_notifier); EXPORT_SYMBOL_GPL(intel_scu_notifier); /* Called by IPC driver */ -void intel_scu_devices_create(void) +void __devinit intel_scu_devices_create(void) { int i; diff --git a/trunk/arch/x86/platform/uv/tlb_uv.c b/trunk/arch/x86/platform/uv/tlb_uv.c index 3ae0e61abd23..59880afa851f 100644 --- a/trunk/arch/x86/platform/uv/tlb_uv.c +++ b/trunk/arch/x86/platform/uv/tlb_uv.c @@ -1295,7 +1295,6 @@ static void __init enable_timeouts(void) */ mmr_image |= (1L << SOFTACK_MSHIFT); if (is_uv2_hub()) { - mmr_image &= ~(1L << UV2_LEG_SHFT); mmr_image |= (1L << UV2_EXT_SHFT); } write_mmr_misc_control(pnode, mmr_image); diff --git a/trunk/arch/x86/tools/gen-insn-attr-x86.awk b/trunk/arch/x86/tools/gen-insn-attr-x86.awk index 5f6a5b6c3a15..ddcf39b1a18d 100644 --- a/trunk/arch/x86/tools/gen-insn-attr-x86.awk +++ b/trunk/arch/x86/tools/gen-insn-attr-x86.awk @@ -66,9 +66,10 @@ BEGIN { rex_expr = "^REX(\\.[XRWB]+)*" fpu_expr = "^ESC" # TODO - lprefix1_expr = "\\(66\\)" + lprefix1_expr = "\\((66|!F3)\\)" lprefix2_expr = "\\(F3\\)" - lprefix3_expr = "\\(F2\\)" + lprefix3_expr = "\\((F2|!F3)\\)" + lprefix_expr = "\\((66|F2|F3)\\)" max_lprefix = 4 # All opcodes starting with lower-case 'v' or with (v1) superscript @@ -333,13 +334,16 @@ function convert_operands(count,opnd, i,j,imm,mod) if (match(ext, lprefix1_expr)) { lptable1[idx] = add_flags(lptable1[idx],flags) variant = "INAT_VARIANT" - } else if (match(ext, lprefix2_expr)) { + } + if (match(ext, lprefix2_expr)) { lptable2[idx] = add_flags(lptable2[idx],flags) variant = "INAT_VARIANT" - } else if (match(ext, lprefix3_expr)) { + } + if (match(ext, lprefix3_expr)) { lptable3[idx] = add_flags(lptable3[idx],flags) variant = "INAT_VARIANT" - } else { + } + if (!match(ext, lprefix_expr)){ table[idx] = add_flags(table[idx],flags) } } diff --git a/trunk/arch/xtensa/include/asm/syscall.h b/trunk/arch/xtensa/include/asm/syscall.h index 0b9f2e13c781..c1dacca312f3 100644 --- a/trunk/arch/xtensa/include/asm/syscall.h +++ b/trunk/arch/xtensa/include/asm/syscall.h @@ -31,5 +31,5 @@ asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp, asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds, struct timespec __user *tsp, const sigset_t __user *sigmask, size_t sigsetsize); - - +asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, + size_t sigsetsize); diff --git a/trunk/arch/xtensa/kernel/signal.c b/trunk/arch/xtensa/kernel/signal.c index b9f8e5850d3a..efe4e854b3cd 100644 --- a/trunk/arch/xtensa/kernel/signal.c +++ b/trunk/arch/xtensa/kernel/signal.c @@ -493,7 +493,7 @@ static void do_signal(struct pt_regs *regs) if (ret) return; - signal_delivered(signr, info, ka, regs, 0); + signal_delivered(signr, &info, &ka, regs, 0); if (current->ptrace & PT_SINGLESTEP) task_pt_regs(current)->icountlevel = 1; diff --git a/trunk/drivers/acpi/Kconfig b/trunk/drivers/acpi/Kconfig index 47768ff87343..80998958cf45 100644 --- a/trunk/drivers/acpi/Kconfig +++ b/trunk/drivers/acpi/Kconfig @@ -208,7 +208,7 @@ config ACPI_IPMI config ACPI_HOTPLUG_CPU bool - depends on ACPI_PROCESSOR && HOTPLUG_CPU + depends on EXPERIMENTAL && ACPI_PROCESSOR && HOTPLUG_CPU select ACPI_CONTAINER default y diff --git a/trunk/drivers/acpi/battery.c b/trunk/drivers/acpi/battery.c index 86933ca8b472..7dd3f9fb9f3f 100644 --- a/trunk/drivers/acpi/battery.c +++ b/trunk/drivers/acpi/battery.c @@ -643,11 +643,19 @@ static int acpi_battery_update(struct acpi_battery *battery) static void acpi_battery_refresh(struct acpi_battery *battery) { + int power_unit; + if (!battery->bat.dev) return; + power_unit = battery->power_unit; + acpi_battery_get_info(battery); - /* The battery may have changed its reporting units. */ + + if (power_unit == battery->power_unit) + return; + + /* The battery has changed its reporting units. */ sysfs_remove_battery(battery); sysfs_add_battery(battery); } diff --git a/trunk/drivers/acpi/bus.c b/trunk/drivers/acpi/bus.c index 3188da3df8da..adceafda9c17 100644 --- a/trunk/drivers/acpi/bus.c +++ b/trunk/drivers/acpi/bus.c @@ -182,41 +182,66 @@ EXPORT_SYMBOL(acpi_bus_get_private_data); Power Management -------------------------------------------------------------------------- */ +static const char *state_string(int state) +{ + switch (state) { + case ACPI_STATE_D0: + return "D0"; + case ACPI_STATE_D1: + return "D1"; + case ACPI_STATE_D2: + return "D2"; + case ACPI_STATE_D3_HOT: + return "D3hot"; + case ACPI_STATE_D3_COLD: + return "D3"; + default: + return "(unknown)"; + } +} + static int __acpi_bus_get_power(struct acpi_device *device, int *state) { - int result = 0; - acpi_status status = 0; - unsigned long long psc = 0; + int result = ACPI_STATE_UNKNOWN; if (!device || !state) return -EINVAL; - *state = ACPI_STATE_UNKNOWN; - - if (device->flags.power_manageable) { - /* - * Get the device's power state either directly (via _PSC) or - * indirectly (via power resources). - */ - if (device->power.flags.power_resources) { - result = acpi_power_get_inferred_state(device, state); - if (result) - return result; - } else if (device->power.flags.explicit_get) { - status = acpi_evaluate_integer(device->handle, "_PSC", - NULL, &psc); - if (ACPI_FAILURE(status)) - return -ENODEV; - *state = (int)psc; - } - } else { + if (!device->flags.power_manageable) { /* TBD: Non-recursive algorithm for walking up hierarchy. */ *state = device->parent ? device->parent->power.state : ACPI_STATE_D0; + goto out; + } + + /* + * Get the device's power state either directly (via _PSC) or + * indirectly (via power resources). + */ + if (device->power.flags.explicit_get) { + unsigned long long psc; + acpi_status status = acpi_evaluate_integer(device->handle, + "_PSC", NULL, &psc); + if (ACPI_FAILURE(status)) + return -ENODEV; + + result = psc; + } + /* The test below covers ACPI_STATE_UNKNOWN too. */ + if (result <= ACPI_STATE_D2) { + ; /* Do nothing. */ + } else if (device->power.flags.power_resources) { + int error = acpi_power_get_inferred_state(device, &result); + if (error) + return error; + } else if (result == ACPI_STATE_D3_HOT) { + result = ACPI_STATE_D3; } + *state = result; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n", - device->pnp.bus_id, *state)); + out: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n", + device->pnp.bus_id, state_string(*state))); return 0; } @@ -234,13 +259,14 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state) /* Make sure this is a valid target state */ if (state == device->power.state) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", - state)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n", + state_string(state))); return 0; } if (!device->power.states[state].flags.valid) { - printk(KERN_WARNING PREFIX "Device does not support D%d\n", state); + printk(KERN_WARNING PREFIX "Device does not support %s\n", + state_string(state)); return -ENODEV; } if (device->parent && (state < device->parent->power.state)) { @@ -294,13 +320,13 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state) end: if (result) printk(KERN_WARNING PREFIX - "Device [%s] failed to transition to D%d\n", - device->pnp.bus_id, state); + "Device [%s] failed to transition to %s\n", + device->pnp.bus_id, state_string(state)); else { device->power.state = state; ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device [%s] transitioned to D%d\n", - device->pnp.bus_id, state)); + "Device [%s] transitioned to %s\n", + device->pnp.bus_id, state_string(state))); } return result; diff --git a/trunk/drivers/acpi/power.c b/trunk/drivers/acpi/power.c index 0500f719f63e..dd6d6a3c6780 100644 --- a/trunk/drivers/acpi/power.c +++ b/trunk/drivers/acpi/power.c @@ -631,7 +631,7 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state) * We know a device's inferred power state when all the resources * required for a given D-state are 'on'. */ - for (i = ACPI_STATE_D0; i < ACPI_STATE_D3_HOT; i++) { + for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) { list = &device->power.states[i].resources; if (list->count < 1) continue; diff --git a/trunk/drivers/acpi/processor_perflib.c b/trunk/drivers/acpi/processor_perflib.c index 0af48a8554cd..a093dc163a42 100644 --- a/trunk/drivers/acpi/processor_perflib.c +++ b/trunk/drivers/acpi/processor_perflib.c @@ -333,6 +333,7 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr) struct acpi_buffer state = { 0, NULL }; union acpi_object *pss = NULL; int i; + int last_invalid = -1; status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer); @@ -394,14 +395,33 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr) ((u32)(px->core_frequency * 1000) != (px->core_frequency * 1000))) { printk(KERN_ERR FW_BUG PREFIX - "Invalid BIOS _PSS frequency: 0x%llx MHz\n", - px->core_frequency); - result = -EFAULT; - kfree(pr->performance->states); - goto end; + "Invalid BIOS _PSS frequency found for processor %d: 0x%llx MHz\n", + pr->id, px->core_frequency); + if (last_invalid == -1) + last_invalid = i; + } else { + if (last_invalid != -1) { + /* + * Copy this valid entry over last_invalid entry + */ + memcpy(&(pr->performance->states[last_invalid]), + px, sizeof(struct acpi_processor_px)); + ++last_invalid; + } } } + if (last_invalid == 0) { + printk(KERN_ERR FW_BUG PREFIX + "No valid BIOS _PSS frequency found for processor %d\n", pr->id); + result = -EFAULT; + kfree(pr->performance->states); + pr->performance->states = NULL; + } + + if (last_invalid > 0) + pr->performance->state_count = last_invalid; + end: kfree(buffer.pointer); diff --git a/trunk/drivers/acpi/scan.c b/trunk/drivers/acpi/scan.c index 85cbfdccc97c..c8a1f3b68110 100644 --- a/trunk/drivers/acpi/scan.c +++ b/trunk/drivers/acpi/scan.c @@ -1567,6 +1567,7 @@ static int acpi_bus_scan_fixed(void) ACPI_BUS_TYPE_POWER_BUTTON, ACPI_STA_DEFAULT, &ops); + device_init_wakeup(&device->dev, true); } if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { diff --git a/trunk/drivers/acpi/sleep.c b/trunk/drivers/acpi/sleep.c index 74ee4ab577b6..88561029cca8 100644 --- a/trunk/drivers/acpi/sleep.c +++ b/trunk/drivers/acpi/sleep.c @@ -57,6 +57,7 @@ MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend."); MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".); static u8 sleep_states[ACPI_S_STATE_COUNT]; +static bool pwr_btn_event_pending; static void acpi_sleep_tts_switch(u32 acpi_state) { @@ -184,6 +185,14 @@ static int acpi_pm_prepare(void) return error; } +static int find_powerf_dev(struct device *dev, void *data) +{ + struct acpi_device *device = to_acpi_device(dev); + const char *hid = acpi_device_hid(device); + + return !strcmp(hid, ACPI_BUTTON_HID_POWERF); +} + /** * acpi_pm_finish - Instruct the platform to leave a sleep state. * @@ -192,6 +201,7 @@ static int acpi_pm_prepare(void) */ static void acpi_pm_finish(void) { + struct device *pwr_btn_dev; u32 acpi_state = acpi_target_sleep_state; acpi_ec_unblock_transactions(); @@ -209,6 +219,23 @@ static void acpi_pm_finish(void) acpi_set_firmware_waking_vector((acpi_physical_address) 0); acpi_target_sleep_state = ACPI_STATE_S0; + + /* If we were woken with the fixed power button, provide a small + * hint to userspace in the form of a wakeup event on the fixed power + * button device (if it can be found). + * + * We delay the event generation til now, as the PM layer requires + * timekeeping to be running before we generate events. */ + if (!pwr_btn_event_pending) + return; + + pwr_btn_event_pending = false; + pwr_btn_dev = bus_find_device(&acpi_bus_type, NULL, NULL, + find_powerf_dev); + if (pwr_btn_dev) { + pm_wakeup_event(pwr_btn_dev, 0); + put_device(pwr_btn_dev); + } } /** @@ -298,9 +325,23 @@ static int acpi_suspend_enter(suspend_state_t pm_state) /* ACPI 3.0 specs (P62) says that it's the responsibility * of the OSPM to clear the status bit [ implying that the * POWER_BUTTON event should not reach userspace ] + * + * However, we do generate a small hint for userspace in the form of + * a wakeup event. We flag this condition for now and generate the + * event later, as we're currently too early in resume to be able to + * generate wakeup events. */ - if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) - acpi_clear_event(ACPI_EVENT_POWER_BUTTON); + if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) { + acpi_event_status pwr_btn_status; + + acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status); + + if (pwr_btn_status & ACPI_EVENT_FLAG_SET) { + acpi_clear_event(ACPI_EVENT_POWER_BUTTON); + /* Flag for later */ + pwr_btn_event_pending = true; + } + } /* * Disable and clear GPE status before interrupt is enabled. Some GPEs @@ -730,8 +771,8 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) * can wake the system. _S0W may be valid, too. */ if (acpi_target_sleep_state == ACPI_STATE_S0 || - (device_may_wakeup(dev) && - adev->wakeup.sleep_state <= acpi_target_sleep_state)) { + (device_may_wakeup(dev) && adev->wakeup.flags.valid && + adev->wakeup.sleep_state >= acpi_target_sleep_state)) { acpi_status status; acpi_method[3] = 'W'; diff --git a/trunk/drivers/acpi/video.c b/trunk/drivers/acpi/video.c index 9577b6fa2650..a576575617d7 100644 --- a/trunk/drivers/acpi/video.c +++ b/trunk/drivers/acpi/video.c @@ -1687,10 +1687,6 @@ static int acpi_video_bus_add(struct acpi_device *device) set_bit(KEY_BRIGHTNESS_ZERO, input->keybit); set_bit(KEY_DISPLAY_OFF, input->keybit); - error = input_register_device(input); - if (error) - goto err_stop_video; - printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n", ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device), video->flags.multihead ? "yes" : "no", @@ -1701,12 +1697,16 @@ static int acpi_video_bus_add(struct acpi_device *device) video->pm_nb.priority = 0; error = register_pm_notifier(&video->pm_nb); if (error) - goto err_unregister_input_dev; + goto err_stop_video; + + error = input_register_device(input); + if (error) + goto err_unregister_pm_notifier; return 0; - err_unregister_input_dev: - input_unregister_device(input); + err_unregister_pm_notifier: + unregister_pm_notifier(&video->pm_nb); err_stop_video: acpi_video_bus_stop_devices(video); err_free_input_dev: @@ -1743,9 +1743,18 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) return 0; } +static int __init is_i740(struct pci_dev *dev) +{ + if (dev->device == 0x00D1) + return 1; + if (dev->device == 0x7000) + return 1; + return 0; +} + static int __init intel_opregion_present(void) { -#if defined(CONFIG_DRM_I915) || defined(CONFIG_DRM_I915_MODULE) + int opregion = 0; struct pci_dev *dev = NULL; u32 address; @@ -1754,13 +1763,15 @@ static int __init intel_opregion_present(void) continue; if (dev->vendor != PCI_VENDOR_ID_INTEL) continue; + /* We don't want to poke around undefined i740 registers */ + if (is_i740(dev)) + continue; pci_read_config_dword(dev, 0xfc, &address); if (!address) continue; - return 1; + opregion = 1; } -#endif - return 0; + return opregion; } int acpi_video_register(void) diff --git a/trunk/drivers/char/agp/intel-agp.c b/trunk/drivers/char/agp/intel-agp.c index 764f70c5e690..0a4185279417 100644 --- a/trunk/drivers/char/agp/intel-agp.c +++ b/trunk/drivers/char/agp/intel-agp.c @@ -898,6 +898,7 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_B43_HB), ID(PCI_DEVICE_ID_INTEL_B43_1_HB), ID(PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB), + ID(PCI_DEVICE_ID_INTEL_IRONLAKE_D2_HB), ID(PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB), ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB), ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB), diff --git a/trunk/drivers/char/agp/intel-agp.h b/trunk/drivers/char/agp/intel-agp.h index c0091753a0d1..8e2d9140f300 100644 --- a/trunk/drivers/char/agp/intel-agp.h +++ b/trunk/drivers/char/agp/intel-agp.h @@ -212,6 +212,7 @@ #define PCI_DEVICE_ID_INTEL_G41_HB 0x2E30 #define PCI_DEVICE_ID_INTEL_G41_IG 0x2E32 #define PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB 0x0040 +#define PCI_DEVICE_ID_INTEL_IRONLAKE_D2_HB 0x0069 #define PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG 0x0042 #define PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB 0x0044 #define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB 0x0062 diff --git a/trunk/drivers/clocksource/Makefile b/trunk/drivers/clocksource/Makefile index 8d81a1d32653..dd3e661a124d 100644 --- a/trunk/drivers/clocksource/Makefile +++ b/trunk/drivers/clocksource/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o +obj-$(CONFIG_EM_TIMER_STI) += em_sti.o obj-$(CONFIG_CLKBLD_I8253) += i8253.o obj-$(CONFIG_CLKSRC_MMIO) += mmio.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o diff --git a/trunk/drivers/clocksource/em_sti.c b/trunk/drivers/clocksource/em_sti.c new file mode 100644 index 000000000000..372051d1bba8 --- /dev/null +++ b/trunk/drivers/clocksource/em_sti.c @@ -0,0 +1,406 @@ +/* + * Emma Mobile Timer Support - STI + * + * Copyright (C) 2012 Magnus Damm + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { USER_CLOCKSOURCE, USER_CLOCKEVENT, USER_NR }; + +struct em_sti_priv { + void __iomem *base; + struct clk *clk; + struct platform_device *pdev; + unsigned int active[USER_NR]; + unsigned long rate; + raw_spinlock_t lock; + struct clock_event_device ced; + struct clocksource cs; +}; + +#define STI_CONTROL 0x00 +#define STI_COMPA_H 0x10 +#define STI_COMPA_L 0x14 +#define STI_COMPB_H 0x18 +#define STI_COMPB_L 0x1c +#define STI_COUNT_H 0x20 +#define STI_COUNT_L 0x24 +#define STI_COUNT_RAW_H 0x28 +#define STI_COUNT_RAW_L 0x2c +#define STI_SET_H 0x30 +#define STI_SET_L 0x34 +#define STI_INTSTATUS 0x40 +#define STI_INTRAWSTATUS 0x44 +#define STI_INTENSET 0x48 +#define STI_INTENCLR 0x4c +#define STI_INTFFCLR 0x50 + +static inline unsigned long em_sti_read(struct em_sti_priv *p, int offs) +{ + return ioread32(p->base + offs); +} + +static inline void em_sti_write(struct em_sti_priv *p, int offs, + unsigned long value) +{ + iowrite32(value, p->base + offs); +} + +static int em_sti_enable(struct em_sti_priv *p) +{ + int ret; + + /* enable clock */ + ret = clk_enable(p->clk); + if (ret) { + dev_err(&p->pdev->dev, "cannot enable clock\n"); + return ret; + } + + /* configure channel, periodic mode and maximum timeout */ + p->rate = clk_get_rate(p->clk); + + /* reset the counter */ + em_sti_write(p, STI_SET_H, 0x40000000); + em_sti_write(p, STI_SET_L, 0x00000000); + + /* mask and clear pending interrupts */ + em_sti_write(p, STI_INTENCLR, 3); + em_sti_write(p, STI_INTFFCLR, 3); + + /* enable updates of counter registers */ + em_sti_write(p, STI_CONTROL, 1); + + return 0; +} + +static void em_sti_disable(struct em_sti_priv *p) +{ + /* mask interrupts */ + em_sti_write(p, STI_INTENCLR, 3); + + /* stop clock */ + clk_disable(p->clk); +} + +static cycle_t em_sti_count(struct em_sti_priv *p) +{ + cycle_t ticks; + unsigned long flags; + + /* the STI hardware buffers the 48-bit count, but to + * break it out into two 32-bit access the registers + * must be accessed in a certain order. + * Always read STI_COUNT_H before STI_COUNT_L. + */ + raw_spin_lock_irqsave(&p->lock, flags); + ticks = (cycle_t)(em_sti_read(p, STI_COUNT_H) & 0xffff) << 32; + ticks |= em_sti_read(p, STI_COUNT_L); + raw_spin_unlock_irqrestore(&p->lock, flags); + + return ticks; +} + +static cycle_t em_sti_set_next(struct em_sti_priv *p, cycle_t next) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&p->lock, flags); + + /* mask compare A interrupt */ + em_sti_write(p, STI_INTENCLR, 1); + + /* update compare A value */ + em_sti_write(p, STI_COMPA_H, next >> 32); + em_sti_write(p, STI_COMPA_L, next & 0xffffffff); + + /* clear compare A interrupt source */ + em_sti_write(p, STI_INTFFCLR, 1); + + /* unmask compare A interrupt */ + em_sti_write(p, STI_INTENSET, 1); + + raw_spin_unlock_irqrestore(&p->lock, flags); + + return next; +} + +static irqreturn_t em_sti_interrupt(int irq, void *dev_id) +{ + struct em_sti_priv *p = dev_id; + + p->ced.event_handler(&p->ced); + return IRQ_HANDLED; +} + +static int em_sti_start(struct em_sti_priv *p, unsigned int user) +{ + unsigned long flags; + int used_before; + int ret = 0; + + raw_spin_lock_irqsave(&p->lock, flags); + used_before = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT]; + if (!used_before) + ret = em_sti_enable(p); + + if (!ret) + p->active[user] = 1; + raw_spin_unlock_irqrestore(&p->lock, flags); + + return ret; +} + +static void em_sti_stop(struct em_sti_priv *p, unsigned int user) +{ + unsigned long flags; + int used_before, used_after; + + raw_spin_lock_irqsave(&p->lock, flags); + used_before = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT]; + p->active[user] = 0; + used_after = p->active[USER_CLOCKSOURCE] | p->active[USER_CLOCKEVENT]; + + if (used_before && !used_after) + em_sti_disable(p); + raw_spin_unlock_irqrestore(&p->lock, flags); +} + +static struct em_sti_priv *cs_to_em_sti(struct clocksource *cs) +{ + return container_of(cs, struct em_sti_priv, cs); +} + +static cycle_t em_sti_clocksource_read(struct clocksource *cs) +{ + return em_sti_count(cs_to_em_sti(cs)); +} + +static int em_sti_clocksource_enable(struct clocksource *cs) +{ + int ret; + struct em_sti_priv *p = cs_to_em_sti(cs); + + ret = em_sti_start(p, USER_CLOCKSOURCE); + if (!ret) + __clocksource_updatefreq_hz(cs, p->rate); + return ret; +} + +static void em_sti_clocksource_disable(struct clocksource *cs) +{ + em_sti_stop(cs_to_em_sti(cs), USER_CLOCKSOURCE); +} + +static void em_sti_clocksource_resume(struct clocksource *cs) +{ + em_sti_clocksource_enable(cs); +} + +static int em_sti_register_clocksource(struct em_sti_priv *p) +{ + struct clocksource *cs = &p->cs; + + memset(cs, 0, sizeof(*cs)); + cs->name = dev_name(&p->pdev->dev); + cs->rating = 200; + cs->read = em_sti_clocksource_read; + cs->enable = em_sti_clocksource_enable; + cs->disable = em_sti_clocksource_disable; + cs->suspend = em_sti_clocksource_disable; + cs->resume = em_sti_clocksource_resume; + cs->mask = CLOCKSOURCE_MASK(48); + cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; + + dev_info(&p->pdev->dev, "used as clock source\n"); + + /* Register with dummy 1 Hz value, gets updated in ->enable() */ + clocksource_register_hz(cs, 1); + return 0; +} + +static struct em_sti_priv *ced_to_em_sti(struct clock_event_device *ced) +{ + return container_of(ced, struct em_sti_priv, ced); +} + +static void em_sti_clock_event_mode(enum clock_event_mode mode, + struct clock_event_device *ced) +{ + struct em_sti_priv *p = ced_to_em_sti(ced); + + /* deal with old setting first */ + switch (ced->mode) { + case CLOCK_EVT_MODE_ONESHOT: + em_sti_stop(p, USER_CLOCKEVENT); + break; + default: + break; + } + + switch (mode) { + case CLOCK_EVT_MODE_ONESHOT: + dev_info(&p->pdev->dev, "used for oneshot clock events\n"); + em_sti_start(p, USER_CLOCKEVENT); + clockevents_config(&p->ced, p->rate); + break; + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + em_sti_stop(p, USER_CLOCKEVENT); + break; + default: + break; + } +} + +static int em_sti_clock_event_next(unsigned long delta, + struct clock_event_device *ced) +{ + struct em_sti_priv *p = ced_to_em_sti(ced); + cycle_t next; + int safe; + + next = em_sti_set_next(p, em_sti_count(p) + delta); + safe = em_sti_count(p) < (next - 1); + + return !safe; +} + +static void em_sti_register_clockevent(struct em_sti_priv *p) +{ + struct clock_event_device *ced = &p->ced; + + memset(ced, 0, sizeof(*ced)); + ced->name = dev_name(&p->pdev->dev); + ced->features = CLOCK_EVT_FEAT_ONESHOT; + ced->rating = 200; + ced->cpumask = cpumask_of(0); + ced->set_next_event = em_sti_clock_event_next; + ced->set_mode = em_sti_clock_event_mode; + + dev_info(&p->pdev->dev, "used for clock events\n"); + + /* Register with dummy 1 Hz value, gets updated in ->set_mode() */ + clockevents_config_and_register(ced, 1, 2, 0xffffffff); +} + +static int __devinit em_sti_probe(struct platform_device *pdev) +{ + struct em_sti_priv *p; + struct resource *res; + int irq, ret; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + ret = -ENOMEM; + goto err0; + } + + p->pdev = pdev; + platform_set_drvdata(pdev, p); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get I/O memory\n"); + ret = -EINVAL; + goto err0; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq\n"); + ret = -EINVAL; + goto err0; + } + + /* map memory, let base point to the STI instance */ + p->base = ioremap_nocache(res->start, resource_size(res)); + if (p->base == NULL) { + dev_err(&pdev->dev, "failed to remap I/O memory\n"); + ret = -ENXIO; + goto err0; + } + + /* get hold of clock */ + p->clk = clk_get(&pdev->dev, "sclk"); + if (IS_ERR(p->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + ret = PTR_ERR(p->clk); + goto err1; + } + + if (request_irq(irq, em_sti_interrupt, + IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, + dev_name(&pdev->dev), p)) { + dev_err(&pdev->dev, "failed to request low IRQ\n"); + ret = -ENOENT; + goto err2; + } + + raw_spin_lock_init(&p->lock); + em_sti_register_clockevent(p); + em_sti_register_clocksource(p); + return 0; + +err2: + clk_put(p->clk); +err1: + iounmap(p->base); +err0: + kfree(p); + return ret; +} + +static int __devexit em_sti_remove(struct platform_device *pdev) +{ + return -EBUSY; /* cannot unregister clockevent and clocksource */ +} + +static const struct of_device_id em_sti_dt_ids[] __devinitconst = { + { .compatible = "renesas,em-sti", }, + {}, +}; +MODULE_DEVICE_TABLE(of, em_sti_dt_ids); + +static struct platform_driver em_sti_device_driver = { + .probe = em_sti_probe, + .remove = __devexit_p(em_sti_remove), + .driver = { + .name = "em_sti", + .of_match_table = em_sti_dt_ids, + } +}; + +module_platform_driver(em_sti_device_driver); + +MODULE_AUTHOR("Magnus Damm"); +MODULE_DESCRIPTION("Renesas Emma Mobile STI Timer Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/gpio/gpio-samsung.c b/trunk/drivers/gpio/gpio-samsung.c index 7bb00448e13d..b6453d0e44ad 100644 --- a/trunk/drivers/gpio/gpio-samsung.c +++ b/trunk/drivers/gpio/gpio-samsung.c @@ -2833,7 +2833,7 @@ static __init void exynos5_gpiolib_init(void) } /* need to set base address for gpc4 */ - exonys5_gpios_1[11].base = gpio_base1 + 0x2E0; + exynos5_gpios_1[11].base = gpio_base1 + 0x2E0; /* need to set base address for gpx */ chip = &exynos5_gpios_1[21]; diff --git a/trunk/drivers/gpu/drm/exynos/exynos_drm_drv.c b/trunk/drivers/gpu/drm/exynos/exynos_drm_drv.c index 420953197d0a..d6de2e07fa03 100644 --- a/trunk/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/trunk/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -244,8 +244,8 @@ static const struct file_operations exynos_drm_driver_fops = { }; static struct drm_driver exynos_drm_driver = { - .driver_features = DRIVER_HAVE_IRQ | DRIVER_BUS_PLATFORM | - DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, + .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | + DRIVER_GEM | DRIVER_PRIME, .load = exynos_drm_load, .unload = exynos_drm_unload, .open = exynos_drm_open, diff --git a/trunk/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/trunk/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 6e9ac7bd1dcf..23d5ad379f86 100644 --- a/trunk/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/trunk/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -172,19 +172,12 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder) manager_ops->commit(manager->dev); } -static struct drm_crtc * -exynos_drm_encoder_get_crtc(struct drm_encoder *encoder) -{ - return encoder->crtc; -} - static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { .dpms = exynos_drm_encoder_dpms, .mode_fixup = exynos_drm_encoder_mode_fixup, .mode_set = exynos_drm_encoder_mode_set, .prepare = exynos_drm_encoder_prepare, .commit = exynos_drm_encoder_commit, - .get_crtc = exynos_drm_encoder_get_crtc, }; static void exynos_drm_encoder_destroy(struct drm_encoder *encoder) diff --git a/trunk/drivers/gpu/drm/exynos/exynos_drm_fb.c b/trunk/drivers/gpu/drm/exynos/exynos_drm_fb.c index f82a299553fb..4ccfe4328fab 100644 --- a/trunk/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/trunk/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -51,11 +51,22 @@ struct exynos_drm_fb { static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) { struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); + unsigned int i; DRM_DEBUG_KMS("%s\n", __FILE__); drm_framebuffer_cleanup(fb); + for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem_obj); i++) { + struct drm_gem_object *obj; + + if (exynos_fb->exynos_gem_obj[i] == NULL) + continue; + + obj = &exynos_fb->exynos_gem_obj[i]->base; + drm_gem_object_unreference_unlocked(obj); + } + kfree(exynos_fb); exynos_fb = NULL; } @@ -134,11 +145,11 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, return ERR_PTR(-ENOENT); } - drm_gem_object_unreference_unlocked(obj); - fb = exynos_drm_framebuffer_init(dev, mode_cmd, obj); - if (IS_ERR(fb)) + if (IS_ERR(fb)) { + drm_gem_object_unreference_unlocked(obj); return fb; + } exynos_fb = to_exynos_fb(fb); nr = exynos_drm_format_num_buffers(fb->pixel_format); @@ -152,8 +163,6 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, return ERR_PTR(-ENOENT); } - drm_gem_object_unreference_unlocked(obj); - exynos_fb->exynos_gem_obj[i] = to_exynos_gem_obj(obj); } diff --git a/trunk/drivers/gpu/drm/exynos/exynos_drm_fb.h b/trunk/drivers/gpu/drm/exynos/exynos_drm_fb.h index 3ecb30d93552..50823756cdea 100644 --- a/trunk/drivers/gpu/drm/exynos/exynos_drm_fb.h +++ b/trunk/drivers/gpu/drm/exynos/exynos_drm_fb.h @@ -31,10 +31,10 @@ static inline int exynos_drm_format_num_buffers(uint32_t format) { switch (format) { - case DRM_FORMAT_NV12M: + case DRM_FORMAT_NV12: case DRM_FORMAT_NV12MT: return 2; - case DRM_FORMAT_YUV420M: + case DRM_FORMAT_YUV420: return 3; default: return 1; diff --git a/trunk/drivers/gpu/drm/exynos/exynos_drm_gem.c b/trunk/drivers/gpu/drm/exynos/exynos_drm_gem.c index fc91293c4560..5c8b683029ea 100644 --- a/trunk/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/trunk/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -689,7 +689,6 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle, uint64_t *offset) { - struct exynos_drm_gem_obj *exynos_gem_obj; struct drm_gem_object *obj; int ret = 0; @@ -710,15 +709,13 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, goto unlock; } - exynos_gem_obj = to_exynos_gem_obj(obj); - - if (!exynos_gem_obj->base.map_list.map) { - ret = drm_gem_create_mmap_offset(&exynos_gem_obj->base); + if (!obj->map_list.map) { + ret = drm_gem_create_mmap_offset(obj); if (ret) goto out; } - *offset = (u64)exynos_gem_obj->base.map_list.hash.key << PAGE_SHIFT; + *offset = (u64)obj->map_list.hash.key << PAGE_SHIFT; DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset); out: diff --git a/trunk/drivers/gpu/drm/exynos/exynos_mixer.c b/trunk/drivers/gpu/drm/exynos/exynos_mixer.c index 68ef01028375..e2147a2ddcec 100644 --- a/trunk/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/trunk/drivers/gpu/drm/exynos/exynos_mixer.c @@ -365,7 +365,7 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) switch (win_data->pixel_format) { case DRM_FORMAT_NV12MT: tiled_mode = true; - case DRM_FORMAT_NV12M: + case DRM_FORMAT_NV12: crcb_mode = false; buf_num = 2; break; @@ -601,18 +601,20 @@ static void mixer_win_reset(struct mixer_context *ctx) mixer_reg_write(res, MXR_BG_COLOR2, 0x008080); /* setting graphical layers */ - val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */ val |= MXR_GRP_CFG_WIN_BLEND_EN; + val |= MXR_GRP_CFG_BLEND_PRE_MUL; + val |= MXR_GRP_CFG_PIXEL_BLEND_EN; val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */ /* the same configuration for both layers */ mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val); - - val |= MXR_GRP_CFG_BLEND_PRE_MUL; - val |= MXR_GRP_CFG_PIXEL_BLEND_EN; mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val); + /* setting video layers */ + val = MXR_GRP_CFG_ALPHA_VAL(0); + mixer_reg_write(res, MXR_VIDEO_CFG, val); + /* configuration of Video Processor Registers */ vp_win_reset(ctx); vp_default_filter(res); diff --git a/trunk/drivers/gpu/drm/i915/i915_drv.c b/trunk/drivers/gpu/drm/i915/i915_drv.c index 238a52165833..9fe9ebe52a7a 100644 --- a/trunk/drivers/gpu/drm/i915/i915_drv.c +++ b/trunk/drivers/gpu/drm/i915/i915_drv.c @@ -233,6 +233,7 @@ static const struct intel_device_info intel_sandybridge_d_info = { .has_blt_ring = 1, .has_llc = 1, .has_pch_split = 1, + .has_force_wake = 1, }; static const struct intel_device_info intel_sandybridge_m_info = { @@ -243,6 +244,7 @@ static const struct intel_device_info intel_sandybridge_m_info = { .has_blt_ring = 1, .has_llc = 1, .has_pch_split = 1, + .has_force_wake = 1, }; static const struct intel_device_info intel_ivybridge_d_info = { @@ -252,6 +254,7 @@ static const struct intel_device_info intel_ivybridge_d_info = { .has_blt_ring = 1, .has_llc = 1, .has_pch_split = 1, + .has_force_wake = 1, }; static const struct intel_device_info intel_ivybridge_m_info = { @@ -262,6 +265,7 @@ static const struct intel_device_info intel_ivybridge_m_info = { .has_blt_ring = 1, .has_llc = 1, .has_pch_split = 1, + .has_force_wake = 1, }; static const struct intel_device_info intel_valleyview_m_info = { @@ -289,6 +293,7 @@ static const struct intel_device_info intel_haswell_d_info = { .has_blt_ring = 1, .has_llc = 1, .has_pch_split = 1, + .has_force_wake = 1, }; static const struct intel_device_info intel_haswell_m_info = { @@ -298,6 +303,7 @@ static const struct intel_device_info intel_haswell_m_info = { .has_blt_ring = 1, .has_llc = 1, .has_pch_split = 1, + .has_force_wake = 1, }; static const struct pci_device_id pciidlist[] = { /* aka */ @@ -1139,10 +1145,9 @@ MODULE_LICENSE("GPL and additional rights"); /* We give fast paths for the really cool registers */ #define NEEDS_FORCE_WAKE(dev_priv, reg) \ - (((dev_priv)->info->gen >= 6) && \ - ((reg) < 0x40000) && \ - ((reg) != FORCEWAKE)) && \ - (!IS_VALLEYVIEW((dev_priv)->dev)) + ((HAS_FORCE_WAKE((dev_priv)->dev)) && \ + ((reg) < 0x40000) && \ + ((reg) != FORCEWAKE)) #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ diff --git a/trunk/drivers/gpu/drm/i915/i915_drv.h b/trunk/drivers/gpu/drm/i915/i915_drv.h index c9cfc67c2cf5..b0b676abde0d 100644 --- a/trunk/drivers/gpu/drm/i915/i915_drv.h +++ b/trunk/drivers/gpu/drm/i915/i915_drv.h @@ -285,6 +285,7 @@ struct intel_device_info { u8 is_ivybridge:1; u8 is_valleyview:1; u8 has_pch_split:1; + u8 has_force_wake:1; u8 is_haswell:1; u8 has_fbc:1; u8 has_pipe_cxsr:1; @@ -1101,6 +1102,8 @@ struct drm_i915_file_private { #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) #define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX) +#define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake) + #include "i915_trace.h" /** diff --git a/trunk/drivers/gpu/drm/i915/i915_irq.c b/trunk/drivers/gpu/drm/i915/i915_irq.c index 1417660a93ec..b1fe0edda955 100644 --- a/trunk/drivers/gpu/drm/i915/i915_irq.c +++ b/trunk/drivers/gpu/drm/i915/i915_irq.c @@ -510,7 +510,7 @@ static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS) return ret; } -static void pch_irq_handler(struct drm_device *dev, u32 pch_iir) +static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; @@ -550,6 +550,35 @@ static void pch_irq_handler(struct drm_device *dev, u32 pch_iir) DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n"); } +static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe; + + if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) + DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", + (pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> + SDE_AUDIO_POWER_SHIFT_CPT); + + if (pch_iir & SDE_AUX_MASK_CPT) + DRM_DEBUG_DRIVER("AUX channel interrupt\n"); + + if (pch_iir & SDE_GMBUS_CPT) + DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n"); + + if (pch_iir & SDE_AUDIO_CP_REQ_CPT) + DRM_DEBUG_DRIVER("Audio CP request interrupt\n"); + + if (pch_iir & SDE_AUDIO_CP_CHG_CPT) + DRM_DEBUG_DRIVER("Audio CP change interrupt\n"); + + if (pch_iir & SDE_FDI_MASK_CPT) + for_each_pipe(pipe) + DRM_DEBUG_DRIVER(" pipe %c FDI IIR: 0x%08x\n", + pipe_name(pipe), + I915_READ(FDI_RX_IIR(pipe))); +} + static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; @@ -591,7 +620,7 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) if (pch_iir & SDE_HOTPLUG_MASK_CPT) queue_work(dev_priv->wq, &dev_priv->hotplug_work); - pch_irq_handler(dev, pch_iir); + cpt_irq_handler(dev, pch_iir); /* clear PCH hotplug event before clear CPU irq */ I915_WRITE(SDEIIR, pch_iir); @@ -684,7 +713,10 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) if (de_iir & DE_PCH_EVENT) { if (pch_iir & hotplug_mask) queue_work(dev_priv->wq, &dev_priv->hotplug_work); - pch_irq_handler(dev, pch_iir); + if (HAS_PCH_CPT(dev)) + cpt_irq_handler(dev, pch_iir); + else + ibx_irq_handler(dev, pch_iir); } if (de_iir & DE_PCU_EVENT) { diff --git a/trunk/drivers/gpu/drm/i915/i915_reg.h b/trunk/drivers/gpu/drm/i915/i915_reg.h index 2d49b9507ed0..48d5e8e051cf 100644 --- a/trunk/drivers/gpu/drm/i915/i915_reg.h +++ b/trunk/drivers/gpu/drm/i915/i915_reg.h @@ -210,6 +210,14 @@ #define MI_DISPLAY_FLIP MI_INSTR(0x14, 2) #define MI_DISPLAY_FLIP_I915 MI_INSTR(0x14, 1) #define MI_DISPLAY_FLIP_PLANE(n) ((n) << 20) +/* IVB has funny definitions for which plane to flip. */ +#define MI_DISPLAY_FLIP_IVB_PLANE_A (0 << 19) +#define MI_DISPLAY_FLIP_IVB_PLANE_B (1 << 19) +#define MI_DISPLAY_FLIP_IVB_SPRITE_A (2 << 19) +#define MI_DISPLAY_FLIP_IVB_SPRITE_B (3 << 19) +#define MI_DISPLAY_FLIP_IVB_PLANE_C (4 << 19) +#define MI_DISPLAY_FLIP_IVB_SPRITE_C (5 << 19) + #define MI_SET_CONTEXT MI_INSTR(0x18, 0) #define MI_MM_SPACE_GTT (1<<8) #define MI_MM_SPACE_PHYSICAL (0<<8) @@ -3313,7 +3321,7 @@ /* PCH */ -/* south display engine interrupt */ +/* south display engine interrupt: IBX */ #define SDE_AUDIO_POWER_D (1 << 27) #define SDE_AUDIO_POWER_C (1 << 26) #define SDE_AUDIO_POWER_B (1 << 25) @@ -3349,15 +3357,44 @@ #define SDE_TRANSA_CRC_ERR (1 << 1) #define SDE_TRANSA_FIFO_UNDER (1 << 0) #define SDE_TRANS_MASK (0x3f) -/* CPT */ -#define SDE_CRT_HOTPLUG_CPT (1 << 19) + +/* south display engine interrupt: CPT/PPT */ +#define SDE_AUDIO_POWER_D_CPT (1 << 31) +#define SDE_AUDIO_POWER_C_CPT (1 << 30) +#define SDE_AUDIO_POWER_B_CPT (1 << 29) +#define SDE_AUDIO_POWER_SHIFT_CPT 29 +#define SDE_AUDIO_POWER_MASK_CPT (7 << 29) +#define SDE_AUXD_CPT (1 << 27) +#define SDE_AUXC_CPT (1 << 26) +#define SDE_AUXB_CPT (1 << 25) +#define SDE_AUX_MASK_CPT (7 << 25) #define SDE_PORTD_HOTPLUG_CPT (1 << 23) #define SDE_PORTC_HOTPLUG_CPT (1 << 22) #define SDE_PORTB_HOTPLUG_CPT (1 << 21) +#define SDE_CRT_HOTPLUG_CPT (1 << 19) #define SDE_HOTPLUG_MASK_CPT (SDE_CRT_HOTPLUG_CPT | \ SDE_PORTD_HOTPLUG_CPT | \ SDE_PORTC_HOTPLUG_CPT | \ SDE_PORTB_HOTPLUG_CPT) +#define SDE_GMBUS_CPT (1 << 17) +#define SDE_AUDIO_CP_REQ_C_CPT (1 << 10) +#define SDE_AUDIO_CP_CHG_C_CPT (1 << 9) +#define SDE_FDI_RXC_CPT (1 << 8) +#define SDE_AUDIO_CP_REQ_B_CPT (1 << 6) +#define SDE_AUDIO_CP_CHG_B_CPT (1 << 5) +#define SDE_FDI_RXB_CPT (1 << 4) +#define SDE_AUDIO_CP_REQ_A_CPT (1 << 2) +#define SDE_AUDIO_CP_CHG_A_CPT (1 << 1) +#define SDE_FDI_RXA_CPT (1 << 0) +#define SDE_AUDIO_CP_REQ_CPT (SDE_AUDIO_CP_REQ_C_CPT | \ + SDE_AUDIO_CP_REQ_B_CPT | \ + SDE_AUDIO_CP_REQ_A_CPT) +#define SDE_AUDIO_CP_CHG_CPT (SDE_AUDIO_CP_CHG_C_CPT | \ + SDE_AUDIO_CP_CHG_B_CPT | \ + SDE_AUDIO_CP_CHG_A_CPT) +#define SDE_FDI_MASK_CPT (SDE_FDI_RXC_CPT | \ + SDE_FDI_RXB_CPT | \ + SDE_FDI_RXA_CPT) #define SDEISR 0xc4000 #define SDEIMR 0xc4004 diff --git a/trunk/drivers/gpu/drm/i915/intel_display.c b/trunk/drivers/gpu/drm/i915/intel_display.c index 914789420906..e0aa064def31 100644 --- a/trunk/drivers/gpu/drm/i915/intel_display.c +++ b/trunk/drivers/gpu/drm/i915/intel_display.c @@ -6158,17 +6158,34 @@ static int intel_gen7_queue_flip(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_ring_buffer *ring = &dev_priv->ring[BCS]; + uint32_t plane_bit = 0; int ret; ret = intel_pin_and_fence_fb_obj(dev, obj, ring); if (ret) goto err; + switch(intel_crtc->plane) { + case PLANE_A: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_A; + break; + case PLANE_B: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_B; + break; + case PLANE_C: + plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_C; + break; + default: + WARN_ONCE(1, "unknown plane in flip command\n"); + ret = -ENODEV; + goto err; + } + ret = intel_ring_begin(ring, 4); if (ret) goto err_unpin; - intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | (intel_crtc->plane << 19)); + intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit); intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); intel_ring_emit(ring, (obj->gtt_offset)); intel_ring_emit(ring, (MI_NOOP)); diff --git a/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c b/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c index b59b6d5b7583..e5b84ff89ca5 100644 --- a/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -266,10 +266,15 @@ u32 intel_ring_get_active_head(struct intel_ring_buffer *ring) static int init_ring_common(struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = ring->dev->dev_private; + struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj = ring->obj; + int ret = 0; u32 head; + if (HAS_FORCE_WAKE(dev)) + gen6_gt_force_wake_get(dev_priv); + /* Stop the ring if it's running. */ I915_WRITE_CTL(ring, 0); I915_WRITE_HEAD(ring, 0); @@ -317,7 +322,8 @@ static int init_ring_common(struct intel_ring_buffer *ring) I915_READ_HEAD(ring), I915_READ_TAIL(ring), I915_READ_START(ring)); - return -EIO; + ret = -EIO; + goto out; } if (!drm_core_check_feature(ring->dev, DRIVER_MODESET)) @@ -326,9 +332,14 @@ static int init_ring_common(struct intel_ring_buffer *ring) ring->head = I915_READ_HEAD(ring); ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; ring->space = ring_space(ring); + ring->last_retired_head = -1; } - return 0; +out: + if (HAS_FORCE_WAKE(dev)) + gen6_gt_force_wake_put(dev_priv); + + return ret; } static int @@ -987,6 +998,10 @@ static int intel_init_ring_buffer(struct drm_device *dev, if (ret) goto err_unref; + ret = i915_gem_object_set_to_gtt_domain(obj, true); + if (ret) + goto err_unpin; + ring->virtual_start = ioremap_wc(dev->agp->base + obj->gtt_offset, ring->size); if (ring->virtual_start == NULL) { diff --git a/trunk/drivers/gpu/drm/radeon/ni.c b/trunk/drivers/gpu/drm/radeon/ni.c index 3df4efa11942..3186522a4458 100644 --- a/trunk/drivers/gpu/drm/radeon/ni.c +++ b/trunk/drivers/gpu/drm/radeon/ni.c @@ -460,15 +460,28 @@ static void cayman_gpu_init(struct radeon_device *rdev) rdev->config.cayman.max_pipes_per_simd = 4; rdev->config.cayman.max_tile_pipes = 2; if ((rdev->pdev->device == 0x9900) || - (rdev->pdev->device == 0x9901)) { + (rdev->pdev->device == 0x9901) || + (rdev->pdev->device == 0x9905) || + (rdev->pdev->device == 0x9906) || + (rdev->pdev->device == 0x9907) || + (rdev->pdev->device == 0x9908) || + (rdev->pdev->device == 0x9909) || + (rdev->pdev->device == 0x9910) || + (rdev->pdev->device == 0x9917)) { rdev->config.cayman.max_simds_per_se = 6; rdev->config.cayman.max_backends_per_se = 2; } else if ((rdev->pdev->device == 0x9903) || - (rdev->pdev->device == 0x9904)) { + (rdev->pdev->device == 0x9904) || + (rdev->pdev->device == 0x990A) || + (rdev->pdev->device == 0x9913) || + (rdev->pdev->device == 0x9918)) { rdev->config.cayman.max_simds_per_se = 4; rdev->config.cayman.max_backends_per_se = 2; - } else if ((rdev->pdev->device == 0x9990) || - (rdev->pdev->device == 0x9991)) { + } else if ((rdev->pdev->device == 0x9919) || + (rdev->pdev->device == 0x9990) || + (rdev->pdev->device == 0x9991) || + (rdev->pdev->device == 0x9994) || + (rdev->pdev->device == 0x99A0)) { rdev->config.cayman.max_simds_per_se = 3; rdev->config.cayman.max_backends_per_se = 1; } else { diff --git a/trunk/drivers/gpu/drm/radeon/r600.c b/trunk/drivers/gpu/drm/radeon/r600.c index 45cfcea63507..f30dc95f83b1 100644 --- a/trunk/drivers/gpu/drm/radeon/r600.c +++ b/trunk/drivers/gpu/drm/radeon/r600.c @@ -2426,6 +2426,12 @@ int r600_startup(struct radeon_device *rdev) if (r) return r; + r = r600_audio_init(rdev); + if (r) { + DRM_ERROR("radeon: audio init failed\n"); + return r; + } + return 0; } @@ -2462,12 +2468,6 @@ int r600_resume(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); - if (r) { - DRM_ERROR("radeon: audio resume failed\n"); - return r; - } - return r; } @@ -2577,9 +2577,6 @@ int r600_init(struct radeon_device *rdev) rdev->accel_working = false; } - r = r600_audio_init(rdev); - if (r) - return r; /* TODO error handling */ return 0; } diff --git a/trunk/drivers/gpu/drm/radeon/r600_audio.c b/trunk/drivers/gpu/drm/radeon/r600_audio.c index 7c4fa77f018f..7479a5c503e4 100644 --- a/trunk/drivers/gpu/drm/radeon/r600_audio.c +++ b/trunk/drivers/gpu/drm/radeon/r600_audio.c @@ -192,6 +192,7 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock) struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); int base_rate = 48000; switch (radeon_encoder->encoder_id) { @@ -217,8 +218,8 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock) WREG32(EVERGREEN_AUDIO_PLL1_DIV, clock * 10); WREG32(EVERGREEN_AUDIO_PLL1_UNK, 0x00000071); - /* Some magic trigger or src sel? */ - WREG32_P(0x5ac, 0x01, ~0x77); + /* Select DTO source */ + WREG32(0x5ac, radeon_crtc->crtc_id); } else { switch (dig->dig_encoder) { case 0: diff --git a/trunk/drivers/gpu/drm/radeon/r600_hdmi.c b/trunk/drivers/gpu/drm/radeon/r600_hdmi.c index 226379e00ac1..969c27529dfe 100644 --- a/trunk/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/trunk/drivers/gpu/drm/radeon/r600_hdmi.c @@ -348,7 +348,6 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */ HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ - HDMI0_AUDIO_SEND_MAX_PACKETS | /* send NULL packets if no audio is available */ HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */ HDMI0_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ } diff --git a/trunk/drivers/gpu/drm/radeon/radeon.h b/trunk/drivers/gpu/drm/radeon/radeon.h index 85dac33e3cce..fefcca55c1eb 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon.h +++ b/trunk/drivers/gpu/drm/radeon/radeon.h @@ -1374,9 +1374,9 @@ struct cayman_asic { struct si_asic { unsigned max_shader_engines; - unsigned max_pipes_per_simd; unsigned max_tile_pipes; - unsigned max_simds_per_se; + unsigned max_cu_per_sh; + unsigned max_sh_per_se; unsigned max_backends_per_se; unsigned max_texture_channel_caches; unsigned max_gprs; @@ -1387,7 +1387,6 @@ struct si_asic { unsigned sc_hiz_tile_fifo_size; unsigned sc_earlyz_tile_fifo_size; - unsigned num_shader_engines; unsigned num_tile_pipes; unsigned num_backends_per_se; unsigned backend_disable_mask_per_asic; diff --git a/trunk/drivers/gpu/drm/radeon/radeon_gart.c b/trunk/drivers/gpu/drm/radeon/radeon_gart.c index 79db56e6c2ac..59d44937dd9f 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_gart.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_gart.c @@ -476,12 +476,18 @@ int radeon_vm_bo_add(struct radeon_device *rdev, mutex_lock(&vm->mutex); if (last_pfn > vm->last_pfn) { - /* grow va space 32M by 32M */ - unsigned align = ((32 << 20) >> 12) - 1; + /* release mutex and lock in right order */ + mutex_unlock(&vm->mutex); radeon_mutex_lock(&rdev->cs_mutex); - radeon_vm_unbind_locked(rdev, vm); + mutex_lock(&vm->mutex); + /* and check again */ + if (last_pfn > vm->last_pfn) { + /* grow va space 32M by 32M */ + unsigned align = ((32 << 20) >> 12) - 1; + radeon_vm_unbind_locked(rdev, vm); + vm->last_pfn = (last_pfn + align) & ~align; + } radeon_mutex_unlock(&rdev->cs_mutex); - vm->last_pfn = (last_pfn + align) & ~align; } head = &vm->va; last_offset = 0; @@ -595,8 +601,8 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev, if (bo_va == NULL) return 0; - mutex_lock(&vm->mutex); radeon_mutex_lock(&rdev->cs_mutex); + mutex_lock(&vm->mutex); radeon_vm_bo_update_pte(rdev, vm, bo, NULL); radeon_mutex_unlock(&rdev->cs_mutex); list_del(&bo_va->vm_list); @@ -641,9 +647,8 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) struct radeon_bo_va *bo_va, *tmp; int r; - mutex_lock(&vm->mutex); - radeon_mutex_lock(&rdev->cs_mutex); + mutex_lock(&vm->mutex); radeon_vm_unbind_locked(rdev, vm); radeon_mutex_unlock(&rdev->cs_mutex); diff --git a/trunk/drivers/gpu/drm/radeon/radeon_kms.c b/trunk/drivers/gpu/drm/radeon/radeon_kms.c index f1016a5820d1..5c58d7d90cb2 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_kms.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_kms.c @@ -273,7 +273,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) break; case RADEON_INFO_MAX_PIPES: if (rdev->family >= CHIP_TAHITI) - value = rdev->config.si.max_pipes_per_simd; + value = rdev->config.si.max_cu_per_sh; else if (rdev->family >= CHIP_CAYMAN) value = rdev->config.cayman.max_pipes_per_simd; else if (rdev->family >= CHIP_CEDAR) diff --git a/trunk/drivers/gpu/drm/radeon/rs600.c b/trunk/drivers/gpu/drm/radeon/rs600.c index 25f9eef12c42..e95c5e61d4e2 100644 --- a/trunk/drivers/gpu/drm/radeon/rs600.c +++ b/trunk/drivers/gpu/drm/radeon/rs600.c @@ -908,12 +908,6 @@ static int rs600_startup(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); - if (r) { - dev_err(rdev->dev, "failed initializing audio\n"); - return r; - } - r = radeon_ib_pool_start(rdev); if (r) return r; @@ -922,6 +916,12 @@ static int rs600_startup(struct radeon_device *rdev) if (r) return r; + r = r600_audio_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing audio\n"); + return r; + } + return 0; } diff --git a/trunk/drivers/gpu/drm/radeon/rs690.c b/trunk/drivers/gpu/drm/radeon/rs690.c index 3277ddecfe9f..159b6a43fda0 100644 --- a/trunk/drivers/gpu/drm/radeon/rs690.c +++ b/trunk/drivers/gpu/drm/radeon/rs690.c @@ -637,12 +637,6 @@ static int rs690_startup(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); - if (r) { - dev_err(rdev->dev, "failed initializing audio\n"); - return r; - } - r = radeon_ib_pool_start(rdev); if (r) return r; @@ -651,6 +645,12 @@ static int rs690_startup(struct radeon_device *rdev) if (r) return r; + r = r600_audio_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing audio\n"); + return r; + } + return 0; } diff --git a/trunk/drivers/gpu/drm/radeon/rv770.c b/trunk/drivers/gpu/drm/radeon/rv770.c index 04ddc365a908..4ad0281fdc37 100644 --- a/trunk/drivers/gpu/drm/radeon/rv770.c +++ b/trunk/drivers/gpu/drm/radeon/rv770.c @@ -956,6 +956,12 @@ static int rv770_startup(struct radeon_device *rdev) if (r) return r; + r = r600_audio_init(rdev); + if (r) { + DRM_ERROR("radeon: audio init failed\n"); + return r; + } + return 0; } @@ -978,12 +984,6 @@ int rv770_resume(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); - if (r) { - dev_err(rdev->dev, "radeon: audio init failed\n"); - return r; - } - return r; } @@ -1092,12 +1092,6 @@ int rv770_init(struct radeon_device *rdev) rdev->accel_working = false; } - r = r600_audio_init(rdev); - if (r) { - dev_err(rdev->dev, "radeon: audio init failed\n"); - return r; - } - return 0; } diff --git a/trunk/drivers/gpu/drm/radeon/si.c b/trunk/drivers/gpu/drm/radeon/si.c index 549732e56ca9..c7b61f16ecfd 100644 --- a/trunk/drivers/gpu/drm/radeon/si.c +++ b/trunk/drivers/gpu/drm/radeon/si.c @@ -867,200 +867,6 @@ void dce6_bandwidth_update(struct radeon_device *rdev) /* * Core functions */ -static u32 si_get_tile_pipe_to_backend_map(struct radeon_device *rdev, - u32 num_tile_pipes, - u32 num_backends_per_asic, - u32 *backend_disable_mask_per_asic, - u32 num_shader_engines) -{ - u32 backend_map = 0; - u32 enabled_backends_mask = 0; - u32 enabled_backends_count = 0; - u32 num_backends_per_se; - u32 cur_pipe; - u32 swizzle_pipe[SI_MAX_PIPES]; - u32 cur_backend = 0; - u32 i; - bool force_no_swizzle; - - /* force legal values */ - if (num_tile_pipes < 1) - num_tile_pipes = 1; - if (num_tile_pipes > rdev->config.si.max_tile_pipes) - num_tile_pipes = rdev->config.si.max_tile_pipes; - if (num_shader_engines < 1) - num_shader_engines = 1; - if (num_shader_engines > rdev->config.si.max_shader_engines) - num_shader_engines = rdev->config.si.max_shader_engines; - if (num_backends_per_asic < num_shader_engines) - num_backends_per_asic = num_shader_engines; - if (num_backends_per_asic > (rdev->config.si.max_backends_per_se * num_shader_engines)) - num_backends_per_asic = rdev->config.si.max_backends_per_se * num_shader_engines; - - /* make sure we have the same number of backends per se */ - num_backends_per_asic = ALIGN(num_backends_per_asic, num_shader_engines); - /* set up the number of backends per se */ - num_backends_per_se = num_backends_per_asic / num_shader_engines; - if (num_backends_per_se > rdev->config.si.max_backends_per_se) { - num_backends_per_se = rdev->config.si.max_backends_per_se; - num_backends_per_asic = num_backends_per_se * num_shader_engines; - } - - /* create enable mask and count for enabled backends */ - for (i = 0; i < SI_MAX_BACKENDS; ++i) { - if (((*backend_disable_mask_per_asic >> i) & 1) == 0) { - enabled_backends_mask |= (1 << i); - ++enabled_backends_count; - } - if (enabled_backends_count == num_backends_per_asic) - break; - } - - /* force the backends mask to match the current number of backends */ - if (enabled_backends_count != num_backends_per_asic) { - u32 this_backend_enabled; - u32 shader_engine; - u32 backend_per_se; - - enabled_backends_mask = 0; - enabled_backends_count = 0; - *backend_disable_mask_per_asic = SI_MAX_BACKENDS_MASK; - for (i = 0; i < SI_MAX_BACKENDS; ++i) { - /* calc the current se */ - shader_engine = i / rdev->config.si.max_backends_per_se; - /* calc the backend per se */ - backend_per_se = i % rdev->config.si.max_backends_per_se; - /* default to not enabled */ - this_backend_enabled = 0; - if ((shader_engine < num_shader_engines) && - (backend_per_se < num_backends_per_se)) - this_backend_enabled = 1; - if (this_backend_enabled) { - enabled_backends_mask |= (1 << i); - *backend_disable_mask_per_asic &= ~(1 << i); - ++enabled_backends_count; - } - } - } - - - memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * SI_MAX_PIPES); - switch (rdev->family) { - case CHIP_TAHITI: - case CHIP_PITCAIRN: - case CHIP_VERDE: - force_no_swizzle = true; - break; - default: - force_no_swizzle = false; - break; - } - if (force_no_swizzle) { - bool last_backend_enabled = false; - - force_no_swizzle = false; - for (i = 0; i < SI_MAX_BACKENDS; ++i) { - if (((enabled_backends_mask >> i) & 1) == 1) { - if (last_backend_enabled) - force_no_swizzle = true; - last_backend_enabled = true; - } else - last_backend_enabled = false; - } - } - - switch (num_tile_pipes) { - case 1: - case 3: - case 5: - case 7: - DRM_ERROR("odd number of pipes!\n"); - break; - case 2: - swizzle_pipe[0] = 0; - swizzle_pipe[1] = 1; - break; - case 4: - if (force_no_swizzle) { - swizzle_pipe[0] = 0; - swizzle_pipe[1] = 1; - swizzle_pipe[2] = 2; - swizzle_pipe[3] = 3; - } else { - swizzle_pipe[0] = 0; - swizzle_pipe[1] = 2; - swizzle_pipe[2] = 1; - swizzle_pipe[3] = 3; - } - break; - case 6: - if (force_no_swizzle) { - swizzle_pipe[0] = 0; - swizzle_pipe[1] = 1; - swizzle_pipe[2] = 2; - swizzle_pipe[3] = 3; - swizzle_pipe[4] = 4; - swizzle_pipe[5] = 5; - } else { - swizzle_pipe[0] = 0; - swizzle_pipe[1] = 2; - swizzle_pipe[2] = 4; - swizzle_pipe[3] = 1; - swizzle_pipe[4] = 3; - swizzle_pipe[5] = 5; - } - break; - case 8: - if (force_no_swizzle) { - swizzle_pipe[0] = 0; - swizzle_pipe[1] = 1; - swizzle_pipe[2] = 2; - swizzle_pipe[3] = 3; - swizzle_pipe[4] = 4; - swizzle_pipe[5] = 5; - swizzle_pipe[6] = 6; - swizzle_pipe[7] = 7; - } else { - swizzle_pipe[0] = 0; - swizzle_pipe[1] = 2; - swizzle_pipe[2] = 4; - swizzle_pipe[3] = 6; - swizzle_pipe[4] = 1; - swizzle_pipe[5] = 3; - swizzle_pipe[6] = 5; - swizzle_pipe[7] = 7; - } - break; - } - - for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) { - while (((1 << cur_backend) & enabled_backends_mask) == 0) - cur_backend = (cur_backend + 1) % SI_MAX_BACKENDS; - - backend_map |= (((cur_backend & 0xf) << (swizzle_pipe[cur_pipe] * 4))); - - cur_backend = (cur_backend + 1) % SI_MAX_BACKENDS; - } - - return backend_map; -} - -static u32 si_get_disable_mask_per_asic(struct radeon_device *rdev, - u32 disable_mask_per_se, - u32 max_disable_mask_per_se, - u32 num_shader_engines) -{ - u32 disable_field_width_per_se = r600_count_pipe_bits(disable_mask_per_se); - u32 disable_mask_per_asic = disable_mask_per_se & max_disable_mask_per_se; - - if (num_shader_engines == 1) - return disable_mask_per_asic; - else if (num_shader_engines == 2) - return disable_mask_per_asic | (disable_mask_per_asic << disable_field_width_per_se); - else - return 0xffffffff; -} - static void si_tiling_mode_table_init(struct radeon_device *rdev) { const u32 num_tile_mode_states = 32; @@ -1562,18 +1368,151 @@ static void si_tiling_mode_table_init(struct radeon_device *rdev) DRM_ERROR("unknown asic: 0x%x\n", rdev->family); } +static void si_select_se_sh(struct radeon_device *rdev, + u32 se_num, u32 sh_num) +{ + u32 data = INSTANCE_BROADCAST_WRITES; + + if ((se_num == 0xffffffff) && (sh_num == 0xffffffff)) + data = SH_BROADCAST_WRITES | SE_BROADCAST_WRITES; + else if (se_num == 0xffffffff) + data |= SE_BROADCAST_WRITES | SH_INDEX(sh_num); + else if (sh_num == 0xffffffff) + data |= SH_BROADCAST_WRITES | SE_INDEX(se_num); + else + data |= SH_INDEX(sh_num) | SE_INDEX(se_num); + WREG32(GRBM_GFX_INDEX, data); +} + +static u32 si_create_bitmask(u32 bit_width) +{ + u32 i, mask = 0; + + for (i = 0; i < bit_width; i++) { + mask <<= 1; + mask |= 1; + } + return mask; +} + +static u32 si_get_cu_enabled(struct radeon_device *rdev, u32 cu_per_sh) +{ + u32 data, mask; + + data = RREG32(CC_GC_SHADER_ARRAY_CONFIG); + if (data & 1) + data &= INACTIVE_CUS_MASK; + else + data = 0; + data |= RREG32(GC_USER_SHADER_ARRAY_CONFIG); + + data >>= INACTIVE_CUS_SHIFT; + + mask = si_create_bitmask(cu_per_sh); + + return ~data & mask; +} + +static void si_setup_spi(struct radeon_device *rdev, + u32 se_num, u32 sh_per_se, + u32 cu_per_sh) +{ + int i, j, k; + u32 data, mask, active_cu; + + for (i = 0; i < se_num; i++) { + for (j = 0; j < sh_per_se; j++) { + si_select_se_sh(rdev, i, j); + data = RREG32(SPI_STATIC_THREAD_MGMT_3); + active_cu = si_get_cu_enabled(rdev, cu_per_sh); + + mask = 1; + for (k = 0; k < 16; k++) { + mask <<= k; + if (active_cu & mask) { + data &= ~mask; + WREG32(SPI_STATIC_THREAD_MGMT_3, data); + break; + } + } + } + } + si_select_se_sh(rdev, 0xffffffff, 0xffffffff); +} + +static u32 si_get_rb_disabled(struct radeon_device *rdev, + u32 max_rb_num, u32 se_num, + u32 sh_per_se) +{ + u32 data, mask; + + data = RREG32(CC_RB_BACKEND_DISABLE); + if (data & 1) + data &= BACKEND_DISABLE_MASK; + else + data = 0; + data |= RREG32(GC_USER_RB_BACKEND_DISABLE); + + data >>= BACKEND_DISABLE_SHIFT; + + mask = si_create_bitmask(max_rb_num / se_num / sh_per_se); + + return data & mask; +} + +static void si_setup_rb(struct radeon_device *rdev, + u32 se_num, u32 sh_per_se, + u32 max_rb_num) +{ + int i, j; + u32 data, mask; + u32 disabled_rbs = 0; + u32 enabled_rbs = 0; + + for (i = 0; i < se_num; i++) { + for (j = 0; j < sh_per_se; j++) { + si_select_se_sh(rdev, i, j); + data = si_get_rb_disabled(rdev, max_rb_num, se_num, sh_per_se); + disabled_rbs |= data << ((i * sh_per_se + j) * TAHITI_RB_BITMAP_WIDTH_PER_SH); + } + } + si_select_se_sh(rdev, 0xffffffff, 0xffffffff); + + mask = 1; + for (i = 0; i < max_rb_num; i++) { + if (!(disabled_rbs & mask)) + enabled_rbs |= mask; + mask <<= 1; + } + + for (i = 0; i < se_num; i++) { + si_select_se_sh(rdev, i, 0xffffffff); + data = 0; + for (j = 0; j < sh_per_se; j++) { + switch (enabled_rbs & 3) { + case 1: + data |= (RASTER_CONFIG_RB_MAP_0 << (i * sh_per_se + j) * 2); + break; + case 2: + data |= (RASTER_CONFIG_RB_MAP_3 << (i * sh_per_se + j) * 2); + break; + case 3: + default: + data |= (RASTER_CONFIG_RB_MAP_2 << (i * sh_per_se + j) * 2); + break; + } + enabled_rbs >>= 2; + } + WREG32(PA_SC_RASTER_CONFIG, data); + } + si_select_se_sh(rdev, 0xffffffff, 0xffffffff); +} + static void si_gpu_init(struct radeon_device *rdev) { - u32 cc_rb_backend_disable = 0; - u32 cc_gc_shader_array_config; u32 gb_addr_config = 0; u32 mc_shared_chmap, mc_arb_ramcfg; - u32 gb_backend_map; - u32 cgts_tcc_disable; u32 sx_debug_1; - u32 gc_user_shader_array_config; - u32 gc_user_rb_backend_disable; - u32 cgts_user_tcc_disable; u32 hdp_host_path_cntl; u32 tmp; int i, j; @@ -1581,9 +1520,9 @@ static void si_gpu_init(struct radeon_device *rdev) switch (rdev->family) { case CHIP_TAHITI: rdev->config.si.max_shader_engines = 2; - rdev->config.si.max_pipes_per_simd = 4; rdev->config.si.max_tile_pipes = 12; - rdev->config.si.max_simds_per_se = 8; + rdev->config.si.max_cu_per_sh = 8; + rdev->config.si.max_sh_per_se = 2; rdev->config.si.max_backends_per_se = 4; rdev->config.si.max_texture_channel_caches = 12; rdev->config.si.max_gprs = 256; @@ -1594,12 +1533,13 @@ static void si_gpu_init(struct radeon_device *rdev) rdev->config.si.sc_prim_fifo_size_backend = 0x100; rdev->config.si.sc_hiz_tile_fifo_size = 0x30; rdev->config.si.sc_earlyz_tile_fifo_size = 0x130; + gb_addr_config = TAHITI_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_PITCAIRN: rdev->config.si.max_shader_engines = 2; - rdev->config.si.max_pipes_per_simd = 4; rdev->config.si.max_tile_pipes = 8; - rdev->config.si.max_simds_per_se = 5; + rdev->config.si.max_cu_per_sh = 5; + rdev->config.si.max_sh_per_se = 2; rdev->config.si.max_backends_per_se = 4; rdev->config.si.max_texture_channel_caches = 8; rdev->config.si.max_gprs = 256; @@ -1610,13 +1550,14 @@ static void si_gpu_init(struct radeon_device *rdev) rdev->config.si.sc_prim_fifo_size_backend = 0x100; rdev->config.si.sc_hiz_tile_fifo_size = 0x30; rdev->config.si.sc_earlyz_tile_fifo_size = 0x130; + gb_addr_config = TAHITI_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_VERDE: default: rdev->config.si.max_shader_engines = 1; - rdev->config.si.max_pipes_per_simd = 4; rdev->config.si.max_tile_pipes = 4; - rdev->config.si.max_simds_per_se = 2; + rdev->config.si.max_cu_per_sh = 2; + rdev->config.si.max_sh_per_se = 2; rdev->config.si.max_backends_per_se = 4; rdev->config.si.max_texture_channel_caches = 4; rdev->config.si.max_gprs = 256; @@ -1627,6 +1568,7 @@ static void si_gpu_init(struct radeon_device *rdev) rdev->config.si.sc_prim_fifo_size_backend = 0x40; rdev->config.si.sc_hiz_tile_fifo_size = 0x30; rdev->config.si.sc_earlyz_tile_fifo_size = 0x130; + gb_addr_config = VERDE_GB_ADDR_CONFIG_GOLDEN; break; } @@ -1648,31 +1590,7 @@ static void si_gpu_init(struct radeon_device *rdev) mc_shared_chmap = RREG32(MC_SHARED_CHMAP); mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); - cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE); - cc_gc_shader_array_config = RREG32(CC_GC_SHADER_ARRAY_CONFIG); - cgts_tcc_disable = 0xffff0000; - for (i = 0; i < rdev->config.si.max_texture_channel_caches; i++) - cgts_tcc_disable &= ~(1 << (16 + i)); - gc_user_rb_backend_disable = RREG32(GC_USER_RB_BACKEND_DISABLE); - gc_user_shader_array_config = RREG32(GC_USER_SHADER_ARRAY_CONFIG); - cgts_user_tcc_disable = RREG32(CGTS_USER_TCC_DISABLE); - - rdev->config.si.num_shader_engines = rdev->config.si.max_shader_engines; rdev->config.si.num_tile_pipes = rdev->config.si.max_tile_pipes; - tmp = ((~gc_user_rb_backend_disable) & BACKEND_DISABLE_MASK) >> BACKEND_DISABLE_SHIFT; - rdev->config.si.num_backends_per_se = r600_count_pipe_bits(tmp); - tmp = (gc_user_rb_backend_disable & BACKEND_DISABLE_MASK) >> BACKEND_DISABLE_SHIFT; - rdev->config.si.backend_disable_mask_per_asic = - si_get_disable_mask_per_asic(rdev, tmp, SI_MAX_BACKENDS_PER_SE_MASK, - rdev->config.si.num_shader_engines); - rdev->config.si.backend_map = - si_get_tile_pipe_to_backend_map(rdev, rdev->config.si.num_tile_pipes, - rdev->config.si.num_backends_per_se * - rdev->config.si.num_shader_engines, - &rdev->config.si.backend_disable_mask_per_asic, - rdev->config.si.num_shader_engines); - tmp = ((~cgts_user_tcc_disable) & TCC_DISABLE_MASK) >> TCC_DISABLE_SHIFT; - rdev->config.si.num_texture_channel_caches = r600_count_pipe_bits(tmp); rdev->config.si.mem_max_burst_length_bytes = 256; tmp = (mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT; rdev->config.si.mem_row_size_in_kb = (4 * (1 << (8 + tmp))) / 1024; @@ -1683,55 +1601,8 @@ static void si_gpu_init(struct radeon_device *rdev) rdev->config.si.num_gpus = 1; rdev->config.si.multi_gpu_tile_size = 64; - gb_addr_config = 0; - switch (rdev->config.si.num_tile_pipes) { - case 1: - gb_addr_config |= NUM_PIPES(0); - break; - case 2: - gb_addr_config |= NUM_PIPES(1); - break; - case 4: - gb_addr_config |= NUM_PIPES(2); - break; - case 8: - default: - gb_addr_config |= NUM_PIPES(3); - break; - } - - tmp = (rdev->config.si.mem_max_burst_length_bytes / 256) - 1; - gb_addr_config |= PIPE_INTERLEAVE_SIZE(tmp); - gb_addr_config |= NUM_SHADER_ENGINES(rdev->config.si.num_shader_engines - 1); - tmp = (rdev->config.si.shader_engine_tile_size / 16) - 1; - gb_addr_config |= SHADER_ENGINE_TILE_SIZE(tmp); - switch (rdev->config.si.num_gpus) { - case 1: - default: - gb_addr_config |= NUM_GPUS(0); - break; - case 2: - gb_addr_config |= NUM_GPUS(1); - break; - case 4: - gb_addr_config |= NUM_GPUS(2); - break; - } - switch (rdev->config.si.multi_gpu_tile_size) { - case 16: - gb_addr_config |= MULTI_GPU_TILE_SIZE(0); - break; - case 32: - default: - gb_addr_config |= MULTI_GPU_TILE_SIZE(1); - break; - case 64: - gb_addr_config |= MULTI_GPU_TILE_SIZE(2); - break; - case 128: - gb_addr_config |= MULTI_GPU_TILE_SIZE(3); - break; - } + /* fix up row size */ + gb_addr_config &= ~ROW_SIZE_MASK; switch (rdev->config.si.mem_row_size_in_kb) { case 1: default: @@ -1745,26 +1616,6 @@ static void si_gpu_init(struct radeon_device *rdev) break; } - tmp = (gb_addr_config & NUM_PIPES_MASK) >> NUM_PIPES_SHIFT; - rdev->config.si.num_tile_pipes = (1 << tmp); - tmp = (gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT; - rdev->config.si.mem_max_burst_length_bytes = (tmp + 1) * 256; - tmp = (gb_addr_config & NUM_SHADER_ENGINES_MASK) >> NUM_SHADER_ENGINES_SHIFT; - rdev->config.si.num_shader_engines = tmp + 1; - tmp = (gb_addr_config & NUM_GPUS_MASK) >> NUM_GPUS_SHIFT; - rdev->config.si.num_gpus = tmp + 1; - tmp = (gb_addr_config & MULTI_GPU_TILE_SIZE_MASK) >> MULTI_GPU_TILE_SIZE_SHIFT; - rdev->config.si.multi_gpu_tile_size = 1 << tmp; - tmp = (gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT; - rdev->config.si.mem_row_size_in_kb = 1 << tmp; - - gb_backend_map = - si_get_tile_pipe_to_backend_map(rdev, rdev->config.si.num_tile_pipes, - rdev->config.si.num_backends_per_se * - rdev->config.si.num_shader_engines, - &rdev->config.si.backend_disable_mask_per_asic, - rdev->config.si.num_shader_engines); - /* setup tiling info dword. gb_addr_config is not adequate since it does * not have bank info, so create a custom tiling dword. * bits 3:0 num_pipes @@ -1789,33 +1640,29 @@ static void si_gpu_init(struct radeon_device *rdev) rdev->config.si.tile_config |= (3 << 0); break; } - rdev->config.si.tile_config |= - ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; + if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) + rdev->config.si.tile_config |= 1 << 4; + else + rdev->config.si.tile_config |= 0 << 4; rdev->config.si.tile_config |= ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8; rdev->config.si.tile_config |= ((gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT) << 12; - rdev->config.si.backend_map = gb_backend_map; WREG32(GB_ADDR_CONFIG, gb_addr_config); WREG32(DMIF_ADDR_CONFIG, gb_addr_config); WREG32(HDP_ADDR_CONFIG, gb_addr_config); - /* primary versions */ - WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); - WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); - WREG32(CC_GC_SHADER_ARRAY_CONFIG, cc_gc_shader_array_config); - - WREG32(CGTS_TCC_DISABLE, cgts_tcc_disable); + si_tiling_mode_table_init(rdev); - /* user versions */ - WREG32(GC_USER_RB_BACKEND_DISABLE, cc_rb_backend_disable); - WREG32(GC_USER_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); - WREG32(GC_USER_SHADER_ARRAY_CONFIG, cc_gc_shader_array_config); + si_setup_rb(rdev, rdev->config.si.max_shader_engines, + rdev->config.si.max_sh_per_se, + rdev->config.si.max_backends_per_se); - WREG32(CGTS_USER_TCC_DISABLE, cgts_tcc_disable); + si_setup_spi(rdev, rdev->config.si.max_shader_engines, + rdev->config.si.max_sh_per_se, + rdev->config.si.max_cu_per_sh); - si_tiling_mode_table_init(rdev); /* set HW defaults for 3D engine */ WREG32(CP_QUEUE_THRESHOLDS, (ROQ_IB1_START(0x16) | diff --git a/trunk/drivers/gpu/drm/radeon/sid.h b/trunk/drivers/gpu/drm/radeon/sid.h index 53ea2c42dbd6..db4067962868 100644 --- a/trunk/drivers/gpu/drm/radeon/sid.h +++ b/trunk/drivers/gpu/drm/radeon/sid.h @@ -24,6 +24,11 @@ #ifndef SI_H #define SI_H +#define TAHITI_RB_BITMAP_WIDTH_PER_SH 2 + +#define TAHITI_GB_ADDR_CONFIG_GOLDEN 0x12011003 +#define VERDE_GB_ADDR_CONFIG_GOLDEN 0x12010002 + #define CG_MULT_THERMAL_STATUS 0x714 #define ASIC_MAX_TEMP(x) ((x) << 0) #define ASIC_MAX_TEMP_MASK 0x000001ff @@ -408,6 +413,12 @@ #define SOFT_RESET_IA (1 << 15) #define GRBM_GFX_INDEX 0x802C +#define INSTANCE_INDEX(x) ((x) << 0) +#define SH_INDEX(x) ((x) << 8) +#define SE_INDEX(x) ((x) << 16) +#define SH_BROADCAST_WRITES (1 << 29) +#define INSTANCE_BROADCAST_WRITES (1 << 30) +#define SE_BROADCAST_WRITES (1 << 31) #define GRBM_INT_CNTL 0x8060 # define RDERR_INT_ENABLE (1 << 0) @@ -480,6 +491,8 @@ #define VGT_TF_MEMORY_BASE 0x89B8 #define CC_GC_SHADER_ARRAY_CONFIG 0x89bc +#define INACTIVE_CUS_MASK 0xFFFF0000 +#define INACTIVE_CUS_SHIFT 16 #define GC_USER_SHADER_ARRAY_CONFIG 0x89c0 #define PA_CL_ENHANCE 0x8A14 @@ -688,6 +701,12 @@ #define RLC_MC_CNTL 0xC344 #define RLC_UCODE_CNTL 0xC348 +#define PA_SC_RASTER_CONFIG 0x28350 +# define RASTER_CONFIG_RB_MAP_0 0 +# define RASTER_CONFIG_RB_MAP_1 1 +# define RASTER_CONFIG_RB_MAP_2 2 +# define RASTER_CONFIG_RB_MAP_3 3 + #define VGT_EVENT_INITIATOR 0x28a90 # define SAMPLE_STREAMOUTSTATS1 (1 << 0) # define SAMPLE_STREAMOUTSTATS2 (2 << 0) diff --git a/trunk/drivers/i2c/muxes/Kconfig b/trunk/drivers/i2c/muxes/Kconfig index beb2491db274..a0edd9854218 100644 --- a/trunk/drivers/i2c/muxes/Kconfig +++ b/trunk/drivers/i2c/muxes/Kconfig @@ -37,4 +37,16 @@ config I2C_MUX_PCA954x This driver can also be built as a module. If so, the module will be called i2c-mux-pca954x. +config I2C_MUX_PINCTRL + tristate "pinctrl-based I2C multiplexer" + depends on PINCTRL + help + If you say yes to this option, support will be included for an I2C + multiplexer that uses the pinctrl subsystem, i.e. pin multiplexing. + This is useful for SoCs whose I2C module's signals can be routed to + different sets of pins at run-time. + + This driver can also be built as a module. If so, the module will be + called pinctrl-i2cmux. + endmenu diff --git a/trunk/drivers/i2c/muxes/Makefile b/trunk/drivers/i2c/muxes/Makefile index 5826249b29ca..76da8692afff 100644 --- a/trunk/drivers/i2c/muxes/Makefile +++ b/trunk/drivers/i2c/muxes/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o +obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG diff --git a/trunk/drivers/i2c/muxes/i2c-mux-pinctrl.c b/trunk/drivers/i2c/muxes/i2c-mux-pinctrl.c new file mode 100644 index 000000000000..46a669763476 --- /dev/null +++ b/trunk/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -0,0 +1,279 @@ +/* + * I2C multiplexer using pinctrl API + * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct i2c_mux_pinctrl { + struct device *dev; + struct i2c_mux_pinctrl_platform_data *pdata; + struct pinctrl *pinctrl; + struct pinctrl_state **states; + struct pinctrl_state *state_idle; + struct i2c_adapter *parent; + struct i2c_adapter **busses; +}; + +static int i2c_mux_pinctrl_select(struct i2c_adapter *adap, void *data, + u32 chan) +{ + struct i2c_mux_pinctrl *mux = data; + + return pinctrl_select_state(mux->pinctrl, mux->states[chan]); +} + +static int i2c_mux_pinctrl_deselect(struct i2c_adapter *adap, void *data, + u32 chan) +{ + struct i2c_mux_pinctrl *mux = data; + + return pinctrl_select_state(mux->pinctrl, mux->state_idle); +} + +#ifdef CONFIG_OF +static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux, + struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + int num_names, i, ret; + struct device_node *adapter_np; + struct i2c_adapter *adapter; + + if (!np) + return 0; + + mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL); + if (!mux->pdata) { + dev_err(mux->dev, + "Cannot allocate i2c_mux_pinctrl_platform_data\n"); + return -ENOMEM; + } + + num_names = of_property_count_strings(np, "pinctrl-names"); + if (num_names < 0) { + dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n", + num_names); + return num_names; + } + + mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev, + sizeof(*mux->pdata->pinctrl_states) * num_names, + GFP_KERNEL); + if (!mux->pdata->pinctrl_states) { + dev_err(mux->dev, "Cannot allocate pinctrl_states\n"); + return -ENOMEM; + } + + for (i = 0; i < num_names; i++) { + ret = of_property_read_string_index(np, "pinctrl-names", i, + &mux->pdata->pinctrl_states[mux->pdata->bus_count]); + if (ret < 0) { + dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n", + ret); + return ret; + } + if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count], + "idle")) { + if (i != num_names - 1) { + dev_err(mux->dev, "idle state must be last\n"); + return -EINVAL; + } + mux->pdata->pinctrl_state_idle = "idle"; + } else { + mux->pdata->bus_count++; + } + } + + adapter_np = of_parse_phandle(np, "i2c-parent", 0); + if (!adapter_np) { + dev_err(mux->dev, "Cannot parse i2c-parent\n"); + return -ENODEV; + } + adapter = of_find_i2c_adapter_by_node(adapter_np); + if (!adapter) { + dev_err(mux->dev, "Cannot find parent bus\n"); + return -ENODEV; + } + mux->pdata->parent_bus_num = i2c_adapter_id(adapter); + put_device(&adapter->dev); + + return 0; +} +#else +static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux, + struct platform_device *pdev) +{ + return 0; +} +#endif + +static int __devinit i2c_mux_pinctrl_probe(struct platform_device *pdev) +{ + struct i2c_mux_pinctrl *mux; + int (*deselect)(struct i2c_adapter *, void *, u32); + int i, ret; + + mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); + if (!mux) { + dev_err(&pdev->dev, "Cannot allocate i2c_mux_pinctrl\n"); + ret = -ENOMEM; + goto err; + } + platform_set_drvdata(pdev, mux); + + mux->dev = &pdev->dev; + + mux->pdata = pdev->dev.platform_data; + if (!mux->pdata) { + ret = i2c_mux_pinctrl_parse_dt(mux, pdev); + if (ret < 0) + goto err; + } + if (!mux->pdata) { + dev_err(&pdev->dev, "Missing platform data\n"); + ret = -ENODEV; + goto err; + } + + mux->states = devm_kzalloc(&pdev->dev, + sizeof(*mux->states) * mux->pdata->bus_count, + GFP_KERNEL); + if (!mux->states) { + dev_err(&pdev->dev, "Cannot allocate states\n"); + ret = -ENOMEM; + goto err; + } + + mux->busses = devm_kzalloc(&pdev->dev, + sizeof(mux->busses) * mux->pdata->bus_count, + GFP_KERNEL); + if (!mux->states) { + dev_err(&pdev->dev, "Cannot allocate busses\n"); + ret = -ENOMEM; + goto err; + } + + mux->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(mux->pinctrl)) { + ret = PTR_ERR(mux->pinctrl); + dev_err(&pdev->dev, "Cannot get pinctrl: %d\n", ret); + goto err; + } + for (i = 0; i < mux->pdata->bus_count; i++) { + mux->states[i] = pinctrl_lookup_state(mux->pinctrl, + mux->pdata->pinctrl_states[i]); + if (IS_ERR(mux->states[i])) { + ret = PTR_ERR(mux->states[i]); + dev_err(&pdev->dev, + "Cannot look up pinctrl state %s: %d\n", + mux->pdata->pinctrl_states[i], ret); + goto err; + } + } + if (mux->pdata->pinctrl_state_idle) { + mux->state_idle = pinctrl_lookup_state(mux->pinctrl, + mux->pdata->pinctrl_state_idle); + if (IS_ERR(mux->state_idle)) { + ret = PTR_ERR(mux->state_idle); + dev_err(&pdev->dev, + "Cannot look up pinctrl state %s: %d\n", + mux->pdata->pinctrl_state_idle, ret); + goto err; + } + + deselect = i2c_mux_pinctrl_deselect; + } else { + deselect = NULL; + } + + mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num); + if (!mux->parent) { + dev_err(&pdev->dev, "Parent adapter (%d) not found\n", + mux->pdata->parent_bus_num); + ret = -ENODEV; + goto err; + } + + for (i = 0; i < mux->pdata->bus_count; i++) { + u32 bus = mux->pdata->base_bus_num ? + (mux->pdata->base_bus_num + i) : 0; + + mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev, + mux, bus, i, + i2c_mux_pinctrl_select, + deselect); + if (!mux->busses[i]) { + ret = -ENODEV; + dev_err(&pdev->dev, "Failed to add adapter %d\n", i); + goto err_del_adapter; + } + } + + return 0; + +err_del_adapter: + for (; i > 0; i--) + i2c_del_mux_adapter(mux->busses[i - 1]); + i2c_put_adapter(mux->parent); +err: + return ret; +} + +static int __devexit i2c_mux_pinctrl_remove(struct platform_device *pdev) +{ + struct i2c_mux_pinctrl *mux = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < mux->pdata->bus_count; i++) + i2c_del_mux_adapter(mux->busses[i]); + + i2c_put_adapter(mux->parent); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id i2c_mux_pinctrl_of_match[] __devinitconst = { + { .compatible = "i2c-mux-pinctrl", }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_mux_pinctrl_of_match); +#endif + +static struct platform_driver i2c_mux_pinctrl_driver = { + .driver = { + .name = "i2c-mux-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(i2c_mux_pinctrl_of_match), + }, + .probe = i2c_mux_pinctrl_probe, + .remove = __devexit_p(i2c_mux_pinctrl_remove), +}; +module_platform_driver(i2c_mux_pinctrl_driver); + +MODULE_DESCRIPTION("pinctrl-based I2C multiplexer driver"); +MODULE_AUTHOR("Stephen Warren "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:i2c-mux-pinctrl"); diff --git a/trunk/drivers/infiniband/hw/cxgb4/cm.c b/trunk/drivers/infiniband/hw/cxgb4/cm.c index 55ab284e22f2..b18870c455ad 100644 --- a/trunk/drivers/infiniband/hw/cxgb4/cm.c +++ b/trunk/drivers/infiniband/hw/cxgb4/cm.c @@ -1593,6 +1593,10 @@ static int import_ep(struct c4iw_ep *ep, __be32 peer_ip, struct dst_entry *dst, struct net_device *pdev; pdev = ip_dev_find(&init_net, peer_ip); + if (!pdev) { + err = -ENODEV; + goto out; + } ep->l2t = cxgb4_l2t_get(cdev->rdev.lldi.l2t, n, pdev, 0); if (!ep->l2t) diff --git a/trunk/drivers/infiniband/hw/mlx4/main.c b/trunk/drivers/infiniband/hw/mlx4/main.c index ee1c577238f7..3530c41fcd1f 100644 --- a/trunk/drivers/infiniband/hw/mlx4/main.c +++ b/trunk/drivers/infiniband/hw/mlx4/main.c @@ -140,7 +140,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, props->max_mr_size = ~0ull; props->page_size_cap = dev->dev->caps.page_size_cap; props->max_qp = dev->dev->caps.num_qps - dev->dev->caps.reserved_qps; - props->max_qp_wr = dev->dev->caps.max_wqes; + props->max_qp_wr = dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE; props->max_sge = min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg); props->max_cq = dev->dev->caps.num_cqs - dev->dev->caps.reserved_cqs; @@ -1084,12 +1084,9 @@ static void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev) int total_eqs = 0; int i, j, eq; - /* Init eq table */ - ibdev->eq_table = NULL; - ibdev->eq_added = 0; - - /* Legacy mode? */ - if (dev->caps.comp_pool == 0) + /* Legacy mode or comp_pool is not large enough */ + if (dev->caps.comp_pool == 0 || + dev->caps.num_ports > dev->caps.comp_pool) return; eq_per_port = rounddown_pow_of_two(dev->caps.comp_pool/ @@ -1135,7 +1132,10 @@ static void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev) static void mlx4_ib_free_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev) { int i; - int total_eqs; + + /* no additional eqs were added */ + if (!ibdev->eq_table) + return; /* Reset the advertised EQ number */ ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors; @@ -1148,12 +1148,7 @@ static void mlx4_ib_free_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev) mlx4_release_eq(dev, ibdev->eq_table[i]); } - total_eqs = dev->caps.num_comp_vectors + ibdev->eq_added; - memset(ibdev->eq_table, 0, total_eqs * sizeof(int)); kfree(ibdev->eq_table); - - ibdev->eq_table = NULL; - ibdev->eq_added = 0; } static void *mlx4_ib_add(struct mlx4_dev *dev) diff --git a/trunk/drivers/infiniband/hw/mlx4/mlx4_ib.h b/trunk/drivers/infiniband/hw/mlx4/mlx4_ib.h index e62297cc77cc..ff36655d23d3 100644 --- a/trunk/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/trunk/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -44,6 +44,14 @@ #include #include +enum { + MLX4_IB_SQ_MIN_WQE_SHIFT = 6, + MLX4_IB_MAX_HEADROOM = 2048 +}; + +#define MLX4_IB_SQ_HEADROOM(shift) ((MLX4_IB_MAX_HEADROOM >> (shift)) + 1) +#define MLX4_IB_SQ_MAX_SPARE (MLX4_IB_SQ_HEADROOM(MLX4_IB_SQ_MIN_WQE_SHIFT)) + struct mlx4_ib_ucontext { struct ib_ucontext ibucontext; struct mlx4_uar uar; diff --git a/trunk/drivers/infiniband/hw/mlx4/qp.c b/trunk/drivers/infiniband/hw/mlx4/qp.c index ceb33327091a..8d4ed24aef93 100644 --- a/trunk/drivers/infiniband/hw/mlx4/qp.c +++ b/trunk/drivers/infiniband/hw/mlx4/qp.c @@ -310,8 +310,8 @@ static int set_rq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, int is_user, int has_rq, struct mlx4_ib_qp *qp) { /* Sanity check RQ size before proceeding */ - if (cap->max_recv_wr > dev->dev->caps.max_wqes || - cap->max_recv_sge > dev->dev->caps.max_rq_sg) + if (cap->max_recv_wr > dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE || + cap->max_recv_sge > min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg)) return -EINVAL; if (!has_rq) { @@ -329,8 +329,17 @@ static int set_rq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, qp->rq.wqe_shift = ilog2(qp->rq.max_gs * sizeof (struct mlx4_wqe_data_seg)); } - cap->max_recv_wr = qp->rq.max_post = qp->rq.wqe_cnt; - cap->max_recv_sge = qp->rq.max_gs; + /* leave userspace return values as they were, so as not to break ABI */ + if (is_user) { + cap->max_recv_wr = qp->rq.max_post = qp->rq.wqe_cnt; + cap->max_recv_sge = qp->rq.max_gs; + } else { + cap->max_recv_wr = qp->rq.max_post = + min(dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE, qp->rq.wqe_cnt); + cap->max_recv_sge = min(qp->rq.max_gs, + min(dev->dev->caps.max_sq_sg, + dev->dev->caps.max_rq_sg)); + } return 0; } @@ -341,8 +350,8 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, int s; /* Sanity check SQ size before proceeding */ - if (cap->max_send_wr > dev->dev->caps.max_wqes || - cap->max_send_sge > dev->dev->caps.max_sq_sg || + if (cap->max_send_wr > (dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE) || + cap->max_send_sge > min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg) || cap->max_inline_data + send_wqe_overhead(type, qp->flags) + sizeof (struct mlx4_wqe_inline_seg) > dev->dev->caps.max_sq_desc_sz) return -EINVAL; diff --git a/trunk/drivers/infiniband/hw/ocrdma/ocrdma.h b/trunk/drivers/infiniband/hw/ocrdma/ocrdma.h index 85a69c958559..037f5cea85bd 100644 --- a/trunk/drivers/infiniband/hw/ocrdma/ocrdma.h +++ b/trunk/drivers/infiniband/hw/ocrdma/ocrdma.h @@ -231,7 +231,6 @@ struct ocrdma_qp_hwq_info { u32 entry_size; u32 max_cnt; u32 max_wqe_idx; - u32 free_delta; u16 dbid; /* qid, where to ring the doorbell. */ u32 len; dma_addr_t pa; diff --git a/trunk/drivers/infiniband/hw/ocrdma/ocrdma_abi.h b/trunk/drivers/infiniband/hw/ocrdma/ocrdma_abi.h index a411a4e3193d..517ab20b727c 100644 --- a/trunk/drivers/infiniband/hw/ocrdma/ocrdma_abi.h +++ b/trunk/drivers/infiniband/hw/ocrdma/ocrdma_abi.h @@ -101,8 +101,6 @@ struct ocrdma_create_qp_uresp { u32 rsvd1; u32 num_wqe_allocated; u32 num_rqe_allocated; - u32 free_wqe_delta; - u32 free_rqe_delta; u32 db_sq_offset; u32 db_rq_offset; u32 db_shift; @@ -126,8 +124,7 @@ struct ocrdma_create_srq_uresp { u32 db_rq_offset; u32 db_shift; - u32 free_rqe_delta; - u32 rsvd2; + u64 rsvd2; u64 rsvd3; } __packed; diff --git a/trunk/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/trunk/drivers/infiniband/hw/ocrdma/ocrdma_hw.c index 9b204b1ba336..9343a1522977 100644 --- a/trunk/drivers/infiniband/hw/ocrdma/ocrdma_hw.c +++ b/trunk/drivers/infiniband/hw/ocrdma/ocrdma_hw.c @@ -732,7 +732,7 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev, break; case OCRDMA_SRQ_LIMIT_EVENT: ib_evt.element.srq = &qp->srq->ibsrq; - ib_evt.event = IB_EVENT_QP_LAST_WQE_REACHED; + ib_evt.event = IB_EVENT_SRQ_LIMIT_REACHED; srq_event = 1; qp_event = 0; break; @@ -1990,19 +1990,12 @@ static void ocrdma_get_create_qp_rsp(struct ocrdma_create_qp_rsp *rsp, max_wqe_allocated = 1 << max_wqe_allocated; max_rqe_allocated = 1 << ((u16)rsp->max_wqe_rqe); - if (qp->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) { - qp->sq.free_delta = 0; - qp->rq.free_delta = 1; - } else - qp->sq.free_delta = 1; - qp->sq.max_cnt = max_wqe_allocated; qp->sq.max_wqe_idx = max_wqe_allocated - 1; if (!attrs->srq) { qp->rq.max_cnt = max_rqe_allocated; qp->rq.max_wqe_idx = max_rqe_allocated - 1; - qp->rq.free_delta = 1; } } diff --git a/trunk/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/trunk/drivers/infiniband/hw/ocrdma/ocrdma_main.c index a20d16eaae71..04fef3de6d75 100644 --- a/trunk/drivers/infiniband/hw/ocrdma/ocrdma_main.c +++ b/trunk/drivers/infiniband/hw/ocrdma/ocrdma_main.c @@ -26,7 +26,6 @@ *******************************************************************/ #include -#include #include #include #include diff --git a/trunk/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/trunk/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index e9f74d1b48f6..d16d172b6b6b 100644 --- a/trunk/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/trunk/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -940,8 +940,6 @@ static int ocrdma_copy_qp_uresp(struct ocrdma_qp *qp, uresp.db_rq_offset = OCRDMA_DB_RQ_OFFSET; uresp.db_shift = 16; } - uresp.free_wqe_delta = qp->sq.free_delta; - uresp.free_rqe_delta = qp->rq.free_delta; if (qp->dpp_enabled) { uresp.dpp_credit = dpp_credit_lmt; @@ -1307,8 +1305,6 @@ static int ocrdma_hwq_free_cnt(struct ocrdma_qp_hwq_info *q) free_cnt = (q->max_cnt - q->head) + q->tail; else free_cnt = q->tail - q->head; - if (q->free_delta) - free_cnt -= q->free_delta; return free_cnt; } @@ -1501,7 +1497,6 @@ static int ocrdma_copy_srq_uresp(struct ocrdma_srq *srq, struct ib_udata *udata) (srq->pd->id * srq->dev->nic_info.db_page_size); uresp.db_page_size = srq->dev->nic_info.db_page_size; uresp.num_rqe_allocated = srq->rq.max_cnt; - uresp.free_rqe_delta = 1; if (srq->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) { uresp.db_rq_offset = OCRDMA_DB_GEN2_RQ1_OFFSET; uresp.db_shift = 24; diff --git a/trunk/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h b/trunk/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h index e6483439f25f..633f03d80274 100644 --- a/trunk/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h +++ b/trunk/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h @@ -28,7 +28,6 @@ #ifndef __OCRDMA_VERBS_H__ #define __OCRDMA_VERBS_H__ -#include int ocrdma_post_send(struct ib_qp *, struct ib_send_wr *, struct ib_send_wr **bad_wr); int ocrdma_post_recv(struct ib_qp *, struct ib_recv_wr *, diff --git a/trunk/drivers/iommu/amd_iommu.c b/trunk/drivers/iommu/amd_iommu.c index d90a421e9cac..a2e418cba0ff 100644 --- a/trunk/drivers/iommu/amd_iommu.c +++ b/trunk/drivers/iommu/amd_iommu.c @@ -547,26 +547,12 @@ static void iommu_poll_events(struct amd_iommu *iommu) spin_unlock_irqrestore(&iommu->lock, flags); } -static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u32 head) +static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u64 *raw) { struct amd_iommu_fault fault; - volatile u64 *raw; - int i; INC_STATS_COUNTER(pri_requests); - raw = (u64 *)(iommu->ppr_log + head); - - /* - * Hardware bug: Interrupt may arrive before the entry is written to - * memory. If this happens we need to wait for the entry to arrive. - */ - for (i = 0; i < LOOP_TIMEOUT; ++i) { - if (PPR_REQ_TYPE(raw[0]) != 0) - break; - udelay(1); - } - if (PPR_REQ_TYPE(raw[0]) != PPR_REQ_FAULT) { pr_err_ratelimited("AMD-Vi: Unknown PPR request received\n"); return; @@ -578,12 +564,6 @@ static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u32 head) fault.tag = PPR_TAG(raw[0]); fault.flags = PPR_FLAGS(raw[0]); - /* - * To detect the hardware bug we need to clear the entry - * to back to zero. - */ - raw[0] = raw[1] = 0; - atomic_notifier_call_chain(&ppr_notifier, 0, &fault); } @@ -595,25 +575,62 @@ static void iommu_poll_ppr_log(struct amd_iommu *iommu) if (iommu->ppr_log == NULL) return; + /* enable ppr interrupts again */ + writel(MMIO_STATUS_PPR_INT_MASK, iommu->mmio_base + MMIO_STATUS_OFFSET); + spin_lock_irqsave(&iommu->lock, flags); head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET); tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET); while (head != tail) { + volatile u64 *raw; + u64 entry[2]; + int i; - /* Handle PPR entry */ - iommu_handle_ppr_entry(iommu, head); + raw = (u64 *)(iommu->ppr_log + head); + + /* + * Hardware bug: Interrupt may arrive before the entry is + * written to memory. If this happens we need to wait for the + * entry to arrive. + */ + for (i = 0; i < LOOP_TIMEOUT; ++i) { + if (PPR_REQ_TYPE(raw[0]) != 0) + break; + udelay(1); + } + + /* Avoid memcpy function-call overhead */ + entry[0] = raw[0]; + entry[1] = raw[1]; - /* Update and refresh ring-buffer state*/ + /* + * To detect the hardware bug we need to clear the entry + * back to zero. + */ + raw[0] = raw[1] = 0UL; + + /* Update head pointer of hardware ring-buffer */ head = (head + PPR_ENTRY_SIZE) % PPR_LOG_SIZE; writel(head, iommu->mmio_base + MMIO_PPR_HEAD_OFFSET); + + /* + * Release iommu->lock because ppr-handling might need to + * re-aquire it + */ + spin_unlock_irqrestore(&iommu->lock, flags); + + /* Handle PPR entry */ + iommu_handle_ppr_entry(iommu, entry); + + spin_lock_irqsave(&iommu->lock, flags); + + /* Refresh ring-buffer information */ + head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET); tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET); } - /* enable ppr interrupts again */ - writel(MMIO_STATUS_PPR_INT_MASK, iommu->mmio_base + MMIO_STATUS_OFFSET); - spin_unlock_irqrestore(&iommu->lock, flags); } diff --git a/trunk/drivers/iommu/amd_iommu_init.c b/trunk/drivers/iommu/amd_iommu_init.c index c56790375e0f..542024ba6dba 100644 --- a/trunk/drivers/iommu/amd_iommu_init.c +++ b/trunk/drivers/iommu/amd_iommu_init.c @@ -1029,6 +1029,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) if (!iommu->dev) return 1; + iommu->root_pdev = pci_get_bus_and_slot(iommu->dev->bus->number, + PCI_DEVFN(0, 0)); + iommu->cap_ptr = h->cap_ptr; iommu->pci_seg = h->pci_seg; iommu->mmio_phys = h->mmio_phys; @@ -1323,20 +1326,16 @@ static void iommu_apply_resume_quirks(struct amd_iommu *iommu) { int i, j; u32 ioc_feature_control; - struct pci_dev *pdev = NULL; + struct pci_dev *pdev = iommu->root_pdev; /* RD890 BIOSes may not have completely reconfigured the iommu */ - if (!is_rd890_iommu(iommu->dev)) + if (!is_rd890_iommu(iommu->dev) || !pdev) return; /* * First, we need to ensure that the iommu is enabled. This is * controlled by a register in the northbridge */ - pdev = pci_get_bus_and_slot(iommu->dev->bus->number, PCI_DEVFN(0, 0)); - - if (!pdev) - return; /* Select Northbridge indirect register 0x75 and enable writing */ pci_write_config_dword(pdev, 0x60, 0x75 | (1 << 7)); @@ -1346,8 +1345,6 @@ static void iommu_apply_resume_quirks(struct amd_iommu *iommu) if (!(ioc_feature_control & 0x1)) pci_write_config_dword(pdev, 0x64, ioc_feature_control | 1); - pci_dev_put(pdev); - /* Restore the iommu BAR */ pci_write_config_dword(iommu->dev, iommu->cap_ptr + 4, iommu->stored_addr_lo); diff --git a/trunk/drivers/iommu/amd_iommu_types.h b/trunk/drivers/iommu/amd_iommu_types.h index 2452f3b71736..24355559a2ad 100644 --- a/trunk/drivers/iommu/amd_iommu_types.h +++ b/trunk/drivers/iommu/amd_iommu_types.h @@ -481,6 +481,9 @@ struct amd_iommu { /* Pointer to PCI device of this IOMMU */ struct pci_dev *dev; + /* Cache pdev to root device for resume quirks */ + struct pci_dev *root_pdev; + /* physical address of MMIO space */ u64 mmio_phys; /* virtual address of MMIO space */ diff --git a/trunk/drivers/md/raid1.c b/trunk/drivers/md/raid1.c index 835de7168cd3..a9c7981ddd24 100644 --- a/trunk/drivers/md/raid1.c +++ b/trunk/drivers/md/raid1.c @@ -2550,6 +2550,7 @@ static struct r1conf *setup_conf(struct mddev *mddev) err = -EINVAL; spin_lock_init(&conf->device_lock); rdev_for_each(rdev, mddev) { + struct request_queue *q; int disk_idx = rdev->raid_disk; if (disk_idx >= mddev->raid_disks || disk_idx < 0) @@ -2562,6 +2563,9 @@ static struct r1conf *setup_conf(struct mddev *mddev) if (disk->rdev) goto abort; disk->rdev = rdev; + q = bdev_get_queue(rdev->bdev); + if (q->merge_bvec_fn) + mddev->merge_check_needed = 1; disk->head_position = 0; } diff --git a/trunk/drivers/md/raid10.c b/trunk/drivers/md/raid10.c index 987db37cb875..99ae6068e456 100644 --- a/trunk/drivers/md/raid10.c +++ b/trunk/drivers/md/raid10.c @@ -3475,6 +3475,7 @@ static int run(struct mddev *mddev) rdev_for_each(rdev, mddev) { long long diff; + struct request_queue *q; disk_idx = rdev->raid_disk; if (disk_idx < 0) @@ -3493,6 +3494,9 @@ static int run(struct mddev *mddev) goto out_free_conf; disk->rdev = rdev; } + q = bdev_get_queue(rdev->bdev); + if (q->merge_bvec_fn) + mddev->merge_check_needed = 1; diff = (rdev->new_data_offset - rdev->data_offset); if (!mddev->reshape_backwards) diff = -diff; diff --git a/trunk/drivers/mtd/ubi/debug.c b/trunk/drivers/mtd/ubi/debug.c index 9f957c2d48e9..09d4f8d9d592 100644 --- a/trunk/drivers/mtd/ubi/debug.c +++ b/trunk/drivers/mtd/ubi/debug.c @@ -264,6 +264,9 @@ static struct dentry *dfs_rootdir; */ int ubi_debugfs_init(void) { + if (!IS_ENABLED(DEBUG_FS)) + return 0; + dfs_rootdir = debugfs_create_dir("ubi", NULL); if (IS_ERR_OR_NULL(dfs_rootdir)) { int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir); @@ -281,7 +284,8 @@ int ubi_debugfs_init(void) */ void ubi_debugfs_exit(void) { - debugfs_remove(dfs_rootdir); + if (IS_ENABLED(DEBUG_FS)) + debugfs_remove(dfs_rootdir); } /* Read an UBI debugfs file */ @@ -403,6 +407,9 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi) struct dentry *dent; struct ubi_debug_info *d = ubi->dbg; + if (!IS_ENABLED(DEBUG_FS)) + return 0; + n = snprintf(d->dfs_dir_name, UBI_DFS_DIR_LEN + 1, UBI_DFS_DIR_NAME, ubi->ubi_num); if (n == UBI_DFS_DIR_LEN) { @@ -470,5 +477,6 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi) */ void ubi_debugfs_exit_dev(struct ubi_device *ubi) { - debugfs_remove_recursive(ubi->dbg->dfs_dir); + if (IS_ENABLED(DEBUG_FS)) + debugfs_remove_recursive(ubi->dbg->dfs_dir); } diff --git a/trunk/drivers/mtd/ubi/wl.c b/trunk/drivers/mtd/ubi/wl.c index 9df100a4ec38..b6be644e7b85 100644 --- a/trunk/drivers/mtd/ubi/wl.c +++ b/trunk/drivers/mtd/ubi/wl.c @@ -1262,11 +1262,11 @@ int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum) dbg_wl("flush pending work for LEB %d:%d (%d pending works)", vol_id, lnum, ubi->works_count); - down_write(&ubi->work_sem); while (found) { struct ubi_work *wrk; found = 0; + down_read(&ubi->work_sem); spin_lock(&ubi->wl_lock); list_for_each_entry(wrk, &ubi->works, list) { if ((vol_id == UBI_ALL || wrk->vol_id == vol_id) && @@ -1277,18 +1277,27 @@ int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum) spin_unlock(&ubi->wl_lock); err = wrk->func(ubi, wrk, 0); - if (err) - goto out; + if (err) { + up_read(&ubi->work_sem); + return err; + } + spin_lock(&ubi->wl_lock); found = 1; break; } } spin_unlock(&ubi->wl_lock); + up_read(&ubi->work_sem); } -out: + /* + * Make sure all the works which have been done in parallel are + * finished. + */ + down_write(&ubi->work_sem); up_write(&ubi->work_sem); + return err; } diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/port.c b/trunk/drivers/net/ethernet/mellanox/mlx4/port.c index 1fe2c7a8b40c..a8fb52992c64 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/port.c @@ -697,10 +697,10 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, if (slave != dev->caps.function) memset(inbox->buf, 0, 256); if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { - *(u8 *) inbox->buf = !!reset_qkey_viols << 6; + *(u8 *) inbox->buf |= !!reset_qkey_viols << 6; ((__be32 *) inbox->buf)[2] = agg_cap_mask; } else { - ((u8 *) inbox->buf)[3] = !!reset_qkey_viols; + ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols; ((__be32 *) inbox->buf)[1] = agg_cap_mask; } diff --git a/trunk/drivers/platform/x86/acerhdf.c b/trunk/drivers/platform/x86/acerhdf.c index 639db4d0aa76..2fd9d36acd15 100644 --- a/trunk/drivers/platform/x86/acerhdf.c +++ b/trunk/drivers/platform/x86/acerhdf.c @@ -5,7 +5,7 @@ * * (C) 2009 - Peter Feuerer peter (a) piie.net * http://piie.net - * 2009 Borislav Petkov + * 2009 Borislav Petkov bp (a) alien8.de * * Inspired by and many thanks to: * o acerfand - Rachel Greenham diff --git a/trunk/drivers/rtc/rtc-cmos.c b/trunk/drivers/rtc/rtc-cmos.c index 7d5f56edb8ef..4267789ca995 100644 --- a/trunk/drivers/rtc/rtc-cmos.c +++ b/trunk/drivers/rtc/rtc-cmos.c @@ -910,14 +910,17 @@ static inline int cmos_poweroff(struct device *dev) static u32 rtc_handler(void *context) { + struct device *dev = context; + + pm_wakeup_event(dev, 0); acpi_clear_event(ACPI_EVENT_RTC); acpi_disable_event(ACPI_EVENT_RTC, 0); return ACPI_INTERRUPT_HANDLED; } -static inline void rtc_wake_setup(void) +static inline void rtc_wake_setup(struct device *dev) { - acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); + acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, dev); /* * After the RTC handler is installed, the Fixed_RTC event should * be disabled. Only when the RTC alarm is set will it be enabled. @@ -950,7 +953,7 @@ cmos_wake_setup(struct device *dev) if (acpi_disabled) return; - rtc_wake_setup(); + rtc_wake_setup(dev); acpi_rtc_info.wake_on = rtc_wake_on; acpi_rtc_info.wake_off = rtc_wake_off; diff --git a/trunk/drivers/staging/ramster/zcache-main.c b/trunk/drivers/staging/ramster/zcache-main.c index 4e7ef0e6b79c..d46764b5aaba 100644 --- a/trunk/drivers/staging/ramster/zcache-main.c +++ b/trunk/drivers/staging/ramster/zcache-main.c @@ -3002,7 +3002,7 @@ static inline struct tmem_oid oswiz(unsigned type, u32 ind) return oid; } -static int zcache_frontswap_put_page(unsigned type, pgoff_t offset, +static int zcache_frontswap_store(unsigned type, pgoff_t offset, struct page *page) { u64 ind64 = (u64)offset; @@ -3025,7 +3025,7 @@ static int zcache_frontswap_put_page(unsigned type, pgoff_t offset, /* returns 0 if the page was successfully gotten from frontswap, -1 if * was not present (should never happen!) */ -static int zcache_frontswap_get_page(unsigned type, pgoff_t offset, +static int zcache_frontswap_load(unsigned type, pgoff_t offset, struct page *page) { u64 ind64 = (u64)offset; @@ -3080,8 +3080,8 @@ static void zcache_frontswap_init(unsigned ignored) } static struct frontswap_ops zcache_frontswap_ops = { - .put_page = zcache_frontswap_put_page, - .get_page = zcache_frontswap_get_page, + .store = zcache_frontswap_store, + .load = zcache_frontswap_load, .invalidate_page = zcache_frontswap_flush_page, .invalidate_area = zcache_frontswap_flush_area, .init = zcache_frontswap_init diff --git a/trunk/drivers/staging/zcache/zcache-main.c b/trunk/drivers/staging/zcache/zcache-main.c index 2734dacacbaf..784c796b9848 100644 --- a/trunk/drivers/staging/zcache/zcache-main.c +++ b/trunk/drivers/staging/zcache/zcache-main.c @@ -1835,7 +1835,7 @@ static int zcache_frontswap_poolid = -1; * Swizzling increases objects per swaptype, increasing tmem concurrency * for heavy swaploads. Later, larger nr_cpus -> larger SWIZ_BITS * Setting SWIZ_BITS to 27 basically reconstructs the swap entry from - * frontswap_get_page(), but has side-effects. Hence using 8. + * frontswap_load(), but has side-effects. Hence using 8. */ #define SWIZ_BITS 8 #define SWIZ_MASK ((1 << SWIZ_BITS) - 1) @@ -1849,7 +1849,7 @@ static inline struct tmem_oid oswiz(unsigned type, u32 ind) return oid; } -static int zcache_frontswap_put_page(unsigned type, pgoff_t offset, +static int zcache_frontswap_store(unsigned type, pgoff_t offset, struct page *page) { u64 ind64 = (u64)offset; @@ -1870,7 +1870,7 @@ static int zcache_frontswap_put_page(unsigned type, pgoff_t offset, /* returns 0 if the page was successfully gotten from frontswap, -1 if * was not present (should never happen!) */ -static int zcache_frontswap_get_page(unsigned type, pgoff_t offset, +static int zcache_frontswap_load(unsigned type, pgoff_t offset, struct page *page) { u64 ind64 = (u64)offset; @@ -1919,8 +1919,8 @@ static void zcache_frontswap_init(unsigned ignored) } static struct frontswap_ops zcache_frontswap_ops = { - .put_page = zcache_frontswap_put_page, - .get_page = zcache_frontswap_get_page, + .store = zcache_frontswap_store, + .load = zcache_frontswap_load, .invalidate_page = zcache_frontswap_flush_page, .invalidate_area = zcache_frontswap_flush_area, .init = zcache_frontswap_init diff --git a/trunk/drivers/target/sbp/sbp_target.c b/trunk/drivers/target/sbp/sbp_target.c index 37c609898f84..7e6136e2ce81 100644 --- a/trunk/drivers/target/sbp/sbp_target.c +++ b/trunk/drivers/target/sbp/sbp_target.c @@ -587,14 +587,14 @@ static void sbp_management_request_logout( { struct sbp_tport *tport = agent->tport; struct sbp_tpg *tpg = tport->tpg; - int login_id; + int id; struct sbp_login_descriptor *login; - login_id = LOGOUT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc)); + id = LOGOUT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc)); - login = sbp_login_find_by_id(tpg, login_id); + login = sbp_login_find_by_id(tpg, id); if (!login) { - pr_warn("cannot find login: %d\n", login_id); + pr_warn("cannot find login: %d\n", id); req->status.status = cpu_to_be32( STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) | diff --git a/trunk/drivers/target/target_core_file.c b/trunk/drivers/target/target_core_file.c index 686dba189f8e..9f99d0404908 100644 --- a/trunk/drivers/target/target_core_file.c +++ b/trunk/drivers/target/target_core_file.c @@ -133,16 +133,11 @@ static struct se_device *fd_create_virtdevice( ret = PTR_ERR(dev_p); goto fail; } - - /* O_DIRECT too? */ - flags = O_RDWR | O_CREAT | O_LARGEFILE; - /* - * If fd_buffered_io=1 has not been set explicitly (the default), - * use O_SYNC to force FILEIO writes to disk. + * Use O_DSYNC by default instead of O_SYNC to forgo syncing + * of pure timestamp updates. */ - if (!(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO)) - flags |= O_SYNC; + flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC; file = filp_open(dev_p, flags, 0600); if (IS_ERR(file)) { @@ -380,23 +375,6 @@ static void fd_emulate_sync_cache(struct se_cmd *cmd) } } -static void fd_emulate_write_fua(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - struct fd_dev *fd_dev = dev->dev_ptr; - loff_t start = cmd->t_task_lba * - dev->se_sub_dev->se_dev_attrib.block_size; - loff_t end = start + cmd->data_length; - int ret; - - pr_debug("FILEIO: FUA WRITE LBA: %llu, bytes: %u\n", - cmd->t_task_lba, cmd->data_length); - - ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1); - if (ret != 0) - pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret); -} - static int fd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) { @@ -411,19 +389,21 @@ static int fd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, ret = fd_do_readv(cmd, sgl, sgl_nents); } else { ret = fd_do_writev(cmd, sgl, sgl_nents); - + /* + * Perform implict vfs_fsync_range() for fd_do_writev() ops + * for SCSI WRITEs with Forced Unit Access (FUA) set. + * Allow this to happen independent of WCE=0 setting. + */ if (ret > 0 && - dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0 && dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 && (cmd->se_cmd_flags & SCF_FUA)) { - /* - * We might need to be a bit smarter here - * and return some sense data to let the initiator - * know the FUA WRITE cache sync failed..? - */ - fd_emulate_write_fua(cmd); - } + struct fd_dev *fd_dev = dev->dev_ptr; + loff_t start = cmd->t_task_lba * + dev->se_sub_dev->se_dev_attrib.block_size; + loff_t end = start + cmd->data_length; + vfs_fsync_range(fd_dev->fd_file, start, end, 1); + } } if (ret < 0) { @@ -442,7 +422,6 @@ enum { static match_table_t tokens = { {Opt_fd_dev_name, "fd_dev_name=%s"}, {Opt_fd_dev_size, "fd_dev_size=%s"}, - {Opt_fd_buffered_io, "fd_buffered_io=%d"}, {Opt_err, NULL} }; @@ -454,7 +433,7 @@ static ssize_t fd_set_configfs_dev_params( struct fd_dev *fd_dev = se_dev->se_dev_su_ptr; char *orig, *ptr, *arg_p, *opts; substring_t args[MAX_OPT_ARGS]; - int ret = 0, arg, token; + int ret = 0, token; opts = kstrdup(page, GFP_KERNEL); if (!opts) @@ -498,19 +477,6 @@ static ssize_t fd_set_configfs_dev_params( " bytes\n", fd_dev->fd_dev_size); fd_dev->fbd_flags |= FBDF_HAS_SIZE; break; - case Opt_fd_buffered_io: - match_int(args, &arg); - if (arg != 1) { - pr_err("bogus fd_buffered_io=%d value\n", arg); - ret = -EINVAL; - goto out; - } - - pr_debug("FILEIO: Using buffered I/O" - " operations for struct fd_dev\n"); - - fd_dev->fbd_flags |= FDBD_USE_BUFFERED_IO; - break; default: break; } @@ -542,10 +508,8 @@ static ssize_t fd_show_configfs_dev_params( ssize_t bl = 0; bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id); - bl += sprintf(b + bl, " File: %s Size: %llu Mode: %s\n", - fd_dev->fd_dev_name, fd_dev->fd_dev_size, - (fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO) ? - "Buffered" : "Synchronous"); + bl += sprintf(b + bl, " File: %s Size: %llu Mode: O_DSYNC\n", + fd_dev->fd_dev_name, fd_dev->fd_dev_size); return bl; } diff --git a/trunk/drivers/target/target_core_file.h b/trunk/drivers/target/target_core_file.h index fbd59ef7d8be..70ce7fd7111d 100644 --- a/trunk/drivers/target/target_core_file.h +++ b/trunk/drivers/target/target_core_file.h @@ -14,7 +14,6 @@ #define FBDF_HAS_PATH 0x01 #define FBDF_HAS_SIZE 0x02 -#define FDBD_USE_BUFFERED_IO 0x04 struct fd_dev { u32 fbd_flags; diff --git a/trunk/drivers/xen/tmem.c b/trunk/drivers/xen/tmem.c index dcb79521e6c8..89f264c67420 100644 --- a/trunk/drivers/xen/tmem.c +++ b/trunk/drivers/xen/tmem.c @@ -269,7 +269,7 @@ static inline struct tmem_oid oswiz(unsigned type, u32 ind) } /* returns 0 if the page was successfully put into frontswap, -1 if not */ -static int tmem_frontswap_put_page(unsigned type, pgoff_t offset, +static int tmem_frontswap_store(unsigned type, pgoff_t offset, struct page *page) { u64 ind64 = (u64)offset; @@ -295,7 +295,7 @@ static int tmem_frontswap_put_page(unsigned type, pgoff_t offset, * returns 0 if the page was successfully gotten from frontswap, -1 if * was not present (should never happen!) */ -static int tmem_frontswap_get_page(unsigned type, pgoff_t offset, +static int tmem_frontswap_load(unsigned type, pgoff_t offset, struct page *page) { u64 ind64 = (u64)offset; @@ -362,8 +362,8 @@ static int __init no_frontswap(char *s) __setup("nofrontswap", no_frontswap); static struct frontswap_ops __initdata tmem_frontswap_ops = { - .put_page = tmem_frontswap_put_page, - .get_page = tmem_frontswap_get_page, + .store = tmem_frontswap_store, + .load = tmem_frontswap_load, .invalidate_page = tmem_frontswap_flush_page, .invalidate_area = tmem_frontswap_flush_area, .init = tmem_frontswap_init diff --git a/trunk/fs/cifs/cifsglob.h b/trunk/fs/cifs/cifsglob.h index 20350a93ed99..6df0cbe1cbc9 100644 --- a/trunk/fs/cifs/cifsglob.h +++ b/trunk/fs/cifs/cifsglob.h @@ -174,6 +174,7 @@ struct smb_version_operations { void (*add_credits)(struct TCP_Server_Info *, const unsigned int); void (*set_credits)(struct TCP_Server_Info *, const int); int * (*get_credits_field)(struct TCP_Server_Info *); + __u64 (*get_next_mid)(struct TCP_Server_Info *); /* data offset from read response message */ unsigned int (*read_data_offset)(char *); /* data length from read response message */ @@ -399,6 +400,12 @@ set_credits(struct TCP_Server_Info *server, const int val) server->ops->set_credits(server, val); } +static inline __u64 +get_next_mid(struct TCP_Server_Info *server) +{ + return server->ops->get_next_mid(server); +} + /* * Macros to allow the TCP_Server_Info->net field and related code to drop out * when CONFIG_NET_NS isn't set. diff --git a/trunk/fs/cifs/cifsproto.h b/trunk/fs/cifs/cifsproto.h index 5ec21ecf7980..0a6cbfe2761e 100644 --- a/trunk/fs/cifs/cifsproto.h +++ b/trunk/fs/cifs/cifsproto.h @@ -114,7 +114,6 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct, void **request_buf); extern int CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses, const struct nls_table *nls_cp); -extern __u64 GetNextMid(struct TCP_Server_Info *server); extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); extern u64 cifs_UnixTimeToNT(struct timespec); extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, diff --git a/trunk/fs/cifs/cifssmb.c b/trunk/fs/cifs/cifssmb.c index b5ad716b2642..5b400730c213 100644 --- a/trunk/fs/cifs/cifssmb.c +++ b/trunk/fs/cifs/cifssmb.c @@ -268,7 +268,7 @@ small_smb_init_no_tc(const int smb_command, const int wct, return rc; buffer = (struct smb_hdr *)*request_buf; - buffer->Mid = GetNextMid(ses->server); + buffer->Mid = get_next_mid(ses->server); if (ses->capabilities & CAP_UNICODE) buffer->Flags2 |= SMBFLG2_UNICODE; if (ses->capabilities & CAP_STATUS32) @@ -402,7 +402,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) cFYI(1, "secFlags 0x%x", secFlags); - pSMB->hdr.Mid = GetNextMid(server); + pSMB->hdr.Mid = get_next_mid(server); pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) @@ -782,7 +782,7 @@ CIFSSMBLogoff(const int xid, struct cifs_ses *ses) return rc; } - pSMB->hdr.Mid = GetNextMid(ses->server); + pSMB->hdr.Mid = get_next_mid(ses->server); if (ses->server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) @@ -4762,7 +4762,7 @@ CIFSGetDFSRefer(const int xid, struct cifs_ses *ses, /* server pointer checked in called function, but should never be null here anyway */ - pSMB->hdr.Mid = GetNextMid(ses->server); + pSMB->hdr.Mid = get_next_mid(ses->server); pSMB->hdr.Tid = ses->ipc_tid; pSMB->hdr.Uid = ses->Suid; if (ses->capabilities & CAP_STATUS32) diff --git a/trunk/fs/cifs/connect.c b/trunk/fs/cifs/connect.c index ccafdedd0dbc..78db68a5cf44 100644 --- a/trunk/fs/cifs/connect.c +++ b/trunk/fs/cifs/connect.c @@ -1058,13 +1058,15 @@ cifs_demultiplex_thread(void *p) if (mid_entry != NULL) { if (!mid_entry->multiRsp || mid_entry->multiEnd) mid_entry->callback(mid_entry); - } else if (!server->ops->is_oplock_break(buf, server)) { + } else if (!server->ops->is_oplock_break || + !server->ops->is_oplock_break(buf, server)) { cERROR(1, "No task to wake, unknown frame received! " "NumMids %d", atomic_read(&midCount)); cifs_dump_mem("Received Data is: ", buf, HEADER_SIZE(server)); #ifdef CONFIG_CIFS_DEBUG2 - server->ops->dump_detail(buf); + if (server->ops->dump_detail) + server->ops->dump_detail(buf); cifs_dump_mids(server); #endif /* CIFS_DEBUG2 */ @@ -3938,7 +3940,7 @@ CIFSTCon(unsigned int xid, struct cifs_ses *ses, header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, NULL /*no tid */ , 4 /*wct */ ); - smb_buffer->Mid = GetNextMid(ses->server); + smb_buffer->Mid = get_next_mid(ses->server); smb_buffer->Uid = ses->Suid; pSMB = (TCONX_REQ *) smb_buffer; pSMBr = (TCONX_RSP *) smb_buffer_response; diff --git a/trunk/fs/cifs/file.c b/trunk/fs/cifs/file.c index 253170dfa716..513adbc211d7 100644 --- a/trunk/fs/cifs/file.c +++ b/trunk/fs/cifs/file.c @@ -876,7 +876,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) struct cifsLockInfo *li, *tmp; struct cifs_tcon *tcon; struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); - unsigned int num, max_num; + unsigned int num, max_num, max_buf; LOCKING_ANDX_RANGE *buf, *cur; int types[] = {LOCKING_ANDX_LARGE_FILES, LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES}; @@ -892,8 +892,19 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) return rc; } - max_num = (tcon->ses->server->maxBuf - sizeof(struct smb_hdr)) / - sizeof(LOCKING_ANDX_RANGE); + /* + * Accessing maxBuf is racy with cifs_reconnect - need to store value + * and check it for zero before using. + */ + max_buf = tcon->ses->server->maxBuf; + if (!max_buf) { + mutex_unlock(&cinode->lock_mutex); + FreeXid(xid); + return -EINVAL; + } + + max_num = (max_buf - sizeof(struct smb_hdr)) / + sizeof(LOCKING_ANDX_RANGE); buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); if (!buf) { mutex_unlock(&cinode->lock_mutex); @@ -1218,7 +1229,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) int types[] = {LOCKING_ANDX_LARGE_FILES, LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES}; unsigned int i; - unsigned int max_num, num; + unsigned int max_num, num, max_buf; LOCKING_ANDX_RANGE *buf, *cur; struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); @@ -1228,8 +1239,16 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) INIT_LIST_HEAD(&tmp_llist); - max_num = (tcon->ses->server->maxBuf - sizeof(struct smb_hdr)) / - sizeof(LOCKING_ANDX_RANGE); + /* + * Accessing maxBuf is racy with cifs_reconnect - need to store value + * and check it for zero before using. + */ + max_buf = tcon->ses->server->maxBuf; + if (!max_buf) + return -EINVAL; + + max_num = (max_buf - sizeof(struct smb_hdr)) / + sizeof(LOCKING_ANDX_RANGE); buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); if (!buf) return -ENOMEM; @@ -1247,46 +1266,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) continue; if (types[i] != li->type) continue; - if (!cinode->can_cache_brlcks) { - cur->Pid = cpu_to_le16(li->pid); - cur->LengthLow = cpu_to_le32((u32)li->length); - cur->LengthHigh = - cpu_to_le32((u32)(li->length>>32)); - cur->OffsetLow = cpu_to_le32((u32)li->offset); - cur->OffsetHigh = - cpu_to_le32((u32)(li->offset>>32)); - /* - * We need to save a lock here to let us add - * it again to the file's list if the unlock - * range request fails on the server. - */ - list_move(&li->llist, &tmp_llist); - if (++num == max_num) { - stored_rc = cifs_lockv(xid, tcon, - cfile->netfid, - li->type, num, - 0, buf); - if (stored_rc) { - /* - * We failed on the unlock range - * request - add all locks from - * the tmp list to the head of - * the file's list. - */ - cifs_move_llist(&tmp_llist, - &cfile->llist); - rc = stored_rc; - } else - /* - * The unlock range request - * succeed - free the tmp list. - */ - cifs_free_llist(&tmp_llist); - cur = buf; - num = 0; - } else - cur++; - } else { + if (cinode->can_cache_brlcks) { /* * We can cache brlock requests - simply remove * a lock from the file's list. @@ -1294,7 +1274,41 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) list_del(&li->llist); cifs_del_lock_waiters(li); kfree(li); + continue; } + cur->Pid = cpu_to_le16(li->pid); + cur->LengthLow = cpu_to_le32((u32)li->length); + cur->LengthHigh = cpu_to_le32((u32)(li->length>>32)); + cur->OffsetLow = cpu_to_le32((u32)li->offset); + cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32)); + /* + * We need to save a lock here to let us add it again to + * the file's list if the unlock range request fails on + * the server. + */ + list_move(&li->llist, &tmp_llist); + if (++num == max_num) { + stored_rc = cifs_lockv(xid, tcon, cfile->netfid, + li->type, num, 0, buf); + if (stored_rc) { + /* + * We failed on the unlock range + * request - add all locks from the tmp + * list to the head of the file's list. + */ + cifs_move_llist(&tmp_llist, + &cfile->llist); + rc = stored_rc; + } else + /* + * The unlock range request succeed - + * free the tmp list. + */ + cifs_free_llist(&tmp_llist); + cur = buf; + num = 0; + } else + cur++; } if (num) { stored_rc = cifs_lockv(xid, tcon, cfile->netfid, diff --git a/trunk/fs/cifs/misc.c b/trunk/fs/cifs/misc.c index e2552d2b2e42..557506ae1e2a 100644 --- a/trunk/fs/cifs/misc.c +++ b/trunk/fs/cifs/misc.c @@ -212,93 +212,6 @@ cifs_small_buf_release(void *buf_to_free) return; } -/* - * Find a free multiplex id (SMB mid). Otherwise there could be - * mid collisions which might cause problems, demultiplexing the - * wrong response to this request. Multiplex ids could collide if - * one of a series requests takes much longer than the others, or - * if a very large number of long lived requests (byte range - * locks or FindNotify requests) are pending. No more than - * 64K-1 requests can be outstanding at one time. If no - * mids are available, return zero. A future optimization - * could make the combination of mids and uid the key we use - * to demultiplex on (rather than mid alone). - * In addition to the above check, the cifs demultiplex - * code already used the command code as a secondary - * check of the frame and if signing is negotiated the - * response would be discarded if the mid were the same - * but the signature was wrong. Since the mid is not put in the - * pending queue until later (when it is about to be dispatched) - * we do have to limit the number of outstanding requests - * to somewhat less than 64K-1 although it is hard to imagine - * so many threads being in the vfs at one time. - */ -__u64 GetNextMid(struct TCP_Server_Info *server) -{ - __u64 mid = 0; - __u16 last_mid, cur_mid; - bool collision; - - spin_lock(&GlobalMid_Lock); - - /* mid is 16 bit only for CIFS/SMB */ - cur_mid = (__u16)((server->CurrentMid) & 0xffff); - /* we do not want to loop forever */ - last_mid = cur_mid; - cur_mid++; - - /* - * This nested loop looks more expensive than it is. - * In practice the list of pending requests is short, - * fewer than 50, and the mids are likely to be unique - * on the first pass through the loop unless some request - * takes longer than the 64 thousand requests before it - * (and it would also have to have been a request that - * did not time out). - */ - while (cur_mid != last_mid) { - struct mid_q_entry *mid_entry; - unsigned int num_mids; - - collision = false; - if (cur_mid == 0) - cur_mid++; - - num_mids = 0; - list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { - ++num_mids; - if (mid_entry->mid == cur_mid && - mid_entry->mid_state == MID_REQUEST_SUBMITTED) { - /* This mid is in use, try a different one */ - collision = true; - break; - } - } - - /* - * if we have more than 32k mids in the list, then something - * is very wrong. Possibly a local user is trying to DoS the - * box by issuing long-running calls and SIGKILL'ing them. If - * we get to 2^16 mids then we're in big trouble as this - * function could loop forever. - * - * Go ahead and assign out the mid in this situation, but force - * an eventual reconnect to clean out the pending_mid_q. - */ - if (num_mids > 32768) - server->tcpStatus = CifsNeedReconnect; - - if (!collision) { - mid = (__u64)cur_mid; - server->CurrentMid = mid; - break; - } - cur_mid++; - } - spin_unlock(&GlobalMid_Lock); - return mid; -} - /* NB: MID can not be set if treeCon not passed in, in that case it is responsbility of caller to set the mid */ void @@ -334,7 +247,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , /* Uid is not converted */ buffer->Uid = treeCon->ses->Suid; - buffer->Mid = GetNextMid(treeCon->ses->server); + buffer->Mid = get_next_mid(treeCon->ses->server); } if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) buffer->Flags2 |= SMBFLG2_DFS; diff --git a/trunk/fs/cifs/smb1ops.c b/trunk/fs/cifs/smb1ops.c index d9d615fbed3f..6dec38f5522d 100644 --- a/trunk/fs/cifs/smb1ops.c +++ b/trunk/fs/cifs/smb1ops.c @@ -125,6 +125,94 @@ cifs_get_credits_field(struct TCP_Server_Info *server) return &server->credits; } +/* + * Find a free multiplex id (SMB mid). Otherwise there could be + * mid collisions which might cause problems, demultiplexing the + * wrong response to this request. Multiplex ids could collide if + * one of a series requests takes much longer than the others, or + * if a very large number of long lived requests (byte range + * locks or FindNotify requests) are pending. No more than + * 64K-1 requests can be outstanding at one time. If no + * mids are available, return zero. A future optimization + * could make the combination of mids and uid the key we use + * to demultiplex on (rather than mid alone). + * In addition to the above check, the cifs demultiplex + * code already used the command code as a secondary + * check of the frame and if signing is negotiated the + * response would be discarded if the mid were the same + * but the signature was wrong. Since the mid is not put in the + * pending queue until later (when it is about to be dispatched) + * we do have to limit the number of outstanding requests + * to somewhat less than 64K-1 although it is hard to imagine + * so many threads being in the vfs at one time. + */ +static __u64 +cifs_get_next_mid(struct TCP_Server_Info *server) +{ + __u64 mid = 0; + __u16 last_mid, cur_mid; + bool collision; + + spin_lock(&GlobalMid_Lock); + + /* mid is 16 bit only for CIFS/SMB */ + cur_mid = (__u16)((server->CurrentMid) & 0xffff); + /* we do not want to loop forever */ + last_mid = cur_mid; + cur_mid++; + + /* + * This nested loop looks more expensive than it is. + * In practice the list of pending requests is short, + * fewer than 50, and the mids are likely to be unique + * on the first pass through the loop unless some request + * takes longer than the 64 thousand requests before it + * (and it would also have to have been a request that + * did not time out). + */ + while (cur_mid != last_mid) { + struct mid_q_entry *mid_entry; + unsigned int num_mids; + + collision = false; + if (cur_mid == 0) + cur_mid++; + + num_mids = 0; + list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { + ++num_mids; + if (mid_entry->mid == cur_mid && + mid_entry->mid_state == MID_REQUEST_SUBMITTED) { + /* This mid is in use, try a different one */ + collision = true; + break; + } + } + + /* + * if we have more than 32k mids in the list, then something + * is very wrong. Possibly a local user is trying to DoS the + * box by issuing long-running calls and SIGKILL'ing them. If + * we get to 2^16 mids then we're in big trouble as this + * function could loop forever. + * + * Go ahead and assign out the mid in this situation, but force + * an eventual reconnect to clean out the pending_mid_q. + */ + if (num_mids > 32768) + server->tcpStatus = CifsNeedReconnect; + + if (!collision) { + mid = (__u64)cur_mid; + server->CurrentMid = mid; + break; + } + cur_mid++; + } + spin_unlock(&GlobalMid_Lock); + return mid; +} + struct smb_version_operations smb1_operations = { .send_cancel = send_nt_cancel, .compare_fids = cifs_compare_fids, @@ -133,6 +221,7 @@ struct smb_version_operations smb1_operations = { .add_credits = cifs_add_credits, .set_credits = cifs_set_credits, .get_credits_field = cifs_get_credits_field, + .get_next_mid = cifs_get_next_mid, .read_data_offset = cifs_read_data_offset, .read_data_length = cifs_read_data_length, .map_error = map_smb_to_linux_error, diff --git a/trunk/fs/cifs/transport.c b/trunk/fs/cifs/transport.c index 1b36ffe6a47b..3097ee58fd7d 100644 --- a/trunk/fs/cifs/transport.c +++ b/trunk/fs/cifs/transport.c @@ -779,7 +779,7 @@ send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon, pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES; pSMB->Timeout = 0; - pSMB->hdr.Mid = GetNextMid(ses->server); + pSMB->hdr.Mid = get_next_mid(ses->server); return SendReceive(xid, ses, in_buf, out_buf, &bytes_returned, 0); diff --git a/trunk/fs/dcache.c b/trunk/fs/dcache.c index 85c9e2bff8e6..40469044088d 100644 --- a/trunk/fs/dcache.c +++ b/trunk/fs/dcache.c @@ -683,6 +683,8 @@ EXPORT_SYMBOL(dget_parent); /** * d_find_alias - grab a hashed alias of inode * @inode: inode in question + * @want_discon: flag, used by d_splice_alias, to request + * that only a DISCONNECTED alias be returned. * * If inode has a hashed alias, or is a directory and has any alias, * acquire the reference to alias and return it. Otherwise return NULL. @@ -691,9 +693,10 @@ EXPORT_SYMBOL(dget_parent); * of a filesystem. * * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer - * any other hashed alias over that. + * any other hashed alias over that one unless @want_discon is set, + * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias. */ -static struct dentry *__d_find_alias(struct inode *inode) +static struct dentry *__d_find_alias(struct inode *inode, int want_discon) { struct dentry *alias, *discon_alias; @@ -705,7 +708,7 @@ static struct dentry *__d_find_alias(struct inode *inode) if (IS_ROOT(alias) && (alias->d_flags & DCACHE_DISCONNECTED)) { discon_alias = alias; - } else { + } else if (!want_discon) { __dget_dlock(alias); spin_unlock(&alias->d_lock); return alias; @@ -736,7 +739,7 @@ struct dentry *d_find_alias(struct inode *inode) if (!list_empty(&inode->i_dentry)) { spin_lock(&inode->i_lock); - de = __d_find_alias(inode); + de = __d_find_alias(inode, 0); spin_unlock(&inode->i_lock); } return de; @@ -1647,8 +1650,9 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) if (inode && S_ISDIR(inode->i_mode)) { spin_lock(&inode->i_lock); - new = __d_find_any_alias(inode); + new = __d_find_alias(inode, 1); if (new) { + BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); spin_unlock(&inode->i_lock); security_d_instantiate(new, inode); d_move(new, dentry); @@ -2478,7 +2482,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) struct dentry *alias; /* Does an aliased dentry already exist? */ - alias = __d_find_alias(inode); + alias = __d_find_alias(inode, 0); if (alias) { actual = alias; write_seqlock(&rename_lock); diff --git a/trunk/fs/ext4/balloc.c b/trunk/fs/ext4/balloc.c index 99b6324290db..cee7812cc3cf 100644 --- a/trunk/fs/ext4/balloc.c +++ b/trunk/fs/ext4/balloc.c @@ -90,8 +90,8 @@ unsigned ext4_num_overhead_clusters(struct super_block *sb, * unusual file system layouts. */ if (ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp), block_group)) { - block_cluster = EXT4_B2C(sbi, (start - - ext4_block_bitmap(sb, gdp))); + block_cluster = EXT4_B2C(sbi, + ext4_block_bitmap(sb, gdp) - start); if (block_cluster < num_clusters) block_cluster = -1; else if (block_cluster == num_clusters) { @@ -102,7 +102,7 @@ unsigned ext4_num_overhead_clusters(struct super_block *sb, if (ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp), block_group)) { inode_cluster = EXT4_B2C(sbi, - start - ext4_inode_bitmap(sb, gdp)); + ext4_inode_bitmap(sb, gdp) - start); if (inode_cluster < num_clusters) inode_cluster = -1; else if (inode_cluster == num_clusters) { @@ -114,7 +114,7 @@ unsigned ext4_num_overhead_clusters(struct super_block *sb, itbl_blk = ext4_inode_table(sb, gdp); for (i = 0; i < sbi->s_itb_per_group; i++) { if (ext4_block_in_group(sb, itbl_blk + i, block_group)) { - c = EXT4_B2C(sbi, start - itbl_blk + i); + c = EXT4_B2C(sbi, itbl_blk + i - start); if ((c < num_clusters) || (c == inode_cluster) || (c == block_cluster) || (c == itbl_cluster)) continue; diff --git a/trunk/fs/ext4/ioctl.c b/trunk/fs/ext4/ioctl.c index 8ad112ae0ade..e34deac3f366 100644 --- a/trunk/fs/ext4/ioctl.c +++ b/trunk/fs/ext4/ioctl.c @@ -123,7 +123,6 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) else ext4_clear_inode_flag(inode, i); } - ei->i_flags = flags; ext4_set_inode_flags(inode); inode->i_ctime = ext4_current_time(inode); diff --git a/trunk/fs/fuse/control.c b/trunk/fs/fuse/control.c index 42593c587d48..03ff5b1eba93 100644 --- a/trunk/fs/fuse/control.c +++ b/trunk/fs/fuse/control.c @@ -75,19 +75,13 @@ static ssize_t fuse_conn_limit_write(struct file *file, const char __user *buf, unsigned global_limit) { unsigned long t; - char tmp[32]; unsigned limit = (1 << 16) - 1; int err; - if (*ppos || count >= sizeof(tmp) - 1) - return -EINVAL; - - if (copy_from_user(tmp, buf, count)) + if (*ppos) return -EINVAL; - tmp[count] = '\0'; - - err = strict_strtoul(tmp, 0, &t); + err = kstrtoul_from_user(buf, count, 0, &t); if (err) return err; diff --git a/trunk/fs/fuse/dir.c b/trunk/fs/fuse/dir.c index df5ac048dc74..334e0b18a014 100644 --- a/trunk/fs/fuse/dir.c +++ b/trunk/fs/fuse/dir.c @@ -775,6 +775,8 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, struct kstat *stat) { + unsigned int blkbits; + stat->dev = inode->i_sb->s_dev; stat->ino = attr->ino; stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); @@ -790,7 +792,13 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, stat->ctime.tv_nsec = attr->ctimensec; stat->size = attr->size; stat->blocks = attr->blocks; - stat->blksize = (1 << inode->i_blkbits); + + if (attr->blksize != 0) + blkbits = ilog2(attr->blksize); + else + blkbits = inode->i_sb->s_blocksize_bits; + + stat->blksize = 1 << blkbits; } static int fuse_do_getattr(struct inode *inode, struct kstat *stat, @@ -863,6 +871,7 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat, if (stat) { generic_fillattr(inode, stat); stat->mode = fi->orig_i_mode; + stat->ino = fi->orig_ino; } } diff --git a/trunk/fs/fuse/file.c b/trunk/fs/fuse/file.c index 9562109d3a87..b321a688cde7 100644 --- a/trunk/fs/fuse/file.c +++ b/trunk/fs/fuse/file.c @@ -2173,6 +2173,44 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, return ret; } +long fuse_file_fallocate(struct file *file, int mode, loff_t offset, + loff_t length) +{ + struct fuse_file *ff = file->private_data; + struct fuse_conn *fc = ff->fc; + struct fuse_req *req; + struct fuse_fallocate_in inarg = { + .fh = ff->fh, + .offset = offset, + .length = length, + .mode = mode + }; + int err; + + if (fc->no_fallocate) + return -EOPNOTSUPP; + + req = fuse_get_req(fc); + if (IS_ERR(req)) + return PTR_ERR(req); + + req->in.h.opcode = FUSE_FALLOCATE; + req->in.h.nodeid = ff->nodeid; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + fuse_request_send(fc, req); + err = req->out.h.error; + if (err == -ENOSYS) { + fc->no_fallocate = 1; + err = -EOPNOTSUPP; + } + fuse_put_request(fc, req); + + return err; +} +EXPORT_SYMBOL_GPL(fuse_file_fallocate); + static const struct file_operations fuse_file_operations = { .llseek = fuse_file_llseek, .read = do_sync_read, @@ -2190,6 +2228,7 @@ static const struct file_operations fuse_file_operations = { .unlocked_ioctl = fuse_file_ioctl, .compat_ioctl = fuse_file_compat_ioctl, .poll = fuse_file_poll, + .fallocate = fuse_file_fallocate, }; static const struct file_operations fuse_direct_io_file_operations = { @@ -2206,6 +2245,7 @@ static const struct file_operations fuse_direct_io_file_operations = { .unlocked_ioctl = fuse_file_ioctl, .compat_ioctl = fuse_file_compat_ioctl, .poll = fuse_file_poll, + .fallocate = fuse_file_fallocate, /* no splice_read */ }; diff --git a/trunk/fs/fuse/fuse_i.h b/trunk/fs/fuse/fuse_i.h index 572cefc78012..771fb6322c07 100644 --- a/trunk/fs/fuse/fuse_i.h +++ b/trunk/fs/fuse/fuse_i.h @@ -82,6 +82,9 @@ struct fuse_inode { preserve the original mode */ umode_t orig_i_mode; + /** 64 bit inode number */ + u64 orig_ino; + /** Version of last attribute change */ u64 attr_version; @@ -478,6 +481,9 @@ struct fuse_conn { /** Are BSD file locking primitives not implemented by fs? */ unsigned no_flock:1; + /** Is fallocate not implemented by fs? */ + unsigned no_fallocate:1; + /** The number of requests waiting for completion */ atomic_t num_waiting; diff --git a/trunk/fs/fuse/inode.c b/trunk/fs/fuse/inode.c index 42678a33b7bb..1cd61652018c 100644 --- a/trunk/fs/fuse/inode.c +++ b/trunk/fs/fuse/inode.c @@ -91,6 +91,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) fi->nlookup = 0; fi->attr_version = 0; fi->writectr = 0; + fi->orig_ino = 0; INIT_LIST_HEAD(&fi->write_files); INIT_LIST_HEAD(&fi->queued_writes); INIT_LIST_HEAD(&fi->writepages); @@ -139,6 +140,18 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) return 0; } +/* + * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down + * so that it will fit. + */ +static ino_t fuse_squash_ino(u64 ino64) +{ + ino_t ino = (ino_t) ino64; + if (sizeof(ino_t) < sizeof(u64)) + ino ^= ino64 >> (sizeof(u64) - sizeof(ino_t)) * 8; + return ino; +} + void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, u64 attr_valid) { @@ -148,7 +161,7 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, fi->attr_version = ++fc->attr_version; fi->i_time = attr_valid; - inode->i_ino = attr->ino; + inode->i_ino = fuse_squash_ino(attr->ino); inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); set_nlink(inode, attr->nlink); inode->i_uid = attr->uid; @@ -174,6 +187,8 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, fi->orig_i_mode = inode->i_mode; if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) inode->i_mode &= ~S_ISVTX; + + fi->orig_ino = attr->ino; } void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, diff --git a/trunk/fs/proc/base.c b/trunk/fs/proc/base.c index 616f41a7cde6..437195f204e1 100644 --- a/trunk/fs/proc/base.c +++ b/trunk/fs/proc/base.c @@ -1803,7 +1803,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) rcu_read_lock(); file = fcheck_files(files, fd); if (file) { - unsigned i_mode, f_mode = file->f_mode; + unsigned f_mode = file->f_mode; rcu_read_unlock(); put_files_struct(files); @@ -1819,12 +1819,14 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) inode->i_gid = GLOBAL_ROOT_GID; } - i_mode = S_IFLNK; - if (f_mode & FMODE_READ) - i_mode |= S_IRUSR | S_IXUSR; - if (f_mode & FMODE_WRITE) - i_mode |= S_IWUSR | S_IXUSR; - inode->i_mode = i_mode; + if (S_ISLNK(inode->i_mode)) { + unsigned i_mode = S_IFLNK; + if (f_mode & FMODE_READ) + i_mode |= S_IRUSR | S_IXUSR; + if (f_mode & FMODE_WRITE) + i_mode |= S_IWUSR | S_IXUSR; + inode->i_mode = i_mode; + } security_task_to_inode(task, inode); put_task_struct(task); @@ -1859,6 +1861,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir, ei = PROC_I(inode); ei->fd = fd; + inode->i_mode = S_IFLNK; inode->i_op = &proc_pid_link_inode_operations; inode->i_size = 64; ei->op.proc_get_link = proc_fd_link; diff --git a/trunk/fs/ubifs/debug.c b/trunk/fs/ubifs/debug.c index 685a83756b2b..84a7e6f3c046 100644 --- a/trunk/fs/ubifs/debug.c +++ b/trunk/fs/ubifs/debug.c @@ -2918,6 +2918,9 @@ int dbg_debugfs_init_fs(struct ubifs_info *c) struct dentry *dent; struct ubifs_debug_info *d = c->dbg; + if (!IS_ENABLED(DEBUG_FS)) + return 0; + n = snprintf(d->dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME, c->vi.ubi_num, c->vi.vol_id); if (n == UBIFS_DFS_DIR_LEN) { @@ -3010,7 +3013,8 @@ int dbg_debugfs_init_fs(struct ubifs_info *c) */ void dbg_debugfs_exit_fs(struct ubifs_info *c) { - debugfs_remove_recursive(c->dbg->dfs_dir); + if (IS_ENABLED(DEBUG_FS)) + debugfs_remove_recursive(c->dbg->dfs_dir); } struct ubifs_global_debug_info ubifs_dbg; @@ -3095,6 +3099,9 @@ int dbg_debugfs_init(void) const char *fname; struct dentry *dent; + if (!IS_ENABLED(DEBUG_FS)) + return 0; + fname = "ubifs"; dent = debugfs_create_dir(fname, NULL); if (IS_ERR_OR_NULL(dent)) @@ -3159,7 +3166,8 @@ int dbg_debugfs_init(void) */ void dbg_debugfs_exit(void) { - debugfs_remove_recursive(dfs_rootdir); + if (IS_ENABLED(DEBUG_FS)) + debugfs_remove_recursive(dfs_rootdir); } /** diff --git a/trunk/include/acpi/acpi_bus.h b/trunk/include/acpi/acpi_bus.h index b0d62820ada1..9e6e1c6eb60a 100644 --- a/trunk/include/acpi/acpi_bus.h +++ b/trunk/include/acpi/acpi_bus.h @@ -440,8 +440,8 @@ static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable) #else /* CONFIG_ACPI */ -static int register_acpi_bus_type(struct acpi_bus_type *bus) { return 0; } -static int unregister_acpi_bus_type(struct acpi_bus_type *bus) { return 0; } +static inline int register_acpi_bus_type(void *bus) { return 0; } +static inline int unregister_acpi_bus_type(void *bus) { return 0; } #endif /* CONFIG_ACPI */ diff --git a/trunk/include/drm/drm_pciids.h b/trunk/include/drm/drm_pciids.h index 58d0bdab68dd..81368ab6c611 100644 --- a/trunk/include/drm/drm_pciids.h +++ b/trunk/include/drm/drm_pciids.h @@ -181,6 +181,7 @@ {0x1002, 0x6747, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6748, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x674A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6758, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ @@ -198,6 +199,7 @@ {0x1002, 0x6767, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6768, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6770, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6771, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6778, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6779, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ @@ -229,10 +231,11 @@ {0x1002, 0x6827, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ - {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ - {0x1002, 0x6831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ @@ -531,6 +534,7 @@ {0x1002, 0x9645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ {0x1002, 0x9648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ + {0x1002, 0x9649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ {0x1002, 0x964a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x964b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x964c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ @@ -550,6 +554,7 @@ {0x1002, 0x9807, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x980A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ @@ -561,11 +566,19 @@ {0x1002, 0x9909, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x990A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x990F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9910, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9913, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9917, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9918, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9990, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9991, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9993, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9994, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x99A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x99A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x99A4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0, 0, 0} #define r128_PCI_IDS \ diff --git a/trunk/include/drm/exynos_drm.h b/trunk/include/drm/exynos_drm.h index b6d7ce92eadd..68733587e700 100644 --- a/trunk/include/drm/exynos_drm.h +++ b/trunk/include/drm/exynos_drm.h @@ -64,6 +64,7 @@ struct drm_exynos_gem_map_off { * A structure for mapping buffer. * * @handle: a handle to gem object created. + * @pad: just padding to be 64-bit aligned. * @size: memory size to be mapped. * @mapped: having user virtual address mmaped. * - this variable would be filled by exynos gem module @@ -72,7 +73,8 @@ struct drm_exynos_gem_map_off { */ struct drm_exynos_gem_mmap { unsigned int handle; - unsigned int size; + unsigned int pad; + uint64_t size; uint64_t mapped; }; diff --git a/trunk/include/linux/clockchips.h b/trunk/include/linux/clockchips.h index 81e803e90aa4..acba894374a1 100644 --- a/trunk/include/linux/clockchips.h +++ b/trunk/include/linux/clockchips.h @@ -132,6 +132,7 @@ extern u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt); extern void clockevents_register_device(struct clock_event_device *dev); +extern void clockevents_config(struct clock_event_device *dev, u32 freq); extern void clockevents_config_and_register(struct clock_event_device *dev, u32 freq, unsigned long min_delta, unsigned long max_delta); diff --git a/trunk/include/linux/compaction.h b/trunk/include/linux/compaction.h index e988037abd2a..51a90b7f2d60 100644 --- a/trunk/include/linux/compaction.h +++ b/trunk/include/linux/compaction.h @@ -1,8 +1,6 @@ #ifndef _LINUX_COMPACTION_H #define _LINUX_COMPACTION_H -#include - /* Return values for compact_zone() and try_to_compact_pages() */ /* compaction didn't start as it was not possible or direct reclaim was more suitable */ #define COMPACT_SKIPPED 0 @@ -13,23 +11,6 @@ /* The full zone was compacted */ #define COMPACT_COMPLETE 3 -/* - * compaction supports three modes - * - * COMPACT_ASYNC_MOVABLE uses asynchronous migration and only scans - * MIGRATE_MOVABLE pageblocks as migration sources and targets. - * COMPACT_ASYNC_UNMOVABLE uses asynchronous migration and only scans - * MIGRATE_MOVABLE pageblocks as migration sources. - * MIGRATE_UNMOVABLE pageblocks are scanned as potential migration - * targets and convers them to MIGRATE_MOVABLE if possible - * COMPACT_SYNC uses synchronous migration and scans all pageblocks - */ -enum compact_mode { - COMPACT_ASYNC_MOVABLE, - COMPACT_ASYNC_UNMOVABLE, - COMPACT_SYNC, -}; - #ifdef CONFIG_COMPACTION extern int sysctl_compact_memory; extern int sysctl_compaction_handler(struct ctl_table *table, int write, diff --git a/trunk/include/linux/frontswap.h b/trunk/include/linux/frontswap.h new file mode 100644 index 000000000000..0e4e2eec5c1d --- /dev/null +++ b/trunk/include/linux/frontswap.h @@ -0,0 +1,127 @@ +#ifndef _LINUX_FRONTSWAP_H +#define _LINUX_FRONTSWAP_H + +#include +#include +#include + +struct frontswap_ops { + void (*init)(unsigned); + int (*store)(unsigned, pgoff_t, struct page *); + int (*load)(unsigned, pgoff_t, struct page *); + void (*invalidate_page)(unsigned, pgoff_t); + void (*invalidate_area)(unsigned); +}; + +extern bool frontswap_enabled; +extern struct frontswap_ops + frontswap_register_ops(struct frontswap_ops *ops); +extern void frontswap_shrink(unsigned long); +extern unsigned long frontswap_curr_pages(void); +extern void frontswap_writethrough(bool); + +extern void __frontswap_init(unsigned type); +extern int __frontswap_store(struct page *page); +extern int __frontswap_load(struct page *page); +extern void __frontswap_invalidate_page(unsigned, pgoff_t); +extern void __frontswap_invalidate_area(unsigned); + +#ifdef CONFIG_FRONTSWAP + +static inline bool frontswap_test(struct swap_info_struct *sis, pgoff_t offset) +{ + bool ret = false; + + if (frontswap_enabled && sis->frontswap_map) + ret = test_bit(offset, sis->frontswap_map); + return ret; +} + +static inline void frontswap_set(struct swap_info_struct *sis, pgoff_t offset) +{ + if (frontswap_enabled && sis->frontswap_map) + set_bit(offset, sis->frontswap_map); +} + +static inline void frontswap_clear(struct swap_info_struct *sis, pgoff_t offset) +{ + if (frontswap_enabled && sis->frontswap_map) + clear_bit(offset, sis->frontswap_map); +} + +static inline void frontswap_map_set(struct swap_info_struct *p, + unsigned long *map) +{ + p->frontswap_map = map; +} + +static inline unsigned long *frontswap_map_get(struct swap_info_struct *p) +{ + return p->frontswap_map; +} +#else +/* all inline routines become no-ops and all externs are ignored */ + +#define frontswap_enabled (0) + +static inline bool frontswap_test(struct swap_info_struct *sis, pgoff_t offset) +{ + return false; +} + +static inline void frontswap_set(struct swap_info_struct *sis, pgoff_t offset) +{ +} + +static inline void frontswap_clear(struct swap_info_struct *sis, pgoff_t offset) +{ +} + +static inline void frontswap_map_set(struct swap_info_struct *p, + unsigned long *map) +{ +} + +static inline unsigned long *frontswap_map_get(struct swap_info_struct *p) +{ + return NULL; +} +#endif + +static inline int frontswap_store(struct page *page) +{ + int ret = -1; + + if (frontswap_enabled) + ret = __frontswap_store(page); + return ret; +} + +static inline int frontswap_load(struct page *page) +{ + int ret = -1; + + if (frontswap_enabled) + ret = __frontswap_load(page); + return ret; +} + +static inline void frontswap_invalidate_page(unsigned type, pgoff_t offset) +{ + if (frontswap_enabled) + __frontswap_invalidate_page(type, offset); +} + +static inline void frontswap_invalidate_area(unsigned type) +{ + if (frontswap_enabled) + __frontswap_invalidate_area(type); +} + +static inline void frontswap_init(unsigned type) +{ + if (frontswap_enabled) + __frontswap_init(type); +} + +#endif /* _LINUX_FRONTSWAP_H */ diff --git a/trunk/include/linux/fs.h b/trunk/include/linux/fs.h index 51978ed43e97..17fd887c798f 100644 --- a/trunk/include/linux/fs.h +++ b/trunk/include/linux/fs.h @@ -802,13 +802,14 @@ struct inode { unsigned int __i_nlink; }; dev_t i_rdev; + loff_t i_size; struct timespec i_atime; struct timespec i_mtime; struct timespec i_ctime; spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ unsigned short i_bytes; + unsigned int i_blkbits; blkcnt_t i_blocks; - loff_t i_size; #ifdef __NEED_I_SIZE_ORDERED seqcount_t i_size_seqcount; @@ -828,9 +829,8 @@ struct inode { struct list_head i_dentry; struct rcu_head i_rcu; }; - atomic_t i_count; - unsigned int i_blkbits; u64 i_version; + atomic_t i_count; atomic_t i_dio_count; atomic_t i_writecount; const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ diff --git a/trunk/include/linux/fuse.h b/trunk/include/linux/fuse.h index 8f2ab8fef929..9303348965fb 100644 --- a/trunk/include/linux/fuse.h +++ b/trunk/include/linux/fuse.h @@ -54,6 +54,9 @@ * 7.18 * - add FUSE_IOCTL_DIR flag * - add FUSE_NOTIFY_DELETE + * + * 7.19 + * - add FUSE_FALLOCATE */ #ifndef _LINUX_FUSE_H @@ -85,7 +88,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 18 +#define FUSE_KERNEL_MINOR_VERSION 19 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -278,6 +281,7 @@ enum fuse_opcode { FUSE_POLL = 40, FUSE_NOTIFY_REPLY = 41, FUSE_BATCH_FORGET = 42, + FUSE_FALLOCATE = 43, /* CUSE specific operations */ CUSE_INIT = 4096, @@ -571,6 +575,14 @@ struct fuse_notify_poll_wakeup_out { __u64 kh; }; +struct fuse_fallocate_in { + __u64 fh; + __u64 offset; + __u64 length; + __u32 mode; + __u32 padding; +}; + struct fuse_in_header { __u32 len; __u32 opcode; diff --git a/trunk/include/linux/i2c-mux-pinctrl.h b/trunk/include/linux/i2c-mux-pinctrl.h new file mode 100644 index 000000000000..a65c86429e84 --- /dev/null +++ b/trunk/include/linux/i2c-mux-pinctrl.h @@ -0,0 +1,41 @@ +/* + * i2c-mux-pinctrl platform data + * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _LINUX_I2C_MUX_PINCTRL_H +#define _LINUX_I2C_MUX_PINCTRL_H + +/** + * struct i2c_mux_pinctrl_platform_data - Platform data for i2c-mux-pinctrl + * @parent_bus_num: Parent I2C bus number + * @base_bus_num: Base I2C bus number for the child busses. 0 for dynamic. + * @bus_count: Number of child busses. Also the number of elements in + * @pinctrl_states + * @pinctrl_states: The names of the pinctrl state to select for each child bus + * @pinctrl_state_idle: The pinctrl state to select when no child bus is being + * accessed. If NULL, the most recently used pinctrl state will be left + * selected. + */ +struct i2c_mux_pinctrl_platform_data { + int parent_bus_num; + int base_bus_num; + int bus_count; + const char **pinctrl_states; + const char *pinctrl_state_idle; +}; + +#endif diff --git a/trunk/include/linux/init_task.h b/trunk/include/linux/init_task.h index e4baff5f7ff4..9e65eff6af3b 100644 --- a/trunk/include/linux/init_task.h +++ b/trunk/include/linux/init_task.h @@ -149,6 +149,7 @@ extern struct cred init_cred; .normal_prio = MAX_PRIO-20, \ .policy = SCHED_NORMAL, \ .cpus_allowed = CPU_MASK_ALL, \ + .nr_cpus_allowed= NR_CPUS, \ .mm = NULL, \ .active_mm = &init_mm, \ .se = { \ @@ -157,7 +158,6 @@ extern struct cred init_cred; .rt = { \ .run_list = LIST_HEAD_INIT(tsk.rt.run_list), \ .time_slice = RR_TIMESLICE, \ - .nr_cpus_allowed = NR_CPUS, \ }, \ .tasks = LIST_HEAD_INIT(tsk.tasks), \ INIT_PUSHABLE_TASKS(tsk) \ diff --git a/trunk/include/linux/mfd/abx500/ab8500-codec.h b/trunk/include/linux/mfd/abx500/ab8500-codec.h new file mode 100644 index 000000000000..dc6529202cdd --- /dev/null +++ b/trunk/include/linux/mfd/abx500/ab8500-codec.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) ST-Ericsson SA 2012 + * + * Author: Ola Lilja + * 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 AB8500_CORE_CODEC_H +#define AB8500_CORE_CODEC_H + +/* Mic-types */ +enum amic_type { + AMIC_TYPE_SINGLE_ENDED, + AMIC_TYPE_DIFFERENTIAL +}; + +/* Mic-biases */ +enum amic_micbias { + AMIC_MICBIAS_VAMIC1, + AMIC_MICBIAS_VAMIC2 +}; + +/* Bias-voltage */ +enum ear_cm_voltage { + EAR_CMV_0_95V, + EAR_CMV_1_10V, + EAR_CMV_1_27V, + EAR_CMV_1_58V +}; + +/* Analog microphone settings */ +struct amic_settings { + enum amic_type mic1_type; + enum amic_type mic2_type; + enum amic_micbias mic1a_micbias; + enum amic_micbias mic1b_micbias; + enum amic_micbias mic2_micbias; +}; + +/* Platform data structure for the audio-parts of the AB8500 */ +struct ab8500_codec_platform_data { + struct amic_settings amics; + enum ear_cm_voltage ear_cmv; +}; + +#endif diff --git a/trunk/include/linux/mfd/abx500/ab8500.h b/trunk/include/linux/mfd/abx500/ab8500.h index 91dd3ef63e99..bc9b84b60ec6 100644 --- a/trunk/include/linux/mfd/abx500/ab8500.h +++ b/trunk/include/linux/mfd/abx500/ab8500.h @@ -266,6 +266,7 @@ struct ab8500 { struct regulator_reg_init; struct regulator_init_data; struct ab8500_gpio_platform_data; +struct ab8500_codec_platform_data; /** * struct ab8500_platform_data - AB8500 platform data @@ -284,6 +285,7 @@ struct ab8500_platform_data { int num_regulator; struct regulator_init_data *regulator; struct ab8500_gpio_platform_data *gpio; + struct ab8500_codec_platform_data *codec; }; extern int __devinit ab8500_init(struct ab8500 *ab8500, diff --git a/trunk/include/linux/moduleparam.h b/trunk/include/linux/moduleparam.h index 1b14d25162cb..d6a58065c09c 100644 --- a/trunk/include/linux/moduleparam.h +++ b/trunk/include/linux/moduleparam.h @@ -128,7 +128,7 @@ struct kparam_array * The ops can have NULL set or get functions. */ #define module_param_cb(name, ops, arg, perm) \ - __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, 0) + __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1) /** * _param_cb - general callback for a module/cmdline parameter @@ -192,7 +192,7 @@ struct kparam_array { (void *)set, (void *)get }; \ __module_param_call(MODULE_PARAM_PREFIX, \ name, &__param_ops_##name, arg, \ - (perm) + sizeof(__check_old_set_param(set))*0, 0) + (perm) + sizeof(__check_old_set_param(set))*0, -1) /* We don't get oldget: it's often a new-style param_get_uint, etc. */ static inline int @@ -272,7 +272,7 @@ static inline void __kernel_param_unlock(void) */ #define core_param(name, var, type, perm) \ param_check_##type(name, &(var)); \ - __module_param_call("", name, ¶m_ops_##type, &var, perm, 0) + __module_param_call("", name, ¶m_ops_##type, &var, perm, -1) #endif /* !MODULE */ /** @@ -290,7 +290,7 @@ static inline void __kernel_param_unlock(void) = { len, string }; \ __module_param_call(MODULE_PARAM_PREFIX, name, \ ¶m_ops_string, \ - .str = &__param_string_##name, perm, 0); \ + .str = &__param_string_##name, perm, -1); \ __MODULE_PARM_TYPE(name, "string") /** @@ -432,7 +432,7 @@ extern int param_set_bint(const char *val, const struct kernel_param *kp); __module_param_call(MODULE_PARAM_PREFIX, name, \ ¶m_array_ops, \ .arr = &__param_arr_##name, \ - perm, 0); \ + perm, -1); \ __MODULE_PARM_TYPE(name, "array of " #type) extern struct kernel_param_ops param_array_ops; diff --git a/trunk/include/linux/perf_event.h b/trunk/include/linux/perf_event.h index f32578634d9d..45db49f64bb4 100644 --- a/trunk/include/linux/perf_event.h +++ b/trunk/include/linux/perf_event.h @@ -555,6 +555,8 @@ enum perf_event_type { PERF_RECORD_MAX, /* non-ABI */ }; +#define PERF_MAX_STACK_DEPTH 127 + enum perf_callchain_context { PERF_CONTEXT_HV = (__u64)-32, PERF_CONTEXT_KERNEL = (__u64)-128, @@ -609,8 +611,6 @@ struct perf_guest_info_callbacks { #include #include -#define PERF_MAX_STACK_DEPTH 255 - struct perf_callchain_entry { __u64 nr; __u64 ip[PERF_MAX_STACK_DEPTH]; diff --git a/trunk/include/linux/prctl.h b/trunk/include/linux/prctl.h index 711e0a30aacc..3988012255dc 100644 --- a/trunk/include/linux/prctl.h +++ b/trunk/include/linux/prctl.h @@ -127,8 +127,8 @@ #define PR_SET_PTRACER 0x59616d61 # define PR_SET_PTRACER_ANY ((unsigned long)-1) -#define PR_SET_CHILD_SUBREAPER 36 -#define PR_GET_CHILD_SUBREAPER 37 +#define PR_SET_CHILD_SUBREAPER 36 +#define PR_GET_CHILD_SUBREAPER 37 /* * If no_new_privs is set, then operations that grant new privileges (i.e. @@ -142,7 +142,9 @@ * asking selinux for a specific new context (e.g. with runcon) will result * in execve returning -EPERM. */ -#define PR_SET_NO_NEW_PRIVS 38 -#define PR_GET_NO_NEW_PRIVS 39 +#define PR_SET_NO_NEW_PRIVS 38 +#define PR_GET_NO_NEW_PRIVS 39 + +#define PR_GET_TID_ADDRESS 40 #endif /* _LINUX_PRCTL_H */ diff --git a/trunk/include/linux/radix-tree.h b/trunk/include/linux/radix-tree.h index 0d04cd69ab9b..ffc444c38b0a 100644 --- a/trunk/include/linux/radix-tree.h +++ b/trunk/include/linux/radix-tree.h @@ -368,8 +368,11 @@ radix_tree_next_slot(void **slot, struct radix_tree_iter *iter, unsigned flags) iter->index++; if (likely(*slot)) return slot; - if (flags & RADIX_TREE_ITER_CONTIG) + if (flags & RADIX_TREE_ITER_CONTIG) { + /* forbid switching to the next chunk */ + iter->next_index = 0; break; + } } } return NULL; diff --git a/trunk/include/linux/sched.h b/trunk/include/linux/sched.h index f34437e835a7..4059c0f33f07 100644 --- a/trunk/include/linux/sched.h +++ b/trunk/include/linux/sched.h @@ -145,6 +145,7 @@ extern unsigned long this_cpu_load(void); extern void calc_global_load(unsigned long ticks); +extern void update_cpu_load_nohz(void); extern unsigned long get_parent_ip(unsigned long addr); @@ -438,6 +439,7 @@ extern int get_dumpable(struct mm_struct *mm); /* leave room for more dump flags */ #define MMF_VM_MERGEABLE 16 /* KSM may merge identical pages */ #define MMF_VM_HUGEPAGE 17 /* set when VM_HUGEPAGE is set on vma */ +#define MMF_EXE_FILE_CHANGED 18 /* see prctl_set_mm_exe_file() */ #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK) @@ -875,6 +877,8 @@ struct sched_group_power { * Number of busy cpus in this group. */ atomic_t nr_busy_cpus; + + unsigned long cpumask[0]; /* iteration mask */ }; struct sched_group { @@ -899,6 +903,15 @@ static inline struct cpumask *sched_group_cpus(struct sched_group *sg) return to_cpumask(sg->cpumask); } +/* + * cpumask masking which cpus in the group are allowed to iterate up the domain + * tree. + */ +static inline struct cpumask *sched_group_mask(struct sched_group *sg) +{ + return to_cpumask(sg->sgp->cpumask); +} + /** * group_first_cpu - Returns the first cpu in the cpumask of a sched_group. * @group: The group whose first cpu is to be returned. @@ -1187,7 +1200,6 @@ struct sched_rt_entity { struct list_head run_list; unsigned long timeout; unsigned int time_slice; - int nr_cpus_allowed; struct sched_rt_entity *back; #ifdef CONFIG_RT_GROUP_SCHED @@ -1252,6 +1264,7 @@ struct task_struct { #endif unsigned int policy; + int nr_cpus_allowed; cpumask_t cpus_allowed; #ifdef CONFIG_PREEMPT_RCU diff --git a/trunk/include/linux/swap.h b/trunk/include/linux/swap.h index b6661933e252..c84ec68eaec9 100644 --- a/trunk/include/linux/swap.h +++ b/trunk/include/linux/swap.h @@ -197,6 +197,10 @@ struct swap_info_struct { struct block_device *bdev; /* swap device or bdev of swap file */ struct file *swap_file; /* seldom referenced */ unsigned int old_block_size; /* seldom referenced */ +#ifdef CONFIG_FRONTSWAP + unsigned long *frontswap_map; /* frontswap in-use, one bit per page */ + atomic_t frontswap_pages; /* frontswap pages in-use counter */ +#endif }; struct swap_list_t { diff --git a/trunk/include/linux/swapfile.h b/trunk/include/linux/swapfile.h new file mode 100644 index 000000000000..e282624e8c10 --- /dev/null +++ b/trunk/include/linux/swapfile.h @@ -0,0 +1,13 @@ +#ifndef _LINUX_SWAPFILE_H +#define _LINUX_SWAPFILE_H + +/* + * these were static in swapfile.c but frontswap.c needs them and we don't + * want to expose them to the dozens of source files that include swap.h + */ +extern spinlock_t swap_lock; +extern struct swap_list_t swap_list; +extern struct swap_info_struct *swap_info[]; +extern int try_to_unuse(unsigned int, bool, unsigned long); + +#endif /* _LINUX_SWAPFILE_H */ diff --git a/trunk/include/sound/pcm.h b/trunk/include/sound/pcm.h index a55d5db7eb5a..0d1112815be3 100644 --- a/trunk/include/sound/pcm.h +++ b/trunk/include/sound/pcm.h @@ -1073,15 +1073,4 @@ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max) const char *snd_pcm_format_name(snd_pcm_format_t format); -/** - * Get a string naming the direction of a stream - */ -static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream) -{ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return "Playback"; - else - return "Capture"; -} - #endif /* __SOUND_PCM_H */ diff --git a/trunk/include/sound/soc-dapm.h b/trunk/include/sound/soc-dapm.h index 05559e571d44..e3833d9f1914 100644 --- a/trunk/include/sound/soc-dapm.h +++ b/trunk/include/sound/soc-dapm.h @@ -229,10 +229,6 @@ struct device; { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ .shift = wshift, .invert = winvert, \ .event = wevent, .event_flags = wflags} -#define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \ -{ .id = snd_soc_dapm_clock_supply, .name = wname, \ - .reg = SND_SOC_NOPM, .event = dapm_clock_event, \ - .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD } /* generic widgets */ #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \ @@ -249,7 +245,6 @@ struct device; .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD } - /* dapm kcontrol types */ #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ @@ -332,8 +327,6 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); int dapm_regulator_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -int dapm_clock_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event); /* dapm controls */ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, @@ -439,7 +432,6 @@ enum snd_soc_dapm_type { snd_soc_dapm_post, /* machine specific post widget - exec last */ snd_soc_dapm_supply, /* power/clock supply */ snd_soc_dapm_regulator_supply, /* external regulator */ - snd_soc_dapm_clock_supply, /* external clock */ snd_soc_dapm_aif_in, /* audio interface input */ snd_soc_dapm_aif_out, /* audio interface output */ snd_soc_dapm_siggen, /* signal generator */ @@ -545,8 +537,6 @@ struct snd_soc_dapm_widget { struct list_head dirty; int inputs; int outputs; - - struct clk *clk; }; struct snd_soc_dapm_update { diff --git a/trunk/include/sound/soc.h b/trunk/include/sound/soc.h index e4348d25fca3..c703871f5f65 100644 --- a/trunk/include/sound/soc.h +++ b/trunk/include/sound/soc.h @@ -47,13 +47,6 @@ .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_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ - .info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \ - .put = snd_soc_put_volsw_range, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = xreg, .shift = xshift, .min = xmin,\ - .max = xmax, .platform_max = xmax, .invert = xinvert} } #define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ @@ -74,16 +67,6 @@ {.reg = xreg, .rreg = xreg, \ .shift = xshift, .rshift = xshift, \ .max = xmax, .min = xmin} } -#define SOC_SINGLE_RANGE_TLV(xname, xreg, xshift, xmin, xmax, xinvert, 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_range, \ - .get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = xreg, .shift = xshift, .min = xmin,\ - .max = xmax, .platform_max = xmax, .invert = xinvert} } #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, \ @@ -477,12 +460,6 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo); -int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_soc_get_volsw_range(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_bytes_info(struct snd_kcontrol *kcontrol, @@ -808,36 +785,13 @@ struct snd_soc_dai_link { /* config - must be set by machine driver */ const char *name; /* Codec name */ const char *stream_name; /* Stream name */ - /* - * You MAY specify the link's CPU-side device, either by device name, - * or by DT/OF node, but not both. If this information is omitted, - * the CPU-side DAI is matched using .cpu_dai_name only, which hence - * must be globally unique. These fields are currently typically used - * only for codec to codec links, or systems using device tree. - */ - const char *cpu_name; - const struct device_node *cpu_of_node; - /* - * You MAY specify the DAI name of the CPU DAI. If this information is - * omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node - * only, which only works well when that device exposes a single DAI. - */ - const char *cpu_dai_name; - /* - * You MUST specify the link's codec, either by device name, or by - * DT/OF node, but not both. - */ - const char *codec_name; + const char *codec_name; /* for multi-codec */ const struct device_node *codec_of_node; - /* You MUST specify the DAI name within the codec */ - const char *codec_dai_name; - /* - * You MAY specify the link's platform/PCM/DMA driver, either by - * device name, or by DT/OF node, but not both. Some forms of link - * do not need a platform. - */ - const char *platform_name; + const char *platform_name; /* for multi-platform */ const struct device_node *platform_of_node; + const char *cpu_dai_name; + const struct device_node *cpu_dai_of_node; + const char *codec_dai_name; int be_id; /* optional ID for machine driver BE identification */ const struct snd_soc_pcm_stream *params; diff --git a/trunk/init/main.c b/trunk/init/main.c index 1ca6b32c4828..b5cc0a7c4708 100644 --- a/trunk/init/main.c +++ b/trunk/init/main.c @@ -508,7 +508,7 @@ asmlinkage void __init start_kernel(void) parse_early_param(); parse_args("Booting kernel", static_command_line, __start___param, __stop___param - __start___param, - 0, 0, &unknown_bootoption); + -1, -1, &unknown_bootoption); jump_label_init(); @@ -755,13 +755,8 @@ static void __init do_initcalls(void) { int level; - for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) { - pr_info("initlevel:%d=%s, %d registered initcalls\n", - level, initcall_level_names[level], - (int) (initcall_levels[level+1] - - initcall_levels[level])); + for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) do_initcall_level(level); - } } /* diff --git a/trunk/ipc/shm.c b/trunk/ipc/shm.c index 5e2cbfdab6fc..41c1285d697a 100644 --- a/trunk/ipc/shm.c +++ b/trunk/ipc/shm.c @@ -393,6 +393,16 @@ static int shm_fsync(struct file *file, loff_t start, loff_t end, int datasync) return sfd->file->f_op->fsync(sfd->file, start, end, datasync); } +static long shm_fallocate(struct file *file, int mode, loff_t offset, + loff_t len) +{ + struct shm_file_data *sfd = shm_file_data(file); + + if (!sfd->file->f_op->fallocate) + return -EOPNOTSUPP; + return sfd->file->f_op->fallocate(file, mode, offset, len); +} + static unsigned long shm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) @@ -410,6 +420,7 @@ static const struct file_operations shm_file_operations = { .get_unmapped_area = shm_get_unmapped_area, #endif .llseek = noop_llseek, + .fallocate = shm_fallocate, }; static const struct file_operations shm_file_operations_huge = { @@ -418,6 +429,7 @@ static const struct file_operations shm_file_operations_huge = { .release = shm_release, .get_unmapped_area = shm_get_unmapped_area, .llseek = noop_llseek, + .fallocate = shm_fallocate, }; int is_file_shm_hugepages(struct file *file) diff --git a/trunk/kernel/cgroup.c b/trunk/kernel/cgroup.c index 0f3527d6184a..72fcd3069a90 100644 --- a/trunk/kernel/cgroup.c +++ b/trunk/kernel/cgroup.c @@ -896,10 +896,13 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode) mutex_unlock(&cgroup_mutex); /* - * Drop the active superblock reference that we took when we - * created the cgroup + * We want to drop the active superblock reference from the + * cgroup creation after all the dentry refs are gone - + * kill_sb gets mighty unhappy otherwise. Mark + * dentry->d_fsdata with cgroup_diput() to tell + * cgroup_d_release() to call deactivate_super(). */ - deactivate_super(cgrp->root->sb); + dentry->d_fsdata = cgroup_diput; /* * if we're getting rid of the cgroup, refcount should ensure @@ -925,6 +928,13 @@ static int cgroup_delete(const struct dentry *d) return 1; } +static void cgroup_d_release(struct dentry *dentry) +{ + /* did cgroup_diput() tell me to deactivate super? */ + if (dentry->d_fsdata == cgroup_diput) + deactivate_super(dentry->d_sb); +} + static void remove_dir(struct dentry *d) { struct dentry *parent = dget(d->d_parent); @@ -1532,6 +1542,7 @@ static int cgroup_get_rootdir(struct super_block *sb) static const struct dentry_operations cgroup_dops = { .d_iput = cgroup_diput, .d_delete = cgroup_delete, + .d_release = cgroup_d_release, }; struct inode *inode = diff --git a/trunk/kernel/events/core.c b/trunk/kernel/events/core.c index 5b06cbbf6931..f85c0154b333 100644 --- a/trunk/kernel/events/core.c +++ b/trunk/kernel/events/core.c @@ -3181,7 +3181,6 @@ static void perf_event_for_each(struct perf_event *event, event = event->group_leader; perf_event_for_each_child(event, func); - func(event); list_for_each_entry(sibling, &event->sibling_list, group_entry) perf_event_for_each_child(sibling, func); mutex_unlock(&ctx->mutex); diff --git a/trunk/kernel/irq/chip.c b/trunk/kernel/irq/chip.c index fc275e4f629b..eebd6d5cfb44 100644 --- a/trunk/kernel/irq/chip.c +++ b/trunk/kernel/irq/chip.c @@ -275,8 +275,10 @@ void handle_nested_irq(unsigned int irq) kstat_incr_irqs_this_cpu(irq, desc); action = desc->action; - if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) + if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) { + desc->istate |= IRQS_PENDING; goto out_unlock; + } irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); raw_spin_unlock_irq(&desc->lock); @@ -324,8 +326,10 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc) desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); kstat_incr_irqs_this_cpu(irq, desc); - if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) + if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { + desc->istate |= IRQS_PENDING; goto out_unlock; + } handle_irq_event(desc); diff --git a/trunk/kernel/irq/internals.h b/trunk/kernel/irq/internals.h index 8e5c56b3b7d9..001fa5bab490 100644 --- a/trunk/kernel/irq/internals.h +++ b/trunk/kernel/irq/internals.h @@ -101,6 +101,9 @@ extern int irq_select_affinity_usr(unsigned int irq, struct cpumask *mask); extern void irq_set_thread_affinity(struct irq_desc *desc); +extern int irq_do_set_affinity(struct irq_data *data, + const struct cpumask *dest, bool force); + /* Inline functions for support of irq chips on slow busses */ static inline void chip_bus_lock(struct irq_desc *desc) { diff --git a/trunk/kernel/irq/manage.c b/trunk/kernel/irq/manage.c index ea0c6c2ae6f7..8c548232ba39 100644 --- a/trunk/kernel/irq/manage.c +++ b/trunk/kernel/irq/manage.c @@ -142,6 +142,25 @@ static inline void irq_get_pending(struct cpumask *mask, struct irq_desc *desc) { } #endif +int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask, + bool force) +{ + struct irq_desc *desc = irq_data_to_desc(data); + struct irq_chip *chip = irq_data_get_irq_chip(data); + int ret; + + ret = chip->irq_set_affinity(data, mask, false); + switch (ret) { + case IRQ_SET_MASK_OK: + cpumask_copy(data->affinity, mask); + case IRQ_SET_MASK_OK_NOCOPY: + irq_set_thread_affinity(desc); + ret = 0; + } + + return ret; +} + int __irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask) { struct irq_chip *chip = irq_data_get_irq_chip(data); @@ -152,14 +171,7 @@ int __irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask) return -EINVAL; if (irq_can_move_pcntxt(data)) { - ret = chip->irq_set_affinity(data, mask, false); - switch (ret) { - case IRQ_SET_MASK_OK: - cpumask_copy(data->affinity, mask); - case IRQ_SET_MASK_OK_NOCOPY: - irq_set_thread_affinity(desc); - ret = 0; - } + ret = irq_do_set_affinity(data, mask, false); } else { irqd_set_move_pending(data); irq_copy_pending(desc, mask); @@ -283,9 +295,8 @@ EXPORT_SYMBOL_GPL(irq_set_affinity_notifier); static int setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask) { - struct irq_chip *chip = irq_desc_get_chip(desc); struct cpumask *set = irq_default_affinity; - int ret, node = desc->irq_data.node; + int node = desc->irq_data.node; /* Excludes PER_CPU and NO_BALANCE interrupts */ if (!irq_can_set_affinity(irq)) @@ -311,13 +322,7 @@ setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask) if (cpumask_intersects(mask, nodemask)) cpumask_and(mask, mask, nodemask); } - ret = chip->irq_set_affinity(&desc->irq_data, mask, false); - switch (ret) { - case IRQ_SET_MASK_OK: - cpumask_copy(desc->irq_data.affinity, mask); - case IRQ_SET_MASK_OK_NOCOPY: - irq_set_thread_affinity(desc); - } + irq_do_set_affinity(&desc->irq_data, mask, false); return 0; } #else diff --git a/trunk/kernel/irq/migration.c b/trunk/kernel/irq/migration.c index c3c89751b327..ca3f4aaff707 100644 --- a/trunk/kernel/irq/migration.c +++ b/trunk/kernel/irq/migration.c @@ -42,17 +42,8 @@ void irq_move_masked_irq(struct irq_data *idata) * For correct operation this depends on the caller * masking the irqs. */ - if (likely(cpumask_any_and(desc->pending_mask, cpu_online_mask) - < nr_cpu_ids)) { - int ret = chip->irq_set_affinity(&desc->irq_data, - desc->pending_mask, false); - switch (ret) { - case IRQ_SET_MASK_OK: - cpumask_copy(desc->irq_data.affinity, desc->pending_mask); - case IRQ_SET_MASK_OK_NOCOPY: - irq_set_thread_affinity(desc); - } - } + if (cpumask_any_and(desc->pending_mask, cpu_online_mask) < nr_cpu_ids) + irq_do_set_affinity(&desc->irq_data, desc->pending_mask, false); cpumask_clear(desc->pending_mask); } diff --git a/trunk/kernel/sched/core.c b/trunk/kernel/sched/core.c index 39eb6011bc38..d5594a4268d4 100644 --- a/trunk/kernel/sched/core.c +++ b/trunk/kernel/sched/core.c @@ -142,9 +142,8 @@ const_debug unsigned int sysctl_sched_features = #define SCHED_FEAT(name, enabled) \ #name , -static __read_mostly char *sched_feat_names[] = { +static const char * const sched_feat_names[] = { #include "features.h" - NULL }; #undef SCHED_FEAT @@ -2517,25 +2516,32 @@ static void __update_cpu_load(struct rq *this_rq, unsigned long this_load, sched_avg_update(this_rq); } +#ifdef CONFIG_NO_HZ +/* + * There is no sane way to deal with nohz on smp when using jiffies because the + * cpu doing the jiffies update might drift wrt the cpu doing the jiffy reading + * causing off-by-one errors in observed deltas; {0,2} instead of {1,1}. + * + * Therefore we cannot use the delta approach from the regular tick since that + * would seriously skew the load calculation. However we'll make do for those + * updates happening while idle (nohz_idle_balance) or coming out of idle + * (tick_nohz_idle_exit). + * + * This means we might still be one tick off for nohz periods. + */ + /* * Called from nohz_idle_balance() to update the load ratings before doing the * idle balance. */ void update_idle_cpu_load(struct rq *this_rq) { - unsigned long curr_jiffies = jiffies; + unsigned long curr_jiffies = ACCESS_ONCE(jiffies); unsigned long load = this_rq->load.weight; unsigned long pending_updates; /* - * Bloody broken means of dealing with nohz, but better than nothing.. - * jiffies is updated by one cpu, another cpu can drift wrt the jiffy - * update and see 0 difference the one time and 2 the next, even though - * we ticked at roughtly the same rate. - * - * Hence we only use this from nohz_idle_balance() and skip this - * nonsense when called from the scheduler_tick() since that's - * guaranteed a stable rate. + * bail if there's load or we're actually up-to-date. */ if (load || curr_jiffies == this_rq->last_load_update_tick) return; @@ -2546,13 +2552,39 @@ void update_idle_cpu_load(struct rq *this_rq) __update_cpu_load(this_rq, load, pending_updates); } +/* + * Called from tick_nohz_idle_exit() -- try and fix up the ticks we missed. + */ +void update_cpu_load_nohz(void) +{ + struct rq *this_rq = this_rq(); + unsigned long curr_jiffies = ACCESS_ONCE(jiffies); + unsigned long pending_updates; + + if (curr_jiffies == this_rq->last_load_update_tick) + return; + + raw_spin_lock(&this_rq->lock); + pending_updates = curr_jiffies - this_rq->last_load_update_tick; + if (pending_updates) { + this_rq->last_load_update_tick = curr_jiffies; + /* + * We were idle, this means load 0, the current load might be + * !0 due to remote wakeups and the sort. + */ + __update_cpu_load(this_rq, 0, pending_updates); + } + raw_spin_unlock(&this_rq->lock); +} +#endif /* CONFIG_NO_HZ */ + /* * Called from scheduler_tick() */ static void update_cpu_load_active(struct rq *this_rq) { /* - * See the mess in update_idle_cpu_load(). + * See the mess around update_idle_cpu_load() / update_cpu_load_nohz(). */ this_rq->last_load_update_tick = jiffies; __update_cpu_load(this_rq, this_rq->load.weight, 1); @@ -4982,7 +5014,7 @@ void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask) p->sched_class->set_cpus_allowed(p, new_mask); cpumask_copy(&p->cpus_allowed, new_mask); - p->rt.nr_cpus_allowed = cpumask_weight(new_mask); + p->nr_cpus_allowed = cpumask_weight(new_mask); } /* @@ -5524,15 +5556,20 @@ static cpumask_var_t sched_domains_tmpmask; /* sched_domains_mutex */ #ifdef CONFIG_SCHED_DEBUG -static __read_mostly int sched_domain_debug_enabled; +static __read_mostly int sched_debug_enabled; -static int __init sched_domain_debug_setup(char *str) +static int __init sched_debug_setup(char *str) { - sched_domain_debug_enabled = 1; + sched_debug_enabled = 1; return 0; } -early_param("sched_debug", sched_domain_debug_setup); +early_param("sched_debug", sched_debug_setup); + +static inline bool sched_debug(void) +{ + return sched_debug_enabled; +} static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, struct cpumask *groupmask) @@ -5572,7 +5609,12 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, break; } - if (!group->sgp->power) { + /* + * Even though we initialize ->power to something semi-sane, + * we leave power_orig unset. This allows us to detect if + * domain iteration is still funny without causing /0 traps. + */ + if (!group->sgp->power_orig) { printk(KERN_CONT "\n"); printk(KERN_ERR "ERROR: domain->cpu_power not " "set\n"); @@ -5620,7 +5662,7 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu) { int level = 0; - if (!sched_domain_debug_enabled) + if (!sched_debug_enabled) return; if (!sd) { @@ -5641,6 +5683,10 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu) } #else /* !CONFIG_SCHED_DEBUG */ # define sched_domain_debug(sd, cpu) do { } while (0) +static inline bool sched_debug(void) +{ + return false; +} #endif /* CONFIG_SCHED_DEBUG */ static int sd_degenerate(struct sched_domain *sd) @@ -5962,6 +6008,44 @@ struct sched_domain_topology_level { struct sd_data data; }; +/* + * Build an iteration mask that can exclude certain CPUs from the upwards + * domain traversal. + * + * Asymmetric node setups can result in situations where the domain tree is of + * unequal depth, make sure to skip domains that already cover the entire + * range. + * + * In that case build_sched_domains() will have terminated the iteration early + * and our sibling sd spans will be empty. Domains should always include the + * cpu they're built on, so check that. + * + */ +static void build_group_mask(struct sched_domain *sd, struct sched_group *sg) +{ + const struct cpumask *span = sched_domain_span(sd); + struct sd_data *sdd = sd->private; + struct sched_domain *sibling; + int i; + + for_each_cpu(i, span) { + sibling = *per_cpu_ptr(sdd->sd, i); + if (!cpumask_test_cpu(i, sched_domain_span(sibling))) + continue; + + cpumask_set_cpu(i, sched_group_mask(sg)); + } +} + +/* + * Return the canonical balance cpu for this group, this is the first cpu + * of this group that's also in the iteration mask. + */ +int group_balance_cpu(struct sched_group *sg) +{ + return cpumask_first_and(sched_group_cpus(sg), sched_group_mask(sg)); +} + static int build_overlap_sched_groups(struct sched_domain *sd, int cpu) { @@ -5980,6 +6064,12 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu) if (cpumask_test_cpu(i, covered)) continue; + child = *per_cpu_ptr(sdd->sd, i); + + /* See the comment near build_group_mask(). */ + if (!cpumask_test_cpu(i, sched_domain_span(child))) + continue; + sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(), GFP_KERNEL, cpu_to_node(cpu)); @@ -5987,8 +6077,6 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu) goto fail; sg_span = sched_group_cpus(sg); - - child = *per_cpu_ptr(sdd->sd, i); if (child->child) { child = child->child; cpumask_copy(sg_span, sched_domain_span(child)); @@ -5997,10 +6085,24 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu) cpumask_or(covered, covered, sg_span); - sg->sgp = *per_cpu_ptr(sdd->sgp, cpumask_first(sg_span)); - atomic_inc(&sg->sgp->ref); + sg->sgp = *per_cpu_ptr(sdd->sgp, i); + if (atomic_inc_return(&sg->sgp->ref) == 1) + build_group_mask(sd, sg); - if (cpumask_test_cpu(cpu, sg_span)) + /* + * Initialize sgp->power such that even if we mess up the + * domains and no possible iteration will get us here, we won't + * die on a /0 trap. + */ + sg->sgp->power = SCHED_POWER_SCALE * cpumask_weight(sg_span); + + /* + * Make sure the first group of this domain contains the + * canonical balance cpu. Otherwise the sched_domain iteration + * breaks. See update_sg_lb_stats(). + */ + if ((!groups && cpumask_test_cpu(cpu, sg_span)) || + group_balance_cpu(sg) == cpu) groups = sg; if (!first) @@ -6074,6 +6176,7 @@ build_sched_groups(struct sched_domain *sd, int cpu) cpumask_clear(sched_group_cpus(sg)); sg->sgp->power = 0; + cpumask_setall(sched_group_mask(sg)); for_each_cpu(j, span) { if (get_group(j, sdd, NULL) != group) @@ -6115,7 +6218,7 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) sg = sg->next; } while (sg != sd->groups); - if (cpu != group_first_cpu(sg)) + if (cpu != group_balance_cpu(sg)) return; update_group_power(sd, cpu); @@ -6165,11 +6268,8 @@ int sched_domain_level_max; static int __init setup_relax_domain_level(char *str) { - unsigned long val; - - val = simple_strtoul(str, NULL, 0); - if (val < sched_domain_level_max) - default_relax_domain_level = val; + if (kstrtoint(str, 0, &default_relax_domain_level)) + pr_warn("Unable to set relax_domain_level\n"); return 1; } @@ -6279,14 +6379,13 @@ static struct sched_domain_topology_level *sched_domain_topology = default_topol #ifdef CONFIG_NUMA static int sched_domains_numa_levels; -static int sched_domains_numa_scale; static int *sched_domains_numa_distance; static struct cpumask ***sched_domains_numa_masks; static int sched_domains_curr_level; static inline int sd_local_flags(int level) { - if (sched_domains_numa_distance[level] > REMOTE_DISTANCE) + if (sched_domains_numa_distance[level] > RECLAIM_DISTANCE) return 0; return SD_BALANCE_EXEC | SD_BALANCE_FORK | SD_WAKE_AFFINE; @@ -6344,6 +6443,42 @@ static const struct cpumask *sd_numa_mask(int cpu) return sched_domains_numa_masks[sched_domains_curr_level][cpu_to_node(cpu)]; } +static void sched_numa_warn(const char *str) +{ + static int done = false; + int i,j; + + if (done) + return; + + done = true; + + printk(KERN_WARNING "ERROR: %s\n\n", str); + + for (i = 0; i < nr_node_ids; i++) { + printk(KERN_WARNING " "); + for (j = 0; j < nr_node_ids; j++) + printk(KERN_CONT "%02d ", node_distance(i,j)); + printk(KERN_CONT "\n"); + } + printk(KERN_WARNING "\n"); +} + +static bool find_numa_distance(int distance) +{ + int i; + + if (distance == node_distance(0, 0)) + return true; + + for (i = 0; i < sched_domains_numa_levels; i++) { + if (sched_domains_numa_distance[i] == distance) + return true; + } + + return false; +} + static void sched_init_numa(void) { int next_distance, curr_distance = node_distance(0, 0); @@ -6351,7 +6486,6 @@ static void sched_init_numa(void) int level = 0; int i, j, k; - sched_domains_numa_scale = curr_distance; sched_domains_numa_distance = kzalloc(sizeof(int) * nr_node_ids, GFP_KERNEL); if (!sched_domains_numa_distance) return; @@ -6362,23 +6496,41 @@ static void sched_init_numa(void) * * Assumes node_distance(0,j) includes all distances in * node_distance(i,j) in order to avoid cubic time. - * - * XXX: could be optimized to O(n log n) by using sort() */ next_distance = curr_distance; for (i = 0; i < nr_node_ids; i++) { for (j = 0; j < nr_node_ids; j++) { - int distance = node_distance(0, j); - if (distance > curr_distance && - (distance < next_distance || - next_distance == curr_distance)) - next_distance = distance; + for (k = 0; k < nr_node_ids; k++) { + int distance = node_distance(i, k); + + if (distance > curr_distance && + (distance < next_distance || + next_distance == curr_distance)) + next_distance = distance; + + /* + * While not a strong assumption it would be nice to know + * about cases where if node A is connected to B, B is not + * equally connected to A. + */ + if (sched_debug() && node_distance(k, i) != distance) + sched_numa_warn("Node-distance not symmetric"); + + if (sched_debug() && i && !find_numa_distance(distance)) + sched_numa_warn("Node-0 not representative"); + } + if (next_distance != curr_distance) { + sched_domains_numa_distance[level++] = next_distance; + sched_domains_numa_levels = level; + curr_distance = next_distance; + } else break; } - if (next_distance != curr_distance) { - sched_domains_numa_distance[level++] = next_distance; - sched_domains_numa_levels = level; - curr_distance = next_distance; - } else break; + + /* + * In case of sched_debug() we verify the above assumption. + */ + if (!sched_debug()) + break; } /* * 'level' contains the number of unique distances, excluding the @@ -6403,7 +6555,7 @@ static void sched_init_numa(void) return; for (j = 0; j < nr_node_ids; j++) { - struct cpumask *mask = kzalloc_node(cpumask_size(), GFP_KERNEL, j); + struct cpumask *mask = kzalloc(cpumask_size(), GFP_KERNEL); if (!mask) return; @@ -6490,7 +6642,7 @@ static int __sdt_alloc(const struct cpumask *cpu_map) *per_cpu_ptr(sdd->sg, j) = sg; - sgp = kzalloc_node(sizeof(struct sched_group_power), + sgp = kzalloc_node(sizeof(struct sched_group_power) + cpumask_size(), GFP_KERNEL, cpu_to_node(j)); if (!sgp) return -ENOMEM; @@ -6543,7 +6695,6 @@ struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl, if (!sd) return child; - set_domain_attribute(sd, attr); cpumask_and(sched_domain_span(sd), cpu_map, tl->mask(cpu)); if (child) { sd->level = child->level + 1; @@ -6551,6 +6702,7 @@ struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl, child->parent = sd; } sd->child = child; + set_domain_attribute(sd, attr); return sd; } @@ -6691,7 +6843,6 @@ static int init_sched_domains(const struct cpumask *cpu_map) if (!doms_cur) doms_cur = &fallback_doms; cpumask_andnot(doms_cur[0], cpu_map, cpu_isolated_map); - dattr_cur = NULL; err = build_sched_domains(doms_cur[0], NULL); register_sched_domain_sysctl(); diff --git a/trunk/kernel/sched/fair.c b/trunk/kernel/sched/fair.c index 940e6d17cf96..c099cc6eebe3 100644 --- a/trunk/kernel/sched/fair.c +++ b/trunk/kernel/sched/fair.c @@ -2703,7 +2703,7 @@ select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flags) int want_sd = 1; int sync = wake_flags & WF_SYNC; - if (p->rt.nr_cpus_allowed == 1) + if (p->nr_cpus_allowed == 1) return prev_cpu; if (sd_flag & SD_BALANCE_WAKE) { @@ -3503,15 +3503,22 @@ unsigned long __weak arch_scale_smt_power(struct sched_domain *sd, int cpu) unsigned long scale_rt_power(int cpu) { struct rq *rq = cpu_rq(cpu); - u64 total, available; + u64 total, available, age_stamp, avg; - total = sched_avg_period() + (rq->clock - rq->age_stamp); + /* + * Since we're reading these variables without serialization make sure + * we read them once before doing sanity checks on them. + */ + age_stamp = ACCESS_ONCE(rq->age_stamp); + avg = ACCESS_ONCE(rq->rt_avg); + + total = sched_avg_period() + (rq->clock - age_stamp); - if (unlikely(total < rq->rt_avg)) { + if (unlikely(total < avg)) { /* Ensures that power won't end up being negative */ available = 0; } else { - available = total - rq->rt_avg; + available = total - avg; } if (unlikely((s64)total < SCHED_POWER_SCALE)) @@ -3574,13 +3581,28 @@ void update_group_power(struct sched_domain *sd, int cpu) power = 0; - group = child->groups; - do { - power += group->sgp->power; - group = group->next; - } while (group != child->groups); + if (child->flags & SD_OVERLAP) { + /* + * SD_OVERLAP domains cannot assume that child groups + * span the current group. + */ - sdg->sgp->power = power; + for_each_cpu(cpu, sched_group_cpus(sdg)) + power += power_of(cpu); + } else { + /* + * !SD_OVERLAP domains can assume that child groups + * span the current group. + */ + + group = child->groups; + do { + power += group->sgp->power; + group = group->next; + } while (group != child->groups); + } + + sdg->sgp->power_orig = sdg->sgp->power = power; } /* @@ -3610,7 +3632,7 @@ fix_small_capacity(struct sched_domain *sd, struct sched_group *group) /** * update_sg_lb_stats - Update sched_group's statistics for load balancing. - * @sd: The sched_domain whose statistics are to be updated. + * @env: The load balancing environment. * @group: sched_group whose statistics are to be updated. * @load_idx: Load index of sched_domain of this_cpu for load calc. * @local_group: Does group contain this_cpu. @@ -3630,7 +3652,7 @@ static inline void update_sg_lb_stats(struct lb_env *env, int i; if (local_group) - balance_cpu = group_first_cpu(group); + balance_cpu = group_balance_cpu(group); /* Tally up the load of all CPUs in the group */ max_cpu_load = 0; @@ -3645,7 +3667,8 @@ static inline void update_sg_lb_stats(struct lb_env *env, /* Bias balancing toward cpus of our domain */ if (local_group) { - if (idle_cpu(i) && !first_idle_cpu) { + if (idle_cpu(i) && !first_idle_cpu && + cpumask_test_cpu(i, sched_group_mask(group))) { first_idle_cpu = 1; balance_cpu = i; } @@ -3719,11 +3742,10 @@ static inline void update_sg_lb_stats(struct lb_env *env, /** * update_sd_pick_busiest - return 1 on busiest group - * @sd: sched_domain whose statistics are to be checked + * @env: The load balancing environment. * @sds: sched_domain statistics * @sg: sched_group candidate to be checked for being the busiest * @sgs: sched_group statistics - * @this_cpu: the current cpu * * Determine if @sg is a busier group than the previously selected * busiest group. @@ -3761,9 +3783,7 @@ static bool update_sd_pick_busiest(struct lb_env *env, /** * update_sd_lb_stats - Update sched_domain's statistics for load balancing. - * @sd: sched_domain whose statistics are to be updated. - * @this_cpu: Cpu for which load balance is currently performed. - * @idle: Idle status of this_cpu + * @env: The load balancing environment. * @cpus: Set of cpus considered for load balancing. * @balance: Should we balance. * @sds: variable to hold the statistics for this sched_domain. @@ -3852,10 +3872,8 @@ static inline void update_sd_lb_stats(struct lb_env *env, * Returns 1 when packing is required and a task should be moved to * this CPU. The amount of the imbalance is returned in *imbalance. * - * @sd: The sched_domain whose packing is to be checked. + * @env: The load balancing environment. * @sds: Statistics of the sched_domain which is to be packed - * @this_cpu: The cpu at whose sched_domain we're performing load-balance. - * @imbalance: returns amount of imbalanced due to packing. */ static int check_asym_packing(struct lb_env *env, struct sd_lb_stats *sds) { @@ -3881,9 +3899,8 @@ static int check_asym_packing(struct lb_env *env, struct sd_lb_stats *sds) * fix_small_imbalance - Calculate the minor imbalance that exists * amongst the groups of a sched_domain, during * load balancing. + * @env: The load balancing environment. * @sds: Statistics of the sched_domain whose imbalance is to be calculated. - * @this_cpu: The cpu at whose sched_domain we're performing load-balance. - * @imbalance: Variable to store the imbalance. */ static inline void fix_small_imbalance(struct lb_env *env, struct sd_lb_stats *sds) @@ -4026,11 +4043,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s * Also calculates the amount of weighted load which should be moved * to restore balance. * - * @sd: The sched_domain whose busiest group is to be returned. - * @this_cpu: The cpu for which load balancing is currently being performed. - * @imbalance: Variable which stores amount of weighted load which should - * be moved to restore balance/put a group to idle. - * @idle: The idle status of this_cpu. + * @env: The load balancing environment. * @cpus: The set of CPUs under consideration for load-balancing. * @balance: Pointer to a variable indicating if this_cpu * is the appropriate cpu to perform load balancing at this_level. diff --git a/trunk/kernel/sched/rt.c b/trunk/kernel/sched/rt.c index c5565c3c515f..573e1ca01102 100644 --- a/trunk/kernel/sched/rt.c +++ b/trunk/kernel/sched/rt.c @@ -274,13 +274,16 @@ static void update_rt_migration(struct rt_rq *rt_rq) static void inc_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) { + struct task_struct *p; + if (!rt_entity_is_task(rt_se)) return; + p = rt_task_of(rt_se); rt_rq = &rq_of_rt_rq(rt_rq)->rt; rt_rq->rt_nr_total++; - if (rt_se->nr_cpus_allowed > 1) + if (p->nr_cpus_allowed > 1) rt_rq->rt_nr_migratory++; update_rt_migration(rt_rq); @@ -288,13 +291,16 @@ static void inc_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) static void dec_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) { + struct task_struct *p; + if (!rt_entity_is_task(rt_se)) return; + p = rt_task_of(rt_se); rt_rq = &rq_of_rt_rq(rt_rq)->rt; rt_rq->rt_nr_total--; - if (rt_se->nr_cpus_allowed > 1) + if (p->nr_cpus_allowed > 1) rt_rq->rt_nr_migratory--; update_rt_migration(rt_rq); @@ -1161,7 +1167,7 @@ enqueue_task_rt(struct rq *rq, struct task_struct *p, int flags) enqueue_rt_entity(rt_se, flags & ENQUEUE_HEAD); - if (!task_current(rq, p) && p->rt.nr_cpus_allowed > 1) + if (!task_current(rq, p) && p->nr_cpus_allowed > 1) enqueue_pushable_task(rq, p); inc_nr_running(rq); @@ -1225,7 +1231,7 @@ select_task_rq_rt(struct task_struct *p, int sd_flag, int flags) cpu = task_cpu(p); - if (p->rt.nr_cpus_allowed == 1) + if (p->nr_cpus_allowed == 1) goto out; /* For anything but wake ups, just return the task_cpu */ @@ -1260,9 +1266,9 @@ select_task_rq_rt(struct task_struct *p, int sd_flag, int flags) * will have to sort it out. */ if (curr && unlikely(rt_task(curr)) && - (curr->rt.nr_cpus_allowed < 2 || + (curr->nr_cpus_allowed < 2 || curr->prio <= p->prio) && - (p->rt.nr_cpus_allowed > 1)) { + (p->nr_cpus_allowed > 1)) { int target = find_lowest_rq(p); if (target != -1) @@ -1276,10 +1282,10 @@ select_task_rq_rt(struct task_struct *p, int sd_flag, int flags) static void check_preempt_equal_prio(struct rq *rq, struct task_struct *p) { - if (rq->curr->rt.nr_cpus_allowed == 1) + if (rq->curr->nr_cpus_allowed == 1) return; - if (p->rt.nr_cpus_allowed != 1 + if (p->nr_cpus_allowed != 1 && cpupri_find(&rq->rd->cpupri, p, NULL)) return; @@ -1395,7 +1401,7 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p) * The previous task needs to be made eligible for pushing * if it is still active */ - if (on_rt_rq(&p->rt) && p->rt.nr_cpus_allowed > 1) + if (on_rt_rq(&p->rt) && p->nr_cpus_allowed > 1) enqueue_pushable_task(rq, p); } @@ -1408,7 +1414,7 @@ static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu) { if (!task_running(rq, p) && (cpu < 0 || cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) && - (p->rt.nr_cpus_allowed > 1)) + (p->nr_cpus_allowed > 1)) return 1; return 0; } @@ -1464,7 +1470,7 @@ static int find_lowest_rq(struct task_struct *task) if (unlikely(!lowest_mask)) return -1; - if (task->rt.nr_cpus_allowed == 1) + if (task->nr_cpus_allowed == 1) return -1; /* No other targets possible */ if (!cpupri_find(&task_rq(task)->rd->cpupri, task, lowest_mask)) @@ -1556,7 +1562,7 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq) task_running(rq, task) || !task->on_rq)) { - raw_spin_unlock(&lowest_rq->lock); + double_unlock_balance(rq, lowest_rq); lowest_rq = NULL; break; } @@ -1586,7 +1592,7 @@ static struct task_struct *pick_next_pushable_task(struct rq *rq) BUG_ON(rq->cpu != task_cpu(p)); BUG_ON(task_current(rq, p)); - BUG_ON(p->rt.nr_cpus_allowed <= 1); + BUG_ON(p->nr_cpus_allowed <= 1); BUG_ON(!p->on_rq); BUG_ON(!rt_task(p)); @@ -1793,9 +1799,9 @@ static void task_woken_rt(struct rq *rq, struct task_struct *p) if (!task_running(rq, p) && !test_tsk_need_resched(rq->curr) && has_pushable_tasks(rq) && - p->rt.nr_cpus_allowed > 1 && + p->nr_cpus_allowed > 1 && rt_task(rq->curr) && - (rq->curr->rt.nr_cpus_allowed < 2 || + (rq->curr->nr_cpus_allowed < 2 || rq->curr->prio <= p->prio)) push_rt_tasks(rq); } @@ -1817,7 +1823,7 @@ static void set_cpus_allowed_rt(struct task_struct *p, * Only update if the process changes its state from whether it * can migrate or not. */ - if ((p->rt.nr_cpus_allowed > 1) == (weight > 1)) + if ((p->nr_cpus_allowed > 1) == (weight > 1)) return; rq = task_rq(p); @@ -1979,6 +1985,8 @@ static void watchdog(struct rq *rq, struct task_struct *p) static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued) { + struct sched_rt_entity *rt_se = &p->rt; + update_curr_rt(rq); watchdog(rq, p); @@ -1996,12 +2004,15 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued) p->rt.time_slice = RR_TIMESLICE; /* - * Requeue to the end of queue if we are not the only element - * on the queue: + * Requeue to the end of queue if we (and all of our ancestors) are the + * only element on the queue */ - if (p->rt.run_list.prev != p->rt.run_list.next) { - requeue_task_rt(rq, p, 0); - set_tsk_need_resched(p); + for_each_sched_rt_entity(rt_se) { + if (rt_se->run_list.prev != rt_se->run_list.next) { + requeue_task_rt(rq, p, 0); + set_tsk_need_resched(p); + return; + } } } diff --git a/trunk/kernel/sched/sched.h b/trunk/kernel/sched/sched.h index ba9dccfd24ce..6d52cea7f33d 100644 --- a/trunk/kernel/sched/sched.h +++ b/trunk/kernel/sched/sched.h @@ -526,6 +526,8 @@ static inline struct sched_domain *highest_flag_domain(int cpu, int flag) DECLARE_PER_CPU(struct sched_domain *, sd_llc); DECLARE_PER_CPU(int, sd_llc_id); +extern int group_balance_cpu(struct sched_group *sg); + #endif /* CONFIG_SMP */ #include "stats.h" diff --git a/trunk/kernel/smpboot.c b/trunk/kernel/smpboot.c index e1a797e028a3..98f60c5caa1b 100644 --- a/trunk/kernel/smpboot.c +++ b/trunk/kernel/smpboot.c @@ -31,6 +31,12 @@ void __init idle_thread_set_boot_cpu(void) per_cpu(idle_threads, smp_processor_id()) = current; } +/** + * idle_init - Initialize the idle thread for a cpu + * @cpu: The cpu for which the idle thread should be initialized + * + * Creates the thread if it does not exist. + */ static inline void idle_init(unsigned int cpu) { struct task_struct *tsk = per_cpu(idle_threads, cpu); @@ -45,17 +51,16 @@ static inline void idle_init(unsigned int cpu) } /** - * idle_thread_init - Initialize the idle thread for a cpu - * @cpu: The cpu for which the idle thread should be initialized - * - * Creates the thread if it does not exist. + * idle_threads_init - Initialize idle threads for all cpus */ void __init idle_threads_init(void) { - unsigned int cpu; + unsigned int cpu, boot_cpu; + + boot_cpu = smp_processor_id(); for_each_possible_cpu(cpu) { - if (cpu != smp_processor_id()) + if (cpu != boot_cpu) idle_init(cpu); } } diff --git a/trunk/kernel/sys.c b/trunk/kernel/sys.c index 9ff89cb9657a..f0ec44dcd415 100644 --- a/trunk/kernel/sys.c +++ b/trunk/kernel/sys.c @@ -1786,27 +1786,13 @@ SYSCALL_DEFINE1(umask, int, mask) } #ifdef CONFIG_CHECKPOINT_RESTORE -static bool vma_flags_mismatch(struct vm_area_struct *vma, - unsigned long required, - unsigned long banned) -{ - return (vma->vm_flags & required) != required || - (vma->vm_flags & banned); -} - static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) { + struct vm_area_struct *vma; struct file *exe_file; struct dentry *dentry; int err; - /* - * Setting new mm::exe_file is only allowed when no VM_EXECUTABLE vma's - * remain. So perform a quick test first. - */ - if (mm->num_exe_file_vmas) - return -EBUSY; - exe_file = fget(fd); if (!exe_file) return -EBADF; @@ -1827,17 +1813,30 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) if (err) goto exit; + down_write(&mm->mmap_sem); + + /* + * Forbid mm->exe_file change if there are mapped other files. + */ + err = -EBUSY; + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (vma->vm_file && !path_equal(&vma->vm_file->f_path, + &exe_file->f_path)) + goto exit_unlock; + } + /* * The symlink can be changed only once, just to disallow arbitrary * transitions malicious software might bring in. This means one * could make a snapshot over all processes running and monitor * /proc/pid/exe changes to notice unusual activity if needed. */ - down_write(&mm->mmap_sem); - if (likely(!mm->exe_file)) - set_mm_exe_file(mm, exe_file); - else - err = -EBUSY; + err = -EPERM; + if (test_and_set_bit(MMF_EXE_FILE_CHANGED, &mm->flags)) + goto exit_unlock; + + set_mm_exe_file(mm, exe_file); +exit_unlock: up_write(&mm->mmap_sem); exit: @@ -1862,7 +1861,7 @@ static int prctl_set_mm(int opt, unsigned long addr, if (opt == PR_SET_MM_EXE_FILE) return prctl_set_mm_exe_file(mm, (unsigned int)addr); - if (addr >= TASK_SIZE) + if (addr >= TASK_SIZE || addr < mmap_min_addr) return -EINVAL; error = -EINVAL; @@ -1924,12 +1923,6 @@ static int prctl_set_mm(int opt, unsigned long addr, error = -EFAULT; goto out; } -#ifdef CONFIG_STACK_GROWSUP - if (vma_flags_mismatch(vma, VM_READ | VM_WRITE | VM_GROWSUP, 0)) -#else - if (vma_flags_mismatch(vma, VM_READ | VM_WRITE | VM_GROWSDOWN, 0)) -#endif - goto out; if (opt == PR_SET_MM_START_STACK) mm->start_stack = addr; else if (opt == PR_SET_MM_ARG_START) @@ -1981,12 +1974,22 @@ static int prctl_set_mm(int opt, unsigned long addr, up_read(&mm->mmap_sem); return error; } + +static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr) +{ + return put_user(me->clear_child_tid, tid_addr); +} + #else /* CONFIG_CHECKPOINT_RESTORE */ static int prctl_set_mm(int opt, unsigned long addr, unsigned long arg4, unsigned long arg5) { return -EINVAL; } +static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr) +{ + return -EINVAL; +} #endif SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, @@ -2124,6 +2127,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, else return -EINVAL; break; + case PR_GET_TID_ADDRESS: + error = prctl_get_tid_address(me, (int __user **)arg2); + break; default: return -EINVAL; } diff --git a/trunk/kernel/time/clockevents.c b/trunk/kernel/time/clockevents.c index 9cd928f7a7c6..7e1ce012a851 100644 --- a/trunk/kernel/time/clockevents.c +++ b/trunk/kernel/time/clockevents.c @@ -297,8 +297,7 @@ void clockevents_register_device(struct clock_event_device *dev) } EXPORT_SYMBOL_GPL(clockevents_register_device); -static void clockevents_config(struct clock_event_device *dev, - u32 freq) +void clockevents_config(struct clock_event_device *dev, u32 freq) { u64 sec; diff --git a/trunk/kernel/time/tick-sched.c b/trunk/kernel/time/tick-sched.c index 6a3a5b9ff561..da70c6db496c 100644 --- a/trunk/kernel/time/tick-sched.c +++ b/trunk/kernel/time/tick-sched.c @@ -576,6 +576,7 @@ void tick_nohz_idle_exit(void) /* Update jiffies first */ select_nohz_load_balancer(0); tick_do_update_jiffies64(now); + update_cpu_load_nohz(); #ifndef CONFIG_VIRT_CPU_ACCOUNTING /* @@ -814,6 +815,16 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) return HRTIMER_RESTART; } +static int sched_skew_tick; + +static int __init skew_tick(char *str) +{ + get_option(&str, &sched_skew_tick); + + return 0; +} +early_param("skew_tick", skew_tick); + /** * tick_setup_sched_timer - setup the tick emulation timer */ @@ -831,6 +842,14 @@ void tick_setup_sched_timer(void) /* Get the next period (per cpu) */ hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update()); + /* Offset the tick to avert xtime_lock contention. */ + if (sched_skew_tick) { + u64 offset = ktime_to_ns(tick_period) >> 1; + do_div(offset, num_possible_cpus()); + offset *= smp_processor_id(); + hrtimer_add_expires_ns(&ts->sched_timer, offset); + } + for (;;) { hrtimer_forward(&ts->sched_timer, now, tick_period); hrtimer_start_expires(&ts->sched_timer, diff --git a/trunk/kernel/time/timekeeping.c b/trunk/kernel/time/timekeeping.c index 6e46cacf5969..6f46a00a1e8a 100644 --- a/trunk/kernel/time/timekeeping.c +++ b/trunk/kernel/time/timekeeping.c @@ -962,6 +962,7 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift) timekeeper.xtime.tv_sec++; leap = second_overflow(timekeeper.xtime.tv_sec); timekeeper.xtime.tv_sec += leap; + timekeeper.wall_to_monotonic.tv_sec -= leap; } /* Accumulate raw time */ @@ -1077,6 +1078,7 @@ static void update_wall_time(void) timekeeper.xtime.tv_sec++; leap = second_overflow(timekeeper.xtime.tv_sec); timekeeper.xtime.tv_sec += leap; + timekeeper.wall_to_monotonic.tv_sec -= leap; } timekeeping_update(false); diff --git a/trunk/lib/btree.c b/trunk/lib/btree.c index e5ec1e9c1aa5..f9a484676cb6 100644 --- a/trunk/lib/btree.c +++ b/trunk/lib/btree.c @@ -319,8 +319,8 @@ void *btree_get_prev(struct btree_head *head, struct btree_geo *geo, if (head->height == 0) return NULL; -retry: longcpy(key, __key, geo->keylen); +retry: dec_key(geo, key); node = head->node; @@ -351,7 +351,7 @@ void *btree_get_prev(struct btree_head *head, struct btree_geo *geo, } miss: if (retry_key) { - __key = retry_key; + longcpy(key, retry_key, geo->keylen); retry_key = NULL; goto retry; } @@ -509,6 +509,7 @@ static int btree_insert_level(struct btree_head *head, struct btree_geo *geo, int btree_insert(struct btree_head *head, struct btree_geo *geo, unsigned long *key, void *val, gfp_t gfp) { + BUG_ON(!val); return btree_insert_level(head, geo, key, val, 1, gfp); } EXPORT_SYMBOL_GPL(btree_insert); diff --git a/trunk/lib/radix-tree.c b/trunk/lib/radix-tree.c index d7c878cc006c..e7964296fd50 100644 --- a/trunk/lib/radix-tree.c +++ b/trunk/lib/radix-tree.c @@ -686,6 +686,9 @@ void **radix_tree_next_chunk(struct radix_tree_root *root, * during iterating; it can be zero only at the beginning. * And we cannot overflow iter->next_index in a single step, * because RADIX_TREE_MAP_SHIFT < BITS_PER_LONG. + * + * This condition also used by radix_tree_next_slot() to stop + * contiguous iterating, and forbid swithing to the next chunk. */ index = iter->next_index; if (!index && iter->index) diff --git a/trunk/lib/raid6/recov.c b/trunk/lib/raid6/recov.c index 1805a5cc5daa..a95bccb8497d 100644 --- a/trunk/lib/raid6/recov.c +++ b/trunk/lib/raid6/recov.c @@ -22,8 +22,8 @@ #include /* Recover two failed data blocks. */ -void raid6_2data_recov_intx1(int disks, size_t bytes, int faila, int failb, - void **ptrs) +static void raid6_2data_recov_intx1(int disks, size_t bytes, int faila, + int failb, void **ptrs) { u8 *p, *q, *dp, *dq; u8 px, qx, db; @@ -66,7 +66,8 @@ void raid6_2data_recov_intx1(int disks, size_t bytes, int faila, int failb, } /* Recover failure of one data block plus the P block */ -void raid6_datap_recov_intx1(int disks, size_t bytes, int faila, void **ptrs) +static void raid6_datap_recov_intx1(int disks, size_t bytes, int faila, + void **ptrs) { u8 *p, *q, *dq; const u8 *qmul; /* Q multiplier table */ diff --git a/trunk/lib/raid6/recov_ssse3.c b/trunk/lib/raid6/recov_ssse3.c index 37ae61930559..ecb710c0b4d9 100644 --- a/trunk/lib/raid6/recov_ssse3.c +++ b/trunk/lib/raid6/recov_ssse3.c @@ -19,8 +19,8 @@ static int raid6_has_ssse3(void) boot_cpu_has(X86_FEATURE_SSSE3); } -void raid6_2data_recov_ssse3(int disks, size_t bytes, int faila, int failb, - void **ptrs) +static void raid6_2data_recov_ssse3(int disks, size_t bytes, int faila, + int failb, void **ptrs) { u8 *p, *q, *dp, *dq; const u8 *pbmul; /* P multiplier table for B data */ @@ -194,7 +194,8 @@ void raid6_2data_recov_ssse3(int disks, size_t bytes, int faila, int failb, } -void raid6_datap_recov_ssse3(int disks, size_t bytes, int faila, void **ptrs) +static void raid6_datap_recov_ssse3(int disks, size_t bytes, int faila, + void **ptrs) { u8 *p, *q, *dq; const u8 *qmul; /* Q multiplier table */ diff --git a/trunk/mm/Kconfig b/trunk/mm/Kconfig index b2176374b98e..82fed4eb2b6f 100644 --- a/trunk/mm/Kconfig +++ b/trunk/mm/Kconfig @@ -389,3 +389,20 @@ config CLEANCACHE in a negligible performance hit. If unsure, say Y to enable cleancache + +config FRONTSWAP + bool "Enable frontswap to cache swap pages if tmem is present" + depends on SWAP + default n + help + Frontswap is so named because it can be thought of as the opposite + of a "backing" store for a swap device. The data is stored into + "transcendent memory", memory that is not directly accessible or + addressable by the kernel and is of unknown and possibly + time-varying size. When space in transcendent memory is available, + a significant swap I/O reduction may be achieved. When none is + available, all frontswap calls are reduced to a single pointer- + compare-against-NULL resulting in a negligible performance hit + and swap data is stored as normal on the matching swap device. + + If unsure, say Y to enable frontswap. diff --git a/trunk/mm/Makefile b/trunk/mm/Makefile index a156285ce88d..2e2fbbefb99f 100644 --- a/trunk/mm/Makefile +++ b/trunk/mm/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o obj-$(CONFIG_BOUNCE) += bounce.o obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o +obj-$(CONFIG_FRONTSWAP) += frontswap.o obj-$(CONFIG_HAS_DMA) += dmapool.o obj-$(CONFIG_HUGETLBFS) += hugetlb.o obj-$(CONFIG_NUMA) += mempolicy.o diff --git a/trunk/mm/compaction.c b/trunk/mm/compaction.c index 4ac338af5120..7ea259d82a99 100644 --- a/trunk/mm/compaction.c +++ b/trunk/mm/compaction.c @@ -236,7 +236,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc, */ while (unlikely(too_many_isolated(zone))) { /* async migration should just abort */ - if (cc->mode != COMPACT_SYNC) + if (!cc->sync) return 0; congestion_wait(BLK_RW_ASYNC, HZ/10); @@ -304,8 +304,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc, * satisfies the allocation */ pageblock_nr = low_pfn >> pageblock_order; - if (cc->mode != COMPACT_SYNC && - last_pageblock_nr != pageblock_nr && + if (!cc->sync && last_pageblock_nr != pageblock_nr && !migrate_async_suitable(get_pageblock_migratetype(page))) { low_pfn += pageblock_nr_pages; low_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1; @@ -326,7 +325,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc, continue; } - if (cc->mode != COMPACT_SYNC) + if (!cc->sync) mode |= ISOLATE_ASYNC_MIGRATE; lruvec = mem_cgroup_page_lruvec(page, zone); @@ -361,90 +360,27 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc, #endif /* CONFIG_COMPACTION || CONFIG_CMA */ #ifdef CONFIG_COMPACTION -/* - * Returns true if MIGRATE_UNMOVABLE pageblock was successfully - * converted to MIGRATE_MOVABLE type, false otherwise. - */ -static bool rescue_unmovable_pageblock(struct page *page) -{ - unsigned long pfn, start_pfn, end_pfn; - struct page *start_page, *end_page; - - pfn = page_to_pfn(page); - start_pfn = pfn & ~(pageblock_nr_pages - 1); - end_pfn = start_pfn + pageblock_nr_pages; - - start_page = pfn_to_page(start_pfn); - end_page = pfn_to_page(end_pfn); - - /* Do not deal with pageblocks that overlap zones */ - if (page_zone(start_page) != page_zone(end_page)) - return false; - - for (page = start_page, pfn = start_pfn; page < end_page; pfn++, - page++) { - if (!pfn_valid_within(pfn)) - continue; - - if (PageBuddy(page)) { - int order = page_order(page); - - pfn += (1 << order) - 1; - page += (1 << order) - 1; - - continue; - } else if (page_count(page) == 0 || PageLRU(page)) - continue; - - return false; - } - - set_pageblock_migratetype(page, MIGRATE_MOVABLE); - move_freepages_block(page_zone(page), page, MIGRATE_MOVABLE); - return true; -} -enum smt_result { - GOOD_AS_MIGRATION_TARGET, - FAIL_UNMOVABLE_TARGET, - FAIL_BAD_TARGET, -}; - -/* - * Returns GOOD_AS_MIGRATION_TARGET if the page is within a block - * suitable for migration to, FAIL_UNMOVABLE_TARGET if the page - * is within a MIGRATE_UNMOVABLE block, FAIL_BAD_TARGET otherwise. - */ -static enum smt_result suitable_migration_target(struct page *page, - struct compact_control *cc) +/* Returns true if the page is within a block suitable for migration to */ +static bool suitable_migration_target(struct page *page) { int migratetype = get_pageblock_migratetype(page); /* Don't interfere with memory hot-remove or the min_free_kbytes blocks */ if (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE) - return FAIL_BAD_TARGET; + return false; /* If the page is a large free page, then allow migration */ if (PageBuddy(page) && page_order(page) >= pageblock_order) - return GOOD_AS_MIGRATION_TARGET; + return true; /* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */ - if (cc->mode != COMPACT_ASYNC_UNMOVABLE && - migrate_async_suitable(migratetype)) - return GOOD_AS_MIGRATION_TARGET; - - if (cc->mode == COMPACT_ASYNC_MOVABLE && - migratetype == MIGRATE_UNMOVABLE) - return FAIL_UNMOVABLE_TARGET; - - if (cc->mode != COMPACT_ASYNC_MOVABLE && - migratetype == MIGRATE_UNMOVABLE && - rescue_unmovable_pageblock(page)) - return GOOD_AS_MIGRATION_TARGET; + if (migrate_async_suitable(migratetype)) + return true; /* Otherwise skip the block */ - return FAIL_BAD_TARGET; + return false; } /* @@ -477,13 +413,6 @@ static void isolate_freepages(struct zone *zone, zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages; - /* - * isolate_freepages() may be called more than once during - * compact_zone_order() run and we want only the most recent - * count. - */ - cc->nr_pageblocks_skipped = 0; - /* * Isolate free pages until enough are available to migrate the * pages on cc->migratepages. We stop searching if the migrate @@ -492,7 +421,6 @@ static void isolate_freepages(struct zone *zone, for (; pfn > low_pfn && cc->nr_migratepages > nr_freepages; pfn -= pageblock_nr_pages) { unsigned long isolated; - enum smt_result ret; if (!pfn_valid(pfn)) continue; @@ -509,12 +437,9 @@ static void isolate_freepages(struct zone *zone, continue; /* Check the block is suitable for migration */ - ret = suitable_migration_target(page, cc); - if (ret != GOOD_AS_MIGRATION_TARGET) { - if (ret == FAIL_UNMOVABLE_TARGET) - cc->nr_pageblocks_skipped++; + if (!suitable_migration_target(page)) continue; - } + /* * Found a block suitable for isolating free pages from. Now * we disabled interrupts, double check things are ok and @@ -523,14 +448,12 @@ static void isolate_freepages(struct zone *zone, */ isolated = 0; spin_lock_irqsave(&zone->lock, flags); - ret = suitable_migration_target(page, cc); - if (ret == GOOD_AS_MIGRATION_TARGET) { + if (suitable_migration_target(page)) { end_pfn = min(pfn + pageblock_nr_pages, zone_end_pfn); isolated = isolate_freepages_block(pfn, end_pfn, freelist, false); nr_freepages += isolated; - } else if (ret == FAIL_UNMOVABLE_TARGET) - cc->nr_pageblocks_skipped++; + } spin_unlock_irqrestore(&zone->lock, flags); /* @@ -762,9 +685,8 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) nr_migrate = cc->nr_migratepages; err = migrate_pages(&cc->migratepages, compaction_alloc, - (unsigned long)&cc->freepages, false, - (cc->mode == COMPACT_SYNC) ? MIGRATE_SYNC_LIGHT - : MIGRATE_ASYNC); + (unsigned long)cc, false, + cc->sync ? MIGRATE_SYNC_LIGHT : MIGRATE_ASYNC); update_nr_listpages(cc); nr_remaining = cc->nr_migratepages; @@ -793,8 +715,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) static unsigned long compact_zone_order(struct zone *zone, int order, gfp_t gfp_mask, - enum compact_mode mode, - unsigned long *nr_pageblocks_skipped) + bool sync) { struct compact_control cc = { .nr_freepages = 0, @@ -802,17 +723,12 @@ static unsigned long compact_zone_order(struct zone *zone, .order = order, .migratetype = allocflags_to_migratetype(gfp_mask), .zone = zone, - .mode = mode, + .sync = sync, }; - unsigned long rc; - INIT_LIST_HEAD(&cc.freepages); INIT_LIST_HEAD(&cc.migratepages); - rc = compact_zone(zone, &cc); - *nr_pageblocks_skipped = cc.nr_pageblocks_skipped; - - return rc; + return compact_zone(zone, &cc); } int sysctl_extfrag_threshold = 500; @@ -837,8 +753,6 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist, struct zoneref *z; struct zone *zone; int rc = COMPACT_SKIPPED; - unsigned long nr_pageblocks_skipped; - enum compact_mode mode; /* * Check whether it is worth even starting compaction. The order check is @@ -855,22 +769,12 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist, nodemask) { int status; - mode = sync ? COMPACT_SYNC : COMPACT_ASYNC_MOVABLE; -retry: - status = compact_zone_order(zone, order, gfp_mask, mode, - &nr_pageblocks_skipped); + status = compact_zone_order(zone, order, gfp_mask, sync); rc = max(status, rc); /* If a normal allocation would succeed, stop compacting */ if (zone_watermark_ok(zone, order, low_wmark_pages(zone), 0, 0)) break; - - if (rc == COMPACT_COMPLETE && mode == COMPACT_ASYNC_MOVABLE) { - if (nr_pageblocks_skipped) { - mode = COMPACT_ASYNC_UNMOVABLE; - goto retry; - } - } } return rc; @@ -904,7 +808,7 @@ static int __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc) if (ok && cc->order > zone->compact_order_failed) zone->compact_order_failed = cc->order + 1; /* Currently async compaction is never deferred. */ - else if (!ok && cc->mode == COMPACT_SYNC) + else if (!ok && cc->sync) defer_compaction(zone, cc->order); } @@ -919,7 +823,7 @@ int compact_pgdat(pg_data_t *pgdat, int order) { struct compact_control cc = { .order = order, - .mode = COMPACT_ASYNC_MOVABLE, + .sync = false, }; return __compact_pgdat(pgdat, &cc); @@ -929,7 +833,7 @@ static int compact_node(int nid) { struct compact_control cc = { .order = -1, - .mode = COMPACT_SYNC, + .sync = true, }; return __compact_pgdat(NODE_DATA(nid), &cc); diff --git a/trunk/mm/frontswap.c b/trunk/mm/frontswap.c new file mode 100644 index 000000000000..e25025574a02 --- /dev/null +++ b/trunk/mm/frontswap.c @@ -0,0 +1,314 @@ +/* + * Frontswap frontend + * + * This code provides the generic "frontend" layer to call a matching + * "backend" driver implementation of frontswap. See + * Documentation/vm/frontswap.txt for more information. + * + * Copyright (C) 2009-2012 Oracle Corp. All rights reserved. + * Author: Dan Magenheimer + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * frontswap_ops is set by frontswap_register_ops to contain the pointers + * to the frontswap "backend" implementation functions. + */ +static struct frontswap_ops frontswap_ops __read_mostly; + +/* + * This global enablement flag reduces overhead on systems where frontswap_ops + * has not been registered, so is preferred to the slower alternative: a + * function call that checks a non-global. + */ +bool frontswap_enabled __read_mostly; +EXPORT_SYMBOL(frontswap_enabled); + +/* + * If enabled, frontswap_store will return failure even on success. As + * a result, the swap subsystem will always write the page to swap, in + * effect converting frontswap into a writethrough cache. In this mode, + * there is no direct reduction in swap writes, but a frontswap backend + * can unilaterally "reclaim" any pages in use with no data loss, thus + * providing increases control over maximum memory usage due to frontswap. + */ +static bool frontswap_writethrough_enabled __read_mostly; + +#ifdef CONFIG_DEBUG_FS +/* + * Counters available via /sys/kernel/debug/frontswap (if debugfs is + * properly configured). These are for information only so are not protected + * against increment races. + */ +static u64 frontswap_loads; +static u64 frontswap_succ_stores; +static u64 frontswap_failed_stores; +static u64 frontswap_invalidates; + +static inline void inc_frontswap_loads(void) { + frontswap_loads++; +} +static inline void inc_frontswap_succ_stores(void) { + frontswap_succ_stores++; +} +static inline void inc_frontswap_failed_stores(void) { + frontswap_failed_stores++; +} +static inline void inc_frontswap_invalidates(void) { + frontswap_invalidates++; +} +#else +static inline void inc_frontswap_loads(void) { } +static inline void inc_frontswap_succ_stores(void) { } +static inline void inc_frontswap_failed_stores(void) { } +static inline void inc_frontswap_invalidates(void) { } +#endif +/* + * Register operations for frontswap, returning previous thus allowing + * detection of multiple backends and possible nesting. + */ +struct frontswap_ops frontswap_register_ops(struct frontswap_ops *ops) +{ + struct frontswap_ops old = frontswap_ops; + + frontswap_ops = *ops; + frontswap_enabled = true; + return old; +} +EXPORT_SYMBOL(frontswap_register_ops); + +/* + * Enable/disable frontswap writethrough (see above). + */ +void frontswap_writethrough(bool enable) +{ + frontswap_writethrough_enabled = enable; +} +EXPORT_SYMBOL(frontswap_writethrough); + +/* + * Called when a swap device is swapon'd. + */ +void __frontswap_init(unsigned type) +{ + struct swap_info_struct *sis = swap_info[type]; + + BUG_ON(sis == NULL); + if (sis->frontswap_map == NULL) + return; + if (frontswap_enabled) + (*frontswap_ops.init)(type); +} +EXPORT_SYMBOL(__frontswap_init); + +/* + * "Store" data from a page to frontswap and associate it with the page's + * swaptype and offset. Page must be locked and in the swap cache. + * If frontswap already contains a page with matching swaptype and + * offset, the frontswap implmentation may either overwrite the data and + * return success or invalidate the page from frontswap and return failure. + */ +int __frontswap_store(struct page *page) +{ + int ret = -1, dup = 0; + swp_entry_t entry = { .val = page_private(page), }; + int type = swp_type(entry); + struct swap_info_struct *sis = swap_info[type]; + pgoff_t offset = swp_offset(entry); + + BUG_ON(!PageLocked(page)); + BUG_ON(sis == NULL); + if (frontswap_test(sis, offset)) + dup = 1; + ret = (*frontswap_ops.store)(type, offset, page); + if (ret == 0) { + frontswap_set(sis, offset); + inc_frontswap_succ_stores(); + if (!dup) + atomic_inc(&sis->frontswap_pages); + } else if (dup) { + /* + failed dup always results in automatic invalidate of + the (older) page from frontswap + */ + frontswap_clear(sis, offset); + atomic_dec(&sis->frontswap_pages); + inc_frontswap_failed_stores(); + } else + inc_frontswap_failed_stores(); + if (frontswap_writethrough_enabled) + /* report failure so swap also writes to swap device */ + ret = -1; + return ret; +} +EXPORT_SYMBOL(__frontswap_store); + +/* + * "Get" data from frontswap associated with swaptype and offset that were + * specified when the data was put to frontswap and use it to fill the + * specified page with data. Page must be locked and in the swap cache. + */ +int __frontswap_load(struct page *page) +{ + int ret = -1; + swp_entry_t entry = { .val = page_private(page), }; + int type = swp_type(entry); + struct swap_info_struct *sis = swap_info[type]; + pgoff_t offset = swp_offset(entry); + + BUG_ON(!PageLocked(page)); + BUG_ON(sis == NULL); + if (frontswap_test(sis, offset)) + ret = (*frontswap_ops.load)(type, offset, page); + if (ret == 0) + inc_frontswap_loads(); + return ret; +} +EXPORT_SYMBOL(__frontswap_load); + +/* + * Invalidate any data from frontswap associated with the specified swaptype + * and offset so that a subsequent "get" will fail. + */ +void __frontswap_invalidate_page(unsigned type, pgoff_t offset) +{ + struct swap_info_struct *sis = swap_info[type]; + + BUG_ON(sis == NULL); + if (frontswap_test(sis, offset)) { + (*frontswap_ops.invalidate_page)(type, offset); + atomic_dec(&sis->frontswap_pages); + frontswap_clear(sis, offset); + inc_frontswap_invalidates(); + } +} +EXPORT_SYMBOL(__frontswap_invalidate_page); + +/* + * Invalidate all data from frontswap associated with all offsets for the + * specified swaptype. + */ +void __frontswap_invalidate_area(unsigned type) +{ + struct swap_info_struct *sis = swap_info[type]; + + BUG_ON(sis == NULL); + if (sis->frontswap_map == NULL) + return; + (*frontswap_ops.invalidate_area)(type); + atomic_set(&sis->frontswap_pages, 0); + memset(sis->frontswap_map, 0, sis->max / sizeof(long)); +} +EXPORT_SYMBOL(__frontswap_invalidate_area); + +/* + * Frontswap, like a true swap device, may unnecessarily retain pages + * under certain circumstances; "shrink" frontswap is essentially a + * "partial swapoff" and works by calling try_to_unuse to attempt to + * unuse enough frontswap pages to attempt to -- subject to memory + * constraints -- reduce the number of pages in frontswap to the + * number given in the parameter target_pages. + */ +void frontswap_shrink(unsigned long target_pages) +{ + struct swap_info_struct *si = NULL; + int si_frontswap_pages; + unsigned long total_pages = 0, total_pages_to_unuse; + unsigned long pages = 0, pages_to_unuse = 0; + int type; + bool locked = false; + + /* + * we don't want to hold swap_lock while doing a very + * lengthy try_to_unuse, but swap_list may change + * so restart scan from swap_list.head each time + */ + spin_lock(&swap_lock); + locked = true; + total_pages = 0; + for (type = swap_list.head; type >= 0; type = si->next) { + si = swap_info[type]; + total_pages += atomic_read(&si->frontswap_pages); + } + if (total_pages <= target_pages) + goto out; + total_pages_to_unuse = total_pages - target_pages; + for (type = swap_list.head; type >= 0; type = si->next) { + si = swap_info[type]; + si_frontswap_pages = atomic_read(&si->frontswap_pages); + if (total_pages_to_unuse < si_frontswap_pages) + pages = pages_to_unuse = total_pages_to_unuse; + else { + pages = si_frontswap_pages; + pages_to_unuse = 0; /* unuse all */ + } + /* ensure there is enough RAM to fetch pages from frontswap */ + if (security_vm_enough_memory_mm(current->mm, pages)) + continue; + vm_unacct_memory(pages); + break; + } + if (type < 0) + goto out; + locked = false; + spin_unlock(&swap_lock); + try_to_unuse(type, true, pages_to_unuse); +out: + if (locked) + spin_unlock(&swap_lock); + return; +} +EXPORT_SYMBOL(frontswap_shrink); + +/* + * Count and return the number of frontswap pages across all + * swap devices. This is exported so that backend drivers can + * determine current usage without reading debugfs. + */ +unsigned long frontswap_curr_pages(void) +{ + int type; + unsigned long totalpages = 0; + struct swap_info_struct *si = NULL; + + spin_lock(&swap_lock); + for (type = swap_list.head; type >= 0; type = si->next) { + si = swap_info[type]; + totalpages += atomic_read(&si->frontswap_pages); + } + spin_unlock(&swap_lock); + return totalpages; +} +EXPORT_SYMBOL(frontswap_curr_pages); + +static int __init init_frontswap(void) +{ +#ifdef CONFIG_DEBUG_FS + struct dentry *root = debugfs_create_dir("frontswap", NULL); + if (root == NULL) + return -ENXIO; + debugfs_create_u64("loads", S_IRUGO, root, &frontswap_loads); + debugfs_create_u64("succ_stores", S_IRUGO, root, &frontswap_succ_stores); + debugfs_create_u64("failed_stores", S_IRUGO, root, + &frontswap_failed_stores); + debugfs_create_u64("invalidates", S_IRUGO, + root, &frontswap_invalidates); +#endif + return 0; +} + +module_init(init_frontswap); diff --git a/trunk/mm/internal.h b/trunk/mm/internal.h index 5cbb78190041..2ba87fbfb75b 100644 --- a/trunk/mm/internal.h +++ b/trunk/mm/internal.h @@ -94,9 +94,6 @@ extern void putback_lru_page(struct page *page); /* * in mm/page_alloc.c */ -extern void set_pageblock_migratetype(struct page *page, int migratetype); -extern int move_freepages_block(struct zone *zone, struct page *page, - int migratetype); extern void __free_pages_bootmem(struct page *page, unsigned int order); extern void prep_compound_page(struct page *page, unsigned long order); #ifdef CONFIG_MEMORY_FAILURE @@ -104,7 +101,6 @@ extern bool is_free_buddy_page(struct page *page); #endif #if defined CONFIG_COMPACTION || defined CONFIG_CMA -#include /* * in mm/compaction.c @@ -123,14 +119,11 @@ struct compact_control { unsigned long nr_migratepages; /* Number of pages to migrate */ unsigned long free_pfn; /* isolate_freepages search base */ unsigned long migrate_pfn; /* isolate_migratepages search base */ - enum compact_mode mode; /* Compaction mode */ + bool sync; /* Synchronous migration */ int order; /* order a direct compactor needs */ int migratetype; /* MOVABLE, RECLAIMABLE etc */ struct zone *zone; - - /* Number of UNMOVABLE destination pageblocks skipped during scan */ - unsigned long nr_pageblocks_skipped; }; unsigned long diff --git a/trunk/mm/migrate.c b/trunk/mm/migrate.c index ab81d482ae6f..be26d5cbe56b 100644 --- a/trunk/mm/migrate.c +++ b/trunk/mm/migrate.c @@ -436,7 +436,10 @@ void migrate_page_copy(struct page *newpage, struct page *page) * is actually a signal that all of the page has become dirty. * Whereas only part of our page may be dirty. */ - __set_page_dirty_nobuffers(newpage); + if (PageSwapBacked(page)) + SetPageDirty(newpage); + else + __set_page_dirty_nobuffers(newpage); } mlock_migrate_page(newpage, page); diff --git a/trunk/mm/nommu.c b/trunk/mm/nommu.c index c4acfbc09972..d4b0c10872de 100644 --- a/trunk/mm/nommu.c +++ b/trunk/mm/nommu.c @@ -1486,7 +1486,7 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - ret = vm_mmap_pgoff(file, addr, len, prot, flags, pgoff); + retval = vm_mmap_pgoff(file, addr, len, prot, flags, pgoff); if (file) fput(file); diff --git a/trunk/mm/oom_kill.c b/trunk/mm/oom_kill.c index ed0e19677360..416637f0e924 100644 --- a/trunk/mm/oom_kill.c +++ b/trunk/mm/oom_kill.c @@ -183,7 +183,7 @@ static bool oom_unkillable_task(struct task_struct *p, unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg, const nodemask_t *nodemask, unsigned long totalpages) { - unsigned long points; + long points; if (oom_unkillable_task(p, memcg, nodemask)) return 0; @@ -223,7 +223,7 @@ unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg, * Never return 0 for an eligible task regardless of the root bonus and * oom_score_adj (oom_score_adj can't be OOM_SCORE_ADJ_MIN here). */ - return points ? points : 1; + return points > 0 ? points : 1; } /* diff --git a/trunk/mm/page_alloc.c b/trunk/mm/page_alloc.c index 6092f331b32e..44030096da63 100644 --- a/trunk/mm/page_alloc.c +++ b/trunk/mm/page_alloc.c @@ -219,7 +219,7 @@ EXPORT_SYMBOL(nr_online_nodes); int page_group_by_mobility_disabled __read_mostly; -void set_pageblock_migratetype(struct page *page, int migratetype) +static void set_pageblock_migratetype(struct page *page, int migratetype) { if (unlikely(page_group_by_mobility_disabled)) @@ -954,8 +954,8 @@ static int move_freepages(struct zone *zone, return pages_moved; } -int move_freepages_block(struct zone *zone, struct page *page, - int migratetype) +static int move_freepages_block(struct zone *zone, struct page *page, + int migratetype) { unsigned long start_pfn, end_pfn; struct page *start_page, *end_page; @@ -5651,7 +5651,7 @@ static int __alloc_contig_migrate_range(unsigned long start, unsigned long end) .nr_migratepages = 0, .order = -1, .zone = page_zone(pfn_to_page(start)), - .mode = COMPACT_SYNC, + .sync = true, }; INIT_LIST_HEAD(&cc.migratepages); diff --git a/trunk/mm/page_io.c b/trunk/mm/page_io.c index dc76b4d0611e..34f02923744c 100644 --- a/trunk/mm/page_io.c +++ b/trunk/mm/page_io.c @@ -18,6 +18,7 @@ #include #include #include +#include #include static struct bio *get_swap_bio(gfp_t gfp_flags, @@ -98,6 +99,12 @@ int swap_writepage(struct page *page, struct writeback_control *wbc) unlock_page(page); goto out; } + if (frontswap_store(page) == 0) { + set_page_writeback(page); + unlock_page(page); + end_page_writeback(page); + goto out; + } bio = get_swap_bio(GFP_NOIO, page, end_swap_bio_write); if (bio == NULL) { set_page_dirty(page); @@ -122,6 +129,11 @@ int swap_readpage(struct page *page) VM_BUG_ON(!PageLocked(page)); VM_BUG_ON(PageUptodate(page)); + if (frontswap_load(page) == 0) { + SetPageUptodate(page); + unlock_page(page); + goto out; + } bio = get_swap_bio(GFP_KERNEL, page, end_swap_bio_read); if (bio == NULL) { unlock_page(page); diff --git a/trunk/mm/shmem.c b/trunk/mm/shmem.c index 585bd220a21e..a15a466d0d1d 100644 --- a/trunk/mm/shmem.c +++ b/trunk/mm/shmem.c @@ -683,10 +683,21 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, mutex_lock(&shmem_swaplist_mutex); /* * We needed to drop mutex to make that restrictive page - * allocation; but the inode might already be freed by now, - * and we cannot refer to inode or mapping or info to check. - * However, we do hold page lock on the PageSwapCache page, - * so can check if that still has our reference remaining. + * allocation, but the inode might have been freed while we + * dropped it: although a racing shmem_evict_inode() cannot + * complete without emptying the radix_tree, our page lock + * on this swapcache page is not enough to prevent that - + * free_swap_and_cache() of our swap entry will only + * trylock_page(), removing swap from radix_tree whatever. + * + * We must not proceed to shmem_add_to_page_cache() if the + * inode has been freed, but of course we cannot rely on + * inode or mapping or info to check that. However, we can + * safely check if our swap entry is still in use (and here + * it can't have got reused for another page): if it's still + * in use, then the inode cannot have been freed yet, and we + * can safely proceed (if it's no longer in use, that tells + * nothing about the inode, but we don't need to unuse swap). */ if (!page_swapcount(*pagep)) error = -ENOENT; @@ -730,9 +741,9 @@ int shmem_unuse(swp_entry_t swap, struct page *page) /* * There's a faint possibility that swap page was replaced before - * caller locked it: it will come back later with the right page. + * caller locked it: caller will come back later with the right page. */ - if (unlikely(!PageSwapCache(page))) + if (unlikely(!PageSwapCache(page) || page_private(page) != swap.val)) goto out; /* @@ -995,21 +1006,15 @@ static int shmem_replace_page(struct page **pagep, gfp_t gfp, newpage = shmem_alloc_page(gfp, info, index); if (!newpage) return -ENOMEM; - VM_BUG_ON(shmem_should_replace_page(newpage, gfp)); - *pagep = newpage; page_cache_get(newpage); copy_highpage(newpage, oldpage); + flush_dcache_page(newpage); - VM_BUG_ON(!PageLocked(oldpage)); __set_page_locked(newpage); - VM_BUG_ON(!PageUptodate(oldpage)); SetPageUptodate(newpage); - VM_BUG_ON(!PageSwapBacked(oldpage)); SetPageSwapBacked(newpage); - VM_BUG_ON(!swap_index); set_page_private(newpage, swap_index); - VM_BUG_ON(!PageSwapCache(oldpage)); SetPageSwapCache(newpage); /* @@ -1019,13 +1024,24 @@ static int shmem_replace_page(struct page **pagep, gfp_t gfp, spin_lock_irq(&swap_mapping->tree_lock); error = shmem_radix_tree_replace(swap_mapping, swap_index, oldpage, newpage); - __inc_zone_page_state(newpage, NR_FILE_PAGES); - __dec_zone_page_state(oldpage, NR_FILE_PAGES); + if (!error) { + __inc_zone_page_state(newpage, NR_FILE_PAGES); + __dec_zone_page_state(oldpage, NR_FILE_PAGES); + } spin_unlock_irq(&swap_mapping->tree_lock); - BUG_ON(error); - mem_cgroup_replace_page_cache(oldpage, newpage); - lru_cache_add_anon(newpage); + if (unlikely(error)) { + /* + * Is this possible? I think not, now that our callers check + * both PageSwapCache and page_private after getting page lock; + * but be defensive. Reverse old to newpage for clear and free. + */ + oldpage = newpage; + } else { + mem_cgroup_replace_page_cache(oldpage, newpage); + lru_cache_add_anon(newpage); + *pagep = newpage; + } ClearPageSwapCache(oldpage); set_page_private(oldpage, 0); @@ -1033,7 +1049,7 @@ static int shmem_replace_page(struct page **pagep, gfp_t gfp, unlock_page(oldpage); page_cache_release(oldpage); page_cache_release(oldpage); - return 0; + return error; } /* @@ -1107,7 +1123,8 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index, /* We have to do this with page locked to prevent races */ lock_page(page); - if (!PageSwapCache(page) || page->mapping) { + if (!PageSwapCache(page) || page_private(page) != swap.val || + page->mapping) { error = -EEXIST; /* try again */ goto failed; } diff --git a/trunk/mm/swapfile.c b/trunk/mm/swapfile.c index 457b10baef59..de5bc51c4a66 100644 --- a/trunk/mm/swapfile.c +++ b/trunk/mm/swapfile.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -42,7 +44,7 @@ static bool swap_count_continued(struct swap_info_struct *, pgoff_t, static void free_swap_count_continuations(struct swap_info_struct *); static sector_t map_swap_entry(swp_entry_t, struct block_device**); -static DEFINE_SPINLOCK(swap_lock); +DEFINE_SPINLOCK(swap_lock); static unsigned int nr_swapfiles; long nr_swap_pages; long total_swap_pages; @@ -53,9 +55,9 @@ static const char Unused_file[] = "Unused swap file entry "; static const char Bad_offset[] = "Bad swap offset entry "; static const char Unused_offset[] = "Unused swap offset entry "; -static struct swap_list_t swap_list = {-1, -1}; +struct swap_list_t swap_list = {-1, -1}; -static struct swap_info_struct *swap_info[MAX_SWAPFILES]; +struct swap_info_struct *swap_info[MAX_SWAPFILES]; static DEFINE_MUTEX(swapon_mutex); @@ -556,6 +558,7 @@ static unsigned char swap_entry_free(struct swap_info_struct *p, swap_list.next = p->type; nr_swap_pages++; p->inuse_pages--; + frontswap_invalidate_page(p->type, offset); if ((p->flags & SWP_BLKDEV) && disk->fops->swap_slot_free_notify) disk->fops->swap_slot_free_notify(p->bdev, offset); @@ -985,11 +988,12 @@ static int unuse_mm(struct mm_struct *mm, } /* - * Scan swap_map from current position to next entry still in use. + * Scan swap_map (or frontswap_map if frontswap parameter is true) + * from current position to next entry still in use. * Recycle to start on reaching the end, returning 0 when empty. */ static unsigned int find_next_to_unuse(struct swap_info_struct *si, - unsigned int prev) + unsigned int prev, bool frontswap) { unsigned int max = si->max; unsigned int i = prev; @@ -1015,6 +1019,12 @@ static unsigned int find_next_to_unuse(struct swap_info_struct *si, prev = 0; i = 1; } + if (frontswap) { + if (frontswap_test(si, i)) + break; + else + continue; + } count = si->swap_map[i]; if (count && swap_count(count) != SWAP_MAP_BAD) break; @@ -1026,8 +1036,12 @@ static unsigned int find_next_to_unuse(struct swap_info_struct *si, * We completely avoid races by reading each swap page in advance, * and then search for the process using it. All the necessary * page table adjustments can then be made atomically. + * + * if the boolean frontswap is true, only unuse pages_to_unuse pages; + * pages_to_unuse==0 means all pages; ignored if frontswap is false */ -static int try_to_unuse(unsigned int type) +int try_to_unuse(unsigned int type, bool frontswap, + unsigned long pages_to_unuse) { struct swap_info_struct *si = swap_info[type]; struct mm_struct *start_mm; @@ -1060,7 +1074,7 @@ static int try_to_unuse(unsigned int type) * one pass through swap_map is enough, but not necessarily: * there are races when an instance of an entry might be missed. */ - while ((i = find_next_to_unuse(si, i)) != 0) { + while ((i = find_next_to_unuse(si, i, frontswap)) != 0) { if (signal_pending(current)) { retval = -EINTR; break; @@ -1227,6 +1241,10 @@ static int try_to_unuse(unsigned int type) * interactive performance. */ cond_resched(); + if (frontswap && pages_to_unuse > 0) { + if (!--pages_to_unuse) + break; + } } mmput(start_mm); @@ -1486,7 +1504,8 @@ static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span) } static void enable_swap_info(struct swap_info_struct *p, int prio, - unsigned char *swap_map) + unsigned char *swap_map, + unsigned long *frontswap_map) { int i, prev; @@ -1496,6 +1515,7 @@ static void enable_swap_info(struct swap_info_struct *p, int prio, else p->prio = --least_priority; p->swap_map = swap_map; + frontswap_map_set(p, frontswap_map); p->flags |= SWP_WRITEOK; nr_swap_pages += p->pages; total_swap_pages += p->pages; @@ -1512,6 +1532,7 @@ static void enable_swap_info(struct swap_info_struct *p, int prio, swap_list.head = swap_list.next = p->type; else swap_info[prev]->next = p->type; + frontswap_init(p->type); spin_unlock(&swap_lock); } @@ -1585,7 +1606,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) spin_unlock(&swap_lock); oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX); - err = try_to_unuse(type); + err = try_to_unuse(type, false, 0); /* force all pages to be unused */ compare_swap_oom_score_adj(OOM_SCORE_ADJ_MAX, oom_score_adj); if (err) { @@ -1596,7 +1617,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) * sys_swapoff for this swap_info_struct at this point. */ /* re-insert swap space back into swap_list */ - enable_swap_info(p, p->prio, p->swap_map); + enable_swap_info(p, p->prio, p->swap_map, frontswap_map_get(p)); goto out_dput; } @@ -1622,9 +1643,11 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) swap_map = p->swap_map; p->swap_map = NULL; p->flags = 0; + frontswap_invalidate_area(type); spin_unlock(&swap_lock); mutex_unlock(&swapon_mutex); vfree(swap_map); + vfree(frontswap_map_get(p)); /* Destroy swap account informatin */ swap_cgroup_swapoff(type); @@ -1988,6 +2011,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) sector_t span; unsigned long maxpages; unsigned char *swap_map = NULL; + unsigned long *frontswap_map = NULL; struct page *page = NULL; struct inode *inode = NULL; @@ -2071,6 +2095,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = nr_extents; goto bad_swap; } + /* frontswap enabled? set up bit-per-page map for frontswap */ + if (frontswap_enabled) + frontswap_map = vzalloc(maxpages / sizeof(long)); if (p->bdev) { if (blk_queue_nonrot(bdev_get_queue(p->bdev))) { @@ -2086,14 +2113,15 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) if (swap_flags & SWAP_FLAG_PREFER) prio = (swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT; - enable_swap_info(p, prio, swap_map); + enable_swap_info(p, prio, swap_map, frontswap_map); printk(KERN_INFO "Adding %uk swap on %s. " - "Priority:%d extents:%d across:%lluk %s%s\n", + "Priority:%d extents:%d across:%lluk %s%s%s\n", p->pages<<(PAGE_SHIFT-10), name, p->prio, nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10), (p->flags & SWP_SOLIDSTATE) ? "SS" : "", - (p->flags & SWP_DISCARDABLE) ? "D" : ""); + (p->flags & SWP_DISCARDABLE) ? "D" : "", + (frontswap_map) ? "FS" : ""); mutex_unlock(&swapon_mutex); atomic_inc(&proc_poll_event); diff --git a/trunk/sound/soc/codecs/Kconfig b/trunk/sound/soc/codecs/Kconfig index 43f5240e6942..1e1613a438dd 100644 --- a/trunk/sound/soc/codecs/Kconfig +++ b/trunk/sound/soc/codecs/Kconfig @@ -12,7 +12,6 @@ config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" select SND_SOC_88PM860X if MFD_88PM860X select SND_SOC_L3 - select SND_SOC_AB8500_CODEC if ABX500_CORE select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS select SND_SOC_AD1836 if SPI_MASTER select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI @@ -36,9 +35,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI select SND_SOC_CX20442 select SND_SOC_DA7210 if I2C - select SND_SOC_DA732X if I2C select SND_SOC_DFBMCS320 - select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C select SND_SOC_LM49453 if I2C @@ -134,9 +131,6 @@ config SND_SOC_WM_HUBS default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m -config SND_SOC_AB8500_CODEC - tristate - config SND_SOC_AC97_CODEC tristate select SND_AC97_CODEC @@ -225,18 +219,12 @@ config SND_SOC_L3 config SND_SOC_DA7210 tristate -config SND_SOC_DA732X - tristate - config SND_SOC_DFBMCS320 tristate config SND_SOC_DMIC tristate -config SND_SOC_ISABELLE - tristate - config SND_SOC_LM49453 tristate diff --git a/trunk/sound/soc/codecs/Makefile b/trunk/sound/soc/codecs/Makefile index 3d30654f6fcc..fc27fec39487 100644 --- a/trunk/sound/soc/codecs/Makefile +++ b/trunk/sound/soc/codecs/Makefile @@ -1,5 +1,4 @@ snd-soc-88pm860x-objs := 88pm860x-codec.o -snd-soc-ab8500-codec-objs := ab8500-codec.o snd-soc-ac97-objs := ac97.o snd-soc-ad1836-objs := ad1836.o snd-soc-ad193x-objs := ad193x.o @@ -22,10 +21,8 @@ snd-soc-cs4270-objs := cs4270.o snd-soc-cs4271-objs := cs4271.o snd-soc-cx20442-objs := cx20442.o snd-soc-da7210-objs := da7210.o -snd-soc-da732x-objs := da732x.o snd-soc-dfbmcs320-objs := dfbmcs320.o snd-soc-dmic-objs := dmic.o -snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o snd-soc-lm4857-objs := lm4857.o @@ -111,7 +108,6 @@ snd-soc-max9877-objs := max9877.o snd-soc-tpa6130a2-objs := tpa6130a2.o obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o -obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o @@ -136,10 +132,8 @@ obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o -obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o -obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.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 diff --git a/trunk/sound/soc/codecs/ab8500-codec.c b/trunk/sound/soc/codecs/ab8500-codec.c deleted file mode 100644 index 95dc7d5bb076..000000000000 --- a/trunk/sound/soc/codecs/ab8500-codec.c +++ /dev/null @@ -1,2521 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2012 - * - * Author: Ola Lilja , - * Kristoffer Karlsson , - * Roger Nilsson , - * for ST-Ericsson. - * - * Based on the early work done by: - * Mikko J. Lehto , - * Mikko Sarmanne , - * Jarmo K. Kuronen , - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "ab8500-codec.h" - -/* Macrocell value definitions */ -#define CLK_32K_OUT2_DISABLE 0x01 -#define INACTIVE_RESET_AUDIO 0x02 -#define ENABLE_AUDIO_CLK_TO_AUDIO_BLK 0x10 -#define ENABLE_VINTCORE12_SUPPLY 0x04 -#define GPIO27_DIR_OUTPUT 0x04 -#define GPIO29_DIR_OUTPUT 0x10 -#define GPIO31_DIR_OUTPUT 0x40 - -/* Macrocell register definitions */ -#define AB8500_CTRL3_REG 0x0200 -#define AB8500_GPIO_DIR4_REG 0x1013 - -/* Nr of FIR/IIR-coeff banks in ANC-block */ -#define AB8500_NR_OF_ANC_COEFF_BANKS 2 - -/* Minimum duration to keep ANC IIR Init bit high or -low before proceeding with the configuration sequence */ -#define AB8500_ANC_SM_DELAY 2000 - -#define AB8500_FILTER_CONTROL(xname, xcount, xmin, xmax) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ - .info = filter_control_info, \ - .get = filter_control_get, .put = filter_control_put, \ - .private_value = (unsigned long)&(struct filter_control) \ - {.count = xcount, .min = xmin, .max = xmax} } - -struct filter_control { - long min, max; - unsigned int count; - long value[128]; -}; - -/* Sidetone states */ -static const char * const enum_sid_state[] = { - "Unconfigured", - "Apply FIR", - "FIR is configured", -}; -enum sid_state { - SID_UNCONFIGURED = 0, - SID_APPLY_FIR = 1, - SID_FIR_CONFIGURED = 2, -}; - -static const char * const enum_anc_state[] = { - "Unconfigured", - "Apply FIR and IIR", - "FIR and IIR are configured", - "Apply FIR", - "FIR is configured", - "Apply IIR", - "IIR is configured" -}; -enum anc_state { - ANC_UNCONFIGURED = 0, - ANC_APPLY_FIR_IIR = 1, - ANC_FIR_IIR_CONFIGURED = 2, - ANC_APPLY_FIR = 3, - ANC_FIR_CONFIGURED = 4, - ANC_APPLY_IIR = 5, - ANC_IIR_CONFIGURED = 6 -}; - -/* Analog microphones */ -enum amic_idx { - AMIC_IDX_1A, - AMIC_IDX_1B, - AMIC_IDX_2 -}; - -struct ab8500_codec_drvdata_dbg { - struct regulator *vaud; - struct regulator *vamic1; - struct regulator *vamic2; - struct regulator *vdmic; -}; - -/* Private data for AB8500 device-driver */ -struct ab8500_codec_drvdata { - /* Sidetone */ - long *sid_fir_values; - enum sid_state sid_status; - - /* ANC */ - struct mutex anc_lock; - long *anc_fir_values; - long *anc_iir_values; - enum anc_state anc_status; -}; - -static inline const char *amic_micbias_str(enum amic_micbias micbias) -{ - switch (micbias) { - case AMIC_MICBIAS_VAMIC1: - return "VAMIC1"; - case AMIC_MICBIAS_VAMIC2: - return "VAMIC2"; - default: - return "Unknown"; - } -} - -static inline const char *amic_type_str(enum amic_type type) -{ - switch (type) { - case AMIC_TYPE_DIFFERENTIAL: - return "DIFFERENTIAL"; - case AMIC_TYPE_SINGLE_ENDED: - return "SINGLE ENDED"; - default: - return "Unknown"; - } -} - -/* - * Read'n'write functions - */ - -/* Read a register from the audio-bank of AB8500 */ -static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec, - unsigned int reg) -{ - int status; - unsigned int value = 0; - - u8 value8; - status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO, - reg, &value8); - if (status < 0) { - dev_err(codec->dev, - "%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n", - __func__, (u8)AB8500_AUDIO, (u8)reg, status); - } else { - dev_dbg(codec->dev, - "%s: Read 0x%02x from register 0x%02x:0x%02x\n", - __func__, value8, (u8)AB8500_AUDIO, (u8)reg); - value = (unsigned int)value8; - } - - return value; -} - -/* Write to a register in the audio-bank of AB8500 */ -static int ab8500_codec_write_reg(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - int status; - - status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO, - reg, value); - if (status < 0) - dev_err(codec->dev, - "%s: ERROR: Register (%02x:%02x) write failed (%d).\n", - __func__, (u8)AB8500_AUDIO, (u8)reg, status); - else - dev_dbg(codec->dev, - "%s: Wrote 0x%02x into register %02x:%02x\n", - __func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg); - - return status; -} - -/* - * Controls - DAPM - */ - -/* Earpiece */ - -/* Earpiece source selector */ -static const char * const enum_ear_lineout_source[] = {"Headset Left", - "Speaker Left"}; -static SOC_ENUM_SINGLE_DECL(dapm_enum_ear_lineout_source, AB8500_DMICFILTCONF, - AB8500_DMICFILTCONF_DA3TOEAR, enum_ear_lineout_source); -static const struct snd_kcontrol_new dapm_ear_lineout_source = - SOC_DAPM_ENUM("Earpiece or LineOut Mono Source", - dapm_enum_ear_lineout_source); - -/* LineOut */ - -/* LineOut source selector */ -static const char * const enum_lineout_source[] = {"Mono Path", "Stereo Path"}; -static SOC_ENUM_DOUBLE_DECL(dapm_enum_lineout_source, AB8500_ANACONF5, - AB8500_ANACONF5_HSLDACTOLOL, - AB8500_ANACONF5_HSRDACTOLOR, enum_lineout_source); -static const struct snd_kcontrol_new dapm_lineout_source[] = { - SOC_DAPM_ENUM("LineOut Source", dapm_enum_lineout_source), -}; - -/* Handsfree */ - -/* Speaker Left - ANC selector */ -static const char * const enum_HFx_sel[] = {"Audio Path", "ANC"}; -static SOC_ENUM_SINGLE_DECL(dapm_enum_HFl_sel, AB8500_DIGMULTCONF2, - AB8500_DIGMULTCONF2_HFLSEL, enum_HFx_sel); -static const struct snd_kcontrol_new dapm_HFl_select[] = { - SOC_DAPM_ENUM("Speaker Left Source", dapm_enum_HFl_sel), -}; - -/* Speaker Right - ANC selector */ -static SOC_ENUM_SINGLE_DECL(dapm_enum_HFr_sel, AB8500_DIGMULTCONF2, - AB8500_DIGMULTCONF2_HFRSEL, enum_HFx_sel); -static const struct snd_kcontrol_new dapm_HFr_select[] = { - SOC_DAPM_ENUM("Speaker Right Source", dapm_enum_HFr_sel), -}; - -/* Mic 1 */ - -/* Mic 1 - Mic 1a or 1b selector */ -static const char * const enum_mic1ab_sel[] = {"Mic 1b", "Mic 1a"}; -static SOC_ENUM_SINGLE_DECL(dapm_enum_mic1ab_sel, AB8500_ANACONF3, - AB8500_ANACONF3_MIC1SEL, enum_mic1ab_sel); -static const struct snd_kcontrol_new dapm_mic1ab_mux[] = { - SOC_DAPM_ENUM("Mic 1a or 1b Select", dapm_enum_mic1ab_sel), -}; - -/* Mic 1 - AD3 - Mic 1 or DMic 3 selector */ -static const char * const enum_ad3_sel[] = {"Mic 1", "DMic 3"}; -static SOC_ENUM_SINGLE_DECL(dapm_enum_ad3_sel, AB8500_DIGMULTCONF1, - AB8500_DIGMULTCONF1_AD3SEL, enum_ad3_sel); -static const struct snd_kcontrol_new dapm_ad3_select[] = { - SOC_DAPM_ENUM("AD3 Source Select", dapm_enum_ad3_sel), -}; - -/* Mic 1 - AD6 - Mic 1 or DMic 6 selector */ -static const char * const enum_ad6_sel[] = {"Mic 1", "DMic 6"}; -static SOC_ENUM_SINGLE_DECL(dapm_enum_ad6_sel, AB8500_DIGMULTCONF1, - AB8500_DIGMULTCONF1_AD6SEL, enum_ad6_sel); -static const struct snd_kcontrol_new dapm_ad6_select[] = { - SOC_DAPM_ENUM("AD6 Source Select", dapm_enum_ad6_sel), -}; - -/* Mic 2 */ - -/* Mic 2 - AD5 - Mic 2 or DMic 5 selector */ -static const char * const enum_ad5_sel[] = {"Mic 2", "DMic 5"}; -static SOC_ENUM_SINGLE_DECL(dapm_enum_ad5_sel, AB8500_DIGMULTCONF1, - AB8500_DIGMULTCONF1_AD5SEL, enum_ad5_sel); -static const struct snd_kcontrol_new dapm_ad5_select[] = { - SOC_DAPM_ENUM("AD5 Source Select", dapm_enum_ad5_sel), -}; - -/* LineIn */ - -/* LineIn left - AD1 - LineIn Left or DMic 1 selector */ -static const char * const enum_ad1_sel[] = {"LineIn Left", "DMic 1"}; -static SOC_ENUM_SINGLE_DECL(dapm_enum_ad1_sel, AB8500_DIGMULTCONF1, - AB8500_DIGMULTCONF1_AD1SEL, enum_ad1_sel); -static const struct snd_kcontrol_new dapm_ad1_select[] = { - SOC_DAPM_ENUM("AD1 Source Select", dapm_enum_ad1_sel), -}; - -/* LineIn right - Mic 2 or LineIn Right selector */ -static const char * const enum_mic2lr_sel[] = {"Mic 2", "LineIn Right"}; -static SOC_ENUM_SINGLE_DECL(dapm_enum_mic2lr_sel, AB8500_ANACONF3, - AB8500_ANACONF3_LINRSEL, enum_mic2lr_sel); -static const struct snd_kcontrol_new dapm_mic2lr_select[] = { - SOC_DAPM_ENUM("Mic 2 or LINR Select", dapm_enum_mic2lr_sel), -}; - -/* LineIn right - AD2 - LineIn Right or DMic2 selector */ -static const char * const enum_ad2_sel[] = {"LineIn Right", "DMic 2"}; -static SOC_ENUM_SINGLE_DECL(dapm_enum_ad2_sel, AB8500_DIGMULTCONF1, - AB8500_DIGMULTCONF1_AD2SEL, enum_ad2_sel); -static const struct snd_kcontrol_new dapm_ad2_select[] = { - SOC_DAPM_ENUM("AD2 Source Select", dapm_enum_ad2_sel), -}; - - -/* ANC */ - -static const char * const enum_anc_in_sel[] = {"Mic 1 / DMic 6", - "Mic 2 / DMic 5"}; -static SOC_ENUM_SINGLE_DECL(dapm_enum_anc_in_sel, AB8500_DMICFILTCONF, - AB8500_DMICFILTCONF_ANCINSEL, enum_anc_in_sel); -static const struct snd_kcontrol_new dapm_anc_in_select[] = { - SOC_DAPM_ENUM("ANC Source", dapm_enum_anc_in_sel), -}; - -/* ANC - Enable/Disable */ -static const struct snd_kcontrol_new dapm_anc_enable[] = { - SOC_DAPM_SINGLE("Switch", AB8500_ANCCONF1, - AB8500_ANCCONF1_ENANC, 0, 0), -}; - -/* ANC to Earpiece - Mute */ -static const struct snd_kcontrol_new dapm_anc_ear_mute[] = { - SOC_DAPM_SINGLE("Switch", AB8500_DIGMULTCONF1, - AB8500_DIGMULTCONF1_ANCSEL, 1, 0), -}; - - - -/* Sidetone left */ - -/* Sidetone left - Input selector */ -static const char * const enum_stfir1_in_sel[] = { - "LineIn Left", "LineIn Right", "Mic 1", "Headset Left" -}; -static SOC_ENUM_SINGLE_DECL(dapm_enum_stfir1_in_sel, AB8500_DIGMULTCONF2, - AB8500_DIGMULTCONF2_FIRSID1SEL, enum_stfir1_in_sel); -static const struct snd_kcontrol_new dapm_stfir1_in_select[] = { - SOC_DAPM_ENUM("Sidetone Left Source", dapm_enum_stfir1_in_sel), -}; - -/* Sidetone right path */ - -/* Sidetone right - Input selector */ -static const char * const enum_stfir2_in_sel[] = { - "LineIn Right", "Mic 1", "DMic 4", "Headset Right" -}; -static SOC_ENUM_SINGLE_DECL(dapm_enum_stfir2_in_sel, AB8500_DIGMULTCONF2, - AB8500_DIGMULTCONF2_FIRSID2SEL, enum_stfir2_in_sel); -static const struct snd_kcontrol_new dapm_stfir2_in_select[] = { - SOC_DAPM_ENUM("Sidetone Right Source", dapm_enum_stfir2_in_sel), -}; - -/* Vibra */ - -static const char * const enum_pwm2vibx[] = {"Audio Path", "PWM Generator"}; - -static SOC_ENUM_SINGLE_DECL(dapm_enum_pwm2vib1, AB8500_PWMGENCONF1, - AB8500_PWMGENCONF1_PWMTOVIB1, enum_pwm2vibx); - -static const struct snd_kcontrol_new dapm_pwm2vib1[] = { - SOC_DAPM_ENUM("Vibra 1 Controller", dapm_enum_pwm2vib1), -}; - -static SOC_ENUM_SINGLE_DECL(dapm_enum_pwm2vib2, AB8500_PWMGENCONF1, - AB8500_PWMGENCONF1_PWMTOVIB2, enum_pwm2vibx); - -static const struct snd_kcontrol_new dapm_pwm2vib2[] = { - SOC_DAPM_ENUM("Vibra 2 Controller", dapm_enum_pwm2vib2), -}; - -/* - * DAPM-widgets - */ - -static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = { - - /* Clocks */ - SND_SOC_DAPM_CLOCK_SUPPLY("audioclk"), - - /* Regulators */ - SND_SOC_DAPM_REGULATOR_SUPPLY("V-AUD", 0), - SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC1", 0), - SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC2", 0), - SND_SOC_DAPM_REGULATOR_SUPPLY("V-DMIC", 0), - - /* Power */ - SND_SOC_DAPM_SUPPLY("Audio Power", - AB8500_POWERUP, AB8500_POWERUP_POWERUP, 0, - NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("Audio Analog Power", - AB8500_POWERUP, AB8500_POWERUP_ENANA, 0, - NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - - /* Main supply node */ - SND_SOC_DAPM_SUPPLY("Main Supply", SND_SOC_NOPM, 0, 0, - NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - - /* DA/AD */ - - SND_SOC_DAPM_INPUT("ADC Input"), - SND_SOC_DAPM_ADC("ADC", "ab8500_0c", SND_SOC_NOPM, 0, 0), - - SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_OUTPUT("DAC Output"), - - SND_SOC_DAPM_AIF_IN("DA_IN1", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("DA_IN2", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("DA_IN3", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("DA_IN4", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("DA_IN5", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("DA_IN6", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("AD_OUT1", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("AD_OUT2", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("AD_OUT3", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("AD_OUT4", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("AD_OUT57", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("AD_OUT68", NULL, 0, SND_SOC_NOPM, 0, 0), - - /* Headset path */ - - SND_SOC_DAPM_SUPPLY("Charge Pump", AB8500_ANACONF5, - AB8500_ANACONF5_ENCPHS, 0, NULL, 0), - - SND_SOC_DAPM_DAC("DA1 Enable", "ab8500_0p", - AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA1, 0), - SND_SOC_DAPM_DAC("DA2 Enable", "ab8500_0p", - AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA2, 0), - - SND_SOC_DAPM_PGA("HSL Digital Volume", SND_SOC_NOPM, 0, 0, - NULL, 0), - SND_SOC_DAPM_PGA("HSR Digital Volume", SND_SOC_NOPM, 0, 0, - NULL, 0), - - SND_SOC_DAPM_DAC("HSL DAC", "ab8500_0p", - AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHSL, 0), - SND_SOC_DAPM_DAC("HSR DAC", "ab8500_0p", - AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHSR, 0), - SND_SOC_DAPM_MIXER("HSL DAC Mute", AB8500_MUTECONF, - AB8500_MUTECONF_MUTDACHSL, 1, - NULL, 0), - SND_SOC_DAPM_MIXER("HSR DAC Mute", AB8500_MUTECONF, - AB8500_MUTECONF_MUTDACHSR, 1, - NULL, 0), - SND_SOC_DAPM_DAC("HSL DAC Driver", "ab8500_0p", - AB8500_ANACONF3, AB8500_ANACONF3_ENDRVHSL, 0), - SND_SOC_DAPM_DAC("HSR DAC Driver", "ab8500_0p", - AB8500_ANACONF3, AB8500_ANACONF3_ENDRVHSR, 0), - - SND_SOC_DAPM_MIXER("HSL Mute", - AB8500_MUTECONF, AB8500_MUTECONF_MUTHSL, 1, - NULL, 0), - SND_SOC_DAPM_MIXER("HSR Mute", - AB8500_MUTECONF, AB8500_MUTECONF_MUTHSR, 1, - NULL, 0), - SND_SOC_DAPM_MIXER("HSL Enable", - AB8500_ANACONF4, AB8500_ANACONF4_ENHSL, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("HSR Enable", - AB8500_ANACONF4, AB8500_ANACONF4_ENHSR, 0, - NULL, 0), - SND_SOC_DAPM_PGA("HSL Volume", - SND_SOC_NOPM, 0, 0, - NULL, 0), - SND_SOC_DAPM_PGA("HSR Volume", - SND_SOC_NOPM, 0, 0, - NULL, 0), - - SND_SOC_DAPM_OUTPUT("Headset Left"), - SND_SOC_DAPM_OUTPUT("Headset Right"), - - /* LineOut path */ - - SND_SOC_DAPM_MUX("LineOut Source", - SND_SOC_NOPM, 0, 0, dapm_lineout_source), - - SND_SOC_DAPM_MIXER("LOL Disable HFL", - AB8500_ANACONF4, AB8500_ANACONF4_ENHFL, 1, - NULL, 0), - SND_SOC_DAPM_MIXER("LOR Disable HFR", - AB8500_ANACONF4, AB8500_ANACONF4_ENHFR, 1, - NULL, 0), - - SND_SOC_DAPM_MIXER("LOL Enable", - AB8500_ANACONF5, AB8500_ANACONF5_ENLOL, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("LOR Enable", - AB8500_ANACONF5, AB8500_ANACONF5_ENLOR, 0, - NULL, 0), - - SND_SOC_DAPM_OUTPUT("LineOut Left"), - SND_SOC_DAPM_OUTPUT("LineOut Right"), - - /* Earpiece path */ - - SND_SOC_DAPM_MUX("Earpiece or LineOut Mono Source", - SND_SOC_NOPM, 0, 0, &dapm_ear_lineout_source), - SND_SOC_DAPM_MIXER("EAR DAC", - AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACEAR, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("EAR Mute", - AB8500_MUTECONF, AB8500_MUTECONF_MUTEAR, 1, - NULL, 0), - SND_SOC_DAPM_MIXER("EAR Enable", - AB8500_ANACONF4, AB8500_ANACONF4_ENEAR, 0, - NULL, 0), - - SND_SOC_DAPM_OUTPUT("Earpiece"), - - /* Handsfree path */ - - SND_SOC_DAPM_MIXER("DA3 Channel Volume", - AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA3, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("DA4 Channel Volume", - AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA4, 0, - NULL, 0), - SND_SOC_DAPM_MUX("Speaker Left Source", - SND_SOC_NOPM, 0, 0, dapm_HFl_select), - SND_SOC_DAPM_MUX("Speaker Right Source", - SND_SOC_NOPM, 0, 0, dapm_HFr_select), - SND_SOC_DAPM_MIXER("HFL DAC", AB8500_DAPATHCONF, - AB8500_DAPATHCONF_ENDACHFL, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("HFR DAC", - AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHFR, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("DA4 or ANC path to HfR", - AB8500_DIGMULTCONF2, AB8500_DIGMULTCONF2_DATOHFREN, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("DA3 or ANC path to HfL", - AB8500_DIGMULTCONF2, AB8500_DIGMULTCONF2_DATOHFLEN, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("HFL Enable", - AB8500_ANACONF4, AB8500_ANACONF4_ENHFL, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("HFR Enable", - AB8500_ANACONF4, AB8500_ANACONF4_ENHFR, 0, - NULL, 0), - - SND_SOC_DAPM_OUTPUT("Speaker Left"), - SND_SOC_DAPM_OUTPUT("Speaker Right"), - - /* Vibrator path */ - - SND_SOC_DAPM_INPUT("PWMGEN1"), - SND_SOC_DAPM_INPUT("PWMGEN2"), - - SND_SOC_DAPM_MIXER("DA5 Channel Volume", - AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA5, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("DA6 Channel Volume", - AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA6, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("VIB1 DAC", - AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACVIB1, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("VIB2 DAC", - AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACVIB2, 0, - NULL, 0), - SND_SOC_DAPM_MUX("Vibra 1 Controller", - SND_SOC_NOPM, 0, 0, dapm_pwm2vib1), - SND_SOC_DAPM_MUX("Vibra 2 Controller", - SND_SOC_NOPM, 0, 0, dapm_pwm2vib2), - SND_SOC_DAPM_MIXER("VIB1 Enable", - AB8500_ANACONF4, AB8500_ANACONF4_ENVIB1, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("VIB2 Enable", - AB8500_ANACONF4, AB8500_ANACONF4_ENVIB2, 0, - NULL, 0), - - SND_SOC_DAPM_OUTPUT("Vibra 1"), - SND_SOC_DAPM_OUTPUT("Vibra 2"), - - /* Mic 1 */ - - SND_SOC_DAPM_INPUT("Mic 1"), - - SND_SOC_DAPM_MUX("Mic 1a or 1b Select", - SND_SOC_NOPM, 0, 0, dapm_mic1ab_mux), - SND_SOC_DAPM_MIXER("MIC1 Mute", - AB8500_ANACONF2, AB8500_ANACONF2_MUTMIC1, 1, - NULL, 0), - SND_SOC_DAPM_MIXER("MIC1A V-AMICx Enable", - AB8500_ANACONF2, AB8500_ANACONF2_ENMIC1, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("MIC1B V-AMICx Enable", - AB8500_ANACONF2, AB8500_ANACONF2_ENMIC1, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("MIC1 ADC", - AB8500_ANACONF3, AB8500_ANACONF3_ENADCMIC, 0, - NULL, 0), - SND_SOC_DAPM_MUX("AD3 Source Select", - SND_SOC_NOPM, 0, 0, dapm_ad3_select), - SND_SOC_DAPM_MIXER("AD3 Channel Volume", - SND_SOC_NOPM, 0, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("AD3 Enable", - AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD34, 0, - NULL, 0), - - /* Mic 2 */ - - SND_SOC_DAPM_INPUT("Mic 2"), - - SND_SOC_DAPM_MIXER("MIC2 Mute", - AB8500_ANACONF2, AB8500_ANACONF2_MUTMIC2, 1, - NULL, 0), - SND_SOC_DAPM_MIXER("MIC2 V-AMICx Enable", AB8500_ANACONF2, - AB8500_ANACONF2_ENMIC2, 0, - NULL, 0), - - /* LineIn */ - - SND_SOC_DAPM_INPUT("LineIn Left"), - SND_SOC_DAPM_INPUT("LineIn Right"), - - SND_SOC_DAPM_MIXER("LINL Mute", - AB8500_ANACONF2, AB8500_ANACONF2_MUTLINL, 1, - NULL, 0), - SND_SOC_DAPM_MIXER("LINR Mute", - AB8500_ANACONF2, AB8500_ANACONF2_MUTLINR, 1, - NULL, 0), - SND_SOC_DAPM_MIXER("LINL Enable", AB8500_ANACONF2, - AB8500_ANACONF2_ENLINL, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("LINR Enable", AB8500_ANACONF2, - AB8500_ANACONF2_ENLINR, 0, - NULL, 0), - - /* LineIn Bypass path */ - SND_SOC_DAPM_MIXER("LINL to HSL Volume", - SND_SOC_NOPM, 0, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("LINR to HSR Volume", - SND_SOC_NOPM, 0, 0, - NULL, 0), - - /* LineIn, Mic 2 */ - SND_SOC_DAPM_MUX("Mic 2 or LINR Select", - SND_SOC_NOPM, 0, 0, dapm_mic2lr_select), - SND_SOC_DAPM_MIXER("LINL ADC", AB8500_ANACONF3, - AB8500_ANACONF3_ENADCLINL, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("LINR ADC", AB8500_ANACONF3, - AB8500_ANACONF3_ENADCLINR, 0, - NULL, 0), - SND_SOC_DAPM_MUX("AD1 Source Select", - SND_SOC_NOPM, 0, 0, dapm_ad1_select), - SND_SOC_DAPM_MUX("AD2 Source Select", - SND_SOC_NOPM, 0, 0, dapm_ad2_select), - SND_SOC_DAPM_MIXER("AD1 Channel Volume", - SND_SOC_NOPM, 0, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("AD2 Channel Volume", - SND_SOC_NOPM, 0, 0, - NULL, 0), - - SND_SOC_DAPM_MIXER("AD12 Enable", - AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD12, 0, - NULL, 0), - - /* HD Capture path */ - - SND_SOC_DAPM_MUX("AD5 Source Select", - SND_SOC_NOPM, 0, 0, dapm_ad5_select), - SND_SOC_DAPM_MUX("AD6 Source Select", - SND_SOC_NOPM, 0, 0, dapm_ad6_select), - SND_SOC_DAPM_MIXER("AD5 Channel Volume", - SND_SOC_NOPM, 0, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("AD6 Channel Volume", - SND_SOC_NOPM, 0, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("AD57 Enable", - AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD5768, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("AD68 Enable", - AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD5768, 0, - NULL, 0), - - /* Digital Microphone path */ - - SND_SOC_DAPM_INPUT("DMic 1"), - SND_SOC_DAPM_INPUT("DMic 2"), - SND_SOC_DAPM_INPUT("DMic 3"), - SND_SOC_DAPM_INPUT("DMic 4"), - SND_SOC_DAPM_INPUT("DMic 5"), - SND_SOC_DAPM_INPUT("DMic 6"), - - SND_SOC_DAPM_MIXER("DMIC1", - AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC1, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("DMIC2", - AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC2, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("DMIC3", - AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC3, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("DMIC4", - AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC4, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("DMIC5", - AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC5, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("DMIC6", - AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC6, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("AD4 Channel Volume", - SND_SOC_NOPM, 0, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("AD4 Enable", - AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD34, - 0, NULL, 0), - - /* Acoustical Noise Cancellation path */ - - SND_SOC_DAPM_INPUT("ANC Configure Input"), - SND_SOC_DAPM_OUTPUT("ANC Configure Output"), - - SND_SOC_DAPM_MUX("ANC Source", - SND_SOC_NOPM, 0, 0, - dapm_anc_in_select), - SND_SOC_DAPM_SWITCH("ANC", - SND_SOC_NOPM, 0, 0, - dapm_anc_enable), - SND_SOC_DAPM_SWITCH("ANC to Earpiece", - SND_SOC_NOPM, 0, 0, - dapm_anc_ear_mute), - - /* Sidetone Filter path */ - - SND_SOC_DAPM_MUX("Sidetone Left Source", - SND_SOC_NOPM, 0, 0, - dapm_stfir1_in_select), - SND_SOC_DAPM_MUX("Sidetone Right Source", - SND_SOC_NOPM, 0, 0, - dapm_stfir2_in_select), - SND_SOC_DAPM_MIXER("STFIR1 Control", - SND_SOC_NOPM, 0, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("STFIR2 Control", - SND_SOC_NOPM, 0, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("STFIR1 Volume", - SND_SOC_NOPM, 0, 0, - NULL, 0), - SND_SOC_DAPM_MIXER("STFIR2 Volume", - SND_SOC_NOPM, 0, 0, - NULL, 0), -}; - -/* - * DAPM-routes - */ -static const struct snd_soc_dapm_route ab8500_dapm_routes[] = { - /* Power AB8500 audio-block when AD/DA is active */ - {"Main Supply", NULL, "V-AUD"}, - {"Main Supply", NULL, "audioclk"}, - {"Main Supply", NULL, "Audio Power"}, - {"Main Supply", NULL, "Audio Analog Power"}, - - {"DAC", NULL, "ab8500_0p"}, - {"DAC", NULL, "Main Supply"}, - {"ADC", NULL, "ab8500_0c"}, - {"ADC", NULL, "Main Supply"}, - - /* ANC Configure */ - {"ANC Configure Input", NULL, "Main Supply"}, - {"ANC Configure Output", NULL, "ANC Configure Input"}, - - /* AD/DA */ - {"ADC", NULL, "ADC Input"}, - {"DAC Output", NULL, "DAC"}, - - /* Powerup charge pump if DA1/2 is in use */ - - {"DA_IN1", NULL, "ab8500_0p"}, - {"DA_IN1", NULL, "Charge Pump"}, - {"DA_IN2", NULL, "ab8500_0p"}, - {"DA_IN2", NULL, "Charge Pump"}, - - /* Headset path */ - - {"DA1 Enable", NULL, "DA_IN1"}, - {"DA2 Enable", NULL, "DA_IN2"}, - - {"HSL Digital Volume", NULL, "DA1 Enable"}, - {"HSR Digital Volume", NULL, "DA2 Enable"}, - - {"HSL DAC", NULL, "HSL Digital Volume"}, - {"HSR DAC", NULL, "HSR Digital Volume"}, - - {"HSL DAC Mute", NULL, "HSL DAC"}, - {"HSR DAC Mute", NULL, "HSR DAC"}, - - {"HSL DAC Driver", NULL, "HSL DAC Mute"}, - {"HSR DAC Driver", NULL, "HSR DAC Mute"}, - - {"HSL Mute", NULL, "HSL DAC Driver"}, - {"HSR Mute", NULL, "HSR DAC Driver"}, - - {"HSL Enable", NULL, "HSL Mute"}, - {"HSR Enable", NULL, "HSR Mute"}, - - {"HSL Volume", NULL, "HSL Enable"}, - {"HSR Volume", NULL, "HSR Enable"}, - - {"Headset Left", NULL, "HSL Volume"}, - {"Headset Right", NULL, "HSR Volume"}, - - /* HF or LineOut path */ - - {"DA_IN3", NULL, "ab8500_0p"}, - {"DA3 Channel Volume", NULL, "DA_IN3"}, - {"DA_IN4", NULL, "ab8500_0p"}, - {"DA4 Channel Volume", NULL, "DA_IN4"}, - - {"Speaker Left Source", "Audio Path", "DA3 Channel Volume"}, - {"Speaker Right Source", "Audio Path", "DA4 Channel Volume"}, - - {"DA3 or ANC path to HfL", NULL, "Speaker Left Source"}, - {"DA4 or ANC path to HfR", NULL, "Speaker Right Source"}, - - /* HF path */ - - {"HFL DAC", NULL, "DA3 or ANC path to HfL"}, - {"HFR DAC", NULL, "DA4 or ANC path to HfR"}, - - {"HFL Enable", NULL, "HFL DAC"}, - {"HFR Enable", NULL, "HFR DAC"}, - - {"Speaker Left", NULL, "HFL Enable"}, - {"Speaker Right", NULL, "HFR Enable"}, - - /* Earpiece path */ - - {"Earpiece or LineOut Mono Source", "Headset Left", - "HSL Digital Volume"}, - {"Earpiece or LineOut Mono Source", "Speaker Left", - "DA3 or ANC path to HfL"}, - - {"EAR DAC", NULL, "Earpiece or LineOut Mono Source"}, - - {"EAR Mute", NULL, "EAR DAC"}, - - {"EAR Enable", NULL, "EAR Mute"}, - - {"Earpiece", NULL, "EAR Enable"}, - - /* LineOut path stereo */ - - {"LineOut Source", "Stereo Path", "HSL DAC Driver"}, - {"LineOut Source", "Stereo Path", "HSR DAC Driver"}, - - /* LineOut path mono */ - - {"LineOut Source", "Mono Path", "EAR DAC"}, - - /* LineOut path */ - - {"LOL Disable HFL", NULL, "LineOut Source"}, - {"LOR Disable HFR", NULL, "LineOut Source"}, - - {"LOL Enable", NULL, "LOL Disable HFL"}, - {"LOR Enable", NULL, "LOR Disable HFR"}, - - {"LineOut Left", NULL, "LOL Enable"}, - {"LineOut Right", NULL, "LOR Enable"}, - - /* Vibrator path */ - - {"DA_IN5", NULL, "ab8500_0p"}, - {"DA5 Channel Volume", NULL, "DA_IN5"}, - {"DA_IN6", NULL, "ab8500_0p"}, - {"DA6 Channel Volume", NULL, "DA_IN6"}, - - {"VIB1 DAC", NULL, "DA5 Channel Volume"}, - {"VIB2 DAC", NULL, "DA6 Channel Volume"}, - - {"Vibra 1 Controller", "Audio Path", "VIB1 DAC"}, - {"Vibra 2 Controller", "Audio Path", "VIB2 DAC"}, - {"Vibra 1 Controller", "PWM Generator", "PWMGEN1"}, - {"Vibra 2 Controller", "PWM Generator", "PWMGEN2"}, - - {"VIB1 Enable", NULL, "Vibra 1 Controller"}, - {"VIB2 Enable", NULL, "Vibra 2 Controller"}, - - {"Vibra 1", NULL, "VIB1 Enable"}, - {"Vibra 2", NULL, "VIB2 Enable"}, - - - /* Mic 2 */ - - {"MIC2 V-AMICx Enable", NULL, "Mic 2"}, - - /* LineIn */ - {"LINL Mute", NULL, "LineIn Left"}, - {"LINR Mute", NULL, "LineIn Right"}, - - {"LINL Enable", NULL, "LINL Mute"}, - {"LINR Enable", NULL, "LINR Mute"}, - - /* LineIn, Mic 2 */ - {"Mic 2 or LINR Select", "LineIn Right", "LINR Enable"}, - {"Mic 2 or LINR Select", "Mic 2", "MIC2 V-AMICx Enable"}, - - {"LINL ADC", NULL, "LINL Enable"}, - {"LINR ADC", NULL, "Mic 2 or LINR Select"}, - - {"AD1 Source Select", "LineIn Left", "LINL ADC"}, - {"AD2 Source Select", "LineIn Right", "LINR ADC"}, - - {"AD1 Channel Volume", NULL, "AD1 Source Select"}, - {"AD2 Channel Volume", NULL, "AD2 Source Select"}, - - {"AD12 Enable", NULL, "AD1 Channel Volume"}, - {"AD12 Enable", NULL, "AD2 Channel Volume"}, - - {"AD_OUT1", NULL, "ab8500_0c"}, - {"AD_OUT1", NULL, "AD12 Enable"}, - {"AD_OUT2", NULL, "ab8500_0c"}, - {"AD_OUT2", NULL, "AD12 Enable"}, - - /* Mic 1 */ - - {"MIC1 Mute", NULL, "Mic 1"}, - - {"MIC1A V-AMICx Enable", NULL, "MIC1 Mute"}, - {"MIC1B V-AMICx Enable", NULL, "MIC1 Mute"}, - - {"Mic 1a or 1b Select", "Mic 1a", "MIC1A V-AMICx Enable"}, - {"Mic 1a or 1b Select", "Mic 1b", "MIC1B V-AMICx Enable"}, - - {"MIC1 ADC", NULL, "Mic 1a or 1b Select"}, - - {"AD3 Source Select", "Mic 1", "MIC1 ADC"}, - - {"AD3 Channel Volume", NULL, "AD3 Source Select"}, - - {"AD3 Enable", NULL, "AD3 Channel Volume"}, - - {"AD_OUT3", NULL, "ab8500_0c"}, - {"AD_OUT3", NULL, "AD3 Enable"}, - - /* HD Capture path */ - - {"AD5 Source Select", "Mic 2", "LINR ADC"}, - {"AD6 Source Select", "Mic 1", "MIC1 ADC"}, - - {"AD5 Channel Volume", NULL, "AD5 Source Select"}, - {"AD6 Channel Volume", NULL, "AD6 Source Select"}, - - {"AD57 Enable", NULL, "AD5 Channel Volume"}, - {"AD68 Enable", NULL, "AD6 Channel Volume"}, - - {"AD_OUT57", NULL, "ab8500_0c"}, - {"AD_OUT57", NULL, "AD57 Enable"}, - {"AD_OUT68", NULL, "ab8500_0c"}, - {"AD_OUT68", NULL, "AD68 Enable"}, - - /* Digital Microphone path */ - - {"DMic 1", NULL, "V-DMIC"}, - {"DMic 2", NULL, "V-DMIC"}, - {"DMic 3", NULL, "V-DMIC"}, - {"DMic 4", NULL, "V-DMIC"}, - {"DMic 5", NULL, "V-DMIC"}, - {"DMic 6", NULL, "V-DMIC"}, - - {"AD1 Source Select", NULL, "DMic 1"}, - {"AD2 Source Select", NULL, "DMic 2"}, - {"AD3 Source Select", NULL, "DMic 3"}, - {"AD5 Source Select", NULL, "DMic 5"}, - {"AD6 Source Select", NULL, "DMic 6"}, - - {"AD4 Channel Volume", NULL, "DMic 4"}, - {"AD4 Enable", NULL, "AD4 Channel Volume"}, - - {"AD_OUT4", NULL, "ab8500_0c"}, - {"AD_OUT4", NULL, "AD4 Enable"}, - - /* LineIn Bypass path */ - - {"LINL to HSL Volume", NULL, "LINL Enable"}, - {"LINR to HSR Volume", NULL, "LINR Enable"}, - - {"HSL DAC Driver", NULL, "LINL to HSL Volume"}, - {"HSR DAC Driver", NULL, "LINR to HSR Volume"}, - - /* ANC path (Acoustic Noise Cancellation) */ - - {"ANC Source", "Mic 2 / DMic 5", "AD5 Channel Volume"}, - {"ANC Source", "Mic 1 / DMic 6", "AD6 Channel Volume"}, - - {"ANC", "Switch", "ANC Source"}, - - {"Speaker Left Source", "ANC", "ANC"}, - {"Speaker Right Source", "ANC", "ANC"}, - {"ANC to Earpiece", "Switch", "ANC"}, - - {"HSL Digital Volume", NULL, "ANC to Earpiece"}, - - /* Sidetone Filter path */ - - {"Sidetone Left Source", "LineIn Left", "AD12 Enable"}, - {"Sidetone Left Source", "LineIn Right", "AD12 Enable"}, - {"Sidetone Left Source", "Mic 1", "AD3 Enable"}, - {"Sidetone Left Source", "Headset Left", "DA_IN1"}, - {"Sidetone Right Source", "LineIn Right", "AD12 Enable"}, - {"Sidetone Right Source", "Mic 1", "AD3 Enable"}, - {"Sidetone Right Source", "DMic 4", "AD4 Enable"}, - {"Sidetone Right Source", "Headset Right", "DA_IN2"}, - - {"STFIR1 Control", NULL, "Sidetone Left Source"}, - {"STFIR2 Control", NULL, "Sidetone Right Source"}, - - {"STFIR1 Volume", NULL, "STFIR1 Control"}, - {"STFIR2 Volume", NULL, "STFIR2 Control"}, - - {"DA1 Enable", NULL, "STFIR1 Volume"}, - {"DA2 Enable", NULL, "STFIR2 Volume"}, -}; - -static const struct snd_soc_dapm_route ab8500_dapm_routes_mic1a_vamicx[] = { - {"MIC1A V-AMICx Enable", NULL, "V-AMIC1"}, - {"MIC1A V-AMICx Enable", NULL, "V-AMIC2"}, -}; - -static const struct snd_soc_dapm_route ab8500_dapm_routes_mic1b_vamicx[] = { - {"MIC1B V-AMICx Enable", NULL, "V-AMIC1"}, - {"MIC1B V-AMICx Enable", NULL, "V-AMIC2"}, -}; - -static const struct snd_soc_dapm_route ab8500_dapm_routes_mic2_vamicx[] = { - {"MIC2 V-AMICx Enable", NULL, "V-AMIC1"}, - {"MIC2 V-AMICx Enable", NULL, "V-AMIC2"}, -}; - -/* ANC FIR-coefficients configuration sequence */ -static void anc_fir(struct snd_soc_codec *codec, - unsigned int bnk, unsigned int par, unsigned int val) -{ - if (par == 0 && bnk == 0) - snd_soc_update_bits(codec, AB8500_ANCCONF1, - BIT(AB8500_ANCCONF1_ANCFIRUPDATE), - BIT(AB8500_ANCCONF1_ANCFIRUPDATE)); - - snd_soc_write(codec, AB8500_ANCCONF5, val >> 8 & 0xff); - snd_soc_write(codec, AB8500_ANCCONF6, val & 0xff); - - if (par == AB8500_ANC_FIR_COEFFS - 1 && bnk == 1) - snd_soc_update_bits(codec, AB8500_ANCCONF1, - BIT(AB8500_ANCCONF1_ANCFIRUPDATE), 0); -} - -/* ANC IIR-coefficients configuration sequence */ -static void anc_iir(struct snd_soc_codec *codec, unsigned int bnk, - unsigned int par, unsigned int val) -{ - if (par == 0) { - if (bnk == 0) { - snd_soc_update_bits(codec, AB8500_ANCCONF1, - BIT(AB8500_ANCCONF1_ANCIIRINIT), - BIT(AB8500_ANCCONF1_ANCIIRINIT)); - usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY); - snd_soc_update_bits(codec, AB8500_ANCCONF1, - BIT(AB8500_ANCCONF1_ANCIIRINIT), 0); - usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY); - } else { - snd_soc_update_bits(codec, AB8500_ANCCONF1, - BIT(AB8500_ANCCONF1_ANCIIRUPDATE), - BIT(AB8500_ANCCONF1_ANCIIRUPDATE)); - } - } else if (par > 3) { - snd_soc_write(codec, AB8500_ANCCONF7, 0); - snd_soc_write(codec, AB8500_ANCCONF8, val >> 16 & 0xff); - } - - snd_soc_write(codec, AB8500_ANCCONF7, val >> 8 & 0xff); - snd_soc_write(codec, AB8500_ANCCONF8, val & 0xff); - - if (par == AB8500_ANC_IIR_COEFFS - 1 && bnk == 1) - snd_soc_update_bits(codec, AB8500_ANCCONF1, - BIT(AB8500_ANCCONF1_ANCIIRUPDATE), 0); -} - -/* ANC IIR-/FIR-coefficients configuration sequence */ -static void anc_configure(struct snd_soc_codec *codec, - bool apply_fir, bool apply_iir) -{ - struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); - unsigned int bnk, par, val; - - dev_dbg(codec->dev, "%s: Enter.\n", __func__); - - if (apply_fir) - snd_soc_update_bits(codec, AB8500_ANCCONF1, - BIT(AB8500_ANCCONF1_ENANC), 0); - - snd_soc_update_bits(codec, AB8500_ANCCONF1, - BIT(AB8500_ANCCONF1_ENANC), BIT(AB8500_ANCCONF1_ENANC)); - - if (apply_fir) - for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++) - for (par = 0; par < AB8500_ANC_FIR_COEFFS; par++) { - val = snd_soc_read(codec, - drvdata->anc_fir_values[par]); - anc_fir(codec, bnk, par, val); - } - - if (apply_iir) - for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++) - for (par = 0; par < AB8500_ANC_IIR_COEFFS; par++) { - val = snd_soc_read(codec, - drvdata->anc_iir_values[par]); - anc_iir(codec, bnk, par, val); - } - - dev_dbg(codec->dev, "%s: Exit.\n", __func__); -} - -/* - * Control-events - */ - -static int sid_status_control_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); - - mutex_lock(&codec->mutex); - ucontrol->value.integer.value[0] = drvdata->sid_status; - mutex_unlock(&codec->mutex); - - return 0; -} - -/* Write sidetone FIR-coefficients configuration sequence */ -static int sid_status_control_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); - unsigned int param, sidconf, val; - int status = 1; - - dev_dbg(codec->dev, "%s: Enter\n", __func__); - - if (ucontrol->value.integer.value[0] != SID_APPLY_FIR) { - dev_err(codec->dev, - "%s: ERROR: This control supports '%s' only!\n", - __func__, enum_sid_state[SID_APPLY_FIR]); - return -EIO; - } - - mutex_lock(&codec->mutex); - - sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF); - if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) { - if ((sidconf & BIT(AB8500_SIDFIRCONF_ENFIRSIDS)) == 0) { - dev_err(codec->dev, "%s: Sidetone busy while off!\n", - __func__); - status = -EPERM; - } else { - status = -EBUSY; - } - goto out; - } - - snd_soc_write(codec, AB8500_SIDFIRADR, 0); - - for (param = 0; param < AB8500_SID_FIR_COEFFS; param++) { - val = snd_soc_read(codec, drvdata->sid_fir_values[param]); - snd_soc_write(codec, AB8500_SIDFIRCOEF1, val >> 8 & 0xff); - snd_soc_write(codec, AB8500_SIDFIRCOEF2, val & 0xff); - } - - snd_soc_update_bits(codec, AB8500_SIDFIRADR, - BIT(AB8500_SIDFIRADR_FIRSIDSET), - BIT(AB8500_SIDFIRADR_FIRSIDSET)); - snd_soc_update_bits(codec, AB8500_SIDFIRADR, - BIT(AB8500_SIDFIRADR_FIRSIDSET), 0); - - drvdata->sid_status = SID_FIR_CONFIGURED; - -out: - mutex_unlock(&codec->mutex); - - dev_dbg(codec->dev, "%s: Exit\n", __func__); - - return status; -} - -static int anc_status_control_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); - - mutex_lock(&codec->mutex); - ucontrol->value.integer.value[0] = drvdata->anc_status; - mutex_unlock(&codec->mutex); - - return 0; -} - -static int anc_status_control_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); - struct device *dev = codec->dev; - bool apply_fir, apply_iir; - int req, status; - - dev_dbg(dev, "%s: Enter.\n", __func__); - - mutex_lock(&drvdata->anc_lock); - - req = ucontrol->value.integer.value[0]; - if (req != ANC_APPLY_FIR_IIR && req != ANC_APPLY_FIR && - req != ANC_APPLY_IIR) { - dev_err(dev, "%s: ERROR: Unsupported status to set '%s'!\n", - __func__, enum_anc_state[req]); - return -EINVAL; - } - apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR; - apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR; - - status = snd_soc_dapm_force_enable_pin(&codec->dapm, - "ANC Configure Input"); - if (status < 0) { - dev_err(dev, - "%s: ERROR: Failed to enable power (status = %d)!\n", - __func__, status); - goto cleanup; - } - snd_soc_dapm_sync(&codec->dapm); - - mutex_lock(&codec->mutex); - anc_configure(codec, apply_fir, apply_iir); - mutex_unlock(&codec->mutex); - - if (apply_fir) { - if (drvdata->anc_status == ANC_IIR_CONFIGURED) - drvdata->anc_status = ANC_FIR_IIR_CONFIGURED; - else if (drvdata->anc_status != ANC_FIR_IIR_CONFIGURED) - drvdata->anc_status = ANC_FIR_CONFIGURED; - } - if (apply_iir) { - if (drvdata->anc_status == ANC_FIR_CONFIGURED) - drvdata->anc_status = ANC_FIR_IIR_CONFIGURED; - else if (drvdata->anc_status != ANC_FIR_IIR_CONFIGURED) - drvdata->anc_status = ANC_IIR_CONFIGURED; - } - - status = snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input"); - snd_soc_dapm_sync(&codec->dapm); - -cleanup: - mutex_unlock(&drvdata->anc_lock); - - if (status < 0) - dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n", - __func__, status); - - dev_dbg(dev, "%s: Exit.\n", __func__); - - return (status < 0) ? status : 1; -} - -static int filter_control_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct filter_control *fc = - (struct filter_control *)kcontrol->private_value; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = fc->count; - uinfo->value.integer.min = fc->min; - uinfo->value.integer.max = fc->max; - - return 0; -} - -static int filter_control_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct filter_control *fc = - (struct filter_control *)kcontrol->private_value; - unsigned int i; - - mutex_lock(&codec->mutex); - for (i = 0; i < fc->count; i++) - ucontrol->value.integer.value[i] = fc->value[i]; - mutex_unlock(&codec->mutex); - - return 0; -} - -static int filter_control_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct filter_control *fc = - (struct filter_control *)kcontrol->private_value; - unsigned int i; - - mutex_lock(&codec->mutex); - for (i = 0; i < fc->count; i++) - fc->value[i] = ucontrol->value.integer.value[i]; - mutex_unlock(&codec->mutex); - - return 0; -} - -/* - * Controls - Non-DAPM ASoC - */ - -static DECLARE_TLV_DB_SCALE(adx_dig_gain_tlv, -3200, 100, 1); -/* -32dB = Mute */ - -static DECLARE_TLV_DB_SCALE(dax_dig_gain_tlv, -6300, 100, 1); -/* -63dB = Mute */ - -static DECLARE_TLV_DB_SCALE(hs_ear_dig_gain_tlv, -100, 100, 1); -/* -1dB = Mute */ - -static const unsigned int hs_gain_tlv[] = { - TLV_DB_RANGE_HEAD(2), - 0, 3, TLV_DB_SCALE_ITEM(-3200, 400, 0), - 4, 15, TLV_DB_SCALE_ITEM(-1800, 200, 0), -}; - -static DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0); - -static DECLARE_TLV_DB_SCALE(lin_gain_tlv, -1000, 200, 0); - -static DECLARE_TLV_DB_SCALE(lin2hs_gain_tlv, -3800, 200, 1); -/* -38dB = Mute */ - -static const char * const enum_hsfadspeed[] = {"2ms", "0.5ms", "10.6ms", - "5ms"}; -static SOC_ENUM_SINGLE_DECL(soc_enum_hsfadspeed, - AB8500_DIGMICCONF, AB8500_DIGMICCONF_HSFADSPEED, enum_hsfadspeed); - -static const char * const enum_envdetthre[] = { - "250mV", "300mV", "350mV", "400mV", - "450mV", "500mV", "550mV", "600mV", - "650mV", "700mV", "750mV", "800mV", - "850mV", "900mV", "950mV", "1.00V" }; -static SOC_ENUM_SINGLE_DECL(soc_enum_envdeththre, - AB8500_ENVCPCONF, AB8500_ENVCPCONF_ENVDETHTHRE, enum_envdetthre); -static SOC_ENUM_SINGLE_DECL(soc_enum_envdetlthre, - AB8500_ENVCPCONF, AB8500_ENVCPCONF_ENVDETLTHRE, enum_envdetthre); -static const char * const enum_envdettime[] = { - "26.6us", "53.2us", "106us", "213us", - "426us", "851us", "1.70ms", "3.40ms", - "6.81ms", "13.6ms", "27.2ms", "54.5ms", - "109ms", "218ms", "436ms", "872ms" }; -static SOC_ENUM_SINGLE_DECL(soc_enum_envdettime, - AB8500_SIGENVCONF, AB8500_SIGENVCONF_ENVDETTIME, enum_envdettime); - -static const char * const enum_sinc31[] = {"Sinc 3", "Sinc 1"}; -static SOC_ENUM_SINGLE_DECL(soc_enum_hsesinc, AB8500_HSLEARDIGGAIN, - AB8500_HSLEARDIGGAIN_HSSINC1, enum_sinc31); - -static const char * const enum_fadespeed[] = {"1ms", "4ms", "8ms", "16ms"}; -static SOC_ENUM_SINGLE_DECL(soc_enum_fadespeed, AB8500_HSRDIGGAIN, - AB8500_HSRDIGGAIN_FADESPEED, enum_fadespeed); - -/* Earpiece */ - -static const char * const enum_lowpow[] = {"Normal", "Low Power"}; -static SOC_ENUM_SINGLE_DECL(soc_enum_eardaclowpow, AB8500_ANACONF1, - AB8500_ANACONF1_EARDACLOWPOW, enum_lowpow); -static SOC_ENUM_SINGLE_DECL(soc_enum_eardrvlowpow, AB8500_ANACONF1, - AB8500_ANACONF1_EARDRVLOWPOW, enum_lowpow); - -static const char * const enum_av_mode[] = {"Audio", "Voice"}; -static SOC_ENUM_DOUBLE_DECL(soc_enum_ad12voice, AB8500_ADFILTCONF, - AB8500_ADFILTCONF_AD1VOICE, AB8500_ADFILTCONF_AD2VOICE, enum_av_mode); -static SOC_ENUM_DOUBLE_DECL(soc_enum_ad34voice, AB8500_ADFILTCONF, - AB8500_ADFILTCONF_AD3VOICE, AB8500_ADFILTCONF_AD4VOICE, enum_av_mode); - -/* DA */ - -static SOC_ENUM_SINGLE_DECL(soc_enum_da12voice, - AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_DA12VOICE, - enum_av_mode); -static SOC_ENUM_SINGLE_DECL(soc_enum_da34voice, - AB8500_DASLOTCONF3, AB8500_DASLOTCONF3_DA34VOICE, - enum_av_mode); -static SOC_ENUM_SINGLE_DECL(soc_enum_da56voice, - AB8500_DASLOTCONF5, AB8500_DASLOTCONF5_DA56VOICE, - enum_av_mode); - -static const char * const enum_da2hslr[] = {"Sidetone", "Audio Path"}; -static SOC_ENUM_DOUBLE_DECL(soc_enum_da2hslr, AB8500_DIGMULTCONF1, - AB8500_DIGMULTCONF1_DATOHSLEN, - AB8500_DIGMULTCONF1_DATOHSREN, enum_da2hslr); - -static const char * const enum_sinc53[] = {"Sinc 5", "Sinc 3"}; -static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic12sinc, AB8500_DMICFILTCONF, - AB8500_DMICFILTCONF_DMIC1SINC3, - AB8500_DMICFILTCONF_DMIC2SINC3, enum_sinc53); -static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic34sinc, AB8500_DMICFILTCONF, - AB8500_DMICFILTCONF_DMIC3SINC3, - AB8500_DMICFILTCONF_DMIC4SINC3, enum_sinc53); -static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic56sinc, AB8500_DMICFILTCONF, - AB8500_DMICFILTCONF_DMIC5SINC3, - AB8500_DMICFILTCONF_DMIC6SINC3, enum_sinc53); - -/* Digital interface - DA from slot mapping */ -static const char * const enum_da_from_slot_map[] = {"SLOT0", - "SLOT1", - "SLOT2", - "SLOT3", - "SLOT4", - "SLOT5", - "SLOT6", - "SLOT7", - "SLOT8", - "SLOT9", - "SLOT10", - "SLOT11", - "SLOT12", - "SLOT13", - "SLOT14", - "SLOT15", - "SLOT16", - "SLOT17", - "SLOT18", - "SLOT19", - "SLOT20", - "SLOT21", - "SLOT22", - "SLOT23", - "SLOT24", - "SLOT25", - "SLOT26", - "SLOT27", - "SLOT28", - "SLOT29", - "SLOT30", - "SLOT31"}; -static SOC_ENUM_SINGLE_DECL(soc_enum_da1slotmap, - AB8500_DASLOTCONF1, AB8500_DASLOTCONFX_SLTODAX_SHIFT, - enum_da_from_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_da2slotmap, - AB8500_DASLOTCONF2, AB8500_DASLOTCONFX_SLTODAX_SHIFT, - enum_da_from_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_da3slotmap, - AB8500_DASLOTCONF3, AB8500_DASLOTCONFX_SLTODAX_SHIFT, - enum_da_from_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_da4slotmap, - AB8500_DASLOTCONF4, AB8500_DASLOTCONFX_SLTODAX_SHIFT, - enum_da_from_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_da5slotmap, - AB8500_DASLOTCONF5, AB8500_DASLOTCONFX_SLTODAX_SHIFT, - enum_da_from_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_da6slotmap, - AB8500_DASLOTCONF6, AB8500_DASLOTCONFX_SLTODAX_SHIFT, - enum_da_from_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_da7slotmap, - AB8500_DASLOTCONF7, AB8500_DASLOTCONFX_SLTODAX_SHIFT, - enum_da_from_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_da8slotmap, - AB8500_DASLOTCONF8, AB8500_DASLOTCONFX_SLTODAX_SHIFT, - enum_da_from_slot_map); - -/* Digital interface - AD to slot mapping */ -static const char * const enum_ad_to_slot_map[] = {"AD_OUT1", - "AD_OUT2", - "AD_OUT3", - "AD_OUT4", - "AD_OUT5", - "AD_OUT6", - "AD_OUT7", - "AD_OUT8", - "zeroes", - "tristate"}; -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot0map, - AB8500_ADSLOTSEL1, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot1map, - AB8500_ADSLOTSEL1, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot2map, - AB8500_ADSLOTSEL2, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot3map, - AB8500_ADSLOTSEL2, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot4map, - AB8500_ADSLOTSEL3, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot5map, - AB8500_ADSLOTSEL3, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot6map, - AB8500_ADSLOTSEL4, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot7map, - AB8500_ADSLOTSEL4, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot8map, - AB8500_ADSLOTSEL5, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot9map, - AB8500_ADSLOTSEL5, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot10map, - AB8500_ADSLOTSEL6, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot11map, - AB8500_ADSLOTSEL6, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot12map, - AB8500_ADSLOTSEL7, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot13map, - AB8500_ADSLOTSEL7, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot14map, - AB8500_ADSLOTSEL8, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot15map, - AB8500_ADSLOTSEL8, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot16map, - AB8500_ADSLOTSEL9, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot17map, - AB8500_ADSLOTSEL9, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot18map, - AB8500_ADSLOTSEL10, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot19map, - AB8500_ADSLOTSEL10, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot20map, - AB8500_ADSLOTSEL11, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot21map, - AB8500_ADSLOTSEL11, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot22map, - AB8500_ADSLOTSEL12, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot23map, - AB8500_ADSLOTSEL12, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot24map, - AB8500_ADSLOTSEL13, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot25map, - AB8500_ADSLOTSEL13, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot26map, - AB8500_ADSLOTSEL14, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot27map, - AB8500_ADSLOTSEL14, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot28map, - AB8500_ADSLOTSEL15, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot29map, - AB8500_ADSLOTSEL15, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot30map, - AB8500_ADSLOTSEL16, AB8500_ADSLOTSELX_EVEN_SHIFT, - enum_ad_to_slot_map); -static SOC_ENUM_SINGLE_DECL(soc_enum_adslot31map, - AB8500_ADSLOTSEL16, AB8500_ADSLOTSELX_ODD_SHIFT, - enum_ad_to_slot_map); - -/* Digital interface - Burst mode */ -static const char * const enum_mask[] = {"Unmasked", "Masked"}; -static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomask, - AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFOMASK, - enum_mask); -static const char * const enum_bitclk0[] = {"19_2_MHz", "38_4_MHz"}; -static SOC_ENUM_SINGLE_DECL(soc_enum_bfifo19m2, - AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFO19M2, - enum_bitclk0); -static const char * const enum_slavemaster[] = {"Slave", "Master"}; -static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomast, - AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOMAST_SHIFT, - enum_slavemaster); - -/* Sidetone */ -static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_sidstate, enum_sid_state); - -/* ANC */ -static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_ancstate, enum_anc_state); - -static struct snd_kcontrol_new ab8500_ctrls[] = { - /* Charge pump */ - SOC_ENUM("Charge Pump High Threshold For Low Voltage", - soc_enum_envdeththre), - SOC_ENUM("Charge Pump Low Threshold For Low Voltage", - soc_enum_envdetlthre), - SOC_SINGLE("Charge Pump Envelope Detection Switch", - AB8500_SIGENVCONF, AB8500_SIGENVCONF_ENVDETCPEN, - 1, 0), - SOC_ENUM("Charge Pump Envelope Detection Decay Time", - soc_enum_envdettime), - - /* Headset */ - SOC_ENUM("Headset Mode", soc_enum_da12voice), - SOC_SINGLE("Headset High Pass Switch", - AB8500_ANACONF1, AB8500_ANACONF1_HSHPEN, - 1, 0), - SOC_SINGLE("Headset Low Power Switch", - AB8500_ANACONF1, AB8500_ANACONF1_HSLOWPOW, - 1, 0), - SOC_SINGLE("Headset DAC Low Power Switch", - AB8500_ANACONF1, AB8500_ANACONF1_DACLOWPOW1, - 1, 0), - SOC_SINGLE("Headset DAC Drv Low Power Switch", - AB8500_ANACONF1, AB8500_ANACONF1_DACLOWPOW0, - 1, 0), - SOC_ENUM("Headset Fade Speed", soc_enum_hsfadspeed), - SOC_ENUM("Headset Source", soc_enum_da2hslr), - SOC_ENUM("Headset Filter", soc_enum_hsesinc), - SOC_DOUBLE_R_TLV("Headset Master Volume", - AB8500_DADIGGAIN1, AB8500_DADIGGAIN2, - 0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv), - SOC_DOUBLE_R_TLV("Headset Digital Volume", - AB8500_HSLEARDIGGAIN, AB8500_HSRDIGGAIN, - 0, AB8500_HSLEARDIGGAIN_HSLDGAIN_MAX, 1, hs_ear_dig_gain_tlv), - SOC_DOUBLE_TLV("Headset Volume", - AB8500_ANAGAIN3, - AB8500_ANAGAIN3_HSLGAIN, AB8500_ANAGAIN3_HSRGAIN, - AB8500_ANAGAIN3_HSXGAIN_MAX, 1, hs_gain_tlv), - - /* Earpiece */ - SOC_ENUM("Earpiece DAC Mode", - soc_enum_eardaclowpow), - SOC_ENUM("Earpiece DAC Drv Mode", - soc_enum_eardrvlowpow), - - /* HandsFree */ - SOC_ENUM("HF Mode", soc_enum_da34voice), - SOC_SINGLE("HF and Headset Swap Switch", - AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_SWAPDA12_34, - 1, 0), - SOC_DOUBLE("HF Low EMI Mode Switch", - AB8500_CLASSDCONF1, - AB8500_CLASSDCONF1_HFLSWAPEN, AB8500_CLASSDCONF1_HFRSWAPEN, - 1, 0), - SOC_DOUBLE("HF FIR Bypass Switch", - AB8500_CLASSDCONF2, - AB8500_CLASSDCONF2_FIRBYP0, AB8500_CLASSDCONF2_FIRBYP1, - 1, 0), - SOC_DOUBLE("HF High Volume Switch", - AB8500_CLASSDCONF2, - AB8500_CLASSDCONF2_HIGHVOLEN0, AB8500_CLASSDCONF2_HIGHVOLEN1, - 1, 0), - SOC_SINGLE("HF L and R Bridge Switch", - AB8500_CLASSDCONF1, AB8500_CLASSDCONF1_PARLHF, - 1, 0), - SOC_DOUBLE_R_TLV("HF Master Volume", - AB8500_DADIGGAIN3, AB8500_DADIGGAIN4, - 0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv), - - /* Vibra */ - SOC_DOUBLE("Vibra High Volume Switch", - AB8500_CLASSDCONF2, - AB8500_CLASSDCONF2_HIGHVOLEN2, AB8500_CLASSDCONF2_HIGHVOLEN3, - 1, 0), - SOC_DOUBLE("Vibra Low EMI Mode Switch", - AB8500_CLASSDCONF1, - AB8500_CLASSDCONF1_VIB1SWAPEN, AB8500_CLASSDCONF1_VIB2SWAPEN, - 1, 0), - SOC_DOUBLE("Vibra FIR Bypass Switch", - AB8500_CLASSDCONF2, - AB8500_CLASSDCONF2_FIRBYP2, AB8500_CLASSDCONF2_FIRBYP3, - 1, 0), - SOC_ENUM("Vibra Mode", soc_enum_da56voice), - SOC_DOUBLE_R("Vibra PWM Duty Cycle N", - AB8500_PWMGENCONF3, AB8500_PWMGENCONF5, - AB8500_PWMGENCONFX_PWMVIBXDUTCYC, - AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX, 0), - SOC_DOUBLE_R("Vibra PWM Duty Cycle P", - AB8500_PWMGENCONF2, AB8500_PWMGENCONF4, - AB8500_PWMGENCONFX_PWMVIBXDUTCYC, - AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX, 0), - SOC_SINGLE("Vibra 1 and 2 Bridge Switch", - AB8500_CLASSDCONF1, AB8500_CLASSDCONF1_PARLVIB, - 1, 0), - SOC_DOUBLE_R_TLV("Vibra Master Volume", - AB8500_DADIGGAIN5, AB8500_DADIGGAIN6, - 0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv), - - /* HandsFree, Vibra */ - SOC_SINGLE("ClassD High Pass Volume", - AB8500_CLASSDCONF3, AB8500_CLASSDCONF3_DITHHPGAIN, - AB8500_CLASSDCONF3_DITHHPGAIN_MAX, 0), - SOC_SINGLE("ClassD White Volume", - AB8500_CLASSDCONF3, AB8500_CLASSDCONF3_DITHWGAIN, - AB8500_CLASSDCONF3_DITHWGAIN_MAX, 0), - - /* Mic 1, Mic 2, LineIn */ - SOC_DOUBLE_R_TLV("Mic Master Volume", - AB8500_ADDIGGAIN3, AB8500_ADDIGGAIN4, - 0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv), - - /* Mic 1 */ - SOC_SINGLE_TLV("Mic 1", - AB8500_ANAGAIN1, - AB8500_ANAGAINX_MICXGAIN, - AB8500_ANAGAINX_MICXGAIN_MAX, 0, mic_gain_tlv), - SOC_SINGLE("Mic 1 Low Power Switch", - AB8500_ANAGAIN1, AB8500_ANAGAINX_LOWPOWMICX, - 1, 0), - - /* Mic 2 */ - SOC_DOUBLE("Mic High Pass Switch", - AB8500_ADFILTCONF, - AB8500_ADFILTCONF_AD3NH, AB8500_ADFILTCONF_AD4NH, - 1, 1), - SOC_ENUM("Mic Mode", soc_enum_ad34voice), - SOC_ENUM("Mic Filter", soc_enum_dmic34sinc), - SOC_SINGLE_TLV("Mic 2", - AB8500_ANAGAIN2, - AB8500_ANAGAINX_MICXGAIN, - AB8500_ANAGAINX_MICXGAIN_MAX, 0, mic_gain_tlv), - SOC_SINGLE("Mic 2 Low Power Switch", - AB8500_ANAGAIN2, AB8500_ANAGAINX_LOWPOWMICX, - 1, 0), - - /* LineIn */ - SOC_DOUBLE("LineIn High Pass Switch", - AB8500_ADFILTCONF, - AB8500_ADFILTCONF_AD1NH, AB8500_ADFILTCONF_AD2NH, - 1, 1), - SOC_ENUM("LineIn Filter", soc_enum_dmic12sinc), - SOC_ENUM("LineIn Mode", soc_enum_ad12voice), - SOC_DOUBLE_R_TLV("LineIn Master Volume", - AB8500_ADDIGGAIN1, AB8500_ADDIGGAIN2, - 0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv), - SOC_DOUBLE_TLV("LineIn", - AB8500_ANAGAIN4, - AB8500_ANAGAIN4_LINLGAIN, AB8500_ANAGAIN4_LINRGAIN, - AB8500_ANAGAIN4_LINXGAIN_MAX, 0, lin_gain_tlv), - SOC_DOUBLE_R_TLV("LineIn to Headset Volume", - AB8500_DIGLINHSLGAIN, AB8500_DIGLINHSRGAIN, - AB8500_DIGLINHSXGAIN_LINTOHSXGAIN, - AB8500_DIGLINHSXGAIN_LINTOHSXGAIN_MAX, - 1, lin2hs_gain_tlv), - - /* DMic */ - SOC_ENUM("DMic Filter", soc_enum_dmic56sinc), - SOC_DOUBLE_R_TLV("DMic Master Volume", - AB8500_ADDIGGAIN5, AB8500_ADDIGGAIN6, - 0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv), - - /* Digital gains */ - SOC_ENUM("Digital Gain Fade Speed", soc_enum_fadespeed), - - /* Analog loopback */ - SOC_DOUBLE_R_TLV("Analog Loopback Volume", - AB8500_ADDIGLOOPGAIN1, AB8500_ADDIGLOOPGAIN2, - 0, AB8500_ADDIGLOOPGAINX_ADXLBGAIN_MAX, 1, dax_dig_gain_tlv), - - /* Digital interface - DA from slot mapping */ - SOC_ENUM("Digital Interface DA 1 From Slot Map", soc_enum_da1slotmap), - SOC_ENUM("Digital Interface DA 2 From Slot Map", soc_enum_da2slotmap), - SOC_ENUM("Digital Interface DA 3 From Slot Map", soc_enum_da3slotmap), - SOC_ENUM("Digital Interface DA 4 From Slot Map", soc_enum_da4slotmap), - SOC_ENUM("Digital Interface DA 5 From Slot Map", soc_enum_da5slotmap), - SOC_ENUM("Digital Interface DA 6 From Slot Map", soc_enum_da6slotmap), - SOC_ENUM("Digital Interface DA 7 From Slot Map", soc_enum_da7slotmap), - SOC_ENUM("Digital Interface DA 8 From Slot Map", soc_enum_da8slotmap), - - /* Digital interface - AD to slot mapping */ - SOC_ENUM("Digital Interface AD To Slot 0 Map", soc_enum_adslot0map), - SOC_ENUM("Digital Interface AD To Slot 1 Map", soc_enum_adslot1map), - SOC_ENUM("Digital Interface AD To Slot 2 Map", soc_enum_adslot2map), - SOC_ENUM("Digital Interface AD To Slot 3 Map", soc_enum_adslot3map), - SOC_ENUM("Digital Interface AD To Slot 4 Map", soc_enum_adslot4map), - SOC_ENUM("Digital Interface AD To Slot 5 Map", soc_enum_adslot5map), - SOC_ENUM("Digital Interface AD To Slot 6 Map", soc_enum_adslot6map), - SOC_ENUM("Digital Interface AD To Slot 7 Map", soc_enum_adslot7map), - SOC_ENUM("Digital Interface AD To Slot 8 Map", soc_enum_adslot8map), - SOC_ENUM("Digital Interface AD To Slot 9 Map", soc_enum_adslot9map), - SOC_ENUM("Digital Interface AD To Slot 10 Map", soc_enum_adslot10map), - SOC_ENUM("Digital Interface AD To Slot 11 Map", soc_enum_adslot11map), - SOC_ENUM("Digital Interface AD To Slot 12 Map", soc_enum_adslot12map), - SOC_ENUM("Digital Interface AD To Slot 13 Map", soc_enum_adslot13map), - SOC_ENUM("Digital Interface AD To Slot 14 Map", soc_enum_adslot14map), - SOC_ENUM("Digital Interface AD To Slot 15 Map", soc_enum_adslot15map), - SOC_ENUM("Digital Interface AD To Slot 16 Map", soc_enum_adslot16map), - SOC_ENUM("Digital Interface AD To Slot 17 Map", soc_enum_adslot17map), - SOC_ENUM("Digital Interface AD To Slot 18 Map", soc_enum_adslot18map), - SOC_ENUM("Digital Interface AD To Slot 19 Map", soc_enum_adslot19map), - SOC_ENUM("Digital Interface AD To Slot 20 Map", soc_enum_adslot20map), - SOC_ENUM("Digital Interface AD To Slot 21 Map", soc_enum_adslot21map), - SOC_ENUM("Digital Interface AD To Slot 22 Map", soc_enum_adslot22map), - SOC_ENUM("Digital Interface AD To Slot 23 Map", soc_enum_adslot23map), - SOC_ENUM("Digital Interface AD To Slot 24 Map", soc_enum_adslot24map), - SOC_ENUM("Digital Interface AD To Slot 25 Map", soc_enum_adslot25map), - SOC_ENUM("Digital Interface AD To Slot 26 Map", soc_enum_adslot26map), - SOC_ENUM("Digital Interface AD To Slot 27 Map", soc_enum_adslot27map), - SOC_ENUM("Digital Interface AD To Slot 28 Map", soc_enum_adslot28map), - SOC_ENUM("Digital Interface AD To Slot 29 Map", soc_enum_adslot29map), - SOC_ENUM("Digital Interface AD To Slot 30 Map", soc_enum_adslot30map), - SOC_ENUM("Digital Interface AD To Slot 31 Map", soc_enum_adslot31map), - - /* Digital interface - Loopback */ - SOC_SINGLE("Digital Interface AD 1 Loopback Switch", - AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_DAI7TOADO1, - 1, 0), - SOC_SINGLE("Digital Interface AD 2 Loopback Switch", - AB8500_DASLOTCONF2, AB8500_DASLOTCONF2_DAI8TOADO2, - 1, 0), - SOC_SINGLE("Digital Interface AD 3 Loopback Switch", - AB8500_DASLOTCONF3, AB8500_DASLOTCONF3_DAI7TOADO3, - 1, 0), - SOC_SINGLE("Digital Interface AD 4 Loopback Switch", - AB8500_DASLOTCONF4, AB8500_DASLOTCONF4_DAI8TOADO4, - 1, 0), - SOC_SINGLE("Digital Interface AD 5 Loopback Switch", - AB8500_DASLOTCONF5, AB8500_DASLOTCONF5_DAI7TOADO5, - 1, 0), - SOC_SINGLE("Digital Interface AD 6 Loopback Switch", - AB8500_DASLOTCONF6, AB8500_DASLOTCONF6_DAI8TOADO6, - 1, 0), - SOC_SINGLE("Digital Interface AD 7 Loopback Switch", - AB8500_DASLOTCONF7, AB8500_DASLOTCONF7_DAI8TOADO7, - 1, 0), - SOC_SINGLE("Digital Interface AD 8 Loopback Switch", - AB8500_DASLOTCONF8, AB8500_DASLOTCONF8_DAI7TOADO8, - 1, 0), - - /* Digital interface - Burst FIFO */ - SOC_SINGLE("Digital Interface 0 FIFO Enable Switch", - AB8500_DIGIFCONF3, AB8500_DIGIFCONF3_IF0BFIFOEN, - 1, 0), - SOC_ENUM("Burst FIFO Mask", soc_enum_bfifomask), - SOC_ENUM("Burst FIFO Bit-clock Frequency", soc_enum_bfifo19m2), - SOC_SINGLE("Burst FIFO Threshold", - AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFOINT_SHIFT, - AB8500_FIFOCONF1_BFIFOINT_MAX, 0), - SOC_SINGLE("Burst FIFO Length", - AB8500_FIFOCONF2, AB8500_FIFOCONF2_BFIFOTX_SHIFT, - AB8500_FIFOCONF2_BFIFOTX_MAX, 0), - SOC_SINGLE("Burst FIFO EOS Extra Slots", - AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOEXSL_SHIFT, - AB8500_FIFOCONF3_BFIFOEXSL_MAX, 0), - SOC_SINGLE("Burst FIFO FS Extra Bit-clocks", - AB8500_FIFOCONF3, AB8500_FIFOCONF3_PREBITCLK0_SHIFT, - AB8500_FIFOCONF3_PREBITCLK0_MAX, 0), - SOC_ENUM("Burst FIFO Interface Mode", soc_enum_bfifomast), - - SOC_SINGLE("Burst FIFO Interface Switch", - AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFORUN_SHIFT, - 1, 0), - SOC_SINGLE("Burst FIFO Switch Frame Number", - AB8500_FIFOCONF4, AB8500_FIFOCONF4_BFIFOFRAMSW_SHIFT, - AB8500_FIFOCONF4_BFIFOFRAMSW_MAX, 0), - SOC_SINGLE("Burst FIFO Wake Up Delay", - AB8500_FIFOCONF5, AB8500_FIFOCONF5_BFIFOWAKEUP_SHIFT, - AB8500_FIFOCONF5_BFIFOWAKEUP_MAX, 0), - SOC_SINGLE("Burst FIFO Samples In FIFO", - AB8500_FIFOCONF6, AB8500_FIFOCONF6_BFIFOSAMPLE_SHIFT, - AB8500_FIFOCONF6_BFIFOSAMPLE_MAX, 0), - - /* ANC */ - SOC_ENUM_EXT("ANC Status", soc_enum_ancstate, - anc_status_control_get, anc_status_control_put), - SOC_SINGLE_XR_SX("ANC Warp Delay Shift", - AB8500_ANCCONF2, 1, AB8500_ANCCONF2_SHIFT, - AB8500_ANCCONF2_MIN, AB8500_ANCCONF2_MAX, 0), - SOC_SINGLE_XR_SX("ANC FIR Output Shift", - AB8500_ANCCONF3, 1, AB8500_ANCCONF3_SHIFT, - AB8500_ANCCONF3_MIN, AB8500_ANCCONF3_MAX, 0), - SOC_SINGLE_XR_SX("ANC IIR Output Shift", - AB8500_ANCCONF4, 1, AB8500_ANCCONF4_SHIFT, - AB8500_ANCCONF4_MIN, AB8500_ANCCONF4_MAX, 0), - SOC_SINGLE_XR_SX("ANC Warp Delay", - AB8500_ANCCONF9, 2, AB8500_ANC_WARP_DELAY_SHIFT, - AB8500_ANC_WARP_DELAY_MIN, AB8500_ANC_WARP_DELAY_MAX, 0), - - /* Sidetone */ - SOC_ENUM_EXT("Sidetone Status", soc_enum_sidstate, - sid_status_control_get, sid_status_control_put), - SOC_SINGLE_STROBE("Sidetone Reset", - AB8500_SIDFIRADR, AB8500_SIDFIRADR_FIRSIDSET, 0), -}; - -static struct snd_kcontrol_new ab8500_filter_controls[] = { - AB8500_FILTER_CONTROL("ANC FIR Coefficients", AB8500_ANC_FIR_COEFFS, - AB8500_ANC_FIR_COEFF_MIN, AB8500_ANC_FIR_COEFF_MAX), - AB8500_FILTER_CONTROL("ANC IIR Coefficients", AB8500_ANC_IIR_COEFFS, - AB8500_ANC_IIR_COEFF_MIN, AB8500_ANC_IIR_COEFF_MAX), - AB8500_FILTER_CONTROL("Sidetone FIR Coefficients", - AB8500_SID_FIR_COEFFS, AB8500_SID_FIR_COEFF_MIN, - AB8500_SID_FIR_COEFF_MAX) -}; -enum ab8500_filter { - AB8500_FILTER_ANC_FIR = 0, - AB8500_FILTER_ANC_IIR = 1, - AB8500_FILTER_SID_FIR = 2, -}; - -/* - * Extended interface for codec-driver - */ - -static int ab8500_audio_init_audioblock(struct snd_soc_codec *codec) -{ - int status; - - dev_dbg(codec->dev, "%s: Enter.\n", __func__); - - /* Reset audio-registers and disable 32kHz-clock output 2 */ - status = ab8500_sysctrl_write(AB8500_STW4500CTRL3, - AB8500_STW4500CTRL3_CLK32KOUT2DIS | - AB8500_STW4500CTRL3_RESETAUDN, - AB8500_STW4500CTRL3_RESETAUDN); - if (status < 0) - return status; - - return 0; -} - -static int ab8500_audio_setup_mics(struct snd_soc_codec *codec, - struct amic_settings *amics) -{ - u8 value8; - unsigned int value; - int status; - const struct snd_soc_dapm_route *route; - - dev_dbg(codec->dev, "%s: Enter.\n", __func__); - - /* Set DMic-clocks to outputs */ - status = abx500_get_register_interruptible(codec->dev, (u8)AB8500_MISC, - (u8)AB8500_GPIO_DIR4_REG, - &value8); - if (status < 0) - return status; - value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT | - GPIO31_DIR_OUTPUT; - status = abx500_set_register_interruptible(codec->dev, - (u8)AB8500_MISC, - (u8)AB8500_GPIO_DIR4_REG, - value); - if (status < 0) - return status; - - /* Attach regulators to AMic DAPM-paths */ - dev_dbg(codec->dev, "%s: Mic 1a regulator: %s\n", __func__, - amic_micbias_str(amics->mic1a_micbias)); - route = &ab8500_dapm_routes_mic1a_vamicx[amics->mic1a_micbias]; - status = snd_soc_dapm_add_routes(&codec->dapm, route, 1); - dev_dbg(codec->dev, "%s: Mic 1b regulator: %s\n", __func__, - amic_micbias_str(amics->mic1b_micbias)); - route = &ab8500_dapm_routes_mic1b_vamicx[amics->mic1b_micbias]; - status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1); - dev_dbg(codec->dev, "%s: Mic 2 regulator: %s\n", __func__, - amic_micbias_str(amics->mic2_micbias)); - route = &ab8500_dapm_routes_mic2_vamicx[amics->mic2_micbias]; - status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1); - if (status < 0) { - dev_err(codec->dev, - "%s: Failed to add AMic-regulator DAPM-routes (%d).\n", - __func__, status); - return status; - } - - /* Set AMic-configuration */ - dev_dbg(codec->dev, "%s: Mic 1 mic-type: %s\n", __func__, - amic_type_str(amics->mic1_type)); - snd_soc_update_bits(codec, AB8500_ANAGAIN1, AB8500_ANAGAINX_ENSEMICX, - amics->mic1_type == AMIC_TYPE_DIFFERENTIAL ? - 0 : AB8500_ANAGAINX_ENSEMICX); - dev_dbg(codec->dev, "%s: Mic 2 mic-type: %s\n", __func__, - amic_type_str(amics->mic2_type)); - snd_soc_update_bits(codec, AB8500_ANAGAIN2, AB8500_ANAGAINX_ENSEMICX, - amics->mic2_type == AMIC_TYPE_DIFFERENTIAL ? - 0 : AB8500_ANAGAINX_ENSEMICX); - - return 0; -} -EXPORT_SYMBOL_GPL(ab8500_audio_setup_mics); - -static int ab8500_audio_set_ear_cmv(struct snd_soc_codec *codec, - enum ear_cm_voltage ear_cmv) -{ - char *cmv_str; - - switch (ear_cmv) { - case EAR_CMV_0_95V: - cmv_str = "0.95V"; - break; - case EAR_CMV_1_10V: - cmv_str = "1.10V"; - break; - case EAR_CMV_1_27V: - cmv_str = "1.27V"; - break; - case EAR_CMV_1_58V: - cmv_str = "1.58V"; - break; - default: - dev_err(codec->dev, - "%s: Unknown earpiece CM-voltage (%d)!\n", - __func__, (int)ear_cmv); - return -EINVAL; - } - dev_dbg(codec->dev, "%s: Earpiece CM-voltage: %s\n", __func__, - cmv_str); - snd_soc_update_bits(codec, AB8500_ANACONF1, AB8500_ANACONF1_EARSELCM, - ear_cmv); - - return 0; -} -EXPORT_SYMBOL_GPL(ab8500_audio_set_ear_cmv); - -static int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai, - unsigned int delay) -{ - unsigned int mask, val; - struct snd_soc_codec *codec = dai->codec; - - mask = BIT(AB8500_DIGIFCONF2_IF0DEL); - val = 0; - - switch (delay) { - case 0: - break; - case 1: - val |= BIT(AB8500_DIGIFCONF2_IF0DEL); - break; - default: - dev_err(dai->codec->dev, - "%s: ERROR: Unsupported bit-delay (0x%x)!\n", - __func__, delay); - return -EINVAL; - } - - dev_dbg(dai->codec->dev, "%s: IF0 Bit-delay: %d bits.\n", - __func__, delay); - snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val); - - return 0; -} - -/* Gates clocking according format mask */ -static int ab8500_codec_set_dai_clock_gate(struct snd_soc_codec *codec, - unsigned int fmt) -{ - unsigned int mask; - unsigned int val; - - mask = BIT(AB8500_DIGIFCONF1_ENMASTGEN) | - BIT(AB8500_DIGIFCONF1_ENFSBITCLK0); - - val = BIT(AB8500_DIGIFCONF1_ENMASTGEN); - - switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { - case SND_SOC_DAIFMT_CONT: /* continuous clock */ - dev_dbg(codec->dev, "%s: IF0 Clock is continuous.\n", - __func__); - val |= BIT(AB8500_DIGIFCONF1_ENFSBITCLK0); - break; - case SND_SOC_DAIFMT_GATED: /* clock is gated */ - dev_dbg(codec->dev, "%s: IF0 Clock is gated.\n", - __func__); - break; - default: - dev_err(codec->dev, - "%s: ERROR: Unsupported clock mask (0x%x)!\n", - __func__, fmt & SND_SOC_DAIFMT_CLOCK_MASK); - return -EINVAL; - } - - snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val); - - return 0; -} - -static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - unsigned int mask; - unsigned int val; - struct snd_soc_codec *codec = dai->codec; - int status; - - dev_dbg(codec->dev, "%s: Enter (fmt = 0x%x)\n", __func__, fmt); - - mask = BIT(AB8500_DIGIFCONF3_IF1DATOIF0AD) | - BIT(AB8500_DIGIFCONF3_IF1CLKTOIF0CLK) | - BIT(AB8500_DIGIFCONF3_IF0BFIFOEN) | - BIT(AB8500_DIGIFCONF3_IF0MASTER); - val = 0; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & FRM master */ - dev_dbg(dai->codec->dev, - "%s: IF0 Master-mode: AB8500 master.\n", __func__); - val |= BIT(AB8500_DIGIFCONF3_IF0MASTER); - break; - case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & FRM slave */ - dev_dbg(dai->codec->dev, - "%s: IF0 Master-mode: AB8500 slave.\n", __func__); - break; - case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & FRM master */ - case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */ - dev_err(dai->codec->dev, - "%s: ERROR: The device is either a master or a slave.\n", - __func__); - default: - dev_err(dai->codec->dev, - "%s: ERROR: Unsupporter master mask 0x%x\n", - __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); - return -EINVAL; - break; - } - - snd_soc_update_bits(codec, AB8500_DIGIFCONF3, mask, val); - - /* Set clock gating */ - status = ab8500_codec_set_dai_clock_gate(codec, fmt); - if (status) { - dev_err(dai->codec->dev, - "%s: ERRROR: Failed to set clock gate (%d).\n", - __func__, status); - return status; - } - - /* Setting data transfer format */ - - mask = BIT(AB8500_DIGIFCONF2_IF0FORMAT0) | - BIT(AB8500_DIGIFCONF2_IF0FORMAT1) | - BIT(AB8500_DIGIFCONF2_FSYNC0P) | - BIT(AB8500_DIGIFCONF2_BITCLK0P); - val = 0; - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: /* I2S mode */ - dev_dbg(dai->codec->dev, "%s: IF0 Protocol: I2S\n", __func__); - val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT1); - ab8500_audio_set_bit_delay(dai, 0); - break; - - case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */ - dev_dbg(dai->codec->dev, - "%s: IF0 Protocol: DSP A (TDM)\n", __func__); - val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0); - ab8500_audio_set_bit_delay(dai, 1); - break; - - case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */ - dev_dbg(dai->codec->dev, - "%s: IF0 Protocol: DSP B (TDM)\n", __func__); - val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0); - ab8500_audio_set_bit_delay(dai, 0); - break; - - default: - dev_err(dai->codec->dev, - "%s: ERROR: Unsupported format (0x%x)!\n", - __func__, fmt & SND_SOC_DAIFMT_FORMAT_MASK); - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */ - dev_dbg(dai->codec->dev, - "%s: IF0: Normal bit clock, normal frame\n", - __func__); - break; - case SND_SOC_DAIFMT_NB_IF: /* normal BCLK + inv FRM */ - dev_dbg(dai->codec->dev, - "%s: IF0: Normal bit clock, inverted frame\n", - __func__); - val |= BIT(AB8500_DIGIFCONF2_FSYNC0P); - break; - case SND_SOC_DAIFMT_IB_NF: /* invert BCLK + nor FRM */ - dev_dbg(dai->codec->dev, - "%s: IF0: Inverted bit clock, normal frame\n", - __func__); - val |= BIT(AB8500_DIGIFCONF2_BITCLK0P); - break; - case SND_SOC_DAIFMT_IB_IF: /* invert BCLK + FRM */ - dev_dbg(dai->codec->dev, - "%s: IF0: Inverted bit clock, inverted frame\n", - __func__); - val |= BIT(AB8500_DIGIFCONF2_FSYNC0P); - val |= BIT(AB8500_DIGIFCONF2_BITCLK0P); - break; - default: - dev_err(dai->codec->dev, - "%s: ERROR: Unsupported INV mask 0x%x\n", - __func__, fmt & SND_SOC_DAIFMT_INV_MASK); - return -EINVAL; - } - - snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val); - - return 0; -} - -static int ab8500_codec_set_dai_tdm_slot(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, mask, slots_active; - - mask = BIT(AB8500_DIGIFCONF2_IF0WL0) | - BIT(AB8500_DIGIFCONF2_IF0WL1); - val = 0; - - switch (slot_width) { - case 16: - break; - case 20: - val |= BIT(AB8500_DIGIFCONF2_IF0WL0); - break; - case 24: - val |= BIT(AB8500_DIGIFCONF2_IF0WL1); - break; - case 32: - val |= BIT(AB8500_DIGIFCONF2_IF0WL1) | - BIT(AB8500_DIGIFCONF2_IF0WL0); - break; - default: - dev_err(dai->codec->dev, "%s: Unsupported slot-width 0x%x\n", - __func__, slot_width); - return -EINVAL; - } - - dev_dbg(dai->codec->dev, "%s: IF0 slot-width: %d bits.\n", - __func__, slot_width); - snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val); - - /* Setup TDM clocking according to slot count */ - dev_dbg(dai->codec->dev, "%s: Slots, total: %d\n", __func__, slots); - mask = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) | - BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1); - switch (slots) { - case 2: - val = AB8500_MASK_NONE; - break; - case 4: - val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0); - break; - case 8: - val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1); - break; - case 16: - val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) | - BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1); - break; - default: - dev_err(dai->codec->dev, - "%s: ERROR: Unsupported number of slots (%d)!\n", - __func__, slots); - return -EINVAL; - } - snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val); - - /* Setup TDM DA according to active tx slots */ - mask = AB8500_DASLOTCONFX_SLTODAX_MASK; - slots_active = hweight32(tx_mask); - dev_dbg(dai->codec->dev, "%s: Slots, active, TX: %d\n", __func__, - slots_active); - switch (slots_active) { - case 0: - break; - case 1: - /* Slot 9 -> DA_IN1 & DA_IN3 */ - snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 11); - snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 11); - snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11); - snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11); - break; - case 2: - /* Slot 9 -> DA_IN1 & DA_IN3, Slot 11 -> DA_IN2 & DA_IN4 */ - snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 9); - snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 9); - snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11); - snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11); - - break; - case 8: - dev_dbg(dai->codec->dev, - "%s: In 8-channel mode DA-from-slot mapping is set manually.", - __func__); - break; - default: - dev_err(dai->codec->dev, - "%s: Unsupported number of active TX-slots (%d)!\n", - __func__, slots_active); - return -EINVAL; - } - - /* Setup TDM AD according to active RX-slots */ - slots_active = hweight32(rx_mask); - dev_dbg(dai->codec->dev, "%s: Slots, active, RX: %d\n", __func__, - slots_active); - switch (slots_active) { - case 0: - break; - case 1: - /* AD_OUT3 -> slot 0 & 1 */ - snd_soc_update_bits(codec, AB8500_ADSLOTSEL1, AB8500_MASK_ALL, - AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN | - AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD); - break; - case 2: - /* AD_OUT3 -> slot 0, AD_OUT2 -> slot 1 */ - snd_soc_update_bits(codec, - AB8500_ADSLOTSEL1, - AB8500_MASK_ALL, - AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN | - AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD); - break; - case 8: - dev_dbg(dai->codec->dev, - "%s: In 8-channel mode AD-to-slot mapping is set manually.", - __func__); - break; - default: - dev_err(dai->codec->dev, - "%s: Unsupported number of active RX-slots (%d)!\n", - __func__, slots_active); - return -EINVAL; - } - - return 0; -} - -struct snd_soc_dai_driver ab8500_codec_dai[] = { - { - .name = "ab8500-codec-dai.0", - .id = 0, - .playback = { - .stream_name = "ab8500_0p", - .channels_min = 1, - .channels_max = 8, - .rates = AB8500_SUPPORTED_RATE, - .formats = AB8500_SUPPORTED_FMT, - }, - .ops = (struct snd_soc_dai_ops[]) { - { - .set_tdm_slot = ab8500_codec_set_dai_tdm_slot, - .set_fmt = ab8500_codec_set_dai_fmt, - } - }, - .symmetric_rates = 1 - }, - { - .name = "ab8500-codec-dai.1", - .id = 1, - .capture = { - .stream_name = "ab8500_0c", - .channels_min = 1, - .channels_max = 8, - .rates = AB8500_SUPPORTED_RATE, - .formats = AB8500_SUPPORTED_FMT, - }, - .ops = (struct snd_soc_dai_ops[]) { - { - .set_tdm_slot = ab8500_codec_set_dai_tdm_slot, - .set_fmt = ab8500_codec_set_dai_fmt, - } - }, - .symmetric_rates = 1 - } -}; - -static int ab8500_codec_probe(struct snd_soc_codec *codec) -{ - struct device *dev = codec->dev; - struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev); - struct ab8500_platform_data *pdata; - struct filter_control *fc; - int status; - - dev_dbg(dev, "%s: Enter.\n", __func__); - - /* Setup AB8500 according to board-settings */ - pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent); - status = ab8500_audio_setup_mics(codec, &pdata->codec->amics); - if (status < 0) { - pr_err("%s: Failed to setup mics (%d)!\n", __func__, status); - return status; - } - status = ab8500_audio_set_ear_cmv(codec, pdata->codec->ear_cmv); - if (status < 0) { - pr_err("%s: Failed to set earpiece CM-voltage (%d)!\n", - __func__, status); - return status; - } - - status = ab8500_audio_init_audioblock(codec); - if (status < 0) { - dev_err(dev, "%s: failed to init audio-block (%d)!\n", - __func__, status); - return status; - } - - /* Override HW-defaults */ - ab8500_codec_write_reg(codec, - AB8500_ANACONF5, - BIT(AB8500_ANACONF5_HSAUTOEN)); - ab8500_codec_write_reg(codec, - AB8500_SHORTCIRCONF, - BIT(AB8500_SHORTCIRCONF_HSZCDDIS)); - - /* Add filter controls */ - status = snd_soc_add_codec_controls(codec, ab8500_filter_controls, - ARRAY_SIZE(ab8500_filter_controls)); - if (status < 0) { - dev_err(dev, - "%s: failed to add ab8500 filter controls (%d).\n", - __func__, status); - return status; - } - fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; - drvdata->anc_fir_values = (long *)fc->value; - fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; - drvdata->anc_iir_values = (long *)fc->value; - fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; - drvdata->sid_fir_values = (long *)fc->value; - - (void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input"); - - mutex_init(&drvdata->anc_lock); - - return status; -} - -static struct snd_soc_codec_driver ab8500_codec_driver = { - .probe = ab8500_codec_probe, - .read = ab8500_codec_read_reg, - .write = ab8500_codec_write_reg, - .reg_word_size = sizeof(u8), - .controls = ab8500_ctrls, - .num_controls = ARRAY_SIZE(ab8500_ctrls), - .dapm_widgets = ab8500_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ab8500_dapm_widgets), - .dapm_routes = ab8500_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(ab8500_dapm_routes), -}; - -static int __devinit ab8500_codec_driver_probe(struct platform_device *pdev) -{ - int status; - struct ab8500_codec_drvdata *drvdata; - - dev_dbg(&pdev->dev, "%s: Enter.\n", __func__); - - /* Create driver private-data struct */ - drvdata = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_codec_drvdata), - GFP_KERNEL); - drvdata->sid_status = SID_UNCONFIGURED; - drvdata->anc_status = ANC_UNCONFIGURED; - dev_set_drvdata(&pdev->dev, drvdata); - - dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__); - status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver, - ab8500_codec_dai, - ARRAY_SIZE(ab8500_codec_dai)); - if (status < 0) - dev_err(&pdev->dev, - "%s: Error: Failed to register codec (%d).\n", - __func__, status); - - return status; -} - -static int __devexit ab8500_codec_driver_remove(struct platform_device *pdev) -{ - dev_info(&pdev->dev, "%s Enter.\n", __func__); - - snd_soc_unregister_codec(&pdev->dev); - - return 0; -} - -static struct platform_driver ab8500_codec_platform_driver = { - .driver = { - .name = "ab8500-codec", - .owner = THIS_MODULE, - }, - .probe = ab8500_codec_driver_probe, - .remove = __devexit_p(ab8500_codec_driver_remove), - .suspend = NULL, - .resume = NULL, -}; -module_platform_driver(ab8500_codec_platform_driver); - -MODULE_LICENSE("GPLv2"); diff --git a/trunk/sound/soc/codecs/ab8500-codec.h b/trunk/sound/soc/codecs/ab8500-codec.h deleted file mode 100644 index 114f69a0c629..000000000000 --- a/trunk/sound/soc/codecs/ab8500-codec.h +++ /dev/null @@ -1,590 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2012 - * - * Author: Ola Lilja , - * Kristoffer Karlsson , - * Roger Nilsson , - * for ST-Ericsson. - * - * Based on the early work done by: - * Mikko J. Lehto , - * Mikko Sarmanne , - * 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 AB8500_CODEC_REGISTERS_H -#define AB8500_CODEC_REGISTERS_H - -#define AB8500_SUPPORTED_RATE (SNDRV_PCM_RATE_48000) -#define AB8500_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE) - -/* AB8500 audio bank (0x0d) register definitions */ - -#define AB8500_POWERUP 0x00 -#define AB8500_AUDSWRESET 0x01 -#define AB8500_ADPATHENA 0x02 -#define AB8500_DAPATHENA 0x03 -#define AB8500_ANACONF1 0x04 -#define AB8500_ANACONF2 0x05 -#define AB8500_DIGMICCONF 0x06 -#define AB8500_ANACONF3 0x07 -#define AB8500_ANACONF4 0x08 -#define AB8500_DAPATHCONF 0x09 -#define AB8500_MUTECONF 0x0A -#define AB8500_SHORTCIRCONF 0x0B -#define AB8500_ANACONF5 0x0C -#define AB8500_ENVCPCONF 0x0D -#define AB8500_SIGENVCONF 0x0E -#define AB8500_PWMGENCONF1 0x0F -#define AB8500_PWMGENCONF2 0x10 -#define AB8500_PWMGENCONF3 0x11 -#define AB8500_PWMGENCONF4 0x12 -#define AB8500_PWMGENCONF5 0x13 -#define AB8500_ANAGAIN1 0x14 -#define AB8500_ANAGAIN2 0x15 -#define AB8500_ANAGAIN3 0x16 -#define AB8500_ANAGAIN4 0x17 -#define AB8500_DIGLINHSLGAIN 0x18 -#define AB8500_DIGLINHSRGAIN 0x19 -#define AB8500_ADFILTCONF 0x1A -#define AB8500_DIGIFCONF1 0x1B -#define AB8500_DIGIFCONF2 0x1C -#define AB8500_DIGIFCONF3 0x1D -#define AB8500_DIGIFCONF4 0x1E -#define AB8500_ADSLOTSEL1 0x1F -#define AB8500_ADSLOTSEL2 0x20 -#define AB8500_ADSLOTSEL3 0x21 -#define AB8500_ADSLOTSEL4 0x22 -#define AB8500_ADSLOTSEL5 0x23 -#define AB8500_ADSLOTSEL6 0x24 -#define AB8500_ADSLOTSEL7 0x25 -#define AB8500_ADSLOTSEL8 0x26 -#define AB8500_ADSLOTSEL9 0x27 -#define AB8500_ADSLOTSEL10 0x28 -#define AB8500_ADSLOTSEL11 0x29 -#define AB8500_ADSLOTSEL12 0x2A -#define AB8500_ADSLOTSEL13 0x2B -#define AB8500_ADSLOTSEL14 0x2C -#define AB8500_ADSLOTSEL15 0x2D -#define AB8500_ADSLOTSEL16 0x2E -#define AB8500_ADSLOTHIZCTRL1 0x2F -#define AB8500_ADSLOTHIZCTRL2 0x30 -#define AB8500_ADSLOTHIZCTRL3 0x31 -#define AB8500_ADSLOTHIZCTRL4 0x32 -#define AB8500_DASLOTCONF1 0x33 -#define AB8500_DASLOTCONF2 0x34 -#define AB8500_DASLOTCONF3 0x35 -#define AB8500_DASLOTCONF4 0x36 -#define AB8500_DASLOTCONF5 0x37 -#define AB8500_DASLOTCONF6 0x38 -#define AB8500_DASLOTCONF7 0x39 -#define AB8500_DASLOTCONF8 0x3A -#define AB8500_CLASSDCONF1 0x3B -#define AB8500_CLASSDCONF2 0x3C -#define AB8500_CLASSDCONF3 0x3D -#define AB8500_DMICFILTCONF 0x3E -#define AB8500_DIGMULTCONF1 0x3F -#define AB8500_DIGMULTCONF2 0x40 -#define AB8500_ADDIGGAIN1 0x41 -#define AB8500_ADDIGGAIN2 0x42 -#define AB8500_ADDIGGAIN3 0x43 -#define AB8500_ADDIGGAIN4 0x44 -#define AB8500_ADDIGGAIN5 0x45 -#define AB8500_ADDIGGAIN6 0x46 -#define AB8500_DADIGGAIN1 0x47 -#define AB8500_DADIGGAIN2 0x48 -#define AB8500_DADIGGAIN3 0x49 -#define AB8500_DADIGGAIN4 0x4A -#define AB8500_DADIGGAIN5 0x4B -#define AB8500_DADIGGAIN6 0x4C -#define AB8500_ADDIGLOOPGAIN1 0x4D -#define AB8500_ADDIGLOOPGAIN2 0x4E -#define AB8500_HSLEARDIGGAIN 0x4F -#define AB8500_HSRDIGGAIN 0x50 -#define AB8500_SIDFIRGAIN1 0x51 -#define AB8500_SIDFIRGAIN2 0x52 -#define AB8500_ANCCONF1 0x53 -#define AB8500_ANCCONF2 0x54 -#define AB8500_ANCCONF3 0x55 -#define AB8500_ANCCONF4 0x56 -#define AB8500_ANCCONF5 0x57 -#define AB8500_ANCCONF6 0x58 -#define AB8500_ANCCONF7 0x59 -#define AB8500_ANCCONF8 0x5A -#define AB8500_ANCCONF9 0x5B -#define AB8500_ANCCONF10 0x5C -#define AB8500_ANCCONF11 0x5D -#define AB8500_ANCCONF12 0x5E -#define AB8500_ANCCONF13 0x5F -#define AB8500_ANCCONF14 0x60 -#define AB8500_SIDFIRADR 0x61 -#define AB8500_SIDFIRCOEF1 0x62 -#define AB8500_SIDFIRCOEF2 0x63 -#define AB8500_SIDFIRCONF 0x64 -#define AB8500_AUDINTMASK1 0x65 -#define AB8500_AUDINTSOURCE1 0x66 -#define AB8500_AUDINTMASK2 0x67 -#define AB8500_AUDINTSOURCE2 0x68 -#define AB8500_FIFOCONF1 0x69 -#define AB8500_FIFOCONF2 0x6A -#define AB8500_FIFOCONF3 0x6B -#define AB8500_FIFOCONF4 0x6C -#define AB8500_FIFOCONF5 0x6D -#define AB8500_FIFOCONF6 0x6E -#define AB8500_AUDREV 0x6F - -#define AB8500_FIRST_REG AB8500_POWERUP -#define AB8500_LAST_REG AB8500_AUDREV -#define AB8500_CACHEREGNUM (AB8500_LAST_REG + 1) - -#define AB8500_MASK_ALL 0xFF -#define AB8500_MASK_NONE 0x00 - -/* AB8500_POWERUP */ -#define AB8500_POWERUP_POWERUP 7 -#define AB8500_POWERUP_ENANA 3 - -/* AB8500_AUDSWRESET */ -#define AB8500_AUDSWRESET_SWRESET 7 - -/* AB8500_ADPATHENA */ -#define AB8500_ADPATHENA_ENAD12 7 -#define AB8500_ADPATHENA_ENAD34 5 -#define AB8500_ADPATHENA_ENAD5768 3 - -/* AB8500_DAPATHENA */ -#define AB8500_DAPATHENA_ENDA1 7 -#define AB8500_DAPATHENA_ENDA2 6 -#define AB8500_DAPATHENA_ENDA3 5 -#define AB8500_DAPATHENA_ENDA4 4 -#define AB8500_DAPATHENA_ENDA5 3 -#define AB8500_DAPATHENA_ENDA6 2 - -/* AB8500_ANACONF1 */ -#define AB8500_ANACONF1_HSLOWPOW 7 -#define AB8500_ANACONF1_DACLOWPOW1 6 -#define AB8500_ANACONF1_DACLOWPOW0 5 -#define AB8500_ANACONF1_EARDACLOWPOW 4 -#define AB8500_ANACONF1_EARSELCM 2 -#define AB8500_ANACONF1_HSHPEN 1 -#define AB8500_ANACONF1_EARDRVLOWPOW 0 - -/* AB8500_ANACONF2 */ -#define AB8500_ANACONF2_ENMIC1 7 -#define AB8500_ANACONF2_ENMIC2 6 -#define AB8500_ANACONF2_ENLINL 5 -#define AB8500_ANACONF2_ENLINR 4 -#define AB8500_ANACONF2_MUTMIC1 3 -#define AB8500_ANACONF2_MUTMIC2 2 -#define AB8500_ANACONF2_MUTLINL 1 -#define AB8500_ANACONF2_MUTLINR 0 - -/* AB8500_DIGMICCONF */ -#define AB8500_DIGMICCONF_ENDMIC1 7 -#define AB8500_DIGMICCONF_ENDMIC2 6 -#define AB8500_DIGMICCONF_ENDMIC3 5 -#define AB8500_DIGMICCONF_ENDMIC4 4 -#define AB8500_DIGMICCONF_ENDMIC5 3 -#define AB8500_DIGMICCONF_ENDMIC6 2 -#define AB8500_DIGMICCONF_HSFADSPEED 0 - -/* AB8500_ANACONF3 */ -#define AB8500_ANACONF3_MIC1SEL 7 -#define AB8500_ANACONF3_LINRSEL 6 -#define AB8500_ANACONF3_ENDRVHSL 5 -#define AB8500_ANACONF3_ENDRVHSR 4 -#define AB8500_ANACONF3_ENADCMIC 2 -#define AB8500_ANACONF3_ENADCLINL 1 -#define AB8500_ANACONF3_ENADCLINR 0 - -/* AB8500_ANACONF4 */ -#define AB8500_ANACONF4_DISPDVSS 7 -#define AB8500_ANACONF4_ENEAR 6 -#define AB8500_ANACONF4_ENHSL 5 -#define AB8500_ANACONF4_ENHSR 4 -#define AB8500_ANACONF4_ENHFL 3 -#define AB8500_ANACONF4_ENHFR 2 -#define AB8500_ANACONF4_ENVIB1 1 -#define AB8500_ANACONF4_ENVIB2 0 - -/* AB8500_DAPATHCONF */ -#define AB8500_DAPATHCONF_ENDACEAR 6 -#define AB8500_DAPATHCONF_ENDACHSL 5 -#define AB8500_DAPATHCONF_ENDACHSR 4 -#define AB8500_DAPATHCONF_ENDACHFL 3 -#define AB8500_DAPATHCONF_ENDACHFR 2 -#define AB8500_DAPATHCONF_ENDACVIB1 1 -#define AB8500_DAPATHCONF_ENDACVIB2 0 - -/* AB8500_MUTECONF */ -#define AB8500_MUTECONF_MUTEAR 6 -#define AB8500_MUTECONF_MUTHSL 5 -#define AB8500_MUTECONF_MUTHSR 4 -#define AB8500_MUTECONF_MUTDACEAR 2 -#define AB8500_MUTECONF_MUTDACHSL 1 -#define AB8500_MUTECONF_MUTDACHSR 0 - -/* AB8500_SHORTCIRCONF */ -#define AB8500_SHORTCIRCONF_ENSHORTPWD 7 -#define AB8500_SHORTCIRCONF_EARSHORTDIS 6 -#define AB8500_SHORTCIRCONF_HSSHORTDIS 5 -#define AB8500_SHORTCIRCONF_HSPULLDEN 4 -#define AB8500_SHORTCIRCONF_HSOSCEN 2 -#define AB8500_SHORTCIRCONF_HSFADDIS 1 -#define AB8500_SHORTCIRCONF_HSZCDDIS 0 -/* Zero cross should be disabled */ - -/* AB8500_ANACONF5 */ -#define AB8500_ANACONF5_ENCPHS 7 -#define AB8500_ANACONF5_HSLDACTOLOL 5 -#define AB8500_ANACONF5_HSRDACTOLOR 4 -#define AB8500_ANACONF5_ENLOL 3 -#define AB8500_ANACONF5_ENLOR 2 -#define AB8500_ANACONF5_HSAUTOEN 0 - -/* AB8500_ENVCPCONF */ -#define AB8500_ENVCPCONF_ENVDETHTHRE 4 -#define AB8500_ENVCPCONF_ENVDETLTHRE 0 -#define AB8500_ENVCPCONF_ENVDETHTHRE_MAX 0x0F -#define AB8500_ENVCPCONF_ENVDETLTHRE_MAX 0x0F - -/* AB8500_SIGENVCONF */ -#define AB8500_SIGENVCONF_CPLVEN 5 -#define AB8500_SIGENVCONF_ENVDETCPEN 4 -#define AB8500_SIGENVCONF_ENVDETTIME 0 -#define AB8500_SIGENVCONF_ENVDETTIME_MAX 0x0F - -/* AB8500_PWMGENCONF1 */ -#define AB8500_PWMGENCONF1_PWMTOVIB1 7 -#define AB8500_PWMGENCONF1_PWMTOVIB2 6 -#define AB8500_PWMGENCONF1_PWM1CTRL 5 -#define AB8500_PWMGENCONF1_PWM2CTRL 4 -#define AB8500_PWMGENCONF1_PWM1NCTRL 3 -#define AB8500_PWMGENCONF1_PWM1PCTRL 2 -#define AB8500_PWMGENCONF1_PWM2NCTRL 1 -#define AB8500_PWMGENCONF1_PWM2PCTRL 0 - -/* AB8500_PWMGENCONF2 */ -/* AB8500_PWMGENCONF3 */ -/* AB8500_PWMGENCONF4 */ -/* AB8500_PWMGENCONF5 */ -#define AB8500_PWMGENCONFX_PWMVIBXPOL 7 -#define AB8500_PWMGENCONFX_PWMVIBXDUTCYC 0 -#define AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX 0x64 - -/* AB8500_ANAGAIN1 */ -/* AB8500_ANAGAIN2 */ -#define AB8500_ANAGAINX_ENSEMICX 7 -#define AB8500_ANAGAINX_LOWPOWMICX 6 -#define AB8500_ANAGAINX_MICXGAIN 0 -#define AB8500_ANAGAINX_MICXGAIN_MAX 0x1F - -/* AB8500_ANAGAIN3 */ -#define AB8500_ANAGAIN3_HSLGAIN 4 -#define AB8500_ANAGAIN3_HSRGAIN 0 -#define AB8500_ANAGAIN3_HSXGAIN_MAX 0x0F - -/* AB8500_ANAGAIN4 */ -#define AB8500_ANAGAIN4_LINLGAIN 4 -#define AB8500_ANAGAIN4_LINRGAIN 0 -#define AB8500_ANAGAIN4_LINXGAIN_MAX 0x0F - -/* AB8500_DIGLINHSLGAIN */ -/* AB8500_DIGLINHSRGAIN */ -#define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN 0 -#define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN_MAX 0x13 - -/* AB8500_ADFILTCONF */ -#define AB8500_ADFILTCONF_AD1NH 7 -#define AB8500_ADFILTCONF_AD2NH 6 -#define AB8500_ADFILTCONF_AD3NH 5 -#define AB8500_ADFILTCONF_AD4NH 4 -#define AB8500_ADFILTCONF_AD1VOICE 3 -#define AB8500_ADFILTCONF_AD2VOICE 2 -#define AB8500_ADFILTCONF_AD3VOICE 1 -#define AB8500_ADFILTCONF_AD4VOICE 0 - -/* AB8500_DIGIFCONF1 */ -#define AB8500_DIGIFCONF1_ENMASTGEN 7 -#define AB8500_DIGIFCONF1_IF1BITCLKOS1 6 -#define AB8500_DIGIFCONF1_IF1BITCLKOS0 5 -#define AB8500_DIGIFCONF1_ENFSBITCLK1 4 -#define AB8500_DIGIFCONF1_IF0BITCLKOS1 2 -#define AB8500_DIGIFCONF1_IF0BITCLKOS0 1 -#define AB8500_DIGIFCONF1_ENFSBITCLK0 0 - -/* AB8500_DIGIFCONF2 */ -#define AB8500_DIGIFCONF2_FSYNC0P 6 -#define AB8500_DIGIFCONF2_BITCLK0P 5 -#define AB8500_DIGIFCONF2_IF0DEL 4 -#define AB8500_DIGIFCONF2_IF0FORMAT1 3 -#define AB8500_DIGIFCONF2_IF0FORMAT0 2 -#define AB8500_DIGIFCONF2_IF0WL1 1 -#define AB8500_DIGIFCONF2_IF0WL0 0 - -/* AB8500_DIGIFCONF3 */ -#define AB8500_DIGIFCONF3_IF0DATOIF1AD 7 -#define AB8500_DIGIFCONF3_IF0CLKTOIF1CLK 6 -#define AB8500_DIGIFCONF3_IF1MASTER 5 -#define AB8500_DIGIFCONF3_IF1DATOIF0AD 3 -#define AB8500_DIGIFCONF3_IF1CLKTOIF0CLK 2 -#define AB8500_DIGIFCONF3_IF0MASTER 1 -#define AB8500_DIGIFCONF3_IF0BFIFOEN 0 - -/* AB8500_DIGIFCONF4 */ -#define AB8500_DIGIFCONF4_FSYNC1P 6 -#define AB8500_DIGIFCONF4_BITCLK1P 5 -#define AB8500_DIGIFCONF4_IF1DEL 4 -#define AB8500_DIGIFCONF4_IF1FORMAT1 3 -#define AB8500_DIGIFCONF4_IF1FORMAT0 2 -#define AB8500_DIGIFCONF4_IF1WL1 1 -#define AB8500_DIGIFCONF4_IF1WL0 0 - -/* AB8500_ADSLOTSELX */ -#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_ODD 0x00 -#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD 0x01 -#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD 0x02 -#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_ODD 0x03 -#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_ODD 0x04 -#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_ODD 0x05 -#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_ODD 0x06 -#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_ODD 0x07 -#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_ODD 0x08 -#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_ODD 0x0F -#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_EVEN 0x00 -#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_EVEN 0x10 -#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN 0x20 -#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_EVEN 0x30 -#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_EVEN 0x40 -#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_EVEN 0x50 -#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_EVEN 0x60 -#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_EVEN 0x70 -#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_EVEN 0x80 -#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_EVEN 0xF0 -#define AB8500_ADSLOTSELX_EVEN_SHIFT 0 -#define AB8500_ADSLOTSELX_ODD_SHIFT 4 - -/* AB8500_ADSLOTHIZCTRL1 */ -/* AB8500_ADSLOTHIZCTRL2 */ -/* AB8500_ADSLOTHIZCTRL3 */ -/* AB8500_ADSLOTHIZCTRL4 */ -/* AB8500_DASLOTCONF1 */ -#define AB8500_DASLOTCONF1_DA12VOICE 7 -#define AB8500_DASLOTCONF1_SWAPDA12_34 6 -#define AB8500_DASLOTCONF1_DAI7TOADO1 5 - -/* AB8500_DASLOTCONF2 */ -#define AB8500_DASLOTCONF2_DAI8TOADO2 5 - -/* AB8500_DASLOTCONF3 */ -#define AB8500_DASLOTCONF3_DA34VOICE 7 -#define AB8500_DASLOTCONF3_DAI7TOADO3 5 - -/* AB8500_DASLOTCONF4 */ -#define AB8500_DASLOTCONF4_DAI8TOADO4 5 - -/* AB8500_DASLOTCONF5 */ -#define AB8500_DASLOTCONF5_DA56VOICE 7 -#define AB8500_DASLOTCONF5_DAI7TOADO5 5 - -/* AB8500_DASLOTCONF6 */ -#define AB8500_DASLOTCONF6_DAI8TOADO6 5 - -/* AB8500_DASLOTCONF7 */ -#define AB8500_DASLOTCONF7_DAI8TOADO7 5 - -/* AB8500_DASLOTCONF8 */ -#define AB8500_DASLOTCONF8_DAI7TOADO8 5 - -#define AB8500_DASLOTCONFX_SLTODAX_SHIFT 0 -#define AB8500_DASLOTCONFX_SLTODAX_MASK 0x1F - -/* AB8500_CLASSDCONF1 */ -#define AB8500_CLASSDCONF1_PARLHF 7 -#define AB8500_CLASSDCONF1_PARLVIB 6 -#define AB8500_CLASSDCONF1_VIB1SWAPEN 3 -#define AB8500_CLASSDCONF1_VIB2SWAPEN 2 -#define AB8500_CLASSDCONF1_HFLSWAPEN 1 -#define AB8500_CLASSDCONF1_HFRSWAPEN 0 - -/* AB8500_CLASSDCONF2 */ -#define AB8500_CLASSDCONF2_FIRBYP3 7 -#define AB8500_CLASSDCONF2_FIRBYP2 6 -#define AB8500_CLASSDCONF2_FIRBYP1 5 -#define AB8500_CLASSDCONF2_FIRBYP0 4 -#define AB8500_CLASSDCONF2_HIGHVOLEN3 3 -#define AB8500_CLASSDCONF2_HIGHVOLEN2 2 -#define AB8500_CLASSDCONF2_HIGHVOLEN1 1 -#define AB8500_CLASSDCONF2_HIGHVOLEN0 0 - -/* AB8500_CLASSDCONF3 */ -#define AB8500_CLASSDCONF3_DITHHPGAIN 4 -#define AB8500_CLASSDCONF3_DITHHPGAIN_MAX 0x0A -#define AB8500_CLASSDCONF3_DITHWGAIN 0 -#define AB8500_CLASSDCONF3_DITHWGAIN_MAX 0x0A - -/* AB8500_DMICFILTCONF */ -#define AB8500_DMICFILTCONF_ANCINSEL 7 -#define AB8500_DMICFILTCONF_DA3TOEAR 6 -#define AB8500_DMICFILTCONF_DMIC1SINC3 5 -#define AB8500_DMICFILTCONF_DMIC2SINC3 4 -#define AB8500_DMICFILTCONF_DMIC3SINC3 3 -#define AB8500_DMICFILTCONF_DMIC4SINC3 2 -#define AB8500_DMICFILTCONF_DMIC5SINC3 1 -#define AB8500_DMICFILTCONF_DMIC6SINC3 0 - -/* AB8500_DIGMULTCONF1 */ -#define AB8500_DIGMULTCONF1_DATOHSLEN 7 -#define AB8500_DIGMULTCONF1_DATOHSREN 6 -#define AB8500_DIGMULTCONF1_AD1SEL 5 -#define AB8500_DIGMULTCONF1_AD2SEL 4 -#define AB8500_DIGMULTCONF1_AD3SEL 3 -#define AB8500_DIGMULTCONF1_AD5SEL 2 -#define AB8500_DIGMULTCONF1_AD6SEL 1 -#define AB8500_DIGMULTCONF1_ANCSEL 0 - -/* AB8500_DIGMULTCONF2 */ -#define AB8500_DIGMULTCONF2_DATOHFREN 7 -#define AB8500_DIGMULTCONF2_DATOHFLEN 6 -#define AB8500_DIGMULTCONF2_HFRSEL 5 -#define AB8500_DIGMULTCONF2_HFLSEL 4 -#define AB8500_DIGMULTCONF2_FIRSID1SEL 2 -#define AB8500_DIGMULTCONF2_FIRSID2SEL 0 - -/* AB8500_ADDIGGAIN1 */ -/* AB8500_ADDIGGAIN2 */ -/* AB8500_ADDIGGAIN3 */ -/* AB8500_ADDIGGAIN4 */ -/* AB8500_ADDIGGAIN5 */ -/* AB8500_ADDIGGAIN6 */ -#define AB8500_ADDIGGAINX_FADEDISADX 6 -#define AB8500_ADDIGGAINX_ADXGAIN_MAX 0x3F - -/* AB8500_DADIGGAIN1 */ -/* AB8500_DADIGGAIN2 */ -/* AB8500_DADIGGAIN3 */ -/* AB8500_DADIGGAIN4 */ -/* AB8500_DADIGGAIN5 */ -/* AB8500_DADIGGAIN6 */ -#define AB8500_DADIGGAINX_FADEDISDAX 6 -#define AB8500_DADIGGAINX_DAXGAIN_MAX 0x3F - -/* AB8500_ADDIGLOOPGAIN1 */ -/* AB8500_ADDIGLOOPGAIN2 */ -#define AB8500_ADDIGLOOPGAINX_FADEDISADXL 6 -#define AB8500_ADDIGLOOPGAINX_ADXLBGAIN_MAX 0x3F - -/* AB8500_HSLEARDIGGAIN */ -#define AB8500_HSLEARDIGGAIN_HSSINC1 7 -#define AB8500_HSLEARDIGGAIN_FADEDISHSL 4 -#define AB8500_HSLEARDIGGAIN_HSLDGAIN_MAX 0x09 - -/* AB8500_HSRDIGGAIN */ -#define AB8500_HSRDIGGAIN_FADESPEED 6 -#define AB8500_HSRDIGGAIN_FADEDISHSR 4 -#define AB8500_HSRDIGGAIN_HSRDGAIN_MAX 0x09 - -/* AB8500_SIDFIRGAIN1 */ -/* AB8500_SIDFIRGAIN2 */ -#define AB8500_SIDFIRGAINX_FIRSIDXGAIN_MAX 0x1F - -/* AB8500_ANCCONF1 */ -#define AB8500_ANCCONF1_ANCIIRUPDATE 3 -#define AB8500_ANCCONF1_ENANC 2 -#define AB8500_ANCCONF1_ANCIIRINIT 1 -#define AB8500_ANCCONF1_ANCFIRUPDATE 0 - -/* AB8500_ANCCONF2 */ -#define AB8500_ANCCONF2_SHIFT 5 -#define AB8500_ANCCONF2_MIN -0x10 -#define AB8500_ANCCONF2_MAX 0xF - -/* AB8500_ANCCONF3 */ -#define AB8500_ANCCONF3_SHIFT 5 -#define AB8500_ANCCONF3_MIN -0x10 -#define AB8500_ANCCONF3_MAX 0xF - -/* AB8500_ANCCONF4 */ -#define AB8500_ANCCONF4_SHIFT 5 -#define AB8500_ANCCONF4_MIN -0x10 -#define AB8500_ANCCONF4_MAX 0xF - -/* AB8500_ANC_FIR_COEFFS */ -#define AB8500_ANC_FIR_COEFF_MIN -0x8000 -#define AB8500_ANC_FIR_COEFF_MAX 0x7FFF -#define AB8500_ANC_FIR_COEFFS 15 - -/* AB8500_ANC_IIR_COEFFS */ -#define AB8500_ANC_IIR_COEFF_MIN -0x800000 -#define AB8500_ANC_IIR_COEFF_MAX 0x7FFFFF -#define AB8500_ANC_IIR_COEFFS 24 -/* AB8500_ANC_WARP_DELAY */ -#define AB8500_ANC_WARP_DELAY_SHIFT 16 -#define AB8500_ANC_WARP_DELAY_MIN 0x0000 -#define AB8500_ANC_WARP_DELAY_MAX 0xFFFF - -/* AB8500_ANCCONF11 */ -/* AB8500_ANCCONF12 */ -/* AB8500_ANCCONF13 */ -/* AB8500_ANCCONF14 */ - -/* AB8500_SIDFIRADR */ -#define AB8500_SIDFIRADR_FIRSIDSET 7 -#define AB8500_SIDFIRADR_ADDRESS_SHIFT 0 -#define AB8500_SIDFIRADR_ADDRESS_MAX 0x7F - -/* AB8500_SIDFIRCOEF1 */ -/* AB8500_SIDFIRCOEF2 */ -#define AB8500_SID_FIR_COEFF_MIN 0 -#define AB8500_SID_FIR_COEFF_MAX 0xFFFF -#define AB8500_SID_FIR_COEFFS 128 - -/* AB8500_SIDFIRCONF */ -#define AB8500_SIDFIRCONF_ENFIRSIDS 2 -#define AB8500_SIDFIRCONF_FIRSIDSTOIF1 1 -#define AB8500_SIDFIRCONF_FIRSIDBUSY 0 - -/* AB8500_AUDINTMASK1 */ -/* AB8500_AUDINTSOURCE1 */ -/* AB8500_AUDINTMASK2 */ -/* AB8500_AUDINTSOURCE2 */ - -/* AB8500_FIFOCONF1 */ -#define AB8500_FIFOCONF1_BFIFOMASK 0x80 -#define AB8500_FIFOCONF1_BFIFO19M2 0x40 -#define AB8500_FIFOCONF1_BFIFOINT_SHIFT 0 -#define AB8500_FIFOCONF1_BFIFOINT_MAX 0x3F - -/* AB8500_FIFOCONF2 */ -#define AB8500_FIFOCONF2_BFIFOTX_SHIFT 0 -#define AB8500_FIFOCONF2_BFIFOTX_MAX 0xFF - -/* AB8500_FIFOCONF3 */ -#define AB8500_FIFOCONF3_BFIFOEXSL_SHIFT 5 -#define AB8500_FIFOCONF3_BFIFOEXSL_MAX 0x5 -#define AB8500_FIFOCONF3_PREBITCLK0_SHIFT 2 -#define AB8500_FIFOCONF3_PREBITCLK0_MAX 0x7 -#define AB8500_FIFOCONF3_BFIFOMAST_SHIFT 1 -#define AB8500_FIFOCONF3_BFIFORUN_SHIFT 0 - -/* AB8500_FIFOCONF4 */ -#define AB8500_FIFOCONF4_BFIFOFRAMSW_SHIFT 0 -#define AB8500_FIFOCONF4_BFIFOFRAMSW_MAX 0xFF - -/* AB8500_FIFOCONF5 */ -#define AB8500_FIFOCONF5_BFIFOWAKEUP_SHIFT 0 -#define AB8500_FIFOCONF5_BFIFOWAKEUP_MAX 0xFF - -/* AB8500_FIFOCONF6 */ -#define AB8500_FIFOCONF6_BFIFOSAMPLE_SHIFT 0 -#define AB8500_FIFOCONF6_BFIFOSAMPLE_MAX 0xFF - -/* AB8500_AUDREV */ - -#endif diff --git a/trunk/sound/soc/codecs/ac97.c b/trunk/sound/soc/codecs/ac97.c index ea06b834a7de..2023c749f232 100644 --- a/trunk/sound/soc/codecs/ac97.c +++ b/trunk/sound/soc/codecs/ac97.c @@ -91,6 +91,11 @@ static int ac97_soc_probe(struct snd_soc_codec *codec) return 0; } +static int ac97_soc_remove(struct snd_soc_codec *codec) +{ + return 0; +} + #ifdef CONFIG_PM static int ac97_soc_suspend(struct snd_soc_codec *codec) { @@ -114,6 +119,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ac97 = { .write = ac97_write, .read = ac97_read, .probe = ac97_soc_probe, + .remove = ac97_soc_remove, .suspend = ac97_soc_suspend, .resume = ac97_soc_resume, }; diff --git a/trunk/sound/soc/codecs/cs42l52.c b/trunk/sound/soc/codecs/cs42l52.c index 628daf6a1d97..a7109413aef1 100644 --- a/trunk/sound/soc/codecs/cs42l52.c +++ b/trunk/sound/soc/codecs/cs42l52.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -1216,11 +1217,11 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, return -ENOMEM; cs42l52->dev = &i2c_client->dev; - cs42l52->regmap = devm_regmap_init_i2c(i2c_client, &cs42l52_regmap); + 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); - return ret; + goto err; } i2c_set_clientdata(i2c_client, cs42l52); @@ -1242,7 +1243,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, dev_err(&i2c_client->dev, "CS42L52 Device ID (%X). Expected %X\n", devid, CS42L52_CHIP_ID); - return ret; + goto err_regmap; } regcache_cache_only(cs42l52->regmap, true); @@ -1250,13 +1251,23 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, ret = snd_soc_register_codec(&i2c_client->dev, &soc_codec_dev_cs42l52, &cs42l52_dai, 1); if (ret < 0) - return ret; + 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; } diff --git a/trunk/sound/soc/codecs/cs42l73.c b/trunk/sound/soc/codecs/cs42l73.c index 2c08c4cb465a..e0d45fdaa750 100644 --- a/trunk/sound/soc/codecs/cs42l73.c +++ b/trunk/sound/soc/codecs/cs42l73.c @@ -1362,11 +1362,11 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client, i2c_set_clientdata(i2c_client, cs42l73); - cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap); + cs42l73->regmap = regmap_init_i2c(i2c_client, &cs42l73_regmap); if (IS_ERR(cs42l73->regmap)) { ret = PTR_ERR(cs42l73->regmap); dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); - return ret; + goto err; } /* initialize codec */ ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®); @@ -1384,13 +1384,13 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client, dev_err(&i2c_client->dev, "CS42L73 Device ID (%X). Expected %X\n", devid, CS42L73_DEVID); - return ret; + goto err_regmap; } ret = regmap_read(cs42l73->regmap, CS42L73_REVID, ®); if (ret < 0) { dev_err(&i2c_client->dev, "Get Revision ID failed\n"); - return ret;; + goto err_regmap; } dev_info(&i2c_client->dev, @@ -1402,13 +1402,23 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client, &soc_codec_dev_cs42l73, cs42l73_dai, ARRAY_SIZE(cs42l73_dai)); if (ret < 0) - return ret; + goto err_regmap; return 0; + +err_regmap: + regmap_exit(cs42l73->regmap); + +err: + return ret; } static __devexit int cs42l73_i2c_remove(struct i2c_client *client) { + struct cs42l73_private *cs42l73 = i2c_get_clientdata(client); + snd_soc_unregister_codec(&client->dev); + regmap_exit(cs42l73->regmap); + return 0; } diff --git a/trunk/sound/soc/codecs/da732x.c b/trunk/sound/soc/codecs/da732x.c deleted file mode 100644 index 04af369f228c..000000000000 --- a/trunk/sound/soc/codecs/da732x.c +++ /dev/null @@ -1,1627 +0,0 @@ -/* - * da732x.c --- Dialog DA732X ALSA SoC Audio Driver - * - * Copyright (C) 2012 Dialog Semiconductor GmbH - * - * Author: Michal Hajduk - * - * This program is free software; you can 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "da732x.h" -#include "da732x_reg.h" - - -struct da732x_priv { - struct regmap *regmap; - struct snd_soc_codec *codec; - - unsigned int sysclk; - bool pll_en; -}; - -/* - * da732x register cache - default settings - */ -static struct reg_default da732x_reg_cache[] = { - { DA732X_REG_REF1 , 0x02 }, - { DA732X_REG_BIAS_EN , 0x80 }, - { DA732X_REG_BIAS1 , 0x00 }, - { DA732X_REG_BIAS2 , 0x00 }, - { DA732X_REG_BIAS3 , 0x00 }, - { DA732X_REG_BIAS4 , 0x00 }, - { DA732X_REG_MICBIAS2 , 0x00 }, - { DA732X_REG_MICBIAS1 , 0x00 }, - { DA732X_REG_MICDET , 0x00 }, - { DA732X_REG_MIC1_PRE , 0x01 }, - { DA732X_REG_MIC1 , 0x40 }, - { DA732X_REG_MIC2_PRE , 0x01 }, - { DA732X_REG_MIC2 , 0x40 }, - { DA732X_REG_AUX1L , 0x75 }, - { DA732X_REG_AUX1R , 0x75 }, - { DA732X_REG_MIC3_PRE , 0x01 }, - { DA732X_REG_MIC3 , 0x40 }, - { DA732X_REG_INP_PINBIAS , 0x00 }, - { DA732X_REG_INP_ZC_EN , 0x00 }, - { DA732X_REG_INP_MUX , 0x50 }, - { DA732X_REG_HP_DET , 0x00 }, - { DA732X_REG_HPL_DAC_OFFSET , 0x00 }, - { DA732X_REG_HPL_DAC_OFF_CNTL , 0x00 }, - { DA732X_REG_HPL_OUT_OFFSET , 0x00 }, - { DA732X_REG_HPL , 0x40 }, - { DA732X_REG_HPL_VOL , 0x0F }, - { DA732X_REG_HPR_DAC_OFFSET , 0x00 }, - { DA732X_REG_HPR_DAC_OFF_CNTL , 0x00 }, - { DA732X_REG_HPR_OUT_OFFSET , 0x00 }, - { DA732X_REG_HPR , 0x40 }, - { DA732X_REG_HPR_VOL , 0x0F }, - { DA732X_REG_LIN2 , 0x4F }, - { DA732X_REG_LIN3 , 0x4F }, - { DA732X_REG_LIN4 , 0x4F }, - { DA732X_REG_OUT_ZC_EN , 0x00 }, - { DA732X_REG_HP_LIN1_GNDSEL , 0x00 }, - { DA732X_REG_CP_HP1 , 0x0C }, - { DA732X_REG_CP_HP2 , 0x03 }, - { DA732X_REG_CP_CTRL1 , 0x00 }, - { DA732X_REG_CP_CTRL2 , 0x99 }, - { DA732X_REG_CP_CTRL3 , 0x25 }, - { DA732X_REG_CP_LEVEL_MASK , 0x3F }, - { DA732X_REG_CP_DET , 0x00 }, - { DA732X_REG_CP_STATUS , 0x00 }, - { DA732X_REG_CP_THRESH1 , 0x00 }, - { DA732X_REG_CP_THRESH2 , 0x00 }, - { DA732X_REG_CP_THRESH3 , 0x00 }, - { DA732X_REG_CP_THRESH4 , 0x00 }, - { DA732X_REG_CP_THRESH5 , 0x00 }, - { DA732X_REG_CP_THRESH6 , 0x00 }, - { DA732X_REG_CP_THRESH7 , 0x00 }, - { DA732X_REG_CP_THRESH8 , 0x00 }, - { DA732X_REG_PLL_DIV_LO , 0x00 }, - { DA732X_REG_PLL_DIV_MID , 0x00 }, - { DA732X_REG_PLL_DIV_HI , 0x00 }, - { DA732X_REG_PLL_CTRL , 0x02 }, - { DA732X_REG_CLK_CTRL , 0xaa }, - { DA732X_REG_CLK_DSP , 0x07 }, - { DA732X_REG_CLK_EN1 , 0x00 }, - { DA732X_REG_CLK_EN2 , 0x00 }, - { DA732X_REG_CLK_EN3 , 0x00 }, - { DA732X_REG_CLK_EN4 , 0x00 }, - { DA732X_REG_CLK_EN5 , 0x00 }, - { DA732X_REG_AIF_MCLK , 0x00 }, - { DA732X_REG_AIFA1 , 0x02 }, - { DA732X_REG_AIFA2 , 0x00 }, - { DA732X_REG_AIFA3 , 0x08 }, - { DA732X_REG_AIFB1 , 0x02 }, - { DA732X_REG_AIFB2 , 0x00 }, - { DA732X_REG_AIFB3 , 0x08 }, - { DA732X_REG_PC_CTRL , 0xC0 }, - { DA732X_REG_DATA_ROUTE , 0x00 }, - { DA732X_REG_DSP_CTRL , 0x00 }, - { DA732X_REG_CIF_CTRL2 , 0x00 }, - { DA732X_REG_HANDSHAKE , 0x00 }, - { DA732X_REG_SPARE1_OUT , 0x00 }, - { DA732X_REG_SPARE2_OUT , 0x00 }, - { DA732X_REG_SPARE1_IN , 0x00 }, - { DA732X_REG_ADC1_PD , 0x00 }, - { DA732X_REG_ADC1_HPF , 0x00 }, - { DA732X_REG_ADC1_SEL , 0x00 }, - { DA732X_REG_ADC1_EQ12 , 0x00 }, - { DA732X_REG_ADC1_EQ34 , 0x00 }, - { DA732X_REG_ADC1_EQ5 , 0x00 }, - { DA732X_REG_ADC2_PD , 0x00 }, - { DA732X_REG_ADC2_HPF , 0x00 }, - { DA732X_REG_ADC2_SEL , 0x00 }, - { DA732X_REG_ADC2_EQ12 , 0x00 }, - { DA732X_REG_ADC2_EQ34 , 0x00 }, - { DA732X_REG_ADC2_EQ5 , 0x00 }, - { DA732X_REG_DAC1_HPF , 0x00 }, - { DA732X_REG_DAC1_L_VOL , 0x00 }, - { DA732X_REG_DAC1_R_VOL , 0x00 }, - { DA732X_REG_DAC1_SEL , 0x00 }, - { DA732X_REG_DAC1_SOFTMUTE , 0x00 }, - { DA732X_REG_DAC1_EQ12 , 0x00 }, - { DA732X_REG_DAC1_EQ34 , 0x00 }, - { DA732X_REG_DAC1_EQ5 , 0x00 }, - { DA732X_REG_DAC2_HPF , 0x00 }, - { DA732X_REG_DAC2_L_VOL , 0x00 }, - { DA732X_REG_DAC2_R_VOL , 0x00 }, - { DA732X_REG_DAC2_SEL , 0x00 }, - { DA732X_REG_DAC2_SOFTMUTE , 0x00 }, - { DA732X_REG_DAC2_EQ12 , 0x00 }, - { DA732X_REG_DAC2_EQ34 , 0x00 }, - { DA732X_REG_DAC2_EQ5 , 0x00 }, - { DA732X_REG_DAC3_HPF , 0x00 }, - { DA732X_REG_DAC3_VOL , 0x00 }, - { DA732X_REG_DAC3_SEL , 0x00 }, - { DA732X_REG_DAC3_SOFTMUTE , 0x00 }, - { DA732X_REG_DAC3_EQ12 , 0x00 }, - { DA732X_REG_DAC3_EQ34 , 0x00 }, - { DA732X_REG_DAC3_EQ5 , 0x00 }, - { DA732X_REG_BIQ_BYP , 0x00 }, - { DA732X_REG_DMA_CMD , 0x00 }, - { DA732X_REG_DMA_ADDR0 , 0x00 }, - { DA732X_REG_DMA_ADDR1 , 0x00 }, - { DA732X_REG_DMA_DATA0 , 0x00 }, - { DA732X_REG_DMA_DATA1 , 0x00 }, - { DA732X_REG_DMA_DATA2 , 0x00 }, - { DA732X_REG_DMA_DATA3 , 0x00 }, - { DA732X_REG_UNLOCK , 0x00 }, -}; - -static inline int da732x_get_input_div(struct snd_soc_codec *codec, int sysclk) -{ - int val; - int ret; - - if (sysclk < DA732X_MCLK_10MHZ) { - val = DA732X_MCLK_RET_0_10MHZ; - ret = DA732X_MCLK_VAL_0_10MHZ; - } else if ((sysclk >= DA732X_MCLK_10MHZ) && - (sysclk < DA732X_MCLK_20MHZ)) { - val = DA732X_MCLK_RET_10_20MHZ; - ret = DA732X_MCLK_VAL_10_20MHZ; - } else if ((sysclk >= DA732X_MCLK_20MHZ) && - (sysclk < DA732X_MCLK_40MHZ)) { - val = DA732X_MCLK_RET_20_40MHZ; - ret = DA732X_MCLK_VAL_20_40MHZ; - } else if ((sysclk >= DA732X_MCLK_40MHZ) && - (sysclk <= DA732X_MCLK_54MHZ)) { - val = DA732X_MCLK_RET_40_54MHZ; - ret = DA732X_MCLK_VAL_40_54MHZ; - } else { - return -EINVAL; - } - - snd_soc_write(codec, DA732X_REG_PLL_CTRL, val); - - return ret; -} - -static void da732x_set_charge_pump(struct snd_soc_codec *codec, int state) -{ - switch (state) { - case DA732X_ENABLE_CP: - snd_soc_write(codec, DA732X_REG_CLK_EN2, DA732X_CP_CLK_EN); - snd_soc_write(codec, DA732X_REG_CP_HP2, DA732X_HP_CP_EN | - DA732X_HP_CP_REG | DA732X_HP_CP_PULSESKIP); - snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA732X_CP_EN | - DA732X_CP_CTRL_CPVDD1); - snd_soc_write(codec, DA732X_REG_CP_CTRL2, - DA732X_CP_MANAGE_MAGNITUDE | DA732X_CP_BOOST); - snd_soc_write(codec, DA732X_REG_CP_CTRL3, DA732X_CP_1MHZ); - break; - case DA732X_DISABLE_CP: - snd_soc_write(codec, DA732X_REG_CLK_EN2, DA732X_CP_CLK_DIS); - snd_soc_write(codec, DA732X_REG_CP_HP2, DA732X_HP_CP_DIS); - snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA723X_CP_DIS); - break; - default: - pr_err(KERN_ERR "Wrong charge pump state\n"); - break; - } -} - -static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, DA732X_MIC_PRE_VOL_DB_MIN, - DA732X_MIC_PRE_VOL_DB_INC, 0); - -static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, DA732X_MIC_VOL_DB_MIN, - DA732X_MIC_VOL_DB_INC, 0); - -static const DECLARE_TLV_DB_SCALE(aux_pga_tlv, DA732X_AUX_VOL_DB_MIN, - DA732X_AUX_VOL_DB_INC, 0); - -static const DECLARE_TLV_DB_SCALE(hp_pga_tlv, DA732X_HP_VOL_DB_MIN, - DA732X_AUX_VOL_DB_INC, 0); - -static const DECLARE_TLV_DB_SCALE(lin2_pga_tlv, DA732X_LIN2_VOL_DB_MIN, - DA732X_LIN2_VOL_DB_INC, 0); - -static const DECLARE_TLV_DB_SCALE(lin3_pga_tlv, DA732X_LIN3_VOL_DB_MIN, - DA732X_LIN3_VOL_DB_INC, 0); - -static const DECLARE_TLV_DB_SCALE(lin4_pga_tlv, DA732X_LIN4_VOL_DB_MIN, - DA732X_LIN4_VOL_DB_INC, 0); - -static const DECLARE_TLV_DB_SCALE(adc_pga_tlv, DA732X_ADC_VOL_DB_MIN, - DA732X_ADC_VOL_DB_INC, 0); - -static const DECLARE_TLV_DB_SCALE(dac_pga_tlv, DA732X_DAC_VOL_DB_MIN, - DA732X_DAC_VOL_DB_INC, 0); - -static const DECLARE_TLV_DB_SCALE(eq_band_pga_tlv, DA732X_EQ_BAND_VOL_DB_MIN, - DA732X_EQ_BAND_VOL_DB_INC, 0); - -static const DECLARE_TLV_DB_SCALE(eq_overall_tlv, DA732X_EQ_OVERALL_VOL_DB_MIN, - DA732X_EQ_OVERALL_VOL_DB_INC, 0); - -/* High Pass Filter */ -static const char *da732x_hpf_mode[] = { - "Disable", "Music", "Voice", -}; - -static const char *da732x_hpf_music[] = { - "1.8Hz", "3.75Hz", "7.5Hz", "15Hz", -}; - -static const char *da732x_hpf_voice[] = { - "2.5Hz", "25Hz", "50Hz", "100Hz", - "150Hz", "200Hz", "300Hz", "400Hz" -}; - -static const struct soc_enum da732x_dac1_hpf_mode_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT, - DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; - -static const struct soc_enum da732x_dac2_hpf_mode_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT, - DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; - -static const struct soc_enum da732x_dac3_hpf_mode_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT, - DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; - -static const struct soc_enum da732x_adc1_hpf_mode_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT, - DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; - -static const struct soc_enum da732x_adc2_hpf_mode_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT, - DA732X_HPF_MODE_MAX, da732x_hpf_mode) -}; - -static const struct soc_enum da732x_dac1_hp_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT, - DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; - -static const struct soc_enum da732x_dac2_hp_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT, - DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; - -static const struct soc_enum da732x_dac3_hp_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT, - DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; - -static const struct soc_enum da732x_adc1_hp_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT, - DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; - -static const struct soc_enum da732x_adc2_hp_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT, - DA732X_HPF_MUSIC_MAX, da732x_hpf_music) -}; - -static const struct soc_enum da732x_dac1_voice_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT, - DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; - -static const struct soc_enum da732x_dac2_voice_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT, - DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; - -static const struct soc_enum da732x_dac3_voice_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT, - DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; - -static const struct soc_enum da732x_adc1_voice_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT, - DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; - -static const struct soc_enum da732x_adc2_voice_filter_enum[] = { - SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT, - DA732X_HPF_VOICE_MAX, da732x_hpf_voice) -}; - - -static int da732x_hpf_set(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value; - unsigned int reg = enum_ctrl->reg; - unsigned int sel = ucontrol->value.integer.value[0]; - unsigned int bits; - - switch (sel) { - case DA732X_HPF_DISABLED: - bits = DA732X_HPF_DIS; - break; - case DA732X_HPF_VOICE: - bits = DA732X_HPF_VOICE_EN; - break; - case DA732X_HPF_MUSIC: - bits = DA732X_HPF_MUSIC_EN; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, reg, DA732X_HPF_MASK, bits); - - return 0; -} - -static int da732x_hpf_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value; - unsigned int reg = enum_ctrl->reg; - int val; - - val = snd_soc_read(codec, reg) & DA732X_HPF_MASK; - - switch (val) { - case DA732X_HPF_VOICE_EN: - ucontrol->value.integer.value[0] = DA732X_HPF_VOICE; - break; - case DA732X_HPF_MUSIC_EN: - ucontrol->value.integer.value[0] = DA732X_HPF_MUSIC; - break; - default: - ucontrol->value.integer.value[0] = DA732X_HPF_DISABLED; - break; - } - - return 0; -} - -static const struct snd_kcontrol_new da732x_snd_controls[] = { - /* Input PGAs */ - SOC_SINGLE_RANGE_TLV("MIC1 Boost Volume", DA732X_REG_MIC1_PRE, - DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN, - DA732X_MICBOOST_MAX, 0, mic_boost_tlv), - SOC_SINGLE_RANGE_TLV("MIC2 Boost Volume", DA732X_REG_MIC2_PRE, - DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN, - DA732X_MICBOOST_MAX, 0, mic_boost_tlv), - SOC_SINGLE_RANGE_TLV("MIC3 Boost Volume", DA732X_REG_MIC3_PRE, - DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN, - DA732X_MICBOOST_MAX, 0, mic_boost_tlv), - - /* MICs */ - SOC_SINGLE("MIC1 Switch", DA732X_REG_MIC1, DA732X_MIC_MUTE_SHIFT, - DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_SINGLE_RANGE_TLV("MIC1 Volume", DA732X_REG_MIC1, - DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN, - DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv), - SOC_SINGLE("MIC2 Switch", DA732X_REG_MIC2, DA732X_MIC_MUTE_SHIFT, - DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_SINGLE_RANGE_TLV("MIC2 Volume", DA732X_REG_MIC2, - DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN, - DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv), - SOC_SINGLE("MIC3 Switch", DA732X_REG_MIC3, DA732X_MIC_MUTE_SHIFT, - DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_SINGLE_RANGE_TLV("MIC3 Volume", DA732X_REG_MIC3, - DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN, - DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv), - - /* AUXs */ - SOC_SINGLE("AUX1L Switch", DA732X_REG_AUX1L, DA732X_AUX_MUTE_SHIFT, - DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_SINGLE_TLV("AUX1L Volume", DA732X_REG_AUX1L, - DA732X_AUX_VOL_SHIFT, DA732X_AUX_VOL_VAL_MAX, - DA732X_NO_INVERT, aux_pga_tlv), - SOC_SINGLE("AUX1R Switch", DA732X_REG_AUX1R, DA732X_AUX_MUTE_SHIFT, - DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_SINGLE_TLV("AUX1R Volume", DA732X_REG_AUX1R, - DA732X_AUX_VOL_SHIFT, DA732X_AUX_VOL_VAL_MAX, - DA732X_NO_INVERT, aux_pga_tlv), - - /* ADCs */ - SOC_DOUBLE_TLV("ADC1 Volume", DA732X_REG_ADC1_SEL, - DA732X_ADCL_VOL_SHIFT, DA732X_ADCR_VOL_SHIFT, - DA732X_ADC_VOL_VAL_MAX, DA732X_INVERT, adc_pga_tlv), - - SOC_DOUBLE_TLV("ADC2 Volume", DA732X_REG_ADC2_SEL, - DA732X_ADCL_VOL_SHIFT, DA732X_ADCR_VOL_SHIFT, - DA732X_ADC_VOL_VAL_MAX, DA732X_INVERT, adc_pga_tlv), - - /* DACs */ - SOC_DOUBLE("Digital Playback DAC12 Switch", DA732X_REG_DAC1_SEL, - DA732X_DACL_MUTE_SHIFT, DA732X_DACR_MUTE_SHIFT, - DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_DOUBLE_R_TLV("Digital Playback DAC12 Volume", DA732X_REG_DAC1_L_VOL, - DA732X_REG_DAC1_R_VOL, DA732X_DAC_VOL_SHIFT, - DA732X_DAC_VOL_VAL_MAX, DA732X_INVERT, dac_pga_tlv), - SOC_SINGLE("Digital Playback DAC3 Switch", DA732X_REG_DAC2_SEL, - DA732X_DACL_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_SINGLE_TLV("Digital Playback DAC3 Volume", DA732X_REG_DAC2_L_VOL, - DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX, - DA732X_INVERT, dac_pga_tlv), - SOC_SINGLE("Digital Playback DAC4 Switch", DA732X_REG_DAC2_SEL, - DA732X_DACR_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_SINGLE_TLV("Digital Playback DAC4 Volume", DA732X_REG_DAC2_R_VOL, - DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX, - DA732X_INVERT, dac_pga_tlv), - SOC_SINGLE("Digital Playback DAC5 Switch", DA732X_REG_DAC3_SEL, - DA732X_DACL_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_SINGLE_TLV("Digital Playback DAC5 Volume", DA732X_REG_DAC3_VOL, - DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX, - DA732X_INVERT, dac_pga_tlv), - - /* High Pass Filters */ - SOC_ENUM_EXT("DAC1 High Pass Filter Mode", - da732x_dac1_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set), - SOC_ENUM("DAC1 High Pass Filter", da732x_dac1_hp_filter_enum), - SOC_ENUM("DAC1 Voice Filter", da732x_dac1_voice_filter_enum), - - SOC_ENUM_EXT("DAC2 High Pass Filter Mode", - da732x_dac2_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set), - SOC_ENUM("DAC2 High Pass Filter", da732x_dac2_hp_filter_enum), - SOC_ENUM("DAC2 Voice Filter", da732x_dac2_voice_filter_enum), - - SOC_ENUM_EXT("DAC3 High Pass Filter Mode", - da732x_dac3_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set), - SOC_ENUM("DAC3 High Pass Filter", da732x_dac3_hp_filter_enum), - SOC_ENUM("DAC3 Filter Mode", da732x_dac3_voice_filter_enum), - - SOC_ENUM_EXT("ADC1 High Pass Filter Mode", - da732x_adc1_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set), - SOC_ENUM("ADC1 High Pass Filter", da732x_adc1_hp_filter_enum), - SOC_ENUM("ADC1 Voice Filter", da732x_adc1_voice_filter_enum), - - SOC_ENUM_EXT("ADC2 High Pass Filter Mode", - da732x_adc2_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set), - SOC_ENUM("ADC2 High Pass Filter", da732x_adc2_hp_filter_enum), - SOC_ENUM("ADC2 Voice Filter", da732x_adc2_voice_filter_enum), - - /* Equalizers */ - SOC_SINGLE("ADC1 EQ Switch", DA732X_REG_ADC1_EQ5, - DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT), - SOC_SINGLE_TLV("ADC1 EQ Band 1 Volume", DA732X_REG_ADC1_EQ12, - DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("ADC1 EQ Band 2 Volume", DA732X_REG_ADC1_EQ12, - DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("ADC1 EQ Band 3 Volume", DA732X_REG_ADC1_EQ34, - DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("ADC1 EQ Band 4 Volume", DA732X_REG_ADC1_EQ34, - DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("ADC1 EQ Band 5 Volume", DA732X_REG_ADC1_EQ5, - DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("ADC1 EQ Overall Volume", DA732X_REG_ADC1_EQ5, - DA732X_EQ_OVERALL_SHIFT, DA732X_EQ_OVERALL_VOL_VAL_MAX, - DA732X_INVERT, eq_overall_tlv), - - SOC_SINGLE("ADC2 EQ Switch", DA732X_REG_ADC2_EQ5, - DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT), - SOC_SINGLE_TLV("ADC2 EQ Band 1 Volume", DA732X_REG_ADC2_EQ12, - DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("ADC2 EQ Band 2 Volume", DA732X_REG_ADC2_EQ12, - DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("ADC2 EQ Band 3 Volume", DA732X_REG_ADC2_EQ34, - DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("ACD2 EQ Band 4 Volume", DA732X_REG_ADC2_EQ34, - DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("ACD2 EQ Band 5 Volume", DA732X_REG_ADC2_EQ5, - DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("ADC2 EQ Overall Volume", DA732X_REG_ADC1_EQ5, - DA732X_EQ_OVERALL_SHIFT, DA732X_EQ_OVERALL_VOL_VAL_MAX, - DA732X_INVERT, eq_overall_tlv), - - SOC_SINGLE("DAC1 EQ Switch", DA732X_REG_DAC1_EQ5, - DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT), - SOC_SINGLE_TLV("DAC1 EQ Band 1 Volume", DA732X_REG_DAC1_EQ12, - DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("DAC1 EQ Band 2 Volume", DA732X_REG_DAC1_EQ12, - DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("DAC1 EQ Band 3 Volume", DA732X_REG_DAC1_EQ34, - DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("DAC1 EQ Band 4 Volume", DA732X_REG_DAC1_EQ34, - DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("DAC1 EQ Band 5 Volume", DA732X_REG_DAC1_EQ5, - DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - - SOC_SINGLE("DAC2 EQ Switch", DA732X_REG_DAC2_EQ5, - DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT), - SOC_SINGLE_TLV("DAC2 EQ Band 1 Volume", DA732X_REG_DAC2_EQ12, - DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("DAC2 EQ Band 2 Volume", DA732X_REG_DAC2_EQ12, - DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("DAC2 EQ Band 3 Volume", DA732X_REG_DAC2_EQ34, - DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("DAC2 EQ Band 4 Volume", DA732X_REG_DAC2_EQ34, - DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("DAC2 EQ Band 5 Volume", DA732X_REG_DAC2_EQ5, - DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - - SOC_SINGLE("DAC3 EQ Switch", DA732X_REG_DAC3_EQ5, - DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT), - SOC_SINGLE_TLV("DAC3 EQ Band 1 Volume", DA732X_REG_DAC3_EQ12, - DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("DAC3 EQ Band 2 Volume", DA732X_REG_DAC3_EQ12, - DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("DAC3 EQ Band 3 Volume", DA732X_REG_DAC3_EQ34, - DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("DAC3 EQ Band 4 Volume", DA732X_REG_DAC3_EQ34, - DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - SOC_SINGLE_TLV("DAC3 EQ Band 5 Volume", DA732X_REG_DAC3_EQ5, - DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX, - DA732X_INVERT, eq_band_pga_tlv), - - /* Lineout 2 Reciever*/ - SOC_SINGLE("Lineout 2 Switch", DA732X_REG_LIN2, DA732X_LOUT_MUTE_SHIFT, - DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_SINGLE_TLV("Lineout 2 Volume", DA732X_REG_LIN2, - DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX, - DA732X_NO_INVERT, lin2_pga_tlv), - - /* Lineout 3 SPEAKER*/ - SOC_SINGLE("Lineout 3 Switch", DA732X_REG_LIN3, DA732X_LOUT_MUTE_SHIFT, - DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_SINGLE_TLV("Lineout 3 Volume", DA732X_REG_LIN3, - DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX, - DA732X_NO_INVERT, lin3_pga_tlv), - - /* Lineout 4 */ - SOC_SINGLE("Lineout 4 Switch", DA732X_REG_LIN4, DA732X_LOUT_MUTE_SHIFT, - DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_SINGLE_TLV("Lineout 4 Volume", DA732X_REG_LIN4, - DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX, - DA732X_NO_INVERT, lin4_pga_tlv), - - /* Headphones */ - SOC_DOUBLE_R("Headphone Switch", DA732X_REG_HPR, DA732X_REG_HPL, - DA732X_HP_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT), - SOC_DOUBLE_R_TLV("Headphone Volume", DA732X_REG_HPL_VOL, - DA732X_REG_HPR_VOL, DA732X_HP_VOL_SHIFT, - DA732X_HP_VOL_VAL_MAX, DA732X_NO_INVERT, hp_pga_tlv), -}; - -static int da732x_adc_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - switch (w->reg) { - case DA732X_REG_ADC1_PD: - snd_soc_update_bits(codec, DA732X_REG_CLK_EN3, - DA732X_ADCA_BB_CLK_EN, - DA732X_ADCA_BB_CLK_EN); - break; - case DA732X_REG_ADC2_PD: - snd_soc_update_bits(codec, DA732X_REG_CLK_EN3, - DA732X_ADCC_BB_CLK_EN, - DA732X_ADCC_BB_CLK_EN); - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, w->reg, DA732X_ADC_RST_MASK, - DA732X_ADC_SET_ACT); - snd_soc_update_bits(codec, w->reg, DA732X_ADC_PD_MASK, - DA732X_ADC_ON); - break; - case SND_SOC_DAPM_POST_PMD: - snd_soc_update_bits(codec, w->reg, DA732X_ADC_PD_MASK, - DA732X_ADC_OFF); - snd_soc_update_bits(codec, w->reg, DA732X_ADC_RST_MASK, - DA732X_ADC_SET_RST); - - switch (w->reg) { - case DA732X_REG_ADC1_PD: - snd_soc_update_bits(codec, DA732X_REG_CLK_EN3, - DA732X_ADCA_BB_CLK_EN, 0); - break; - case DA732X_REG_ADC2_PD: - snd_soc_update_bits(codec, DA732X_REG_CLK_EN3, - DA732X_ADCC_BB_CLK_EN, 0); - break; - default: - return -EINVAL; - } - - break; - default: - return -EINVAL; - } - - return 0; -} - -static int da732x_out_pga_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - snd_soc_update_bits(codec, w->reg, - (1 << w->shift) | DA732X_OUT_HIZ_EN, - (1 << w->shift) | DA732X_OUT_HIZ_EN); - break; - case SND_SOC_DAPM_POST_PMD: - snd_soc_update_bits(codec, w->reg, - (1 << w->shift) | DA732X_OUT_HIZ_EN, - (1 << w->shift) | DA732X_OUT_HIZ_DIS); - break; - default: - return -EINVAL; - } - - return 0; -} - -static const char *adcl_text[] = { - "AUX1L", "MIC1" -}; - -static const char *adcr_text[] = { - "AUX1R", "MIC2", "MIC3" -}; - -static const char *enable_text[] = { - "Disabled", - "Enabled" -}; - -/* ADC1LMUX */ -static const struct soc_enum adc1l_enum = - SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT, - DA732X_ADCL_MUX_MAX, adcl_text); -static const struct snd_kcontrol_new adc1l_mux = - SOC_DAPM_ENUM("ADC Route", adc1l_enum); - -/* ADC1RMUX */ -static const struct soc_enum adc1r_enum = - SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT, - DA732X_ADCR_MUX_MAX, adcr_text); -static const struct snd_kcontrol_new adc1r_mux = - SOC_DAPM_ENUM("ADC Route", adc1r_enum); - -/* ADC2LMUX */ -static const struct soc_enum adc2l_enum = - SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT, - DA732X_ADCL_MUX_MAX, adcl_text); -static const struct snd_kcontrol_new adc2l_mux = - SOC_DAPM_ENUM("ADC Route", adc2l_enum); - -/* ADC2RMUX */ -static const struct soc_enum adc2r_enum = - SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT, - DA732X_ADCR_MUX_MAX, adcr_text); - -static const struct snd_kcontrol_new adc2r_mux = - SOC_DAPM_ENUM("ADC Route", adc2r_enum); - -static const struct soc_enum da732x_hp_left_output = - SOC_ENUM_SINGLE(DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT, - DA732X_DAC_EN_MAX, enable_text); - -static const struct snd_kcontrol_new hpl_mux = - SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output); - -static const struct soc_enum da732x_hp_right_output = - SOC_ENUM_SINGLE(DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT, - DA732X_DAC_EN_MAX, enable_text); - -static const struct snd_kcontrol_new hpr_mux = - SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output); - -static const struct soc_enum da732x_speaker_output = - SOC_ENUM_SINGLE(DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT, - DA732X_DAC_EN_MAX, enable_text); - -static const struct snd_kcontrol_new spk_mux = - SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output); - -static const struct soc_enum da732x_lout4_output = - SOC_ENUM_SINGLE(DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT, - DA732X_DAC_EN_MAX, enable_text); - -static const struct snd_kcontrol_new lout4_mux = - SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output); - -static const struct soc_enum da732x_lout2_output = - SOC_ENUM_SINGLE(DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT, - DA732X_DAC_EN_MAX, enable_text); - -static const struct snd_kcontrol_new lout2_mux = - SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output); - -static const struct snd_soc_dapm_widget da732x_dapm_widgets[] = { - /* Supplies */ - SND_SOC_DAPM_SUPPLY("ADC1 Supply", DA732X_REG_ADC1_PD, 0, - DA732X_NO_INVERT, da732x_adc_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("ADC2 Supply", DA732X_REG_ADC2_PD, 0, - DA732X_NO_INVERT, da732x_adc_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("DAC1 CLK", DA732X_REG_CLK_EN4, - DA732X_DACA_BB_CLK_SHIFT, DA732X_NO_INVERT, - NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC2 CLK", DA732X_REG_CLK_EN4, - DA732X_DACC_BB_CLK_SHIFT, DA732X_NO_INVERT, - NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC3 CLK", DA732X_REG_CLK_EN5, - DA732X_DACE_BB_CLK_SHIFT, DA732X_NO_INVERT, - NULL, 0), - - /* Micbias */ - SND_SOC_DAPM_SUPPLY("MICBIAS1", DA732X_REG_MICBIAS1, - DA732X_MICBIAS_EN_SHIFT, - DA732X_NO_INVERT, NULL, 0), - SND_SOC_DAPM_SUPPLY("MICBIAS2", DA732X_REG_MICBIAS2, - DA732X_MICBIAS_EN_SHIFT, - DA732X_NO_INVERT, NULL, 0), - - /* Inputs */ - SND_SOC_DAPM_INPUT("MIC1"), - SND_SOC_DAPM_INPUT("MIC2"), - SND_SOC_DAPM_INPUT("MIC3"), - SND_SOC_DAPM_INPUT("AUX1L"), - SND_SOC_DAPM_INPUT("AUX1R"), - - /* Outputs */ - SND_SOC_DAPM_OUTPUT("HPL"), - SND_SOC_DAPM_OUTPUT("HPR"), - SND_SOC_DAPM_OUTPUT("LOUTL"), - SND_SOC_DAPM_OUTPUT("LOUTR"), - SND_SOC_DAPM_OUTPUT("ClassD"), - - /* ADCs */ - SND_SOC_DAPM_ADC("ADC1L", NULL, DA732X_REG_ADC1_SEL, - DA732X_ADCL_EN_SHIFT, DA732X_NO_INVERT), - SND_SOC_DAPM_ADC("ADC1R", NULL, DA732X_REG_ADC1_SEL, - DA732X_ADCR_EN_SHIFT, DA732X_NO_INVERT), - SND_SOC_DAPM_ADC("ADC2L", NULL, DA732X_REG_ADC2_SEL, - DA732X_ADCL_EN_SHIFT, DA732X_NO_INVERT), - SND_SOC_DAPM_ADC("ADC2R", NULL, DA732X_REG_ADC2_SEL, - DA732X_ADCR_EN_SHIFT, DA732X_NO_INVERT), - - /* DACs */ - SND_SOC_DAPM_DAC("DAC1L", NULL, DA732X_REG_DAC1_SEL, - DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT), - SND_SOC_DAPM_DAC("DAC1R", NULL, DA732X_REG_DAC1_SEL, - DA732X_DACR_EN_SHIFT, DA732X_NO_INVERT), - SND_SOC_DAPM_DAC("DAC2L", NULL, DA732X_REG_DAC2_SEL, - DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT), - SND_SOC_DAPM_DAC("DAC2R", NULL, DA732X_REG_DAC2_SEL, - DA732X_DACR_EN_SHIFT, DA732X_NO_INVERT), - SND_SOC_DAPM_DAC("DAC3", NULL, DA732X_REG_DAC3_SEL, - DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT), - - /* Input Pgas */ - SND_SOC_DAPM_PGA("MIC1 PGA", DA732X_REG_MIC1, DA732X_MIC_EN_SHIFT, - 0, NULL, 0), - SND_SOC_DAPM_PGA("MIC2 PGA", DA732X_REG_MIC2, DA732X_MIC_EN_SHIFT, - 0, NULL, 0), - SND_SOC_DAPM_PGA("MIC3 PGA", DA732X_REG_MIC3, DA732X_MIC_EN_SHIFT, - 0, NULL, 0), - SND_SOC_DAPM_PGA("AUX1L PGA", DA732X_REG_AUX1L, DA732X_AUX_EN_SHIFT, - 0, NULL, 0), - SND_SOC_DAPM_PGA("AUX1R PGA", DA732X_REG_AUX1R, DA732X_AUX_EN_SHIFT, - 0, NULL, 0), - - SND_SOC_DAPM_PGA_E("HP Left", DA732X_REG_HPL, DA732X_HP_OUT_EN_SHIFT, - 0, NULL, 0, da732x_out_pga_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_PGA_E("HP Right", DA732X_REG_HPR, DA732X_HP_OUT_EN_SHIFT, - 0, NULL, 0, da732x_out_pga_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_PGA_E("LIN2", DA732X_REG_LIN2, DA732X_LIN_OUT_EN_SHIFT, - 0, NULL, 0, da732x_out_pga_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_PGA_E("LIN3", DA732X_REG_LIN3, DA732X_LIN_OUT_EN_SHIFT, - 0, NULL, 0, da732x_out_pga_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_PGA_E("LIN4", DA732X_REG_LIN4, DA732X_LIN_OUT_EN_SHIFT, - 0, NULL, 0, da732x_out_pga_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - - /* MUXs */ - SND_SOC_DAPM_MUX("ADC1 Left MUX", SND_SOC_NOPM, 0, 0, &adc1l_mux), - SND_SOC_DAPM_MUX("ADC1 Right MUX", SND_SOC_NOPM, 0, 0, &adc1r_mux), - SND_SOC_DAPM_MUX("ADC2 Left MUX", SND_SOC_NOPM, 0, 0, &adc2l_mux), - SND_SOC_DAPM_MUX("ADC2 Right MUX", SND_SOC_NOPM, 0, 0, &adc2r_mux), - - SND_SOC_DAPM_MUX("HP Left MUX", SND_SOC_NOPM, 0, 0, &hpl_mux), - SND_SOC_DAPM_MUX("HP Right MUX", SND_SOC_NOPM, 0, 0, &hpr_mux), - SND_SOC_DAPM_MUX("Speaker MUX", SND_SOC_NOPM, 0, 0, &spk_mux), - SND_SOC_DAPM_MUX("LOUT2 MUX", SND_SOC_NOPM, 0, 0, &lout2_mux), - SND_SOC_DAPM_MUX("LOUT4 MUX", SND_SOC_NOPM, 0, 0, &lout4_mux), - - /* AIF interfaces */ - SND_SOC_DAPM_AIF_OUT("AIFA Output", "AIFA Capture", 0, DA732X_REG_AIFA3, - DA732X_AIF_EN_SHIFT, 0), - SND_SOC_DAPM_AIF_IN("AIFA Input", "AIFA Playback", 0, DA732X_REG_AIFA3, - DA732X_AIF_EN_SHIFT, 0), - - SND_SOC_DAPM_AIF_OUT("AIFB Output", "AIFB Capture", 0, DA732X_REG_AIFB3, - DA732X_AIF_EN_SHIFT, 0), - SND_SOC_DAPM_AIF_IN("AIFB Input", "AIFB Playback", 0, DA732X_REG_AIFB3, - DA732X_AIF_EN_SHIFT, 0), -}; - -static const struct snd_soc_dapm_route da732x_dapm_routes[] = { - /* Inputs */ - {"AUX1L PGA", "NULL", "AUX1L"}, - {"AUX1R PGA", "NULL", "AUX1R"}, - {"MIC1 PGA", NULL, "MIC1"}, - {"MIC2 PGA", "NULL", "MIC2"}, - {"MIC3 PGA", "NULL", "MIC3"}, - - /* Capture Path */ - {"ADC1 Left MUX", "MIC1", "MIC1 PGA"}, - {"ADC1 Left MUX", "AUX1L", "AUX1L PGA"}, - - {"ADC1 Right MUX", "AUX1R", "AUX1R PGA"}, - {"ADC1 Right MUX", "MIC2", "MIC2 PGA"}, - {"ADC1 Right MUX", "MIC3", "MIC3 PGA"}, - - {"ADC2 Left MUX", "AUX1L", "AUX1L PGA"}, - {"ADC2 Left MUX", "MIC1", "MIC1 PGA"}, - - {"ADC2 Right MUX", "AUX1R", "AUX1R PGA"}, - {"ADC2 Right MUX", "MIC2", "MIC2 PGA"}, - {"ADC2 Right MUX", "MIC3", "MIC3 PGA"}, - - {"ADC1L", NULL, "ADC1 Supply"}, - {"ADC1R", NULL, "ADC1 Supply"}, - {"ADC2L", NULL, "ADC2 Supply"}, - {"ADC2R", NULL, "ADC2 Supply"}, - - {"ADC1L", NULL, "ADC1 Left MUX"}, - {"ADC1R", NULL, "ADC1 Right MUX"}, - {"ADC2L", NULL, "ADC2 Left MUX"}, - {"ADC2R", NULL, "ADC2 Right MUX"}, - - {"AIFA Output", NULL, "ADC1L"}, - {"AIFA Output", NULL, "ADC1R"}, - {"AIFB Output", NULL, "ADC2L"}, - {"AIFB Output", NULL, "ADC2R"}, - - {"HP Left MUX", "Enabled", "AIFA Input"}, - {"HP Right MUX", "Enabled", "AIFA Input"}, - {"Speaker MUX", "Enabled", "AIFB Input"}, - {"LOUT2 MUX", "Enabled", "AIFB Input"}, - {"LOUT4 MUX", "Enabled", "AIFB Input"}, - - {"DAC1L", NULL, "DAC1 CLK"}, - {"DAC1R", NULL, "DAC1 CLK"}, - {"DAC2L", NULL, "DAC2 CLK"}, - {"DAC2R", NULL, "DAC2 CLK"}, - {"DAC3", NULL, "DAC3 CLK"}, - - {"DAC1L", NULL, "HP Left MUX"}, - {"DAC1R", NULL, "HP Right MUX"}, - {"DAC2L", NULL, "Speaker MUX"}, - {"DAC2R", NULL, "LOUT4 MUX"}, - {"DAC3", NULL, "LOUT2 MUX"}, - - /* Output Pgas */ - {"HP Left", NULL, "DAC1L"}, - {"HP Right", NULL, "DAC1R"}, - {"LIN3", NULL, "DAC2L"}, - {"LIN4", NULL, "DAC2R"}, - {"LIN2", NULL, "DAC3"}, - - /* Outputs */ - {"ClassD", NULL, "LIN3"}, - {"LOUTL", NULL, "LIN2"}, - {"LOUTR", NULL, "LIN4"}, - {"HPL", NULL, "HP Left"}, - {"HPR", NULL, "HP Right"}, -}; - -static int da732x_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; - u32 aif = 0; - u32 reg_aif; - u32 fs; - - reg_aif = dai->driver->base; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - aif |= DA732X_AIF_WORD_16; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - aif |= DA732X_AIF_WORD_20; - break; - case SNDRV_PCM_FORMAT_S24_LE: - aif |= DA732X_AIF_WORD_24; - break; - case SNDRV_PCM_FORMAT_S32_LE: - aif |= DA732X_AIF_WORD_32; - break; - default: - return -EINVAL; - } - - switch (params_rate(params)) { - case 8000: - fs = DA732X_SR_8KHZ; - break; - case 11025: - fs = DA732X_SR_11_025KHZ; - break; - case 12000: - fs = DA732X_SR_12KHZ; - break; - case 16000: - fs = DA732X_SR_16KHZ; - break; - case 22050: - fs = DA732X_SR_22_05KHZ; - break; - case 24000: - fs = DA732X_SR_24KHZ; - break; - case 32000: - fs = DA732X_SR_32KHZ; - break; - case 44100: - fs = DA732X_SR_44_1KHZ; - break; - case 48000: - fs = DA732X_SR_48KHZ; - break; - case 88100: - fs = DA732X_SR_88_1KHZ; - break; - case 96000: - fs = DA732X_SR_96KHZ; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, reg_aif, DA732X_AIF_WORD_MASK, aif); - snd_soc_update_bits(codec, DA732X_REG_CLK_CTRL, DA732X_SR1_MASK, fs); - - return 0; -} - -static int da732x_set_dai_fmt(struct snd_soc_dai *dai, u32 fmt) -{ - struct snd_soc_codec *codec = dai->codec; - u32 aif_mclk, pc_count; - u32 reg_aif1, aif1; - u32 reg_aif3, aif3; - - switch (dai->id) { - case DA732X_DAI_ID1: - reg_aif1 = DA732X_REG_AIFA1; - reg_aif3 = DA732X_REG_AIFA3; - pc_count = DA732X_PC_PULSE_AIFA | DA732X_PC_RESYNC_NOT_AUT | - DA732X_PC_SAME; - break; - case DA732X_DAI_ID2: - reg_aif1 = DA732X_REG_AIFB1; - reg_aif3 = DA732X_REG_AIFB3; - pc_count = DA732X_PC_PULSE_AIFB | DA732X_PC_RESYNC_NOT_AUT | - DA732X_PC_SAME; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - aif1 = DA732X_AIF_SLAVE; - aif_mclk = DA732X_AIFM_FRAME_64 | DA732X_AIFM_SRC_SEL_AIFA; - break; - case SND_SOC_DAIFMT_CBM_CFM: - aif1 = DA732X_AIF_CLK_FROM_SRC; - aif_mclk = DA732X_CLK_GENERATION_AIF_A; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - aif3 = DA732X_AIF_I2S_MODE; - break; - case SND_SOC_DAIFMT_RIGHT_J: - aif3 = DA732X_AIF_RIGHT_J_MODE; - break; - case SND_SOC_DAIFMT_LEFT_J: - aif3 = DA732X_AIF_LEFT_J_MODE; - break; - case SND_SOC_DAIFMT_DSP_B: - aif3 = DA732X_AIF_DSP_MODE; - break; - default: - return -EINVAL; - } - - /* Clock inversion */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_DSP_B: - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_IB_NF: - aif3 |= DA732X_AIF_BCLK_INV; - break; - default: - return -EINVAL; - } - break; - case SND_SOC_DAIFMT_I2S: - case SND_SOC_DAIFMT_RIGHT_J: - case SND_SOC_DAIFMT_LEFT_J: - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_IB_IF: - aif3 |= DA732X_AIF_BCLK_INV | DA732X_AIF_WCLK_INV; - break; - case SND_SOC_DAIFMT_IB_NF: - aif3 |= DA732X_AIF_BCLK_INV; - break; - case SND_SOC_DAIFMT_NB_IF: - aif3 |= DA732X_AIF_WCLK_INV; - break; - default: - return -EINVAL; - } - break; - default: - return -EINVAL; - } - - snd_soc_write(codec, DA732X_REG_AIF_MCLK, aif_mclk); - snd_soc_update_bits(codec, reg_aif1, DA732X_AIF1_CLK_MASK, aif1); - snd_soc_update_bits(codec, reg_aif3, DA732X_AIF_BCLK_INV | - DA732X_AIF_WCLK_INV | DA732X_AIF_MODE_MASK, aif3); - snd_soc_write(codec, DA732X_REG_PC_CTRL, pc_count); - - return 0; -} - - - -static int da732x_set_dai_pll(struct snd_soc_codec *codec, int pll_id, - int source, unsigned int freq_in, - unsigned int freq_out) -{ - struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec); - int fref, indiv; - u8 div_lo, div_mid, div_hi; - u64 frac_div; - - /* Disable PLL */ - if (freq_out == 0) { - snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL, - DA732X_PLL_EN, 0); - da732x->pll_en = false; - return 0; - } - - if (da732x->pll_en) - return -EBUSY; - - if (source == DA732X_SRCCLK_MCLK) { - /* Validate Sysclk rate */ - switch (da732x->sysclk) { - case 11290000: - case 12288000: - case 22580000: - case 24576000: - case 45160000: - case 49152000: - snd_soc_write(codec, DA732X_REG_PLL_CTRL, - DA732X_PLL_BYPASS); - return 0; - default: - dev_err(codec->dev, - "Cannot use PLL Bypass, invalid SYSCLK rate\n"); - return -EINVAL; - } - } - - indiv = da732x_get_input_div(codec, da732x->sysclk); - if (indiv < 0) - return indiv; - - fref = (da732x->sysclk / indiv); - div_hi = freq_out / fref; - frac_div = (u64)(freq_out % fref) * 8192ULL; - do_div(frac_div, fref); - div_mid = (frac_div >> DA732X_1BYTE_SHIFT) & DA732X_U8_MASK; - div_lo = (frac_div) & DA732X_U8_MASK; - - snd_soc_write(codec, DA732X_REG_PLL_DIV_LO, div_lo); - snd_soc_write(codec, DA732X_REG_PLL_DIV_MID, div_mid); - snd_soc_write(codec, DA732X_REG_PLL_DIV_HI, div_hi); - - snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL, DA732X_PLL_EN, - DA732X_PLL_EN); - - da732x->pll_en = true; - - return 0; -} - -static int da732x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = dai->codec; - struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec); - - da732x->sysclk = freq; - - return 0; -} - -#define DA732X_RATES SNDRV_PCM_RATE_8000_96000 - -#define DA732X_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 da732x_dai1_ops = { - .hw_params = da732x_hw_params, - .set_fmt = da732x_set_dai_fmt, - .set_sysclk = da732x_set_dai_sysclk, -}; - -static struct snd_soc_dai_ops da732x_dai2_ops = { - .hw_params = da732x_hw_params, - .set_fmt = da732x_set_dai_fmt, - .set_sysclk = da732x_set_dai_sysclk, -}; - -static struct snd_soc_dai_driver da732x_dai[] = { - { - .name = "DA732X_AIFA", - .id = DA732X_DAI_ID1, - .base = DA732X_REG_AIFA1, - .playback = { - .stream_name = "AIFA Playback", - .channels_min = 1, - .channels_max = 2, - .rates = DA732X_RATES, - .formats = DA732X_FORMATS, - }, - .capture = { - .stream_name = "AIFA Capture", - .channels_min = 1, - .channels_max = 2, - .rates = DA732X_RATES, - .formats = DA732X_FORMATS, - }, - .ops = &da732x_dai1_ops, - }, - { - .name = "DA732X_AIFB", - .id = DA732X_DAI_ID2, - .base = DA732X_REG_AIFB1, - .playback = { - .stream_name = "AIFB Playback", - .channels_min = 1, - .channels_max = 2, - .rates = DA732X_RATES, - .formats = DA732X_FORMATS, - }, - .capture = { - .stream_name = "AIFB Capture", - .channels_min = 1, - .channels_max = 2, - .rates = DA732X_RATES, - .formats = DA732X_FORMATS, - }, - .ops = &da732x_dai2_ops, - }, -}; - -static const struct regmap_config da732x_regmap = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = DA732X_MAX_REG, - .reg_defaults = da732x_reg_cache, - .num_reg_defaults = ARRAY_SIZE(da732x_reg_cache), - .cache_type = REGCACHE_RBTREE, -}; - - -static void da732x_dac_offset_adjust(struct snd_soc_codec *codec) -{ - u8 offset[DA732X_HP_DACS]; - u8 sign[DA732X_HP_DACS]; - u8 step = DA732X_DAC_OFFSET_STEP; - - /* Initialize DAC offset calibration circuits and registers */ - snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET, - DA732X_HP_DAC_OFFSET_TRIM_VAL); - snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET, - DA732X_HP_DAC_OFFSET_TRIM_VAL); - snd_soc_write(codec, DA732X_REG_HPL_DAC_OFF_CNTL, - DA732X_HP_DAC_OFF_CALIBRATION | - DA732X_HP_DAC_OFF_SCALE_STEPS); - snd_soc_write(codec, DA732X_REG_HPR_DAC_OFF_CNTL, - DA732X_HP_DAC_OFF_CALIBRATION | - DA732X_HP_DAC_OFF_SCALE_STEPS); - - /* Wait for voltage stabilization */ - msleep(DA732X_WAIT_FOR_STABILIZATION); - - /* Check DAC offset sign */ - sign[DA732X_HPL_DAC] = (codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) & - DA732X_HP_DAC_OFF_CNTL_COMPO); - sign[DA732X_HPR_DAC] = (codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) & - DA732X_HP_DAC_OFF_CNTL_COMPO); - - /* Binary search DAC offset values (both channels at once) */ - offset[DA732X_HPL_DAC] = sign[DA732X_HPL_DAC] << DA732X_HP_DAC_COMPO_SHIFT; - offset[DA732X_HPR_DAC] = sign[DA732X_HPR_DAC] << DA732X_HP_DAC_COMPO_SHIFT; - - do { - offset[DA732X_HPL_DAC] |= step; - offset[DA732X_HPR_DAC] |= step; - snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET, - ~offset[DA732X_HPL_DAC] & DA732X_HP_DAC_OFF_MASK); - snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET, - ~offset[DA732X_HPR_DAC] & DA732X_HP_DAC_OFF_MASK); - - msleep(DA732X_WAIT_FOR_STABILIZATION); - - if ((codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) & - DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPL_DAC]) - offset[DA732X_HPL_DAC] &= ~step; - if ((codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) & - DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPR_DAC]) - offset[DA732X_HPR_DAC] &= ~step; - - step >>= 1; - } while (step); - - /* Write final DAC offsets to registers */ - snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET, - ~offset[DA732X_HPL_DAC] & DA732X_HP_DAC_OFF_MASK); - snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET, - ~offset[DA732X_HPR_DAC] & DA732X_HP_DAC_OFF_MASK); - - /* End DAC calibration mode */ - snd_soc_write(codec, DA732X_REG_HPL_DAC_OFF_CNTL, - DA732X_HP_DAC_OFF_SCALE_STEPS); - snd_soc_write(codec, DA732X_REG_HPR_DAC_OFF_CNTL, - DA732X_HP_DAC_OFF_SCALE_STEPS); -} - -static void da732x_output_offset_adjust(struct snd_soc_codec *codec) -{ - u8 offset[DA732X_HP_AMPS]; - u8 sign[DA732X_HP_AMPS]; - u8 step = DA732X_OUTPUT_OFFSET_STEP; - - offset[DA732X_HPL_AMP] = DA732X_HP_OUT_TRIM_VAL; - offset[DA732X_HPR_AMP] = DA732X_HP_OUT_TRIM_VAL; - - /* Initialize output offset calibration circuits and registers */ - snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL); - snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL); - snd_soc_write(codec, DA732X_REG_HPL, - DA732X_HP_OUT_COMP | DA732X_HP_OUT_EN); - snd_soc_write(codec, DA732X_REG_HPR, - DA732X_HP_OUT_COMP | DA732X_HP_OUT_EN); - - /* Wait for voltage stabilization */ - msleep(DA732X_WAIT_FOR_STABILIZATION); - - /* Check output offset sign */ - sign[DA732X_HPL_AMP] = codec->hw_read(codec, DA732X_REG_HPL) & - DA732X_HP_OUT_COMPO; - sign[DA732X_HPR_AMP] = codec->hw_read(codec, DA732X_REG_HPR) & - DA732X_HP_OUT_COMPO; - - snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_COMP | - (sign[DA732X_HPL_AMP] >> DA732X_HP_OUT_COMPO_SHIFT) | - DA732X_HP_OUT_EN); - snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_OUT_COMP | - (sign[DA732X_HPR_AMP] >> DA732X_HP_OUT_COMPO_SHIFT) | - DA732X_HP_OUT_EN); - - /* Binary search output offset values (both channels at once) */ - do { - offset[DA732X_HPL_AMP] |= step; - offset[DA732X_HPR_AMP] |= step; - snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET, - offset[DA732X_HPL_AMP]); - snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET, - offset[DA732X_HPR_AMP]); - - msleep(DA732X_WAIT_FOR_STABILIZATION); - - if ((codec->hw_read(codec, DA732X_REG_HPL) & - DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPL_AMP]) - offset[DA732X_HPL_AMP] &= ~step; - if ((codec->hw_read(codec, DA732X_REG_HPR) & - DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPR_AMP]) - offset[DA732X_HPR_AMP] &= ~step; - - step >>= 1; - } while (step); - - /* Write final DAC offsets to registers */ - snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET, offset[DA732X_HPL_AMP]); - snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET, offset[DA732X_HPR_AMP]); -} - -static void da732x_hp_dc_offset_cancellation(struct snd_soc_codec *codec) -{ - /* Make sure that we have Soft Mute enabled */ - snd_soc_write(codec, DA732X_REG_DAC1_SOFTMUTE, DA732X_SOFTMUTE_EN | - DA732X_GAIN_RAMPED | DA732X_16_SAMPLES); - snd_soc_write(codec, DA732X_REG_DAC1_SEL, DA732X_DACL_EN | - DA732X_DACR_EN | DA732X_DACL_SDM | DA732X_DACR_SDM | - DA732X_DACL_MUTE | DA732X_DACR_MUTE); - snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN | - DA732X_HP_OUT_MUTE | DA732X_HP_OUT_EN); - snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_OUT_EN | - DA732X_HP_OUT_MUTE | DA732X_HP_OUT_DAC_EN); - - da732x_dac_offset_adjust(codec); - da732x_output_offset_adjust(codec); - - snd_soc_write(codec, DA732X_REG_DAC1_SEL, DA732X_DACS_DIS); - snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_DIS); - snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_DIS); -} - -static int da732x_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec); - - switch (level) { - case SND_SOC_BIAS_ON: - snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, - DA732X_BIAS_BOOST_MASK, - DA732X_BIAS_BOOST_100PC); - break; - case SND_SOC_BIAS_PREPARE: - break; - case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - /* Init Codec */ - snd_soc_write(codec, DA732X_REG_REF1, - DA732X_VMID_FASTCHG); - snd_soc_write(codec, DA732X_REG_BIAS_EN, - DA732X_BIAS_EN); - - mdelay(DA732X_STARTUP_DELAY); - - /* Disable Fast Charge and enable DAC ref voltage */ - snd_soc_write(codec, DA732X_REG_REF1, - DA732X_REFBUFX2_EN); - - /* Enable bypass DSP routing */ - snd_soc_write(codec, DA732X_REG_DATA_ROUTE, - DA732X_BYPASS_DSP); - - /* Enable Digital subsystem */ - snd_soc_write(codec, DA732X_REG_DSP_CTRL, - DA732X_DIGITAL_EN); - - snd_soc_write(codec, DA732X_REG_SPARE1_OUT, - DA732X_HP_DRIVER_EN | - DA732X_HP_GATE_LOW | - DA732X_HP_LOOP_GAIN_CTRL); - snd_soc_write(codec, DA732X_REG_HP_LIN1_GNDSEL, - DA732X_HP_OUT_GNDSEL); - - da732x_set_charge_pump(codec, DA732X_ENABLE_CP); - - snd_soc_write(codec, DA732X_REG_CLK_EN1, - DA732X_SYS3_CLK_EN | DA732X_PC_CLK_EN); - - /* Enable Zero Crossing */ - snd_soc_write(codec, DA732X_REG_INP_ZC_EN, - DA732X_MIC1_PRE_ZC_EN | - DA732X_MIC1_ZC_EN | - DA732X_MIC2_PRE_ZC_EN | - DA732X_MIC2_ZC_EN | - DA732X_AUXL_ZC_EN | - DA732X_AUXR_ZC_EN | - DA732X_MIC3_PRE_ZC_EN | - DA732X_MIC3_ZC_EN); - snd_soc_write(codec, DA732X_REG_OUT_ZC_EN, - DA732X_HPL_ZC_EN | DA732X_HPR_ZC_EN | - DA732X_LIN2_ZC_EN | DA732X_LIN3_ZC_EN | - DA732X_LIN4_ZC_EN); - - da732x_hp_dc_offset_cancellation(codec); - - regcache_cache_only(codec->control_data, false); - regcache_sync(codec->control_data); - } else { - snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, - DA732X_BIAS_BOOST_MASK, - DA732X_BIAS_BOOST_50PC); - snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL, - DA732X_PLL_EN, 0); - da732x->pll_en = false; - } - break; - case SND_SOC_BIAS_OFF: - regcache_cache_only(codec->control_data, true); - da732x_set_charge_pump(codec, DA732X_DISABLE_CP); - snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN, - DA732X_BIAS_DIS); - da732x->pll_en = false; - break; - } - - codec->dapm.bias_level = level; - - return 0; -} - -static int da732x_probe(struct snd_soc_codec *codec) -{ - struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec); - struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret = 0; - - da732x->codec = codec; - - dapm->idle_bias_off = false; - - codec->control_data = da732x->regmap; - - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); - if (ret != 0) { - dev_err(codec->dev, "Failed to register codec.\n"); - goto err; - } - - da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -err: - return ret; -} - -static int da732x_remove(struct snd_soc_codec *codec) -{ - - da732x_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -struct snd_soc_codec_driver soc_codec_dev_da732x = { - .probe = da732x_probe, - .remove = da732x_remove, - .set_bias_level = da732x_set_bias_level, - .controls = da732x_snd_controls, - .num_controls = ARRAY_SIZE(da732x_snd_controls), - .dapm_widgets = da732x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(da732x_dapm_widgets), - .dapm_routes = da732x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(da732x_dapm_routes), - .set_pll = da732x_set_dai_pll, - .reg_cache_size = ARRAY_SIZE(da732x_reg_cache), -}; - -static __devinit int da732x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct da732x_priv *da732x; - unsigned int reg; - int ret; - - da732x = devm_kzalloc(&i2c->dev, sizeof(struct da732x_priv), - GFP_KERNEL); - if (!da732x) - return -ENOMEM; - - i2c_set_clientdata(i2c, da732x); - - da732x->regmap = devm_regmap_init_i2c(i2c, &da732x_regmap); - if (IS_ERR(da732x->regmap)) { - ret = PTR_ERR(da732x->regmap); - dev_err(&i2c->dev, "Failed to initialize regmap\n"); - goto err; - } - - ret = regmap_read(da732x->regmap, DA732X_REG_ID, ®); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret); - goto err; - } - - dev_info(&i2c->dev, "Revision: %d.%d\n", - (reg & DA732X_ID_MAJOR_MASK), (reg & DA732X_ID_MINOR_MASK)); - - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da732x, - da732x_dai, ARRAY_SIZE(da732x_dai)); - if (ret != 0) - dev_err(&i2c->dev, "Failed to register codec.\n"); - -err: - return ret; -} - -static __devexit int da732x_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - - return 0; -} - -static const struct i2c_device_id da732x_i2c_id[] = { - { "da7320", 0}, - { } -}; -MODULE_DEVICE_TABLE(i2c, da732x_i2c_id); - -static struct i2c_driver da732x_i2c_driver = { - .driver = { - .name = "da7320", - .owner = THIS_MODULE, - }, - .probe = da732x_i2c_probe, - .remove = __devexit_p(da732x_i2c_remove), - .id_table = da732x_i2c_id, -}; - -module_i2c_driver(da732x_i2c_driver); - - -MODULE_DESCRIPTION("ASoC DA732X driver"); -MODULE_AUTHOR("Michal Hajduk "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/da732x.h b/trunk/sound/soc/codecs/da732x.h deleted file mode 100644 index c8ce5475de22..000000000000 --- a/trunk/sound/soc/codecs/da732x.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * da732x.h -- Dialog DA732X ALSA SoC Audio Driver Header File - * - * Copyright (C) 2012 Dialog Semiconductor GmbH - * - * Author: Michal Hajduk - * - * This program is free software; you can 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 __DA732X_H_ -#define __DA732X_H - -#include - -/* General */ -#define DA732X_U8_MASK 0xFF -#define DA732X_4BYTES 4 -#define DA732X_3BYTES 3 -#define DA732X_2BYTES 2 -#define DA732X_1BYTE 1 -#define DA732X_1BYTE_SHIFT 8 -#define DA732X_2BYTES_SHIFT 16 -#define DA732X_3BYTES_SHIFT 24 -#define DA732X_4BYTES_SHIFT 32 - -#define DA732X_DACS_DIS 0x0 -#define DA732X_HP_DIS 0x0 -#define DA732X_CLEAR_REG 0x0 - -/* Calibration */ -#define DA732X_DAC_OFFSET_STEP 0x20 -#define DA732X_OUTPUT_OFFSET_STEP 0x80 -#define DA732X_HP_OUT_TRIM_VAL 0x0 -#define DA732X_WAIT_FOR_STABILIZATION 1 -#define DA732X_HPL_DAC 0 -#define DA732X_HPR_DAC 1 -#define DA732X_HP_DACS 2 -#define DA732X_HPL_AMP 0 -#define DA732X_HPR_AMP 1 -#define DA732X_HP_AMPS 2 - -/* Clock settings */ -#define DA732X_STARTUP_DELAY 100 -#define DA732X_PLL_OUT_196608 196608000 -#define DA732X_PLL_OUT_180634 180633600 -#define DA732X_PLL_OUT_SRM 188620800 -#define DA732X_MCLK_10MHZ 10000000 -#define DA732X_MCLK_20MHZ 20000000 -#define DA732X_MCLK_40MHZ 40000000 -#define DA732X_MCLK_54MHZ 54000000 -#define DA732X_MCLK_RET_0_10MHZ 0 -#define DA732X_MCLK_VAL_0_10MHZ 1 -#define DA732X_MCLK_RET_10_20MHZ 1 -#define DA732X_MCLK_VAL_10_20MHZ 2 -#define DA732X_MCLK_RET_20_40MHZ 2 -#define DA732X_MCLK_VAL_20_40MHZ 4 -#define DA732X_MCLK_RET_40_54MHZ 3 -#define DA732X_MCLK_VAL_40_54MHZ 8 -#define DA732X_DAI_ID1 0 -#define DA732X_DAI_ID2 1 -#define DA732X_SRCCLK_PLL 0 -#define DA732X_SRCCLK_MCLK 1 - -#define DA732X_LIN_LP_VOL 0x4F -#define DA732X_LP_VOL 0x40 - -/* Kcontrols */ -#define DA732X_DAC_EN_MAX 2 -#define DA732X_ADCL_MUX_MAX 2 -#define DA732X_ADCR_MUX_MAX 3 -#define DA732X_HPF_MODE_MAX 3 -#define DA732X_HPF_MODE_SHIFT 4 -#define DA732X_HPF_MUSIC_SHIFT 0 -#define DA732X_HPF_MUSIC_MAX 4 -#define DA732X_HPF_VOICE_SHIFT 4 -#define DA732X_HPF_VOICE_MAX 8 -#define DA732X_EQ_EN_MAX 1 -#define DA732X_HPF_VOICE 1 -#define DA732X_HPF_MUSIC 2 -#define DA732X_HPF_DISABLED 0 -#define DA732X_NO_INVERT 0 -#define DA732X_INVERT 1 -#define DA732X_SWITCH_MAX 1 -#define DA732X_ENABLE_CP 1 -#define DA732X_DISABLE_CP 0 -#define DA732X_DISABLE_ALL_CLKS 0 -#define DA732X_RESET_ADCS 0 - -/* dB values */ -#define DA732X_MIC_VOL_DB_MIN 0 -#define DA732X_MIC_VOL_DB_INC 50 -#define DA732X_MIC_PRE_VOL_DB_MIN 0 -#define DA732X_MIC_PRE_VOL_DB_INC 600 -#define DA732X_AUX_VOL_DB_MIN -6000 -#define DA732X_AUX_VOL_DB_INC 150 -#define DA732X_HP_VOL_DB_MIN -2250 -#define DA732X_HP_VOL_DB_INC 150 -#define DA732X_LIN2_VOL_DB_MIN -1650 -#define DA732X_LIN2_VOL_DB_INC 150 -#define DA732X_LIN3_VOL_DB_MIN -1650 -#define DA732X_LIN3_VOL_DB_INC 150 -#define DA732X_LIN4_VOL_DB_MIN -2250 -#define DA732X_LIN4_VOL_DB_INC 150 -#define DA732X_EQ_BAND_VOL_DB_MIN -1050 -#define DA732X_EQ_BAND_VOL_DB_INC 150 -#define DA732X_DAC_VOL_DB_MIN -7725 -#define DA732X_DAC_VOL_DB_INC 75 -#define DA732X_ADC_VOL_DB_MIN 0 -#define DA732X_ADC_VOL_DB_INC -1 -#define DA732X_EQ_OVERALL_VOL_DB_MIN -1800 -#define DA732X_EQ_OVERALL_VOL_DB_INC 600 - -#define DA732X_SOC_ENUM_DOUBLE_R(xreg, xrreg, xmax, xtext) \ - {.reg = xreg, .reg2 = xrreg, .max = xmax, .texts = xtext} - -enum da732x_sysctl { - DA732X_SR_8KHZ = 0x1, - DA732X_SR_11_025KHZ = 0x2, - DA732X_SR_12KHZ = 0x3, - DA732X_SR_16KHZ = 0x5, - DA732X_SR_22_05KHZ = 0x6, - DA732X_SR_24KHZ = 0x7, - DA732X_SR_32KHZ = 0x9, - DA732X_SR_44_1KHZ = 0xA, - DA732X_SR_48KHZ = 0xB, - DA732X_SR_88_1KHZ = 0xE, - DA732X_SR_96KHZ = 0xF, -}; - -#endif /* __DA732X_H_ */ diff --git a/trunk/sound/soc/codecs/da732x_reg.h b/trunk/sound/soc/codecs/da732x_reg.h deleted file mode 100644 index bdd03ca4b2de..000000000000 --- a/trunk/sound/soc/codecs/da732x_reg.h +++ /dev/null @@ -1,654 +0,0 @@ -/* - * da732x_reg.h --- Dialog DA732X ALSA SoC Audio Registers Header File - * - * Copyright (C) 2012 Dialog Semiconductor GmbH - * - * Author: Michal Hajduk - * - * This program is free software; you can 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 __DA732X_REG_H_ -#define __DA732X_REG_H_ - -/* DA732X registers */ -#define DA732X_REG_STATUS_EXT 0x00 -#define DA732X_REG_STATUS 0x01 -#define DA732X_REG_REF1 0x02 -#define DA732X_REG_BIAS_EN 0x03 -#define DA732X_REG_BIAS1 0x04 -#define DA732X_REG_BIAS2 0x05 -#define DA732X_REG_BIAS3 0x06 -#define DA732X_REG_BIAS4 0x07 -#define DA732X_REG_MICBIAS2 0x0F -#define DA732X_REG_MICBIAS1 0x10 -#define DA732X_REG_MICDET 0x11 -#define DA732X_REG_MIC1_PRE 0x12 -#define DA732X_REG_MIC1 0x13 -#define DA732X_REG_MIC2_PRE 0x14 -#define DA732X_REG_MIC2 0x15 -#define DA732X_REG_AUX1L 0x16 -#define DA732X_REG_AUX1R 0x17 -#define DA732X_REG_MIC3_PRE 0x18 -#define DA732X_REG_MIC3 0x19 -#define DA732X_REG_INP_PINBIAS 0x1A -#define DA732X_REG_INP_ZC_EN 0x1B -#define DA732X_REG_INP_MUX 0x1D -#define DA732X_REG_HP_DET 0x20 -#define DA732X_REG_HPL_DAC_OFFSET 0x21 -#define DA732X_REG_HPL_DAC_OFF_CNTL 0x22 -#define DA732X_REG_HPL_OUT_OFFSET 0x23 -#define DA732X_REG_HPL 0x24 -#define DA732X_REG_HPL_VOL 0x25 -#define DA732X_REG_HPR_DAC_OFFSET 0x26 -#define DA732X_REG_HPR_DAC_OFF_CNTL 0x27 -#define DA732X_REG_HPR_OUT_OFFSET 0x28 -#define DA732X_REG_HPR 0x29 -#define DA732X_REG_HPR_VOL 0x2A -#define DA732X_REG_LIN2 0x2B -#define DA732X_REG_LIN3 0x2C -#define DA732X_REG_LIN4 0x2D -#define DA732X_REG_OUT_ZC_EN 0x2E -#define DA732X_REG_HP_LIN1_GNDSEL 0x37 -#define DA732X_REG_CP_HP1 0x3A -#define DA732X_REG_CP_HP2 0x3B -#define DA732X_REG_CP_CTRL1 0x40 -#define DA732X_REG_CP_CTRL2 0x41 -#define DA732X_REG_CP_CTRL3 0x42 -#define DA732X_REG_CP_LEVEL_MASK 0x43 -#define DA732X_REG_CP_DET 0x44 -#define DA732X_REG_CP_STATUS 0x45 -#define DA732X_REG_CP_THRESH1 0x46 -#define DA732X_REG_CP_THRESH2 0x47 -#define DA732X_REG_CP_THRESH3 0x48 -#define DA732X_REG_CP_THRESH4 0x49 -#define DA732X_REG_CP_THRESH5 0x4A -#define DA732X_REG_CP_THRESH6 0x4B -#define DA732X_REG_CP_THRESH7 0x4C -#define DA732X_REG_CP_THRESH8 0x4D -#define DA732X_REG_PLL_DIV_LO 0x50 -#define DA732X_REG_PLL_DIV_MID 0x51 -#define DA732X_REG_PLL_DIV_HI 0x52 -#define DA732X_REG_PLL_CTRL 0x53 -#define DA732X_REG_CLK_CTRL 0x54 -#define DA732X_REG_CLK_DSP 0x5A -#define DA732X_REG_CLK_EN1 0x5B -#define DA732X_REG_CLK_EN2 0x5C -#define DA732X_REG_CLK_EN3 0x5D -#define DA732X_REG_CLK_EN4 0x5E -#define DA732X_REG_CLK_EN5 0x5F -#define DA732X_REG_AIF_MCLK 0x60 -#define DA732X_REG_AIFA1 0x61 -#define DA732X_REG_AIFA2 0x62 -#define DA732X_REG_AIFA3 0x63 -#define DA732X_REG_AIFB1 0x64 -#define DA732X_REG_AIFB2 0x65 -#define DA732X_REG_AIFB3 0x66 -#define DA732X_REG_PC_CTRL 0x6A -#define DA732X_REG_DATA_ROUTE 0x70 -#define DA732X_REG_DSP_CTRL 0x71 -#define DA732X_REG_CIF_CTRL2 0x74 -#define DA732X_REG_HANDSHAKE 0x75 -#define DA732X_REG_MBOX0 0x76 -#define DA732X_REG_MBOX1 0x77 -#define DA732X_REG_MBOX2 0x78 -#define DA732X_REG_MBOX_STATUS 0x79 -#define DA732X_REG_SPARE1_OUT 0x7D -#define DA732X_REG_SPARE2_OUT 0x7E -#define DA732X_REG_SPARE1_IN 0x7F -#define DA732X_REG_ID 0x81 -#define DA732X_REG_ADC1_PD 0x90 -#define DA732X_REG_ADC1_HPF 0x93 -#define DA732X_REG_ADC1_SEL 0x94 -#define DA732X_REG_ADC1_EQ12 0x95 -#define DA732X_REG_ADC1_EQ34 0x96 -#define DA732X_REG_ADC1_EQ5 0x97 -#define DA732X_REG_ADC2_PD 0x98 -#define DA732X_REG_ADC2_HPF 0x9B -#define DA732X_REG_ADC2_SEL 0x9C -#define DA732X_REG_ADC2_EQ12 0x9D -#define DA732X_REG_ADC2_EQ34 0x9E -#define DA732X_REG_ADC2_EQ5 0x9F -#define DA732X_REG_DAC1_HPF 0xA0 -#define DA732X_REG_DAC1_L_VOL 0xA1 -#define DA732X_REG_DAC1_R_VOL 0xA2 -#define DA732X_REG_DAC1_SEL 0xA3 -#define DA732X_REG_DAC1_SOFTMUTE 0xA4 -#define DA732X_REG_DAC1_EQ12 0xA5 -#define DA732X_REG_DAC1_EQ34 0xA6 -#define DA732X_REG_DAC1_EQ5 0xA7 -#define DA732X_REG_DAC2_HPF 0xB0 -#define DA732X_REG_DAC2_L_VOL 0xB1 -#define DA732X_REG_DAC2_R_VOL 0xB2 -#define DA732X_REG_DAC2_SEL 0xB3 -#define DA732X_REG_DAC2_SOFTMUTE 0xB4 -#define DA732X_REG_DAC2_EQ12 0xB5 -#define DA732X_REG_DAC2_EQ34 0xB6 -#define DA732X_REG_DAC2_EQ5 0xB7 -#define DA732X_REG_DAC3_HPF 0xC0 -#define DA732X_REG_DAC3_VOL 0xC1 -#define DA732X_REG_DAC3_SEL 0xC3 -#define DA732X_REG_DAC3_SOFTMUTE 0xC4 -#define DA732X_REG_DAC3_EQ12 0xC5 -#define DA732X_REG_DAC3_EQ34 0xC6 -#define DA732X_REG_DAC3_EQ5 0xC7 -#define DA732X_REG_BIQ_BYP 0xD2 -#define DA732X_REG_DMA_CMD 0xD3 -#define DA732X_REG_DMA_ADDR0 0xD4 -#define DA732X_REG_DMA_ADDR1 0xD5 -#define DA732X_REG_DMA_DATA0 0xD6 -#define DA732X_REG_DMA_DATA1 0xD7 -#define DA732X_REG_DMA_DATA2 0xD8 -#define DA732X_REG_DMA_DATA3 0xD9 -#define DA732X_REG_DMA_STATUS 0xDA -#define DA732X_REG_BROWNOUT 0xDF -#define DA732X_REG_UNLOCK 0xE0 - -#define DA732X_MAX_REG DA732X_REG_UNLOCK -/* - * Bits - */ - -/* DA732X_REG_STATUS_EXT (addr=0x00) */ -#define DA732X_STATUS_EXT_DSP (1 << 4) -#define DA732X_STATUS_EXT_CLEAR (0 << 0) - -/* DA732X_REG_STATUS (addr=0x01) */ -#define DA732X_STATUS_PLL_LOCK (1 << 0) -#define DA732X_STATUS_PLL_MCLK_DET (1 << 1) -#define DA732X_STATUS_HPDET_OUT (1 << 2) -#define DA732X_STATUS_INP_MIXDET_1 (1 << 3) -#define DA732X_STATUS_INP_MIXDET_2 (1 << 4) -#define DA732X_STATUS_BO_STATUS (1 << 5) - -/* DA732X_REG_REF1 (addr=0x02) */ -#define DA732X_VMID_FASTCHG (1 << 1) -#define DA732X_VMID_FASTDISCHG (1 << 2) -#define DA732X_REFBUFX2_EN (1 << 6) -#define DA732X_REFBUFX2_DIS (0 << 6) - -/* DA732X_REG_BIAS_EN (addr=0x03) */ -#define DA732X_BIAS_BOOST_MASK (3 << 0) -#define DA732X_BIAS_BOOST_100PC (0 << 0) -#define DA732X_BIAS_BOOST_133PC (1 << 0) -#define DA732X_BIAS_BOOST_88PC (2 << 0) -#define DA732X_BIAS_BOOST_50PC (3 << 0) -#define DA732X_BIAS_EN (1 << 7) -#define DA732X_BIAS_DIS (0 << 7) - -/* DA732X_REG_BIAS1 (addr=0x04) */ -#define DA732X_BIAS1_HP_DAC_BIAS_MASK (3 << 0) -#define DA732X_BIAS1_HP_DAC_BIAS_100PC (0 << 0) -#define DA732X_BIAS1_HP_DAC_BIAS_150PC (1 << 0) -#define DA732X_BIAS1_HP_DAC_BIAS_50PC (2 << 0) -#define DA732X_BIAS1_HP_DAC_BIAS_75PC (3 << 0) -#define DA732X_BIAS1_HP_OUT_BIAS_MASK (7 << 4) -#define DA732X_BIAS1_HP_OUT_BIAS_100PC (0 << 4) -#define DA732X_BIAS1_HP_OUT_BIAS_125PC (1 << 4) -#define DA732X_BIAS1_HP_OUT_BIAS_150PC (2 << 4) -#define DA732X_BIAS1_HP_OUT_BIAS_175PC (3 << 4) -#define DA732X_BIAS1_HP_OUT_BIAS_200PC (4 << 4) -#define DA732X_BIAS1_HP_OUT_BIAS_250PC (5 << 4) -#define DA732X_BIAS1_HP_OUT_BIAS_300PC (6 << 4) -#define DA732X_BIAS1_HP_OUT_BIAS_350PC (7 << 4) - -/* DA732X_REG_BIAS2 (addr=0x05) */ -#define DA732X_BIAS2_LINE2_DAC_BIAS_MASK (3 << 0) -#define DA732X_BIAS2_LINE2_DAC_BIAS_100PC (0 << 0) -#define DA732X_BIAS2_LINE2_DAC_BIAS_150PC (1 << 0) -#define DA732X_BIAS2_LINE2_DAC_BIAS_50PC (2 << 0) -#define DA732X_BIAS2_LINE2_DAC_BIAS_75PC (3 << 0) -#define DA732X_BIAS2_LINE2_OUT_BIAS_MASK (7 << 4) -#define DA732X_BIAS2_LINE2_OUT_BIAS_100PC (0 << 4) -#define DA732X_BIAS2_LINE2_OUT_BIAS_125PC (1 << 4) -#define DA732X_BIAS2_LINE2_OUT_BIAS_150PC (2 << 4) -#define DA732X_BIAS2_LINE2_OUT_BIAS_175PC (3 << 4) -#define DA732X_BIAS2_LINE2_OUT_BIAS_200PC (4 << 4) -#define DA732X_BIAS2_LINE2_OUT_BIAS_250PC (5 << 4) -#define DA732X_BIAS2_LINE2_OUT_BIAS_300PC (6 << 4) -#define DA732X_BIAS2_LINE2_OUT_BIAS_350PC (7 << 4) - -/* DA732X_REG_BIAS3 (addr=0x06) */ -#define DA732X_BIAS3_LINE3_DAC_BIAS_MASK (3 << 0) -#define DA732X_BIAS3_LINE3_DAC_BIAS_100PC (0 << 0) -#define DA732X_BIAS3_LINE3_DAC_BIAS_150PC (1 << 0) -#define DA732X_BIAS3_LINE3_DAC_BIAS_50PC (2 << 0) -#define DA732X_BIAS3_LINE3_DAC_BIAS_75PC (3 << 0) -#define DA732X_BIAS3_LINE3_OUT_BIAS_MASK (7 << 4) -#define DA732X_BIAS3_LINE3_OUT_BIAS_100PC (0 << 4) -#define DA732X_BIAS3_LINE3_OUT_BIAS_125PC (1 << 4) -#define DA732X_BIAS3_LINE3_OUT_BIAS_150PC (2 << 4) -#define DA732X_BIAS3_LINE3_OUT_BIAS_175PC (3 << 4) -#define DA732X_BIAS3_LINE3_OUT_BIAS_200PC (4 << 4) -#define DA732X_BIAS3_LINE3_OUT_BIAS_250PC (5 << 4) -#define DA732X_BIAS3_LINE3_OUT_BIAS_300PC (6 << 4) -#define DA732X_BIAS3_LINE3_OUT_BIAS_350PC (7 << 4) - -/* DA732X_REG_BIAS4 (addr=0x07) */ -#define DA732X_BIAS4_LINE4_DAC_BIAS_MASK (3 << 0) -#define DA732X_BIAS4_LINE4_DAC_BIAS_100PC (0 << 0) -#define DA732X_BIAS4_LINE4_DAC_BIAS_150PC (1 << 0) -#define DA732X_BIAS4_LINE4_DAC_BIAS_50PC (2 << 0) -#define DA732X_BIAS4_LINE4_DAC_BIAS_75PC (3 << 0) -#define DA732X_BIAS4_LINE4_OUT_BIAS_MASK (7 << 4) -#define DA732X_BIAS4_LINE4_OUT_BIAS_100PC (0 << 4) -#define DA732X_BIAS4_LINE4_OUT_BIAS_125PC (1 << 4) -#define DA732X_BIAS4_LINE4_OUT_BIAS_150PC (2 << 4) -#define DA732X_BIAS4_LINE4_OUT_BIAS_175PC (3 << 4) -#define DA732X_BIAS4_LINE4_OUT_BIAS_200PC (4 << 4) -#define DA732X_BIAS4_LINE4_OUT_BIAS_250PC (5 << 4) -#define DA732X_BIAS4_LINE4_OUT_BIAS_300PC (6 << 4) -#define DA732X_BIAS4_LINE4_OUT_BIAS_350PC (7 << 4) - -/* DA732X_REG_SIF_VDD_SEL (addr=0x08) */ -#define DA732X_SIF_VDD_SEL_AIFA_VDD2 (1 << 0) -#define DA732X_SIF_VDD_SEL_AIFB_VDD2 (1 << 1) -#define DA732X_SIF_VDD_SEL_CIFA_VDD2 (1 << 4) - -/* DA732X_REG_MICBIAS2/1 (addr=0x0F/0x10) */ -#define DA732X_MICBIAS_VOLTAGE_MASK (0x0F << 0) -#define DA732X_MICBIAS_VOLTAGE_2V (0x00 << 0) -#define DA732X_MICBIAS_VOLTAGE_2V05 (0x01 << 0) -#define DA732X_MICBIAS_VOLTAGE_2V1 (0x02 << 0) -#define DA732X_MICBIAS_VOLTAGE_2V15 (0x03 << 0) -#define DA732X_MICBIAS_VOLTAGE_2V2 (0x04 << 0) -#define DA732X_MICBIAS_VOLTAGE_2V25 (0x05 << 0) -#define DA732X_MICBIAS_VOLTAGE_2V3 (0x06 << 0) -#define DA732X_MICBIAS_VOLTAGE_2V35 (0x07 << 0) -#define DA732X_MICBIAS_VOLTAGE_2V4 (0x08 << 0) -#define DA732X_MICBIAS_VOLTAGE_2V45 (0x09 << 0) -#define DA732X_MICBIAS_VOLTAGE_2V5 (0x0A << 0) -#define DA732X_MICBIAS_EN (1 << 7) -#define DA732X_MICBIAS_EN_SHIFT 7 -#define DA732X_MICBIAS_VOLTAGE_SHIFT 0 -#define DA732X_MICBIAS_VOLTAGE_MAX 0x0B - -/* DA732X_REG_MICDET (addr=0x11) */ -#define DA732X_MICDET_INP_MICRES (1 << 0) -#define DA732X_MICDET_INP_MICHOOK (1 << 1) -#define DA732X_MICDET_INP_DEBOUNCE_PRD_8MS (0 << 0) -#define DA732X_MICDET_INP_DEBOUNCE_PRD_16MS (1 << 0) -#define DA732X_MICDET_INP_DEBOUNCE_PRD_32MS (2 << 0) -#define DA732X_MICDET_INP_DEBOUNCE_PRD_64MS (3 << 0) -#define DA732X_MICDET_INP_MICDET_EN (1 << 7) - -/* DA732X_REG_MIC1/2/3_PRE (addr=0x11/0x14/0x18) */ -#define DA732X_MICBOOST_MASK 0x7 -#define DA732X_MICBOOST_SHIFT 0 -#define DA732X_MICBOOST_MIN 0x1 -#define DA732X_MICBOOST_MAX DA732X_MICBOOST_MASK - -/* DA732X_REG_MIC1/2/3 (addr=0x13/0x15/0x19) */ -#define DA732X_MIC_VOL_SHIFT 0 -#define DA732X_MIC_VOL_VAL_MASK 0x1F -#define DA732X_MIC_MUTE_SHIFT 6 -#define DA732X_MIC_EN_SHIFT 7 -#define DA732X_MIC_VOL_VAL_MIN 0x7 -#define DA732X_MIC_VOL_VAL_MAX DA732X_MIC_VOL_VAL_MASK - -/* DA732X_REG_AUX1L/R (addr=0x16/0x17) */ -#define DA732X_AUX_VOL_SHIFT 0 -#define DA732X_AUX_VOL_MASK 0x7 -#define DA732X_AUX_MUTE_SHIFT 6 -#define DA732X_AUX_EN_SHIFT 7 -#define DA732X_AUX_VOL_VAL_MAX DA732X_AUX_VOL_MASK - -/* DA732X_REG_INP_PINBIAS (addr=0x1A) */ -#define DA732X_INP_MICL_PINBIAS_EN (1 << 0) -#define DA732X_INP_MICR_PINBIAS_EN (1 << 1) -#define DA732X_INP_AUX1L_PINBIAS_EN (1 << 2) -#define DA732X_INP_AUX1R_PINBIAS_EN (1 << 3) -#define DA732X_INP_AUX2_PINBIAS_EN (1 << 4) - -/* DA732X_REG_INP_ZC_EN (addr=0x1B) */ -#define DA732X_MIC1_PRE_ZC_EN (1 << 0) -#define DA732X_MIC1_ZC_EN (1 << 1) -#define DA732X_MIC2_PRE_ZC_EN (1 << 2) -#define DA732X_MIC2_ZC_EN (1 << 3) -#define DA732X_AUXL_ZC_EN (1 << 4) -#define DA732X_AUXR_ZC_EN (1 << 5) -#define DA732X_MIC3_PRE_ZC_EN (1 << 6) -#define DA732X_MIC3_ZC_EN (1 << 7) - -/* DA732X_REG_INP_MUX (addr=0x1D) */ -#define DA732X_INP_ADC1L_MUX_SEL_AUX1L (0 << 0) -#define DA732X_INP_ADC1L_MUX_SEL_MIC1 (1 << 0) -#define DA732X_INP_ADC1R_MUX_SEL_MASK (3 << 2) -#define DA732X_INP_ADC1R_MUX_SEL_AUX1R (0 << 2) -#define DA732X_INP_ADC1R_MUX_SEL_MIC2 (1 << 2) -#define DA732X_INP_ADC1R_MUX_SEL_MIC3 (2 << 2) -#define DA732X_INP_ADC2L_MUX_SEL_AUX1L (0 << 4) -#define DA732X_INP_ADC2L_MUX_SEL_MICL (1 << 4) -#define DA732X_INP_ADC2R_MUX_SEL_MASK (3 << 6) -#define DA732X_INP_ADC2R_MUX_SEL_AUX1R (0 << 6) -#define DA732X_INP_ADC2R_MUX_SEL_MICR (1 << 6) -#define DA732X_INP_ADC2R_MUX_SEL_AUX2 (2 << 6) -#define DA732X_ADC1L_MUX_SEL_SHIFT 0 -#define DA732X_ADC1R_MUX_SEL_SHIFT 2 -#define DA732X_ADC2L_MUX_SEL_SHIFT 4 -#define DA732X_ADC2R_MUX_SEL_SHIFT 6 - -/* DA732X_REG_HP_DET (addr=0x20) */ -#define DA732X_HP_DET_AZ (1 << 0) -#define DA732X_HP_DET_SEL1 (1 << 1) -#define DA732X_HP_DET_IS_MASK (3 << 2) -#define DA732X_HP_DET_IS_0_5UA (0 << 2) -#define DA732X_HP_DET_IS_1UA (1 << 2) -#define DA732X_HP_DET_IS_2UA (2 << 2) -#define DA732X_HP_DET_IS_4UA (3 << 2) -#define DA732X_HP_DET_RS_MASK (3 << 4) -#define DA732X_HP_DET_RS_INFINITE (0 << 4) -#define DA732X_HP_DET_RS_100KOHM (1 << 4) -#define DA732X_HP_DET_RS_10KOHM (2 << 4) -#define DA732X_HP_DET_RS_1KOHM (3 << 4) -#define DA732X_HP_DET_EN (1 << 7) - -/* DA732X_REG_HPL_DAC_OFFSET (addr=0x21/0x26) */ -#define DA732X_HP_DAC_OFFSET_TRIM_MASK (0x3F << 0) -#define DA732X_HP_DAC_OFFSET_DAC_SIGN (1 << 6) - -/* DA732X_REG_HPL_DAC_OFF_CNTL (addr=0x22/0x27) */ -#define DA732X_HP_DAC_OFF_CNTL_CONT_MASK (7 << 0) -#define DA732X_HP_DAC_OFF_CNTL_COMPO (1 << 3) -#define DA732X_HP_DAC_OFF_CALIBRATION (1 << 0) -#define DA732X_HP_DAC_OFF_SCALE_STEPS (1 << 1) -#define DA732X_HP_DAC_OFF_MASK 0x7F -#define DA732X_HP_DAC_COMPO_SHIFT 3 - -/* DA732X_REG_HPL_OUT_OFFSET (addr=0x23/0x28) */ -#define DA732X_HP_OUT_OFFSET_MASK (0xFF << 0) -#define DA732X_HP_DAC_OFFSET_TRIM_VAL 0x7F - -/* DA732X_REG_HPL/R (addr=0x24/0x29) */ -#define DA732X_HP_OUT_SIGN (1 << 0) -#define DA732X_HP_OUT_COMP (1 << 1) -#define DA732X_HP_OUT_RESERVED (1 << 2) -#define DA732X_HP_OUT_COMPO (1 << 3) -#define DA732X_HP_OUT_DAC_EN (1 << 4) -#define DA732X_HP_OUT_HIZ_EN (1 << 5) -#define DA732X_HP_OUT_HIZ_DIS (0 << 5) -#define DA732X_HP_OUT_MUTE (1 << 6) -#define DA732X_HP_OUT_EN (1 << 7) -#define DA732X_HP_OUT_COMPO_SHIFT 3 -#define DA732X_HP_OUT_DAC_EN_SHIFT 4 -#define DA732X_HP_HIZ_SHIFT 5 -#define DA732X_HP_MUTE_SHIFT 6 -#define DA732X_HP_OUT_EN_SHIFT 7 - -#define DA732X_OUT_HIZ_EN (1 << 5) -#define DA732X_OUT_HIZ_DIS (0 << 5) - -/* DA732X_REG_HPL/R_VOL (addr=0x25/0x2A) */ -#define DA732X_HP_VOL_VAL_MASK 0xF -#define DA732X_HP_VOL_SHIFT 0 -#define DA732X_HP_VOL_VAL_MAX DA732X_HP_VOL_VAL_MASK - -/* DA732X_REG_LIN2/3/4 (addr=0x2B/0x2C/0x2D) */ -#define DA732X_LOUT_VOL_SHIFT 0 -#define DA732X_LOUT_VOL_MASK 0x0F -#define DA732X_LOUT_DAC_OFF (0 << 4) -#define DA732X_LOUT_DAC_EN (1 << 4) -#define DA732X_LOUT_HIZ_N_DIS (0 << 5) -#define DA732X_LOUT_HIZ_N_EN (1 << 5) -#define DA732X_LOUT_UNMUTED (0 << 6) -#define DA732X_LOUT_MUTED (1 << 6) -#define DA732X_LOUT_EN (0 << 7) -#define DA732X_LOUT_DIS (1 << 7) -#define DA732X_LOUT_DAC_EN_SHIFT 4 -#define DA732X_LOUT_MUTE_SHIFT 6 -#define DA732X_LIN_OUT_EN_SHIFT 7 -#define DA732X_LOUT_VOL_VAL_MAX DA732X_LOUT_VOL_MASK - -/* DA732X_REG_OUT_ZC_EN (addr=0x2E) */ -#define DA732X_HPL_ZC_EN_SHIFT 0 -#define DA732X_HPR_ZC_EN_SHIFT 1 -#define DA732X_HPL_ZC_EN (1 << 0) -#define DA732X_HPL_ZC_DIS (0 << 0) -#define DA732X_HPR_ZC_EN (1 << 1) -#define DA732X_HPR_ZC_DIS (0 << 1) -#define DA732X_LIN2_ZC_EN (1 << 2) -#define DA732X_LIN2_ZC_DIS (0 << 2) -#define DA732X_LIN3_ZC_EN (1 << 3) -#define DA732X_LIN3_ZC_DIS (0 << 3) -#define DA732X_LIN4_ZC_EN (1 << 4) -#define DA732X_LIN4_ZC_DIS (0 << 4) - -/* DA732X_REG_HP_LIN1_GNDSEL (addr=0x37) */ -#define DA732X_HP_OUT_GNDSEL (1 << 0) - -/* DA732X_REG_CP_HP2 (addr=0x3a) */ -#define DA732X_HP_CP_PULSESKIP (1 << 0) -#define DA732X_HP_CP_REG (1 << 1) -#define DA732X_HP_CP_EN (1 << 3) -#define DA732X_HP_CP_DIS (0 << 3) - -/* DA732X_REG_CP_CTRL1 (addr=0x40) */ -#define DA732X_CP_MODE_MASK (7 << 1) -#define DA732X_CP_CTRL_STANDBY (0 << 1) -#define DA732X_CP_CTRL_CPVDD6 (2 << 1) -#define DA732X_CP_CTRL_CPVDD5 (3 << 1) -#define DA732X_CP_CTRL_CPVDD4 (4 << 1) -#define DA732X_CP_CTRL_CPVDD3 (5 << 1) -#define DA732X_CP_CTRL_CPVDD2 (6 << 1) -#define DA732X_CP_CTRL_CPVDD1 (7 << 1) -#define DA723X_CP_DIS (0 << 7) -#define DA732X_CP_EN (1 << 7) - -/* DA732X_REG_CP_CTRL2 (addr=0x41) */ -#define DA732X_CP_BOOST (1 << 0) -#define DA732X_CP_MANAGE_MAGNITUDE (2 << 2) - -/* DA732X_REG_CP_CTRL3 (addr=0x42) */ -#define DA732X_CP_1MHZ (0 << 0) -#define DA732X_CP_500KHZ (1 << 0) -#define DA732X_CP_250KHZ (2 << 0) -#define DA732X_CP_125KHZ (3 << 0) -#define DA732X_CP_63KHZ (4 << 0) -#define DA732X_CP_0KHZ (5 << 0) - -/* DA732X_REG_PLL_CTRL (addr=0x53) */ -#define DA732X_PLL_INDIV_MASK (3 << 0) -#define DA732X_PLL_SRM_EN (1 << 2) -#define DA732X_PLL_EN (1 << 7) -#define DA732X_PLL_BYPASS (0 << 0) - -/* DA732X_REG_CLK_CTRL (addr=0x54) */ -#define DA732X_SR1_MASK (0xF) -#define DA732X_SR2_MASK (0xF0) - -/* DA732X_REG_CLK_DSP (addr=0x5A) */ -#define DA732X_DSP_FREQ_MASK (7 << 0) -#define DA732X_DSP_FREQ_12MHZ (0 << 0) -#define DA732X_DSP_FREQ_24MHZ (1 << 0) -#define DA732X_DSP_FREQ_36MHZ (2 << 0) -#define DA732X_DSP_FREQ_48MHZ (3 << 0) -#define DA732X_DSP_FREQ_60MHZ (4 << 0) -#define DA732X_DSP_FREQ_72MHZ (5 << 0) -#define DA732X_DSP_FREQ_84MHZ (6 << 0) -#define DA732X_DSP_FREQ_96MHZ (7 << 0) - -/* DA732X_REG_CLK_EN1 (addr=0x5B) */ -#define DA732X_DSP_CLK_EN (1 << 0) -#define DA732X_SYS3_CLK_EN (1 << 1) -#define DA732X_DSP12_CLK_EN (1 << 2) -#define DA732X_PC_CLK_EN (1 << 3) -#define DA732X_MCLK_SQR_EN (1 << 7) - -/* DA732X_REG_CLK_EN2 (addr=0x5C) */ -#define DA732X_UART_CLK_EN (1 << 1) -#define DA732X_CP_CLK_EN (1 << 2) -#define DA732X_CP_CLK_DIS (0 << 2) - -/* DA732X_REG_CLK_EN3 (addr=0x5D) */ -#define DA732X_ADCA_BB_CLK_EN (1 << 0) -#define DA732X_ADCC_BB_CLK_EN (1 << 4) - -/* DA732X_REG_CLK_EN4 (addr=0x5E) */ -#define DA732X_DACA_BB_CLK_EN (1 << 0) -#define DA732X_DACC_BB_CLK_EN (1 << 4) -#define DA732X_DACA_BB_CLK_SHIFT 0 -#define DA732X_DACC_BB_CLK_SHIFT 4 - -/* DA732X_REG_CLK_EN5 (addr=0x5F) */ -#define DA732X_DACE_BB_CLK_EN (1 << 0) -#define DA732X_DACE_BB_CLK_SHIFT 0 - -/* DA732X_REG_AIF_MCLK (addr=0x60) */ -#define DA732X_AIFM_FRAME_64 (1 << 2) -#define DA732X_AIFM_SRC_SEL_AIFA (1 << 6) -#define DA732X_CLK_GENERATION_AIF_A (1 << 4) -#define DA732X_NO_CLK_GENERATION 0x0 - -/* DA732X_REG_AIFA1 (addr=0x61) */ -#define DA732X_AIF_WORD_MASK (0x3 << 0) -#define DA732X_AIF_WORD_16 (0 << 0) -#define DA732X_AIF_WORD_20 (1 << 0) -#define DA732X_AIF_WORD_24 (2 << 0) -#define DA732X_AIF_WORD_32 (3 << 0) -#define DA732X_AIF_TDM_MONO_SHIFT (1 << 6) -#define DA732X_AIF1_CLK_MASK (1 << 7) -#define DA732X_AIF_SLAVE (0 << 7) -#define DA732X_AIF_CLK_FROM_SRC (1 << 7) - -/* DA732X_REG_AIFA3 (addr=0x63) */ -#define DA732X_AIF_MODE_SHIFT 0 -#define DA732X_AIF_MODE_MASK 0x3 -#define DA732X_AIF_I2S_MODE (0 << 0) -#define DA732X_AIF_LEFT_J_MODE (1 << 0) -#define DA732X_AIF_RIGHT_J_MODE (2 << 0) -#define DA732X_AIF_DSP_MODE (3 << 0) -#define DA732X_AIF_WCLK_INV (1 << 4) -#define DA732X_AIF_BCLK_INV (1 << 5) -#define DA732X_AIF_EN (1 << 7) -#define DA732X_AIF_EN_SHIFT 7 - -/* DA732X_REG_PC_CTRL (addr=0x6a) */ -#define DA732X_PC_PULSE_AIFA (0 << 0) -#define DA732X_PC_PULSE_AIFB (1 << 0) -#define DA732X_PC_RESYNC_AUT (1 << 6) -#define DA732X_PC_RESYNC_NOT_AUT (0 << 6) -#define DA732X_PC_SAME (1 << 7) - -/* DA732X_REG_DATA_ROUTE (addr=0x70) */ -#define DA732X_ADC1_TO_AIFA (0 << 0) -#define DA732X_DSP_TO_AIFA (1 << 0) -#define DA732X_ADC2_TO_AIFB (0 << 1) -#define DA732X_DSP_TO_AIFB (1 << 1) -#define DA732X_AIFA_TO_DAC1L (0 << 2) -#define DA732X_DSP_TO_DAC1L (1 << 2) -#define DA732X_AIFA_TO_DAC1R (0 << 3) -#define DA732X_DSP_TO_DAC1R (1 << 3) -#define DA732X_AIFB_TO_DAC2L (0 << 4) -#define DA732X_DSP_TO_DAC2L (1 << 4) -#define DA732X_AIFB_TO_DAC2R (0 << 5) -#define DA732X_DSP_TO_DAC2R (1 << 5) -#define DA732X_AIFB_TO_DAC3 (0 << 6) -#define DA732X_DSP_TO_DAC3 (1 << 6) -#define DA732X_BYPASS_DSP (0 << 0) -#define DA732X_ALL_TO_DSP (0x7F << 0) - -/* DA732X_REG_DSP_CTRL (addr=0x71) */ -#define DA732X_DIGITAL_EN (1 << 0) -#define DA732X_DIGITAL_RESET (0 << 0) -#define DA732X_DSP_CORE_EN (1 << 1) -#define DA732X_DSP_CORE_RESET (0 << 1) - -/* DA732X_REG_SPARE1_OUT (addr=0x7D)*/ -#define DA732X_HP_DRIVER_EN (1 << 0) -#define DA732X_HP_GATE_LOW (1 << 2) -#define DA732X_HP_LOOP_GAIN_CTRL (1 << 3) - -/* DA732X_REG_ID (addr=0x81)*/ -#define DA732X_ID_MINOR_MASK (0xF << 0) -#define DA732X_ID_MAJOR_MASK (0xF << 4) - -/* DA732X_REG_ADC1/2_PD (addr=0x90/0x98) */ -#define DA732X_ADC_RST_MASK (0x3 << 0) -#define DA732X_ADC_PD_MASK (0x3 << 2) -#define DA732X_ADC_SET_ACT (0x3 << 0) -#define DA732X_ADC_SET_RST (0x0 << 0) -#define DA732X_ADC_ON (0x3 << 2) -#define DA732X_ADC_OFF (0x0 << 2) - -/* DA732X_REG_ADC1/2_SEL (addr=0x94/0x9C) */ -#define DA732X_ADC_VOL_VAL_MASK 0x7 -#define DA732X_ADCL_VOL_SHIFT 0 -#define DA732X_ADCR_VOL_SHIFT 4 -#define DA732X_ADCL_EN_SHIFT 2 -#define DA732X_ADCR_EN_SHIFT 3 -#define DA732X_ADCL_EN (1 << 2) -#define DA732X_ADCR_EN (1 << 3) -#define DA732X_ADC_VOL_VAL_MAX DA732X_ADC_VOL_VAL_MASK - -/* - * DA732X_REG_ADC1/2_HPF (addr=0x93/0x9b) - * DA732x_REG_DAC1/2/3_HPG (addr=0xA5/0xB5/0xC5) - */ -#define DA732X_HPF_MUSIC_EN (1 << 3) -#define DA732X_HPF_VOICE_EN ((1 << 3) | (1 << 7)) -#define DA732X_HPF_MASK ((1 << 3) | (1 << 7)) -#define DA732X_HPF_DIS ((0 << 3) | (0 << 7)) - -/* DA732X_REG_DAC1/2/3_VOL */ -#define DA732X_DAC_VOL_VAL_MASK 0x7F -#define DA732X_DAC_VOL_SHIFT 0 -#define DA732X_DAC_VOL_VAL_MAX DA732X_DAC_VOL_VAL_MASK - -/* DA732X_REG_DAC1/2/3_SEL (addr=0xA3/0xB3/0xC3) */ -#define DA732X_DACL_EN_SHIFT 3 -#define DA732X_DACR_EN_SHIFT 7 -#define DA732X_DACL_MUTE_SHIFT 2 -#define DA732X_DACR_MUTE_SHIFT 6 -#define DA732X_DACL_EN (1 << 3) -#define DA732X_DACR_EN (1 << 7) -#define DA732X_DACL_SDM (1 << 0) -#define DA732X_DACR_SDM (1 << 4) -#define DA732X_DACL_MUTE (1 << 2) -#define DA732X_DACR_MUTE (1 << 6) - -/* DA732X_REG_DAC_SOFTMUTE (addr=0xA4/0xB4/0xC4) */ -#define DA732X_SOFTMUTE_EN (1 << 7) -#define DA732X_GAIN_RAMPED (1 << 6) -#define DA732X_16_SAMPLES (4 << 0) -#define DA732X_SOFTMUTE_MASK (1 << 7) -#define DA732X_SOFTMUTE_SHIFT 7 - -/* - * DA732x_REG_ADC1/2_EQ12 (addr=0x95/0x9D) - * DA732x_REG_ADC1/2_EQ34 (addr=0x96/0x9E) - * DA732x_REG_ADC1/2_EQ5 (addr=0x97/0x9F) - * DA732x_REG_DAC1/2/3_EQ12 (addr=0xA5/0xB5/0xC5) - * DA732x_REG_DAC1/2/3_EQ34 (addr=0xA6/0xB6/0xC6) - * DA732x_REG_DAC1/2/3_EQ5 (addr=0xA7/0xB7/0xB7) - */ -#define DA732X_EQ_VOL_VAL_MASK 0xF -#define DA732X_EQ_BAND1_SHIFT 0 -#define DA732X_EQ_BAND2_SHIFT 4 -#define DA732X_EQ_BAND3_SHIFT 0 -#define DA732X_EQ_BAND4_SHIFT 4 -#define DA732X_EQ_BAND5_SHIFT 0 -#define DA732X_EQ_OVERALL_SHIFT 4 -#define DA732X_EQ_OVERALL_VOL_VAL_MASK 0x3 -#define DA732X_EQ_DIS (0 << 7) -#define DA732X_EQ_EN (1 << 7) -#define DA732X_EQ_EN_SHIFT 7 -#define DA732X_EQ_VOL_VAL_MAX DA732X_EQ_VOL_VAL_MASK -#define DA732X_EQ_OVERALL_VOL_VAL_MAX DA732X_EQ_OVERALL_VOL_VAL_MASK - -/* DA732X_REG_DMA_CMD (addr=0xD3) */ -#define DA732X_SEL_DSP_DMA_MASK (3 << 0) -#define DA732X_SEL_DSP_DMA_DIS (0 << 0) -#define DA732X_SEL_DSP_DMA_PMEM (1 << 0) -#define DA732X_SEL_DSP_DMA_XMEM (2 << 0) -#define DA732X_SEL_DSP_DMA_YMEM (3 << 0) -#define DA732X_DSP_RW_MASK (1 << 4) -#define DA732X_DSP_DMA_WRITE (0 << 4) -#define DA732X_DSP_DMA_READ (1 << 4) - -/* DA732X_REG_DMA_STATUS (addr=0xDA) */ -#define DA732X_DSP_DMA_FREE (0 << 0) -#define DA732X_DSP_DMA_BUSY (1 << 0) - -#endif /* __DA732X_REG_H_ */ diff --git a/trunk/sound/soc/codecs/isabelle.c b/trunk/sound/soc/codecs/isabelle.c deleted file mode 100644 index 0d62f3b0f474..000000000000 --- a/trunk/sound/soc/codecs/isabelle.c +++ /dev/null @@ -1,1176 +0,0 @@ -/* - * isabelle.c - Low power high fidelity audio codec 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/twl6040.c - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "isabelle.h" - - -/* Register default values for ISABELLE driver. */ -static struct reg_default isabelle_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, 0x02 }, - { 22, 0x02 }, - { 23, 0x02 }, - { 24, 0x02 }, - { 25, 0x0F }, - { 26, 0x8F }, - { 27, 0x0F }, - { 28, 0x8F }, - { 29, 0x00 }, - { 30, 0x00 }, - { 31, 0x00 }, - { 32, 0x00 }, - { 33, 0x00 }, - { 34, 0x00 }, - { 35, 0x00 }, - { 36, 0x00 }, - { 37, 0x00 }, - { 38, 0x00 }, - { 39, 0x00 }, - { 40, 0x00 }, - { 41, 0x00 }, - { 42, 0x00 }, - { 43, 0x00 }, - { 44, 0x00 }, - { 45, 0x00 }, - { 46, 0x00 }, - { 47, 0x00 }, - { 48, 0x00 }, - { 49, 0x00 }, - { 50, 0x00 }, - { 51, 0x00 }, - { 52, 0x00 }, - { 53, 0x00 }, - { 54, 0x00 }, - { 55, 0x00 }, - { 56, 0x00 }, - { 57, 0x00 }, - { 58, 0x00 }, - { 59, 0x00 }, - { 60, 0x00 }, - { 61, 0x00 }, - { 62, 0x00 }, - { 63, 0x00 }, - { 64, 0x00 }, - { 65, 0x00 }, - { 66, 0x00 }, - { 67, 0x00 }, - { 68, 0x00 }, - { 69, 0x90 }, - { 70, 0x90 }, - { 71, 0x90 }, - { 72, 0x00 }, - { 73, 0x00 }, - { 74, 0x00 }, - { 75, 0x00 }, - { 76, 0x00 }, - { 77, 0x00 }, - { 78, 0x00 }, - { 79, 0x00 }, - { 80, 0x00 }, - { 81, 0x00 }, - { 82, 0x00 }, - { 83, 0x00 }, - { 84, 0x00 }, - { 85, 0x07 }, - { 86, 0x00 }, - { 87, 0x00 }, - { 88, 0x00 }, - { 89, 0x07 }, - { 90, 0x80 }, - { 91, 0x07 }, - { 92, 0x07 }, - { 93, 0x00 }, - { 94, 0x00 }, - { 95, 0x00 }, - { 96, 0x00 }, - { 97, 0x00 }, - { 98, 0x00 }, - { 99, 0x00 }, -}; - -static const char *isabelle_rx1_texts[] = {"VRX1", "ARX1"}; -static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"}; - -static const struct soc_enum isabelle_rx1_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, 1, isabelle_rx1_texts), - SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, 1, isabelle_rx1_texts), -}; - -static const struct soc_enum isabelle_rx2_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, 1, isabelle_rx2_texts), - SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, 1, isabelle_rx2_texts), -}; - -/* Headset DAC playback switches */ -static const struct snd_kcontrol_new rx1_mux_controls = - SOC_DAPM_ENUM("Route", isabelle_rx1_enum); - -static const struct snd_kcontrol_new rx2_mux_controls = - SOC_DAPM_ENUM("Route", isabelle_rx2_enum); - -/* TX input selection */ -static const char *isabelle_atx_texts[] = {"AMIC1", "DMIC"}; -static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"}; - -static const struct soc_enum isabelle_atx_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, 1, isabelle_atx_texts), - SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_atx_texts), -}; - -static const struct soc_enum isabelle_vtx_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, 1, isabelle_vtx_texts), - SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_vtx_texts), -}; - -static const struct snd_kcontrol_new atx_mux_controls = - SOC_DAPM_ENUM("Route", isabelle_atx_enum); - -static const struct snd_kcontrol_new vtx_mux_controls = - SOC_DAPM_ENUM("Route", isabelle_vtx_enum); - -/* Left analog microphone selection */ -static const char *isabelle_amic1_texts[] = { - "Main Mic", "Headset Mic", "Aux/FM Left"}; - -/* Left analog microphone selection */ -static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"}; - -static const struct soc_enum isabelle_amic1_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 5, - ARRAY_SIZE(isabelle_amic1_texts), - isabelle_amic1_texts), -}; - -static const struct soc_enum isabelle_amic2_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 4, - ARRAY_SIZE(isabelle_amic2_texts), - isabelle_amic2_texts), -}; - -static const struct snd_kcontrol_new amic1_control = - SOC_DAPM_ENUM("Route", isabelle_amic1_enum); - -static const struct snd_kcontrol_new amic2_control = - SOC_DAPM_ENUM("Route", isabelle_amic2_enum); - -static const char *isabelle_st_audio_texts[] = {"ATX1", "ATX2"}; - -static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"}; - -static const struct soc_enum isabelle_st_audio_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, 1, - isabelle_st_audio_texts), - SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, 1, - isabelle_st_audio_texts), -}; - -static const struct soc_enum isabelle_st_voice_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, 1, - isabelle_st_voice_texts), - SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, 1, - isabelle_st_voice_texts), -}; - -static const struct snd_kcontrol_new st_audio_control = - SOC_DAPM_ENUM("Route", isabelle_st_audio_enum); - -static const struct snd_kcontrol_new st_voice_control = - SOC_DAPM_ENUM("Route", isabelle_st_voice_enum); - -/* Mixer controls */ -static const struct snd_kcontrol_new isabelle_hs_left_mixer_controls[] = { -SOC_DAPM_SINGLE("DAC1L Playback Switch", ISABELLE_HSDRV_CFG1_REG, 7, 1, 0), -SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_HSDRV_CFG1_REG, 6, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_hs_right_mixer_controls[] = { -SOC_DAPM_SINGLE("DAC1R Playback Switch", ISABELLE_HSDRV_CFG1_REG, 5, 1, 0), -SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_HSDRV_CFG1_REG, 4, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_hf_left_mixer_controls[] = { -SOC_DAPM_SINGLE("DAC2L Playback Switch", ISABELLE_HFLPGA_CFG_REG, 7, 1, 0), -SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_HFLPGA_CFG_REG, 6, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_hf_right_mixer_controls[] = { -SOC_DAPM_SINGLE("DAC2R Playback Switch", ISABELLE_HFRPGA_CFG_REG, 7, 1, 0), -SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_HFRPGA_CFG_REG, 6, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_ep_mixer_controls[] = { -SOC_DAPM_SINGLE("DAC2L Playback Switch", ISABELLE_EARDRV_CFG1_REG, 7, 1, 0), -SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_EARDRV_CFG1_REG, 6, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_aux_left_mixer_controls[] = { -SOC_DAPM_SINGLE("DAC3L Playback Switch", ISABELLE_LINEAMP_CFG_REG, 7, 1, 0), -SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_LINEAMP_CFG_REG, 6, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_aux_right_mixer_controls[] = { -SOC_DAPM_SINGLE("DAC3R Playback Switch", ISABELLE_LINEAMP_CFG_REG, 5, 1, 0), -SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_LINEAMP_CFG_REG, 4, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_dpga1_left_mixer_controls[] = { -SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 7, 1, 0), -SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 6, 1, 0), -SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 5, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_dpga1_right_mixer_controls[] = { -SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 3, 1, 0), -SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 2, 1, 0), -SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 1, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_dpga2_left_mixer_controls[] = { -SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 7, 1, 0), -SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 6, 1, 0), -SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 5, 1, 0), -SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 4, 1, 0), -SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 3, 1, 0), -SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 2, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_dpga2_right_mixer_controls[] = { -SOC_DAPM_SINGLE("USNC Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 7, 1, 0), -SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 3, 1, 0), -SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 2, 1, 0), -SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 1, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_dpga3_left_mixer_controls[] = { -SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 7, 1, 0), -SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 6, 1, 0), -SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 5, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_dpga3_right_mixer_controls[] = { -SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 3, 1, 0), -SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 2, 1, 0), -SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 1, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_rx1_mixer_controls[] = { -SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 7, 1, 0), -SOC_DAPM_SINGLE("DL1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 6, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_rx2_mixer_controls[] = { -SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 5, 1, 0), -SOC_DAPM_SINGLE("DL2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 4, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_rx3_mixer_controls[] = { -SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 3, 1, 0), -SOC_DAPM_SINGLE("DL3 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 2, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_rx4_mixer_controls[] = { -SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 1, 1, 0), -SOC_DAPM_SINGLE("DL4 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 0, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_rx5_mixer_controls[] = { -SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 7, 1, 0), -SOC_DAPM_SINGLE("DL5 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 6, 1, 0), -}; - -static const struct snd_kcontrol_new isabelle_rx6_mixer_controls[] = { -SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 5, 1, 0), -SOC_DAPM_SINGLE("DL6 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 4, 1, 0), -}; - -static const struct snd_kcontrol_new ep_path_enable_control = - SOC_DAPM_SINGLE("Switch", ISABELLE_EARDRV_CFG2_REG, 0, 1, 0); - -/* TLV Declarations */ -static const DECLARE_TLV_DB_SCALE(mic_amp_tlv, 0, 100, 0); -static const DECLARE_TLV_DB_SCALE(afm_amp_tlv, -3300, 300, 0); -static const DECLARE_TLV_DB_SCALE(dac_tlv, -1200, 200, 0); -static const DECLARE_TLV_DB_SCALE(hf_tlv, -5000, 200, 0); - -/* from -63 to 0 dB in 1 dB steps */ -static const DECLARE_TLV_DB_SCALE(dpga_tlv, -6300, 100, 1); - -/* from -63 to 9 dB in 1 dB steps */ -static const DECLARE_TLV_DB_SCALE(rx_tlv, -6300, 100, 1); - -static const DECLARE_TLV_DB_SCALE(st_tlv, -2700, 300, 1); -static const DECLARE_TLV_DB_SCALE(tx_tlv, -600, 100, 0); - -static const struct snd_kcontrol_new isabelle_snd_controls[] = { - SOC_DOUBLE_TLV("Headset Playback Volume", ISABELLE_HSDRV_GAIN_REG, - 4, 0, 0xF, 0, dac_tlv), - SOC_DOUBLE_R_TLV("Handsfree Playback Volume", - ISABELLE_HFLPGA_CFG_REG, ISABELLE_HFRPGA_CFG_REG, - 0, 0x1F, 0, hf_tlv), - SOC_DOUBLE_TLV("Aux Playback Volume", ISABELLE_LINEAMP_GAIN_REG, - 4, 0, 0xF, 0, dac_tlv), - SOC_SINGLE_TLV("Earpiece Playback Volume", ISABELLE_EARDRV_CFG1_REG, - 0, 0xF, 0, dac_tlv), - - SOC_DOUBLE_TLV("Aux FM Volume", ISABELLE_APGA_GAIN_REG, 4, 0, 0xF, 0, - afm_amp_tlv), - SOC_SINGLE_TLV("Mic1 Capture Volume", ISABELLE_MIC1_GAIN_REG, 3, 0x1F, - 0, mic_amp_tlv), - SOC_SINGLE_TLV("Mic2 Capture Volume", ISABELLE_MIC2_GAIN_REG, 3, 0x1F, - 0, mic_amp_tlv), - - SOC_DOUBLE_R_TLV("DPGA1 Volume", ISABELLE_DPGA1L_GAIN_REG, - ISABELLE_DPGA1R_GAIN_REG, 0, 0x3F, 0, dpga_tlv), - SOC_DOUBLE_R_TLV("DPGA2 Volume", ISABELLE_DPGA2L_GAIN_REG, - ISABELLE_DPGA2R_GAIN_REG, 0, 0x3F, 0, dpga_tlv), - SOC_DOUBLE_R_TLV("DPGA3 Volume", ISABELLE_DPGA3L_GAIN_REG, - ISABELLE_DPGA3R_GAIN_REG, 0, 0x3F, 0, dpga_tlv), - - SOC_SINGLE_TLV("Sidetone Audio TX1 Volume", - ISABELLE_ATX_STPGA1_CFG_REG, 0, 0xF, 0, st_tlv), - SOC_SINGLE_TLV("Sidetone Audio TX2 Volume", - ISABELLE_ATX_STPGA2_CFG_REG, 0, 0xF, 0, st_tlv), - SOC_SINGLE_TLV("Sidetone Voice TX1 Volume", - ISABELLE_VTX_STPGA1_CFG_REG, 0, 0xF, 0, st_tlv), - SOC_SINGLE_TLV("Sidetone Voice TX2 Volume", - ISABELLE_VTX2_STPGA2_CFG_REG, 0, 0xF, 0, st_tlv), - - SOC_SINGLE_TLV("Audio TX1 Volume", ISABELLE_ATX1_DPGA_REG, 4, 0xF, 0, - tx_tlv), - SOC_SINGLE_TLV("Audio TX2 Volume", ISABELLE_ATX2_DPGA_REG, 4, 0xF, 0, - tx_tlv), - SOC_SINGLE_TLV("Voice TX1 Volume", ISABELLE_VTX1_DPGA_REG, 4, 0xF, 0, - tx_tlv), - SOC_SINGLE_TLV("Voice TX2 Volume", ISABELLE_VTX2_DPGA_REG, 4, 0xF, 0, - tx_tlv), - - SOC_SINGLE_TLV("RX1 DPGA Volume", ISABELLE_RX1_DPGA_REG, 0, 0x3F, 0, - rx_tlv), - SOC_SINGLE_TLV("RX2 DPGA Volume", ISABELLE_RX2_DPGA_REG, 0, 0x3F, 0, - rx_tlv), - SOC_SINGLE_TLV("RX3 DPGA Volume", ISABELLE_RX3_DPGA_REG, 0, 0x3F, 0, - rx_tlv), - SOC_SINGLE_TLV("RX4 DPGA Volume", ISABELLE_RX4_DPGA_REG, 0, 0x3F, 0, - rx_tlv), - SOC_SINGLE_TLV("RX5 DPGA Volume", ISABELLE_RX5_DPGA_REG, 0, 0x3F, 0, - rx_tlv), - SOC_SINGLE_TLV("RX6 DPGA Volume", ISABELLE_RX6_DPGA_REG, 0, 0x3F, 0, - rx_tlv), - - SOC_SINGLE("Headset Noise Gate", ISABELLE_HS_NG_CFG1_REG, 7, 1, 0), - SOC_SINGLE("Handsfree Noise Gate", ISABELLE_HF_NG_CFG1_REG, 7, 1, 0), - - SOC_SINGLE("ATX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, - 7, 1, 0), - SOC_SINGLE("ATX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, - 6, 1, 0), - SOC_SINGLE("ARX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, - 5, 1, 0), - SOC_SINGLE("ARX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, - 4, 1, 0), - SOC_SINGLE("ARX3 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, - 3, 1, 0), - SOC_SINGLE("ARX4 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, - 2, 1, 0), - SOC_SINGLE("ARX5 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, - 1, 1, 0), - SOC_SINGLE("ARX6 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, - 0, 1, 0), - SOC_SINGLE("VRX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, - 3, 1, 0), - SOC_SINGLE("VRX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, - 2, 1, 0), - - SOC_SINGLE("ATX1 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG, - 7, 1, 0), - SOC_SINGLE("ATX2 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG, - 6, 1, 0), - SOC_SINGLE("VTX1 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG, - 5, 1, 0), - SOC_SINGLE("VTX2 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG, - 4, 1, 0), - SOC_SINGLE("RX1 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG, - 5, 1, 0), - SOC_SINGLE("RX2 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG, - 4, 1, 0), - SOC_SINGLE("RX3 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG, - 3, 1, 0), - SOC_SINGLE("RX4 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG, - 2, 1, 0), - SOC_SINGLE("RX5 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG, - 1, 1, 0), - SOC_SINGLE("RX6 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG, - 0, 1, 0), - - SOC_SINGLE("ULATX12 Capture Switch", ISABELLE_ULATX12_INTF_CFG_REG, - 7, 1, 0), - - SOC_SINGLE("DL12 Playback Switch", ISABELLE_DL12_INTF_CFG_REG, - 7, 1, 0), - SOC_SINGLE("DL34 Playback Switch", ISABELLE_DL34_INTF_CFG_REG, - 7, 1, 0), - SOC_SINGLE("DL56 Playback Switch", ISABELLE_DL56_INTF_CFG_REG, - 7, 1, 0), - - /* DMIC Switch */ - SOC_SINGLE("DMIC Switch", ISABELLE_DMIC_CFG_REG, 0, 1, 0), -}; - -static const struct snd_soc_dapm_widget isabelle_dapm_widgets[] = { - /* Inputs */ - SND_SOC_DAPM_INPUT("MAINMIC"), - SND_SOC_DAPM_INPUT("HSMIC"), - SND_SOC_DAPM_INPUT("SUBMIC"), - SND_SOC_DAPM_INPUT("LINEIN1"), - SND_SOC_DAPM_INPUT("LINEIN2"), - SND_SOC_DAPM_INPUT("DMICDAT"), - - /* Outputs */ - SND_SOC_DAPM_OUTPUT("HSOL"), - SND_SOC_DAPM_OUTPUT("HSOR"), - SND_SOC_DAPM_OUTPUT("HFL"), - SND_SOC_DAPM_OUTPUT("HFR"), - SND_SOC_DAPM_OUTPUT("EP"), - SND_SOC_DAPM_OUTPUT("LINEOUT1"), - SND_SOC_DAPM_OUTPUT("LINEOUT2"), - - SND_SOC_DAPM_PGA("DL1", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("DL2", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("DL3", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("DL4", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("DL5", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("DL6", SND_SOC_NOPM, 0, 0, NULL, 0), - - /* Analog input muxes for the capture amplifiers */ - SND_SOC_DAPM_MUX("Analog Left Capture Route", - SND_SOC_NOPM, 0, 0, &amic1_control), - SND_SOC_DAPM_MUX("Analog Right Capture Route", - SND_SOC_NOPM, 0, 0, &amic2_control), - - SND_SOC_DAPM_MUX("Sidetone Audio Playback", SND_SOC_NOPM, 0, 0, - &st_audio_control), - SND_SOC_DAPM_MUX("Sidetone Voice Playback", SND_SOC_NOPM, 0, 0, - &st_voice_control), - - /* AIF */ - SND_SOC_DAPM_AIF_IN("INTF1_SDI", NULL, 0, ISABELLE_INTF_EN_REG, 7, 0), - SND_SOC_DAPM_AIF_IN("INTF2_SDI", NULL, 0, ISABELLE_INTF_EN_REG, 6, 0), - - SND_SOC_DAPM_AIF_OUT("INTF1_SDO", NULL, 0, ISABELLE_INTF_EN_REG, 5, 0), - SND_SOC_DAPM_AIF_OUT("INTF2_SDO", NULL, 0, ISABELLE_INTF_EN_REG, 4, 0), - - SND_SOC_DAPM_OUT_DRV("ULATX1", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("ULATX2", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("ULVTX1", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("ULVTX2", SND_SOC_NOPM, 0, 0, NULL, 0), - - /* Analog Capture PGAs */ - SND_SOC_DAPM_PGA("MicAmp1", ISABELLE_AMIC_CFG_REG, 5, 0, NULL, 0), - SND_SOC_DAPM_PGA("MicAmp2", ISABELLE_AMIC_CFG_REG, 4, 0, NULL, 0), - - /* Auxiliary FM PGAs */ - SND_SOC_DAPM_PGA("APGA1", ISABELLE_APGA_CFG_REG, 7, 0, NULL, 0), - SND_SOC_DAPM_PGA("APGA2", ISABELLE_APGA_CFG_REG, 6, 0, NULL, 0), - - /* ADCs */ - SND_SOC_DAPM_ADC("ADC1", "Left Front Capture", - ISABELLE_AMIC_CFG_REG, 7, 0), - SND_SOC_DAPM_ADC("ADC2", "Right Front Capture", - ISABELLE_AMIC_CFG_REG, 6, 0), - - /* Microphone Bias */ - SND_SOC_DAPM_SUPPLY("Headset Mic Bias", ISABELLE_ABIAS_CFG_REG, - 3, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("Main Mic Bias", ISABELLE_ABIAS_CFG_REG, - 2, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("Digital Mic1 Bias", - ISABELLE_DBIAS_CFG_REG, 3, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("Digital Mic2 Bias", - ISABELLE_DBIAS_CFG_REG, 2, 0, NULL, 0), - - /* Mixers */ - SND_SOC_DAPM_MIXER("Headset Left Mixer", SND_SOC_NOPM, 0, 0, - isabelle_hs_left_mixer_controls, - ARRAY_SIZE(isabelle_hs_left_mixer_controls)), - SND_SOC_DAPM_MIXER("Headset Right Mixer", SND_SOC_NOPM, 0, 0, - isabelle_hs_right_mixer_controls, - ARRAY_SIZE(isabelle_hs_right_mixer_controls)), - SND_SOC_DAPM_MIXER("Handsfree Left Mixer", SND_SOC_NOPM, 0, 0, - isabelle_hf_left_mixer_controls, - ARRAY_SIZE(isabelle_hf_left_mixer_controls)), - SND_SOC_DAPM_MIXER("Handsfree Right Mixer", SND_SOC_NOPM, 0, 0, - isabelle_hf_right_mixer_controls, - ARRAY_SIZE(isabelle_hf_right_mixer_controls)), - SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0, - isabelle_aux_left_mixer_controls, - ARRAY_SIZE(isabelle_aux_left_mixer_controls)), - SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0, - isabelle_aux_right_mixer_controls, - ARRAY_SIZE(isabelle_aux_right_mixer_controls)), - SND_SOC_DAPM_MIXER("Earphone Mixer", SND_SOC_NOPM, 0, 0, - isabelle_ep_mixer_controls, - ARRAY_SIZE(isabelle_ep_mixer_controls)), - - SND_SOC_DAPM_MIXER("DPGA1L Mixer", SND_SOC_NOPM, 0, 0, - isabelle_dpga1_left_mixer_controls, - ARRAY_SIZE(isabelle_dpga1_left_mixer_controls)), - SND_SOC_DAPM_MIXER("DPGA1R Mixer", SND_SOC_NOPM, 0, 0, - isabelle_dpga1_right_mixer_controls, - ARRAY_SIZE(isabelle_dpga1_right_mixer_controls)), - SND_SOC_DAPM_MIXER("DPGA2L Mixer", SND_SOC_NOPM, 0, 0, - isabelle_dpga2_left_mixer_controls, - ARRAY_SIZE(isabelle_dpga2_left_mixer_controls)), - SND_SOC_DAPM_MIXER("DPGA2R Mixer", SND_SOC_NOPM, 0, 0, - isabelle_dpga2_right_mixer_controls, - ARRAY_SIZE(isabelle_dpga2_right_mixer_controls)), - SND_SOC_DAPM_MIXER("DPGA3L Mixer", SND_SOC_NOPM, 0, 0, - isabelle_dpga3_left_mixer_controls, - ARRAY_SIZE(isabelle_dpga3_left_mixer_controls)), - SND_SOC_DAPM_MIXER("DPGA3R Mixer", SND_SOC_NOPM, 0, 0, - isabelle_dpga3_right_mixer_controls, - ARRAY_SIZE(isabelle_dpga3_right_mixer_controls)), - - SND_SOC_DAPM_MIXER("RX1 Mixer", SND_SOC_NOPM, 0, 0, - isabelle_rx1_mixer_controls, - ARRAY_SIZE(isabelle_rx1_mixer_controls)), - SND_SOC_DAPM_MIXER("RX2 Mixer", SND_SOC_NOPM, 0, 0, - isabelle_rx2_mixer_controls, - ARRAY_SIZE(isabelle_rx2_mixer_controls)), - SND_SOC_DAPM_MIXER("RX3 Mixer", SND_SOC_NOPM, 0, 0, - isabelle_rx3_mixer_controls, - ARRAY_SIZE(isabelle_rx3_mixer_controls)), - SND_SOC_DAPM_MIXER("RX4 Mixer", SND_SOC_NOPM, 0, 0, - isabelle_rx4_mixer_controls, - ARRAY_SIZE(isabelle_rx4_mixer_controls)), - SND_SOC_DAPM_MIXER("RX5 Mixer", SND_SOC_NOPM, 0, 0, - isabelle_rx5_mixer_controls, - ARRAY_SIZE(isabelle_rx5_mixer_controls)), - SND_SOC_DAPM_MIXER("RX6 Mixer", SND_SOC_NOPM, 0, 0, - isabelle_rx6_mixer_controls, - ARRAY_SIZE(isabelle_rx6_mixer_controls)), - - /* DACs */ - SND_SOC_DAPM_DAC("DAC1L", "Headset Playback", ISABELLE_DAC_CFG_REG, - 5, 0), - SND_SOC_DAPM_DAC("DAC1R", "Headset Playback", ISABELLE_DAC_CFG_REG, - 4, 0), - SND_SOC_DAPM_DAC("DAC2L", "Handsfree Playback", ISABELLE_DAC_CFG_REG, - 3, 0), - SND_SOC_DAPM_DAC("DAC2R", "Handsfree Playback", ISABELLE_DAC_CFG_REG, - 2, 0), - SND_SOC_DAPM_DAC("DAC3L", "Lineout Playback", ISABELLE_DAC_CFG_REG, - 1, 0), - SND_SOC_DAPM_DAC("DAC3R", "Lineout Playback", ISABELLE_DAC_CFG_REG, - 0, 0), - - /* Analog Playback PGAs */ - SND_SOC_DAPM_PGA("Sidetone Audio PGA", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("Sidetone Voice PGA", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("HF Left PGA", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("HF Right PGA", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("DPGA1L", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("DPGA1R", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("DPGA2L", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("DPGA2R", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("DPGA3L", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("DPGA3R", SND_SOC_NOPM, 0, 0, NULL, 0), - - /* Analog Playback Mux */ - SND_SOC_DAPM_MUX("RX1 Playback", ISABELLE_ALU_RX_EN_REG, 5, 0, - &rx1_mux_controls), - SND_SOC_DAPM_MUX("RX2 Playback", ISABELLE_ALU_RX_EN_REG, 4, 0, - &rx2_mux_controls), - - /* TX Select */ - SND_SOC_DAPM_MUX("ATX Select", ISABELLE_TX_INPUT_CFG_REG, - 7, 0, &atx_mux_controls), - SND_SOC_DAPM_MUX("VTX Select", ISABELLE_TX_INPUT_CFG_REG, - 6, 0, &vtx_mux_controls), - - SND_SOC_DAPM_SWITCH("Earphone Playback", SND_SOC_NOPM, 0, 0, - &ep_path_enable_control), - - /* Output Drivers */ - SND_SOC_DAPM_OUT_DRV("HS Left Driver", ISABELLE_HSDRV_CFG2_REG, - 1, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("HS Right Driver", ISABELLE_HSDRV_CFG2_REG, - 0, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("LINEOUT1 Left Driver", ISABELLE_LINEAMP_CFG_REG, - 1, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("LINEOUT2 Right Driver", ISABELLE_LINEAMP_CFG_REG, - 0, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("Earphone Driver", ISABELLE_EARDRV_CFG2_REG, - 1, 0, NULL, 0), - - SND_SOC_DAPM_OUT_DRV("HF Left Driver", ISABELLE_HFDRV_CFG_REG, - 1, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("HF Right Driver", ISABELLE_HFDRV_CFG_REG, - 0, 0, NULL, 0), -}; - -static const struct snd_soc_dapm_route isabelle_intercon[] = { - /* Interface mapping */ - { "DL1", "DL12 Playback Switch", "INTF1_SDI" }, - { "DL2", "DL12 Playback Switch", "INTF1_SDI" }, - { "DL3", "DL34 Playback Switch", "INTF1_SDI" }, - { "DL4", "DL34 Playback Switch", "INTF1_SDI" }, - { "DL5", "DL56 Playback Switch", "INTF1_SDI" }, - { "DL6", "DL56 Playback Switch", "INTF1_SDI" }, - - { "DL1", "DL12 Playback Switch", "INTF2_SDI" }, - { "DL2", "DL12 Playback Switch", "INTF2_SDI" }, - { "DL3", "DL34 Playback Switch", "INTF2_SDI" }, - { "DL4", "DL34 Playback Switch", "INTF2_SDI" }, - { "DL5", "DL56 Playback Switch", "INTF2_SDI" }, - { "DL6", "DL56 Playback Switch", "INTF2_SDI" }, - - /* Input side mapping */ - { "Sidetone Audio PGA", NULL, "Sidetone Audio Playback" }, - { "Sidetone Voice PGA", NULL, "Sidetone Voice Playback" }, - - { "RX1 Mixer", "ST1 Playback Switch", "Sidetone Audio PGA" }, - - { "RX1 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" }, - { "RX1 Mixer", "DL1 Playback Switch", "DL1" }, - - { "RX2 Mixer", "ST2 Playback Switch", "Sidetone Audio PGA" }, - - { "RX2 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" }, - { "RX2 Mixer", "DL2 Playback Switch", "DL2" }, - - { "RX3 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" }, - { "RX3 Mixer", "DL3 Playback Switch", "DL3" }, - - { "RX4 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" }, - { "RX4 Mixer", "DL4 Playback Switch", "DL4" }, - - { "RX5 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" }, - { "RX5 Mixer", "DL5 Playback Switch", "DL5" }, - - { "RX6 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" }, - { "RX6 Mixer", "DL6 Playback Switch", "DL6" }, - - /* Capture path */ - { "Analog Left Capture Route", "Headset Mic", "HSMIC" }, - { "Analog Left Capture Route", "Main Mic", "MAINMIC" }, - { "Analog Left Capture Route", "Aux/FM Left", "LINEIN1" }, - - { "Analog Right Capture Route", "Sub Mic", "SUBMIC" }, - { "Analog Right Capture Route", "Aux/FM Right", "LINEIN2" }, - - { "MicAmp1", NULL, "Analog Left Capture Route" }, - { "MicAmp2", NULL, "Analog Right Capture Route" }, - - { "ADC1", NULL, "MicAmp1" }, - { "ADC2", NULL, "MicAmp2" }, - - { "ATX Select", "AMIC1", "ADC1" }, - { "ATX Select", "DMIC", "DMICDAT" }, - { "ATX Select", "AMIC2", "ADC2" }, - - { "VTX Select", "AMIC1", "ADC1" }, - { "VTX Select", "DMIC", "DMICDAT" }, - { "VTX Select", "AMIC2", "ADC2" }, - - { "ULATX1", "ATX1 Filter Enable Switch", "ATX Select" }, - { "ULATX1", "ATX1 Filter Bypass Switch", "ATX Select" }, - { "ULATX2", "ATX2 Filter Enable Switch", "ATX Select" }, - { "ULATX2", "ATX2 Filter Bypass Switch", "ATX Select" }, - - { "ULVTX1", "VTX1 Filter Enable Switch", "VTX Select" }, - { "ULVTX1", "VTX1 Filter Bypass Switch", "VTX Select" }, - { "ULVTX2", "VTX2 Filter Enable Switch", "VTX Select" }, - { "ULVTX2", "VTX2 Filter Bypass Switch", "VTX Select" }, - - { "INTF1_SDO", "ULATX12 Capture Switch", "ULATX1" }, - { "INTF1_SDO", "ULATX12 Capture Switch", "ULATX2" }, - { "INTF2_SDO", "ULATX12 Capture Switch", "ULATX1" }, - { "INTF2_SDO", "ULATX12 Capture Switch", "ULATX2" }, - - { "INTF1_SDO", NULL, "ULVTX1" }, - { "INTF1_SDO", NULL, "ULVTX2" }, - { "INTF2_SDO", NULL, "ULVTX1" }, - { "INTF2_SDO", NULL, "ULVTX2" }, - - /* AFM Path */ - { "APGA1", NULL, "LINEIN1" }, - { "APGA2", NULL, "LINEIN2" }, - - { "RX1 Playback", "VRX1 Filter Bypass Switch", "RX1 Mixer" }, - { "RX1 Playback", "ARX1 Filter Bypass Switch", "RX1 Mixer" }, - { "RX1 Playback", "RX1 Filter Enable Switch", "RX1 Mixer" }, - - { "RX2 Playback", "VRX2 Filter Bypass Switch", "RX2 Mixer" }, - { "RX2 Playback", "ARX2 Filter Bypass Switch", "RX2 Mixer" }, - { "RX2 Playback", "RX2 Filter Enable Switch", "RX2 Mixer" }, - - { "RX3 Playback", "ARX3 Filter Bypass Switch", "RX3 Mixer" }, - { "RX3 Playback", "RX3 Filter Enable Switch", "RX3 Mixer" }, - - { "RX4 Playback", "ARX4 Filter Bypass Switch", "RX4 Mixer" }, - { "RX4 Playback", "RX4 Filter Enable Switch", "RX4 Mixer" }, - - { "RX5 Playback", "ARX5 Filter Bypass Switch", "RX5 Mixer" }, - { "RX5 Playback", "RX5 Filter Enable Switch", "RX5 Mixer" }, - - { "RX6 Playback", "ARX6 Filter Bypass Switch", "RX6 Mixer" }, - { "RX6 Playback", "RX6 Filter Enable Switch", "RX6 Mixer" }, - - { "DPGA1L Mixer", "RX1 Playback Switch", "RX1 Playback" }, - { "DPGA1L Mixer", "RX3 Playback Switch", "RX3 Playback" }, - { "DPGA1L Mixer", "RX5 Playback Switch", "RX5 Playback" }, - - { "DPGA1R Mixer", "RX2 Playback Switch", "RX2 Playback" }, - { "DPGA1R Mixer", "RX4 Playback Switch", "RX4 Playback" }, - { "DPGA1R Mixer", "RX6 Playback Switch", "RX6 Playback" }, - - { "DPGA1L", NULL, "DPGA1L Mixer" }, - { "DPGA1R", NULL, "DPGA1R Mixer" }, - - { "DAC1L", NULL, "DPGA1L" }, - { "DAC1R", NULL, "DPGA1R" }, - - { "DPGA2L Mixer", "RX1 Playback Switch", "RX1 Playback" }, - { "DPGA2L Mixer", "RX2 Playback Switch", "RX2 Playback" }, - { "DPGA2L Mixer", "RX3 Playback Switch", "RX3 Playback" }, - { "DPGA2L Mixer", "RX4 Playback Switch", "RX4 Playback" }, - { "DPGA2L Mixer", "RX5 Playback Switch", "RX5 Playback" }, - { "DPGA2L Mixer", "RX6 Playback Switch", "RX6 Playback" }, - - { "DPGA2R Mixer", "RX2 Playback Switch", "RX2 Playback" }, - { "DPGA2R Mixer", "RX4 Playback Switch", "RX4 Playback" }, - { "DPGA2R Mixer", "RX6 Playback Switch", "RX6 Playback" }, - - { "DPGA2L", NULL, "DPGA2L Mixer" }, - { "DPGA2R", NULL, "DPGA2R Mixer" }, - - { "DAC2L", NULL, "DPGA2L" }, - { "DAC2R", NULL, "DPGA2R" }, - - { "DPGA3L Mixer", "RX1 Playback Switch", "RX1 Playback" }, - { "DPGA3L Mixer", "RX3 Playback Switch", "RX3 Playback" }, - { "DPGA3L Mixer", "RX5 Playback Switch", "RX5 Playback" }, - - { "DPGA3R Mixer", "RX2 Playback Switch", "RX2 Playback" }, - { "DPGA3R Mixer", "RX4 Playback Switch", "RX4 Playback" }, - { "DPGA3R Mixer", "RX6 Playback Switch", "RX6 Playback" }, - - { "DPGA3L", NULL, "DPGA3L Mixer" }, - { "DPGA3R", NULL, "DPGA3R Mixer" }, - - { "DAC3L", NULL, "DPGA3L" }, - { "DAC3R", NULL, "DPGA3R" }, - - { "Headset Left Mixer", "DAC1L Playback Switch", "DAC1L" }, - { "Headset Left Mixer", "APGA1 Playback Switch", "APGA1" }, - - { "Headset Right Mixer", "DAC1R Playback Switch", "DAC1R" }, - { "Headset Right Mixer", "APGA2 Playback Switch", "APGA2" }, - - { "HS Left Driver", NULL, "Headset Left Mixer" }, - { "HS Right Driver", NULL, "Headset Right Mixer" }, - - { "HSOL", NULL, "HS Left Driver" }, - { "HSOR", NULL, "HS Right Driver" }, - - /* Earphone playback path */ - { "Earphone Mixer", "DAC2L Playback Switch", "DAC2L" }, - { "Earphone Mixer", "APGA1 Playback Switch", "APGA1" }, - - { "Earphone Playback", "Switch", "Earphone Mixer" }, - { "Earphone Driver", NULL, "Earphone Playback" }, - { "EP", NULL, "Earphone Driver" }, - - { "Handsfree Left Mixer", "DAC2L Playback Switch", "DAC2L" }, - { "Handsfree Left Mixer", "APGA1 Playback Switch", "APGA1" }, - - { "Handsfree Right Mixer", "DAC2R Playback Switch", "DAC2R" }, - { "Handsfree Right Mixer", "APGA2 Playback Switch", "APGA2" }, - - { "HF Left PGA", NULL, "Handsfree Left Mixer" }, - { "HF Right PGA", NULL, "Handsfree Right Mixer" }, - - { "HF Left Driver", NULL, "HF Left PGA" }, - { "HF Right Driver", NULL, "HF Right PGA" }, - - { "HFL", NULL, "HF Left Driver" }, - { "HFR", NULL, "HF Right Driver" }, - - { "LINEOUT1 Mixer", "DAC3L Playback Switch", "DAC3L" }, - { "LINEOUT1 Mixer", "APGA1 Playback Switch", "APGA1" }, - - { "LINEOUT2 Mixer", "DAC3R Playback Switch", "DAC3R" }, - { "LINEOUT2 Mixer", "APGA2 Playback Switch", "APGA2" }, - - { "LINEOUT1 Driver", NULL, "LINEOUT1 Mixer" }, - { "LINEOUT2 Driver", NULL, "LINEOUT2 Mixer" }, - - { "LINEOUT1", NULL, "LINEOUT1 Driver" }, - { "LINEOUT2", NULL, "LINEOUT2 Driver" }, -}; - -static int isabelle_hs_mute(struct snd_soc_dai *dai, int mute) -{ - snd_soc_update_bits(dai->codec, ISABELLE_DAC1_SOFTRAMP_REG, - BIT(4), (mute ? BIT(4) : 0)); - - return 0; -} - -static int isabelle_hf_mute(struct snd_soc_dai *dai, int mute) -{ - snd_soc_update_bits(dai->codec, ISABELLE_DAC2_SOFTRAMP_REG, - BIT(4), (mute ? BIT(4) : 0)); - - return 0; -} - -static int isabelle_line_mute(struct snd_soc_dai *dai, int mute) -{ - snd_soc_update_bits(dai->codec, ISABELLE_DAC3_SOFTRAMP_REG, - BIT(4), (mute ? BIT(4) : 0)); - - return 0; -} - -static int isabelle_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - switch (level) { - case SND_SOC_BIAS_ON: - break; - case SND_SOC_BIAS_PREPARE: - break; - - case SND_SOC_BIAS_STANDBY: - snd_soc_update_bits(codec, ISABELLE_PWR_EN_REG, - ISABELLE_CHIP_EN, BIT(0)); - break; - - case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, ISABELLE_PWR_EN_REG, - ISABELLE_CHIP_EN, 0); - break; - } - - codec->dapm.bias_level = level; - - return 0; -} - -static int isabelle_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 aif = 0; - unsigned int fs_val = 0; - - switch (params_rate(params)) { - case 8000: - fs_val = ISABELLE_FS_RATE_8; - break; - case 11025: - fs_val = ISABELLE_FS_RATE_11; - break; - case 12000: - fs_val = ISABELLE_FS_RATE_12; - break; - case 16000: - fs_val = ISABELLE_FS_RATE_16; - break; - case 22050: - fs_val = ISABELLE_FS_RATE_22; - break; - case 24000: - fs_val = ISABELLE_FS_RATE_24; - break; - case 32000: - fs_val = ISABELLE_FS_RATE_32; - break; - case 44100: - fs_val = ISABELLE_FS_RATE_44; - break; - case 48000: - fs_val = ISABELLE_FS_RATE_48; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, ISABELLE_FS_RATE_CFG_REG, - ISABELLE_FS_RATE_MASK, fs_val); - - /* bit size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S20_3LE: - aif |= ISABELLE_AIF_LENGTH_20; - break; - case SNDRV_PCM_FORMAT_S32_LE: - aif |= ISABELLE_AIF_LENGTH_32; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, ISABELLE_INTF_CFG_REG, - ISABELLE_AIF_LENGTH_MASK, aif); - - return 0; -} - -static int isabelle_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - unsigned int aif_val = 0; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - aif_val &= ~ISABELLE_AIF_MS; - break; - case SND_SOC_DAIFMT_CBM_CFM: - aif_val |= ISABELLE_AIF_MS; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - aif_val |= ISABELLE_I2S_MODE; - break; - case SND_SOC_DAIFMT_LEFT_J: - aif_val |= ISABELLE_LEFT_J_MODE; - break; - case SND_SOC_DAIFMT_PDM: - aif_val |= ISABELLE_PDM_MODE; - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, ISABELLE_INTF_CFG_REG, - (ISABELLE_AIF_MS | ISABELLE_AIF_FMT_MASK), aif_val); - - return 0; -} - -/* Rates supported by Isabelle driver */ -#define ISABELLE_RATES SNDRV_PCM_RATE_8000_48000 - -/* Formates supported by Isabelle driver. */ -#define ISABELLE_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S32_LE) - -static struct snd_soc_dai_ops isabelle_hs_dai_ops = { - .hw_params = isabelle_hw_params, - .set_fmt = isabelle_set_dai_fmt, - .digital_mute = isabelle_hs_mute, -}; - -static struct snd_soc_dai_ops isabelle_hf_dai_ops = { - .hw_params = isabelle_hw_params, - .set_fmt = isabelle_set_dai_fmt, - .digital_mute = isabelle_hf_mute, -}; - -static struct snd_soc_dai_ops isabelle_line_dai_ops = { - .hw_params = isabelle_hw_params, - .set_fmt = isabelle_set_dai_fmt, - .digital_mute = isabelle_line_mute, -}; - -static struct snd_soc_dai_ops isabelle_ul_dai_ops = { - .hw_params = isabelle_hw_params, - .set_fmt = isabelle_set_dai_fmt, -}; - -/* ISABELLE dai structure */ -struct snd_soc_dai_driver isabelle_dai[] = { - { - .name = "isabelle-dl1", - .playback = { - .stream_name = "Headset Playback", - .channels_min = 1, - .channels_max = 2, - .rates = ISABELLE_RATES, - .formats = ISABELLE_FORMATS, - }, - .ops = &isabelle_hs_dai_ops, - }, - { - .name = "isabelle-dl2", - .playback = { - .stream_name = "Handsfree Playback", - .channels_min = 1, - .channels_max = 2, - .rates = ISABELLE_RATES, - .formats = ISABELLE_FORMATS, - }, - .ops = &isabelle_hf_dai_ops, - }, - { - .name = "isabelle-lineout", - .playback = { - .stream_name = "Lineout Playback", - .channels_min = 1, - .channels_max = 2, - .rates = ISABELLE_RATES, - .formats = ISABELLE_FORMATS, - }, - .ops = &isabelle_line_dai_ops, - }, - { - .name = "isabelle-ul", - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = ISABELLE_RATES, - .formats = ISABELLE_FORMATS, - }, - .ops = &isabelle_ul_dai_ops, - }, -}; - -static int isabelle_probe(struct snd_soc_codec *codec) -{ - int ret = 0; - - codec->control_data = dev_get_regmap(codec->dev, NULL); - - 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; -} - -static struct snd_soc_codec_driver soc_codec_dev_isabelle = { - .probe = isabelle_probe, - .set_bias_level = isabelle_set_bias_level, - .controls = isabelle_snd_controls, - .num_controls = ARRAY_SIZE(isabelle_snd_controls), - .dapm_widgets = isabelle_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(isabelle_dapm_widgets), - .dapm_routes = isabelle_intercon, - .num_dapm_routes = ARRAY_SIZE(isabelle_intercon), - .idle_bias_off = true, -}; - -static const struct regmap_config isabelle_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = ISABELLE_MAX_REGISTER, - .reg_defaults = isabelle_reg_defs, - .num_reg_defaults = ARRAY_SIZE(isabelle_reg_defs), - .cache_type = REGCACHE_RBTREE, -}; - -static int __devinit isabelle_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct regmap *isabelle_regmap; - int ret = 0; - - isabelle_regmap = devm_regmap_init_i2c(i2c, &isabelle_regmap_config); - if (IS_ERR(isabelle_regmap)) { - ret = PTR_ERR(isabelle_regmap); - dev_err(&i2c->dev, "Failed to allocate register map: %d\n", - ret); - return ret; - } - i2c_set_clientdata(i2c, isabelle_regmap); - - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_isabelle, isabelle_dai, - ARRAY_SIZE(isabelle_dai)); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); - return ret; - } - - return ret; -} - -static int __devexit isabelle_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - return 0; -} - -static const struct i2c_device_id isabelle_i2c_id[] = { - { "isabelle", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, isabelle_i2c_id); - -static struct i2c_driver isabelle_i2c_driver = { - .driver = { - .name = "isabelle", - .owner = THIS_MODULE, - }, - .probe = isabelle_i2c_probe, - .remove = __devexit_p(isabelle_i2c_remove), - .id_table = isabelle_i2c_id, -}; - -module_i2c_driver(isabelle_i2c_driver); - -MODULE_DESCRIPTION("ASoC ISABELLE driver"); -MODULE_AUTHOR("Vishwas A Deshpande "); -MODULE_AUTHOR("M R Swami Reddy "); -MODULE_LICENSE("GPL v2"); diff --git a/trunk/sound/soc/codecs/isabelle.h b/trunk/sound/soc/codecs/isabelle.h deleted file mode 100644 index 96d839a8c956..000000000000 --- a/trunk/sound/soc/codecs/isabelle.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * isabelle.h - Low power high fidelity audio codec driver header file - * - * 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 _ISABELLE_H -#define _ISABELLE_H - -#include - -/* ISABELLE REGISTERS */ - -#define ISABELLE_PWR_CFG_REG 0x01 -#define ISABELLE_PWR_EN_REG 0x02 -#define ISABELLE_PS_EN1_REG 0x03 -#define ISABELLE_INT1_STATUS_REG 0x04 -#define ISABELLE_INT1_MASK_REG 0x05 -#define ISABELLE_INT2_STATUS_REG 0x06 -#define ISABELLE_INT2_MASK_REG 0x07 -#define ISABELLE_HKCTL1_REG 0x08 -#define ISABELLE_HKCTL2_REG 0x09 -#define ISABELLE_HKCTL3_REG 0x0A -#define ISABELLE_ACCDET_STATUS_REG 0x0B -#define ISABELLE_BUTTON_ID_REG 0x0C -#define ISABELLE_PLL_CFG_REG 0x10 -#define ISABELLE_PLL_EN_REG 0x11 -#define ISABELLE_FS_RATE_CFG_REG 0x12 -#define ISABELLE_INTF_CFG_REG 0x13 -#define ISABELLE_INTF_EN_REG 0x14 -#define ISABELLE_ULATX12_INTF_CFG_REG 0x15 -#define ISABELLE_DL12_INTF_CFG_REG 0x16 -#define ISABELLE_DL34_INTF_CFG_REG 0x17 -#define ISABELLE_DL56_INTF_CFG_REG 0x18 -#define ISABELLE_ATX_STPGA1_CFG_REG 0x19 -#define ISABELLE_ATX_STPGA2_CFG_REG 0x1A -#define ISABELLE_VTX_STPGA1_CFG_REG 0x1B -#define ISABELLE_VTX2_STPGA2_CFG_REG 0x1C -#define ISABELLE_ATX1_DPGA_REG 0x1D -#define ISABELLE_ATX2_DPGA_REG 0x1E -#define ISABELLE_VTX1_DPGA_REG 0x1F -#define ISABELLE_VTX2_DPGA_REG 0x20 -#define ISABELLE_TX_INPUT_CFG_REG 0x21 -#define ISABELLE_RX_INPUT_CFG_REG 0x22 -#define ISABELLE_RX_INPUT_CFG2_REG 0x23 -#define ISABELLE_VOICE_HPF_CFG_REG 0x24 -#define ISABELLE_AUDIO_HPF_CFG_REG 0x25 -#define ISABELLE_RX1_DPGA_REG 0x26 -#define ISABELLE_RX2_DPGA_REG 0x27 -#define ISABELLE_RX3_DPGA_REG 0x28 -#define ISABELLE_RX4_DPGA_REG 0x29 -#define ISABELLE_RX5_DPGA_REG 0x2A -#define ISABELLE_RX6_DPGA_REG 0x2B -#define ISABELLE_ALU_TX_EN_REG 0x2C -#define ISABELLE_ALU_RX_EN_REG 0x2D -#define ISABELLE_IIR_RESYNC_REG 0x2E -#define ISABELLE_ABIAS_CFG_REG 0x30 -#define ISABELLE_DBIAS_CFG_REG 0x31 -#define ISABELLE_MIC1_GAIN_REG 0x32 -#define ISABELLE_MIC2_GAIN_REG 0x33 -#define ISABELLE_AMIC_CFG_REG 0x34 -#define ISABELLE_DMIC_CFG_REG 0x35 -#define ISABELLE_APGA_GAIN_REG 0x36 -#define ISABELLE_APGA_CFG_REG 0x37 -#define ISABELLE_TX_GAIN_DLY_REG 0x38 -#define ISABELLE_RX_GAIN_DLY_REG 0x39 -#define ISABELLE_RX_PWR_CTRL_REG 0x3A -#define ISABELLE_DPGA1LR_IN_SEL_REG 0x3B -#define ISABELLE_DPGA1L_GAIN_REG 0x3C -#define ISABELLE_DPGA1R_GAIN_REG 0x3D -#define ISABELLE_DPGA2L_IN_SEL_REG 0x3E -#define ISABELLE_DPGA2R_IN_SEL_REG 0x3F -#define ISABELLE_DPGA2L_GAIN_REG 0x40 -#define ISABELLE_DPGA2R_GAIN_REG 0x41 -#define ISABELLE_DPGA3LR_IN_SEL_REG 0x42 -#define ISABELLE_DPGA3L_GAIN_REG 0x43 -#define ISABELLE_DPGA3R_GAIN_REG 0x44 -#define ISABELLE_DAC1_SOFTRAMP_REG 0x45 -#define ISABELLE_DAC2_SOFTRAMP_REG 0x46 -#define ISABELLE_DAC3_SOFTRAMP_REG 0x47 -#define ISABELLE_DAC_CFG_REG 0x48 -#define ISABELLE_EARDRV_CFG1_REG 0x49 -#define ISABELLE_EARDRV_CFG2_REG 0x4A -#define ISABELLE_HSDRV_GAIN_REG 0x4B -#define ISABELLE_HSDRV_CFG1_REG 0x4C -#define ISABELLE_HSDRV_CFG2_REG 0x4D -#define ISABELLE_HS_NG_CFG1_REG 0x4E -#define ISABELLE_HS_NG_CFG2_REG 0x4F -#define ISABELLE_LINEAMP_GAIN_REG 0x50 -#define ISABELLE_LINEAMP_CFG_REG 0x51 -#define ISABELLE_HFL_VOL_CTRL_REG 0x52 -#define ISABELLE_HFL_SFTVOL_CTRL_REG 0x53 -#define ISABELLE_HFL_LIM_CTRL_1_REG 0x54 -#define ISABELLE_HFL_LIM_CTRL_2_REG 0x55 -#define ISABELLE_HFR_VOL_CTRL_REG 0x56 -#define ISABELLE_HFR_SFTVOL_CTRL_REG 0x57 -#define ISABELLE_HFR_LIM_CTRL_1_REG 0x58 -#define ISABELLE_HFR_LIM_CTRL_2_REG 0x59 -#define ISABELLE_HF_MODE_REG 0x5A -#define ISABELLE_HFLPGA_CFG_REG 0x5B -#define ISABELLE_HFRPGA_CFG_REG 0x5C -#define ISABELLE_HFDRV_CFG_REG 0x5D -#define ISABELLE_PDMOUT_CFG1_REG 0x5E -#define ISABELLE_PDMOUT_CFG2_REG 0x5F -#define ISABELLE_PDMOUT_L_WM_REG 0x60 -#define ISABELLE_PDMOUT_R_WM_REG 0x61 -#define ISABELLE_HF_NG_CFG1_REG 0x62 -#define ISABELLE_HF_NG_CFG2_REG 0x63 - -/* ISABELLE_PWR_EN_REG (0x02h) */ -#define ISABELLE_CHIP_EN BIT(0) - -/* ISABELLE DAI FORMATS */ -#define ISABELLE_AIF_FMT_MASK 0x70 -#define ISABELLE_I2S_MODE 0x0 -#define ISABELLE_LEFT_J_MODE 0x1 -#define ISABELLE_PDM_MODE 0x2 - -#define ISABELLE_AIF_LENGTH_MASK 0x30 -#define ISABELLE_AIF_LENGTH_20 0x00 -#define ISABELLE_AIF_LENGTH_32 0x10 - -#define ISABELLE_AIF_MS 0x80 - -#define ISABELLE_FS_RATE_MASK 0xF -#define ISABELLE_FS_RATE_8 0x0 -#define ISABELLE_FS_RATE_11 0x1 -#define ISABELLE_FS_RATE_12 0x2 -#define ISABELLE_FS_RATE_16 0x4 -#define ISABELLE_FS_RATE_22 0x5 -#define ISABELLE_FS_RATE_24 0x6 -#define ISABELLE_FS_RATE_32 0x8 -#define ISABELLE_FS_RATE_44 0x9 -#define ISABELLE_FS_RATE_48 0xA - -#define ISABELLE_MAX_REGISTER 0xFF - -#endif diff --git a/trunk/sound/soc/codecs/lm49453.c b/trunk/sound/soc/codecs/lm49453.c index 99b0a9dcff34..802b9f176b16 100644 --- a/trunk/sound/soc/codecs/lm49453.c +++ b/trunk/sound/soc/codecs/lm49453.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -1357,7 +1358,7 @@ static struct snd_soc_dai_ops lm49453_lineout_dai_ops = { }; /* LM49453 dai structure. */ -static struct snd_soc_dai_driver lm49453_dai[] = { +static const struct snd_soc_dai_driver lm49453_dai[] = { { .name = "LM49453 Headset", .playback = { diff --git a/trunk/sound/soc/codecs/max98095.c b/trunk/sound/soc/codecs/max98095.c index 7cd508e16a5c..35179e2c23c9 100644 --- a/trunk/sound/soc/codecs/max98095.c +++ b/trunk/sound/soc/codecs/max98095.c @@ -2216,7 +2216,7 @@ static irqreturn_t max98095_report_jack(int irq, void *data) return IRQ_HANDLED; } -static int max98095_jack_detect_enable(struct snd_soc_codec *codec) +int max98095_jack_detect_enable(struct snd_soc_codec *codec) { struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); int ret = 0; @@ -2245,7 +2245,7 @@ static int max98095_jack_detect_enable(struct snd_soc_codec *codec) return ret; } -static int max98095_jack_detect_disable(struct snd_soc_codec *codec) +int max98095_jack_detect_disable(struct snd_soc_codec *codec) { int ret = 0; @@ -2286,7 +2286,6 @@ int max98095_jack_detect(struct snd_soc_codec *codec, max98095_report_jack(client->irq, codec); return 0; } -EXPORT_SYMBOL_GPL(max98095_jack_detect); #ifdef CONFIG_PM static int max98095_suspend(struct snd_soc_codec *codec) diff --git a/trunk/sound/soc/codecs/tlv320aic3x.c b/trunk/sound/soc/codecs/tlv320aic3x.c index 58ef59dfbae9..64d2a4fa34b2 100644 --- a/trunk/sound/soc/codecs/tlv320aic3x.c +++ b/trunk/sound/soc/codecs/tlv320aic3x.c @@ -368,7 +368,7 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0); static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl = - SOC_DOUBLE_TLV("Class-D Playback Volume", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv); + SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv); /* Left DAC Mux */ static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = diff --git a/trunk/sound/soc/codecs/wm2000.c b/trunk/sound/soc/codecs/wm2000.c index 78a148f0a8ef..a75c3766aede 100644 --- a/trunk/sound/soc/codecs/wm2000.c +++ b/trunk/sound/soc/codecs/wm2000.c @@ -1,7 +1,7 @@ /* * wm2000.c -- WM2000 ALSA Soc Audio driver * - * Copyright 2008-2011 Wolfson Microelectronics PLC. + * Copyright 2008-2010 Wolfson Microelectronics PLC. * * Author: Mark Brown * @@ -691,39 +691,9 @@ static int wm2000_resume(struct snd_soc_codec *codec) #define wm2000_resume NULL #endif -static bool wm2000_readable_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case WM2000_REG_SYS_START: - case WM2000_REG_SPEECH_CLARITY: - case WM2000_REG_SYS_WATCHDOG: - case WM2000_REG_ANA_VMID_PD_TIME: - case WM2000_REG_ANA_VMID_PU_TIME: - case WM2000_REG_CAT_FLTR_INDX: - case WM2000_REG_CAT_GAIN_0: - case WM2000_REG_SYS_STATUS: - case WM2000_REG_SYS_MODE_CNTRL: - case WM2000_REG_SYS_START0: - case WM2000_REG_SYS_START1: - case WM2000_REG_ID1: - case WM2000_REG_ID2: - case WM2000_REG_REVISON: - case WM2000_REG_SYS_CTL1: - case WM2000_REG_SYS_CTL2: - case WM2000_REG_ANC_STAT: - case WM2000_REG_IF_CTL: - return true; - default: - return false; - } -} - static const struct regmap_config wm2000_regmap = { .reg_bits = 8, .val_bits = 8, - - .max_register = WM2000_REG_IF_CTL, - .readable_reg = wm2000_readable_reg, }; static int wm2000_probe(struct snd_soc_codec *codec) diff --git a/trunk/sound/soc/codecs/wm5100-tables.c b/trunk/sound/soc/codecs/wm5100-tables.c index e239f4bf2460..e167207a19cc 100644 --- a/trunk/sound/soc/codecs/wm5100-tables.c +++ b/trunk/sound/soc/codecs/wm5100-tables.c @@ -1,7 +1,7 @@ /* * wm5100-tables.c -- WM5100 ALSA SoC Audio driver data * - * Copyright 2011-2 Wolfson Microelectronics plc + * Copyright 2011 Wolfson Microelectronics plc * * Author: Mark Brown * diff --git a/trunk/sound/soc/codecs/wm5100.c b/trunk/sound/soc/codecs/wm5100.c index 3823af362912..cb6d5372103a 100644 --- a/trunk/sound/soc/codecs/wm5100.c +++ b/trunk/sound/soc/codecs/wm5100.c @@ -1,7 +1,7 @@ /* * wm5100.c -- WM5100 ALSA SoC Audio driver * - * Copyright 2011-2 Wolfson Microelectronics plc + * Copyright 2011 Wolfson Microelectronics plc * * Author: Mark Brown * diff --git a/trunk/sound/soc/codecs/wm8350.c b/trunk/sound/soc/codecs/wm8350.c index d26c8ae4e6d9..555ee146ae0d 100644 --- a/trunk/sound/soc/codecs/wm8350.c +++ b/trunk/sound/soc/codecs/wm8350.c @@ -1,7 +1,7 @@ /* * wm8350.c -- WM8350 ALSA SoC audio driver * - * Copyright (C) 2007-12 Wolfson Microelectronics PLC. + * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC. * * Author: Liam Girdwood * @@ -71,6 +71,20 @@ struct wm8350_data { int fll_freq_in; }; +static unsigned int wm8350_codec_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + struct wm8350 *wm8350 = codec->control_data; + return wm8350_reg_read(wm8350, reg); +} + +static int wm8350_codec_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + struct wm8350 *wm8350 = codec->control_data; + return wm8350_reg_write(wm8350, reg, value); +} + /* * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown. */ @@ -1505,9 +1519,7 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) if (ret != 0) return ret; - codec->control_data = wm8350->regmap; - - snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); + codec->control_data = wm8350; /* Put the codec into reset if it wasn't already */ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); @@ -1617,6 +1629,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8350 = { .remove = wm8350_codec_remove, .suspend = wm8350_suspend, .resume = wm8350_resume, + .read = wm8350_codec_read, + .write = wm8350_codec_write, .set_bias_level = wm8350_set_bias_level, .controls = wm8350_snd_controls, diff --git a/trunk/sound/soc/codecs/wm8400.c b/trunk/sound/soc/codecs/wm8400.c index 5d277a915f81..5dc31ebcd0e7 100644 --- a/trunk/sound/soc/codecs/wm8400.c +++ b/trunk/sound/soc/codecs/wm8400.c @@ -1,7 +1,7 @@ /* * wm8400.c -- WM8400 ALSA Soc Audio driver * - * Copyright 2008-11 Wolfson Microelectronics PLC. + * Copyright 2008, 2009 Wolfson Microelectronics PLC. * Author: Mark Brown * * This program is free software; you can redistribute it and/or modify it diff --git a/trunk/sound/soc/codecs/wm8580.c b/trunk/sound/soc/codecs/wm8580.c index 7c68226376e4..211285164d70 100644 --- a/trunk/sound/soc/codecs/wm8580.c +++ b/trunk/sound/soc/codecs/wm8580.c @@ -1,7 +1,7 @@ /* * wm8580.c -- WM8580 ALSA Soc Audio driver * - * Copyright 2008-11 Wolfson Microelectronics PLC. + * Copyright 2008, 2009 Wolfson Microelectronics PLC. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/trunk/sound/soc/codecs/wm8731.c b/trunk/sound/soc/codecs/wm8731.c index bb1d26919b10..9d1b9b0271f1 100644 --- a/trunk/sound/soc/codecs/wm8731.c +++ b/trunk/sound/soc/codecs/wm8731.c @@ -2,7 +2,6 @@ * wm8731.c -- WM8731 ALSA SoC Audio driver * * Copyright 2005 Openedhand Ltd. - * Copyright 2006-12 Wolfson Microelectronics, plc * * Author: Richard Purdie * diff --git a/trunk/sound/soc/codecs/wm8741.c b/trunk/sound/soc/codecs/wm8741.c index 35f3d23200e0..6e849cb04243 100644 --- a/trunk/sound/soc/codecs/wm8741.c +++ b/trunk/sound/soc/codecs/wm8741.c @@ -1,7 +1,7 @@ /* * wm8741.c -- WM8741 ALSA SoC Audio driver * - * Copyright 2010-1 Wolfson Microelectronics plc + * Copyright 2010 Wolfson Microelectronics plc * * Author: Ian Lartey * diff --git a/trunk/sound/soc/codecs/wm8753.c b/trunk/sound/soc/codecs/wm8753.c index 13bff87ddcf5..a26482cd7654 100644 --- a/trunk/sound/soc/codecs/wm8753.c +++ b/trunk/sound/soc/codecs/wm8753.c @@ -1,7 +1,7 @@ /* * wm8753.c -- WM8753 ALSA Soc Audio driver * - * Copyright 2003-11 Wolfson Microelectronics PLC. + * Copyright 2003 Wolfson Microelectronics PLC. * Author: Liam Girdwood * * This program is free software; you can redistribute it and/or modify it diff --git a/trunk/sound/soc/codecs/wm8776.c b/trunk/sound/soc/codecs/wm8776.c index 879c356a9045..a19db5a0a17a 100644 --- a/trunk/sound/soc/codecs/wm8776.c +++ b/trunk/sound/soc/codecs/wm8776.c @@ -1,7 +1,7 @@ /* * wm8776.c -- WM8776 ALSA SoC Audio driver * - * Copyright 2009-12 Wolfson Microelectronics plc + * Copyright 2009 Wolfson Microelectronics plc * * Author: Mark Brown * diff --git a/trunk/sound/soc/codecs/wm8804.c b/trunk/sound/soc/codecs/wm8804.c index c088020172ab..6bd1b767b138 100644 --- a/trunk/sound/soc/codecs/wm8804.c +++ b/trunk/sound/soc/codecs/wm8804.c @@ -1,7 +1,7 @@ /* * wm8804.c -- WM8804 S/PDIF transceiver driver * - * Copyright 2010-11 Wolfson Microelectronics plc + * Copyright 2010 Wolfson Microelectronics plc * * Author: Dimitris Papastamos * diff --git a/trunk/sound/soc/codecs/wm8903.c b/trunk/sound/soc/codecs/wm8903.c index 73f1c8d7bafb..86b8a2926591 100644 --- a/trunk/sound/soc/codecs/wm8903.c +++ b/trunk/sound/soc/codecs/wm8903.c @@ -1,8 +1,8 @@ /* * wm8903.c -- WM8903 ALSA SoC Audio driver * - * Copyright 2008-12 Wolfson Microelectronics - * Copyright 2011-2012 NVIDIA, Inc. + * Copyright 2008 Wolfson Microelectronics + * Copyright 2011 NVIDIA, Inc. * * Author: Mark Brown * @@ -116,7 +116,6 @@ static const struct reg_default wm8903_reg_defaults[] = { struct wm8903_priv { struct wm8903_platform_data *pdata; - struct device *dev; struct snd_soc_codec *codec; struct regmap *regmap; @@ -1636,27 +1635,17 @@ EXPORT_SYMBOL_GPL(wm8903_mic_detect); static irqreturn_t wm8903_irq(int irq, void *data) { - struct wm8903_priv *wm8903 = data; - int mic_report, ret; - unsigned int int_val, mask, int_pol; - - ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1_MASK, - &mask); - if (ret != 0) { - dev_err(wm8903->dev, "Failed to read IRQ mask: %d\n", ret); - return IRQ_NONE; - } - - ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1, &int_val); - if (ret != 0) { - dev_err(wm8903->dev, "Failed to read IRQ status: %d\n", ret); - return IRQ_NONE; - } + struct snd_soc_codec *codec = data; + struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); + int mic_report; + int int_pol; + int int_val = 0; + int mask = ~snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1_MASK); - int_val &= ~mask; + int_val = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1) & mask; if (int_val & WM8903_WSEQ_BUSY_EINT) { - dev_warn(wm8903->dev, "Write sequencer done\n"); + dev_warn(codec->dev, "Write sequencer done\n"); } /* @@ -1667,28 +1656,22 @@ static irqreturn_t wm8903_irq(int irq, void *data) * the polarity register. */ mic_report = wm8903->mic_last_report; - ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1, - &int_pol); - if (ret != 0) { - dev_err(wm8903->dev, "Failed to read interrupt polarity: %d\n", - ret); - return IRQ_HANDLED; - } + int_pol = snd_soc_read(codec, WM8903_INTERRUPT_POLARITY_1); #ifndef CONFIG_SND_SOC_WM8903_MODULE if (int_val & (WM8903_MICSHRT_EINT | WM8903_MICDET_EINT)) - trace_snd_soc_jack_irq(dev_name(wm8903->dev)); + trace_snd_soc_jack_irq(dev_name(codec->dev)); #endif if (int_val & WM8903_MICSHRT_EINT) { - dev_dbg(wm8903->dev, "Microphone short (pol=%x)\n", int_pol); + dev_dbg(codec->dev, "Microphone short (pol=%x)\n", int_pol); mic_report ^= wm8903->mic_short; int_pol ^= WM8903_MICSHRT_INV; } if (int_val & WM8903_MICDET_EINT) { - dev_dbg(wm8903->dev, "Microphone detect (pol=%x)\n", int_pol); + dev_dbg(codec->dev, "Microphone detect (pol=%x)\n", int_pol); mic_report ^= wm8903->mic_det; int_pol ^= WM8903_MICDET_INV; @@ -1696,8 +1679,8 @@ static irqreturn_t wm8903_irq(int irq, void *data) msleep(wm8903->mic_delay); } - regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1, - WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol); + snd_soc_update_bits(codec, WM8903_INTERRUPT_POLARITY_1, + WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol); snd_soc_jack_report(wm8903->mic_jack, mic_report, wm8903->mic_short | wm8903->mic_det); @@ -1791,6 +1774,7 @@ static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset) static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); + struct snd_soc_codec *codec = wm8903->codec; unsigned int mask, val; int ret; @@ -1798,8 +1782,8 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset) val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) | WM8903_GP1_DIR; - ret = regmap_update_bits(wm8903->regmap, - WM8903_GPIO_CONTROL_1 + offset, mask, val); + ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, + mask, val); if (ret < 0) return ret; @@ -1809,9 +1793,10 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset) static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset) { struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); - unsigned int reg; + struct snd_soc_codec *codec = wm8903->codec; + int reg; - regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, ®); + reg = snd_soc_read(codec, WM8903_GPIO_CONTROL_1 + offset); return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT; } @@ -1820,6 +1805,7 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); + struct snd_soc_codec *codec = wm8903->codec; unsigned int mask, val; int ret; @@ -1827,8 +1813,8 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip, val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) | (value << WM8903_GP2_LVL_SHIFT); - ret = regmap_update_bits(wm8903->regmap, - WM8903_GPIO_CONTROL_1 + offset, mask, val); + ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, + mask, val); if (ret < 0) return ret; @@ -1838,10 +1824,11 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip, static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); + struct snd_soc_codec *codec = wm8903->codec; - regmap_update_bits(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, - WM8903_GP1_LVL_MASK, - !!value << WM8903_GP1_LVL_SHIFT); + snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, + WM8903_GP1_LVL_MASK, + !!value << WM8903_GP1_LVL_SHIFT); } static struct gpio_chip wm8903_template_chip = { @@ -1855,14 +1842,15 @@ static struct gpio_chip wm8903_template_chip = { .can_sleep = 1, }; -static void wm8903_init_gpio(struct wm8903_priv *wm8903) +static void wm8903_init_gpio(struct snd_soc_codec *codec) { + struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); struct wm8903_platform_data *pdata = wm8903->pdata; int ret; wm8903->gpio_chip = wm8903_template_chip; wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO; - wm8903->gpio_chip.dev = wm8903->dev; + wm8903->gpio_chip.dev = codec->dev; if (pdata->gpio_base) wm8903->gpio_chip.base = pdata->gpio_base; @@ -1871,23 +1859,24 @@ static void wm8903_init_gpio(struct wm8903_priv *wm8903) ret = gpiochip_add(&wm8903->gpio_chip); if (ret != 0) - dev_err(wm8903->dev, "Failed to add GPIOs: %d\n", ret); + dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); } -static void wm8903_free_gpio(struct wm8903_priv *wm8903) +static void wm8903_free_gpio(struct snd_soc_codec *codec) { + struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); int ret; ret = gpiochip_remove(&wm8903->gpio_chip); if (ret != 0) - dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret); + dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret); } #else -static void wm8903_init_gpio(struct wm8903_priv *wm8903) +static void wm8903_init_gpio(struct snd_soc_codec *codec) { } -static void wm8903_free_gpio(struct wm8903_priv *wm8903) +static void wm8903_free_gpio(struct snd_soc_codec *codec) { } #endif @@ -1895,7 +1884,11 @@ static void wm8903_free_gpio(struct wm8903_priv *wm8903) static int wm8903_probe(struct snd_soc_codec *codec) { struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); - int ret; + struct wm8903_platform_data *pdata = wm8903->pdata; + int ret, i; + int trigger, irq_pol; + u16 val; + bool mic_gpio = false; wm8903->codec = codec; codec->control_data = wm8903->regmap; @@ -1906,16 +1899,121 @@ static int wm8903_probe(struct snd_soc_codec *codec) return ret; } + /* Set up GPIOs, detect if any are MIC detect outputs */ + for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) { + if ((!pdata->gpio_cfg[i]) || + (pdata->gpio_cfg[i] > WM8903_GPIO_CONFIG_ZERO)) + continue; + + snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i, + pdata->gpio_cfg[i] & 0x7fff); + + val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK) + >> WM8903_GP1_FN_SHIFT; + + switch (val) { + case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT: + case WM8903_GPn_FN_MICBIAS_SHORT_DETECT: + mic_gpio = true; + break; + default: + break; + } + } + + /* Set up microphone detection */ + snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0, + pdata->micdet_cfg); + + /* Microphone detection needs the WSEQ clock */ + if (pdata->micdet_cfg) + snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0, + WM8903_WSEQ_ENA, WM8903_WSEQ_ENA); + + /* If microphone detection is enabled by pdata but + * detected via IRQ then interrupts can be lost before + * the machine driver has set up microphone detection + * IRQs as the IRQs are clear on read. The detection + * will be enabled when the machine driver configures. + */ + WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA)); + + wm8903->mic_delay = pdata->micdet_delay; + + if (wm8903->irq) { + if (pdata->irq_active_low) { + trigger = IRQF_TRIGGER_LOW; + irq_pol = WM8903_IRQ_POL; + } else { + trigger = IRQF_TRIGGER_HIGH; + irq_pol = 0; + } + + snd_soc_update_bits(codec, WM8903_INTERRUPT_CONTROL, + WM8903_IRQ_POL, irq_pol); + + ret = request_threaded_irq(wm8903->irq, NULL, wm8903_irq, + trigger | IRQF_ONESHOT, + "wm8903", codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to request IRQ: %d\n", + ret); + return ret; + } + + /* Enable write sequencer interrupts */ + snd_soc_update_bits(codec, WM8903_INTERRUPT_STATUS_1_MASK, + WM8903_IM_WSEQ_BUSY_EINT, 0); + } + /* power on device */ wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + /* Latch volume update bits */ + val = snd_soc_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT); + val |= WM8903_ADCVU; + snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val); + snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val); + + val = snd_soc_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT); + val |= WM8903_DACVU; + snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val); + snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val); + + val = snd_soc_read(codec, WM8903_ANALOGUE_OUT1_LEFT); + val |= WM8903_HPOUTVU; + snd_soc_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val); + snd_soc_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val); + + val = snd_soc_read(codec, WM8903_ANALOGUE_OUT2_LEFT); + val |= WM8903_LINEOUTVU; + snd_soc_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val); + snd_soc_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val); + + val = snd_soc_read(codec, WM8903_ANALOGUE_OUT3_LEFT); + val |= WM8903_SPKVU; + snd_soc_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val); + snd_soc_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val); + + /* Enable DAC soft mute by default */ + snd_soc_update_bits(codec, WM8903_DAC_DIGITAL_1, + WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE, + WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE); + + wm8903_init_gpio(codec); + return ret; } /* power down chip */ static int wm8903_remove(struct snd_soc_codec *codec) { + struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); + + wm8903_free_gpio(codec); wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); + if (wm8903->irq) + free_irq(wm8903->irq, codec); return 0; } @@ -2025,18 +2123,15 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, { struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev); struct wm8903_priv *wm8903; - int trigger; - bool mic_gpio = false; - unsigned int val, irq_pol; - int ret, i; + unsigned int val; + int ret; wm8903 = devm_kzalloc(&i2c->dev, sizeof(struct wm8903_priv), GFP_KERNEL); if (wm8903 == NULL) return -ENOMEM; - wm8903->dev = &i2c->dev; - wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap); + wm8903->regmap = regmap_init_i2c(i2c, &wm8903_regmap); if (IS_ERR(wm8903->regmap)) { ret = PTR_ERR(wm8903->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", @@ -2045,6 +2140,7 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, } i2c_set_clientdata(i2c, wm8903); + wm8903->irq = i2c->irq; /* If no platform data was supplied, create storage for defaults */ if (pdata) { @@ -2071,8 +2167,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, } } - pdata = wm8903->pdata; - ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val); if (ret != 0) { dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret); @@ -2095,107 +2189,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, /* Reset the device */ regmap_write(wm8903->regmap, WM8903_SW_RESET_AND_ID, 0x8903); - wm8903_init_gpio(wm8903); - - /* Set up GPIO pin state, detect if any are MIC detect outputs */ - for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) { - if ((!pdata->gpio_cfg[i]) || - (pdata->gpio_cfg[i] > WM8903_GPIO_CONFIG_ZERO)) - continue; - - regmap_write(wm8903->regmap, WM8903_GPIO_CONTROL_1 + i, - pdata->gpio_cfg[i] & 0x7fff); - - val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK) - >> WM8903_GP1_FN_SHIFT; - - switch (val) { - case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT: - case WM8903_GPn_FN_MICBIAS_SHORT_DETECT: - mic_gpio = true; - break; - default: - break; - } - } - - /* Set up microphone detection */ - regmap_write(wm8903->regmap, WM8903_MIC_BIAS_CONTROL_0, - pdata->micdet_cfg); - - /* Microphone detection needs the WSEQ clock */ - if (pdata->micdet_cfg) - regmap_update_bits(wm8903->regmap, WM8903_WRITE_SEQUENCER_0, - WM8903_WSEQ_ENA, WM8903_WSEQ_ENA); - - /* If microphone detection is enabled by pdata but - * detected via IRQ then interrupts can be lost before - * the machine driver has set up microphone detection - * IRQs as the IRQs are clear on read. The detection - * will be enabled when the machine driver configures. - */ - WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA)); - - wm8903->mic_delay = pdata->micdet_delay; - - if (i2c->irq) { - if (pdata->irq_active_low) { - trigger = IRQF_TRIGGER_LOW; - irq_pol = WM8903_IRQ_POL; - } else { - trigger = IRQF_TRIGGER_HIGH; - irq_pol = 0; - } - - regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_CONTROL, - WM8903_IRQ_POL, irq_pol); - - ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq, - trigger | IRQF_ONESHOT, - "wm8903", wm8903); - if (ret != 0) { - dev_err(wm8903->dev, "Failed to request IRQ: %d\n", - ret); - return ret; - } - - /* Enable write sequencer interrupts */ - regmap_update_bits(wm8903->regmap, - WM8903_INTERRUPT_STATUS_1_MASK, - WM8903_IM_WSEQ_BUSY_EINT, 0); - } - - /* Latch volume update bits */ - regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_LEFT, - WM8903_ADCVU, WM8903_ADCVU); - regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_RIGHT, - WM8903_ADCVU, WM8903_ADCVU); - - regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_LEFT, - WM8903_DACVU, WM8903_DACVU); - regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_RIGHT, - WM8903_DACVU, WM8903_DACVU); - - regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_LEFT, - WM8903_HPOUTVU, WM8903_HPOUTVU); - regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_RIGHT, - WM8903_HPOUTVU, WM8903_HPOUTVU); - - regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_LEFT, - WM8903_LINEOUTVU, WM8903_LINEOUTVU); - regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_RIGHT, - WM8903_LINEOUTVU, WM8903_LINEOUTVU); - - regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_LEFT, - WM8903_SPKVU, WM8903_SPKVU); - regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_RIGHT, - WM8903_SPKVU, WM8903_SPKVU); - - /* Enable DAC soft mute by default */ - regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_1, - WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE, - WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE); - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8903, &wm8903_dai, 1); if (ret != 0) @@ -2203,6 +2196,7 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, return 0; err: + regmap_exit(wm8903->regmap); return ret; } @@ -2210,9 +2204,7 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client) { struct wm8903_priv *wm8903 = i2c_get_clientdata(client); - if (client->irq) - free_irq(client->irq, wm8903); - wm8903_free_gpio(wm8903); + regmap_exit(wm8903->regmap); snd_soc_unregister_codec(&client->dev); return 0; diff --git a/trunk/sound/soc/codecs/wm8904.c b/trunk/sound/soc/codecs/wm8904.c index 560a9a47596b..65d525d74c54 100644 --- a/trunk/sound/soc/codecs/wm8904.c +++ b/trunk/sound/soc/codecs/wm8904.c @@ -1,7 +1,7 @@ /* * wm8904.c -- WM8904 ALSA SoC Audio driver * - * Copyright 2009-12 Wolfson Microelectronics plc + * Copyright 2009 Wolfson Microelectronics plc * * Author: Mark Brown * @@ -2263,7 +2263,7 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c, if (wm8904 == NULL) return -ENOMEM; - wm8904->regmap = devm_regmap_init_i2c(i2c, &wm8904_regmap); + wm8904->regmap = regmap_init_i2c(i2c, &wm8904_regmap); if (IS_ERR(wm8904->regmap)) { ret = PTR_ERR(wm8904->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", @@ -2283,12 +2283,15 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c, return 0; err: + regmap_exit(wm8904->regmap); return ret; } static __devexit int wm8904_i2c_remove(struct i2c_client *client) { + struct wm8904_priv *wm8904 = i2c_get_clientdata(client); snd_soc_unregister_codec(&client->dev); + regmap_exit(wm8904->regmap); return 0; } @@ -2310,7 +2313,23 @@ static struct i2c_driver wm8904_i2c_driver = { .id_table = wm8904_i2c_id, }; -module_i2c_driver(wm8904_i2c_driver); +static int __init wm8904_modinit(void) +{ + int ret = 0; + ret = i2c_add_driver(&wm8904_i2c_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register wm8904 I2C driver: %d\n", + ret); + } + return ret; +} +module_init(wm8904_modinit); + +static void __exit wm8904_exit(void) +{ + i2c_del_driver(&wm8904_i2c_driver); +} +module_exit(wm8904_exit); MODULE_DESCRIPTION("ASoC WM8904 driver"); MODULE_AUTHOR("Mark Brown "); diff --git a/trunk/sound/soc/codecs/wm8960.c b/trunk/sound/soc/codecs/wm8960.c index 96518ac8e24c..8bc659d8dd2e 100644 --- a/trunk/sound/soc/codecs/wm8960.c +++ b/trunk/sound/soc/codecs/wm8960.c @@ -1,8 +1,6 @@ /* * wm8960.c -- WM8960 ALSA SoC Audio driver * - * Copyright 2007-11 Wolfson Microelectronics, plc - * * Author: Liam Girdwood * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/sound/soc/codecs/wm8961.c b/trunk/sound/soc/codecs/wm8961.c index 01edbcc754d2..05ea7c274093 100644 --- a/trunk/sound/soc/codecs/wm8961.c +++ b/trunk/sound/soc/codecs/wm8961.c @@ -1,8 +1,6 @@ /* * wm8961.c -- WM8961 ALSA SoC Audio driver * - * Copyright 2009-10 Wolfson Microelectronics, plc - * * Author: Mark Brown * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/sound/soc/codecs/wm8962.c b/trunk/sound/soc/codecs/wm8962.c index 27da4d722edc..0cfce9999c89 100644 --- a/trunk/sound/soc/codecs/wm8962.c +++ b/trunk/sound/soc/codecs/wm8962.c @@ -1,7 +1,7 @@ /* * wm8962.c -- WM8962 ALSA SoC Audio driver * - * Copyright 2010-2 Wolfson Microelectronics plc + * Copyright 2010 Wolfson Microelectronics plc * * Author: Mark Brown * diff --git a/trunk/sound/soc/codecs/wm8993.c b/trunk/sound/soc/codecs/wm8993.c index 9fd80d688979..36acfccab999 100644 --- a/trunk/sound/soc/codecs/wm8993.c +++ b/trunk/sound/soc/codecs/wm8993.c @@ -1,7 +1,7 @@ /* * wm8993.c -- WM8993 ALSA SoC audio driver * - * Copyright 2009-12 Wolfson Microelectronics plc + * Copyright 2009, 2010 Wolfson Microelectronics plc * * Author: Mark Brown * diff --git a/trunk/sound/soc/codecs/wm8994.c b/trunk/sound/soc/codecs/wm8994.c index 5d4d7df8d339..993639d694ce 100644 --- a/trunk/sound/soc/codecs/wm8994.c +++ b/trunk/sound/soc/codecs/wm8994.c @@ -1,7 +1,7 @@ /* * wm8994.c -- WM8994 ALSA SoC Audio driver * - * Copyright 2009-12 Wolfson Microelectronics plc + * Copyright 2009 Wolfson Microelectronics plc * * Author: Mark Brown * diff --git a/trunk/sound/soc/codecs/wm8996.c b/trunk/sound/soc/codecs/wm8996.c index a6b5cffa498a..8af422e38fd0 100644 --- a/trunk/sound/soc/codecs/wm8996.c +++ b/trunk/sound/soc/codecs/wm8996.c @@ -1,7 +1,7 @@ /* * wm8996.c - WM8996 audio codec interface * - * Copyright 2011-2 Wolfson Microelectronics PLC. + * Copyright 2011 Wolfson Microelectronics PLC. * Author: Mark Brown * * This program is free software; you can redistribute it and/or modify it @@ -296,6 +296,184 @@ static struct reg_default wm8996_reg[] = { { WM8996_RIGHT_PDM_SPEAKER, 0x1 }, { WM8996_PDM_SPEAKER_MUTE_SEQUENCE, 0x69 }, { WM8996_PDM_SPEAKER_VOLUME, 0x66 }, + { WM8996_WRITE_SEQUENCER_0, 0x1 }, + { WM8996_WRITE_SEQUENCER_1, 0x1 }, + { WM8996_WRITE_SEQUENCER_3, 0x6 }, + { WM8996_WRITE_SEQUENCER_4, 0x40 }, + { WM8996_WRITE_SEQUENCER_5, 0x1 }, + { WM8996_WRITE_SEQUENCER_6, 0xf }, + { WM8996_WRITE_SEQUENCER_7, 0x6 }, + { WM8996_WRITE_SEQUENCER_8, 0x1 }, + { WM8996_WRITE_SEQUENCER_9, 0x3 }, + { WM8996_WRITE_SEQUENCER_10, 0x104 }, + { WM8996_WRITE_SEQUENCER_12, 0x60 }, + { WM8996_WRITE_SEQUENCER_13, 0x11 }, + { WM8996_WRITE_SEQUENCER_14, 0x401 }, + { WM8996_WRITE_SEQUENCER_16, 0x50 }, + { WM8996_WRITE_SEQUENCER_17, 0x3 }, + { WM8996_WRITE_SEQUENCER_18, 0x100 }, + { WM8996_WRITE_SEQUENCER_20, 0x51 }, + { WM8996_WRITE_SEQUENCER_21, 0x3 }, + { WM8996_WRITE_SEQUENCER_22, 0x104 }, + { WM8996_WRITE_SEQUENCER_23, 0xa }, + { WM8996_WRITE_SEQUENCER_24, 0x60 }, + { WM8996_WRITE_SEQUENCER_25, 0x3b }, + { WM8996_WRITE_SEQUENCER_26, 0x502 }, + { WM8996_WRITE_SEQUENCER_27, 0x100 }, + { WM8996_WRITE_SEQUENCER_28, 0x2fff }, + { WM8996_WRITE_SEQUENCER_32, 0x2fff }, + { WM8996_WRITE_SEQUENCER_36, 0x2fff }, + { WM8996_WRITE_SEQUENCER_40, 0x2fff }, + { WM8996_WRITE_SEQUENCER_44, 0x2fff }, + { WM8996_WRITE_SEQUENCER_48, 0x2fff }, + { WM8996_WRITE_SEQUENCER_52, 0x2fff }, + { WM8996_WRITE_SEQUENCER_56, 0x2fff }, + { WM8996_WRITE_SEQUENCER_60, 0x2fff }, + { WM8996_WRITE_SEQUENCER_64, 0x1 }, + { WM8996_WRITE_SEQUENCER_65, 0x1 }, + { WM8996_WRITE_SEQUENCER_67, 0x6 }, + { WM8996_WRITE_SEQUENCER_68, 0x40 }, + { WM8996_WRITE_SEQUENCER_69, 0x1 }, + { WM8996_WRITE_SEQUENCER_70, 0xf }, + { WM8996_WRITE_SEQUENCER_71, 0x6 }, + { WM8996_WRITE_SEQUENCER_72, 0x1 }, + { WM8996_WRITE_SEQUENCER_73, 0x3 }, + { WM8996_WRITE_SEQUENCER_74, 0x104 }, + { WM8996_WRITE_SEQUENCER_76, 0x60 }, + { WM8996_WRITE_SEQUENCER_77, 0x11 }, + { WM8996_WRITE_SEQUENCER_78, 0x401 }, + { WM8996_WRITE_SEQUENCER_80, 0x50 }, + { WM8996_WRITE_SEQUENCER_81, 0x3 }, + { WM8996_WRITE_SEQUENCER_82, 0x100 }, + { WM8996_WRITE_SEQUENCER_84, 0x60 }, + { WM8996_WRITE_SEQUENCER_85, 0x3b }, + { WM8996_WRITE_SEQUENCER_86, 0x502 }, + { WM8996_WRITE_SEQUENCER_87, 0x100 }, + { WM8996_WRITE_SEQUENCER_88, 0x2fff }, + { WM8996_WRITE_SEQUENCER_92, 0x2fff }, + { WM8996_WRITE_SEQUENCER_96, 0x2fff }, + { WM8996_WRITE_SEQUENCER_100, 0x2fff }, + { WM8996_WRITE_SEQUENCER_104, 0x2fff }, + { WM8996_WRITE_SEQUENCER_108, 0x2fff }, + { WM8996_WRITE_SEQUENCER_112, 0x2fff }, + { WM8996_WRITE_SEQUENCER_116, 0x2fff }, + { WM8996_WRITE_SEQUENCER_120, 0x2fff }, + { WM8996_WRITE_SEQUENCER_124, 0x2fff }, + { WM8996_WRITE_SEQUENCER_128, 0x1 }, + { WM8996_WRITE_SEQUENCER_129, 0x1 }, + { WM8996_WRITE_SEQUENCER_131, 0x6 }, + { WM8996_WRITE_SEQUENCER_132, 0x40 }, + { WM8996_WRITE_SEQUENCER_133, 0x1 }, + { WM8996_WRITE_SEQUENCER_134, 0xf }, + { WM8996_WRITE_SEQUENCER_135, 0x6 }, + { WM8996_WRITE_SEQUENCER_136, 0x1 }, + { WM8996_WRITE_SEQUENCER_137, 0x3 }, + { WM8996_WRITE_SEQUENCER_138, 0x106 }, + { WM8996_WRITE_SEQUENCER_140, 0x61 }, + { WM8996_WRITE_SEQUENCER_141, 0x11 }, + { WM8996_WRITE_SEQUENCER_142, 0x401 }, + { WM8996_WRITE_SEQUENCER_144, 0x50 }, + { WM8996_WRITE_SEQUENCER_145, 0x3 }, + { WM8996_WRITE_SEQUENCER_146, 0x102 }, + { WM8996_WRITE_SEQUENCER_148, 0x51 }, + { WM8996_WRITE_SEQUENCER_149, 0x3 }, + { WM8996_WRITE_SEQUENCER_150, 0x106 }, + { WM8996_WRITE_SEQUENCER_151, 0xa }, + { WM8996_WRITE_SEQUENCER_152, 0x61 }, + { WM8996_WRITE_SEQUENCER_153, 0x3b }, + { WM8996_WRITE_SEQUENCER_154, 0x502 }, + { WM8996_WRITE_SEQUENCER_155, 0x100 }, + { WM8996_WRITE_SEQUENCER_156, 0x2fff }, + { WM8996_WRITE_SEQUENCER_160, 0x2fff }, + { WM8996_WRITE_SEQUENCER_164, 0x2fff }, + { WM8996_WRITE_SEQUENCER_168, 0x2fff }, + { WM8996_WRITE_SEQUENCER_172, 0x2fff }, + { WM8996_WRITE_SEQUENCER_176, 0x2fff }, + { WM8996_WRITE_SEQUENCER_180, 0x2fff }, + { WM8996_WRITE_SEQUENCER_184, 0x2fff }, + { WM8996_WRITE_SEQUENCER_188, 0x2fff }, + { WM8996_WRITE_SEQUENCER_192, 0x1 }, + { WM8996_WRITE_SEQUENCER_193, 0x1 }, + { WM8996_WRITE_SEQUENCER_195, 0x6 }, + { WM8996_WRITE_SEQUENCER_196, 0x40 }, + { WM8996_WRITE_SEQUENCER_197, 0x1 }, + { WM8996_WRITE_SEQUENCER_198, 0xf }, + { WM8996_WRITE_SEQUENCER_199, 0x6 }, + { WM8996_WRITE_SEQUENCER_200, 0x1 }, + { WM8996_WRITE_SEQUENCER_201, 0x3 }, + { WM8996_WRITE_SEQUENCER_202, 0x106 }, + { WM8996_WRITE_SEQUENCER_204, 0x61 }, + { WM8996_WRITE_SEQUENCER_205, 0x11 }, + { WM8996_WRITE_SEQUENCER_206, 0x401 }, + { WM8996_WRITE_SEQUENCER_208, 0x50 }, + { WM8996_WRITE_SEQUENCER_209, 0x3 }, + { WM8996_WRITE_SEQUENCER_210, 0x102 }, + { WM8996_WRITE_SEQUENCER_212, 0x61 }, + { WM8996_WRITE_SEQUENCER_213, 0x3b }, + { WM8996_WRITE_SEQUENCER_214, 0x502 }, + { WM8996_WRITE_SEQUENCER_215, 0x100 }, + { WM8996_WRITE_SEQUENCER_216, 0x2fff }, + { WM8996_WRITE_SEQUENCER_220, 0x2fff }, + { WM8996_WRITE_SEQUENCER_224, 0x2fff }, + { WM8996_WRITE_SEQUENCER_228, 0x2fff }, + { WM8996_WRITE_SEQUENCER_232, 0x2fff }, + { WM8996_WRITE_SEQUENCER_236, 0x2fff }, + { WM8996_WRITE_SEQUENCER_240, 0x2fff }, + { WM8996_WRITE_SEQUENCER_244, 0x2fff }, + { WM8996_WRITE_SEQUENCER_248, 0x2fff }, + { WM8996_WRITE_SEQUENCER_252, 0x2fff }, + { WM8996_WRITE_SEQUENCER_256, 0x60 }, + { WM8996_WRITE_SEQUENCER_258, 0x601 }, + { WM8996_WRITE_SEQUENCER_260, 0x50 }, + { WM8996_WRITE_SEQUENCER_262, 0x100 }, + { WM8996_WRITE_SEQUENCER_264, 0x1 }, + { WM8996_WRITE_SEQUENCER_266, 0x104 }, + { WM8996_WRITE_SEQUENCER_267, 0x100 }, + { WM8996_WRITE_SEQUENCER_268, 0x2fff }, + { WM8996_WRITE_SEQUENCER_272, 0x2fff }, + { WM8996_WRITE_SEQUENCER_276, 0x2fff }, + { WM8996_WRITE_SEQUENCER_280, 0x2fff }, + { WM8996_WRITE_SEQUENCER_284, 0x2fff }, + { WM8996_WRITE_SEQUENCER_288, 0x2fff }, + { WM8996_WRITE_SEQUENCER_292, 0x2fff }, + { WM8996_WRITE_SEQUENCER_296, 0x2fff }, + { WM8996_WRITE_SEQUENCER_300, 0x2fff }, + { WM8996_WRITE_SEQUENCER_304, 0x2fff }, + { WM8996_WRITE_SEQUENCER_308, 0x2fff }, + { WM8996_WRITE_SEQUENCER_312, 0x2fff }, + { WM8996_WRITE_SEQUENCER_316, 0x2fff }, + { WM8996_WRITE_SEQUENCER_320, 0x61 }, + { WM8996_WRITE_SEQUENCER_322, 0x601 }, + { WM8996_WRITE_SEQUENCER_324, 0x50 }, + { WM8996_WRITE_SEQUENCER_326, 0x102 }, + { WM8996_WRITE_SEQUENCER_328, 0x1 }, + { WM8996_WRITE_SEQUENCER_330, 0x106 }, + { WM8996_WRITE_SEQUENCER_331, 0x100 }, + { WM8996_WRITE_SEQUENCER_332, 0x2fff }, + { WM8996_WRITE_SEQUENCER_336, 0x2fff }, + { WM8996_WRITE_SEQUENCER_340, 0x2fff }, + { WM8996_WRITE_SEQUENCER_344, 0x2fff }, + { WM8996_WRITE_SEQUENCER_348, 0x2fff }, + { WM8996_WRITE_SEQUENCER_352, 0x2fff }, + { WM8996_WRITE_SEQUENCER_356, 0x2fff }, + { WM8996_WRITE_SEQUENCER_360, 0x2fff }, + { WM8996_WRITE_SEQUENCER_364, 0x2fff }, + { WM8996_WRITE_SEQUENCER_368, 0x2fff }, + { WM8996_WRITE_SEQUENCER_372, 0x2fff }, + { WM8996_WRITE_SEQUENCER_376, 0x2fff }, + { WM8996_WRITE_SEQUENCER_380, 0x2fff }, + { WM8996_WRITE_SEQUENCER_384, 0x60 }, + { WM8996_WRITE_SEQUENCER_386, 0x601 }, + { WM8996_WRITE_SEQUENCER_388, 0x61 }, + { WM8996_WRITE_SEQUENCER_390, 0x601 }, + { WM8996_WRITE_SEQUENCER_392, 0x50 }, + { WM8996_WRITE_SEQUENCER_394, 0x300 }, + { WM8996_WRITE_SEQUENCER_396, 0x1 }, + { WM8996_WRITE_SEQUENCER_398, 0x304 }, + { WM8996_WRITE_SEQUENCER_400, 0x40 }, + { WM8996_WRITE_SEQUENCER_402, 0xf }, + { WM8996_WRITE_SEQUENCER_404, 0x1 }, + { WM8996_WRITE_SEQUENCER_407, 0x100 }, }; static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0); @@ -3000,7 +3178,7 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c, msleep(5); } - wm8996->regmap = devm_regmap_init_i2c(i2c, &wm8996_regmap); + wm8996->regmap = regmap_init_i2c(i2c, &wm8996_regmap); if (IS_ERR(wm8996->regmap)) { ret = PTR_ERR(wm8996->regmap); dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); @@ -3049,6 +3227,7 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c, err_gpiolib: wm8996_free_gpio(wm8996); err_regmap: + regmap_exit(wm8996->regmap); err_enable: if (wm8996->pdata.ldo_ena > 0) gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); @@ -3067,6 +3246,7 @@ static __devexit int wm8996_i2c_remove(struct i2c_client *client) snd_soc_unregister_codec(&client->dev); wm8996_free_gpio(wm8996); + regmap_exit(wm8996->regmap); if (wm8996->pdata.ldo_ena > 0) { gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); gpio_free(wm8996->pdata.ldo_ena); diff --git a/trunk/sound/soc/codecs/wm9081.c b/trunk/sound/soc/codecs/wm9081.c index 2de74e1ea225..9328270df16c 100644 --- a/trunk/sound/soc/codecs/wm9081.c +++ b/trunk/sound/soc/codecs/wm9081.c @@ -3,7 +3,7 @@ * * Author: Mark Brown * - * Copyright 2009-12 Wolfson Microelectronics plc + * Copyright 2009 Wolfson Microelectronics plc * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/trunk/sound/soc/codecs/wm9090.c b/trunk/sound/soc/codecs/wm9090.c index 2c2346fdd637..4b263b6edf13 100644 --- a/trunk/sound/soc/codecs/wm9090.c +++ b/trunk/sound/soc/codecs/wm9090.c @@ -1,7 +1,7 @@ /* * ALSA SoC WM9090 driver * - * Copyright 2009-12 Wolfson Microelectronics + * Copyright 2009, 2010 Wolfson Microelectronics * * Author: Mark Brown * diff --git a/trunk/sound/soc/codecs/wm9712.c b/trunk/sound/soc/codecs/wm9712.c index 099e6ec32125..a1541414d904 100644 --- a/trunk/sound/soc/codecs/wm9712.c +++ b/trunk/sound/soc/codecs/wm9712.c @@ -1,7 +1,7 @@ /* * wm9712.c -- ALSA Soc WM9712 codec support * - * Copyright 2006-12 Wolfson Microelectronics PLC. + * Copyright 2006 Wolfson Microelectronics PLC. * Author: Liam Girdwood * * This program is free software; you can redistribute it and/or modify it diff --git a/trunk/sound/soc/codecs/wm9713.c b/trunk/sound/soc/codecs/wm9713.c index 3eb19fb71d17..2d22cc70d536 100644 --- a/trunk/sound/soc/codecs/wm9713.c +++ b/trunk/sound/soc/codecs/wm9713.c @@ -1,7 +1,7 @@ /* * wm9713.c -- ALSA Soc WM9713 codec support * - * Copyright 2006-10 Wolfson Microelectronics PLC. + * Copyright 2006 Wolfson Microelectronics PLC. * Author: Liam Girdwood * * This program is free software; you can redistribute it and/or modify it diff --git a/trunk/sound/soc/codecs/wm_hubs.c b/trunk/sound/soc/codecs/wm_hubs.c index 61baa48823cb..dfe957a47f29 100644 --- a/trunk/sound/soc/codecs/wm_hubs.c +++ b/trunk/sound/soc/codecs/wm_hubs.c @@ -1,7 +1,7 @@ /* * wm_hubs.c -- WM8993/4 common code * - * Copyright 2009-12 Wolfson Microelectronics plc + * Copyright 2009 Wolfson Microelectronics plc * * Author: Mark Brown * diff --git a/trunk/sound/soc/mxs/mxs-sgtl5000.c b/trunk/sound/soc/mxs/mxs-sgtl5000.c index 215113b05f7d..3e6e8764b2e6 100644 --- a/trunk/sound/soc/mxs/mxs-sgtl5000.c +++ b/trunk/sound/soc/mxs/mxs-sgtl5000.c @@ -133,7 +133,7 @@ static int __devinit mxs_sgtl5000_probe_dt(struct platform_device *pdev) 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_of_node = saif_np[i]; + 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]; } diff --git a/trunk/sound/soc/sh/fsi.c b/trunk/sound/soc/sh/fsi.c index 53486ff9c2af..2ef98536f1da 100644 --- a/trunk/sound/soc/sh/fsi.c +++ b/trunk/sound/soc/sh/fsi.c @@ -247,7 +247,7 @@ struct fsi_priv { struct fsi_stream_handler { int (*init)(struct fsi_priv *fsi, struct fsi_stream *io); int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io); - int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev); + int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io); int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io); int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io); void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io, @@ -571,16 +571,16 @@ static int fsi_stream_transfer(struct fsi_stream *io) #define fsi_stream_stop(fsi, io)\ fsi_stream_handler_call(io, start_stop, fsi, io, 0) -static int fsi_stream_probe(struct fsi_priv *fsi, struct device *dev) +static int fsi_stream_probe(struct fsi_priv *fsi) { struct fsi_stream *io; int ret1, ret2; io = &fsi->playback; - ret1 = fsi_stream_handler_call(io, probe, fsi, io, dev); + ret1 = fsi_stream_handler_call(io, probe, fsi, io); io = &fsi->capture; - ret2 = fsi_stream_handler_call(io, probe, fsi, io, dev); + ret2 = fsi_stream_handler_call(io, probe, fsi, io); if (ret1 < 0) return ret1; @@ -1089,10 +1089,13 @@ static void fsi_dma_do_tasklet(unsigned long data) { struct fsi_stream *io = (struct fsi_stream *)data; struct fsi_priv *fsi = fsi_stream_to_priv(io); + struct dma_chan *chan; struct snd_soc_dai *dai; struct dma_async_tx_descriptor *desc; + struct scatterlist sg; struct snd_pcm_runtime *runtime; enum dma_data_direction dir; + dma_cookie_t cookie; int is_play = fsi_stream_is_play(fsi, io); int len; dma_addr_t buf; @@ -1101,6 +1104,7 @@ static void fsi_dma_do_tasklet(unsigned long data) return; dai = fsi_get_dai(io->substream); + chan = io->chan; runtime = io->substream->runtime; dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; len = samples_to_bytes(runtime, io->period_samples); @@ -1108,8 +1112,14 @@ static void fsi_dma_do_tasklet(unsigned long data) dma_sync_single_for_device(dai->dev, buf, len, dir); - desc = dmaengine_prep_slave_single(io->chan, buf, len, dir, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + sg_init_table(&sg, 1); + sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)), + len , offset_in_page(buf)); + sg_dma_address(&sg) = buf; + sg_dma_len(&sg) = len; + + desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n"); return; @@ -1118,12 +1128,13 @@ static void fsi_dma_do_tasklet(unsigned long data) desc->callback = fsi_dma_complete; desc->callback_param = io; - if (dmaengine_submit(desc) < 0) { + cookie = desc->tx_submit(desc); + if (cookie < 0) { dev_err(dai->dev, "tx_submit() fail\n"); return; } - dma_async_issue_pending(io->chan); + dma_async_issue_pending(chan); /* * FIXME @@ -1173,7 +1184,7 @@ static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); } -static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev) +static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io) { dma_cap_mask_t mask; @@ -1181,19 +1192,8 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct dev dma_cap_set(DMA_SLAVE, mask); io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave); - if (!io->chan) { - - /* switch to PIO handler */ - if (fsi_stream_is_play(fsi, io)) - fsi->playback.handler = &fsi_pio_push_handler; - else - fsi->capture.handler = &fsi_pio_pop_handler; - - dev_info(dev, "switch handler (dma => pio)\n"); - - /* probe again */ - return fsi_stream_probe(fsi, dev); - } + if (!io->chan) + return -EIO; tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io); @@ -1683,7 +1683,7 @@ static int fsi_probe(struct platform_device *pdev) master->fsia.master = master; master->fsia.info = &info->port_a; fsi_handler_init(&master->fsia); - ret = fsi_stream_probe(&master->fsia, &pdev->dev); + ret = fsi_stream_probe(&master->fsia); if (ret < 0) { dev_err(&pdev->dev, "FSIA stream probe failed\n"); goto exit_iounmap; @@ -1694,7 +1694,7 @@ static int fsi_probe(struct platform_device *pdev) master->fsib.master = master; master->fsib.info = &info->port_b; fsi_handler_init(&master->fsib); - ret = fsi_stream_probe(&master->fsib, &pdev->dev); + ret = fsi_stream_probe(&master->fsib); if (ret < 0) { dev_err(&pdev->dev, "FSIB stream probe failed\n"); goto exit_fsia; diff --git a/trunk/sound/soc/soc-core.c b/trunk/sound/soc/soc-core.c index 3d803f3cd272..b37ee8077ed1 100644 --- a/trunk/sound/soc/soc-core.c +++ b/trunk/sound/soc/soc-core.c @@ -812,15 +812,13 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) /* Find CPU DAI from registered DAIs*/ list_for_each_entry(cpu_dai, &dai_list, list) { - if (dai_link->cpu_of_node && - (cpu_dai->dev->of_node != dai_link->cpu_of_node)) - continue; - if (dai_link->cpu_name && - strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name)) - continue; - if (dai_link->cpu_dai_name && - strcmp(cpu_dai->name, dai_link->cpu_dai_name)) - continue; + if (dai_link->cpu_dai_of_node) { + if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node) + continue; + } else { + if (strcmp(cpu_dai->name, dai_link->cpu_dai_name)) + continue; + } rtd->cpu_dai = cpu_dai; } @@ -2791,104 +2789,6 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); -/** - * snd_soc_info_volsw_range - single mixer info callback with range. - * @kcontrol: mixer control - * @uinfo: control element information - * - * Callback to provide information, within a range, about a single - * mixer control. - * - * returns 0 for success. - */ -int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - int platform_max; - int min = mc->min; - - if (!mc->platform_max) - mc->platform_max = mc->max; - platform_max = mc->platform_max; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = platform_max - min; - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range); - -/** - * snd_soc_put_volsw_range - single mixer put value callback with range. - * @kcontrol: mixer control - * @ucontrol: control element information - * - * Callback to set the value, within a range, for a single mixer control. - * - * Returns 0 for success. - */ -int snd_soc_put_volsw_range(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; - int min = mc->min; - int max = mc->max; - unsigned int mask = (1 << fls(max)) - 1; - unsigned int invert = mc->invert; - unsigned int val, val_mask; - - val = ((ucontrol->value.integer.value[0] + min) & mask); - if (invert) - val = max - val; - val_mask = mask << shift; - val = val << shift; - - return snd_soc_update_bits_locked(codec, reg, val_mask, val); -} -EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); - -/** - * snd_soc_get_volsw_range - single mixer get callback with range - * @kcontrol: mixer control - * @ucontrol: control element information - * - * Callback to get the value, within a range, of a single mixer control. - * - * Returns 0 for success. - */ -int snd_soc_get_volsw_range(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; - int min = mc->min; - int max = mc->max; - unsigned int mask = (1 << fls(max)) - 1; - unsigned int invert = mc->invert; - - ucontrol->value.integer.value[0] = - (snd_soc_read(codec, reg) >> shift) & mask; - if (invert) - ucontrol->value.integer.value[0] = - max - ucontrol->value.integer.value[0]; - ucontrol->value.integer.value[0] = - ucontrol->value.integer.value[0] - min; - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); - /** * snd_soc_limit_volume - Set new limit to an existing volume control. * @@ -3446,12 +3346,6 @@ int snd_soc_register_card(struct snd_soc_card *card) link->name); return -EINVAL; } - /* Codec DAI name must be specified */ - if (!link->codec_dai_name) { - dev_err(card->dev, "codec_dai_name not set for %s\n", - link->name); - return -EINVAL; - } /* * Platform may be specified by either name or OF node, but @@ -3464,24 +3358,12 @@ int snd_soc_register_card(struct snd_soc_card *card) } /* - * CPU device may be specified by either name or OF node, but - * can be left unspecified, and will be matched based on DAI - * name alone.. - */ - if (link->cpu_name && link->cpu_of_node) { - dev_err(card->dev, - "Neither/both cpu name/of_node are set for %s\n", - link->name); - return -EINVAL; - } - /* - * At least one of CPU DAI name or CPU device name/node must be - * specified + * CPU DAI must be specified by 1 of name or OF node, + * not both or neither. */ - if (!link->cpu_dai_name && - !(link->cpu_name || link->cpu_of_node)) { + if (!!link->cpu_dai_name == !!link->cpu_dai_of_node) { dev_err(card->dev, - "Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", + "Neither/both cpu_dai name/of_node are set for %s\n", link->name); return -EINVAL; } diff --git a/trunk/sound/soc/soc-dapm.c b/trunk/sound/soc/soc-dapm.c index 7365fed1ba74..90ee77d2409d 100644 --- a/trunk/sound/soc/soc-dapm.c +++ b/trunk/sound/soc/soc-dapm.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -52,7 +51,6 @@ static int dapm_up_seq[] = { [snd_soc_dapm_pre] = 0, [snd_soc_dapm_supply] = 1, [snd_soc_dapm_regulator_supply] = 1, - [snd_soc_dapm_clock_supply] = 1, [snd_soc_dapm_micbias] = 2, [snd_soc_dapm_dai_link] = 2, [snd_soc_dapm_dai] = 3, @@ -94,7 +92,6 @@ static int dapm_down_seq[] = { [snd_soc_dapm_aif_out] = 10, [snd_soc_dapm_dai] = 10, [snd_soc_dapm_dai_link] = 11, - [snd_soc_dapm_clock_supply] = 12, [snd_soc_dapm_regulator_supply] = 12, [snd_soc_dapm_supply] = 12, [snd_soc_dapm_post] = 13, @@ -394,7 +391,6 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, case snd_soc_dapm_vmid: case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: - case snd_soc_dapm_clock_supply: case snd_soc_dapm_aif_in: case snd_soc_dapm_aif_out: case snd_soc_dapm_dai: @@ -768,7 +764,6 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, switch (widget->id) { case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: - case snd_soc_dapm_clock_supply: return 0; default: break; @@ -855,7 +850,6 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, switch (widget->id) { case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: - case snd_soc_dapm_clock_supply: return 0; default: break; @@ -1002,26 +996,6 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, } EXPORT_SYMBOL_GPL(dapm_regulator_event); -/* - * Handler for clock supply widget. - */ -int dapm_clock_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - if (!w->clk) - return -EIO; - -#ifdef CONFIG_HAVE_CLK - if (SND_SOC_DAPM_EVENT_ON(event)) { - return clk_enable(w->clk); - } else { - clk_disable(w->clk); - return 0; - } -#endif -} -EXPORT_SYMBOL_GPL(dapm_clock_event); - static int dapm_widget_power_check(struct snd_soc_dapm_widget *w) { if (w->power_checked) @@ -1513,7 +1487,6 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, switch (w->id) { case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: - case snd_soc_dapm_clock_supply: /* Supplies can't affect their outputs, only their inputs */ break; default: @@ -1614,7 +1587,6 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) break; case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: - case snd_soc_dapm_clock_supply: case snd_soc_dapm_micbias: if (d->target_bias_level < SND_SOC_BIAS_STANDBY) d->target_bias_level = SND_SOC_BIAS_STANDBY; @@ -1969,7 +1941,6 @@ static ssize_t dapm_widget_show(struct device *dev, case snd_soc_dapm_mixer_named_ctl: case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: - case snd_soc_dapm_clock_supply: if (w->name) count += sprintf(buf + count, "%s: %s\n", w->name, w->power ? "On":"Off"); @@ -2216,7 +2187,6 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, case snd_soc_dapm_post: case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: - case snd_soc_dapm_clock_supply: case snd_soc_dapm_aif_in: case snd_soc_dapm_aif_out: case snd_soc_dapm_dai: @@ -2903,19 +2873,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, return NULL; } break; - case snd_soc_dapm_clock_supply: -#ifdef CONFIG_CLKDEV_LOOKUP - w->clk = devm_clk_get(dapm->dev, w->name); - if (IS_ERR(w->clk)) { - ret = PTR_ERR(w->clk); - dev_err(dapm->dev, "Failed to request %s: %d\n", - w->name, ret); - return NULL; - } -#else - return NULL; -#endif - break; default: break; } @@ -2967,7 +2924,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, break; case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: - case snd_soc_dapm_clock_supply: w->power_check = dapm_supply_check_power; break; case snd_soc_dapm_dai: diff --git a/trunk/sound/soc/soc-io.c b/trunk/sound/soc/soc-io.c index 44d0174b4d97..4d8dc6a27d4d 100644 --- a/trunk/sound/soc/soc-io.c +++ b/trunk/sound/soc/soc-io.c @@ -142,8 +142,6 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, case SND_SOC_REGMAP: /* Device has made its own regmap arrangements */ codec->using_regmap = true; - if (!codec->control_data) - codec->control_data = dev_get_regmap(codec->dev, NULL); ret = regmap_get_val_bytes(codec->control_data); /* Errors are legitimate for non-integer byte multiples */ diff --git a/trunk/sound/soc/tegra/tegra20_i2s.c b/trunk/sound/soc/tegra/tegra20_i2s.c index c5fc6b1404f6..0c7af63d444b 100644 --- a/trunk/sound/soc/tegra/tegra20_i2s.c +++ b/trunk/sound/soc/tegra/tegra20_i2s.c @@ -46,6 +46,18 @@ #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); @@ -73,7 +85,6 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai); - unsigned int mask, val; switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: @@ -82,10 +93,10 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai, return -EINVAL; } - mask = TEGRA20_I2S_CTRL_MASTER_ENABLE; + i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_MASTER_ENABLE; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: - val = TEGRA20_I2S_CTRL_MASTER_ENABLE; + i2s->reg_ctrl |= TEGRA20_I2S_CTRL_MASTER_ENABLE; break; case SND_SOC_DAIFMT_CBM_CFM: break; @@ -93,35 +104,33 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai, return -EINVAL; } - mask |= TEGRA20_I2S_CTRL_BIT_FORMAT_MASK | - TEGRA20_I2S_CTRL_LRCK_MASK; + 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: - val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP; - val |= TEGRA20_I2S_CTRL_LRCK_L_LOW; + 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: - val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP; - val |= TEGRA20_I2S_CTRL_LRCK_R_LOW; + i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP; + i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_R_LOW; break; case SND_SOC_DAIFMT_I2S: - val |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S; - val |= TEGRA20_I2S_CTRL_LRCK_L_LOW; + 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: - val |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM; - val |= TEGRA20_I2S_CTRL_LRCK_L_LOW; + 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: - val |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM; - val |= TEGRA20_I2S_CTRL_LRCK_L_LOW; + i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM; + i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW; break; default: return -EINVAL; } - regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val); - return 0; } @@ -129,34 +138,29 @@ 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 = dai->dev; + struct device *dev = substream->pcm->card->dev; struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai); - unsigned int mask, val; + u32 reg; int ret, sample_size, srate, i2sclock, bitcnt; - mask = TEGRA20_I2S_CTRL_BIT_SIZE_MASK; + i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_BIT_SIZE_MASK; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: - val = TEGRA20_I2S_CTRL_BIT_SIZE_16; + i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_16; sample_size = 16; break; case SNDRV_PCM_FORMAT_S24_LE: - val = TEGRA20_I2S_CTRL_BIT_SIZE_24; + i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_24; sample_size = 24; break; case SNDRV_PCM_FORMAT_S32_LE: - val = TEGRA20_I2S_CTRL_BIT_SIZE_32; + i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_32; sample_size = 32; break; default: return -EINVAL; } - mask |= TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK; - val |= TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED; - - regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val); - srate = params_rate(params); /* Final "* 2" required by Tegra hardware */ @@ -171,44 +175,42 @@ static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream, bitcnt = (i2sclock / (2 * srate)) - 1; if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US) return -EINVAL; - val = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; + reg = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; if (i2sclock % (2 * srate)) - val |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE; + reg |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE; - regmap_write(i2s->regmap, TEGRA20_I2S_TIMING, val); + tegra20_i2s_write(i2s, TEGRA20_I2S_TIMING, reg); - regmap_write(i2s->regmap, TEGRA20_I2S_FIFO_SCR, - TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS | - TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS); + 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) { - regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, - TEGRA20_I2S_CTRL_FIFO1_ENABLE, - TEGRA20_I2S_CTRL_FIFO1_ENABLE); + 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) { - regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, - TEGRA20_I2S_CTRL_FIFO1_ENABLE, 0); + 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) { - regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, - TEGRA20_I2S_CTRL_FIFO2_ENABLE, - TEGRA20_I2S_CTRL_FIFO2_ENABLE); + 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) { - regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, - TEGRA20_I2S_CTRL_FIFO2_ENABLE, 0); + 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, @@ -259,14 +261,12 @@ static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = { static const struct snd_soc_dai_driver tegra20_i2s_dai_template = { .probe = tegra20_i2s_probe, .playback = { - .stream_name = "Playback", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_96000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { - .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_96000, @@ -412,6 +412,8 @@ static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev) 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); diff --git a/trunk/sound/soc/tegra/tegra20_i2s.h b/trunk/sound/soc/tegra/tegra20_i2s.h index c27069d24d77..a57efc6a597e 100644 --- a/trunk/sound/soc/tegra/tegra20_i2s.h +++ b/trunk/sound/soc/tegra/tegra20_i2s.h @@ -158,6 +158,7 @@ struct tegra20_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/trunk/sound/soc/tegra/tegra20_spdif.c b/trunk/sound/soc/tegra/tegra20_spdif.c index 5c33c618929d..f9b57418bd08 100644 --- a/trunk/sound/soc/tegra/tegra20_spdif.c +++ b/trunk/sound/soc/tegra/tegra20_spdif.c @@ -37,6 +37,19 @@ #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); @@ -64,24 +77,21 @@ 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 = dai->dev; + struct device *dev = substream->pcm->card->dev; struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); - unsigned int mask, val; int ret, spdifclock; - mask = TEGRA20_SPDIF_CTRL_PACK | - TEGRA20_SPDIF_CTRL_BIT_MODE_MASK; + 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: - val = TEGRA20_SPDIF_CTRL_PACK | - TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT; + spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_PACK; + spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT; break; default: return -EINVAL; } - regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, mask, val); - switch (params_rate(params)) { case 32000: spdifclock = 4096000; @@ -119,15 +129,14 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, static void tegra20_spdif_start_playback(struct tegra20_spdif *spdif) { - regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, - TEGRA20_SPDIF_CTRL_TX_EN, - TEGRA20_SPDIF_CTRL_TX_EN); + 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) { - regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, - TEGRA20_SPDIF_CTRL_TX_EN, 0); + 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, @@ -172,7 +181,6 @@ static struct snd_soc_dai_driver tegra20_spdif_dai = { .name = DRV_NAME, .probe = tegra20_spdif_probe, .playback = { - .stream_name = "Playback", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | diff --git a/trunk/sound/soc/tegra/tegra20_spdif.h b/trunk/sound/soc/tegra/tegra20_spdif.h index b48d699fd583..ed756527efea 100644 --- a/trunk/sound/soc/tegra/tegra20_spdif.h +++ b/trunk/sound/soc/tegra/tegra20_spdif.h @@ -465,6 +465,7 @@ struct tegra20_spdif { 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/trunk/sound/soc/tegra/tegra30_i2s.c b/trunk/sound/soc/tegra/tegra30_i2s.c index b68e27a14608..8596032985dc 100644 --- a/trunk/sound/soc/tegra/tegra30_i2s.c +++ b/trunk/sound/soc/tegra/tegra30_i2s.c @@ -44,6 +44,18 @@ #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); @@ -116,7 +128,6 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); - unsigned int mask, val; switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: @@ -125,10 +136,10 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, return -EINVAL; } - mask = TEGRA30_I2S_CTRL_MASTER_ENABLE; + i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_MASTER_ENABLE; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: - val = TEGRA30_I2S_CTRL_MASTER_ENABLE; + i2s->reg_ctrl |= TEGRA30_I2S_CTRL_MASTER_ENABLE; break; case SND_SOC_DAIFMT_CBM_CFM: break; @@ -136,37 +147,33 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, return -EINVAL; } - mask |= TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK | - TEGRA30_I2S_CTRL_LRCK_MASK; + 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: - val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; - val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; + 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: - val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; - val |= TEGRA30_I2S_CTRL_LRCK_R_LOW; + i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; + i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW; break; case SND_SOC_DAIFMT_I2S: - val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; - val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; + 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: - val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; - val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; + 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: - val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; - val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; + i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; + i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW; break; default: return -EINVAL; } - pm_runtime_get_sync(dai->dev); - regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, mask, val); - pm_runtime_put(dai->dev); - return 0; } @@ -174,26 +181,24 @@ 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 = dai->dev; + struct device *dev = substream->pcm->card->dev; struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); - unsigned int mask, val, reg; + u32 val; int ret, sample_size, srate, i2sclock, bitcnt; if (params_channels(params) != 2) return -EINVAL; - mask = TEGRA30_I2S_CTRL_BIT_SIZE_MASK; + i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: - val = TEGRA30_I2S_CTRL_BIT_SIZE_16; + i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16; sample_size = 16; break; default: return -EINVAL; } - regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, mask, val); - srate = params_rate(params); /* Final "* 2" required by Tegra hardware */ @@ -214,7 +219,7 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, if (i2sclock % (2 * srate)) val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; - regmap_write(i2s->regmap, TEGRA30_I2S_TIMING, val); + tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val); val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | @@ -224,17 +229,15 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; - reg = TEGRA30_I2S_CIF_RX_CTRL; + tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val); } else { val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; - reg = TEGRA30_I2S_CIF_RX_CTRL; + tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val); } - regmap_write(i2s->regmap, reg, val); - val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); - regmap_write(i2s->regmap, TEGRA30_I2S_OFFSET, val); + tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val); return 0; } @@ -242,31 +245,29 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s) { tegra30_ahub_enable_tx_fifo(i2s->playback_fifo_cif); - regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, - TEGRA30_I2S_CTRL_XFER_EN_TX, - TEGRA30_I2S_CTRL_XFER_EN_TX); + 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); - regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, - TEGRA30_I2S_CTRL_XFER_EN_TX, 0); + 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); - regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, - TEGRA30_I2S_CTRL_XFER_EN_RX, - TEGRA30_I2S_CTRL_XFER_EN_RX); + 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); - regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, - TEGRA30_I2S_CTRL_XFER_EN_RX, 0); + 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, @@ -319,14 +320,12 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = { static const struct snd_soc_dai_driver tegra30_i2s_dai_template = { .probe = tegra30_i2s_probe, .playback = { - .stream_name = "Playback", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_96000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { - .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_96000, diff --git a/trunk/sound/soc/tegra/tegra30_i2s.h b/trunk/sound/soc/tegra/tegra30_i2s.h index 34dc47b9581c..91adf29c7a87 100644 --- a/trunk/sound/soc/tegra/tegra30_i2s.h +++ b/trunk/sound/soc/tegra/tegra30_i2s.h @@ -236,6 +236,7 @@ struct tegra30_i2s { enum tegra30_ahub_txcif playback_fifo_cif; struct tegra_pcm_dma_params playback_dma_data; struct regmap *regmap; + u32 reg_ctrl; }; #endif diff --git a/trunk/sound/soc/tegra/tegra_alc5632.c b/trunk/sound/soc/tegra/tegra_alc5632.c index d684df294c0c..32de7006daf0 100644 --- a/trunk/sound/soc/tegra/tegra_alc5632.c +++ b/trunk/sound/soc/tegra/tegra_alc5632.c @@ -1,5 +1,5 @@ /* -* tegra_alc5632.c -- Toshiba AC100(PAZ00) machine ASoC driver + * tegra_alc5632.c -- Toshiba AC100(PAZ00) machine ASoC driver * * Copyright (C) 2011 The AC100 Kernel Team * Copyright (C) 2012 - NVIDIA, Inc. @@ -33,8 +33,11 @@ #define DRV_NAME "tegra-alc5632" +#define GPIO_HP_DET BIT(0) + struct tegra_alc5632 { struct tegra_asoc_utils_data util_data; + int gpio_requested; int gpio_hp_det; }; @@ -43,7 +46,7 @@ static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_alc5632 *alc5632 = snd_soc_card_get_drvdata(card); int srate, mclk; @@ -105,9 +108,9 @@ static const struct snd_kcontrol_new tegra_alc5632_controls[] = { static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; + struct device_node *np = codec->card->dev->of_node; struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(codec->card); snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, @@ -116,11 +119,14 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) ARRAY_SIZE(tegra_alc5632_hs_jack_pins), tegra_alc5632_hs_jack_pins); + machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); + if (gpio_is_valid(machine->gpio_hp_det)) { tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det; snd_soc_jack_add_gpios(&tegra_alc5632_hs_jack, 1, &tegra_alc5632_hp_jack_gpio); + machine->gpio_requested |= GPIO_HP_DET; } snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); @@ -153,7 +159,6 @@ static struct snd_soc_card snd_soc_tegra_alc5632 = { static __devinit int tegra_alc5632_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct snd_soc_card *card = &snd_soc_tegra_alc5632; struct tegra_alc5632 *alc5632; int ret; @@ -176,10 +181,6 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev) goto err; } - alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); - if (alc5632->gpio_hp_det == -ENODEV) - return -EPROBE_DEFER; - ret = snd_soc_of_parse_card_name(card, "nvidia,model"); if (ret) goto err; @@ -198,16 +199,16 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev) goto err; } - tegra_alc5632_dai.cpu_of_node = of_parse_phandle( + tegra_alc5632_dai.cpu_dai_of_node = of_parse_phandle( pdev->dev.of_node, "nvidia,i2s-controller", 0); - if (!tegra_alc5632_dai.cpu_of_node) { + if (!tegra_alc5632_dai.cpu_dai_of_node) { dev_err(&pdev->dev, "Property 'nvidia,i2s-controller' missing or invalid\n"); ret = -EINVAL; goto err; } - tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_of_node; + 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) @@ -233,8 +234,11 @@ static int __devexit tegra_alc5632_remove(struct platform_device *pdev) struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card); - snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, 1, - &tegra_alc5632_hp_jack_gpio); + if (machine->gpio_requested & GPIO_HP_DET) + snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, + 1, + &tegra_alc5632_hp_jack_gpio); + machine->gpio_requested = 0; snd_soc_unregister_card(card); diff --git a/trunk/sound/soc/tegra/tegra_wm8753.c b/trunk/sound/soc/tegra/tegra_wm8753.c index ea9166d5c4eb..4e77026807a2 100644 --- a/trunk/sound/soc/tegra/tegra_wm8753.c +++ b/trunk/sound/soc/tegra/tegra_wm8753.c @@ -57,7 +57,7 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; + 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; @@ -157,9 +157,9 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev) goto err; } - tegra_wm8753_dai.cpu_of_node = of_parse_phandle( + tegra_wm8753_dai.cpu_dai_of_node = of_parse_phandle( pdev->dev.of_node, "nvidia,i2s-controller", 0); - if (!tegra_wm8753_dai.cpu_of_node) { + if (!tegra_wm8753_dai.cpu_dai_of_node) { dev_err(&pdev->dev, "Property 'nvidia,i2s-controller' missing or invalid\n"); ret = -EINVAL; @@ -167,7 +167,7 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev) } tegra_wm8753_dai.platform_of_node = - tegra_wm8753_dai.cpu_of_node; + tegra_wm8753_dai.cpu_dai_of_node; ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); if (ret) diff --git a/trunk/sound/soc/tegra/tegra_wm8903.c b/trunk/sound/soc/tegra/tegra_wm8903.c index 08b5fef67b31..0b0df49d9d33 100644 --- a/trunk/sound/soc/tegra/tegra_wm8903.c +++ b/trunk/sound/soc/tegra/tegra_wm8903.c @@ -28,6 +28,8 @@ * */ +#include + #include #include #include @@ -48,9 +50,16 @@ #define DRV_NAME "tegra-snd-wm8903" +#define GPIO_SPKR_EN BIT(0) +#define GPIO_HP_MUTE BIT(1) +#define GPIO_INT_MIC_EN BIT(2) +#define GPIO_EXT_MIC_EN BIT(3) +#define GPIO_HP_DET BIT(4) + struct tegra_wm8903 { struct tegra_wm8903_platform_data pdata; struct tegra_asoc_utils_data util_data; + int gpio_requested; }; static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, @@ -58,7 +67,8 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); int srate, mclk; @@ -85,6 +95,24 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, return err; } + err = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + if (err < 0) { + dev_err(card->dev, "codec_dai fmt not set\n"); + return err; + } + + err = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + if (err < 0) { + dev_err(card->dev, "cpu_dai fmt not set\n"); + return err; + } + err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); if (err < 0) { @@ -132,7 +160,7 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); struct tegra_wm8903_platform_data *pdata = &machine->pdata; - if (!gpio_is_valid(pdata->gpio_spkr_en)) + if (!(machine->gpio_requested & GPIO_SPKR_EN)) return 0; gpio_set_value_cansleep(pdata->gpio_spkr_en, @@ -149,7 +177,7 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); struct tegra_wm8903_platform_data *pdata = &machine->pdata; - if (!gpio_is_valid(pdata->gpio_hp_mute)) + if (!(machine->gpio_requested & GPIO_HP_MUTE)) return 0; gpio_set_value_cansleep(pdata->gpio_hp_mute, @@ -175,18 +203,122 @@ static const struct snd_soc_dapm_route harmony_audio_map[] = { {"IN1L", NULL, "Mic Jack"}, }; +static const struct snd_soc_dapm_route seaboard_audio_map[] = { + {"Headphone Jack", NULL, "HPOUTR"}, + {"Headphone Jack", NULL, "HPOUTL"}, + {"Int Spk", NULL, "ROP"}, + {"Int Spk", NULL, "RON"}, + {"Int Spk", NULL, "LOP"}, + {"Int Spk", NULL, "LON"}, + {"Mic Jack", NULL, "MICBIAS"}, + {"IN1R", NULL, "Mic Jack"}, +}; + +static const struct snd_soc_dapm_route kaen_audio_map[] = { + {"Headphone Jack", NULL, "HPOUTR"}, + {"Headphone Jack", NULL, "HPOUTL"}, + {"Int Spk", NULL, "ROP"}, + {"Int Spk", NULL, "RON"}, + {"Int Spk", NULL, "LOP"}, + {"Int Spk", NULL, "LON"}, + {"Mic Jack", NULL, "MICBIAS"}, + {"IN2R", NULL, "Mic Jack"}, +}; + +static const struct snd_soc_dapm_route aebl_audio_map[] = { + {"Headphone Jack", NULL, "HPOUTR"}, + {"Headphone Jack", NULL, "HPOUTL"}, + {"Int Spk", NULL, "LINEOUTR"}, + {"Int Spk", NULL, "LINEOUTL"}, + {"Mic Jack", NULL, "MICBIAS"}, + {"IN1R", NULL, "Mic Jack"}, +}; + static const struct snd_kcontrol_new tegra_wm8903_controls[] = { SOC_DAPM_PIN_SWITCH("Int Spk"), }; static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_card *card = codec->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); struct tegra_wm8903_platform_data *pdata = &machine->pdata; + struct device_node *np = card->dev->of_node; + int ret; + + if (card->dev->platform_data) { + memcpy(pdata, card->dev->platform_data, sizeof(*pdata)); + } else if (np) { + /* + * This part must be in init() rather than probe() in order to + * guarantee that the WM8903 has been probed, and hence its + * GPIO controller registered, which is a pre-condition for + * of_get_named_gpio() to be able to map the phandles in the + * properties to the controller node. Given this, all + * pdata handling is in init() for consistency. + */ + pdata->gpio_spkr_en = of_get_named_gpio(np, + "nvidia,spkr-en-gpios", 0); + pdata->gpio_hp_mute = of_get_named_gpio(np, + "nvidia,hp-mute-gpios", 0); + pdata->gpio_hp_det = of_get_named_gpio(np, + "nvidia,hp-det-gpios", 0); + pdata->gpio_int_mic_en = of_get_named_gpio(np, + "nvidia,int-mic-en-gpios", 0); + pdata->gpio_ext_mic_en = of_get_named_gpio(np, + "nvidia,ext-mic-en-gpios", 0); + } else { + dev_err(card->dev, "No platform data supplied\n"); + return -EINVAL; + } + + if (gpio_is_valid(pdata->gpio_spkr_en)) { + ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); + if (ret) { + dev_err(card->dev, "cannot get spkr_en gpio\n"); + return ret; + } + machine->gpio_requested |= GPIO_SPKR_EN; + + gpio_direction_output(pdata->gpio_spkr_en, 0); + } + + if (gpio_is_valid(pdata->gpio_hp_mute)) { + ret = gpio_request(pdata->gpio_hp_mute, "hp_mute"); + if (ret) { + dev_err(card->dev, "cannot get hp_mute gpio\n"); + return ret; + } + machine->gpio_requested |= GPIO_HP_MUTE; + + gpio_direction_output(pdata->gpio_hp_mute, 1); + } + + if (gpio_is_valid(pdata->gpio_int_mic_en)) { + ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); + if (ret) { + dev_err(card->dev, "cannot get int_mic_en gpio\n"); + return ret; + } + machine->gpio_requested |= GPIO_INT_MIC_EN; + + /* Disable int mic; enable signal is active-high */ + gpio_direction_output(pdata->gpio_int_mic_en, 0); + } + + if (gpio_is_valid(pdata->gpio_ext_mic_en)) { + ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); + if (ret) { + dev_err(card->dev, "cannot get ext_mic_en gpio\n"); + return ret; + } + machine->gpio_requested |= GPIO_EXT_MIC_EN; + + /* Enable ext mic; enable signal is active-low */ + gpio_direction_output(pdata->gpio_ext_mic_en, 0); + } if (gpio_is_valid(pdata->gpio_hp_det)) { tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det; @@ -198,6 +330,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, 1, &tegra_wm8903_hp_jack_gpio); + machine->gpio_requested |= GPIO_HP_DET; } snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, @@ -222,9 +355,6 @@ static struct snd_soc_dai_link tegra_wm8903_dai = { .codec_dai_name = "wm8903-hifi", .init = tegra_wm8903_init, .ops = &tegra_wm8903_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_wm8903 = { @@ -242,10 +372,8 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = { static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct snd_soc_card *card = &snd_soc_tegra_wm8903; struct tegra_wm8903 *machine; - struct tegra_wm8903_platform_data *pdata; int ret; if (!pdev->dev.platform_data && !pdev->dev.of_node) { @@ -260,42 +388,12 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) ret = -ENOMEM; goto err; } - pdata = &machine->pdata; card->dev = &pdev->dev; platform_set_drvdata(pdev, card); snd_soc_card_set_drvdata(card, machine); - if (pdev->dev.platform_data) { - memcpy(pdata, card->dev->platform_data, sizeof(*pdata)); - } else if (np) { - pdata->gpio_spkr_en = of_get_named_gpio(np, - "nvidia,spkr-en-gpios", 0); - if (pdata->gpio_spkr_en == -ENODEV) - return -EPROBE_DEFER; - - pdata->gpio_hp_mute = of_get_named_gpio(np, - "nvidia,hp-mute-gpios", 0); - if (pdata->gpio_hp_mute == -ENODEV) - return -EPROBE_DEFER; - - pdata->gpio_hp_det = of_get_named_gpio(np, - "nvidia,hp-det-gpios", 0); - if (pdata->gpio_hp_det == -ENODEV) - return -EPROBE_DEFER; - - pdata->gpio_int_mic_en = of_get_named_gpio(np, - "nvidia,int-mic-en-gpios", 0); - if (pdata->gpio_int_mic_en == -ENODEV) - return -EPROBE_DEFER; - - pdata->gpio_ext_mic_en = of_get_named_gpio(np, - "nvidia,ext-mic-en-gpios", 0); - if (pdata->gpio_ext_mic_en == -ENODEV) - return -EPROBE_DEFER; - } - - if (np) { + if (pdev->dev.of_node) { ret = snd_soc_of_parse_card_name(card, "nvidia,model"); if (ret) goto err; @@ -306,8 +404,8 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) goto err; tegra_wm8903_dai.codec_name = NULL; - tegra_wm8903_dai.codec_of_node = of_parse_phandle(np, - "nvidia,audio-codec", 0); + tegra_wm8903_dai.codec_of_node = of_parse_phandle( + pdev->dev.of_node, "nvidia,audio-codec", 0); if (!tegra_wm8903_dai.codec_of_node) { dev_err(&pdev->dev, "Property 'nvidia,audio-codec' missing or invalid\n"); @@ -316,9 +414,9 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) } tegra_wm8903_dai.cpu_dai_name = NULL; - tegra_wm8903_dai.cpu_of_node = of_parse_phandle(np, - "nvidia,i2s-controller", 0); - if (!tegra_wm8903_dai.cpu_of_node) { + tegra_wm8903_dai.cpu_dai_of_node = of_parse_phandle( + pdev->dev.of_node, "nvidia,i2s-controller", 0); + if (!tegra_wm8903_dai.cpu_dai_of_node) { dev_err(&pdev->dev, "Property 'nvidia,i2s-controller' missing or invalid\n"); ret = -EINVAL; @@ -327,47 +425,20 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) tegra_wm8903_dai.platform_name = NULL; tegra_wm8903_dai.platform_of_node = - tegra_wm8903_dai.cpu_of_node; + tegra_wm8903_dai.cpu_dai_of_node; } else { - card->dapm_routes = harmony_audio_map; - card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); - } - - if (gpio_is_valid(pdata->gpio_spkr_en)) { - ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_spkr_en, - GPIOF_OUT_INIT_LOW, "spkr_en"); - if (ret) { - dev_err(card->dev, "cannot get spkr_en gpio\n"); - return ret; - } - } - - if (gpio_is_valid(pdata->gpio_hp_mute)) { - ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_hp_mute, - GPIOF_OUT_INIT_HIGH, "hp_mute"); - if (ret) { - dev_err(card->dev, "cannot get hp_mute gpio\n"); - return ret; - } - } - - if (gpio_is_valid(pdata->gpio_int_mic_en)) { - /* Disable int mic; enable signal is active-high */ - ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_int_mic_en, - GPIOF_OUT_INIT_LOW, "int_mic_en"); - if (ret) { - dev_err(card->dev, "cannot get int_mic_en gpio\n"); - return ret; - } - } - - if (gpio_is_valid(pdata->gpio_ext_mic_en)) { - /* Enable ext mic; enable signal is active-low */ - ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_ext_mic_en, - GPIOF_OUT_INIT_LOW, "ext_mic_en"); - if (ret) { - dev_err(card->dev, "cannot get ext_mic_en gpio\n"); - return ret; + if (machine_is_harmony()) { + card->dapm_routes = harmony_audio_map; + card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); + } else if (machine_is_seaboard()) { + card->dapm_routes = seaboard_audio_map; + card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); + } else if (machine_is_kaen()) { + card->dapm_routes = kaen_audio_map; + card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map); + } else { + card->dapm_routes = aebl_audio_map; + card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map); } } @@ -394,9 +465,21 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); + struct tegra_wm8903_platform_data *pdata = &machine->pdata; - snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 1, - &tegra_wm8903_hp_jack_gpio); + if (machine->gpio_requested & GPIO_HP_DET) + snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, + 1, + &tegra_wm8903_hp_jack_gpio); + if (machine->gpio_requested & GPIO_EXT_MIC_EN) + gpio_free(pdata->gpio_ext_mic_en); + if (machine->gpio_requested & GPIO_INT_MIC_EN) + gpio_free(pdata->gpio_int_mic_en); + if (machine->gpio_requested & GPIO_HP_MUTE) + gpio_free(pdata->gpio_hp_mute); + if (machine->gpio_requested & GPIO_SPKR_EN) + gpio_free(pdata->gpio_spkr_en); + machine->gpio_requested = 0; snd_soc_unregister_card(card); diff --git a/trunk/sound/soc/tegra/trimslice.c b/trunk/sound/soc/tegra/trimslice.c index e69a4f7000d6..4a8d5b672c9f 100644 --- a/trunk/sound/soc/tegra/trimslice.c +++ b/trunk/sound/soc/tegra/trimslice.c @@ -52,7 +52,8 @@ static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); int srate, mclk; @@ -67,6 +68,24 @@ static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, return err; } + err = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + if (err < 0) { + dev_err(card->dev, "codec_dai fmt not set\n"); + return err; + } + + err = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + if (err < 0) { + dev_err(card->dev, "cpu_dai fmt not set\n"); + return err; + } + err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); if (err < 0) { @@ -102,9 +121,6 @@ static struct snd_soc_dai_link trimslice_tlv320aic23_dai = { .cpu_dai_name = "tegra20-i2s.0", .codec_dai_name = "tlv320aic23-hifi", .ops = &trimslice_asoc_ops, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, }; static struct snd_soc_card snd_soc_trimslice = { @@ -146,9 +162,9 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev) } trimslice_tlv320aic23_dai.cpu_dai_name = NULL; - trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle( + trimslice_tlv320aic23_dai.cpu_dai_of_node = of_parse_phandle( pdev->dev.of_node, "nvidia,i2s-controller", 0); - if (!trimslice_tlv320aic23_dai.cpu_of_node) { + if (!trimslice_tlv320aic23_dai.cpu_dai_of_node) { dev_err(&pdev->dev, "Property 'nvidia,i2s-controller' missing or invalid\n"); ret = -EINVAL; @@ -157,7 +173,7 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev) trimslice_tlv320aic23_dai.platform_name = NULL; trimslice_tlv320aic23_dai.platform_of_node = - trimslice_tlv320aic23_dai.cpu_of_node; + trimslice_tlv320aic23_dai.cpu_dai_of_node; } ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); diff --git a/trunk/sound/soc/ux500/Kconfig b/trunk/sound/soc/ux500/Kconfig index 1d385150064f..44cf43404cd9 100644 --- a/trunk/sound/soc/ux500/Kconfig +++ b/trunk/sound/soc/ux500/Kconfig @@ -12,10 +12,3 @@ menuconfig SND_SOC_UX500 config SND_SOC_UX500_PLAT_MSP_I2S tristate depends on SND_SOC_UX500 - -config SND_SOC_UX500_PLAT_DMA - tristate "Platform - DB8500 (DMA)" - depends on SND_SOC_UX500 - select SND_SOC_DMAENGINE_PCM - help - Say Y if you want to enable the Ux500 platform-driver. diff --git a/trunk/sound/soc/ux500/Makefile b/trunk/sound/soc/ux500/Makefile index 4634bf015f62..19974c5a2ea1 100644 --- a/trunk/sound/soc/ux500/Makefile +++ b/trunk/sound/soc/ux500/Makefile @@ -2,6 +2,3 @@ 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 - -snd-soc-ux500-plat-dma-objs := ux500_pcm.o -obj-$(CONFIG_SND_SOC_UX500_PLAT_DMA) += snd-soc-ux500-plat-dma.o diff --git a/trunk/sound/soc/ux500/ux500_pcm.c b/trunk/sound/soc/ux500/ux500_pcm.c deleted file mode 100644 index 66b080e5de96..000000000000 --- a/trunk/sound/soc/ux500/ux500_pcm.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2012 - * - * Author: Ola Lilja , - * Roger Nilsson - * 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 - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "ux500_msp_i2s.h" -#include "ux500_pcm.h" - -static struct snd_pcm_hardware ux500_pcm_hw_playback = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_PAUSE, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_U16_LE | - SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_U16_BE, - .rates = SNDRV_PCM_RATE_KNOT, - .rate_min = UX500_PLATFORM_MIN_RATE_PLAYBACK, - .rate_max = UX500_PLATFORM_MAX_RATE_PLAYBACK, - .channels_min = UX500_PLATFORM_MIN_CHANNELS, - .channels_max = UX500_PLATFORM_MAX_CHANNELS, - .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX, - .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN, - .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX, - .periods_min = UX500_PLATFORM_PERIODS_MIN, - .periods_max = UX500_PLATFORM_PERIODS_MAX, -}; - -static struct snd_pcm_hardware ux500_pcm_hw_capture = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_PAUSE, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_U16_LE | - SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_U16_BE, - .rates = SNDRV_PCM_RATE_KNOT, - .rate_min = UX500_PLATFORM_MIN_RATE_CAPTURE, - .rate_max = UX500_PLATFORM_MAX_RATE_CAPTURE, - .channels_min = UX500_PLATFORM_MIN_CHANNELS, - .channels_max = UX500_PLATFORM_MAX_CHANNELS, - .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX, - .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN, - .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX, - .periods_min = UX500_PLATFORM_PERIODS_MIN, - .periods_max = UX500_PLATFORM_PERIODS_MAX, -}; - -static void ux500_pcm_dma_hw_free(struct device *dev, - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *buf = runtime->dma_buffer_p; - - if (runtime->dma_area == NULL) - return; - - if (buf != &substream->dma_buffer) { - dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, - buf->addr); - kfree(runtime->dma_buffer_p); - } - - snd_pcm_set_runtime_buffer(substream, NULL); -} - -static int ux500_pcm_open(struct snd_pcm_substream *substream) -{ - int stream_id = substream->pstr->stream; - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *dai = rtd->cpu_dai; - struct device *dev = dai->dev; - int ret; - struct ux500_msp_dma_params *dma_params; - u16 per_data_width, mem_data_width; - struct stedma40_chan_cfg *dma_cfg; - - dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id, - snd_pcm_stream_str(substream)); - - dev_dbg(dev, "%s: Set runtime hwparams.\n", __func__); - if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_set_runtime_hwparams(substream, - &ux500_pcm_hw_playback); - else - snd_soc_set_runtime_hwparams(substream, - &ux500_pcm_hw_capture); - - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) { - dev_err(dev, "%s: Error: snd_pcm_hw_constraints failed (%d)\n", - __func__, ret); - return ret; - } - - dev_dbg(dev, "%s: Set hw-struct for %s.\n", __func__, - snd_pcm_stream_str(substream)); - runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ? - ux500_pcm_hw_playback : ux500_pcm_hw_capture; - - mem_data_width = STEDMA40_HALFWORD_WIDTH; - - dma_params = snd_soc_dai_get_dma_data(dai, substream); - switch (dma_params->data_size) { - case 32: - per_data_width = STEDMA40_WORD_WIDTH; - break; - case 16: - per_data_width = STEDMA40_HALFWORD_WIDTH; - break; - case 8: - per_data_width = STEDMA40_BYTE_WIDTH; - break; - default: - per_data_width = STEDMA40_WORD_WIDTH; - dev_warn(rtd->platform->dev, - "%s: Unknown data-size (%d)! Assuming 32 bits.\n", - __func__, dma_params->data_size); - } - - dma_cfg = dma_params->dma_cfg; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - dma_cfg->src_info.data_width = mem_data_width; - dma_cfg->dst_info.data_width = per_data_width; - } else { - dma_cfg->src_info.data_width = per_data_width; - dma_cfg->dst_info.data_width = mem_data_width; - } - - - ret = snd_dmaengine_pcm_open(substream, stedma40_filter, dma_cfg); - if (ret) { - dev_dbg(dai->dev, - "%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n", - __func__, ret); - return ret; - } - - snd_dmaengine_pcm_set_data(substream, dma_cfg); - - return 0; -} - -static int ux500_pcm_close(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *dai = rtd->cpu_dai; - - dev_dbg(dai->dev, "%s: Enter\n", __func__); - - snd_dmaengine_pcm_close(substream); - - return 0; -} - -static int ux500_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *buf = runtime->dma_buffer_p; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - int ret = 0; - int size; - - dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__); - - size = params_buffer_bytes(hw_params); - - if (buf) { - if (buf->bytes >= size) - goto out; - ux500_pcm_dma_hw_free(NULL, substream); - } - - if (substream->dma_buffer.area != NULL && - substream->dma_buffer.bytes >= size) { - buf = &substream->dma_buffer; - } else { - buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL); - if (!buf) - goto nomem; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = NULL; - buf->area = dma_alloc_coherent(NULL, size, &buf->addr, - GFP_KERNEL); - buf->bytes = size; - buf->private_data = NULL; - - if (!buf->area) - goto free; - } - snd_pcm_set_runtime_buffer(substream, buf); - ret = 1; - out: - runtime->dma_bytes = size; - return ret; - - free: - kfree(buf); - nomem: - return -ENOMEM; -} - -static int ux500_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__); - - ux500_pcm_dma_hw_free(NULL, substream); - - return 0; -} - -static int ux500_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - dev_dbg(rtd->platform->dev, "%s: Enter.\n", __func__); - - return dma_mmap_coherent(NULL, vma, runtime->dma_area, - runtime->dma_addr, runtime->dma_bytes); -} - -static struct snd_pcm_ops ux500_pcm_ops = { - .open = ux500_pcm_open, - .close = ux500_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = ux500_pcm_hw_params, - .hw_free = ux500_pcm_hw_free, - .trigger = snd_dmaengine_pcm_trigger, - .pointer = snd_dmaengine_pcm_pointer, - .mmap = ux500_pcm_mmap -}; - -int ux500_pcm_new(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_pcm *pcm = rtd->pcm; - - dev_dbg(rtd->platform->dev, "%s: Enter (id = '%s').\n", __func__, - pcm->id); - - pcm->info_flags = 0; - - return 0; -} - -static struct snd_soc_platform_driver ux500_pcm_soc_drv = { - .ops = &ux500_pcm_ops, - .pcm_new = ux500_pcm_new, -}; - -static int __devexit ux500_pcm_drv_probe(struct platform_device *pdev) -{ - int ret; - - ret = snd_soc_register_platform(&pdev->dev, &ux500_pcm_soc_drv); - if (ret < 0) { - dev_err(&pdev->dev, - "%s: ERROR: Failed to register platform '%s' (%d)!\n", - __func__, pdev->name, ret); - return ret; - } - - return 0; -} - -static int __devinit ux500_pcm_drv_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - - return 0; -} - -static struct platform_driver ux500_pcm_driver = { - .driver = { - .name = "ux500-pcm", - .owner = THIS_MODULE, - }, - - .probe = ux500_pcm_drv_probe, - .remove = __devexit_p(ux500_pcm_drv_remove), -}; -module_platform_driver(ux500_pcm_driver); - -MODULE_LICENSE("GPLv2"); diff --git a/trunk/sound/soc/ux500/ux500_pcm.h b/trunk/sound/soc/ux500/ux500_pcm.h deleted file mode 100644 index 77ed44d371e9..000000000000 --- a/trunk/sound/soc/ux500/ux500_pcm.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2012 - * - * Author: Ola Lilja , - * Roger Nilsson - * 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_PCM_H -#define UX500_PCM_H - -#include - -#include - -#define UX500_PLATFORM_MIN_RATE_PLAYBACK 8000 -#define UX500_PLATFORM_MAX_RATE_PLAYBACK 48000 -#define UX500_PLATFORM_MIN_RATE_CAPTURE 8000 -#define UX500_PLATFORM_MAX_RATE_CAPTURE 48000 - -#define UX500_PLATFORM_MIN_CHANNELS 1 -#define UX500_PLATFORM_MAX_CHANNELS 8 - -#define UX500_PLATFORM_PERIODS_BYTES_MIN 128 -#define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE) -#define UX500_PLATFORM_PERIODS_MIN 2 -#define UX500_PLATFORM_PERIODS_MAX 48 -#define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) - -#endif diff --git a/trunk/tools/perf/MANIFEST b/trunk/tools/perf/MANIFEST index 5476bc0a1eac..b4b572e8c100 100644 --- a/trunk/tools/perf/MANIFEST +++ b/trunk/tools/perf/MANIFEST @@ -1,4 +1,6 @@ tools/perf +tools/scripts +tools/lib/traceevent include/linux/const.h include/linux/perf_event.h include/linux/rbtree.h diff --git a/trunk/tools/perf/builtin-report.c b/trunk/tools/perf/builtin-report.c index 8c767c6bca91..25249f76329d 100644 --- a/trunk/tools/perf/builtin-report.c +++ b/trunk/tools/perf/builtin-report.c @@ -152,7 +152,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, if (symbol_conf.use_callchain) { err = callchain_append(he->callchain, - &evsel->hists.callchain_cursor, + &callchain_cursor, sample->period); if (err) return err; @@ -162,7 +162,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, * so we don't allocated the extra space needed because the stdio * code will not use it. */ - if (al->sym != NULL && use_browser > 0) { + if (he->ms.sym != NULL && use_browser > 0) { struct annotation *notes = symbol__annotation(he->ms.sym); assert(evsel != NULL); diff --git a/trunk/tools/perf/builtin-stat.c b/trunk/tools/perf/builtin-stat.c index 62ae30d34fa6..262589991ea4 100644 --- a/trunk/tools/perf/builtin-stat.c +++ b/trunk/tools/perf/builtin-stat.c @@ -1129,7 +1129,7 @@ static int add_default_attributes(void) return 0; if (!evsel_list->nr_entries) { - if (perf_evlist__add_attrs_array(evsel_list, default_attrs) < 0) + if (perf_evlist__add_default_attrs(evsel_list, default_attrs) < 0) return -1; } @@ -1139,21 +1139,21 @@ static int add_default_attributes(void) return 0; /* Append detailed run extra attributes: */ - if (perf_evlist__add_attrs_array(evsel_list, detailed_attrs) < 0) + if (perf_evlist__add_default_attrs(evsel_list, detailed_attrs) < 0) return -1; if (detailed_run < 2) return 0; /* Append very detailed run extra attributes: */ - if (perf_evlist__add_attrs_array(evsel_list, very_detailed_attrs) < 0) + if (perf_evlist__add_default_attrs(evsel_list, very_detailed_attrs) < 0) return -1; if (detailed_run < 3) return 0; /* Append very, very detailed run extra attributes: */ - return perf_evlist__add_attrs_array(evsel_list, very_very_detailed_attrs); + return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs); } int cmd_stat(int argc, const char **argv, const char *prefix __used) diff --git a/trunk/tools/perf/builtin-top.c b/trunk/tools/perf/builtin-top.c index 871b540293e1..6bb0277b7dfe 100644 --- a/trunk/tools/perf/builtin-top.c +++ b/trunk/tools/perf/builtin-top.c @@ -787,7 +787,7 @@ static void perf_event__process_sample(struct perf_tool *tool, } if (symbol_conf.use_callchain) { - err = callchain_append(he->callchain, &evsel->hists.callchain_cursor, + err = callchain_append(he->callchain, &callchain_cursor, sample->period); if (err) return; diff --git a/trunk/tools/perf/design.txt b/trunk/tools/perf/design.txt index bd0bb1b1279b..67e5d0cace85 100644 --- a/trunk/tools/perf/design.txt +++ b/trunk/tools/perf/design.txt @@ -409,14 +409,15 @@ Counters can be enabled and disabled in two ways: via ioctl and via prctl. When a counter is disabled, it doesn't count or generate events but does continue to exist and maintain its count value. -An individual counter or counter group can be enabled with +An individual counter can be enabled with - ioctl(fd, PERF_EVENT_IOC_ENABLE); + ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); or disabled with - ioctl(fd, PERF_EVENT_IOC_DISABLE); + ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); +For a counter group, pass PERF_IOC_FLAG_GROUP as the third argument. Enabling or disabling the leader of a group enables or disables the whole group; that is, while the group leader is disabled, none of the counters in the group will count. Enabling or disabling a member of a diff --git a/trunk/tools/perf/ui/browsers/annotate.c b/trunk/tools/perf/ui/browsers/annotate.c index 4deea6aaf927..34b1c46eaf42 100644 --- a/trunk/tools/perf/ui/browsers/annotate.c +++ b/trunk/tools/perf/ui/browsers/annotate.c @@ -668,7 +668,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx, "q/ESC/CTRL+C Exit\n\n" "-> Go to target\n" "<- Exit\n" - "h Cycle thru hottest instructions\n" + "H Cycle thru hottest instructions\n" "j Toggle showing jump to target arrows\n" "J Toggle showing number of jump sources on targets\n" "n Search next string\n" diff --git a/trunk/tools/perf/util/PERF-VERSION-GEN b/trunk/tools/perf/util/PERF-VERSION-GEN index ad73300f7bac..95264f304179 100755 --- a/trunk/tools/perf/util/PERF-VERSION-GEN +++ b/trunk/tools/perf/util/PERF-VERSION-GEN @@ -12,7 +12,7 @@ LF=' # First check if there is a .git to get the version from git describe # otherwise try to get the version from the kernel makefile if test -d ../../.git -o -f ../../.git && - VN=$(git describe --abbrev=4 HEAD 2>/dev/null) && + VN=$(git describe --match 'v[0-9].[0-9]*' --abbrev=4 HEAD 2>/dev/null) && case "$VN" in *$LF*) (exit 1) ;; v[0-9]*) diff --git a/trunk/tools/perf/util/callchain.c b/trunk/tools/perf/util/callchain.c index 9f7106a8d9a4..3a6bff47614f 100644 --- a/trunk/tools/perf/util/callchain.c +++ b/trunk/tools/perf/util/callchain.c @@ -18,6 +18,8 @@ #include "util.h" #include "callchain.h" +__thread struct callchain_cursor callchain_cursor; + bool ip_callchain__valid(struct ip_callchain *chain, const union perf_event *event) { diff --git a/trunk/tools/perf/util/callchain.h b/trunk/tools/perf/util/callchain.h index 7f9c0f1ae3a9..3bdb407f9cd9 100644 --- a/trunk/tools/perf/util/callchain.h +++ b/trunk/tools/perf/util/callchain.h @@ -76,6 +76,8 @@ struct callchain_cursor { struct callchain_cursor_node *curr; }; +extern __thread struct callchain_cursor callchain_cursor; + static inline void callchain_init(struct callchain_root *root) { INIT_LIST_HEAD(&root->node.siblings); diff --git a/trunk/tools/perf/util/evlist.c b/trunk/tools/perf/util/evlist.c index 4ac5f5ae4ce9..7400fb3fc50c 100644 --- a/trunk/tools/perf/util/evlist.c +++ b/trunk/tools/perf/util/evlist.c @@ -159,6 +159,17 @@ int perf_evlist__add_attrs(struct perf_evlist *evlist, return -1; } +int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, + struct perf_event_attr *attrs, size_t nr_attrs) +{ + size_t i; + + for (i = 0; i < nr_attrs; i++) + event_attr_init(attrs + i); + + return perf_evlist__add_attrs(evlist, attrs, nr_attrs); +} + static int trace_event__id(const char *evname) { char *filename, *colon; @@ -263,7 +274,8 @@ void perf_evlist__disable(struct perf_evlist *evlist) for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { list_for_each_entry(pos, &evlist->entries, node) { for (thread = 0; thread < evlist->threads->nr; thread++) - ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE); + ioctl(FD(pos, cpu, thread), + PERF_EVENT_IOC_DISABLE, 0); } } } @@ -276,7 +288,8 @@ void perf_evlist__enable(struct perf_evlist *evlist) for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { list_for_each_entry(pos, &evlist->entries, node) { for (thread = 0; thread < evlist->threads->nr; thread++) - ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE); + ioctl(FD(pos, cpu, thread), + PERF_EVENT_IOC_ENABLE, 0); } } } diff --git a/trunk/tools/perf/util/evlist.h b/trunk/tools/perf/util/evlist.h index 58abb63ac13a..989bee9624c2 100644 --- a/trunk/tools/perf/util/evlist.h +++ b/trunk/tools/perf/util/evlist.h @@ -54,6 +54,8 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); int perf_evlist__add_default(struct perf_evlist *evlist); int perf_evlist__add_attrs(struct perf_evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs); +int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, + struct perf_event_attr *attrs, size_t nr_attrs); int perf_evlist__add_tracepoints(struct perf_evlist *evlist, const char *tracepoints[], size_t nr_tracepoints); int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, @@ -62,6 +64,8 @@ int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, #define perf_evlist__add_attrs_array(evlist, array) \ perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) +#define perf_evlist__add_default_attrs(evlist, array) \ + __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) #define perf_evlist__add_tracepoints_array(evlist, array) \ perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) diff --git a/trunk/tools/perf/util/evsel.c b/trunk/tools/perf/util/evsel.c index 91d19138f3ec..9f6cebd798ee 100644 --- a/trunk/tools/perf/util/evsel.c +++ b/trunk/tools/perf/util/evsel.c @@ -494,16 +494,24 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel, } static int perf_event__parse_id_sample(const union perf_event *event, u64 type, - struct perf_sample *sample) + struct perf_sample *sample, + bool swapped) { const u64 *array = event->sample.array; + union u64_swap u; array += ((event->header.size - sizeof(event->header)) / sizeof(u64)) - 1; if (type & PERF_SAMPLE_CPU) { - u32 *p = (u32 *)array; - sample->cpu = *p; + u.val64 = *array; + if (swapped) { + /* undo swap of u64, then swap on individual u32s */ + u.val64 = bswap_64(u.val64); + u.val32[0] = bswap_32(u.val32[0]); + } + + sample->cpu = u.val32[0]; array--; } @@ -523,9 +531,16 @@ static int perf_event__parse_id_sample(const union perf_event *event, u64 type, } if (type & PERF_SAMPLE_TID) { - u32 *p = (u32 *)array; - sample->pid = p[0]; - sample->tid = p[1]; + u.val64 = *array; + if (swapped) { + /* undo swap of u64, then swap on individual u32s */ + u.val64 = bswap_64(u.val64); + u.val32[0] = bswap_32(u.val32[0]); + u.val32[1] = bswap_32(u.val32[1]); + } + + sample->pid = u.val32[0]; + sample->tid = u.val32[1]; } return 0; @@ -562,7 +577,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, if (event->header.type != PERF_RECORD_SAMPLE) { if (!sample_id_all) return 0; - return perf_event__parse_id_sample(event, type, data); + return perf_event__parse_id_sample(event, type, data, swapped); } array = event->sample.array; diff --git a/trunk/tools/perf/util/hist.c b/trunk/tools/perf/util/hist.c index 1293b5ebea4d..514e2a4b367d 100644 --- a/trunk/tools/perf/util/hist.c +++ b/trunk/tools/perf/util/hist.c @@ -378,7 +378,7 @@ void hist_entry__free(struct hist_entry *he) * collapse the histogram */ -static bool hists__collapse_insert_entry(struct hists *hists, +static bool hists__collapse_insert_entry(struct hists *hists __used, struct rb_root *root, struct hist_entry *he) { @@ -397,8 +397,9 @@ static bool hists__collapse_insert_entry(struct hists *hists, iter->period += he->period; iter->nr_events += he->nr_events; if (symbol_conf.use_callchain) { - callchain_cursor_reset(&hists->callchain_cursor); - callchain_merge(&hists->callchain_cursor, iter->callchain, + callchain_cursor_reset(&callchain_cursor); + callchain_merge(&callchain_cursor, + iter->callchain, he->callchain); } hist_entry__free(he); diff --git a/trunk/tools/perf/util/hist.h b/trunk/tools/perf/util/hist.h index cfc64e293f90..34bb556d6219 100644 --- a/trunk/tools/perf/util/hist.h +++ b/trunk/tools/perf/util/hist.h @@ -67,8 +67,6 @@ struct hists { struct events_stats stats; u64 event_stream; u16 col_len[HISTC_NR_COLS]; - /* Best would be to reuse the session callchain cursor */ - struct callchain_cursor callchain_cursor; }; struct hist_entry *__hists__add_entry(struct hists *self, diff --git a/trunk/tools/perf/util/pager.c b/trunk/tools/perf/util/pager.c index 1915de20dcac..3322b8446e89 100644 --- a/trunk/tools/perf/util/pager.c +++ b/trunk/tools/perf/util/pager.c @@ -57,6 +57,10 @@ void setup_pager(void) } if (!pager) pager = getenv("PAGER"); + if (!pager) { + if (!access("/usr/bin/pager", X_OK)) + pager = "/usr/bin/pager"; + } if (!pager) pager = "less"; else if (!*pager || !strcmp(pager, "cat")) diff --git a/trunk/tools/perf/util/probe-event.c b/trunk/tools/perf/util/probe-event.c index 59dccc98b554..0dda25d82d06 100644 --- a/trunk/tools/perf/util/probe-event.c +++ b/trunk/tools/perf/util/probe-event.c @@ -2164,16 +2164,12 @@ int del_perf_probe_events(struct strlist *dellist) error: if (kfd >= 0) { - if (namelist) - strlist__delete(namelist); - + strlist__delete(namelist); close(kfd); } if (ufd >= 0) { - if (unamelist) - strlist__delete(unamelist); - + strlist__delete(unamelist); close(ufd); } diff --git a/trunk/tools/perf/util/session.c b/trunk/tools/perf/util/session.c index 93d355d27109..2600916efa83 100644 --- a/trunk/tools/perf/util/session.c +++ b/trunk/tools/perf/util/session.c @@ -288,7 +288,8 @@ struct branch_info *machine__resolve_bstack(struct machine *self, return bi; } -int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, +int machine__resolve_callchain(struct machine *self, + struct perf_evsel *evsel __used, struct thread *thread, struct ip_callchain *chain, struct symbol **parent) @@ -297,7 +298,12 @@ int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, unsigned int i; int err; - callchain_cursor_reset(&evsel->hists.callchain_cursor); + callchain_cursor_reset(&callchain_cursor); + + if (chain->nr > PERF_MAX_STACK_DEPTH) { + pr_warning("corrupted callchain. skipping...\n"); + return 0; + } for (i = 0; i < chain->nr; i++) { u64 ip; @@ -317,7 +323,14 @@ int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, case PERF_CONTEXT_USER: cpumode = PERF_RECORD_MISC_USER; break; default: - break; + pr_debug("invalid callchain context: " + "%"PRId64"\n", (s64) ip); + /* + * It seems the callchain is corrupted. + * Discard all. + */ + callchain_cursor_reset(&callchain_cursor); + return 0; } continue; } @@ -333,7 +346,7 @@ int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, break; } - err = callchain_cursor_append(&evsel->hists.callchain_cursor, + err = callchain_cursor_append(&callchain_cursor, ip, al.map, al.sym); if (err) return err; @@ -441,37 +454,65 @@ void mem_bswap_64(void *src, int byte_size) } } -static void perf_event__all64_swap(union perf_event *event) +static void swap_sample_id_all(union perf_event *event, void *data) +{ + void *end = (void *) event + event->header.size; + int size = end - data; + + BUG_ON(size % sizeof(u64)); + mem_bswap_64(data, size); +} + +static void perf_event__all64_swap(union perf_event *event, + bool sample_id_all __used) { struct perf_event_header *hdr = &event->header; mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr)); } -static void perf_event__comm_swap(union perf_event *event) +static void perf_event__comm_swap(union perf_event *event, bool sample_id_all) { event->comm.pid = bswap_32(event->comm.pid); event->comm.tid = bswap_32(event->comm.tid); + + if (sample_id_all) { + void *data = &event->comm.comm; + + data += ALIGN(strlen(data) + 1, sizeof(u64)); + swap_sample_id_all(event, data); + } } -static void perf_event__mmap_swap(union perf_event *event) +static void perf_event__mmap_swap(union perf_event *event, + bool sample_id_all) { event->mmap.pid = bswap_32(event->mmap.pid); event->mmap.tid = bswap_32(event->mmap.tid); event->mmap.start = bswap_64(event->mmap.start); event->mmap.len = bswap_64(event->mmap.len); event->mmap.pgoff = bswap_64(event->mmap.pgoff); + + if (sample_id_all) { + void *data = &event->mmap.filename; + + data += ALIGN(strlen(data) + 1, sizeof(u64)); + swap_sample_id_all(event, data); + } } -static void perf_event__task_swap(union perf_event *event) +static void perf_event__task_swap(union perf_event *event, bool sample_id_all) { event->fork.pid = bswap_32(event->fork.pid); event->fork.tid = bswap_32(event->fork.tid); event->fork.ppid = bswap_32(event->fork.ppid); event->fork.ptid = bswap_32(event->fork.ptid); event->fork.time = bswap_64(event->fork.time); + + if (sample_id_all) + swap_sample_id_all(event, &event->fork + 1); } -static void perf_event__read_swap(union perf_event *event) +static void perf_event__read_swap(union perf_event *event, bool sample_id_all) { event->read.pid = bswap_32(event->read.pid); event->read.tid = bswap_32(event->read.tid); @@ -479,6 +520,9 @@ static void perf_event__read_swap(union perf_event *event) event->read.time_enabled = bswap_64(event->read.time_enabled); event->read.time_running = bswap_64(event->read.time_running); event->read.id = bswap_64(event->read.id); + + if (sample_id_all) + swap_sample_id_all(event, &event->read + 1); } static u8 revbyte(u8 b) @@ -530,7 +574,8 @@ void perf_event__attr_swap(struct perf_event_attr *attr) swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); } -static void perf_event__hdr_attr_swap(union perf_event *event) +static void perf_event__hdr_attr_swap(union perf_event *event, + bool sample_id_all __used) { size_t size; @@ -541,18 +586,21 @@ static void perf_event__hdr_attr_swap(union perf_event *event) mem_bswap_64(event->attr.id, size); } -static void perf_event__event_type_swap(union perf_event *event) +static void perf_event__event_type_swap(union perf_event *event, + bool sample_id_all __used) { event->event_type.event_type.event_id = bswap_64(event->event_type.event_type.event_id); } -static void perf_event__tracing_data_swap(union perf_event *event) +static void perf_event__tracing_data_swap(union perf_event *event, + bool sample_id_all __used) { event->tracing_data.size = bswap_32(event->tracing_data.size); } -typedef void (*perf_event__swap_op)(union perf_event *event); +typedef void (*perf_event__swap_op)(union perf_event *event, + bool sample_id_all); static perf_event__swap_op perf_event__swap_ops[] = { [PERF_RECORD_MMAP] = perf_event__mmap_swap, @@ -986,6 +1034,15 @@ static int perf_session__process_user_event(struct perf_session *session, union } } +static void event_swap(union perf_event *event, bool sample_id_all) +{ + perf_event__swap_op swap; + + swap = perf_event__swap_ops[event->header.type]; + if (swap) + swap(event, sample_id_all); +} + static int perf_session__process_event(struct perf_session *session, union perf_event *event, struct perf_tool *tool, @@ -994,9 +1051,8 @@ static int perf_session__process_event(struct perf_session *session, struct perf_sample sample; int ret; - if (session->header.needs_swap && - perf_event__swap_ops[event->header.type]) - perf_event__swap_ops[event->header.type](event); + if (session->header.needs_swap) + event_swap(event, session->sample_id_all); if (event->header.type >= PERF_RECORD_HEADER_MAX) return -EINVAL; @@ -1428,7 +1484,6 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, int print_sym, int print_dso, int print_symoffset) { struct addr_location al; - struct callchain_cursor *cursor = &evsel->hists.callchain_cursor; struct callchain_cursor_node *node; if (perf_event__preprocess_sample(event, machine, &al, sample, @@ -1446,10 +1501,10 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, error("Failed to resolve callchain. Skipping\n"); return; } - callchain_cursor_commit(cursor); + callchain_cursor_commit(&callchain_cursor); while (1) { - node = callchain_cursor_current(cursor); + node = callchain_cursor_current(&callchain_cursor); if (!node) break; @@ -1460,12 +1515,12 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, } if (print_dso) { printf(" ("); - map__fprintf_dsoname(al.map, stdout); + map__fprintf_dsoname(node->map, stdout); printf(")"); } printf("\n"); - callchain_cursor_advance(cursor); + callchain_cursor_advance(&callchain_cursor); } } else { diff --git a/trunk/tools/perf/util/symbol.c b/trunk/tools/perf/util/symbol.c index e2ba8858f3e1..3e2e5ea0f03f 100644 --- a/trunk/tools/perf/util/symbol.c +++ b/trunk/tools/perf/util/symbol.c @@ -323,6 +323,7 @@ struct dso *dso__new(const char *name) dso->sorted_by_name = 0; dso->has_build_id = 0; dso->kernel = DSO_TYPE_USER; + dso->needs_swap = DSO_SWAP__UNSET; INIT_LIST_HEAD(&dso->node); } @@ -1156,6 +1157,33 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) return -1; } +static int dso__swap_init(struct dso *dso, unsigned char eidata) +{ + static unsigned int const endian = 1; + + dso->needs_swap = DSO_SWAP__NO; + + switch (eidata) { + case ELFDATA2LSB: + /* We are big endian, DSO is little endian. */ + if (*(unsigned char const *)&endian != 1) + dso->needs_swap = DSO_SWAP__YES; + break; + + case ELFDATA2MSB: + /* We are little endian, DSO is big endian. */ + if (*(unsigned char const *)&endian != 0) + dso->needs_swap = DSO_SWAP__YES; + break; + + default: + pr_err("unrecognized DSO data encoding %d\n", eidata); + return -EINVAL; + } + + return 0; +} + static int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, symbol_filter_t filter, int kmodule, int want_symtab) @@ -1187,6 +1215,9 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name, goto out_elf_end; } + if (dso__swap_init(dso, ehdr.e_ident[EI_DATA])) + goto out_elf_end; + /* Always reject images with a mismatched build-id: */ if (dso->has_build_id) { u8 build_id[BUILD_ID_SIZE]; @@ -1272,7 +1303,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name, if (opdsec && sym.st_shndx == opdidx) { u32 offset = sym.st_value - opdshdr.sh_addr; u64 *opd = opddata->d_buf + offset; - sym.st_value = *opd; + sym.st_value = DSO__SWAP(dso, u64, *opd); sym.st_shndx = elf_addr_to_index(elf, sym.st_value); } @@ -2786,8 +2817,11 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type, struct map *dso__new_map(const char *name) { + struct map *map = NULL; struct dso *dso = dso__new(name); - struct map *map = map__new2(0, dso, MAP__FUNCTION); + + if (dso) + map = map__new2(0, dso, MAP__FUNCTION); return map; } diff --git a/trunk/tools/perf/util/symbol.h b/trunk/tools/perf/util/symbol.h index 5649d63798cb..af0752b1aca1 100644 --- a/trunk/tools/perf/util/symbol.h +++ b/trunk/tools/perf/util/symbol.h @@ -9,6 +9,7 @@ #include #include #include +#include #ifdef HAVE_CPLUS_DEMANGLE extern char *cplus_demangle(const char *, int); @@ -160,11 +161,18 @@ enum dso_kernel_type { DSO_TYPE_GUEST_KERNEL }; +enum dso_swap_type { + DSO_SWAP__UNSET, + DSO_SWAP__NO, + DSO_SWAP__YES, +}; + struct dso { struct list_head node; struct rb_root symbols[MAP__NR_TYPES]; struct rb_root symbol_names[MAP__NR_TYPES]; enum dso_kernel_type kernel; + enum dso_swap_type needs_swap; u8 adjust_symbols:1; u8 has_build_id:1; u8 hit:1; @@ -182,6 +190,28 @@ struct dso { char name[0]; }; +#define DSO__SWAP(dso, type, val) \ +({ \ + type ____r = val; \ + BUG_ON(dso->needs_swap == DSO_SWAP__UNSET); \ + if (dso->needs_swap == DSO_SWAP__YES) { \ + switch (sizeof(____r)) { \ + case 2: \ + ____r = bswap_16(val); \ + break; \ + case 4: \ + ____r = bswap_32(val); \ + break; \ + case 8: \ + ____r = bswap_64(val); \ + break; \ + default: \ + BUG_ON(1); \ + } \ + } \ + ____r; \ +}) + struct dso *dso__new(const char *name); void dso__delete(struct dso *dso); diff --git a/trunk/tools/power/x86/turbostat/turbostat.c b/trunk/tools/power/x86/turbostat/turbostat.c index ab2f682fd44c..16de7ad4850f 100644 --- a/trunk/tools/power/x86/turbostat/turbostat.c +++ b/trunk/tools/power/x86/turbostat/turbostat.c @@ -73,8 +73,8 @@ int backwards_count; char *progname; int num_cpus; -cpu_set_t *cpu_mask; -size_t cpu_mask_size; +cpu_set_t *cpu_present_set, *cpu_mask; +size_t cpu_present_setsize, cpu_mask_size; struct counters { unsigned long long tsc; /* per thread */ @@ -103,6 +103,12 @@ struct timeval tv_even; struct timeval tv_odd; struct timeval tv_delta; +int mark_cpu_present(int pkg, int core, int cpu) +{ + CPU_SET_S(cpu, cpu_present_setsize, cpu_present_set); + return 0; +} + /* * cpu_mask_init(ncpus) * @@ -118,6 +124,18 @@ void cpu_mask_init(int ncpus) } cpu_mask_size = CPU_ALLOC_SIZE(ncpus); CPU_ZERO_S(cpu_mask_size, cpu_mask); + + /* + * Allocate and initialize cpu_present_set + */ + cpu_present_set = CPU_ALLOC(ncpus); + if (cpu_present_set == NULL) { + perror("CPU_ALLOC"); + exit(3); + } + cpu_present_setsize = CPU_ALLOC_SIZE(ncpus); + CPU_ZERO_S(cpu_present_setsize, cpu_present_set); + for_all_cpus(mark_cpu_present); } void cpu_mask_uninit() @@ -125,6 +143,9 @@ void cpu_mask_uninit() CPU_FREE(cpu_mask); cpu_mask = NULL; cpu_mask_size = 0; + CPU_FREE(cpu_present_set); + cpu_present_set = NULL; + cpu_present_setsize = 0; } int cpu_migrate(int cpu) @@ -912,6 +933,8 @@ int is_snb(unsigned int family, unsigned int model) switch (model) { case 0x2A: case 0x2D: + case 0x3A: /* IVB */ + case 0x3D: /* IVB Xeon */ return 1; } return 0; @@ -1047,6 +1070,9 @@ int fork_it(char **argv) int retval; pid_t child_pid; get_counters(cnt_even); + + /* clear affinity side-effect of get_counters() */ + sched_setaffinity(0, cpu_present_setsize, cpu_present_set); gettimeofday(&tv_even, (struct timezone *)NULL); child_pid = fork(); diff --git a/trunk/virt/kvm/irq_comm.c b/trunk/virt/kvm/irq_comm.c index a6a0365475ed..5afb43114020 100644 --- a/trunk/virt/kvm/irq_comm.c +++ b/trunk/virt/kvm/irq_comm.c @@ -332,6 +332,7 @@ static int setup_routing_entry(struct kvm_irq_routing_table *rt, */ hlist_for_each_entry(ei, n, &rt->map[ue->gsi], link) if (ei->type == KVM_IRQ_ROUTING_MSI || + ue->type == KVM_IRQ_ROUTING_MSI || ue->u.irqchip.irqchip == ei->irqchip.irqchip) return r;