summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-08-31 16:25:22 +0200
committerTakashi Iwai <tiwai@suse.de>2015-08-31 16:25:22 +0200
commit08ceab9d875824f8b389530e830349d5d6c4e582 (patch)
tree4ced69544742b87cb369de553df505870be593e1
parent22c103cd3dfadff340b3b639e477a3c161cb2104 (diff)
parent91931320cfbbcc1dd874c2d0aef62e7d90f07f70 (diff)
downloadop-kernel-dev-08ceab9d875824f8b389530e830349d5d6c4e582.zip
op-kernel-dev-08ceab9d875824f8b389530e830349d5d6c4e582.tar.gz
Merge tag 'asoc-v4.2-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for v4.3 Not many updates to the core here, but an awful lot of driver updates this time round: - Factoring out of AC'97 reset code into the core - New drivers for Cirrus CS4349, GTM601, InvenSense ICS43432, Realtek RT298 and ST STI controllers. - Machine drivers for Rockchip systems with MAX98090 and RT5645 and RT5650. - Initial driver support for Intel Skylake devices. - A large number of cleanups for Lars-Peter Clausen and Axel Lin.
-rw-r--r--.get_maintainer.ignore1
-rw-r--r--.mailmap1
-rw-r--r--Documentation/DocBook/alsa-driver-api.tmpl2
-rw-r--r--Documentation/devicetree/bindings/arm/cpus.txt1
-rw-r--r--Documentation/devicetree/bindings/phy/ti-phy.txt16
-rw-r--r--Documentation/devicetree/bindings/sound/cs4349.txt19
-rw-r--r--Documentation/devicetree/bindings/sound/ics43432.txt17
-rw-r--r--Documentation/devicetree/bindings/sound/max98357a.txt6
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsnd.txt22
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt7
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip-max98090.txt19
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip-rt5645.txt17
-rw-r--r--Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt155
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt2
-rw-r--r--Documentation/input/alps.txt6
-rw-r--r--MAINTAINERS9
-rw-r--r--Makefile11
-rw-r--r--arch/arc/Kconfig13
-rw-r--r--arch/arc/Makefile10
-rw-r--r--arch/arc/include/asm/arcregs.h7
-rw-r--r--arch/arc/include/asm/atomic.h78
-rw-r--r--arch/arc/include/asm/ptrace.h54
-rw-r--r--arch/arc/include/asm/spinlock.h538
-rw-r--r--arch/arc/include/asm/spinlock_types.h2
-rw-r--r--arch/arc/include/uapi/asm/ptrace.h20
-rw-r--r--arch/arc/kernel/setup.c12
-rw-r--r--arch/arc/kernel/time.c40
-rw-r--r--arch/arc/lib/memcpy-archs.S2
-rw-r--r--arch/arc/lib/memset-archs.S43
-rw-r--r--arch/arc/plat-axs10x/axs10x.c15
-rw-r--r--arch/arm/Makefile3
-rw-r--r--arch/arm/boot/dts/dra7.dtsi3
-rw-r--r--arch/arm/boot/dts/imx6qdl.dtsi8
-rw-r--r--arch/arm/boot/dts/k2e.dtsi15
-rw-r--r--arch/arm/boot/dts/k2hk.dtsi11
-rw-r--r--arch/arm/boot/dts/k2l.dtsi16
-rw-r--r--arch/arm/boot/dts/keystone.dtsi11
-rw-r--r--arch/arm/boot/dts/omap2430.dtsi3
-rw-r--r--arch/arm/boot/dts/omap4.dtsi3
-rw-r--r--arch/arm/boot/dts/omap5.dtsi3
-rw-r--r--arch/arm/boot/dts/ste-dbx5x0.dtsi53
-rw-r--r--arch/arm/kernel/entry-common.S1
-rw-r--r--arch/arm/kernel/head.S3
-rw-r--r--arch/arm/kernel/vdso.c7
-rw-r--r--arch/arm/lib/uaccess_with_memcpy.c2
-rw-r--r--arch/arm/mach-exynos/pm_domains.c3
-rw-r--r--arch/arm/mach-omap2/omap-wakeupgen.c1
-rw-r--r--arch/arm/vdso/Makefile2
-rw-r--r--arch/arm64/kernel/signal32.c5
-rw-r--r--arch/arm64/kernel/vdso.c7
-rw-r--r--arch/mips/Kconfig1
-rw-r--r--arch/mips/ath79/setup.c1
-rw-r--r--arch/mips/cavium-octeon/smp.c2
-rw-r--r--arch/mips/include/asm/mach-bcm63xx/dma-coherence.h10
-rw-r--r--arch/mips/include/asm/pgtable.h31
-rw-r--r--arch/mips/include/asm/smp.h2
-rw-r--r--arch/mips/include/asm/stackframe.h25
-rw-r--r--arch/mips/kernel/genex.S2
-rw-r--r--arch/mips/kernel/mips-mt-fpaff.c5
-rw-r--r--arch/mips/kernel/prom.c2
-rw-r--r--arch/mips/kernel/relocate_kernel.S8
-rw-r--r--arch/mips/kernel/scall64-64.S2
-rw-r--r--arch/mips/kernel/scall64-n32.S2
-rw-r--r--arch/mips/kernel/signal32.c2
-rw-r--r--arch/mips/kernel/smp-bmips.c4
-rw-r--r--arch/mips/kernel/smp.c10
-rw-r--r--arch/mips/kernel/traps.c13
-rw-r--r--arch/mips/kernel/unaligned.c2
-rw-r--r--arch/mips/lantiq/irq.c3
-rw-r--r--arch/mips/loongson64/loongson-3/smp.c7
-rw-r--r--arch/mips/mm/cache.c8
-rw-r--r--arch/mips/mm/fault.c3
-rw-r--r--arch/mips/mti-malta/malta-int.c2
-rw-r--r--arch/mips/mti-malta/malta-time.c16
-rw-r--r--arch/mips/mti-sead3/sead3-time.c1
-rw-r--r--arch/mips/netlogic/common/smp.c2
-rw-r--r--arch/mips/paravirt/paravirt-smp.c2
-rw-r--r--arch/mips/pistachio/time.c1
-rw-r--r--arch/mips/pmcs-msp71xx/msp_smp.c2
-rw-r--r--arch/mips/ralink/irq.c1
-rw-r--r--arch/mips/sgi-ip27/ip27-irq.c8
-rw-r--r--arch/mips/sibyte/bcm1480/smp.c9
-rw-r--r--arch/mips/sibyte/sb1250/smp.c7
-rw-r--r--arch/powerpc/kernel/signal_32.c2
-rw-r--r--arch/s390/kvm/kvm-s390.c4
-rw-r--r--arch/sparc/include/asm/visasm.h16
-rw-r--r--arch/sparc/lib/NG4memcpy.S5
-rw-r--r--arch/sparc/lib/VISsave.S67
-rw-r--r--arch/sparc/lib/ksyms.c4
-rw-r--r--arch/tile/kernel/compat_signal.c2
-rw-r--r--arch/x86/entry/entry_64_compat.S3
-rw-r--r--arch/x86/include/asm/sigcontext.h6
-rw-r--r--arch/x86/include/asm/switch_to.h12
-rw-r--r--arch/x86/include/uapi/asm/sigcontext.h21
-rw-r--r--arch/x86/kernel/apic/vector.c2
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c23
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_cqm.c8
-rw-r--r--arch/x86/kernel/fpu/core.c2
-rw-r--r--arch/x86/kernel/fpu/init.c7
-rw-r--r--arch/x86/kernel/process.c2
-rw-r--r--arch/x86/kernel/signal.c26
-rw-r--r--arch/x86/kernel/step.c4
-rw-r--r--arch/x86/kvm/mtrr.c8
-rw-r--r--arch/x86/kvm/x86.c7
-rw-r--r--arch/x86/math-emu/fpu_entry.c3
-rw-r--r--arch/x86/math-emu/fpu_system.h21
-rw-r--r--arch/x86/math-emu/get_address.c3
-rw-r--r--arch/x86/xen/Kconfig4
-rw-r--r--arch/x86/xen/Makefile4
-rw-r--r--arch/x86/xen/xen-ops.h6
-rw-r--r--block/blk-settings.c4
-rw-r--r--crypto/authencesn.c44
-rw-r--r--drivers/acpi/video_detect.c16
-rw-r--r--drivers/ata/ahci_brcmstb.c6
-rw-r--r--drivers/ata/libata-core.c24
-rw-r--r--drivers/ata/libata-eh.c105
-rw-r--r--drivers/ata/libata-scsi.c21
-rw-r--r--drivers/ata/libata.h6
-rw-r--r--drivers/ata/sata_sx4.c16
-rw-r--r--drivers/base/regmap/internal.h2
-rw-r--r--drivers/base/regmap/regcache-rbtree.c19
-rw-r--r--drivers/base/regmap/regmap.c73
-rw-r--r--drivers/block/rbd.c22
-rw-r--r--drivers/block/xen-blkback/blkback.c4
-rw-r--r--drivers/block/xen-blkfront.c128
-rw-r--r--drivers/block/zram/zram_drv.c6
-rw-r--r--drivers/char/hw_random/core.c2
-rw-r--r--drivers/clk/pxa/clk-pxa3xx.c2
-rw-r--r--drivers/clocksource/sh_cmt.c6
-rw-r--r--drivers/clocksource/timer-imx-gpt.c1
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c6
-rw-r--r--drivers/cpufreq/loongson2_cpufreq.c2
-rw-r--r--drivers/crypto/caam/caamhash.c7
-rw-r--r--drivers/crypto/ixp4xx_crypto.c1
-rw-r--r--drivers/crypto/nx/nx-sha256.c27
-rw-r--r--drivers/crypto/nx/nx-sha512.c28
-rw-r--r--drivers/crypto/qat/qat_common/qat_algs.c24
-rw-r--r--drivers/dma/dmaengine.c4
-rw-r--r--drivers/edac/ppc4xx_edac.c2
-rw-r--r--drivers/extcon/extcon-palmas.c13
-rw-r--r--drivers/extcon/extcon.c61
-rw-r--r--drivers/firmware/broadcom/bcm47xx_nvram.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c17
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_sdma.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c38
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c6
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c2
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c18
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c20
-rw-r--r--drivers/gpu/drm/drm_irq.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimc.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gsc.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c7
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c21
-rw-r--r--drivers/gpu/drm/i2c/adv7511.c2
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c4
-rw-r--r--drivers/gpu/drm/i915/intel_atomic.c45
-rw-r--r--drivers/gpu/drm/i915/intel_display.c59
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c35
-rw-r--r--drivers/gpu/drm/i915/intel_dp_mst.c11
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c29
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c5
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c4
-rw-r--r--drivers/hid/hid-input.c7
-rw-r--r--drivers/hid/hid-uclogic.c2
-rw-r--r--drivers/hid/wacom_sys.c70
-rw-r--r--drivers/hwmon/dell-smm-hwmon.c18
-rw-r--r--drivers/hwmon/g762.c1
-rw-r--r--drivers/hwmon/nct7904.c1
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c4
-rw-r--r--drivers/i2c/busses/i2c-omap.c11
-rw-r--r--drivers/i2c/i2c-core.c24
-rw-r--r--drivers/i2c/i2c-slave-eeprom.c6
-rw-r--r--drivers/infiniband/hw/cxgb4/cq.c2
-rw-r--r--drivers/input/joystick/turbografx.c2
-rw-r--r--drivers/input/keyboard/gpio_keys_polled.c2
-rw-r--r--drivers/input/misc/axp20x-pek.c1
-rw-r--r--drivers/input/misc/drv260x.c6
-rw-r--r--drivers/input/misc/drv2665.c2
-rw-r--r--drivers/input/misc/drv2667.c4
-rw-r--r--drivers/input/misc/twl4030-vibra.c3
-rw-r--r--drivers/input/mouse/alps.c8
-rw-r--r--drivers/input/mouse/elantech.c22
-rw-r--r--drivers/input/mouse/elantech.h1
-rw-r--r--drivers/irqchip/irq-crossbar.c4
-rw-r--r--drivers/irqchip/irq-mips-gic.c2
-rw-r--r--drivers/md/dm-cache-policy-mq.c2
-rw-r--r--drivers/md/dm-cache-policy-smq.c2
-rw-r--r--drivers/md/dm-thin-metadata.c4
-rw-r--r--drivers/md/dm.c27
-rw-r--r--drivers/md/md.c2
-rw-r--r--drivers/md/persistent-data/dm-btree-internal.h6
-rw-r--r--drivers/md/persistent-data/dm-btree-remove.c17
-rw-r--r--drivers/md/persistent-data/dm-btree-spine.c37
-rw-r--r--drivers/md/persistent-data/dm-btree.c7
-rw-r--r--drivers/md/raid1.c10
-rw-r--r--drivers/md/raid5.c5
-rw-r--r--drivers/media/dvb-frontends/Kconfig2
-rw-r--r--drivers/media/pci/cobalt/Kconfig1
-rw-r--r--drivers/media/pci/cobalt/cobalt-irq.c2
-rw-r--r--drivers/media/pci/mantis/mantis_dma.c5
-rw-r--r--drivers/media/rc/ir-rc5-decoder.c116
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c122
-rw-r--r--drivers/media/rc/nuvoton-cir.c127
-rw-r--r--drivers/media/rc/nuvoton-cir.h1
-rw-r--r--drivers/media/rc/rc-core-priv.h36
-rw-r--r--drivers/media/rc/rc-ir-raw.c139
-rw-r--r--drivers/media/rc/rc-loopback.c36
-rw-r--r--drivers/media/rc/rc-main.c7
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c40
-rw-r--r--drivers/memory/omap-gpmc.c6
-rw-r--r--drivers/mfd/Kconfig2
-rw-r--r--drivers/mfd/arizona-core.c18
-rw-r--r--drivers/mfd/twl6040.c2
-rw-r--r--drivers/mfd/wm5102-tables.c6
-rw-r--r--drivers/mfd/wm5110-tables.c22
-rw-r--r--drivers/mfd/wm8994-core.c8
-rw-r--r--drivers/mfd/wm8997-tables.c2
-rw-r--r--drivers/misc/eeprom/at24.c3
-rw-r--r--drivers/net/bonding/bond_main.c1
-rw-r--r--drivers/net/ethernet/3com/3c59x.c17
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c16
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c2
-rw-r--r--drivers/net/ethernet/cavium/Kconfig3
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c3
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h5
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c191
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c1
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c3
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mac-fec.c2
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c5
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c345
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_main.c2
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c2
-rw-r--r--drivers/net/ethernet/marvell/mvpp2.c244
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c2
-rw-r--r--drivers/net/ethernet/micrel/ks8842.c5
-rw-r--r--drivers/net/ethernet/realtek/r8169.c4
-rw-r--r--drivers/net/ethernet/rocker/rocker.c1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c4
-rw-r--r--drivers/net/ethernet/ti/netcp.h1
-rw-r--r--drivers/net/ethernet/ti/netcp_core.c35
-rw-r--r--drivers/net/hamradio/mkiss.c7
-rw-r--r--drivers/net/ntb_netdev.c9
-rw-r--r--drivers/net/phy/phy.c16
-rw-r--r--drivers/net/phy/smsc.c31
-rw-r--r--drivers/net/ppp/ppp_generic.c78
-rw-r--r--drivers/net/usb/qmi_wwan.c1
-rw-r--r--drivers/net/virtio_net.c4
-rw-r--r--drivers/net/wan/cosa.c3
-rw-r--r--drivers/net/wireless/b43/tables_nphy.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c2
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c22
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c15
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_sdio_ops.c8
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_usb_ops.c4
-rw-r--r--drivers/net/wireless/rtlwifi/core.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/sw.c1
-rw-r--r--drivers/net/xen-netback/interface.c6
-rw-r--r--drivers/net/xen-netback/netback.c62
-rw-r--r--drivers/ntb/ntb.c2
-rw-r--r--drivers/ntb/ntb_transport.c201
-rw-r--r--drivers/pci/Kconfig2
-rw-r--r--drivers/pci/probe.c7
-rw-r--r--drivers/phy/phy-sun4i-usb.c1
-rw-r--r--drivers/phy/phy-ti-pipe3.c61
-rw-r--r--drivers/platform/chrome/Kconfig1
-rw-r--r--drivers/scsi/fnic/fnic.h2
-rw-r--r--drivers/scsi/fnic/fnic_scsi.c4
-rw-r--r--drivers/scsi/libfc/fc_exch.c8
-rw-r--r--drivers/scsi/libfc/fc_fcp.c19
-rw-r--r--drivers/scsi/libiscsi.c25
-rw-r--r--drivers/scsi/scsi_error.c31
-rw-r--r--drivers/scsi/scsi_pm.c22
-rw-r--r--drivers/scsi/sd.c6
-rw-r--r--drivers/staging/comedi/drivers/das1800.c1
-rw-r--r--drivers/staging/lustre/lustre/obdclass/debug.c2
-rw-r--r--drivers/staging/vt6655/device_main.c5
-rw-r--r--drivers/target/iscsi/iscsi_target.c4
-rw-r--r--drivers/target/target_core_configfs.c9
-rw-r--r--drivers/target/target_core_hba.c10
-rw-r--r--drivers/target/target_core_spc.c44
-rw-r--r--drivers/thermal/cpu_cooling.c73
-rw-r--r--drivers/thermal/hisi_thermal.c1
-rw-r--r--drivers/thermal/power_allocator.c34
-rw-r--r--drivers/thermal/samsung/Kconfig2
-rw-r--r--drivers/thermal/samsung/exynos_tmu.c5
-rw-r--r--drivers/thermal/thermal_core.c1
-rw-r--r--drivers/usb/chipidea/core.c13
-rw-r--r--drivers/usb/chipidea/host.c7
-rw-r--r--drivers/usb/chipidea/host.h6
-rw-r--r--drivers/usb/gadget/function/f_hid.c4
-rw-r--r--drivers/usb/gadget/function/f_printer.c10
-rw-r--r--drivers/usb/gadget/function/f_uac2.c4
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_ep.c2
-rw-r--r--drivers/usb/gadget/udc/udc-core.c1
-rw-r--r--drivers/usb/host/xhci-mem.c3
-rw-r--r--drivers/usb/host/xhci-ring.c2
-rw-r--r--drivers/usb/serial/option.c2
-rw-r--r--drivers/usb/serial/qcserial.c2
-rw-r--r--drivers/usb/serial/sierra.c1
-rw-r--r--drivers/video/console/fbcon.c3
-rw-r--r--drivers/video/fbdev/Kconfig2
-rw-r--r--drivers/video/fbdev/omap2/dss/dss-of.c4
-rw-r--r--drivers/video/fbdev/pxa3xx-gcu.c4
-rw-r--r--drivers/video/of_videomode.c4
-rw-r--r--drivers/virtio/virtio_input.c4
-rw-r--r--drivers/xen/balloon.c15
-rw-r--r--drivers/xen/gntdev.c2
-rw-r--r--drivers/xen/xenbus/xenbus_client.c4
-rw-r--r--fs/btrfs/qgroup.c5
-rw-r--r--fs/ceph/caps.c22
-rw-r--r--fs/ceph/locks.c2
-rw-r--r--fs/ceph/super.h1
-rw-r--r--fs/dcache.c13
-rw-r--r--fs/file_table.c24
-rw-r--r--fs/fuse/dev.c10
-rw-r--r--fs/hugetlbfs/inode.c2
-rw-r--r--fs/namei.c2
-rw-r--r--fs/nfsd/nfs4layouts.c1
-rw-r--r--fs/nfsd/nfs4state.c12
-rw-r--r--fs/nfsd/nfs4xdr.c11
-rw-r--r--fs/notify/mark.c30
-rw-r--r--fs/ocfs2/aops.c4
-rw-r--r--fs/ocfs2/dlmglue.c10
-rw-r--r--fs/signalfd.c5
-rw-r--r--include/drm/drmP.h2
-rw-r--r--include/drm/drm_crtc.h2
-rw-r--r--include/drm/drm_crtc_helper.h3
-rw-r--r--include/drm/drm_edid.h19
-rw-r--r--include/drm/drm_pciids.h1
-rw-r--r--include/linux/ata.h18
-rw-r--r--include/linux/fs.h5
-rw-r--r--include/linux/irq.h1
-rw-r--r--include/linux/mfd/arizona/registers.h37
-rw-r--r--include/linux/mm.h28
-rw-r--r--include/linux/mm_types.h9
-rw-r--r--include/linux/page-flags.h10
-rw-r--r--include/linux/regmap.h28
-rw-r--r--include/linux/skbuff.h20
-rw-r--r--include/media/rc-core.h7
-rw-r--r--include/media/videobuf2-core.h2
-rw-r--r--include/scsi/scsi_eh.h1
-rw-r--r--include/sound/ac97_codec.h2
-rw-r--r--include/sound/rcar_snd.h14
-rw-r--r--include/sound/rt298.h20
-rw-r--r--include/sound/soc-dapm.h84
-rw-r--r--include/sound/soc-topology.h13
-rw-r--r--include/sound/soc.h29
-rw-r--r--include/trace/events/asoc.h53
-rw-r--r--include/uapi/linux/pci_regs.h1
-rw-r--r--init/main.c2
-rw-r--r--ipc/mqueue.c5
-rw-r--r--ipc/sem.c47
-rw-r--r--ipc/shm.c2
-rw-r--r--kernel/cpuset.c2
-rw-r--r--kernel/events/core.c91
-rw-r--r--kernel/events/ring_buffer.c10
-rw-r--r--kernel/irq/chip.c19
-rw-r--r--kernel/kthread.c4
-rw-r--r--kernel/locking/qspinlock_paravirt.h11
-rw-r--r--kernel/module.c8
-rw-r--r--kernel/signal.c13
-rw-r--r--kernel/time/timer.c4
-rw-r--r--lib/iommu-common.c2
-rw-r--r--mm/cma.h2
-rw-r--r--mm/huge_memory.c7
-rw-r--r--mm/kasan/kasan.c2
-rw-r--r--mm/kasan/report.c2
-rw-r--r--mm/memory-failure.c54
-rw-r--r--mm/memory_hotplug.c13
-rw-r--r--mm/migrate.c8
-rw-r--r--mm/page-writeback.c4
-rw-r--r--mm/page_alloc.c62
-rw-r--r--mm/shmem.c4
-rw-r--r--mm/slab.c4
-rw-r--r--mm/slab_common.c3
-rw-r--r--mm/slub.c2
-rw-r--r--mm/vmscan.c16
-rw-r--r--net/9p/client.c2
-rw-r--r--net/batman-adv/distributed-arp-table.c18
-rw-r--r--net/batman-adv/gateway_client.c2
-rw-r--r--net/batman-adv/soft-interface.c3
-rw-r--r--net/batman-adv/translation-table.c32
-rw-r--r--net/bluetooth/mgmt.c2
-rw-r--r--net/bridge/br_multicast.c4
-rw-r--r--net/bridge/br_netlink.c4
-rw-r--r--net/core/datagram.c13
-rw-r--r--net/core/pktgen.c3
-rw-r--r--net/core/request_sock.c8
-rw-r--r--net/core/skbuff.c39
-rw-r--r--net/dsa/slave.c3
-rw-r--r--net/ipv4/fib_trie.c2
-rw-r--r--net/ipv4/igmp.c33
-rw-r--r--net/ipv4/inet_connection_sock.c2
-rw-r--r--net/ipv4/netfilter/ipt_SYNPROXY.c3
-rw-r--r--net/ipv4/sysctl_net_ipv4.c10
-rw-r--r--net/ipv4/tcp_ipv4.c2
-rw-r--r--net/ipv4/udp.c13
-rw-r--r--net/ipv6/ip6_fib.c2
-rw-r--r--net/ipv6/mcast_snoop.c33
-rw-r--r--net/ipv6/netfilter/ip6t_SYNPROXY.c19
-rw-r--r--net/ipv6/route.c85
-rw-r--r--net/ipv6/tcp_ipv6.c2
-rw-r--r--net/mac80211/rc80211_minstrel.c11
-rw-r--r--net/netfilter/nf_conntrack_core.c8
-rw-r--r--net/netfilter/nf_synproxy_core.c4
-rw-r--r--net/netfilter/xt_CT.c5
-rw-r--r--net/netlink/af_netlink.c5
-rw-r--r--net/openvswitch/actions.c16
-rw-r--r--net/rds/info.c2
-rw-r--r--net/sched/act_mirred.c2
-rw-r--r--net/sched/sch_fq_codel.c22
-rwxr-xr-xscripts/kconfig/streamline_config.pl2
-rw-r--r--security/yama/yama_lsm.c1
-rw-r--r--sound/ac97_bus.c62
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c2
-rw-r--r--sound/soc/au1x/dbdma2.c11
-rw-r--r--sound/soc/au1x/dma.c11
-rw-r--r--sound/soc/au1x/psc-i2s.c16
-rw-r--r--sound/soc/bcm/bcm2835-i2s.c2
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c10
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c10
-rw-r--r--sound/soc/blackfin/bfin-eval-adau1x61.c1
-rw-r--r--sound/soc/codecs/88pm860x-codec.c32
-rw-r--r--sound/soc/codecs/Kconfig25
-rw-r--r--sound/soc/codecs/Makefile10
-rw-r--r--sound/soc/codecs/ab8500-codec.c7
-rw-r--r--sound/soc/codecs/ad1980.c36
-rw-r--r--sound/soc/codecs/adau1373.c22
-rw-r--r--sound/soc/codecs/adau1701.c1
-rw-r--r--sound/soc/codecs/adau1761-i2c.c1
-rw-r--r--sound/soc/codecs/adau1781-i2c.c1
-rw-r--r--sound/soc/codecs/adau1977-i2c.c1
-rw-r--r--sound/soc/codecs/adav803.c1
-rw-r--r--sound/soc/codecs/adav80x.c3
-rw-r--r--sound/soc/codecs/ak4535.c1
-rw-r--r--sound/soc/codecs/ak4641.c1
-rw-r--r--sound/soc/codecs/ak4642.c34
-rw-r--r--sound/soc/codecs/ak4671.c1
-rw-r--r--sound/soc/codecs/alc5623.c8
-rw-r--r--sound/soc/codecs/alc5632.c10
-rw-r--r--sound/soc/codecs/arizona.c129
-rw-r--r--sound/soc/codecs/arizona.h20
-rw-r--r--sound/soc/codecs/cs35l32.c60
-rw-r--r--sound/soc/codecs/cs35l32.h2
-rw-r--r--sound/soc/codecs/cs4265.c19
-rw-r--r--sound/soc/codecs/cs4270.c1
-rw-r--r--sound/soc/codecs/cs4271-i2c.c1
-rw-r--r--sound/soc/codecs/cs42l51-i2c.c1
-rw-r--r--sound/soc/codecs/cs42l52.c65
-rw-r--r--sound/soc/codecs/cs42l56.c71
-rw-r--r--sound/soc/codecs/cs42l73.c115
-rw-r--r--sound/soc/codecs/cs42xx8-i2c.c4
-rw-r--r--sound/soc/codecs/cs42xx8.c19
-rw-r--r--sound/soc/codecs/cs42xx8.h1
-rw-r--r--sound/soc/codecs/cs4349.c392
-rw-r--r--sound/soc/codecs/cs4349.h136
-rw-r--r--sound/soc/codecs/da7210.c29
-rw-r--r--sound/soc/codecs/da7213.c18
-rw-r--r--sound/soc/codecs/da732x.c15
-rw-r--r--sound/soc/codecs/da9055.c19
-rw-r--r--sound/soc/codecs/gtm601.c95
-rw-r--r--sound/soc/codecs/ics43432.c76
-rw-r--r--sound/soc/codecs/isabelle.c11
-rw-r--r--sound/soc/codecs/jz4740.c7
-rw-r--r--sound/soc/codecs/lm4857.c1
-rw-r--r--sound/soc/codecs/lm49453.c19
-rw-r--r--sound/soc/codecs/max9768.c71
-rw-r--r--sound/soc/codecs/max98088.c329
-rw-r--r--sound/soc/codecs/max98088.h2
-rw-r--r--sound/soc/codecs/max98090.c171
-rw-r--r--sound/soc/codecs/max98090.h1
-rw-r--r--sound/soc/codecs/max98095.c354
-rw-r--r--sound/soc/codecs/max98357a.c25
-rw-r--r--sound/soc/codecs/max9850.c8
-rw-r--r--sound/soc/codecs/max9877.c33
-rw-r--r--sound/soc/codecs/max98925.c6
-rw-r--r--sound/soc/codecs/mc13783.c6
-rw-r--r--sound/soc/codecs/ml26124.c3
-rw-r--r--sound/soc/codecs/pcm1681.c14
-rw-r--r--sound/soc/codecs/pcm512x-i2c.c1
-rw-r--r--sound/soc/codecs/pcm512x.c4
-rw-r--r--sound/soc/codecs/rl6231.c104
-rw-r--r--sound/soc/codecs/rl6231.h1
-rw-r--r--sound/soc/codecs/rt286.c11
-rw-r--r--sound/soc/codecs/rt298.c1271
-rw-r--r--sound/soc/codecs/rt298.h206
-rw-r--r--sound/soc/codecs/rt5631.c8
-rw-r--r--sound/soc/codecs/rt5640.c59
-rw-r--r--sound/soc/codecs/rt5645.c443
-rw-r--r--sound/soc/codecs/rt5645.h27
-rw-r--r--sound/soc/codecs/rt5651.c19
-rw-r--r--sound/soc/codecs/rt5670.c21
-rw-r--r--sound/soc/codecs/rt5677-spi.c233
-rw-r--r--sound/soc/codecs/rt5677-spi.h8
-rw-r--r--sound/soc/codecs/rt5677.c159
-rw-r--r--sound/soc/codecs/rt5677.h5
-rw-r--r--sound/soc/codecs/sgtl5000.c8
-rw-r--r--sound/soc/codecs/si476x.c2
-rw-r--r--sound/soc/codecs/sirf-audio-codec.c4
-rw-r--r--sound/soc/codecs/ssm2518.c10
-rw-r--r--sound/soc/codecs/ssm2602-i2c.c1
-rw-r--r--sound/soc/codecs/ssm2602.c7
-rw-r--r--sound/soc/codecs/ssm4567.c34
-rw-r--r--sound/soc/codecs/sta32x.c1
-rw-r--r--sound/soc/codecs/sta350.c1
-rw-r--r--sound/soc/codecs/sta529.c4
-rw-r--r--sound/soc/codecs/stac9766.c57
-rw-r--r--sound/soc/codecs/sti-sas.c628
-rw-r--r--sound/soc/codecs/tas2552.c20
-rw-r--r--sound/soc/codecs/tas2552.h2
-rw-r--r--sound/soc/codecs/tas5086.c11
-rw-r--r--sound/soc/codecs/tas571x.c2
-rw-r--r--sound/soc/codecs/tfa9879.c3
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c3
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c1
-rw-r--r--sound/soc/codecs/tlv320aic3x.c3
-rw-r--r--sound/soc/codecs/tlv320dac33.c1
-rw-r--r--sound/soc/codecs/tpa6130a2.c15
-rw-r--r--sound/soc/codecs/ts3a227e.c48
-rw-r--r--sound/soc/codecs/twl4030.c7
-rw-r--r--sound/soc/codecs/uda134x.c180
-rw-r--r--sound/soc/codecs/uda134x.h2
-rw-r--r--sound/soc/codecs/uda1380.c15
-rw-r--r--sound/soc/codecs/wm0010.c3
-rw-r--r--sound/soc/codecs/wm1250-ev1.c1
-rw-r--r--sound/soc/codecs/wm2000.c1
-rw-r--r--sound/soc/codecs/wm2200.c9
-rw-r--r--sound/soc/codecs/wm5100.c13
-rw-r--r--sound/soc/codecs/wm5102.c27
-rw-r--r--sound/soc/codecs/wm5110.c315
-rw-r--r--sound/soc/codecs/wm8350.c7
-rw-r--r--sound/soc/codecs/wm8400.c5
-rw-r--r--sound/soc/codecs/wm8510.c2
-rw-r--r--sound/soc/codecs/wm8523.c2
-rw-r--r--sound/soc/codecs/wm8580.c2
-rw-r--r--sound/soc/codecs/wm8711.c1
-rw-r--r--sound/soc/codecs/wm8728.c1
-rw-r--r--sound/soc/codecs/wm8731.c88
-rw-r--r--sound/soc/codecs/wm8737.c8
-rw-r--r--sound/soc/codecs/wm8741.c63
-rw-r--r--sound/soc/codecs/wm8750.c1
-rw-r--r--sound/soc/codecs/wm8753.c14
-rw-r--r--sound/soc/codecs/wm8776.c5
-rw-r--r--sound/soc/codecs/wm8804-i2c.c1
-rw-r--r--sound/soc/codecs/wm8804.c2
-rw-r--r--sound/soc/codecs/wm8900.c1
-rw-r--r--sound/soc/codecs/wm8903.c1
-rw-r--r--sound/soc/codecs/wm8904.c5
-rw-r--r--sound/soc/codecs/wm8940.c1
-rw-r--r--sound/soc/codecs/wm8955.c1
-rw-r--r--sound/soc/codecs/wm8960.c221
-rw-r--r--sound/soc/codecs/wm8960.h1
-rw-r--r--sound/soc/codecs/wm8961.c8
-rw-r--r--sound/soc/codecs/wm8962.c21
-rw-r--r--sound/soc/codecs/wm8971.c1
-rw-r--r--sound/soc/codecs/wm8974.c1
-rw-r--r--sound/soc/codecs/wm8978.c1
-rw-r--r--sound/soc/codecs/wm8983.c81
-rw-r--r--sound/soc/codecs/wm8985.c1
-rw-r--r--sound/soc/codecs/wm8988.c1
-rw-r--r--sound/soc/codecs/wm8990.c6
-rw-r--r--sound/soc/codecs/wm8991.c53
-rw-r--r--sound/soc/codecs/wm8993.c12
-rw-r--r--sound/soc/codecs/wm8994.c18
-rw-r--r--sound/soc/codecs/wm8995.c1
-rw-r--r--sound/soc/codecs/wm8996.c11
-rw-r--r--sound/soc/codecs/wm8997.c20
-rw-r--r--sound/soc/codecs/wm9081.c10
-rw-r--r--sound/soc/codecs/wm9090.c22
-rw-r--r--sound/soc/codecs/wm9705.c40
-rw-r--r--sound/soc/codecs/wm9712.c45
-rw-r--r--sound/soc/codecs/wm9713.c55
-rw-r--r--sound/soc/codecs/wm9713.h2
-rw-r--r--sound/soc/codecs/wm_hubs.c7
-rw-r--r--sound/soc/davinci/davinci-i2s.c25
-rw-r--r--sound/soc/davinci/davinci-mcasp.c18
-rw-r--r--sound/soc/davinci/davinci-vcif.c14
-rw-r--r--sound/soc/fsl/eukrea-tlv320.c2
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c16
-rw-r--r--sound/soc/fsl/fsl_asrc.c25
-rw-r--r--sound/soc/fsl/fsl_esai.c2
-rw-r--r--sound/soc/fsl/fsl_sai.c2
-rw-r--r--sound/soc/fsl/fsl_sai.h15
-rw-r--r--sound/soc/fsl/fsl_spdif.c25
-rw-r--r--sound/soc/fsl/fsl_ssi.c68
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c25
-rw-r--r--sound/soc/fsl/imx-pcm.h9
-rw-r--r--sound/soc/fsl/imx-ssi.c2
-rw-r--r--sound/soc/generic/simple-card.c9
-rw-r--r--sound/soc/intel/Kconfig29
-rw-r--r--sound/soc/intel/Makefile1
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.c6
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c1
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform.h1
-rw-r--r--sound/soc/intel/atom/sst/sst_drv_interface.c9
-rw-r--r--sound/soc/intel/atom/sst/sst_ipc.c3
-rw-r--r--sound/soc/intel/boards/byt-max98090.c1
-rw-r--r--sound/soc/intel/boards/byt-rt5640.c1
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c1
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c19
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c2
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c1
-rw-r--r--sound/soc/intel/common/sst-dsp-priv.h23
-rw-r--r--sound/soc/intel/common/sst-dsp.c71
-rw-r--r--sound/soc/intel/common/sst-dsp.h6
-rw-r--r--sound/soc/intel/skylake/Makefile9
-rw-r--r--sound/soc/intel/skylake/skl-messages.c884
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c140
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.h106
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c916
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.c327
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.h251
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.c342
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.h145
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c771
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.h125
-rw-r--r--sound/soc/intel/skylake/skl-sst.c280
-rw-r--r--sound/soc/intel/skylake/skl-topology.h286
-rw-r--r--sound/soc/intel/skylake/skl-tplg-interface.h88
-rw-r--r--sound/soc/intel/skylake/skl.c536
-rw-r--r--sound/soc/intel/skylake/skl.h84
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c4
-rw-r--r--sound/soc/mediatek/mt8173-max98090.c2
-rw-r--r--sound/soc/mediatek/mt8173-rt5650-rt5676.c2
-rw-r--r--sound/soc/mediatek/mtk-afe-common.h8
-rw-r--r--sound/soc/mediatek/mtk-afe-pcm.c89
-rw-r--r--sound/soc/nuc900/nuc900-pcm.c9
-rw-r--r--sound/soc/omap/mcbsp.c20
-rw-r--r--sound/soc/omap/omap-hdmi-audio.c10
-rw-r--r--sound/soc/omap/omap3pandora.c6
-rw-r--r--sound/soc/pxa/mmp-pcm.c9
-rw-r--r--sound/soc/pxa/pxa-ssp.c11
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c11
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c9
-rw-r--r--sound/soc/qcom/Kconfig7
-rw-r--r--sound/soc/qcom/lpass-cpu.c2
-rw-r--r--sound/soc/qcom/lpass-ipq806x.c2
-rw-r--r--sound/soc/qcom/lpass.h2
-rw-r--r--sound/soc/rockchip/Kconfig19
-rw-r--r--sound/soc/rockchip/Makefile6
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c8
-rw-r--r--sound/soc/rockchip/rockchip_max98090.c236
-rw-r--r--sound/soc/rockchip/rockchip_rt5645.c225
-rw-r--r--sound/soc/samsung/arndale_rt5631.c11
-rw-r--r--sound/soc/samsung/snow.c1
-rw-r--r--sound/soc/sh/dma-sh7760.c9
-rw-r--r--sound/soc/sh/fsi.c1
-rw-r--r--sound/soc/sh/rcar/Makefile2
-rw-r--r--sound/soc/sh/rcar/core.c195
-rw-r--r--sound/soc/sh/rcar/ctu.c171
-rw-r--r--sound/soc/sh/rcar/dma.c128
-rw-r--r--sound/soc/sh/rcar/dvc.c73
-rw-r--r--sound/soc/sh/rcar/gen.c33
-rw-r--r--sound/soc/sh/rcar/mix.c200
-rw-r--r--sound/soc/sh/rcar/rsnd.h111
-rw-r--r--sound/soc/sh/rcar/rsrc-card.c22
-rw-r--r--sound/soc/sh/rcar/src.c117
-rw-r--r--sound/soc/sh/rcar/ssi.c4
-rw-r--r--sound/soc/sh/ssi.c12
-rw-r--r--sound/soc/soc-ac97.c30
-rw-r--r--sound/soc/soc-core.c86
-rw-r--r--sound/soc/soc-dapm.c503
-rw-r--r--sound/soc/soc-pcm.c16
-rw-r--r--sound/soc/soc-topology.c145
-rw-r--r--sound/soc/spear/spdif_in.c20
-rw-r--r--sound/soc/spear/spear_pcm.c2
-rw-r--r--sound/soc/sti/Kconfig11
-rw-r--r--sound/soc/sti/Makefile4
-rw-r--r--sound/soc/sti/sti_uniperif.c254
-rw-r--r--sound/soc/sti/uniperif.h1229
-rw-r--r--sound/soc/sti/uniperif_player.c1110
-rw-r--r--sound/soc/sti/uniperif_reader.c362
-rw-r--r--sound/soc/tegra/tegra20_das.c23
-rw-r--r--sound/soc/tegra/tegra20_i2s.c23
-rw-r--r--sound/soc/tegra/tegra20_spdif.c47
-rw-r--r--sound/soc/tegra/tegra30_ahub.c80
-rw-r--r--sound/soc/tegra/tegra30_i2s.c23
-rw-r--r--sound/soc/txx9/txx9aclc.c10
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c29
-rw-r--r--sound/soc/xtensa/xtfpga-i2s.c8
-rw-r--r--sound/soc/zte/zx296702-i2s.c6
-rw-r--r--tools/perf/builtin-record.c11
-rw-r--r--tools/perf/builtin-top.c4
-rw-r--r--tools/perf/config/Makefile2
-rw-r--r--tools/perf/util/machine.c20
-rw-r--r--tools/perf/util/stat-shadow.c8
-rw-r--r--tools/perf/util/thread.c6
699 files changed, 19508 insertions, 6704 deletions
diff --git a/.get_maintainer.ignore b/.get_maintainer.ignore
new file mode 100644
index 0000000..cca6d87
--- /dev/null
+++ b/.get_maintainer.ignore
@@ -0,0 +1 @@
+Christoph Hellwig <hch@lst.de>
diff --git a/.mailmap b/.mailmap
index b4091b7..4b31af5 100644
--- a/.mailmap
+++ b/.mailmap
@@ -17,6 +17,7 @@ Aleksey Gorelov <aleksey_gorelov@phoenix.com>
Al Viro <viro@ftp.linux.org.uk>
Al Viro <viro@zenIV.linux.org.uk>
Andreas Herrmann <aherrman@de.ibm.com>
+Andrey Ryabinin <ryabinin.a.a@gmail.com> <a.ryabinin@samsung.com>
Andrew Morton <akpm@linux-foundation.org>
Andrew Vasquez <andrew.vasquez@qlogic.com>
Andy Adamson <andros@citi.umich.edu>
diff --git a/Documentation/DocBook/alsa-driver-api.tmpl b/Documentation/DocBook/alsa-driver-api.tmpl
index 71f9246..e94a10b 100644
--- a/Documentation/DocBook/alsa-driver-api.tmpl
+++ b/Documentation/DocBook/alsa-driver-api.tmpl
@@ -108,7 +108,7 @@
<sect1><title>ASoC Core API</title>
!Iinclude/sound/soc.h
!Esound/soc/soc-core.c
-!Esound/soc/soc-cache.c
+<!-- !Esound/soc/soc-cache.c no docbook comments here -->
!Esound/soc/soc-devres.c
!Esound/soc/soc-io.c
!Esound/soc/soc-pcm.c
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index d6b794c..91e6e5c 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -199,6 +199,7 @@ nodes to be present and contain the properties described below.
"qcom,kpss-acc-v1"
"qcom,kpss-acc-v2"
"rockchip,rk3066-smp"
+ "ste,dbx500-smp"
- cpu-release-addr
Usage: required for systems that have an "enable-method"
diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt
index 305e3df..9cf9446 100644
--- a/Documentation/devicetree/bindings/phy/ti-phy.txt
+++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
@@ -82,6 +82,9 @@ Optional properties:
- id: If there are multiple instance of the same type, in order to
differentiate between each instance "id" can be used (e.g., multi-lane PCIe
PHY). If "id" is not provided, it is set to default value of '1'.
+ - syscon-pllreset: Handle to system control region that contains the
+ CTRL_CORE_SMA_SW_0 register and register offset to the CTRL_CORE_SMA_SW_0
+ register that contains the SATA_PLL_SOFT_RESET bit. Only valid for sata_phy.
This is usually a subnode of ocp2scp to which it is connected.
@@ -100,3 +103,16 @@ usb3phy@4a084400 {
"sysclk",
"refclk";
};
+
+sata_phy: phy@4A096000 {
+ compatible = "ti,phy-pipe3-sata";
+ reg = <0x4A096000 0x80>, /* phy_rx */
+ <0x4A096400 0x64>, /* phy_tx */
+ <0x4A096800 0x40>; /* pll_ctrl */
+ reg-names = "phy_rx", "phy_tx", "pll_ctrl";
+ ctrl-module = <&omap_control_sata>;
+ clocks = <&sys_clkin1>, <&sata_ref_clk>;
+ clock-names = "sysclk", "refclk";
+ syscon-pllreset = <&scm_conf 0x3fc>;
+ #phy-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/cs4349.txt b/Documentation/devicetree/bindings/sound/cs4349.txt
new file mode 100644
index 0000000..54c117b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cs4349.txt
@@ -0,0 +1,19 @@
+CS4349 audio CODEC
+
+Required properties:
+
+ - compatible : "cirrus,cs4349"
+
+ - reg : the I2C address of the device for I2C
+
+Optional properties:
+
+ - reset-gpios : a GPIO spec for the reset pin.
+
+Example:
+
+codec: cs4349@48 {
+ compatible = "cirrus,cs4349";
+ reg = <0x48>;
+ reset-gpios = <&gpio 54 0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/ics43432.txt b/Documentation/devicetree/bindings/sound/ics43432.txt
new file mode 100644
index 0000000..b02e3a6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ics43432.txt
@@ -0,0 +1,17 @@
+Invensense ICS-43432 MEMS microphone with I2S output.
+
+There are no software configuration options for this device, indeed, the only
+host connection is the I2S interface. Apart from requirements on clock
+frequency (460 kHz to 3.379 MHz according to the data sheet) there must be
+64 clock cycles in each stereo output frame; 24 of the 32 available bits
+contain audio data. A hardware pin determines if the device outputs data
+on the left or right channel of the I2S frame.
+
+Required properties:
+ - compatible : Must be "invensense,ics43432"
+
+Example:
+
+ ics43432: ics43432 {
+ compatible = "invensense,ics43432";
+ };
diff --git a/Documentation/devicetree/bindings/sound/max98357a.txt b/Documentation/devicetree/bindings/sound/max98357a.txt
index a7a149a..28645a2 100644
--- a/Documentation/devicetree/bindings/sound/max98357a.txt
+++ b/Documentation/devicetree/bindings/sound/max98357a.txt
@@ -4,7 +4,11 @@ This node models the Maxim MAX98357A DAC.
Required properties:
- compatible : "maxim,max98357a"
-- sdmode-gpios : GPIO specifier for the GPIO -> DAC SDMODE pin
+
+Optional properties:
+- sdmode-gpios : GPIO specifier for the chip's SD_MODE pin.
+ If this option is not specified then driver does not manage
+ the pin state (e.g. chip is always on).
Example:
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
index b6b3a78..1173395 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -18,6 +18,12 @@ Required properties:
- rcar_sound,src : Should contain SRC feature.
The number of SRC subnode should be same as HW.
see below for detail.
+- rcar_sound,ctu : Should contain CTU feature.
+ The number of CTU subnode should be same as HW.
+ see below for detail.
+- rcar_sound,mix : Should contain MIX feature.
+ The number of MIX subnode should be same as HW.
+ see below for detail.
- rcar_sound,dvc : Should contain DVC feature.
The number of DVC subnode should be same as HW.
see below for detail.
@@ -90,6 +96,22 @@ rcar_sound: sound@ec500000 {
};
};
+ rcar_sound,mix {
+ mix0: mix@0 { };
+ mix1: mix@1 { };
+ };
+
+ rcar_sound,ctu {
+ ctu00: ctu@0 { };
+ ctu01: ctu@1 { };
+ ctu02: ctu@2 { };
+ ctu03: ctu@3 { };
+ ctu10: ctu@4 { };
+ ctu11: ctu@5 { };
+ ctu12: ctu@6 { };
+ ctu13: ctu@7 { };
+ };
+
rcar_sound,src {
src0: src@0 {
interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
index c641550..962748a 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
@@ -6,6 +6,7 @@ Required properties:
- compatible : "renesas,rsrc-card,<board>"
Examples with soctypes are:
+ - "renesas,rsrc-card"
- "renesas,rsrc-card,lager"
- "renesas,rsrc-card,koelsch"
Optional properties:
@@ -29,6 +30,12 @@ Optional subnode properties:
- frame-inversion : bool property. Add this if the
dai-link uses frame clock inversion.
- convert-rate : platform specified sampling rate convert
+- audio-prefix : see audio-routing
+- audio-routing : A list of the connections between audio components.
+ Each entry is a pair of strings, the first being the connection's sink,
+ the second being the connection's source. Valid names for sources.
+ use audio-prefix if some components is using same sink/sources naming.
+ it can be used if compatible was "renesas,rsrc-card";
Required CPU/CODEC subnodes properties:
diff --git a/Documentation/devicetree/bindings/sound/rockchip-max98090.txt b/Documentation/devicetree/bindings/sound/rockchip-max98090.txt
new file mode 100644
index 0000000..a805aa9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip-max98090.txt
@@ -0,0 +1,19 @@
+ROCKCHIP with MAX98090 CODEC
+
+Required properties:
+- compatible: "rockchip,rockchip-audio-max98090"
+- rockchip,model: The user-visible name of this sound complex
+- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's
+ connected to the CODEC
+- rockchip,audio-codec: The phandle of the MAX98090 audio codec
+- rockchip,headset-codec: The phandle of Ext chip for jack detection
+
+Example:
+
+sound {
+ compatible = "rockchip,rockchip-audio-max98090";
+ rockchip,model = "ROCKCHIP-I2S";
+ rockchip,i2s-controller = <&i2s>;
+ rockchip,audio-codec = <&max98090>;
+ rockchip,headset-codec = <&headsetcodec>;
+};
diff --git a/Documentation/devicetree/bindings/sound/rockchip-rt5645.txt b/Documentation/devicetree/bindings/sound/rockchip-rt5645.txt
new file mode 100644
index 0000000..411a62b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip-rt5645.txt
@@ -0,0 +1,17 @@
+ROCKCHIP with RT5645/RT5650 CODECS
+
+Required properties:
+- compatible: "rockchip,rockchip-audio-rt5645"
+- rockchip,model: The user-visible name of this sound complex
+- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's
+ connected to the CODEC
+- rockchip,audio-codec: The phandle of the RT5645/RT5650 audio codec
+
+Example:
+
+sound {
+ compatible = "rockchip,rockchip-audio-rt5645";
+ rockchip,model = "ROCKCHIP-I2S";
+ rockchip,i2s-controller = <&i2s>;
+ rockchip,audio-codec = <&rt5645>;
+};
diff --git a/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt
new file mode 100644
index 0000000..028fa1c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt
@@ -0,0 +1,155 @@
+STMicroelectronics sti ASoC cards
+
+The sti ASoC Sound Card can be used, for all sti SoCs using internal sti-sas
+codec or external codecs.
+
+sti sound drivers allows to expose sti SoC audio interface through the
+generic ASoC simple card. For details about sound card declaration please refer to
+Documentation/devicetree/bindings/sound/simple-card.txt.
+
+1) sti-uniperiph-dai: audio dai device.
+---------------------------------------
+
+Required properties:
+ - compatible: "st,sti-uni-player" or "st,sti-uni-reader"
+
+ - st,syscfg: phandle to boot-device system configuration registers
+
+ - clock-names: name of the clocks listed in clocks property in the same order
+
+ - reg: CPU DAI IP Base address and size entries, listed in same
+ order than the CPU_DAI properties.
+
+ - reg-names: names of the mapped memory regions listed in regs property in
+ the same order.
+
+ - interrupts: CPU_DAI interrupt line, listed in the same order than the
+ CPU_DAI properties.
+
+ - dma: CPU_DAI DMA controller phandle and DMA request line, listed in the same
+ order than the CPU_DAI properties.
+
+ - dma-names: identifier string for each DMA request line in the dmas property.
+ "tx" for "st,sti-uni-player" compatibility
+ "rx" for "st,sti-uni-reader" compatibility
+
+ - version: IP version integrated in SOC.
+
+ - dai-name: DAI name that describes the IP.
+
+Required properties ("st,sti-uni-player" compatibility only):
+ - clocks: CPU_DAI IP clock source, listed in the same order than the
+ CPU_DAI properties.
+
+ - uniperiph-id: internal SOC IP instance ID.
+
+ - IP mode: IP working mode depending on associated codec.
+ "HDMI" connected to HDMI codec IP and IEC HDMI formats.
+ "SPDIF"connected to SPDIF codec and support SPDIF formats.
+ "PCM" PCM standard mode for I2S or TDM bus.
+
+Optional properties:
+ - pinctrl-0: defined for CPU_DAI@1 and CPU_DAI@4 to describe I2S PIOs for
+ external codecs connection.
+
+ - pinctrl-names: should contain only one value - "default".
+
+Example:
+
+ sti_uni_player2: sti-uni-player@2 {
+ compatible = "st,sti-uni-player";
+ status = "okay";
+ #sound-dai-cells = <0>;
+ st,syscfg = <&syscfg_core>;
+ clocks = <&clk_s_d0_flexgen CLK_PCM_2>;
+ reg = <0x8D82000 0x158>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
+ dmas = <&fdma0 4 0 1>;
+ dai-name = "Uni Player #1 (DAC)";
+ dma-names = "tx";
+ uniperiph-id = <2>;
+ version = <5>;
+ mode = "PCM";
+ };
+
+ sti_uni_player3: sti-uni-player@3 {
+ compatible = "st,sti-uni-player";
+ status = "okay";
+ #sound-dai-cells = <0>;
+ st,syscfg = <&syscfg_core>;
+ clocks = <&clk_s_d0_flexgen CLK_SPDIFF>;
+ reg = <0x8D85000 0x158>;
+ interrupts = <GIC_SPI 89 IRQ_TYPE_NONE>;
+ dmas = <&fdma0 7 0 1>;
+ dma-names = "tx";
+ dai-name = "Uni Player #1 (PIO)";
+ uniperiph-id = <3>;
+ version = <5>;
+ mode = "SPDIF";
+ };
+
+ sti_uni_reader1: sti-uni-reader@1 {
+ compatible = "st,sti-uni-reader";
+ status = "disabled";
+ #sound-dai-cells = <0>;
+ st,syscfg = <&syscfg_core>;
+ reg = <0x8D84000 0x158>;
+ interrupts = <GIC_SPI 88 IRQ_TYPE_NONE>;
+ dmas = <&fdma0 6 0 1>;
+ dma-names = "rx";
+ dai-name = "Uni Reader #1 (HDMI RX)";
+ version = <3>;
+ };
+
+2) sti-sas-codec: internal audio codec IPs driver
+-------------------------------------------------
+
+Required properties:
+ - compatible: "st,sti<chip>-sas-codec" .
+ Should be chip "st,stih416-sas-codec" or "st,stih407-sas-codec"
+
+ - st,syscfg: phandle to boot-device system configuration registers.
+
+ - pinctrl-0: SPDIF PIO description.
+
+ - pinctrl-names: should contain only one value - "default".
+
+Example:
+ sti_sas_codec: sti-sas-codec {
+ compatible = "st,stih407-sas-codec";
+ #sound-dai-cells = <1>;
+ st,reg_audio = <&syscfg_core>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spdif_out >;
+ };
+
+Example of audio card declaration:
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "sti audio card";
+ status = "okay";
+
+ simple-audio-card,dai-link@0 {
+ /* DAC */
+ format = "i2s";
+ dai-tdm-slot-width = <32>;
+ cpu {
+ sound-dai = <&sti_uni_player2>;
+ };
+
+ codec {
+ sound-dai = <&sti_sasg_codec 1>;
+ };
+ };
+ simple-audio-card,dai-link@1 {
+ /* SPDIF */
+ format = "left_j";
+ cpu {
+ sound-dai = <&sti_uni_player3>;
+ };
+
+ codec {
+ sound-dai = <&sti_sasg_codec 0>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index d444757..66a33ae 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -110,6 +110,7 @@ ingenic Ingenic Semiconductor
innolux Innolux Corporation
intel Intel Corporation
intercontrol Inter Control Group
+invensense InvenSense Inc.
isee ISEE 2007 S.L.
isil Intersil
karo Ka-Ro electronics GmbH
@@ -150,6 +151,7 @@ nvidia NVIDIA
nxp NXP Semiconductors
onnn ON Semiconductor Corp.
opencores OpenCores.org
+option Option NV
ortustech Ortus Technology Co., Ltd.
ovti OmniVision Technologies
panasonic Panasonic Corporation
diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt
index c86f2f1..1fec113 100644
--- a/Documentation/input/alps.txt
+++ b/Documentation/input/alps.txt
@@ -119,8 +119,10 @@ ALPS Absolute Mode - Protocol Version 2
byte 5: 0 z6 z5 z4 z3 z2 z1 z0
Protocol Version 2 DualPoint devices send standard PS/2 mouse packets for
-the DualPoint Stick. For non interleaved dualpoint devices the pointingstick
-buttons get reported separately in the PSM, PSR and PSL bits.
+the DualPoint Stick. The M, R and L bits signal the combined status of both
+the pointingstick and touchpad buttons, except for Dell dualpoint devices
+where the pointingstick buttons get reported separately in the PSM, PSR
+and PSL bits.
Dualpoint device -- interleaved packet format
---------------------------------------------
diff --git a/MAINTAINERS b/MAINTAINERS
index a9ae6c1..569568f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3587,6 +3587,15 @@ S: Maintained
F: drivers/gpu/drm/rockchip/
F: Documentation/devicetree/bindings/video/rockchip*
+DRM DRIVERS FOR STI
+M: Benjamin Gaignard <benjamin.gaignard@linaro.org>
+M: Vincent Abriou <vincent.abriou@st.com>
+L: dri-devel@lists.freedesktop.org
+T: git http://git.linaro.org/people/benjamin.gaignard/kernel.git
+S: Maintained
+F: drivers/gpu/drm/sti
+F: Documentation/devicetree/bindings/gpu/st,stih4xx.txt
+
DSBR100 USB FM RADIO DRIVER
M: Alexey Klimov <klimov.linux@gmail.com>
L: linux-media@vger.kernel.org
diff --git a/Makefile b/Makefile
index e79448d..246053f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 4
PATCHLEVEL = 2
SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc8
NAME = Hurr durr I'ma sheep
# *DOCUMENTATION*
@@ -597,6 +597,11 @@ endif # $(dot-config)
# Defaults to vmlinux, but the arch makefile usually adds further targets
all: vmlinux
+# The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default
+# values of the respective KBUILD_* variables
+ARCH_CPPFLAGS :=
+ARCH_AFLAGS :=
+ARCH_CFLAGS :=
include arch/$(SRCARCH)/Makefile
KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,)
@@ -848,10 +853,10 @@ export mod_strip_cmd
mod_compress_cmd = true
ifdef CONFIG_MODULE_COMPRESS
ifdef CONFIG_MODULE_COMPRESS_GZIP
- mod_compress_cmd = gzip -n
+ mod_compress_cmd = gzip -n -f
endif # CONFIG_MODULE_COMPRESS_GZIP
ifdef CONFIG_MODULE_COMPRESS_XZ
- mod_compress_cmd = xz
+ mod_compress_cmd = xz -f
endif # CONFIG_MODULE_COMPRESS_XZ
endif # CONFIG_MODULE_COMPRESS
export mod_compress_cmd
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 91cf405..bd4670d 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -313,11 +313,11 @@ config ARC_PAGE_SIZE_8K
config ARC_PAGE_SIZE_16K
bool "16KB"
- depends on ARC_MMU_V3
+ depends on ARC_MMU_V3 || ARC_MMU_V4
config ARC_PAGE_SIZE_4K
bool "4KB"
- depends on ARC_MMU_V3
+ depends on ARC_MMU_V3 || ARC_MMU_V4
endchoice
@@ -365,6 +365,11 @@ config ARC_HAS_LLSC
default y
depends on !ARC_CANT_LLSC
+config ARC_STAR_9000923308
+ bool "Workaround for llock/scond livelock"
+ default y
+ depends on ISA_ARCV2 && SMP && ARC_HAS_LLSC
+
config ARC_HAS_SWAPE
bool "Insn: SWAPE (endian-swap)"
default y
@@ -379,6 +384,10 @@ config ARC_HAS_LL64
dest operands with 2 possible source operands.
default y
+config ARC_HAS_DIV_REM
+ bool "Insn: div, divu, rem, remu"
+ default y
+
config ARC_HAS_RTC
bool "Local 64-bit r/o cycle counter"
default n
diff --git a/arch/arc/Makefile b/arch/arc/Makefile
index 46d8731..8a27a48 100644
--- a/arch/arc/Makefile
+++ b/arch/arc/Makefile
@@ -36,8 +36,16 @@ cflags-$(atleast_gcc44) += -fsection-anchors
cflags-$(CONFIG_ARC_HAS_LLSC) += -mlock
cflags-$(CONFIG_ARC_HAS_SWAPE) += -mswape
+ifdef CONFIG_ISA_ARCV2
+
ifndef CONFIG_ARC_HAS_LL64
-cflags-$(CONFIG_ISA_ARCV2) += -mno-ll64
+cflags-y += -mno-ll64
+endif
+
+ifndef CONFIG_ARC_HAS_DIV_REM
+cflags-y += -mno-div-rem
+endif
+
endif
cflags-$(CONFIG_ARC_DW2_UNWIND) += -fasynchronous-unwind-tables
diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h
index 070f588..c8f57b8 100644
--- a/arch/arc/include/asm/arcregs.h
+++ b/arch/arc/include/asm/arcregs.h
@@ -89,11 +89,10 @@
#define ECR_C_BIT_DTLB_LD_MISS 8
#define ECR_C_BIT_DTLB_ST_MISS 9
-
/* Auxiliary registers */
#define AUX_IDENTITY 4
#define AUX_INTR_VEC_BASE 0x25
-
+#define AUX_NON_VOL 0x5e
/*
* Floating Pt Registers
@@ -240,9 +239,9 @@ struct bcr_extn_xymem {
struct bcr_perip {
#ifdef CONFIG_CPU_BIG_ENDIAN
- unsigned int start:8, pad2:8, sz:8, pad:8;
+ unsigned int start:8, pad2:8, sz:8, ver:8;
#else
- unsigned int pad:8, sz:8, pad2:8, start:8;
+ unsigned int ver:8, sz:8, pad2:8, start:8;
#endif
};
diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h
index 03484cb..87d18ae 100644
--- a/arch/arc/include/asm/atomic.h
+++ b/arch/arc/include/asm/atomic.h
@@ -23,33 +23,60 @@
#define atomic_set(v, i) (((v)->counter) = (i))
-#ifdef CONFIG_ISA_ARCV2
-#define PREFETCHW " prefetchw [%1] \n"
-#else
-#define PREFETCHW
+#ifdef CONFIG_ARC_STAR_9000923308
+
+#define SCOND_FAIL_RETRY_VAR_DEF \
+ unsigned int delay = 1, tmp; \
+
+#define SCOND_FAIL_RETRY_ASM \
+ " bz 4f \n" \
+ " ; --- scond fail delay --- \n" \
+ " mov %[tmp], %[delay] \n" /* tmp = delay */ \
+ "2: brne.d %[tmp], 0, 2b \n" /* while (tmp != 0) */ \
+ " sub %[tmp], %[tmp], 1 \n" /* tmp-- */ \
+ " rol %[delay], %[delay] \n" /* delay *= 2 */ \
+ " b 1b \n" /* start over */ \
+ "4: ; --- success --- \n" \
+
+#define SCOND_FAIL_RETRY_VARS \
+ ,[delay] "+&r" (delay),[tmp] "=&r" (tmp) \
+
+#else /* !CONFIG_ARC_STAR_9000923308 */
+
+#define SCOND_FAIL_RETRY_VAR_DEF
+
+#define SCOND_FAIL_RETRY_ASM \
+ " bnz 1b \n" \
+
+#define SCOND_FAIL_RETRY_VARS
+
#endif
#define ATOMIC_OP(op, c_op, asm_op) \
static inline void atomic_##op(int i, atomic_t *v) \
{ \
- unsigned int temp; \
+ unsigned int val; \
+ SCOND_FAIL_RETRY_VAR_DEF \
\
__asm__ __volatile__( \
- "1: \n" \
- PREFETCHW \
- " llock %0, [%1] \n" \
- " " #asm_op " %0, %0, %2 \n" \
- " scond %0, [%1] \n" \
- " bnz 1b \n" \
- : "=&r"(temp) /* Early clobber, to prevent reg reuse */ \
- : "r"(&v->counter), "ir"(i) \
+ "1: llock %[val], [%[ctr]] \n" \
+ " " #asm_op " %[val], %[val], %[i] \n" \
+ " scond %[val], [%[ctr]] \n" \
+ " \n" \
+ SCOND_FAIL_RETRY_ASM \
+ \
+ : [val] "=&r" (val) /* Early clobber to prevent reg reuse */ \
+ SCOND_FAIL_RETRY_VARS \
+ : [ctr] "r" (&v->counter), /* Not "m": llock only supports reg direct addr mode */ \
+ [i] "ir" (i) \
: "cc"); \
} \
#define ATOMIC_OP_RETURN(op, c_op, asm_op) \
static inline int atomic_##op##_return(int i, atomic_t *v) \
{ \
- unsigned int temp; \
+ unsigned int val; \
+ SCOND_FAIL_RETRY_VAR_DEF \
\
/* \
* Explicit full memory barrier needed before/after as \
@@ -58,19 +85,21 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \
smp_mb(); \
\
__asm__ __volatile__( \
- "1: \n" \
- PREFETCHW \
- " llock %0, [%1] \n" \
- " " #asm_op " %0, %0, %2 \n" \
- " scond %0, [%1] \n" \
- " bnz 1b \n" \
- : "=&r"(temp) \
- : "r"(&v->counter), "ir"(i) \
+ "1: llock %[val], [%[ctr]] \n" \
+ " " #asm_op " %[val], %[val], %[i] \n" \
+ " scond %[val], [%[ctr]] \n" \
+ " \n" \
+ SCOND_FAIL_RETRY_ASM \
+ \
+ : [val] "=&r" (val) \
+ SCOND_FAIL_RETRY_VARS \
+ : [ctr] "r" (&v->counter), \
+ [i] "ir" (i) \
: "cc"); \
\
smp_mb(); \
\
- return temp; \
+ return val; \
}
#else /* !CONFIG_ARC_HAS_LLSC */
@@ -150,6 +179,9 @@ ATOMIC_OP(and, &=, and)
#undef ATOMIC_OPS
#undef ATOMIC_OP_RETURN
#undef ATOMIC_OP
+#undef SCOND_FAIL_RETRY_VAR_DEF
+#undef SCOND_FAIL_RETRY_ASM
+#undef SCOND_FAIL_RETRY_VARS
/**
* __atomic_add_unless - add unless the number is a given value
diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h
index 91694ec..69095da 100644
--- a/arch/arc/include/asm/ptrace.h
+++ b/arch/arc/include/asm/ptrace.h
@@ -20,20 +20,20 @@
struct pt_regs {
/* Real registers */
- long bta; /* bta_l1, bta_l2, erbta */
+ unsigned long bta; /* bta_l1, bta_l2, erbta */
- long lp_start, lp_end, lp_count;
+ unsigned long lp_start, lp_end, lp_count;
- long status32; /* status32_l1, status32_l2, erstatus */
- long ret; /* ilink1, ilink2 or eret */
- long blink;
- long fp;
- long r26; /* gp */
+ unsigned long status32; /* status32_l1, status32_l2, erstatus */
+ unsigned long ret; /* ilink1, ilink2 or eret */
+ unsigned long blink;
+ unsigned long fp;
+ unsigned long r26; /* gp */
- long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
+ unsigned long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
- long sp; /* user/kernel sp depending on where we came from */
- long orig_r0;
+ unsigned long sp; /* User/Kernel depending on where we came from */
+ unsigned long orig_r0;
/*
* To distinguish bet excp, syscall, irq
@@ -55,13 +55,13 @@ struct pt_regs {
unsigned long event;
};
- long user_r25;
+ unsigned long user_r25;
};
#else
struct pt_regs {
- long orig_r0;
+ unsigned long orig_r0;
union {
struct {
@@ -76,26 +76,26 @@ struct pt_regs {
unsigned long event;
};
- long bta; /* bta_l1, bta_l2, erbta */
+ unsigned long bta; /* bta_l1, bta_l2, erbta */
- long user_r25;
+ unsigned long user_r25;
- long r26; /* gp */
- long fp;
- long sp; /* user/kernel sp depending on where we came from */
+ unsigned long r26; /* gp */
+ unsigned long fp;
+ unsigned long sp; /* user/kernel sp depending on where we came from */
- long r12;
+ unsigned long r12;
/*------- Below list auto saved by h/w -----------*/
- long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
+ unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
- long blink;
- long lp_end, lp_start, lp_count;
+ unsigned long blink;
+ unsigned long lp_end, lp_start, lp_count;
- long ei, ldi, jli;
+ unsigned long ei, ldi, jli;
- long ret;
- long status32;
+ unsigned long ret;
+ unsigned long status32;
};
#endif
@@ -103,10 +103,10 @@ struct pt_regs {
/* Callee saved registers - need to be saved only when you are scheduled out */
struct callee_regs {
- long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
+ unsigned long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
};
-#define instruction_pointer(regs) (unsigned long)((regs)->ret)
+#define instruction_pointer(regs) ((regs)->ret)
#define profile_pc(regs) instruction_pointer(regs)
/* return 1 if user mode or 0 if kernel mode */
@@ -142,7 +142,7 @@ struct callee_regs {
static inline long regs_return_value(struct pt_regs *regs)
{
- return regs->r0;
+ return (long)regs->r0;
}
#endif /* !__ASSEMBLY__ */
diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h
index e1651df..db8c59d 100644
--- a/arch/arc/include/asm/spinlock.h
+++ b/arch/arc/include/asm/spinlock.h
@@ -18,9 +18,518 @@
#define arch_spin_unlock_wait(x) \
do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0)
+#ifdef CONFIG_ARC_HAS_LLSC
+
+/*
+ * A normal LLOCK/SCOND based system, w/o need for livelock workaround
+ */
+#ifndef CONFIG_ARC_STAR_9000923308
+
static inline void arch_spin_lock(arch_spinlock_t *lock)
{
- unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__;
+ unsigned int val;
+
+ smp_mb();
+
+ __asm__ __volatile__(
+ "1: llock %[val], [%[slock]] \n"
+ " breq %[val], %[LOCKED], 1b \n" /* spin while LOCKED */
+ " scond %[LOCKED], [%[slock]] \n" /* acquire */
+ " bnz 1b \n"
+ " \n"
+ : [val] "=&r" (val)
+ : [slock] "r" (&(lock->slock)),
+ [LOCKED] "r" (__ARCH_SPIN_LOCK_LOCKED__)
+ : "memory", "cc");
+
+ smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+ unsigned int val, got_it = 0;
+
+ smp_mb();
+
+ __asm__ __volatile__(
+ "1: llock %[val], [%[slock]] \n"
+ " breq %[val], %[LOCKED], 4f \n" /* already LOCKED, just bail */
+ " scond %[LOCKED], [%[slock]] \n" /* acquire */
+ " bnz 1b \n"
+ " mov %[got_it], 1 \n"
+ "4: \n"
+ " \n"
+ : [val] "=&r" (val),
+ [got_it] "+&r" (got_it)
+ : [slock] "r" (&(lock->slock)),
+ [LOCKED] "r" (__ARCH_SPIN_LOCK_LOCKED__)
+ : "memory", "cc");
+
+ smp_mb();
+
+ return got_it;
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+ smp_mb();
+
+ lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__;
+
+ smp_mb();
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
+ */
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+ unsigned int val;
+
+ smp_mb();
+
+ /*
+ * zero means writer holds the lock exclusively, deny Reader.
+ * Otherwise grant lock to first/subseq reader
+ *
+ * if (rw->counter > 0) {
+ * rw->counter--;
+ * ret = 1;
+ * }
+ */
+
+ __asm__ __volatile__(
+ "1: llock %[val], [%[rwlock]] \n"
+ " brls %[val], %[WR_LOCKED], 1b\n" /* <= 0: spin while write locked */
+ " sub %[val], %[val], 1 \n" /* reader lock */
+ " scond %[val], [%[rwlock]] \n"
+ " bnz 1b \n"
+ " \n"
+ : [val] "=&r" (val)
+ : [rwlock] "r" (&(rw->counter)),
+ [WR_LOCKED] "ir" (0)
+ : "memory", "cc");
+
+ smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+ unsigned int val, got_it = 0;
+
+ smp_mb();
+
+ __asm__ __volatile__(
+ "1: llock %[val], [%[rwlock]] \n"
+ " brls %[val], %[WR_LOCKED], 4f\n" /* <= 0: already write locked, bail */
+ " sub %[val], %[val], 1 \n" /* counter-- */
+ " scond %[val], [%[rwlock]] \n"
+ " bnz 1b \n" /* retry if collided with someone */
+ " mov %[got_it], 1 \n"
+ " \n"
+ "4: ; --- done --- \n"
+
+ : [val] "=&r" (val),
+ [got_it] "+&r" (got_it)
+ : [rwlock] "r" (&(rw->counter)),
+ [WR_LOCKED] "ir" (0)
+ : "memory", "cc");
+
+ smp_mb();
+
+ return got_it;
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+ unsigned int val;
+
+ smp_mb();
+
+ /*
+ * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
+ * deny writer. Otherwise if unlocked grant to writer
+ * Hence the claim that Linux rwlocks are unfair to writers.
+ * (can be starved for an indefinite time by readers).
+ *
+ * if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
+ * rw->counter = 0;
+ * ret = 1;
+ * }
+ */
+
+ __asm__ __volatile__(
+ "1: llock %[val], [%[rwlock]] \n"
+ " brne %[val], %[UNLOCKED], 1b \n" /* while !UNLOCKED spin */
+ " mov %[val], %[WR_LOCKED] \n"
+ " scond %[val], [%[rwlock]] \n"
+ " bnz 1b \n"
+ " \n"
+ : [val] "=&r" (val)
+ : [rwlock] "r" (&(rw->counter)),
+ [UNLOCKED] "ir" (__ARCH_RW_LOCK_UNLOCKED__),
+ [WR_LOCKED] "ir" (0)
+ : "memory", "cc");
+
+ smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+ unsigned int val, got_it = 0;
+
+ smp_mb();
+
+ __asm__ __volatile__(
+ "1: llock %[val], [%[rwlock]] \n"
+ " brne %[val], %[UNLOCKED], 4f \n" /* !UNLOCKED, bail */
+ " mov %[val], %[WR_LOCKED] \n"
+ " scond %[val], [%[rwlock]] \n"
+ " bnz 1b \n" /* retry if collided with someone */
+ " mov %[got_it], 1 \n"
+ " \n"
+ "4: ; --- done --- \n"
+
+ : [val] "=&r" (val),
+ [got_it] "+&r" (got_it)
+ : [rwlock] "r" (&(rw->counter)),
+ [UNLOCKED] "ir" (__ARCH_RW_LOCK_UNLOCKED__),
+ [WR_LOCKED] "ir" (0)
+ : "memory", "cc");
+
+ smp_mb();
+
+ return got_it;
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+ unsigned int val;
+
+ smp_mb();
+
+ /*
+ * rw->counter++;
+ */
+ __asm__ __volatile__(
+ "1: llock %[val], [%[rwlock]] \n"
+ " add %[val], %[val], 1 \n"
+ " scond %[val], [%[rwlock]] \n"
+ " bnz 1b \n"
+ " \n"
+ : [val] "=&r" (val)
+ : [rwlock] "r" (&(rw->counter))
+ : "memory", "cc");
+
+ smp_mb();
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+ smp_mb();
+
+ rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
+
+ smp_mb();
+}
+
+#else /* CONFIG_ARC_STAR_9000923308 */
+
+/*
+ * HS38x4 could get into a LLOCK/SCOND livelock in case of multiple overlapping
+ * coherency transactions in the SCU. The exclusive line state keeps rotating
+ * among contenting cores leading to a never ending cycle. So break the cycle
+ * by deferring the retry of failed exclusive access (SCOND). The actual delay
+ * needed is function of number of contending cores as well as the unrelated
+ * coherency traffic from other cores. To keep the code simple, start off with
+ * small delay of 1 which would suffice most cases and in case of contention
+ * double the delay. Eventually the delay is sufficient such that the coherency
+ * pipeline is drained, thus a subsequent exclusive access would succeed.
+ */
+
+#define SCOND_FAIL_RETRY_VAR_DEF \
+ unsigned int delay, tmp; \
+
+#define SCOND_FAIL_RETRY_ASM \
+ " ; --- scond fail delay --- \n" \
+ " mov %[tmp], %[delay] \n" /* tmp = delay */ \
+ "2: brne.d %[tmp], 0, 2b \n" /* while (tmp != 0) */ \
+ " sub %[tmp], %[tmp], 1 \n" /* tmp-- */ \
+ " rol %[delay], %[delay] \n" /* delay *= 2 */ \
+ " b 1b \n" /* start over */ \
+ " \n" \
+ "4: ; --- done --- \n" \
+
+#define SCOND_FAIL_RETRY_VARS \
+ ,[delay] "=&r" (delay), [tmp] "=&r" (tmp) \
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+ unsigned int val;
+ SCOND_FAIL_RETRY_VAR_DEF;
+
+ smp_mb();
+
+ __asm__ __volatile__(
+ "0: mov %[delay], 1 \n"
+ "1: llock %[val], [%[slock]] \n"
+ " breq %[val], %[LOCKED], 0b \n" /* spin while LOCKED */
+ " scond %[LOCKED], [%[slock]] \n" /* acquire */
+ " bz 4f \n" /* done */
+ " \n"
+ SCOND_FAIL_RETRY_ASM
+
+ : [val] "=&r" (val)
+ SCOND_FAIL_RETRY_VARS
+ : [slock] "r" (&(lock->slock)),
+ [LOCKED] "r" (__ARCH_SPIN_LOCK_LOCKED__)
+ : "memory", "cc");
+
+ smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+ unsigned int val, got_it = 0;
+ SCOND_FAIL_RETRY_VAR_DEF;
+
+ smp_mb();
+
+ __asm__ __volatile__(
+ "0: mov %[delay], 1 \n"
+ "1: llock %[val], [%[slock]] \n"
+ " breq %[val], %[LOCKED], 4f \n" /* already LOCKED, just bail */
+ " scond %[LOCKED], [%[slock]] \n" /* acquire */
+ " bz.d 4f \n"
+ " mov.z %[got_it], 1 \n" /* got it */
+ " \n"
+ SCOND_FAIL_RETRY_ASM
+
+ : [val] "=&r" (val),
+ [got_it] "+&r" (got_it)
+ SCOND_FAIL_RETRY_VARS
+ : [slock] "r" (&(lock->slock)),
+ [LOCKED] "r" (__ARCH_SPIN_LOCK_LOCKED__)
+ : "memory", "cc");
+
+ smp_mb();
+
+ return got_it;
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+ smp_mb();
+
+ lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__;
+
+ smp_mb();
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
+ */
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+ unsigned int val;
+ SCOND_FAIL_RETRY_VAR_DEF;
+
+ smp_mb();
+
+ /*
+ * zero means writer holds the lock exclusively, deny Reader.
+ * Otherwise grant lock to first/subseq reader
+ *
+ * if (rw->counter > 0) {
+ * rw->counter--;
+ * ret = 1;
+ * }
+ */
+
+ __asm__ __volatile__(
+ "0: mov %[delay], 1 \n"
+ "1: llock %[val], [%[rwlock]] \n"
+ " brls %[val], %[WR_LOCKED], 0b\n" /* <= 0: spin while write locked */
+ " sub %[val], %[val], 1 \n" /* reader lock */
+ " scond %[val], [%[rwlock]] \n"
+ " bz 4f \n" /* done */
+ " \n"
+ SCOND_FAIL_RETRY_ASM
+
+ : [val] "=&r" (val)
+ SCOND_FAIL_RETRY_VARS
+ : [rwlock] "r" (&(rw->counter)),
+ [WR_LOCKED] "ir" (0)
+ : "memory", "cc");
+
+ smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+ unsigned int val, got_it = 0;
+ SCOND_FAIL_RETRY_VAR_DEF;
+
+ smp_mb();
+
+ __asm__ __volatile__(
+ "0: mov %[delay], 1 \n"
+ "1: llock %[val], [%[rwlock]] \n"
+ " brls %[val], %[WR_LOCKED], 4f\n" /* <= 0: already write locked, bail */
+ " sub %[val], %[val], 1 \n" /* counter-- */
+ " scond %[val], [%[rwlock]] \n"
+ " bz.d 4f \n"
+ " mov.z %[got_it], 1 \n" /* got it */
+ " \n"
+ SCOND_FAIL_RETRY_ASM
+
+ : [val] "=&r" (val),
+ [got_it] "+&r" (got_it)
+ SCOND_FAIL_RETRY_VARS
+ : [rwlock] "r" (&(rw->counter)),
+ [WR_LOCKED] "ir" (0)
+ : "memory", "cc");
+
+ smp_mb();
+
+ return got_it;
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+ unsigned int val;
+ SCOND_FAIL_RETRY_VAR_DEF;
+
+ smp_mb();
+
+ /*
+ * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
+ * deny writer. Otherwise if unlocked grant to writer
+ * Hence the claim that Linux rwlocks are unfair to writers.
+ * (can be starved for an indefinite time by readers).
+ *
+ * if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
+ * rw->counter = 0;
+ * ret = 1;
+ * }
+ */
+
+ __asm__ __volatile__(
+ "0: mov %[delay], 1 \n"
+ "1: llock %[val], [%[rwlock]] \n"
+ " brne %[val], %[UNLOCKED], 0b \n" /* while !UNLOCKED spin */
+ " mov %[val], %[WR_LOCKED] \n"
+ " scond %[val], [%[rwlock]] \n"
+ " bz 4f \n"
+ " \n"
+ SCOND_FAIL_RETRY_ASM
+
+ : [val] "=&r" (val)
+ SCOND_FAIL_RETRY_VARS
+ : [rwlock] "r" (&(rw->counter)),
+ [UNLOCKED] "ir" (__ARCH_RW_LOCK_UNLOCKED__),
+ [WR_LOCKED] "ir" (0)
+ : "memory", "cc");
+
+ smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+ unsigned int val, got_it = 0;
+ SCOND_FAIL_RETRY_VAR_DEF;
+
+ smp_mb();
+
+ __asm__ __volatile__(
+ "0: mov %[delay], 1 \n"
+ "1: llock %[val], [%[rwlock]] \n"
+ " brne %[val], %[UNLOCKED], 4f \n" /* !UNLOCKED, bail */
+ " mov %[val], %[WR_LOCKED] \n"
+ " scond %[val], [%[rwlock]] \n"
+ " bz.d 4f \n"
+ " mov.z %[got_it], 1 \n" /* got it */
+ " \n"
+ SCOND_FAIL_RETRY_ASM
+
+ : [val] "=&r" (val),
+ [got_it] "+&r" (got_it)
+ SCOND_FAIL_RETRY_VARS
+ : [rwlock] "r" (&(rw->counter)),
+ [UNLOCKED] "ir" (__ARCH_RW_LOCK_UNLOCKED__),
+ [WR_LOCKED] "ir" (0)
+ : "memory", "cc");
+
+ smp_mb();
+
+ return got_it;
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+ unsigned int val;
+
+ smp_mb();
+
+ /*
+ * rw->counter++;
+ */
+ __asm__ __volatile__(
+ "1: llock %[val], [%[rwlock]] \n"
+ " add %[val], %[val], 1 \n"
+ " scond %[val], [%[rwlock]] \n"
+ " bnz 1b \n"
+ " \n"
+ : [val] "=&r" (val)
+ : [rwlock] "r" (&(rw->counter))
+ : "memory", "cc");
+
+ smp_mb();
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+ unsigned int val;
+
+ smp_mb();
+
+ /*
+ * rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
+ */
+ __asm__ __volatile__(
+ "1: llock %[val], [%[rwlock]] \n"
+ " scond %[UNLOCKED], [%[rwlock]]\n"
+ " bnz 1b \n"
+ " \n"
+ : [val] "=&r" (val)
+ : [rwlock] "r" (&(rw->counter)),
+ [UNLOCKED] "r" (__ARCH_RW_LOCK_UNLOCKED__)
+ : "memory", "cc");
+
+ smp_mb();
+}
+
+#undef SCOND_FAIL_RETRY_VAR_DEF
+#undef SCOND_FAIL_RETRY_ASM
+#undef SCOND_FAIL_RETRY_VARS
+
+#endif /* CONFIG_ARC_STAR_9000923308 */
+
+#else /* !CONFIG_ARC_HAS_LLSC */
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+ unsigned int val = __ARCH_SPIN_LOCK_LOCKED__;
/*
* This smp_mb() is technically superfluous, we only need the one
@@ -33,7 +542,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
__asm__ __volatile__(
"1: ex %0, [%1] \n"
" breq %0, %2, 1b \n"
- : "+&r" (tmp)
+ : "+&r" (val)
: "r"(&(lock->slock)), "ir"(__ARCH_SPIN_LOCK_LOCKED__)
: "memory");
@@ -48,26 +557,27 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
smp_mb();
}
+/* 1 - lock taken successfully */
static inline int arch_spin_trylock(arch_spinlock_t *lock)
{
- unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__;
+ unsigned int val = __ARCH_SPIN_LOCK_LOCKED__;
smp_mb();
__asm__ __volatile__(
"1: ex %0, [%1] \n"
- : "+r" (tmp)
+ : "+r" (val)
: "r"(&(lock->slock))
: "memory");
smp_mb();
- return (tmp == __ARCH_SPIN_LOCK_UNLOCKED__);
+ return (val == __ARCH_SPIN_LOCK_UNLOCKED__);
}
static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
- unsigned int tmp = __ARCH_SPIN_LOCK_UNLOCKED__;
+ unsigned int val = __ARCH_SPIN_LOCK_UNLOCKED__;
/*
* RELEASE barrier: given the instructions avail on ARCv2, full barrier
@@ -77,7 +587,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
__asm__ __volatile__(
" ex %0, [%1] \n"
- : "+r" (tmp)
+ : "+r" (val)
: "r"(&(lock->slock))
: "memory");
@@ -90,19 +600,12 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
/*
* Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
*
* The spinlock itself is contained in @counter and access to it is
* serialized with @lock_mutex.
- *
- * Unfair locking as Writers could be starved indefinitely by Reader(s)
*/
-/* Would read_trylock() succeed? */
-#define arch_read_can_lock(x) ((x)->counter > 0)
-
-/* Would write_trylock() succeed? */
-#define arch_write_can_lock(x) ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__)
-
/* 1 - lock taken successfully */
static inline int arch_read_trylock(arch_rwlock_t *rw)
{
@@ -173,6 +676,11 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
arch_spin_unlock(&(rw->lock_mutex));
}
+#endif
+
+#define arch_read_can_lock(x) ((x)->counter > 0)
+#define arch_write_can_lock(x) ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__)
+
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
diff --git a/arch/arc/include/asm/spinlock_types.h b/arch/arc/include/asm/spinlock_types.h
index 662627c..4e1ef5f 100644
--- a/arch/arc/include/asm/spinlock_types.h
+++ b/arch/arc/include/asm/spinlock_types.h
@@ -26,7 +26,9 @@ typedef struct {
*/
typedef struct {
volatile unsigned int counter;
+#ifndef CONFIG_ARC_HAS_LLSC
arch_spinlock_t lock_mutex;
+#endif
} arch_rwlock_t;
#define __ARCH_RW_LOCK_UNLOCKED__ 0x01000000
diff --git a/arch/arc/include/uapi/asm/ptrace.h b/arch/arc/include/uapi/asm/ptrace.h
index 76a7739..0b3ef63 100644
--- a/arch/arc/include/uapi/asm/ptrace.h
+++ b/arch/arc/include/uapi/asm/ptrace.h
@@ -32,20 +32,20 @@
*/
struct user_regs_struct {
- long pad;
+ unsigned long pad;
struct {
- long bta, lp_start, lp_end, lp_count;
- long status32, ret, blink, fp, gp;
- long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
- long sp;
+ unsigned long bta, lp_start, lp_end, lp_count;
+ unsigned long status32, ret, blink, fp, gp;
+ unsigned long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
+ unsigned long sp;
} scratch;
- long pad2;
+ unsigned long pad2;
struct {
- long r25, r24, r23, r22, r21, r20;
- long r19, r18, r17, r16, r15, r14, r13;
+ unsigned long r25, r24, r23, r22, r21, r20;
+ unsigned long r19, r18, r17, r16, r15, r14, r13;
} callee;
- long efa; /* break pt addr, for break points in delay slots */
- long stop_pc; /* give dbg stop_pc after ensuring brkpt trap */
+ unsigned long efa; /* break pt addr, for break points in delay slots */
+ unsigned long stop_pc; /* give dbg stop_pc after ensuring brkpt trap */
};
#endif /* !__ASSEMBLY__ */
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index 18cc015..cabde9d 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -47,6 +47,7 @@ static void read_arc_build_cfg_regs(void)
struct bcr_perip uncached_space;
struct bcr_generic bcr;
struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
+ unsigned long perip_space;
FIX_PTR(cpu);
READ_BCR(AUX_IDENTITY, cpu->core);
@@ -56,7 +57,12 @@ static void read_arc_build_cfg_regs(void)
cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);
READ_BCR(ARC_REG_D_UNCACH_BCR, uncached_space);
- BUG_ON((uncached_space.start << 24) != ARC_UNCACHED_ADDR_SPACE);
+ if (uncached_space.ver < 3)
+ perip_space = uncached_space.start << 24;
+ else
+ perip_space = read_aux_reg(AUX_NON_VOL) & 0xF0000000;
+
+ BUG_ON(perip_space != ARC_UNCACHED_ADDR_SPACE);
READ_BCR(ARC_REG_MUL_BCR, cpu->extn_mpy);
@@ -330,6 +336,10 @@ static void arc_chk_core_config(void)
pr_warn("CONFIG_ARC_FPU_SAVE_RESTORE needed for working apps\n");
else if (!cpu->extn.fpu_dp && fpu_enabled)
panic("FPU non-existent, disable CONFIG_ARC_FPU_SAVE_RESTORE\n");
+
+ if (is_isa_arcv2() && IS_ENABLED(CONFIG_SMP) && cpu->isa.atomic &&
+ !IS_ENABLED(CONFIG_ARC_STAR_9000923308))
+ panic("llock/scond livelock workaround missing\n");
}
/*
diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c
index 3364d2b..4294761 100644
--- a/arch/arc/kernel/time.c
+++ b/arch/arc/kernel/time.c
@@ -203,34 +203,24 @@ static int arc_clkevent_set_next_event(unsigned long delta,
return 0;
}
-static void arc_clkevent_set_mode(enum clock_event_mode mode,
- struct clock_event_device *dev)
+static int arc_clkevent_set_periodic(struct clock_event_device *dev)
{
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- /*
- * At X Hz, 1 sec = 1000ms -> X cycles;
- * 10ms -> X / 100 cycles
- */
- arc_timer_event_setup(arc_get_core_freq() / HZ);
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- break;
- default:
- break;
- }
-
- return;
+ /*
+ * At X Hz, 1 sec = 1000ms -> X cycles;
+ * 10ms -> X / 100 cycles
+ */
+ arc_timer_event_setup(arc_get_core_freq() / HZ);
+ return 0;
}
static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = {
- .name = "ARC Timer0",
- .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
- .mode = CLOCK_EVT_MODE_UNUSED,
- .rating = 300,
- .irq = TIMER0_IRQ, /* hardwired, no need for resources */
- .set_next_event = arc_clkevent_set_next_event,
- .set_mode = arc_clkevent_set_mode,
+ .name = "ARC Timer0",
+ .features = CLOCK_EVT_FEAT_ONESHOT |
+ CLOCK_EVT_FEAT_PERIODIC,
+ .rating = 300,
+ .irq = TIMER0_IRQ, /* hardwired, no need for resources */
+ .set_next_event = arc_clkevent_set_next_event,
+ .set_state_periodic = arc_clkevent_set_periodic,
};
static irqreturn_t timer_irq_handler(int irq, void *dev_id)
@@ -240,7 +230,7 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id)
* irq_set_chip_and_handler() asked for handle_percpu_devid_irq()
*/
struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
- int irq_reenable = evt->mode == CLOCK_EVT_MODE_PERIODIC;
+ int irq_reenable = clockevent_state_periodic(evt);
/*
* Any write to CTRL reg ACks the interrupt, we rewrite the
diff --git a/arch/arc/lib/memcpy-archs.S b/arch/arc/lib/memcpy-archs.S
index 1b2b3ac..0cab0b8 100644
--- a/arch/arc/lib/memcpy-archs.S
+++ b/arch/arc/lib/memcpy-archs.S
@@ -206,7 +206,7 @@ unalignedOffby3:
ld.ab r6, [r1, 4]
prefetch [r1, 28] ;Prefetch the next read location
ld.ab r8, [r1,4]
- prefetch [r3, 32] ;Prefetch the next write location
+ prefetchw [r3, 32] ;Prefetch the next write location
SHIFT_1 (r7, r6, 8)
or r7, r7, r5
diff --git a/arch/arc/lib/memset-archs.S b/arch/arc/lib/memset-archs.S
index 92d573c..365b183 100644
--- a/arch/arc/lib/memset-archs.S
+++ b/arch/arc/lib/memset-archs.S
@@ -10,12 +10,6 @@
#undef PREALLOC_NOT_AVAIL
-#ifdef PREALLOC_NOT_AVAIL
-#define PREWRITE(A,B) prefetchw [(A),(B)]
-#else
-#define PREWRITE(A,B) prealloc [(A),(B)]
-#endif
-
ENTRY(memset)
prefetchw [r0] ; Prefetch the write location
mov.f 0, r2
@@ -51,9 +45,15 @@ ENTRY(memset)
;;; Convert len to Dwords, unfold x8
lsr.f lp_count, lp_count, 6
+
lpnz @.Lset64bytes
;; LOOP START
- PREWRITE(r3, 64) ;Prefetch the next write location
+#ifdef PREALLOC_NOT_AVAIL
+ prefetchw [r3, 64] ;Prefetch the next write location
+#else
+ prealloc [r3, 64]
+#endif
+#ifdef CONFIG_ARC_HAS_LL64
std.ab r4, [r3, 8]
std.ab r4, [r3, 8]
std.ab r4, [r3, 8]
@@ -62,16 +62,45 @@ ENTRY(memset)
std.ab r4, [r3, 8]
std.ab r4, [r3, 8]
std.ab r4, [r3, 8]
+#else
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+#endif
.Lset64bytes:
lsr.f lp_count, r2, 5 ;Last remaining max 124 bytes
lpnz .Lset32bytes
;; LOOP START
prefetchw [r3, 32] ;Prefetch the next write location
+#ifdef CONFIG_ARC_HAS_LL64
std.ab r4, [r3, 8]
std.ab r4, [r3, 8]
std.ab r4, [r3, 8]
std.ab r4, [r3, 8]
+#else
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+ st.ab r4, [r3, 4]
+#endif
.Lset32bytes:
and.f lp_count, r2, 0x1F ;Last remaining 31 bytes
diff --git a/arch/arc/plat-axs10x/axs10x.c b/arch/arc/plat-axs10x/axs10x.c
index 99f7da5..e7769c3 100644
--- a/arch/arc/plat-axs10x/axs10x.c
+++ b/arch/arc/plat-axs10x/axs10x.c
@@ -389,6 +389,21 @@ axs103_set_freq(unsigned int id, unsigned int fd, unsigned int od)
static void __init axs103_early_init(void)
{
+ /*
+ * AXS103 configurations for SMP/QUAD configurations share device tree
+ * which defaults to 90 MHz. However recent failures of Quad config
+ * revealed P&R timing violations so clamp it down to safe 50 MHz
+ * Instead of duplicating defconfig/DT for SMP/QUAD, add a small hack
+ *
+ * This hack is really hacky as of now. Fix it properly by getting the
+ * number of cores as return value of platform's early SMP callback
+ */
+#ifdef CONFIG_ARC_MCIP
+ unsigned int num_cores = (read_aux_reg(ARC_REG_MCIP_BCR) >> 16) & 0x3F;
+ if (num_cores > 2)
+ arc_set_core_freq(50 * 1000000);
+#endif
+
switch (arc_get_core_freq()/1000000) {
case 33:
axs103_set_freq(1, 1, 1);
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 07ab3d2..7451b44 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -312,6 +312,9 @@ INSTALL_TARGETS = zinstall uinstall install
PHONY += bzImage $(BOOT_TARGETS) $(INSTALL_TARGETS)
+bootpImage uImage: zImage
+zImage: Image
+
$(BOOT_TARGETS): vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index 8f1e25b..1e29ccf 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -116,7 +116,7 @@
ranges = <0 0x2000 0x2000>;
scm_conf: scm_conf@0 {
- compatible = "syscon";
+ compatible = "syscon", "simple-bus";
reg = <0x0 0x1400>;
#address-cells = <1>;
#size-cells = <1>;
@@ -1140,6 +1140,7 @@
ctrl-module = <&omap_control_sata>;
clocks = <&sys_clkin1>, <&sata_ref_clk>;
clock-names = "sysclk", "refclk";
+ syscon-pllreset = <&scm_conf 0x3fc>;
#phy-cells = <0>;
};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index e6d1359..b57033e 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -181,10 +181,10 @@
interrupt-names = "msi";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
- interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-map = <0 0 0 1 &gpc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gpc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gpc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gpc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6QDL_CLK_PCIE_AXI>,
<&clks IMX6QDL_CLK_LVDS1_GATE>,
<&clks IMX6QDL_CLK_PCIE_REF_125M>;
diff --git a/arch/arm/boot/dts/k2e.dtsi b/arch/arm/boot/dts/k2e.dtsi
index 1b6494f..675fb8e 100644
--- a/arch/arm/boot/dts/k2e.dtsi
+++ b/arch/arm/boot/dts/k2e.dtsi
@@ -131,10 +131,17 @@
<GIC_SPI 376 IRQ_TYPE_EDGE_RISING>;
};
};
+
+ mdio: mdio@24200f00 {
+ compatible = "ti,keystone_mdio", "ti,davinci_mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x24200f00 0x100>;
+ status = "disabled";
+ clocks = <&clkcpgmac>;
+ clock-names = "fck";
+ bus_freq = <2500000>;
+ };
/include/ "k2e-netcp.dtsi"
};
};
-
-&mdio {
- reg = <0x24200f00 0x100>;
-};
diff --git a/arch/arm/boot/dts/k2hk.dtsi b/arch/arm/boot/dts/k2hk.dtsi
index ae64724..d0810a5 100644
--- a/arch/arm/boot/dts/k2hk.dtsi
+++ b/arch/arm/boot/dts/k2hk.dtsi
@@ -98,6 +98,17 @@
#gpio-cells = <2>;
gpio,syscon-dev = <&devctrl 0x25c>;
};
+
+ mdio: mdio@02090300 {
+ compatible = "ti,keystone_mdio", "ti,davinci_mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x02090300 0x100>;
+ status = "disabled";
+ clocks = <&clkcpgmac>;
+ clock-names = "fck";
+ bus_freq = <2500000>;
+ };
/include/ "k2hk-netcp.dtsi"
};
};
diff --git a/arch/arm/boot/dts/k2l.dtsi b/arch/arm/boot/dts/k2l.dtsi
index 0e00748..49fd414 100644
--- a/arch/arm/boot/dts/k2l.dtsi
+++ b/arch/arm/boot/dts/k2l.dtsi
@@ -29,7 +29,6 @@
};
soc {
-
/include/ "k2l-clocks.dtsi"
uart2: serial@02348400 {
@@ -79,6 +78,17 @@
#gpio-cells = <2>;
gpio,syscon-dev = <&devctrl 0x24c>;
};
+
+ mdio: mdio@26200f00 {
+ compatible = "ti,keystone_mdio", "ti,davinci_mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x26200f00 0x100>;
+ status = "disabled";
+ clocks = <&clkcpgmac>;
+ clock-names = "fck";
+ bus_freq = <2500000>;
+ };
/include/ "k2l-netcp.dtsi"
};
};
@@ -96,7 +106,3 @@
/* Pin muxed. Enabled and configured by Bootloader */
status = "disabled";
};
-
-&mdio {
- reg = <0x26200f00 0x100>;
-};
diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi
index e7a6f6d..72816d6 100644
--- a/arch/arm/boot/dts/keystone.dtsi
+++ b/arch/arm/boot/dts/keystone.dtsi
@@ -267,17 +267,6 @@
1 0 0x21000A00 0x00000100>;
};
- mdio: mdio@02090300 {
- compatible = "ti,keystone_mdio", "ti,davinci_mdio";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x02090300 0x100>;
- status = "disabled";
- clocks = <&clkpa>;
- clock-names = "fck";
- bus_freq = <2500000>;
- };
-
kirq0: keystone_irq@26202a0 {
compatible = "ti,keystone-irq";
interrupts = <GIC_SPI 4 IRQ_TYPE_EDGE_RISING>;
diff --git a/arch/arm/boot/dts/omap2430.dtsi b/arch/arm/boot/dts/omap2430.dtsi
index 11a7963..2390f38 100644
--- a/arch/arm/boot/dts/omap2430.dtsi
+++ b/arch/arm/boot/dts/omap2430.dtsi
@@ -51,7 +51,8 @@
};
scm_conf: scm_conf@270 {
- compatible = "syscon";
+ compatible = "syscon",
+ "simple-bus";
reg = <0x270 0x240>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 7d31c6f..abc4473 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -191,7 +191,8 @@
};
omap4_padconf_global: omap4_padconf_global@5a0 {
- compatible = "syscon";
+ compatible = "syscon",
+ "simple-bus";
reg = <0x5a0 0x170>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index c8fd648..b1a1263 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -180,7 +180,8 @@
};
omap5_padconf_global: omap5_padconf_global@5a0 {
- compatible = "syscon";
+ compatible = "syscon",
+ "simple-bus";
reg = <0x5a0 0xec>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi
index a75f328..b8f81fb 100644
--- a/arch/arm/boot/dts/ste-dbx5x0.dtsi
+++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi
@@ -15,6 +15,33 @@
#include "skeleton.dtsi"
/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ enable-method = "ste,dbx500-smp";
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+ core1 {
+ cpu = <&CPU1>;
+ };
+ };
+ };
+ CPU0: cpu@300 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0x300>;
+ };
+ CPU1: cpu@301 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0x301>;
+ };
+ };
+
soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -22,32 +49,6 @@
interrupt-parent = <&intc>;
ranges;
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- cpu-map {
- cluster0 {
- core0 {
- cpu = <&CPU0>;
- };
- core1 {
- cpu = <&CPU1>;
- };
- };
- };
- CPU0: cpu@0 {
- device_type = "cpu";
- compatible = "arm,cortex-a9";
- reg = <0>;
- };
- CPU1: cpu@1 {
- device_type = "cpu";
- compatible = "arm,cortex-a9";
- reg = <1>;
- };
- };
-
ptm@801ae000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0x801ae000 0x1000>;
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 92828a1..b48dd4f 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -61,6 +61,7 @@ work_pending:
movlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)
ldmia sp, {r0 - r6} @ have to reload r0 - r6
b local_restart @ ... and off we go
+ENDPROC(ret_fast_syscall)
/*
* "slow" syscall return path. "why" tells us if this was a real syscall.
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index bd755d9..29e2991 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -399,6 +399,9 @@ ENTRY(secondary_startup)
sub lr, r4, r5 @ mmu has been enabled
add r3, r7, lr
ldrd r4, [r3, #0] @ get secondary_data.pgdir
+ARM_BE8(eor r4, r4, r5) @ Swap r5 and r4 in BE:
+ARM_BE8(eor r5, r4, r5) @ it can be done in 3 steps
+ARM_BE8(eor r4, r4, r5) @ without using a temp reg.
ldr r8, [r3, #8] @ get secondary_data.swapper_pg_dir
badr lr, __enable_mmu @ return address
mov r13, r12 @ __secondary_switched address
diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
index efe17dd..54a5aea 100644
--- a/arch/arm/kernel/vdso.c
+++ b/arch/arm/kernel/vdso.c
@@ -296,7 +296,6 @@ static bool tk_is_cntvct(const struct timekeeper *tk)
*/
void update_vsyscall(struct timekeeper *tk)
{
- struct timespec xtime_coarse;
struct timespec64 *wtm = &tk->wall_to_monotonic;
if (!cntvct_ok) {
@@ -308,10 +307,10 @@ void update_vsyscall(struct timekeeper *tk)
vdso_write_begin(vdso_data);
- xtime_coarse = __current_kernel_time();
vdso_data->tk_is_cntvct = tk_is_cntvct(tk);
- vdso_data->xtime_coarse_sec = xtime_coarse.tv_sec;
- vdso_data->xtime_coarse_nsec = xtime_coarse.tv_nsec;
+ vdso_data->xtime_coarse_sec = tk->xtime_sec;
+ vdso_data->xtime_coarse_nsec = (u32)(tk->tkr_mono.xtime_nsec >>
+ tk->tkr_mono.shift);
vdso_data->wtm_clock_sec = wtm->tv_sec;
vdso_data->wtm_clock_nsec = wtm->tv_nsec;
diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c
index 3e58d71..4b39af2 100644
--- a/arch/arm/lib/uaccess_with_memcpy.c
+++ b/arch/arm/lib/uaccess_with_memcpy.c
@@ -96,7 +96,7 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
}
/* the mmap semaphore is taken only if not in an atomic context */
- atomic = in_atomic();
+ atomic = faulthandler_disabled();
if (!atomic)
down_read(&current->mm->mmap_sem);
diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c
index 6001f1c..4a87e86 100644
--- a/arch/arm/mach-exynos/pm_domains.c
+++ b/arch/arm/mach-exynos/pm_domains.c
@@ -146,9 +146,8 @@ static __init int exynos4_pm_init_power_domain(void)
pd->base = of_iomap(np, 0);
if (!pd->base) {
pr_warn("%s: failed to map memory\n", __func__);
- kfree(pd->pd.name);
+ kfree_const(pd->pd.name);
kfree(pd);
- of_node_put(np);
continue;
}
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index 8e52621..e1d2e99 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -392,6 +392,7 @@ static struct irq_chip wakeupgen_chip = {
.irq_mask = wakeupgen_mask,
.irq_unmask = wakeupgen_unmask,
.irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_set_type = irq_chip_set_type_parent,
.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
#ifdef CONFIG_SMP
.irq_set_affinity = irq_chip_set_affinity_parent,
diff --git a/arch/arm/vdso/Makefile b/arch/arm/vdso/Makefile
index 9d259d9..1160434 100644
--- a/arch/arm/vdso/Makefile
+++ b/arch/arm/vdso/Makefile
@@ -14,7 +14,7 @@ VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
VDSO_LDFLAGS += -nostdlib -shared
VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--build-id)
-VDSO_LDFLAGS += $(call cc-option, -fuse-ld=bfd)
+VDSO_LDFLAGS += $(call cc-ldoption, -fuse-ld=bfd)
obj-$(CONFIG_VDSO) += vdso.o
extra-$(CONFIG_VDSO) += vdso.lds
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 1670f15..948f0ad 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -168,7 +168,8 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
* Other callers might not initialize the si_lsb field,
* so check explicitely for the right codes here.
*/
- if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
+ if (from->si_signo == SIGBUS &&
+ (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
#endif
break;
@@ -201,8 +202,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
{
- memset(to, 0, sizeof *to);
-
if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) ||
copy_from_user(to->_sifields._pad,
from->_sifields._pad, SI_PAD_SIZE))
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index ec37ab3..97bc68f 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -199,16 +199,15 @@ up_fail:
*/
void update_vsyscall(struct timekeeper *tk)
{
- struct timespec xtime_coarse;
u32 use_syscall = strcmp(tk->tkr_mono.clock->name, "arch_sys_counter");
++vdso_data->tb_seq_count;
smp_wmb();
- xtime_coarse = __current_kernel_time();
vdso_data->use_syscall = use_syscall;
- vdso_data->xtime_coarse_sec = xtime_coarse.tv_sec;
- vdso_data->xtime_coarse_nsec = xtime_coarse.tv_nsec;
+ vdso_data->xtime_coarse_sec = tk->xtime_sec;
+ vdso_data->xtime_coarse_nsec = tk->tkr_mono.xtime_nsec >>
+ tk->tkr_mono.shift;
vdso_data->wtm_clock_sec = tk->wall_to_monotonic.tv_sec;
vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec;
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index cee5f93..199a835 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -151,7 +151,6 @@ config BMIPS_GENERIC
select BCM7120_L2_IRQ
select BRCMSTB_L2_IRQ
select IRQ_MIPS_CPU
- select RAW_IRQ_ACCESSORS
select DMA_NONCOHERENT
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c
index 01a644f..1ba2120 100644
--- a/arch/mips/ath79/setup.c
+++ b/arch/mips/ath79/setup.c
@@ -190,6 +190,7 @@ int get_c0_perfcount_int(void)
{
return ATH79_MISC_IRQ(5);
}
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
unsigned int get_c0_compare_int(void)
{
diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c
index 56f5d08..b7fa9ae 100644
--- a/arch/mips/cavium-octeon/smp.c
+++ b/arch/mips/cavium-octeon/smp.c
@@ -42,7 +42,7 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action);
if (action & SMP_CALL_FUNCTION)
- smp_call_function_interrupt();
+ generic_smp_call_function_interrupt();
if (action & SMP_RESCHEDULE_YOURSELF)
scheduler_ipi();
diff --git a/arch/mips/include/asm/mach-bcm63xx/dma-coherence.h b/arch/mips/include/asm/mach-bcm63xx/dma-coherence.h
deleted file mode 100644
index 11d3b57..0000000
--- a/arch/mips/include/asm/mach-bcm63xx/dma-coherence.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __ASM_MACH_BCM63XX_DMA_COHERENCE_H
-#define __ASM_MACH_BCM63XX_DMA_COHERENCE_H
-
-#include <asm/bmips.h>
-
-#define plat_post_dma_flush bmips_post_dma_flush
-
-#include <asm/mach-generic/dma-coherence.h>
-
-#endif /* __ASM_MACH_BCM63XX_DMA_COHERENCE_H */
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index 9d81067..ae85694 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -182,8 +182,39 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
* Make sure the buddy is global too (if it's !none,
* it better already be global)
*/
+#ifdef CONFIG_SMP
+ /*
+ * For SMP, multiple CPUs can race, so we need to do
+ * this atomically.
+ */
+#ifdef CONFIG_64BIT
+#define LL_INSN "lld"
+#define SC_INSN "scd"
+#else /* CONFIG_32BIT */
+#define LL_INSN "ll"
+#define SC_INSN "sc"
+#endif
+ unsigned long page_global = _PAGE_GLOBAL;
+ unsigned long tmp;
+
+ __asm__ __volatile__ (
+ " .set push\n"
+ " .set noreorder\n"
+ "1: " LL_INSN " %[tmp], %[buddy]\n"
+ " bnez %[tmp], 2f\n"
+ " or %[tmp], %[tmp], %[global]\n"
+ " " SC_INSN " %[tmp], %[buddy]\n"
+ " beqz %[tmp], 1b\n"
+ " nop\n"
+ "2:\n"
+ " .set pop"
+ : [buddy] "+m" (buddy->pte),
+ [tmp] "=&r" (tmp)
+ : [global] "r" (page_global));
+#else /* !CONFIG_SMP */
if (pte_none(*buddy))
pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL;
+#endif /* CONFIG_SMP */
}
#endif
}
diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h
index 16f1ea9..03722d4 100644
--- a/arch/mips/include/asm/smp.h
+++ b/arch/mips/include/asm/smp.h
@@ -83,8 +83,6 @@ static inline void __cpu_die(unsigned int cpu)
extern void play_dead(void);
#endif
-extern asmlinkage void smp_call_function_interrupt(void);
-
static inline void arch_send_call_function_single_ipi(int cpu)
{
extern struct plat_smp_ops *mp_ops; /* private */
diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h
index 28d6d93..a71da57 100644
--- a/arch/mips/include/asm/stackframe.h
+++ b/arch/mips/include/asm/stackframe.h
@@ -152,6 +152,31 @@
.set noreorder
bltz k0, 8f
move k1, sp
+#ifdef CONFIG_EVA
+ /*
+ * Flush interAptiv's Return Prediction Stack (RPS) by writing
+ * EntryHi. Toggling Config7.RPS is slower and less portable.
+ *
+ * The RPS isn't automatically flushed when exceptions are
+ * taken, which can result in kernel mode speculative accesses
+ * to user addresses if the RPS mispredicts. That's harmless
+ * when user and kernel share the same address space, but with
+ * EVA the same user segments may be unmapped to kernel mode,
+ * even containing sensitive MMIO regions or invalid memory.
+ *
+ * This can happen when the kernel sets the return address to
+ * ret_from_* and jr's to the exception handler, which looks
+ * more like a tail call than a function call. If nested calls
+ * don't evict the last user address in the RPS, it will
+ * mispredict the return and fetch from a user controlled
+ * address into the icache.
+ *
+ * More recent EVA-capable cores with MAAR to restrict
+ * speculative accesses aren't affected.
+ */
+ MFC0 k0, CP0_ENTRYHI
+ MTC0 k0, CP0_ENTRYHI
+#endif
.set reorder
/* Called from user mode, new stack. */
get_saved_sp
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index af42e70..baa7b6f 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -407,7 +407,7 @@ NESTED(nmi_handler, PT_SIZE, sp)
.set noat
SAVE_ALL
FEXPORT(handle_\exception\ext)
- __BUILD_clear_\clear
+ __build_clear_\clear
.set at
__BUILD_\verbose \exception
move a0, sp
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
index 3e4491a..789d7bf 100644
--- a/arch/mips/kernel/mips-mt-fpaff.c
+++ b/arch/mips/kernel/mips-mt-fpaff.c
@@ -154,7 +154,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
unsigned long __user *user_mask_ptr)
{
unsigned int real_len;
- cpumask_t mask;
+ cpumask_t allowed, mask;
int retval;
struct task_struct *p;
@@ -173,7 +173,8 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
if (retval)
goto out_unlock;
- cpumask_and(&mask, &p->thread.user_cpus_allowed, cpu_possible_mask);
+ cpumask_or(&allowed, &p->thread.user_cpus_allowed, &p->cpus_allowed);
+ cpumask_and(&mask, &allowed, cpu_active_mask);
out_unlock:
read_unlock(&tasklist_lock);
diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
index b130033..5fcec30 100644
--- a/arch/mips/kernel/prom.c
+++ b/arch/mips/kernel/prom.c
@@ -38,7 +38,7 @@ char *mips_get_machine_name(void)
return mips_machine_name;
}
-#ifdef CONFIG_OF
+#ifdef CONFIG_USE_OF
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{
return add_memory_region(base, size, BOOT_MEM_RAM);
diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S
index 74bab9d..c6bbf21 100644
--- a/arch/mips/kernel/relocate_kernel.S
+++ b/arch/mips/kernel/relocate_kernel.S
@@ -24,7 +24,7 @@ LEAF(relocate_new_kernel)
process_entry:
PTR_L s2, (s0)
- PTR_ADD s0, s0, SZREG
+ PTR_ADDIU s0, s0, SZREG
/*
* In case of a kdump/crash kernel, the indirection page is not
@@ -61,9 +61,9 @@ copy_word:
/* copy page word by word */
REG_L s5, (s2)
REG_S s5, (s4)
- PTR_ADD s4, s4, SZREG
- PTR_ADD s2, s2, SZREG
- LONG_SUB s6, s6, 1
+ PTR_ADDIU s4, s4, SZREG
+ PTR_ADDIU s2, s2, SZREG
+ LONG_ADDIU s6, s6, -1
beq s6, zero, process_entry
b copy_word
b process_entry
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index ad4d4463..a6f6b76 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -80,7 +80,7 @@ syscall_trace_entry:
SAVE_STATIC
move s0, t2
move a0, sp
- daddiu a1, v0, __NR_64_Linux
+ move a1, v0
jal syscall_trace_enter
bltz v0, 2f # seccomp failed? Skip syscall
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 446cc65..4b20106 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -72,7 +72,7 @@ n32_syscall_trace_entry:
SAVE_STATIC
move s0, t2
move a0, sp
- daddiu a1, v0, __NR_N32_Linux
+ move a1, v0
jal syscall_trace_enter
bltz v0, 2f # seccomp failed? Skip syscall
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 19a7705..5d7f263 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -409,8 +409,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
{
- memset(to, 0, sizeof *to);
-
if (copy_from_user(to, from, 3*sizeof(int)) ||
copy_from_user(to->_sifields._pad,
from->_sifields._pad, SI_PAD_SIZE32))
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index 336708a..78cf8c2 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -284,7 +284,7 @@ static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id)
if (action == 0)
scheduler_ipi();
else
- smp_call_function_interrupt();
+ generic_smp_call_function_interrupt();
return IRQ_HANDLED;
}
@@ -336,7 +336,7 @@ static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id)
if (action & SMP_RESCHEDULE_YOURSELF)
scheduler_ipi();
if (action & SMP_CALL_FUNCTION)
- smp_call_function_interrupt();
+ generic_smp_call_function_interrupt();
return IRQ_HANDLED;
}
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index d0744cc..a31896c 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -192,16 +192,6 @@ asmlinkage void start_secondary(void)
cpu_startup_entry(CPUHP_ONLINE);
}
-/*
- * Call into both interrupt handlers, as we share the IPI for them
- */
-void __irq_entry smp_call_function_interrupt(void)
-{
- irq_enter();
- generic_smp_call_function_interrupt();
- irq_exit();
-}
-
static void stop_this_cpu(void *dummy)
{
/*
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index e207a43..8ea28e6 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -192,6 +192,7 @@ static void show_stacktrace(struct task_struct *task,
void show_stack(struct task_struct *task, unsigned long *sp)
{
struct pt_regs regs;
+ mm_segment_t old_fs = get_fs();
if (sp) {
regs.regs[29] = (unsigned long)sp;
regs.regs[31] = 0;
@@ -210,7 +211,13 @@ void show_stack(struct task_struct *task, unsigned long *sp)
prepare_frametrace(&regs);
}
}
+ /*
+ * show_stack() deals exclusively with kernel mode, so be sure to access
+ * the stack in the kernel (not user) address space.
+ */
+ set_fs(KERNEL_DS);
show_stacktrace(task, &regs);
+ set_fs(old_fs);
}
static void show_code(unsigned int __user *pc)
@@ -1519,6 +1526,7 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
const int field = 2 * sizeof(unsigned long);
int multi_match = regs->cp0_status & ST0_TS;
enum ctx_state prev_state;
+ mm_segment_t old_fs = get_fs();
prev_state = exception_enter();
show_regs(regs);
@@ -1540,8 +1548,13 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
dump_tlb_all();
}
+ if (!user_mode(regs))
+ set_fs(KERNEL_DS);
+
show_code((unsigned int __user *) regs->cp0_epc);
+ set_fs(old_fs);
+
/*
* Some chips may have other causes of machine check (e.g. SB1
* graduation timer)
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index af84bef..eb3efd1 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -438,7 +438,7 @@ do { \
: "memory"); \
} while(0)
-#define StoreDW(addr, value, res) \
+#define _StoreDW(addr, value, res) \
do { \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
index 6ab1057..2c218c3 100644
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -293,7 +293,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
{
- smp_call_function_interrupt();
+ generic_smp_call_function_interrupt();
return IRQ_HANDLED;
}
@@ -466,6 +466,7 @@ int get_c0_perfcount_int(void)
{
return ltq_perfcount_irq;
}
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
unsigned int get_c0_compare_int(void)
{
diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c
index 509877c..1a4738a 100644
--- a/arch/mips/loongson64/loongson-3/smp.c
+++ b/arch/mips/loongson64/loongson-3/smp.c
@@ -266,8 +266,11 @@ void loongson3_ipi_interrupt(struct pt_regs *regs)
if (action & SMP_RESCHEDULE_YOURSELF)
scheduler_ipi();
- if (action & SMP_CALL_FUNCTION)
- smp_call_function_interrupt();
+ if (action & SMP_CALL_FUNCTION) {
+ irq_enter();
+ generic_smp_call_function_interrupt();
+ irq_exit();
+ }
if (action & SMP_ASK_C0COUNT) {
BUG_ON(cpu != 0);
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index 77d96db..aab218c 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -160,18 +160,18 @@ static inline void setup_protection_map(void)
protection_map[1] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC);
protection_map[2] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ);
protection_map[3] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC);
- protection_map[4] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ);
+ protection_map[4] = __pgprot(_page_cachable_default | _PAGE_PRESENT);
protection_map[5] = __pgprot(_page_cachable_default | _PAGE_PRESENT);
- protection_map[6] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ);
+ protection_map[6] = __pgprot(_page_cachable_default | _PAGE_PRESENT);
protection_map[7] = __pgprot(_page_cachable_default | _PAGE_PRESENT);
protection_map[8] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ);
protection_map[9] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC);
protection_map[10] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE | _PAGE_NO_READ);
protection_map[11] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE);
- protection_map[12] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ);
+ protection_map[12] = __pgprot(_page_cachable_default | _PAGE_PRESENT);
protection_map[13] = __pgprot(_page_cachable_default | _PAGE_PRESENT);
- protection_map[14] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE | _PAGE_NO_READ);
+ protection_map[14] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE);
protection_map[15] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE);
} else {
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index 36c0f26..852a41c 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -133,7 +133,8 @@ good_area:
#endif
goto bad_area;
}
- if (!(vma->vm_flags & VM_READ)) {
+ if (!(vma->vm_flags & VM_READ) &&
+ exception_epc(regs) != address) {
#if 0
pr_notice("Cpu%d[%s:%d:%0*lx:%ld:%0*lx] RI violation\n",
raw_smp_processor_id(),
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index d1392f8..fa8f591 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -222,7 +222,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
{
- smp_call_function_interrupt();
+ generic_smp_call_function_interrupt();
return IRQ_HANDLED;
}
diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c
index 5625b19..b7bf721 100644
--- a/arch/mips/mti-malta/malta-time.c
+++ b/arch/mips/mti-malta/malta-time.c
@@ -154,6 +154,7 @@ int get_c0_perfcount_int(void)
return mips_cpu_perf_irq;
}
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
unsigned int get_c0_compare_int(void)
{
@@ -171,14 +172,17 @@ unsigned int get_c0_compare_int(void)
static void __init init_rtc(void)
{
- /* stop the clock whilst setting it up */
- CMOS_WRITE(RTC_SET | RTC_24H, RTC_CONTROL);
+ unsigned char freq, ctrl;
- /* 32KHz time base */
- CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT);
+ /* Set 32KHz time base if not already set */
+ freq = CMOS_READ(RTC_FREQ_SELECT);
+ if ((freq & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ)
+ CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT);
- /* start the clock */
- CMOS_WRITE(RTC_24H, RTC_CONTROL);
+ /* Ensure SET bit is clear so RTC can run */
+ ctrl = CMOS_READ(RTC_CONTROL);
+ if (ctrl & RTC_SET)
+ CMOS_WRITE(ctrl & ~RTC_SET, RTC_CONTROL);
}
void __init plat_time_init(void)
diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c
index e1d6989..a120b7a 100644
--- a/arch/mips/mti-sead3/sead3-time.c
+++ b/arch/mips/mti-sead3/sead3-time.c
@@ -77,6 +77,7 @@ int get_c0_perfcount_int(void)
return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
return -1;
}
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
unsigned int get_c0_compare_int(void)
{
diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c
index dc3e327..f5fff22 100644
--- a/arch/mips/netlogic/common/smp.c
+++ b/arch/mips/netlogic/common/smp.c
@@ -86,7 +86,7 @@ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc)
{
clear_c0_eimr(irq);
ack_c0_eirr(irq);
- smp_call_function_interrupt();
+ generic_smp_call_function_interrupt();
set_c0_eimr(irq);
}
diff --git a/arch/mips/paravirt/paravirt-smp.c b/arch/mips/paravirt/paravirt-smp.c
index 42181c7..f8d3e08 100644
--- a/arch/mips/paravirt/paravirt-smp.c
+++ b/arch/mips/paravirt/paravirt-smp.c
@@ -114,7 +114,7 @@ static irqreturn_t paravirt_reched_interrupt(int irq, void *dev_id)
static irqreturn_t paravirt_function_interrupt(int irq, void *dev_id)
{
- smp_call_function_interrupt();
+ generic_smp_call_function_interrupt();
return IRQ_HANDLED;
}
diff --git a/arch/mips/pistachio/time.c b/arch/mips/pistachio/time.c
index 7c73fcb..8a37734 100644
--- a/arch/mips/pistachio/time.c
+++ b/arch/mips/pistachio/time.c
@@ -26,6 +26,7 @@ int get_c0_perfcount_int(void)
{
return gic_get_c0_perfcount_int();
}
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
int get_c0_fdc_int(void)
{
diff --git a/arch/mips/pmcs-msp71xx/msp_smp.c b/arch/mips/pmcs-msp71xx/msp_smp.c
index 1017058..ffa0f71 100644
--- a/arch/mips/pmcs-msp71xx/msp_smp.c
+++ b/arch/mips/pmcs-msp71xx/msp_smp.c
@@ -44,7 +44,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
{
- smp_call_function_interrupt();
+ generic_smp_call_function_interrupt();
return IRQ_HANDLED;
}
diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c
index 53707aa..8c624a8 100644
--- a/arch/mips/ralink/irq.c
+++ b/arch/mips/ralink/irq.c
@@ -89,6 +89,7 @@ int get_c0_perfcount_int(void)
{
return rt_perfcount_irq;
}
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
unsigned int get_c0_compare_int(void)
{
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 3fbaef9..16ec4e1 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -107,10 +107,14 @@ static void ip27_do_irq_mask0(void)
scheduler_ipi();
} else if (pend0 & (1UL << CPU_CALL_A_IRQ)) {
LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ);
- smp_call_function_interrupt();
+ irq_enter();
+ generic_smp_call_function_interrupt();
+ irq_exit();
} else if (pend0 & (1UL << CPU_CALL_B_IRQ)) {
LOCAL_HUB_CLR_INTR(CPU_CALL_B_IRQ);
- smp_call_function_interrupt();
+ irq_enter();
+ generic_smp_call_function_interrupt();
+ irq_exit();
} else
#endif
{
diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c
index af7d44e..4c71aea 100644
--- a/arch/mips/sibyte/bcm1480/smp.c
+++ b/arch/mips/sibyte/bcm1480/smp.c
@@ -29,8 +29,6 @@
#include <asm/sibyte/bcm1480_regs.h>
#include <asm/sibyte/bcm1480_int.h>
-extern void smp_call_function_interrupt(void);
-
/*
* These are routines for dealing with the bcm1480 smp capabilities
* independent of board/firmware
@@ -184,6 +182,9 @@ void bcm1480_mailbox_interrupt(void)
if (action & SMP_RESCHEDULE_YOURSELF)
scheduler_ipi();
- if (action & SMP_CALL_FUNCTION)
- smp_call_function_interrupt();
+ if (action & SMP_CALL_FUNCTION) {
+ irq_enter();
+ generic_smp_call_function_interrupt();
+ irq_exit();
+ }
}
diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c
index c0c4b3f..1cf66f5 100644
--- a/arch/mips/sibyte/sb1250/smp.c
+++ b/arch/mips/sibyte/sb1250/smp.c
@@ -172,6 +172,9 @@ void sb1250_mailbox_interrupt(void)
if (action & SMP_RESCHEDULE_YOURSELF)
scheduler_ipi();
- if (action & SMP_CALL_FUNCTION)
- smp_call_function_interrupt();
+ if (action & SMP_CALL_FUNCTION) {
+ irq_enter();
+ generic_smp_call_function_interrupt();
+ irq_exit();
+ }
}
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index d3a831a..da50e0c 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -966,8 +966,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s)
int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
{
- memset(to, 0, sizeof *to);
-
if (copy_from_user(to, from, 3*sizeof(int)) ||
copy_from_user(to->_sifields._pad,
from->_sifields._pad, SI_PAD_SIZE32))
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 2078f92..f32f843 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -1742,10 +1742,10 @@ static bool ibs_enabled(struct kvm_vcpu *vcpu)
static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
{
- if (!vcpu->requests)
- return 0;
retry:
kvm_s390_vcpu_request_handled(vcpu);
+ if (!vcpu->requests)
+ return 0;
/*
* We use MMU_RELOAD just to re-arm the ipte notifier for the
* guest prefix page. gmap_ipte_notify will wait on the ptl lock.
diff --git a/arch/sparc/include/asm/visasm.h b/arch/sparc/include/asm/visasm.h
index 1f0aa20..6424249 100644
--- a/arch/sparc/include/asm/visasm.h
+++ b/arch/sparc/include/asm/visasm.h
@@ -28,16 +28,10 @@
* Must preserve %o5 between VISEntryHalf and VISExitHalf */
#define VISEntryHalf \
- rd %fprs, %o5; \
- andcc %o5, FPRS_FEF, %g0; \
- be,pt %icc, 297f; \
- sethi %hi(298f), %g7; \
- sethi %hi(VISenterhalf), %g1; \
- jmpl %g1 + %lo(VISenterhalf), %g0; \
- or %g7, %lo(298f), %g7; \
- clr %o5; \
-297: wr %o5, FPRS_FEF, %fprs; \
-298:
+ VISEntry
+
+#define VISExitHalf \
+ VISExit
#define VISEntryHalfFast(fail_label) \
rd %fprs, %o5; \
@@ -47,7 +41,7 @@
ba,a,pt %xcc, fail_label; \
297: wr %o5, FPRS_FEF, %fprs;
-#define VISExitHalf \
+#define VISExitHalfFast \
wr %o5, 0, %fprs;
#ifndef __ASSEMBLY__
diff --git a/arch/sparc/lib/NG4memcpy.S b/arch/sparc/lib/NG4memcpy.S
index 140527a..83aeeb1 100644
--- a/arch/sparc/lib/NG4memcpy.S
+++ b/arch/sparc/lib/NG4memcpy.S
@@ -240,8 +240,11 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
add %o0, 0x40, %o0
bne,pt %icc, 1b
LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
+#ifdef NON_USER_COPY
+ VISExitHalfFast
+#else
VISExitHalf
-
+#endif
brz,pn %o2, .Lexit
cmp %o2, 19
ble,pn %icc, .Lsmall_unaligned
diff --git a/arch/sparc/lib/VISsave.S b/arch/sparc/lib/VISsave.S
index b320ae9..a063d84 100644
--- a/arch/sparc/lib/VISsave.S
+++ b/arch/sparc/lib/VISsave.S
@@ -44,9 +44,8 @@ vis1: ldub [%g6 + TI_FPSAVED], %g3
stx %g3, [%g6 + TI_GSR]
2: add %g6, %g1, %g3
- cmp %o5, FPRS_DU
- be,pn %icc, 6f
- sll %g1, 3, %g1
+ mov FPRS_DU | FPRS_DL | FPRS_FEF, %o5
+ sll %g1, 3, %g1
stb %o5, [%g3 + TI_FPSAVED]
rd %gsr, %g2
add %g6, %g1, %g3
@@ -80,65 +79,3 @@ vis1: ldub [%g6 + TI_FPSAVED], %g3
.align 32
80: jmpl %g7 + %g0, %g0
nop
-
-6: ldub [%g3 + TI_FPSAVED], %o5
- or %o5, FPRS_DU, %o5
- add %g6, TI_FPREGS+0x80, %g2
- stb %o5, [%g3 + TI_FPSAVED]
-
- sll %g1, 5, %g1
- add %g6, TI_FPREGS+0xc0, %g3
- wr %g0, FPRS_FEF, %fprs
- membar #Sync
- stda %f32, [%g2 + %g1] ASI_BLK_P
- stda %f48, [%g3 + %g1] ASI_BLK_P
- membar #Sync
- ba,pt %xcc, 80f
- nop
-
- .align 32
-80: jmpl %g7 + %g0, %g0
- nop
-
- .align 32
-VISenterhalf:
- ldub [%g6 + TI_FPDEPTH], %g1
- brnz,a,pn %g1, 1f
- cmp %g1, 1
- stb %g0, [%g6 + TI_FPSAVED]
- stx %fsr, [%g6 + TI_XFSR]
- clr %o5
- jmpl %g7 + %g0, %g0
- wr %g0, FPRS_FEF, %fprs
-
-1: bne,pn %icc, 2f
- srl %g1, 1, %g1
- ba,pt %xcc, vis1
- sub %g7, 8, %g7
-2: addcc %g6, %g1, %g3
- sll %g1, 3, %g1
- andn %o5, FPRS_DU, %g2
- stb %g2, [%g3 + TI_FPSAVED]
-
- rd %gsr, %g2
- add %g6, %g1, %g3
- stx %g2, [%g3 + TI_GSR]
- add %g6, %g1, %g2
- stx %fsr, [%g2 + TI_XFSR]
- sll %g1, 5, %g1
-3: andcc %o5, FPRS_DL, %g0
- be,pn %icc, 4f
- add %g6, TI_FPREGS, %g2
-
- add %g6, TI_FPREGS+0x40, %g3
- membar #Sync
- stda %f0, [%g2 + %g1] ASI_BLK_P
- stda %f16, [%g3 + %g1] ASI_BLK_P
- membar #Sync
- ba,pt %xcc, 4f
- nop
-
- .align 32
-4: and %o5, FPRS_DU, %o5
- jmpl %g7 + %g0, %g0
- wr %o5, FPRS_FEF, %fprs
diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c
index 1d649a9..8069ce1 100644
--- a/arch/sparc/lib/ksyms.c
+++ b/arch/sparc/lib/ksyms.c
@@ -135,10 +135,6 @@ EXPORT_SYMBOL(copy_user_page);
void VISenter(void);
EXPORT_SYMBOL(VISenter);
-/* CRYPTO code needs this */
-void VISenterhalf(void);
-EXPORT_SYMBOL(VISenterhalf);
-
extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *);
extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *,
unsigned long *);
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index e8c2c04..c667e10 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -113,8 +113,6 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
return -EFAULT;
- memset(to, 0, sizeof(*to));
-
err = __get_user(to->si_signo, &from->si_signo);
err |= __get_user(to->si_errno, &from->si_errno);
err |= __get_user(to->si_code, &from->si_code);
diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S
index 5a18447..a7e257d 100644
--- a/arch/x86/entry/entry_64_compat.S
+++ b/arch/x86/entry/entry_64_compat.S
@@ -140,6 +140,7 @@ sysexit_from_sys_call:
*/
andl $~TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
movl RIP(%rsp), %ecx /* User %eip */
+ movq RAX(%rsp), %rax
RESTORE_RSI_RDI
xorl %edx, %edx /* Do not leak kernel information */
xorq %r8, %r8
@@ -219,7 +220,6 @@ sysexit_from_sys_call:
1: setbe %al /* 1 if error, 0 if not */
movzbl %al, %edi /* zero-extend that into %edi */
call __audit_syscall_exit
- movq RAX(%rsp), %rax /* reload syscall return value */
movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %edi
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF
@@ -368,6 +368,7 @@ sysretl_from_sys_call:
RESTORE_RSI_RDI_RDX
movl RIP(%rsp), %ecx
movl EFLAGS(%rsp), %r11d
+ movq RAX(%rsp), %rax
xorq %r10, %r10
xorq %r9, %r9
xorq %r8, %r8
diff --git a/arch/x86/include/asm/sigcontext.h b/arch/x86/include/asm/sigcontext.h
index 6fe6b18..9dfce4e 100644
--- a/arch/x86/include/asm/sigcontext.h
+++ b/arch/x86/include/asm/sigcontext.h
@@ -57,9 +57,9 @@ struct sigcontext {
unsigned long ip;
unsigned long flags;
unsigned short cs;
- unsigned short __pad2; /* Was called gs, but was always zero. */
- unsigned short __pad1; /* Was called fs, but was always zero. */
- unsigned short ss;
+ unsigned short gs;
+ unsigned short fs;
+ unsigned short __pad0;
unsigned long err;
unsigned long trapno;
unsigned long oldmask;
diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h
index 751bf4b..d7f3b3b 100644
--- a/arch/x86/include/asm/switch_to.h
+++ b/arch/x86/include/asm/switch_to.h
@@ -79,12 +79,12 @@ do { \
#else /* CONFIG_X86_32 */
/* frame pointer must be last for get_wchan */
-#define SAVE_CONTEXT "pushq %%rbp ; movq %%rsi,%%rbp\n\t"
-#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp\t"
+#define SAVE_CONTEXT "pushf ; pushq %%rbp ; movq %%rsi,%%rbp\n\t"
+#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp ; popf\t"
#define __EXTRA_CLOBBER \
, "rcx", "rbx", "rdx", "r8", "r9", "r10", "r11", \
- "r12", "r13", "r14", "r15", "flags"
+ "r12", "r13", "r14", "r15"
#ifdef CONFIG_CC_STACKPROTECTOR
#define __switch_canary \
@@ -100,11 +100,7 @@ do { \
#define __switch_canary_iparam
#endif /* CC_STACKPROTECTOR */
-/*
- * There is no need to save or restore flags, because flags are always
- * clean in kernel mode, with the possible exception of IOPL. Kernel IOPL
- * has no effect.
- */
+/* Save restore flags to clear handle leaking NT */
#define switch_to(prev, next, last) \
asm volatile(SAVE_CONTEXT \
"movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \
diff --git a/arch/x86/include/uapi/asm/sigcontext.h b/arch/x86/include/uapi/asm/sigcontext.h
index 0e8a973..40836a9 100644
--- a/arch/x86/include/uapi/asm/sigcontext.h
+++ b/arch/x86/include/uapi/asm/sigcontext.h
@@ -177,24 +177,9 @@ struct sigcontext {
__u64 rip;
__u64 eflags; /* RFLAGS */
__u16 cs;
-
- /*
- * Prior to 2.5.64 ("[PATCH] x86-64 updates for 2.5.64-bk3"),
- * Linux saved and restored fs and gs in these slots. This
- * was counterproductive, as fsbase and gsbase were never
- * saved, so arch_prctl was presumably unreliable.
- *
- * If these slots are ever needed for any other purpose, there
- * is some risk that very old 64-bit binaries could get
- * confused. I doubt that many such binaries still work,
- * though, since the same patch in 2.5.64 also removed the
- * 64-bit set_thread_area syscall, so it appears that there is
- * no TLS API that works in both pre- and post-2.5.64 kernels.
- */
- __u16 __pad2; /* Was gs. */
- __u16 __pad1; /* Was fs. */
-
- __u16 ss;
+ __u16 gs;
+ __u16 fs;
+ __u16 __pad0;
__u64 err;
__u64 trapno;
__u64 oldmask;
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index f813261..2683f36 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -322,7 +322,7 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
irq_data->chip = &lapic_controller;
irq_data->chip_data = data;
irq_data->hwirq = virq + i;
- err = assign_irq_vector_policy(virq, irq_data->node, data,
+ err = assign_irq_vector_policy(virq + i, irq_data->node, data,
info);
if (err)
goto error;
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index b9826a9..6326ae2 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -2534,7 +2534,7 @@ static int intel_pmu_cpu_prepare(int cpu)
if (x86_pmu.extra_regs || x86_pmu.lbr_sel_map) {
cpuc->shared_regs = allocate_shared_regs(cpu);
if (!cpuc->shared_regs)
- return NOTIFY_BAD;
+ goto err;
}
if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) {
@@ -2542,18 +2542,27 @@ static int intel_pmu_cpu_prepare(int cpu)
cpuc->constraint_list = kzalloc(sz, GFP_KERNEL);
if (!cpuc->constraint_list)
- return NOTIFY_BAD;
+ goto err_shared_regs;
cpuc->excl_cntrs = allocate_excl_cntrs(cpu);
- if (!cpuc->excl_cntrs) {
- kfree(cpuc->constraint_list);
- kfree(cpuc->shared_regs);
- return NOTIFY_BAD;
- }
+ if (!cpuc->excl_cntrs)
+ goto err_constraint_list;
+
cpuc->excl_thread_id = 0;
}
return NOTIFY_OK;
+
+err_constraint_list:
+ kfree(cpuc->constraint_list);
+ cpuc->constraint_list = NULL;
+
+err_shared_regs:
+ kfree(cpuc->shared_regs);
+ cpuc->shared_regs = NULL;
+
+err:
+ return NOTIFY_BAD;
}
static void intel_pmu_cpu_starting(int cpu)
diff --git a/arch/x86/kernel/cpu/perf_event_intel_cqm.c b/arch/x86/kernel/cpu/perf_event_intel_cqm.c
index 63eb68b..377e8f8 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_cqm.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_cqm.c
@@ -1255,7 +1255,7 @@ static inline void cqm_pick_event_reader(int cpu)
cpumask_set_cpu(cpu, &cqm_cpumask);
}
-static void intel_cqm_cpu_prepare(unsigned int cpu)
+static void intel_cqm_cpu_starting(unsigned int cpu)
{
struct intel_pqr_state *state = &per_cpu(pqr_state, cpu);
struct cpuinfo_x86 *c = &cpu_data(cpu);
@@ -1296,13 +1296,11 @@ static int intel_cqm_cpu_notifier(struct notifier_block *nb,
unsigned int cpu = (unsigned long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
- case CPU_UP_PREPARE:
- intel_cqm_cpu_prepare(cpu);
- break;
case CPU_DOWN_PREPARE:
intel_cqm_cpu_exit(cpu);
break;
case CPU_STARTING:
+ intel_cqm_cpu_starting(cpu);
cqm_pick_event_reader(cpu);
break;
}
@@ -1373,7 +1371,7 @@ static int __init intel_cqm_init(void)
goto out;
for_each_online_cpu(i) {
- intel_cqm_cpu_prepare(i);
+ intel_cqm_cpu_starting(i);
cqm_pick_event_reader(i);
}
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index 79de954..d25097c 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -270,7 +270,7 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)
dst_fpu->fpregs_active = 0;
dst_fpu->last_cpu = -1;
- if (src_fpu->fpstate_active)
+ if (src_fpu->fpstate_active && cpu_has_fpu)
fpu_copy(dst_fpu, src_fpu);
return 0;
diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c
index 1e173f6..d14e9ac 100644
--- a/arch/x86/kernel/fpu/init.c
+++ b/arch/x86/kernel/fpu/init.c
@@ -40,7 +40,12 @@ static void fpu__init_cpu_generic(void)
write_cr0(cr0);
/* Flush out any pending x87 state: */
- asm volatile ("fninit");
+#ifdef CONFIG_MATH_EMULATION
+ if (!cpu_has_fpu)
+ fpstate_init_soft(&current->thread.fpu.state.soft);
+ else
+#endif
+ asm volatile ("fninit");
}
/*
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 397688b..c27cad7 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -408,6 +408,7 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
static void mwait_idle(void)
{
if (!current_set_polling_and_test()) {
+ trace_cpu_idle_rcuidle(1, smp_processor_id());
if (this_cpu_has(X86_BUG_CLFLUSH_MONITOR)) {
smp_mb(); /* quirk */
clflush((void *)&current_thread_info()->flags);
@@ -419,6 +420,7 @@ static void mwait_idle(void)
__sti_mwait(0, 0);
else
local_irq_enable();
+ trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
} else {
local_irq_enable();
}
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 206996c..71820c4 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -93,8 +93,15 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
COPY(r15);
#endif /* CONFIG_X86_64 */
+#ifdef CONFIG_X86_32
COPY_SEG_CPL3(cs);
COPY_SEG_CPL3(ss);
+#else /* !CONFIG_X86_32 */
+ /* Kernel saves and restores only the CS segment register on signals,
+ * which is the bare minimum needed to allow mixed 32/64-bit code.
+ * App's signal handler can save/restore other segments if needed. */
+ COPY_SEG_CPL3(cs);
+#endif /* CONFIG_X86_32 */
get_user_ex(tmpflags, &sc->flags);
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
@@ -154,9 +161,8 @@ int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
#else /* !CONFIG_X86_32 */
put_user_ex(regs->flags, &sc->flags);
put_user_ex(regs->cs, &sc->cs);
- put_user_ex(0, &sc->__pad2);
- put_user_ex(0, &sc->__pad1);
- put_user_ex(regs->ss, &sc->ss);
+ put_user_ex(0, &sc->gs);
+ put_user_ex(0, &sc->fs);
#endif /* CONFIG_X86_32 */
put_user_ex(fpstate, &sc->fpstate);
@@ -451,19 +457,9 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
regs->sp = (unsigned long)frame;
- /*
- * Set up the CS and SS registers to run signal handlers in
- * 64-bit mode, even if the handler happens to be interrupting
- * 32-bit or 16-bit code.
- *
- * SS is subtle. In 64-bit mode, we don't need any particular
- * SS descriptor, but we do need SS to be valid. It's possible
- * that the old SS is entirely bogus -- this can happen if the
- * signal we're trying to deliver is #GP or #SS caused by a bad
- * SS value.
- */
+ /* Set up the CS register to run signal handlers in 64-bit mode,
+ even if the handler happens to be interrupting 32-bit code. */
regs->cs = __USER_CS;
- regs->ss = __USER_DS;
return 0;
}
diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c
index 6273324..0ccb53a 100644
--- a/arch/x86/kernel/step.c
+++ b/arch/x86/kernel/step.c
@@ -28,11 +28,11 @@ unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *re
struct desc_struct *desc;
unsigned long base;
- seg &= ~7UL;
+ seg >>= 3;
mutex_lock(&child->mm->context.lock);
if (unlikely(!child->mm->context.ldt ||
- (seg >> 3) >= child->mm->context.ldt->size))
+ seg >= child->mm->context.ldt->size))
addr = -1L; /* bogus selector, access would fault */
else {
desc = &child->mm->context.ldt->entries[seg];
diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c
index dc0a84a..9e8bf13 100644
--- a/arch/x86/kvm/mtrr.c
+++ b/arch/x86/kvm/mtrr.c
@@ -672,16 +672,16 @@ u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
if (iter.mtrr_disabled)
return mtrr_disabled_type();
+ /* not contained in any MTRRs. */
+ if (type == -1)
+ return mtrr_default_type(mtrr_state);
+
/*
* We just check one page, partially covered by MTRRs is
* impossible.
*/
WARN_ON(iter.partial_map);
- /* not contained in any MTRRs. */
- if (type == -1)
- return mtrr_default_type(mtrr_state);
-
return type;
}
EXPORT_SYMBOL_GPL(kvm_mtrr_get_guest_memory_type);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 5ef2560..8f0f6ec 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2105,7 +2105,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
if (guest_cpuid_has_tsc_adjust(vcpu)) {
if (!msr_info->host_initiated) {
s64 adj = data - vcpu->arch.ia32_tsc_adjust_msr;
- kvm_x86_ops->adjust_tsc_offset(vcpu, adj, true);
+ adjust_tsc_offset_guest(vcpu, adj);
}
vcpu->arch.ia32_tsc_adjust_msr = data;
}
@@ -6327,6 +6327,7 @@ static void process_smi_save_state_64(struct kvm_vcpu *vcpu, char *buf)
static void process_smi(struct kvm_vcpu *vcpu)
{
struct kvm_segment cs, ds;
+ struct desc_ptr dt;
char buf[512];
u32 cr0;
@@ -6359,6 +6360,10 @@ static void process_smi(struct kvm_vcpu *vcpu)
kvm_x86_ops->set_cr4(vcpu, 0);
+ /* Undocumented: IDT limit is set to zero on entry to SMM. */
+ dt.address = dt.size = 0;
+ kvm_x86_ops->set_idt(vcpu, &dt);
+
__kvm_set_dr(vcpu, 7, DR7_FIXED_1);
cs.selector = (vcpu->arch.smbase >> 4) & 0xffff;
diff --git a/arch/x86/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c
index f37e84a..3d8f2e4 100644
--- a/arch/x86/math-emu/fpu_entry.c
+++ b/arch/x86/math-emu/fpu_entry.c
@@ -29,7 +29,6 @@
#include <asm/uaccess.h>
#include <asm/traps.h>
-#include <asm/desc.h>
#include <asm/user.h>
#include <asm/fpu/internal.h>
@@ -181,7 +180,7 @@ void math_emulate(struct math_emu_info *info)
math_abort(FPU_info, SIGILL);
}
- code_descriptor = LDT_DESCRIPTOR(FPU_CS);
+ code_descriptor = FPU_get_ldt_descriptor(FPU_CS);
if (SEG_D_SIZE(code_descriptor)) {
/* The above test may be wrong, the book is not clear */
/* Segmented 32 bit protected mode */
diff --git a/arch/x86/math-emu/fpu_system.h b/arch/x86/math-emu/fpu_system.h
index 9ccecb6..5e044d5 100644
--- a/arch/x86/math-emu/fpu_system.h
+++ b/arch/x86/math-emu/fpu_system.h
@@ -16,9 +16,24 @@
#include <linux/kernel.h>
#include <linux/mm.h>
-/* s is always from a cpu register, and the cpu does bounds checking
- * during register load --> no further bounds checks needed */
-#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3])
+#include <asm/desc.h>
+#include <asm/mmu_context.h>
+
+static inline struct desc_struct FPU_get_ldt_descriptor(unsigned seg)
+{
+ static struct desc_struct zero_desc;
+ struct desc_struct ret = zero_desc;
+
+#ifdef CONFIG_MODIFY_LDT_SYSCALL
+ seg >>= 3;
+ mutex_lock(&current->mm->context.lock);
+ if (current->mm->context.ldt && seg < current->mm->context.ldt->size)
+ ret = current->mm->context.ldt->entries[seg];
+ mutex_unlock(&current->mm->context.lock);
+#endif
+ return ret;
+}
+
#define SEG_D_SIZE(x) ((x).b & (3 << 21))
#define SEG_G_BIT(x) ((x).b & (1 << 23))
#define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1)
diff --git a/arch/x86/math-emu/get_address.c b/arch/x86/math-emu/get_address.c
index 6ef5e99..8300db7 100644
--- a/arch/x86/math-emu/get_address.c
+++ b/arch/x86/math-emu/get_address.c
@@ -20,7 +20,6 @@
#include <linux/stddef.h>
#include <asm/uaccess.h>
-#include <asm/desc.h>
#include "fpu_system.h"
#include "exception.h"
@@ -158,7 +157,7 @@ static long pm_address(u_char FPU_modrm, u_char segment,
addr->selector = PM_REG_(segment);
}
- descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
+ descriptor = FPU_get_ldt_descriptor(addr->selector);
base_address = SEG_BASE_ADDR(descriptor);
address = base_address + offset;
limit = base_address
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index e88fda8..4841453 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -8,7 +8,7 @@ config XEN
select PARAVIRT_CLOCK
select XEN_HAVE_PVMMU
depends on X86_64 || (X86_32 && X86_PAE)
- depends on X86_TSC
+ depends on X86_LOCAL_APIC && X86_TSC
help
This is the Linux Xen port. Enabling this will allow the
kernel to boot in a paravirtualized environment under the
@@ -17,7 +17,7 @@ config XEN
config XEN_DOM0
def_bool y
depends on XEN && PCI_XEN && SWIOTLB_XEN
- depends on X86_LOCAL_APIC && X86_IO_APIC && ACPI && PCI
+ depends on X86_IO_APIC && ACPI && PCI
config XEN_PVHVM
def_bool y
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
index 7322755..4b6e29a 100644
--- a/arch/x86/xen/Makefile
+++ b/arch/x86/xen/Makefile
@@ -13,13 +13,13 @@ CFLAGS_mmu.o := $(nostackp)
obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \
time.o xen-asm.o xen-asm_$(BITS).o \
grant-table.o suspend.o platform-pci-unplug.o \
- p2m.o
+ p2m.o apic.o
obj-$(CONFIG_EVENT_TRACING) += trace.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o
-obj-$(CONFIG_XEN_DOM0) += apic.o vga.o
+obj-$(CONFIG_XEN_DOM0) += vga.o
obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o
obj-$(CONFIG_XEN_EFI) += efi.o
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index c20fe29..2292721 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -101,17 +101,15 @@ struct dom0_vga_console_info;
#ifdef CONFIG_XEN_DOM0
void __init xen_init_vga(const struct dom0_vga_console_info *, size_t size);
-void __init xen_init_apic(void);
#else
static inline void __init xen_init_vga(const struct dom0_vga_console_info *info,
size_t size)
{
}
-static inline void __init xen_init_apic(void)
-{
-}
#endif
+void __init xen_init_apic(void);
+
#ifdef CONFIG_XEN_EFI
extern void xen_efi_init(void);
#else
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 12600bf..e0057d0 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -241,8 +241,8 @@ EXPORT_SYMBOL(blk_queue_bounce_limit);
* Description:
* Enables a low level driver to set a hard upper limit,
* max_hw_sectors, on the size of requests. max_hw_sectors is set by
- * the device driver based upon the combined capabilities of I/O
- * controller and storage device.
+ * the device driver based upon the capabilities of the I/O
+ * controller.
*
* max_sectors is a soft limit imposed by the block layer for
* filesystem type requests. This value can be overridden on a
diff --git a/crypto/authencesn.c b/crypto/authencesn.c
index a3da677..b8efe36 100644
--- a/crypto/authencesn.c
+++ b/crypto/authencesn.c
@@ -393,8 +393,6 @@ static int crypto_authenc_esn_genicv(struct aead_request *req, u8 *iv,
struct scatterlist *cipher = areq_ctx->cipher;
struct scatterlist *hsg = areq_ctx->hsg;
struct scatterlist *tsg = areq_ctx->tsg;
- struct scatterlist *assoc1;
- struct scatterlist *assoc2;
unsigned int ivsize = crypto_aead_ivsize(authenc_esn);
unsigned int cryptlen = req->cryptlen;
struct page *dstp;
@@ -412,27 +410,19 @@ static int crypto_authenc_esn_genicv(struct aead_request *req, u8 *iv,
cryptlen += ivsize;
}
- if (sg_is_last(assoc))
- return -EINVAL;
-
- assoc1 = assoc + 1;
- if (sg_is_last(assoc1))
- return -EINVAL;
-
- assoc2 = assoc + 2;
- if (!sg_is_last(assoc2))
+ if (assoc->length < 12)
return -EINVAL;
sg_init_table(hsg, 2);
- sg_set_page(hsg, sg_page(assoc), assoc->length, assoc->offset);
- sg_set_page(hsg + 1, sg_page(assoc2), assoc2->length, assoc2->offset);
+ sg_set_page(hsg, sg_page(assoc), 4, assoc->offset);
+ sg_set_page(hsg + 1, sg_page(assoc), 4, assoc->offset + 8);
sg_init_table(tsg, 1);
- sg_set_page(tsg, sg_page(assoc1), assoc1->length, assoc1->offset);
+ sg_set_page(tsg, sg_page(assoc), 4, assoc->offset + 4);
areq_ctx->cryptlen = cryptlen;
- areq_ctx->headlen = assoc->length + assoc2->length;
- areq_ctx->trailen = assoc1->length;
+ areq_ctx->headlen = 8;
+ areq_ctx->trailen = 4;
areq_ctx->sg = dst;
areq_ctx->complete = authenc_esn_geniv_ahash_done;
@@ -563,8 +553,6 @@ static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv,
struct scatterlist *cipher = areq_ctx->cipher;
struct scatterlist *hsg = areq_ctx->hsg;
struct scatterlist *tsg = areq_ctx->tsg;
- struct scatterlist *assoc1;
- struct scatterlist *assoc2;
unsigned int ivsize = crypto_aead_ivsize(authenc_esn);
struct page *srcp;
u8 *vsrc;
@@ -580,27 +568,19 @@ static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv,
cryptlen += ivsize;
}
- if (sg_is_last(assoc))
- return -EINVAL;
-
- assoc1 = assoc + 1;
- if (sg_is_last(assoc1))
- return -EINVAL;
-
- assoc2 = assoc + 2;
- if (!sg_is_last(assoc2))
+ if (assoc->length < 12)
return -EINVAL;
sg_init_table(hsg, 2);
- sg_set_page(hsg, sg_page(assoc), assoc->length, assoc->offset);
- sg_set_page(hsg + 1, sg_page(assoc2), assoc2->length, assoc2->offset);
+ sg_set_page(hsg, sg_page(assoc), 4, assoc->offset);
+ sg_set_page(hsg + 1, sg_page(assoc), 4, assoc->offset + 8);
sg_init_table(tsg, 1);
- sg_set_page(tsg, sg_page(assoc1), assoc1->length, assoc1->offset);
+ sg_set_page(tsg, sg_page(assoc), 4, assoc->offset + 4);
areq_ctx->cryptlen = cryptlen;
- areq_ctx->headlen = assoc->length + assoc2->length;
- areq_ctx->trailen = assoc1->length;
+ areq_ctx->headlen = 8;
+ areq_ctx->trailen = 4;
areq_ctx->sg = src;
areq_ctx->complete = authenc_esn_verify_ahash_done;
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 815f75e..2922f1f 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -32,6 +32,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
#include <acpi/video.h>
ACPI_MODULE_NAME("video");
@@ -41,6 +42,7 @@ void acpi_video_unregister_backlight(void);
static bool backlight_notifier_registered;
static struct notifier_block backlight_nb;
+static struct work_struct backlight_notify_work;
static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef;
static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef;
@@ -262,6 +264,13 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
{ },
};
+/* This uses a workqueue to avoid various locking ordering issues */
+static void acpi_video_backlight_notify_work(struct work_struct *work)
+{
+ if (acpi_video_get_backlight_type() != acpi_backlight_video)
+ acpi_video_unregister_backlight();
+}
+
static int acpi_video_backlight_notify(struct notifier_block *nb,
unsigned long val, void *bd)
{
@@ -269,9 +278,8 @@ static int acpi_video_backlight_notify(struct notifier_block *nb,
/* A raw bl registering may change video -> native */
if (backlight->props.type == BACKLIGHT_RAW &&
- val == BACKLIGHT_REGISTERED &&
- acpi_video_get_backlight_type() != acpi_backlight_video)
- acpi_video_unregister_backlight();
+ val == BACKLIGHT_REGISTERED)
+ schedule_work(&backlight_notify_work);
return NOTIFY_OK;
}
@@ -304,6 +312,8 @@ enum acpi_backlight_type acpi_video_get_backlight_type(void)
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_video, NULL,
&video_caps, NULL);
+ INIT_WORK(&backlight_notify_work,
+ acpi_video_backlight_notify_work);
backlight_nb.notifier_call = acpi_video_backlight_notify;
backlight_nb.priority = 0;
if (backlight_register_notifier(&backlight_nb) == 0)
diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c
index ce1e3a8..14b7305 100644
--- a/drivers/ata/ahci_brcmstb.c
+++ b/drivers/ata/ahci_brcmstb.c
@@ -92,7 +92,7 @@ static inline u32 brcm_sata_readreg(void __iomem *addr)
* Other architectures (e.g., ARM) either do not support big endian, or
* else leave I/O in little endian mode.
*/
- if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
return __raw_readl(addr);
else
return readl_relaxed(addr);
@@ -101,7 +101,7 @@ static inline u32 brcm_sata_readreg(void __iomem *addr)
static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
{
/* See brcm_sata_readreg() comments */
- if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
__raw_writel(val, addr);
else
writel_relaxed(val, addr);
@@ -209,6 +209,7 @@ static void brcm_sata_init(struct brcm_ahci_priv *priv)
priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
}
+#ifdef CONFIG_PM_SLEEP
static int brcm_ahci_suspend(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
@@ -231,6 +232,7 @@ static int brcm_ahci_resume(struct device *dev)
brcm_sata_phys_enable(priv);
return ahci_platform_resume(dev);
}
+#endif
static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME),
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index db5d9f7..19bcb80 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -694,11 +694,11 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
* RETURNS:
* Block address read from @tf.
*/
-u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
+u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
{
u64 block = 0;
- if (!dev || tf->flags & ATA_TFLAG_LBA) {
+ if (tf->flags & ATA_TFLAG_LBA) {
if (tf->flags & ATA_TFLAG_LBA48) {
block |= (u64)tf->hob_lbah << 40;
block |= (u64)tf->hob_lbam << 32;
@@ -2147,24 +2147,6 @@ static int ata_dev_config_ncq(struct ata_device *dev,
return 0;
}
-static void ata_dev_config_sense_reporting(struct ata_device *dev)
-{
- unsigned int err_mask;
-
- if (!ata_id_has_sense_reporting(dev->id))
- return;
-
- if (ata_id_sense_reporting_enabled(dev->id))
- return;
-
- err_mask = ata_dev_set_feature(dev, SETFEATURE_SENSE_DATA, 0x1);
- if (err_mask) {
- ata_dev_dbg(dev,
- "failed to enable Sense Data Reporting, Emask 0x%x\n",
- err_mask);
- }
-}
-
/**
* ata_dev_configure - Configure the specified ATA/ATAPI device
* @dev: Target device to configure
@@ -2387,7 +2369,7 @@ int ata_dev_configure(struct ata_device *dev)
dev->devslp_timing[i] = sata_setting[j];
}
}
- ata_dev_config_sense_reporting(dev);
+
dev->cdb_len = 16;
}
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 7465031..cb0508a 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1592,8 +1592,6 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
tf->hob_lbah = buf[10];
tf->nsect = buf[12];
tf->hob_nsect = buf[13];
- if (ata_id_has_ncq_autosense(dev->id))
- tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];
return 0;
}
@@ -1630,70 +1628,6 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
}
/**
- * ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT
- * @dev: device to perform REQUEST_SENSE_SENSE_DATA_EXT to
- * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
- * @dfl_sense_key: default sense key to use
- *
- * Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK
- * SENSE. This function is EH helper.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * encoded sense data on success, 0 on failure or if sense data
- * is not available.
- */
-static u32 ata_eh_request_sense(struct ata_queued_cmd *qc,
- struct scsi_cmnd *cmd)
-{
- struct ata_device *dev = qc->dev;
- struct ata_taskfile tf;
- unsigned int err_mask;
-
- if (!cmd)
- return 0;
-
- DPRINTK("ATA request sense\n");
- ata_dev_warn(dev, "request sense\n");
- if (!ata_id_sense_reporting_enabled(dev->id)) {
- ata_dev_warn(qc->dev, "sense data reporting disabled\n");
- return 0;
- }
- ata_tf_init(dev, &tf);
-
- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
- tf.command = ATA_CMD_REQ_SENSE_DATA;
- tf.protocol = ATA_PROT_NODATA;
-
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
- /*
- * ACS-4 states:
- * The device may set the SENSE DATA AVAILABLE bit to one in the
- * STATUS field and clear the ERROR bit to zero in the STATUS field
- * to indicate that the command returned completion without an error
- * and the sense data described in table 306 is available.
- *
- * IOW the 'ATA_SENSE' bit might not be set even though valid
- * sense data is available.
- * So check for both.
- */
- if ((tf.command & ATA_SENSE) ||
- tf.lbah != 0 || tf.lbam != 0 || tf.lbal != 0) {
- ata_scsi_set_sense(cmd, tf.lbah, tf.lbam, tf.lbal);
- qc->flags |= ATA_QCFLAG_SENSE_VALID;
- ata_dev_warn(dev, "sense data %02x/%02x/%02x\n",
- tf.lbah, tf.lbam, tf.lbal);
- } else {
- ata_dev_warn(dev, "request sense failed stat %02x emask %x\n",
- tf.command, err_mask);
- }
- return err_mask;
-}
-
-/**
* atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
* @dev: device to perform REQUEST_SENSE to
* @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
@@ -1855,19 +1789,6 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
memcpy(&qc->result_tf, &tf, sizeof(tf));
qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
- if (qc->result_tf.auxiliary) {
- char sense_key, asc, ascq;
-
- sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;
- asc = (qc->result_tf.auxiliary >> 8) & 0xff;
- ascq = qc->result_tf.auxiliary & 0xff;
- ata_dev_dbg(dev, "NCQ Autosense %02x/%02x/%02x\n",
- sense_key, asc, ascq);
- ata_scsi_set_sense(qc->scsicmd, sense_key, asc, ascq);
- ata_scsi_set_sense_information(qc->scsicmd, &qc->result_tf);
- qc->flags |= ATA_QCFLAG_SENSE_VALID;
- }
-
ehc->i.err_mask &= ~AC_ERR_DEV;
}
@@ -1897,27 +1818,6 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
return ATA_EH_RESET;
}
- /*
- * Sense data reporting does not work if the
- * device fault bit is set.
- */
- if ((stat & ATA_SENSE) && !(stat & ATA_DF) &&
- !(qc->flags & ATA_QCFLAG_SENSE_VALID)) {
- if (!(qc->ap->pflags & ATA_PFLAG_FROZEN)) {
- tmp = ata_eh_request_sense(qc, qc->scsicmd);
- if (tmp)
- qc->err_mask |= tmp;
- else
- ata_scsi_set_sense_information(qc->scsicmd, tf);
- } else {
- ata_dev_warn(qc->dev, "sense data available but port frozen\n");
- }
- }
-
- /* Set by NCQ autosense or request sense above */
- if (qc->flags & ATA_QCFLAG_SENSE_VALID)
- return 0;
-
if (stat & (ATA_ERR | ATA_DF))
qc->err_mask |= AC_ERR_DEV;
else
@@ -2661,15 +2561,14 @@ static void ata_eh_link_report(struct ata_link *link)
#ifdef CONFIG_ATA_VERBOSE_ERROR
if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
- ATA_SENSE | ATA_ERR)) {
+ ATA_ERR)) {
if (res->command & ATA_BUSY)
ata_dev_err(qc->dev, "status: { Busy }\n");
else
- ata_dev_err(qc->dev, "status: { %s%s%s%s%s}\n",
+ ata_dev_err(qc->dev, "status: { %s%s%s%s}\n",
res->command & ATA_DRDY ? "DRDY " : "",
res->command & ATA_DF ? "DF " : "",
res->command & ATA_DRQ ? "DRQ " : "",
- res->command & ATA_SENSE ? "SENSE " : "",
res->command & ATA_ERR ? "ERR " : "");
}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 641a61a..0d7f0da 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -270,28 +270,13 @@ DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR,
ata_scsi_park_show, ata_scsi_park_store);
EXPORT_SYMBOL_GPL(dev_attr_unload_heads);
-void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
+static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
{
- if (!cmd)
- return;
-
cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq);
}
-void ata_scsi_set_sense_information(struct scsi_cmnd *cmd,
- const struct ata_taskfile *tf)
-{
- u64 information;
-
- if (!cmd)
- return;
-
- information = ata_tf_read_block(tf, NULL);
- scsi_set_sense_information(cmd->sense_buffer, information);
-}
-
static ssize_t
ata_scsi_em_message_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -1792,9 +1777,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
((cdb[2] & 0x20) || need_sense)) {
ata_gen_passthru_sense(qc);
} else {
- if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
- cmd->result = SAM_STAT_CHECK_CONDITION;
- } else if (!need_sense) {
+ if (!need_sense) {
cmd->result = SAM_STAT_GOOD;
} else {
/* TODO: decide which descriptor format to use
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index a998a17..f840ca1 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -67,8 +67,7 @@ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag);
extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
u64 block, u32 n_block, unsigned int tf_flags,
unsigned int tag);
-extern u64 ata_tf_read_block(const struct ata_taskfile *tf,
- struct ata_device *dev);
+extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev);
extern unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, void *buf, unsigned int buflen,
@@ -138,9 +137,6 @@ extern int ata_scsi_add_hosts(struct ata_host *host,
struct scsi_host_template *sht);
extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev);
-extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq);
-extern void ata_scsi_set_sense_information(struct scsi_cmnd *cmd,
- const struct ata_taskfile *tf);
extern void ata_scsi_media_change_notify(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work);
extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 3a18a8a..fab504f 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -1238,8 +1238,12 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_host *host)
readl(mmio + PDC_SDRAM_CONTROL);
/* Turn on for ECC */
- pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
- PDC_DIMM_SPD_TYPE, &spd0);
+ if (!pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
+ PDC_DIMM_SPD_TYPE, &spd0)) {
+ pr_err("Failed in i2c read: device=%#x, subaddr=%#x\n",
+ PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE);
+ return 1;
+ }
if (spd0 == 0x02) {
data |= (0x01 << 16);
writel(data, mmio + PDC_SDRAM_CONTROL);
@@ -1380,8 +1384,12 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
/* ECC initiliazation. */
- pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
- PDC_DIMM_SPD_TYPE, &spd0);
+ if (!pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
+ PDC_DIMM_SPD_TYPE, &spd0)) {
+ pr_err("Failed in i2c read: device=%#x, subaddr=%#x\n",
+ PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE);
+ return 1;
+ }
if (spd0 == 0x02) {
void *buf;
VPRINTK("Start ECC initialization\n");
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index b2b2849..873ddf9 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -136,7 +136,7 @@ struct regmap {
/* if set, the HW registers are known to match map->reg_defaults */
bool no_sync_defaults;
- struct reg_default *patch;
+ struct reg_sequence *patch;
int patch_regs;
/* if set, converts bulk rw to single rw */
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 81751a4..56486d9 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -296,11 +296,20 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
if (!blk)
return -ENOMEM;
- present = krealloc(rbnode->cache_present,
- BITS_TO_LONGS(blklen) * sizeof(*present), GFP_KERNEL);
- if (!present) {
- kfree(blk);
- return -ENOMEM;
+ if (BITS_TO_LONGS(blklen) > BITS_TO_LONGS(rbnode->blklen)) {
+ present = krealloc(rbnode->cache_present,
+ BITS_TO_LONGS(blklen) * sizeof(*present),
+ GFP_KERNEL);
+ if (!present) {
+ kfree(blk);
+ return -ENOMEM;
+ }
+
+ memset(present + BITS_TO_LONGS(rbnode->blklen), 0,
+ (BITS_TO_LONGS(blklen) - BITS_TO_LONGS(rbnode->blklen))
+ * sizeof(*present));
+ } else {
+ present = rbnode->cache_present;
}
/* insert the register value in the correct place in the rbnode block */
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 7111d04..0a849ee 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -34,7 +34,7 @@
static int _regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
- bool *change);
+ bool *change, bool force_write);
static int _regmap_bus_reg_read(void *context, unsigned int reg,
unsigned int *val);
@@ -1178,7 +1178,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
ret = _regmap_update_bits(map, range->selector_reg,
range->selector_mask,
win_page << range->selector_shift,
- &page_chg);
+ &page_chg, false);
map->work_buf = orig_work_buf;
@@ -1624,6 +1624,18 @@ int regmap_fields_write(struct regmap_field *field, unsigned int id,
}
EXPORT_SYMBOL_GPL(regmap_fields_write);
+int regmap_fields_force_write(struct regmap_field *field, unsigned int id,
+ unsigned int val)
+{
+ if (id >= field->id_size)
+ return -EINVAL;
+
+ return regmap_write_bits(field->regmap,
+ field->reg + (field->id_offset * id),
+ field->mask, val << field->shift);
+}
+EXPORT_SYMBOL_GPL(regmap_fields_force_write);
+
/**
* regmap_fields_update_bits(): Perform a read/modify/write cycle
* on the register field
@@ -1743,7 +1755,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
* relative. The page register has been written if that was neccessary.
*/
static int _regmap_raw_multi_reg_write(struct regmap *map,
- const struct reg_default *regs,
+ const struct reg_sequence *regs,
size_t num_regs)
{
int ret;
@@ -1800,12 +1812,12 @@ static unsigned int _regmap_register_page(struct regmap *map,
}
static int _regmap_range_multi_paged_reg_write(struct regmap *map,
- struct reg_default *regs,
+ struct reg_sequence *regs,
size_t num_regs)
{
int ret;
int i, n;
- struct reg_default *base;
+ struct reg_sequence *base;
unsigned int this_page = 0;
/*
* the set of registers are not neccessarily in order, but
@@ -1843,7 +1855,7 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map,
}
static int _regmap_multi_reg_write(struct regmap *map,
- const struct reg_default *regs,
+ const struct reg_sequence *regs,
size_t num_regs)
{
int i;
@@ -1895,8 +1907,8 @@ static int _regmap_multi_reg_write(struct regmap *map,
struct regmap_range_node *range;
range = _regmap_range_lookup(map, reg);
if (range) {
- size_t len = sizeof(struct reg_default)*num_regs;
- struct reg_default *base = kmemdup(regs, len,
+ size_t len = sizeof(struct reg_sequence)*num_regs;
+ struct reg_sequence *base = kmemdup(regs, len,
GFP_KERNEL);
if (!base)
return -ENOMEM;
@@ -1929,7 +1941,7 @@ static int _regmap_multi_reg_write(struct regmap *map,
* A value of zero will be returned on success, a negative errno will be
* returned in error cases.
*/
-int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
+int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs,
int num_regs)
{
int ret;
@@ -1962,7 +1974,7 @@ EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
* be returned in error cases.
*/
int regmap_multi_reg_write_bypassed(struct regmap *map,
- const struct reg_default *regs,
+ const struct reg_sequence *regs,
int num_regs)
{
int ret;
@@ -2327,7 +2339,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_read);
static int _regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
- bool *change)
+ bool *change, bool force_write)
{
int ret;
unsigned int tmp, orig;
@@ -2339,7 +2351,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
tmp = orig & ~mask;
tmp |= val & mask;
- if (tmp != orig) {
+ if (force_write || (tmp != orig)) {
ret = _regmap_write(map, reg, tmp);
if (change)
*change = true;
@@ -2367,7 +2379,7 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
int ret;
map->lock(map->lock_arg);
- ret = _regmap_update_bits(map, reg, mask, val, NULL);
+ ret = _regmap_update_bits(map, reg, mask, val, NULL, false);
map->unlock(map->lock_arg);
return ret;
@@ -2375,6 +2387,29 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
EXPORT_SYMBOL_GPL(regmap_update_bits);
/**
+ * regmap_write_bits: Perform a read/modify/write cycle on the register map
+ *
+ * @map: Register map to update
+ * @reg: Register to update
+ * @mask: Bitmask to change
+ * @val: New value for bitmask
+ *
+ * Returns zero for success, a negative number on error.
+ */
+int regmap_write_bits(struct regmap *map, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ int ret;
+
+ map->lock(map->lock_arg);
+ ret = _regmap_update_bits(map, reg, mask, val, NULL, true);
+ map->unlock(map->lock_arg);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_write_bits);
+
+/**
* regmap_update_bits_async: Perform a read/modify/write cycle on the register
* map asynchronously
*
@@ -2398,7 +2433,7 @@ int regmap_update_bits_async(struct regmap *map, unsigned int reg,
map->async = true;
- ret = _regmap_update_bits(map, reg, mask, val, NULL);
+ ret = _regmap_update_bits(map, reg, mask, val, NULL, false);
map->async = false;
@@ -2427,7 +2462,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
int ret;
map->lock(map->lock_arg);
- ret = _regmap_update_bits(map, reg, mask, val, change);
+ ret = _regmap_update_bits(map, reg, mask, val, change, false);
map->unlock(map->lock_arg);
return ret;
}
@@ -2460,7 +2495,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
map->async = true;
- ret = _regmap_update_bits(map, reg, mask, val, change);
+ ret = _regmap_update_bits(map, reg, mask, val, change, false);
map->async = false;
@@ -2552,10 +2587,10 @@ EXPORT_SYMBOL_GPL(regmap_async_complete);
* The caller must ensure that this function cannot be called
* concurrently with either itself or regcache_sync().
*/
-int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
+int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs,
int num_regs)
{
- struct reg_default *p;
+ struct reg_sequence *p;
int ret;
bool bypass;
@@ -2564,7 +2599,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
return 0;
p = krealloc(map->patch,
- sizeof(struct reg_default) * (map->patch_regs + num_regs),
+ sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
GFP_KERNEL);
if (p) {
memcpy(p + map->patch_regs, regs, num_regs * sizeof(*regs));
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index d94529d..bc67a93 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -523,6 +523,7 @@ void rbd_warn(struct rbd_device *rbd_dev, const char *fmt, ...)
# define rbd_assert(expr) ((void) 0)
#endif /* !RBD_DEBUG */
+static void rbd_osd_copyup_callback(struct rbd_obj_request *obj_request);
static int rbd_img_obj_request_submit(struct rbd_obj_request *obj_request);
static void rbd_img_parent_read(struct rbd_obj_request *obj_request);
static void rbd_dev_remove_parent(struct rbd_device *rbd_dev);
@@ -1818,6 +1819,16 @@ static void rbd_osd_stat_callback(struct rbd_obj_request *obj_request)
obj_request_done_set(obj_request);
}
+static void rbd_osd_call_callback(struct rbd_obj_request *obj_request)
+{
+ dout("%s: obj %p\n", __func__, obj_request);
+
+ if (obj_request_img_data_test(obj_request))
+ rbd_osd_copyup_callback(obj_request);
+ else
+ obj_request_done_set(obj_request);
+}
+
static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
struct ceph_msg *msg)
{
@@ -1866,6 +1877,8 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
rbd_osd_discard_callback(obj_request);
break;
case CEPH_OSD_OP_CALL:
+ rbd_osd_call_callback(obj_request);
+ break;
case CEPH_OSD_OP_NOTIFY_ACK:
case CEPH_OSD_OP_WATCH:
rbd_osd_trivial_callback(obj_request);
@@ -2530,13 +2543,15 @@ out_unwind:
}
static void
-rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request)
+rbd_osd_copyup_callback(struct rbd_obj_request *obj_request)
{
struct rbd_img_request *img_request;
struct rbd_device *rbd_dev;
struct page **pages;
u32 page_count;
+ dout("%s: obj %p\n", __func__, obj_request);
+
rbd_assert(obj_request->type == OBJ_REQUEST_BIO ||
obj_request->type == OBJ_REQUEST_NODATA);
rbd_assert(obj_request_img_data_test(obj_request));
@@ -2563,9 +2578,7 @@ rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request)
if (!obj_request->result)
obj_request->xferred = obj_request->length;
- /* Finish up with the normal image object callback */
-
- rbd_img_obj_callback(obj_request);
+ obj_request_done_set(obj_request);
}
static void
@@ -2650,7 +2663,6 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
/* All set, send it off. */
- orig_request->callback = rbd_img_obj_copyup_callback;
osdc = &rbd_dev->rbd_client->client->osdc;
img_result = rbd_obj_request_submit(osdc, orig_request);
if (!img_result)
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
index ced9677..954c002 100644
--- a/drivers/block/xen-blkback/blkback.c
+++ b/drivers/block/xen-blkback/blkback.c
@@ -369,8 +369,8 @@ static void purge_persistent_gnt(struct xen_blkif *blkif)
return;
}
- if (work_pending(&blkif->persistent_purge_work)) {
- pr_alert_ratelimited("Scheduled work from previous purge is still pending, cannot purge list\n");
+ if (work_busy(&blkif->persistent_purge_work)) {
+ pr_alert_ratelimited("Scheduled work from previous purge is still busy, cannot purge list\n");
return;
}
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 6d89ed3..7a8a73f 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -179,6 +179,7 @@ static DEFINE_SPINLOCK(minor_lock);
((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
static int blkfront_setup_indirect(struct blkfront_info *info);
+static int blkfront_gather_backend_features(struct blkfront_info *info);
static int get_id_from_freelist(struct blkfront_info *info)
{
@@ -1128,8 +1129,10 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
* Add the used indirect page back to the list of
* available pages for indirect grefs.
*/
- indirect_page = pfn_to_page(s->indirect_grants[i]->pfn);
- list_add(&indirect_page->lru, &info->indirect_pages);
+ if (!info->feature_persistent) {
+ indirect_page = pfn_to_page(s->indirect_grants[i]->pfn);
+ list_add(&indirect_page->lru, &info->indirect_pages);
+ }
s->indirect_grants[i]->gref = GRANT_INVALID_REF;
list_add_tail(&s->indirect_grants[i]->node, &info->grants);
}
@@ -1519,7 +1522,7 @@ static int blkif_recover(struct blkfront_info *info)
info->shadow_free = info->ring.req_prod_pvt;
info->shadow[BLK_RING_SIZE(info)-1].req.u.rw.id = 0x0fffffff;
- rc = blkfront_setup_indirect(info);
+ rc = blkfront_gather_backend_features(info);
if (rc) {
kfree(copy);
return rc;
@@ -1720,20 +1723,13 @@ static void blkfront_setup_discard(struct blkfront_info *info)
static int blkfront_setup_indirect(struct blkfront_info *info)
{
- unsigned int indirect_segments, segs;
+ unsigned int segs;
int err, i;
- err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
- "feature-max-indirect-segments", "%u", &indirect_segments,
- NULL);
- if (err) {
- info->max_indirect_segments = 0;
+ if (info->max_indirect_segments == 0)
segs = BLKIF_MAX_SEGMENTS_PER_REQUEST;
- } else {
- info->max_indirect_segments = min(indirect_segments,
- xen_blkif_max_segments);
+ else
segs = info->max_indirect_segments;
- }
err = fill_grant_buffer(info, (segs + INDIRECT_GREFS(segs)) * BLK_RING_SIZE(info));
if (err)
@@ -1797,6 +1793,68 @@ out_of_memory:
}
/*
+ * Gather all backend feature-*
+ */
+static int blkfront_gather_backend_features(struct blkfront_info *info)
+{
+ int err;
+ int barrier, flush, discard, persistent;
+ unsigned int indirect_segments;
+
+ info->feature_flush = 0;
+
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "feature-barrier", "%d", &barrier,
+ NULL);
+
+ /*
+ * If there's no "feature-barrier" defined, then it means
+ * we're dealing with a very old backend which writes
+ * synchronously; nothing to do.
+ *
+ * If there are barriers, then we use flush.
+ */
+ if (!err && barrier)
+ info->feature_flush = REQ_FLUSH | REQ_FUA;
+ /*
+ * And if there is "feature-flush-cache" use that above
+ * barriers.
+ */
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "feature-flush-cache", "%d", &flush,
+ NULL);
+
+ if (!err && flush)
+ info->feature_flush = REQ_FLUSH;
+
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "feature-discard", "%d", &discard,
+ NULL);
+
+ if (!err && discard)
+ blkfront_setup_discard(info);
+
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "feature-persistent", "%u", &persistent,
+ NULL);
+ if (err)
+ info->feature_persistent = 0;
+ else
+ info->feature_persistent = persistent;
+
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "feature-max-indirect-segments", "%u", &indirect_segments,
+ NULL);
+ if (err)
+ info->max_indirect_segments = 0;
+ else
+ info->max_indirect_segments = min(indirect_segments,
+ xen_blkif_max_segments);
+
+ return blkfront_setup_indirect(info);
+}
+
+/*
* Invoked when the backend is finally 'ready' (and has told produced
* the details about the physical device - #sectors, size, etc).
*/
@@ -1807,7 +1865,6 @@ static void blkfront_connect(struct blkfront_info *info)
unsigned int physical_sector_size;
unsigned int binfo;
int err;
- int barrier, flush, discard, persistent;
switch (info->connected) {
case BLKIF_STATE_CONNECTED:
@@ -1864,48 +1921,7 @@ static void blkfront_connect(struct blkfront_info *info)
if (err != 1)
physical_sector_size = sector_size;
- info->feature_flush = 0;
-
- err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
- "feature-barrier", "%d", &barrier,
- NULL);
-
- /*
- * If there's no "feature-barrier" defined, then it means
- * we're dealing with a very old backend which writes
- * synchronously; nothing to do.
- *
- * If there are barriers, then we use flush.
- */
- if (!err && barrier)
- info->feature_flush = REQ_FLUSH | REQ_FUA;
- /*
- * And if there is "feature-flush-cache" use that above
- * barriers.
- */
- err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
- "feature-flush-cache", "%d", &flush,
- NULL);
-
- if (!err && flush)
- info->feature_flush = REQ_FLUSH;
-
- err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
- "feature-discard", "%d", &discard,
- NULL);
-
- if (!err && discard)
- blkfront_setup_discard(info);
-
- err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
- "feature-persistent", "%u", &persistent,
- NULL);
- if (err)
- info->feature_persistent = 0;
- else
- info->feature_persistent = persistent;
-
- err = blkfront_setup_indirect(info);
+ err = blkfront_gather_backend_features(info);
if (err) {
xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s",
info->xbdev->otherend);
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index fb655e8..763301c 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -496,10 +496,9 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
kfree(meta);
}
-static struct zram_meta *zram_meta_alloc(int device_id, u64 disksize)
+static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize)
{
size_t num_pages;
- char pool_name[8];
struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
if (!meta)
@@ -512,7 +511,6 @@ static struct zram_meta *zram_meta_alloc(int device_id, u64 disksize)
goto out_error;
}
- snprintf(pool_name, sizeof(pool_name), "zram%d", device_id);
meta->mem_pool = zs_create_pool(pool_name, GFP_NOIO | __GFP_HIGHMEM);
if (!meta->mem_pool) {
pr_err("Error creating memory pool\n");
@@ -1031,7 +1029,7 @@ static ssize_t disksize_store(struct device *dev,
return -EINVAL;
disksize = PAGE_ALIGN(disksize);
- meta = zram_meta_alloc(zram->disk->first_minor, disksize);
+ meta = zram_meta_alloc(zram->disk->disk_name, disksize);
if (!meta)
return -ENOMEM;
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index da8faf7..5643b65 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -429,7 +429,7 @@ static int hwrng_fillfn(void *unused)
static void start_khwrngd(void)
{
hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
- if (hwrng_fill == ERR_PTR(-ENOMEM)) {
+ if (IS_ERR(hwrng_fill)) {
pr_err("hwrng_fill thread creation failed");
hwrng_fill = NULL;
}
diff --git a/drivers/clk/pxa/clk-pxa3xx.c b/drivers/clk/pxa/clk-pxa3xx.c
index 4b93a1e..ac03ba4 100644
--- a/drivers/clk/pxa/clk-pxa3xx.c
+++ b/drivers/clk/pxa/clk-pxa3xx.c
@@ -126,7 +126,7 @@ PARENTS(pxa3xx_ac97_bus) = { "ring_osc_60mhz", "ac97" };
PARENTS(pxa3xx_sbus) = { "ring_osc_60mhz", "system_bus" };
PARENTS(pxa3xx_smemcbus) = { "ring_osc_60mhz", "smemc" };
-#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENA : &CKENB)
+#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENB : &CKENA)
#define PXA3XX_CKEN(dev_id, con_id, parents, mult_lp, div_lp, mult_hp, \
div_hp, bit, is_lp, flags) \
PXA_CKEN(dev_id, con_id, bit, parents, mult_lp, div_lp, \
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index b8ff3c6..c96de14 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -661,6 +661,9 @@ static void sh_cmt_clocksource_suspend(struct clocksource *cs)
{
struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
+ if (!ch->cs_enabled)
+ return;
+
sh_cmt_stop(ch, FLAG_CLOCKSOURCE);
pm_genpd_syscore_poweroff(&ch->cmt->pdev->dev);
}
@@ -669,6 +672,9 @@ static void sh_cmt_clocksource_resume(struct clocksource *cs)
{
struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
+ if (!ch->cs_enabled)
+ return;
+
pm_genpd_syscore_poweron(&ch->cmt->pdev->dev);
sh_cmt_start(ch, FLAG_CLOCKSOURCE);
}
diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c
index 2d59038..86c7eb6 100644
--- a/drivers/clocksource/timer-imx-gpt.c
+++ b/drivers/clocksource/timer-imx-gpt.c
@@ -462,6 +462,7 @@ void __init mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type)
BUG_ON(!imxtm->base);
imxtm->type = type;
+ imxtm->irq = irq;
_mxc_timer_init(imxtm);
}
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index ae5b2bd..fa3dd84 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -180,7 +180,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
ret = exynos5250_cpufreq_init(exynos_info);
} else {
pr_err("%s: Unknown SoC type\n", __func__);
- return -ENODEV;
+ ret = -ENODEV;
}
if (ret)
@@ -188,12 +188,14 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
if (exynos_info->set_freq == NULL) {
dev_err(&pdev->dev, "No set_freq function (ERR)\n");
+ ret = -EINVAL;
goto err_vdd_arm;
}
arm_regulator = regulator_get(NULL, "vdd_arm");
if (IS_ERR(arm_regulator)) {
dev_err(&pdev->dev, "failed to get resource vdd_arm\n");
+ ret = -EINVAL;
goto err_vdd_arm;
}
@@ -225,7 +227,7 @@ err_cpufreq_reg:
regulator_put(arm_regulator);
err_vdd_arm:
kfree(exynos_info);
- return -EINVAL;
+ return ret;
}
static struct platform_driver exynos_cpufreq_platdrv = {
diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c
index e362860..cd593c1 100644
--- a/drivers/cpufreq/loongson2_cpufreq.c
+++ b/drivers/cpufreq/loongson2_cpufreq.c
@@ -20,7 +20,7 @@
#include <asm/clock.h>
#include <asm/idle.h>
-#include <asm/mach-loongson/loongson.h>
+#include <asm/mach-loongson64/loongson.h>
static uint nowait;
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index dae1e80..f9c7875 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -909,13 +909,14 @@ static int ahash_final_ctx(struct ahash_request *req)
state->buflen_1;
u32 *sh_desc = ctx->sh_desc_fin, *desc;
dma_addr_t ptr = ctx->sh_desc_fin_dma;
- int sec4_sg_bytes;
+ int sec4_sg_bytes, sec4_sg_src_index;
int digestsize = crypto_ahash_digestsize(ahash);
struct ahash_edesc *edesc;
int ret = 0;
int sh_len;
- sec4_sg_bytes = (1 + (buflen ? 1 : 0)) * sizeof(struct sec4_sg_entry);
+ sec4_sg_src_index = 1 + (buflen ? 1 : 0);
+ sec4_sg_bytes = sec4_sg_src_index * sizeof(struct sec4_sg_entry);
/* allocate space for base edesc and hw desc commands, link tables */
edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN +
@@ -942,7 +943,7 @@ static int ahash_final_ctx(struct ahash_request *req)
state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1,
buf, state->buf_dma, buflen,
last_buflen);
- (edesc->sec4_sg + sec4_sg_bytes - 1)->len |= SEC4_SG_LEN_FIN;
+ (edesc->sec4_sg + sec4_sg_src_index - 1)->len |= SEC4_SG_LEN_FIN;
edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
sec4_sg_bytes, DMA_TO_DEVICE);
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index 7ba495f..402631a 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -905,7 +905,6 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt)
crypt->mode |= NPE_OP_NOT_IN_PLACE;
/* This was never tested by Intel
* for more than one dst buffer, I think. */
- BUG_ON(req->dst->length < nbytes);
req_ctx->dst = NULL;
if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook,
flags, DMA_FROM_DEVICE))
diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c
index 08f8d5c..becb738 100644
--- a/drivers/crypto/nx/nx-sha256.c
+++ b/drivers/crypto/nx/nx-sha256.c
@@ -71,7 +71,6 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
struct sha256_state *sctx = shash_desc_ctx(desc);
struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
- struct nx_sg *in_sg;
struct nx_sg *out_sg;
u64 to_process = 0, leftover, total;
unsigned long irq_flags;
@@ -97,7 +96,6 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
- in_sg = nx_ctx->in_sg;
max_sg_len = min_t(u64, nx_ctx->ap->sglen,
nx_driver.of.max_sg_len/sizeof(struct nx_sg));
max_sg_len = min_t(u64, max_sg_len,
@@ -114,17 +112,12 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
}
do {
- /*
- * to_process: the SHA256_BLOCK_SIZE data chunk to process in
- * this update. This value is also restricted by the sg list
- * limits.
- */
- to_process = total - to_process;
- to_process = to_process & ~(SHA256_BLOCK_SIZE - 1);
+ int used_sgs = 0;
+ struct nx_sg *in_sg = nx_ctx->in_sg;
if (buf_len) {
data_len = buf_len;
- in_sg = nx_build_sg_list(nx_ctx->in_sg,
+ in_sg = nx_build_sg_list(in_sg,
(u8 *) sctx->buf,
&data_len,
max_sg_len);
@@ -133,15 +126,27 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
rc = -EINVAL;
goto out;
}
+ used_sgs = in_sg - nx_ctx->in_sg;
}
+ /* to_process: SHA256_BLOCK_SIZE aligned chunk to be
+ * processed in this iteration. This value is restricted
+ * by sg list limits and number of sgs we already used
+ * for leftover data. (see above)
+ * In ideal case, we could allow NX_PAGE_SIZE * max_sg_len,
+ * but because data may not be aligned, we need to account
+ * for that too. */
+ to_process = min_t(u64, total,
+ (max_sg_len - 1 - used_sgs) * NX_PAGE_SIZE);
+ to_process = to_process & ~(SHA256_BLOCK_SIZE - 1);
+
data_len = to_process - buf_len;
in_sg = nx_build_sg_list(in_sg, (u8 *) data,
&data_len, max_sg_len);
nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
- to_process = (data_len + buf_len);
+ to_process = data_len + buf_len;
leftover = total - to_process;
/*
diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c
index aff0fe5..b6e183d 100644
--- a/drivers/crypto/nx/nx-sha512.c
+++ b/drivers/crypto/nx/nx-sha512.c
@@ -71,7 +71,6 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
struct sha512_state *sctx = shash_desc_ctx(desc);
struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
- struct nx_sg *in_sg;
struct nx_sg *out_sg;
u64 to_process, leftover = 0, total;
unsigned long irq_flags;
@@ -97,7 +96,6 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
- in_sg = nx_ctx->in_sg;
max_sg_len = min_t(u64, nx_ctx->ap->sglen,
nx_driver.of.max_sg_len/sizeof(struct nx_sg));
max_sg_len = min_t(u64, max_sg_len,
@@ -114,18 +112,12 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
}
do {
- /*
- * to_process: the SHA512_BLOCK_SIZE data chunk to process in
- * this update. This value is also restricted by the sg list
- * limits.
- */
- to_process = total - leftover;
- to_process = to_process & ~(SHA512_BLOCK_SIZE - 1);
- leftover = total - to_process;
+ int used_sgs = 0;
+ struct nx_sg *in_sg = nx_ctx->in_sg;
if (buf_len) {
data_len = buf_len;
- in_sg = nx_build_sg_list(nx_ctx->in_sg,
+ in_sg = nx_build_sg_list(in_sg,
(u8 *) sctx->buf,
&data_len, max_sg_len);
@@ -133,8 +125,20 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
rc = -EINVAL;
goto out;
}
+ used_sgs = in_sg - nx_ctx->in_sg;
}
+ /* to_process: SHA512_BLOCK_SIZE aligned chunk to be
+ * processed in this iteration. This value is restricted
+ * by sg list limits and number of sgs we already used
+ * for leftover data. (see above)
+ * In ideal case, we could allow NX_PAGE_SIZE * max_sg_len,
+ * but because data may not be aligned, we need to account
+ * for that too. */
+ to_process = min_t(u64, total,
+ (max_sg_len - 1 - used_sgs) * NX_PAGE_SIZE);
+ to_process = to_process & ~(SHA512_BLOCK_SIZE - 1);
+
data_len = to_process - buf_len;
in_sg = nx_build_sg_list(in_sg, (u8 *) data,
&data_len, max_sg_len);
@@ -146,7 +150,7 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
goto out;
}
- to_process = (data_len + buf_len);
+ to_process = data_len + buf_len;
leftover = total - to_process;
/*
diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
index 067402c..df427c0e 100644
--- a/drivers/crypto/qat/qat_common/qat_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_algs.c
@@ -73,7 +73,8 @@
ICP_QAT_HW_CIPHER_KEY_CONVERT, \
ICP_QAT_HW_CIPHER_DECRYPT)
-static atomic_t active_dev;
+static DEFINE_MUTEX(algs_lock);
+static unsigned int active_devs;
struct qat_alg_buf {
uint32_t len;
@@ -1280,7 +1281,10 @@ static struct crypto_alg qat_algs[] = { {
int qat_algs_register(void)
{
- if (atomic_add_return(1, &active_dev) == 1) {
+ int ret = 0;
+
+ mutex_lock(&algs_lock);
+ if (++active_devs == 1) {
int i;
for (i = 0; i < ARRAY_SIZE(qat_algs); i++)
@@ -1289,21 +1293,25 @@ int qat_algs_register(void)
CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC :
CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
- return crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs));
+ ret = crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs));
}
- return 0;
+ mutex_unlock(&algs_lock);
+ return ret;
}
int qat_algs_unregister(void)
{
- if (atomic_sub_return(1, &active_dev) == 0)
- return crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs));
- return 0;
+ int ret = 0;
+
+ mutex_lock(&algs_lock);
+ if (--active_devs == 0)
+ ret = crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs));
+ mutex_unlock(&algs_lock);
+ return ret;
}
int qat_algs_init(void)
{
- atomic_set(&active_dev, 0);
crypto_get_default_rng();
return 0;
}
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 4a4cce1..3ff284c 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -689,6 +689,10 @@ struct dma_chan *dma_request_slave_channel(struct device *dev,
struct dma_chan *ch = dma_request_slave_channel_reason(dev, name);
if (IS_ERR(ch))
return NULL;
+
+ dma_cap_set(DMA_PRIVATE, ch->device->cap_mask);
+ ch->device->privatecnt++;
+
return ch;
}
EXPORT_SYMBOL_GPL(dma_request_slave_channel);
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
index 3515b381..711d8ad 100644
--- a/drivers/edac/ppc4xx_edac.c
+++ b/drivers/edac/ppc4xx_edac.c
@@ -920,7 +920,7 @@ static int ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
*/
for (row = 0; row < mci->nr_csrows; row++) {
- struct csrow_info *csi = &mci->csrows[row];
+ struct csrow_info *csi = mci->csrows[row];
/*
* Get the configuration settings for this
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
index 080d5cc..eebdf2a 100644
--- a/drivers/extcon/extcon-palmas.c
+++ b/drivers/extcon/extcon-palmas.c
@@ -200,7 +200,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev);
if (status) {
dev_err(&pdev->dev, "failed to register extcon device\n");
- kfree(palmas_usb->edev->name);
return status;
}
@@ -214,7 +213,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
if (status < 0) {
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
palmas_usb->id_irq, status);
- kfree(palmas_usb->edev->name);
return status;
}
}
@@ -229,7 +227,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
if (status < 0) {
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
palmas_usb->vbus_irq, status);
- kfree(palmas_usb->edev->name);
return status;
}
}
@@ -239,15 +236,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
return 0;
}
-static int palmas_usb_remove(struct platform_device *pdev)
-{
- struct palmas_usb *palmas_usb = platform_get_drvdata(pdev);
-
- kfree(palmas_usb->edev->name);
-
- return 0;
-}
-
#ifdef CONFIG_PM_SLEEP
static int palmas_usb_suspend(struct device *dev)
{
@@ -288,7 +276,6 @@ static const struct of_device_id of_palmas_match_tbl[] = {
static struct platform_driver palmas_usb_driver = {
.probe = palmas_usb_probe,
- .remove = palmas_usb_remove,
.driver = {
.name = "palmas-usb",
.of_match_table = of_palmas_match_tbl,
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
index 76157ab..43b57b0 100644
--- a/drivers/extcon/extcon.c
+++ b/drivers/extcon/extcon.c
@@ -124,25 +124,35 @@ static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id
return -EINVAL;
}
-static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
+static int find_cable_id_by_name(struct extcon_dev *edev, const char *name)
{
- unsigned int id = EXTCON_NONE;
+ unsigned int id = -EINVAL;
int i = 0;
- if (edev->max_supported == 0)
- return -EINVAL;
-
- /* Find the the number of extcon cable */
+ /* Find the id of extcon cable */
while (extcon_name[i]) {
if (!strncmp(extcon_name[i], name, CABLE_NAME_MAX)) {
id = i;
break;
}
+ i++;
}
- if (id == EXTCON_NONE)
+ return id;
+}
+
+static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
+{
+ unsigned int id;
+
+ if (edev->max_supported == 0)
return -EINVAL;
+ /* Find the the number of extcon cable */
+ id = find_cable_id_by_name(edev, name);
+ if (id < 0)
+ return id;
+
return find_cable_index_by_id(edev, id);
}
@@ -228,9 +238,11 @@ static ssize_t cable_state_show(struct device *dev,
struct extcon_cable *cable = container_of(attr, struct extcon_cable,
attr_state);
+ int i = cable->cable_index;
+
return sprintf(buf, "%d\n",
extcon_get_cable_state_(cable->edev,
- cable->cable_index));
+ cable->edev->supported_cable[i]));
}
/**
@@ -263,20 +275,25 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
spin_lock_irqsave(&edev->lock, flags);
if (edev->state != ((edev->state & ~mask) | (state & mask))) {
+ u32 old_state;
+
if (check_mutually_exclusive(edev, (edev->state & ~mask) |
(state & mask))) {
spin_unlock_irqrestore(&edev->lock, flags);
return -EPERM;
}
- for (index = 0; index < edev->max_supported; index++) {
- if (is_extcon_changed(edev->state, state, index, &attached))
- raw_notifier_call_chain(&edev->nh[index], attached, edev);
- }
-
+ old_state = edev->state;
edev->state &= ~mask;
edev->state |= state & mask;
+ for (index = 0; index < edev->max_supported; index++) {
+ if (is_extcon_changed(old_state, edev->state, index,
+ &attached))
+ raw_notifier_call_chain(&edev->nh[index],
+ attached, edev);
+ }
+
/* This could be in interrupt handler */
prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
if (prop_buf) {
@@ -361,8 +378,13 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
*/
int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
{
- return extcon_get_cable_state_(edev, find_cable_index_by_name
- (edev, cable_name));
+ unsigned int id;
+
+ id = find_cable_id_by_name(edev, cable_name);
+ if (id < 0)
+ return id;
+
+ return extcon_get_cable_state_(edev, id);
}
EXPORT_SYMBOL_GPL(extcon_get_cable_state);
@@ -404,8 +426,13 @@ EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
int extcon_set_cable_state(struct extcon_dev *edev,
const char *cable_name, bool cable_state)
{
- return extcon_set_cable_state_(edev, find_cable_index_by_name
- (edev, cable_name), cable_state);
+ unsigned int id;
+
+ id = find_cable_id_by_name(edev, cable_name);
+ if (id < 0)
+ return id;
+
+ return extcon_set_cable_state_(edev, id, cable_state);
}
EXPORT_SYMBOL_GPL(extcon_set_cable_state);
diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c
index 87add3f..e415945 100644
--- a/drivers/firmware/broadcom/bcm47xx_nvram.c
+++ b/drivers/firmware/broadcom/bcm47xx_nvram.c
@@ -245,4 +245,4 @@ char *bcm47xx_nvram_get_contents(size_t *nvram_size)
}
EXPORT_SYMBOL(bcm47xx_nvram_get_contents);
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 31b00f9..f7b49d5c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1130,6 +1130,9 @@ struct amdgpu_gfx {
uint32_t me_feature_version;
uint32_t ce_feature_version;
uint32_t pfp_feature_version;
+ uint32_t rlc_feature_version;
+ uint32_t mec_feature_version;
+ uint32_t mec2_feature_version;
struct amdgpu_ring gfx_ring[AMDGPU_MAX_GFX_RINGS];
unsigned num_gfx_rings;
struct amdgpu_ring compute_ring[AMDGPU_MAX_COMPUTE_RINGS];
@@ -1639,6 +1642,7 @@ struct amdgpu_sdma {
/* SDMA firmware */
const struct firmware *fw;
uint32_t fw_version;
+ uint32_t feature_version;
struct amdgpu_ring ring;
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 9736892..3bfe67d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -317,16 +317,17 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
break;
case AMDGPU_INFO_FW_GFX_RLC:
fw_info.ver = adev->gfx.rlc_fw_version;
- fw_info.feature = 0;
+ fw_info.feature = adev->gfx.rlc_feature_version;
break;
case AMDGPU_INFO_FW_GFX_MEC:
- if (info->query_fw.index == 0)
+ if (info->query_fw.index == 0) {
fw_info.ver = adev->gfx.mec_fw_version;
- else if (info->query_fw.index == 1)
+ fw_info.feature = adev->gfx.mec_feature_version;
+ } else if (info->query_fw.index == 1) {
fw_info.ver = adev->gfx.mec2_fw_version;
- else
+ fw_info.feature = adev->gfx.mec2_feature_version;
+ } else
return -EINVAL;
- fw_info.feature = 0;
break;
case AMDGPU_INFO_FW_SMC:
fw_info.ver = adev->pm.fw_version;
@@ -336,7 +337,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
if (info->query_fw.index >= 2)
return -EINVAL;
fw_info.ver = adev->sdma[info->query_fw.index].fw_version;
- fw_info.feature = 0;
+ fw_info.feature = adev->sdma[info->query_fw.index].feature_version;
break;
default:
return -EINVAL;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
index 2f7a5ef..f5c2255 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -374,7 +374,7 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
unsigned height_in_mb = ALIGN(height / 16, 2);
unsigned fs_in_mb = width_in_mb * height_in_mb;
- unsigned image_size, tmp, min_dpb_size, num_dpb_buffer;
+ unsigned image_size, tmp, min_dpb_size, num_dpb_buffer, min_ctx_size;
image_size = width * height;
image_size += image_size / 2;
@@ -466,6 +466,8 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
num_dpb_buffer = (le32_to_cpu(msg[59]) & 0xff) + 2;
min_dpb_size = image_size * num_dpb_buffer;
+ min_ctx_size = ((width + 255) / 16) * ((height + 255) / 16)
+ * 16 * num_dpb_buffer + 52 * 1024;
break;
default:
@@ -486,6 +488,7 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
buf_sizes[0x1] = dpb_size;
buf_sizes[0x2] = image_size;
+ buf_sizes[0x4] = min_ctx_size;
return 0;
}
@@ -628,6 +631,13 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx)
return -EINVAL;
}
+ } else if (cmd == 0x206) {
+ if ((end - start) < ctx->buf_sizes[4]) {
+ DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
+ (unsigned)(end - start),
+ ctx->buf_sizes[4]);
+ return -EINVAL;
+ }
} else if ((cmd != 0x100) && (cmd != 0x204)) {
DRM_ERROR("invalid UVD command %X!\n", cmd);
return -EINVAL;
@@ -755,9 +765,10 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx)
struct amdgpu_uvd_cs_ctx ctx = {};
unsigned buf_sizes[] = {
[0x00000000] = 2048,
- [0x00000001] = 32 * 1024 * 1024,
- [0x00000002] = 2048 * 1152 * 3,
+ [0x00000001] = 0xFFFFFFFF,
+ [0x00000002] = 0xFFFFFFFF,
[0x00000003] = 2048,
+ [0x00000004] = 0xFFFFFFFF,
};
struct amdgpu_ib *ib = &parser->ibs[ib_idx];
int r;
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
index ab83cc1..15df46c 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
@@ -500,6 +500,7 @@ static int cik_sdma_load_microcode(struct amdgpu_device *adev)
amdgpu_ucode_print_sdma_hdr(&hdr->header);
fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+ adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version);
fw_data = (const __le32 *)
(adev->sdma[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], 0);
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
index 2db6ab0..0d8bf2c 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
@@ -3080,6 +3080,8 @@ static int gfx_v7_0_cp_compute_load_microcode(struct amdgpu_device *adev)
mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
amdgpu_ucode_print_gfx_hdr(&mec_hdr->header);
adev->gfx.mec_fw_version = le32_to_cpu(mec_hdr->header.ucode_version);
+ adev->gfx.mec_feature_version = le32_to_cpu(
+ mec_hdr->ucode_feature_version);
gfx_v7_0_cp_compute_enable(adev, false);
@@ -3102,6 +3104,8 @@ static int gfx_v7_0_cp_compute_load_microcode(struct amdgpu_device *adev)
mec2_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
amdgpu_ucode_print_gfx_hdr(&mec2_hdr->header);
adev->gfx.mec2_fw_version = le32_to_cpu(mec2_hdr->header.ucode_version);
+ adev->gfx.mec2_feature_version = le32_to_cpu(
+ mec2_hdr->ucode_feature_version);
/* MEC2 */
fw_data = (const __le32 *)
@@ -4066,6 +4070,8 @@ static int gfx_v7_0_rlc_resume(struct amdgpu_device *adev)
hdr = (const struct rlc_firmware_header_v1_0 *)adev->gfx.rlc_fw->data;
amdgpu_ucode_print_rlc_hdr(&hdr->header);
adev->gfx.rlc_fw_version = le32_to_cpu(hdr->header.ucode_version);
+ adev->gfx.rlc_feature_version = le32_to_cpu(
+ hdr->ucode_feature_version);
gfx_v7_0_rlc_stop(adev);
@@ -5122,7 +5128,7 @@ static void gfx_v7_0_print_status(void *handle)
dev_info(adev->dev, " CP_HPD_EOP_CONTROL=0x%08X\n",
RREG32(mmCP_HPD_EOP_CONTROL));
- for (queue = 0; queue < 8; i++) {
+ for (queue = 0; queue < 8; queue++) {
cik_srbm_select(adev, me, pipe, queue, 0);
dev_info(adev->dev, " queue: %d\n", queue);
dev_info(adev->dev, " CP_PQ_WPTR_POLL_CNTL=0x%08X\n",
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index 9e1d4dd..20e2cfd 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -587,6 +587,7 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
int err;
struct amdgpu_firmware_info *info = NULL;
const struct common_firmware_header *header = NULL;
+ const struct gfx_firmware_header_v1_0 *cp_hdr;
DRM_DEBUG("\n");
@@ -611,6 +612,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
err = amdgpu_ucode_validate(adev->gfx.pfp_fw);
if (err)
goto out;
+ cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
+ adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+ adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name);
err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
@@ -619,6 +623,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
err = amdgpu_ucode_validate(adev->gfx.me_fw);
if (err)
goto out;
+ cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
+ adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+ adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name);
err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev);
@@ -627,12 +634,18 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
err = amdgpu_ucode_validate(adev->gfx.ce_fw);
if (err)
goto out;
+ cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
+ adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+ adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name);
err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
if (err)
goto out;
err = amdgpu_ucode_validate(adev->gfx.rlc_fw);
+ cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.rlc_fw->data;
+ adev->gfx.rlc_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+ adev->gfx.rlc_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name);
err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev);
@@ -641,6 +654,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
err = amdgpu_ucode_validate(adev->gfx.mec_fw);
if (err)
goto out;
+ cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
+ adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+ adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name);
err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
@@ -648,6 +664,12 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
err = amdgpu_ucode_validate(adev->gfx.mec2_fw);
if (err)
goto out;
+ cp_hdr = (const struct gfx_firmware_header_v1_0 *)
+ adev->gfx.mec2_fw->data;
+ adev->gfx.mec2_fw_version = le32_to_cpu(
+ cp_hdr->header.ucode_version);
+ adev->gfx.mec2_feature_version = le32_to_cpu(
+ cp_hdr->ucode_feature_version);
} else {
err = 0;
adev->gfx.mec2_fw = NULL;
@@ -1983,6 +2005,7 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
adev->gfx.config.max_shader_engines = 1;
adev->gfx.config.max_tile_pipes = 2;
adev->gfx.config.max_sh_per_se = 1;
+ adev->gfx.config.max_backends_per_se = 2;
switch (adev->pdev->revision) {
case 0xc4:
@@ -1991,7 +2014,6 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
case 0xcc:
/* B10 */
adev->gfx.config.max_cu_per_sh = 8;
- adev->gfx.config.max_backends_per_se = 2;
break;
case 0xc5:
case 0x81:
@@ -2000,14 +2022,12 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
case 0xcd:
/* B8 */
adev->gfx.config.max_cu_per_sh = 6;
- adev->gfx.config.max_backends_per_se = 2;
break;
case 0xc6:
case 0xca:
case 0xce:
/* B6 */
adev->gfx.config.max_cu_per_sh = 6;
- adev->gfx.config.max_backends_per_se = 2;
break;
case 0xc7:
case 0x87:
@@ -2015,7 +2035,6 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
default:
/* B4 */
adev->gfx.config.max_cu_per_sh = 4;
- adev->gfx.config.max_backends_per_se = 1;
break;
}
@@ -2275,7 +2294,6 @@ static int gfx_v8_0_rlc_load_microcode(struct amdgpu_device *adev)
hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data;
amdgpu_ucode_print_rlc_hdr(&hdr->header);
- adev->gfx.rlc_fw_version = le32_to_cpu(hdr->header.ucode_version);
fw_data = (const __le32 *)(adev->gfx.rlc_fw->data +
le32_to_cpu(hdr->header.ucode_array_offset_bytes));
@@ -2361,12 +2379,6 @@ static int gfx_v8_0_cp_gfx_load_microcode(struct amdgpu_device *adev)
amdgpu_ucode_print_gfx_hdr(&pfp_hdr->header);
amdgpu_ucode_print_gfx_hdr(&ce_hdr->header);
amdgpu_ucode_print_gfx_hdr(&me_hdr->header);
- adev->gfx.pfp_fw_version = le32_to_cpu(pfp_hdr->header.ucode_version);
- adev->gfx.ce_fw_version = le32_to_cpu(ce_hdr->header.ucode_version);
- adev->gfx.me_fw_version = le32_to_cpu(me_hdr->header.ucode_version);
- adev->gfx.me_feature_version = le32_to_cpu(me_hdr->ucode_feature_version);
- adev->gfx.ce_feature_version = le32_to_cpu(ce_hdr->ucode_feature_version);
- adev->gfx.pfp_feature_version = le32_to_cpu(pfp_hdr->ucode_feature_version);
gfx_v8_0_cp_gfx_enable(adev, false);
@@ -2622,7 +2634,6 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev)
mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
amdgpu_ucode_print_gfx_hdr(&mec_hdr->header);
- adev->gfx.mec_fw_version = le32_to_cpu(mec_hdr->header.ucode_version);
fw_data = (const __le32 *)
(adev->gfx.mec_fw->data +
@@ -2641,7 +2652,6 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev)
mec2_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
amdgpu_ucode_print_gfx_hdr(&mec2_hdr->header);
- adev->gfx.mec2_fw_version = le32_to_cpu(mec2_hdr->header.ucode_version);
fw_data = (const __le32 *)
(adev->gfx.mec2_fw->data +
@@ -3125,7 +3135,7 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER,
AMDGPU_DOORBELL_KIQ << 2);
WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER,
- 0x7FFFF << 2);
+ AMDGPU_DOORBELL_MEC_RING7 << 2);
}
tmp = RREG32(mmCP_HQD_PQ_DOORBELL_CONTROL);
tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
index d789588..a988dfb 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
@@ -121,6 +121,7 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev)
int err, i;
struct amdgpu_firmware_info *info = NULL;
const struct common_firmware_header *header = NULL;
+ const struct sdma_firmware_header_v1_0 *hdr;
DRM_DEBUG("\n");
@@ -142,6 +143,9 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev)
err = amdgpu_ucode_validate(adev->sdma[i].fw);
if (err)
goto out;
+ hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
+ adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+ adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version);
if (adev->firmware.smu_load) {
info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i];
@@ -541,8 +545,6 @@ static int sdma_v2_4_load_microcode(struct amdgpu_device *adev)
hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
amdgpu_ucode_print_sdma_hdr(&hdr->header);
fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
- adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
-
fw_data = (const __le32 *)
(adev->sdma[i].fw->data +
le32_to_cpu(hdr->header.ucode_array_offset_bytes));
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
index 7bb37b9..2b86569 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
@@ -159,6 +159,7 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
int err, i;
struct amdgpu_firmware_info *info = NULL;
const struct common_firmware_header *header = NULL;
+ const struct sdma_firmware_header_v1_0 *hdr;
DRM_DEBUG("\n");
@@ -183,6 +184,9 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
err = amdgpu_ucode_validate(adev->sdma[i].fw);
if (err)
goto out;
+ hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
+ adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+ adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version);
if (adev->firmware.smu_load) {
info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i];
@@ -630,8 +634,6 @@ static int sdma_v3_0_load_microcode(struct amdgpu_device *adev)
hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
amdgpu_ucode_print_sdma_hdr(&hdr->header);
fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
- adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
-
fw_data = (const __le32 *)
(adev->sdma[i].fw->data +
le32_to_cpu(hdr->header.ucode_array_offset_bytes));
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 6fad1f9..ef6182b 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -559,7 +559,7 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index aac2122..9dcc728 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -196,7 +196,12 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
}
funcs = connector->helper_private;
- new_encoder = funcs->best_encoder(connector);
+
+ if (funcs->atomic_best_encoder)
+ new_encoder = funcs->atomic_best_encoder(connector,
+ connector_state);
+ else
+ new_encoder = funcs->best_encoder(connector);
if (!new_encoder) {
DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n",
@@ -229,13 +234,14 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
}
}
+ if (WARN_ON(!connector_state->crtc))
+ return -EINVAL;
+
connector_state->best_encoder = new_encoder;
- if (connector_state->crtc) {
- idx = drm_crtc_index(connector_state->crtc);
+ idx = drm_crtc_index(connector_state->crtc);
- crtc_state = state->crtc_states[idx];
- crtc_state->mode_changed = true;
- }
+ crtc_state = state->crtc_states[idx];
+ crtc_state->mode_changed = true;
DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n",
connector->base.id,
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 778bbb6..eb603f1de 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -873,9 +873,10 @@ static void drm_dp_destroy_port(struct kref *kref)
from an EDID retrieval */
if (port->connector) {
mutex_lock(&mgr->destroy_connector_lock);
- list_add(&port->connector->destroy_list, &mgr->destroy_connector_list);
+ list_add(&port->next, &mgr->destroy_connector_list);
mutex_unlock(&mgr->destroy_connector_lock);
schedule_work(&mgr->destroy_connector_work);
+ return;
}
drm_dp_port_teardown_pdt(port, port->pdt);
@@ -1294,7 +1295,6 @@ retry:
goto retry;
}
DRM_DEBUG_KMS("failed to dpcd write %d %d\n", tosend, ret);
- WARN(1, "fail\n");
return -EIO;
}
@@ -2660,7 +2660,7 @@ static void drm_dp_tx_work(struct work_struct *work)
static void drm_dp_destroy_connector_work(struct work_struct *work)
{
struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
- struct drm_connector *connector;
+ struct drm_dp_mst_port *port;
/*
* Not a regular list traverse as we have to drop the destroy
@@ -2669,15 +2669,21 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
*/
for (;;) {
mutex_lock(&mgr->destroy_connector_lock);
- connector = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_connector, destroy_list);
- if (!connector) {
+ port = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_dp_mst_port, next);
+ if (!port) {
mutex_unlock(&mgr->destroy_connector_lock);
break;
}
- list_del(&connector->destroy_list);
+ list_del(&port->next);
mutex_unlock(&mgr->destroy_connector_lock);
- mgr->cbs->destroy_connector(mgr, connector);
+ mgr->cbs->destroy_connector(mgr, port->connector);
+
+ drm_dp_port_teardown_pdt(port, port->pdt);
+
+ if (!port->input && port->vcpi.vcpi > 0)
+ drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
+ kfree(port);
}
}
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index f9cc68f..b50fa0a 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -75,7 +75,7 @@ module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600)
module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
static void store_vblank(struct drm_device *dev, int crtc,
- unsigned vblank_count_inc,
+ u32 vblank_count_inc,
struct timeval *t_vblank)
{
struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 842d6b8..2a65235 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -1745,7 +1745,6 @@ static int fimc_probe(struct platform_device *pdev)
spin_lock_init(&ctx->lock);
platform_set_drvdata(pdev, ctx);
- pm_runtime_set_active(dev);
pm_runtime_enable(dev);
ret = exynos_drm_ippdrv_register(ippdrv);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 8040ed2..f1c6b76 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -593,8 +593,7 @@ static int gsc_src_set_transf(struct device *dev,
gsc_write(cfg, GSC_IN_CON);
- ctx->rotation = cfg &
- (GSC_IN_ROT_90 | GSC_IN_ROT_270) ? 1 : 0;
+ ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0;
*swap = ctx->rotation;
return 0;
@@ -857,8 +856,7 @@ static int gsc_dst_set_transf(struct device *dev,
gsc_write(cfg, GSC_IN_CON);
- ctx->rotation = cfg &
- (GSC_IN_ROT_90 | GSC_IN_ROT_270) ? 1 : 0;
+ ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0;
*swap = ctx->rotation;
return 0;
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 99e2864..4a00990 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -1064,6 +1064,7 @@ static int hdmi_get_modes(struct drm_connector *connector)
{
struct hdmi_context *hdata = ctx_from_connector(connector);
struct edid *edid;
+ int ret;
if (!hdata->ddc_adpt)
return -ENODEV;
@@ -1079,7 +1080,11 @@ static int hdmi_get_modes(struct drm_connector *connector)
drm_mode_connector_update_edid_property(connector, edid);
- return drm_add_edid_modes(connector, edid);
+ ret = drm_add_edid_modes(connector, edid);
+
+ kfree(edid);
+
+ return ret;
}
static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index cae98db..4706b56 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -718,6 +718,10 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
/* handling VSYNC */
if (val & MXR_INT_STATUS_VSYNC) {
+ /* vsync interrupt use different bit for read and clear */
+ val |= MXR_INT_CLEAR_VSYNC;
+ val &= ~MXR_INT_STATUS_VSYNC;
+
/* interlace scan need to check shadow register */
if (ctx->interlace) {
base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
@@ -743,11 +747,6 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
out:
/* clear interrupts */
- if (~val & MXR_INT_EN_VSYNC) {
- /* vsync interrupt use different bit for read and clear */
- val &= ~MXR_INT_EN_VSYNC;
- val |= MXR_INT_CLEAR_VSYNC;
- }
mixer_reg_write(res, MXR_INT_STATUS, val);
spin_unlock(&res->reg_slock);
@@ -907,8 +906,8 @@ static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
}
/* enable vsync interrupt */
- mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
- MXR_INT_EN_VSYNC);
+ mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
+ mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
return 0;
}
@@ -918,7 +917,13 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
struct mixer_context *mixer_ctx = crtc->ctx;
struct mixer_resources *res = &mixer_ctx->mixer_res;
+ if (!mixer_ctx->powered) {
+ mixer_ctx->int_en &= MXR_INT_EN_VSYNC;
+ return;
+ }
+
/* disable vsync interrupt */
+ mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
}
@@ -1047,6 +1052,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
+ if (ctx->int_en & MXR_INT_EN_VSYNC)
+ mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
mixer_win_reset(ctx);
}
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 2aaa3c8..00416f2 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -54,7 +54,7 @@ static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder)
}
/* ADI recommended values for proper operation. */
-static const struct reg_default adv7511_fixed_registers[] = {
+static const struct reg_sequence adv7511_fixed_registers[] = {
{ 0x98, 0x03 },
{ 0x9a, 0xe0 },
{ 0x9c, 0x30 },
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index fe1599d..424228b 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -606,8 +606,6 @@ static void
tda998x_write_if(struct tda998x_priv *priv, uint8_t bit, uint16_t addr,
uint8_t *buf, size_t size)
{
- buf[PB(0)] = tda998x_cksum(buf, size);
-
reg_clear(priv, REG_DIP_IF_FLAGS, bit);
reg_write_range(priv, addr, buf, size);
reg_set(priv, REG_DIP_IF_FLAGS, bit);
@@ -627,6 +625,8 @@ tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p)
buf[PB(4)] = p->audio_frame[4];
buf[PB(5)] = p->audio_frame[5] & 0xf8; /* DM_INH + LSV */
+ buf[PB(0)] = tda998x_cksum(buf, sizeof(buf));
+
tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf,
sizeof(buf));
}
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 7ed8033..8e35e0d 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -129,8 +129,9 @@ int intel_atomic_commit(struct drm_device *dev,
struct drm_atomic_state *state,
bool async)
{
- int ret;
- int i;
+ struct drm_crtc_state *crtc_state;
+ struct drm_crtc *crtc;
+ int ret, i;
if (async) {
DRM_DEBUG_KMS("i915 does not yet support async commit\n");
@@ -142,48 +143,18 @@ int intel_atomic_commit(struct drm_device *dev,
return ret;
/* Point of no return */
-
- /*
- * FIXME: The proper sequence here will eventually be:
- *
- * drm_atomic_helper_swap_state(dev, state)
- * drm_atomic_helper_commit_modeset_disables(dev, state);
- * drm_atomic_helper_commit_planes(dev, state);
- * drm_atomic_helper_commit_modeset_enables(dev, state);
- * drm_atomic_helper_wait_for_vblanks(dev, state);
- * drm_atomic_helper_cleanup_planes(dev, state);
- * drm_atomic_state_free(state);
- *
- * once we have full atomic modeset. For now, just manually update
- * plane states to avoid clobbering good states with dummy states
- * while nuclear pageflipping.
- */
- for (i = 0; i < dev->mode_config.num_total_plane; i++) {
- struct drm_plane *plane = state->planes[i];
-
- if (!plane)
- continue;
-
- plane->state->state = state;
- swap(state->plane_states[i], plane->state);
- plane->state->state = NULL;
- }
+ drm_atomic_helper_swap_state(dev, state);
/* swap crtc_scaler_state */
- for (i = 0; i < dev->mode_config.num_crtc; i++) {
- struct drm_crtc *crtc = state->crtcs[i];
- if (!crtc) {
- continue;
- }
-
- to_intel_crtc(crtc)->config->scaler_state =
- to_intel_crtc_state(state->crtc_states[i])->scaler_state;
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state);
if (INTEL_INFO(dev)->gen >= 9)
skl_detach_scalers(to_intel_crtc(crtc));
+
+ drm_atomic_helper_commit_planes_on_crtc(crtc_state);
}
- drm_atomic_helper_commit_planes(dev, state);
drm_atomic_helper_wait_for_vblanks(dev, state);
drm_atomic_helper_cleanup_planes(dev, state);
drm_atomic_state_free(state);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 30e0f54..87476ff 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -11826,7 +11826,9 @@ encoder_retry:
goto encoder_retry;
}
- pipe_config->dither = pipe_config->pipe_bpp != base_bpp;
+ /* Dithering seems to not pass-through bits correctly when it should, so
+ * only enable it on 6bpc panels. */
+ pipe_config->dither = pipe_config->pipe_bpp == 6*3;
DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n",
base_bpp, pipe_config->pipe_bpp, pipe_config->dither);
@@ -12624,17 +12626,17 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc,
modeset_update_crtc_power_domains(state);
- drm_atomic_helper_commit_planes(dev, state);
-
/* Now enable the clocks, plane, pipe, and connectors that we set up. */
for_each_crtc_in_state(state, crtc, crtc_state, i) {
- if (!needs_modeset(crtc->state) || !crtc->state->enable)
+ if (!needs_modeset(crtc->state) || !crtc->state->enable) {
+ drm_atomic_helper_commit_planes_on_crtc(crtc_state);
continue;
+ }
update_scanline_offset(to_intel_crtc(crtc));
dev_priv->display.crtc_enable(crtc);
- intel_crtc_enable_planes(crtc);
+ drm_atomic_helper_commit_planes_on_crtc(crtc_state);
}
/* FIXME: add subpixel order */
@@ -12891,20 +12893,11 @@ intel_modeset_stage_output_state(struct drm_device *dev,
return 0;
}
-static bool primary_plane_visible(struct drm_crtc *crtc)
-{
- struct intel_plane_state *plane_state =
- to_intel_plane_state(crtc->primary->state);
-
- return plane_state->visible;
-}
-
static int intel_crtc_set_config(struct drm_mode_set *set)
{
struct drm_device *dev;
struct drm_atomic_state *state = NULL;
struct intel_crtc_state *pipe_config;
- bool primary_plane_was_visible;
int ret;
BUG_ON(!set);
@@ -12943,38 +12936,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
intel_update_pipe_size(to_intel_crtc(set->crtc));
- primary_plane_was_visible = primary_plane_visible(set->crtc);
-
ret = intel_set_mode_with_config(set->crtc, pipe_config, true);
- if (ret == 0 &&
- pipe_config->base.enable &&
- pipe_config->base.planes_changed &&
- !needs_modeset(&pipe_config->base)) {
- struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc);
-
- /*
- * We need to make sure the primary plane is re-enabled if it
- * has previously been turned off.
- */
- if (ret == 0 && !primary_plane_was_visible &&
- primary_plane_visible(set->crtc)) {
- WARN_ON(!intel_crtc->active);
- intel_post_enable_primary(set->crtc);
- }
-
- /*
- * In the fastboot case this may be our only check of the
- * state after boot. It would be better to only do it on
- * the first update, but we don't have a nice way of doing that
- * (and really, set_config isn't used much for high freq page
- * flipping, so increasing its cost here shouldn't be a big
- * deal).
- */
- if (i915.fastboot && ret == 0)
- intel_modeset_check_state(set->crtc->dev);
- }
-
if (ret) {
DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n",
set->crtc->base.id, ret);
@@ -13305,6 +13268,9 @@ intel_check_primary_plane(struct drm_plane *plane,
*/
if (IS_BROADWELL(dev))
intel_crtc->atomic.wait_vblank = true;
+
+ if (crtc_state)
+ intel_crtc->atomic.post_enable_primary = true;
}
/*
@@ -13317,6 +13283,10 @@ intel_check_primary_plane(struct drm_plane *plane,
if (!state->visible || !fb)
intel_crtc->atomic.disable_ips = true;
+ if (!state->visible && old_state->visible &&
+ crtc_state && !needs_modeset(&crtc_state->base))
+ intel_crtc->atomic.pre_disable_primary = true;
+
intel_crtc->atomic.fb_bits |=
INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
@@ -15034,6 +15004,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
struct intel_plane_state *plane_state;
memset(crtc->config, 0, sizeof(*crtc->config));
+ crtc->config->base.crtc = &crtc->base;
crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 6e8faa2..1df0e1f 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -93,9 +93,6 @@ static const struct dp_link_dpll chv_dpll[] = {
static const int skl_rates[] = { 162000, 216000, 270000,
324000, 432000, 540000 };
-static const int chv_rates[] = { 162000, 202500, 210000, 216000,
- 243000, 270000, 324000, 405000,
- 420000, 432000, 540000 };
static const int default_rates[] = { 162000, 270000, 540000 };
/**
@@ -1169,24 +1166,31 @@ intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
}
+static bool intel_dp_source_supports_hbr2(struct drm_device *dev)
+{
+ /* WaDisableHBR2:skl */
+ if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0)
+ return false;
+
+ if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
+ (INTEL_INFO(dev)->gen >= 9))
+ return true;
+ else
+ return false;
+}
+
static int
intel_dp_source_rates(struct drm_device *dev, const int **source_rates)
{
if (IS_SKYLAKE(dev)) {
*source_rates = skl_rates;
return ARRAY_SIZE(skl_rates);
- } else if (IS_CHERRYVIEW(dev)) {
- *source_rates = chv_rates;
- return ARRAY_SIZE(chv_rates);
}
*source_rates = default_rates;
- if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0)
- /* WaDisableHBR2:skl */
- return (DP_LINK_BW_2_7 >> 3) + 1;
- else if (INTEL_INFO(dev)->gen >= 8 ||
- (IS_HASWELL(dev) && !IS_HSW_ULX(dev)))
+ /* This depends on the fact that 5.4 is last value in the array */
+ if (intel_dp_source_supports_hbr2(dev))
return (DP_LINK_BW_5_4 >> 3) + 1;
else
return (DP_LINK_BW_2_7 >> 3) + 1;
@@ -3941,10 +3945,15 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
}
}
- /* Training Pattern 3 support, both source and sink */
+ /* Training Pattern 3 support, Intel platforms that support HBR2 alone
+ * have support for TP3 hence that check is used along with dpcd check
+ * to ensure TP3 can be enabled.
+ * SKL < B0: due it's WaDisableHBR2 is the only exception where TP3 is
+ * supported but still not enabled.
+ */
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x12 &&
intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED &&
- (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)) {
+ intel_dp_source_supports_hbr2(dev)) {
intel_dp->use_tps3 = true;
DRM_DEBUG_KMS("Displayport TPS3 supported\n");
} else
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 6e4cc53..600afdb 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -357,6 +357,16 @@ intel_dp_mst_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
+static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector,
+ struct drm_connector_state *state)
+{
+ struct intel_connector *intel_connector = to_intel_connector(connector);
+ struct intel_dp *intel_dp = intel_connector->mst_port;
+ struct intel_crtc *crtc = to_intel_crtc(state->crtc);
+
+ return &intel_dp->mst_encoders[crtc->pipe]->base.base;
+}
+
static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connector)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
@@ -367,6 +377,7 @@ static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connecto
static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = {
.get_modes = intel_dp_mst_get_modes,
.mode_valid = intel_dp_mst_mode_valid,
+ .atomic_best_encoder = intel_mst_atomic_best_encoder,
.best_encoder = intel_mst_best_encoder,
};
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 9b74ffa..7f2161a 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -1012,6 +1012,8 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring,
ret = intel_pin_and_map_ringbuffer_obj(ring->dev, ringbuf);
if (ret)
goto unpin_ctx_obj;
+
+ ctx_obj->dirty = true;
}
return ret;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
index 52c22b0..e10f964 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
@@ -166,30 +166,14 @@ gk104_fifo_context_attach(struct nvkm_object *parent,
}
static int
-gk104_fifo_chan_kick(struct gk104_fifo_chan *chan)
-{
- struct nvkm_object *obj = (void *)chan;
- struct gk104_fifo_priv *priv = (void *)obj->engine;
-
- nv_wr32(priv, 0x002634, chan->base.chid);
- if (!nv_wait(priv, 0x002634, 0x100000, 0x000000)) {
- nv_error(priv, "channel %d [%s] kick timeout\n",
- chan->base.chid, nvkm_client_name(chan));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend,
struct nvkm_object *object)
{
struct nvkm_bar *bar = nvkm_bar(parent);
+ struct gk104_fifo_priv *priv = (void *)parent->engine;
struct gk104_fifo_base *base = (void *)parent->parent;
struct gk104_fifo_chan *chan = (void *)parent;
u32 addr;
- int ret;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
@@ -204,9 +188,13 @@ gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend,
return -EINVAL;
}
- ret = gk104_fifo_chan_kick(chan);
- if (ret && suspend)
- return ret;
+ nv_wr32(priv, 0x002634, chan->base.chid);
+ if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
+ nv_error(priv, "channel %d [%s] kick timeout\n",
+ chan->base.chid, nvkm_client_name(chan));
+ if (suspend)
+ return -EBUSY;
+ }
if (addr) {
nv_wo32(base, addr + 0x00, 0x00000000);
@@ -331,7 +319,6 @@ gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend)
gk104_fifo_runlist_update(priv, chan->engine);
}
- gk104_fifo_chan_kick(chan);
nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
return nvkm_fifo_channel_fini(&chan->base, suspend);
}
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 1162bfa..171d3e4 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -79,6 +79,11 @@ static void radeon_hotplug_work_func(struct work_struct *work)
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
+ /* we can race here at startup, some boards seem to trigger
+ * hotplug irqs when they shouldn't. */
+ if (!rdev->mode_info.mode_config_initialized)
+ return;
+
mutex_lock(&mode_config->mutex);
if (mode_config->num_connector) {
list_for_each_entry(connector, &mode_config->connector_list, head)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 654c8da..97ad3bc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -2492,7 +2492,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes,
true, NULL);
if (unlikely(ret != 0))
- goto out_err;
+ goto out_err_nores;
ret = vmw_validate_buffers(dev_priv, sw_context);
if (unlikely(ret != 0))
@@ -2536,6 +2536,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
vmw_resource_relocations_free(&sw_context->res_relocations);
vmw_fifo_commit(dev_priv, command_size);
+ mutex_unlock(&dev_priv->binding_mutex);
vmw_query_bo_switch_commit(dev_priv, sw_context);
ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
@@ -2551,7 +2552,6 @@ int vmw_execbuf_process(struct drm_file *file_priv,
DRM_ERROR("Fence submission error. Syncing.\n");
vmw_resource_list_unreserve(&sw_context->resource_list, false);
- mutex_unlock(&dev_priv->binding_mutex);
ttm_eu_fence_buffer_objects(&ticket, &sw_context->validate_nodes,
(void *) fence);
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 3511bbab..e3c6364 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -462,12 +462,15 @@ out:
static void hidinput_cleanup_battery(struct hid_device *dev)
{
+ const struct power_supply_desc *psy_desc;
+
if (!dev->battery)
return;
+ psy_desc = dev->battery->desc;
power_supply_unregister(dev->battery);
- kfree(dev->battery->desc->name);
- kfree(dev->battery->desc);
+ kfree(psy_desc->name);
+ kfree(psy_desc);
dev->battery = NULL;
}
#else /* !CONFIG_HID_BATTERY_STRENGTH */
diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c
index 9416731..b905d50 100644
--- a/drivers/hid/hid-uclogic.c
+++ b/drivers/hid/hid-uclogic.c
@@ -858,7 +858,7 @@ static int uclogic_tablet_enable(struct hid_device *hdev)
for (p = drvdata->rdesc;
p <= drvdata->rdesc + drvdata->rsize - 4;) {
if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
- p[3] < sizeof(params)) {
+ p[3] < ARRAY_SIZE(params)) {
v = params[p[3]];
put_unaligned(cpu_to_le32(v), (s32 *)p);
p += 4;
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 44958d7..01b937e 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -1284,6 +1284,39 @@ fail_register_pen_input:
return error;
}
+/*
+ * Not all devices report physical dimensions from HID.
+ * Compute the default from hardcoded logical dimension
+ * and resolution before driver overwrites them.
+ */
+static void wacom_set_default_phy(struct wacom_features *features)
+{
+ if (features->x_resolution) {
+ features->x_phy = (features->x_max * 100) /
+ features->x_resolution;
+ features->y_phy = (features->y_max * 100) /
+ features->y_resolution;
+ }
+}
+
+static void wacom_calculate_res(struct wacom_features *features)
+{
+ /* set unit to "100th of a mm" for devices not reported by HID */
+ if (!features->unit) {
+ features->unit = 0x11;
+ features->unitExpo = -3;
+ }
+
+ features->x_resolution = wacom_calc_hid_res(features->x_max,
+ features->x_phy,
+ features->unit,
+ features->unitExpo);
+ features->y_resolution = wacom_calc_hid_res(features->y_max,
+ features->y_phy,
+ features->unit,
+ features->unitExpo);
+}
+
static void wacom_wireless_work(struct work_struct *work)
{
struct wacom *wacom = container_of(work, struct wacom, work);
@@ -1341,6 +1374,8 @@ static void wacom_wireless_work(struct work_struct *work)
if (wacom_wac1->features.type != INTUOSHT &&
wacom_wac1->features.type != BAMBOO_PT)
wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PAD;
+ wacom_set_default_phy(&wacom_wac1->features);
+ wacom_calculate_res(&wacom_wac1->features);
snprintf(wacom_wac1->pen_name, WACOM_NAME_MAX, "%s (WL) Pen",
wacom_wac1->features.name);
snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",
@@ -1359,7 +1394,9 @@ static void wacom_wireless_work(struct work_struct *work)
wacom_wac2->features =
*((struct wacom_features *)id->driver_data);
wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
+ wacom_set_default_phy(&wacom_wac2->features);
wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
+ wacom_calculate_res(&wacom_wac2->features);
snprintf(wacom_wac2->touch_name, WACOM_NAME_MAX,
"%s (WL) Finger",wacom_wac2->features.name);
snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
@@ -1407,39 +1444,6 @@ void wacom_battery_work(struct work_struct *work)
}
}
-/*
- * Not all devices report physical dimensions from HID.
- * Compute the default from hardcoded logical dimension
- * and resolution before driver overwrites them.
- */
-static void wacom_set_default_phy(struct wacom_features *features)
-{
- if (features->x_resolution) {
- features->x_phy = (features->x_max * 100) /
- features->x_resolution;
- features->y_phy = (features->y_max * 100) /
- features->y_resolution;
- }
-}
-
-static void wacom_calculate_res(struct wacom_features *features)
-{
- /* set unit to "100th of a mm" for devices not reported by HID */
- if (!features->unit) {
- features->unit = 0x11;
- features->unitExpo = -3;
- }
-
- features->x_resolution = wacom_calc_hid_res(features->x_max,
- features->x_phy,
- features->unit,
- features->unitExpo);
- features->y_resolution = wacom_calc_hid_res(features->y_max,
- features->y_phy,
- features->unit,
- features->unitExpo);
-}
-
static size_t wacom_compute_pktlen(struct hid_device *hdev)
{
struct hid_report_enum *report_enum;
diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
index 37c16af..c848789 100644
--- a/drivers/hwmon/dell-smm-hwmon.c
+++ b/drivers/hwmon/dell-smm-hwmon.c
@@ -929,6 +929,21 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
MODULE_DEVICE_TABLE(dmi, i8k_dmi_table);
+static struct dmi_system_id i8k_blacklist_dmi_table[] __initdata = {
+ {
+ /*
+ * CPU fan speed going up and down on Dell Studio XPS 8100
+ * for unknown reasons.
+ */
+ .ident = "Dell Studio XPS 8100",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Studio XPS 8100"),
+ },
+ },
+ { }
+};
+
/*
* Probe for the presence of a supported laptop.
*/
@@ -940,7 +955,8 @@ static int __init i8k_probe(void)
/*
* Get DMI information
*/
- if (!dmi_check_system(i8k_dmi_table)) {
+ if (!dmi_check_system(i8k_dmi_table) ||
+ dmi_check_system(i8k_blacklist_dmi_table)) {
if (!ignore_dmi && !force)
return -ENODEV;
diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c
index 9b55e67..85d106f 100644
--- a/drivers/hwmon/g762.c
+++ b/drivers/hwmon/g762.c
@@ -582,6 +582,7 @@ static const struct of_device_id g762_dt_match[] = {
{ .compatible = "gmt,g763" },
{ },
};
+MODULE_DEVICE_TABLE(of, g762_dt_match);
/*
* Grab clock (a required property), enable it, get (fixed) clock frequency
diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c
index 6153df73..08ff89d 100644
--- a/drivers/hwmon/nct7904.c
+++ b/drivers/hwmon/nct7904.c
@@ -575,6 +575,7 @@ static const struct i2c_device_id nct7904_id[] = {
{"nct7904", 0},
{}
};
+MODULE_DEVICE_TABLE(i2c, nct7904_id);
static struct i2c_driver nct7904_driver = {
.class = I2C_CLASS_HWMON,
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index af162b4..025686d 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -692,7 +692,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, iface);
- dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, "
+ dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Controller, "
"regs_base@%p\n", iface->regs_base);
return 0;
@@ -735,6 +735,6 @@ subsys_initcall(i2c_bfin_twi_init);
module_exit(i2c_bfin_twi_exit);
MODULE_AUTHOR("Bryan Wu, Sonic Zhang");
-MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver");
+MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Controller Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:i2c-bfin-twi");
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index d1c22e3..fc9bf7f 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -1247,7 +1247,14 @@ static void omap_i2c_prepare_recovery(struct i2c_adapter *adap)
u32 reg;
reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+ /* enable test mode */
reg |= OMAP_I2C_SYSTEST_ST_EN;
+ /* select SDA/SCL IO mode */
+ reg |= 3 << OMAP_I2C_SYSTEST_TMODE_SHIFT;
+ /* set SCL to high-impedance state (reset value is 0) */
+ reg |= OMAP_I2C_SYSTEST_SCL_O;
+ /* set SDA to high-impedance state (reset value is 0) */
+ reg |= OMAP_I2C_SYSTEST_SDA_O;
omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
}
@@ -1257,7 +1264,11 @@ static void omap_i2c_unprepare_recovery(struct i2c_adapter *adap)
u32 reg;
reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+ /* restore reset values */
reg &= ~OMAP_I2C_SYSTEST_ST_EN;
+ reg &= ~OMAP_I2C_SYSTEST_TMODE_MASK;
+ reg &= ~OMAP_I2C_SYSTEST_SCL_O;
+ reg &= ~OMAP_I2C_SYSTEST_SDA_O;
omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
}
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index e6d4935..c83e4d1 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -567,6 +567,9 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
if (bri->prepare_recovery)
bri->prepare_recovery(adap);
+ bri->set_scl(adap, val);
+ ndelay(RECOVERY_NDELAY);
+
/*
* By this time SCL is high, as we need to give 9 falling-rising edges
*/
@@ -597,7 +600,6 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
int i2c_generic_scl_recovery(struct i2c_adapter *adap)
{
- adap->bus_recovery_info->set_scl(adap, 1);
return i2c_generic_recovery(adap);
}
EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery);
@@ -1338,13 +1340,17 @@ static int of_dev_node_match(struct device *dev, void *data)
struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
{
struct device *dev;
+ struct i2c_client *client;
- dev = bus_find_device(&i2c_bus_type, NULL, node,
- of_dev_node_match);
+ dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
if (!dev)
return NULL;
- return i2c_verify_client(dev);
+ client = i2c_verify_client(dev);
+ if (!client)
+ put_device(dev);
+
+ return client;
}
EXPORT_SYMBOL(of_find_i2c_device_by_node);
@@ -1352,13 +1358,17 @@ EXPORT_SYMBOL(of_find_i2c_device_by_node);
struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
{
struct device *dev;
+ struct i2c_adapter *adapter;
- dev = bus_find_device(&i2c_bus_type, NULL, node,
- of_dev_node_match);
+ dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
if (!dev)
return NULL;
- return i2c_verify_adapter(dev);
+ adapter = i2c_verify_adapter(dev);
+ if (!adapter)
+ put_device(dev);
+
+ return adapter;
}
EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
#else
diff --git a/drivers/i2c/i2c-slave-eeprom.c b/drivers/i2c/i2c-slave-eeprom.c
index 8223746..1da4496 100644
--- a/drivers/i2c/i2c-slave-eeprom.c
+++ b/drivers/i2c/i2c-slave-eeprom.c
@@ -80,9 +80,6 @@ static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj
struct eeprom_data *eeprom;
unsigned long flags;
- if (off + count > attr->size)
- return -EFBIG;
-
eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
spin_lock_irqsave(&eeprom->buffer_lock, flags);
@@ -98,9 +95,6 @@ static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kob
struct eeprom_data *eeprom;
unsigned long flags;
- if (off + count > attr->size)
- return -EFBIG;
-
eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
spin_lock_irqsave(&eeprom->buffer_lock, flags);
diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
index c7aab48..92d5183 100644
--- a/drivers/infiniband/hw/cxgb4/cq.c
+++ b/drivers/infiniband/hw/cxgb4/cq.c
@@ -814,7 +814,7 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
printk(KERN_ERR MOD
"Unexpected cqe_status 0x%x for QPID=0x%0x\n",
CQE_STATUS(&cqe), CQE_QPID(&cqe));
- ret = -EINVAL;
+ wc->status = IB_WC_FATAL_ERR;
}
}
out:
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index 27b6a3c..891797a 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -196,7 +196,7 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
if (n_buttons[i] < 1)
continue;
- if (n_buttons[i] > 6) {
+ if (n_buttons[i] > ARRAY_SIZE(tgfx_buttons)) {
printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]);
err = -EINVAL;
goto err_unreg_devs;
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 097d721..c6dc644 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -246,7 +246,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
* convert it to descriptor.
*/
if (!button->gpiod && gpio_is_valid(button->gpio)) {
- unsigned flags = 0;
+ unsigned flags = GPIOF_IN;
if (button->active_low)
flags |= GPIOF_ACTIVE_LOW;
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
index 10e140a..1ac898d 100644
--- a/drivers/input/misc/axp20x-pek.c
+++ b/drivers/input/misc/axp20x-pek.c
@@ -292,3 +292,4 @@ module_platform_driver(axp20x_pek_driver);
MODULE_DESCRIPTION("axp20x Power Button");
MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:axp20x-pek");
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
index e5d60ec..f5c9cf2 100644
--- a/drivers/input/misc/drv260x.c
+++ b/drivers/input/misc/drv260x.c
@@ -313,14 +313,14 @@ static void drv260x_close(struct input_dev *input)
gpiod_set_value(haptics->enable_gpio, 0);
}
-static const struct reg_default drv260x_lra_cal_regs[] = {
+static const struct reg_sequence drv260x_lra_cal_regs[] = {
{ DRV260X_MODE, DRV260X_AUTO_CAL },
{ DRV260X_CTRL3, DRV260X_NG_THRESH_2 },
{ DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE |
DRV260X_BRAKE_FACTOR_4X | DRV260X_LOOP_GAIN_HIGH },
};
-static const struct reg_default drv260x_lra_init_regs[] = {
+static const struct reg_sequence drv260x_lra_init_regs[] = {
{ DRV260X_MODE, DRV260X_RT_PLAYBACK },
{ DRV260X_A_TO_V_CTRL, DRV260X_AUDIO_HAPTICS_PEAK_20MS |
DRV260X_AUDIO_HAPTICS_FILTER_125HZ },
@@ -337,7 +337,7 @@ static const struct reg_default drv260x_lra_init_regs[] = {
{ DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS },
};
-static const struct reg_default drv260x_erm_cal_regs[] = {
+static const struct reg_sequence drv260x_erm_cal_regs[] = {
{ DRV260X_MODE, DRV260X_AUTO_CAL },
{ DRV260X_A_TO_V_MIN_INPUT, DRV260X_AUDIO_HAPTICS_MIN_IN_VOLT },
{ DRV260X_A_TO_V_MAX_INPUT, DRV260X_AUDIO_HAPTICS_MAX_IN_VOLT },
diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c
index 0afaa33..924456e 100644
--- a/drivers/input/misc/drv2665.c
+++ b/drivers/input/misc/drv2665.c
@@ -132,7 +132,7 @@ static void drv2665_close(struct input_dev *input)
"Failed to enter standby mode: %d\n", error);
}
-static const struct reg_default drv2665_init_regs[] = {
+static const struct reg_sequence drv2665_init_regs[] = {
{ DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT },
{ DRV2665_CTRL_1, DRV2665_25_VPP_GAIN },
};
diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c
index fc0fddf..047136a 100644
--- a/drivers/input/misc/drv2667.c
+++ b/drivers/input/misc/drv2667.c
@@ -262,14 +262,14 @@ static void drv2667_close(struct input_dev *input)
"Failed to enter standby mode: %d\n", error);
}
-static const struct reg_default drv2667_init_regs[] = {
+static const struct reg_sequence drv2667_init_regs[] = {
{ DRV2667_CTRL_2, 0 },
{ DRV2667_CTRL_1, DRV2667_25_VPP_GAIN },
{ DRV2667_WV_SEQ_0, 1 },
{ DRV2667_WV_SEQ_1, 0 }
};
-static const struct reg_default drv2667_page1_init[] = {
+static const struct reg_sequence drv2667_page1_init[] = {
{ DRV2667_RAM_HDR_SZ, 0x05 },
{ DRV2667_RAM_START_HI, 0x80 },
{ DRV2667_RAM_START_LO, 0x06 },
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index fc17b95..10c4e3d 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -183,7 +183,8 @@ static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
if (pdata && pdata->coexist)
return true;
- if (of_find_node_by_name(node, "codec")) {
+ node = of_find_node_by_name(node, "codec");
+ if (node) {
of_node_put(node);
return true;
}
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 113d6f1..4d24686 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -20,6 +20,7 @@
#include <linux/input/mt.h>
#include <linux/serio.h>
#include <linux/libps2.h>
+#include <linux/dmi.h>
#include "psmouse.h"
#include "alps.h"
@@ -99,6 +100,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
6-byte ALPS packet */
+#define ALPS_DELL 0x100 /* device is a Dell laptop */
#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */
static const struct alps_model_info alps_model_data[] = {
@@ -251,9 +253,9 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
return;
}
- /* Non interleaved V2 dualpoint has separate stick button bits */
+ /* Dell non interleaved V2 dualpoint has separate stick button bits */
if (priv->proto_version == ALPS_PROTO_V2 &&
- priv->flags == (ALPS_PASS | ALPS_DUALPOINT)) {
+ priv->flags == (ALPS_DELL | ALPS_PASS | ALPS_DUALPOINT)) {
left |= packet[0] & 1;
right |= packet[0] & 2;
middle |= packet[0] & 4;
@@ -2550,6 +2552,8 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->byte0 = protocol->byte0;
priv->mask0 = protocol->mask0;
priv->flags = protocol->flags;
+ if (dmi_name_in_vendors("Dell"))
+ priv->flags |= ALPS_DELL;
priv->x_max = 2000;
priv->y_max = 1400;
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 22b9ca9..2955f1d 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -783,19 +783,26 @@ static int elantech_packet_check_v4(struct psmouse *psmouse)
struct elantech_data *etd = psmouse->private;
unsigned char *packet = psmouse->packet;
unsigned char packet_type = packet[3] & 0x03;
+ unsigned int ic_version;
bool sanity_check;
if (etd->tp_dev && (packet[3] & 0x0f) == 0x06)
return PACKET_TRACKPOINT;
+ /* This represents the version of IC body. */
+ ic_version = (etd->fw_version & 0x0f0000) >> 16;
+
/*
* Sanity check based on the constant bits of a packet.
* The constant bits change depending on the value of
- * the hardware flag 'crc_enabled' but are the same for
- * every packet, regardless of the type.
+ * the hardware flag 'crc_enabled' and the version of
+ * the IC body, but are the same for every packet,
+ * regardless of the type.
*/
if (etd->crc_enabled)
sanity_check = ((packet[3] & 0x08) == 0x00);
+ else if (ic_version == 7 && etd->samples[1] == 0x2A)
+ sanity_check = ((packet[3] & 0x1c) == 0x10);
else
sanity_check = ((packet[0] & 0x0c) == 0x04 &&
(packet[3] & 0x1c) == 0x10);
@@ -1116,6 +1123,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
* Avatar AVIU-145A2 0x361f00 ? clickpad
* Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons
* Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons
+ * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons
* Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**)
* Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons
* Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*)
@@ -1651,6 +1659,16 @@ int elantech_init(struct psmouse *psmouse)
etd->capabilities[0], etd->capabilities[1],
etd->capabilities[2]);
+ if (etd->hw_version != 1) {
+ if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, etd->samples)) {
+ psmouse_err(psmouse, "failed to query sample data\n");
+ goto init_fail;
+ }
+ psmouse_info(psmouse,
+ "Elan sample query result %02x, %02x, %02x\n",
+ etd->samples[0], etd->samples[1], etd->samples[2]);
+ }
+
if (elantech_set_absolute_mode(psmouse)) {
psmouse_err(psmouse,
"failed to put touchpad into absolute mode.\n");
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index f965d15..e1cbf40 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -129,6 +129,7 @@ struct elantech_data {
unsigned char reg_26;
unsigned char debug;
unsigned char capabilities[3];
+ unsigned char samples[3];
bool paritycheck;
bool jumpy_cursor;
bool reports_pressure;
diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c
index 692fe2b..c12bb93 100644
--- a/drivers/irqchip/irq-crossbar.c
+++ b/drivers/irqchip/irq-crossbar.c
@@ -68,7 +68,9 @@ static struct irq_chip crossbar_chip = {
.irq_mask = irq_chip_mask_parent,
.irq_unmask = irq_chip_unmask_parent,
.irq_retrigger = irq_chip_retrigger_hierarchy,
- .irq_set_wake = irq_chip_set_wake_parent,
+ .irq_set_type = irq_chip_set_type_parent,
+ .flags = IRQCHIP_MASK_ON_SUSPEND |
+ IRQCHIP_SKIP_SET_WAKE,
#ifdef CONFIG_SMP
.irq_set_affinity = irq_chip_set_affinity_parent,
#endif
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index b7d54d4..ff4be05 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -538,7 +538,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
{
- smp_call_function_interrupt();
+ generic_smp_call_function_interrupt();
return IRQ_HANDLED;
}
diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c
index 3281437..aa1b41c 100644
--- a/drivers/md/dm-cache-policy-mq.c
+++ b/drivers/md/dm-cache-policy-mq.c
@@ -1471,5 +1471,3 @@ module_exit(mq_exit);
MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("mq cache policy");
-
-MODULE_ALIAS("dm-cache-default");
diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c
index 48a4a82..200366c 100644
--- a/drivers/md/dm-cache-policy-smq.c
+++ b/drivers/md/dm-cache-policy-smq.c
@@ -1789,3 +1789,5 @@ module_exit(smq_exit);
MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("smq cache policy");
+
+MODULE_ALIAS("dm-cache-default");
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 48dfe3c..6ba47cf 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -1293,8 +1293,8 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd)
return r;
disk_super = dm_block_data(copy);
- dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->data_mapping_root));
- dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->device_details_root));
+ dm_btree_del(&pmd->info, le64_to_cpu(disk_super->data_mapping_root));
+ dm_btree_del(&pmd->details_info, le64_to_cpu(disk_super->device_details_root));
dm_sm_dec_block(pmd->metadata_sm, held_root);
return dm_tm_unlock(pmd->tm, copy);
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index ab37ae1..0d7ab20 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1729,7 +1729,8 @@ static int dm_merge_bvec(struct request_queue *q,
struct mapped_device *md = q->queuedata;
struct dm_table *map = dm_get_live_table_fast(md);
struct dm_target *ti;
- sector_t max_sectors, max_size = 0;
+ sector_t max_sectors;
+ int max_size = 0;
if (unlikely(!map))
goto out;
@@ -1742,18 +1743,10 @@ static int dm_merge_bvec(struct request_queue *q,
* Find maximum amount of I/O that won't need splitting
*/
max_sectors = min(max_io_len(bvm->bi_sector, ti),
- (sector_t) queue_max_sectors(q));
+ (sector_t) BIO_MAX_SECTORS);
max_size = (max_sectors << SECTOR_SHIFT) - bvm->bi_size;
-
- /*
- * FIXME: this stop-gap fix _must_ be cleaned up (by passing a sector_t
- * to the targets' merge function since it holds sectors not bytes).
- * Just doing this as an interim fix for stable@ because the more
- * comprehensive cleanup of switching to sector_t will impact every
- * DM target that implements a ->merge hook.
- */
- if (max_size > INT_MAX)
- max_size = INT_MAX;
+ if (max_size < 0)
+ max_size = 0;
/*
* merge_bvec_fn() returns number of bytes
@@ -1761,13 +1754,13 @@ static int dm_merge_bvec(struct request_queue *q,
* max is precomputed maximal io size
*/
if (max_size && ti->type->merge)
- max_size = ti->type->merge(ti, bvm, biovec, (int) max_size);
+ max_size = ti->type->merge(ti, bvm, biovec, max_size);
/*
* If the target doesn't support merge method and some of the devices
- * provided their merge_bvec method (we know this by looking for the
- * max_hw_sectors that dm_set_device_limits may set), then we can't
- * allow bios with multiple vector entries. So always set max_size
- * to 0, and the code below allows just one page.
+ * provided their merge_bvec method (we know this by looking at
+ * queue_max_hw_sectors), then we can't allow bios with multiple vector
+ * entries. So always set max_size to 0, and the code below allows
+ * just one page.
*/
else if (queue_max_hw_sectors(q) <= PAGE_SIZE >> 9)
max_size = 0;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 0c2a4e8..e25f00f 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -5759,7 +5759,7 @@ static int get_bitmap_file(struct mddev *mddev, void __user * arg)
char *ptr;
int err;
- file = kmalloc(sizeof(*file), GFP_NOIO);
+ file = kzalloc(sizeof(*file), GFP_NOIO);
if (!file)
return -ENOMEM;
diff --git a/drivers/md/persistent-data/dm-btree-internal.h b/drivers/md/persistent-data/dm-btree-internal.h
index bf2b80d..8731b6e 100644
--- a/drivers/md/persistent-data/dm-btree-internal.h
+++ b/drivers/md/persistent-data/dm-btree-internal.h
@@ -138,4 +138,10 @@ int lower_bound(struct btree_node *n, uint64_t key);
extern struct dm_block_validator btree_node_validator;
+/*
+ * Value type for upper levels of multi-level btrees.
+ */
+extern void init_le64_type(struct dm_transaction_manager *tm,
+ struct dm_btree_value_type *vt);
+
#endif /* DM_BTREE_INTERNAL_H */
diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c
index 9836c0a..4222f77 100644
--- a/drivers/md/persistent-data/dm-btree-remove.c
+++ b/drivers/md/persistent-data/dm-btree-remove.c
@@ -544,14 +544,6 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info,
return r;
}
-static struct dm_btree_value_type le64_type = {
- .context = NULL,
- .size = sizeof(__le64),
- .inc = NULL,
- .dec = NULL,
- .equal = NULL
-};
-
int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, dm_block_t *new_root)
{
@@ -559,12 +551,14 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
int index = 0, r = 0;
struct shadow_spine spine;
struct btree_node *n;
+ struct dm_btree_value_type le64_vt;
+ init_le64_type(info->tm, &le64_vt);
init_shadow_spine(&spine, info);
for (level = 0; level < info->levels; level++) {
r = remove_raw(&spine, info,
(level == last_level ?
- &info->value_type : &le64_type),
+ &info->value_type : &le64_vt),
root, keys[level], (unsigned *)&index);
if (r < 0)
break;
@@ -654,11 +648,13 @@ static int remove_one(struct dm_btree_info *info, dm_block_t root,
int index = 0, r = 0;
struct shadow_spine spine;
struct btree_node *n;
+ struct dm_btree_value_type le64_vt;
uint64_t k;
+ init_le64_type(info->tm, &le64_vt);
init_shadow_spine(&spine, info);
for (level = 0; level < last_level; level++) {
- r = remove_raw(&spine, info, &le64_type,
+ r = remove_raw(&spine, info, &le64_vt,
root, keys[level], (unsigned *) &index);
if (r < 0)
goto out;
@@ -689,6 +685,7 @@ static int remove_one(struct dm_btree_info *info, dm_block_t root,
value_ptr(n, index));
delete_at(n, index);
+ keys[last_level] = k + 1ull;
} else
r = -ENODATA;
diff --git a/drivers/md/persistent-data/dm-btree-spine.c b/drivers/md/persistent-data/dm-btree-spine.c
index 1b5e13e..0dee514 100644
--- a/drivers/md/persistent-data/dm-btree-spine.c
+++ b/drivers/md/persistent-data/dm-btree-spine.c
@@ -249,3 +249,40 @@ int shadow_root(struct shadow_spine *s)
{
return s->root;
}
+
+static void le64_inc(void *context, const void *value_le)
+{
+ struct dm_transaction_manager *tm = context;
+ __le64 v_le;
+
+ memcpy(&v_le, value_le, sizeof(v_le));
+ dm_tm_inc(tm, le64_to_cpu(v_le));
+}
+
+static void le64_dec(void *context, const void *value_le)
+{
+ struct dm_transaction_manager *tm = context;
+ __le64 v_le;
+
+ memcpy(&v_le, value_le, sizeof(v_le));
+ dm_tm_dec(tm, le64_to_cpu(v_le));
+}
+
+static int le64_equal(void *context, const void *value1_le, const void *value2_le)
+{
+ __le64 v1_le, v2_le;
+
+ memcpy(&v1_le, value1_le, sizeof(v1_le));
+ memcpy(&v2_le, value2_le, sizeof(v2_le));
+ return v1_le == v2_le;
+}
+
+void init_le64_type(struct dm_transaction_manager *tm,
+ struct dm_btree_value_type *vt)
+{
+ vt->context = tm;
+ vt->size = sizeof(__le64);
+ vt->inc = le64_inc;
+ vt->dec = le64_dec;
+ vt->equal = le64_equal;
+}
diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c
index fdd3793..c7726ce 100644
--- a/drivers/md/persistent-data/dm-btree.c
+++ b/drivers/md/persistent-data/dm-btree.c
@@ -667,12 +667,7 @@ static int insert(struct dm_btree_info *info, dm_block_t root,
struct btree_node *n;
struct dm_btree_value_type le64_type;
- le64_type.context = NULL;
- le64_type.size = sizeof(__le64);
- le64_type.inc = NULL;
- le64_type.dec = NULL;
- le64_type.equal = NULL;
-
+ init_le64_type(info->tm, &le64_type);
init_shadow_spine(&spine, info);
for (level = 0; level < (info->levels - 1); level++) {
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 94f5b55..967a4ed 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1476,6 +1476,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
{
char b[BDEVNAME_SIZE];
struct r1conf *conf = mddev->private;
+ unsigned long flags;
/*
* If it is not operational, then we have already marked it as dead
@@ -1495,14 +1496,13 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
return;
}
set_bit(Blocked, &rdev->flags);
+ spin_lock_irqsave(&conf->device_lock, flags);
if (test_and_clear_bit(In_sync, &rdev->flags)) {
- unsigned long flags;
- spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded++;
set_bit(Faulty, &rdev->flags);
- spin_unlock_irqrestore(&conf->device_lock, flags);
} else
set_bit(Faulty, &rdev->flags);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
/*
* if recovery is running, make sure it aborts.
*/
@@ -1568,7 +1568,10 @@ static int raid1_spare_active(struct mddev *mddev)
* Find all failed disks within the RAID1 configuration
* and mark them readable.
* Called under mddev lock, so rcu protection not needed.
+ * device_lock used to avoid races with raid1_end_read_request
+ * which expects 'In_sync' flags and ->degraded to be consistent.
*/
+ spin_lock_irqsave(&conf->device_lock, flags);
for (i = 0; i < conf->raid_disks; i++) {
struct md_rdev *rdev = conf->mirrors[i].rdev;
struct md_rdev *repl = conf->mirrors[conf->raid_disks + i].rdev;
@@ -1599,7 +1602,6 @@ static int raid1_spare_active(struct mddev *mddev)
sysfs_notify_dirent_safe(rdev->sysfs_state);
}
}
- spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded -= count;
spin_unlock_irqrestore(&conf->device_lock, flags);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 643d217..f757023 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2256,7 +2256,7 @@ static int resize_stripes(struct r5conf *conf, int newsize)
static int drop_one_stripe(struct r5conf *conf)
{
struct stripe_head *sh;
- int hash = (conf->max_nr_stripes - 1) % NR_STRIPE_HASH_LOCKS;
+ int hash = (conf->max_nr_stripes - 1) & STRIPE_HASH_LOCKS_MASK;
spin_lock_irq(conf->hash_locks + hash);
sh = get_free_stripe(conf, hash);
@@ -6388,7 +6388,8 @@ static unsigned long raid5_cache_scan(struct shrinker *shrink,
if (mutex_trylock(&conf->cache_size_mutex)) {
ret= 0;
- while (ret < sc->nr_to_scan) {
+ while (ret < sc->nr_to_scan &&
+ conf->max_nr_stripes > conf->min_nr_stripes) {
if (drop_one_stripe(conf) == 0) {
ret = SHRINK_STOP;
break;
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 0d35f58..5ab90f3 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -240,7 +240,7 @@ config DVB_SI21XX
config DVB_TS2020
tristate "Montage Tehnology TS2020 based tuners"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
select REGMAP_I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig
index 3be1b2c..6a1c008 100644
--- a/drivers/media/pci/cobalt/Kconfig
+++ b/drivers/media/pci/cobalt/Kconfig
@@ -2,6 +2,7 @@ config VIDEO_COBALT
tristate "Cisco Cobalt support"
depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER
depends on PCI_MSI && MTD_COMPLEX_MAPPINGS && GPIOLIB
+ depends on SND
select I2C_ALGOBIT
select VIDEO_ADV7604
select VIDEO_ADV7511
diff --git a/drivers/media/pci/cobalt/cobalt-irq.c b/drivers/media/pci/cobalt/cobalt-irq.c
index dd4bff9..d1f5898 100644
--- a/drivers/media/pci/cobalt/cobalt-irq.c
+++ b/drivers/media/pci/cobalt/cobalt-irq.c
@@ -139,7 +139,7 @@ done:
also know about dropped frames. */
cb->vb.v4l2_buf.sequence = s->sequence++;
vb2_buffer_done(&cb->vb, (skip || s->unstable_frame) ?
- VB2_BUF_STATE_QUEUED : VB2_BUF_STATE_DONE);
+ VB2_BUF_STATE_REQUEUEING : VB2_BUF_STATE_DONE);
}
irqreturn_t cobalt_irq_handler(int irq, void *dev_id)
diff --git a/drivers/media/pci/mantis/mantis_dma.c b/drivers/media/pci/mantis/mantis_dma.c
index 1d59c7e..87990ec 100644
--- a/drivers/media/pci/mantis/mantis_dma.c
+++ b/drivers/media/pci/mantis/mantis_dma.c
@@ -130,10 +130,11 @@ err:
int mantis_dma_init(struct mantis_pci *mantis)
{
- int err = 0;
+ int err;
dprintk(MANTIS_DEBUG, 1, "Mantis DMA init");
- if (mantis_alloc_buffers(mantis) < 0) {
+ err = mantis_alloc_buffers(mantis);
+ if (err < 0) {
dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer");
/* Stop RISC Engine */
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 8939ebd..84fa6e9 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -184,125 +184,9 @@ out:
return -EINVAL;
}
-static struct ir_raw_timings_manchester ir_rc5_timings = {
- .leader = RC5_UNIT,
- .pulse_space_start = 0,
- .clock = RC5_UNIT,
- .trailer_space = RC5_UNIT * 10,
-};
-
-static struct ir_raw_timings_manchester ir_rc5x_timings[2] = {
- {
- .leader = RC5_UNIT,
- .pulse_space_start = 0,
- .clock = RC5_UNIT,
- .trailer_space = RC5X_SPACE,
- },
- {
- .clock = RC5_UNIT,
- .trailer_space = RC5_UNIT * 10,
- },
-};
-
-static struct ir_raw_timings_manchester ir_rc5_sz_timings = {
- .leader = RC5_UNIT,
- .pulse_space_start = 0,
- .clock = RC5_UNIT,
- .trailer_space = RC5_UNIT * 10,
-};
-
-static int ir_rc5_validate_filter(const struct rc_scancode_filter *scancode,
- unsigned int important_bits)
-{
- /* all important bits of scancode should be set in mask */
- if (~scancode->mask & important_bits)
- return -EINVAL;
- /* extra bits in mask should be zero in data */
- if (scancode->mask & scancode->data & ~important_bits)
- return -EINVAL;
- return 0;
-}
-
-/**
- * ir_rc5_encode() - Encode a scancode as a stream of raw events
- *
- * @protocols: allowed protocols
- * @scancode: scancode filter describing scancode (helps distinguish between
- * protocol subtypes when scancode is ambiguous)
- * @events: array of raw ir events to write into
- * @max: maximum size of @events
- *
- * Returns: The number of events written.
- * -ENOBUFS if there isn't enough space in the array to fit the
- * encoding. In this case all @max events will have been written.
- * -EINVAL if the scancode is ambiguous or invalid.
- */
-static int ir_rc5_encode(u64 protocols,
- const struct rc_scancode_filter *scancode,
- struct ir_raw_event *events, unsigned int max)
-{
- int ret;
- struct ir_raw_event *e = events;
- unsigned int data, xdata, command, commandx, system;
-
- /* Detect protocol and convert scancode to raw data */
- if (protocols & RC_BIT_RC5 &&
- !ir_rc5_validate_filter(scancode, 0x1f7f)) {
- /* decode scancode */
- command = (scancode->data & 0x003f) >> 0;
- commandx = (scancode->data & 0x0040) >> 6;
- system = (scancode->data & 0x1f00) >> 8;
- /* encode data */
- data = !commandx << 12 | system << 6 | command;
-
- /* Modulate the data */
- ret = ir_raw_gen_manchester(&e, max, &ir_rc5_timings, RC5_NBITS,
- data);
- if (ret < 0)
- return ret;
- } else if (protocols & RC_BIT_RC5X &&
- !ir_rc5_validate_filter(scancode, 0x1f7f3f)) {
- /* decode scancode */
- xdata = (scancode->data & 0x00003f) >> 0;
- command = (scancode->data & 0x003f00) >> 8;
- commandx = (scancode->data & 0x004000) >> 14;
- system = (scancode->data & 0x1f0000) >> 16;
- /* commandx and system overlap, bits must match when encoded */
- if (commandx == (system & 0x1))
- return -EINVAL;
- /* encode data */
- data = 1 << 18 | system << 12 | command << 6 | xdata;
-
- /* Modulate the data */
- ret = ir_raw_gen_manchester(&e, max, &ir_rc5x_timings[0],
- CHECK_RC5X_NBITS,
- data >> (RC5X_NBITS-CHECK_RC5X_NBITS));
- if (ret < 0)
- return ret;
- ret = ir_raw_gen_manchester(&e, max - (e - events),
- &ir_rc5x_timings[1],
- RC5X_NBITS - CHECK_RC5X_NBITS,
- data);
- if (ret < 0)
- return ret;
- } else if (protocols & RC_BIT_RC5_SZ &&
- !ir_rc5_validate_filter(scancode, 0x2fff)) {
- /* RC5-SZ scancode is raw enough for Manchester as it is */
- ret = ir_raw_gen_manchester(&e, max, &ir_rc5_sz_timings,
- RC5_SZ_NBITS, scancode->data & 0x2fff);
- if (ret < 0)
- return ret;
- } else {
- return -EINVAL;
- }
-
- return e - events;
-}
-
static struct ir_raw_handler rc5_handler = {
.protocols = RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ,
.decode = ir_rc5_decode,
- .encode = ir_rc5_encode,
};
static int __init ir_rc5_decode_init(void)
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index f9c70ba..d16bc67 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -291,133 +291,11 @@ out:
return -EINVAL;
}
-static struct ir_raw_timings_manchester ir_rc6_timings[4] = {
- {
- .leader = RC6_PREFIX_PULSE,
- .pulse_space_start = 0,
- .clock = RC6_UNIT,
- .invert = 1,
- .trailer_space = RC6_PREFIX_SPACE,
- },
- {
- .clock = RC6_UNIT,
- .invert = 1,
- },
- {
- .clock = RC6_UNIT * 2,
- .invert = 1,
- },
- {
- .clock = RC6_UNIT,
- .invert = 1,
- .trailer_space = RC6_SUFFIX_SPACE,
- },
-};
-
-static int ir_rc6_validate_filter(const struct rc_scancode_filter *scancode,
- unsigned int important_bits)
-{
- /* all important bits of scancode should be set in mask */
- if (~scancode->mask & important_bits)
- return -EINVAL;
- /* extra bits in mask should be zero in data */
- if (scancode->mask & scancode->data & ~important_bits)
- return -EINVAL;
- return 0;
-}
-
-/**
- * ir_rc6_encode() - Encode a scancode as a stream of raw events
- *
- * @protocols: allowed protocols
- * @scancode: scancode filter describing scancode (helps distinguish between
- * protocol subtypes when scancode is ambiguous)
- * @events: array of raw ir events to write into
- * @max: maximum size of @events
- *
- * Returns: The number of events written.
- * -ENOBUFS if there isn't enough space in the array to fit the
- * encoding. In this case all @max events will have been written.
- * -EINVAL if the scancode is ambiguous or invalid.
- */
-static int ir_rc6_encode(u64 protocols,
- const struct rc_scancode_filter *scancode,
- struct ir_raw_event *events, unsigned int max)
-{
- int ret;
- struct ir_raw_event *e = events;
-
- if (protocols & RC_BIT_RC6_0 &&
- !ir_rc6_validate_filter(scancode, 0xffff)) {
-
- /* Modulate the preamble */
- ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0);
- if (ret < 0)
- return ret;
-
- /* Modulate the header (Start Bit & Mode-0) */
- ret = ir_raw_gen_manchester(&e, max - (e - events),
- &ir_rc6_timings[1],
- RC6_HEADER_NBITS, (1 << 3));
- if (ret < 0)
- return ret;
-
- /* Modulate Trailer Bit */
- ret = ir_raw_gen_manchester(&e, max - (e - events),
- &ir_rc6_timings[2], 1, 0);
- if (ret < 0)
- return ret;
-
- /* Modulate rest of the data */
- ret = ir_raw_gen_manchester(&e, max - (e - events),
- &ir_rc6_timings[3], RC6_0_NBITS,
- scancode->data);
- if (ret < 0)
- return ret;
-
- } else if (protocols & (RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
- RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE) &&
- !ir_rc6_validate_filter(scancode, 0x8fffffff)) {
-
- /* Modulate the preamble */
- ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0);
- if (ret < 0)
- return ret;
-
- /* Modulate the header (Start Bit & Header-version 6 */
- ret = ir_raw_gen_manchester(&e, max - (e - events),
- &ir_rc6_timings[1],
- RC6_HEADER_NBITS, (1 << 3 | 6));
- if (ret < 0)
- return ret;
-
- /* Modulate Trailer Bit */
- ret = ir_raw_gen_manchester(&e, max - (e - events),
- &ir_rc6_timings[2], 1, 0);
- if (ret < 0)
- return ret;
-
- /* Modulate rest of the data */
- ret = ir_raw_gen_manchester(&e, max - (e - events),
- &ir_rc6_timings[3],
- fls(scancode->mask),
- scancode->data);
- if (ret < 0)
- return ret;
-
- } else {
- return -EINVAL;
- }
-
- return e - events;
-}
-
static struct ir_raw_handler rc6_handler = {
.protocols = RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 |
RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 |
RC_BIT_RC6_MCE,
.decode = ir_rc6_decode,
- .encode = ir_rc6_encode,
};
static int __init ir_rc6_decode_init(void)
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index baeb597..85af7a8 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -526,130 +526,6 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
return 0;
}
-static int nvt_write_wakeup_codes(struct rc_dev *dev,
- const u8 *wakeup_sample_buf, int count)
-{
- int i = 0;
- u8 reg, reg_learn_mode;
- unsigned long flags;
- struct nvt_dev *nvt = dev->priv;
-
- nvt_dbg_wake("writing wakeup samples");
-
- reg = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
- reg_learn_mode = reg & ~CIR_WAKE_IRCON_MODE0;
- reg_learn_mode |= CIR_WAKE_IRCON_MODE1;
-
- /* Lock the learn area to prevent racing with wake-isr */
- spin_lock_irqsave(&nvt->nvt_lock, flags);
-
- /* Enable fifo writes */
- nvt_cir_wake_reg_write(nvt, reg_learn_mode, CIR_WAKE_IRCON);
-
- /* Clear cir wake rx fifo */
- nvt_clear_cir_wake_fifo(nvt);
-
- if (count > WAKE_FIFO_LEN) {
- nvt_dbg_wake("HW FIFO too small for all wake samples");
- count = WAKE_FIFO_LEN;
- }
-
- if (count)
- pr_info("Wake samples (%d) =", count);
- else
- pr_info("Wake sample fifo cleared");
-
- /* Write wake samples to fifo */
- for (i = 0; i < count; i++) {
- pr_cont(" %02x", wakeup_sample_buf[i]);
- nvt_cir_wake_reg_write(nvt, wakeup_sample_buf[i],
- CIR_WAKE_WR_FIFO_DATA);
- }
- pr_cont("\n");
-
- /* Switch cir to wakeup mode and disable fifo writing */
- nvt_cir_wake_reg_write(nvt, reg, CIR_WAKE_IRCON);
-
- /* Set number of bytes needed for wake */
- nvt_cir_wake_reg_write(nvt, count ? count :
- CIR_WAKE_FIFO_CMP_BYTES,
- CIR_WAKE_FIFO_CMP_DEEP);
-
- spin_unlock_irqrestore(&nvt->nvt_lock, flags);
-
- return 0;
-}
-
-static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev,
- struct rc_scancode_filter *sc_filter)
-{
- u8 *reg_buf;
- u8 buf_val;
- int i, ret, count;
- unsigned int val;
- struct ir_raw_event *raw;
- bool complete;
-
- /* Require both mask and data to be set before actually committing */
- if (!sc_filter->mask || !sc_filter->data)
- return 0;
-
- raw = kmalloc_array(WAKE_FIFO_LEN, sizeof(*raw), GFP_KERNEL);
- if (!raw)
- return -ENOMEM;
-
- ret = ir_raw_encode_scancode(dev->enabled_wakeup_protocols, sc_filter,
- raw, WAKE_FIFO_LEN);
- complete = (ret != -ENOBUFS);
- if (!complete)
- ret = WAKE_FIFO_LEN;
- else if (ret < 0)
- goto out_raw;
-
- reg_buf = kmalloc_array(WAKE_FIFO_LEN, sizeof(*reg_buf), GFP_KERNEL);
- if (!reg_buf) {
- ret = -ENOMEM;
- goto out_raw;
- }
-
- /* Inspect the ir samples */
- for (i = 0, count = 0; i < ret && count < WAKE_FIFO_LEN; ++i) {
- val = NS_TO_US((raw[i]).duration) / SAMPLE_PERIOD;
-
- /* Split too large values into several smaller ones */
- while (val > 0 && count < WAKE_FIFO_LEN) {
-
- /* Skip last value for better comparison tolerance */
- if (complete && i == ret - 1 && val < BUF_LEN_MASK)
- break;
-
- /* Clamp values to BUF_LEN_MASK at most */
- buf_val = (val > BUF_LEN_MASK) ? BUF_LEN_MASK : val;
-
- reg_buf[count] = buf_val;
- val -= buf_val;
- if ((raw[i]).pulse)
- reg_buf[count] |= BUF_PULSE_BIT;
- count++;
- }
- }
-
- ret = nvt_write_wakeup_codes(dev, reg_buf, count);
-
- kfree(reg_buf);
-out_raw:
- kfree(raw);
-
- return ret;
-}
-
-/* Dummy implementation. nuvoton is agnostic to the protocol used */
-static int nvt_ir_raw_change_wakeup_protocol(struct rc_dev *dev,
- u64 *rc_type)
-{
- return 0;
-}
-
/*
* nvt_tx_ir
*
@@ -1167,14 +1043,11 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
/* Set up the rc device */
rdev->priv = nvt;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->encode_wakeup = true;
rdev->allowed_protocols = RC_BIT_ALL;
rdev->open = nvt_open;
rdev->close = nvt_close;
rdev->tx_ir = nvt_tx_ir;
rdev->s_tx_carrier = nvt_set_tx_carrier;
- rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_filter;
- rdev->change_wakeup_protocol = nvt_ir_raw_change_wakeup_protocol;
rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
rdev->input_phys = "nuvoton/cir0";
rdev->input_id.bustype = BUS_HOST;
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index 9d0e161..e1cf23c 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -63,7 +63,6 @@ static int debug;
*/
#define TX_BUF_LEN 256
#define RX_BUF_LEN 32
-#define WAKE_FIFO_LEN 67
struct nvt_dev {
struct pnp_dev *pdev;
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 4b994aa..b68d4f76 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -25,8 +25,6 @@ struct ir_raw_handler {
u64 protocols; /* which are handled by this handler */
int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
- int (*encode)(u64 protocols, const struct rc_scancode_filter *scancode,
- struct ir_raw_event *events, unsigned int max);
/* These two should only be used by the lirc decoder */
int (*raw_register)(struct rc_dev *dev);
@@ -152,44 +150,10 @@ static inline bool is_timing_event(struct ir_raw_event ev)
#define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000)
#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space")
-/* functions for IR encoders */
-
-static inline void init_ir_raw_event_duration(struct ir_raw_event *ev,
- unsigned int pulse,
- u32 duration)
-{
- init_ir_raw_event(ev);
- ev->duration = duration;
- ev->pulse = pulse;
-}
-
-/**
- * struct ir_raw_timings_manchester - Manchester coding timings
- * @leader: duration of leader pulse (if any) 0 if continuing
- * existing signal (see @pulse_space_start)
- * @pulse_space_start: 1 for starting with pulse (0 for starting with space)
- * @clock: duration of each pulse/space in ns
- * @invert: if set clock logic is inverted
- * (0 = space + pulse, 1 = pulse + space)
- * @trailer_space: duration of trailer space in ns
- */
-struct ir_raw_timings_manchester {
- unsigned int leader;
- unsigned int pulse_space_start:1;
- unsigned int clock;
- unsigned int invert:1;
- unsigned int trailer_space;
-};
-
-int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
- const struct ir_raw_timings_manchester *timings,
- unsigned int n, unsigned int data);
-
/*
* Routines from rc-raw.c to be used internally and by decoders
*/
u64 ir_raw_get_allowed_protocols(void);
-u64 ir_raw_get_encode_protocols(void);
int ir_raw_event_register(struct rc_dev *dev);
void ir_raw_event_unregister(struct rc_dev *dev);
int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index b9e4645..b732ac6 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -30,7 +30,6 @@ static LIST_HEAD(ir_raw_client_list);
static DEFINE_MUTEX(ir_raw_handler_lock);
static LIST_HEAD(ir_raw_handler_list);
static u64 available_protocols;
-static u64 encode_protocols;
static int ir_raw_event_thread(void *data)
{
@@ -241,146 +240,12 @@ ir_raw_get_allowed_protocols(void)
return protocols;
}
-/* used internally by the sysfs interface */
-u64
-ir_raw_get_encode_protocols(void)
-{
- u64 protocols;
-
- mutex_lock(&ir_raw_handler_lock);
- protocols = encode_protocols;
- mutex_unlock(&ir_raw_handler_lock);
- return protocols;
-}
-
static int change_protocol(struct rc_dev *dev, u64 *rc_type)
{
/* the caller will update dev->enabled_protocols */
return 0;
}
-/**
- * ir_raw_gen_manchester() - Encode data with Manchester (bi-phase) modulation.
- * @ev: Pointer to pointer to next free event. *@ev is incremented for
- * each raw event filled.
- * @max: Maximum number of raw events to fill.
- * @timings: Manchester modulation timings.
- * @n: Number of bits of data.
- * @data: Data bits to encode.
- *
- * Encodes the @n least significant bits of @data using Manchester (bi-phase)
- * modulation with the timing characteristics described by @timings, writing up
- * to @max raw IR events using the *@ev pointer.
- *
- * Returns: 0 on success.
- * -ENOBUFS if there isn't enough space in the array to fit the
- * full encoded data. In this case all @max events will have been
- * written.
- */
-int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
- const struct ir_raw_timings_manchester *timings,
- unsigned int n, unsigned int data)
-{
- bool need_pulse;
- unsigned int i;
- int ret = -ENOBUFS;
-
- i = 1 << (n - 1);
-
- if (timings->leader) {
- if (!max--)
- return ret;
- if (timings->pulse_space_start) {
- init_ir_raw_event_duration((*ev)++, 1, timings->leader);
-
- if (!max--)
- return ret;
- init_ir_raw_event_duration((*ev), 0, timings->leader);
- } else {
- init_ir_raw_event_duration((*ev), 1, timings->leader);
- }
- i >>= 1;
- } else {
- /* continue existing signal */
- --(*ev);
- }
- /* from here on *ev will point to the last event rather than the next */
-
- while (n && i > 0) {
- need_pulse = !(data & i);
- if (timings->invert)
- need_pulse = !need_pulse;
- if (need_pulse == !!(*ev)->pulse) {
- (*ev)->duration += timings->clock;
- } else {
- if (!max--)
- goto nobufs;
- init_ir_raw_event_duration(++(*ev), need_pulse,
- timings->clock);
- }
-
- if (!max--)
- goto nobufs;
- init_ir_raw_event_duration(++(*ev), !need_pulse,
- timings->clock);
- i >>= 1;
- }
-
- if (timings->trailer_space) {
- if (!(*ev)->pulse)
- (*ev)->duration += timings->trailer_space;
- else if (!max--)
- goto nobufs;
- else
- init_ir_raw_event_duration(++(*ev), 0,
- timings->trailer_space);
- }
-
- ret = 0;
-nobufs:
- /* point to the next event rather than last event before returning */
- ++(*ev);
- return ret;
-}
-EXPORT_SYMBOL(ir_raw_gen_manchester);
-
-/**
- * ir_raw_encode_scancode() - Encode a scancode as raw events
- *
- * @protocols: permitted protocols
- * @scancode: scancode filter describing a single scancode
- * @events: array of raw events to write into
- * @max: max number of raw events
- *
- * Attempts to encode the scancode as raw events.
- *
- * Returns: The number of events written.
- * -ENOBUFS if there isn't enough space in the array to fit the
- * encoding. In this case all @max events will have been written.
- * -EINVAL if the scancode is ambiguous or invalid, or if no
- * compatible encoder was found.
- */
-int ir_raw_encode_scancode(u64 protocols,
- const struct rc_scancode_filter *scancode,
- struct ir_raw_event *events, unsigned int max)
-{
- struct ir_raw_handler *handler;
- int ret = -EINVAL;
-
- mutex_lock(&ir_raw_handler_lock);
- list_for_each_entry(handler, &ir_raw_handler_list, list) {
- if (handler->protocols & protocols && handler->encode) {
- ret = handler->encode(protocols, scancode, events, max);
- if (ret >= 0 || ret == -ENOBUFS)
- break;
- }
- }
- mutex_unlock(&ir_raw_handler_lock);
-
- return ret;
-}
-EXPORT_SYMBOL(ir_raw_encode_scancode);
-
/*
* Used to (un)register raw event clients
*/
@@ -463,8 +328,6 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
list_for_each_entry(raw, &ir_raw_client_list, list)
ir_raw_handler->raw_register(raw->dev);
available_protocols |= ir_raw_handler->protocols;
- if (ir_raw_handler->encode)
- encode_protocols |= ir_raw_handler->protocols;
mutex_unlock(&ir_raw_handler_lock);
return 0;
@@ -481,8 +344,6 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
list_for_each_entry(raw, &ir_raw_client_list, list)
ir_raw_handler->raw_unregister(raw->dev);
available_protocols &= ~ir_raw_handler->protocols;
- if (ir_raw_handler->encode)
- encode_protocols &= ~ir_raw_handler->protocols;
mutex_unlock(&ir_raw_handler_lock);
}
EXPORT_SYMBOL(ir_raw_handler_unregister);
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index d8bdf63..63dace8 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -26,7 +26,6 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/sched.h>
-#include <linux/slab.h>
#include <media/rc-core.h>
#define DRIVER_NAME "rc-loopback"
@@ -177,39 +176,6 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable)
return 0;
}
-static int loop_set_wakeup_filter(struct rc_dev *dev,
- struct rc_scancode_filter *sc_filter)
-{
- static const unsigned int max = 512;
- struct ir_raw_event *raw;
- int ret;
- int i;
-
- /* fine to disable filter */
- if (!sc_filter->mask)
- return 0;
-
- /* encode the specified filter and loop it back */
- raw = kmalloc_array(max, sizeof(*raw), GFP_KERNEL);
- ret = ir_raw_encode_scancode(dev->enabled_wakeup_protocols, sc_filter,
- raw, max);
- /* still loop back the partial raw IR even if it's incomplete */
- if (ret == -ENOBUFS)
- ret = max;
- if (ret >= 0) {
- /* do the loopback */
- for (i = 0; i < ret; ++i)
- ir_raw_event_store(dev, &raw[i]);
- ir_raw_event_handle(dev);
-
- ret = 0;
- }
-
- kfree(raw);
-
- return ret;
-}
-
static int __init loop_init(void)
{
struct rc_dev *rc;
@@ -229,7 +195,6 @@ static int __init loop_init(void)
rc->map_name = RC_MAP_EMPTY;
rc->priv = &loopdev;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc->encode_wakeup = true;
rc->allowed_protocols = RC_BIT_ALL;
rc->timeout = 100 * 1000 * 1000; /* 100 ms */
rc->min_timeout = 1;
@@ -244,7 +209,6 @@ static int __init loop_init(void)
rc->s_idle = loop_set_idle;
rc->s_learning_mode = loop_set_learning_mode;
rc->s_carrier_report = loop_set_carrier_report;
- rc->s_wakeup_filter = loop_set_wakeup_filter;
loopdev.txmask = RXMASK_REGULAR;
loopdev.txcarrier = 36000;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 9d015db..0ff388a 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -865,8 +865,6 @@ static ssize_t show_protocols(struct device *device,
} else {
enabled = dev->enabled_wakeup_protocols;
allowed = dev->allowed_wakeup_protocols;
- if (dev->encode_wakeup && !allowed)
- allowed = ir_raw_get_encode_protocols();
}
mutex_unlock(&dev->lock);
@@ -1408,16 +1406,13 @@ int rc_register_device(struct rc_dev *dev)
path ? path : "N/A");
kfree(path);
- if (dev->driver_type == RC_DRIVER_IR_RAW || dev->encode_wakeup) {
+ if (dev->driver_type == RC_DRIVER_IR_RAW) {
/* Load raw decoders, if they aren't already */
if (!raw_init) {
IR_dprintk(1, "Loading raw decoders\n");
ir_raw_init();
raw_init = true;
}
- }
-
- if (dev->driver_type == RC_DRIVER_IR_RAW) {
/* calls ir_register_device so unlock mutex here*/
mutex_unlock(&dev->lock);
rc = ir_raw_event_register(dev);
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index 93b3154..a14c428 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -715,6 +715,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
break;
case VB2_BUF_STATE_PREPARING:
case VB2_BUF_STATE_DEQUEUED:
+ case VB2_BUF_STATE_REQUEUEING:
/* nothing */
break;
}
@@ -1182,7 +1183,8 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
if (WARN_ON(state != VB2_BUF_STATE_DONE &&
state != VB2_BUF_STATE_ERROR &&
- state != VB2_BUF_STATE_QUEUED))
+ state != VB2_BUF_STATE_QUEUED &&
+ state != VB2_BUF_STATE_REQUEUEING))
state = VB2_BUF_STATE_ERROR;
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1199,22 +1201,30 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
for (plane = 0; plane < vb->num_planes; ++plane)
call_void_memop(vb, finish, vb->planes[plane].mem_priv);
- /* Add the buffer to the done buffers list */
spin_lock_irqsave(&q->done_lock, flags);
- vb->state = state;
- if (state != VB2_BUF_STATE_QUEUED)
+ if (state == VB2_BUF_STATE_QUEUED ||
+ state == VB2_BUF_STATE_REQUEUEING) {
+ vb->state = VB2_BUF_STATE_QUEUED;
+ } else {
+ /* Add the buffer to the done buffers list */
list_add_tail(&vb->done_entry, &q->done_list);
+ vb->state = state;
+ }
atomic_dec(&q->owned_by_drv_count);
spin_unlock_irqrestore(&q->done_lock, flags);
- if (state == VB2_BUF_STATE_QUEUED) {
+ switch (state) {
+ case VB2_BUF_STATE_QUEUED:
+ return;
+ case VB2_BUF_STATE_REQUEUEING:
if (q->start_streaming_called)
__enqueue_in_driver(vb);
return;
+ default:
+ /* Inform any processes that may be waiting for buffers */
+ wake_up(&q->done_wq);
+ break;
}
-
- /* Inform any processes that may be waiting for buffers */
- wake_up(&q->done_wq);
}
EXPORT_SYMBOL_GPL(vb2_buffer_done);
@@ -1244,19 +1254,19 @@ EXPORT_SYMBOL_GPL(vb2_discard_done);
static void vb2_warn_zero_bytesused(struct vb2_buffer *vb)
{
- static bool __check_once __read_mostly;
+ static bool check_once;
- if (__check_once)
+ if (check_once)
return;
- __check_once = true;
- __WARN();
+ check_once = true;
+ WARN_ON(1);
- pr_warn_once("use of bytesused == 0 is deprecated and will be removed in the future,\n");
+ pr_warn("use of bytesused == 0 is deprecated and will be removed in the future,\n");
if (vb->vb2_queue->allow_zero_bytesused)
- pr_warn_once("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n");
+ pr_warn("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n");
else
- pr_warn_once("use the actual size instead.\n");
+ pr_warn("use the actual size instead.\n");
}
/**
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 3a27a84..9426276 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -2245,6 +2245,9 @@ void omap3_gpmc_save_context(void)
{
int i;
+ if (!gpmc_base)
+ return;
+
gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
@@ -2277,6 +2280,9 @@ void omap3_gpmc_restore_context(void)
{
int i;
+ if (!gpmc_base)
+ return;
+
gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6538159..3f68dd2 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -115,7 +115,7 @@ config MFD_CROS_EC_I2C
config MFD_CROS_EC_SPI
tristate "ChromeOS Embedded Controller (SPI)"
- depends on MFD_CROS_EC && CROS_EC_PROTO && SPI && OF
+ depends on MFD_CROS_EC && CROS_EC_PROTO && SPI
---help---
If you say Y here, you get support for talking to the ChromeOS EC
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index bebf58a..0ce20ce 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -392,7 +392,7 @@ err:
* Register patch to some of the CODECs internal write sequences
* to ensure a clean exit from the low power sleep state.
*/
-static const struct reg_default wm5110_sleep_patch[] = {
+static const struct reg_sequence wm5110_sleep_patch[] = {
{ 0x337A, 0xC100 },
{ 0x337B, 0x0041 },
{ 0x3300, 0xA210 },
@@ -651,7 +651,7 @@ static int arizona_runtime_suspend(struct device *dev)
arizona->has_fully_powered_off = true;
- disable_irq(arizona->irq);
+ disable_irq_nosync(arizona->irq);
arizona_enable_reset(arizona);
regulator_bulk_disable(arizona->num_core_supplies,
arizona->core_supplies);
@@ -1141,10 +1141,6 @@ int arizona_dev_init(struct arizona *arizona)
arizona->pdata.gpio_defaults[i]);
}
- pm_runtime_set_autosuspend_delay(arizona->dev, 100);
- pm_runtime_use_autosuspend(arizona->dev);
- pm_runtime_enable(arizona->dev);
-
/* Chip default */
if (!arizona->pdata.clk32k_src)
arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2;
@@ -1245,11 +1241,17 @@ int arizona_dev_init(struct arizona *arizona)
arizona->pdata.spk_fmt[i]);
}
+ pm_runtime_set_active(arizona->dev);
+ pm_runtime_enable(arizona->dev);
+
/* Set up for interrupts */
ret = arizona_irq_init(arizona);
if (ret != 0)
goto err_reset;
+ pm_runtime_set_autosuspend_delay(arizona->dev, 100);
+ pm_runtime_use_autosuspend(arizona->dev);
+
arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error",
arizona_clkgen_err, arizona);
arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked",
@@ -1278,10 +1280,6 @@ int arizona_dev_init(struct arizona *arizona)
goto err_irq;
}
-#ifdef CONFIG_PM
- regulator_disable(arizona->dcvdd);
-#endif
-
return 0;
err_irq:
diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c
index c5265c1..583dc33 100644
--- a/drivers/mfd/twl6040.c
+++ b/drivers/mfd/twl6040.c
@@ -86,7 +86,7 @@ static const struct reg_default twl6040_defaults[] = {
{ 0x2E, 0x00 }, /* REG_STATUS (ro) */
};
-static struct reg_default twl6040_patch[] = {
+static struct reg_sequence twl6040_patch[] = {
/*
* Select I2C bus access to dual access registers
* Interrupt register is cleared on read
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index aeae6ec..423fb37 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -21,7 +21,7 @@
#define WM5102_NUM_AOD_ISR 2
#define WM5102_NUM_ISR 5
-static const struct reg_default wm5102_reva_patch[] = {
+static const struct reg_sequence wm5102_reva_patch[] = {
{ 0x80, 0x0003 },
{ 0x221, 0x0090 },
{ 0x211, 0x0014 },
@@ -57,7 +57,7 @@ static const struct reg_default wm5102_reva_patch[] = {
{ 0x80, 0x0000 },
};
-static const struct reg_default wm5102_revb_patch[] = {
+static const struct reg_sequence wm5102_revb_patch[] = {
{ 0x19, 0x0001 },
{ 0x80, 0x0003 },
{ 0x081, 0xE022 },
@@ -80,7 +80,7 @@ static const struct reg_default wm5102_revb_patch[] = {
/* We use a function so we can use ARRAY_SIZE() */
int wm5102_patch(struct arizona *arizona)
{
- const struct reg_default *wm5102_patch;
+ const struct reg_sequence *wm5102_patch;
int patch_size;
switch (arizona->rev) {
diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c
index 12cad94..dae04dd 100644
--- a/drivers/mfd/wm5110-tables.c
+++ b/drivers/mfd/wm5110-tables.c
@@ -21,7 +21,7 @@
#define WM5110_NUM_AOD_ISR 2
#define WM5110_NUM_ISR 5
-static const struct reg_default wm5110_reva_patch[] = {
+static const struct reg_sequence wm5110_reva_patch[] = {
{ 0x80, 0x3 },
{ 0x44, 0x20 },
{ 0x45, 0x40 },
@@ -134,7 +134,7 @@ static const struct reg_default wm5110_reva_patch[] = {
{ 0x209, 0x002A },
};
-static const struct reg_default wm5110_revb_patch[] = {
+static const struct reg_sequence wm5110_revb_patch[] = {
{ 0x80, 0x3 },
{ 0x36e, 0x0210 },
{ 0x370, 0x0210 },
@@ -224,7 +224,7 @@ static const struct reg_default wm5110_revb_patch[] = {
{ 0x80, 0x0 },
};
-static const struct reg_default wm5110_revd_patch[] = {
+static const struct reg_sequence wm5110_revd_patch[] = {
{ 0x80, 0x3 },
{ 0x80, 0x3 },
{ 0x393, 0x27 },
@@ -249,6 +249,16 @@ static const struct reg_default wm5110_revd_patch[] = {
{ 0x80, 0x0 },
};
+/* Add extra headphone write sequence locations */
+static const struct reg_default wm5110_reve_patch[] = {
+ { 0x80, 0x3 },
+ { 0x80, 0x3 },
+ { 0x4b, 0x138 },
+ { 0x4c, 0x13d },
+ { 0x80, 0x0 },
+ { 0x80, 0x0 },
+};
+
/* We use a function so we can use ARRAY_SIZE() */
int wm5110_patch(struct arizona *arizona)
{
@@ -266,7 +276,9 @@ int wm5110_patch(struct arizona *arizona)
wm5110_revd_patch,
ARRAY_SIZE(wm5110_revd_patch));
default:
- return 0;
+ return regmap_register_patch(arizona->regmap,
+ wm5110_reve_patch,
+ ARRAY_SIZE(wm5110_reve_patch));
}
}
EXPORT_SYMBOL_GPL(wm5110_patch);
@@ -676,6 +688,7 @@ static const struct reg_default wm5110_reg_default[] = {
{ 0x00000032, 0x0100 }, /* R50 - PWM Drive 3 */
{ 0x00000040, 0x0000 }, /* R64 - Wake control */
{ 0x00000041, 0x0000 }, /* R65 - Sequence control */
+ { 0x00000042, 0x0000 }, /* R66 - Spare Triggers */
{ 0x00000061, 0x01FF }, /* R97 - Sample Rate Sequence Select 1 */
{ 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */
{ 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */
@@ -1716,6 +1729,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_PWM_DRIVE_3:
case ARIZONA_WAKE_CONTROL:
case ARIZONA_SEQUENCE_CONTROL:
+ case ARIZONA_SPARE_TRIGGERS:
case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1:
case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2:
case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3:
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 53ae5af..0f4169a 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -243,21 +243,21 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
}
#endif
-static const struct reg_default wm8994_revc_patch[] = {
+static const struct reg_sequence wm8994_revc_patch[] = {
{ 0x102, 0x3 },
{ 0x56, 0x3 },
{ 0x817, 0x0 },
{ 0x102, 0x0 },
};
-static const struct reg_default wm8958_reva_patch[] = {
+static const struct reg_sequence wm8958_reva_patch[] = {
{ 0x102, 0x3 },
{ 0xcb, 0x81 },
{ 0x817, 0x0 },
{ 0x102, 0x0 },
};
-static const struct reg_default wm1811_reva_patch[] = {
+static const struct reg_sequence wm1811_reva_patch[] = {
{ 0x102, 0x3 },
{ 0x56, 0xc07 },
{ 0x5d, 0x7e },
@@ -326,7 +326,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
{
struct wm8994_pdata *pdata;
struct regmap_config *regmap_config;
- const struct reg_default *regmap_patch = NULL;
+ const struct reg_sequence *regmap_patch = NULL;
const char *devname;
int ret, i, patch_regs = 0;
int pulls = 0;
diff --git a/drivers/mfd/wm8997-tables.c b/drivers/mfd/wm8997-tables.c
index c0c25d75..cab2c68 100644
--- a/drivers/mfd/wm8997-tables.c
+++ b/drivers/mfd/wm8997-tables.c
@@ -17,7 +17,7 @@
#include "arizona.h"
-static const struct reg_default wm8997_reva_patch[] = {
+static const struct reg_sequence wm8997_reva_patch[] = {
{ 0x80, 0x0003 },
{ 0x214, 0x0008 },
{ 0x458, 0x0000 },
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 2d3db81..6ded3dc 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -438,9 +438,6 @@ static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
{
struct at24_data *at24;
- if (unlikely(off >= attr->size))
- return -EFBIG;
-
at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
return at24_write(at24, buf, off, count);
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index e1ccefc..a98dd4f 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -786,6 +786,7 @@ static bool bond_should_notify_peers(struct bonding *bond)
slave ? slave->dev->name : "NULL");
if (!slave || !bond->send_peer_notif ||
+ !netif_carrier_ok(bond->dev) ||
test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
return false;
diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c
index 2d1ce3c..753887d 100644
--- a/drivers/net/ethernet/3com/3c59x.c
+++ b/drivers/net/ethernet/3com/3c59x.c
@@ -1763,16 +1763,9 @@ vortex_open(struct net_device *dev)
vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
}
if (i != RX_RING_SIZE) {
- int j;
pr_emerg("%s: no memory for rx ring\n", dev->name);
- for (j = 0; j < i; j++) {
- if (vp->rx_skbuff[j]) {
- dev_kfree_skb(vp->rx_skbuff[j]);
- vp->rx_skbuff[j] = NULL;
- }
- }
retval = -ENOMEM;
- goto err_free_irq;
+ goto err_free_skb;
}
/* Wrap the ring. */
vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
@@ -1782,7 +1775,13 @@ vortex_open(struct net_device *dev)
if (!retval)
goto out;
-err_free_irq:
+err_free_skb:
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ if (vp->rx_skbuff[i]) {
+ dev_kfree_skb(vp->rx_skbuff[i]);
+ vp->rx_skbuff[i] = NULL;
+ }
+ }
free_irq(dev->irq, dev);
err:
if (vortex_debug > 1)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index a90d736..f7fbdc9 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -262,9 +262,9 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata,
if (likely(skb)) {
(*pkts_compl)++;
(*bytes_compl) += skb->len;
+ dev_kfree_skb_any(skb);
}
- dev_kfree_skb_any(skb);
tx_buf->first_bd = 0;
tx_buf->skb = NULL;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index 76b9052..5907c82 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -1718,6 +1718,22 @@ static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf,
offset += sizeof(u32);
data_buf += sizeof(u32);
written_so_far += sizeof(u32);
+
+ /* At end of each 4Kb page, release nvram lock to allow MFW
+ * chance to take it for its own use.
+ */
+ if ((cmd_flags & MCPR_NVM_COMMAND_LAST) &&
+ (written_so_far < buf_size)) {
+ DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
+ "Releasing NVM lock after offset 0x%x\n",
+ (u32)(offset - sizeof(u32)));
+ bnx2x_release_nvram_lock(bp);
+ usleep_range(1000, 2000);
+ rc = bnx2x_acquire_nvram_lock(bp);
+ if (rc)
+ return rc;
+ }
+
cmd_flags = 0;
}
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index 0612b19..506047c 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -676,6 +676,7 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
if (!next_cmpl->valid)
break;
}
+ packets++;
/* TODO: BNA_CQ_EF_LOCAL ? */
if (unlikely(flags & (BNA_CQ_EF_MAC_ERROR |
@@ -692,7 +693,6 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
else
bnad_cq_setup_skb_frags(rcb, skb, sop_ci, nvecs, len);
- packets++;
rcb->rxq->rx_packets++;
rcb->rxq->rx_bytes += totlen;
ccb->bytes_per_intr += totlen;
diff --git a/drivers/net/ethernet/cavium/Kconfig b/drivers/net/ethernet/cavium/Kconfig
index c4d6bbe..02e23e6 100644
--- a/drivers/net/ethernet/cavium/Kconfig
+++ b/drivers/net/ethernet/cavium/Kconfig
@@ -16,7 +16,6 @@ if NET_VENDOR_CAVIUM
config THUNDER_NIC_PF
tristate "Thunder Physical function driver"
depends on 64BIT
- default ARCH_THUNDER
select THUNDER_NIC_BGX
---help---
This driver supports Thunder's NIC physical function.
@@ -29,14 +28,12 @@ config THUNDER_NIC_PF
config THUNDER_NIC_VF
tristate "Thunder Virtual function driver"
depends on 64BIT
- default ARCH_THUNDER
---help---
This driver supports Thunder's NIC virtual function
config THUNDER_NIC_BGX
tristate "Thunder MAC interface driver (BGX)"
depends on 64BIT
- default ARCH_THUNDER
---help---
This driver supports programming and controlling of MAC
interface from NIC physical function driver.
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
index a11485f..c3c7db4 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
@@ -2332,10 +2332,11 @@ int t4_setup_debugfs(struct adapter *adap)
EXT_MEM1_SIZE_G(size));
}
} else {
- if (i & EXT_MEM_ENABLE_F)
+ if (i & EXT_MEM_ENABLE_F) {
size = t4_read_reg(adap, MA_EXT_MEMORY_BAR_A);
add_debugfs_mem(adap, "mc", MEM_MC,
EXT_MEM_SIZE_G(size));
+ }
}
de = debugfs_create_file_size("flash", S_IRUSR, adap->debugfs_root, adap,
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 2716e6f..00e3a6b 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -620,6 +620,11 @@ enum be_if_flags {
BE_IF_FLAGS_VLAN_PROMISCUOUS |\
BE_IF_FLAGS_MCAST_PROMISCUOUS)
+#define BE_IF_EN_FLAGS (BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |\
+ BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_UNTAGGED)
+
+#define BE_IF_ALL_FILT_FLAGS (BE_IF_EN_FLAGS | BE_IF_FLAGS_ALL_PROMISCUOUS)
+
/* An RX interface is an object with one or more MAC addresses and
* filtering capabilities. */
struct be_cmd_req_if_create {
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 6f64242..6ca693b 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -273,6 +273,10 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
if (ether_addr_equal(addr->sa_data, netdev->dev_addr))
return 0;
+ /* if device is not running, copy MAC to netdev->dev_addr */
+ if (!netif_running(netdev))
+ goto done;
+
/* The PMAC_ADD cmd may fail if the VF doesn't have FILTMGMT
* privilege or if PF did not provision the new MAC address.
* On BE3, this cmd will always fail if the VF doesn't have the
@@ -307,9 +311,9 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
status = -EPERM;
goto err;
}
-
- memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
- dev_info(dev, "MAC address changed to %pM\n", mac);
+done:
+ ether_addr_copy(netdev->dev_addr, addr->sa_data);
+ dev_info(dev, "MAC address changed to %pM\n", addr->sa_data);
return 0;
err:
dev_warn(dev, "MAC address change to %pM failed\n", addr->sa_data);
@@ -2447,10 +2451,24 @@ static void be_eq_clean(struct be_eq_obj *eqo)
be_eq_notify(eqo->adapter, eqo->q.id, false, true, num, 0);
}
-static void be_rx_cq_clean(struct be_rx_obj *rxo)
+/* Free posted rx buffers that were not used */
+static void be_rxq_clean(struct be_rx_obj *rxo)
{
- struct be_rx_page_info *page_info;
struct be_queue_info *rxq = &rxo->q;
+ struct be_rx_page_info *page_info;
+
+ while (atomic_read(&rxq->used) > 0) {
+ page_info = get_rx_page_info(rxo);
+ put_page(page_info->page);
+ memset(page_info, 0, sizeof(*page_info));
+ }
+ BUG_ON(atomic_read(&rxq->used));
+ rxq->tail = 0;
+ rxq->head = 0;
+}
+
+static void be_rx_cq_clean(struct be_rx_obj *rxo)
+{
struct be_queue_info *rx_cq = &rxo->cq;
struct be_rx_compl_info *rxcp;
struct be_adapter *adapter = rxo->adapter;
@@ -2487,16 +2505,6 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
/* After cleanup, leave the CQ in unarmed state */
be_cq_notify(adapter, rx_cq->id, false, 0);
-
- /* Then free posted rx buffers that were not used */
- while (atomic_read(&rxq->used) > 0) {
- page_info = get_rx_page_info(rxo);
- put_page(page_info->page);
- memset(page_info, 0, sizeof(*page_info));
- }
- BUG_ON(atomic_read(&rxq->used));
- rxq->tail = 0;
- rxq->head = 0;
}
static void be_tx_compl_clean(struct be_adapter *adapter)
@@ -2576,8 +2584,8 @@ static void be_evt_queues_destroy(struct be_adapter *adapter)
be_cmd_q_destroy(adapter, &eqo->q, QTYPE_EQ);
napi_hash_del(&eqo->napi);
netif_napi_del(&eqo->napi);
+ free_cpumask_var(eqo->affinity_mask);
}
- free_cpumask_var(eqo->affinity_mask);
be_queue_free(adapter, &eqo->q);
}
}
@@ -2594,13 +2602,7 @@ static int be_evt_queues_create(struct be_adapter *adapter)
for_all_evt_queues(adapter, eqo, i) {
int numa_node = dev_to_node(&adapter->pdev->dev);
- if (!zalloc_cpumask_var(&eqo->affinity_mask, GFP_KERNEL))
- return -ENOMEM;
- cpumask_set_cpu(cpumask_local_spread(i, numa_node),
- eqo->affinity_mask);
- netif_napi_add(adapter->netdev, &eqo->napi, be_poll,
- BE_NAPI_WEIGHT);
- napi_hash_add(&eqo->napi);
+
aic = &adapter->aic_obj[i];
eqo->adapter = adapter;
eqo->idx = i;
@@ -2616,6 +2618,14 @@ static int be_evt_queues_create(struct be_adapter *adapter)
rc = be_cmd_eq_create(adapter, eqo);
if (rc)
return rc;
+
+ if (!zalloc_cpumask_var(&eqo->affinity_mask, GFP_KERNEL))
+ return -ENOMEM;
+ cpumask_set_cpu(cpumask_local_spread(i, numa_node),
+ eqo->affinity_mask);
+ netif_napi_add(adapter->netdev, &eqo->napi, be_poll,
+ BE_NAPI_WEIGHT);
+ napi_hash_add(&eqo->napi);
}
return 0;
}
@@ -3354,13 +3364,54 @@ static void be_rx_qs_destroy(struct be_adapter *adapter)
for_all_rx_queues(adapter, rxo, i) {
q = &rxo->q;
if (q->created) {
+ /* If RXQs are destroyed while in an "out of buffer"
+ * state, there is a possibility of an HW stall on
+ * Lancer. So, post 64 buffers to each queue to relieve
+ * the "out of buffer" condition.
+ * Make sure there's space in the RXQ before posting.
+ */
+ if (lancer_chip(adapter)) {
+ be_rx_cq_clean(rxo);
+ if (atomic_read(&q->used) == 0)
+ be_post_rx_frags(rxo, GFP_KERNEL,
+ MAX_RX_POST);
+ }
+
be_cmd_rxq_destroy(adapter, q);
be_rx_cq_clean(rxo);
+ be_rxq_clean(rxo);
}
be_queue_free(adapter, q);
}
}
+static void be_disable_if_filters(struct be_adapter *adapter)
+{
+ be_cmd_pmac_del(adapter, adapter->if_handle,
+ adapter->pmac_id[0], 0);
+
+ be_clear_uc_list(adapter);
+
+ /* The IFACE flags are enabled in the open path and cleared
+ * in the close path. When a VF gets detached from the host and
+ * assigned to a VM the following happens:
+ * - VF's IFACE flags get cleared in the detach path
+ * - IFACE create is issued by the VF in the attach path
+ * Due to a bug in the BE3/Skyhawk-R FW
+ * (Lancer FW doesn't have the bug), the IFACE capability flags
+ * specified along with the IFACE create cmd issued by a VF are not
+ * honoured by FW. As a consequence, if a *new* driver
+ * (that enables/disables IFACE flags in open/close)
+ * is loaded in the host and an *old* driver is * used by a VM/VF,
+ * the IFACE gets created *without* the needed flags.
+ * To avoid this, disable RX-filter flags only for Lancer.
+ */
+ if (lancer_chip(adapter)) {
+ be_cmd_rx_filter(adapter, BE_IF_ALL_FILT_FLAGS, OFF);
+ adapter->if_flags &= ~BE_IF_ALL_FILT_FLAGS;
+ }
+}
+
static int be_close(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -3373,6 +3424,8 @@ static int be_close(struct net_device *netdev)
if (!(adapter->flags & BE_FLAGS_SETUP_DONE))
return 0;
+ be_disable_if_filters(adapter);
+
be_roce_dev_close(adapter);
if (adapter->flags & BE_FLAGS_NAPI_ENABLED) {
@@ -3392,7 +3445,6 @@ static int be_close(struct net_device *netdev)
be_tx_compl_clean(adapter);
be_rx_qs_destroy(adapter);
- be_clear_uc_list(adapter);
for_all_evt_queues(adapter, eqo, i) {
if (msix_enabled(adapter))
@@ -3477,6 +3529,31 @@ static int be_rx_qs_create(struct be_adapter *adapter)
return 0;
}
+static int be_enable_if_filters(struct be_adapter *adapter)
+{
+ int status;
+
+ status = be_cmd_rx_filter(adapter, BE_IF_EN_FLAGS, ON);
+ if (status)
+ return status;
+
+ /* For BE3 VFs, the PF programs the initial MAC address */
+ if (!(BEx_chip(adapter) && be_virtfn(adapter))) {
+ status = be_cmd_pmac_add(adapter, adapter->netdev->dev_addr,
+ adapter->if_handle,
+ &adapter->pmac_id[0], 0);
+ if (status)
+ return status;
+ }
+
+ if (adapter->vlans_added)
+ be_vid_config(adapter);
+
+ be_set_rx_mode(adapter->netdev);
+
+ return 0;
+}
+
static int be_open(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -3490,6 +3567,10 @@ static int be_open(struct net_device *netdev)
if (status)
goto err;
+ status = be_enable_if_filters(adapter);
+ if (status)
+ goto err;
+
status = be_irq_register(adapter);
if (status)
goto err;
@@ -3686,16 +3767,6 @@ static void be_cancel_err_detection(struct be_adapter *adapter)
}
}
-static void be_mac_clear(struct be_adapter *adapter)
-{
- if (adapter->pmac_id) {
- be_cmd_pmac_del(adapter, adapter->if_handle,
- adapter->pmac_id[0], 0);
- kfree(adapter->pmac_id);
- adapter->pmac_id = NULL;
- }
-}
-
#ifdef CONFIG_BE2NET_VXLAN
static void be_disable_vxlan_offloads(struct be_adapter *adapter)
{
@@ -3770,8 +3841,8 @@ static int be_clear(struct be_adapter *adapter)
#ifdef CONFIG_BE2NET_VXLAN
be_disable_vxlan_offloads(adapter);
#endif
- /* delete the primary mac along with the uc-mac list */
- be_mac_clear(adapter);
+ kfree(adapter->pmac_id);
+ adapter->pmac_id = NULL;
be_cmd_if_destroy(adapter, adapter->if_handle, 0);
@@ -3782,25 +3853,11 @@ static int be_clear(struct be_adapter *adapter)
return 0;
}
-static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
- u32 cap_flags, u32 vf)
-{
- u32 en_flags;
-
- en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
- BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |
- BE_IF_FLAGS_RSS | BE_IF_FLAGS_DEFQ_RSS;
-
- en_flags &= cap_flags;
-
- return be_cmd_if_create(adapter, cap_flags, en_flags, if_handle, vf);
-}
-
static int be_vfs_if_create(struct be_adapter *adapter)
{
struct be_resources res = {0};
+ u32 cap_flags, en_flags, vf;
struct be_vf_cfg *vf_cfg;
- u32 cap_flags, vf;
int status;
/* If a FW profile exists, then cap_flags are updated */
@@ -3821,8 +3878,12 @@ static int be_vfs_if_create(struct be_adapter *adapter)
}
}
- status = be_if_create(adapter, &vf_cfg->if_handle,
- cap_flags, vf + 1);
+ en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
+ BE_IF_FLAGS_BROADCAST |
+ BE_IF_FLAGS_MULTICAST |
+ BE_IF_FLAGS_PASS_L3L4_ERRORS);
+ status = be_cmd_if_create(adapter, cap_flags, en_flags,
+ &vf_cfg->if_handle, vf + 1);
if (status)
return status;
}
@@ -4194,15 +4255,8 @@ static int be_mac_setup(struct be_adapter *adapter)
memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
- } else {
- /* Maybe the HW was reset; dev_addr must be re-programmed */
- memcpy(mac, adapter->netdev->dev_addr, ETH_ALEN);
}
- /* For BE3-R VFs, the PF programs the initial MAC address */
- if (!(BEx_chip(adapter) && be_virtfn(adapter)))
- be_cmd_pmac_add(adapter, mac, adapter->if_handle,
- &adapter->pmac_id[0], 0);
return 0;
}
@@ -4342,6 +4396,7 @@ static int be_func_init(struct be_adapter *adapter)
static int be_setup(struct be_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
+ u32 en_flags;
int status;
status = be_func_init(adapter);
@@ -4364,8 +4419,11 @@ static int be_setup(struct be_adapter *adapter)
if (status)
goto err;
- status = be_if_create(adapter, &adapter->if_handle,
- be_if_cap_flags(adapter), 0);
+ /* will enable all the needed filter flags in be_open() */
+ en_flags = BE_IF_FLAGS_RSS | BE_IF_FLAGS_DEFQ_RSS;
+ en_flags = en_flags & be_if_cap_flags(adapter);
+ status = be_cmd_if_create(adapter, be_if_cap_flags(adapter), en_flags,
+ &adapter->if_handle, 0);
if (status)
goto err;
@@ -4391,11 +4449,6 @@ static int be_setup(struct be_adapter *adapter)
dev_err(dev, "Please upgrade firmware to version >= 4.0\n");
}
- if (adapter->vlans_added)
- be_vid_config(adapter);
-
- be_set_rx_mode(adapter->netdev);
-
status = be_cmd_set_flow_control(adapter, adapter->tx_fc,
adapter->rx_fc);
if (status)
@@ -5121,7 +5174,7 @@ static void be_add_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
struct device *dev = &adapter->pdev->dev;
int status;
- if (lancer_chip(adapter) || BEx_chip(adapter))
+ if (lancer_chip(adapter) || BEx_chip(adapter) || be_is_mc(adapter))
return;
if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS) {
@@ -5168,7 +5221,7 @@ static void be_del_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
{
struct be_adapter *adapter = netdev_priv(netdev);
- if (lancer_chip(adapter) || BEx_chip(adapter))
+ if (lancer_chip(adapter) || BEx_chip(adapter) || be_is_mc(adapter))
return;
if (adapter->vxlan_port != port)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 32e3807c..271bb58 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -3433,6 +3433,7 @@ fec_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(&pdev->dev, FEC_MDIO_PM_TIMEOUT);
pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index 56316db..cf8e546 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -586,7 +586,8 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
frag = skb_shinfo(skb)->frags;
while (nr_frags) {
CBDC_SC(bdp,
- BD_ENET_TX_STATS | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+ BD_ENET_TX_STATS | BD_ENET_TX_INTR | BD_ENET_TX_LAST |
+ BD_ENET_TX_TC);
CBDS_SC(bdp, BD_ENET_TX_READY);
if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0)
diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
index b34214e..016743e 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
@@ -110,7 +110,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
}
#define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB)
-#define FEC_NAPI_TX_EVENT_MSK (FEC_ENET_TXF | FEC_ENET_TXB)
+#define FEC_NAPI_TX_EVENT_MSK (FEC_ENET_TXF)
#define FEC_RX_EVENT (FEC_ENET_RXF)
#define FEC_TX_EVENT (FEC_ENET_TXF)
#define FEC_ERR_EVENT_MSK (FEC_ENET_HBERR | FEC_ENET_BABR | \
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 2b7610f..10b3bbbb 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -2102,6 +2102,11 @@ int startup_gfar(struct net_device *ndev)
/* Start Rx/Tx DMA and enable the interrupts */
gfar_start(priv);
+ /* force link state update after mac reset */
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
+
phy_start(priv->phydev);
enable_napi(priv);
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 3c0a8f8..5b90fcf 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -900,27 +900,6 @@ static int gfar_check_filer_hardware(struct gfar_private *priv)
return 0;
}
-static int gfar_comp_asc(const void *a, const void *b)
-{
- return memcmp(a, b, 4);
-}
-
-static int gfar_comp_desc(const void *a, const void *b)
-{
- return -memcmp(a, b, 4);
-}
-
-static void gfar_swap(void *a, void *b, int size)
-{
- u32 *_a = a;
- u32 *_b = b;
-
- swap(_a[0], _b[0]);
- swap(_a[1], _b[1]);
- swap(_a[2], _b[2]);
- swap(_a[3], _b[3]);
-}
-
/* Write a mask to filer cache */
static void gfar_set_mask(u32 mask, struct filer_table *tab)
{
@@ -1270,310 +1249,6 @@ static int gfar_convert_to_filer(struct ethtool_rx_flow_spec *rule,
return 0;
}
-/* Copy size filer entries */
-static void gfar_copy_filer_entries(struct gfar_filer_entry dst[0],
- struct gfar_filer_entry src[0], s32 size)
-{
- while (size > 0) {
- size--;
- dst[size].ctrl = src[size].ctrl;
- dst[size].prop = src[size].prop;
- }
-}
-
-/* Delete the contents of the filer-table between start and end
- * and collapse them
- */
-static int gfar_trim_filer_entries(u32 begin, u32 end, struct filer_table *tab)
-{
- int length;
-
- if (end > MAX_FILER_CACHE_IDX || end < begin)
- return -EINVAL;
-
- end++;
- length = end - begin;
-
- /* Copy */
- while (end < tab->index) {
- tab->fe[begin].ctrl = tab->fe[end].ctrl;
- tab->fe[begin++].prop = tab->fe[end++].prop;
-
- }
- /* Fill up with don't cares */
- while (begin < tab->index) {
- tab->fe[begin].ctrl = 0x60;
- tab->fe[begin].prop = 0xFFFFFFFF;
- begin++;
- }
-
- tab->index -= length;
- return 0;
-}
-
-/* Make space on the wanted location */
-static int gfar_expand_filer_entries(u32 begin, u32 length,
- struct filer_table *tab)
-{
- if (length == 0 || length + tab->index > MAX_FILER_CACHE_IDX ||
- begin > MAX_FILER_CACHE_IDX)
- return -EINVAL;
-
- gfar_copy_filer_entries(&(tab->fe[begin + length]), &(tab->fe[begin]),
- tab->index - length + 1);
-
- tab->index += length;
- return 0;
-}
-
-static int gfar_get_next_cluster_start(int start, struct filer_table *tab)
-{
- for (; (start < tab->index) && (start < MAX_FILER_CACHE_IDX - 1);
- start++) {
- if ((tab->fe[start].ctrl & (RQFCR_AND | RQFCR_CLE)) ==
- (RQFCR_AND | RQFCR_CLE))
- return start;
- }
- return -1;
-}
-
-static int gfar_get_next_cluster_end(int start, struct filer_table *tab)
-{
- for (; (start < tab->index) && (start < MAX_FILER_CACHE_IDX - 1);
- start++) {
- if ((tab->fe[start].ctrl & (RQFCR_AND | RQFCR_CLE)) ==
- (RQFCR_CLE))
- return start;
- }
- return -1;
-}
-
-/* Uses hardwares clustering option to reduce
- * the number of filer table entries
- */
-static void gfar_cluster_filer(struct filer_table *tab)
-{
- s32 i = -1, j, iend, jend;
-
- while ((i = gfar_get_next_cluster_start(++i, tab)) != -1) {
- j = i;
- while ((j = gfar_get_next_cluster_start(++j, tab)) != -1) {
- /* The cluster entries self and the previous one
- * (a mask) must be identical!
- */
- if (tab->fe[i].ctrl != tab->fe[j].ctrl)
- break;
- if (tab->fe[i].prop != tab->fe[j].prop)
- break;
- if (tab->fe[i - 1].ctrl != tab->fe[j - 1].ctrl)
- break;
- if (tab->fe[i - 1].prop != tab->fe[j - 1].prop)
- break;
- iend = gfar_get_next_cluster_end(i, tab);
- jend = gfar_get_next_cluster_end(j, tab);
- if (jend == -1 || iend == -1)
- break;
-
- /* First we make some free space, where our cluster
- * element should be. Then we copy it there and finally
- * delete in from its old location.
- */
- if (gfar_expand_filer_entries(iend, (jend - j), tab) ==
- -EINVAL)
- break;
-
- gfar_copy_filer_entries(&(tab->fe[iend + 1]),
- &(tab->fe[jend + 1]), jend - j);
-
- if (gfar_trim_filer_entries(jend - 1,
- jend + (jend - j),
- tab) == -EINVAL)
- return;
-
- /* Mask out cluster bit */
- tab->fe[iend].ctrl &= ~(RQFCR_CLE);
- }
- }
-}
-
-/* Swaps the masked bits of a1<>a2 and b1<>b2 */
-static void gfar_swap_bits(struct gfar_filer_entry *a1,
- struct gfar_filer_entry *a2,
- struct gfar_filer_entry *b1,
- struct gfar_filer_entry *b2, u32 mask)
-{
- u32 temp[4];
- temp[0] = a1->ctrl & mask;
- temp[1] = a2->ctrl & mask;
- temp[2] = b1->ctrl & mask;
- temp[3] = b2->ctrl & mask;
-
- a1->ctrl &= ~mask;
- a2->ctrl &= ~mask;
- b1->ctrl &= ~mask;
- b2->ctrl &= ~mask;
-
- a1->ctrl |= temp[1];
- a2->ctrl |= temp[0];
- b1->ctrl |= temp[3];
- b2->ctrl |= temp[2];
-}
-
-/* Generate a list consisting of masks values with their start and
- * end of validity and block as indicator for parts belonging
- * together (glued by ANDs) in mask_table
- */
-static u32 gfar_generate_mask_table(struct gfar_mask_entry *mask_table,
- struct filer_table *tab)
-{
- u32 i, and_index = 0, block_index = 1;
-
- for (i = 0; i < tab->index; i++) {
-
- /* LSByte of control = 0 sets a mask */
- if (!(tab->fe[i].ctrl & 0xF)) {
- mask_table[and_index].mask = tab->fe[i].prop;
- mask_table[and_index].start = i;
- mask_table[and_index].block = block_index;
- if (and_index >= 1)
- mask_table[and_index - 1].end = i - 1;
- and_index++;
- }
- /* cluster starts and ends will be separated because they should
- * hold their position
- */
- if (tab->fe[i].ctrl & RQFCR_CLE)
- block_index++;
- /* A not set AND indicates the end of a depended block */
- if (!(tab->fe[i].ctrl & RQFCR_AND))
- block_index++;
- }
-
- mask_table[and_index - 1].end = i - 1;
-
- return and_index;
-}
-
-/* Sorts the entries of mask_table by the values of the masks.
- * Important: The 0xFF80 flags of the first and last entry of a
- * block must hold their position (which queue, CLusterEnable, ReJEct,
- * AND)
- */
-static void gfar_sort_mask_table(struct gfar_mask_entry *mask_table,
- struct filer_table *temp_table, u32 and_index)
-{
- /* Pointer to compare function (_asc or _desc) */
- int (*gfar_comp)(const void *, const void *);
-
- u32 i, size = 0, start = 0, prev = 1;
- u32 old_first, old_last, new_first, new_last;
-
- gfar_comp = &gfar_comp_desc;
-
- for (i = 0; i < and_index; i++) {
- if (prev != mask_table[i].block) {
- old_first = mask_table[start].start + 1;
- old_last = mask_table[i - 1].end;
- sort(mask_table + start, size,
- sizeof(struct gfar_mask_entry),
- gfar_comp, &gfar_swap);
-
- /* Toggle order for every block. This makes the
- * thing more efficient!
- */
- if (gfar_comp == gfar_comp_desc)
- gfar_comp = &gfar_comp_asc;
- else
- gfar_comp = &gfar_comp_desc;
-
- new_first = mask_table[start].start + 1;
- new_last = mask_table[i - 1].end;
-
- gfar_swap_bits(&temp_table->fe[new_first],
- &temp_table->fe[old_first],
- &temp_table->fe[new_last],
- &temp_table->fe[old_last],
- RQFCR_QUEUE | RQFCR_CLE |
- RQFCR_RJE | RQFCR_AND);
-
- start = i;
- size = 0;
- }
- size++;
- prev = mask_table[i].block;
- }
-}
-
-/* Reduces the number of masks needed in the filer table to save entries
- * This is done by sorting the masks of a depended block. A depended block is
- * identified by gluing ANDs or CLE. The sorting order toggles after every
- * block. Of course entries in scope of a mask must change their location with
- * it.
- */
-static int gfar_optimize_filer_masks(struct filer_table *tab)
-{
- struct filer_table *temp_table;
- struct gfar_mask_entry *mask_table;
-
- u32 and_index = 0, previous_mask = 0, i = 0, j = 0, size = 0;
- s32 ret = 0;
-
- /* We need a copy of the filer table because
- * we want to change its order
- */
- temp_table = kmemdup(tab, sizeof(*temp_table), GFP_KERNEL);
- if (temp_table == NULL)
- return -ENOMEM;
-
- mask_table = kcalloc(MAX_FILER_CACHE_IDX / 2 + 1,
- sizeof(struct gfar_mask_entry), GFP_KERNEL);
-
- if (mask_table == NULL) {
- ret = -ENOMEM;
- goto end;
- }
-
- and_index = gfar_generate_mask_table(mask_table, tab);
-
- gfar_sort_mask_table(mask_table, temp_table, and_index);
-
- /* Now we can copy the data from our duplicated filer table to
- * the real one in the order the mask table says
- */
- for (i = 0; i < and_index; i++) {
- size = mask_table[i].end - mask_table[i].start + 1;
- gfar_copy_filer_entries(&(tab->fe[j]),
- &(temp_table->fe[mask_table[i].start]), size);
- j += size;
- }
-
- /* And finally we just have to check for duplicated masks and drop the
- * second ones
- */
- for (i = 0; i < tab->index && i < MAX_FILER_CACHE_IDX; i++) {
- if (tab->fe[i].ctrl == 0x80) {
- previous_mask = i++;
- break;
- }
- }
- for (; i < tab->index && i < MAX_FILER_CACHE_IDX; i++) {
- if (tab->fe[i].ctrl == 0x80) {
- if (tab->fe[i].prop == tab->fe[previous_mask].prop) {
- /* Two identical ones found!
- * So drop the second one!
- */
- gfar_trim_filer_entries(i, i, tab);
- } else
- /* Not identical! */
- previous_mask = i;
- }
- }
-
- kfree(mask_table);
-end: kfree(temp_table);
- return ret;
-}
-
/* Write the bit-pattern from software's buffer to hardware registers */
static int gfar_write_filer_table(struct gfar_private *priv,
struct filer_table *tab)
@@ -1583,11 +1258,10 @@ static int gfar_write_filer_table(struct gfar_private *priv,
return -EBUSY;
/* Fill regular entries */
- for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].prop);
- i++)
+ for (; i < MAX_FILER_IDX && (tab->fe[i].ctrl | tab->fe[i].prop); i++)
gfar_write_filer(priv, i, tab->fe[i].ctrl, tab->fe[i].prop);
/* Fill the rest with fall-troughs */
- for (; i < MAX_FILER_IDX - 1; i++)
+ for (; i < MAX_FILER_IDX; i++)
gfar_write_filer(priv, i, 0x60, 0xFFFFFFFF);
/* Last entry must be default accept
* because that's what people expect
@@ -1621,7 +1295,6 @@ static int gfar_process_filer_changes(struct gfar_private *priv)
{
struct ethtool_flow_spec_container *j;
struct filer_table *tab;
- s32 i = 0;
s32 ret = 0;
/* So index is set to zero, too! */
@@ -1646,17 +1319,6 @@ static int gfar_process_filer_changes(struct gfar_private *priv)
}
}
- i = tab->index;
-
- /* Optimizations to save entries */
- gfar_cluster_filer(tab);
- gfar_optimize_filer_masks(tab);
-
- pr_debug("\tSummary:\n"
- "\tData on hardware: %d\n"
- "\tCompression rate: %d%%\n",
- tab->index, 100 - (100 * tab->index) / i);
-
/* Write everything to hardware */
ret = gfar_write_filer_table(priv, tab);
if (ret == -EBUSY) {
@@ -1722,13 +1384,14 @@ static int gfar_add_cls(struct gfar_private *priv,
}
process:
+ priv->rx_list.count++;
ret = gfar_process_filer_changes(priv);
if (ret)
goto clean_list;
- priv->rx_list.count++;
return ret;
clean_list:
+ priv->rx_list.count--;
list_del(&temp->list);
clean_mem:
kfree(temp);
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
index 982fdcd..b5b2925 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
@@ -216,7 +216,7 @@ static void fm10k_reuse_rx_page(struct fm10k_ring *rx_ring,
static inline bool fm10k_page_is_reserved(struct page *page)
{
- return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc;
+ return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page);
}
static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer,
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 2f70a9b..830466c 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -6566,7 +6566,7 @@ static void igb_reuse_rx_page(struct igb_ring *rx_ring,
static inline bool igb_page_is_reserved(struct page *page)
{
- return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc;
+ return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page);
}
static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 9aa6104..ae21e0b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1832,7 +1832,7 @@ static void ixgbe_reuse_rx_page(struct ixgbe_ring *rx_ring,
static inline bool ixgbe_page_is_reserved(struct page *page)
{
- return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc;
+ return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page);
}
/**
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index e71cdde..1d7b00b 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -765,7 +765,7 @@ static void ixgbevf_reuse_rx_page(struct ixgbevf_ring *rx_ring,
static inline bool ixgbevf_page_is_reserved(struct page *page)
{
- return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc;
+ return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page);
}
/**
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 3e8b1bf..d9884fd 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -27,6 +27,8 @@
#include <linux/of_address.h>
#include <linux/phy.h>
#include <linux/clk.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
#include <uapi/linux/ppp_defs.h>
#include <net/ip.h>
#include <net/ipv6.h>
@@ -299,6 +301,7 @@
/* Coalescing */
#define MVPP2_TXDONE_COAL_PKTS_THRESH 15
+#define MVPP2_TXDONE_HRTIMER_PERIOD_NS 1000000UL
#define MVPP2_RX_COAL_PKTS 32
#define MVPP2_RX_COAL_USEC 100
@@ -660,6 +663,14 @@ struct mvpp2_pcpu_stats {
u64 tx_bytes;
};
+/* Per-CPU port control */
+struct mvpp2_port_pcpu {
+ struct hrtimer tx_done_timer;
+ bool timer_scheduled;
+ /* Tasklet for egress finalization */
+ struct tasklet_struct tx_done_tasklet;
+};
+
struct mvpp2_port {
u8 id;
@@ -679,6 +690,9 @@ struct mvpp2_port {
u32 pending_cause_rx;
struct napi_struct napi;
+ /* Per-CPU port control */
+ struct mvpp2_port_pcpu __percpu *pcpu;
+
/* Flags */
unsigned long flags;
@@ -776,6 +790,9 @@ struct mvpp2_txq_pcpu {
/* Array of transmitted skb */
struct sk_buff **tx_skb;
+ /* Array of transmitted buffers' physical addresses */
+ dma_addr_t *tx_buffs;
+
/* Index of last TX DMA descriptor that was inserted */
int txq_put_index;
@@ -913,8 +930,6 @@ struct mvpp2_bm_pool {
/* Occupied buffers indicator */
atomic_t in_use;
int in_use_thresh;
-
- spinlock_t lock;
};
struct mvpp2_buff_hdr {
@@ -963,9 +978,13 @@ static void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu)
}
static void mvpp2_txq_inc_put(struct mvpp2_txq_pcpu *txq_pcpu,
- struct sk_buff *skb)
+ struct sk_buff *skb,
+ struct mvpp2_tx_desc *tx_desc)
{
txq_pcpu->tx_skb[txq_pcpu->txq_put_index] = skb;
+ if (skb)
+ txq_pcpu->tx_buffs[txq_pcpu->txq_put_index] =
+ tx_desc->buf_phys_addr;
txq_pcpu->txq_put_index++;
if (txq_pcpu->txq_put_index == txq_pcpu->size)
txq_pcpu->txq_put_index = 0;
@@ -3376,7 +3395,6 @@ static int mvpp2_bm_pool_create(struct platform_device *pdev,
bm_pool->pkt_size = 0;
bm_pool->buf_num = 0;
atomic_set(&bm_pool->in_use, 0);
- spin_lock_init(&bm_pool->lock);
return 0;
}
@@ -3647,7 +3665,6 @@ static struct mvpp2_bm_pool *
mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
int pkt_size)
{
- unsigned long flags = 0;
struct mvpp2_bm_pool *new_pool = &port->priv->bm_pools[pool];
int num;
@@ -3656,8 +3673,6 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
return NULL;
}
- spin_lock_irqsave(&new_pool->lock, flags);
-
if (new_pool->type == MVPP2_BM_FREE)
new_pool->type = type;
@@ -3686,8 +3701,6 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
if (num != pkts_num) {
WARN(1, "pool %d: %d of %d allocated\n",
new_pool->id, num, pkts_num);
- /* We need to undo the bufs_add() allocations */
- spin_unlock_irqrestore(&new_pool->lock, flags);
return NULL;
}
}
@@ -3695,15 +3708,12 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
mvpp2_bm_pool_bufsize_set(port->priv, new_pool,
MVPP2_RX_BUF_SIZE(new_pool->pkt_size));
- spin_unlock_irqrestore(&new_pool->lock, flags);
-
return new_pool;
}
/* Initialize pools for swf */
static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port)
{
- unsigned long flags = 0;
int rxq;
if (!port->pool_long) {
@@ -3714,9 +3724,7 @@ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port)
if (!port->pool_long)
return -ENOMEM;
- spin_lock_irqsave(&port->pool_long->lock, flags);
port->pool_long->port_map |= (1 << port->id);
- spin_unlock_irqrestore(&port->pool_long->lock, flags);
for (rxq = 0; rxq < rxq_number; rxq++)
mvpp2_rxq_long_pool_set(port, rxq, port->pool_long->id);
@@ -3730,9 +3738,7 @@ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port)
if (!port->pool_short)
return -ENOMEM;
- spin_lock_irqsave(&port->pool_short->lock, flags);
port->pool_short->port_map |= (1 << port->id);
- spin_unlock_irqrestore(&port->pool_short->lock, flags);
for (rxq = 0; rxq < rxq_number; rxq++)
mvpp2_rxq_short_pool_set(port, rxq,
@@ -3806,7 +3812,6 @@ static void mvpp2_interrupts_unmask(void *arg)
mvpp2_write(port->priv, MVPP2_ISR_RX_TX_MASK_REG(port->id),
(MVPP2_CAUSE_MISC_SUM_MASK |
- MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK |
MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK));
}
@@ -4382,23 +4387,6 @@ static void mvpp2_rx_time_coal_set(struct mvpp2_port *port,
rxq->time_coal = usec;
}
-/* Set threshold for TX_DONE pkts coalescing */
-static void mvpp2_tx_done_pkts_coal_set(void *arg)
-{
- struct mvpp2_port *port = arg;
- int queue;
- u32 val;
-
- for (queue = 0; queue < txq_number; queue++) {
- struct mvpp2_tx_queue *txq = port->txqs[queue];
-
- val = (txq->done_pkts_coal << MVPP2_TRANSMITTED_THRESH_OFFSET) &
- MVPP2_TRANSMITTED_THRESH_MASK;
- mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id);
- mvpp2_write(port->priv, MVPP2_TXQ_THRESH_REG, val);
- }
-}
-
/* Free Tx queue skbuffs */
static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
struct mvpp2_tx_queue *txq,
@@ -4407,8 +4395,8 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
int i;
for (i = 0; i < num; i++) {
- struct mvpp2_tx_desc *tx_desc = txq->descs +
- txq_pcpu->txq_get_index;
+ dma_addr_t buf_phys_addr =
+ txq_pcpu->tx_buffs[txq_pcpu->txq_get_index];
struct sk_buff *skb = txq_pcpu->tx_skb[txq_pcpu->txq_get_index];
mvpp2_txq_inc_get(txq_pcpu);
@@ -4416,8 +4404,8 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
if (!skb)
continue;
- dma_unmap_single(port->dev->dev.parent, tx_desc->buf_phys_addr,
- tx_desc->data_size, DMA_TO_DEVICE);
+ dma_unmap_single(port->dev->dev.parent, buf_phys_addr,
+ skb_headlen(skb), DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
}
}
@@ -4433,7 +4421,7 @@ static inline struct mvpp2_rx_queue *mvpp2_get_rx_queue(struct mvpp2_port *port,
static inline struct mvpp2_tx_queue *mvpp2_get_tx_queue(struct mvpp2_port *port,
u32 cause)
{
- int queue = fls(cause >> 16) - 1;
+ int queue = fls(cause) - 1;
return port->txqs[queue];
}
@@ -4460,6 +4448,29 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
netif_tx_wake_queue(nq);
}
+static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause)
+{
+ struct mvpp2_tx_queue *txq;
+ struct mvpp2_txq_pcpu *txq_pcpu;
+ unsigned int tx_todo = 0;
+
+ while (cause) {
+ txq = mvpp2_get_tx_queue(port, cause);
+ if (!txq)
+ break;
+
+ txq_pcpu = this_cpu_ptr(txq->pcpu);
+
+ if (txq_pcpu->count) {
+ mvpp2_txq_done(port, txq, txq_pcpu);
+ tx_todo += txq_pcpu->count;
+ }
+
+ cause &= ~(1 << txq->log_id);
+ }
+ return tx_todo;
+}
+
/* Rx/Tx queue initialization/cleanup methods */
/* Allocate and initialize descriptors for aggr TXQ */
@@ -4649,12 +4660,13 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
txq_pcpu->tx_skb = kmalloc(txq_pcpu->size *
sizeof(*txq_pcpu->tx_skb),
GFP_KERNEL);
- if (!txq_pcpu->tx_skb) {
- dma_free_coherent(port->dev->dev.parent,
- txq->size * MVPP2_DESC_ALIGNED_SIZE,
- txq->descs, txq->descs_phys);
- return -ENOMEM;
- }
+ if (!txq_pcpu->tx_skb)
+ goto error;
+
+ txq_pcpu->tx_buffs = kmalloc(txq_pcpu->size *
+ sizeof(dma_addr_t), GFP_KERNEL);
+ if (!txq_pcpu->tx_buffs)
+ goto error;
txq_pcpu->count = 0;
txq_pcpu->reserved_num = 0;
@@ -4663,6 +4675,19 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
}
return 0;
+
+error:
+ for_each_present_cpu(cpu) {
+ txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
+ kfree(txq_pcpu->tx_skb);
+ kfree(txq_pcpu->tx_buffs);
+ }
+
+ dma_free_coherent(port->dev->dev.parent,
+ txq->size * MVPP2_DESC_ALIGNED_SIZE,
+ txq->descs, txq->descs_phys);
+
+ return -ENOMEM;
}
/* Free allocated TXQ resources */
@@ -4675,6 +4700,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port,
for_each_present_cpu(cpu) {
txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
kfree(txq_pcpu->tx_skb);
+ kfree(txq_pcpu->tx_buffs);
}
if (txq->descs)
@@ -4805,7 +4831,6 @@ static int mvpp2_setup_txqs(struct mvpp2_port *port)
goto err_cleanup;
}
- on_each_cpu(mvpp2_tx_done_pkts_coal_set, port, 1);
on_each_cpu(mvpp2_txq_sent_counter_clear, port, 1);
return 0;
@@ -4887,6 +4912,49 @@ static void mvpp2_link_event(struct net_device *dev)
}
}
+static void mvpp2_timer_set(struct mvpp2_port_pcpu *port_pcpu)
+{
+ ktime_t interval;
+
+ if (!port_pcpu->timer_scheduled) {
+ port_pcpu->timer_scheduled = true;
+ interval = ktime_set(0, MVPP2_TXDONE_HRTIMER_PERIOD_NS);
+ hrtimer_start(&port_pcpu->tx_done_timer, interval,
+ HRTIMER_MODE_REL_PINNED);
+ }
+}
+
+static void mvpp2_tx_proc_cb(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct mvpp2_port *port = netdev_priv(dev);
+ struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu);
+ unsigned int tx_todo, cause;
+
+ if (!netif_running(dev))
+ return;
+ port_pcpu->timer_scheduled = false;
+
+ /* Process all the Tx queues */
+ cause = (1 << txq_number) - 1;
+ tx_todo = mvpp2_tx_done(port, cause);
+
+ /* Set the timer in case not all the packets were processed */
+ if (tx_todo)
+ mvpp2_timer_set(port_pcpu);
+}
+
+static enum hrtimer_restart mvpp2_hr_timer_cb(struct hrtimer *timer)
+{
+ struct mvpp2_port_pcpu *port_pcpu = container_of(timer,
+ struct mvpp2_port_pcpu,
+ tx_done_timer);
+
+ tasklet_schedule(&port_pcpu->tx_done_tasklet);
+
+ return HRTIMER_NORESTART;
+}
+
/* Main RX/TX processing routines */
/* Display more error info */
@@ -5144,11 +5212,11 @@ static int mvpp2_tx_frag_process(struct mvpp2_port *port, struct sk_buff *skb,
if (i == (skb_shinfo(skb)->nr_frags - 1)) {
/* Last descriptor */
tx_desc->command = MVPP2_TXD_L_DESC;
- mvpp2_txq_inc_put(txq_pcpu, skb);
+ mvpp2_txq_inc_put(txq_pcpu, skb, tx_desc);
} else {
/* Descriptor in the middle: Not First, Not Last */
tx_desc->command = 0;
- mvpp2_txq_inc_put(txq_pcpu, NULL);
+ mvpp2_txq_inc_put(txq_pcpu, NULL, tx_desc);
}
}
@@ -5214,12 +5282,12 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
/* First and Last descriptor */
tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC;
tx_desc->command = tx_cmd;
- mvpp2_txq_inc_put(txq_pcpu, skb);
+ mvpp2_txq_inc_put(txq_pcpu, skb, tx_desc);
} else {
/* First but not Last */
tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_PADDING_DISABLE;
tx_desc->command = tx_cmd;
- mvpp2_txq_inc_put(txq_pcpu, NULL);
+ mvpp2_txq_inc_put(txq_pcpu, NULL, tx_desc);
/* Continue with other skb fragments */
if (mvpp2_tx_frag_process(port, skb, aggr_txq, txq)) {
@@ -5255,6 +5323,17 @@ out:
dev_kfree_skb_any(skb);
}
+ /* Finalize TX processing */
+ if (txq_pcpu->count >= txq->done_pkts_coal)
+ mvpp2_txq_done(port, txq, txq_pcpu);
+
+ /* Set the timer in case not all frags were processed */
+ if (txq_pcpu->count <= frags && txq_pcpu->count > 0) {
+ struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu);
+
+ mvpp2_timer_set(port_pcpu);
+ }
+
return NETDEV_TX_OK;
}
@@ -5268,10 +5347,11 @@ static inline void mvpp2_cause_error(struct net_device *dev, int cause)
netdev_err(dev, "tx fifo underrun error\n");
}
-static void mvpp2_txq_done_percpu(void *arg)
+static int mvpp2_poll(struct napi_struct *napi, int budget)
{
- struct mvpp2_port *port = arg;
- u32 cause_rx_tx, cause_tx, cause_misc;
+ u32 cause_rx_tx, cause_rx, cause_misc;
+ int rx_done = 0;
+ struct mvpp2_port *port = netdev_priv(napi->dev);
/* Rx/Tx cause register
*
@@ -5285,7 +5365,7 @@ static void mvpp2_txq_done_percpu(void *arg)
*/
cause_rx_tx = mvpp2_read(port->priv,
MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
- cause_tx = cause_rx_tx & MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
+ cause_rx_tx &= ~MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK;
if (cause_misc) {
@@ -5297,26 +5377,6 @@ static void mvpp2_txq_done_percpu(void *arg)
cause_rx_tx & ~MVPP2_CAUSE_MISC_SUM_MASK);
}
- /* Release TX descriptors */
- if (cause_tx) {
- struct mvpp2_tx_queue *txq = mvpp2_get_tx_queue(port, cause_tx);
- struct mvpp2_txq_pcpu *txq_pcpu = this_cpu_ptr(txq->pcpu);
-
- if (txq_pcpu->count)
- mvpp2_txq_done(port, txq, txq_pcpu);
- }
-}
-
-static int mvpp2_poll(struct napi_struct *napi, int budget)
-{
- u32 cause_rx_tx, cause_rx;
- int rx_done = 0;
- struct mvpp2_port *port = netdev_priv(napi->dev);
-
- on_each_cpu(mvpp2_txq_done_percpu, port, 1);
-
- cause_rx_tx = mvpp2_read(port->priv,
- MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
/* Process RX packets */
@@ -5561,6 +5621,8 @@ err_cleanup_rxqs:
static int mvpp2_stop(struct net_device *dev)
{
struct mvpp2_port *port = netdev_priv(dev);
+ struct mvpp2_port_pcpu *port_pcpu;
+ int cpu;
mvpp2_stop_dev(port);
mvpp2_phy_disconnect(port);
@@ -5569,6 +5631,13 @@ static int mvpp2_stop(struct net_device *dev)
on_each_cpu(mvpp2_interrupts_mask, port, 1);
free_irq(port->irq, port);
+ for_each_present_cpu(cpu) {
+ port_pcpu = per_cpu_ptr(port->pcpu, cpu);
+
+ hrtimer_cancel(&port_pcpu->tx_done_timer);
+ port_pcpu->timer_scheduled = false;
+ tasklet_kill(&port_pcpu->tx_done_tasklet);
+ }
mvpp2_cleanup_rxqs(port);
mvpp2_cleanup_txqs(port);
@@ -5784,7 +5853,6 @@ static int mvpp2_ethtool_set_coalesce(struct net_device *dev,
txq->done_pkts_coal = c->tx_max_coalesced_frames;
}
- on_each_cpu(mvpp2_tx_done_pkts_coal_set, port, 1);
return 0;
}
@@ -6035,6 +6103,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
{
struct device_node *phy_node;
struct mvpp2_port *port;
+ struct mvpp2_port_pcpu *port_pcpu;
struct net_device *dev;
struct resource *res;
const char *dt_mac_addr;
@@ -6044,7 +6113,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
int features;
int phy_mode;
int priv_common_regs_num = 2;
- int err, i;
+ int err, i, cpu;
dev = alloc_etherdev_mqs(sizeof(struct mvpp2_port), txq_number,
rxq_number);
@@ -6135,6 +6204,24 @@ static int mvpp2_port_probe(struct platform_device *pdev,
}
mvpp2_port_power_up(port);
+ port->pcpu = alloc_percpu(struct mvpp2_port_pcpu);
+ if (!port->pcpu) {
+ err = -ENOMEM;
+ goto err_free_txq_pcpu;
+ }
+
+ for_each_present_cpu(cpu) {
+ port_pcpu = per_cpu_ptr(port->pcpu, cpu);
+
+ hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL_PINNED);
+ port_pcpu->tx_done_timer.function = mvpp2_hr_timer_cb;
+ port_pcpu->timer_scheduled = false;
+
+ tasklet_init(&port_pcpu->tx_done_tasklet, mvpp2_tx_proc_cb,
+ (unsigned long)dev);
+ }
+
netif_napi_add(dev, &port->napi, mvpp2_poll, NAPI_POLL_WEIGHT);
features = NETIF_F_SG | NETIF_F_IP_CSUM;
dev->features = features | NETIF_F_RXCSUM;
@@ -6144,7 +6231,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
err = register_netdev(dev);
if (err < 0) {
dev_err(&pdev->dev, "failed to register netdev\n");
- goto err_free_txq_pcpu;
+ goto err_free_port_pcpu;
}
netdev_info(dev, "Using %s mac address %pM\n", mac_from, dev->dev_addr);
@@ -6153,6 +6240,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
priv->port_list[id] = port;
return 0;
+err_free_port_pcpu:
+ free_percpu(port->pcpu);
err_free_txq_pcpu:
for (i = 0; i < txq_number; i++)
free_percpu(port->txqs[i]->pcpu);
@@ -6171,6 +6260,7 @@ static void mvpp2_port_remove(struct mvpp2_port *port)
int i;
unregister_netdev(port->dev);
+ free_percpu(port->pcpu);
free_percpu(port->stats);
for (i = 0; i < txq_number; i++)
free_percpu(port->txqs[i]->pcpu);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index afad529..06e3e1e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -391,6 +391,8 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)
/* disable cmdif checksum */
MLX5_SET(cmd_hca_cap, set_hca_cap, cmdif_checksum, 0);
+ MLX5_SET(cmd_hca_cap, set_hca_cap, log_uar_page_sz, PAGE_SHIFT - 12);
+
err = set_caps(dev, set_ctx, set_sz);
query_ex:
diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c
index f78909a..09d2e16 100644
--- a/drivers/net/ethernet/micrel/ks8842.c
+++ b/drivers/net/ethernet/micrel/ks8842.c
@@ -952,9 +952,8 @@ static int ks8842_alloc_dma_bufs(struct net_device *netdev)
sg_dma_address(&tx_ctl->sg) = dma_map_single(adapter->dev,
tx_ctl->buf, DMA_BUFFER_SIZE, DMA_TO_DEVICE);
- err = dma_mapping_error(adapter->dev,
- sg_dma_address(&tx_ctl->sg));
- if (err) {
+ if (dma_mapping_error(adapter->dev, sg_dma_address(&tx_ctl->sg))) {
+ err = -ENOMEM;
sg_dma_address(&tx_ctl->sg) = 0;
goto err;
}
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 3df51fa..f790f61 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -4875,10 +4875,12 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_46:
case RTL_GIGA_MAC_VER_47:
case RTL_GIGA_MAC_VER_48:
+ RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
+ break;
case RTL_GIGA_MAC_VER_49:
case RTL_GIGA_MAC_VER_50:
case RTL_GIGA_MAC_VER_51:
- RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
+ RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
break;
default:
RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST);
diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index 2d8578cade..2e7f9a2 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -4821,6 +4821,7 @@ static void rocker_remove_ports(const struct rocker *rocker)
rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE,
ROCKER_OP_FLAG_REMOVE);
unregister_netdev(rocker_port->dev);
+ free_netdev(rocker_port->dev);
}
kfree(rocker->ports);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
index 7e3129e..f0e4bb4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
@@ -42,7 +42,7 @@
#define NSS_COMMON_CLK_DIV_MASK 0x7f
#define NSS_COMMON_CLK_SRC_CTRL 0x14
-#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x) (1 << x)
+#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x) (x)
/* Mode is coded on 1 bit but is different depending on the MAC ID:
* MAC0: QSGMII=0 RGMII=1
* MAC1: QSGMII=0 SGMII=0 RGMII=1
@@ -291,7 +291,7 @@ static void *ipq806x_gmac_setup(struct platform_device *pdev)
/* Configure the clock src according to the mode */
regmap_read(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, &val);
- val &= ~NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
+ val &= ~(1 << NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id));
switch (gmac->phy_mode) {
case PHY_INTERFACE_MODE_RGMII:
val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) <<
diff --git a/drivers/net/ethernet/ti/netcp.h b/drivers/net/ethernet/ti/netcp.h
index a8a7306..bb1bb72 100644
--- a/drivers/net/ethernet/ti/netcp.h
+++ b/drivers/net/ethernet/ti/netcp.h
@@ -85,7 +85,6 @@ struct netcp_intf {
struct list_head rxhook_list_head;
unsigned int rx_queue_id;
void *rx_fdq[KNAV_DMA_FDQ_PER_CHAN];
- u32 rx_buffer_sizes[KNAV_DMA_FDQ_PER_CHAN];
struct napi_struct rx_napi;
struct napi_struct tx_napi;
diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c
index 9749dfd..4755838 100644
--- a/drivers/net/ethernet/ti/netcp_core.c
+++ b/drivers/net/ethernet/ti/netcp_core.c
@@ -34,6 +34,7 @@
#define NETCP_SOP_OFFSET (NET_IP_ALIGN + NET_SKB_PAD)
#define NETCP_NAPI_WEIGHT 64
#define NETCP_TX_TIMEOUT (5 * HZ)
+#define NETCP_PACKET_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN)
#define NETCP_MIN_PACKET_SIZE ETH_ZLEN
#define NETCP_MAX_MCAST_ADDR 16
@@ -804,30 +805,28 @@ static void netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
if (likely(fdq == 0)) {
unsigned int primary_buf_len;
/* Allocate a primary receive queue entry */
- buf_len = netcp->rx_buffer_sizes[0] + NETCP_SOP_OFFSET;
+ buf_len = NETCP_PACKET_SIZE + NETCP_SOP_OFFSET;
primary_buf_len = SKB_DATA_ALIGN(buf_len) +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
- if (primary_buf_len <= PAGE_SIZE) {
- bufptr = netdev_alloc_frag(primary_buf_len);
- pad[1] = primary_buf_len;
- } else {
- bufptr = kmalloc(primary_buf_len, GFP_ATOMIC |
- GFP_DMA32 | __GFP_COLD);
- pad[1] = 0;
- }
+ bufptr = netdev_alloc_frag(primary_buf_len);
+ pad[1] = primary_buf_len;
if (unlikely(!bufptr)) {
- dev_warn_ratelimited(netcp->ndev_dev, "Primary RX buffer alloc failed\n");
+ dev_warn_ratelimited(netcp->ndev_dev,
+ "Primary RX buffer alloc failed\n");
goto fail;
}
dma = dma_map_single(netcp->dev, bufptr, buf_len,
DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(netcp->dev, dma)))
+ goto fail;
+
pad[0] = (u32)bufptr;
} else {
/* Allocate a secondary receive queue entry */
- page = alloc_page(GFP_ATOMIC | GFP_DMA32 | __GFP_COLD);
+ page = alloc_page(GFP_ATOMIC | GFP_DMA | __GFP_COLD);
if (unlikely(!page)) {
dev_warn_ratelimited(netcp->ndev_dev, "Secondary page alloc failed\n");
goto fail;
@@ -1010,7 +1009,7 @@ netcp_tx_map_skb(struct sk_buff *skb, struct netcp_intf *netcp)
/* Map the linear buffer */
dma_addr = dma_map_single(dev, skb->data, pkt_len, DMA_TO_DEVICE);
- if (unlikely(!dma_addr)) {
+ if (unlikely(dma_mapping_error(dev, dma_addr))) {
dev_err(netcp->ndev_dev, "Failed to map skb buffer\n");
return NULL;
}
@@ -1546,8 +1545,8 @@ static int netcp_setup_navigator_resources(struct net_device *ndev)
knav_queue_disable_notify(netcp->rx_queue);
/* open Rx FDQs */
- for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN &&
- netcp->rx_queue_depths[i] && netcp->rx_buffer_sizes[i]; ++i) {
+ for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && netcp->rx_queue_depths[i];
+ ++i) {
snprintf(name, sizeof(name), "rx-fdq-%s-%d", ndev->name, i);
netcp->rx_fdq[i] = knav_queue_open(name, KNAV_QUEUE_GP, 0);
if (IS_ERR_OR_NULL(netcp->rx_fdq[i])) {
@@ -1941,14 +1940,6 @@ static int netcp_create_interface(struct netcp_device *netcp_device,
netcp->rx_queue_depths[0] = 128;
}
- ret = of_property_read_u32_array(node_interface, "rx-buffer-size",
- netcp->rx_buffer_sizes,
- KNAV_DMA_FDQ_PER_CHAN);
- if (ret) {
- dev_err(dev, "missing \"rx-buffer-size\" parameter\n");
- netcp->rx_buffer_sizes[0] = 1536;
- }
-
ret = of_property_read_u32_array(node_interface, "rx-pool", temp, 2);
if (ret < 0) {
dev_err(dev, "missing \"rx-pool\" parameter\n");
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 2ffbf13..216bfd3 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -728,11 +728,12 @@ static int mkiss_open(struct tty_struct *tty)
dev->type = ARPHRD_AX25;
/* Perform the low-level AX25 initialization. */
- if ((err = ax_open(ax->dev))) {
+ err = ax_open(ax->dev);
+ if (err)
goto out_free_netdev;
- }
- if (register_netdev(dev))
+ err = register_netdev(dev);
+ if (err)
goto out_free_buffers;
/* after register_netdev() - because else printk smashes the kernel */
diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c
index 3cc316cb..d8757bf 100644
--- a/drivers/net/ntb_netdev.c
+++ b/drivers/net/ntb_netdev.c
@@ -102,6 +102,12 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
netdev_dbg(ndev, "%s: %d byte payload received\n", __func__, len);
+ if (len < 0) {
+ ndev->stats.rx_errors++;
+ ndev->stats.rx_length_errors++;
+ goto enqueue_again;
+ }
+
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, ndev);
skb->ip_summed = CHECKSUM_NONE;
@@ -121,6 +127,7 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
return;
}
+enqueue_again:
rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
if (rc) {
dev_kfree_skb(skb);
@@ -184,7 +191,7 @@ static int ntb_netdev_open(struct net_device *ndev)
rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
ndev->mtu + ETH_HLEN);
- if (rc == -EINVAL) {
+ if (rc) {
dev_kfree_skb(skb);
goto err;
}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index b2197b5..1e1fbb0 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -811,6 +811,7 @@ void phy_state_machine(struct work_struct *work)
bool needs_aneg = false, do_suspend = false;
enum phy_state old_state;
int err = 0;
+ int old_link;
mutex_lock(&phydev->lock);
@@ -896,11 +897,18 @@ void phy_state_machine(struct work_struct *work)
phydev->adjust_link(phydev->attached_dev);
break;
case PHY_RUNNING:
- /* Only register a CHANGE if we are
- * polling or ignoring interrupts
+ /* Only register a CHANGE if we are polling or ignoring
+ * interrupts and link changed since latest checking.
*/
- if (!phy_interrupt_is_valid(phydev))
- phydev->state = PHY_CHANGELINK;
+ if (!phy_interrupt_is_valid(phydev)) {
+ old_link = phydev->link;
+ err = phy_read_status(phydev);
+ if (err)
+ break;
+
+ if (old_link != phydev->link)
+ phydev->state = PHY_CHANGELINK;
+ }
break;
case PHY_CHANGELINK:
err = phy_read_status(phydev);
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index c0f6479e..70b0895 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -91,19 +91,18 @@ static int lan911x_config_init(struct phy_device *phydev)
}
/*
- * The LAN8710/LAN8720 requires a minimum of 2 link pulses within 64ms of each
- * other in order to set the ENERGYON bit and exit EDPD mode. If a link partner
- * does send the pulses within this interval, the PHY will remained powered
- * down.
- *
- * This workaround will manually toggle the PHY on/off upon calls to read_status
- * in order to generate link test pulses if the link is down. If a link partner
- * is present, it will respond to the pulses, which will cause the ENERGYON bit
- * to be set and will cause the EDPD mode to be exited.
+ * The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable
+ * plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to
+ * unstable detection of plugging in Ethernet cable.
+ * This workaround disables Energy Detect Power-Down mode and waiting for
+ * response on link pulses to detect presence of plugged Ethernet cable.
+ * The Energy Detect Power-Down mode is enabled again in the end of procedure to
+ * save approximately 220 mW of power if cable is unplugged.
*/
static int lan87xx_read_status(struct phy_device *phydev)
{
int err = genphy_read_status(phydev);
+ int i;
if (!phydev->link) {
/* Disable EDPD to wake up PHY */
@@ -116,8 +115,16 @@ static int lan87xx_read_status(struct phy_device *phydev)
if (rc < 0)
return rc;
- /* Sleep 64 ms to allow ~5 link test pulses to be sent */
- msleep(64);
+ /* Wait max 640 ms to detect energy */
+ for (i = 0; i < 64; i++) {
+ /* Sleep to allow link test pulses to be sent */
+ msleep(10);
+ rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
+ if (rc < 0)
+ return rc;
+ if (rc & MII_LAN83C185_ENERGYON)
+ break;
+ }
/* Re-enable EDPD */
rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
@@ -191,7 +198,7 @@ static struct phy_driver smsc_phy_driver[] = {
/* basic functions */
.config_aneg = genphy_config_aneg,
- .read_status = genphy_read_status,
+ .read_status = lan87xx_read_status,
.config_init = smsc_phy_config_init,
.soft_reset = smsc_phy_reset,
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 9d15566..fa8f504 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -269,9 +269,9 @@ static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound);
static void ppp_ccp_closed(struct ppp *ppp);
static struct compressor *find_compressor(int type);
static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st);
-static struct ppp *ppp_create_interface(struct net *net, int unit, int *retp);
+static struct ppp *ppp_create_interface(struct net *net, int unit,
+ struct file *file, int *retp);
static void init_ppp_file(struct ppp_file *pf, int kind);
-static void ppp_shutdown_interface(struct ppp *ppp);
static void ppp_destroy_interface(struct ppp *ppp);
static struct ppp *ppp_find_unit(struct ppp_net *pn, int unit);
static struct channel *ppp_find_channel(struct ppp_net *pn, int unit);
@@ -392,8 +392,10 @@ static int ppp_release(struct inode *unused, struct file *file)
file->private_data = NULL;
if (pf->kind == INTERFACE) {
ppp = PF_TO_PPP(pf);
+ rtnl_lock();
if (file == ppp->owner)
- ppp_shutdown_interface(ppp);
+ unregister_netdevice(ppp->dev);
+ rtnl_unlock();
}
if (atomic_dec_and_test(&pf->refcnt)) {
switch (pf->kind) {
@@ -593,8 +595,10 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
mutex_lock(&ppp_mutex);
if (pf->kind == INTERFACE) {
ppp = PF_TO_PPP(pf);
+ rtnl_lock();
if (file == ppp->owner)
- ppp_shutdown_interface(ppp);
+ unregister_netdevice(ppp->dev);
+ rtnl_unlock();
}
if (atomic_long_read(&file->f_count) < 2) {
ppp_release(NULL, file);
@@ -838,11 +842,10 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
/* Create a new ppp unit */
if (get_user(unit, p))
break;
- ppp = ppp_create_interface(net, unit, &err);
+ ppp = ppp_create_interface(net, unit, file, &err);
if (!ppp)
break;
file->private_data = &ppp->file;
- ppp->owner = file;
err = -EFAULT;
if (put_user(ppp->file.index, p))
break;
@@ -916,6 +919,16 @@ static __net_init int ppp_init_net(struct net *net)
static __net_exit void ppp_exit_net(struct net *net)
{
struct ppp_net *pn = net_generic(net, ppp_net_id);
+ struct ppp *ppp;
+ LIST_HEAD(list);
+ int id;
+
+ rtnl_lock();
+ idr_for_each_entry(&pn->units_idr, ppp, id)
+ unregister_netdevice_queue(ppp->dev, &list);
+
+ unregister_netdevice_many(&list);
+ rtnl_unlock();
idr_destroy(&pn->units_idr);
}
@@ -1088,8 +1101,28 @@ static int ppp_dev_init(struct net_device *dev)
return 0;
}
+static void ppp_dev_uninit(struct net_device *dev)
+{
+ struct ppp *ppp = netdev_priv(dev);
+ struct ppp_net *pn = ppp_pernet(ppp->ppp_net);
+
+ ppp_lock(ppp);
+ ppp->closing = 1;
+ ppp_unlock(ppp);
+
+ mutex_lock(&pn->all_ppp_mutex);
+ unit_put(&pn->units_idr, ppp->file.index);
+ mutex_unlock(&pn->all_ppp_mutex);
+
+ ppp->owner = NULL;
+
+ ppp->file.dead = 1;
+ wake_up_interruptible(&ppp->file.rwait);
+}
+
static const struct net_device_ops ppp_netdev_ops = {
.ndo_init = ppp_dev_init,
+ .ndo_uninit = ppp_dev_uninit,
.ndo_start_xmit = ppp_start_xmit,
.ndo_do_ioctl = ppp_net_ioctl,
.ndo_get_stats64 = ppp_get_stats64,
@@ -2667,8 +2700,8 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st)
* or if there is already a unit with the requested number.
* unit == -1 means allocate a new number.
*/
-static struct ppp *
-ppp_create_interface(struct net *net, int unit, int *retp)
+static struct ppp *ppp_create_interface(struct net *net, int unit,
+ struct file *file, int *retp)
{
struct ppp *ppp;
struct ppp_net *pn;
@@ -2688,6 +2721,7 @@ ppp_create_interface(struct net *net, int unit, int *retp)
ppp->mru = PPP_MRU;
init_ppp_file(&ppp->file, INTERFACE);
ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */
+ ppp->owner = file;
for (i = 0; i < NUM_NP; ++i)
ppp->npmode[i] = NPMODE_PASS;
INIT_LIST_HEAD(&ppp->channels);
@@ -2776,34 +2810,6 @@ init_ppp_file(struct ppp_file *pf, int kind)
}
/*
- * Take down a ppp interface unit - called when the owning file
- * (the one that created the unit) is closed or detached.
- */
-static void ppp_shutdown_interface(struct ppp *ppp)
-{
- struct ppp_net *pn;
-
- pn = ppp_pernet(ppp->ppp_net);
- mutex_lock(&pn->all_ppp_mutex);
-
- /* This will call dev_close() for us. */
- ppp_lock(ppp);
- if (!ppp->closing) {
- ppp->closing = 1;
- ppp_unlock(ppp);
- unregister_netdev(ppp->dev);
- unit_put(&pn->units_idr, ppp->file.index);
- } else
- ppp_unlock(ppp);
-
- ppp->file.dead = 1;
- ppp->owner = NULL;
- wake_up_interruptible(&ppp->file.rwait);
-
- mutex_unlock(&pn->all_ppp_mutex);
-}
-
-/*
* Free the memory used by a ppp unit. This is only called once
* there are no channels connected to the unit and no file structs
* that reference the unit.
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 9d43460..64a60af 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -785,6 +785,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x413c, 0x81a4, 8)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
{QMI_FIXED_INTF(0x413c, 0x81a8, 8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
{QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
+ {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
{QMI_FIXED_INTF(0x03f0, 0x581d, 4)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */
/* 4. Gobi 1000 devices */
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 7fbca37..237f8e5 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -1756,9 +1756,9 @@ static int virtnet_probe(struct virtio_device *vdev)
/* Do we support "hardware" checksums? */
if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
/* This opens up the world of extra features. */
- dev->hw_features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+ dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
if (csum)
- dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+ dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 7193b73..848ea6a 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -589,7 +589,8 @@ static int cosa_probe(int base, int irq, int dma)
chan->netdev->base_addr = chan->cosa->datareg;
chan->netdev->irq = chan->cosa->irq;
chan->netdev->dma = chan->cosa->dma;
- if (register_hdlc_device(chan->netdev)) {
+ err = register_hdlc_device(chan->netdev);
+ if (err) {
netdev_warn(chan->netdev,
"register_hdlc_device() failed\n");
free_netdev(chan->netdev);
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index 25d1cbd..b2f0d24 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -3728,7 +3728,7 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev)
switch (phy->rev) {
case 6:
case 5:
- if (sprom->fem.ghz5.extpa_gain == 3)
+ if (sprom->fem.ghz2.extpa_gain == 3)
return b43_ntab_tx_gain_epa_rev3_hi_pwr_2g;
/* fall through */
case 4:
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 5000bfcd..5514ad6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -1023,7 +1023,7 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
cmd->scan_priority =
iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
- if (iwl_mvm_scan_total_iterations(params) == 0)
+ if (iwl_mvm_scan_total_iterations(params) == 1)
cmd->ooc_priority =
iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
else
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 6203c4a..9e144e7 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -478,10 +478,16 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000)
iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_WAKE_ME);
- else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+ else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
+ iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+ CSR_RESET_LINK_PWR_MGMT_DISABLED);
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_PREPARE |
CSR_HW_IF_CONFIG_REG_ENABLE_PME);
+ mdelay(1);
+ iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+ CSR_RESET_LINK_PWR_MGMT_DISABLED);
+ }
mdelay(5);
}
@@ -575,6 +581,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
if (ret >= 0)
return 0;
+ iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+ CSR_RESET_LINK_PWR_MGMT_DISABLED);
+ msleep(1);
+
for (iter = 0; iter < 10; iter++) {
/* If HW is not ready, prepare the conditions to check again */
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
@@ -582,8 +592,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
do {
ret = iwl_pcie_set_hw_ready(trans);
- if (ret >= 0)
- return 0;
+ if (ret >= 0) {
+ ret = 0;
+ goto out;
+ }
usleep_range(200, 1000);
t += 200;
@@ -593,6 +605,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
IWL_ERR(trans, "Couldn't prepare the card\n");
+out:
+ iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+ CSR_RESET_LINK_PWR_MGMT_DISABLED);
+
return ret;
}
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 2b86c21..607acb5 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -1875,8 +1875,19 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
/* start timer if queue currently empty */
if (q->read_ptr == q->write_ptr) {
- if (txq->wd_timeout)
- mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);
+ if (txq->wd_timeout) {
+ /*
+ * If the TXQ is active, then set the timer, if not,
+ * set the timer in remainder so that the timer will
+ * be armed with the right value when the station will
+ * wake up.
+ */
+ if (!txq->frozen)
+ mod_timer(&txq->stuck_timer,
+ jiffies + txq->wd_timeout);
+ else
+ txq->frozen_expiry_remainder = txq->wd_timeout;
+ }
IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id);
iwl_trans_pcie_ref(trans);
}
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index b6cc9ff..1c6788a 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -172,6 +172,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
(struct rsi_91x_sdiodev *)adapter->rsi_dev;
u32 len;
u32 num_blocks;
+ const u8 *fw;
const struct firmware *fw_entry = NULL;
u32 block_size = dev->tx_blk_size;
int status = 0;
@@ -200,6 +201,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
return status;
}
+ /* Copy firmware into DMA-accessible memory */
+ fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+ if (!fw)
+ return -ENOMEM;
len = fw_entry->size;
if (len % 4)
@@ -210,7 +215,8 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len);
rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
- status = rsi_copy_to_card(common, fw_entry->data, len, num_blocks);
+ status = rsi_copy_to_card(common, fw, len, num_blocks);
+ kfree(fw);
release_firmware(fw_entry);
return status;
}
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
index 1106ce7..30c2cf7 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
@@ -146,7 +146,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
return status;
}
+ /* Copy firmware into DMA-accessible memory */
fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+ if (!fw)
+ return -ENOMEM;
len = fw_entry->size;
if (len % 4)
@@ -158,6 +161,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
status = rsi_copy_to_card(common, fw, len, num_blocks);
+ kfree(fw);
release_firmware(fw_entry);
return status;
}
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index 3b3a88b..585d088 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -1015,9 +1015,12 @@ static void send_beacon_frame(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
+ struct rtl_tcb_desc tcb_desc;
- if (skb)
- rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, NULL);
+ if (skb) {
+ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+ rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc);
+ }
}
static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c
index 1017f02..7bf88d9 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c
@@ -385,6 +385,7 @@ module_param_named(debug, rtl8723be_mod_params.debug, int, 0444);
module_param_named(ips, rtl8723be_mod_params.inactiveps, bool, 0444);
module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444);
module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444);
+module_param_named(msi, rtl8723be_mod_params.msi_support, bool, 0444);
module_param_named(disable_watchdog, rtl8723be_mod_params.disable_watchdog,
bool, 0444);
MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 1a83e19..28577a3 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -61,6 +61,12 @@ void xenvif_skb_zerocopy_prepare(struct xenvif_queue *queue,
void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue)
{
atomic_dec(&queue->inflight_packets);
+
+ /* Wake the dealloc thread _after_ decrementing inflight_packets so
+ * that if kthread_stop() has already been called, the dealloc thread
+ * does not wait forever with nothing to wake it.
+ */
+ wake_up(&queue->dealloc_wq);
}
int xenvif_schedulable(struct xenvif *vif)
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 7d50711..3f44b52 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -810,23 +810,17 @@ static inline struct sk_buff *xenvif_alloc_skb(unsigned int size)
static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *queue,
struct sk_buff *skb,
struct xen_netif_tx_request *txp,
- struct gnttab_map_grant_ref *gop)
+ struct gnttab_map_grant_ref *gop,
+ unsigned int frag_overflow,
+ struct sk_buff *nskb)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
skb_frag_t *frags = shinfo->frags;
u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
int start;
pending_ring_idx_t index;
- unsigned int nr_slots, frag_overflow = 0;
+ unsigned int nr_slots;
- /* At this point shinfo->nr_frags is in fact the number of
- * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX.
- */
- if (shinfo->nr_frags > MAX_SKB_FRAGS) {
- frag_overflow = shinfo->nr_frags - MAX_SKB_FRAGS;
- BUG_ON(frag_overflow > MAX_SKB_FRAGS);
- shinfo->nr_frags = MAX_SKB_FRAGS;
- }
nr_slots = shinfo->nr_frags;
/* Skip first skb fragment if it is on same page as header fragment. */
@@ -841,13 +835,6 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *que
}
if (frag_overflow) {
- struct sk_buff *nskb = xenvif_alloc_skb(0);
- if (unlikely(nskb == NULL)) {
- if (net_ratelimit())
- netdev_err(queue->vif->dev,
- "Can't allocate the frag_list skb.\n");
- return NULL;
- }
shinfo = skb_shinfo(nskb);
frags = shinfo->frags;
@@ -1175,9 +1162,10 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
unsigned *copy_ops,
unsigned *map_ops)
{
- struct gnttab_map_grant_ref *gop = queue->tx_map_ops, *request_gop;
- struct sk_buff *skb;
+ struct gnttab_map_grant_ref *gop = queue->tx_map_ops;
+ struct sk_buff *skb, *nskb;
int ret;
+ unsigned int frag_overflow;
while (skb_queue_len(&queue->tx_queue) < budget) {
struct xen_netif_tx_request txreq;
@@ -1265,6 +1253,29 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
break;
}
+ skb_shinfo(skb)->nr_frags = ret;
+ if (data_len < txreq.size)
+ skb_shinfo(skb)->nr_frags++;
+ /* At this point shinfo->nr_frags is in fact the number of
+ * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX.
+ */
+ frag_overflow = 0;
+ nskb = NULL;
+ if (skb_shinfo(skb)->nr_frags > MAX_SKB_FRAGS) {
+ frag_overflow = skb_shinfo(skb)->nr_frags - MAX_SKB_FRAGS;
+ BUG_ON(frag_overflow > MAX_SKB_FRAGS);
+ skb_shinfo(skb)->nr_frags = MAX_SKB_FRAGS;
+ nskb = xenvif_alloc_skb(0);
+ if (unlikely(nskb == NULL)) {
+ kfree_skb(skb);
+ xenvif_tx_err(queue, &txreq, idx);
+ if (net_ratelimit())
+ netdev_err(queue->vif->dev,
+ "Can't allocate the frag_list skb.\n");
+ break;
+ }
+ }
+
if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
struct xen_netif_extra_info *gso;
gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
@@ -1272,6 +1283,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
if (xenvif_set_skb_gso(queue->vif, skb, gso)) {
/* Failure in xenvif_set_skb_gso is fatal. */
kfree_skb(skb);
+ kfree_skb(nskb);
break;
}
}
@@ -1294,9 +1306,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
(*copy_ops)++;
- skb_shinfo(skb)->nr_frags = ret;
if (data_len < txreq.size) {
- skb_shinfo(skb)->nr_frags++;
frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
pending_idx);
xenvif_tx_create_map_op(queue, pending_idx, &txreq, gop);
@@ -1310,13 +1320,8 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
queue->pending_cons++;
- request_gop = xenvif_get_requests(queue, skb, txfrags, gop);
- if (request_gop == NULL) {
- kfree_skb(skb);
- xenvif_tx_err(queue, &txreq, idx);
- break;
- }
- gop = request_gop;
+ gop = xenvif_get_requests(queue, skb, txfrags, gop,
+ frag_overflow, nskb);
__skb_queue_tail(&queue->tx_queue, skb);
@@ -1536,7 +1541,6 @@ void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success)
smp_wmb();
queue->dealloc_prod++;
} while (ubuf);
- wake_up(&queue->dealloc_wq);
spin_unlock_irqrestore(&queue->callback_lock, flags);
if (likely(zerocopy_success))
diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c
index 23435f2..2e25307 100644
--- a/drivers/ntb/ntb.c
+++ b/drivers/ntb/ntb.c
@@ -114,7 +114,7 @@ int ntb_register_device(struct ntb_dev *ntb)
ntb->dev.bus = &ntb_bus;
ntb->dev.parent = &ntb->pdev->dev;
ntb->dev.release = ntb_dev_release;
- dev_set_name(&ntb->dev, pci_name(ntb->pdev));
+ dev_set_name(&ntb->dev, "%s", pci_name(ntb->pdev));
ntb->ctx = NULL;
ntb->ctx_ops = NULL;
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index efe3ad4..1c6386d 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -142,10 +142,11 @@ struct ntb_transport_qp {
void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data,
void *data, int len);
+ struct list_head rx_post_q;
struct list_head rx_pend_q;
struct list_head rx_free_q;
- spinlock_t ntb_rx_pend_q_lock;
- spinlock_t ntb_rx_free_q_lock;
+ /* ntb_rx_q_lock: synchronize access to rx_XXXX_q */
+ spinlock_t ntb_rx_q_lock;
void *rx_buff;
unsigned int rx_index;
unsigned int rx_max_entry;
@@ -211,6 +212,8 @@ struct ntb_transport_ctx {
bool link_is_up;
struct delayed_work link_work;
struct work_struct link_cleanup;
+
+ struct dentry *debugfs_node_dir;
};
enum {
@@ -436,13 +439,17 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
char *buf;
ssize_t ret, out_offset, out_count;
+ qp = filp->private_data;
+
+ if (!qp || !qp->link_is_up)
+ return 0;
+
out_count = 1000;
buf = kmalloc(out_count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- qp = filp->private_data;
out_offset = 0;
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"NTB QP stats\n");
@@ -534,6 +541,27 @@ out:
return entry;
}
+static struct ntb_queue_entry *ntb_list_mv(spinlock_t *lock,
+ struct list_head *list,
+ struct list_head *to_list)
+{
+ struct ntb_queue_entry *entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
+
+ if (list_empty(list)) {
+ entry = NULL;
+ } else {
+ entry = list_first_entry(list, struct ntb_queue_entry, entry);
+ list_move_tail(&entry->entry, to_list);
+ }
+
+ spin_unlock_irqrestore(lock, flags);
+
+ return entry;
+}
+
static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt,
unsigned int qp_num)
{
@@ -601,13 +629,16 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
}
static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
- unsigned int size)
+ resource_size_t size)
{
struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
struct pci_dev *pdev = nt->ndev->pdev;
- unsigned int xlat_size, buff_size;
+ size_t xlat_size, buff_size;
int rc;
+ if (!size)
+ return -EINVAL;
+
xlat_size = round_up(size, mw->xlat_align_size);
buff_size = round_up(size, mw->xlat_align);
@@ -627,7 +658,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
if (!mw->virt_addr) {
mw->xlat_size = 0;
mw->buff_size = 0;
- dev_err(&pdev->dev, "Unable to alloc MW buff of size %d\n",
+ dev_err(&pdev->dev, "Unable to alloc MW buff of size %zu\n",
buff_size);
return -ENOMEM;
}
@@ -867,6 +898,8 @@ static void ntb_qp_link_work(struct work_struct *work)
if (qp->event_handler)
qp->event_handler(qp->cb_data, qp->link_is_up);
+
+ tasklet_schedule(&qp->rxc_db_work);
} else if (nt->link_is_up)
schedule_delayed_work(&qp->link_work,
msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT));
@@ -923,12 +956,12 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt,
qp->tx_max_frame = min(transport_mtu, tx_size / 2);
qp->tx_max_entry = tx_size / qp->tx_max_frame;
- if (nt_debugfs_dir) {
+ if (nt->debugfs_node_dir) {
char debugfs_name[4];
snprintf(debugfs_name, 4, "qp%d", qp_num);
qp->debugfs_dir = debugfs_create_dir(debugfs_name,
- nt_debugfs_dir);
+ nt->debugfs_node_dir);
qp->debugfs_stats = debugfs_create_file("stats", S_IRUSR,
qp->debugfs_dir, qp,
@@ -941,10 +974,10 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt,
INIT_DELAYED_WORK(&qp->link_work, ntb_qp_link_work);
INIT_WORK(&qp->link_cleanup, ntb_qp_link_cleanup_work);
- spin_lock_init(&qp->ntb_rx_pend_q_lock);
- spin_lock_init(&qp->ntb_rx_free_q_lock);
+ spin_lock_init(&qp->ntb_rx_q_lock);
spin_lock_init(&qp->ntb_tx_free_q_lock);
+ INIT_LIST_HEAD(&qp->rx_post_q);
INIT_LIST_HEAD(&qp->rx_pend_q);
INIT_LIST_HEAD(&qp->rx_free_q);
INIT_LIST_HEAD(&qp->tx_free_q);
@@ -1031,6 +1064,12 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
goto err2;
}
+ if (nt_debugfs_dir) {
+ nt->debugfs_node_dir =
+ debugfs_create_dir(pci_name(ndev->pdev),
+ nt_debugfs_dir);
+ }
+
for (i = 0; i < qp_count; i++) {
rc = ntb_transport_init_queue(nt, i);
if (rc)
@@ -1107,22 +1146,47 @@ static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev)
kfree(nt);
}
-static void ntb_rx_copy_callback(void *data)
+static void ntb_complete_rxc(struct ntb_transport_qp *qp)
{
- struct ntb_queue_entry *entry = data;
- struct ntb_transport_qp *qp = entry->qp;
- void *cb_data = entry->cb_data;
- unsigned int len = entry->len;
- struct ntb_payload_header *hdr = entry->rx_hdr;
+ struct ntb_queue_entry *entry;
+ void *cb_data;
+ unsigned int len;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&qp->ntb_rx_q_lock, irqflags);
+
+ while (!list_empty(&qp->rx_post_q)) {
+ entry = list_first_entry(&qp->rx_post_q,
+ struct ntb_queue_entry, entry);
+ if (!(entry->flags & DESC_DONE_FLAG))
+ break;
+
+ entry->rx_hdr->flags = 0;
+ iowrite32(entry->index, &qp->rx_info->entry);
- hdr->flags = 0;
+ cb_data = entry->cb_data;
+ len = entry->len;
- iowrite32(entry->index, &qp->rx_info->entry);
+ list_move_tail(&entry->entry, &qp->rx_free_q);
- ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q);
+ spin_unlock_irqrestore(&qp->ntb_rx_q_lock, irqflags);
- if (qp->rx_handler && qp->client_ready)
- qp->rx_handler(qp, qp->cb_data, cb_data, len);
+ if (qp->rx_handler && qp->client_ready)
+ qp->rx_handler(qp, qp->cb_data, cb_data, len);
+
+ spin_lock_irqsave(&qp->ntb_rx_q_lock, irqflags);
+ }
+
+ spin_unlock_irqrestore(&qp->ntb_rx_q_lock, irqflags);
+}
+
+static void ntb_rx_copy_callback(void *data)
+{
+ struct ntb_queue_entry *entry = data;
+
+ entry->flags |= DESC_DONE_FLAG;
+
+ ntb_complete_rxc(entry->qp);
}
static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset)
@@ -1138,19 +1202,18 @@ static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset)
ntb_rx_copy_callback(entry);
}
-static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset,
- size_t len)
+static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset)
{
struct dma_async_tx_descriptor *txd;
struct ntb_transport_qp *qp = entry->qp;
struct dma_chan *chan = qp->dma_chan;
struct dma_device *device;
- size_t pay_off, buff_off;
+ size_t pay_off, buff_off, len;
struct dmaengine_unmap_data *unmap;
dma_cookie_t cookie;
void *buf = entry->buf;
- entry->len = len;
+ len = entry->len;
if (!chan)
goto err;
@@ -1226,7 +1289,6 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp)
struct ntb_payload_header *hdr;
struct ntb_queue_entry *entry;
void *offset;
- int rc;
offset = qp->rx_buff + qp->rx_max_frame * qp->rx_index;
hdr = offset + qp->rx_max_frame - sizeof(struct ntb_payload_header);
@@ -1255,65 +1317,43 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp)
return -EIO;
}
- entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
+ entry = ntb_list_mv(&qp->ntb_rx_q_lock, &qp->rx_pend_q, &qp->rx_post_q);
if (!entry) {
dev_dbg(&qp->ndev->pdev->dev, "no receive buffer\n");
qp->rx_err_no_buf++;
-
- rc = -ENOMEM;
- goto err;
+ return -EAGAIN;
}
+ entry->rx_hdr = hdr;
+ entry->index = qp->rx_index;
+
if (hdr->len > entry->len) {
dev_dbg(&qp->ndev->pdev->dev,
"receive buffer overflow! Wanted %d got %d\n",
hdr->len, entry->len);
qp->rx_err_oflow++;
- rc = -EIO;
- goto err;
- }
+ entry->len = -EIO;
+ entry->flags |= DESC_DONE_FLAG;
- dev_dbg(&qp->ndev->pdev->dev,
- "RX OK index %u ver %u size %d into buf size %d\n",
- qp->rx_index, hdr->ver, hdr->len, entry->len);
+ ntb_complete_rxc(qp);
+ } else {
+ dev_dbg(&qp->ndev->pdev->dev,
+ "RX OK index %u ver %u size %d into buf size %d\n",
+ qp->rx_index, hdr->ver, hdr->len, entry->len);
- qp->rx_bytes += hdr->len;
- qp->rx_pkts++;
+ qp->rx_bytes += hdr->len;
+ qp->rx_pkts++;
- entry->index = qp->rx_index;
- entry->rx_hdr = hdr;
+ entry->len = hdr->len;
- ntb_async_rx(entry, offset, hdr->len);
+ ntb_async_rx(entry, offset);
+ }
qp->rx_index++;
qp->rx_index %= qp->rx_max_entry;
return 0;
-
-err:
- /* FIXME: if this syncrhonous update of the rx_index gets ahead of
- * asyncrhonous ntb_rx_copy_callback of previous entry, there are three
- * scenarios:
- *
- * 1) The peer might miss this update, but observe the update
- * from the memcpy completion callback. In this case, the buffer will
- * not be freed on the peer to be reused for a different packet. The
- * successful rx of a later packet would clear the condition, but the
- * condition could persist if several rx fail in a row.
- *
- * 2) The peer may observe this update before the asyncrhonous copy of
- * prior packets is completed. The peer may overwrite the buffers of
- * the prior packets before they are copied.
- *
- * 3) Both: the peer may observe the update, and then observe the index
- * decrement by the asynchronous completion callback. Who knows what
- * badness that will cause.
- */
- hdr->flags = 0;
- iowrite32(qp->rx_index, &qp->rx_info->entry);
-
- return rc;
}
static void ntb_transport_rxc_db(unsigned long data)
@@ -1333,7 +1373,7 @@ static void ntb_transport_rxc_db(unsigned long data)
break;
}
- if (qp->dma_chan)
+ if (i && qp->dma_chan)
dma_async_issue_pending(qp->dma_chan);
if (i == qp->rx_max_entry) {
@@ -1609,7 +1649,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
goto err1;
entry->qp = qp;
- ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry,
+ ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry,
&qp->rx_free_q);
}
@@ -1634,7 +1674,7 @@ err2:
while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
kfree(entry);
err1:
- while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
+ while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q)))
kfree(entry);
if (qp->dma_chan)
dma_release_channel(qp->dma_chan);
@@ -1652,7 +1692,6 @@ EXPORT_SYMBOL_GPL(ntb_transport_create_queue);
*/
void ntb_transport_free_queue(struct ntb_transport_qp *qp)
{
- struct ntb_transport_ctx *nt = qp->transport;
struct pci_dev *pdev;
struct ntb_queue_entry *entry;
u64 qp_bit;
@@ -1689,18 +1728,23 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
qp->tx_handler = NULL;
qp->event_handler = NULL;
- while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
+ while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q)))
kfree(entry);
- while ((entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q))) {
- dev_warn(&pdev->dev, "Freeing item from a non-empty queue\n");
+ while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_pend_q))) {
+ dev_warn(&pdev->dev, "Freeing item from non-empty rx_pend_q\n");
+ kfree(entry);
+ }
+
+ while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_post_q))) {
+ dev_warn(&pdev->dev, "Freeing item from non-empty rx_post_q\n");
kfree(entry);
}
while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
kfree(entry);
- nt->qp_bitmap_free |= qp_bit;
+ qp->transport->qp_bitmap_free |= qp_bit;
dev_info(&pdev->dev, "NTB Transport QP %d freed\n", qp->qp_num);
}
@@ -1724,14 +1768,14 @@ void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len)
if (!qp || qp->client_ready)
return NULL;
- entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
+ entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_pend_q);
if (!entry)
return NULL;
buf = entry->cb_data;
*len = entry->len;
- ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q);
+ ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_free_q);
return buf;
}
@@ -1757,15 +1801,18 @@ int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
if (!qp)
return -EINVAL;
- entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q);
+ entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q);
if (!entry)
return -ENOMEM;
entry->cb_data = cb;
entry->buf = data;
entry->len = len;
+ entry->flags = 0;
+
+ ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_pend_q);
- ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, &qp->rx_pend_q);
+ tasklet_schedule(&qp->rxc_db_work);
return 0;
}
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 73de4ef..944f500 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -2,7 +2,7 @@
# PCI configuration
#
config PCI_BUS_ADDR_T_64BIT
- def_bool y if (ARCH_DMA_ADDR_T_64BIT || 64BIT)
+ def_bool y if (ARCH_DMA_ADDR_T_64BIT || (64BIT && !PARISC))
depends on PCI
config PCI_MSI
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index cefd636..b978bbf 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -997,7 +997,12 @@ void set_pcie_port_type(struct pci_dev *pdev)
else if (type == PCI_EXP_TYPE_UPSTREAM ||
type == PCI_EXP_TYPE_DOWNSTREAM) {
parent = pci_upstream_bridge(pdev);
- if (!parent->has_secondary_link)
+
+ /*
+ * Usually there's an upstream device (Root Port or Switch
+ * Downstream Port), but we can't assume one exists.
+ */
+ if (parent && !parent->has_secondary_link)
pdev->has_secondary_link = 1;
}
}
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
index e17c539..2dad7e8 100644
--- a/drivers/phy/phy-sun4i-usb.c
+++ b/drivers/phy/phy-sun4i-usb.c
@@ -212,6 +212,7 @@ void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled)
sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2);
}
+EXPORT_SYMBOL_GPL(sun4i_usb_phy_set_squelch_detect);
static struct phy_ops sun4i_usb_phy_ops = {
.init = sun4i_usb_phy_init,
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index 3510b81..08020dc 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -28,6 +28,8 @@
#include <linux/delay.h>
#include <linux/phy/omap_control_phy.h>
#include <linux/of_platform.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#define PLL_STATUS 0x00000004
#define PLL_GO 0x00000008
@@ -52,6 +54,8 @@
#define PLL_LOCK 0x2
#define PLL_IDLE 0x1
+#define SATA_PLL_SOFT_RESET BIT(18)
+
/*
* This is an Empirical value that works, need to confirm the actual
* value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status
@@ -82,6 +86,9 @@ struct ti_pipe3 {
struct clk *refclk;
struct clk *div_clk;
struct pipe3_dpll_map *dpll_map;
+ struct regmap *dpll_reset_syscon; /* ctrl. reg. acces */
+ unsigned int dpll_reset_reg; /* reg. index within syscon */
+ bool sata_refclk_enabled;
};
static struct pipe3_dpll_map dpll_map_usb[] = {
@@ -249,8 +256,11 @@ static int ti_pipe3_exit(struct phy *x)
u32 val;
unsigned long timeout;
- /* SATA DPLL can't be powered down due to Errata i783 */
- if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
+ /* If dpll_reset_syscon is not present we wont power down SATA DPLL
+ * due to Errata i783
+ */
+ if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") &&
+ !phy->dpll_reset_syscon)
return 0;
/* PCIe doesn't have internal DPLL */
@@ -276,6 +286,14 @@ static int ti_pipe3_exit(struct phy *x)
}
}
+ /* i783: SATA needs control bit toggle after PLL unlock */
+ if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) {
+ regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg,
+ SATA_PLL_SOFT_RESET, SATA_PLL_SOFT_RESET);
+ regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg,
+ SATA_PLL_SOFT_RESET, 0);
+ }
+
ti_pipe3_disable_clocks(phy);
return 0;
@@ -350,6 +368,21 @@ static int ti_pipe3_probe(struct platform_device *pdev)
}
} else {
phy->wkupclk = ERR_PTR(-ENODEV);
+ phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node,
+ "syscon-pllreset");
+ if (IS_ERR(phy->dpll_reset_syscon)) {
+ dev_info(&pdev->dev,
+ "can't get syscon-pllreset, sata dpll won't idle\n");
+ phy->dpll_reset_syscon = NULL;
+ } else {
+ if (of_property_read_u32_index(node,
+ "syscon-pllreset", 1,
+ &phy->dpll_reset_reg)) {
+ dev_err(&pdev->dev,
+ "couldn't get pllreset reg. offset\n");
+ return -EINVAL;
+ }
+ }
}
if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
@@ -402,10 +435,16 @@ static int ti_pipe3_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, phy);
pm_runtime_enable(phy->dev);
- /* Prevent auto-disable of refclk for SATA PHY due to Errata i783 */
- if (of_device_is_compatible(node, "ti,phy-pipe3-sata"))
- if (!IS_ERR(phy->refclk))
+
+ /*
+ * Prevent auto-disable of refclk for SATA PHY due to Errata i783
+ */
+ if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
+ if (!IS_ERR(phy->refclk)) {
clk_prepare_enable(phy->refclk);
+ phy->sata_refclk_enabled = true;
+ }
+ }
generic_phy = devm_phy_create(phy->dev, NULL, &ops);
if (IS_ERR(generic_phy))
@@ -472,8 +511,18 @@ static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
{
if (!IS_ERR(phy->wkupclk))
clk_disable_unprepare(phy->wkupclk);
- if (!IS_ERR(phy->refclk))
+ if (!IS_ERR(phy->refclk)) {
clk_disable_unprepare(phy->refclk);
+ /*
+ * SATA refclk needs an additional disable as we left it
+ * on in probe to avoid Errata i783
+ */
+ if (phy->sata_refclk_enabled) {
+ clk_disable_unprepare(phy->refclk);
+ phy->sata_refclk_enabled = false;
+ }
+ }
+
if (!IS_ERR(phy->div_clk))
clk_disable_unprepare(phy->div_clk);
}
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index cb13299..3271cd1 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -4,7 +4,6 @@
menuconfig CHROME_PLATFORMS
bool "Platform support for Chrome hardware"
- depends on X86 || ARM
---help---
Say Y here to get to see options for platform support for
various Chromebooks and Chromeboxes. This option alone does
diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h
index 26270c3..ce129e5 100644
--- a/drivers/scsi/fnic/fnic.h
+++ b/drivers/scsi/fnic/fnic.h
@@ -39,7 +39,7 @@
#define DRV_NAME "fnic"
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
-#define DRV_VERSION "1.6.0.17"
+#define DRV_VERSION "1.6.0.17a"
#define PFX DRV_NAME ": "
#define DFX DRV_NAME "%d: "
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index 155b286..25436cd 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -425,6 +425,7 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
unsigned long ptr;
struct fc_rport_priv *rdata;
spinlock_t *io_lock = NULL;
+ int io_lock_acquired = 0;
if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED)))
return SCSI_MLQUEUE_HOST_BUSY;
@@ -518,6 +519,7 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
spin_lock_irqsave(io_lock, flags);
/* initialize rest of io_req */
+ io_lock_acquired = 1;
io_req->port_id = rport->port_id;
io_req->start_time = jiffies;
CMD_STATE(sc) = FNIC_IOREQ_CMD_PENDING;
@@ -571,7 +573,7 @@ out:
(((u64)CMD_FLAGS(sc) >> 32) | CMD_STATE(sc)));
/* if only we issued IO, will we have the io lock */
- if (CMD_FLAGS(sc) & FNIC_IO_INITIALIZED)
+ if (io_lock_acquired)
spin_unlock_irqrestore(io_lock, flags);
atomic_dec(&fnic->in_flight);
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 1b3a094..30f9ef0 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -733,8 +733,6 @@ static bool fc_invoke_resp(struct fc_exch *ep, struct fc_seq *sp,
if (resp) {
resp(sp, fp, arg);
res = true;
- } else if (!IS_ERR(fp)) {
- fc_frame_free(fp);
}
spin_lock_bh(&ep->ex_lock);
@@ -1596,7 +1594,8 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
* If new exch resp handler is valid then call that
* first.
*/
- fc_invoke_resp(ep, sp, fp);
+ if (!fc_invoke_resp(ep, sp, fp))
+ fc_frame_free(fp);
fc_exch_release(ep);
return;
@@ -1695,7 +1694,8 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp)
fc_exch_hold(ep);
if (!rc)
fc_exch_delete(ep);
- fc_invoke_resp(ep, sp, fp);
+ if (!fc_invoke_resp(ep, sp, fp))
+ fc_frame_free(fp);
if (has_rec)
fc_exch_timer_set(ep, ep->r_a_tov);
fc_exch_release(ep);
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index c679594..2d5909c 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -1039,11 +1039,26 @@ restart:
fc_fcp_pkt_hold(fsp);
spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
- if (!fc_fcp_lock_pkt(fsp)) {
+ spin_lock_bh(&fsp->scsi_pkt_lock);
+ if (!(fsp->state & FC_SRB_COMPL)) {
+ fsp->state |= FC_SRB_COMPL;
+ /*
+ * TODO: dropping scsi_pkt_lock and then reacquiring
+ * again around fc_fcp_cleanup_cmd() is required,
+ * since fc_fcp_cleanup_cmd() calls into
+ * fc_seq_set_resp() and that func preempts cpu using
+ * schedule. May be schedule and related code should be
+ * removed instead of unlocking here to avoid scheduling
+ * while atomic bug.
+ */
+ spin_unlock_bh(&fsp->scsi_pkt_lock);
+
fc_fcp_cleanup_cmd(fsp, error);
+
+ spin_lock_bh(&fsp->scsi_pkt_lock);
fc_io_compl(fsp);
- fc_fcp_unlock_pkt(fsp);
}
+ spin_unlock_bh(&fsp->scsi_pkt_lock);
fc_fcp_pkt_release(fsp);
spin_lock_irqsave(&si->scsi_queue_lock, flags);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 8053f24..98d9bb6 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -2941,10 +2941,10 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_session *session = conn->session;
- unsigned long flags;
del_timer_sync(&conn->transport_timer);
+ mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->frwd_lock);
conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
if (session->leadconn == conn) {
@@ -2956,28 +2956,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
}
spin_unlock_bh(&session->frwd_lock);
- /*
- * Block until all in-progress commands for this connection
- * time out or fail.
- */
- for (;;) {
- spin_lock_irqsave(session->host->host_lock, flags);
- if (!atomic_read(&session->host->host_busy)) { /* OK for ERL == 0 */
- spin_unlock_irqrestore(session->host->host_lock, flags);
- break;
- }
- spin_unlock_irqrestore(session->host->host_lock, flags);
- msleep_interruptible(500);
- iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): "
- "host_busy %d host_failed %d\n",
- atomic_read(&session->host->host_busy),
- session->host->host_failed);
- /*
- * force eh_abort() to unblock
- */
- wake_up(&conn->ehwait);
- }
-
/* flush queued up work because we free the connection below */
iscsi_suspend_tx(conn);
@@ -2994,6 +2972,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
if (session->leadconn == conn)
session->leadconn = NULL;
spin_unlock_bh(&session->frwd_lock);
+ mutex_unlock(&session->eh_mutex);
iscsi_destroy_conn(cls_conn);
}
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index cfadcce..6457a8a 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -26,7 +26,6 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
-#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -2523,33 +2522,3 @@ void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq)
}
}
EXPORT_SYMBOL(scsi_build_sense_buffer);
-
-/**
- * scsi_set_sense_information - set the information field in a
- * formatted sense data buffer
- * @buf: Where to build sense data
- * @info: 64-bit information value to be set
- *
- **/
-void scsi_set_sense_information(u8 *buf, u64 info)
-{
- if ((buf[0] & 0x7f) == 0x72) {
- u8 *ucp, len;
-
- len = buf[7];
- ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0);
- if (!ucp) {
- buf[7] = len + 0xa;
- ucp = buf + 8 + len;
- }
- ucp[0] = 0;
- ucp[1] = 0xa;
- ucp[2] = 0x80; /* Valid bit */
- ucp[3] = 0;
- put_unaligned_be64(info, &ucp[4]);
- } else if ((buf[0] & 0x7f) == 0x70) {
- buf[0] |= 0x80;
- put_unaligned_be64(info, &buf[3]);
- }
-}
-EXPORT_SYMBOL(scsi_set_sense_information);
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index 9e43ae1..e4b7998 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -217,15 +217,15 @@ static int sdev_runtime_suspend(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
struct scsi_device *sdev = to_scsi_device(dev);
- int err;
+ int err = 0;
- err = blk_pre_runtime_suspend(sdev->request_queue);
- if (err)
- return err;
- if (pm && pm->runtime_suspend)
+ if (pm && pm->runtime_suspend) {
+ err = blk_pre_runtime_suspend(sdev->request_queue);
+ if (err)
+ return err;
err = pm->runtime_suspend(dev);
- blk_post_runtime_suspend(sdev->request_queue, err);
-
+ blk_post_runtime_suspend(sdev->request_queue, err);
+ }
return err;
}
@@ -248,11 +248,11 @@ static int sdev_runtime_resume(struct device *dev)
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int err = 0;
- blk_pre_runtime_resume(sdev->request_queue);
- if (pm && pm->runtime_resume)
+ if (pm && pm->runtime_resume) {
+ blk_pre_runtime_resume(sdev->request_queue);
err = pm->runtime_resume(dev);
- blk_post_runtime_resume(sdev->request_queue, err);
-
+ blk_post_runtime_resume(sdev->request_queue, err);
+ }
return err;
}
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 3b2fcb4..a20da8c 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -2770,9 +2770,9 @@ static int sd_revalidate_disk(struct gendisk *disk)
max_xfer = sdkp->max_xfer_blocks;
max_xfer <<= ilog2(sdp->sector_size) - 9;
- max_xfer = min_not_zero(queue_max_hw_sectors(sdkp->disk->queue),
- max_xfer);
- blk_queue_max_hw_sectors(sdkp->disk->queue, max_xfer);
+ sdkp->disk->queue->limits.max_sectors =
+ min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), max_xfer);
+
set_capacity(disk, sdkp->capacity);
sd_config_write_same(sdkp);
kfree(buffer);
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index bfa4262..94078118 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -1266,6 +1266,7 @@ static const struct das1800_board *das1800_probe(struct comedi_device *dev)
if (index == das1801hc || index == das1802hc)
return board;
index = das1801hc;
+ break;
default:
dev_err(dev->class_dev,
"Board model: probe returned 0x%x (unknown, please report)\n",
diff --git a/drivers/staging/lustre/lustre/obdclass/debug.c b/drivers/staging/lustre/lustre/obdclass/debug.c
index 9c934e6..c61add4 100644
--- a/drivers/staging/lustre/lustre/obdclass/debug.c
+++ b/drivers/staging/lustre/lustre/obdclass/debug.c
@@ -40,7 +40,7 @@
#define DEBUG_SUBSYSTEM D_OTHER
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
#include "../include/obd_support.h"
#include "../include/lustre_debug.h"
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index b0c8e23..69bdc8f 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -1483,8 +1483,9 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw,
}
}
- if (changed & BSS_CHANGED_ASSOC && priv->op_mode != NL80211_IFTYPE_AP) {
- if (conf->assoc) {
+ if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) &&
+ priv->op_mode != NL80211_IFTYPE_AP) {
+ if (conf->assoc && conf->beacon_rate) {
CARDbUpdateTSF(priv, conf->beacon_rate->hw_value,
conf->sync_tsf);
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index cd77a06..fd09290 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -968,9 +968,9 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
cmd->cmd_flags |= ICF_NON_IMMEDIATE_UNSOLICITED_DATA;
conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
- if (hdr->flags & ISCSI_FLAG_CMD_READ) {
+ if (hdr->flags & ISCSI_FLAG_CMD_READ)
cmd->targ_xfer_tag = session_get_next_ttt(conn->sess);
- } else if (hdr->flags & ISCSI_FLAG_CMD_WRITE)
+ else
cmd->targ_xfer_tag = 0xFFFFFFFF;
cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index c2e9fea9..860e840 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -457,8 +457,15 @@ void target_unregister_template(const struct target_core_fabric_ops *fo)
if (!strcmp(t->tf_ops->name, fo->name)) {
BUG_ON(atomic_read(&t->tf_access_cnt));
list_del(&t->tf_list);
+ mutex_unlock(&g_tf_lock);
+ /*
+ * Wait for any outstanding fabric se_deve_entry->rcu_head
+ * callbacks to complete post kfree_rcu(), before allowing
+ * fabric driver unload of TFO->module to proceed.
+ */
+ rcu_barrier();
kfree(t);
- break;
+ return;
}
}
mutex_unlock(&g_tf_lock);
diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c
index 62ea4e8..be9cefc 100644
--- a/drivers/target/target_core_hba.c
+++ b/drivers/target/target_core_hba.c
@@ -84,8 +84,16 @@ void target_backend_unregister(const struct target_backend_ops *ops)
list_for_each_entry(tb, &backend_list, list) {
if (tb->ops == ops) {
list_del(&tb->list);
+ mutex_unlock(&backend_mutex);
+ /*
+ * Wait for any outstanding backend driver ->rcu_head
+ * callbacks to complete post TBO->free_device() ->
+ * call_rcu(), before allowing backend driver module
+ * unload of target_backend_ops->owner to proceed.
+ */
+ rcu_barrier();
kfree(tb);
- break;
+ return;
}
}
mutex_unlock(&backend_mutex);
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index b5ba1ec..f87d4ce 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -1203,17 +1203,13 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
struct se_dev_entry *deve;
struct se_session *sess = cmd->se_sess;
struct se_node_acl *nacl;
+ struct scsi_lun slun;
unsigned char *buf;
u32 lun_count = 0, offset = 8;
-
- if (cmd->data_length < 16) {
- pr_warn("REPORT LUNS allocation length %u too small\n",
- cmd->data_length);
- return TCM_INVALID_CDB_FIELD;
- }
+ __be32 len;
buf = transport_kmap_data_sg(cmd);
- if (!buf)
+ if (cmd->data_length && !buf)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
/*
@@ -1221,11 +1217,9 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
* coming via a target_core_mod PASSTHROUGH op, and not through
* a $FABRIC_MOD. In that case, report LUN=0 only.
*/
- if (!sess) {
- int_to_scsilun(0, (struct scsi_lun *)&buf[offset]);
- lun_count = 1;
+ if (!sess)
goto done;
- }
+
nacl = sess->se_node_acl;
rcu_read_lock();
@@ -1236,10 +1230,12 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
* See SPC2-R20 7.19.
*/
lun_count++;
- if ((offset + 8) > cmd->data_length)
+ if (offset >= cmd->data_length)
continue;
- int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]);
+ int_to_scsilun(deve->mapped_lun, &slun);
+ memcpy(buf + offset, &slun,
+ min(8u, cmd->data_length - offset));
offset += 8;
}
rcu_read_unlock();
@@ -1248,12 +1244,22 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
* See SPC3 r07, page 159.
*/
done:
- lun_count *= 8;
- buf[0] = ((lun_count >> 24) & 0xff);
- buf[1] = ((lun_count >> 16) & 0xff);
- buf[2] = ((lun_count >> 8) & 0xff);
- buf[3] = (lun_count & 0xff);
- transport_kunmap_data_sg(cmd);
+ /*
+ * If no LUNs are accessible, report virtual LUN 0.
+ */
+ if (lun_count == 0) {
+ int_to_scsilun(0, &slun);
+ if (cmd->data_length > 8)
+ memcpy(buf + offset, &slun,
+ min(8u, cmd->data_length - offset));
+ lun_count = 1;
+ }
+
+ if (buf) {
+ len = cpu_to_be32(lun_count * 8);
+ memcpy(buf, &len, min_t(int, sizeof len, cmd->data_length));
+ transport_kunmap_data_sg(cmd);
+ }
target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8);
return 0;
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 6509c61..620dcd4 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -68,7 +68,7 @@ struct power_table {
* registered cooling device.
* @cpufreq_state: integer value representing the current state of cpufreq
* cooling devices.
- * @cpufreq_val: integer value representing the absolute value of the clipped
+ * @clipped_freq: integer value representing the absolute value of the clipped
* frequency.
* @max_level: maximum cooling level. One less than total number of valid
* cpufreq frequencies.
@@ -91,7 +91,7 @@ struct cpufreq_cooling_device {
int id;
struct thermal_cooling_device *cool_dev;
unsigned int cpufreq_state;
- unsigned int cpufreq_val;
+ unsigned int clipped_freq;
unsigned int max_level;
unsigned int *freq_table; /* In descending order */
struct cpumask allowed_cpus;
@@ -107,6 +107,9 @@ struct cpufreq_cooling_device {
static DEFINE_IDR(cpufreq_idr);
static DEFINE_MUTEX(cooling_cpufreq_lock);
+static unsigned int cpufreq_dev_count;
+
+static DEFINE_MUTEX(cooling_list_lock);
static LIST_HEAD(cpufreq_dev_list);
/**
@@ -185,14 +188,14 @@ unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
{
struct cpufreq_cooling_device *cpufreq_dev;
- mutex_lock(&cooling_cpufreq_lock);
+ mutex_lock(&cooling_list_lock);
list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) {
- mutex_unlock(&cooling_cpufreq_lock);
+ mutex_unlock(&cooling_list_lock);
return get_level(cpufreq_dev, freq);
}
}
- mutex_unlock(&cooling_cpufreq_lock);
+ mutex_unlock(&cooling_list_lock);
pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu);
return THERMAL_CSTATE_INVALID;
@@ -215,29 +218,35 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
struct cpufreq_policy *policy = data;
- unsigned long max_freq = 0;
+ unsigned long clipped_freq;
struct cpufreq_cooling_device *cpufreq_dev;
- switch (event) {
+ if (event != CPUFREQ_ADJUST)
+ return NOTIFY_DONE;
- case CPUFREQ_ADJUST:
- mutex_lock(&cooling_cpufreq_lock);
- list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
- if (!cpumask_test_cpu(policy->cpu,
- &cpufreq_dev->allowed_cpus))
- continue;
+ mutex_lock(&cooling_list_lock);
+ list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
+ if (!cpumask_test_cpu(policy->cpu, &cpufreq_dev->allowed_cpus))
+ continue;
- max_freq = cpufreq_dev->cpufreq_val;
+ /*
+ * policy->max is the maximum allowed frequency defined by user
+ * and clipped_freq is the maximum that thermal constraints
+ * allow.
+ *
+ * If clipped_freq is lower than policy->max, then we need to
+ * readjust policy->max.
+ *
+ * But, if clipped_freq is greater than policy->max, we don't
+ * need to do anything.
+ */
+ clipped_freq = cpufreq_dev->clipped_freq;
- if (policy->max != max_freq)
- cpufreq_verify_within_limits(policy, 0,
- max_freq);
- }
- mutex_unlock(&cooling_cpufreq_lock);
+ if (policy->max > clipped_freq)
+ cpufreq_verify_within_limits(policy, 0, clipped_freq);
break;
- default:
- return NOTIFY_DONE;
}
+ mutex_unlock(&cooling_list_lock);
return NOTIFY_OK;
}
@@ -519,7 +528,7 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
clip_freq = cpufreq_device->freq_table[state];
cpufreq_device->cpufreq_state = state;
- cpufreq_device->cpufreq_val = clip_freq;
+ cpufreq_device->clipped_freq = clip_freq;
cpufreq_update_policy(cpu);
@@ -861,17 +870,19 @@ __cpufreq_cooling_register(struct device_node *np,
pr_debug("%s: freq:%u KHz\n", __func__, freq);
}
- cpufreq_dev->cpufreq_val = cpufreq_dev->freq_table[0];
+ cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0];
cpufreq_dev->cool_dev = cool_dev;
mutex_lock(&cooling_cpufreq_lock);
+ mutex_lock(&cooling_list_lock);
+ list_add(&cpufreq_dev->node, &cpufreq_dev_list);
+ mutex_unlock(&cooling_list_lock);
+
/* Register the notifier for first cpufreq cooling device */
- if (list_empty(&cpufreq_dev_list))
+ if (!cpufreq_dev_count++)
cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
CPUFREQ_POLICY_NOTIFIER);
- list_add(&cpufreq_dev->node, &cpufreq_dev_list);
-
mutex_unlock(&cooling_cpufreq_lock);
return cool_dev;
@@ -1013,13 +1024,17 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
return;
cpufreq_dev = cdev->devdata;
- mutex_lock(&cooling_cpufreq_lock);
- list_del(&cpufreq_dev->node);
/* Unregister the notifier for the last cpufreq cooling device */
- if (list_empty(&cpufreq_dev_list))
+ mutex_lock(&cooling_cpufreq_lock);
+ if (!--cpufreq_dev_count)
cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
CPUFREQ_POLICY_NOTIFIER);
+
+ mutex_lock(&cooling_list_lock);
+ list_del(&cpufreq_dev->node);
+ mutex_unlock(&cooling_list_lock);
+
mutex_unlock(&cooling_cpufreq_lock);
thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c
index d5dd357..b49f97c 100644
--- a/drivers/thermal/hisi_thermal.c
+++ b/drivers/thermal/hisi_thermal.c
@@ -405,7 +405,6 @@ static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops,
static struct platform_driver hisi_thermal_driver = {
.driver = {
.name = "hisi_thermal",
- .owner = THIS_MODULE,
.pm = &hisi_thermal_pm_ops,
.of_match_table = of_hisi_thermal_match,
},
diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c
index 4672250..7006860 100644
--- a/drivers/thermal/power_allocator.c
+++ b/drivers/thermal/power_allocator.c
@@ -229,7 +229,8 @@ static int allocate_power(struct thermal_zone_device *tz,
struct thermal_instance *instance;
struct power_allocator_params *params = tz->governor_data;
u32 *req_power, *max_power, *granted_power, *extra_actor_power;
- u32 total_req_power, max_allocatable_power;
+ u32 *weighted_req_power;
+ u32 total_req_power, max_allocatable_power, total_weighted_req_power;
u32 total_granted_power, power_range;
int i, num_actors, total_weight, ret = 0;
int trip_max_desired_temperature = params->trip_max_desired_temperature;
@@ -247,16 +248,17 @@ static int allocate_power(struct thermal_zone_device *tz,
}
/*
- * We need to allocate three arrays of the same size:
- * req_power, max_power and granted_power. They are going to
- * be needed until this function returns. Allocate them all
- * in one go to simplify the allocation and deallocation
- * logic.
+ * We need to allocate five arrays of the same size:
+ * req_power, max_power, granted_power, extra_actor_power and
+ * weighted_req_power. They are going to be needed until this
+ * function returns. Allocate them all in one go to simplify
+ * the allocation and deallocation logic.
*/
BUILD_BUG_ON(sizeof(*req_power) != sizeof(*max_power));
BUILD_BUG_ON(sizeof(*req_power) != sizeof(*granted_power));
BUILD_BUG_ON(sizeof(*req_power) != sizeof(*extra_actor_power));
- req_power = devm_kcalloc(&tz->device, num_actors * 4,
+ BUILD_BUG_ON(sizeof(*req_power) != sizeof(*weighted_req_power));
+ req_power = devm_kcalloc(&tz->device, num_actors * 5,
sizeof(*req_power), GFP_KERNEL);
if (!req_power) {
ret = -ENOMEM;
@@ -266,8 +268,10 @@ static int allocate_power(struct thermal_zone_device *tz,
max_power = &req_power[num_actors];
granted_power = &req_power[2 * num_actors];
extra_actor_power = &req_power[3 * num_actors];
+ weighted_req_power = &req_power[4 * num_actors];
i = 0;
+ total_weighted_req_power = 0;
total_req_power = 0;
max_allocatable_power = 0;
@@ -289,13 +293,14 @@ static int allocate_power(struct thermal_zone_device *tz,
else
weight = instance->weight;
- req_power[i] = frac_to_int(weight * req_power[i]);
+ weighted_req_power[i] = frac_to_int(weight * req_power[i]);
if (power_actor_get_max_power(cdev, tz, &max_power[i]))
continue;
total_req_power += req_power[i];
max_allocatable_power += max_power[i];
+ total_weighted_req_power += weighted_req_power[i];
i++;
}
@@ -303,8 +308,9 @@ static int allocate_power(struct thermal_zone_device *tz,
power_range = pid_controller(tz, current_temp, control_temp,
max_allocatable_power);
- divvy_up_power(req_power, max_power, num_actors, total_req_power,
- power_range, granted_power, extra_actor_power);
+ divvy_up_power(weighted_req_power, max_power, num_actors,
+ total_weighted_req_power, power_range, granted_power,
+ extra_actor_power);
total_granted_power = 0;
i = 0;
@@ -328,7 +334,7 @@ static int allocate_power(struct thermal_zone_device *tz,
max_allocatable_power, current_temp,
(s32)control_temp - (s32)current_temp);
- devm_kfree(&tz->device, req_power);
+ kfree(req_power);
unlock:
mutex_unlock(&tz->lock);
@@ -420,7 +426,7 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
return -EINVAL;
}
- params = devm_kzalloc(&tz->device, sizeof(*params), GFP_KERNEL);
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
if (!params)
return -ENOMEM;
@@ -462,14 +468,14 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
return 0;
free:
- devm_kfree(&tz->device, params);
+ kfree(params);
return ret;
}
static void power_allocator_unbind(struct thermal_zone_device *tz)
{
dev_dbg(&tz->device, "Unbinding from thermal zone %d\n", tz->id);
- devm_kfree(&tz->device, tz->governor_data);
+ kfree(tz->governor_data);
tz->governor_data = NULL;
}
diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
index c8e35c1..e0da386 100644
--- a/drivers/thermal/samsung/Kconfig
+++ b/drivers/thermal/samsung/Kconfig
@@ -1,6 +1,6 @@
config EXYNOS_THERMAL
tristate "Exynos thermal management unit driver"
- depends on OF
+ depends on THERMAL_OF
help
If you say yes here you get support for the TMU (Thermal Management
Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 531f4b17..c96ff10 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -1296,7 +1296,6 @@ static struct thermal_zone_of_device_ops exynos_sensor_ops = {
static int exynos_tmu_probe(struct platform_device *pdev)
{
- struct exynos_tmu_platform_data *pdata;
struct exynos_tmu_data *data;
int ret;
@@ -1318,8 +1317,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
if (ret)
goto err_sensor;
- pdata = data->pdata;
-
INIT_WORK(&data->irq_work, exynos_tmu_work);
data->clk = devm_clk_get(&pdev->dev, "tmu_apbif");
@@ -1392,6 +1389,8 @@ err_clk_sec:
if (!IS_ERR(data->clk_sec))
clk_unprepare(data->clk_sec);
err_sensor:
+ if (!IS_ERR_OR_NULL(data->regulator))
+ regulator_disable(data->regulator);
thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
return ret;
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 04659bf..4ca211b 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1333,6 +1333,7 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
return -ENODEV;
unbind:
+ device_remove_file(&tz->device, &pos->weight_attr);
device_remove_file(&tz->device, &pos->attr);
sysfs_remove_link(&tz->device.kobj, pos->name);
release_idr(&tz->idr, &tz->lock, pos->id);
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 74fea4f..3ad48e1 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -1024,7 +1024,18 @@ static struct platform_driver ci_hdrc_driver = {
},
};
-module_platform_driver(ci_hdrc_driver);
+static int __init ci_hdrc_platform_register(void)
+{
+ ci_hdrc_host_driver_init();
+ return platform_driver_register(&ci_hdrc_driver);
+}
+module_init(ci_hdrc_platform_register);
+
+static void __exit ci_hdrc_platform_unregister(void)
+{
+ platform_driver_unregister(&ci_hdrc_driver);
+}
+module_exit(ci_hdrc_platform_unregister);
MODULE_ALIAS("platform:ci_hdrc");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index 6cf87b8..7161439 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -249,9 +249,12 @@ int ci_hdrc_host_init(struct ci_hdrc *ci)
rdrv->name = "host";
ci->roles[CI_ROLE_HOST] = rdrv;
+ return 0;
+}
+
+void ci_hdrc_host_driver_init(void)
+{
ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides);
orig_bus_suspend = ci_ehci_hc_driver.bus_suspend;
ci_ehci_hc_driver.bus_suspend = ci_ehci_bus_suspend;
-
- return 0;
}
diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h
index 5707bf3..0f12f13 100644
--- a/drivers/usb/chipidea/host.h
+++ b/drivers/usb/chipidea/host.h
@@ -5,6 +5,7 @@
int ci_hdrc_host_init(struct ci_hdrc *ci);
void ci_hdrc_host_destroy(struct ci_hdrc *ci);
+void ci_hdrc_host_driver_init(void);
#else
@@ -18,6 +19,11 @@ static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci)
}
+static void ci_hdrc_host_driver_init(void)
+{
+
+}
+
#endif
#endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index f7f35a3..6df9715 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -699,6 +699,10 @@ static inline int hidg_get_minor(void)
int ret;
ret = ida_simple_get(&hidg_ida, 0, 0, GFP_KERNEL);
+ if (ret >= HIDG_MINORS) {
+ ida_simple_remove(&hidg_ida, ret);
+ ret = -ENODEV;
+ }
return ret;
}
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index 44173df..357f63f 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -1248,7 +1248,15 @@ static struct config_item_type printer_func_type = {
static inline int gprinter_get_minor(void)
{
- return ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL);
+ int ret;
+
+ ret = ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL);
+ if (ret >= PRINTER_MINORS) {
+ ida_simple_remove(&printer_ida, ret);
+ ret = -ENODEV;
+ }
+
+ return ret;
}
static inline void gprinter_put_minor(int minor)
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 6d3eb8b..5318615 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -1162,14 +1162,14 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
factor = 1000;
} else {
ep_desc = &hs_epin_desc;
- factor = 125;
+ factor = 8000;
}
/* pre-compute some values for iso_complete() */
uac2->p_framesize = opts->p_ssize *
num_channels(opts->p_chmask);
rate = opts->p_srate * uac2->p_framesize;
- uac2->p_interval = (1 << (ep_desc->bInterval - 1)) * factor;
+ uac2->p_interval = factor / (1 << (ep_desc->bInterval - 1));
uac2->p_pktsize = min_t(unsigned int, rate / uac2->p_interval,
prm->max_psize);
diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c
index b04980c..1efa612 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_ep.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c
@@ -779,7 +779,7 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req)
/* The current hw dequeue pointer */
tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(0));
deq_ptr_64 = tmp_32;
- tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(1));
+ tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1(0));
deq_ptr_64 |= ((u64)tmp_32 << 32);
/* we have the dma addr of next bd that will be fetched by hardware */
diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
index 362ee8a..89ed5e7 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -323,6 +323,7 @@ err4:
err3:
put_device(&udc->dev);
+ device_del(&gadget->dev);
err2:
put_device(&gadget->dev);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 3e442f7..9a8c936 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1792,7 +1792,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
int size;
int i, j, num_ports;
- del_timer_sync(&xhci->cmd_timer);
+ if (timer_pending(&xhci->cmd_timer))
+ del_timer_sync(&xhci->cmd_timer);
/* Free the Event Ring Segment Table and the actual Event Ring */
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 6a8fc52..32f4d56 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -82,7 +82,7 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
return 0;
/* offset in TRBs */
segment_offset = trb - seg->trbs;
- if (segment_offset > TRBS_PER_SEGMENT)
+ if (segment_offset >= TRBS_PER_SEGMENT)
return 0;
return seg->dma + (segment_offset * sizeof(*trb));
}
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 19b85ee..876423b 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1099,6 +1099,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
{ USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x68c0, 0xff),
.driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC73xx */
+ { USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x9041, 0xff),
+ .driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC7305/MC7355 */
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 9c63897..d156545 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -145,7 +145,6 @@ static const struct usb_device_id id_table[] = {
{DEVICE_SWI(0x1199, 0x901c)}, /* Sierra Wireless EM7700 */
{DEVICE_SWI(0x1199, 0x901f)}, /* Sierra Wireless EM7355 */
{DEVICE_SWI(0x1199, 0x9040)}, /* Sierra Wireless Modem */
- {DEVICE_SWI(0x1199, 0x9041)}, /* Sierra Wireless MC7305/MC7355 */
{DEVICE_SWI(0x1199, 0x9051)}, /* Netgear AirCard 340U */
{DEVICE_SWI(0x1199, 0x9053)}, /* Sierra Wireless Modem */
{DEVICE_SWI(0x1199, 0x9054)}, /* Sierra Wireless Modem */
@@ -158,6 +157,7 @@ static const struct usb_device_id id_table[] = {
{DEVICE_SWI(0x413c, 0x81a4)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81a8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81a9)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
+ {DEVICE_SWI(0x413c, 0x81b1)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
/* Huawei devices */
{DEVICE_HWI(0x03f0, 0x581d)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 46179a0..07d1ecd 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -289,6 +289,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68AA, 0xFF, 0xFF, 0xFF),
.driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
},
+ { USB_DEVICE(0x1199, 0x68AB) }, /* Sierra Wireless AR8550 */
/* AT&T Direct IP LTE modems */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68AA, 0xFF, 0xFF, 0xFF),
.driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 658c34b..1aaf893 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -1306,10 +1306,11 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
int y;
int c = scr_readw((u16 *) vc->vc_pos);
+ ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
+
if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
return;
- ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
if (vc->vc_cursor_type & 0x10)
fbcon_del_cursor_timer(info);
else
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 2d98de5..f888561 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -298,7 +298,7 @@ config FB_ARMCLCD
# Helper logic selected only by the ARM Versatile platform family.
config PLAT_VERSATILE_CLCD
- def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS
+ def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || ARCH_INTEGRATOR
depends on ARM
depends on FB_ARMCLCD && FB=y
diff --git a/drivers/video/fbdev/omap2/dss/dss-of.c b/drivers/video/fbdev/omap2/dss/dss-of.c
index 928ee63..bf407b6 100644
--- a/drivers/video/fbdev/omap2/dss/dss-of.c
+++ b/drivers/video/fbdev/omap2/dss/dss-of.c
@@ -60,6 +60,8 @@ omapdss_of_get_next_port(const struct device_node *parent,
}
prev = port;
} while (of_node_cmp(port->name, "port") != 0);
+
+ of_node_put(ports);
}
return port;
@@ -94,7 +96,7 @@ struct device_node *dss_of_port_get_parent_device(struct device_node *port)
if (!port)
return NULL;
- np = of_get_next_parent(port);
+ np = of_get_parent(port);
for (i = 0; i < 2 && np; ++i) {
struct property *prop;
diff --git a/drivers/video/fbdev/pxa3xx-gcu.c b/drivers/video/fbdev/pxa3xx-gcu.c
index 86bd457..50bce45 100644
--- a/drivers/video/fbdev/pxa3xx-gcu.c
+++ b/drivers/video/fbdev/pxa3xx-gcu.c
@@ -653,7 +653,7 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev)
goto err_free_dma;
}
- ret = clk_enable(priv->clk);
+ ret = clk_prepare_enable(priv->clk);
if (ret < 0) {
dev_err(dev, "failed to enable clock\n");
goto err_misc_deregister;
@@ -685,7 +685,7 @@ err_misc_deregister:
misc_deregister(&priv->misc_dev);
err_disable_clk:
- clk_disable(priv->clk);
+ clk_disable_unprepare(priv->clk);
return ret;
}
diff --git a/drivers/video/of_videomode.c b/drivers/video/of_videomode.c
index 111c2d1..b5102aa 100644
--- a/drivers/video/of_videomode.c
+++ b/drivers/video/of_videomode.c
@@ -44,11 +44,9 @@ int of_get_videomode(struct device_node *np, struct videomode *vm,
index = disp->native_mode;
ret = videomode_from_timings(disp, vm, index);
- if (ret)
- return ret;
display_timings_release(disp);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(of_get_videomode);
diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c
index 60e2a16..c96944b 100644
--- a/drivers/virtio/virtio_input.c
+++ b/drivers/virtio/virtio_input.c
@@ -313,6 +313,7 @@ err_init_vq:
static void virtinput_remove(struct virtio_device *vdev)
{
struct virtio_input *vi = vdev->priv;
+ void *buf;
unsigned long flags;
spin_lock_irqsave(&vi->lock, flags);
@@ -320,6 +321,9 @@ static void virtinput_remove(struct virtio_device *vdev)
spin_unlock_irqrestore(&vi->lock, flags);
input_unregister_device(vi->idev);
+ vdev->config->reset(vdev);
+ while ((buf = virtqueue_detach_unused_buf(vi->sts)) != NULL)
+ kfree(buf);
vdev->config->del_vqs(vdev);
kfree(vi);
}
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index fd93369..bf4a23c 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -472,7 +472,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
}
/*
- * We avoid multiple worker processes conflicting via the balloon mutex.
+ * As this is a work item it is guaranteed to run as a single instance only.
* We may of course race updates of the target counts (which are protected
* by the balloon lock), or with changes to the Xen hard limit, but we will
* recover from these in time.
@@ -482,9 +482,10 @@ static void balloon_process(struct work_struct *work)
enum bp_state state = BP_DONE;
long credit;
- mutex_lock(&balloon_mutex);
do {
+ mutex_lock(&balloon_mutex);
+
credit = current_credit();
if (credit > 0) {
@@ -499,17 +500,15 @@ static void balloon_process(struct work_struct *work)
state = update_schedule(state);
-#ifndef CONFIG_PREEMPT
- if (need_resched())
- schedule();
-#endif
+ mutex_unlock(&balloon_mutex);
+
+ cond_resched();
+
} while (credit && state == BP_DONE);
/* Schedule more work if there is some still to be done. */
if (state == BP_EAGAIN)
schedule_delayed_work(&balloon_worker, balloon_stats.schedule_delay * HZ);
-
- mutex_unlock(&balloon_mutex);
}
/* Resets the Xen limit, sets new target, and kicks off processing. */
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index 67b9163..0dbb222 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -568,12 +568,14 @@ static int gntdev_release(struct inode *inode, struct file *flip)
pr_debug("priv %p\n", priv);
+ mutex_lock(&priv->lock);
while (!list_empty(&priv->maps)) {
map = list_entry(priv->maps.next, struct grant_map, next);
list_del(&map->next);
gntdev_put_map(NULL /* already removed */, map);
}
WARN_ON(!list_empty(&priv->freeable_maps));
+ mutex_unlock(&priv->lock);
if (use_ptemod)
mmu_notifier_unregister(&priv->mn, priv->mm);
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
index 9ad3272..e303535 100644
--- a/drivers/xen/xenbus/xenbus_client.c
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -814,8 +814,10 @@ static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr)
rv = xenbus_unmap_ring(dev, node->handles, node->nr_handles,
addrs);
- if (!rv)
+ if (!rv) {
vunmap(vaddr);
+ free_xenballooned_pages(node->nr_handles, node->hvm.pages);
+ }
else
WARN(1, "Leaking %p, size %u page(s)\n", vaddr,
node->nr_handles);
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index e9ace09..8a82029 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1651,6 +1651,11 @@ static int qgroup_update_counters(struct btrfs_fs_info *fs_info,
/* Exclusive -> exclusive, nothing changed */
}
}
+
+ /* For exclusive extent, free its reserved bytes too */
+ if (nr_old_roots == 0 && nr_new_roots == 1 &&
+ cur_new_count == nr_new_roots)
+ qg->reserved -= num_bytes;
if (dirty)
qgroup_dirty(fs_info, qg);
}
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index dc10c9d..ddd5e94 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -1506,7 +1506,6 @@ static int __mark_caps_flushing(struct inode *inode,
swap(cf, ci->i_prealloc_cap_flush);
cf->caps = flushing;
- cf->kick = false;
spin_lock(&mdsc->cap_dirty_lock);
list_del_init(&ci->i_dirty_item);
@@ -2123,8 +2122,7 @@ static void kick_flushing_capsnaps(struct ceph_mds_client *mdsc,
static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
struct ceph_mds_session *session,
- struct ceph_inode_info *ci,
- bool kick_all)
+ struct ceph_inode_info *ci)
{
struct inode *inode = &ci->vfs_inode;
struct ceph_cap *cap;
@@ -2150,9 +2148,7 @@ static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
for (n = rb_first(&ci->i_cap_flush_tree); n; n = rb_next(n)) {
cf = rb_entry(n, struct ceph_cap_flush, i_node);
- if (cf->tid < first_tid)
- continue;
- if (kick_all || cf->kick)
+ if (cf->tid >= first_tid)
break;
}
if (!n) {
@@ -2161,7 +2157,6 @@ static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
}
cf = rb_entry(n, struct ceph_cap_flush, i_node);
- cf->kick = false;
first_tid = cf->tid + 1;
@@ -2181,8 +2176,6 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
{
struct ceph_inode_info *ci;
struct ceph_cap *cap;
- struct ceph_cap_flush *cf;
- struct rb_node *n;
dout("early_kick_flushing_caps mds%d\n", session->s_mds);
list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) {
@@ -2205,16 +2198,11 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
if ((cap->issued & ci->i_flushing_caps) !=
ci->i_flushing_caps) {
spin_unlock(&ci->i_ceph_lock);
- if (!__kick_flushing_caps(mdsc, session, ci, true))
+ if (!__kick_flushing_caps(mdsc, session, ci))
continue;
spin_lock(&ci->i_ceph_lock);
}
- for (n = rb_first(&ci->i_cap_flush_tree); n; n = rb_next(n)) {
- cf = rb_entry(n, struct ceph_cap_flush, i_node);
- cf->kick = true;
- }
-
spin_unlock(&ci->i_ceph_lock);
}
}
@@ -2228,7 +2216,7 @@ void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
dout("kick_flushing_caps mds%d\n", session->s_mds);
list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) {
- int delayed = __kick_flushing_caps(mdsc, session, ci, false);
+ int delayed = __kick_flushing_caps(mdsc, session, ci);
if (delayed) {
spin_lock(&ci->i_ceph_lock);
__cap_delay_requeue(mdsc, ci);
@@ -2261,7 +2249,7 @@ static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc,
spin_unlock(&ci->i_ceph_lock);
- delayed = __kick_flushing_caps(mdsc, session, ci, true);
+ delayed = __kick_flushing_caps(mdsc, session, ci);
if (delayed) {
spin_lock(&ci->i_ceph_lock);
__cap_delay_requeue(mdsc, ci);
diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c
index 4347039..6706bde 100644
--- a/fs/ceph/locks.c
+++ b/fs/ceph/locks.c
@@ -287,7 +287,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
return 0;
spin_lock(&ctx->flc_lock);
- list_for_each_entry(lock, &ctx->flc_flock, fl_list) {
+ list_for_each_entry(lock, &ctx->flc_posix, fl_list) {
++seen_fcntl;
if (seen_fcntl > num_fcntl_locks) {
err = -ENOSPC;
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 860cc016..2f2460d 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -189,7 +189,6 @@ static inline void ceph_put_cap_snap(struct ceph_cap_snap *capsnap)
struct ceph_cap_flush {
u64 tid;
int caps;
- bool kick;
struct rb_node g_node; // global
union {
struct rb_node i_node; // inode
diff --git a/fs/dcache.c b/fs/dcache.c
index 5c8ea15..9b5fe50 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -3442,22 +3442,15 @@ void __init vfs_caches_init_early(void)
inode_init_early();
}
-void __init vfs_caches_init(unsigned long mempages)
+void __init vfs_caches_init(void)
{
- unsigned long reserve;
-
- /* Base hash sizes on available memory, with a reserve equal to
- 150% of current kernel size */
-
- reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);
- mempages -= reserve;
-
names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
dcache_init();
inode_init();
- files_init(mempages);
+ files_init();
+ files_maxfiles_init();
mnt_init();
bdev_cache_init();
chrdev_init();
diff --git a/fs/file_table.c b/fs/file_table.c
index 7f9d407..ad17e05 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -25,6 +25,7 @@
#include <linux/hardirq.h>
#include <linux/task_work.h>
#include <linux/ima.h>
+#include <linux/swap.h>
#include <linux/atomic.h>
@@ -308,19 +309,24 @@ void put_filp(struct file *file)
}
}
-void __init files_init(unsigned long mempages)
+void __init files_init(void)
{
- unsigned long n;
-
filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+ percpu_counter_init(&nr_files, 0, GFP_KERNEL);
+}
- /*
- * One file with associated inode and dcache is very roughly 1K.
- * Per default don't use more than 10% of our memory for files.
- */
+/*
+ * One file with associated inode and dcache is very roughly 1K. Per default
+ * do not use more than 10% of our memory for files.
+ */
+void __init files_maxfiles_init(void)
+{
+ unsigned long n;
+ unsigned long memreserve = (totalram_pages - nr_free_pages()) * 3/2;
+
+ memreserve = min(memreserve, totalram_pages - 1);
+ n = ((totalram_pages - memreserve) * (PAGE_SIZE / 1024)) / 10;
- n = (mempages * (PAGE_SIZE / 1024)) / 10;
files_stat.max_files = max_t(unsigned long, n, NR_FILE);
- percpu_counter_init(&nr_files, 0, GFP_KERNEL);
}
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 80cc1b3..ebb5e37 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -2246,7 +2246,15 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
err = -EINVAL;
if (old) {
- struct fuse_dev *fud = fuse_get_dev(old);
+ struct fuse_dev *fud = NULL;
+
+ /*
+ * Check against file->f_op because CUSE
+ * uses the same ioctl handler.
+ */
+ if (old->f_op == file->f_op &&
+ old->f_cred->user_ns == file->f_cred->user_ns)
+ fud = fuse_get_dev(old);
if (fud) {
mutex_lock(&fuse_mutex);
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 0cf74df..973c24c 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -1010,6 +1010,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
inode = hugetlbfs_get_inode(sb, NULL, S_IFREG | S_IRWXUGO, 0);
if (!inode)
goto out_dentry;
+ if (creat_flags == HUGETLB_SHMFS_INODE)
+ inode->i_flags |= S_PRIVATE;
file = ERR_PTR(-ENOMEM);
if (hugetlb_reserve_pages(inode, 0,
diff --git a/fs/namei.c b/fs/namei.c
index fbbcf09..1c2105e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -879,7 +879,7 @@ static inline int may_follow_link(struct nameidata *nd)
return 0;
/* Allowed if parent directory not sticky and world-writable. */
- parent = nd->path.dentry->d_inode;
+ parent = nd->inode;
if ((parent->i_mode & (S_ISVTX|S_IWOTH)) != (S_ISVTX|S_IWOTH))
return 0;
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c
index 6904213..ebf90e4 100644
--- a/fs/nfsd/nfs4layouts.c
+++ b/fs/nfsd/nfs4layouts.c
@@ -212,6 +212,7 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
BUG_ON(!ls->ls_file);
if (nfsd4_layout_setlease(ls)) {
+ fput(ls->ls_file);
put_nfs4_file(fp);
kmem_cache_free(nfs4_layout_stateid_cache, ls);
return NULL;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 61dfb33..9520271 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4396,9 +4396,9 @@ laundromat_main(struct work_struct *laundry)
queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ);
}
-static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
+static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp)
{
- if (!fh_match(&fhp->fh_handle, &stp->st_stid.sc_file->fi_fhandle))
+ if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle))
return nfserr_bad_stateid;
return nfs_ok;
}
@@ -4601,9 +4601,6 @@ nfs4_check_olstateid(struct svc_fh *fhp, struct nfs4_ol_stateid *ols, int flags)
{
__be32 status;
- status = nfs4_check_fh(fhp, ols);
- if (status)
- return status;
status = nfsd4_check_openowner_confirmed(ols);
if (status)
return status;
@@ -4690,6 +4687,9 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
status = nfserr_bad_stateid;
break;
}
+ if (status)
+ goto out;
+ status = nfs4_check_fh(fhp, s);
done:
if (!status && filpp)
@@ -4798,7 +4798,7 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
if (status)
return status;
- return nfs4_check_fh(current_fh, stp);
+ return nfs4_check_fh(current_fh, &stp->st_stid);
}
/*
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5463385..75e0563 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2143,6 +2143,7 @@ nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp,
#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
FATTR4_WORD0_RDATTR_ERROR)
#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
+#define WORD2_ABSENT_FS_ATTRS 0
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
static inline __be32
@@ -2171,7 +2172,7 @@ nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
{ return 0; }
#endif
-static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
+static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *bmval2, u32 *rdattr_err)
{
/* As per referral draft: */
if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
@@ -2184,6 +2185,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
}
*bmval0 &= WORD0_ABSENT_FS_ATTRS;
*bmval1 &= WORD1_ABSENT_FS_ATTRS;
+ *bmval2 &= WORD2_ABSENT_FS_ATTRS;
return 0;
}
@@ -2246,8 +2248,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion));
if (exp->ex_fslocs.migrated) {
- BUG_ON(bmval[2]);
- status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
+ status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, &rdattr_err);
if (status)
goto out;
}
@@ -2286,8 +2287,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
}
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
- if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) ||
- bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
+ if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) ||
+ bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
err = security_inode_getsecctx(d_inode(dentry),
&context, &contextlen);
contextsupport = (err == 0);
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index 92e48c7..39ddcaf 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -412,16 +412,36 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group,
unsigned int flags)
{
struct fsnotify_mark *lmark, *mark;
+ LIST_HEAD(to_free);
+ /*
+ * We have to be really careful here. Anytime we drop mark_mutex, e.g.
+ * fsnotify_clear_marks_by_inode() can come and free marks. Even in our
+ * to_free list so we have to use mark_mutex even when accessing that
+ * list. And freeing mark requires us to drop mark_mutex. So we can
+ * reliably free only the first mark in the list. That's why we first
+ * move marks to free to to_free list in one go and then free marks in
+ * to_free list one by one.
+ */
mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
- if (mark->flags & flags) {
- fsnotify_get_mark(mark);
- fsnotify_destroy_mark_locked(mark, group);
- fsnotify_put_mark(mark);
- }
+ if (mark->flags & flags)
+ list_move(&mark->g_list, &to_free);
}
mutex_unlock(&group->mark_mutex);
+
+ while (1) {
+ mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
+ if (list_empty(&to_free)) {
+ mutex_unlock(&group->mark_mutex);
+ break;
+ }
+ mark = list_first_entry(&to_free, struct fsnotify_mark, g_list);
+ fsnotify_get_mark(mark);
+ fsnotify_destroy_mark_locked(mark, group);
+ mutex_unlock(&group->mark_mutex);
+ fsnotify_put_mark(mark);
+ }
}
/*
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 1a35c61..0f5fd9d 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -685,7 +685,7 @@ static int ocfs2_direct_IO_zero_extend(struct ocfs2_super *osb,
if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN)) {
u64 s = i_size_read(inode);
- sector_t sector = (p_cpos << (osb->s_clustersize_bits - 9)) +
+ sector_t sector = ((u64)p_cpos << (osb->s_clustersize_bits - 9)) +
(do_div(s, osb->s_clustersize) >> 9);
ret = blkdev_issue_zeroout(osb->sb->s_bdev, sector,
@@ -910,7 +910,7 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb,
BUG_ON(!p_cpos || (ext_flags & OCFS2_EXT_UNWRITTEN));
ret = blkdev_issue_zeroout(osb->sb->s_bdev,
- p_cpos << (osb->s_clustersize_bits - 9),
+ (u64)p_cpos << (osb->s_clustersize_bits - 9),
zero_len_head >> 9, GFP_NOFS, false);
if (ret < 0)
mlog_errno(ret);
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 8b23aa2..23157e4 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -4025,9 +4025,13 @@ static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb)
osb->dc_work_sequence = osb->dc_wake_sequence;
processed = osb->blocked_lock_count;
- while (processed) {
- BUG_ON(list_empty(&osb->blocked_lock_list));
-
+ /*
+ * blocked lock processing in this loop might call iput which can
+ * remove items off osb->blocked_lock_list. Downconvert up to
+ * 'processed' number of locks, but stop short if we had some
+ * removed in ocfs2_mark_lockres_freeing when downconverting.
+ */
+ while (processed && !list_empty(&osb->blocked_lock_list)) {
lockres = list_entry(osb->blocked_lock_list.next,
struct ocfs2_lock_res, l_blocked_list);
list_del_init(&lockres->l_blocked_list);
diff --git a/fs/signalfd.c b/fs/signalfd.c
index 7e412ad..270221f 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -121,8 +121,9 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
* Other callers might not initialize the si_lsb field,
* so check explicitly for the right codes here.
*/
- if (kinfo->si_code == BUS_MCEERR_AR ||
- kinfo->si_code == BUS_MCEERR_AO)
+ if (kinfo->si_signo == SIGBUS &&
+ (kinfo->si_code == BUS_MCEERR_AR ||
+ kinfo->si_code == BUS_MCEERR_AO))
err |= __put_user((short) kinfo->si_addr_lsb,
&uinfo->ssi_addr_lsb);
#endif
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 48db6a5..5aa5197 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -691,7 +691,7 @@ struct drm_vblank_crtc {
struct timer_list disable_timer; /* delayed disable timer */
/* vblank counter, protected by dev->vblank_time_lock for writes */
- unsigned long count;
+ u32 count;
/* vblank timestamps, protected by dev->vblank_time_lock for writes */
struct timeval time[DRM_VBLANKTIME_RBSIZE];
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 57ca8cc..3b4d8a4 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -743,8 +743,6 @@ struct drm_connector {
uint8_t num_h_tile, num_v_tile;
uint8_t tile_h_loc, tile_v_loc;
uint16_t tile_h_size, tile_v_size;
-
- struct list_head destroy_list;
};
/**
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index c8fc187..918aa68 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -168,6 +168,7 @@ struct drm_encoder_helper_funcs {
* @get_modes: get mode list for this connector
* @mode_valid: is this mode valid on the given connector? (optional)
* @best_encoder: return the preferred encoder for this connector
+ * @atomic_best_encoder: atomic version of @best_encoder
*
* The helper operations are called by the mid-layer CRTC helper.
*/
@@ -176,6 +177,8 @@ struct drm_connector_helper_funcs {
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
+ struct drm_encoder *(*atomic_best_encoder)(struct drm_connector *connector,
+ struct drm_connector_state *connector_state);
};
extern void drm_helper_disable_unused_functions(struct drm_device *dev);
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 7990501..53c53c4 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -348,6 +348,25 @@ static inline int drm_eld_mnl(const uint8_t *eld)
}
/**
+ * drm_eld_sad - Get ELD SAD structures.
+ * @eld: pointer to an eld memory structure with sad_count set
+ */
+static inline const uint8_t *drm_eld_sad(const uint8_t *eld)
+{
+ unsigned int ver, mnl;
+
+ ver = (eld[DRM_ELD_VER] & DRM_ELD_VER_MASK) >> DRM_ELD_VER_SHIFT;
+ if (ver != 2 && ver != 31)
+ return NULL;
+
+ mnl = drm_eld_mnl(eld);
+ if (mnl > 16)
+ return NULL;
+
+ return eld + DRM_ELD_CEA_SAD(mnl, 0);
+}
+
+/**
* drm_eld_sad_count - Get ELD SAD count.
* @eld: pointer to an eld memory structure with sad_count set
*/
diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h
index 45c39a3..8bc073d 100644
--- a/include/drm/drm_pciids.h
+++ b/include/drm/drm_pciids.h
@@ -172,6 +172,7 @@
{0x1002, 0x6610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
{0x1002, 0x6611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
{0x1002, 0x6613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x6617, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x6620, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x6621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x6623, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 6c78956..d2992bf 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -385,8 +385,6 @@ enum {
SATA_SSP = 0x06, /* Software Settings Preservation */
SATA_DEVSLP = 0x09, /* Device Sleep */
- SETFEATURE_SENSE_DATA = 0xC3, /* Sense Data Reporting feature */
-
/* feature values for SET_MAX */
ATA_SET_MAX_ADDR = 0x00,
ATA_SET_MAX_PASSWD = 0x01,
@@ -530,8 +528,6 @@ struct ata_bmdma_prd {
#define ata_id_cdb_intr(id) (((id)[ATA_ID_CONFIG] & 0x60) == 0x20)
#define ata_id_has_da(id) ((id)[ATA_ID_SATA_CAPABILITY_2] & (1 << 4))
#define ata_id_has_devslp(id) ((id)[ATA_ID_FEATURE_SUPP] & (1 << 8))
-#define ata_id_has_ncq_autosense(id) \
- ((id)[ATA_ID_FEATURE_SUPP] & (1 << 7))
static inline bool ata_id_has_hipm(const u16 *id)
{
@@ -720,20 +716,6 @@ static inline bool ata_id_has_read_log_dma_ext(const u16 *id)
return false;
}
-static inline bool ata_id_has_sense_reporting(const u16 *id)
-{
- if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
- return false;
- return id[ATA_ID_COMMAND_SET_3] & (1 << 6);
-}
-
-static inline bool ata_id_sense_reporting_enabled(const u16 *id)
-{
- if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
- return false;
- return id[ATA_ID_COMMAND_SET_4] & (1 << 6);
-}
-
/**
* ata_id_major_version - get ATA level of drive
* @id: Identify data
diff --git a/include/linux/fs.h b/include/linux/fs.h
index cc008c3..84b783f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -55,7 +55,8 @@ struct vm_fault;
extern void __init inode_init(void);
extern void __init inode_init_early(void);
-extern void __init files_init(unsigned long);
+extern void __init files_init(void);
+extern void __init files_maxfiles_init(void);
extern struct files_stat_struct files_stat;
extern unsigned long get_max_files(void);
@@ -2245,7 +2246,7 @@ extern int ioctl_preallocate(struct file *filp, void __user *argp);
/* fs/dcache.c */
extern void __init vfs_caches_init_early(void);
-extern void __init vfs_caches_init(unsigned long);
+extern void __init vfs_caches_init(void);
extern struct kmem_cache *names_cachep;
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 92188b0..51744bc 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -484,6 +484,7 @@ extern int irq_chip_set_affinity_parent(struct irq_data *data,
extern int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on);
extern int irq_chip_set_vcpu_affinity_parent(struct irq_data *data,
void *vcpu_info);
+extern int irq_chip_set_type_parent(struct irq_data *data, unsigned int type);
#endif
/* Handling of unhandled and spurious interrupts: */
diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h
index 3499d36..11affb3 100644
--- a/include/linux/mfd/arizona/registers.h
+++ b/include/linux/mfd/arizona/registers.h
@@ -39,6 +39,7 @@
#define ARIZONA_PWM_DRIVE_3 0x32
#define ARIZONA_WAKE_CONTROL 0x40
#define ARIZONA_SEQUENCE_CONTROL 0x41
+#define ARIZONA_SPARE_TRIGGERS 0x42
#define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1 0x61
#define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2 0x62
#define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3 0x63
@@ -1431,6 +1432,42 @@
#define ARIZONA_WSEQ_ENA_JD2_RISE_WIDTH 1 /* WSEQ_ENA_JD2_RISE */
/*
+ * R66 (0x42) - Spare Triggers
+ */
+#define ARIZONA_WS_TRG8 0x0080 /* WS_TRG8 */
+#define ARIZONA_WS_TRG8_MASK 0x0080 /* WS_TRG8 */
+#define ARIZONA_WS_TRG8_SHIFT 7 /* WS_TRG8 */
+#define ARIZONA_WS_TRG8_WIDTH 1 /* WS_TRG8 */
+#define ARIZONA_WS_TRG7 0x0040 /* WS_TRG7 */
+#define ARIZONA_WS_TRG7_MASK 0x0040 /* WS_TRG7 */
+#define ARIZONA_WS_TRG7_SHIFT 6 /* WS_TRG7 */
+#define ARIZONA_WS_TRG7_WIDTH 1 /* WS_TRG7 */
+#define ARIZONA_WS_TRG6 0x0020 /* WS_TRG6 */
+#define ARIZONA_WS_TRG6_MASK 0x0020 /* WS_TRG6 */
+#define ARIZONA_WS_TRG6_SHIFT 5 /* WS_TRG6 */
+#define ARIZONA_WS_TRG6_WIDTH 1 /* WS_TRG6 */
+#define ARIZONA_WS_TRG5 0x0010 /* WS_TRG5 */
+#define ARIZONA_WS_TRG5_MASK 0x0010 /* WS_TRG5 */
+#define ARIZONA_WS_TRG5_SHIFT 4 /* WS_TRG5 */
+#define ARIZONA_WS_TRG5_WIDTH 1 /* WS_TRG5 */
+#define ARIZONA_WS_TRG4 0x0008 /* WS_TRG4 */
+#define ARIZONA_WS_TRG4_MASK 0x0008 /* WS_TRG4 */
+#define ARIZONA_WS_TRG4_SHIFT 3 /* WS_TRG4 */
+#define ARIZONA_WS_TRG4_WIDTH 1 /* WS_TRG4 */
+#define ARIZONA_WS_TRG3 0x0004 /* WS_TRG3 */
+#define ARIZONA_WS_TRG3_MASK 0x0004 /* WS_TRG3 */
+#define ARIZONA_WS_TRG3_SHIFT 2 /* WS_TRG3 */
+#define ARIZONA_WS_TRG3_WIDTH 1 /* WS_TRG3 */
+#define ARIZONA_WS_TRG2 0x0002 /* WS_TRG2 */
+#define ARIZONA_WS_TRG2_MASK 0x0002 /* WS_TRG2 */
+#define ARIZONA_WS_TRG2_SHIFT 1 /* WS_TRG2 */
+#define ARIZONA_WS_TRG2_WIDTH 1 /* WS_TRG2 */
+#define ARIZONA_WS_TRG1 0x0001 /* WS_TRG1 */
+#define ARIZONA_WS_TRG1_MASK 0x0001 /* WS_TRG1 */
+#define ARIZONA_WS_TRG1_SHIFT 0 /* WS_TRG1 */
+#define ARIZONA_WS_TRG1_WIDTH 1 /* WS_TRG1 */
+
+/*
* R97 (0x61) - Sample Rate Sequence Select 1
*/
#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_A_SEQ_ADDR_MASK 0x01FF /* WSEQ_SAMPLE_RATE_DETECT_A_SEQ_ADDR - [8:0] */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 2e872f9..bf6f117 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1003,6 +1003,34 @@ static inline int page_mapped(struct page *page)
}
/*
+ * Return true only if the page has been allocated with
+ * ALLOC_NO_WATERMARKS and the low watermark was not
+ * met implying that the system is under some pressure.
+ */
+static inline bool page_is_pfmemalloc(struct page *page)
+{
+ /*
+ * Page index cannot be this large so this must be
+ * a pfmemalloc page.
+ */
+ return page->index == -1UL;
+}
+
+/*
+ * Only to be called by the page allocator on a freshly allocated
+ * page.
+ */
+static inline void set_page_pfmemalloc(struct page *page)
+{
+ page->index = -1UL;
+}
+
+static inline void clear_page_pfmemalloc(struct page *page)
+{
+ page->index = 0;
+}
+
+/*
* Different kinds of faults, as returned by handle_mm_fault().
* Used to decide whether a process gets delivered SIGBUS or
* just gets major/minor fault counters bumped up.
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 0038ac7..1554957 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -63,15 +63,6 @@ struct page {
union {
pgoff_t index; /* Our offset within mapping. */
void *freelist; /* sl[aou]b first free object */
- bool pfmemalloc; /* If set by the page allocator,
- * ALLOC_NO_WATERMARKS was set
- * and the low watermark was not
- * met implying that the system
- * is under some pressure. The
- * caller should try ensure
- * this page is only used to
- * free other pages.
- */
};
union {
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index f34e040..41c9384 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -631,15 +631,19 @@ static inline void ClearPageSlabPfmemalloc(struct page *page)
1 << PG_private | 1 << PG_private_2 | \
1 << PG_writeback | 1 << PG_reserved | \
1 << PG_slab | 1 << PG_swapcache | 1 << PG_active | \
- 1 << PG_unevictable | __PG_MLOCKED | __PG_HWPOISON | \
+ 1 << PG_unevictable | __PG_MLOCKED | \
__PG_COMPOUND_LOCK)
/*
* Flags checked when a page is prepped for return by the page allocator.
- * Pages being prepped should not have any flags set. It they are set,
+ * Pages being prepped should not have these flags set. It they are set,
* there has been a kernel bug or struct page corruption.
+ *
+ * __PG_HWPOISON is exceptional because it needs to be kept beyond page's
+ * alloc-free cycle to prevent from reusing the page.
*/
-#define PAGE_FLAGS_CHECK_AT_PREP ((1 << NR_PAGEFLAGS) - 1)
+#define PAGE_FLAGS_CHECK_AT_PREP \
+ (((1 << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON)
#define PAGE_FLAGS_PRIVATE \
(1 << PG_private | 1 << PG_private_2)
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 59c55ea..4a67590 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -50,6 +50,17 @@ struct reg_default {
unsigned int def;
};
+/**
+ * Register/value pairs for sequences of writes
+ *
+ * @reg: Register address.
+ * @def: Register value.
+ */
+struct reg_sequence {
+ unsigned int reg;
+ unsigned int def;
+};
+
#ifdef CONFIG_REGMAP
enum regmap_endian {
@@ -410,10 +421,10 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_len);
int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
size_t val_count);
-int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
+int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs,
int num_regs);
int regmap_multi_reg_write_bypassed(struct regmap *map,
- const struct reg_default *regs,
+ const struct reg_sequence *regs,
int num_regs);
int regmap_raw_write_async(struct regmap *map, unsigned int reg,
const void *val, size_t val_len);
@@ -424,6 +435,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
size_t val_count);
int regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val);
+int regmap_write_bits(struct regmap *map, unsigned int reg,
+ unsigned int mask, unsigned int val);
int regmap_update_bits_async(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val);
int regmap_update_bits_check(struct regmap *map, unsigned int reg,
@@ -450,7 +463,7 @@ void regcache_mark_dirty(struct regmap *map);
bool regmap_check_range_table(struct regmap *map, unsigned int reg,
const struct regmap_access_table *table);
-int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
+int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs,
int num_regs);
int regmap_parse_val(struct regmap *map, const void *buf,
unsigned int *val);
@@ -503,6 +516,8 @@ int regmap_field_update_bits(struct regmap_field *field,
int regmap_fields_write(struct regmap_field *field, unsigned int id,
unsigned int val);
+int regmap_fields_force_write(struct regmap_field *field, unsigned int id,
+ unsigned int val);
int regmap_fields_read(struct regmap_field *field, unsigned int id,
unsigned int *val);
int regmap_fields_update_bits(struct regmap_field *field, unsigned int id,
@@ -645,6 +660,13 @@ static inline int regmap_update_bits(struct regmap *map, unsigned int reg,
return -EINVAL;
}
+static inline int regmap_write_bits(struct regmap *map, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ WARN_ONCE(1, "regmap API is disabled");
+ return -EINVAL;
+}
+
static inline int regmap_update_bits_async(struct regmap *map,
unsigned int reg,
unsigned int mask, unsigned int val)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index d6cdd6e..9b88536 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1602,20 +1602,16 @@ static inline void __skb_fill_page_desc(struct sk_buff *skb, int i,
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
/*
- * Propagate page->pfmemalloc to the skb if we can. The problem is
- * that not all callers have unique ownership of the page. If
- * pfmemalloc is set, we check the mapping as a mapping implies
- * page->index is set (index and pfmemalloc share space).
- * If it's a valid mapping, we cannot use page->pfmemalloc but we
- * do not lose pfmemalloc information as the pages would not be
- * allocated using __GFP_MEMALLOC.
+ * Propagate page pfmemalloc to the skb if we can. The problem is
+ * that not all callers have unique ownership of the page but rely
+ * on page_is_pfmemalloc doing the right thing(tm).
*/
frag->page.p = page;
frag->page_offset = off;
skb_frag_size_set(frag, size);
page = compound_head(page);
- if (page->pfmemalloc && !page->mapping)
+ if (page_is_pfmemalloc(page))
skb->pfmemalloc = true;
}
@@ -2263,7 +2259,7 @@ static inline struct page *dev_alloc_page(void)
static inline void skb_propagate_pfmemalloc(struct page *page,
struct sk_buff *skb)
{
- if (page && page->pfmemalloc)
+ if (page_is_pfmemalloc(page))
skb->pfmemalloc = true;
}
@@ -2884,11 +2880,11 @@ static inline bool skb_defer_rx_timestamp(struct sk_buff *skb)
*
* PHY drivers may accept clones of transmitted packets for
* timestamping via their phy_driver.txtstamp method. These drivers
- * must call this function to return the skb back to the stack, with
- * or without a timestamp.
+ * must call this function to return the skb back to the stack with a
+ * timestamp.
*
* @skb: clone of the the original outgoing packet
- * @hwtstamps: hardware time stamps, may be NULL if not available
+ * @hwtstamps: hardware time stamps
*
*/
void skb_complete_tx_timestamp(struct sk_buff *skb,
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 45534da5..644bdc6 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -74,8 +74,6 @@ enum rc_filter_type {
* @input_dev: the input child device used to communicate events to userspace
* @driver_type: specifies if protocol decoding is done in hardware or software
* @idle: used to keep track of RX state
- * @encode_wakeup: wakeup filtering uses IR encode API, therefore the allowed
- * wakeup protocols is the set of all raw encoders
* @allowed_protocols: bitmask with the supported RC_BIT_* protocols
* @enabled_protocols: bitmask with the enabled RC_BIT_* protocols
* @allowed_wakeup_protocols: bitmask with the supported RC_BIT_* wakeup protocols
@@ -136,7 +134,6 @@ struct rc_dev {
struct input_dev *input_dev;
enum rc_driver_type driver_type;
bool idle;
- bool encode_wakeup;
u64 allowed_protocols;
u64 enabled_protocols;
u64 allowed_wakeup_protocols;
@@ -246,7 +243,6 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev)
#define US_TO_NS(usec) ((usec) * 1000)
#define MS_TO_US(msec) ((msec) * 1000)
#define MS_TO_NS(msec) ((msec) * 1000 * 1000)
-#define NS_TO_US(nsec) DIV_ROUND_UP(nsec, 1000L)
void ir_raw_event_handle(struct rc_dev *dev);
int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
@@ -254,9 +250,6 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
int ir_raw_event_store_with_filter(struct rc_dev *dev,
struct ir_raw_event *ev);
void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
-int ir_raw_encode_scancode(u64 protocols,
- const struct rc_scancode_filter *scancode,
- struct ir_raw_event *events, unsigned int max);
static inline void ir_raw_event_reset(struct rc_dev *dev)
{
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 22a44c2..c192e1b 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -139,6 +139,7 @@ enum vb2_io_modes {
* @VB2_BUF_STATE_PREPARING: buffer is being prepared in videobuf
* @VB2_BUF_STATE_PREPARED: buffer prepared in videobuf and by the driver
* @VB2_BUF_STATE_QUEUED: buffer queued in videobuf, but not in driver
+ * @VB2_BUF_STATE_REQUEUEING: re-queue a buffer to the driver
* @VB2_BUF_STATE_ACTIVE: buffer queued in driver and possibly used
* in a hardware operation
* @VB2_BUF_STATE_DONE: buffer returned from driver to videobuf, but
@@ -152,6 +153,7 @@ enum vb2_buffer_state {
VB2_BUF_STATE_PREPARING,
VB2_BUF_STATE_PREPARED,
VB2_BUF_STATE_QUEUED,
+ VB2_BUF_STATE_REQUEUEING,
VB2_BUF_STATE_ACTIVE,
VB2_BUF_STATE_DONE,
VB2_BUF_STATE_ERROR,
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index 4942710..8d1d7fa 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -28,7 +28,6 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
u64 * info_out);
extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
-extern void scsi_set_sense_information(u8 *buf, u64 info);
extern int scsi_ioctl_reset(struct scsi_device *, int __user *);
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 0e9d75b..74bc8547 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -584,6 +584,8 @@ static inline int snd_ac97_update_power(struct snd_ac97 *ac97, int reg,
void snd_ac97_suspend(struct snd_ac97 *ac97);
void snd_ac97_resume(struct snd_ac97 *ac97);
#endif
+int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
+ unsigned int id_mask);
/* quirk types */
enum {
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
index 4cecd0c..bb7b2eb 100644
--- a/include/sound/rcar_snd.h
+++ b/include/sound/rcar_snd.h
@@ -61,6 +61,14 @@ struct rsnd_src_platform_info {
/*
* flags
*/
+struct rsnd_ctu_platform_info {
+ u32 flags;
+};
+
+struct rsnd_mix_platform_info {
+ u32 flags;
+};
+
struct rsnd_dvc_platform_info {
u32 flags;
};
@@ -68,6 +76,8 @@ struct rsnd_dvc_platform_info {
struct rsnd_dai_path_info {
struct rsnd_ssi_platform_info *ssi;
struct rsnd_src_platform_info *src;
+ struct rsnd_ctu_platform_info *ctu;
+ struct rsnd_mix_platform_info *mix;
struct rsnd_dvc_platform_info *dvc;
};
@@ -93,6 +103,10 @@ struct rcar_snd_info {
int ssi_info_nr;
struct rsnd_src_platform_info *src_info;
int src_info_nr;
+ struct rsnd_ctu_platform_info *ctu_info;
+ int ctu_info_nr;
+ struct rsnd_mix_platform_info *mix_info;
+ int mix_info_nr;
struct rsnd_dvc_platform_info *dvc_info;
int dvc_info_nr;
struct rsnd_dai_platform_info *dai_info;
diff --git a/include/sound/rt298.h b/include/sound/rt298.h
new file mode 100644
index 0000000..7fffeaa
--- /dev/null
+++ b/include/sound/rt298.h
@@ -0,0 +1,20 @@
+/*
+ * linux/sound/rt286.h -- Platform data for RT286
+ *
+ * Copyright 2013 Realtek Microelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_RT298_H
+#define __LINUX_SND_RT298_H
+
+struct rt298_platform_data {
+ bool cbj_en; /*combo jack enable*/
+ bool gpio2_en; /*GPIO2 enable*/
+ bool suspend_power_off; /* power is off during suspend */
+};
+
+#endif
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 37d95a8..5abba03 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -397,6 +397,7 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num);
int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num);
+void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w);
/* dapm events */
void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
@@ -511,9 +512,18 @@ struct snd_soc_dapm_route {
struct snd_soc_dapm_path {
const char *name;
- /* source (input) and sink (output) widgets */
- struct snd_soc_dapm_widget *source;
- struct snd_soc_dapm_widget *sink;
+ /*
+ * source (input) and sink (output) widgets
+ * The union is for convience, since it is a lot nicer to type
+ * p->source, rather than p->node[SND_SOC_DAPM_DIR_IN]
+ */
+ union {
+ struct {
+ struct snd_soc_dapm_widget *source;
+ struct snd_soc_dapm_widget *sink;
+ };
+ struct snd_soc_dapm_widget *node[2];
+ };
/* status */
u32 connect:1; /* source and sink widgets are connected */
@@ -524,8 +534,7 @@ struct snd_soc_dapm_path {
int (*connected)(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink);
- struct list_head list_source;
- struct list_head list_sink;
+ struct list_head list_node[2];
struct list_head list_kcontrol;
struct list_head list;
};
@@ -559,8 +568,7 @@ struct snd_soc_dapm_widget {
unsigned char new_power:1; /* power from this run */
unsigned char power_checked:1; /* power checked this run */
unsigned char is_supply:1; /* Widget is a supply type widget */
- unsigned char is_sink:1; /* Widget is a sink type widget */
- unsigned char is_source:1; /* Widget is a source type widget */
+ unsigned char is_ep:2; /* Widget is a endpoint type widget */
int subseq; /* sort within widget type */
int (*power_check)(struct snd_soc_dapm_widget *w);
@@ -575,16 +583,14 @@ struct snd_soc_dapm_widget {
struct snd_kcontrol **kcontrols;
struct snd_soc_dobj dobj;
- /* widget input and outputs */
- struct list_head sources;
- struct list_head sinks;
+ /* widget input and output edges */
+ struct list_head edges[2];
/* used during DAPM updates */
struct list_head work_list;
struct list_head power_list;
struct list_head dirty;
- int inputs;
- int outputs;
+ int endpoints[2];
struct clk *clk;
};
@@ -672,4 +678,58 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level(
return dapm->bias_level;
}
+enum snd_soc_dapm_direction {
+ SND_SOC_DAPM_DIR_IN,
+ SND_SOC_DAPM_DIR_OUT
+};
+
+#define SND_SOC_DAPM_DIR_TO_EP(x) BIT(x)
+
+#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN)
+#define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT)
+
+/**
+ * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths in the
+ * specified direction of a widget
+ * @w: The widget
+ * @dir: Whether to iterate over the paths where the specified widget is the
+ * incoming or outgoing widgets
+ * @p: The path iterator variable
+ */
+#define snd_soc_dapm_widget_for_each_path(w, dir, p) \
+ list_for_each_entry(p, &w->edges[dir], list_node[dir])
+
+/**
+ * snd_soc_dapm_widget_for_each_sink_path_safe - Iterates over all paths in the
+ * specified direction of a widget
+ * @w: The widget
+ * @dir: Whether to iterate over the paths where the specified widget is the
+ * incoming or outgoing widgets
+ * @p: The path iterator variable
+ * @next_p: Temporary storage for the next path
+ *
+ * This function works like snd_soc_dapm_widget_for_each_sink_path, expect that
+ * it is safe to remove the current path from the list while iterating
+ */
+#define snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p) \
+ list_for_each_entry_safe(p, next_p, &w->edges[dir], list_node[dir])
+
+/**
+ * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths leaving a
+ * widget
+ * @w: The widget
+ * @p: The path iterator variable
+ */
+#define snd_soc_dapm_widget_for_each_sink_path(w, p) \
+ snd_soc_dapm_widget_for_each_path(w, SND_SOC_DAPM_DIR_IN, p)
+
+/**
+ * snd_soc_dapm_widget_for_each_source_path - Iterates over all paths leading to
+ * a widget
+ * @w: The widget
+ * @p: The path iterator variable
+ */
+#define snd_soc_dapm_widget_for_each_source_path(w, p) \
+ snd_soc_dapm_widget_for_each_path(w, SND_SOC_DAPM_DIR_OUT, p)
+
#endif
diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h
index 427bc41..086cd7f 100644
--- a/include/sound/soc-topology.h
+++ b/include/sound/soc-topology.h
@@ -89,6 +89,13 @@ struct snd_soc_tplg_kcontrol_ops {
struct snd_ctl_elem_info *uinfo);
};
+/* Bytes ext operations, for TLV byte controls */
+struct snd_soc_tplg_bytes_ext_ops {
+ u32 id;
+ int (*get)(unsigned int __user *bytes, unsigned int size);
+ int (*put)(const unsigned int __user *bytes, unsigned int size);
+};
+
/*
* DAPM widget event handlers - used to map handlers onto widgets.
*/
@@ -136,9 +143,13 @@ struct snd_soc_tplg_ops {
int (*manifest)(struct snd_soc_component *,
struct snd_soc_tplg_manifest *);
- /* bespoke kcontrol handlers available for binding */
+ /* vendor specific kcontrol handlers available for binding */
const struct snd_soc_tplg_kcontrol_ops *io_ops;
int io_ops_count;
+
+ /* vendor specific bytes ext handlers available for binding */
+ const struct snd_soc_tplg_bytes_ext_ops *bytes_ext_ops;
+ int bytes_ext_ops_count;
};
#ifdef CONFIG_SND_SOC_TOPOLOGY
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 93df8bf..884e728 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -526,7 +526,8 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
#ifdef CONFIG_SND_SOC_AC97_BUS
struct snd_ac97 *snd_soc_alloc_ac97_codec(struct snd_soc_codec *codec);
-struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec);
+struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
+ unsigned int id, unsigned int id_mask);
void snd_soc_free_ac97_codec(struct snd_ac97 *ac97);
int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
@@ -619,6 +620,7 @@ int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
* @pin: name of the pin to update
* @mask: bits to check for in reported jack status
* @invert: if non-zero then pin is enabled when status is not reported
+ * @list: internal list entry
*/
struct snd_soc_jack_pin {
struct list_head list;
@@ -635,7 +637,7 @@ struct snd_soc_jack_pin {
* @jack_type: type of jack that is expected for this voltage
* @debounce_time: debounce_time for jack, codec driver should wait for this
* duration before reading the adc for voltages
- * @:list: list container
+ * @list: internal list entry
*/
struct snd_soc_jack_zone {
unsigned int min_mv;
@@ -651,12 +653,12 @@ struct snd_soc_jack_zone {
* @gpio: legacy gpio number
* @idx: gpio descriptor index within the function of the GPIO
* consumer device
- * @gpiod_dev GPIO consumer device
+ * @gpiod_dev: GPIO consumer device
* @name: gpio name. Also as connection ID for the GPIO consumer
* device function name lookup
* @report: value to report when jack detected
* @invert: report presence in low state
- * @debouce_time: debouce time in ms
+ * @debounce_time: debounce time in ms
* @wake: enable as wake source
* @jack_status_check: callback function which overrides the detection
* to provide more complex checks (eg, reading an
@@ -672,11 +674,13 @@ struct snd_soc_jack_gpio {
int debounce_time;
bool wake;
+ /* private: */
struct snd_soc_jack *jack;
struct delayed_work work;
struct gpio_desc *desc;
void *data;
+ /* public: */
int (*jack_status_check)(void *data);
};
@@ -758,7 +762,6 @@ struct snd_soc_component {
unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
unsigned int registered_as_component:1;
- unsigned int probed:1;
struct list_head list;
@@ -792,7 +795,6 @@ struct snd_soc_component {
/* Don't use these, use snd_soc_component_get_dapm() */
struct snd_soc_dapm_context dapm;
- struct snd_soc_dapm_context *dapm_ptr;
const struct snd_kcontrol_new *controls;
unsigned int num_controls;
@@ -832,9 +834,6 @@ struct snd_soc_codec {
/* component */
struct snd_soc_component component;
- /* Don't access this directly, use snd_soc_codec_get_dapm() */
- struct snd_soc_dapm_context dapm;
-
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_reg;
#endif
@@ -1277,7 +1276,7 @@ static inline struct snd_soc_component *snd_soc_dapm_to_component(
static inline struct snd_soc_codec *snd_soc_dapm_to_codec(
struct snd_soc_dapm_context *dapm)
{
- return container_of(dapm, struct snd_soc_codec, dapm);
+ return snd_soc_component_to_codec(snd_soc_dapm_to_component(dapm));
}
/**
@@ -1302,7 +1301,7 @@ static inline struct snd_soc_platform *snd_soc_dapm_to_platform(
static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm(
struct snd_soc_component *component)
{
- return component->dapm_ptr;
+ return &component->dapm;
}
/**
@@ -1314,12 +1313,12 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm(
static inline struct snd_soc_dapm_context *snd_soc_codec_get_dapm(
struct snd_soc_codec *codec)
{
- return &codec->dapm;
+ return snd_soc_component_get_dapm(&codec->component);
}
/**
* snd_soc_dapm_init_bias_level() - Initialize CODEC DAPM bias level
- * @dapm: The CODEC for which to initialize the DAPM bias level
+ * @codec: The CODEC for which to initialize the DAPM bias level
* @level: The DAPM level to initialize to
*
* Initializes the CODEC DAPM bias level. See snd_soc_dapm_init_bias_level().
@@ -1604,6 +1603,10 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
int snd_soc_of_parse_tdm_slot(struct device_node *np,
unsigned int *slots,
unsigned int *slot_width);
+void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
+ struct snd_soc_codec_conf *codec_conf,
+ struct device_node *of_node,
+ const char *propname);
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname);
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h
index 88cf39d..317a1ed 100644
--- a/include/trace/events/asoc.h
+++ b/include/trace/events/asoc.h
@@ -8,6 +8,7 @@
#include <linux/tracepoint.h>
#define DAPM_DIRECT "(direct)"
+#define DAPM_ARROW(dir) (((dir) == SND_SOC_DAPM_DIR_OUT) ? "->" : "<-")
struct snd_soc_jack;
struct snd_soc_codec;
@@ -152,62 +153,38 @@ TRACE_EVENT(snd_soc_dapm_walk_done,
(int)__entry->path_checks, (int)__entry->neighbour_checks)
);
-TRACE_EVENT(snd_soc_dapm_output_path,
+TRACE_EVENT(snd_soc_dapm_path,
TP_PROTO(struct snd_soc_dapm_widget *widget,
+ enum snd_soc_dapm_direction dir,
struct snd_soc_dapm_path *path),
- TP_ARGS(widget, path),
+ TP_ARGS(widget, dir, path),
TP_STRUCT__entry(
__string( wname, widget->name )
__string( pname, path->name ? path->name : DAPM_DIRECT)
- __string( psname, path->sink->name )
- __field( int, path_sink )
+ __string( pnname, path->node[dir]->name )
+ __field( int, path_node )
__field( int, path_connect )
+ __field( int, path_dir )
),
TP_fast_assign(
__assign_str(wname, widget->name);
__assign_str(pname, path->name ? path->name : DAPM_DIRECT);
- __assign_str(psname, path->sink->name);
+ __assign_str(pnname, path->node[dir]->name);
__entry->path_connect = path->connect;
- __entry->path_sink = (long)path->sink;
+ __entry->path_node = (long)path->node[dir];
+ __entry->path_dir = dir;
),
- TP_printk("%c%s -> %s -> %s",
- (int) __entry->path_sink &&
+ TP_printk("%c%s %s %s %s %s",
+ (int) __entry->path_node &&
(int) __entry->path_connect ? '*' : ' ',
- __get_str(wname), __get_str(pname), __get_str(psname))
-);
-
-TRACE_EVENT(snd_soc_dapm_input_path,
-
- TP_PROTO(struct snd_soc_dapm_widget *widget,
- struct snd_soc_dapm_path *path),
-
- TP_ARGS(widget, path),
-
- TP_STRUCT__entry(
- __string( wname, widget->name )
- __string( pname, path->name ? path->name : DAPM_DIRECT)
- __string( psname, path->source->name )
- __field( int, path_source )
- __field( int, path_connect )
- ),
-
- TP_fast_assign(
- __assign_str(wname, widget->name);
- __assign_str(pname, path->name ? path->name : DAPM_DIRECT);
- __assign_str(psname, path->source->name);
- __entry->path_connect = path->connect;
- __entry->path_source = (long)path->source;
- ),
-
- TP_printk("%c%s <- %s <- %s",
- (int) __entry->path_source &&
- (int) __entry->path_connect ? '*' : ' ',
- __get_str(wname), __get_str(pname), __get_str(psname))
+ __get_str(wname), DAPM_ARROW(__entry->path_dir),
+ __get_str(pname), DAPM_ARROW(__entry->path_dir),
+ __get_str(pnname))
);
TRACE_EVENT(snd_soc_dapm_connected,
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index efe3443..413417f 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -319,6 +319,7 @@
#define PCI_MSIX_PBA 8 /* Pending Bit Array offset */
#define PCI_MSIX_PBA_BIR 0x00000007 /* BAR index */
#define PCI_MSIX_PBA_OFFSET 0xfffffff8 /* Offset into specified BAR */
+#define PCI_MSIX_FLAGS_BIRMASK PCI_MSIX_PBA_BIR /* deprecated */
#define PCI_CAP_MSIX_SIZEOF 12 /* size of MSIX registers */
/* MSI-X Table entry format */
diff --git a/init/main.c b/init/main.c
index c5d5626..5650655 100644
--- a/init/main.c
+++ b/init/main.c
@@ -656,7 +656,7 @@ asmlinkage __visible void __init start_kernel(void)
key_init();
security_init();
dbg_late_init();
- vfs_caches_init(totalram_pages);
+ vfs_caches_init();
signals_init();
/* rootfs populating might need page-writeback */
page_writeback_init();
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index a24ba9f..161a180 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -142,7 +142,6 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info)
if (!leaf)
return -ENOMEM;
INIT_LIST_HEAD(&leaf->msg_list);
- info->qsize += sizeof(*leaf);
}
leaf->priority = msg->m_type;
rb_link_node(&leaf->rb_node, parent, p);
@@ -187,7 +186,6 @@ try_again:
"lazy leaf delete!\n");
rb_erase(&leaf->rb_node, &info->msg_tree);
if (info->node_cache) {
- info->qsize -= sizeof(*leaf);
kfree(leaf);
} else {
info->node_cache = leaf;
@@ -200,7 +198,6 @@ try_again:
if (list_empty(&leaf->msg_list)) {
rb_erase(&leaf->rb_node, &info->msg_tree);
if (info->node_cache) {
- info->qsize -= sizeof(*leaf);
kfree(leaf);
} else {
info->node_cache = leaf;
@@ -1034,7 +1031,6 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
/* Save our speculative allocation into the cache */
INIT_LIST_HEAD(&new_leaf->msg_list);
info->node_cache = new_leaf;
- info->qsize += sizeof(*new_leaf);
new_leaf = NULL;
} else {
kfree(new_leaf);
@@ -1142,7 +1138,6 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
/* Save our speculative allocation into the cache */
INIT_LIST_HEAD(&new_leaf->msg_list);
info->node_cache = new_leaf;
- info->qsize += sizeof(*new_leaf);
} else {
kfree(new_leaf);
}
diff --git a/ipc/sem.c b/ipc/sem.c
index bc3d530..b471e5a 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -253,6 +253,16 @@ static void sem_rcu_free(struct rcu_head *head)
}
/*
+ * spin_unlock_wait() and !spin_is_locked() are not memory barriers, they
+ * are only control barriers.
+ * The code must pair with spin_unlock(&sem->lock) or
+ * spin_unlock(&sem_perm.lock), thus just the control barrier is insufficient.
+ *
+ * smp_rmb() is sufficient, as writes cannot pass the control barrier.
+ */
+#define ipc_smp_acquire__after_spin_is_unlocked() smp_rmb()
+
+/*
* Wait until all currently ongoing simple ops have completed.
* Caller must own sem_perm.lock.
* New simple ops cannot start, because simple ops first check
@@ -275,6 +285,7 @@ static void sem_wait_array(struct sem_array *sma)
sem = sma->sem_base + i;
spin_unlock_wait(&sem->lock);
}
+ ipc_smp_acquire__after_spin_is_unlocked();
}
/*
@@ -327,13 +338,12 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
/* Then check that the global lock is free */
if (!spin_is_locked(&sma->sem_perm.lock)) {
/*
- * The ipc object lock check must be visible on all
- * cores before rechecking the complex count. Otherwise
- * we can race with another thread that does:
+ * We need a memory barrier with acquire semantics,
+ * otherwise we can race with another thread that does:
* complex_count++;
* spin_unlock(sem_perm.lock);
*/
- smp_rmb();
+ ipc_smp_acquire__after_spin_is_unlocked();
/*
* Now repeat the test of complex_count:
@@ -2074,17 +2084,28 @@ void exit_sem(struct task_struct *tsk)
rcu_read_lock();
un = list_entry_rcu(ulp->list_proc.next,
struct sem_undo, list_proc);
- if (&un->list_proc == &ulp->list_proc)
- semid = -1;
- else
- semid = un->semid;
+ if (&un->list_proc == &ulp->list_proc) {
+ /*
+ * We must wait for freeary() before freeing this ulp,
+ * in case we raced with last sem_undo. There is a small
+ * possibility where we exit while freeary() didn't
+ * finish unlocking sem_undo_list.
+ */
+ spin_unlock_wait(&ulp->lock);
+ rcu_read_unlock();
+ break;
+ }
+ spin_lock(&ulp->lock);
+ semid = un->semid;
+ spin_unlock(&ulp->lock);
+ /* exit_sem raced with IPC_RMID, nothing to do */
if (semid == -1) {
rcu_read_unlock();
- break;
+ continue;
}
- sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, un->semid);
+ sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, semid);
/* exit_sem raced with IPC_RMID, nothing to do */
if (IS_ERR(sma)) {
rcu_read_unlock();
@@ -2112,9 +2133,11 @@ void exit_sem(struct task_struct *tsk)
ipc_assert_locked_object(&sma->sem_perm);
list_del(&un->list_id);
- spin_lock(&ulp->lock);
+ /* we are the last process using this ulp, acquiring ulp->lock
+ * isn't required. Besides that, we are also protected against
+ * IPC_RMID as we hold sma->sem_perm lock now
+ */
list_del_rcu(&un->list_proc);
- spin_unlock(&ulp->lock);
/* perform adjustments registered in un */
for (i = 0; i < sma->sem_nsems; i++) {
diff --git a/ipc/shm.c b/ipc/shm.c
index 06e5cf2..4aef24d 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -545,7 +545,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
if ((shmflg & SHM_NORESERVE) &&
sysctl_overcommit_memory != OVERCOMMIT_NEVER)
acctflag = VM_NORESERVE;
- file = shmem_file_setup(name, size, acctflag);
+ file = shmem_kernel_file_setup(name, size, acctflag);
}
error = PTR_ERR(file);
if (IS_ERR(file))
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index ee14e3a..f0acff0 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1223,7 +1223,7 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
spin_unlock_irq(&callback_lock);
/* use trialcs->mems_allowed as a temp variable */
- update_nodemasks_hier(cs, &cs->mems_allowed);
+ update_nodemasks_hier(cs, &trialcs->mems_allowed);
done:
return retval;
}
diff --git a/kernel/events/core.c b/kernel/events/core.c
index d3dae34..e6feb51 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -1868,8 +1868,6 @@ event_sched_in(struct perf_event *event,
perf_pmu_disable(event->pmu);
- event->tstamp_running += tstamp - event->tstamp_stopped;
-
perf_set_shadow_time(event, ctx, tstamp);
perf_log_itrace_start(event);
@@ -1881,6 +1879,8 @@ event_sched_in(struct perf_event *event,
goto out;
}
+ event->tstamp_running += tstamp - event->tstamp_stopped;
+
if (!is_software_event(event))
cpuctx->active_oncpu++;
if (!ctx->nr_active++)
@@ -3958,28 +3958,21 @@ static void perf_event_for_each(struct perf_event *event,
perf_event_for_each_child(sibling, func);
}
-static int perf_event_period(struct perf_event *event, u64 __user *arg)
-{
- struct perf_event_context *ctx = event->ctx;
- int ret = 0, active;
+struct period_event {
+ struct perf_event *event;
u64 value;
+};
- if (!is_sampling_event(event))
- return -EINVAL;
-
- if (copy_from_user(&value, arg, sizeof(value)))
- return -EFAULT;
-
- if (!value)
- return -EINVAL;
+static int __perf_event_period(void *info)
+{
+ struct period_event *pe = info;
+ struct perf_event *event = pe->event;
+ struct perf_event_context *ctx = event->ctx;
+ u64 value = pe->value;
+ bool active;
- raw_spin_lock_irq(&ctx->lock);
+ raw_spin_lock(&ctx->lock);
if (event->attr.freq) {
- if (value > sysctl_perf_event_sample_rate) {
- ret = -EINVAL;
- goto unlock;
- }
-
event->attr.sample_freq = value;
} else {
event->attr.sample_period = value;
@@ -3998,11 +3991,53 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
event->pmu->start(event, PERF_EF_RELOAD);
perf_pmu_enable(ctx->pmu);
}
+ raw_spin_unlock(&ctx->lock);
-unlock:
+ return 0;
+}
+
+static int perf_event_period(struct perf_event *event, u64 __user *arg)
+{
+ struct period_event pe = { .event = event, };
+ struct perf_event_context *ctx = event->ctx;
+ struct task_struct *task;
+ u64 value;
+
+ if (!is_sampling_event(event))
+ return -EINVAL;
+
+ if (copy_from_user(&value, arg, sizeof(value)))
+ return -EFAULT;
+
+ if (!value)
+ return -EINVAL;
+
+ if (event->attr.freq && value > sysctl_perf_event_sample_rate)
+ return -EINVAL;
+
+ task = ctx->task;
+ pe.value = value;
+
+ if (!task) {
+ cpu_function_call(event->cpu, __perf_event_period, &pe);
+ return 0;
+ }
+
+retry:
+ if (!task_function_call(task, __perf_event_period, &pe))
+ return 0;
+
+ raw_spin_lock_irq(&ctx->lock);
+ if (ctx->is_active) {
+ raw_spin_unlock_irq(&ctx->lock);
+ task = ctx->task;
+ goto retry;
+ }
+
+ __perf_event_period(&pe);
raw_spin_unlock_irq(&ctx->lock);
- return ret;
+ return 0;
}
static const struct file_operations perf_fops;
@@ -4740,12 +4775,20 @@ static const struct file_operations perf_fops = {
* to user-space before waking everybody up.
*/
+static inline struct fasync_struct **perf_event_fasync(struct perf_event *event)
+{
+ /* only the parent has fasync state */
+ if (event->parent)
+ event = event->parent;
+ return &event->fasync;
+}
+
void perf_event_wakeup(struct perf_event *event)
{
ring_buffer_wakeup(event);
if (event->pending_kill) {
- kill_fasync(&event->fasync, SIGIO, event->pending_kill);
+ kill_fasync(perf_event_fasync(event), SIGIO, event->pending_kill);
event->pending_kill = 0;
}
}
@@ -6124,7 +6167,7 @@ static int __perf_event_overflow(struct perf_event *event,
else
perf_event_output(event, data, regs);
- if (event->fasync && event->pending_kill) {
+ if (*perf_event_fasync(event) && event->pending_kill) {
event->pending_wakeup = 1;
irq_work_queue(&event->pending);
}
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index b2be01b..c8aa3f7 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -559,11 +559,13 @@ static void __rb_free_aux(struct ring_buffer *rb)
rb->aux_priv = NULL;
}
- for (pg = 0; pg < rb->aux_nr_pages; pg++)
- rb_free_aux_page(rb, pg);
+ if (rb->aux_nr_pages) {
+ for (pg = 0; pg < rb->aux_nr_pages; pg++)
+ rb_free_aux_page(rb, pg);
- kfree(rb->aux_pages);
- rb->aux_nr_pages = 0;
+ kfree(rb->aux_pages);
+ rb->aux_nr_pages = 0;
+ }
}
void rb_free_aux(struct ring_buffer *rb)
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 27f4332..ae21682 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -985,6 +985,23 @@ int irq_chip_set_affinity_parent(struct irq_data *data,
}
/**
+ * irq_chip_set_type_parent - Set IRQ type on the parent interrupt
+ * @data: Pointer to interrupt specific data
+ * @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
+ *
+ * Conditional, as the underlying parent chip might not implement it.
+ */
+int irq_chip_set_type_parent(struct irq_data *data, unsigned int type)
+{
+ data = data->parent_data;
+
+ if (data->chip->irq_set_type)
+ return data->chip->irq_set_type(data, type);
+
+ return -ENOSYS;
+}
+
+/**
* irq_chip_retrigger_hierarchy - Retrigger an interrupt in hardware
* @data: Pointer to interrupt specific data
*
@@ -997,7 +1014,7 @@ int irq_chip_retrigger_hierarchy(struct irq_data *data)
if (data->chip && data->chip->irq_retrigger)
return data->chip->irq_retrigger(data);
- return -ENOSYS;
+ return 0;
}
/**
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 10e489c..fdea0be 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -97,6 +97,7 @@ bool kthread_should_park(void)
{
return test_bit(KTHREAD_SHOULD_PARK, &to_kthread(current)->flags);
}
+EXPORT_SYMBOL_GPL(kthread_should_park);
/**
* kthread_freezable_should_stop - should this freezable kthread return now?
@@ -171,6 +172,7 @@ void kthread_parkme(void)
{
__kthread_parkme(to_kthread(current));
}
+EXPORT_SYMBOL_GPL(kthread_parkme);
static int kthread(void *_create)
{
@@ -411,6 +413,7 @@ void kthread_unpark(struct task_struct *k)
if (kthread)
__kthread_unpark(k, kthread);
}
+EXPORT_SYMBOL_GPL(kthread_unpark);
/**
* kthread_park - park a thread created by kthread_create().
@@ -441,6 +444,7 @@ int kthread_park(struct task_struct *k)
}
return ret;
}
+EXPORT_SYMBOL_GPL(kthread_park);
/**
* kthread_stop - stop a thread created by kthread_create().
diff --git a/kernel/locking/qspinlock_paravirt.h b/kernel/locking/qspinlock_paravirt.h
index 04ab181..df19ae4 100644
--- a/kernel/locking/qspinlock_paravirt.h
+++ b/kernel/locking/qspinlock_paravirt.h
@@ -4,6 +4,7 @@
#include <linux/hash.h>
#include <linux/bootmem.h>
+#include <linux/debug_locks.h>
/*
* Implement paravirt qspinlocks; the general idea is to halt the vcpus instead
@@ -286,15 +287,23 @@ __visible void __pv_queued_spin_unlock(struct qspinlock *lock)
{
struct __qspinlock *l = (void *)lock;
struct pv_node *node;
+ u8 lockval = cmpxchg(&l->locked, _Q_LOCKED_VAL, 0);
/*
* We must not unlock if SLOW, because in that case we must first
* unhash. Otherwise it would be possible to have multiple @lock
* entries, which would be BAD.
*/
- if (likely(cmpxchg(&l->locked, _Q_LOCKED_VAL, 0) == _Q_LOCKED_VAL))
+ if (likely(lockval == _Q_LOCKED_VAL))
return;
+ if (unlikely(lockval != _Q_SLOW_VAL)) {
+ if (debug_locks_silent)
+ return;
+ WARN(1, "pvqspinlock: lock %p has corrupted value 0x%x!\n", lock, atomic_read(&lock->val));
+ return;
+ }
+
/*
* Since the above failed to release, this must be the SLOW path.
* Therefore start by looking up the blocked node and unhashing it.
diff --git a/kernel/module.c b/kernel/module.c
index 4d2b82e..b86b7bf 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -602,13 +602,16 @@ const struct kernel_symbol *find_symbol(const char *name,
}
EXPORT_SYMBOL_GPL(find_symbol);
-/* Search for module by name: must hold module_mutex. */
+/*
+ * Search for module by name: must hold module_mutex (or preempt disabled
+ * for read-only access).
+ */
static struct module *find_module_all(const char *name, size_t len,
bool even_unformed)
{
struct module *mod;
- module_assert_mutex();
+ module_assert_mutex_or_preempt();
list_for_each_entry(mod, &modules, list) {
if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
@@ -621,6 +624,7 @@ static struct module *find_module_all(const char *name, size_t len,
struct module *find_module(const char *name)
{
+ module_assert_mutex();
return find_module_all(name, strlen(name), false);
}
EXPORT_SYMBOL_GPL(find_module);
diff --git a/kernel/signal.c b/kernel/signal.c
index 836df8d..0f6bbbe 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2748,12 +2748,15 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
* Other callers might not initialize the si_lsb field,
* so check explicitly for the right codes here.
*/
- if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
+ if (from->si_signo == SIGBUS &&
+ (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
#endif
#ifdef SEGV_BNDERR
- err |= __put_user(from->si_lower, &to->si_lower);
- err |= __put_user(from->si_upper, &to->si_upper);
+ if (from->si_signo == SIGSEGV && from->si_code == SEGV_BNDERR) {
+ err |= __put_user(from->si_lower, &to->si_lower);
+ err |= __put_user(from->si_upper, &to->si_upper);
+ }
#endif
break;
case __SI_CHLD:
@@ -3017,7 +3020,7 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo,
int, sig,
struct compat_siginfo __user *, uinfo)
{
- siginfo_t info;
+ siginfo_t info = {};
int ret = copy_siginfo_from_user32(&info, uinfo);
if (unlikely(ret))
return ret;
@@ -3061,7 +3064,7 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo,
int, sig,
struct compat_siginfo __user *, uinfo)
{
- siginfo_t info;
+ siginfo_t info = {};
if (copy_siginfo_from_user32(&info, uinfo))
return -EFAULT;
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 5e097fa..84190f0 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -807,8 +807,8 @@ __mod_timer(struct timer_list *timer, unsigned long expires,
spin_unlock(&base->lock);
base = new_base;
spin_lock(&base->lock);
- timer->flags &= ~TIMER_BASEMASK;
- timer->flags |= base->cpu;
+ WRITE_ONCE(timer->flags,
+ (timer->flags & ~TIMER_BASEMASK) | base->cpu);
}
}
diff --git a/lib/iommu-common.c b/lib/iommu-common.c
index df30632..ff19f66 100644
--- a/lib/iommu-common.c
+++ b/lib/iommu-common.c
@@ -119,7 +119,7 @@ unsigned long iommu_tbl_range_alloc(struct device *dev,
unsigned long align_mask = 0;
if (align_order > 0)
- align_mask = 0xffffffffffffffffl >> (64 - align_order);
+ align_mask = ~0ul >> (BITS_PER_LONG - align_order);
/* Sanity check */
if (unlikely(npages == 0)) {
diff --git a/mm/cma.h b/mm/cma.h
index 1132d73..17c75a4 100644
--- a/mm/cma.h
+++ b/mm/cma.h
@@ -16,7 +16,7 @@ struct cma {
extern struct cma cma_areas[MAX_CMA_AREAS];
extern unsigned cma_area_count;
-static unsigned long cma_bitmap_maxno(struct cma *cma)
+static inline unsigned long cma_bitmap_maxno(struct cma *cma)
{
return cma->count >> cma->order_per_bit;
}
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index c107094..097c7a4 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1676,12 +1676,7 @@ static void __split_huge_page_refcount(struct page *page,
/* after clearing PageTail the gup refcount can be released */
smp_mb__after_atomic();
- /*
- * retain hwpoison flag of the poisoned tail page:
- * fix for the unsuitable process killed on Guest Machine(KVM)
- * by the memory-failure.
- */
- page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP | __PG_HWPOISON;
+ page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
page_tail->flags |= (page->flags &
((1L << PG_referenced) |
(1L << PG_swapbacked) |
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
index 6c513a6..7b28e9c 100644
--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
@@ -2,7 +2,7 @@
* This file contains shadow memory manipulation code.
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
- * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
+ * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
*
* Some of code borrowed from https://github.com/xairy/linux by
* Andrey Konovalov <adech.fo@gmail.com>
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 680ceed..e07c94f 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -2,7 +2,7 @@
* This file contains error reporting code.
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
- * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
+ * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
*
* Some of code borrowed from https://github.com/xairy/linux by
* Andrey Konovalov <adech.fo@gmail.com>
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index c53543d..1f4446a9 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -909,6 +909,18 @@ int get_hwpoison_page(struct page *page)
* directly for tail pages.
*/
if (PageTransHuge(head)) {
+ /*
+ * Non anonymous thp exists only in allocation/free time. We
+ * can't handle such a case correctly, so let's give it up.
+ * This should be better than triggering BUG_ON when kernel
+ * tries to touch the "partially handled" page.
+ */
+ if (!PageAnon(head)) {
+ pr_err("MCE: %#lx: non anonymous thp\n",
+ page_to_pfn(page));
+ return 0;
+ }
+
if (get_page_unless_zero(head)) {
if (PageTail(page))
get_page(page);
@@ -1134,17 +1146,11 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
}
if (!PageHuge(p) && PageTransHuge(hpage)) {
- if (!PageAnon(hpage)) {
- pr_err("MCE: %#lx: non anonymous thp\n", pfn);
- if (TestClearPageHWPoison(p))
- atomic_long_sub(nr_pages, &num_poisoned_pages);
- put_page(p);
- if (p != hpage)
- put_page(hpage);
- return -EBUSY;
- }
- if (unlikely(split_huge_page(hpage))) {
- pr_err("MCE: %#lx: thp split failed\n", pfn);
+ if (!PageAnon(hpage) || unlikely(split_huge_page(hpage))) {
+ if (!PageAnon(hpage))
+ pr_err("MCE: %#lx: non anonymous thp\n", pfn);
+ else
+ pr_err("MCE: %#lx: thp split failed\n", pfn);
if (TestClearPageHWPoison(p))
atomic_long_sub(nr_pages, &num_poisoned_pages);
put_page(p);
@@ -1209,9 +1215,9 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
if (!PageHWPoison(p)) {
printk(KERN_ERR "MCE %#lx: just unpoisoned\n", pfn);
atomic_long_sub(nr_pages, &num_poisoned_pages);
+ unlock_page(hpage);
put_page(hpage);
- res = 0;
- goto out;
+ return 0;
}
if (hwpoison_filter(p)) {
if (TestClearPageHWPoison(p))
@@ -1535,6 +1541,8 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags)
*/
ret = __get_any_page(page, pfn, 0);
if (!PageLRU(page)) {
+ /* Drop page reference which is from __get_any_page() */
+ put_page(page);
pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n",
pfn, page->flags);
return -EIO;
@@ -1564,13 +1572,12 @@ static int soft_offline_huge_page(struct page *page, int flags)
unlock_page(hpage);
ret = isolate_huge_page(hpage, &pagelist);
- if (ret) {
- /*
- * get_any_page() and isolate_huge_page() takes a refcount each,
- * so need to drop one here.
- */
- put_page(hpage);
- } else {
+ /*
+ * get_any_page() and isolate_huge_page() takes a refcount each,
+ * so need to drop one here.
+ */
+ put_page(hpage);
+ if (!ret) {
pr_info("soft offline: %#lx hugepage failed to isolate\n", pfn);
return -EBUSY;
}
@@ -1656,6 +1663,8 @@ static int __soft_offline_page(struct page *page, int flags)
inc_zone_page_state(page, NR_ISOLATED_ANON +
page_is_file_cache(page));
list_add(&page->lru, &pagelist);
+ if (!TestSetPageHWPoison(page))
+ atomic_long_inc(&num_poisoned_pages);
ret = migrate_pages(&pagelist, new_page, NULL, MPOL_MF_MOVE_ALL,
MIGRATE_SYNC, MR_MEMORY_FAILURE);
if (ret) {
@@ -1670,9 +1679,8 @@ static int __soft_offline_page(struct page *page, int flags)
pfn, ret, page->flags);
if (ret > 0)
ret = -EIO;
- } else {
- SetPageHWPoison(page);
- atomic_long_inc(&num_poisoned_pages);
+ if (TestClearPageHWPoison(page))
+ atomic_long_dec(&num_poisoned_pages);
}
} else {
pr_info("soft offline: %#lx: isolation failed: %d, page count %d, type %lx\n",
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 26fbba7..6da82bc 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -446,7 +446,7 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn)
int nr_pages = PAGES_PER_SECTION;
int nid = pgdat->node_id;
int zone_type;
- unsigned long flags;
+ unsigned long flags, pfn;
int ret;
zone_type = zone - pgdat->node_zones;
@@ -461,6 +461,14 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn)
pgdat_resize_unlock(zone->zone_pgdat, &flags);
memmap_init_zone(nr_pages, nid, zone_type,
phys_start_pfn, MEMMAP_HOTPLUG);
+
+ /* online_page_range is called later and expects pages reserved */
+ for (pfn = phys_start_pfn; pfn < phys_start_pfn + nr_pages; pfn++) {
+ if (!pfn_valid(pfn))
+ continue;
+
+ SetPageReserved(pfn_to_page(pfn));
+ }
return 0;
}
@@ -1269,6 +1277,7 @@ int __ref add_memory(int nid, u64 start, u64 size)
/* create new memmap entry */
firmware_map_add_hotplug(start, start + size, "System RAM");
+ memblock_add_node(start, size, nid);
goto out;
@@ -2005,6 +2014,8 @@ void __ref remove_memory(int nid, u64 start, u64 size)
/* remove memmap entry */
firmware_map_remove(start, start + size, "System RAM");
+ memblock_free(start, size);
+ memblock_remove(start, size);
arch_remove_memory(start, size);
diff --git a/mm/migrate.c b/mm/migrate.c
index ee401e4..eb426710 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -880,7 +880,8 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
/* Establish migration ptes or remove ptes */
if (page_mapped(page)) {
try_to_unmap(page,
- TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
+ TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS|
+ TTU_IGNORE_HWPOISON);
page_was_mapped = 1;
}
@@ -950,7 +951,10 @@ out:
list_del(&page->lru);
dec_zone_page_state(page, NR_ISOLATED_ANON +
page_is_file_cache(page));
- if (reason != MR_MEMORY_FAILURE)
+ /* Soft-offlined page shouldn't go through lru cache list */
+ if (reason == MR_MEMORY_FAILURE)
+ put_page(page);
+ else
putback_lru_page(page);
}
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 22cddd3..5cccc12 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2063,10 +2063,10 @@ static struct notifier_block ratelimit_nb = {
*/
void __init page_writeback_init(void)
{
+ BUG_ON(wb_domain_init(&global_wb_domain, GFP_KERNEL));
+
writeback_set_ratelimit();
register_cpu_notifier(&ratelimit_nb);
-
- BUG_ON(wb_domain_init(&global_wb_domain, GFP_KERNEL));
}
/**
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index ef19f22..5b5240b 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -18,7 +18,6 @@
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/interrupt.h>
-#include <linux/rwsem.h>
#include <linux/pagemap.h>
#include <linux/jiffies.h>
#include <linux/bootmem.h>
@@ -981,21 +980,21 @@ static void __init __free_pages_boot_core(struct page *page,
#if defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) || \
defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP)
-/* Only safe to use early in boot when initialisation is single-threaded */
+
static struct mminit_pfnnid_cache early_pfnnid_cache __meminitdata;
int __meminit early_pfn_to_nid(unsigned long pfn)
{
+ static DEFINE_SPINLOCK(early_pfn_lock);
int nid;
- /* The system will behave unpredictably otherwise */
- BUG_ON(system_state != SYSTEM_BOOTING);
-
+ spin_lock(&early_pfn_lock);
nid = __early_pfn_to_nid(pfn, &early_pfnnid_cache);
- if (nid >= 0)
- return nid;
- /* just returns 0 */
- return 0;
+ if (nid < 0)
+ nid = 0;
+ spin_unlock(&early_pfn_lock);
+
+ return nid;
}
#endif
@@ -1060,7 +1059,15 @@ static void __init deferred_free_range(struct page *page,
__free_pages_boot_core(page, pfn, 0);
}
-static __initdata DECLARE_RWSEM(pgdat_init_rwsem);
+/* Completion tracking for deferred_init_memmap() threads */
+static atomic_t pgdat_init_n_undone __initdata;
+static __initdata DECLARE_COMPLETION(pgdat_init_all_done_comp);
+
+static inline void __init pgdat_init_report_one_done(void)
+{
+ if (atomic_dec_and_test(&pgdat_init_n_undone))
+ complete(&pgdat_init_all_done_comp);
+}
/* Initialise remaining memory on a node */
static int __init deferred_init_memmap(void *data)
@@ -1077,7 +1084,7 @@ static int __init deferred_init_memmap(void *data)
const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id);
if (first_init_pfn == ULONG_MAX) {
- up_read(&pgdat_init_rwsem);
+ pgdat_init_report_one_done();
return 0;
}
@@ -1177,7 +1184,8 @@ free_range:
pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages,
jiffies_to_msecs(jiffies - start));
- up_read(&pgdat_init_rwsem);
+
+ pgdat_init_report_one_done();
return 0;
}
@@ -1185,14 +1193,17 @@ void __init page_alloc_init_late(void)
{
int nid;
+ /* There will be num_node_state(N_MEMORY) threads */
+ atomic_set(&pgdat_init_n_undone, num_node_state(N_MEMORY));
for_each_node_state(nid, N_MEMORY) {
- down_read(&pgdat_init_rwsem);
kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid);
}
/* Block until all are initialised */
- down_write(&pgdat_init_rwsem);
- up_write(&pgdat_init_rwsem);
+ wait_for_completion(&pgdat_init_all_done_comp);
+
+ /* Reinit limits that are based on free pages after the kernel is up */
+ files_maxfiles_init();
}
#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
@@ -1285,6 +1296,10 @@ static inline int check_new_page(struct page *page)
bad_reason = "non-NULL mapping";
if (unlikely(atomic_read(&page->_count) != 0))
bad_reason = "nonzero _count";
+ if (unlikely(page->flags & __PG_HWPOISON)) {
+ bad_reason = "HWPoisoned (hardware-corrupted)";
+ bad_flags = __PG_HWPOISON;
+ }
if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_PREP)) {
bad_reason = "PAGE_FLAGS_CHECK_AT_PREP flag set";
bad_flags = PAGE_FLAGS_CHECK_AT_PREP;
@@ -1328,12 +1343,15 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
set_page_owner(page, order, gfp_flags);
/*
- * page->pfmemalloc is set when ALLOC_NO_WATERMARKS was necessary to
+ * page is set pfmemalloc when ALLOC_NO_WATERMARKS was necessary to
* allocate the page. The expectation is that the caller is taking
* steps that will free more memory. The caller should avoid the page
* being used for !PFMEMALLOC purposes.
*/
- page->pfmemalloc = !!(alloc_flags & ALLOC_NO_WATERMARKS);
+ if (alloc_flags & ALLOC_NO_WATERMARKS)
+ set_page_pfmemalloc(page);
+ else
+ clear_page_pfmemalloc(page);
return 0;
}
@@ -3330,7 +3348,7 @@ refill:
atomic_add(size - 1, &page->_count);
/* reset page count bias and offset to start of new frag */
- nc->pfmemalloc = page->pfmemalloc;
+ nc->pfmemalloc = page_is_pfmemalloc(page);
nc->pagecnt_bias = size;
nc->offset = size;
}
@@ -5045,6 +5063,10 @@ static unsigned long __meminit zone_spanned_pages_in_node(int nid,
{
unsigned long zone_start_pfn, zone_end_pfn;
+ /* When hotadd a new node, the node should be empty */
+ if (!node_start_pfn && !node_end_pfn)
+ return 0;
+
/* Get the start and end of the zone */
zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type];
zone_end_pfn = arch_zone_highest_possible_pfn[zone_type];
@@ -5108,6 +5130,10 @@ static unsigned long __meminit zone_absent_pages_in_node(int nid,
unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type];
unsigned long zone_start_pfn, zone_end_pfn;
+ /* When hotadd a new node, the node should be empty */
+ if (!node_start_pfn && !node_end_pfn)
+ return 0;
+
zone_start_pfn = clamp(node_start_pfn, zone_low, zone_high);
zone_end_pfn = clamp(node_end_pfn, zone_low, zone_high);
diff --git a/mm/shmem.c b/mm/shmem.c
index 4caf8ed..dbe0c1e 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3363,8 +3363,8 @@ put_path:
* shmem_kernel_file_setup - get an unlinked file living in tmpfs which must be
* kernel internal. There will be NO LSM permission checks against the
* underlying inode. So users of this interface must do LSM checks at a
- * higher layer. The one user is the big_key implementation. LSM checks
- * are provided at the key level rather than the inode level.
+ * higher layer. The users are the big_key and shm implementations. LSM
+ * checks are provided at the key or shm level rather than the inode.
* @name: name for dentry (to be seen in /proc/<pid>/maps
* @size: size to be set for the file
* @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
diff --git a/mm/slab.c b/mm/slab.c
index 200e224..bbd0b47 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1603,7 +1603,7 @@ static struct page *kmem_getpages(struct kmem_cache *cachep, gfp_t flags,
}
/* Record if ALLOC_NO_WATERMARKS was set when allocating the slab */
- if (unlikely(page->pfmemalloc))
+ if (page_is_pfmemalloc(page))
pfmemalloc_active = true;
nr_pages = (1 << cachep->gfporder);
@@ -1614,7 +1614,7 @@ static struct page *kmem_getpages(struct kmem_cache *cachep, gfp_t flags,
add_zone_page_state(page_zone(page),
NR_SLAB_UNRECLAIMABLE, nr_pages);
__SetPageSlab(page);
- if (page->pfmemalloc)
+ if (page_is_pfmemalloc(page))
SetPageSlabPfmemalloc(page);
if (kmemcheck_enabled && !(cachep->flags & SLAB_NOTRACK)) {
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 3e5f8f2..8683110 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -37,8 +37,7 @@ struct kmem_cache *kmem_cache;
SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE | \
SLAB_FAILSLAB)
-#define SLAB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \
- SLAB_CACHE_DMA | SLAB_NOTRACK)
+#define SLAB_MERGE_SAME (SLAB_RECLAIM_ACCOUNT | SLAB_CACHE_DMA | SLAB_NOTRACK)
/*
* Merge control. If this is set then no merging of slab caches will occur.
diff --git a/mm/slub.c b/mm/slub.c
index 816df00..f68c0e5 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1427,7 +1427,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
inc_slabs_node(s, page_to_nid(page), page->objects);
page->slab_cache = s;
__SetPageSlab(page);
- if (page->pfmemalloc)
+ if (page_is_pfmemalloc(page))
SetPageSlabPfmemalloc(page);
start = page_address(page);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index e61445d..8286938 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -973,22 +973,18 @@ static unsigned long shrink_page_list(struct list_head *page_list,
* caller can stall after page list has been processed.
*
* 2) Global or new memcg reclaim encounters a page that is
- * not marked for immediate reclaim or the caller does not
- * have __GFP_IO. In this case mark the page for immediate
+ * not marked for immediate reclaim, or the caller does not
+ * have __GFP_FS (or __GFP_IO if it's simply going to swap,
+ * not to fs). In this case mark the page for immediate
* reclaim and continue scanning.
*
- * __GFP_IO is checked because a loop driver thread might
+ * Require may_enter_fs because we would wait on fs, which
+ * may not have submitted IO yet. And the loop driver might
* enter reclaim, and deadlock if it waits on a page for
* which it is needed to do the write (loop masks off
* __GFP_IO|__GFP_FS for this reason); but more thought
* would probably show more reasons.
*
- * Don't require __GFP_FS, since we're not going into the
- * FS, just waiting on its writeback completion. Worryingly,
- * ext4 gfs2 and xfs allocate pages with
- * grab_cache_page_write_begin(,,AOP_FLAG_NOFS), so testing
- * may_enter_fs here is liable to OOM on them.
- *
* 3) Legacy memcg encounters a page that is not already marked
* PageReclaim. memcg does not have any dirty pages
* throttling so we could easily OOM just because too many
@@ -1005,7 +1001,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
/* Case 2 above */
} else if (sane_reclaim(sc) ||
- !PageReclaim(page) || !(sc->gfp_mask & __GFP_IO)) {
+ !PageReclaim(page) || !may_enter_fs) {
/*
* This is slightly racy - end_page_writeback()
* might have just cleared PageReclaim, then
diff --git a/net/9p/client.c b/net/9p/client.c
index 498454b..ea79ee9 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -1541,6 +1541,7 @@ p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
struct p9_client *clnt = fid->clnt;
struct p9_req_t *req;
int total = 0;
+ *err = 0;
p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n",
fid->fid, (unsigned long long) offset, (int)iov_iter_count(to));
@@ -1620,6 +1621,7 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
struct p9_client *clnt = fid->clnt;
struct p9_req_t *req;
int total = 0;
+ *err = 0;
p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %zd\n",
fid->fid, (unsigned long long) offset,
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index fb54e6a..6d0b471 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -1138,6 +1138,9 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
* @bat_priv: the bat priv with all the soft interface information
* @skb: packet to check
* @hdr_size: size of the encapsulation header
+ *
+ * Returns true if the packet was snooped and consumed by DAT. False if the
+ * packet has to be delivered to the interface
*/
bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
struct sk_buff *skb, int hdr_size)
@@ -1145,7 +1148,7 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
uint16_t type;
__be32 ip_src, ip_dst;
uint8_t *hw_src, *hw_dst;
- bool ret = false;
+ bool dropped = false;
unsigned short vid;
if (!atomic_read(&bat_priv->distributed_arp_table))
@@ -1174,12 +1177,17 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
/* if this REPLY is directed to a client of mine, let's deliver the
* packet to the interface
*/
- ret = !batadv_is_my_client(bat_priv, hw_dst, vid);
+ dropped = !batadv_is_my_client(bat_priv, hw_dst, vid);
+
+ /* if this REPLY is sent on behalf of a client of mine, let's drop the
+ * packet because the client will reply by itself
+ */
+ dropped |= batadv_is_my_client(bat_priv, hw_src, vid);
out:
- if (ret)
+ if (dropped)
kfree_skb(skb);
- /* if ret == false -> packet has to be delivered to the interface */
- return ret;
+ /* if dropped == false -> deliver to the interface */
+ return dropped;
}
/**
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index bb015862..cffa92d 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -439,6 +439,8 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv,
INIT_HLIST_NODE(&gw_node->list);
gw_node->orig_node = orig_node;
+ gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
+ gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
atomic_set(&gw_node->refcount, 1);
spin_lock_bh(&bat_priv->gw.list_lock);
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index c002961..a2fc843 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -479,6 +479,9 @@ out:
*/
void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan)
{
+ if (!vlan)
+ return;
+
if (atomic_dec_and_test(&vlan->refcount)) {
spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock);
hlist_del_rcu(&vlan->list);
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index b482495..5809b39 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -594,6 +594,12 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
/* increase the refcounter of the related vlan */
vlan = batadv_softif_vlan_get(bat_priv, vid);
+ if (WARN(!vlan, "adding TT local entry %pM to non-existent VLAN %d",
+ addr, BATADV_PRINT_VID(vid))) {
+ kfree(tt_local);
+ tt_local = NULL;
+ goto out;
+ }
batadv_dbg(BATADV_DBG_TT, bat_priv,
"Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
@@ -1034,6 +1040,7 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
struct batadv_tt_local_entry *tt_local_entry;
uint16_t flags, curr_flags = BATADV_NO_FLAGS;
struct batadv_softif_vlan *vlan;
+ void *tt_entry_exists;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
@@ -1061,11 +1068,22 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
* immediately purge it
*/
batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
- hlist_del_rcu(&tt_local_entry->common.hash_entry);
+
+ tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash,
+ batadv_compare_tt,
+ batadv_choose_tt,
+ &tt_local_entry->common);
+ if (!tt_entry_exists)
+ goto out;
+
+ /* extra call to free the local tt entry */
batadv_tt_local_entry_free_ref(tt_local_entry);
/* decrease the reference held for this vlan */
vlan = batadv_softif_vlan_get(bat_priv, vid);
+ if (!vlan)
+ goto out;
+
batadv_softif_vlan_free_ref(vlan);
batadv_softif_vlan_free_ref(vlan);
@@ -1166,8 +1184,10 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
/* decrease the reference held for this vlan */
vlan = batadv_softif_vlan_get(bat_priv,
tt_common_entry->vid);
- batadv_softif_vlan_free_ref(vlan);
- batadv_softif_vlan_free_ref(vlan);
+ if (vlan) {
+ batadv_softif_vlan_free_ref(vlan);
+ batadv_softif_vlan_free_ref(vlan);
+ }
batadv_tt_local_entry_free_ref(tt_local);
}
@@ -3207,8 +3227,10 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
/* decrease the reference held for this vlan */
vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid);
- batadv_softif_vlan_free_ref(vlan);
- batadv_softif_vlan_free_ref(vlan);
+ if (vlan) {
+ batadv_softif_vlan_free_ref(vlan);
+ batadv_softif_vlan_free_ref(vlan);
+ }
batadv_tt_local_entry_free_ref(tt_local);
}
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 7998fb2..92720f3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7820,7 +7820,7 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
/* Make sure we copy only the significant bytes based on the
* encryption key size, and set the rest of the value to zeroes.
*/
- memcpy(ev.key.val, key->val, sizeof(key->enc_size));
+ memcpy(ev.key.val, key->val, key->enc_size);
memset(ev.key.val + key->enc_size, 0,
sizeof(ev.key.val) - key->enc_size);
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 0b39dcc..1285eaf 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1591,7 +1591,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
break;
}
- if (skb_trimmed)
+ if (skb_trimmed && skb_trimmed != skb)
kfree_skb(skb_trimmed);
return err;
@@ -1636,7 +1636,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
break;
}
- if (skb_trimmed)
+ if (skb_trimmed && skb_trimmed != skb)
kfree_skb(skb_trimmed);
return err;
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 3da5525..4d74a06 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -112,6 +112,8 @@ static inline size_t br_port_info_size(void)
+ nla_total_size(1) /* IFLA_BRPORT_FAST_LEAVE */
+ nla_total_size(1) /* IFLA_BRPORT_LEARNING */
+ nla_total_size(1) /* IFLA_BRPORT_UNICAST_FLOOD */
+ + nla_total_size(1) /* IFLA_BRPORT_PROXYARP */
+ + nla_total_size(1) /* IFLA_BRPORT_PROXYARP_WIFI */
+ 0;
}
@@ -506,6 +508,8 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = {
[IFLA_BRPORT_FAST_LEAVE]= { .type = NLA_U8 },
[IFLA_BRPORT_LEARNING] = { .type = NLA_U8 },
[IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
+ [IFLA_BRPORT_PROXYARP] = { .type = NLA_U8 },
+ [IFLA_BRPORT_PROXYARP_WIFI] = { .type = NLA_U8 },
};
/* Change the state of the port and notify spanning tree */
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 4967262..617088a 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -131,12 +131,12 @@ out_noerr:
goto out;
}
-static int skb_set_peeked(struct sk_buff *skb)
+static struct sk_buff *skb_set_peeked(struct sk_buff *skb)
{
struct sk_buff *nskb;
if (skb->peeked)
- return 0;
+ return skb;
/* We have to unshare an skb before modifying it. */
if (!skb_shared(skb))
@@ -144,7 +144,7 @@ static int skb_set_peeked(struct sk_buff *skb)
nskb = skb_clone(skb, GFP_ATOMIC);
if (!nskb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
skb->prev->next = nskb;
skb->next->prev = nskb;
@@ -157,7 +157,7 @@ static int skb_set_peeked(struct sk_buff *skb)
done:
skb->peeked = 1;
- return 0;
+ return skb;
}
/**
@@ -229,8 +229,9 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
continue;
}
- error = skb_set_peeked(skb);
- if (error)
+ skb = skb_set_peeked(skb);
+ error = PTR_ERR(skb);
+ if (IS_ERR(skb))
goto unlock_err;
atomic_inc(&skb->users);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 1ebdf1c..1cbd209 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -3514,8 +3514,6 @@ static int pktgen_thread_worker(void *arg)
set_freezable();
- __set_current_state(TASK_RUNNING);
-
while (!kthread_should_stop()) {
pkt_dev = next_to_run(t);
@@ -3560,7 +3558,6 @@ static int pktgen_thread_worker(void *arg)
try_to_freeze();
}
- set_current_state(TASK_INTERRUPTIBLE);
pr_debug("%s stopping all device\n", t->tsk->comm);
pktgen_stop(t);
diff --git a/net/core/request_sock.c b/net/core/request_sock.c
index 87b22c0..b42f0e2 100644
--- a/net/core/request_sock.c
+++ b/net/core/request_sock.c
@@ -103,10 +103,16 @@ void reqsk_queue_destroy(struct request_sock_queue *queue)
spin_lock_bh(&queue->syn_wait_lock);
while ((req = lopt->syn_table[i]) != NULL) {
lopt->syn_table[i] = req->dl_next;
+ /* Because of following del_timer_sync(),
+ * we must release the spinlock here
+ * or risk a dead lock.
+ */
+ spin_unlock_bh(&queue->syn_wait_lock);
atomic_inc(&lopt->qlen_dec);
- if (del_timer(&req->rsk_timer))
+ if (del_timer_sync(&req->rsk_timer))
reqsk_put(req);
reqsk_put(req);
+ spin_lock_bh(&queue->syn_wait_lock);
}
spin_unlock_bh(&queue->syn_wait_lock);
}
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index b6a19ca..7b84330 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -340,7 +340,7 @@ struct sk_buff *build_skb(void *data, unsigned int frag_size)
if (skb && frag_size) {
skb->head_frag = 1;
- if (virt_to_head_page(data)->pfmemalloc)
+ if (page_is_pfmemalloc(virt_to_head_page(data)))
skb->pfmemalloc = 1;
}
return skb;
@@ -4022,8 +4022,8 @@ EXPORT_SYMBOL(skb_checksum_setup);
* Otherwise returns the provided skb. Returns NULL in error cases
* (e.g. transport_len exceeds skb length or out-of-memory).
*
- * Caller needs to set the skb transport header and release the returned skb.
- * Provided skb is consumed.
+ * Caller needs to set the skb transport header and free any returned skb if it
+ * differs from the provided skb.
*/
static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb,
unsigned int transport_len)
@@ -4032,16 +4032,12 @@ static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb,
unsigned int len = skb_transport_offset(skb) + transport_len;
int ret;
- if (skb->len < len) {
- kfree_skb(skb);
+ if (skb->len < len)
return NULL;
- } else if (skb->len == len) {
+ else if (skb->len == len)
return skb;
- }
skb_chk = skb_clone(skb, GFP_ATOMIC);
- kfree_skb(skb);
-
if (!skb_chk)
return NULL;
@@ -4066,8 +4062,8 @@ static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb,
* If the skb has data beyond the given transport length, then a
* trimmed & cloned skb is checked and returned.
*
- * Caller needs to set the skb transport header and release the returned skb.
- * Provided skb is consumed.
+ * Caller needs to set the skb transport header and free any returned skb if it
+ * differs from the provided skb.
*/
struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
unsigned int transport_len,
@@ -4079,23 +4075,26 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
skb_chk = skb_checksum_maybe_trim(skb, transport_len);
if (!skb_chk)
- return NULL;
+ goto err;
- if (!pskb_may_pull(skb_chk, offset)) {
- kfree_skb(skb_chk);
- return NULL;
- }
+ if (!pskb_may_pull(skb_chk, offset))
+ goto err;
__skb_pull(skb_chk, offset);
ret = skb_chkf(skb_chk);
__skb_push(skb_chk, offset);
- if (ret) {
- kfree_skb(skb_chk);
- return NULL;
- }
+ if (ret)
+ goto err;
return skb_chk;
+
+err:
+ if (skb_chk && skb_chk != skb)
+ kfree_skb(skb_chk);
+
+ return NULL;
+
}
EXPORT_SYMBOL(skb_checksum_trimmed);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 0917123..35c47dd 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -756,7 +756,8 @@ static int dsa_slave_phy_connect(struct dsa_slave_priv *p,
return -ENODEV;
/* Use already configured phy mode */
- p->phy_interface = p->phy->interface;
+ if (p->phy_interface == PHY_INTERFACE_MODE_NA)
+ p->phy_interface = p->phy->interface;
phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link,
p->phy_interface);
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 37c4bb8..b0c6258 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2465,7 +2465,7 @@ static struct key_vector *fib_route_get_idx(struct fib_route_iter *iter,
key = l->key + 1;
iter->pos++;
- if (pos-- <= 0)
+ if (--pos <= 0)
break;
l = NULL;
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 651cdf6..9fdfd9d 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1435,33 +1435,35 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
struct sk_buff *skb_chk;
unsigned int transport_len;
unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr);
- int ret;
+ int ret = -EINVAL;
transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb);
- skb_get(skb);
skb_chk = skb_checksum_trimmed(skb, transport_len,
ip_mc_validate_checksum);
if (!skb_chk)
- return -EINVAL;
+ goto err;
- if (!pskb_may_pull(skb_chk, len)) {
- kfree_skb(skb_chk);
- return -EINVAL;
- }
+ if (!pskb_may_pull(skb_chk, len))
+ goto err;
ret = ip_mc_check_igmp_msg(skb_chk);
- if (ret) {
- kfree_skb(skb_chk);
- return ret;
- }
+ if (ret)
+ goto err;
if (skb_trimmed)
*skb_trimmed = skb_chk;
- else
+ /* free now unneeded clone */
+ else if (skb_chk != skb)
kfree_skb(skb_chk);
- return 0;
+ ret = 0;
+
+err:
+ if (ret && skb_chk && skb_chk != skb)
+ kfree_skb(skb_chk);
+
+ return ret;
}
/**
@@ -1470,7 +1472,7 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
* @skb_trimmed: to store an skb pointer trimmed to IPv4 packet tail (optional)
*
* Checks whether an IPv4 packet is a valid IGMP packet. If so sets
- * skb network and transport headers accordingly and returns zero.
+ * skb transport header accordingly and returns zero.
*
* -EINVAL: A broken packet was detected, i.e. it violates some internet
* standard
@@ -1485,7 +1487,8 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
* to leave the original skb and its full frame unchanged (which might be
* desirable for layer 2 frame jugglers).
*
- * The caller needs to release a reference count from any returned skb_trimmed.
+ * Caller needs to set the skb network header and free any returned skb if it
+ * differs from the provided skb.
*/
int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
{
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 60021d0..1349571 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -593,7 +593,7 @@ static bool reqsk_queue_unlink(struct request_sock_queue *queue,
}
spin_unlock(&queue->syn_wait_lock);
- if (del_timer(&req->rsk_timer))
+ if (timer_pending(&req->rsk_timer) && del_timer_sync(&req->rsk_timer))
reqsk_put(req);
return found;
}
diff --git a/net/ipv4/netfilter/ipt_SYNPROXY.c b/net/ipv4/netfilter/ipt_SYNPROXY.c
index fe8cc18..95ea633e 100644
--- a/net/ipv4/netfilter/ipt_SYNPROXY.c
+++ b/net/ipv4/netfilter/ipt_SYNPROXY.c
@@ -226,7 +226,8 @@ synproxy_send_client_ack(const struct synproxy_net *snet,
synproxy_build_options(nth, opts);
- synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
+ synproxy_send_tcp(skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
+ niph, nth, tcp_hdr_size);
}
static bool
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 433231c..0330ab2 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -41,8 +41,6 @@ static int tcp_syn_retries_min = 1;
static int tcp_syn_retries_max = MAX_TCP_SYNCNT;
static int ip_ping_group_range_min[] = { 0, 0 };
static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
-static int min_sndbuf = SOCK_MIN_SNDBUF;
-static int min_rcvbuf = SOCK_MIN_RCVBUF;
/* Update system visible IP port range */
static void set_local_port_range(struct net *net, int range[2])
@@ -530,7 +528,7 @@ static struct ctl_table ipv4_table[] = {
.maxlen = sizeof(sysctl_tcp_wmem),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .extra1 = &min_sndbuf,
+ .extra1 = &one,
},
{
.procname = "tcp_notsent_lowat",
@@ -545,7 +543,7 @@ static struct ctl_table ipv4_table[] = {
.maxlen = sizeof(sysctl_tcp_rmem),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .extra1 = &min_rcvbuf,
+ .extra1 = &one,
},
{
.procname = "tcp_app_win",
@@ -758,7 +756,7 @@ static struct ctl_table ipv4_table[] = {
.maxlen = sizeof(sysctl_udp_rmem_min),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .extra1 = &min_rcvbuf,
+ .extra1 = &one
},
{
.procname = "udp_wmem_min",
@@ -766,7 +764,7 @@ static struct ctl_table ipv4_table[] = {
.maxlen = sizeof(sysctl_udp_wmem_min),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .extra1 = &min_sndbuf,
+ .extra1 = &one
},
{ }
};
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index d7d4c2b..0ea2e1c 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1348,7 +1348,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
req = inet_csk_search_req(sk, th->source, iph->saddr, iph->daddr);
if (req) {
nsk = tcp_check_req(sk, skb, req, false);
- if (!nsk)
+ if (!nsk || nsk == sk)
reqsk_put(req);
return nsk;
}
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 83aa604..1b8c5ba 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1995,12 +1995,19 @@ void udp_v4_early_demux(struct sk_buff *skb)
skb->sk = sk;
skb->destructor = sock_efree;
- dst = sk->sk_rx_dst;
+ dst = READ_ONCE(sk->sk_rx_dst);
if (dst)
dst = dst_check(dst, 0);
- if (dst)
- skb_dst_set_noref(skb, dst);
+ if (dst) {
+ /* DST_NOCACHE can not be used without taking a reference */
+ if (dst->flags & DST_NOCACHE) {
+ if (likely(atomic_inc_not_zero(&dst->__refcnt)))
+ skb_dst_set(skb, dst);
+ } else {
+ skb_dst_set_noref(skb, dst);
+ }
+ }
}
int udp_rcv(struct sk_buff *skb)
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 55d1986..548c623 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -172,6 +172,8 @@ static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt)
*ppcpu_rt = NULL;
}
}
+
+ non_pcpu_rt->rt6i_pcpu = NULL;
}
static void rt6_release(struct rt6_info *rt)
diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c
index df8afe5..9405b04 100644
--- a/net/ipv6/mcast_snoop.c
+++ b/net/ipv6/mcast_snoop.c
@@ -143,34 +143,36 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb,
struct sk_buff *skb_chk = NULL;
unsigned int transport_len;
unsigned int len = skb_transport_offset(skb) + sizeof(struct mld_msg);
- int ret;
+ int ret = -EINVAL;
transport_len = ntohs(ipv6_hdr(skb)->payload_len);
transport_len -= skb_transport_offset(skb) - sizeof(struct ipv6hdr);
- skb_get(skb);
skb_chk = skb_checksum_trimmed(skb, transport_len,
ipv6_mc_validate_checksum);
if (!skb_chk)
- return -EINVAL;
+ goto err;
- if (!pskb_may_pull(skb_chk, len)) {
- kfree_skb(skb_chk);
- return -EINVAL;
- }
+ if (!pskb_may_pull(skb_chk, len))
+ goto err;
ret = ipv6_mc_check_mld_msg(skb_chk);
- if (ret) {
- kfree_skb(skb_chk);
- return ret;
- }
+ if (ret)
+ goto err;
if (skb_trimmed)
*skb_trimmed = skb_chk;
- else
+ /* free now unneeded clone */
+ else if (skb_chk != skb)
kfree_skb(skb_chk);
- return 0;
+ ret = 0;
+
+err:
+ if (ret && skb_chk && skb_chk != skb)
+ kfree_skb(skb_chk);
+
+ return ret;
}
/**
@@ -179,7 +181,7 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb,
* @skb_trimmed: to store an skb pointer trimmed to IPv6 packet tail (optional)
*
* Checks whether an IPv6 packet is a valid MLD packet. If so sets
- * skb network and transport headers accordingly and returns zero.
+ * skb transport header accordingly and returns zero.
*
* -EINVAL: A broken packet was detected, i.e. it violates some internet
* standard
@@ -194,7 +196,8 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb,
* to leave the original skb and its full frame unchanged (which might be
* desirable for layer 2 frame jugglers).
*
- * The caller needs to release a reference count from any returned skb_trimmed.
+ * Caller needs to set the skb network header and free any returned skb if it
+ * differs from the provided skb.
*/
int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed)
{
diff --git a/net/ipv6/netfilter/ip6t_SYNPROXY.c b/net/ipv6/netfilter/ip6t_SYNPROXY.c
index 6edb7b1..ebbb754 100644
--- a/net/ipv6/netfilter/ip6t_SYNPROXY.c
+++ b/net/ipv6/netfilter/ip6t_SYNPROXY.c
@@ -37,12 +37,13 @@ synproxy_build_ip(struct sk_buff *skb, const struct in6_addr *saddr,
}
static void
-synproxy_send_tcp(const struct sk_buff *skb, struct sk_buff *nskb,
+synproxy_send_tcp(const struct synproxy_net *snet,
+ const struct sk_buff *skb, struct sk_buff *nskb,
struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
struct ipv6hdr *niph, struct tcphdr *nth,
unsigned int tcp_hdr_size)
{
- struct net *net = nf_ct_net((struct nf_conn *)nfct);
+ struct net *net = nf_ct_net(snet->tmpl);
struct dst_entry *dst;
struct flowi6 fl6;
@@ -83,7 +84,8 @@ free_nskb:
}
static void
-synproxy_send_client_synack(const struct sk_buff *skb, const struct tcphdr *th,
+synproxy_send_client_synack(const struct synproxy_net *snet,
+ const struct sk_buff *skb, const struct tcphdr *th,
const struct synproxy_options *opts)
{
struct sk_buff *nskb;
@@ -119,7 +121,7 @@ synproxy_send_client_synack(const struct sk_buff *skb, const struct tcphdr *th,
synproxy_build_options(nth, opts);
- synproxy_send_tcp(skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
+ synproxy_send_tcp(snet, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
niph, nth, tcp_hdr_size);
}
@@ -163,7 +165,7 @@ synproxy_send_server_syn(const struct synproxy_net *snet,
synproxy_build_options(nth, opts);
- synproxy_send_tcp(skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
+ synproxy_send_tcp(snet, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
niph, nth, tcp_hdr_size);
}
@@ -203,7 +205,7 @@ synproxy_send_server_ack(const struct synproxy_net *snet,
synproxy_build_options(nth, opts);
- synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
+ synproxy_send_tcp(snet, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
}
static void
@@ -241,7 +243,8 @@ synproxy_send_client_ack(const struct synproxy_net *snet,
synproxy_build_options(nth, opts);
- synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
+ synproxy_send_tcp(snet, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
+ niph, nth, tcp_hdr_size);
}
static bool
@@ -301,7 +304,7 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
XT_SYNPROXY_OPT_SACK_PERM |
XT_SYNPROXY_OPT_ECN);
- synproxy_send_client_synack(skb, th, &opts);
+ synproxy_send_client_synack(snet, skb, th, &opts);
return NF_DROP;
} else if (th->ack && !(th->fin || th->rst || th->syn)) {
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 6090969..d155864 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -318,8 +318,7 @@ static const struct rt6_info ip6_blk_hole_entry_template = {
/* allocate dst with ip6_dst_ops */
static struct rt6_info *__ip6_dst_alloc(struct net *net,
struct net_device *dev,
- int flags,
- struct fib6_table *table)
+ int flags)
{
struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
0, DST_OBSOLETE_FORCE_CHK, flags);
@@ -336,10 +335,9 @@ static struct rt6_info *__ip6_dst_alloc(struct net *net,
static struct rt6_info *ip6_dst_alloc(struct net *net,
struct net_device *dev,
- int flags,
- struct fib6_table *table)
+ int flags)
{
- struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags, table);
+ struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
if (rt) {
rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
@@ -950,8 +948,7 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
ort = (struct rt6_info *)ort->dst.from;
- rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev,
- 0, ort->rt6i_table);
+ rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0);
if (!rt)
return NULL;
@@ -983,8 +980,7 @@ static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
struct rt6_info *pcpu_rt;
pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev),
- rt->dst.dev, rt->dst.flags,
- rt->rt6i_table);
+ rt->dst.dev, rt->dst.flags);
if (!pcpu_rt)
return NULL;
@@ -997,32 +993,53 @@ static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
/* It should be called with read_lock_bh(&tb6_lock) acquired */
static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
{
- struct rt6_info *pcpu_rt, *prev, **p;
+ struct rt6_info *pcpu_rt, **p;
p = this_cpu_ptr(rt->rt6i_pcpu);
pcpu_rt = *p;
- if (pcpu_rt)
- goto done;
+ if (pcpu_rt) {
+ dst_hold(&pcpu_rt->dst);
+ rt6_dst_from_metrics_check(pcpu_rt);
+ }
+ return pcpu_rt;
+}
+
+static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
+{
+ struct fib6_table *table = rt->rt6i_table;
+ struct rt6_info *pcpu_rt, *prev, **p;
pcpu_rt = ip6_rt_pcpu_alloc(rt);
if (!pcpu_rt) {
struct net *net = dev_net(rt->dst.dev);
- pcpu_rt = net->ipv6.ip6_null_entry;
- goto done;
+ dst_hold(&net->ipv6.ip6_null_entry->dst);
+ return net->ipv6.ip6_null_entry;
}
- prev = cmpxchg(p, NULL, pcpu_rt);
- if (prev) {
- /* If someone did it before us, return prev instead */
+ read_lock_bh(&table->tb6_lock);
+ if (rt->rt6i_pcpu) {
+ p = this_cpu_ptr(rt->rt6i_pcpu);
+ prev = cmpxchg(p, NULL, pcpu_rt);
+ if (prev) {
+ /* If someone did it before us, return prev instead */
+ dst_destroy(&pcpu_rt->dst);
+ pcpu_rt = prev;
+ }
+ } else {
+ /* rt has been removed from the fib6 tree
+ * before we have a chance to acquire the read_lock.
+ * In this case, don't brother to create a pcpu rt
+ * since rt is going away anyway. The next
+ * dst_check() will trigger a re-lookup.
+ */
dst_destroy(&pcpu_rt->dst);
- pcpu_rt = prev;
+ pcpu_rt = rt;
}
-
-done:
dst_hold(&pcpu_rt->dst);
rt6_dst_from_metrics_check(pcpu_rt);
+ read_unlock_bh(&table->tb6_lock);
return pcpu_rt;
}
@@ -1097,9 +1114,22 @@ redo_rt6_select:
rt->dst.lastuse = jiffies;
rt->dst.__use++;
pcpu_rt = rt6_get_pcpu_route(rt);
- read_unlock_bh(&table->tb6_lock);
+
+ if (pcpu_rt) {
+ read_unlock_bh(&table->tb6_lock);
+ } else {
+ /* We have to do the read_unlock first
+ * because rt6_make_pcpu_route() may trigger
+ * ip6_dst_gc() which will take the write_lock.
+ */
+ dst_hold(&rt->dst);
+ read_unlock_bh(&table->tb6_lock);
+ pcpu_rt = rt6_make_pcpu_route(rt);
+ dst_release(&rt->dst);
+ }
return pcpu_rt;
+
}
}
@@ -1555,7 +1585,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
if (unlikely(!idev))
return ERR_PTR(-ENODEV);
- rt = ip6_dst_alloc(net, dev, 0, NULL);
+ rt = ip6_dst_alloc(net, dev, 0);
if (unlikely(!rt)) {
in6_dev_put(idev);
dst = ERR_PTR(-ENOMEM);
@@ -1742,7 +1772,8 @@ int ip6_route_add(struct fib6_config *cfg)
if (!table)
goto out;
- rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table);
+ rt = ip6_dst_alloc(net, NULL,
+ (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
if (!rt) {
err = -ENOMEM;
@@ -1831,6 +1862,7 @@ int ip6_route_add(struct fib6_config *cfg)
int gwa_type;
gw_addr = &cfg->fc_gateway;
+ gwa_type = ipv6_addr_type(gw_addr);
/* if gw_addr is local we will fail to detect this in case
* address is still TENTATIVE (DAD in progress). rt6_lookup()
@@ -1838,11 +1870,12 @@ int ip6_route_add(struct fib6_config *cfg)
* prefix route was assigned to, which might be non-loopback.
*/
err = -EINVAL;
- if (ipv6_chk_addr_and_flags(net, gw_addr, NULL, 0, 0))
+ if (ipv6_chk_addr_and_flags(net, gw_addr,
+ gwa_type & IPV6_ADDR_LINKLOCAL ?
+ dev : NULL, 0, 0))
goto out;
rt->rt6i_gateway = *gw_addr;
- gwa_type = ipv6_addr_type(gw_addr);
if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
struct rt6_info *grt;
@@ -2397,7 +2430,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
{
struct net *net = dev_net(idev->dev);
struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
- DST_NOCOUNT, NULL);
+ DST_NOCOUNT);
if (!rt)
return ERR_PTR(-ENOMEM);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 6748c42..7a6cea5 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -943,7 +943,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb)
&ipv6_hdr(skb)->daddr, tcp_v6_iif(skb));
if (req) {
nsk = tcp_check_req(sk, skb, req, false);
- if (!nsk)
+ if (!nsk || nsk == sk)
reqsk_put(req);
return nsk;
}
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 247552a..3ece7d1 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -92,14 +92,15 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma)
static inline void
minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
{
- int j = MAX_THR_RATES;
- struct minstrel_rate_stats *tmp_mrs = &mi->r[j - 1].stats;
+ int j;
+ struct minstrel_rate_stats *tmp_mrs;
struct minstrel_rate_stats *cur_mrs = &mi->r[i].stats;
- while (j > 0 && (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) >
- minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))) {
- j--;
+ for (j = MAX_THR_RATES; j > 0; --j) {
tmp_mrs = &mi->r[tp_list[j - 1]].stats;
+ if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) <=
+ minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))
+ break;
}
if (j < MAX_THR_RATES - 1)
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 651039a..3c20d02 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -292,7 +292,7 @@ struct nf_conn *nf_ct_tmpl_alloc(struct net *net, u16 zone, gfp_t flags)
{
struct nf_conn *tmpl;
- tmpl = kzalloc(sizeof(struct nf_conn), GFP_KERNEL);
+ tmpl = kzalloc(sizeof(*tmpl), flags);
if (tmpl == NULL)
return NULL;
@@ -303,7 +303,7 @@ struct nf_conn *nf_ct_tmpl_alloc(struct net *net, u16 zone, gfp_t flags)
if (zone) {
struct nf_conntrack_zone *nf_ct_zone;
- nf_ct_zone = nf_ct_ext_add(tmpl, NF_CT_EXT_ZONE, GFP_ATOMIC);
+ nf_ct_zone = nf_ct_ext_add(tmpl, NF_CT_EXT_ZONE, flags);
if (!nf_ct_zone)
goto out_free;
nf_ct_zone->id = zone;
@@ -1544,10 +1544,8 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls)
sz = nr_slots * sizeof(struct hlist_nulls_head);
hash = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
get_order(sz));
- if (!hash) {
- printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n");
+ if (!hash)
hash = vzalloc(sz);
- }
if (hash && nulls)
for (i = 0; i < nr_slots; i++)
diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c
index 71f1e9f..d7f1685 100644
--- a/net/netfilter/nf_synproxy_core.c
+++ b/net/netfilter/nf_synproxy_core.c
@@ -353,10 +353,8 @@ static int __net_init synproxy_net_init(struct net *net)
int err = -ENOMEM;
ct = nf_ct_tmpl_alloc(net, 0, GFP_KERNEL);
- if (IS_ERR(ct)) {
- err = PTR_ERR(ct);
+ if (!ct)
goto err1;
- }
if (!nfct_seqadj_ext_add(ct))
goto err2;
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index c663003..43ddeee 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -202,9 +202,10 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par,
goto err1;
ct = nf_ct_tmpl_alloc(par->net, info->zone, GFP_KERNEL);
- ret = PTR_ERR(ct);
- if (IS_ERR(ct))
+ if (!ct) {
+ ret = -ENOMEM;
goto err2;
+ }
ret = 0;
if ((info->ct_events || info->exp_events) &&
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index d8e2e39..67d2104 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1096,6 +1096,11 @@ static int netlink_insert(struct sock *sk, u32 portid)
err = __netlink_insert(table, sk);
if (err) {
+ /* In case the hashtable backend returns with -EBUSY
+ * from here, it must not escape to the caller.
+ */
+ if (unlikely(err == -EBUSY))
+ err = -EOVERFLOW;
if (err == -EEXIST)
err = -EADDRINUSE;
nlk_sk(sk)->portid = 0;
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 8a8c0b8..ee34f47 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -273,28 +273,36 @@ static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key,
return 0;
}
-static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
- __be32 *addr, __be32 new_addr)
+static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh,
+ __be32 addr, __be32 new_addr)
{
int transport_len = skb->len - skb_transport_offset(skb);
+ if (nh->frag_off & htons(IP_OFFSET))
+ return;
+
if (nh->protocol == IPPROTO_TCP) {
if (likely(transport_len >= sizeof(struct tcphdr)))
inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb,
- *addr, new_addr, 1);
+ addr, new_addr, 1);
} else if (nh->protocol == IPPROTO_UDP) {
if (likely(transport_len >= sizeof(struct udphdr))) {
struct udphdr *uh = udp_hdr(skb);
if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
inet_proto_csum_replace4(&uh->check, skb,
- *addr, new_addr, 1);
+ addr, new_addr, 1);
if (!uh->check)
uh->check = CSUM_MANGLED_0;
}
}
}
+}
+static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
+ __be32 *addr, __be32 new_addr)
+{
+ update_ip_l4_checksum(skb, nh, *addr, new_addr);
csum_replace4(&nh->check, *addr, new_addr);
skb_clear_hash(skb);
*addr = new_addr;
diff --git a/net/rds/info.c b/net/rds/info.c
index 9a6b4f6..140a44a5f 100644
--- a/net/rds/info.c
+++ b/net/rds/info.c
@@ -176,7 +176,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
/* check for all kinds of wrapping and the like */
start = (unsigned long)optval;
- if (len < 0 || len + PAGE_SIZE - 1 < len || start + len < start) {
+ if (len < 0 || len > INT_MAX - PAGE_SIZE + 1 || start + len < start) {
ret = -EINVAL;
goto out;
}
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index a42a3b2..2685450 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -98,6 +98,8 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
return ret;
ret = ACT_P_CREATED;
} else {
+ if (bind)
+ return 0;
if (!ovr) {
tcf_hash_release(a, bind);
return -EEXIST;
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
index 21ca33c..a9ba030 100644
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -288,10 +288,26 @@ begin:
static void fq_codel_reset(struct Qdisc *sch)
{
- struct sk_buff *skb;
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ int i;
- while ((skb = fq_codel_dequeue(sch)) != NULL)
- kfree_skb(skb);
+ INIT_LIST_HEAD(&q->new_flows);
+ INIT_LIST_HEAD(&q->old_flows);
+ for (i = 0; i < q->flows_cnt; i++) {
+ struct fq_codel_flow *flow = q->flows + i;
+
+ while (flow->head) {
+ struct sk_buff *skb = dequeue_head(flow);
+
+ qdisc_qstats_backlog_dec(sch, skb);
+ kfree_skb(skb);
+ }
+
+ INIT_LIST_HEAD(&flow->flowchain);
+ codel_vars_init(&flow->cvars);
+ }
+ memset(q->backlogs, 0, q->flows_cnt * sizeof(u32));
+ sch->q.qlen = 0;
}
static const struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = {
diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl
index 9cb8522..f3d3fb4 100755
--- a/scripts/kconfig/streamline_config.pl
+++ b/scripts/kconfig/streamline_config.pl
@@ -137,7 +137,7 @@ my $ksource = ($ARGV[0] ? $ARGV[0] : '.');
my $kconfig = $ARGV[1];
my $lsmod_file = $ENV{'LSMOD'};
-my @makefiles = `find $ksource -name Makefile 2>/dev/null`;
+my @makefiles = `find $ksource -name Makefile -or -name Kbuild 2>/dev/null`;
chomp @makefiles;
my %depends;
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 9ed3250..5ebb896 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -406,6 +406,7 @@ static __init int yama_init(void)
*/
if (!security_module_enable("yama"))
return 0;
+ yama_add_hooks();
#endif
pr_info("Yama: becoming mindful.\n");
diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c
index 57a6dfc..52e4bc5 100644
--- a/sound/ac97_bus.c
+++ b/sound/ac97_bus.c
@@ -18,6 +18,68 @@
#include <sound/ac97_codec.h>
/*
+ * snd_ac97_check_id() - Reads and checks the vendor ID of the device
+ * @ac97: The AC97 device to check
+ * @id: The ID to compare to
+ * @id_mask: Mask that is applied to the device ID before comparing to @id
+ *
+ * If @id is 0 this function returns true if the read device vendor ID is
+ * a valid ID. If @id is non 0 this functions returns true if @id
+ * matches the read vendor ID. Otherwise the function returns false.
+ */
+static bool snd_ac97_check_id(struct snd_ac97 *ac97, unsigned int id,
+ unsigned int id_mask)
+{
+ ac97->id = ac97->bus->ops->read(ac97, AC97_VENDOR_ID1) << 16;
+ ac97->id |= ac97->bus->ops->read(ac97, AC97_VENDOR_ID2);
+
+ if (ac97->id == 0x0 || ac97->id == 0xffffffff)
+ return false;
+
+ if (id != 0 && id != (ac97->id & id_mask))
+ return false;
+
+ return true;
+}
+
+/**
+ * snd_ac97_reset() - Reset AC'97 device
+ * @ac97: The AC'97 device to reset
+ * @try_warm: Try a warm reset first
+ * @id: Expected device vendor ID
+ * @id_mask: Mask that is applied to the device ID before comparing to @id
+ *
+ * This function resets the AC'97 device. If @try_warm is true the function
+ * first performs a warm reset. If the warm reset is successful the function
+ * returns 1. Otherwise or if @try_warm is false the function issues cold reset
+ * followed by a warm reset. If this is successful the function returns 0,
+ * otherwise a negative error code. If @id is 0 any valid device ID will be
+ * accepted, otherwise only the ID that matches @id and @id_mask is accepted.
+ */
+int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
+ unsigned int id_mask)
+{
+ struct snd_ac97_bus_ops *ops = ac97->bus->ops;
+
+ if (try_warm && ops->warm_reset) {
+ ops->warm_reset(ac97);
+ if (snd_ac97_check_id(ac97, id, id_mask))
+ return 1;
+ }
+
+ if (ops->reset)
+ ops->reset(ac97);
+ if (ops->warm_reset)
+ ops->warm_reset(ac97);
+
+ if (snd_ac97_check_id(ac97, id, id_mask))
+ return 0;
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(snd_ac97_reset);
+
+/*
* Let drivers decide whether they want to support given codec from their
* probe method. Drivers have direct access to the struct snd_ac97
* structure and may decide based on the id field amongst other things.
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 1d651b8..225bfda 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -57,6 +57,7 @@ source "sound/soc/samsung/Kconfig"
source "sound/soc/sh/Kconfig"
source "sound/soc/sirf/Kconfig"
source "sound/soc/spear/Kconfig"
+source "sound/soc/sti/Kconfig"
source "sound/soc/tegra/Kconfig"
source "sound/soc/txx9/Kconfig"
source "sound/soc/ux500/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 669648b..134aca1 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_SND_SOC) += samsung/
obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += sirf/
obj-$(CONFIG_SND_SOC) += spear/
+obj-$(CONFIG_SND_SOC) += sti/
obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += txx9/
obj-$(CONFIG_SND_SOC) += ux500/
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 841d059..ba8def5 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -290,7 +290,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
int dir, dir_mask;
int ret;
- pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
+ pr_debug("atmel_ssc_startup: SSC_SR=0x%x\n",
ssc_readl(ssc_p->ssc->regs, SR));
/* Enable PMC peripheral clock for this SSC */
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index dd94fea..5741c0a 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -344,14 +344,8 @@ static int au1xpsc_pcm_drvprobe(struct platform_device *pdev)
platform_set_drvdata(pdev, dmadata);
- return snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
-}
-
-static int au1xpsc_pcm_drvremove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
-
- return 0;
+ return devm_snd_soc_register_platform(&pdev->dev,
+ &au1xpsc_soc_platform);
}
static struct platform_driver au1xpsc_pcm_driver = {
@@ -359,7 +353,6 @@ static struct platform_driver au1xpsc_pcm_driver = {
.name = "au1xpsc-pcm",
},
.probe = au1xpsc_pcm_drvprobe,
- .remove = au1xpsc_pcm_drvremove,
};
module_platform_driver(au1xpsc_pcm_driver);
diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
index 24cc7f4..fcf5a9a 100644
--- a/sound/soc/au1x/dma.c
+++ b/sound/soc/au1x/dma.c
@@ -312,14 +312,8 @@ static int alchemy_pcm_drvprobe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx);
- return snd_soc_register_platform(&pdev->dev, &alchemy_pcm_soc_platform);
-}
-
-static int alchemy_pcm_drvremove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
-
- return 0;
+ return devm_snd_soc_register_platform(&pdev->dev,
+ &alchemy_pcm_soc_platform);
}
static struct platform_driver alchemy_pcmdma_driver = {
@@ -327,7 +321,6 @@ static struct platform_driver alchemy_pcmdma_driver = {
.name = "alchemy-pcm-dma",
},
.probe = alchemy_pcm_drvprobe,
- .remove = alchemy_pcm_drvremove,
};
module_platform_driver(alchemy_pcmdma_driver);
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index e742ef6..38e853a 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -305,19 +305,9 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev)
return -ENOMEM;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iores)
- return -ENODEV;
-
- ret = -EBUSY;
- if (!devm_request_mem_region(&pdev->dev, iores->start,
- resource_size(iores),
- pdev->name))
- return -EBUSY;
-
- wd->mmio = devm_ioremap(&pdev->dev, iores->start,
- resource_size(iores));
- if (!wd->mmio)
- return -EBUSY;
+ wd->mmio = devm_ioremap_resource(&pdev->dev, iores);
+ if (IS_ERR(wd->mmio))
+ return PTR_ERR(wd->mmio);
dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!dmares)
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index 03fa1cb..8c435be 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -862,6 +862,8 @@ static const struct of_device_id bcm2835_i2s_of_match[] = {
{},
};
+MODULE_DEVICE_TABLE(of, bcm2835_i2s_of_match);
+
static struct platform_driver bcm2835_i2s_driver = {
.probe = bcm2835_i2s_probe,
.driver = {
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 238913e..02ad260 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -450,13 +450,8 @@ static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = {
static int bf5xx_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&pdev->dev, &bf5xx_ac97_soc_platform);
-}
-
-static int bf5xx_soc_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
+ return devm_snd_soc_register_platform(&pdev->dev,
+ &bf5xx_ac97_soc_platform);
}
static struct platform_driver bf5xx_pcm_driver = {
@@ -465,7 +460,6 @@ static struct platform_driver bf5xx_pcm_driver = {
},
.probe = bf5xx_soc_platform_probe,
- .remove = bf5xx_soc_platform_remove,
};
module_platform_driver(bf5xx_pcm_driver);
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index d95477a..6cba211d 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -342,13 +342,8 @@ static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
static int bfin_i2s_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&pdev->dev, &bf5xx_i2s_soc_platform);
-}
-
-static int bfin_i2s_soc_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
+ return devm_snd_soc_register_platform(&pdev->dev,
+ &bf5xx_i2s_soc_platform);
}
static struct platform_driver bfin_i2s_pcm_driver = {
@@ -357,7 +352,6 @@ static struct platform_driver bfin_i2s_pcm_driver = {
},
.probe = bfin_i2s_soc_platform_probe,
- .remove = bfin_i2s_soc_platform_remove,
};
module_platform_driver(bfin_i2s_pcm_driver);
diff --git a/sound/soc/blackfin/bfin-eval-adau1x61.c b/sound/soc/blackfin/bfin-eval-adau1x61.c
index 4229f76..fddfe00c 100644
--- a/sound/soc/blackfin/bfin-eval-adau1x61.c
+++ b/sound/soc/blackfin/bfin-eval-adau1x61.c
@@ -108,6 +108,7 @@ static struct snd_soc_dai_link bfin_eval_adau1x61_dai = {
static struct snd_soc_card bfin_eval_adau1x61 = {
.name = "bfin-eval-adau1x61",
+ .owner = THIS_MODULE,
.driver_name = "eval-adau1x61",
.dai_link = &bfin_eval_adau1x61_dai,
.num_links = 1,
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index 38b3dad..e8bed6b 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -156,33 +156,29 @@ static const DECLARE_TLV_DB_SCALE(dpga_tlv, -9450, 150, 1);
static const DECLARE_TLV_DB_SCALE(adc_tlv, -900, 300, 0);
/* {-23, -17, -13.5, -11, -9, -6, -3, 0}dB */
-static const unsigned int mic_tlv[] = {
- TLV_DB_RANGE_HEAD(5),
+static const DECLARE_TLV_DB_RANGE(mic_tlv,
0, 0, TLV_DB_SCALE_ITEM(-2300, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(-1700, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(-1350, 0, 0),
3, 3, TLV_DB_SCALE_ITEM(-1100, 0, 0),
- 4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0),
-};
+ 4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0)
+);
/* {0, 0, 0, -6, 0, 6, 12, 18}dB */
-static const unsigned int aux_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(aux_tlv,
0, 2, TLV_DB_SCALE_ITEM(0, 0, 0),
- 3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0),
-};
+ 3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0)
+);
/* {-16, -13, -10, -7, -5.2, -3,3, -2.2, 0}dB, mute instead of -16dB */
-static const unsigned int out_tlv[] = {
- TLV_DB_RANGE_HEAD(4),
+static const DECLARE_TLV_DB_RANGE(out_tlv,
0, 3, TLV_DB_SCALE_ITEM(-1600, 300, 1),
4, 4, TLV_DB_SCALE_ITEM(-520, 0, 0),
5, 5, TLV_DB_SCALE_ITEM(-330, 0, 0),
- 6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0),
-};
+ 6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0)
+);
-static const unsigned int st_tlv[] = {
- TLV_DB_RANGE_HEAD(8),
+static const DECLARE_TLV_DB_RANGE(st_tlv,
0, 1, TLV_DB_SCALE_ITEM(-12041, 602, 0),
2, 3, TLV_DB_SCALE_ITEM(-11087, 250, 0),
4, 5, TLV_DB_SCALE_ITEM(-10643, 158, 0),
@@ -190,8 +186,8 @@ static const unsigned int st_tlv[] = {
8, 9, TLV_DB_SCALE_ITEM(-10133, 92, 0),
10, 13, TLV_DB_SCALE_ITEM(-9958, 70, 0),
14, 17, TLV_DB_SCALE_ITEM(-9689, 53, 0),
- 18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0),
-};
+ 18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0)
+);
/* Sidetone Gain = M * 2^(-5-N) */
struct st_gain {
@@ -1028,10 +1024,8 @@ static int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
if (dir == PM860X_CLK_DIR_OUT)
pm860x->dir = PM860X_CLK_DIR_OUT;
- else {
- pm860x->dir = PM860X_CLK_DIR_IN;
+ else /* Slave mode is not supported */
return -EINVAL;
- }
return 0;
}
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index efaafce..0c9733e 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -53,6 +53,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS4271_I2C if I2C
select SND_SOC_CS4271_SPI if SPI_MASTER
select SND_SOC_CS42XX8_I2C if I2C
+ select SND_SOC_CS4349 if I2C
select SND_SOC_CX20442 if TTY
select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI
select SND_SOC_DA7213 if I2C
@@ -62,6 +63,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_BT_SCO
select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_ES8328_I2C if I2C
+ select SND_SOC_GTM601
+ select SND_SOC_ICS43432
select SND_SOC_ISABELLE if I2C
select SND_SOC_JZ4740_CODEC
select SND_SOC_LM4857 if I2C
@@ -83,6 +86,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM512x_I2C if I2C
select SND_SOC_PCM512x_SPI if SPI_MASTER
select SND_SOC_RT286 if I2C
+ select SND_SOC_RT298 if I2C
select SND_SOC_RT5631 if I2C
select SND_SOC_RT5640 if I2C
select SND_SOC_RT5645 if I2C
@@ -102,6 +106,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_STA350 if I2C
select SND_SOC_STA529 if I2C
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
+ select SND_SOC_STI_SAS
select SND_SOC_TAS2552 if I2C
select SND_SOC_TAS5086 if I2C
select SND_SOC_TAS571X if I2C
@@ -403,6 +408,11 @@ config SND_SOC_CS42XX8_I2C
select SND_SOC_CS42XX8
select REGMAP_I2C
+# Cirrus Logic CS4349 HiFi DAC
+config SND_SOC_CS4349
+ tristate "Cirrus Logic CS4349 CODEC"
+ depends on I2C
+
config SND_SOC_CX20442
tristate
depends on TTY
@@ -446,6 +456,12 @@ config SND_SOC_ES8328_SPI
tristate
select SND_SOC_ES8328
+config SND_SOC_GTM601
+ tristate 'GTM601 UMTS modem audio codec'
+
+config SND_SOC_ICS43432
+ tristate
+
config SND_SOC_ISABELLE
tristate
@@ -512,12 +528,18 @@ config SND_SOC_RL6231
config SND_SOC_RL6347A
tristate
default y if SND_SOC_RT286=y
+ default y if SND_SOC_RT298=y
default m if SND_SOC_RT286=m
+ default m if SND_SOC_RT298=m
config SND_SOC_RT286
tristate
depends on I2C
+config SND_SOC_RT298
+ tristate
+ depends on I2C
+
config SND_SOC_RT5631
tristate "Realtek ALC5631/RT5631 CODEC"
depends on I2C
@@ -610,6 +632,9 @@ config SND_SOC_STA529
config SND_SOC_STAC9766
tristate
+config SND_SOC_STI_SAS
+ tristate "codec Audio support for STI SAS codec"
+
config SND_SOC_TAS2552
tristate "Texas Instruments TAS2552 Mono Audio amplifier"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index cf160d9..4a32077 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -45,6 +45,7 @@ snd-soc-cs4271-i2c-objs := cs4271-i2c.o
snd-soc-cs4271-spi-objs := cs4271-spi.o
snd-soc-cs42xx8-objs := cs42xx8.o
snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
+snd-soc-cs4349-objs := cs4349.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-da7213-objs := da7213.o
@@ -55,6 +56,8 @@ snd-soc-dmic-objs := dmic.o
snd-soc-es8328-objs := es8328.o
snd-soc-es8328-i2c-objs := es8328-i2c.o
snd-soc-es8328-spi-objs := es8328-spi.o
+snd-soc-gtm601-objs := gtm601.o
+snd-soc-ics43432-objs := ics43432.o
snd-soc-isabelle-objs := isabelle.o
snd-soc-jz4740-codec-objs := jz4740.o
snd-soc-l3-objs := l3.o
@@ -79,6 +82,7 @@ snd-soc-pcm512x-spi-objs := pcm512x-spi.o
snd-soc-rl6231-objs := rl6231.o
snd-soc-rl6347a-objs := rl6347a.o
snd-soc-rt286-objs := rt286.o
+snd-soc-rt298-objs := rt298.o
snd-soc-rt5631-objs := rt5631.o
snd-soc-rt5640-objs := rt5640.o
snd-soc-rt5645-objs := rt5645.o
@@ -106,6 +110,7 @@ snd-soc-sta32x-objs := sta32x.o
snd-soc-sta350-objs := sta350.o
snd-soc-sta529-objs := sta529.o
snd-soc-stac9766-objs := stac9766.o
+snd-soc-sti-sas-objs := sti-sas.o
snd-soc-tas5086-objs := tas5086.o
snd-soc-tas571x-objs := tas571x.o
snd-soc-tfa9879-objs := tfa9879.o
@@ -232,6 +237,7 @@ obj-$(CONFIG_SND_SOC_CS4271_I2C) += snd-soc-cs4271-i2c.o
obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o
obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o
obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
+obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o
@@ -242,6 +248,8 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
+obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o
+obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.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
@@ -266,6 +274,7 @@ obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
+obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
@@ -289,6 +298,7 @@ obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o
obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o
obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
+obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o
obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index c7d243d..affb192 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -1335,11 +1335,10 @@ static DECLARE_TLV_DB_SCALE(dax_dig_gain_tlv, -6300, 100, 1);
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),
+static const DECLARE_TLV_DB_RANGE(hs_gain_tlv,
0, 3, TLV_DB_SCALE_ITEM(-3200, 400, 0),
- 4, 15, TLV_DB_SCALE_ITEM(-1800, 200, 0),
-};
+ 4, 15, TLV_DB_SCALE_ITEM(-1800, 200, 0)
+);
static DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0);
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 3cc69a6..9ef20db 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -202,19 +202,21 @@ static struct snd_soc_dai_driver ad1980_dai = {
.formats = SND_SOC_STD_AC97_FMTS, },
};
+#define AD1980_VENDOR_ID 0x41445300
+#define AD1980_VENDOR_MASK 0xffffff00
+
static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
{
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
unsigned int retry_cnt = 0;
+ int ret;
do {
- if (try_warm && soc_ac97_ops->warm_reset) {
- soc_ac97_ops->warm_reset(ac97);
- if (snd_soc_read(codec, AC97_RESET) == 0x0090)
- return 1;
- }
+ ret = snd_ac97_reset(ac97, true, AD1980_VENDOR_ID,
+ AD1980_VENDOR_MASK);
+ if (ret >= 0)
+ return 0;
- soc_ac97_ops->reset(ac97);
/*
* Set bit 16slot in register 74h, then every slot will has only
* 16 bits. This command is sent out in 20bit mode, in which
@@ -223,8 +225,6 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
*/
snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
- if (snd_soc_read(codec, AC97_RESET) == 0x0090)
- return 0;
} while (retry_cnt++ < 10);
dev_err(codec->dev, "Failed to reset: AC97 link error\n");
@@ -240,7 +240,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
u16 vendor_id2;
u16 ext_status;
- ac97 = snd_soc_new_ac97_codec(codec);
+ ac97 = snd_soc_new_ac97_codec(codec, 0, 0);
if (IS_ERR(ac97)) {
ret = PTR_ERR(ac97);
dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret);
@@ -260,22 +260,10 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
if (ret < 0)
goto reset_err;
- /* Read out vendor ID to make sure it is ad1980 */
- if (snd_soc_read(codec, AC97_VENDOR_ID1) != 0x4144) {
- ret = -ENODEV;
- goto reset_err;
- }
-
vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2);
-
- if (vendor_id2 != 0x5370) {
- if (vendor_id2 != 0x5374) {
- ret = -ENODEV;
- goto reset_err;
- } else {
- dev_warn(codec->dev,
- "Found AD1981 - only 2/2 IN/OUT Channels supported\n");
- }
+ if (vendor_id2 == 0x5374) {
+ dev_warn(codec->dev,
+ "Found AD1981 - only 2/2 IN/OUT Channels supported\n");
}
/* unmute captures and playbacks volume */
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index a431602..fe1353a 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -320,13 +320,12 @@ static const struct reg_default adau1373_reg_defaults[] = {
{ ADAU1373_DIGEN, 0x00 },
};
-static const unsigned int adau1373_out_tlv[] = {
- TLV_DB_RANGE_HEAD(4),
+static const DECLARE_TLV_DB_RANGE(adau1373_out_tlv,
0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1),
8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0),
16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0),
- 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0),
-};
+ 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0)
+);
static const DECLARE_TLV_DB_MINMAX(adau1373_digital_tlv, -9563, 0);
static const DECLARE_TLV_DB_SCALE(adau1373_in_pga_tlv, -1300, 100, 1);
@@ -381,12 +380,11 @@ static const char *adau1373_bass_hpf_cutoff_text[] = {
"158Hz", "232Hz", "347Hz", "520Hz",
};
-static const unsigned int adau1373_bass_tlv[] = {
- TLV_DB_RANGE_HEAD(3),
+static const DECLARE_TLV_DB_RANGE(adau1373_bass_tlv,
0, 2, TLV_DB_SCALE_ITEM(-600, 600, 1),
3, 4, TLV_DB_SCALE_ITEM(950, 250, 0),
- 5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0),
-};
+ 5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0)
+);
static SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum,
ADAU1373_BASS1, 5, adau1373_bass_lpf_cutoff_text);
@@ -414,11 +412,10 @@ static SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum,
static SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum,
ADAU1373_3D_CTRL1, 0, adau1373_3d_cutoff_text);
-static const unsigned int adau1373_3d_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(adau1373_3d_tlv,
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
- 1, 7, TLV_DB_LINEAR_ITEM(-1800, -120),
-};
+ 1, 7, TLV_DB_LINEAR_ITEM(-1800, -120)
+);
static const char *adau1373_lr_mux_text[] = {
"Mute",
@@ -1534,7 +1531,6 @@ MODULE_DEVICE_TABLE(i2c, adau1373_i2c_id);
static struct i2c_driver adau1373_i2c_driver = {
.driver = {
.name = "adau1373",
- .owner = THIS_MODULE,
},
.probe = adau1373_i2c_probe,
.remove = adau1373_i2c_remove,
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index ff7f846..de53c0d 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -915,7 +915,6 @@ MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id);
static struct i2c_driver adau1701_i2c_driver = {
.driver = {
.name = "adau1701",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(adau1701_dt_ids),
},
.probe = adau1701_i2c_probe,
diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c
index 862796d..348ccb1 100644
--- a/sound/soc/codecs/adau1761-i2c.c
+++ b/sound/soc/codecs/adau1761-i2c.c
@@ -47,7 +47,6 @@ MODULE_DEVICE_TABLE(i2c, adau1761_i2c_ids);
static struct i2c_driver adau1761_i2c_driver = {
.driver = {
.name = "adau1761",
- .owner = THIS_MODULE,
},
.probe = adau1761_i2c_probe,
.remove = adau1761_i2c_remove,
diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c
index 2ce4362..0e32bba 100644
--- a/sound/soc/codecs/adau1781-i2c.c
+++ b/sound/soc/codecs/adau1781-i2c.c
@@ -45,7 +45,6 @@ MODULE_DEVICE_TABLE(i2c, adau1781_i2c_ids);
static struct i2c_driver adau1781_i2c_driver = {
.driver = {
.name = "adau1781",
- .owner = THIS_MODULE,
},
.probe = adau1781_i2c_probe,
.remove = adau1781_i2c_remove,
diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c
index 9700e8c..21e7394 100644
--- a/sound/soc/codecs/adau1977-i2c.c
+++ b/sound/soc/codecs/adau1977-i2c.c
@@ -46,7 +46,6 @@ MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids);
static struct i2c_driver adau1977_i2c_driver = {
.driver = {
.name = "adau1977",
- .owner = THIS_MODULE,
},
.probe = adau1977_i2c_probe,
.remove = adau1977_i2c_remove,
diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c
index 66d9fce..52881fa 100644
--- a/sound/soc/codecs/adav803.c
+++ b/sound/soc/codecs/adav803.c
@@ -36,7 +36,6 @@ static int adav803_remove(struct i2c_client *client)
static struct i2c_driver adav803_driver = {
.driver = {
.name = "adav803",
- .owner = THIS_MODULE,
},
.probe = adav803_probe,
.remove = adav803_remove,
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index 36d8425..198c924 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -113,7 +113,7 @@
#define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x))
-static struct reg_default adav80x_reg_defaults[] = {
+static const struct reg_default adav80x_reg_defaults[] = {
{ ADAV80X_PLAYBACK_CTRL, 0x01 },
{ ADAV80X_AUX_IN_CTRL, 0x01 },
{ ADAV80X_REC_CTRL, 0x02 },
@@ -865,7 +865,6 @@ const struct regmap_config adav80x_regmap_config = {
.val_bits = 8,
.pad_bits = 1,
.reg_bits = 7,
- .read_flag_mask = 0x01,
.max_register = ADAV80X_PLL_OUTE,
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 8670861..54428c6 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -444,7 +444,6 @@ MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id);
static struct i2c_driver ak4535_i2c_driver = {
.driver = {
.name = "ak4535",
- .owner = THIS_MODULE,
},
.probe = ak4535_i2c_probe,
.remove = ak4535_i2c_remove,
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index 2d0ff45..b14176f 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -609,7 +609,6 @@ MODULE_DEVICE_TABLE(i2c, ak4641_i2c_id);
static struct i2c_driver ak4641_i2c_driver = {
.driver = {
.name = "ak4641",
- .owner = THIS_MODULE,
},
.probe = ak4641_i2c_probe,
.remove = ak4641_i2c_remove,
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 7c0f6552..4a90143 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -64,12 +64,15 @@
#define FIL1_0 0x1c
#define FIL1_1 0x1d
#define FIL1_2 0x1e
-#define FIL1_3 0x1f
+#define FIL1_3 0x1f /* The maximum valid register for ak4642 */
#define PW_MGMT4 0x20
#define MD_CTL5 0x21
#define LO_MS 0x22
#define HP_MS 0x23
-#define SPK_MS 0x24
+#define SPK_MS 0x24 /* The maximum valid register for ak4643 */
+#define EQ_FBEQAB 0x25
+#define EQ_FBEQCD 0x26
+#define EQ_FBEQE 0x27 /* The maximum valid register for ak4648 */
/* PW_MGMT1*/
#define PMVCM (1 << 6) /* VCOM Power Management */
@@ -241,7 +244,7 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = {
/*
* ak4642 register cache
*/
-static const struct reg_default ak4642_reg[] = {
+static const struct reg_default ak4643_reg[] = {
{ 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 },
{ 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
{ 8, 0xe1 }, { 9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 },
@@ -254,6 +257,14 @@ static const struct reg_default ak4642_reg[] = {
{ 36, 0x00 },
};
+/* The default settings for 0x0 ~ 0x1f registers are the same for ak4642
+ and ak4643. So we reuse the ak4643 reg_default for ak4642.
+ The valid registers for ak4642 are 0x0 ~ 0x1f which is a subset of ak4643,
+ so define NUM_AK4642_REG_DEFAULTS for ak4642.
+*/
+#define ak4642_reg ak4643_reg
+#define NUM_AK4642_REG_DEFAULTS (FIL1_3 + 1)
+
static const struct reg_default ak4648_reg[] = {
{ 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 },
{ 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
@@ -535,15 +546,23 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
static const struct regmap_config ak4642_regmap = {
.reg_bits = 8,
.val_bits = 8,
- .max_register = ARRAY_SIZE(ak4642_reg) + 1,
+ .max_register = FIL1_3,
.reg_defaults = ak4642_reg,
- .num_reg_defaults = ARRAY_SIZE(ak4642_reg),
+ .num_reg_defaults = NUM_AK4642_REG_DEFAULTS,
+};
+
+static const struct regmap_config ak4643_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = SPK_MS,
+ .reg_defaults = ak4643_reg,
+ .num_reg_defaults = ARRAY_SIZE(ak4643_reg),
};
static const struct regmap_config ak4648_regmap = {
.reg_bits = 8,
.val_bits = 8,
- .max_register = ARRAY_SIZE(ak4648_reg) + 1,
+ .max_register = EQ_FBEQE,
.reg_defaults = ak4648_reg,
.num_reg_defaults = ARRAY_SIZE(ak4648_reg),
};
@@ -553,7 +572,7 @@ static const struct ak4642_drvdata ak4642_drvdata = {
};
static const struct ak4642_drvdata ak4643_drvdata = {
- .regmap_config = &ak4642_regmap,
+ .regmap_config = &ak4643_regmap,
};
static const struct ak4642_drvdata ak4648_drvdata = {
@@ -626,7 +645,6 @@ MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
static struct i2c_driver ak4642_i2c_driver = {
.driver = {
.name = "ak4642-codec",
- .owner = THIS_MODULE,
.of_match_table = ak4642_of_match,
},
.probe = ak4642_i2c_probe,
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index 0e59063..c73a9f6 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -663,7 +663,6 @@ MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id);
static struct i2c_driver ak4671_i2c_driver = {
.driver = {
.name = "ak4671-codec",
- .owner = THIS_MODULE,
},
.probe = ak4671_i2c_probe,
.remove = ak4671_i2c_remove,
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index 0fc24e0..d2e3a3e 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -82,12 +82,11 @@ static int amp_mixer_event(struct snd_soc_dapm_widget *w,
static const DECLARE_TLV_DB_SCALE(vol_tlv, -3450, 150, 0);
static const DECLARE_TLV_DB_SCALE(hp_tlv, -4650, 150, 0);
static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -1650, 150, 0);
-static const unsigned int boost_tlv[] = {
- TLV_DB_RANGE_HEAD(3),
+static const DECLARE_TLV_DB_RANGE(boost_tlv,
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
- 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
-};
+ 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0)
+);
static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0);
static const struct snd_kcontrol_new alc5621_vol_snd_controls[] = {
@@ -1085,7 +1084,6 @@ MODULE_DEVICE_TABLE(of, alc5623_of_match);
static struct i2c_driver alc5623_i2c_driver = {
.driver = {
.name = "alc562x-codec",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(alc5623_of_match),
},
.probe = alc5623_i2c_probe,
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index 607a63b..4d3ba33 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -35,7 +35,7 @@
/*
* ALC5632 register cache
*/
-static struct reg_default alc5632_reg_defaults[] = {
+static const struct reg_default alc5632_reg_defaults[] = {
{ 2, 0x8080 }, /* R2 - Speaker Output Volume */
{ 4, 0x8080 }, /* R4 - Headphone Output Volume */
{ 6, 0x8080 }, /* R6 - AUXOUT Volume */
@@ -146,11 +146,10 @@ static const DECLARE_TLV_DB_SCALE(vol_tlv, -3450, 150, 0);
static const DECLARE_TLV_DB_SCALE(hp_tlv, -4650, 150, 0);
/* -16.5db min scale, 1.5db steps, no mute */
static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -1650, 150, 0);
-static const unsigned int boost_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(boost_tlv,
0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
- 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0),
-};
+ 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0)
+);
/* 0db min scale, 6 db steps, no mute */
static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0);
/* 0db min scalem 0.75db steps, no mute */
@@ -1183,7 +1182,6 @@ MODULE_DEVICE_TABLE(of, alc5632_of_match);
static struct i2c_driver alc5632_i2c_driver = {
.driver = {
.name = "alc5632",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(alc5632_of_match),
},
.probe = alc5632_i2c_probe,
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 802e05e..8a2221a 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -1366,7 +1366,7 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
- struct reg_default dac_comp[] = {
+ struct reg_sequence dac_comp[] = {
{ 0x80, 0x3 },
{ ARIZONA_DAC_COMP_1, 0 },
{ ARIZONA_DAC_COMP_2, 0 },
@@ -1504,7 +1504,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
else
rates = &arizona_48k_bclk_rates[0];
- wl = snd_pcm_format_width(params_format(params));
+ wl = params_width(params);
if (tdm_slots) {
arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
@@ -1756,17 +1756,6 @@ int arizona_init_dai(struct arizona_priv *priv, int id)
}
EXPORT_SYMBOL_GPL(arizona_init_dai);
-static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
-{
- struct arizona_fll *fll = data;
-
- arizona_fll_dbg(fll, "clock OK\n");
-
- complete(&fll->ok);
-
- return IRQ_HANDLED;
-}
-
static struct {
unsigned int min;
unsigned int max;
@@ -2048,17 +2037,18 @@ static int arizona_is_enabled_fll(struct arizona_fll *fll)
static int arizona_enable_fll(struct arizona_fll *fll)
{
struct arizona *arizona = fll->arizona;
- unsigned long time_left;
bool use_sync = false;
int already_enabled = arizona_is_enabled_fll(fll);
struct arizona_fll_cfg cfg;
+ int i;
+ unsigned int val;
if (already_enabled < 0)
return already_enabled;
if (already_enabled) {
/* Facilitate smooth refclk across the transition */
- regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7,
+ regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
ARIZONA_FLL1_GAIN_MASK, 0);
regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
ARIZONA_FLL1_FREERUN,
@@ -2110,9 +2100,6 @@ static int arizona_enable_fll(struct arizona_fll *fll)
if (!already_enabled)
pm_runtime_get(arizona->dev);
- /* Clear any pending completions */
- try_wait_for_completion(&fll->ok);
-
regmap_update_bits_async(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
if (use_sync)
@@ -2124,10 +2111,24 @@ static int arizona_enable_fll(struct arizona_fll *fll)
regmap_update_bits_async(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_FREERUN, 0);
- time_left = wait_for_completion_timeout(&fll->ok,
- msecs_to_jiffies(250));
- if (time_left == 0)
+ arizona_fll_dbg(fll, "Waiting for FLL lock...\n");
+ val = 0;
+ for (i = 0; i < 15; i++) {
+ if (i < 5)
+ usleep_range(200, 400);
+ else
+ msleep(20);
+
+ regmap_read(arizona->regmap,
+ ARIZONA_INTERRUPT_RAW_STATUS_5,
+ &val);
+ if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1)))
+ break;
+ }
+ if (i == 15)
arizona_fll_warn(fll, "Timed out waiting for lock\n");
+ else
+ arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i);
return 0;
}
@@ -2212,11 +2213,8 @@ EXPORT_SYMBOL_GPL(arizona_set_fll);
int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
int ok_irq, struct arizona_fll *fll)
{
- int ret;
unsigned int val;
- init_completion(&fll->ok);
-
fll->id = id;
fll->base = base;
fll->arizona = arizona;
@@ -2238,13 +2236,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
"FLL%d clock OK", id);
- ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
- arizona_fll_clock_ok, fll);
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
- id, ret);
- }
-
regmap_update_bits(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_FREERUN, 0);
@@ -2313,6 +2304,82 @@ const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = {
};
EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls);
+static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
+{
+ s16 a = be16_to_cpu(_a);
+ s16 b = be16_to_cpu(_b);
+
+ if (!mode) {
+ return abs(a) >= 4096;
+ } else {
+ if (abs(b) >= 4096)
+ return true;
+
+ return (abs((a << 16) / (4096 - b)) >= 4096 << 4);
+ }
+}
+
+int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+ struct soc_bytes *params = (void *)kcontrol->private_value;
+ unsigned int val;
+ __be16 *data;
+ int len;
+ int ret;
+
+ len = params->num_regs * regmap_get_val_bytes(arizona->regmap);
+
+ data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
+ if (!data)
+ return -ENOMEM;
+
+ data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE);
+
+ if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) ||
+ arizona_eq_filter_unstable(true, data[4], data[5]) ||
+ arizona_eq_filter_unstable(true, data[8], data[9]) ||
+ arizona_eq_filter_unstable(true, data[12], data[13]) ||
+ arizona_eq_filter_unstable(false, data[16], data[17])) {
+ dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = regmap_read(arizona->regmap, params->base, &val);
+ if (ret != 0)
+ goto out;
+
+ val &= ~ARIZONA_EQ1_B1_MODE;
+ data[0] |= cpu_to_be16(val);
+
+ ret = regmap_raw_write(arizona->regmap, params->base, data, len);
+
+out:
+ kfree(data);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
+
+int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+ __be16 *data = (__be16 *)ucontrol->value.bytes.data;
+ s16 val = be16_to_cpu(*data);
+
+ if (abs(val) >= 4096) {
+ dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n");
+ return -EINVAL;
+ }
+
+ return snd_soc_bytes_put(kcontrol, ucontrol);
+}
+EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
+
MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 43deb04..ada0a41 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -194,6 +194,20 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
ARIZONA_MIXER_ROUTES(name " Preloader", name "L"), \
ARIZONA_MIXER_ROUTES(name " Preloader", name "R")
+#define ARIZONA_EQ_CONTROL(xname, xbase) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
+ .put = arizona_eq_coeff_put, .private_value = \
+ ((unsigned long)&(struct soc_bytes) { .base = xbase, \
+ .num_regs = 20, .mask = ~ARIZONA_EQ1_B1_MODE }) }
+
+#define ARIZONA_LHPF_CONTROL(xname, xbase) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
+ .put = arizona_lhpf_coeff_put, .private_value = \
+ ((unsigned long)&(struct soc_bytes) { .base = xbase, \
+ .num_regs = 1 }) }
+
#define ARIZONA_RATE_ENUM_SIZE 4
extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
@@ -229,6 +243,11 @@ extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event);
+extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+extern int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir);
@@ -242,7 +261,6 @@ struct arizona_fll {
int id;
unsigned int base;
unsigned int vco_mult;
- struct completion ok;
unsigned int fout;
int sync_src;
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index 8f40025..44c30fe 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -74,33 +74,8 @@ static const struct reg_default cs35l32_reg_defaults[] = {
static bool cs35l32_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
- case CS35L32_DEVID_AB:
- case CS35L32_DEVID_CD:
- case CS35L32_DEVID_E:
- case CS35L32_FAB_ID:
- case CS35L32_REV_ID:
- case CS35L32_PWRCTL1:
- case CS35L32_PWRCTL2:
- case CS35L32_CLK_CTL:
- case CS35L32_BATT_THRESHOLD:
- case CS35L32_VMON:
- case CS35L32_BST_CPCP_CTL:
- case CS35L32_IMON_SCALING:
- case CS35L32_AUDIO_LED_MNGR:
- case CS35L32_ADSP_CTL:
- case CS35L32_CLASSD_CTL:
- case CS35L32_PROTECT_CTL:
- case CS35L32_INT_MASK_1:
- case CS35L32_INT_MASK_2:
- case CS35L32_INT_MASK_3:
- case CS35L32_INT_STATUS_1:
- case CS35L32_INT_STATUS_2:
- case CS35L32_INT_STATUS_3:
- case CS35L32_LED_STATUS:
- case CS35L32_FLASH_MODE:
- case CS35L32_MOVIE_MODE:
- case CS35L32_FLASH_TIMER:
- case CS35L32_FLASH_INHIBIT:
+ case CS35L32_DEVID_AB ... CS35L32_AUDIO_LED_MNGR:
+ case CS35L32_ADSP_CTL ... CS35L32_FLASH_INHIBIT:
return true;
default:
return false;
@@ -110,15 +85,8 @@ static bool cs35l32_readable_register(struct device *dev, unsigned int reg)
static bool cs35l32_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
- case CS35L32_DEVID_AB:
- case CS35L32_DEVID_CD:
- case CS35L32_DEVID_E:
- case CS35L32_FAB_ID:
- case CS35L32_REV_ID:
- case CS35L32_INT_STATUS_1:
- case CS35L32_INT_STATUS_2:
- case CS35L32_INT_STATUS_3:
- case CS35L32_LED_STATUS:
+ case CS35L32_DEVID_AB ... CS35L32_REV_ID:
+ case CS35L32_INT_STATUS_1 ... CS35L32_LED_STATUS:
return true;
default:
return false;
@@ -128,10 +96,7 @@ static bool cs35l32_volatile_register(struct device *dev, unsigned int reg)
static bool cs35l32_precious_register(struct device *dev, unsigned int reg)
{
switch (reg) {
- case CS35L32_INT_STATUS_1:
- case CS35L32_INT_STATUS_2:
- case CS35L32_INT_STATUS_3:
- case CS35L32_LED_STATUS:
+ case CS35L32_INT_STATUS_1 ... CS35L32_LED_STATUS:
return true;
default:
return false;
@@ -276,7 +241,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
};
/* Current and threshold powerup sequence Pg37 in datasheet */
-static const struct reg_default cs35l32_monitor_patch[] = {
+static const struct reg_sequence cs35l32_monitor_patch[] = {
{ 0x00, 0x99 },
{ 0x48, 0x17 },
@@ -441,8 +406,7 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
if (IS_ERR(cs35l32->reset_gpio))
return PTR_ERR(cs35l32->reset_gpio);
- if (cs35l32->reset_gpio)
- gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
+ gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
/* initialize codec */
ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, &reg);
@@ -536,8 +500,7 @@ static int cs35l32_i2c_remove(struct i2c_client *i2c_client)
snd_soc_unregister_codec(&i2c_client->dev);
/* Hold down reset */
- if (cs35l32->reset_gpio)
- gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
return 0;
}
@@ -551,8 +514,7 @@ static int cs35l32_runtime_suspend(struct device *dev)
regcache_mark_dirty(cs35l32->regmap);
/* Hold down reset */
- if (cs35l32->reset_gpio)
- gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
/* remove power */
regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
@@ -575,8 +537,7 @@ static int cs35l32_runtime_resume(struct device *dev)
return ret;
}
- if (cs35l32->reset_gpio)
- gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
+ gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
regcache_cache_only(cs35l32->regmap, false);
regcache_sync(cs35l32->regmap);
@@ -607,7 +568,6 @@ MODULE_DEVICE_TABLE(i2c, cs35l32_id);
static struct i2c_driver cs35l32_i2c_driver = {
.driver = {
.name = "cs35l32",
- .owner = THIS_MODULE,
.pm = &cs35l32_runtime_pm,
.of_match_table = cs35l32_of_match,
},
diff --git a/sound/soc/codecs/cs35l32.h b/sound/soc/codecs/cs35l32.h
index 31ab804..1d6c250 100644
--- a/sound/soc/codecs/cs35l32.h
+++ b/sound/soc/codecs/cs35l32.h
@@ -80,7 +80,7 @@ struct cs35l32_platform_data {
#define CS35L32_GAIN_MGR_MASK 0x08
#define CS35L32_ADSP_SHARE_MASK 0x08
#define CS35L32_ADSP_DATACFG_MASK 0x30
-#define CS35L32_SDOUT_3ST 0x80
+#define CS35L32_SDOUT_3ST 0x08
#define CS35L32_BATT_REC_MASK 0x0E
#define CS35L32_BATT_THRESH_MASK 0x30
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index 8e36198..55db19d 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -60,23 +60,7 @@ static const struct reg_default cs4265_reg_defaults[] = {
static bool cs4265_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
- case CS4265_PWRCTL:
- case CS4265_DAC_CTL:
- case CS4265_ADC_CTL:
- case CS4265_MCLK_FREQ:
- case CS4265_SIG_SEL:
- case CS4265_CHB_PGA_CTL:
- case CS4265_CHA_PGA_CTL:
- case CS4265_ADC_CTL2:
- case CS4265_DAC_CHA_VOL:
- case CS4265_DAC_CHB_VOL:
- case CS4265_DAC_CTL2:
- case CS4265_SPDIF_CTL1:
- case CS4265_SPDIF_CTL2:
- case CS4265_INT_MASK:
- case CS4265_STATUS_MODE_MSB:
- case CS4265_STATUS_MODE_LSB:
- case CS4265_CHIP_ID:
+ case CS4265_CHIP_ID ... CS4265_SPDIF_CTL2:
return true;
default:
return false;
@@ -658,7 +642,6 @@ MODULE_DEVICE_TABLE(i2c, cs4265_id);
static struct i2c_driver cs4265_i2c_driver = {
.driver = {
.name = "cs4265",
- .owner = THIS_MODULE,
.of_match_table = cs4265_of_match,
},
.id_table = cs4265_id,
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index e6d4ff9..e07807d 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -751,7 +751,6 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id);
static struct i2c_driver cs4270_i2c_driver = {
.driver = {
.name = "cs4270",
- .owner = THIS_MODULE,
.of_match_table = cs4270_of_match,
},
.id_table = cs4270_id,
diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c
index b264da0..dcb3223 100644
--- a/sound/soc/codecs/cs4271-i2c.c
+++ b/sound/soc/codecs/cs4271-i2c.c
@@ -48,7 +48,6 @@ MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
static struct i2c_driver cs4271_i2c_driver = {
.driver = {
.name = "cs4271",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(cs4271_dt_ids),
},
.probe = cs4271_i2c_probe,
diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c
index c40428f..9bad478 100644
--- a/sound/soc/codecs/cs42l51-i2c.c
+++ b/sound/soc/codecs/cs42l51-i2c.c
@@ -45,7 +45,6 @@ static int cs42l51_i2c_remove(struct i2c_client *i2c)
static struct i2c_driver cs42l51_i2c_driver = {
.driver = {
.name = "cs42l51",
- .owner = THIS_MODULE,
.of_match_table = cs42l51_of_match,
},
.probe = cs42l51_i2c_probe,
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 4de52c9..47b97fc 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -110,58 +110,7 @@ static const struct reg_default cs42l52_reg_defaults[] = {
static bool cs42l52_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
- case CS42L52_CHIP:
- case CS42L52_PWRCTL1:
- case CS42L52_PWRCTL2:
- case CS42L52_PWRCTL3:
- case CS42L52_CLK_CTL:
- case CS42L52_IFACE_CTL1:
- case CS42L52_IFACE_CTL2:
- case CS42L52_ADC_PGA_A:
- case CS42L52_ADC_PGA_B:
- case CS42L52_ANALOG_HPF_CTL:
- case CS42L52_ADC_HPF_FREQ:
- case CS42L52_ADC_MISC_CTL:
- case CS42L52_PB_CTL1:
- case CS42L52_MISC_CTL:
- case CS42L52_PB_CTL2:
- case CS42L52_MICA_CTL:
- case CS42L52_MICB_CTL:
- case CS42L52_PGAA_CTL:
- case CS42L52_PGAB_CTL:
- case CS42L52_PASSTHRUA_VOL:
- case CS42L52_PASSTHRUB_VOL:
- case CS42L52_ADCA_VOL:
- case CS42L52_ADCB_VOL:
- case CS42L52_ADCA_MIXER_VOL:
- case CS42L52_ADCB_MIXER_VOL:
- case CS42L52_PCMA_MIXER_VOL:
- case CS42L52_PCMB_MIXER_VOL:
- case CS42L52_BEEP_FREQ:
- case CS42L52_BEEP_VOL:
- case CS42L52_BEEP_TONE_CTL:
- case CS42L52_TONE_CTL:
- case CS42L52_MASTERA_VOL:
- case CS42L52_MASTERB_VOL:
- case CS42L52_HPA_VOL:
- case CS42L52_HPB_VOL:
- case CS42L52_SPKA_VOL:
- case CS42L52_SPKB_VOL:
- case CS42L52_ADC_PCM_MIXER:
- case CS42L52_LIMITER_CTL1:
- case CS42L52_LIMITER_CTL2:
- case CS42L52_LIMITER_AT_RATE:
- case CS42L52_ALC_CTL:
- case CS42L52_ALC_RATE:
- case CS42L52_ALC_THRESHOLD:
- case CS42L52_NOISE_GATE_CTL:
- case CS42L52_CLK_STATUS:
- case CS42L52_BATT_COMPEN:
- case CS42L52_BATT_LEVEL:
- case CS42L52_SPK_STATUS:
- case CS42L52_TEM_CTL:
- case CS42L52_THE_FOLDBACK:
- case CS42L52_CHARGE_PUMP:
+ case CS42L52_CHIP ... CS42L52_CHARGE_PUMP:
return true;
default:
return false;
@@ -196,11 +145,10 @@ static DECLARE_TLV_DB_SCALE(mix_tlv, -50, 50, 0);
static DECLARE_TLV_DB_SCALE(beep_tlv, -56, 200, 0);
-static const unsigned int limiter_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(limiter_tlv,
0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
- 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0),
-};
+ 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0)
+);
static const char * const cs42l52_adca_text[] = {
"Input1A", "Input2A", "Input3A", "Input4A", "PGA Input Left"};
@@ -919,7 +867,7 @@ static int cs42l52_set_bias_level(struct snd_soc_codec *codec,
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
-static struct snd_soc_dai_ops cs42l52_ops = {
+static const struct snd_soc_dai_ops cs42l52_ops = {
.hw_params = cs42l52_pcm_hw_params,
.digital_mute = cs42l52_digital_mute,
.set_fmt = cs42l52_set_fmt,
@@ -1118,7 +1066,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
};
/* Current and threshold powerup sequence Pg37 */
-static const struct reg_default cs42l52_threshold_patch[] = {
+static const struct reg_sequence cs42l52_threshold_patch[] = {
{ 0x00, 0x99 },
{ 0x3E, 0xBA },
@@ -1285,7 +1233,6 @@ MODULE_DEVICE_TABLE(i2c, cs42l52_id);
static struct i2c_driver cs42l52_i2c_driver = {
.driver = {
.name = "cs42l52",
- .owner = THIS_MODULE,
.of_match_table = cs42l52_of_match,
},
.id_table = cs42l52_id,
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index 1e11ba4..7cd5f76 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -115,52 +115,7 @@ static const struct reg_default cs42l56_reg_defaults[] = {
static bool cs42l56_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
- case CS42L56_CHIP_ID_1:
- case CS42L56_CHIP_ID_2:
- case CS42L56_PWRCTL_1:
- case CS42L56_PWRCTL_2:
- case CS42L56_CLKCTL_1:
- case CS42L56_CLKCTL_2:
- case CS42L56_SERIAL_FMT:
- case CS42L56_CLASSH_CTL:
- case CS42L56_MISC_CTL:
- case CS42L56_INT_STATUS:
- case CS42L56_PLAYBACK_CTL:
- case CS42L56_DSP_MUTE_CTL:
- case CS42L56_ADCA_MIX_VOLUME:
- case CS42L56_ADCB_MIX_VOLUME:
- case CS42L56_PCMA_MIX_VOLUME:
- case CS42L56_PCMB_MIX_VOLUME:
- case CS42L56_ANAINPUT_ADV_VOLUME:
- case CS42L56_DIGINPUT_ADV_VOLUME:
- case CS42L56_MASTER_A_VOLUME:
- case CS42L56_MASTER_B_VOLUME:
- case CS42L56_BEEP_FREQ_ONTIME:
- case CS42L56_BEEP_FREQ_OFFTIME:
- case CS42L56_BEEP_TONE_CFG:
- case CS42L56_TONE_CTL:
- case CS42L56_CHAN_MIX_SWAP:
- case CS42L56_AIN_REFCFG_ADC_MUX:
- case CS42L56_HPF_CTL:
- case CS42L56_MISC_ADC_CTL:
- case CS42L56_GAIN_BIAS_CTL:
- case CS42L56_PGAA_MUX_VOLUME:
- case CS42L56_PGAB_MUX_VOLUME:
- case CS42L56_ADCA_ATTENUATOR:
- case CS42L56_ADCB_ATTENUATOR:
- case CS42L56_ALC_EN_ATTACK_RATE:
- case CS42L56_ALC_RELEASE_RATE:
- case CS42L56_ALC_THRESHOLD:
- case CS42L56_NOISE_GATE_CTL:
- case CS42L56_ALC_LIM_SFT_ZC:
- case CS42L56_AMUTE_HPLO_MUX:
- case CS42L56_HPA_VOLUME:
- case CS42L56_HPB_VOLUME:
- case CS42L56_LOA_VOLUME:
- case CS42L56_LOB_VOLUME:
- case CS42L56_LIM_THRESHOLD_CTL:
- case CS42L56_LIM_CTL_RELEASE_RATE:
- case CS42L56_LIM_ATTACK_RATE:
+ case CS42L56_CHIP_ID_1 ... CS42L56_LIM_ATTACK_RATE:
return true;
default:
return false;
@@ -185,21 +140,18 @@ static DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
static DECLARE_TLV_DB_SCALE(preamp_tlv, 0, 1000, 0);
static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
-static const unsigned int ngnb_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(ngnb_tlv,
0, 1, TLV_DB_SCALE_ITEM(-8200, 600, 0),
- 2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0),
-};
-static const unsigned int ngb_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+ 2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0)
+);
+static const DECLARE_TLV_DB_RANGE(ngb_tlv,
0, 2, TLV_DB_SCALE_ITEM(-6400, 600, 0),
- 3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0),
-};
-static const unsigned int alc_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+ 3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0)
+);
+static const DECLARE_TLV_DB_RANGE(alc_tlv,
0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
- 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0),
-};
+ 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0)
+);
static const char * const beep_config_text[] = {
"Off", "Single", "Multiple", "Continuous"
@@ -989,7 +941,7 @@ static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
SNDRV_PCM_FMTBIT_S32_LE)
-static struct snd_soc_dai_ops cs42l56_ops = {
+static const struct snd_soc_dai_ops cs42l56_ops = {
.hw_params = cs42l56_pcm_hw_params,
.digital_mute = cs42l56_digital_mute,
.set_fmt = cs42l56_set_dai_fmt,
@@ -1408,7 +1360,6 @@ MODULE_DEVICE_TABLE(i2c, cs42l56_id);
static struct i2c_driver cs42l56_i2c_driver = {
.driver = {
.name = "cs42l56",
- .owner = THIS_MODULE,
.of_match_table = cs42l56_of_match,
},
.id_table = cs42l56_id,
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index b7853b9..42a8fd4 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -153,111 +153,18 @@ static bool cs42l73_volatile_register(struct device *dev, unsigned int reg)
static bool cs42l73_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
- case CS42L73_DEVID_AB:
- case CS42L73_DEVID_CD:
- case CS42L73_DEVID_E:
- case CS42L73_REVID:
- case CS42L73_PWRCTL1:
- case CS42L73_PWRCTL2:
- case CS42L73_PWRCTL3:
- case CS42L73_CPFCHC:
- case CS42L73_OLMBMSDC:
- case CS42L73_DMMCC:
- case CS42L73_XSPC:
- case CS42L73_XSPMMCC:
- case CS42L73_ASPC:
- case CS42L73_ASPMMCC:
- case CS42L73_VSPC:
- case CS42L73_VSPMMCC:
- case CS42L73_VXSPFS:
- case CS42L73_MIOPC:
- case CS42L73_ADCIPC:
- case CS42L73_MICAPREPGAAVOL:
- case CS42L73_MICBPREPGABVOL:
- case CS42L73_IPADVOL:
- case CS42L73_IPBDVOL:
- case CS42L73_PBDC:
- case CS42L73_HLADVOL:
- case CS42L73_HLBDVOL:
- case CS42L73_SPKDVOL:
- case CS42L73_ESLDVOL:
- case CS42L73_HPAAVOL:
- case CS42L73_HPBAVOL:
- case CS42L73_LOAAVOL:
- case CS42L73_LOBAVOL:
- case CS42L73_STRINV:
- case CS42L73_XSPINV:
- case CS42L73_ASPINV:
- case CS42L73_VSPINV:
- case CS42L73_LIMARATEHL:
- case CS42L73_LIMRRATEHL:
- case CS42L73_LMAXHL:
- case CS42L73_LIMARATESPK:
- case CS42L73_LIMRRATESPK:
- case CS42L73_LMAXSPK:
- case CS42L73_LIMARATEESL:
- case CS42L73_LIMRRATEESL:
- case CS42L73_LMAXESL:
- case CS42L73_ALCARATE:
- case CS42L73_ALCRRATE:
- case CS42L73_ALCMINMAX:
- case CS42L73_NGCAB:
- case CS42L73_ALCNGMC:
- case CS42L73_MIXERCTL:
- case CS42L73_HLAIPAA:
- case CS42L73_HLBIPBA:
- case CS42L73_HLAXSPAA:
- case CS42L73_HLBXSPBA:
- case CS42L73_HLAASPAA:
- case CS42L73_HLBASPBA:
- case CS42L73_HLAVSPMA:
- case CS42L73_HLBVSPMA:
- case CS42L73_XSPAIPAA:
- case CS42L73_XSPBIPBA:
- case CS42L73_XSPAXSPAA:
- case CS42L73_XSPBXSPBA:
- case CS42L73_XSPAASPAA:
- case CS42L73_XSPAASPBA:
- case CS42L73_XSPAVSPMA:
- case CS42L73_XSPBVSPMA:
- case CS42L73_ASPAIPAA:
- case CS42L73_ASPBIPBA:
- case CS42L73_ASPAXSPAA:
- case CS42L73_ASPBXSPBA:
- case CS42L73_ASPAASPAA:
- case CS42L73_ASPBASPBA:
- case CS42L73_ASPAVSPMA:
- case CS42L73_ASPBVSPMA:
- case CS42L73_VSPAIPAA:
- case CS42L73_VSPBIPBA:
- case CS42L73_VSPAXSPAA:
- case CS42L73_VSPBXSPBA:
- case CS42L73_VSPAASPAA:
- case CS42L73_VSPBASPBA:
- case CS42L73_VSPAVSPMA:
- case CS42L73_VSPBVSPMA:
- case CS42L73_MMIXCTL:
- case CS42L73_SPKMIPMA:
- case CS42L73_SPKMXSPA:
- case CS42L73_SPKMASPA:
- case CS42L73_SPKMVSPMA:
- case CS42L73_ESLMIPMA:
- case CS42L73_ESLMXSPA:
- case CS42L73_ESLMASPA:
- case CS42L73_ESLMVSPMA:
- case CS42L73_IM1:
- case CS42L73_IM2:
+ case CS42L73_DEVID_AB ... CS42L73_DEVID_E:
+ case CS42L73_REVID ... CS42L73_IM2:
return true;
default:
return false;
}
}
-static const unsigned int hpaloa_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(hpaloa_tlv,
0, 13, TLV_DB_SCALE_ITEM(-7600, 200, 0),
- 14, 75, TLV_DB_SCALE_ITEM(-4900, 100, 0),
-};
+ 14, 75, TLV_DB_SCALE_ITEM(-4900, 100, 0)
+);
static DECLARE_TLV_DB_SCALE(adc_boost_tlv, 0, 2500, 0);
@@ -267,11 +174,10 @@ static DECLARE_TLV_DB_SCALE(ipd_tlv, -9600, 100, 0);
static DECLARE_TLV_DB_SCALE(micpga_tlv, -600, 50, 0);
-static const unsigned int limiter_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(limiter_tlv,
0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
- 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0),
-};
+ 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0)
+);
static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1);
@@ -1236,8 +1142,8 @@ static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate)
struct snd_soc_codec *codec = dai->codec;
int id = dai->id;
- return snd_soc_update_bits(codec, CS42L73_SPC(id),
- 0x7F, tristate << 7);
+ return snd_soc_update_bits(codec, CS42L73_SPC(id), CS42L73_SP_3ST,
+ tristate << 7);
}
static const struct snd_pcm_hw_constraint_list constraints_12_24 = {
@@ -1491,7 +1397,6 @@ MODULE_DEVICE_TABLE(i2c, cs42l73_id);
static struct i2c_driver cs42l73_i2c_driver = {
.driver = {
.name = "cs42l73",
- .owner = THIS_MODULE,
.of_match_table = cs42l73_of_match,
},
.id_table = cs42l73_id,
diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c
index 657dce2..800c1d5 100644
--- a/sound/soc/codecs/cs42xx8-i2c.c
+++ b/sound/soc/codecs/cs42xx8-i2c.c
@@ -20,7 +20,7 @@
static int cs42xx8_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- u32 ret = cs42xx8_probe(&i2c->dev,
+ int ret = cs42xx8_probe(&i2c->dev,
devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config));
if (ret)
return ret;
@@ -49,8 +49,8 @@ MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
static struct i2c_driver cs42xx8_i2c_driver = {
.driver = {
.name = "cs42xx8",
- .owner = THIS_MODULE,
.pm = &cs42xx8_pm,
+ .of_match_table = cs42xx8_of_match,
},
.probe = cs42xx8_i2c_probe,
.remove = cs42xx8_i2c_remove,
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
index e1d4686..d562e1b 100644
--- a/sound/soc/codecs/cs42xx8.c
+++ b/sound/soc/codecs/cs42xx8.c
@@ -425,7 +425,7 @@ const struct cs42xx8_driver_data cs42888_data = {
};
EXPORT_SYMBOL_GPL(cs42888_data);
-static const struct of_device_id cs42xx8_of_match[] = {
+const struct of_device_id cs42xx8_of_match[] = {
{ .compatible = "cirrus,cs42448", .data = &cs42448_data, },
{ .compatible = "cirrus,cs42888", .data = &cs42888_data, },
{ /* sentinel */ }
@@ -435,16 +435,24 @@ EXPORT_SYMBOL_GPL(cs42xx8_of_match);
int cs42xx8_probe(struct device *dev, struct regmap *regmap)
{
- const struct of_device_id *of_id = of_match_device(cs42xx8_of_match, dev);
+ const struct of_device_id *of_id;
struct cs42xx8_priv *cs42xx8;
int ret, val, i;
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ dev_err(dev, "failed to allocate regmap: %d\n", ret);
+ return ret;
+ }
+
cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);
if (cs42xx8 == NULL)
return -ENOMEM;
+ cs42xx8->regmap = regmap;
dev_set_drvdata(dev, cs42xx8);
+ of_id = of_match_device(cs42xx8_of_match, dev);
if (of_id)
cs42xx8->drvdata = of_id->data;
@@ -482,13 +490,6 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap)
/* Make sure hardware reset done */
msleep(5);
- cs42xx8->regmap = regmap;
- if (IS_ERR(cs42xx8->regmap)) {
- ret = PTR_ERR(cs42xx8->regmap);
- dev_err(dev, "failed to allocate regmap: %d\n", ret);
- goto err_enable;
- }
-
/*
* We haven't marked the chip revision as volatile due to
* sharing a register with the right input volume; explicitly
diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h
index b2c10e5..d36c61b 100644
--- a/sound/soc/codecs/cs42xx8.h
+++ b/sound/soc/codecs/cs42xx8.h
@@ -22,6 +22,7 @@ extern const struct dev_pm_ops cs42xx8_pm;
extern const struct cs42xx8_driver_data cs42448_data;
extern const struct cs42xx8_driver_data cs42888_data;
extern const struct regmap_config cs42xx8_regmap_config;
+extern const struct of_device_id cs42xx8_of_match[];
int cs42xx8_probe(struct device *dev, struct regmap *regmap);
/* CS42888 register map */
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
new file mode 100644
index 0000000..0ac8fc5
--- /dev/null
+++ b/sound/soc/codecs/cs4349.c
@@ -0,0 +1,392 @@
+/*
+ * cs4349.c -- CS4349 ALSA Soc Audio driver
+ *
+ * Copyright 2015 Cirrus Logic, Inc.
+ *
+ * Authors: Tim Howe <Tim.Howe@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include "cs4349.h"
+
+
+static const struct reg_default cs4349_reg_defaults[] = {
+ { 2, 0x00 }, /* r02 - Mode Control */
+ { 3, 0x09 }, /* r03 - Volume, Mixing and Inversion Control */
+ { 4, 0x81 }, /* r04 - Mute Control */
+ { 5, 0x00 }, /* r05 - Channel A Volume Control */
+ { 6, 0x00 }, /* r06 - Channel B Volume Control */
+ { 7, 0xB1 }, /* r07 - Ramp and Filter Control */
+ { 8, 0x1C }, /* r08 - Misc. Control */
+};
+
+/* Private data for the CS4349 */
+struct cs4349_private {
+ struct regmap *regmap;
+ struct gpio_desc *reset_gpio;
+ unsigned int mode;
+ int rate;
+};
+
+static bool cs4349_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS4349_CHIPID ... CS4349_MISC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs4349_writeable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS4349_MODE ... CS4349_MISC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int cs4349_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int format)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs4349_private *cs4349 = snd_soc_codec_get_drvdata(codec);
+ unsigned int fmt;
+
+ fmt = format & SND_SOC_DAIFMT_FORMAT_MASK;
+
+ switch (fmt) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ cs4349->mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cs4349_private *cs4349 = snd_soc_codec_get_drvdata(codec);
+ int fmt, ret;
+
+ cs4349->rate = params_rate(params);
+
+ switch (cs4349->mode) {
+ case SND_SOC_DAIFMT_I2S:
+ fmt = DIF_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ fmt = DIF_LEFT_JST;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ switch (params_width(params)) {
+ case 16:
+ fmt = DIF_RGHT_JST16;
+ break;
+ case 24:
+ fmt = DIF_RGHT_JST24;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_update_bits(codec, CS4349_MODE, DIF_MASK,
+ MODE_FORMAT(fmt));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cs4349_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int reg;
+
+ reg = 0;
+ if (mute)
+ reg = MUTE_AB_MASK;
+
+ return snd_soc_update_bits(codec, CS4349_MUTE, MUTE_AB_MASK, reg);
+}
+
+static DECLARE_TLV_DB_SCALE(dig_tlv, -12750, 50, 0);
+
+static const char * const chan_mix_texts[] = {
+ "Mute", "MuteA", "MuteA SwapB", "MuteA MonoB", "SwapA MuteB",
+ "BothR", "Swap", "SwapA MonoB", "MuteB", "Normal", "BothL",
+ "MonoB", "MonoA MuteB", "MonoA", "MonoA SwapB", "Mono",
+ /*Normal == Channel A = Left, Channel B = Right*/
+};
+
+static const char * const fm_texts[] = {
+ "Auto", "Single", "Double", "Quad",
+};
+
+static const char * const deemph_texts[] = {
+ "None", "44.1k", "48k", "32k",
+};
+
+static const char * const softr_zeroc_texts[] = {
+ "Immediate", "Zero Cross", "Soft Ramp", "SR on ZC",
+};
+
+static int deemph_values[] = {
+ 0, 4, 8, 12,
+};
+
+static int softr_zeroc_values[] = {
+ 0, 64, 128, 192,
+};
+
+static const struct soc_enum chan_mix_enum =
+ SOC_ENUM_SINGLE(CS4349_VMI, 0,
+ ARRAY_SIZE(chan_mix_texts),
+ chan_mix_texts);
+
+static const struct soc_enum fm_mode_enum =
+ SOC_ENUM_SINGLE(CS4349_MODE, 0,
+ ARRAY_SIZE(fm_texts),
+ fm_texts);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(deemph_enum, CS4349_MODE, 0, DEM_MASK,
+ deemph_texts, deemph_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(softr_zeroc_enum, CS4349_RMPFLT, 0,
+ SR_ZC_MASK, softr_zeroc_texts,
+ softr_zeroc_values);
+
+static const struct snd_kcontrol_new cs4349_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("Master Playback Volume",
+ CS4349_VOLA, CS4349_VOLB, 0, 0xFF, 1, dig_tlv),
+ SOC_ENUM("Functional Mode", fm_mode_enum),
+ SOC_ENUM("De-Emphasis Control", deemph_enum),
+ SOC_ENUM("Soft Ramp Zero Cross Control", softr_zeroc_enum),
+ SOC_ENUM("Channel Mixer", chan_mix_enum),
+ SOC_SINGLE("VolA = VolB Switch", CS4349_VMI, 7, 1, 0),
+ SOC_SINGLE("InvertA Switch", CS4349_VMI, 6, 1, 0),
+ SOC_SINGLE("InvertB Switch", CS4349_VMI, 5, 1, 0),
+ SOC_SINGLE("Auto-Mute Switch", CS4349_MUTE, 7, 1, 0),
+ SOC_SINGLE("MUTEC A = B Switch", CS4349_MUTE, 5, 1, 0),
+ SOC_SINGLE("Soft Ramp Up Switch", CS4349_RMPFLT, 5, 1, 0),
+ SOC_SINGLE("Soft Ramp Down Switch", CS4349_RMPFLT, 4, 1, 0),
+ SOC_SINGLE("Slow Roll Off Filter Switch", CS4349_RMPFLT, 2, 1, 0),
+ SOC_SINGLE("Freeze Switch", CS4349_MISC, 5, 1, 0),
+ SOC_SINGLE("Popguard Switch", CS4349_MISC, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget cs4349_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("HiFi DAC", NULL, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_OUTPUT("OutputA"),
+ SND_SOC_DAPM_OUTPUT("OutputB"),
+};
+
+static const struct snd_soc_dapm_route cs4349_routes[] = {
+ {"DAC Playback", NULL, "OutputA"},
+ {"DAC Playback", NULL, "OutputB"},
+
+ {"OutputA", NULL, "HiFi DAC"},
+ {"OutputB", NULL, "HiFi DAC"},
+};
+
+#define CS4349_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
+ SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define CS4349_PCM_RATES SNDRV_PCM_RATE_8000_192000
+
+static const struct snd_soc_dai_ops cs4349_dai_ops = {
+ .hw_params = cs4349_pcm_hw_params,
+ .set_fmt = cs4349_set_dai_fmt,
+ .digital_mute = cs4349_digital_mute,
+};
+
+static struct snd_soc_dai_driver cs4349_dai = {
+ .name = "cs4349_hifi",
+ .playback = {
+ .stream_name = "DAC Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = CS4349_PCM_RATES,
+ .formats = CS4349_PCM_FORMATS,
+ },
+ .ops = &cs4349_dai_ops,
+ .symmetric_rates = 1,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_cs4349 = {
+ .controls = cs4349_snd_controls,
+ .num_controls = ARRAY_SIZE(cs4349_snd_controls),
+
+ .dapm_widgets = cs4349_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs4349_dapm_widgets),
+ .dapm_routes = cs4349_routes,
+ .num_dapm_routes = ARRAY_SIZE(cs4349_routes),
+};
+
+static const struct regmap_config cs4349_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = CS4349_MISC,
+ .reg_defaults = cs4349_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(cs4349_reg_defaults),
+ .readable_reg = cs4349_readable_register,
+ .writeable_reg = cs4349_writeable_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int cs4349_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct cs4349_private *cs4349;
+ int ret;
+
+ cs4349 = devm_kzalloc(&client->dev, sizeof(*cs4349), GFP_KERNEL);
+ if (!cs4349)
+ return -ENOMEM;
+
+ cs4349->regmap = devm_regmap_init_i2c(client, &cs4349_regmap);
+ if (IS_ERR(cs4349->regmap)) {
+ ret = PTR_ERR(cs4349->regmap);
+ dev_err(&client->dev, "regmap_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Reset the Device */
+ cs4349->reset_gpio = devm_gpiod_get_optional(&client->dev,
+ "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(cs4349->reset_gpio))
+ return PTR_ERR(cs4349->reset_gpio);
+
+ gpiod_set_value_cansleep(cs4349->reset_gpio, 1);
+
+ i2c_set_clientdata(client, cs4349);
+
+ return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4349,
+ &cs4349_dai, 1);
+}
+
+static int cs4349_i2c_remove(struct i2c_client *client)
+{
+ struct cs4349_private *cs4349 = i2c_get_clientdata(client);
+
+ snd_soc_unregister_codec(&client->dev);
+
+ /* Hold down reset */
+ gpiod_set_value_cansleep(cs4349->reset_gpio, 0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int cs4349_runtime_suspend(struct device *dev)
+{
+ struct cs4349_private *cs4349 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, PWR_DWN);
+ if (ret < 0)
+ return ret;
+
+ regcache_cache_only(cs4349->regmap, true);
+
+ /* Hold down reset */
+ gpiod_set_value_cansleep(cs4349->reset_gpio, 0);
+
+ return 0;
+}
+
+static int cs4349_runtime_resume(struct device *dev)
+{
+ struct cs4349_private *cs4349 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, 0);
+ if (ret < 0)
+ return ret;
+
+ gpiod_set_value_cansleep(cs4349->reset_gpio, 1);
+
+ regcache_cache_only(cs4349->regmap, false);
+ regcache_sync(cs4349->regmap);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops cs4349_runtime_pm = {
+ SET_RUNTIME_PM_OPS(cs4349_runtime_suspend, cs4349_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id cs4349_of_match[] = {
+ { .compatible = "cirrus,cs4349", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, cs4349_of_match);
+
+static const struct i2c_device_id cs4349_i2c_id[] = {
+ {"cs4349", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs4349_i2c_id);
+
+static struct i2c_driver cs4349_i2c_driver = {
+ .driver = {
+ .name = "cs4349",
+ .of_match_table = cs4349_of_match,
+ },
+ .id_table = cs4349_i2c_id,
+ .probe = cs4349_i2c_probe,
+ .remove = cs4349_i2c_remove,
+};
+
+module_i2c_driver(cs4349_i2c_driver);
+
+MODULE_AUTHOR("Tim Howe <tim.howe@cirrus.com>");
+MODULE_DESCRIPTION("Cirrus Logic CS4349 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4349.h b/sound/soc/codecs/cs4349.h
new file mode 100644
index 0000000..d58c06a
--- /dev/null
+++ b/sound/soc/codecs/cs4349.h
@@ -0,0 +1,136 @@
+/*
+ * ALSA SoC CS4349 codec driver
+ *
+ * Copyright 2015 Cirrus Logic, Inc.
+ *
+ * Author: Tim Howe <Tim.Howe@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#ifndef __CS4349_H__
+#define __CS4349_H__
+
+/* CS4349 registers addresses */
+#define CS4349_CHIPID 0x01 /* Device and Rev ID, Read Only */
+#define CS4349_MODE 0x02 /* Mode Control */
+#define CS4349_VMI 0x03 /* Volume, Mixing, Inversion Control */
+#define CS4349_MUTE 0x04 /* Mute Control */
+#define CS4349_VOLA 0x05 /* DAC Channel A Volume Control */
+#define CS4349_VOLB 0x06 /* DAC Channel B Volume Control */
+#define CS4349_RMPFLT 0x07 /* Ramp and Filter Control */
+#define CS4349_MISC 0x08 /* Power Down,Freeze Control,Pop Stop*/
+
+#define CS4349_I2C_INCR 0x80
+
+
+/* Device and Revision ID */
+#define CS4349_REVA 0xF0 /* Rev A */
+#define CS4349_REVB 0xF1 /* Rev B */
+#define CS4349_REVC2 0xFF /* Rev C2 */
+
+
+/* PDN_DONE Poll Maximum
+ * If soft ramp is set it will take much longer to power down
+ * the system.
+ */
+#define PDN_POLL_MAX 900
+
+
+/* Bitfield Definitions */
+
+/* CS4349_MODE */
+/* (Digital Interface Format, De-Emphasis Control, Functional Mode */
+#define DIF2 (1 << 6)
+#define DIF1 (1 << 5)
+#define DIF0 (1 << 4)
+#define DEM1 (1 << 3)
+#define DEM0 (1 << 2)
+#define FM1 (1 << 1)
+#define DIF_LEFT_JST 0x00
+#define DIF_I2S 0x01
+#define DIF_RGHT_JST16 0x02
+#define DIF_RGHT_JST24 0x03
+#define DIF_TDM0 0x04
+#define DIF_TDM1 0x05
+#define DIF_TDM2 0x06
+#define DIF_TDM3 0x07
+#define DIF_MASK 0x70
+#define MODE_FORMAT(x) (((x)&7)<<4)
+#define DEM_MASK 0x0C
+#define NO_DEM 0x00
+#define DEM_441 0x04
+#define DEM_48K 0x08
+#define DEM_32K 0x0C
+#define FM_AUTO 0x00
+#define FM_SNGL 0x01
+#define FM_DBL 0x02
+#define FM_QUAD 0x03
+#define FM_SNGL_MIN 30000
+#define FM_SNGL_MAX 54000
+#define FM_DBL_MAX 108000
+#define FM_QUAD_MAX 216000
+#define FM_MASK 0x03
+
+/* CS4349_VMI (VMI = Volume, Mixing and Inversion Controls) */
+#define VOLBISA (1 << 7)
+#define VOLAISB (1 << 7)
+/* INVERT_A only available for Left Jstfd, Right Jstfd16 and Right Jstfd24 */
+#define INVERT_A (1 << 6)
+/* INVERT_B only available for Left Jstfd, Right Jstfd16 and Right Jstfd24 */
+#define INVERT_B (1 << 5)
+#define ATAPI3 (1 << 3)
+#define ATAPI2 (1 << 2)
+#define ATAPI1 (1 << 1)
+#define ATAPI0 (1 << 0)
+#define MUTEAB 0x00
+#define MUTEA_RIGHTB 0x01
+#define MUTEA_LEFTB 0x02
+#define MUTEA_SUMLRDIV2B 0x03
+#define RIGHTA_MUTEB 0x04
+#define RIGHTA_RIGHTB 0x05
+#define RIGHTA_LEFTB 0x06
+#define RIGHTA_SUMLRDIV2B 0x07
+#define LEFTA_MUTEB 0x08
+#define LEFTA_RIGHTB 0x09 /* Default */
+#define LEFTA_LEFTB 0x0A
+#define LEFTA_SUMLRDIV2B 0x0B
+#define SUMLRDIV2A_MUTEB 0x0C
+#define SUMLRDIV2A_RIGHTB 0x0D
+#define SUMLRDIV2A_LEFTB 0x0E
+#define SUMLRDIV2_AB 0x0F
+#define CHMIX_MASK 0x0F
+
+/* CS4349_MUTE */
+#define AUTOMUTE (1 << 7)
+#define MUTEC_AB (1 << 5)
+#define MUTE_A (1 << 4)
+#define MUTE_B (1 << 3)
+#define MUTE_AB_MASK 0x18
+
+/* CS4349_RMPFLT (Ramp and Filter Control) */
+#define SCZ1 (1 << 7)
+#define SCZ0 (1 << 6)
+#define RMP_UP (1 << 5)
+#define RMP_DN (1 << 4)
+#define FILT_SEL (1 << 2)
+#define IMMDT_CHNG 0x31
+#define ZEROCRSS 0x71
+#define SOFT_RMP 0xB1
+#define SFTRMP_ZEROCRSS 0xF1
+#define SR_ZC_MASK 0xC0
+
+/* CS4349_MISC */
+#define PWR_DWN (1 << 7)
+#define FREEZE (1 << 5)
+#define POPG_EN (1 << 4)
+
+#endif /* __CS4349_H__ */
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 21810e5..7dc52fe 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -267,33 +267,29 @@ enum clk_src {
*
* Reserved area are considered as "mute".
*/
-static const unsigned int hp_out_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(hp_out_tlv,
0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
/* -54 dB to +15 dB */
- 0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0),
-};
+ 0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0)
+);
-static const unsigned int lineout_vol_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(lineout_vol_tlv,
0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
/* -54dB to 15dB */
0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0)
-};
+);
-static const unsigned int mono_vol_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(mono_vol_tlv,
0x0, 0x2, TLV_DB_SCALE_ITEM(-1800, 0, 1),
/* -18dB to 6dB */
0x3, 0x7, TLV_DB_SCALE_ITEM(-1800, 600, 0)
-};
+);
-static const unsigned int aux1_vol_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(aux1_vol_tlv,
0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
/* -48dB to 21dB */
0x11, 0x3f, TLV_DB_SCALE_ITEM(-4800, 150, 0)
-};
+);
static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0);
static const DECLARE_TLV_DB_SCALE(adc_eq_master_gain_tlv, -1800, 600, 1);
@@ -680,7 +676,7 @@ struct da7210_priv {
int master;
};
-static struct reg_default da7210_reg_defaults[] = {
+static const struct reg_default da7210_reg_defaults[] = {
{ 0x00, 0x00 },
{ 0x01, 0x11 },
{ 0x03, 0x00 },
@@ -1182,7 +1178,7 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
#if IS_ENABLED(CONFIG_I2C)
-static struct reg_default da7210_regmap_i2c_patch[] = {
+static const struct reg_sequence da7210_regmap_i2c_patch[] = {
/* System controller master disable */
{ DA7210_STARTUP1, 0x00 },
@@ -1259,7 +1255,6 @@ MODULE_DEVICE_TABLE(i2c, da7210_i2c_id);
static struct i2c_driver da7210_i2c_driver = {
.driver = {
.name = "da7210",
- .owner = THIS_MODULE,
},
.probe = da7210_i2c_probe,
.remove = da7210_i2c_remove,
@@ -1269,7 +1264,7 @@ static struct i2c_driver da7210_i2c_driver = {
#if defined(CONFIG_SPI_MASTER)
-static struct reg_default da7210_regmap_spi_patch[] = {
+static const struct reg_sequence da7210_regmap_spi_patch[] = {
/* Dummy read to give two pulses over nCS for SPI */
{ DA7210_AUX2, 0x00 },
{ DA7210_AUX2, 0x00 },
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 238e48a..a9c86ef 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -28,27 +28,24 @@
/* Gain and Volume */
-static const unsigned int aux_vol_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(aux_vol_tlv,
/* -54dB */
0x0, 0x11, TLV_DB_SCALE_ITEM(-5400, 0, 0),
/* -52.5dB to 15dB */
0x12, 0x3f, TLV_DB_SCALE_ITEM(-5250, 150, 0)
-};
+);
-static const unsigned int digital_gain_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(digital_gain_tlv,
0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
/* -78dB to 12dB */
0x08, 0x7f, TLV_DB_SCALE_ITEM(-7800, 75, 0)
-};
+);
-static const unsigned int alc_analog_gain_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(alc_analog_gain_tlv,
0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
/* 0dB to 36dB */
0x01, 0x07, TLV_DB_SCALE_ITEM(0, 600, 0)
-};
+);
static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0);
static const DECLARE_TLV_DB_SCALE(mixin_gain_tlv, -450, 150, 0);
@@ -954,7 +951,7 @@ static const struct snd_soc_dapm_route da7213_audio_map[] = {
{"LINE", NULL, "Lineout PGA"},
};
-static struct reg_default da7213_reg_defaults[] = {
+static const struct reg_default da7213_reg_defaults[] = {
{ DA7213_DIG_ROUTING_DAI, 0x10 },
{ DA7213_SR, 0x0A },
{ DA7213_REFERENCES, 0x80 },
@@ -1585,7 +1582,6 @@ MODULE_DEVICE_TABLE(i2c, da7213_i2c_id);
static struct i2c_driver da7213_i2c_driver = {
.driver = {
.name = "da7213",
- .owner = THIS_MODULE,
},
.probe = da7213_i2c_probe,
.remove = da7213_remove,
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index 2075236..1d5a89c 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -43,7 +43,7 @@ struct da732x_priv {
/*
* da732x register cache - default settings
*/
-static struct reg_default da732x_reg_cache[] = {
+static const struct reg_default da732x_reg_cache[] = {
{ DA732X_REG_REF1 , 0x02 },
{ DA732X_REG_BIAS_EN , 0x80 },
{ DA732X_REG_BIAS1 , 0x00 },
@@ -1196,13 +1196,7 @@ static int da732x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
#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 = {
+static const struct snd_soc_dai_ops da732x_dai_ops = {
.hw_params = da732x_hw_params,
.set_fmt = da732x_set_dai_fmt,
.set_sysclk = da732x_set_dai_sysclk,
@@ -1227,7 +1221,7 @@ static struct snd_soc_dai_driver da732x_dai[] = {
.rates = DA732X_RATES,
.formats = DA732X_FORMATS,
},
- .ops = &da732x_dai1_ops,
+ .ops = &da732x_dai_ops,
},
{
.name = "DA732X_AIFB",
@@ -1247,7 +1241,7 @@ static struct snd_soc_dai_driver da732x_dai[] = {
.rates = DA732X_RATES,
.formats = DA732X_FORMATS,
},
- .ops = &da732x_dai2_ops,
+ .ops = &da732x_dai_ops,
},
};
@@ -1572,7 +1566,6 @@ 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 = da732x_i2c_remove,
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index 66bb446..0b2ede8 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -289,26 +289,23 @@ enum clk_src {
/* Gain and Volume */
-static const unsigned int aux_vol_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(aux_vol_tlv,
0x0, 0x10, TLV_DB_SCALE_ITEM(-5400, 0, 0),
/* -54dB to 15dB */
0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0)
-};
+);
-static const unsigned int digital_gain_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(digital_gain_tlv,
0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
/* -78dB to 12dB */
0x08, 0x7f, TLV_DB_SCALE_ITEM(-7800, 75, 0)
-};
+);
-static const unsigned int alc_analog_gain_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(alc_analog_gain_tlv,
0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
/* 0dB to 36dB */
0x01, 0x07, TLV_DB_SCALE_ITEM(0, 600, 0)
-};
+);
static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0);
static const DECLARE_TLV_DB_SCALE(mixin_gain_tlv, -450, 150, 0);
@@ -948,7 +945,7 @@ struct da9055_priv {
struct da9055_platform_data *pdata;
};
-static struct reg_default da9055_reg_defaults[] = {
+static const struct reg_default da9055_reg_defaults[] = {
{ 0x21, 0x10 },
{ 0x22, 0x0A },
{ 0x23, 0x00 },
@@ -1533,12 +1530,12 @@ static const struct of_device_id da9055_of_match[] = {
{ .compatible = "dlg,da9055-codec", },
{ }
};
+MODULE_DEVICE_TABLE(of, da9055_of_match);
/* I2C codec control layer */
static struct i2c_driver da9055_i2c_driver = {
.driver = {
.name = "da9055-codec",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(da9055_of_match),
},
.probe = da9055_i2c_probe,
diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c
new file mode 100644
index 0000000..0b80052
--- /dev/null
+++ b/sound/soc/codecs/gtm601.c
@@ -0,0 +1,95 @@
+/*
+ * This is a simple driver for the GTM601 Voice PCM interface
+ *
+ * Copyright (C) 2015 Goldelico GmbH
+ *
+ * Author: Marek Belisko <marek@goldelico.com>
+ *
+ * Based on wm8727.c driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+static const struct snd_soc_dapm_widget gtm601_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("AOUT"),
+ SND_SOC_DAPM_INPUT("AIN"),
+};
+
+static const struct snd_soc_dapm_route gtm601_dapm_routes[] = {
+ { "AOUT", NULL, "Playback" },
+ { "Capture", NULL, "AIN" },
+};
+
+static struct snd_soc_dai_driver gtm601_dai = {
+ .name = "gtm601",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+};
+
+static const struct snd_soc_codec_driver soc_codec_dev_gtm601 = {
+ .dapm_widgets = gtm601_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(gtm601_dapm_widgets),
+ .dapm_routes = gtm601_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(gtm601_dapm_routes),
+};
+
+static int gtm601_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_gtm601, &gtm601_dai, 1);
+}
+
+static int gtm601_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id gtm601_codec_of_match[] = {
+ { .compatible = "option,gtm601", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, gtm601_codec_of_match);
+#endif
+
+static struct platform_driver gtm601_codec_driver = {
+ .driver = {
+ .name = "gtm601",
+ .of_match_table = of_match_ptr(gtm601_codec_of_match),
+ },
+ .probe = gtm601_platform_probe,
+ .remove = gtm601_platform_remove,
+};
+
+module_platform_driver(gtm601_codec_driver);
+
+MODULE_DESCRIPTION("ASoC gtm601 driver");
+MODULE_AUTHOR("Marek Belisko <marek@goldelico.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gtm601");
diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c
new file mode 100644
index 0000000..dd850b9
--- /dev/null
+++ b/sound/soc/codecs/ics43432.c
@@ -0,0 +1,76 @@
+/*
+ * I2S MEMS microphone driver for InvenSense ICS-43432
+ *
+ * - Non configurable.
+ * - I2S interface, 64 BCLs per frame, 32 bits per channel, 24 bit data
+ *
+ * Copyright (c) 2015 Axis Communications AB
+ *
+ * Licensed under GPL v2.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#define ICS43432_RATE_MIN 7190 /* Hz, from data sheet */
+#define ICS43432_RATE_MAX 52800 /* Hz, from data sheet */
+
+#define ICS43432_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32)
+
+static struct snd_soc_dai_driver ics43432_dai = {
+ .name = "ics43432-hifi",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = ICS43432_RATE_MIN,
+ .rate_max = ICS43432_RATE_MAX,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .formats = ICS43432_FORMATS,
+ },
+};
+
+static struct snd_soc_codec_driver ics43432_codec_driver = {
+};
+
+static int ics43432_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &ics43432_codec_driver,
+ &ics43432_dai, 1);
+}
+
+static int ics43432_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id ics43432_ids[] = {
+ { .compatible = "invensense,ics43432", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ics43432_ids);
+#endif
+
+static struct platform_driver ics43432_driver = {
+ .driver = {
+ .name = "ics43432",
+ .of_match_table = of_match_ptr(ics43432_ids),
+ },
+ .probe = ics43432_probe,
+ .remove = ics43432_remove,
+};
+
+module_platform_driver(ics43432_driver);
+
+MODULE_DESCRIPTION("ASoC ICS43432 driver");
+MODULE_AUTHOR("Ricard Wanderlof <ricardw@axis.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index ebd9028..be44837 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -33,7 +33,7 @@
/* Register default values for ISABELLE driver. */
-static struct reg_default isabelle_reg_defs[] = {
+static const struct reg_default isabelle_reg_defs[] = {
{ 0, 0x00 },
{ 1, 0x00 },
{ 2, 0x00 },
@@ -1016,25 +1016,25 @@ static int isabelle_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
#define ISABELLE_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S32_LE)
-static struct snd_soc_dai_ops isabelle_hs_dai_ops = {
+static const 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 = {
+static const 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 = {
+static const 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 = {
+static const struct snd_soc_dai_ops isabelle_ul_dai_ops = {
.hw_params = isabelle_hw_params,
.set_fmt = isabelle_set_dai_fmt,
};
@@ -1149,7 +1149,6 @@ 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 = isabelle_i2c_remove,
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 9363fdb..1f5ab99 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -78,11 +78,10 @@ struct jz4740_codec {
struct regmap *regmap;
};
-static const unsigned int jz4740_mic_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(jz4740_mic_tlv,
0, 2, TLV_DB_SCALE_ITEM(0, 600, 0),
- 3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0),
-};
+ 3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0)
+);
static const DECLARE_TLV_DB_SCALE(jz4740_out_tlv, 0, 200, 0);
static const DECLARE_TLV_DB_SCALE(jz4740_in_tlv, -3450, 150, 0);
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
index 99ffc49..558de10 100644
--- a/sound/soc/codecs/lm4857.c
+++ b/sound/soc/codecs/lm4857.c
@@ -142,7 +142,6 @@ MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id);
static struct i2c_driver lm4857_i2c_driver = {
.driver = {
.name = "lm4857",
- .owner = THIS_MODULE,
},
.probe = lm4857_i2c_probe,
.id_table = lm4857_i2c_id,
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index 6600aa0..9af5640 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -30,7 +30,7 @@
#include <asm/div64.h>
#include "lm49453.h"
-static struct reg_default lm49453_reg_defs[] = {
+static const struct reg_default lm49453_reg_defs[] = {
{ 0, 0x00 },
{ 1, 0x00 },
{ 2, 0x00 },
@@ -188,7 +188,6 @@ static struct reg_default lm49453_reg_defs[] = {
/* codec private data */
struct lm49453_priv {
struct regmap *regmap;
- int fs_rate;
};
/* capture path controls */
@@ -1112,13 +1111,10 @@ static int lm49453_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
- struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
u16 clk_div = 0;
- lm49453->fs_rate = params_rate(params);
-
/* Setting DAC clock dividers based on substream sample rate. */
- switch (lm49453->fs_rate) {
+ switch (params_rate(params)) {
case 8000:
case 16000:
case 32000:
@@ -1291,35 +1287,35 @@ static int lm49453_set_bias_level(struct snd_soc_codec *codec,
#define LM49453_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
-static struct snd_soc_dai_ops lm49453_headset_dai_ops = {
+static const struct snd_soc_dai_ops lm49453_headset_dai_ops = {
.hw_params = lm49453_hw_params,
.set_sysclk = lm49453_set_dai_sysclk,
.set_fmt = lm49453_set_dai_fmt,
.digital_mute = lm49453_hp_mute,
};
-static struct snd_soc_dai_ops lm49453_speaker_dai_ops = {
+static const struct snd_soc_dai_ops lm49453_speaker_dai_ops = {
.hw_params = lm49453_hw_params,
.set_sysclk = lm49453_set_dai_sysclk,
.set_fmt = lm49453_set_dai_fmt,
.digital_mute = lm49453_ls_mute,
};
-static struct snd_soc_dai_ops lm49453_haptic_dai_ops = {
+static const struct snd_soc_dai_ops lm49453_haptic_dai_ops = {
.hw_params = lm49453_hw_params,
.set_sysclk = lm49453_set_dai_sysclk,
.set_fmt = lm49453_set_dai_fmt,
.digital_mute = lm49453_ha_mute,
};
-static struct snd_soc_dai_ops lm49453_ep_dai_ops = {
+static const struct snd_soc_dai_ops lm49453_ep_dai_ops = {
.hw_params = lm49453_hw_params,
.set_sysclk = lm49453_set_dai_sysclk,
.set_fmt = lm49453_set_dai_fmt,
.digital_mute = lm49453_ep_mute,
};
-static struct snd_soc_dai_ops lm49453_lineout_dai_ops = {
+static const struct snd_soc_dai_ops lm49453_lineout_dai_ops = {
.hw_params = lm49453_hw_params,
.set_sysclk = lm49453_set_dai_sysclk,
.set_fmt = lm49453_set_dai_fmt,
@@ -1460,7 +1456,6 @@ MODULE_DEVICE_TABLE(i2c, lm49453_i2c_id);
static struct i2c_driver lm49453_i2c_driver = {
.driver = {
.name = "lm49453",
- .owner = THIS_MODULE,
},
.probe = lm49453_i2c_probe,
.remove = lm49453_i2c_remove,
diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c
index e1c196a..5b82e26 100644
--- a/sound/soc/codecs/max9768.c
+++ b/sound/soc/codecs/max9768.c
@@ -35,7 +35,7 @@ struct max9768 {
u32 flags;
};
-static struct reg_default max9768_default_regs[] = {
+static const struct reg_default max9768_default_regs[] = {
{ 0, 0 },
{ 3, MAX9768_CTRL_FILTERLESS},
};
@@ -43,8 +43,8 @@ static struct reg_default max9768_default_regs[] = {
static int max9768_get_gpio(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct max9768 *max9768 = snd_soc_component_get_drvdata(c);
int val = gpio_get_value_cansleep(max9768->mute_gpio);
ucontrol->value.integer.value[0] = !val;
@@ -55,16 +55,15 @@ static int max9768_get_gpio(struct snd_kcontrol *kcontrol,
static int max9768_set_gpio(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct max9768 *max9768 = snd_soc_component_get_drvdata(c);
gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]);
return 0;
}
-static const unsigned int volume_tlv[] = {
- TLV_DB_RANGE_HEAD(43),
+static const DECLARE_TLV_DB_RANGE(volume_tlv,
0, 0, TLV_DB_SCALE_ITEM(-16150, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(-9280, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(-9030, 0, 0),
@@ -107,8 +106,8 @@ static const unsigned int volume_tlv[] = {
51, 57, TLV_DB_SCALE_ITEM(290, 50, 0),
58, 58, TLV_DB_SCALE_ITEM(650, 0, 0),
59, 62, TLV_DB_SCALE_ITEM(700, 60, 0),
- 63, 63, TLV_DB_SCALE_ITEM(950, 0, 0),
-};
+ 63, 63, TLV_DB_SCALE_ITEM(950, 0, 0)
+);
static const struct snd_kcontrol_new max9768_volume[] = {
SOC_SINGLE_TLV("Playback Volume", MAX9768_VOL, 0, 63, 0, volume_tlv),
@@ -130,19 +129,20 @@ static const struct snd_soc_dapm_route max9768_dapm_routes[] = {
{ "OUT-", NULL, "IN" },
};
-static int max9768_probe(struct snd_soc_codec *codec)
+static int max9768_probe(struct snd_soc_component *component)
{
- struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
+ struct max9768 *max9768 = snd_soc_component_get_drvdata(component);
int ret;
if (max9768->flags & MAX9768_FLAG_CLASSIC_PWM) {
- ret = snd_soc_write(codec, MAX9768_CTRL, MAX9768_CTRL_PWM);
+ ret = regmap_write(max9768->regmap, MAX9768_CTRL,
+ MAX9768_CTRL_PWM);
if (ret)
return ret;
}
if (gpio_is_valid(max9768->mute_gpio)) {
- ret = snd_soc_add_codec_controls(codec, max9768_mute,
+ ret = snd_soc_add_component_controls(component, max9768_mute,
ARRAY_SIZE(max9768_mute));
if (ret)
return ret;
@@ -151,7 +151,7 @@ static int max9768_probe(struct snd_soc_codec *codec)
return 0;
}
-static struct snd_soc_codec_driver max9768_codec_driver = {
+static struct snd_soc_component_driver max9768_component_driver = {
.probe = max9768_probe,
.controls = max9768_volume,
.num_controls = ARRAY_SIZE(max9768_volume),
@@ -183,11 +183,13 @@ static int max9768_i2c_probe(struct i2c_client *client,
if (pdata) {
/* Mute on powerup to avoid clicks */
- err = gpio_request_one(pdata->mute_gpio, GPIOF_INIT_HIGH, "MAX9768 Mute");
+ err = devm_gpio_request_one(&client->dev, pdata->mute_gpio,
+ GPIOF_INIT_HIGH, "MAX9768 Mute");
max9768->mute_gpio = err ?: pdata->mute_gpio;
/* Activate chip by releasing shutdown, enables I2C */
- err = gpio_request_one(pdata->shdn_gpio, GPIOF_INIT_HIGH, "MAX9768 Shutdown");
+ err = devm_gpio_request_one(&client->dev, pdata->shdn_gpio,
+ GPIOF_INIT_HIGH, "MAX9768 Shutdown");
max9768->shdn_gpio = err ?: pdata->shdn_gpio;
max9768->flags = pdata->flags;
@@ -199,38 +201,11 @@ static int max9768_i2c_probe(struct i2c_client *client,
i2c_set_clientdata(client, max9768);
max9768->regmap = devm_regmap_init_i2c(client, &max9768_i2c_regmap_config);
- if (IS_ERR(max9768->regmap)) {
- err = PTR_ERR(max9768->regmap);
- goto err_gpio_free;
- }
+ if (IS_ERR(max9768->regmap))
+ return PTR_ERR(max9768->regmap);
- err = snd_soc_register_codec(&client->dev, &max9768_codec_driver, NULL, 0);
- if (err)
- goto err_gpio_free;
-
- return 0;
-
- err_gpio_free:
- if (gpio_is_valid(max9768->shdn_gpio))
- gpio_free(max9768->shdn_gpio);
- if (gpio_is_valid(max9768->mute_gpio))
- gpio_free(max9768->mute_gpio);
-
- return err;
-}
-
-static int max9768_i2c_remove(struct i2c_client *client)
-{
- struct max9768 *max9768 = i2c_get_clientdata(client);
-
- snd_soc_unregister_codec(&client->dev);
-
- if (gpio_is_valid(max9768->shdn_gpio))
- gpio_free(max9768->shdn_gpio);
- if (gpio_is_valid(max9768->mute_gpio))
- gpio_free(max9768->mute_gpio);
-
- return 0;
+ return devm_snd_soc_register_component(&client->dev,
+ &max9768_component_driver, NULL, 0);
}
static const struct i2c_device_id max9768_i2c_id[] = {
@@ -242,10 +217,8 @@ MODULE_DEVICE_TABLE(i2c, max9768_i2c_id);
static struct i2c_driver max9768_i2c_driver = {
.driver = {
.name = "max9768",
- .owner = THIS_MODULE,
},
.probe = max9768_i2c_probe,
- .remove = max9768_i2c_remove,
.id_table = max9768_i2c_id,
};
module_i2c_driver(max9768_i2c_driver);
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index d0f4534..20dcc49 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -258,292 +258,36 @@ static const struct reg_default max98088_reg[] = {
{ 0xc9, 0x00 }, /* C9 DAI2 biquad */
};
-static struct {
- int readable;
- int writable;
- int vol;
-} max98088_access[M98088_REG_CNT] = {
- { 0xFF, 0xFF, 1 }, /* 00 IRQ status */
- { 0xFF, 0x00, 1 }, /* 01 MIC status */
- { 0xFF, 0x00, 1 }, /* 02 jack status */
- { 0x1F, 0x1F, 1 }, /* 03 battery voltage */
- { 0xFF, 0xFF, 0 }, /* 04 */
- { 0xFF, 0xFF, 0 }, /* 05 */
- { 0xFF, 0xFF, 0 }, /* 06 */
- { 0xFF, 0xFF, 0 }, /* 07 */
- { 0xFF, 0xFF, 0 }, /* 08 */
- { 0xFF, 0xFF, 0 }, /* 09 */
- { 0xFF, 0xFF, 0 }, /* 0A */
- { 0xFF, 0xFF, 0 }, /* 0B */
- { 0xFF, 0xFF, 0 }, /* 0C */
- { 0xFF, 0xFF, 0 }, /* 0D */
- { 0xFF, 0xFF, 0 }, /* 0E */
- { 0xFF, 0xFF, 0 }, /* 0F interrupt enable */
-
- { 0xFF, 0xFF, 0 }, /* 10 master clock */
- { 0xFF, 0xFF, 0 }, /* 11 DAI1 clock mode */
- { 0xFF, 0xFF, 0 }, /* 12 DAI1 clock control */
- { 0xFF, 0xFF, 0 }, /* 13 DAI1 clock control */
- { 0xFF, 0xFF, 0 }, /* 14 DAI1 format */
- { 0xFF, 0xFF, 0 }, /* 15 DAI1 clock */
- { 0xFF, 0xFF, 0 }, /* 16 DAI1 config */
- { 0xFF, 0xFF, 0 }, /* 17 DAI1 TDM */
- { 0xFF, 0xFF, 0 }, /* 18 DAI1 filters */
- { 0xFF, 0xFF, 0 }, /* 19 DAI2 clock mode */
- { 0xFF, 0xFF, 0 }, /* 1A DAI2 clock control */
- { 0xFF, 0xFF, 0 }, /* 1B DAI2 clock control */
- { 0xFF, 0xFF, 0 }, /* 1C DAI2 format */
- { 0xFF, 0xFF, 0 }, /* 1D DAI2 clock */
- { 0xFF, 0xFF, 0 }, /* 1E DAI2 config */
- { 0xFF, 0xFF, 0 }, /* 1F DAI2 TDM */
-
- { 0xFF, 0xFF, 0 }, /* 20 DAI2 filters */
- { 0xFF, 0xFF, 0 }, /* 21 data config */
- { 0xFF, 0xFF, 0 }, /* 22 DAC mixer */
- { 0xFF, 0xFF, 0 }, /* 23 left ADC mixer */
- { 0xFF, 0xFF, 0 }, /* 24 right ADC mixer */
- { 0xFF, 0xFF, 0 }, /* 25 left HP mixer */
- { 0xFF, 0xFF, 0 }, /* 26 right HP mixer */
- { 0xFF, 0xFF, 0 }, /* 27 HP control */
- { 0xFF, 0xFF, 0 }, /* 28 left REC mixer */
- { 0xFF, 0xFF, 0 }, /* 29 right REC mixer */
- { 0xFF, 0xFF, 0 }, /* 2A REC control */
- { 0xFF, 0xFF, 0 }, /* 2B left SPK mixer */
- { 0xFF, 0xFF, 0 }, /* 2C right SPK mixer */
- { 0xFF, 0xFF, 0 }, /* 2D SPK control */
- { 0xFF, 0xFF, 0 }, /* 2E sidetone */
- { 0xFF, 0xFF, 0 }, /* 2F DAI1 playback level */
-
- { 0xFF, 0xFF, 0 }, /* 30 DAI1 playback level */
- { 0xFF, 0xFF, 0 }, /* 31 DAI2 playback level */
- { 0xFF, 0xFF, 0 }, /* 32 DAI2 playbakc level */
- { 0xFF, 0xFF, 0 }, /* 33 left ADC level */
- { 0xFF, 0xFF, 0 }, /* 34 right ADC level */
- { 0xFF, 0xFF, 0 }, /* 35 MIC1 level */
- { 0xFF, 0xFF, 0 }, /* 36 MIC2 level */
- { 0xFF, 0xFF, 0 }, /* 37 INA level */
- { 0xFF, 0xFF, 0 }, /* 38 INB level */
- { 0xFF, 0xFF, 0 }, /* 39 left HP volume */
- { 0xFF, 0xFF, 0 }, /* 3A right HP volume */
- { 0xFF, 0xFF, 0 }, /* 3B left REC volume */
- { 0xFF, 0xFF, 0 }, /* 3C right REC volume */
- { 0xFF, 0xFF, 0 }, /* 3D left SPK volume */
- { 0xFF, 0xFF, 0 }, /* 3E right SPK volume */
- { 0xFF, 0xFF, 0 }, /* 3F MIC config */
-
- { 0xFF, 0xFF, 0 }, /* 40 MIC threshold */
- { 0xFF, 0xFF, 0 }, /* 41 excursion limiter filter */
- { 0xFF, 0xFF, 0 }, /* 42 excursion limiter threshold */
- { 0xFF, 0xFF, 0 }, /* 43 ALC */
- { 0xFF, 0xFF, 0 }, /* 44 power limiter threshold */
- { 0xFF, 0xFF, 0 }, /* 45 power limiter config */
- { 0xFF, 0xFF, 0 }, /* 46 distortion limiter config */
- { 0xFF, 0xFF, 0 }, /* 47 audio input */
- { 0xFF, 0xFF, 0 }, /* 48 microphone */
- { 0xFF, 0xFF, 0 }, /* 49 level control */
- { 0xFF, 0xFF, 0 }, /* 4A bypass switches */
- { 0xFF, 0xFF, 0 }, /* 4B jack detect */
- { 0xFF, 0xFF, 0 }, /* 4C input enable */
- { 0xFF, 0xFF, 0 }, /* 4D output enable */
- { 0xFF, 0xFF, 0 }, /* 4E bias control */
- { 0xFF, 0xFF, 0 }, /* 4F DAC power */
-
- { 0xFF, 0xFF, 0 }, /* 50 DAC power */
- { 0xFF, 0xFF, 0 }, /* 51 system */
- { 0xFF, 0xFF, 0 }, /* 52 DAI1 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 53 DAI1 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 54 DAI1 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 55 DAI1 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 56 DAI1 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 57 DAI1 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 58 DAI1 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 59 DAI1 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 5A DAI1 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 5B DAI1 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 5C DAI1 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 5D DAI1 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 5E DAI1 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 5F DAI1 EQ2 */
-
- { 0xFF, 0xFF, 0 }, /* 60 DAI1 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 61 DAI1 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 62 DAI1 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 63 DAI1 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 64 DAI1 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 65 DAI1 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 66 DAI1 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 67 DAI1 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 68 DAI1 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 69 DAI1 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 6A DAI1 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 6B DAI1 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 6C DAI1 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 6D DAI1 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 6E DAI1 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 6F DAI1 EQ3 */
-
- { 0xFF, 0xFF, 0 }, /* 70 DAI1 EQ4 */
- { 0xFF, 0xFF, 0 }, /* 71 DAI1 EQ4 */
- { 0xFF, 0xFF, 0 }, /* 72 DAI1 EQ4 */
- { 0xFF, 0xFF, 0 }, /* 73 DAI1 EQ4 */
- { 0xFF, 0xFF, 0 }, /* 74 DAI1 EQ4 */
- { 0xFF, 0xFF, 0 }, /* 75 DAI1 EQ4 */
- { 0xFF, 0xFF, 0 }, /* 76 DAI1 EQ4 */
- { 0xFF, 0xFF, 0 }, /* 77 DAI1 EQ4 */
- { 0xFF, 0xFF, 0 }, /* 78 DAI1 EQ4 */
- { 0xFF, 0xFF, 0 }, /* 79 DAI1 EQ4 */
- { 0xFF, 0xFF, 0 }, /* 7A DAI1 EQ5 */
- { 0xFF, 0xFF, 0 }, /* 7B DAI1 EQ5 */
- { 0xFF, 0xFF, 0 }, /* 7C DAI1 EQ5 */
- { 0xFF, 0xFF, 0 }, /* 7D DAI1 EQ5 */
- { 0xFF, 0xFF, 0 }, /* 7E DAI1 EQ5 */
- { 0xFF, 0xFF, 0 }, /* 7F DAI1 EQ5 */
-
- { 0xFF, 0xFF, 0 }, /* 80 DAI1 EQ5 */
- { 0xFF, 0xFF, 0 }, /* 81 DAI1 EQ5 */
- { 0xFF, 0xFF, 0 }, /* 82 DAI1 EQ5 */
- { 0xFF, 0xFF, 0 }, /* 83 DAI1 EQ5 */
- { 0xFF, 0xFF, 0 }, /* 84 DAI2 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 85 DAI2 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 86 DAI2 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 87 DAI2 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 88 DAI2 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 89 DAI2 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 8A DAI2 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 8B DAI2 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 8C DAI2 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 8D DAI2 EQ1 */
- { 0xFF, 0xFF, 0 }, /* 8E DAI2 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 8F DAI2 EQ2 */
-
- { 0xFF, 0xFF, 0 }, /* 90 DAI2 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 91 DAI2 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 92 DAI2 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 93 DAI2 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 94 DAI2 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 95 DAI2 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 96 DAI2 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 97 DAI2 EQ2 */
- { 0xFF, 0xFF, 0 }, /* 98 DAI2 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 99 DAI2 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 9A DAI2 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 9B DAI2 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 9C DAI2 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 9D DAI2 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 9E DAI2 EQ3 */
- { 0xFF, 0xFF, 0 }, /* 9F DAI2 EQ3 */
-
- { 0xFF, 0xFF, 0 }, /* A0 DAI2 EQ3 */
- { 0xFF, 0xFF, 0 }, /* A1 DAI2 EQ3 */
- { 0xFF, 0xFF, 0 }, /* A2 DAI2 EQ4 */
- { 0xFF, 0xFF, 0 }, /* A3 DAI2 EQ4 */
- { 0xFF, 0xFF, 0 }, /* A4 DAI2 EQ4 */
- { 0xFF, 0xFF, 0 }, /* A5 DAI2 EQ4 */
- { 0xFF, 0xFF, 0 }, /* A6 DAI2 EQ4 */
- { 0xFF, 0xFF, 0 }, /* A7 DAI2 EQ4 */
- { 0xFF, 0xFF, 0 }, /* A8 DAI2 EQ4 */
- { 0xFF, 0xFF, 0 }, /* A9 DAI2 EQ4 */
- { 0xFF, 0xFF, 0 }, /* AA DAI2 EQ4 */
- { 0xFF, 0xFF, 0 }, /* AB DAI2 EQ4 */
- { 0xFF, 0xFF, 0 }, /* AC DAI2 EQ5 */
- { 0xFF, 0xFF, 0 }, /* AD DAI2 EQ5 */
- { 0xFF, 0xFF, 0 }, /* AE DAI2 EQ5 */
- { 0xFF, 0xFF, 0 }, /* AF DAI2 EQ5 */
-
- { 0xFF, 0xFF, 0 }, /* B0 DAI2 EQ5 */
- { 0xFF, 0xFF, 0 }, /* B1 DAI2 EQ5 */
- { 0xFF, 0xFF, 0 }, /* B2 DAI2 EQ5 */
- { 0xFF, 0xFF, 0 }, /* B3 DAI2 EQ5 */
- { 0xFF, 0xFF, 0 }, /* B4 DAI2 EQ5 */
- { 0xFF, 0xFF, 0 }, /* B5 DAI2 EQ5 */
- { 0xFF, 0xFF, 0 }, /* B6 DAI1 biquad */
- { 0xFF, 0xFF, 0 }, /* B7 DAI1 biquad */
- { 0xFF, 0xFF, 0 }, /* B8 DAI1 biquad */
- { 0xFF, 0xFF, 0 }, /* B9 DAI1 biquad */
- { 0xFF, 0xFF, 0 }, /* BA DAI1 biquad */
- { 0xFF, 0xFF, 0 }, /* BB DAI1 biquad */
- { 0xFF, 0xFF, 0 }, /* BC DAI1 biquad */
- { 0xFF, 0xFF, 0 }, /* BD DAI1 biquad */
- { 0xFF, 0xFF, 0 }, /* BE DAI1 biquad */
- { 0xFF, 0xFF, 0 }, /* BF DAI1 biquad */
-
- { 0xFF, 0xFF, 0 }, /* C0 DAI2 biquad */
- { 0xFF, 0xFF, 0 }, /* C1 DAI2 biquad */
- { 0xFF, 0xFF, 0 }, /* C2 DAI2 biquad */
- { 0xFF, 0xFF, 0 }, /* C3 DAI2 biquad */
- { 0xFF, 0xFF, 0 }, /* C4 DAI2 biquad */
- { 0xFF, 0xFF, 0 }, /* C5 DAI2 biquad */
- { 0xFF, 0xFF, 0 }, /* C6 DAI2 biquad */
- { 0xFF, 0xFF, 0 }, /* C7 DAI2 biquad */
- { 0xFF, 0xFF, 0 }, /* C8 DAI2 biquad */
- { 0xFF, 0xFF, 0 }, /* C9 DAI2 biquad */
- { 0x00, 0x00, 0 }, /* CA */
- { 0x00, 0x00, 0 }, /* CB */
- { 0x00, 0x00, 0 }, /* CC */
- { 0x00, 0x00, 0 }, /* CD */
- { 0x00, 0x00, 0 }, /* CE */
- { 0x00, 0x00, 0 }, /* CF */
-
- { 0x00, 0x00, 0 }, /* D0 */
- { 0x00, 0x00, 0 }, /* D1 */
- { 0x00, 0x00, 0 }, /* D2 */
- { 0x00, 0x00, 0 }, /* D3 */
- { 0x00, 0x00, 0 }, /* D4 */
- { 0x00, 0x00, 0 }, /* D5 */
- { 0x00, 0x00, 0 }, /* D6 */
- { 0x00, 0x00, 0 }, /* D7 */
- { 0x00, 0x00, 0 }, /* D8 */
- { 0x00, 0x00, 0 }, /* D9 */
- { 0x00, 0x00, 0 }, /* DA */
- { 0x00, 0x00, 0 }, /* DB */
- { 0x00, 0x00, 0 }, /* DC */
- { 0x00, 0x00, 0 }, /* DD */
- { 0x00, 0x00, 0 }, /* DE */
- { 0x00, 0x00, 0 }, /* DF */
-
- { 0x00, 0x00, 0 }, /* E0 */
- { 0x00, 0x00, 0 }, /* E1 */
- { 0x00, 0x00, 0 }, /* E2 */
- { 0x00, 0x00, 0 }, /* E3 */
- { 0x00, 0x00, 0 }, /* E4 */
- { 0x00, 0x00, 0 }, /* E5 */
- { 0x00, 0x00, 0 }, /* E6 */
- { 0x00, 0x00, 0 }, /* E7 */
- { 0x00, 0x00, 0 }, /* E8 */
- { 0x00, 0x00, 0 }, /* E9 */
- { 0x00, 0x00, 0 }, /* EA */
- { 0x00, 0x00, 0 }, /* EB */
- { 0x00, 0x00, 0 }, /* EC */
- { 0x00, 0x00, 0 }, /* ED */
- { 0x00, 0x00, 0 }, /* EE */
- { 0x00, 0x00, 0 }, /* EF */
-
- { 0x00, 0x00, 0 }, /* F0 */
- { 0x00, 0x00, 0 }, /* F1 */
- { 0x00, 0x00, 0 }, /* F2 */
- { 0x00, 0x00, 0 }, /* F3 */
- { 0x00, 0x00, 0 }, /* F4 */
- { 0x00, 0x00, 0 }, /* F5 */
- { 0x00, 0x00, 0 }, /* F6 */
- { 0x00, 0x00, 0 }, /* F7 */
- { 0x00, 0x00, 0 }, /* F8 */
- { 0x00, 0x00, 0 }, /* F9 */
- { 0x00, 0x00, 0 }, /* FA */
- { 0x00, 0x00, 0 }, /* FB */
- { 0x00, 0x00, 0 }, /* FC */
- { 0x00, 0x00, 0 }, /* FD */
- { 0x00, 0x00, 0 }, /* FE */
- { 0xFF, 0x00, 1 }, /* FF */
-};
-
static bool max98088_readable_register(struct device *dev, unsigned int reg)
{
- return max98088_access[reg].readable;
+ switch (reg) {
+ case M98088_REG_00_IRQ_STATUS ... 0xC9:
+ case M98088_REG_FF_REV_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool max98088_writeable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case M98088_REG_03_BATTERY_VOLTAGE ... 0xC9:
+ return true;
+ default:
+ return false;
+ }
}
static bool max98088_volatile_register(struct device *dev, unsigned int reg)
{
- return max98088_access[reg].vol;
+ switch (reg) {
+ case M98088_REG_00_IRQ_STATUS ... M98088_REG_03_BATTERY_VOLTAGE:
+ case M98088_REG_FF_REV_ID:
+ return true;
+ default:
+ return false;
+ }
}
static const struct regmap_config max98088_regmap = {
@@ -551,6 +295,7 @@ static const struct regmap_config max98088_regmap = {
.val_bits = 8,
.readable_reg = max98088_readable_register,
+ .writeable_reg = max98088_writeable_register,
.volatile_reg = max98088_volatile_register,
.max_register = 0xff,
@@ -680,29 +425,26 @@ static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static const unsigned int max98088_micboost_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
- 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
- 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
-};
+static const DECLARE_TLV_DB_RANGE(max98088_micboost_tlv,
+ 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0)
+);
-static const unsigned int max98088_hp_tlv[] = {
- TLV_DB_RANGE_HEAD(5),
+static const DECLARE_TLV_DB_RANGE(max98088_hp_tlv,
0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0),
15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0),
22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0),
- 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0),
-};
+ 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0)
+);
-static const unsigned int max98088_spk_tlv[] = {
- TLV_DB_RANGE_HEAD(5),
+static const DECLARE_TLV_DB_RANGE(max98088_spk_tlv,
0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0),
7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0),
15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0),
22, 27, TLV_DB_SCALE_ITEM(100, 100, 0),
- 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0),
-};
+ 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0)
+);
static const struct snd_kcontrol_new max98088_snd_controls[] = {
@@ -2011,7 +1753,6 @@ MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
static struct i2c_driver max98088_i2c_driver = {
.driver = {
.name = "max98088",
- .owner = THIS_MODULE,
},
.probe = max98088_i2c_probe,
.remove = max98088_i2c_remove,
diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h
index be89a4f..efa39bf 100644
--- a/sound/soc/codecs/max98088.h
+++ b/sound/soc/codecs/max98088.h
@@ -16,7 +16,7 @@
*/
#define M98088_REG_00_IRQ_STATUS 0x00
#define M98088_REG_01_MIC_STATUS 0x01
-#define M98088_REG_02_JACK_STAUS 0x02
+#define M98088_REG_02_JACK_STATUS 0x02
#define M98088_REG_03_BATTERY_VOLTAGE 0x03
#define M98088_REG_0F_IRQ_ENABLE 0x0F
#define M98088_REG_10_SYS_CLK 0x10
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 78268f05..584aab8 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -267,75 +267,8 @@ static bool max98090_volatile_register(struct device *dev, unsigned int reg)
static bool max98090_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
- case M98090_REG_DEVICE_STATUS:
- case M98090_REG_JACK_STATUS:
- case M98090_REG_INTERRUPT_S:
- case M98090_REG_RESERVED:
- case M98090_REG_LINE_INPUT_CONFIG:
- case M98090_REG_LINE_INPUT_LEVEL:
- case M98090_REG_INPUT_MODE:
- case M98090_REG_MIC1_INPUT_LEVEL:
- case M98090_REG_MIC2_INPUT_LEVEL:
- case M98090_REG_MIC_BIAS_VOLTAGE:
- case M98090_REG_DIGITAL_MIC_ENABLE:
- case M98090_REG_DIGITAL_MIC_CONFIG:
- case M98090_REG_LEFT_ADC_MIXER:
- case M98090_REG_RIGHT_ADC_MIXER:
- case M98090_REG_LEFT_ADC_LEVEL:
- case M98090_REG_RIGHT_ADC_LEVEL:
- case M98090_REG_ADC_BIQUAD_LEVEL:
- case M98090_REG_ADC_SIDETONE:
- case M98090_REG_SYSTEM_CLOCK:
- case M98090_REG_CLOCK_MODE:
- case M98090_REG_CLOCK_RATIO_NI_MSB:
- case M98090_REG_CLOCK_RATIO_NI_LSB:
- case M98090_REG_CLOCK_RATIO_MI_MSB:
- case M98090_REG_CLOCK_RATIO_MI_LSB:
- case M98090_REG_MASTER_MODE:
- case M98090_REG_INTERFACE_FORMAT:
- case M98090_REG_TDM_CONTROL:
- case M98090_REG_TDM_FORMAT:
- case M98090_REG_IO_CONFIGURATION:
- case M98090_REG_FILTER_CONFIG:
- case M98090_REG_DAI_PLAYBACK_LEVEL:
- case M98090_REG_DAI_PLAYBACK_LEVEL_EQ:
- case M98090_REG_LEFT_HP_MIXER:
- case M98090_REG_RIGHT_HP_MIXER:
- case M98090_REG_HP_CONTROL:
- case M98090_REG_LEFT_HP_VOLUME:
- case M98090_REG_RIGHT_HP_VOLUME:
- case M98090_REG_LEFT_SPK_MIXER:
- case M98090_REG_RIGHT_SPK_MIXER:
- case M98090_REG_SPK_CONTROL:
- case M98090_REG_LEFT_SPK_VOLUME:
- case M98090_REG_RIGHT_SPK_VOLUME:
- case M98090_REG_DRC_TIMING:
- case M98090_REG_DRC_COMPRESSOR:
- case M98090_REG_DRC_EXPANDER:
- case M98090_REG_DRC_GAIN:
- case M98090_REG_RCV_LOUTL_MIXER:
- case M98090_REG_RCV_LOUTL_CONTROL:
- case M98090_REG_RCV_LOUTL_VOLUME:
- case M98090_REG_LOUTR_MIXER:
- case M98090_REG_LOUTR_CONTROL:
- case M98090_REG_LOUTR_VOLUME:
- case M98090_REG_JACK_DETECT:
- case M98090_REG_INPUT_ENABLE:
- case M98090_REG_OUTPUT_ENABLE:
- case M98090_REG_LEVEL_CONTROL:
- case M98090_REG_DSP_FILTER_ENABLE:
- case M98090_REG_BIAS_CONTROL:
- case M98090_REG_DAC_CONTROL:
- case M98090_REG_ADC_CONTROL:
- case M98090_REG_DEVICE_SHUTDOWN:
- case M98090_REG_EQUALIZER_BASE ... M98090_REG_EQUALIZER_BASE + 0x68:
- case M98090_REG_RECORD_BIQUAD_BASE ... M98090_REG_RECORD_BIQUAD_BASE + 0x0E:
- case M98090_REG_DMIC3_VOLUME:
- case M98090_REG_DMIC4_VOLUME:
- case M98090_REG_DMIC34_BQ_PREATTEN:
- case M98090_REG_RECORD_TDM_SLOT:
- case M98090_REG_SAMPLE_RATE:
- case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E:
+ case M98090_REG_DEVICE_STATUS ... M98090_REG_INTERRUPT_S:
+ case M98090_REG_LINE_INPUT_CONFIG ... 0xD1:
case M98090_REG_REVISION_ID:
return true;
default:
@@ -360,22 +293,20 @@ static int max98090_reset(struct max98090_priv *max98090)
return ret;
}
-static const unsigned int max98090_micboost_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(max98090_micboost_tlv,
0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
- 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
-};
+ 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0)
+);
static const DECLARE_TLV_DB_SCALE(max98090_mic_tlv, 0, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98090_line_single_ended_tlv,
-600, 600, 0);
-static const unsigned int max98090_line_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(max98090_line_tlv,
0, 3, TLV_DB_SCALE_ITEM(-600, 300, 0),
- 4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0),
-};
+ 4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0)
+);
static const DECLARE_TLV_DB_SCALE(max98090_avg_tlv, 0, 600, 0);
static const DECLARE_TLV_DB_SCALE(max98090_av_tlv, -1200, 100, 0);
@@ -391,38 +322,34 @@ static const DECLARE_TLV_DB_SCALE(max98090_alccomp_tlv, -3100, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98090_drcexp_tlv, -6600, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98090_sdg_tlv, 50, 200, 0);
-static const unsigned int max98090_mixout_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(max98090_mixout_tlv,
0, 1, TLV_DB_SCALE_ITEM(-1200, 250, 0),
- 2, 3, TLV_DB_SCALE_ITEM(-600, 600, 0),
-};
+ 2, 3, TLV_DB_SCALE_ITEM(-600, 600, 0)
+);
-static const unsigned int max98090_hp_tlv[] = {
- TLV_DB_RANGE_HEAD(5),
+static const DECLARE_TLV_DB_RANGE(max98090_hp_tlv,
0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0),
15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0),
22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0),
- 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0),
-};
+ 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0)
+);
-static const unsigned int max98090_spk_tlv[] = {
- TLV_DB_RANGE_HEAD(5),
+static const DECLARE_TLV_DB_RANGE(max98090_spk_tlv,
0, 4, TLV_DB_SCALE_ITEM(-4800, 400, 0),
5, 10, TLV_DB_SCALE_ITEM(-2900, 300, 0),
11, 14, TLV_DB_SCALE_ITEM(-1200, 200, 0),
15, 29, TLV_DB_SCALE_ITEM(-500, 100, 0),
- 30, 39, TLV_DB_SCALE_ITEM(950, 50, 0),
-};
+ 30, 39, TLV_DB_SCALE_ITEM(950, 50, 0)
+);
-static const unsigned int max98090_rcv_lout_tlv[] = {
- TLV_DB_RANGE_HEAD(5),
+static const DECLARE_TLV_DB_RANGE(max98090_rcv_lout_tlv,
0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0),
7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0),
15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0),
22, 27, TLV_DB_SCALE_ITEM(100, 100, 0),
- 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0),
-};
+ 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0)
+);
static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -850,6 +777,19 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int max98090_shdn_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+
+ if (event & SND_SOC_DAPM_POST_PMU)
+ max98090->shdn_pending = true;
+
+ return 0;
+
+}
+
static const char *mic1_mux_text[] = { "IN12", "IN56" };
static SOC_ENUM_SINGLE_DECL(mic1_mux_enum,
@@ -1158,9 +1098,11 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SDOEN", M98090_REG_IO_CONFIGURATION,
M98090_SDOEN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DMICL_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_DIGMICL_SHIFT, 0, NULL, 0),
+ M98090_DIGMICL_SHIFT, 0, max98090_shdn_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("DMICR_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_DIGMICR_SHIFT, 0, NULL, 0),
+ M98090_DIGMICR_SHIFT, 0, max98090_shdn_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("AHPF", M98090_REG_FILTER_CONFIG,
M98090_AHPF_SHIFT, 0, NULL, 0),
@@ -1205,10 +1147,12 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
&max98090_right_adc_mixer_controls[0],
ARRAY_SIZE(max98090_right_adc_mixer_controls)),
- SND_SOC_DAPM_ADC("ADCL", NULL, M98090_REG_INPUT_ENABLE,
- M98090_ADLEN_SHIFT, 0),
- SND_SOC_DAPM_ADC("ADCR", NULL, M98090_REG_INPUT_ENABLE,
- M98090_ADREN_SHIFT, 0),
+ SND_SOC_DAPM_ADC_E("ADCL", NULL, M98090_REG_INPUT_ENABLE,
+ M98090_ADLEN_SHIFT, 0, max98090_shdn_event,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_ADC_E("ADCR", NULL, M98090_REG_INPUT_ENABLE,
+ M98090_ADREN_SHIFT, 0, max98090_shdn_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_AIF_OUT("AIFOUTL", "HiFi Capture", 0,
SND_SOC_NOPM, 0, 0),
@@ -1801,10 +1745,13 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
if (IS_ERR(max98090->mclk))
break;
- if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON)
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) {
clk_disable_unprepare(max98090->mclk);
- else
- clk_prepare_enable(max98090->mclk);
+ } else {
+ ret = clk_prepare_enable(max98090->mclk);
+ if (ret)
+ return ret;
+ }
break;
case SND_SOC_BIAS_STANDBY:
@@ -2383,7 +2330,7 @@ EXPORT_SYMBOL_GPL(max98090_mic_detect);
#define MAX98090_RATES SNDRV_PCM_RATE_8000_96000
#define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
-static struct snd_soc_dai_ops max98090_dai_ops = {
+static const struct snd_soc_dai_ops max98090_dai_ops = {
.set_sysclk = max98090_dai_set_sysclk,
.set_fmt = max98090_dai_set_fmt,
.set_tdm_slot = max98090_set_tdm_slot,
@@ -2536,9 +2483,26 @@ static int max98090_remove(struct snd_soc_codec *codec)
return 0;
}
+static void max98090_seq_notifier(struct snd_soc_dapm_context *dapm,
+ enum snd_soc_dapm_type event, int subseq)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
+ struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+
+ if (max98090->shdn_pending) {
+ snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
+ M98090_SHDNN_MASK, 0);
+ msleep(40);
+ snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
+ M98090_SHDNN_MASK, M98090_SHDNN_MASK);
+ max98090->shdn_pending = false;
+ }
+}
+
static struct snd_soc_codec_driver soc_codec_dev_max98090 = {
.probe = max98090_probe,
.remove = max98090_remove,
+ .seq_notifier = max98090_seq_notifier,
.set_bias_level = max98090_set_bias_level,
};
@@ -2714,7 +2678,6 @@ MODULE_DEVICE_TABLE(acpi, max98090_acpi_match);
static struct i2c_driver max98090_i2c_driver = {
.driver = {
.name = "max98090",
- .owner = THIS_MODULE,
.pm = &max98090_pm,
.of_match_table = of_match_ptr(max98090_of_match),
.acpi_match_table = ACPI_PTR(max98090_acpi_match),
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
index 21ff743..bc610d9 100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
@@ -1543,6 +1543,7 @@ struct max98090_priv {
unsigned int pa2en;
unsigned int sidetone;
bool master;
+ bool shdn_pending;
};
int max98090_mic_detect(struct snd_soc_codec *codec,
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 9a46d3d..1fedac5 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -202,300 +202,36 @@ static const struct reg_default max98095_reg_def[] = {
{ 0xff, 0x00 }, /* FF */
};
-static struct {
- int readable;
- int writable;
-} max98095_access[M98095_REG_CNT] = {
- { 0x00, 0x00 }, /* 00 */
- { 0xFF, 0x00 }, /* 01 */
- { 0xFF, 0x00 }, /* 02 */
- { 0xFF, 0x00 }, /* 03 */
- { 0xFF, 0x00 }, /* 04 */
- { 0xFF, 0x00 }, /* 05 */
- { 0xFF, 0x00 }, /* 06 */
- { 0xFF, 0x00 }, /* 07 */
- { 0xFF, 0x00 }, /* 08 */
- { 0xFF, 0x00 }, /* 09 */
- { 0xFF, 0x00 }, /* 0A */
- { 0xFF, 0x00 }, /* 0B */
- { 0xFF, 0x00 }, /* 0C */
- { 0xFF, 0x00 }, /* 0D */
- { 0xFF, 0x00 }, /* 0E */
- { 0xFF, 0x9F }, /* 0F */
- { 0xFF, 0xFF }, /* 10 */
- { 0xFF, 0xFF }, /* 11 */
- { 0xFF, 0xFF }, /* 12 */
- { 0xFF, 0xFF }, /* 13 */
- { 0xFF, 0xFF }, /* 14 */
- { 0xFF, 0xFF }, /* 15 */
- { 0xFF, 0xFF }, /* 16 */
- { 0xFF, 0xFF }, /* 17 */
- { 0xFF, 0xFF }, /* 18 */
- { 0xFF, 0xFF }, /* 19 */
- { 0xFF, 0xFF }, /* 1A */
- { 0xFF, 0xFF }, /* 1B */
- { 0xFF, 0xFF }, /* 1C */
- { 0xFF, 0xFF }, /* 1D */
- { 0xFF, 0x77 }, /* 1E */
- { 0xFF, 0x77 }, /* 1F */
- { 0xFF, 0x77 }, /* 20 */
- { 0xFF, 0x77 }, /* 21 */
- { 0xFF, 0x77 }, /* 22 */
- { 0xFF, 0x77 }, /* 23 */
- { 0xFF, 0xFF }, /* 24 */
- { 0xFF, 0x7F }, /* 25 */
- { 0xFF, 0x31 }, /* 26 */
- { 0xFF, 0xFF }, /* 27 */
- { 0xFF, 0xFF }, /* 28 */
- { 0xFF, 0xFF }, /* 29 */
- { 0xFF, 0xF7 }, /* 2A */
- { 0xFF, 0x2F }, /* 2B */
- { 0xFF, 0xEF }, /* 2C */
- { 0xFF, 0xFF }, /* 2D */
- { 0xFF, 0xFF }, /* 2E */
- { 0xFF, 0xFF }, /* 2F */
- { 0xFF, 0xFF }, /* 30 */
- { 0xFF, 0xFF }, /* 31 */
- { 0xFF, 0xFF }, /* 32 */
- { 0xFF, 0xFF }, /* 33 */
- { 0xFF, 0xF7 }, /* 34 */
- { 0xFF, 0x2F }, /* 35 */
- { 0xFF, 0xCF }, /* 36 */
- { 0xFF, 0xFF }, /* 37 */
- { 0xFF, 0xFF }, /* 38 */
- { 0xFF, 0xFF }, /* 39 */
- { 0xFF, 0xFF }, /* 3A */
- { 0xFF, 0xFF }, /* 3B */
- { 0xFF, 0xFF }, /* 3C */
- { 0xFF, 0xFF }, /* 3D */
- { 0xFF, 0xF7 }, /* 3E */
- { 0xFF, 0x2F }, /* 3F */
- { 0xFF, 0xCF }, /* 40 */
- { 0xFF, 0xFF }, /* 41 */
- { 0xFF, 0x77 }, /* 42 */
- { 0xFF, 0xFF }, /* 43 */
- { 0xFF, 0xFF }, /* 44 */
- { 0xFF, 0xFF }, /* 45 */
- { 0xFF, 0xFF }, /* 46 */
- { 0xFF, 0xFF }, /* 47 */
- { 0xFF, 0xFF }, /* 48 */
- { 0xFF, 0x0F }, /* 49 */
- { 0xFF, 0xFF }, /* 4A */
- { 0xFF, 0xFF }, /* 4B */
- { 0xFF, 0x3F }, /* 4C */
- { 0xFF, 0x3F }, /* 4D */
- { 0xFF, 0x3F }, /* 4E */
- { 0xFF, 0xFF }, /* 4F */
- { 0xFF, 0x7F }, /* 50 */
- { 0xFF, 0x7F }, /* 51 */
- { 0xFF, 0x0F }, /* 52 */
- { 0xFF, 0x3F }, /* 53 */
- { 0xFF, 0x3F }, /* 54 */
- { 0xFF, 0x3F }, /* 55 */
- { 0xFF, 0xFF }, /* 56 */
- { 0xFF, 0xFF }, /* 57 */
- { 0xFF, 0xBF }, /* 58 */
- { 0xFF, 0x1F }, /* 59 */
- { 0xFF, 0xBF }, /* 5A */
- { 0xFF, 0x1F }, /* 5B */
- { 0xFF, 0xBF }, /* 5C */
- { 0xFF, 0x3F }, /* 5D */
- { 0xFF, 0x3F }, /* 5E */
- { 0xFF, 0x7F }, /* 5F */
- { 0xFF, 0x7F }, /* 60 */
- { 0xFF, 0x47 }, /* 61 */
- { 0xFF, 0x9F }, /* 62 */
- { 0xFF, 0x9F }, /* 63 */
- { 0xFF, 0x9F }, /* 64 */
- { 0xFF, 0x9F }, /* 65 */
- { 0xFF, 0x9F }, /* 66 */
- { 0xFF, 0xBF }, /* 67 */
- { 0xFF, 0xBF }, /* 68 */
- { 0xFF, 0xFF }, /* 69 */
- { 0xFF, 0xFF }, /* 6A */
- { 0xFF, 0x7F }, /* 6B */
- { 0xFF, 0xF7 }, /* 6C */
- { 0xFF, 0xFF }, /* 6D */
- { 0xFF, 0xFF }, /* 6E */
- { 0xFF, 0x1F }, /* 6F */
- { 0xFF, 0xF7 }, /* 70 */
- { 0xFF, 0xFF }, /* 71 */
- { 0xFF, 0xFF }, /* 72 */
- { 0xFF, 0x1F }, /* 73 */
- { 0xFF, 0xF7 }, /* 74 */
- { 0xFF, 0xFF }, /* 75 */
- { 0xFF, 0xFF }, /* 76 */
- { 0xFF, 0x1F }, /* 77 */
- { 0xFF, 0xF7 }, /* 78 */
- { 0xFF, 0xFF }, /* 79 */
- { 0xFF, 0xFF }, /* 7A */
- { 0xFF, 0x1F }, /* 7B */
- { 0xFF, 0xF7 }, /* 7C */
- { 0xFF, 0xFF }, /* 7D */
- { 0xFF, 0xFF }, /* 7E */
- { 0xFF, 0x1F }, /* 7F */
- { 0xFF, 0xF7 }, /* 80 */
- { 0xFF, 0xFF }, /* 81 */
- { 0xFF, 0xFF }, /* 82 */
- { 0xFF, 0x1F }, /* 83 */
- { 0xFF, 0x7F }, /* 84 */
- { 0xFF, 0x0F }, /* 85 */
- { 0xFF, 0xD8 }, /* 86 */
- { 0xFF, 0xFF }, /* 87 */
- { 0xFF, 0xEF }, /* 88 */
- { 0xFF, 0xFE }, /* 89 */
- { 0xFF, 0xFE }, /* 8A */
- { 0xFF, 0xFF }, /* 8B */
- { 0xFF, 0xFF }, /* 8C */
- { 0xFF, 0x3F }, /* 8D */
- { 0xFF, 0xFF }, /* 8E */
- { 0xFF, 0x3F }, /* 8F */
- { 0xFF, 0x8F }, /* 90 */
- { 0xFF, 0xFF }, /* 91 */
- { 0xFF, 0x3F }, /* 92 */
- { 0xFF, 0xFF }, /* 93 */
- { 0xFF, 0xFF }, /* 94 */
- { 0xFF, 0x0F }, /* 95 */
- { 0xFF, 0x3F }, /* 96 */
- { 0xFF, 0x8C }, /* 97 */
- { 0x00, 0x00 }, /* 98 */
- { 0x00, 0x00 }, /* 99 */
- { 0x00, 0x00 }, /* 9A */
- { 0x00, 0x00 }, /* 9B */
- { 0x00, 0x00 }, /* 9C */
- { 0x00, 0x00 }, /* 9D */
- { 0x00, 0x00 }, /* 9E */
- { 0x00, 0x00 }, /* 9F */
- { 0x00, 0x00 }, /* A0 */
- { 0x00, 0x00 }, /* A1 */
- { 0x00, 0x00 }, /* A2 */
- { 0x00, 0x00 }, /* A3 */
- { 0x00, 0x00 }, /* A4 */
- { 0x00, 0x00 }, /* A5 */
- { 0x00, 0x00 }, /* A6 */
- { 0x00, 0x00 }, /* A7 */
- { 0x00, 0x00 }, /* A8 */
- { 0x00, 0x00 }, /* A9 */
- { 0x00, 0x00 }, /* AA */
- { 0x00, 0x00 }, /* AB */
- { 0x00, 0x00 }, /* AC */
- { 0x00, 0x00 }, /* AD */
- { 0x00, 0x00 }, /* AE */
- { 0x00, 0x00 }, /* AF */
- { 0x00, 0x00 }, /* B0 */
- { 0x00, 0x00 }, /* B1 */
- { 0x00, 0x00 }, /* B2 */
- { 0x00, 0x00 }, /* B3 */
- { 0x00, 0x00 }, /* B4 */
- { 0x00, 0x00 }, /* B5 */
- { 0x00, 0x00 }, /* B6 */
- { 0x00, 0x00 }, /* B7 */
- { 0x00, 0x00 }, /* B8 */
- { 0x00, 0x00 }, /* B9 */
- { 0x00, 0x00 }, /* BA */
- { 0x00, 0x00 }, /* BB */
- { 0x00, 0x00 }, /* BC */
- { 0x00, 0x00 }, /* BD */
- { 0x00, 0x00 }, /* BE */
- { 0x00, 0x00 }, /* BF */
- { 0x00, 0x00 }, /* C0 */
- { 0x00, 0x00 }, /* C1 */
- { 0x00, 0x00 }, /* C2 */
- { 0x00, 0x00 }, /* C3 */
- { 0x00, 0x00 }, /* C4 */
- { 0x00, 0x00 }, /* C5 */
- { 0x00, 0x00 }, /* C6 */
- { 0x00, 0x00 }, /* C7 */
- { 0x00, 0x00 }, /* C8 */
- { 0x00, 0x00 }, /* C9 */
- { 0x00, 0x00 }, /* CA */
- { 0x00, 0x00 }, /* CB */
- { 0x00, 0x00 }, /* CC */
- { 0x00, 0x00 }, /* CD */
- { 0x00, 0x00 }, /* CE */
- { 0x00, 0x00 }, /* CF */
- { 0x00, 0x00 }, /* D0 */
- { 0x00, 0x00 }, /* D1 */
- { 0x00, 0x00 }, /* D2 */
- { 0x00, 0x00 }, /* D3 */
- { 0x00, 0x00 }, /* D4 */
- { 0x00, 0x00 }, /* D5 */
- { 0x00, 0x00 }, /* D6 */
- { 0x00, 0x00 }, /* D7 */
- { 0x00, 0x00 }, /* D8 */
- { 0x00, 0x00 }, /* D9 */
- { 0x00, 0x00 }, /* DA */
- { 0x00, 0x00 }, /* DB */
- { 0x00, 0x00 }, /* DC */
- { 0x00, 0x00 }, /* DD */
- { 0x00, 0x00 }, /* DE */
- { 0x00, 0x00 }, /* DF */
- { 0x00, 0x00 }, /* E0 */
- { 0x00, 0x00 }, /* E1 */
- { 0x00, 0x00 }, /* E2 */
- { 0x00, 0x00 }, /* E3 */
- { 0x00, 0x00 }, /* E4 */
- { 0x00, 0x00 }, /* E5 */
- { 0x00, 0x00 }, /* E6 */
- { 0x00, 0x00 }, /* E7 */
- { 0x00, 0x00 }, /* E8 */
- { 0x00, 0x00 }, /* E9 */
- { 0x00, 0x00 }, /* EA */
- { 0x00, 0x00 }, /* EB */
- { 0x00, 0x00 }, /* EC */
- { 0x00, 0x00 }, /* ED */
- { 0x00, 0x00 }, /* EE */
- { 0x00, 0x00 }, /* EF */
- { 0x00, 0x00 }, /* F0 */
- { 0x00, 0x00 }, /* F1 */
- { 0x00, 0x00 }, /* F2 */
- { 0x00, 0x00 }, /* F3 */
- { 0x00, 0x00 }, /* F4 */
- { 0x00, 0x00 }, /* F5 */
- { 0x00, 0x00 }, /* F6 */
- { 0x00, 0x00 }, /* F7 */
- { 0x00, 0x00 }, /* F8 */
- { 0x00, 0x00 }, /* F9 */
- { 0x00, 0x00 }, /* FA */
- { 0x00, 0x00 }, /* FB */
- { 0x00, 0x00 }, /* FC */
- { 0x00, 0x00 }, /* FD */
- { 0x00, 0x00 }, /* FE */
- { 0xFF, 0x00 }, /* FF */
-};
-
static bool max98095_readable(struct device *dev, unsigned int reg)
{
- if (reg >= M98095_REG_CNT)
- return 0;
- return max98095_access[reg].readable != 0;
+ switch (reg) {
+ case M98095_001_HOST_INT_STS ... M98095_097_PWR_SYS:
+ case M98095_0FF_REV_ID:
+ return true;
+ default:
+ return false;
+ }
}
-static bool max98095_volatile(struct device *dev, unsigned int reg)
+static bool max98095_writeable(struct device *dev, unsigned int reg)
{
- if (reg > M98095_REG_MAX_CACHED)
- return 1;
-
switch (reg) {
- case M98095_000_HOST_DATA:
- case M98095_001_HOST_INT_STS:
- case M98095_002_HOST_RSP_STS:
- case M98095_003_HOST_CMD_STS:
- case M98095_004_CODEC_STS:
- case M98095_005_DAI1_ALC_STS:
- case M98095_006_DAI2_ALC_STS:
- case M98095_007_JACK_AUTO_STS:
- case M98095_008_JACK_MANUAL_STS:
- case M98095_009_JACK_VBAT_STS:
- case M98095_00A_ACC_ADC_STS:
- case M98095_00B_MIC_NG_AGC_STS:
- case M98095_00C_SPK_L_VOLT_STS:
- case M98095_00D_SPK_R_VOLT_STS:
- case M98095_00E_TEMP_SENSOR_STS:
- return 1;
+ case M98095_00F_HOST_CFG ... M98095_097_PWR_SYS:
+ return true;
+ default:
+ return false;
}
+}
- return 0;
+static bool max98095_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case M98095_000_HOST_DATA ... M98095_00E_TEMP_SENSOR_STS:
+ case M98095_REG_MAX_CACHED + 1 ... M98095_0FF_REV_ID:
+ return true;
+ default:
+ return false;
+ }
}
static const struct regmap_config max98095_regmap = {
@@ -508,6 +244,7 @@ static const struct regmap_config max98095_regmap = {
.cache_type = REGCACHE_RBTREE,
.readable_reg = max98095_readable,
+ .writeable_reg = max98095_writeable,
.volatile_reg = max98095_volatile,
};
@@ -661,48 +398,43 @@ static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static const unsigned int max98095_micboost_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(max98095_micboost_tlv,
0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
- 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
-};
+ 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0)
+);
static const DECLARE_TLV_DB_SCALE(max98095_mic_tlv, 0, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98095_adc_tlv, -1200, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98095_adcboost_tlv, 0, 600, 0);
-static const unsigned int max98095_hp_tlv[] = {
- TLV_DB_RANGE_HEAD(5),
+static const DECLARE_TLV_DB_RANGE(max98095_hp_tlv,
0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0),
15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0),
22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0),
- 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0),
-};
+ 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0)
+);
-static const unsigned int max98095_spk_tlv[] = {
- TLV_DB_RANGE_HEAD(4),
+static const DECLARE_TLV_DB_RANGE(max98095_spk_tlv,
0, 10, TLV_DB_SCALE_ITEM(-5900, 400, 0),
11, 18, TLV_DB_SCALE_ITEM(-1700, 200, 0),
19, 27, TLV_DB_SCALE_ITEM(-200, 100, 0),
- 28, 39, TLV_DB_SCALE_ITEM(650, 50, 0),
-};
+ 28, 39, TLV_DB_SCALE_ITEM(650, 50, 0)
+);
-static const unsigned int max98095_rcv_lout_tlv[] = {
- TLV_DB_RANGE_HEAD(5),
+static const DECLARE_TLV_DB_RANGE(max98095_rcv_lout_tlv,
0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0),
7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0),
15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0),
22, 27, TLV_DB_SCALE_ITEM(100, 100, 0),
- 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0),
-};
+ 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0)
+);
-static const unsigned int max98095_lin_tlv[] = {
- TLV_DB_RANGE_HEAD(3),
+static const DECLARE_TLV_DB_RANGE(max98095_lin_tlv,
0, 2, TLV_DB_SCALE_ITEM(-600, 300, 0),
3, 3, TLV_DB_SCALE_ITEM(300, 1100, 0),
- 4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0),
-};
+ 4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0)
+);
static const struct snd_kcontrol_new max98095_snd_controls[] = {
@@ -1653,10 +1385,13 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
if (IS_ERR(max98095->mclk))
break;
- if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON)
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) {
clk_disable_unprepare(max98095->mclk);
- else
- clk_prepare_enable(max98095->mclk);
+ } else {
+ ret = clk_prepare_enable(max98095->mclk);
+ if (ret)
+ return ret;
+ }
break;
case SND_SOC_BIAS_STANDBY:
@@ -2431,7 +2166,6 @@ MODULE_DEVICE_TABLE(of, max98095_of_match);
static struct i2c_driver max98095_i2c_driver = {
.driver = {
.name = "max98095",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(max98095_of_match),
},
.probe = max98095_i2c_probe,
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index 3a2fda0..f5e3dce 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -31,6 +31,9 @@ static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
{
struct gpio_desc *sdmode = snd_soc_dai_get_drvdata(dai);
+ if (!sdmode)
+ return 0;
+
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -48,24 +51,21 @@ static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dapm_widget max98357a_dapm_widgets[] = {
- SND_SOC_DAPM_DAC("SDMode", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_OUTPUT("Speaker"),
};
static const struct snd_soc_dapm_route max98357a_dapm_routes[] = {
- {"Speaker", NULL, "SDMode"},
+ {"Speaker", NULL, "HiFi Playback"},
};
static int max98357a_codec_probe(struct snd_soc_codec *codec)
{
struct gpio_desc *sdmode;
- sdmode = devm_gpiod_get(codec->dev, "sdmode", GPIOD_OUT_LOW);
- if (IS_ERR(sdmode)) {
- dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n",
- __func__, PTR_ERR(sdmode));
+ sdmode = devm_gpiod_get_optional(codec->dev, "sdmode", GPIOD_OUT_LOW);
+ if (IS_ERR(sdmode))
return PTR_ERR(sdmode);
- }
+
snd_soc_codec_set_drvdata(codec, sdmode);
return 0;
@@ -79,7 +79,7 @@ static struct snd_soc_codec_driver max98357a_codec_driver = {
.num_dapm_routes = ARRAY_SIZE(max98357a_dapm_routes),
};
-static struct snd_soc_dai_ops max98357a_dai_ops = {
+static const struct snd_soc_dai_ops max98357a_dai_ops = {
.trigger = max98357a_daiops_trigger,
};
@@ -104,15 +104,8 @@ static struct snd_soc_dai_driver max98357a_dai_driver = {
static int max98357a_platform_probe(struct platform_device *pdev)
{
- int ret;
-
- ret = snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver,
+ return snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver,
&max98357a_dai_driver, 1);
- if (ret)
- dev_err(&pdev->dev, "%s() error registering codec driver: %d\n",
- __func__, ret);
-
- return ret;
}
static int max98357a_platform_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index 481d58f1..c14a79d 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -67,13 +67,12 @@ static const struct regmap_config max9850_regmap = {
.cache_type = REGCACHE_RBTREE,
};
-static const unsigned int max9850_tlv[] = {
- TLV_DB_RANGE_HEAD(4),
+static const DECLARE_TLV_DB_RANGE(max9850_tlv,
0x18, 0x1f, TLV_DB_SCALE_ITEM(-7450, 400, 0),
0x20, 0x33, TLV_DB_SCALE_ITEM(-4150, 200, 0),
0x34, 0x37, TLV_DB_SCALE_ITEM(-150, 100, 0),
- 0x38, 0x3f, TLV_DB_SCALE_ITEM(250, 50, 0),
-};
+ 0x38, 0x3f, TLV_DB_SCALE_ITEM(250, 50, 0)
+);
static const struct snd_kcontrol_new max9850_controls[] = {
SOC_SINGLE_TLV("Headphone Volume", MAX9850_VOLUME, 0, 0x3f, 1, max9850_tlv),
@@ -352,7 +351,6 @@ MODULE_DEVICE_TABLE(i2c, max9850_i2c_id);
static struct i2c_driver max9850_i2c_driver = {
.driver = {
.name = "max9850",
- .owner = THIS_MODULE,
},
.probe = max9850_i2c_probe,
.remove = max9850_i2c_remove,
diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c
index 29549cd..61cc18e 100644
--- a/sound/soc/codecs/max9877.c
+++ b/sound/soc/codecs/max9877.c
@@ -20,9 +20,7 @@
#include "max9877.h"
-static struct regmap *regmap;
-
-static struct reg_default max9877_regs[] = {
+static const struct reg_default max9877_regs[] = {
{ 0, 0x40 },
{ 1, 0x00 },
{ 2, 0x00 },
@@ -30,19 +28,17 @@ static struct reg_default max9877_regs[] = {
{ 4, 0x49 },
};
-static const unsigned int max9877_pgain_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(max9877_pgain_tlv,
0, 1, TLV_DB_SCALE_ITEM(0, 900, 0),
- 2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0),
-};
+ 2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0)
+);
-static const unsigned int max9877_output_tlv[] = {
- TLV_DB_RANGE_HEAD(4),
+static const DECLARE_TLV_DB_RANGE(max9877_output_tlv,
0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1),
8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0),
16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0),
- 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0),
-};
+ 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0)
+);
static const char *max9877_out_mode[] = {
"INA -> SPK",
@@ -123,7 +119,7 @@ static const struct snd_soc_dapm_route max9877_dapm_routes[] = {
{ "HPR", NULL, "SHDN" },
};
-static const struct snd_soc_codec_driver max9877_codec = {
+static const struct snd_soc_component_driver max9877_component_driver = {
.controls = max9877_controls,
.num_controls = ARRAY_SIZE(max9877_controls),
@@ -145,6 +141,7 @@ static const struct regmap_config max9877_regmap = {
static int max9877_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct regmap *regmap;
int i;
regmap = devm_regmap_init_i2c(client, &max9877_regmap);
@@ -155,14 +152,8 @@ static int max9877_i2c_probe(struct i2c_client *client,
for (i = 0; i < ARRAY_SIZE(max9877_regs); i++)
regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def);
- return snd_soc_register_codec(&client->dev, &max9877_codec, NULL, 0);
-}
-
-static int max9877_i2c_remove(struct i2c_client *client)
-{
- snd_soc_unregister_codec(&client->dev);
-
- return 0;
+ return devm_snd_soc_register_component(&client->dev,
+ &max9877_component_driver, NULL, 0);
}
static const struct i2c_device_id max9877_i2c_id[] = {
@@ -174,10 +165,8 @@ MODULE_DEVICE_TABLE(i2c, max9877_i2c_id);
static struct i2c_driver max9877_i2c_driver = {
.driver = {
.name = "max9877",
- .owner = THIS_MODULE,
},
.probe = max9877_i2c_probe,
- .remove = max9877_i2c_remove,
.id_table = max9877_i2c_id,
};
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
index aad6642..5990de3 100644
--- a/sound/soc/codecs/max98925.c
+++ b/sound/soc/codecs/max98925.c
@@ -271,8 +271,6 @@ static inline int max98925_rate_value(struct snd_soc_codec *codec,
break;
}
}
- dev_dbg(codec->dev, "%s: sample rate is %d, returning %d\n",
- __func__, rate_table[i].rate, *value);
return ret;
}
@@ -432,7 +430,7 @@ static int max98925_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
- switch (snd_pcm_format_width(params_format(params))) {
+ switch (params_width(params)) {
case 16:
regmap_update_bits(max98925->regmap,
MAX98925_FORMAT,
@@ -523,7 +521,6 @@ static int max98925_probe(struct snd_soc_codec *codec)
struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
max98925->codec = codec;
- codec->control_data = max98925->regmap;
regmap_write(max98925->regmap, MAX98925_GLOBAL_ENABLE, 0x00);
/* It's not the default but we need to set DAI_DLY */
regmap_write(max98925->regmap,
@@ -639,7 +636,6 @@ MODULE_DEVICE_TABLE(of, max98925_of_match);
static struct i2c_driver max98925_i2c_driver = {
.driver = {
.name = "max98925",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(max98925_of_match),
.pm = NULL,
},
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 3d44fc5..3e770cb 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -650,14 +650,14 @@ static int mc13783_remove(struct snd_soc_codec *codec)
#define MC13783_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
-static struct snd_soc_dai_ops mc13783_ops_dac = {
+static const struct snd_soc_dai_ops mc13783_ops_dac = {
.hw_params = mc13783_pcm_hw_params_dac,
.set_fmt = mc13783_set_fmt_async,
.set_sysclk = mc13783_set_sysclk_dac,
.set_tdm_slot = mc13783_set_tdm_slot_dac,
};
-static struct snd_soc_dai_ops mc13783_ops_codec = {
+static const struct snd_soc_dai_ops mc13783_ops_codec = {
.hw_params = mc13783_pcm_hw_params_codec,
.set_fmt = mc13783_set_fmt_async,
.set_sysclk = mc13783_set_sysclk_codec,
@@ -698,7 +698,7 @@ static struct snd_soc_dai_driver mc13783_dai_async[] = {
},
};
-static struct snd_soc_dai_ops mc13783_ops_sync = {
+static const struct snd_soc_dai_ops mc13783_ops_sync = {
.hw_params = mc13783_pcm_hw_params_sync,
.set_fmt = mc13783_set_fmt_sync,
.set_sysclk = mc13783_set_sysclk_sync,
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index b74118e..f561c78 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -199,7 +199,7 @@ static const struct clk_coeff coeff_div[] = {
{12288000, 48000, 0xc, 0x0, 0x30, 0x0, 0x4},
};
-static struct reg_default ml26124_reg[] = {
+static const struct reg_default ml26124_reg[] = {
/* CLOCK control Register */
{0x00, 0x00 }, /* Sampling Rate */
{0x02, 0x00}, /* PLL NL */
@@ -597,7 +597,6 @@ MODULE_DEVICE_TABLE(i2c, ml26124_i2c_id);
static struct i2c_driver ml26124_i2c_driver = {
.driver = {
.name = "ml26124",
- .owner = THIS_MODULE,
},
.probe = ml26124_i2c_probe,
.remove = ml26124_i2c_remove,
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index e7ba557..5832523 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -95,17 +95,22 @@ static int pcm1681_set_deemph(struct snd_soc_codec *codec)
struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
int i = 0, val = -1, enable = 0;
- if (priv->deemph)
- for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++)
- if (pcm1681_deemph[i] == priv->rate)
+ if (priv->deemph) {
+ for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++) {
+ if (pcm1681_deemph[i] == priv->rate) {
val = i;
+ break;
+ }
+ }
+ }
if (val != -1) {
regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
PCM1681_DEEMPH_RATE_MASK, val << 3);
enable = 1;
- } else
+ } else {
enable = 0;
+ }
/* enable/disable deemphasis functionality */
return regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
@@ -330,7 +335,6 @@ static int pcm1681_i2c_remove(struct i2c_client *client)
static struct i2c_driver pcm1681_i2c_driver = {
.driver = {
.name = "pcm1681",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(pcm1681_dt_ids),
},
.id_table = pcm1681_i2c_id,
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
index dcdfac0..dbff416 100644
--- a/sound/soc/codecs/pcm512x-i2c.c
+++ b/sound/soc/codecs/pcm512x-i2c.c
@@ -67,7 +67,6 @@ static struct i2c_driver pcm512x_i2c_driver = {
.id_table = pcm512x_i2c_id,
.driver = {
.name = "pcm512x",
- .owner = THIS_MODULE,
.of_match_table = pcm512x_of_match,
.pm = &pcm512x_pm_ops,
},
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index de16429..047c489 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -1117,7 +1117,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
params_rate(params),
params_channels(params));
- switch (snd_pcm_format_width(params_format(params))) {
+ switch (params_width(params)) {
case 16:
alen = PCM512x_ALEN_16;
break;
@@ -1132,7 +1132,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
break;
default:
dev_err(codec->dev, "Bad frame size: %d\n",
- snd_pcm_format_width(params_format(params)));
+ params_width(params));
return -EINVAL;
}
diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c
index 56650d6..aca479f 100644
--- a/sound/soc/codecs/rl6231.c
+++ b/sound/soc/codecs/rl6231.c
@@ -11,38 +11,98 @@
*/
#include <linux/module.h>
+#include <linux/regmap.h>
#include "rl6231.h"
/**
- * rl6231_calc_dmic_clk - Calculate the parameter of dmic.
+ * rl6231_get_pre_div - Return the value of pre divider.
+ *
+ * @map: map for setting.
+ * @reg: register.
+ * @sft: shift.
+ *
+ * Return the value of pre divider from given register value.
+ * Return negative error code for unexpected register value.
+ */
+int rl6231_get_pre_div(struct regmap *map, unsigned int reg, int sft)
+{
+ int pd, val;
+
+ regmap_read(map, reg, &val);
+
+ val = (val >> sft) & 0x7;
+
+ switch (val) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ pd = val + 1;
+ break;
+ case 4:
+ pd = 6;
+ break;
+ case 5:
+ pd = 8;
+ break;
+ case 6:
+ pd = 12;
+ break;
+ case 7:
+ pd = 16;
+ break;
+ default:
+ pd = -EINVAL;
+ break;
+ }
+
+ return pd;
+}
+EXPORT_SYMBOL_GPL(rl6231_get_pre_div);
+
+/**
+ * rl6231_calc_dmic_clk - Calculate the frequency divider parameter of dmic.
*
* @rate: base clock rate.
*
- * Choose dmic clock between 1MHz and 3MHz.
- * It is better for clock to approximate 3MHz.
+ * Choose divider parameter that gives the highest possible DMIC frequency in
+ * 1MHz - 3MHz range.
*/
int rl6231_calc_dmic_clk(int rate)
{
- int div[] = {2, 3, 4, 6, 8, 12}, idx = -EINVAL;
- int i, red, bound, temp;
+ int div[] = {2, 3, 4, 6, 8, 12};
+ int i;
+
+ if (rate < 1000000 * div[0]) {
+ pr_warn("Base clock rate %d is too low\n", rate);
+ return -EINVAL;
+ }
- red = 3000000 * 12;
for (i = 0; i < ARRAY_SIZE(div); i++) {
- bound = div[i] * 3000000;
- if (rate > bound)
- continue;
- temp = bound - rate;
- if (temp < red) {
- red = temp;
- idx = i;
- }
+ /* find divider that gives DMIC frequency below 3MHz */
+ if (3000000 * div[i] >= rate)
+ return i;
}
- return idx;
+ pr_warn("Base clock rate %d is too high\n", rate);
+ return -EINVAL;
}
EXPORT_SYMBOL_GPL(rl6231_calc_dmic_clk);
+struct pll_calc_map {
+ unsigned int pll_in;
+ unsigned int pll_out;
+ int k;
+ int n;
+ int m;
+ bool m_bp;
+};
+
+static const struct pll_calc_map pll_preset_table[] = {
+ {19200000, 24576000, 3, 30, 3, false},
+};
+
/**
* rl6231_pll_calc - Calcualte PLL M/N/K code.
* @freq_in: external clock provided to codec.
@@ -57,7 +117,7 @@ int rl6231_pll_calc(const unsigned int freq_in,
const unsigned int freq_out, struct rl6231_pll_code *pll_code)
{
int max_n = RL6231_PLL_N_MAX, max_m = RL6231_PLL_M_MAX;
- int k, red, n_t, pll_out, in_t, out_t;
+ int i, k, red, n_t, pll_out, in_t, out_t;
int n = 0, m = 0, m_t = 0;
int red_t = abs(freq_out - freq_in);
bool bypass = false;
@@ -65,6 +125,18 @@ int rl6231_pll_calc(const unsigned int freq_in,
if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in)
return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(pll_preset_table); i++) {
+ if (freq_in == pll_preset_table[i].pll_in &&
+ freq_out == pll_preset_table[i].pll_out) {
+ k = pll_preset_table[i].k;
+ m = pll_preset_table[i].m;
+ n = pll_preset_table[i].n;
+ bypass = pll_preset_table[i].m_bp;
+ pr_debug("Use preset PLL parameter table\n");
+ goto code_find;
+ }
+ }
+
k = 100000000 / freq_out - 2;
if (k > RL6231_PLL_K_MAX)
k = RL6231_PLL_K_MAX;
diff --git a/sound/soc/codecs/rl6231.h b/sound/soc/codecs/rl6231.h
index 0f7b057..4c77b44 100644
--- a/sound/soc/codecs/rl6231.h
+++ b/sound/soc/codecs/rl6231.h
@@ -30,5 +30,6 @@ int rl6231_calc_dmic_clk(int rate);
int rl6231_pll_calc(const unsigned int freq_in,
const unsigned int freq_out, struct rl6231_pll_code *pll_code);
int rl6231_get_clk_info(int sclk, int rate);
+int rl6231_get_pre_div(struct regmap *map, unsigned int reg, int sft);
#endif /* __RL6231_H__ */
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 5c43e26..bd93658 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -38,7 +38,7 @@
#define RT288_VENDOR_ID 0x10ec0288
struct rt286_priv {
- struct reg_default *index_cache;
+ const struct reg_default *index_cache;
int index_cache_size;
struct regmap *regmap;
struct snd_soc_codec *codec;
@@ -50,7 +50,7 @@ struct rt286_priv {
int clk_id;
};
-static struct reg_default rt286_index_def[] = {
+static const struct reg_default rt286_index_def[] = {
{ 0x01, 0xaaaa },
{ 0x02, 0x8aaa },
{ 0x03, 0x0002 },
@@ -1108,7 +1108,7 @@ static const struct acpi_device_id rt286_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, rt286_acpi_match);
-static struct dmi_system_id force_combo_jack_table[] = {
+static const struct dmi_system_id force_combo_jack_table[] = {
{
.ident = "Intel Wilson Beach",
.matches = {
@@ -1118,7 +1118,7 @@ static struct dmi_system_id force_combo_jack_table[] = {
{ }
};
-static struct dmi_system_id dmi_dell_dino[] = {
+static const struct dmi_system_id dmi_dell_dino[] = {
{
.ident = "Dell Dino",
.matches = {
@@ -1157,7 +1157,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
}
if (val != RT286_VENDOR_ID && val != RT288_VENDOR_ID) {
dev_err(&i2c->dev,
- "Device with ID register %x is not rt286\n", val);
+ "Device with ID register %#x is not rt286\n", val);
return -ENODEV;
}
@@ -1259,7 +1259,6 @@ static int rt286_i2c_remove(struct i2c_client *i2c)
static struct i2c_driver rt286_i2c_driver = {
.driver = {
.name = "rt286",
- .owner = THIS_MODULE,
.acpi_match_table = ACPI_PTR(rt286_acpi_match),
},
.probe = rt286_i2c_probe,
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
new file mode 100644
index 0000000..3c2f0f8
--- /dev/null
+++ b/sound/soc/codecs/rt298.c
@@ -0,0 +1,1271 @@
+/*
+ * rt298.c -- RT298 ALSA SoC audio codec driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <linux/workqueue.h>
+#include <sound/rt298.h>
+#include <sound/hda_verbs.h>
+
+#include "rl6347a.h"
+#include "rt298.h"
+
+#define RT298_VENDOR_ID 0x10ec0298
+
+struct rt298_priv {
+ struct reg_default *index_cache;
+ int index_cache_size;
+ struct regmap *regmap;
+ struct snd_soc_codec *codec;
+ struct rt298_platform_data pdata;
+ struct i2c_client *i2c;
+ struct snd_soc_jack *jack;
+ struct delayed_work jack_detect_work;
+ int sys_clk;
+ int clk_id;
+ int is_hp_in;
+};
+
+static struct reg_default rt298_index_def[] = {
+ { 0x01, 0xaaaa },
+ { 0x02, 0x8aaa },
+ { 0x03, 0x0002 },
+ { 0x04, 0xaf01 },
+ { 0x08, 0x000d },
+ { 0x09, 0xd810 },
+ { 0x0a, 0x0120 },
+ { 0x0b, 0x0000 },
+ { 0x0d, 0x2800 },
+ { 0x0f, 0x0000 },
+ { 0x19, 0x0a17 },
+ { 0x20, 0x0020 },
+ { 0x33, 0x0208 },
+ { 0x46, 0x0300 },
+ { 0x49, 0x0004 },
+ { 0x4f, 0x50e9 },
+ { 0x50, 0x2000 },
+ { 0x63, 0x2902 },
+ { 0x67, 0x1111 },
+ { 0x68, 0x1016 },
+ { 0x69, 0x273f },
+};
+#define INDEX_CACHE_SIZE ARRAY_SIZE(rt298_index_def)
+
+static const struct reg_default rt298_reg[] = {
+ { 0x00170500, 0x00000400 },
+ { 0x00220000, 0x00000031 },
+ { 0x00239000, 0x0000007f },
+ { 0x0023a000, 0x0000007f },
+ { 0x00270500, 0x00000400 },
+ { 0x00370500, 0x00000400 },
+ { 0x00870500, 0x00000400 },
+ { 0x00920000, 0x00000031 },
+ { 0x00935000, 0x000000c3 },
+ { 0x00936000, 0x000000c3 },
+ { 0x00970500, 0x00000400 },
+ { 0x00b37000, 0x00000097 },
+ { 0x00b37200, 0x00000097 },
+ { 0x00b37300, 0x00000097 },
+ { 0x00c37000, 0x00000000 },
+ { 0x00c37100, 0x00000080 },
+ { 0x01270500, 0x00000400 },
+ { 0x01370500, 0x00000400 },
+ { 0x01371f00, 0x411111f0 },
+ { 0x01439000, 0x00000080 },
+ { 0x0143a000, 0x00000080 },
+ { 0x01470700, 0x00000000 },
+ { 0x01470500, 0x00000400 },
+ { 0x01470c00, 0x00000000 },
+ { 0x01470100, 0x00000000 },
+ { 0x01837000, 0x00000000 },
+ { 0x01870500, 0x00000400 },
+ { 0x02050000, 0x00000000 },
+ { 0x02139000, 0x00000080 },
+ { 0x0213a000, 0x00000080 },
+ { 0x02170100, 0x00000000 },
+ { 0x02170500, 0x00000400 },
+ { 0x02170700, 0x00000000 },
+ { 0x02270100, 0x00000000 },
+ { 0x02370100, 0x00000000 },
+ { 0x01870700, 0x00000020 },
+ { 0x00830000, 0x000000c3 },
+ { 0x00930000, 0x000000c3 },
+ { 0x01270700, 0x00000000 },
+};
+
+static bool rt298_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0 ... 0xff:
+ case RT298_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID):
+ case RT298_GET_HP_SENSE:
+ case RT298_GET_MIC1_SENSE:
+ case RT298_PROC_COEF:
+ case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_MIC1, 0):
+ case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_SPK_OUT, 0):
+ case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_HP_OUT, 0):
+ return true;
+ default:
+ return true;
+ }
+
+
+}
+
+static bool rt298_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0 ... 0xff:
+ case RT298_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID):
+ case RT298_GET_HP_SENSE:
+ case RT298_GET_MIC1_SENSE:
+ case RT298_SET_AUDIO_POWER:
+ case RT298_SET_HPO_POWER:
+ case RT298_SET_SPK_POWER:
+ case RT298_SET_DMIC1_POWER:
+ case RT298_SPK_MUX:
+ case RT298_HPO_MUX:
+ case RT298_ADC0_MUX:
+ case RT298_ADC1_MUX:
+ case RT298_SET_MIC1:
+ case RT298_SET_PIN_HPO:
+ case RT298_SET_PIN_SPK:
+ case RT298_SET_PIN_DMIC1:
+ case RT298_SPK_EAPD:
+ case RT298_SET_AMP_GAIN_HPO:
+ case RT298_SET_DMIC2_DEFAULT:
+ case RT298_DACL_GAIN:
+ case RT298_DACR_GAIN:
+ case RT298_ADCL_GAIN:
+ case RT298_ADCR_GAIN:
+ case RT298_MIC_GAIN:
+ case RT298_SPOL_GAIN:
+ case RT298_SPOR_GAIN:
+ case RT298_HPOL_GAIN:
+ case RT298_HPOR_GAIN:
+ case RT298_F_DAC_SWITCH:
+ case RT298_F_RECMIX_SWITCH:
+ case RT298_REC_MIC_SWITCH:
+ case RT298_REC_I2S_SWITCH:
+ case RT298_REC_LINE_SWITCH:
+ case RT298_REC_BEEP_SWITCH:
+ case RT298_DAC_FORMAT:
+ case RT298_ADC_FORMAT:
+ case RT298_COEF_INDEX:
+ case RT298_PROC_COEF:
+ case RT298_SET_AMP_GAIN_ADC_IN1:
+ case RT298_SET_AMP_GAIN_ADC_IN2:
+ case RT298_SET_POWER(RT298_DAC_OUT1):
+ case RT298_SET_POWER(RT298_DAC_OUT2):
+ case RT298_SET_POWER(RT298_ADC_IN1):
+ case RT298_SET_POWER(RT298_ADC_IN2):
+ case RT298_SET_POWER(RT298_DMIC2):
+ case RT298_SET_POWER(RT298_MIC1):
+ case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_MIC1, 0):
+ case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_SPK_OUT, 0):
+ case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_HP_OUT, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifdef CONFIG_PM
+static void rt298_index_sync(struct snd_soc_codec *codec)
+{
+ struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ for (i = 0; i < INDEX_CACHE_SIZE; i++) {
+ snd_soc_write(codec, rt298->index_cache[i].reg,
+ rt298->index_cache[i].def);
+ }
+}
+#endif
+
+static int rt298_support_power_controls[] = {
+ RT298_DAC_OUT1,
+ RT298_DAC_OUT2,
+ RT298_ADC_IN1,
+ RT298_ADC_IN2,
+ RT298_MIC1,
+ RT298_DMIC1,
+ RT298_DMIC2,
+ RT298_SPK_OUT,
+ RT298_HP_OUT,
+};
+#define RT298_POWER_REG_LEN ARRAY_SIZE(rt298_support_power_controls)
+
+static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic)
+{
+ struct snd_soc_dapm_context *dapm;
+ unsigned int val, buf;
+
+ *hp = false;
+ *mic = false;
+
+ if (!rt298->codec)
+ return -EINVAL;
+
+ dapm = snd_soc_codec_get_dapm(rt298->codec);
+
+ if (rt298->pdata.cbj_en) {
+ regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf);
+ *hp = buf & 0x80000000;
+ if (*hp == rt298->is_hp_in)
+ return -1;
+ rt298->is_hp_in = *hp;
+ if (*hp) {
+ /* power on HV,VERF */
+ regmap_update_bits(rt298->regmap,
+ RT298_DC_GAIN, 0x200, 0x200);
+
+ snd_soc_dapm_force_enable_pin(dapm, "HV");
+ snd_soc_dapm_force_enable_pin(dapm, "VREF");
+ /* power LDO1 */
+ snd_soc_dapm_force_enable_pin(dapm, "LDO1");
+ snd_soc_dapm_sync(dapm);
+
+ regmap_write(rt298->regmap, RT298_SET_MIC1, 0x24);
+ msleep(50);
+
+ regmap_update_bits(rt298->regmap,
+ RT298_CBJ_CTRL1, 0xfcc0, 0xd400);
+ msleep(300);
+ regmap_read(rt298->regmap, RT298_CBJ_CTRL2, &val);
+
+ if (0x0070 == (val & 0x0070)) {
+ *mic = true;
+ } else {
+ regmap_update_bits(rt298->regmap,
+ RT298_CBJ_CTRL1, 0xfcc0, 0xe400);
+ msleep(300);
+ regmap_read(rt298->regmap,
+ RT298_CBJ_CTRL2, &val);
+ if (0x0070 == (val & 0x0070))
+ *mic = true;
+ else
+ *mic = false;
+ }
+ regmap_update_bits(rt298->regmap,
+ RT298_DC_GAIN, 0x200, 0x0);
+
+ } else {
+ *mic = false;
+ regmap_write(rt298->regmap, RT298_SET_MIC1, 0x20);
+ }
+ } else {
+ regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf);
+ *hp = buf & 0x80000000;
+ regmap_read(rt298->regmap, RT298_GET_MIC1_SENSE, &buf);
+ *mic = buf & 0x80000000;
+ }
+
+ snd_soc_dapm_disable_pin(dapm, "HV");
+ snd_soc_dapm_disable_pin(dapm, "VREF");
+ if (!*hp)
+ snd_soc_dapm_disable_pin(dapm, "LDO1");
+ snd_soc_dapm_sync(dapm);
+
+ pr_debug("*hp = %d *mic = %d\n", *hp, *mic);
+
+ return 0;
+}
+
+static void rt298_jack_detect_work(struct work_struct *work)
+{
+ struct rt298_priv *rt298 =
+ container_of(work, struct rt298_priv, jack_detect_work.work);
+ int status = 0;
+ bool hp = false;
+ bool mic = false;
+
+ if (rt298_jack_detect(rt298, &hp, &mic) < 0)
+ return;
+
+ if (hp == true)
+ status |= SND_JACK_HEADPHONE;
+
+ if (mic == true)
+ status |= SND_JACK_MICROPHONE;
+
+ snd_soc_jack_report(rt298->jack, status,
+ SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+}
+
+int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+{
+ struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+
+ rt298->jack = jack;
+
+ /* Send an initial empty report */
+ snd_soc_jack_report(rt298->jack, 0,
+ SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt298_mic_detect);
+
+static int is_mclk_mode(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+ struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+
+ if (rt298->clk_id == RT298_SCLK_S_MCLK)
+ return 1;
+ else
+ return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
+
+static const struct snd_kcontrol_new rt298_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT298_DACL_GAIN,
+ RT298_DACR_GAIN, 0, 0x7f, 0, out_vol_tlv),
+ SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT298_ADCL_GAIN,
+ RT298_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv),
+ SOC_SINGLE_TLV("AMIC Volume", RT298_MIC_GAIN,
+ 0, 0x3, 0, mic_vol_tlv),
+ SOC_DOUBLE_R("Speaker Playback Switch", RT298_SPOL_GAIN,
+ RT298_SPOR_GAIN, RT298_MUTE_SFT, 1, 1),
+};
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt298_front_mix[] = {
+ SOC_DAPM_SINGLE("DAC Switch", RT298_F_DAC_SWITCH,
+ RT298_MUTE_SFT, 1, 1),
+ SOC_DAPM_SINGLE("RECMIX Switch", RT298_F_RECMIX_SWITCH,
+ RT298_MUTE_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt298_rec_mix[] = {
+ SOC_DAPM_SINGLE("Mic1 Switch", RT298_REC_MIC_SWITCH,
+ RT298_MUTE_SFT, 1, 1),
+ SOC_DAPM_SINGLE("I2S Switch", RT298_REC_I2S_SWITCH,
+ RT298_MUTE_SFT, 1, 1),
+ SOC_DAPM_SINGLE("Line1 Switch", RT298_REC_LINE_SWITCH,
+ RT298_MUTE_SFT, 1, 1),
+ SOC_DAPM_SINGLE("Beep Switch", RT298_REC_BEEP_SWITCH,
+ RT298_MUTE_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new spo_enable_control =
+ SOC_DAPM_SINGLE("Switch", RT298_SET_PIN_SPK,
+ RT298_SET_PIN_SFT, 1, 0);
+
+static const struct snd_kcontrol_new hpol_enable_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT298_HPOL_GAIN,
+ RT298_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpor_enable_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT298_HPOR_GAIN,
+ RT298_MUTE_SFT, 1, 1);
+
+/* ADC0 source */
+static const char * const rt298_adc_src[] = {
+ "Mic", "RECMIX", "Dmic"
+};
+
+static const int rt298_adc_values[] = {
+ 0, 4, 5,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+ rt298_adc0_enum, RT298_ADC0_MUX, RT298_ADC_SEL_SFT,
+ RT298_ADC_SEL_MASK, rt298_adc_src, rt298_adc_values);
+
+static const struct snd_kcontrol_new rt298_adc0_mux =
+ SOC_DAPM_ENUM("ADC 0 source", rt298_adc0_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+ rt298_adc1_enum, RT298_ADC1_MUX, RT298_ADC_SEL_SFT,
+ RT298_ADC_SEL_MASK, rt298_adc_src, rt298_adc_values);
+
+static const struct snd_kcontrol_new rt298_adc1_mux =
+ SOC_DAPM_ENUM("ADC 1 source", rt298_adc1_enum);
+
+static const char * const rt298_dac_src[] = {
+ "Front", "Surround"
+};
+/* HP-OUT source */
+static SOC_ENUM_SINGLE_DECL(rt298_hpo_enum, RT298_HPO_MUX,
+ 0, rt298_dac_src);
+
+static const struct snd_kcontrol_new rt298_hpo_mux =
+SOC_DAPM_ENUM("HPO source", rt298_hpo_enum);
+
+/* SPK-OUT source */
+static SOC_ENUM_SINGLE_DECL(rt298_spo_enum, RT298_SPK_MUX,
+ 0, rt298_dac_src);
+
+static const struct snd_kcontrol_new rt298_spo_mux =
+SOC_DAPM_ENUM("SPO source", rt298_spo_enum);
+
+static int rt298_spk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_write(codec,
+ RT298_SPK_EAPD, RT298_SET_EAPD_HIGH);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_write(codec,
+ RT298_SPK_EAPD, RT298_SET_EAPD_LOW);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt298_set_dmic1_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_write(codec, RT298_SET_PIN_DMIC1, 0x20);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_write(codec, RT298_SET_PIN_DMIC1, 0);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt298_adc_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ unsigned int nid;
+
+ nid = (w->reg >> 20) & 0xff;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec,
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
+ 0x7080, 0x7000);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec,
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
+ 0x7080, 0x7080);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt298_mic1_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec,
+ RT298_A_BIAS_CTRL3, 0xc000, 0x8000);
+ snd_soc_update_bits(codec,
+ RT298_A_BIAS_CTRL2, 0xc000, 0x8000);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec,
+ RT298_A_BIAS_CTRL3, 0xc000, 0x0000);
+ snd_soc_update_bits(codec,
+ RT298_A_BIAS_CTRL2, 0xc000, 0x0000);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt298_vref_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec,
+ RT298_CBJ_CTRL1, 0x0400, 0x0000);
+ mdelay(50);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt298_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY_S("HV", 1, RT298_POWER_CTRL1,
+ 12, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("VREF", RT298_POWER_CTRL1,
+ 0, 1, rt298_vref_event, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY_S("BG_MBIAS", 1, RT298_POWER_CTRL2,
+ 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT298_POWER_CTRL2,
+ 2, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("LDO2", 1, RT298_POWER_CTRL2,
+ 3, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("VREF1", 1, RT298_POWER_CTRL2,
+ 4, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("LV", 2, RT298_POWER_CTRL1,
+ 13, 1, NULL, 0),
+
+
+ SND_SOC_DAPM_SUPPLY("MCLK MODE", RT298_PLL_CTRL1,
+ 5, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MIC1 Input Buffer", SND_SOC_NOPM,
+ 0, 0, rt298_mic1_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* Input Lines */
+ SND_SOC_DAPM_INPUT("DMIC1 Pin"),
+ SND_SOC_DAPM_INPUT("DMIC2 Pin"),
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("LINE1"),
+ SND_SOC_DAPM_INPUT("Beep"),
+
+ /* DMIC */
+ SND_SOC_DAPM_PGA_E("DMIC1", RT298_SET_POWER(RT298_DMIC1), 0, 1,
+ NULL, 0, rt298_set_dmic1_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA("DMIC2", RT298_SET_POWER(RT298_DMIC2), 0, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMIC Receiver", SND_SOC_NOPM,
+ 0, 0, NULL, 0),
+
+ /* REC Mixer */
+ SND_SOC_DAPM_MIXER("RECMIX", SND_SOC_NOPM, 0, 0,
+ rt298_rec_mix, ARRAY_SIZE(rt298_rec_mix)),
+
+ /* ADCs */
+ SND_SOC_DAPM_ADC("ADC 0", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0),
+
+ /* ADC Mux */
+ SND_SOC_DAPM_MUX_E("ADC 0 Mux", RT298_SET_POWER(RT298_ADC_IN1), 0, 1,
+ &rt298_adc0_mux, rt298_adc_event, SND_SOC_DAPM_PRE_PMD |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MUX_E("ADC 1 Mux", RT298_SET_POWER(RT298_ADC_IN2), 0, 1,
+ &rt298_adc1_mux, rt298_adc_event, SND_SOC_DAPM_PRE_PMD |
+ SND_SOC_DAPM_POST_PMU),
+
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Output Side */
+ /* DACs */
+ SND_SOC_DAPM_DAC("DAC 0", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC 1", NULL, SND_SOC_NOPM, 0, 0),
+
+ /* Output Mux */
+ SND_SOC_DAPM_MUX("SPK Mux", SND_SOC_NOPM, 0, 0, &rt298_spo_mux),
+ SND_SOC_DAPM_MUX("HPO Mux", SND_SOC_NOPM, 0, 0, &rt298_hpo_mux),
+
+ SND_SOC_DAPM_SUPPLY("HP Power", RT298_SET_PIN_HPO,
+ RT298_SET_PIN_SFT, 0, NULL, 0),
+
+ /* Output Mixer */
+ SND_SOC_DAPM_MIXER("Front", RT298_SET_POWER(RT298_DAC_OUT1), 0, 1,
+ rt298_front_mix, ARRAY_SIZE(rt298_front_mix)),
+ SND_SOC_DAPM_PGA("Surround", RT298_SET_POWER(RT298_DAC_OUT2), 0, 1,
+ NULL, 0),
+
+ /* Output Pga */
+ SND_SOC_DAPM_SWITCH_E("SPO", SND_SOC_NOPM, 0, 0,
+ &spo_enable_control, rt298_spk_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0,
+ &hpol_enable_control),
+ SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0,
+ &hpor_enable_control),
+
+ /* Output Lines */
+ SND_SOC_DAPM_OUTPUT("SPOL"),
+ SND_SOC_DAPM_OUTPUT("SPOR"),
+ SND_SOC_DAPM_OUTPUT("HPO Pin"),
+ SND_SOC_DAPM_OUTPUT("SPDIF"),
+};
+
+static const struct snd_soc_dapm_route rt298_dapm_routes[] = {
+
+ {"ADC 0", NULL, "MCLK MODE", is_mclk_mode},
+ {"ADC 1", NULL, "MCLK MODE", is_mclk_mode},
+ {"Front", NULL, "MCLK MODE", is_mclk_mode},
+ {"Surround", NULL, "MCLK MODE", is_mclk_mode},
+
+ {"HP Power", NULL, "LDO1"},
+ {"HP Power", NULL, "LDO2"},
+ {"HP Power", NULL, "LV"},
+ {"HP Power", NULL, "VREF1"},
+ {"HP Power", NULL, "BG_MBIAS"},
+
+ {"MIC1", NULL, "LDO1"},
+ {"MIC1", NULL, "LDO2"},
+ {"MIC1", NULL, "HV"},
+ {"MIC1", NULL, "LV"},
+ {"MIC1", NULL, "VREF"},
+ {"MIC1", NULL, "VREF1"},
+ {"MIC1", NULL, "BG_MBIAS"},
+ {"MIC1", NULL, "MIC1 Input Buffer"},
+
+ {"SPO", NULL, "LDO1"},
+ {"SPO", NULL, "LDO2"},
+ {"SPO", NULL, "HV"},
+ {"SPO", NULL, "LV"},
+ {"SPO", NULL, "VREF"},
+ {"SPO", NULL, "VREF1"},
+ {"SPO", NULL, "BG_MBIAS"},
+
+ {"DMIC1", NULL, "DMIC1 Pin"},
+ {"DMIC2", NULL, "DMIC2 Pin"},
+ {"DMIC1", NULL, "DMIC Receiver"},
+ {"DMIC2", NULL, "DMIC Receiver"},
+
+ {"RECMIX", "Beep Switch", "Beep"},
+ {"RECMIX", "Line1 Switch", "LINE1"},
+ {"RECMIX", "Mic1 Switch", "MIC1"},
+
+ {"ADC 0 Mux", "Dmic", "DMIC1"},
+ {"ADC 0 Mux", "RECMIX", "RECMIX"},
+ {"ADC 0 Mux", "Mic", "MIC1"},
+ {"ADC 1 Mux", "Dmic", "DMIC2"},
+ {"ADC 1 Mux", "RECMIX", "RECMIX"},
+ {"ADC 1 Mux", "Mic", "MIC1"},
+
+ {"ADC 0", NULL, "ADC 0 Mux"},
+ {"ADC 1", NULL, "ADC 1 Mux"},
+
+ {"AIF1TX", NULL, "ADC 0"},
+ {"AIF2TX", NULL, "ADC 1"},
+
+ {"DAC 0", NULL, "AIF1RX"},
+ {"DAC 1", NULL, "AIF2RX"},
+
+ {"Front", "DAC Switch", "DAC 0"},
+ {"Front", "RECMIX Switch", "RECMIX"},
+
+ {"Surround", NULL, "DAC 1"},
+
+ {"SPK Mux", "Front", "Front"},
+ {"SPK Mux", "Surround", "Surround"},
+
+ {"HPO Mux", "Front", "Front"},
+ {"HPO Mux", "Surround", "Surround"},
+
+ {"SPO", "Switch", "SPK Mux"},
+ {"HPO L", "Switch", "HPO Mux"},
+ {"HPO R", "Switch", "HPO Mux"},
+ {"HPO L", NULL, "HP Power"},
+ {"HPO R", NULL, "HP Power"},
+
+ {"SPOL", NULL, "SPO"},
+ {"SPOR", NULL, "SPO"},
+ {"HPO Pin", NULL, "HPO L"},
+ {"HPO Pin", NULL, "HPO R"},
+};
+
+static int rt298_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val = 0;
+ int d_len_code;
+
+ switch (params_rate(params)) {
+ /* bit 14 0:48K 1:44.1K */
+ case 44100:
+ case 48000:
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported sample rate %d\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+ switch (rt298->sys_clk) {
+ case 12288000:
+ case 24576000:
+ if (params_rate(params) != 48000) {
+ dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n",
+ params_rate(params), rt298->sys_clk);
+ return -EINVAL;
+ }
+ break;
+ case 11289600:
+ case 22579200:
+ if (params_rate(params) != 44100) {
+ dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n",
+ params_rate(params), rt298->sys_clk);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ if (params_channels(params) <= 16) {
+ /* bit 3:0 Number of Channel */
+ val |= (params_channels(params) - 1);
+ } else {
+ dev_err(codec->dev, "Unsupported channels %d\n",
+ params_channels(params));
+ return -EINVAL;
+ }
+
+ d_len_code = 0;
+ switch (params_width(params)) {
+ /* bit 6:4 Bits per Sample */
+ case 16:
+ d_len_code = 0;
+ val |= (0x1 << 4);
+ break;
+ case 32:
+ d_len_code = 2;
+ val |= (0x4 << 4);
+ break;
+ case 20:
+ d_len_code = 1;
+ val |= (0x2 << 4);
+ break;
+ case 24:
+ d_len_code = 2;
+ val |= (0x3 << 4);
+ break;
+ case 8:
+ d_len_code = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL1, 0x0018, d_len_code << 3);
+ dev_dbg(codec->dev, "format val = 0x%x\n", val);
+
+ snd_soc_update_bits(codec, RT298_DAC_FORMAT, 0x407f, val);
+ snd_soc_update_bits(codec, RT298_ADC_FORMAT, 0x407f, val);
+
+ return 0;
+}
+
+static int rt298_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL1, 0x800, 0x800);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL1, 0x800, 0x0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL1, 0x300, 0x0);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL1, 0x300, 0x1 << 8);
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL1, 0x300, 0x2 << 8);
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL1, 0x300, 0x3 << 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* bit 15 Stream Type 0:PCM 1:Non-PCM */
+ snd_soc_update_bits(codec, RT298_DAC_FORMAT, 0x8000, 0);
+ snd_soc_update_bits(codec, RT298_ADC_FORMAT, 0x8000, 0);
+
+ return 0;
+}
+
+static int rt298_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s freq=%d\n", __func__, freq);
+
+ if (RT298_SCLK_S_MCLK == clk_id) {
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL2, 0x0100, 0x0);
+ snd_soc_update_bits(codec,
+ RT298_PLL_CTRL1, 0x20, 0x20);
+ } else {
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL2, 0x0100, 0x0100);
+ snd_soc_update_bits(codec,
+ RT298_PLL_CTRL, 0x4, 0x4);
+ snd_soc_update_bits(codec,
+ RT298_PLL_CTRL1, 0x20, 0x0);
+ }
+
+ switch (freq) {
+ case 19200000:
+ if (RT298_SCLK_S_MCLK == clk_id) {
+ dev_err(codec->dev, "Should not use MCLK\n");
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL2, 0x40, 0x40);
+ break;
+ case 24000000:
+ if (RT298_SCLK_S_MCLK == clk_id) {
+ dev_err(codec->dev, "Should not use MCLK\n");
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL2, 0x40, 0x0);
+ break;
+ case 12288000:
+ case 11289600:
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL2, 0x8, 0x0);
+ snd_soc_update_bits(codec,
+ RT298_CLK_DIV, 0xfc1e, 0x0004);
+ break;
+ case 24576000:
+ case 22579200:
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL2, 0x8, 0x8);
+ snd_soc_update_bits(codec,
+ RT298_CLK_DIV, 0xfc1e, 0x5406);
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported system clock\n");
+ return -EINVAL;
+ }
+
+ rt298->sys_clk = freq;
+ rt298->clk_id = clk_id;
+
+ return 0;
+}
+
+static int rt298_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+ if (50 == ratio)
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL1, 0x1000, 0x1000);
+ else
+ snd_soc_update_bits(codec,
+ RT298_I2S_CTRL1, 0x1000, 0x0);
+
+
+ return 0;
+}
+
+static int rt298_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_PREPARE:
+ if (SND_SOC_BIAS_STANDBY ==
+ snd_soc_codec_get_bias_level(codec)) {
+ snd_soc_write(codec,
+ RT298_SET_AUDIO_POWER, AC_PWRST_D0);
+ snd_soc_update_bits(codec, 0x0d, 0x200, 0x200);
+ snd_soc_update_bits(codec, 0x52, 0x80, 0x0);
+ mdelay(20);
+ snd_soc_update_bits(codec, 0x0d, 0x200, 0x0);
+ snd_soc_update_bits(codec, 0x52, 0x80, 0x80);
+ }
+ break;
+
+ case SND_SOC_BIAS_ON:
+ mdelay(30);
+ snd_soc_update_bits(codec,
+ RT298_CBJ_CTRL1, 0x0400, 0x0400);
+
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ snd_soc_write(codec,
+ RT298_SET_AUDIO_POWER, AC_PWRST_D3);
+ snd_soc_update_bits(codec,
+ RT298_CBJ_CTRL1, 0x0400, 0x0000);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static irqreturn_t rt298_irq(int irq, void *data)
+{
+ struct rt298_priv *rt298 = data;
+ bool hp = false;
+ bool mic = false;
+ int ret, status = 0;
+
+ ret = rt298_jack_detect(rt298, &hp, &mic);
+
+ /* Clear IRQ */
+ regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x1, 0x1);
+
+ if (ret == 0) {
+ if (hp == true)
+ status |= SND_JACK_HEADPHONE;
+
+ if (mic == true)
+ status |= SND_JACK_MICROPHONE;
+
+ snd_soc_jack_report(rt298->jack, status,
+ SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+
+ pm_wakeup_event(&rt298->i2c->dev, 300);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int rt298_probe(struct snd_soc_codec *codec)
+{
+ struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+
+ rt298->codec = codec;
+
+ if (rt298->i2c->irq) {
+ regmap_update_bits(rt298->regmap,
+ RT298_IRQ_CTRL, 0x2, 0x2);
+
+ INIT_DELAYED_WORK(&rt298->jack_detect_work,
+ rt298_jack_detect_work);
+ schedule_delayed_work(&rt298->jack_detect_work,
+ msecs_to_jiffies(1250));
+ }
+
+ return 0;
+}
+
+static int rt298_remove(struct snd_soc_codec *codec)
+{
+ struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+
+ cancel_delayed_work_sync(&rt298->jack_detect_work);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt298_suspend(struct snd_soc_codec *codec)
+{
+ struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+
+ rt298->is_hp_in = -1;
+ regcache_cache_only(rt298->regmap, true);
+ regcache_mark_dirty(rt298->regmap);
+
+ return 0;
+}
+
+static int rt298_resume(struct snd_soc_codec *codec)
+{
+ struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(rt298->regmap, false);
+ rt298_index_sync(codec);
+ regcache_sync(rt298->regmap);
+
+ return 0;
+}
+#else
+#define rt298_suspend NULL
+#define rt298_resume NULL
+#endif
+
+#define RT298_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define RT298_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt298_aif_dai_ops = {
+ .hw_params = rt298_hw_params,
+ .set_fmt = rt298_set_dai_fmt,
+ .set_sysclk = rt298_set_dai_sysclk,
+ .set_bclk_ratio = rt298_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt298_dai[] = {
+ {
+ .name = "rt298-aif1",
+ .id = RT298_AIF1,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT298_STEREO_RATES,
+ .formats = RT298_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT298_STEREO_RATES,
+ .formats = RT298_FORMATS,
+ },
+ .ops = &rt298_aif_dai_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .name = "rt298-aif2",
+ .id = RT298_AIF2,
+ .playback = {
+ .stream_name = "AIF2 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT298_STEREO_RATES,
+ .formats = RT298_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT298_STEREO_RATES,
+ .formats = RT298_FORMATS,
+ },
+ .ops = &rt298_aif_dai_ops,
+ .symmetric_rates = 1,
+ },
+
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt298 = {
+ .probe = rt298_probe,
+ .remove = rt298_remove,
+ .suspend = rt298_suspend,
+ .resume = rt298_resume,
+ .set_bias_level = rt298_set_bias_level,
+ .idle_bias_off = true,
+ .controls = rt298_snd_controls,
+ .num_controls = ARRAY_SIZE(rt298_snd_controls),
+ .dapm_widgets = rt298_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt298_dapm_widgets),
+ .dapm_routes = rt298_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt298_dapm_routes),
+};
+
+static const struct regmap_config rt298_regmap = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .max_register = 0x02370100,
+ .volatile_reg = rt298_volatile_register,
+ .readable_reg = rt298_readable_register,
+ .reg_write = rl6347a_hw_write,
+ .reg_read = rl6347a_hw_read,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rt298_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt298_reg),
+};
+
+static const struct i2c_device_id rt298_i2c_id[] = {
+ {"rt298", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, rt298_i2c_id);
+
+static const struct acpi_device_id rt298_acpi_match[] = {
+ { "INT343A", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, rt298_acpi_match);
+
+static int rt298_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt298_platform_data *pdata = dev_get_platdata(&i2c->dev);
+ struct rt298_priv *rt298;
+ struct device *dev = &i2c->dev;
+ const struct acpi_device_id *acpiid;
+ int i, ret;
+
+ rt298 = devm_kzalloc(&i2c->dev, sizeof(*rt298),
+ GFP_KERNEL);
+ if (NULL == rt298)
+ return -ENOMEM;
+
+ rt298->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt298_regmap);
+ if (IS_ERR(rt298->regmap)) {
+ ret = PTR_ERR(rt298->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_read(rt298->regmap,
+ RT298_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &ret);
+ if (ret != RT298_VENDOR_ID) {
+ dev_err(&i2c->dev,
+ "Device with ID register %#x is not rt298\n", ret);
+ return -ENODEV;
+ }
+
+ rt298->index_cache = rt298_index_def;
+ rt298->index_cache_size = INDEX_CACHE_SIZE;
+ rt298->i2c = i2c;
+ i2c_set_clientdata(i2c, rt298);
+
+ /* restore codec default */
+ for (i = 0; i < INDEX_CACHE_SIZE; i++)
+ regmap_write(rt298->regmap, rt298->index_cache[i].reg,
+ rt298->index_cache[i].def);
+ for (i = 0; i < ARRAY_SIZE(rt298_reg); i++)
+ regmap_write(rt298->regmap, rt298_reg[i].reg,
+ rt298_reg[i].def);
+
+ if (pdata)
+ rt298->pdata = *pdata;
+
+ /* enable jack combo mode on supported devices */
+ acpiid = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (acpiid) {
+ rt298->pdata = *(struct rt298_platform_data *)
+ acpiid->driver_data;
+ }
+
+ /* VREF Charging */
+ regmap_update_bits(rt298->regmap, 0x04, 0x80, 0x80);
+ regmap_update_bits(rt298->regmap, 0x1b, 0x860, 0x860);
+ /* Vref2 */
+ regmap_update_bits(rt298->regmap, 0x08, 0x20, 0x20);
+
+ regmap_write(rt298->regmap, RT298_SET_AUDIO_POWER, AC_PWRST_D3);
+
+ for (i = 0; i < RT298_POWER_REG_LEN; i++)
+ regmap_write(rt298->regmap,
+ RT298_SET_POWER(rt298_support_power_controls[i]),
+ AC_PWRST_D1);
+
+ if (!rt298->pdata.cbj_en) {
+ regmap_write(rt298->regmap, RT298_CBJ_CTRL2, 0x0000);
+ regmap_write(rt298->regmap, RT298_MIC1_DET_CTRL, 0x0816);
+ regmap_update_bits(rt298->regmap,
+ RT298_CBJ_CTRL1, 0xf000, 0xb000);
+ } else {
+ regmap_update_bits(rt298->regmap,
+ RT298_CBJ_CTRL1, 0xf000, 0x5000);
+ }
+
+ mdelay(10);
+
+ if (!rt298->pdata.gpio2_en)
+ regmap_write(rt298->regmap, RT298_SET_DMIC2_DEFAULT, 0x4000);
+ else
+ regmap_write(rt298->regmap, RT298_SET_DMIC2_DEFAULT, 0);
+
+ mdelay(10);
+
+ regmap_write(rt298->regmap, RT298_MISC_CTRL1, 0x0000);
+ regmap_update_bits(rt298->regmap,
+ RT298_WIND_FILTER_CTRL, 0x0082, 0x0082);
+ regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2);
+ rt298->is_hp_in = -1;
+
+ if (rt298->i2c->irq) {
+ ret = request_threaded_irq(rt298->i2c->irq, NULL, rt298_irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt298", rt298);
+ if (ret != 0) {
+ dev_err(&i2c->dev,
+ "Failed to reguest IRQ: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt298,
+ rt298_dai, ARRAY_SIZE(rt298_dai));
+
+ return ret;
+}
+
+static int rt298_i2c_remove(struct i2c_client *i2c)
+{
+ struct rt298_priv *rt298 = i2c_get_clientdata(i2c);
+
+ if (i2c->irq)
+ free_irq(i2c->irq, rt298);
+ snd_soc_unregister_codec(&i2c->dev);
+
+ return 0;
+}
+
+
+static struct i2c_driver rt298_i2c_driver = {
+ .driver = {
+ .name = "rt298",
+ .acpi_match_table = ACPI_PTR(rt298_acpi_match),
+ },
+ .probe = rt298_i2c_probe,
+ .remove = rt298_i2c_remove,
+ .id_table = rt298_i2c_id,
+};
+
+module_i2c_driver(rt298_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT298 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt298.h b/sound/soc/codecs/rt298.h
new file mode 100644
index 0000000..31da162
--- /dev/null
+++ b/sound/soc/codecs/rt298.h
@@ -0,0 +1,206 @@
+/*
+ * rt298.h -- RT298 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT298_H__
+#define __RT298_H__
+
+#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D)
+
+#define RT298_AUDIO_FUNCTION_GROUP 0x01
+#define RT298_DAC_OUT1 0x02
+#define RT298_DAC_OUT2 0x03
+#define RT298_DIG_CVT 0x06
+#define RT298_ADC_IN1 0x09
+#define RT298_ADC_IN2 0x08
+#define RT298_MIXER_IN 0x0b
+#define RT298_MIXER_OUT1 0x0c
+#define RT298_MIXER_OUT2 0x0d
+#define RT298_DMIC1 0x12
+#define RT298_DMIC2 0x13
+#define RT298_SPK_OUT 0x14
+#define RT298_MIC1 0x18
+#define RT298_LINE1 0x1a
+#define RT298_BEEP 0x1d
+#define RT298_SPDIF 0x1e
+#define RT298_VENDOR_REGISTERS 0x20
+#define RT298_HP_OUT 0x21
+#define RT298_MIXER_IN1 0x22
+#define RT298_MIXER_IN2 0x23
+
+#define RT298_SET_PIN_SFT 6
+#define RT298_SET_PIN_ENABLE 0x40
+#define RT298_SET_PIN_DISABLE 0
+#define RT298_SET_EAPD_HIGH 0x2
+#define RT298_SET_EAPD_LOW 0
+
+#define RT298_MUTE_SFT 7
+
+/* Verb commands */
+#define RT298_GET_PARAM(NID, PARAM) VERB_CMD(AC_VERB_PARAMETERS, NID, PARAM)
+#define RT298_SET_POWER(NID) VERB_CMD(AC_VERB_SET_POWER_STATE, NID, 0)
+#define RT298_SET_AUDIO_POWER RT298_SET_POWER(RT298_AUDIO_FUNCTION_GROUP)
+#define RT298_SET_HPO_POWER RT298_SET_POWER(RT298_HP_OUT)
+#define RT298_SET_SPK_POWER RT298_SET_POWER(RT298_SPK_OUT)
+#define RT298_SET_DMIC1_POWER RT298_SET_POWER(RT298_DMIC1)
+#define RT298_SPK_MUX\
+ VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_SPK_OUT, 0)
+#define RT298_HPO_MUX\
+ VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_HP_OUT, 0)
+#define RT298_ADC0_MUX\
+ VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_MIXER_IN1, 0)
+#define RT298_ADC1_MUX\
+ VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_MIXER_IN2, 0)
+#define RT298_SET_MIC1\
+ VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_MIC1, 0)
+#define RT298_SET_PIN_HPO\
+ VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_HP_OUT, 0)
+#define RT298_SET_PIN_SPK\
+ VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_SPK_OUT, 0)
+#define RT298_SET_PIN_DMIC1\
+ VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_DMIC1, 0)
+#define RT298_SET_PIN_SPDIF\
+ VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_SPDIF, 0)
+#define RT298_SET_PIN_DIG_CVT\
+ VERB_CMD(AC_VERB_SET_DIGI_CONVERT_1, RT298_DIG_CVT, 0)
+#define RT298_SPK_EAPD\
+ VERB_CMD(AC_VERB_SET_EAPD_BTLENABLE, RT298_SPK_OUT, 0)
+#define RT298_SET_AMP_GAIN_HPO\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_HP_OUT, 0)
+#define RT298_SET_AMP_GAIN_ADC_IN1\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN1, 0)
+#define RT298_SET_AMP_GAIN_ADC_IN2\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN2, 0)
+#define RT298_GET_HP_SENSE\
+ VERB_CMD(AC_VERB_GET_PIN_SENSE, RT298_HP_OUT, 0)
+#define RT298_GET_MIC1_SENSE\
+ VERB_CMD(AC_VERB_GET_PIN_SENSE, RT298_MIC1, 0)
+#define RT298_SET_DMIC2_DEFAULT\
+ VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT298_DMIC2, 0)
+#define RT298_SET_SPDIF_DEFAULT\
+ VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT298_SPDIF, 0)
+#define RT298_DACL_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_DAC_OUT1, 0xa000)
+#define RT298_DACR_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_DAC_OUT1, 0x9000)
+#define RT298_ADCL_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN1, 0x6000)
+#define RT298_ADCR_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN1, 0x5000)
+#define RT298_MIC_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIC1, 0x7000)
+#define RT298_SPOL_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_SPK_OUT, 0xa000)
+#define RT298_SPOR_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_SPK_OUT, 0x9000)
+#define RT298_HPOL_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_HP_OUT, 0xa000)
+#define RT298_HPOR_GAIN\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_HP_OUT, 0x9000)
+#define RT298_F_DAC_SWITCH\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_OUT1, 0x7000)
+#define RT298_F_RECMIX_SWITCH\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_OUT1, 0x7100)
+#define RT298_REC_MIC_SWITCH\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7000)
+#define RT298_REC_I2S_SWITCH\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7100)
+#define RT298_REC_LINE_SWITCH\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7200)
+#define RT298_REC_BEEP_SWITCH\
+ VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7300)
+#define RT298_DAC_FORMAT\
+ VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT298_DAC_OUT1, 0)
+#define RT298_ADC_FORMAT\
+ VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT298_ADC_IN1, 0)
+#define RT298_COEF_INDEX\
+ VERB_CMD(AC_VERB_SET_COEF_INDEX, RT298_VENDOR_REGISTERS, 0)
+#define RT298_PROC_COEF\
+ VERB_CMD(AC_VERB_SET_PROC_COEF, RT298_VENDOR_REGISTERS, 0)
+
+/* Index registers */
+#define RT298_A_BIAS_CTRL1 0x01
+#define RT298_A_BIAS_CTRL2 0x02
+#define RT298_POWER_CTRL1 0x03
+#define RT298_A_BIAS_CTRL3 0x04
+#define RT298_POWER_CTRL2 0x08
+#define RT298_I2S_CTRL1 0x09
+#define RT298_I2S_CTRL2 0x0a
+#define RT298_CLK_DIV 0x0b
+#define RT298_DC_GAIN 0x0d
+#define RT298_POWER_CTRL3 0x0f
+#define RT298_MIC1_DET_CTRL 0x19
+#define RT298_MISC_CTRL1 0x20
+#define RT298_IRQ_CTRL 0x33
+#define RT298_WIND_FILTER_CTRL 0x46
+#define RT298_PLL_CTRL1 0x49
+#define RT298_CBJ_CTRL1 0x4f
+#define RT298_CBJ_CTRL2 0x50
+#define RT298_PLL_CTRL 0x63
+#define RT298_DEPOP_CTRL1 0x66
+#define RT298_DEPOP_CTRL2 0x67
+#define RT298_DEPOP_CTRL3 0x68
+#define RT298_DEPOP_CTRL4 0x69
+
+/* SPDIF (0x06) */
+#define RT298_SPDIF_SEL_SFT 0
+#define RT298_SPDIF_SEL_PCM0 0
+#define RT298_SPDIF_SEL_PCM1 1
+#define RT298_SPDIF_SEL_SPOUT 2
+#define RT298_SPDIF_SEL_PP 3
+
+/* RECMIX (0x0b) */
+#define RT298_M_REC_BEEP_SFT 0
+#define RT298_M_REC_LINE1_SFT 1
+#define RT298_M_REC_MIC1_SFT 2
+#define RT298_M_REC_I2S_SFT 3
+
+/* Front (0x0c) */
+#define RT298_M_FRONT_DAC_SFT 0
+#define RT298_M_FRONT_REC_SFT 1
+
+/* SPK-OUT (0x14) */
+#define RT298_M_SPK_MUX_SFT 14
+#define RT298_SPK_SEL_MASK 0x1
+#define RT298_SPK_SEL_SFT 0
+#define RT298_SPK_SEL_F 0
+#define RT298_SPK_SEL_S 1
+
+/* HP-OUT (0x21) */
+#define RT298_M_HP_MUX_SFT 14
+#define RT298_HP_SEL_MASK 0x1
+#define RT298_HP_SEL_SFT 0
+#define RT298_HP_SEL_F 0
+#define RT298_HP_SEL_S 1
+
+/* ADC (0x22) (0x23) */
+#define RT298_ADC_SEL_MASK 0x7
+#define RT298_ADC_SEL_SFT 0
+#define RT298_ADC_SEL_SURR 0
+#define RT298_ADC_SEL_FRONT 1
+#define RT298_ADC_SEL_DMIC 2
+#define RT298_ADC_SEL_BEEP 4
+#define RT298_ADC_SEL_LINE1 5
+#define RT298_ADC_SEL_I2S 6
+#define RT298_ADC_SEL_MIC1 7
+
+#define RT298_SCLK_S_MCLK 0
+#define RT298_SCLK_S_PLL 1
+
+enum {
+ RT298_AIF1,
+ RT298_AIF2,
+ RT298_AIFS,
+};
+
+int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+
+#endif /* __RT298_H__ */
+
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 058167c..1be2bab 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -174,16 +174,15 @@ static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -95625, 375, 0);
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
/* {0, +20, +24, +30, +35, +40, +44, +50, +52}dB */
-static unsigned int mic_bst_tlv[] = {
- TLV_DB_RANGE_HEAD(7),
+static const DECLARE_TLV_DB_RANGE(mic_bst_tlv,
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
- 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
-};
+ 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
static int rt5631_dmic_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1725,7 +1724,6 @@ static int rt5631_i2c_remove(struct i2c_client *client)
static struct i2c_driver rt5631_i2c_driver = {
.driver = {
.name = "rt5631",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(rt5631_i2c_dt_ids),
},
.probe = rt5631_i2c_probe,
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 9bc78e5..e1ceeb8 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -51,7 +51,7 @@ static const struct regmap_range_cfg rt5640_ranges[] = {
.window_len = 0x1, },
};
-static const struct reg_default init_list[] = {
+static const struct reg_sequence init_list[] = {
{RT5640_PR_BASE + 0x3d, 0x3600},
{RT5640_PR_BASE + 0x12, 0x0aa8},
{RT5640_PR_BASE + 0x14, 0x0aaa},
@@ -347,16 +347,15 @@ static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
-static unsigned int bst_tlv[] = {
- TLV_DB_RANGE_HEAD(7),
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
- 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
-};
+ 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
/* Interface data select */
static const char * const rt5640_data_select[] = {
@@ -459,10 +458,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- int idx = -EINVAL;
-
- idx = rl6231_calc_dmic_clk(rt5640->sysclk);
+ int idx, rate;
+ rate = rt5640->sysclk / rl6231_get_pre_div(rt5640->regmap,
+ RT5640_ADDA_CLK1, RT5640_I2S_PD1_SFT);
+ idx = rl6231_calc_dmic_clk(rate);
if (idx < 0)
dev_err(codec->dev, "Failed to set DMIC clock\n");
else
@@ -984,6 +984,35 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int rt5640_lout_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ hp_amp_power_on(codec);
+ snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+ RT5640_PWR_LM, RT5640_PWR_LM);
+ snd_soc_update_bits(codec, RT5640_OUTPUT,
+ RT5640_L_MUTE | RT5640_R_MUTE, 0);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5640_OUTPUT,
+ RT5640_L_MUTE | RT5640_R_MUTE,
+ RT5640_L_MUTE | RT5640_R_MUTE);
+ snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+ RT5640_PWR_LM, 0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -1179,13 +1208,16 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
0, rt5640_spo_l_mix, ARRAY_SIZE(rt5640_spo_l_mix)),
SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0,
0, rt5640_spo_r_mix, ARRAY_SIZE(rt5640_spo_r_mix)),
- SND_SOC_DAPM_MIXER("LOUT MIX", RT5640_PWR_ANLG1, RT5640_PWR_LM_BIT, 0,
+ SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0,
rt5640_lout_mix, ARRAY_SIZE(rt5640_lout_mix)),
SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM,
0, 0, rt5640_hp_power_event, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0,
rt5640_hp_event,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0,
+ rt5640_lout_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("HP L Amp", RT5640_PWR_ANLG1,
RT5640_PWR_HP_L_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("HP R Amp", RT5640_PWR_ANLG1,
@@ -1500,8 +1532,10 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"HP R Playback", "Switch", "HP Amp"},
{"HPOL", NULL, "HP L Playback"},
{"HPOR", NULL, "HP R Playback"},
- {"LOUTL", NULL, "LOUT MIX"},
- {"LOUTR", NULL, "LOUT MIX"},
+
+ {"LOUT amp", NULL, "LOUT MIX"},
+ {"LOUTL", NULL, "LOUT amp"},
+ {"LOUTR", NULL, "LOUT amp"},
};
static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = {
@@ -2207,7 +2241,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val);
if (val != RT5640_DEVICE_ID) {
dev_err(&i2c->dev,
- "Device with ID register %x is not rt5640/39\n", val);
+ "Device with ID register %#x is not rt5640/39\n", val);
return -ENODEV;
}
@@ -2242,7 +2276,6 @@ static int rt5640_i2c_remove(struct i2c_client *i2c)
static struct i2c_driver rt5640_i2c_driver = {
.driver = {
.name = "rt5640",
- .owner = THIS_MODULE,
.acpi_match_table = ACPI_PTR(rt5640_acpi_match),
.of_match_table = of_match_ptr(rt5640_of_match),
},
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 961bd7e..4972bf3 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -21,6 +21,7 @@
#include <linux/gpio/consumer.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
+#include <linux/regulator/consumer.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -54,7 +55,7 @@ static const struct regmap_range_cfg rt5645_ranges[] = {
},
};
-static const struct reg_default init_list[] = {
+static const struct reg_sequence init_list[] = {
{RT5645_PR_BASE + 0x3d, 0x3600},
{RT5645_PR_BASE + 0x1c, 0xfd20},
{RT5645_PR_BASE + 0x20, 0x611f},
@@ -63,7 +64,7 @@ static const struct reg_default init_list[] = {
};
#define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list)
-static const struct reg_default rt5650_init_list[] = {
+static const struct reg_sequence rt5650_init_list[] = {
{0xf6, 0x0100},
};
@@ -223,6 +224,39 @@ static const struct reg_default rt5645_reg[] = {
{ 0xff, 0x6308 },
};
+static const char *const rt5645_supply_names[] = {
+ "avdd",
+ "cpvdd",
+};
+
+struct rt5645_priv {
+ struct snd_soc_codec *codec;
+ struct rt5645_platform_data pdata;
+ struct regmap *regmap;
+ struct i2c_client *i2c;
+ struct gpio_desc *gpiod_hp_det;
+ struct snd_soc_jack *hp_jack;
+ struct snd_soc_jack *mic_jack;
+ struct snd_soc_jack *btn_jack;
+ struct delayed_work jack_detect_work;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)];
+
+ int codec_type;
+ int sysclk;
+ int sysclk_src;
+ int lrck[RT5645_AIFS];
+ int bclk[RT5645_AIFS];
+ int master[RT5645_AIFS];
+
+ int pll_src;
+ int pll_in;
+ int pll_out;
+
+ int jack_type;
+ bool en_button_func;
+ bool hp_on;
+};
+
static int rt5645_reset(struct snd_soc_codec *codec)
{
return snd_soc_write(codec, RT5645_RESET, 0);
@@ -360,6 +394,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
case RT5645_DEPOP_M1:
case RT5645_DEPOP_M2:
case RT5645_DEPOP_M3:
+ case RT5645_CHARGE_PUMP:
case RT5645_MICBIAS:
case RT5645_A_JD_CTRL1:
case RT5645_VAD_CTRL4:
@@ -424,16 +459,15 @@ static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
-static unsigned int bst_tlv[] = {
- TLV_DB_RANGE_HEAD(7),
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
- 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
-};
+ 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
static const struct snd_kcontrol_new rt5645_snd_controls[] = {
/* Speaker Output Volume */
@@ -510,10 +544,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
- int idx = -EINVAL;
-
- idx = rl6231_calc_dmic_clk(rt5645->sysclk);
+ int idx, rate;
+ rate = rt5645->sysclk / rl6231_get_pre_div(rt5645->regmap,
+ RT5645_ADDA_CLK1, RT5645_I2S_PD1_SFT);
+ idx = rl6231_calc_dmic_clk(rate);
if (idx < 0)
dev_err(codec->dev, "Failed to set DMIC clock\n");
else
@@ -1331,15 +1366,23 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
if (on) {
if (hp_amp_power_count <= 0) {
if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+ snd_soc_write(codec, RT5645_DEPOP_M2, 0x3100);
snd_soc_write(codec, RT5645_CHARGE_PUMP,
0x0e06);
- snd_soc_write(codec, RT5645_DEPOP_M1, 0x001d);
+ snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ RT5645_HP_DCC_INT1, 0x9f01);
+ msleep(20);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_HP_CO_MASK, RT5645_HP_CO_EN);
regmap_write(rt5645->regmap, RT5645_PR_BASE +
0x3e, 0x7400);
snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
regmap_write(rt5645->regmap, RT5645_PR_BASE +
RT5645_MAMP_INT_REG2, 0xfc00);
snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
+ mdelay(5);
+ rt5645->hp_on = true;
} else {
/* depop parameters */
snd_soc_update_bits(codec, RT5645_DEPOP_M2,
@@ -1553,6 +1596,27 @@ static int rt5645_bst2_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int rt5650_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (rt5645->hp_on) {
+ msleep(100);
+ rt5645->hp_on = false;
+ }
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("LDO2", RT5645_PWR_MIXER,
RT5645_PWR_LDO2_BIT, 0, NULL, 0),
@@ -1697,15 +1761,6 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
/* IF1 2 Mux */
- SND_SOC_DAPM_MUX("RT5645 IF1 ADC1 Swap Mux", SND_SOC_NOPM,
- 0, 0, &rt5645_if1_adc1_in_mux),
- SND_SOC_DAPM_MUX("RT5645 IF1 ADC2 Swap Mux", SND_SOC_NOPM,
- 0, 0, &rt5645_if1_adc2_in_mux),
- SND_SOC_DAPM_MUX("RT5645 IF1 ADC3 Swap Mux", SND_SOC_NOPM,
- 0, 0, &rt5645_if1_adc3_in_mux),
- SND_SOC_DAPM_MUX("RT5645 IF1 ADC Mux", SND_SOC_NOPM,
- 0, 0, &rt5645_if1_adc_in_mux),
-
SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM,
0, 0, &rt5645_if2_adc_in_mux),
@@ -1716,14 +1771,6 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0,
- &rt5645_if1_dac0_tdm_sel_mux),
- SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0,
- &rt5645_if1_dac1_tdm_sel_mux),
- SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0,
- &rt5645_if1_dac2_tdm_sel_mux),
- SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0,
- &rt5645_if1_dac3_tdm_sel_mux),
SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -1854,6 +1901,26 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("PDM1R"),
SND_SOC_DAPM_OUTPUT("SPOL"),
SND_SOC_DAPM_OUTPUT("SPOR"),
+ SND_SOC_DAPM_POST("DAPM_POST", rt5650_hp_event),
+};
+
+static const struct snd_soc_dapm_widget rt5645_specific_dapm_widgets[] = {
+ SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_if1_dac0_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_if1_dac1_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_if1_dac2_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_if1_dac3_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 ADC Mux", SND_SOC_NOPM,
+ 0, 0, &rt5645_if1_adc_in_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 ADC1 Swap Mux", SND_SOC_NOPM,
+ 0, 0, &rt5645_if1_adc1_in_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 ADC2 Swap Mux", SND_SOC_NOPM,
+ 0, 0, &rt5645_if1_adc2_in_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 ADC3 Swap Mux", SND_SOC_NOPM,
+ 0, 0, &rt5645_if1_adc3_in_mux),
};
static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = {
@@ -2642,7 +2709,7 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
+ if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
RT5645_PWR_VREF1 | RT5645_PWR_MB |
RT5645_PWR_BG | RT5645_PWR_VREF2,
@@ -2686,94 +2753,15 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int rt5650_calibration(struct rt5645_priv *rt5645)
-{
- int val, i;
- int ret = -1;
-
- regcache_cache_bypass(rt5645->regmap, true);
- regmap_write(rt5645->regmap, RT5645_RESET, 0);
- regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0800);
- regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_CHOP_DAC_ADC,
- 0x3600);
- regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x25, 0x7000);
- regmap_write(rt5645->regmap, RT5645_I2S1_SDP, 0x8008);
- /* headset type */
- regmap_write(rt5645->regmap, RT5645_GEN_CTRL1, 0x2061);
- regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006);
- regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0x2012);
- regmap_write(rt5645->regmap, RT5645_PWR_MIXER, 0x0002);
- regmap_write(rt5645->regmap, RT5645_PWR_VOL, 0x0020);
- regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0);
- regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006);
- regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x1827);
- regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x0827);
- msleep(400);
- /* Inline command */
- regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0001);
- regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000);
- regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008);
- /* Calbration */
- regmap_write(rt5645->regmap, RT5645_GLB_CLK, 0x8000);
- regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000);
- regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000);
- regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008);
- regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x8800);
- regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0xe8fa);
- regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x8c04);
- regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x3100);
- regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
- regmap_write(rt5645->regmap, RT5645_BASS_BACK, 0x8a13);
- regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0820);
- regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x000d);
- /* Power on and Calbration */
- regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_HP_DCC_INT1,
- 0x9f01);
- msleep(200);
- for (i = 0; i < 5; i++) {
- regmap_read(rt5645->regmap, RT5645_PR_BASE + 0x7a, &val);
- if (val != 0 && val != 0x3f3f) {
- ret = 0;
- break;
- }
- msleep(50);
- }
- pr_debug("%s: PR-7A = 0x%x\n", __func__, val);
-
- /* mute */
- regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x3e, 0x7400);
- regmap_write(rt5645->regmap, RT5645_DEPOP_M3, 0x0737);
- regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2,
- 0xfc00);
- regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x1140);
- regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000);
- regmap_write(rt5645->regmap, RT5645_GEN_CTRL2, 0x4020);
- regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x0006);
- regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x0000);
- msleep(350);
-
- regcache_cache_bypass(rt5645->regmap, false);
-
- return ret;
-}
-
static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec,
bool enable)
{
- struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
if (enable) {
- snd_soc_dapm_mutex_lock(&codec->dapm);
- snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
- "ADC L power");
- snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
- "ADC R power");
- snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
- "LDO2");
- snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
- "Mic Det Power");
- snd_soc_dapm_sync_unlocked(&codec->dapm);
- snd_soc_dapm_mutex_unlock(&codec->dapm);
+ snd_soc_dapm_force_enable_pin(dapm, "ADC L power");
+ snd_soc_dapm_force_enable_pin(dapm, "ADC R power");
+ snd_soc_dapm_sync(dapm);
snd_soc_update_bits(codec,
RT5645_INT_IRQ_ST, 0x8, 0x8);
@@ -2786,36 +2774,26 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec,
snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD2, 0x8000, 0x0);
snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x0);
- snd_soc_dapm_mutex_lock(&codec->dapm);
- snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
- "ADC L power");
- snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
- "ADC R power");
- if (rt5645->pdata.jd_mode == 0)
- snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
- "LDO2");
- snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
- "Mic Det Power");
- snd_soc_dapm_sync_unlocked(&codec->dapm);
- snd_soc_dapm_mutex_unlock(&codec->dapm);
+ snd_soc_dapm_disable_pin(dapm, "ADC L power");
+ snd_soc_dapm_disable_pin(dapm, "ADC R power");
+ snd_soc_dapm_sync(dapm);
}
}
static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
unsigned int val;
if (jack_insert) {
regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006);
- if (codec->component.card->instantiated) {
- /* for jack type detect */
- snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
- snd_soc_dapm_force_enable_pin(&codec->dapm,
- "Mic Det Power");
- snd_soc_dapm_sync(&codec->dapm);
- } else {
+ /* for jack type detect */
+ snd_soc_dapm_force_enable_pin(dapm, "LDO2");
+ snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power");
+ snd_soc_dapm_sync(dapm);
+ if (!dapm->card->instantiated) {
/* Power up necessary bits for JD if dapm is
not ready yet */
regmap_update_bits(rt5645->regmap, RT5645_PWR_ANLG1,
@@ -2828,14 +2806,15 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
}
regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0);
- regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006);
- regmap_update_bits(rt5645->regmap,
- RT5645_IN1_CTRL2, 0x1000, 0x1000);
+ regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2,
+ RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD);
+ regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
+ RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
msleep(100);
- regmap_update_bits(rt5645->regmap,
- RT5645_IN1_CTRL2, 0x1000, 0x0000);
+ regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2,
+ RT5645_CBJ_MN_JD, 0);
- msleep(450);
+ msleep(600);
regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val);
val &= 0x7;
dev_dbg(codec->dev, "val = %d\n", val);
@@ -2846,43 +2825,46 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
rt5645_enable_push_button_irq(codec, true);
}
} else {
- if (codec->component.card->instantiated) {
- snd_soc_dapm_disable_pin(&codec->dapm,
- "Mic Det Power");
- snd_soc_dapm_sync(&codec->dapm);
- } else
- regmap_update_bits(rt5645->regmap,
- RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0);
+ snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+ snd_soc_dapm_sync(dapm);
rt5645->jack_type = SND_JACK_HEADPHONE;
}
+ snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
+ snd_soc_write(codec, RT5645_DEPOP_M1, 0x001d);
+ snd_soc_write(codec, RT5645_DEPOP_M1, 0x0001);
} else { /* jack out */
rt5645->jack_type = 0;
+
+ regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2,
+ RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD);
+ regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
+ RT5645_CBJ_BST1_EN, 0);
+
if (rt5645->en_button_func)
rt5645_enable_push_button_irq(codec, false);
- else {
- if (codec->component.card->instantiated) {
- if (rt5645->pdata.jd_mode == 0)
- snd_soc_dapm_disable_pin(&codec->dapm,
- "LDO2");
- snd_soc_dapm_disable_pin(&codec->dapm,
- "Mic Det Power");
- snd_soc_dapm_sync(&codec->dapm);
- } else {
- if (rt5645->pdata.jd_mode == 0)
- regmap_update_bits(rt5645->regmap,
- RT5645_PWR_MIXER,
- RT5645_PWR_LDO2, 0);
- regmap_update_bits(rt5645->regmap,
- RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0);
- }
- }
+
+ if (rt5645->pdata.jd_mode == 0)
+ snd_soc_dapm_disable_pin(dapm, "LDO2");
+ snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+ snd_soc_dapm_sync(dapm);
}
return rt5645->jack_type;
}
-static int rt5645_irq_detection(struct rt5645_priv *rt5645);
+static int rt5645_button_detect(struct snd_soc_codec *codec)
+{
+ int btn_type, val;
+
+ val = snd_soc_read(codec, RT5650_4BTN_IL_CMD1);
+ pr_debug("val=0x%x\n", val);
+ btn_type = val & 0xfff0;
+ snd_soc_write(codec, RT5650_4BTN_IL_CMD1, val);
+
+ return btn_type;
+}
+
static irqreturn_t rt5645_irq(int irq, void *data);
int rt5645_set_jack_detect(struct snd_soc_codec *codec,
@@ -2913,38 +2895,10 @@ static void rt5645_jack_detect_work(struct work_struct *work)
{
struct rt5645_priv *rt5645 =
container_of(work, struct rt5645_priv, jack_detect_work.work);
-
- rt5645_irq_detection(rt5645);
-}
-
-static irqreturn_t rt5645_irq(int irq, void *data)
-{
- struct rt5645_priv *rt5645 = data;
-
- queue_delayed_work(system_power_efficient_wq,
- &rt5645->jack_detect_work, msecs_to_jiffies(250));
-
- return IRQ_HANDLED;
-}
-
-static int rt5645_button_detect(struct snd_soc_codec *codec)
-{
- int btn_type, val;
-
- val = snd_soc_read(codec, RT5650_4BTN_IL_CMD1);
- pr_debug("val=0x%x\n", val);
- btn_type = val & 0xfff0;
- snd_soc_write(codec, RT5650_4BTN_IL_CMD1, val);
-
- return btn_type;
-}
-
-static int rt5645_irq_detection(struct rt5645_priv *rt5645)
-{
int val, btn_type, gpio_state = 0, report = 0;
if (!rt5645->codec)
- return -EINVAL;
+ return;
switch (rt5645->pdata.jd_mode) {
case 0: /* Not using rt5645 JD */
@@ -2958,7 +2912,7 @@ static int rt5645_irq_detection(struct rt5645_priv *rt5645)
report, SND_JACK_HEADPHONE);
snd_soc_jack_report(rt5645->mic_jack,
report, SND_JACK_MICROPHONE);
- return report;
+ return;
case 1: /* 2 port */
val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0070;
break;
@@ -3040,27 +2994,39 @@ static int rt5645_irq_detection(struct rt5645_priv *rt5645)
snd_soc_jack_report(rt5645->btn_jack,
report, SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3);
+}
+
+static irqreturn_t rt5645_irq(int irq, void *data)
+{
+ struct rt5645_priv *rt5645 = data;
+
+ queue_delayed_work(system_power_efficient_wq,
+ &rt5645->jack_detect_work, msecs_to_jiffies(250));
- return report;
+ return IRQ_HANDLED;
}
static int rt5645_probe(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
rt5645->codec = codec;
switch (rt5645->codec_type) {
case CODEC_TYPE_RT5645:
- snd_soc_dapm_add_routes(&codec->dapm,
+ snd_soc_dapm_new_controls(dapm,
+ rt5645_specific_dapm_widgets,
+ ARRAY_SIZE(rt5645_specific_dapm_widgets));
+ snd_soc_dapm_add_routes(dapm,
rt5645_specific_dapm_routes,
ARRAY_SIZE(rt5645_specific_dapm_routes));
break;
case CODEC_TYPE_RT5650:
- snd_soc_dapm_new_controls(&codec->dapm,
+ snd_soc_dapm_new_controls(dapm,
rt5650_specific_dapm_widgets,
ARRAY_SIZE(rt5650_specific_dapm_widgets));
- snd_soc_dapm_add_routes(&codec->dapm,
+ snd_soc_dapm_add_routes(dapm,
rt5650_specific_dapm_routes,
ARRAY_SIZE(rt5650_specific_dapm_routes));
break;
@@ -3070,9 +3036,9 @@ static int rt5645_probe(struct snd_soc_codec *codec)
/* for JD function */
if (rt5645->pdata.jd_mode) {
- snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power");
- snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_force_enable_pin(dapm, "JD Power");
+ snd_soc_dapm_force_enable_pin(dapm, "LDO2");
+ snd_soc_dapm_sync(dapm);
}
return 0;
@@ -3113,7 +3079,7 @@ static int rt5645_resume(struct snd_soc_codec *codec)
#define RT5645_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
-static struct snd_soc_dai_ops rt5645_aif_dai_ops = {
+static const struct snd_soc_dai_ops rt5645_aif_dai_ops = {
.hw_params = rt5645_hw_params,
.set_fmt = rt5645_set_dai_fmt,
.set_sysclk = rt5645_set_dai_sysclk,
@@ -3224,7 +3190,7 @@ static int strago_quirk_cb(const struct dmi_system_id *id)
return 1;
}
-static struct dmi_system_id dmi_platform_intel_braswell[] = {
+static const struct dmi_system_id dmi_platform_intel_braswell[] = {
{
.ident = "Intel Strago",
.callback = strago_quirk_cb,
@@ -3232,6 +3198,13 @@ static struct dmi_system_id dmi_platform_intel_braswell[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Strago"),
},
},
+ {
+ .ident = "Google Celes",
+ .callback = strago_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Celes"),
+ },
+ },
{ }
};
@@ -3254,7 +3227,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
{
struct rt5645_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5645_priv *rt5645;
- int ret;
+ int ret, i;
unsigned int val;
rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv),
@@ -3288,6 +3261,24 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
return ret;
}
+ for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++)
+ rt5645->supplies[i].supply = rt5645_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c->dev,
+ ARRAY_SIZE(rt5645->supplies),
+ rt5645->supplies);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(rt5645->supplies),
+ rt5645->supplies);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val);
switch (val) {
@@ -3299,16 +3290,10 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
break;
default:
dev_err(&i2c->dev,
- "Device with ID register %x is not rt5645 or rt5650\n",
+ "Device with ID register %#x is not rt5645 or rt5650\n",
val);
- return -ENODEV;
- }
-
- if (rt5645->codec_type == CODEC_TYPE_RT5650) {
- ret = rt5650_calibration(rt5645);
-
- if (ret < 0)
- pr_err("calibration failed!\n");
+ ret = -ENODEV;
+ goto err_enable;
}
regmap_write(rt5645->regmap, RT5645_RESET, 0);
@@ -3398,8 +3383,6 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
RT5645_IRQ_CLK_GATE_CTRL,
RT5645_IRQ_CLK_GATE_CTRL);
- regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
- RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT);
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
@@ -3439,12 +3422,25 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5645", rt5645);
- if (ret)
+ if (ret) {
dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+ goto err_enable;
+ }
}
- return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
- rt5645_dai, ARRAY_SIZE(rt5645_dai));
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
+ rt5645_dai, ARRAY_SIZE(rt5645_dai));
+ if (ret)
+ goto err_irq;
+
+ return 0;
+
+err_irq:
+ if (rt5645->i2c->irq)
+ free_irq(rt5645->i2c->irq, rt5645);
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies);
+ return ret;
}
static int rt5645_i2c_remove(struct i2c_client *i2c)
@@ -3457,18 +3453,31 @@ static int rt5645_i2c_remove(struct i2c_client *i2c)
cancel_delayed_work_sync(&rt5645->jack_detect_work);
snd_soc_unregister_codec(&i2c->dev);
+ regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies);
return 0;
}
+static void rt5645_i2c_shutdown(struct i2c_client *i2c)
+{
+ struct rt5645_priv *rt5645 = i2c_get_clientdata(i2c);
+
+ regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
+ RT5645_RING2_SLEEVE_GND, RT5645_RING2_SLEEVE_GND);
+ regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, RT5645_CBJ_MN_JD,
+ RT5645_CBJ_MN_JD);
+ regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, RT5645_CBJ_BST1_EN,
+ 0);
+}
+
static struct i2c_driver rt5645_i2c_driver = {
.driver = {
.name = "rt5645",
- .owner = THIS_MODULE,
.acpi_match_table = ACPI_PTR(rt5645_acpi_match),
},
.probe = rt5645_i2c_probe,
- .remove = rt5645_i2c_remove,
+ .remove = rt5645_i2c_remove,
+ .shutdown = rt5645_i2c_shutdown,
.id_table = rt5645_i2c_id,
};
module_i2c_driver(rt5645_i2c_driver);
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index 278bb9f..0e4cfc6 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -2115,6 +2115,7 @@ enum {
#define RT5645_JD_PSV_MODE (0x1 << 12)
#define RT5645_IRQ_CLK_GATE_CTRL (0x1 << 11)
#define RT5645_MICINDET_MANU (0x1 << 7)
+#define RT5645_RING2_SLEEVE_GND (0x1 << 5)
/* Vendor ID (0xfd) */
#define RT5645_VER_C 0x2
@@ -2181,32 +2182,6 @@ enum {
int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
unsigned int filter_mask, unsigned int clk_src);
-struct rt5645_priv {
- struct snd_soc_codec *codec;
- struct rt5645_platform_data pdata;
- struct regmap *regmap;
- struct i2c_client *i2c;
- struct gpio_desc *gpiod_hp_det;
- struct snd_soc_jack *hp_jack;
- struct snd_soc_jack *mic_jack;
- struct snd_soc_jack *btn_jack;
- struct delayed_work jack_detect_work;
-
- int codec_type;
- int sysclk;
- int sysclk_src;
- int lrck[RT5645_AIFS];
- int bclk[RT5645_AIFS];
- int master[RT5645_AIFS];
-
- int pll_src;
- int pll_in;
- int pll_out;
-
- int jack_type;
- bool en_button_func;
-};
-
int rt5645_set_jack_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
struct snd_soc_jack *btn_jack);
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index a3506e1..1d40318 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -46,7 +46,7 @@ static const struct regmap_range_cfg rt5651_ranges[] = {
.window_len = 0x1, },
};
-static struct reg_default init_list[] = {
+static const struct reg_sequence init_list[] = {
{RT5651_PR_BASE + 0x3d, 0x3e00},
};
@@ -292,16 +292,15 @@ static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
-static unsigned int bst_tlv[] = {
- TLV_DB_RANGE_HEAD(7),
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
- 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
-};
+ 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
/* Interface data select */
static const char * const rt5651_data_select[] = {
@@ -378,10 +377,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
- int idx = -EINVAL;
-
- idx = rl6231_calc_dmic_clk(rt5651->sysclk);
+ int idx, rate;
+ rate = rt5651->sysclk / rl6231_get_pre_div(rt5651->regmap,
+ RT5651_ADDA_CLK1, RT5651_I2S_PD1_SFT);
+ idx = rl6231_calc_dmic_clk(rate);
if (idx < 0)
dev_err(codec->dev, "Failed to set DMIC clock\n");
else
@@ -1769,7 +1769,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret);
if (ret != RT5651_DEVICE_ID_VALUE) {
dev_err(&i2c->dev,
- "Device with ID register %x is not rt5651\n", ret);
+ "Device with ID register %#x is not rt5651\n", ret);
return -ENODEV;
}
@@ -1806,7 +1806,6 @@ static int rt5651_i2c_remove(struct i2c_client *i2c)
static struct i2c_driver rt5651_i2c_driver = {
.driver = {
.name = "rt5651",
- .owner = THIS_MODULE,
},
.probe = rt5651_i2c_probe,
.remove = rt5651_i2c_remove,
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index a9123d4..49a9e70 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -51,7 +51,7 @@ static const struct regmap_range_cfg rt5670_ranges[] = {
.window_len = 0x1, },
};
-static const struct reg_default init_list[] = {
+static const struct reg_sequence init_list[] = {
{ RT5670_PR_BASE + 0x14, 0x9a8a },
{ RT5670_PR_BASE + 0x38, 0x3ba1 },
{ RT5670_PR_BASE + 0x3d, 0x3640 },
@@ -592,16 +592,15 @@ static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
-static unsigned int bst_tlv[] = {
- TLV_DB_RANGE_HEAD(7),
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
- 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
-};
+ 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
/* Interface data select */
static const char * const rt5670_data_select[] = {
@@ -683,10 +682,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
- int idx = -EINVAL;
-
- idx = rl6231_calc_dmic_clk(rt5670->sysclk);
+ int idx, rate;
+ rate = rt5670->sysclk / rl6231_get_pre_div(rt5670->regmap,
+ RT5670_ADDA_CLK1, RT5670_I2S_PD1_SFT);
+ idx = rl6231_calc_dmic_clk(rate);
if (idx < 0)
dev_err(codec->dev, "Failed to set DMIC clock\n");
else
@@ -2720,7 +2720,7 @@ static int rt5670_resume(struct snd_soc_codec *codec)
#define RT5670_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
-static struct snd_soc_dai_ops rt5670_aif_dai_ops = {
+static const struct snd_soc_dai_ops rt5670_aif_dai_ops = {
.hw_params = rt5670_hw_params,
.set_fmt = rt5670_set_dai_fmt,
.set_sysclk = rt5670_set_dai_sysclk,
@@ -2863,7 +2863,7 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
regmap_read(rt5670->regmap, RT5670_VENDOR_ID2, &val);
if (val != RT5670_DEVICE_ID) {
dev_err(&i2c->dev,
- "Device with ID register %x is not rt5670/72\n", val);
+ "Device with ID register %#x is not rt5670/72\n", val);
return -ENODEV;
}
@@ -3043,7 +3043,6 @@ static int rt5670_i2c_remove(struct i2c_client *i2c)
static struct i2c_driver rt5670_i2c_driver = {
.driver = {
.name = "rt5670",
- .owner = THIS_MODULE,
.acpi_match_table = ACPI_PTR(rt5670_acpi_match),
},
.probe = rt5670_i2c_probe,
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
index ef6348c..3505aaf 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -31,84 +31,197 @@
#include "rt5677-spi.h"
+#define RT5677_SPI_BURST_LEN 240
+#define RT5677_SPI_HEADER 5
+#define RT5677_SPI_FREQ 6000000
+
+/* The AddressPhase and DataPhase of SPI commands are MSB first on the wire.
+ * DataPhase word size of 16-bit commands is 2 bytes.
+ * DataPhase word size of 32-bit commands is 4 bytes.
+ * DataPhase word size of burst commands is 8 bytes.
+ * The DSP CPU is little-endian.
+ */
+#define RT5677_SPI_WRITE_BURST 0x5
+#define RT5677_SPI_READ_BURST 0x4
+#define RT5677_SPI_WRITE_32 0x3
+#define RT5677_SPI_READ_32 0x2
+#define RT5677_SPI_WRITE_16 0x1
+#define RT5677_SPI_READ_16 0x0
+
static struct spi_device *g_spi;
+static DEFINE_MUTEX(spi_mutex);
-/**
- * rt5677_spi_write - Write data to SPI.
- * @txbuf: Data Buffer for writing.
- * @len: Data length.
+/* Select a suitable transfer command for the next transfer to ensure
+ * the transfer address is always naturally aligned while minimizing
+ * the total number of transfers required.
+ *
+ * 3 transfer commands are available:
+ * RT5677_SPI_READ/WRITE_16: Transfer 2 bytes
+ * RT5677_SPI_READ/WRITE_32: Transfer 4 bytes
+ * RT5677_SPI_READ/WRITE_BURST: Transfer any multiples of 8 bytes
+ *
+ * For example, reading 260 bytes at 0x60030002 uses the following commands:
+ * 0x60030002 RT5677_SPI_READ_16 2 bytes
+ * 0x60030004 RT5677_SPI_READ_32 4 bytes
+ * 0x60030008 RT5677_SPI_READ_BURST 240 bytes
+ * 0x600300F8 RT5677_SPI_READ_BURST 8 bytes
+ * 0x60030100 RT5677_SPI_READ_32 4 bytes
+ * 0x60030104 RT5677_SPI_READ_16 2 bytes
*
+ * Input:
+ * @read: true for read commands; false for write commands
+ * @align: alignment of the next transfer address
+ * @remain: number of bytes remaining to transfer
*
- * Returns true for success.
+ * Output:
+ * @len: number of bytes to transfer with the selected command
+ * Returns the selected command
*/
-int rt5677_spi_write(u8 *txbuf, size_t len)
+static u8 rt5677_spi_select_cmd(bool read, u32 align, u32 remain, u32 *len)
{
- int status;
-
- status = spi_write(g_spi, txbuf, len);
-
- if (status)
- dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status);
-
- return status;
+ u8 cmd;
+
+ if (align == 2 || align == 6 || remain == 2) {
+ cmd = RT5677_SPI_READ_16;
+ *len = 2;
+ } else if (align == 4 || remain <= 6) {
+ cmd = RT5677_SPI_READ_32;
+ *len = 4;
+ } else {
+ cmd = RT5677_SPI_READ_BURST;
+ *len = min_t(u32, remain & ~7, RT5677_SPI_BURST_LEN);
+ }
+ return read ? cmd : cmd + 1;
}
-EXPORT_SYMBOL_GPL(rt5677_spi_write);
-/**
- * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address.
- * @addr: Start address.
- * @txbuf: Data Buffer for writng.
- * @len: Data length, it must be a multiple of 8.
- *
- *
- * Returns true for success.
+/* Copy dstlen bytes from src to dst, while reversing byte order for each word.
+ * If srclen < dstlen, zeros are padded.
*/
-int rt5677_spi_burst_write(u32 addr, const struct firmware *fw)
+static void rt5677_spi_reverse(u8 *dst, u32 dstlen, const u8 *src, u32 srclen)
{
- u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE;
- u8 *write_buf;
- unsigned int i, end, offset = 0;
-
- write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL);
-
- if (write_buf == NULL)
- return -ENOMEM;
-
- while (offset < fw->size) {
- if (offset + RT5677_SPI_BUF_LEN <= fw->size)
- end = RT5677_SPI_BUF_LEN;
- else
- end = fw->size % RT5677_SPI_BUF_LEN;
-
- write_buf[0] = spi_cmd;
- write_buf[1] = ((addr + offset) & 0xff000000) >> 24;
- write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16;
- write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8;
- write_buf[4] = ((addr + offset) & 0x000000ff) >> 0;
-
- for (i = 0; i < end; i += 8) {
- write_buf[i + 12] = fw->data[offset + i + 0];
- write_buf[i + 11] = fw->data[offset + i + 1];
- write_buf[i + 10] = fw->data[offset + i + 2];
- write_buf[i + 9] = fw->data[offset + i + 3];
- write_buf[i + 8] = fw->data[offset + i + 4];
- write_buf[i + 7] = fw->data[offset + i + 5];
- write_buf[i + 6] = fw->data[offset + i + 6];
- write_buf[i + 5] = fw->data[offset + i + 7];
+ u32 w, i, si;
+ u32 word_size = min_t(u32, dstlen, 8);
+
+ for (w = 0; w < dstlen; w += word_size) {
+ for (i = 0; i < word_size; i++) {
+ si = w + word_size - i - 1;
+ dst[w + i] = si < srclen ? src[si] : 0;
}
+ }
+}
- write_buf[end + 5] = spi_cmd;
+/* Read DSP address space using SPI. addr and len have to be 2-byte aligned. */
+int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
+{
+ u32 offset;
+ int status = 0;
+ struct spi_transfer t[2];
+ struct spi_message m;
+ /* +4 bytes is for the DummyPhase following the AddressPhase */
+ u8 header[RT5677_SPI_HEADER + 4];
+ u8 body[RT5677_SPI_BURST_LEN];
+ u8 spi_cmd;
+ u8 *cb = rxbuf;
+
+ if (!g_spi)
+ return -ENODEV;
+
+ if ((addr & 1) || (len & 1)) {
+ dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len);
+ return -EACCES;
+ }
- rt5677_spi_write(write_buf, end + 6);
+ memset(t, 0, sizeof(t));
+ t[0].tx_buf = header;
+ t[0].len = sizeof(header);
+ t[0].speed_hz = RT5677_SPI_FREQ;
+ t[1].rx_buf = body;
+ t[1].speed_hz = RT5677_SPI_FREQ;
+ spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t));
+
+ for (offset = 0; offset < len; offset += t[1].len) {
+ spi_cmd = rt5677_spi_select_cmd(true, (addr + offset) & 7,
+ len - offset, &t[1].len);
+
+ /* Construct SPI message header */
+ header[0] = spi_cmd;
+ header[1] = ((addr + offset) & 0xff000000) >> 24;
+ header[2] = ((addr + offset) & 0x00ff0000) >> 16;
+ header[3] = ((addr + offset) & 0x0000ff00) >> 8;
+ header[4] = ((addr + offset) & 0x000000ff) >> 0;
+
+ mutex_lock(&spi_mutex);
+ status |= spi_sync(g_spi, &m);
+ mutex_unlock(&spi_mutex);
+
+ /* Copy data back to caller buffer */
+ rt5677_spi_reverse(cb + offset, t[1].len, body, t[1].len);
+ }
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt5677_spi_read);
- offset += RT5677_SPI_BUF_LEN;
+/* Write DSP address space using SPI. addr has to be 2-byte aligned.
+ * If len is not 2-byte aligned, an extra byte of zero is written at the end
+ * as padding.
+ */
+int rt5677_spi_write(u32 addr, const void *txbuf, size_t len)
+{
+ u32 offset, len_with_pad = len;
+ int status = 0;
+ struct spi_transfer t;
+ struct spi_message m;
+ /* +1 byte is for the DummyPhase following the DataPhase */
+ u8 buf[RT5677_SPI_HEADER + RT5677_SPI_BURST_LEN + 1];
+ u8 *body = buf + RT5677_SPI_HEADER;
+ u8 spi_cmd;
+ const u8 *cb = txbuf;
+
+ if (!g_spi)
+ return -ENODEV;
+
+ if (addr & 1) {
+ dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len);
+ return -EACCES;
}
- kfree(write_buf);
+ if (len & 1)
+ len_with_pad = len + 1;
+
+ memset(&t, 0, sizeof(t));
+ t.tx_buf = buf;
+ t.speed_hz = RT5677_SPI_FREQ;
+ spi_message_init_with_transfers(&m, &t, 1);
+
+ for (offset = 0; offset < len_with_pad;) {
+ spi_cmd = rt5677_spi_select_cmd(false, (addr + offset) & 7,
+ len_with_pad - offset, &t.len);
+
+ /* Construct SPI message header */
+ buf[0] = spi_cmd;
+ buf[1] = ((addr + offset) & 0xff000000) >> 24;
+ buf[2] = ((addr + offset) & 0x00ff0000) >> 16;
+ buf[3] = ((addr + offset) & 0x0000ff00) >> 8;
+ buf[4] = ((addr + offset) & 0x000000ff) >> 0;
+
+ /* Fetch data from caller buffer */
+ rt5677_spi_reverse(body, t.len, cb + offset, len - offset);
+ offset += t.len;
+ t.len += RT5677_SPI_HEADER + 1;
+
+ mutex_lock(&spi_mutex);
+ status |= spi_sync(g_spi, &m);
+ mutex_unlock(&spi_mutex);
+ }
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt5677_spi_write);
- return 0;
+int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw)
+{
+ return rt5677_spi_write(addr, fw->data, fw->size);
}
-EXPORT_SYMBOL_GPL(rt5677_spi_burst_write);
+EXPORT_SYMBOL_GPL(rt5677_spi_write_firmware);
static int rt5677_spi_probe(struct spi_device *spi)
{
diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h
index ec41b2b..662db16 100644
--- a/sound/soc/codecs/rt5677-spi.h
+++ b/sound/soc/codecs/rt5677-spi.h
@@ -12,10 +12,8 @@
#ifndef __RT5677_SPI_H__
#define __RT5677_SPI_H__
-#define RT5677_SPI_BUF_LEN 240
-#define RT5677_SPI_CMD_BURST_WRITE 0x05
-
-int rt5677_spi_write(u8 *txbuf, size_t len);
-int rt5677_spi_burst_write(u32 addr, const struct firmware *fw);
+int rt5677_spi_read(u32 addr, void *rxbuf, size_t len);
+int rt5677_spi_write(u32 addr, const void *txbuf, size_t len);
+int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw);
#endif /* __RT5677_SPI_H__ */
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 31d969a..b4cd7e3 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -15,13 +15,12 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
+#include <linux/property.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -54,7 +53,7 @@ static const struct regmap_range_cfg rt5677_ranges[] = {
},
};
-static const struct reg_default init_list[] = {
+static const struct reg_sequence init_list[] = {
{RT5677_ASRC_12, 0x0018},
{RT5677_PR_BASE + 0x3d, 0x364d},
{RT5677_PR_BASE + 0x17, 0x4fc0},
@@ -746,14 +745,14 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1,
codec->dev);
if (ret == 0) {
- rt5677_spi_burst_write(0x50000000, rt5677->fw1);
+ rt5677_spi_write_firmware(0x50000000, rt5677->fw1);
release_firmware(rt5677->fw1);
}
ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2,
codec->dev);
if (ret == 0) {
- rt5677_spi_burst_write(0x60000000, rt5677->fw2);
+ rt5677_spi_write_firmware(0x60000000, rt5677->fw2);
release_firmware(rt5677->fw2);
}
@@ -789,16 +788,15 @@ static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0);
/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
-static unsigned int bst_tlv[] = {
- TLV_DB_RANGE_HEAD(7),
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
- 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
-};
+ 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -917,8 +915,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
- int idx = rl6231_calc_dmic_clk(rt5677->lrck[RT5677_AIF1] << 8);
+ int idx, rate;
+ rate = rt5677->sysclk / rl6231_get_pre_div(rt5677->regmap,
+ RT5677_CLK_TREE_CTRL1, RT5677_I2S_PD1_SFT);
+ idx = rl6231_calc_dmic_clk(rate);
if (idx < 0)
dev_err(codec->dev, "Failed to set DMIC clock\n");
else
@@ -4764,10 +4765,8 @@ static int rt5677_remove(struct snd_soc_codec *codec)
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
- if (gpio_is_valid(rt5677->pow_ldo2))
- gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
- if (gpio_is_valid(rt5677->reset_pin))
- gpio_set_value_cansleep(rt5677->reset_pin, 0);
+ gpiod_set_value_cansleep(rt5677->pow_ldo2, 0);
+ gpiod_set_value_cansleep(rt5677->reset_pin, 0);
return 0;
}
@@ -4781,10 +4780,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
regcache_cache_only(rt5677->regmap, true);
regcache_mark_dirty(rt5677->regmap);
- if (gpio_is_valid(rt5677->pow_ldo2))
- gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
- if (gpio_is_valid(rt5677->reset_pin))
- gpio_set_value_cansleep(rt5677->reset_pin, 0);
+ gpiod_set_value_cansleep(rt5677->pow_ldo2, 0);
+ gpiod_set_value_cansleep(rt5677->reset_pin, 0);
}
return 0;
@@ -4795,12 +4792,9 @@ static int rt5677_resume(struct snd_soc_codec *codec)
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
if (!rt5677->dsp_vad_en) {
- if (gpio_is_valid(rt5677->pow_ldo2))
- gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
- if (gpio_is_valid(rt5677->reset_pin))
- gpio_set_value_cansleep(rt5677->reset_pin, 1);
- if (gpio_is_valid(rt5677->pow_ldo2) ||
- gpio_is_valid(rt5677->reset_pin))
+ gpiod_set_value_cansleep(rt5677->pow_ldo2, 1);
+ gpiod_set_value_cansleep(rt5677->reset_pin, 1);
+ if (rt5677->pow_ldo2 || rt5677->reset_pin)
msleep(10);
regcache_cache_only(rt5677->regmap, false);
@@ -4863,7 +4857,7 @@ static int rt5677_write(void *context, unsigned int reg, unsigned int val)
#define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
-static struct snd_soc_dai_ops rt5677_aif_dai_ops = {
+static const struct snd_soc_dai_ops rt5677_aif_dai_ops = {
.hw_params = rt5677_hw_params,
.set_fmt = rt5677_set_dai_fmt,
.set_sysclk = rt5677_set_dai_sysclk,
@@ -5024,45 +5018,29 @@ static const struct i2c_device_id rt5677_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
-static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
+static void rt5677_read_device_properties(struct rt5677_priv *rt5677,
+ struct device *dev)
{
- rt5677->pdata.in1_diff = of_property_read_bool(np,
- "realtek,in1-differential");
- rt5677->pdata.in2_diff = of_property_read_bool(np,
- "realtek,in2-differential");
- rt5677->pdata.lout1_diff = of_property_read_bool(np,
- "realtek,lout1-differential");
- rt5677->pdata.lout2_diff = of_property_read_bool(np,
- "realtek,lout2-differential");
- rt5677->pdata.lout3_diff = of_property_read_bool(np,
- "realtek,lout3-differential");
-
- rt5677->pow_ldo2 = of_get_named_gpio(np,
- "realtek,pow-ldo2-gpio", 0);
- rt5677->reset_pin = of_get_named_gpio(np,
- "realtek,reset-gpio", 0);
-
- /*
- * POW_LDO2 is optional (it may be statically tied on the board).
- * -ENOENT means that the property doesn't exist, i.e. there is no
- * GPIO, so is not an error. Any other error code means the property
- * exists, but could not be parsed.
- */
- if (!gpio_is_valid(rt5677->pow_ldo2) &&
- (rt5677->pow_ldo2 != -ENOENT))
- return rt5677->pow_ldo2;
- if (!gpio_is_valid(rt5677->reset_pin) &&
- (rt5677->reset_pin != -ENOENT))
- return rt5677->reset_pin;
-
- of_property_read_u8_array(np, "realtek,gpio-config",
- rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
-
- of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio);
- of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio);
- of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio);
-
- return 0;
+ rt5677->pdata.in1_diff = device_property_read_bool(dev,
+ "realtek,in1-differential");
+ rt5677->pdata.in2_diff = device_property_read_bool(dev,
+ "realtek,in2-differential");
+ rt5677->pdata.lout1_diff = device_property_read_bool(dev,
+ "realtek,lout1-differential");
+ rt5677->pdata.lout2_diff = device_property_read_bool(dev,
+ "realtek,lout2-differential");
+ rt5677->pdata.lout3_diff = device_property_read_bool(dev,
+ "realtek,lout3-differential");
+
+ device_property_read_u8_array(dev, "realtek,gpio-config",
+ rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
+
+ device_property_read_u32(dev, "realtek,jd1-gpio",
+ &rt5677->pdata.jd1_gpio);
+ device_property_read_u32(dev, "realtek,jd2-gpio",
+ &rt5677->pdata.jd2_gpio);
+ device_property_read_u32(dev, "realtek,jd3-gpio",
+ &rt5677->pdata.jd3_gpio);
}
static struct regmap_irq rt5677_irqs[] = {
@@ -5145,43 +5123,29 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
if (pdata)
rt5677->pdata = *pdata;
+ else
+ rt5677_read_device_properties(rt5677, &i2c->dev);
- if (i2c->dev.of_node) {
- ret = rt5677_parse_dt(rt5677, i2c->dev.of_node);
- if (ret) {
- dev_err(&i2c->dev, "Failed to parse device tree: %d\n",
- ret);
- return ret;
- }
- } else {
- rt5677->pow_ldo2 = -EINVAL;
- rt5677->reset_pin = -EINVAL;
- }
-
- if (gpio_is_valid(rt5677->pow_ldo2)) {
- ret = devm_gpio_request_one(&i2c->dev, rt5677->pow_ldo2,
- GPIOF_OUT_INIT_HIGH,
- "RT5677 POW_LDO2");
- if (ret < 0) {
- dev_err(&i2c->dev, "Failed to request POW_LDO2 %d: %d\n",
- rt5677->pow_ldo2, ret);
- return ret;
- }
+ /* pow-ldo2 and reset are optional. The codec pins may be statically
+ * connected on the board without gpios. If the gpio device property
+ * isn't specified, devm_gpiod_get_optional returns NULL.
+ */
+ rt5677->pow_ldo2 = devm_gpiod_get_optional(&i2c->dev,
+ "realtek,pow-ldo2", GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5677->pow_ldo2)) {
+ ret = PTR_ERR(rt5677->pow_ldo2);
+ dev_err(&i2c->dev, "Failed to request POW_LDO2: %d\n", ret);
+ return ret;
}
-
- if (gpio_is_valid(rt5677->reset_pin)) {
- ret = devm_gpio_request_one(&i2c->dev, rt5677->reset_pin,
- GPIOF_OUT_INIT_HIGH,
- "RT5677 RESET");
- if (ret < 0) {
- dev_err(&i2c->dev, "Failed to request RESET %d: %d\n",
- rt5677->reset_pin, ret);
- return ret;
- }
+ rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev,
+ "realtek,reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5677->reset_pin)) {
+ ret = PTR_ERR(rt5677->reset_pin);
+ dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret);
+ return ret;
}
- if (gpio_is_valid(rt5677->pow_ldo2) ||
- gpio_is_valid(rt5677->reset_pin)) {
+ if (rt5677->pow_ldo2 || rt5677->reset_pin) {
/* Wait a while until I2C bus becomes available. The datasheet
* does not specify the exact we should wait but startup
* sequence mentiones at least a few milliseconds.
@@ -5209,7 +5173,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
regmap_read(rt5677->regmap, RT5677_VENDOR_ID2, &val);
if (val != RT5677_DEVICE_ID) {
dev_err(&i2c->dev,
- "Device with ID register %x is not rt5677\n", val);
+ "Device with ID register %#x is not rt5677\n", val);
return -ENODEV;
}
@@ -5273,7 +5237,6 @@ static int rt5677_i2c_remove(struct i2c_client *i2c)
static struct i2c_driver rt5677_i2c_driver = {
.driver = {
.name = "rt5677",
- .owner = THIS_MODULE,
},
.probe = rt5677_i2c_probe,
.remove = rt5677_i2c_remove,
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h
index 7eca38a..d46855a 100644
--- a/sound/soc/codecs/rt5677.h
+++ b/sound/soc/codecs/rt5677.h
@@ -14,6 +14,7 @@
#include <sound/rt5677.h>
#include <linux/gpio/driver.h>
+#include <linux/gpio/consumer.h>
/* Info */
#define RT5677_RESET 0x00
@@ -1775,8 +1776,8 @@ struct rt5677_priv {
int pll_src;
int pll_in;
int pll_out;
- int pow_ldo2; /* POW_LDO2 pin */
- int reset_pin; /* RESET pin */
+ struct gpio_desc *pow_ldo2; /* POW_LDO2 pin */
+ struct gpio_desc *reset_pin; /* RESET pin */
enum rt5677_type type;
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio_chip;
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index e673f6c..bfda25e 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -406,11 +406,10 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0);
/* tlv for mic gain, 0db 20db 30db 40db */
-static const unsigned int mic_gain_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(mic_gain_tlv,
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
- 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0),
-};
+ 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0)
+);
/* tlv for hp volume, -51.5db to 12.0db, step .5db */
static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0);
@@ -1601,7 +1600,6 @@ MODULE_DEVICE_TABLE(of, sgtl5000_dt_ids);
static struct i2c_driver sgtl5000_i2c_driver = {
.driver = {
.name = "sgtl5000",
- .owner = THIS_MODULE,
.of_match_table = sgtl5000_dt_ids,
},
.probe = sgtl5000_i2c_probe,
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index 3e72964..a8402d0 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -208,7 +208,7 @@ out:
return err;
}
-static struct snd_soc_dai_ops si476x_dai_ops = {
+static const struct snd_soc_dai_ops si476x_dai_ops = {
.hw_params = si476x_codec_hw_params,
.set_fmt = si476x_codec_set_dai_fmt,
};
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
index 29cb442..6bfd25c 100644
--- a/sound/soc/codecs/sirf-audio-codec.c
+++ b/sound/soc/codecs/sirf-audio-codec.c
@@ -370,11 +370,11 @@ static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
return 0;
}
-struct snd_soc_dai_ops sirf_audio_codec_dai_ops = {
+static const struct snd_soc_dai_ops sirf_audio_codec_dai_ops = {
.trigger = sirf_audio_codec_trigger,
};
-struct snd_soc_dai_driver sirf_audio_codec_dai = {
+static struct snd_soc_dai_driver sirf_audio_codec_dai = {
.name = "sirf-audio-codec",
.playback = {
.stream_name = "Playback",
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index f30de76..ddb0203 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -806,6 +806,14 @@ static int ssm2518_i2c_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id ssm2518_dt_ids[] = {
+ { .compatible = "adi,ssm2518", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ssm2518_dt_ids);
+#endif
+
static const struct i2c_device_id ssm2518_i2c_ids[] = {
{ "ssm2518", 0 },
{ }
@@ -815,7 +823,7 @@ MODULE_DEVICE_TABLE(i2c, ssm2518_i2c_ids);
static struct i2c_driver ssm2518_driver = {
.driver = {
.name = "ssm2518",
- .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ssm2518_dt_ids),
},
.probe = ssm2518_i2c_probe,
.remove = ssm2518_i2c_remove,
diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c
index 0d9779d..173ba85 100644
--- a/sound/soc/codecs/ssm2602-i2c.c
+++ b/sound/soc/codecs/ssm2602-i2c.c
@@ -52,7 +52,6 @@ MODULE_DEVICE_TABLE(of, ssm2602_of_match);
static struct i2c_driver ssm2602_i2c_driver = {
.driver = {
.name = "ssm2602",
- .owner = THIS_MODULE,
.of_match_table = ssm2602_of_match,
},
.probe = ssm2602_i2c_probe,
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 69a773a..4452fea 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -75,11 +75,10 @@ static const struct soc_enum ssm2602_enum[] = {
ssm2602_deemph),
};
-static const unsigned int ssm260x_outmix_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(ssm260x_outmix_tlv,
0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
- 48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0),
-};
+ 48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0)
+);
static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0);
static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0);
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
index 84a4f5a..e619d56 100644
--- a/sound/soc/codecs/ssm4567.c
+++ b/sound/soc/codecs/ssm4567.c
@@ -10,6 +10,7 @@
* Licensed under the GPL-2.
*/
+#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
@@ -173,6 +174,12 @@ static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = {
SND_SOC_DAPM_SWITCH("Amplifier Boost", SSM4567_REG_POWER_CTRL, 3, 1,
&ssm4567_amplifier_boost_control),
+ SND_SOC_DAPM_SIGGEN("Sense"),
+
+ SND_SOC_DAPM_PGA("Current Sense", SSM4567_REG_POWER_CTRL, 4, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Voltage Sense", SSM4567_REG_POWER_CTRL, 5, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("VBAT Sense", SSM4567_REG_POWER_CTRL, 6, 1, NULL, 0),
+
SND_SOC_DAPM_OUTPUT("OUT"),
};
@@ -180,6 +187,13 @@ static const struct snd_soc_dapm_route ssm4567_routes[] = {
{ "OUT", NULL, "Amplifier Boost" },
{ "Amplifier Boost", "Switch", "DAC" },
{ "OUT", NULL, "DAC" },
+
+ { "Current Sense", NULL, "Sense" },
+ { "Voltage Sense", NULL, "Sense" },
+ { "VBAT Sense", NULL, "Sense" },
+ { "Capture Sense", NULL, "Current Sense" },
+ { "Capture Sense", NULL, "Voltage Sense" },
+ { "Capture Sense", NULL, "VBAT Sense" },
};
static int ssm4567_hw_params(struct snd_pcm_substream *substream,
@@ -387,6 +401,14 @@ static struct snd_soc_dai_driver ssm4567_dai = {
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32,
},
+ .capture = {
+ .stream_name = "Capture Sense",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32,
+ },
.ops = &ssm4567_dai_ops,
};
@@ -456,10 +478,20 @@ static const struct i2c_device_id ssm4567_i2c_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids);
+#ifdef CONFIG_ACPI
+
+static const struct acpi_device_id ssm4567_acpi_match[] = {
+ { "INT343B", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, ssm4567_acpi_match);
+
+#endif
+
static struct i2c_driver ssm4567_driver = {
.driver = {
.name = "ssm4567",
- .owner = THIS_MODULE,
+ .acpi_match_table = ACPI_PTR(ssm4567_acpi_match),
},
.probe = ssm4567_i2c_probe,
.remove = ssm4567_i2c_remove,
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 60eff36..a9844b2 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -1144,7 +1144,6 @@ MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id);
static struct i2c_driver sta32x_i2c_driver = {
.driver = {
.name = "sta32x",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(st32x_dt_ids),
},
.probe = sta32x_i2c_probe,
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index bd819a3..33a4612 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -1264,7 +1264,6 @@ MODULE_DEVICE_TABLE(i2c, sta350_i2c_id);
static struct i2c_driver sta350_i2c_driver = {
.driver = {
.name = "sta350",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(st350_dt_ids),
},
.probe = sta350_i2c_probe,
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 4f70378..2cdaca9 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -339,9 +339,6 @@ static int sta529_i2c_probe(struct i2c_client *i2c,
struct sta529 *sta529;
int ret;
- if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EINVAL;
-
sta529 = devm_kzalloc(&i2c->dev, sizeof(struct sta529), GFP_KERNEL);
if (!sta529)
return -ENOMEM;
@@ -379,7 +376,6 @@ MODULE_DEVICE_TABLE(i2c, sta529_i2c_id);
static struct i2c_driver sta529_i2c_driver = {
.driver = {
.name = "sta529",
- .owner = THIS_MODULE,
},
.probe = sta529_i2c_probe,
.remove = sta529_i2c_remove,
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index ed4cca7..0945c51 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -28,6 +28,9 @@
#include "stac9766.h"
+#define STAC9766_VENDOR_ID 0x83847666
+#define STAC9766_VENDOR_ID_MASK 0xffffffff
+
/*
* STAC9766 register cache
*/
@@ -239,45 +242,12 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
-{
- struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
-
- if (try_warm && soc_ac97_ops->warm_reset) {
- soc_ac97_ops->warm_reset(ac97);
- if (stac9766_ac97_read(codec, 0) == stac9766_reg[0])
- return 1;
- }
-
- soc_ac97_ops->reset(ac97);
- if (soc_ac97_ops->warm_reset)
- soc_ac97_ops->warm_reset(ac97);
- if (stac9766_ac97_read(codec, 0) != stac9766_reg[0])
- return -EIO;
- return 0;
-}
-
static int stac9766_codec_resume(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
- u16 id, reset;
- reset = 0;
- /* give the codec an AC97 warm reset to start the link */
-reset:
- if (reset > 5) {
- dev_err(codec->dev, "Failed to resume\n");
- return -EIO;
- }
- ac97->bus->ops->warm_reset(ac97);
- id = soc_ac97_ops->read(ac97, AC97_VENDOR_ID2);
- if (id != 0x4c13) {
- stac9766_reset(codec, 0);
- reset++;
- goto reset;
- }
-
- return 0;
+ return snd_ac97_reset(ac97, true, STAC9766_VENDOR_ID,
+ STAC9766_VENDOR_ID_MASK);
}
static const struct snd_soc_dai_ops stac9766_dai_ops_analog = {
@@ -330,28 +300,15 @@ static struct snd_soc_dai_driver stac9766_dai[] = {
static int stac9766_codec_probe(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97;
- int ret = 0;
- ac97 = snd_soc_new_ac97_codec(codec);
+ ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID,
+ STAC9766_VENDOR_ID_MASK);
if (IS_ERR(ac97))
return PTR_ERR(ac97);
snd_soc_codec_set_drvdata(codec, ac97);
- /* do a cold reset for the controller and then try
- * a warm reset followed by an optional cold reset for codec */
- stac9766_reset(codec, 0);
- ret = stac9766_reset(codec, 1);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to reset: AC97 link error\n");
- goto codec_err;
- }
-
return 0;
-
-codec_err:
- snd_soc_free_ac97_codec(ac97);
- return ret;
}
static int stac9766_codec_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
new file mode 100644
index 0000000..160d61a
--- /dev/null
+++ b/sound/soc/codecs/sti-sas.c
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
+ * for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/mfd/syscon.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+/* chipID supported */
+#define CHIPID_STIH416 0
+#define CHIPID_STIH407 1
+
+/* DAC definitions */
+
+/* stih416 DAC registers */
+/* sysconf 2517: Audio-DAC-Control */
+#define STIH416_AUDIO_DAC_CTRL 0x00000814
+/* sysconf 2519: Audio-Gue-Control */
+#define STIH416_AUDIO_GLUE_CTRL 0x0000081C
+
+#define STIH416_DAC_NOT_STANDBY 0x3
+#define STIH416_DAC_SOFTMUTE 0x4
+#define STIH416_DAC_ANA_NOT_PWR 0x5
+#define STIH416_DAC_NOT_PNDBG 0x6
+
+#define STIH416_DAC_NOT_STANDBY_MASK BIT(STIH416_DAC_NOT_STANDBY)
+#define STIH416_DAC_SOFTMUTE_MASK BIT(STIH416_DAC_SOFTMUTE)
+#define STIH416_DAC_ANA_NOT_PWR_MASK BIT(STIH416_DAC_ANA_NOT_PWR)
+#define STIH416_DAC_NOT_PNDBG_MASK BIT(STIH416_DAC_NOT_PNDBG)
+
+/* stih407 DAC registers */
+/* sysconf 5041: Audio-Gue-Control */
+#define STIH407_AUDIO_GLUE_CTRL 0x000000A4
+/* sysconf 5042: Audio-DAC-Control */
+#define STIH407_AUDIO_DAC_CTRL 0x000000A8
+
+/* DAC definitions */
+#define STIH407_DAC_SOFTMUTE 0x0
+#define STIH407_DAC_STANDBY_ANA 0x1
+#define STIH407_DAC_STANDBY 0x2
+
+#define STIH407_DAC_SOFTMUTE_MASK BIT(STIH407_DAC_SOFTMUTE)
+#define STIH407_DAC_STANDBY_ANA_MASK BIT(STIH407_DAC_STANDBY_ANA)
+#define STIH407_DAC_STANDBY_MASK BIT(STIH407_DAC_STANDBY)
+
+/* SPDIF definitions */
+#define SPDIF_BIPHASE_ENABLE 0x6
+#define SPDIF_BIPHASE_IDLE 0x7
+
+#define SPDIF_BIPHASE_ENABLE_MASK BIT(SPDIF_BIPHASE_ENABLE)
+#define SPDIF_BIPHASE_IDLE_MASK BIT(SPDIF_BIPHASE_IDLE)
+
+enum {
+ STI_SAS_DAI_SPDIF_OUT,
+ STI_SAS_DAI_ANALOG_OUT,
+};
+
+static const struct reg_default stih416_sas_reg_defaults[] = {
+ { STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
+ { STIH407_AUDIO_DAC_CTRL, 0x000000000 },
+};
+
+static const struct reg_default stih407_sas_reg_defaults[] = {
+ { STIH416_AUDIO_DAC_CTRL, 0x000000000 },
+ { STIH416_AUDIO_GLUE_CTRL, 0x00000040 },
+};
+
+struct sti_dac_audio {
+ struct regmap *regmap;
+ struct regmap *virt_regmap;
+ struct regmap_field **field;
+ struct reset_control *rst;
+ int mclk;
+};
+
+struct sti_spdif_audio {
+ struct regmap *regmap;
+ struct regmap_field **field;
+ int mclk;
+};
+
+/* device data structure */
+struct sti_sas_dev_data {
+ const int chipid; /* IC version */
+ const struct regmap_config *regmap;
+ const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */
+ const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */
+ const int num_dapm_widgets; /* dapms declaration */
+ const struct snd_soc_dapm_route *dapm_routes; /* route declaration */
+ const int num_dapm_routes; /* route declaration */
+};
+
+/* driver data structure */
+struct sti_sas_data {
+ struct device *dev;
+ const struct sti_sas_dev_data *dev_data;
+ struct sti_dac_audio dac;
+ struct sti_spdif_audio spdif;
+};
+
+/* Read a register from the sysconf reg bank */
+static int sti_sas_read_reg(void *context, unsigned int reg,
+ unsigned int *value)
+{
+ struct sti_sas_data *drvdata = context;
+ int status;
+ u32 val;
+
+ status = regmap_read(drvdata->dac.regmap, reg, &val);
+ *value = (unsigned int)val;
+
+ return status;
+}
+
+/* Read a register from the sysconf reg bank */
+static int sti_sas_write_reg(void *context, unsigned int reg,
+ unsigned int value)
+{
+ struct sti_sas_data *drvdata = context;
+ int status;
+
+ status = regmap_write(drvdata->dac.regmap, reg, value);
+
+ return status;
+}
+
+static int sti_sas_init_sas_registers(struct snd_soc_codec *codec,
+ struct sti_sas_data *data)
+{
+ int ret;
+ /*
+ * DAC and SPDIF are activated by default
+ * put them in IDLE to save power
+ */
+
+ /* Initialise bi-phase formatter to disabled */
+ ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
+ SPDIF_BIPHASE_ENABLE_MASK, 0);
+
+ if (!ret)
+ /* Initialise bi-phase formatter idle value to 0 */
+ ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
+ SPDIF_BIPHASE_IDLE_MASK, 0);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to update SPDIF registers");
+ return ret;
+ }
+
+ /* Init DAC configuration */
+ switch (data->dev_data->chipid) {
+ case CHIPID_STIH407:
+ /* init configuration */
+ ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+ STIH407_DAC_STANDBY_MASK,
+ STIH407_DAC_STANDBY_MASK);
+
+ if (!ret)
+ ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+ STIH407_DAC_STANDBY_ANA_MASK,
+ STIH407_DAC_STANDBY_ANA_MASK);
+ if (!ret)
+ ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+ STIH407_DAC_SOFTMUTE_MASK,
+ STIH407_DAC_SOFTMUTE_MASK);
+ break;
+ case CHIPID_STIH416:
+ ret = snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL,
+ STIH416_DAC_NOT_STANDBY_MASK, 0);
+ if (!ret)
+ ret = snd_soc_update_bits(codec,
+ STIH416_AUDIO_DAC_CTRL,
+ STIH416_DAC_ANA_NOT_PWR, 0);
+ if (!ret)
+ ret = snd_soc_update_bits(codec,
+ STIH416_AUDIO_DAC_CTRL,
+ STIH416_DAC_NOT_PNDBG_MASK,
+ 0);
+ if (!ret)
+ ret = snd_soc_update_bits(codec,
+ STIH416_AUDIO_DAC_CTRL,
+ STIH416_DAC_SOFTMUTE_MASK,
+ STIH416_DAC_SOFTMUTE_MASK);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to update DAC registers");
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
+ * DAC
+ */
+static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ /* Sanity check only */
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+ dev_err(dai->codec->dev,
+ "%s: ERROR: Unsupporter master mask 0x%x\n",
+ __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int stih416_dac_probe(struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+ struct sti_dac_audio *dac = &drvdata->dac;
+
+ /* Get reset control */
+ dac->rst = devm_reset_control_get(codec->dev, "dac_rst");
+ if (IS_ERR(dac->rst)) {
+ dev_err(dai->codec->dev,
+ "%s: ERROR: DAC reset control not defined !\n",
+ __func__);
+ dac->rst = NULL;
+ return -EFAULT;
+ }
+ /* Put the DAC into reset */
+ reset_control_assert(dac->rst);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = {
+ SND_SOC_DAPM_PGA("DAC bandgap", STIH416_AUDIO_DAC_CTRL,
+ STIH416_DAC_NOT_PNDBG_MASK, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH416_AUDIO_DAC_CTRL,
+ STIH416_DAC_ANA_NOT_PWR, 0, NULL, 0),
+ SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH416_AUDIO_DAC_CTRL,
+ STIH416_DAC_NOT_STANDBY, 0),
+ SND_SOC_DAPM_OUTPUT("DAC Output"),
+};
+
+static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {
+ SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL,
+ STIH407_DAC_STANDBY_ANA, 1, NULL, 0),
+ SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH407_AUDIO_DAC_CTRL,
+ STIH407_DAC_STANDBY, 1),
+ SND_SOC_DAPM_OUTPUT("DAC Output"),
+};
+
+static const struct snd_soc_dapm_route stih416_sas_route[] = {
+ {"DAC Output", NULL, "DAC bandgap"},
+ {"DAC Output", NULL, "DAC standby ana"},
+ {"DAC standby ana", NULL, "DAC standby"},
+};
+
+static const struct snd_soc_dapm_route stih407_sas_route[] = {
+ {"DAC Output", NULL, "DAC standby ana"},
+ {"DAC standby ana", NULL, "DAC standby"},
+};
+
+static int stih416_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ if (mute) {
+ return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL,
+ STIH416_DAC_SOFTMUTE_MASK,
+ STIH416_DAC_SOFTMUTE_MASK);
+ } else {
+ return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL,
+ STIH416_DAC_SOFTMUTE_MASK, 0);
+ }
+}
+
+static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ if (mute) {
+ return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+ STIH407_DAC_SOFTMUTE_MASK,
+ STIH407_DAC_SOFTMUTE_MASK);
+ } else {
+ return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+ STIH407_DAC_SOFTMUTE_MASK,
+ 0);
+ }
+}
+
+/*
+ * SPDIF
+ */
+static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+ dev_err(dai->codec->dev,
+ "%s: ERROR: Unsupporter master mask 0x%x\n",
+ __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * sti_sas_spdif_trigger:
+ * Trigger function is used to ensure that BiPhase Formater is disabled
+ * before CPU dai is stopped.
+ * This is mandatory to avoid that BPF is stalled
+ */
+static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
+ SPDIF_BIPHASE_ENABLE_MASK,
+ SPDIF_BIPHASE_ENABLE_MASK);
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
+ SPDIF_BIPHASE_ENABLE_MASK,
+ 0);
+ default:
+ return -EINVAL;
+ }
+}
+
+static bool sti_sas_volatile_register(struct device *dev, unsigned int reg)
+{
+ if (reg == STIH407_AUDIO_GLUE_CTRL)
+ return true;
+
+ return false;
+}
+
+/*
+ * CODEC DAIS
+ */
+
+/*
+ * sti_sas_set_sysclk:
+ * get MCLK input frequency to check that MCLK-FS ratio is coherent
+ */
+static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+
+ if (dir == SND_SOC_CLOCK_OUT)
+ return 0;
+
+ if (clk_id != 0)
+ return -EINVAL;
+
+ switch (dai->id) {
+ case STI_SAS_DAI_SPDIF_OUT:
+ drvdata->spdif.mclk = freq;
+ break;
+
+ case STI_SAS_DAI_ANALOG_OUT:
+ drvdata->dac.mclk = freq;
+ break;
+ }
+
+ return 0;
+}
+
+static int sti_sas_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ switch (dai->id) {
+ case STI_SAS_DAI_SPDIF_OUT:
+ if ((drvdata->spdif.mclk / runtime->rate) != 128) {
+ dev_err(codec->dev, "unexpected mclk-fs ratio");
+ return -EINVAL;
+ }
+ break;
+ case STI_SAS_DAI_ANALOG_OUT:
+ if ((drvdata->dac.mclk / runtime->rate) != 256) {
+ dev_err(codec->dev, "unexpected mclk-fs ratio");
+ return -EINVAL;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops stih416_dac_ops = {
+ .set_fmt = sti_sas_dac_set_fmt,
+ .mute_stream = stih416_sas_dac_mute,
+ .prepare = sti_sas_prepare,
+ .set_sysclk = sti_sas_set_sysclk,
+};
+
+static const struct snd_soc_dai_ops stih407_dac_ops = {
+ .set_fmt = sti_sas_dac_set_fmt,
+ .mute_stream = stih407_sas_dac_mute,
+ .prepare = sti_sas_prepare,
+ .set_sysclk = sti_sas_set_sysclk,
+};
+
+static const struct regmap_config stih407_sas_regmap = {
+ .reg_bits = 32,
+ .val_bits = 32,
+
+ .max_register = STIH407_AUDIO_DAC_CTRL,
+ .reg_defaults = stih407_sas_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
+ .volatile_reg = sti_sas_volatile_register,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_read = sti_sas_read_reg,
+ .reg_write = sti_sas_write_reg,
+};
+
+static const struct regmap_config stih416_sas_regmap = {
+ .reg_bits = 32,
+ .val_bits = 32,
+
+ .max_register = STIH416_AUDIO_DAC_CTRL,
+ .reg_defaults = stih416_sas_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(stih416_sas_reg_defaults),
+ .volatile_reg = sti_sas_volatile_register,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_read = sti_sas_read_reg,
+ .reg_write = sti_sas_write_reg,
+};
+
+static const struct sti_sas_dev_data stih416_data = {
+ .chipid = CHIPID_STIH416,
+ .regmap = &stih416_sas_regmap,
+ .dac_ops = &stih416_dac_ops,
+ .dapm_widgets = stih416_sas_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(stih416_sas_dapm_widgets),
+ .dapm_routes = stih416_sas_route,
+ .num_dapm_routes = ARRAY_SIZE(stih416_sas_route),
+};
+
+static const struct sti_sas_dev_data stih407_data = {
+ .chipid = CHIPID_STIH407,
+ .regmap = &stih407_sas_regmap,
+ .dac_ops = &stih407_dac_ops,
+ .dapm_widgets = stih407_sas_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets),
+ .dapm_routes = stih407_sas_route,
+ .num_dapm_routes = ARRAY_SIZE(stih407_sas_route),
+};
+
+static struct snd_soc_dai_driver sti_sas_dai[] = {
+ {
+ .name = "sas-dai-spdif-out",
+ .id = STI_SAS_DAI_SPDIF_OUT,
+ .playback = {
+ .stream_name = "spdif_p",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = (struct snd_soc_dai_ops[]) {
+ {
+ .set_fmt = sti_sas_spdif_set_fmt,
+ .trigger = sti_sas_spdif_trigger,
+ .set_sysclk = sti_sas_set_sysclk,
+ .prepare = sti_sas_prepare,
+ }
+ },
+ },
+ {
+ .name = "sas-dai-dac",
+ .id = STI_SAS_DAI_ANALOG_OUT,
+ .playback = {
+ .stream_name = "dac_p",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ },
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int sti_sas_resume(struct snd_soc_codec *codec)
+{
+ struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+
+ return sti_sas_init_sas_registers(codec, drvdata);
+}
+#else
+#define sti_sas_resume NULL
+#endif
+
+static int sti_sas_codec_probe(struct snd_soc_codec *codec)
+{
+ struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+ int ret;
+
+ ret = sti_sas_init_sas_registers(codec, drvdata);
+
+ return ret;
+}
+
+static struct snd_soc_codec_driver sti_sas_driver = {
+ .probe = sti_sas_codec_probe,
+ .resume = sti_sas_resume,
+};
+
+static const struct of_device_id sti_sas_dev_match[] = {
+ {
+ .compatible = "st,stih416-sas-codec",
+ .data = &stih416_data,
+ },
+ {
+ .compatible = "st,stih407-sas-codec",
+ .data = &stih407_data,
+ },
+ {},
+};
+
+static int sti_sas_driver_probe(struct platform_device *pdev)
+{
+ struct device_node *pnode = pdev->dev.of_node;
+ struct sti_sas_data *drvdata;
+ const struct of_device_id *of_id;
+
+ /* Allocate device structure */
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data),
+ GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ /* Populate data structure depending on compatibility */
+ of_id = of_match_node(sti_sas_dev_match, pnode);
+ if (!of_id->data) {
+ dev_err(&pdev->dev, "data associated to device is missing");
+ return -EINVAL;
+ }
+
+ drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data;
+
+ /* Initialise device structure */
+ drvdata->dev = &pdev->dev;
+
+ /* Request the DAC & SPDIF registers memory region */
+ drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata,
+ drvdata->dev_data->regmap);
+ if (IS_ERR(drvdata->dac.virt_regmap)) {
+ dev_err(&pdev->dev, "audio registers not enabled\n");
+ return PTR_ERR(drvdata->dac.virt_regmap);
+ }
+
+ /* Request the syscon region */
+ drvdata->dac.regmap =
+ syscon_regmap_lookup_by_phandle(pnode, "st,syscfg");
+ if (IS_ERR(drvdata->dac.regmap)) {
+ dev_err(&pdev->dev, "syscon registers not available\n");
+ return PTR_ERR(drvdata->dac.regmap);
+ }
+ drvdata->spdif.regmap = drvdata->dac.regmap;
+
+ /* Set DAC dai probe */
+ if (drvdata->dev_data->chipid == CHIPID_STIH416)
+ sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].probe = stih416_dac_probe;
+
+ sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
+
+ /* Set dapms*/
+ sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
+ sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
+
+ sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes;
+ sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
+
+ /* Store context */
+ dev_set_drvdata(&pdev->dev, drvdata);
+
+ return snd_soc_register_codec(&pdev->dev, &sti_sas_driver,
+ sti_sas_dai,
+ ARRAY_SIZE(sti_sas_dai));
+}
+
+static int sti_sas_driver_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+
+ return 0;
+}
+
+static struct platform_driver sti_sas_platform_driver = {
+ .driver = {
+ .name = "sti-sas-codec",
+ .of_match_table = sti_sas_dev_match,
+ },
+ .probe = sti_sas_driver_probe,
+ .remove = sti_sas_driver_remove,
+};
+
+module_platform_driver(sti_sas_platform_driver);
+
+MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms");
+MODULE_AUTHOR("Arnaud.pouliquen@st.com");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 4f25a7d..e3a0bca 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -38,7 +38,7 @@
#include "tas2552.h"
-static struct reg_default tas2552_reg_defs[] = {
+static const struct reg_default tas2552_reg_defs[] = {
{TAS2552_CFG_1, 0x22},
{TAS2552_CFG_3, 0x80},
{TAS2552_DOUT, 0x00},
@@ -493,8 +493,7 @@ static int tas2552_runtime_suspend(struct device *dev)
regcache_cache_only(tas2552->regmap, true);
regcache_mark_dirty(tas2552->regmap);
- if (tas2552->enable_gpio)
- gpiod_set_value(tas2552->enable_gpio, 0);
+ gpiod_set_value(tas2552->enable_gpio, 0);
return 0;
}
@@ -503,8 +502,7 @@ static int tas2552_runtime_resume(struct device *dev)
{
struct tas2552_data *tas2552 = dev_get_drvdata(dev);
- if (tas2552->enable_gpio)
- gpiod_set_value(tas2552->enable_gpio, 1);
+ gpiod_set_value(tas2552->enable_gpio, 1);
tas2552_sw_shutdown(tas2552, 0);
@@ -520,7 +518,7 @@ static const struct dev_pm_ops tas2552_pm = {
NULL)
};
-static struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
+static const struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
.hw_params = tas2552_hw_params,
.prepare = tas2552_prepare,
.set_sysclk = tas2552_set_dai_sysclk,
@@ -585,8 +583,7 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec)
return ret;
}
- if (tas2552->enable_gpio)
- gpiod_set_value(tas2552->enable_gpio, 1);
+ gpiod_set_value(tas2552->enable_gpio, 1);
ret = pm_runtime_get_sync(codec->dev);
if (ret < 0) {
@@ -610,8 +607,7 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec)
return 0;
probe_fail:
- if (tas2552->enable_gpio)
- gpiod_set_value(tas2552->enable_gpio, 0);
+ gpiod_set_value(tas2552->enable_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies),
tas2552->supplies);
@@ -624,8 +620,7 @@ static int tas2552_codec_remove(struct snd_soc_codec *codec)
pm_runtime_put(codec->dev);
- if (tas2552->enable_gpio)
- gpiod_set_value(tas2552->enable_gpio, 0);
+ gpiod_set_value(tas2552->enable_gpio, 0);
return 0;
};
@@ -769,7 +764,6 @@ MODULE_DEVICE_TABLE(of, tas2552_of_match);
static struct i2c_driver tas2552_i2c_driver = {
.driver = {
.name = "tas2552",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(tas2552_of_match),
.pm = &tas2552_pm,
},
diff --git a/sound/soc/codecs/tas2552.h b/sound/soc/codecs/tas2552.h
index 5746f8f..e34752b 100644
--- a/sound/soc/codecs/tas2552.h
+++ b/sound/soc/codecs/tas2552.h
@@ -42,7 +42,7 @@
#define TAS2552_BOOST_APT_CTRL 0x14
#define TAS2552_VER_NUM 0x16
#define TAS2552_VBAT_DATA 0x19
-#define TAS2552_MAX_REG 0x20
+#define TAS2552_MAX_REG TAS2552_VBAT_DATA
/* CFG1 Register Masks */
#define TAS2552_DEV_RESET (1 << 0)
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index 32942be..d49d25d 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -266,10 +266,14 @@ static int tas5086_set_deemph(struct snd_soc_codec *codec)
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
int i, val = 0;
- if (priv->deemph)
- for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++)
- if (tas5086_deemph[i] == priv->rate)
+ if (priv->deemph) {
+ for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++) {
+ if (tas5086_deemph[i] == priv->rate) {
val = i;
+ break;
+ }
+ }
+ }
return regmap_update_bits(priv->regmap, TAS5086_SYS_CONTROL_1,
TAS5086_DEEMPH_MASK, val);
@@ -994,7 +998,6 @@ static int tas5086_i2c_remove(struct i2c_client *i2c)
static struct i2c_driver tas5086_i2c_driver = {
.driver = {
.name = "tas5086",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(tas5086_dt_ids),
},
.id_table = tas5086_i2c_id,
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c
index 85bcc37..39307ad 100644
--- a/sound/soc/codecs/tas571x.c
+++ b/sound/soc/codecs/tas571x.c
@@ -179,7 +179,7 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
if (!IS_ERR(priv->mclk)) {
ret = clk_prepare_enable(priv->mclk);
if (ret) {
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
index aab0af6..cb5310d 100644
--- a/sound/soc/codecs/tfa9879.c
+++ b/sound/soc/codecs/tfa9879.c
@@ -160,7 +160,7 @@ static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static struct reg_default tfa9879_regs[] = {
+static const struct reg_default tfa9879_regs[] = {
{ TFA9879_DEVICE_CONTROL, 0x0000 }, /* 0x00 */
{ TFA9879_SERIAL_INTERFACE_1, 0x0a18 }, /* 0x01 */
{ TFA9879_PCM_IOM2_FORMAT_1, 0x0007 }, /* 0x02 */
@@ -314,7 +314,6 @@ MODULE_DEVICE_TABLE(i2c, tfa9879_i2c_id);
static struct i2c_driver tfa9879_i2c_driver = {
.driver = {
.name = "tfa9879",
- .owner = THIS_MODULE,
},
.probe = tfa9879_i2c_probe,
.remove = tfa9879_i2c_remove,
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index c4c960f..ee4def4 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1121,7 +1121,7 @@ static struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
.num_dapm_routes = ARRAY_SIZE(aic31xx_audio_map),
};
-static struct snd_soc_dai_ops aic31xx_dai_ops = {
+static const struct snd_soc_dai_ops aic31xx_dai_ops = {
.hw_params = aic31xx_hw_params,
.set_sysclk = aic31xx_set_dai_sysclk,
.set_fmt = aic31xx_set_dai_fmt,
@@ -1283,7 +1283,6 @@ MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
static struct i2c_driver aic31xx_i2c_driver = {
.driver = {
.name = "tlv320aic31xx-codec",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(tlv320aic31xx_of_match),
},
.probe = aic31xx_i2c_probe,
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index ad6cb90..f2d3191 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -871,7 +871,6 @@ MODULE_DEVICE_TABLE(of, aic32x4_of_id);
static struct i2c_driver aic32x4_i2c_driver = {
.driver = {
.name = "tlv320aic32x4",
- .owner = THIS_MODULE,
.of_match_table = aic32x4_of_id,
},
.probe = aic32x4_i2c_probe,
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index a7cf19b..1a82b19 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1668,7 +1668,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
-static const struct reg_default aic3007_class_d[] = {
+static const struct reg_sequence aic3007_class_d[] = {
/* Class-D speaker driver init; datasheet p. 46 */
{ AIC3X_PAGE_SELECT, 0x0D },
{ 0xD, 0x0D },
@@ -1825,7 +1825,6 @@ MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match);
static struct i2c_driver aic3x_i2c_driver = {
.driver = {
.name = "tlv320aic3x-codec",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(tlv320aic3x_of_match),
},
.probe = aic3x_i2c_probe,
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index d67a311..781398fb 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -1585,7 +1585,6 @@ MODULE_DEVICE_TABLE(i2c, tlv320dac33_i2c_id);
static struct i2c_driver tlv320dac33_i2c_driver = {
.driver = {
.name = "tlv320dac33-codec",
- .owner = THIS_MODULE,
},
.probe = dac33_i2c_probe,
.remove = dac33_i2c_remove,
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 6fac9e0..11d85c5 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -259,8 +259,7 @@ static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol,
* TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
* down in gain.
*/
-static const unsigned int tpa6130_tlv[] = {
- TLV_DB_RANGE_HEAD(10),
+static const DECLARE_TLV_DB_RANGE(tpa6130_tlv,
0, 1, TLV_DB_SCALE_ITEM(-5950, 600, 0),
2, 3, TLV_DB_SCALE_ITEM(-5000, 250, 0),
4, 5, TLV_DB_SCALE_ITEM(-4550, 160, 0),
@@ -270,8 +269,8 @@ static const unsigned int tpa6130_tlv[] = {
12, 13, TLV_DB_SCALE_ITEM(-3040, 180, 0),
14, 20, TLV_DB_SCALE_ITEM(-2710, 110, 0),
21, 37, TLV_DB_SCALE_ITEM(-1960, 74, 0),
- 38, 63, TLV_DB_SCALE_ITEM(-720, 45, 0),
-};
+ 38, 63, TLV_DB_SCALE_ITEM(-720, 45, 0)
+);
static const struct snd_kcontrol_new tpa6130a2_controls[] = {
SOC_SINGLE_EXT_TLV("TPA6130A2 Headphone Playback Volume",
@@ -280,12 +279,11 @@ static const struct snd_kcontrol_new tpa6130a2_controls[] = {
tpa6130_tlv),
};
-static const unsigned int tpa6140_tlv[] = {
- TLV_DB_RANGE_HEAD(3),
+static const DECLARE_TLV_DB_RANGE(tpa6140_tlv,
0, 8, TLV_DB_SCALE_ITEM(-5900, 400, 0),
9, 16, TLV_DB_SCALE_ITEM(-2500, 200, 0),
- 17, 31, TLV_DB_SCALE_ITEM(-1000, 100, 0),
-};
+ 17, 31, TLV_DB_SCALE_ITEM(-1000, 100, 0)
+);
static const struct snd_kcontrol_new tpa6140a2_controls[] = {
SOC_SINGLE_EXT_TLV("TPA6140A2 Headphone Playback Volume",
@@ -488,7 +486,6 @@ MODULE_DEVICE_TABLE(of, tpa6130a2_of_match);
static struct i2c_driver tpa6130a2_i2c_driver = {
.driver = {
.name = "tpa6130a2",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(tpa6130a2_of_match),
},
.probe = tpa6130a2_probe,
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
index 12232d7..4356843 100644
--- a/sound/soc/codecs/ts3a227e.c
+++ b/sound/soc/codecs/ts3a227e.c
@@ -23,11 +23,13 @@
#include "ts3a227e.h"
struct ts3a227e {
+ struct device *dev;
struct regmap *regmap;
struct snd_soc_jack *jack;
bool plugged;
bool mic_present;
unsigned int buttons_held;
+ int irq;
};
/* Button values to be reported on the jack */
@@ -189,16 +191,28 @@ static irqreturn_t ts3a227e_interrupt(int irq, void *data)
struct ts3a227e *ts3a227e = (struct ts3a227e *)data;
struct regmap *regmap = ts3a227e->regmap;
unsigned int int_reg, kp_int_reg, acc_reg, i;
+ struct device *dev = ts3a227e->dev;
+ int ret;
/* Check for plug/unplug. */
- regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg);
+ ret = regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg);
+ if (ret) {
+ dev_err(dev, "failed to clear interrupt ret=%d\n", ret);
+ return IRQ_NONE;
+ }
+
if (int_reg & (DETECTION_COMPLETE_EVENT | INS_REM_EVENT)) {
regmap_read(regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg);
ts3a227e_new_jack_state(ts3a227e, acc_reg);
}
/* Report any key events. */
- regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg);
+ ret = regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg);
+ if (ret) {
+ dev_err(dev, "failed to clear key interrupt ret=%d\n", ret);
+ return IRQ_NONE;
+ }
+
for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) {
if (kp_int_reg & PRESS_MASK(i))
ts3a227e->buttons_held |= (1 << i);
@@ -283,6 +297,8 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
i2c_set_clientdata(i2c, ts3a227e);
+ ts3a227e->dev = dev;
+ ts3a227e->irq = i2c->irq;
ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config);
if (IS_ERR(ts3a227e->regmap))
@@ -320,6 +336,32 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int ts3a227e_suspend(struct device *dev)
+{
+ struct ts3a227e *ts3a227e = dev_get_drvdata(dev);
+
+ dev_dbg(ts3a227e->dev, "suspend disable irq\n");
+ disable_irq(ts3a227e->irq);
+
+ return 0;
+}
+
+static int ts3a227e_resume(struct device *dev)
+{
+ struct ts3a227e *ts3a227e = dev_get_drvdata(dev);
+
+ dev_dbg(ts3a227e->dev, "resume enable irq\n");
+ enable_irq(ts3a227e->irq);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops ts3a227e_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(ts3a227e_suspend, ts3a227e_resume)
+};
+
static const struct i2c_device_id ts3a227e_i2c_ids[] = {
{ "ts3a227e", 0 },
{ }
@@ -335,7 +377,7 @@ MODULE_DEVICE_TABLE(of, ts3a227e_of_match);
static struct i2c_driver ts3a227e_driver = {
.driver = {
.name = "ts3a227e",
- .owner = THIS_MODULE,
+ .pm = &ts3a227e_pm,
.of_match_table = of_match_ptr(ts3a227e_of_match),
},
.probe = ts3a227e_i2c_probe,
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 90f5f04..2713e18 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -524,12 +524,11 @@ static const struct snd_kcontrol_new twl4030_dapm_abypassv_control =
SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0);
/* Digital bypass gain, mute instead of -30dB */
-static const unsigned int twl4030_dapm_dbypass_tlv[] = {
- TLV_DB_RANGE_HEAD(3),
+static const DECLARE_TLV_DB_RANGE(twl4030_dapm_dbypass_tlv,
0, 1, TLV_DB_SCALE_ITEM(-3000, 600, 1),
2, 3, TLV_DB_SCALE_ITEM(-2400, 0, 0),
- 4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0),
-};
+ 4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0)
+);
/* Digital bypass left (TX1L -> RX2L) */
static const struct snd_kcontrol_new twl4030_dapm_dbypassl_control =
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 913edf2..e190263 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -37,74 +37,53 @@ struct uda134x_priv {
struct snd_pcm_substream *master_substream;
struct snd_pcm_substream *slave_substream;
-};
-/* In-data addresses are hard-coded into the reg-cache values */
-static const char uda134x_reg[UDA134X_REGS_NUM] = {
- /* Extended address registers */
- 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* Status, data regs */
- 0x00, 0x83, 0x00, 0x40, 0x80, 0xC0, 0x00,
+ struct regmap *regmap;
+ struct uda134x_platform_data *pd;
};
-/*
- * The codec has no support for reading its registers except for peak level...
- */
-static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- u8 *cache = codec->reg_cache;
-
- if (reg >= UDA134X_REGS_NUM)
- return -1;
- return cache[reg];
-}
-
-/*
- * Write the register cache
- */
-static inline void uda134x_write_reg_cache(struct snd_soc_codec *codec,
- u8 reg, unsigned int value)
-{
- u8 *cache = codec->reg_cache;
-
- if (reg >= UDA134X_REGS_NUM)
- return;
- cache[reg] = value;
-}
+static const struct reg_default uda134x_reg_defaults[] = {
+ { UDA134X_EA000, 0x04 },
+ { UDA134X_EA001, 0x04 },
+ { UDA134X_EA010, 0x04 },
+ { UDA134X_EA011, 0x00 },
+ { UDA134X_EA100, 0x00 },
+ { UDA134X_EA101, 0x00 },
+ { UDA134X_EA110, 0x00 },
+ { UDA134X_EA111, 0x00 },
+ { UDA134X_STATUS0, 0x00 },
+ { UDA134X_STATUS1, 0x03 },
+ { UDA134X_DATA000, 0x00 },
+ { UDA134X_DATA001, 0x00 },
+ { UDA134X_DATA010, 0x00 },
+ { UDA134X_DATA011, 0x00 },
+ { UDA134X_DATA1, 0x00 },
+};
/*
* Write to the uda134x registers
*
*/
-static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg,
+static int uda134x_regmap_write(void *context, unsigned int reg,
unsigned int value)
{
+ struct uda134x_platform_data *pd = context;
int ret;
u8 addr;
u8 data = value;
- struct uda134x_platform_data *pd = codec->control_data;
-
- pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value);
-
- if (reg >= UDA134X_REGS_NUM) {
- printk(KERN_ERR "%s unknown register: reg: %u",
- __func__, reg);
- return -EINVAL;
- }
-
- uda134x_write_reg_cache(codec, reg, value);
switch (reg) {
case UDA134X_STATUS0:
case UDA134X_STATUS1:
addr = UDA134X_STATUS_ADDR;
+ data |= (reg - UDA134X_STATUS0) << 7;
break;
case UDA134X_DATA000:
case UDA134X_DATA001:
case UDA134X_DATA010:
case UDA134X_DATA011:
addr = UDA134X_DATA0_ADDR;
+ data |= (reg - UDA134X_DATA000) << 6;
break;
case UDA134X_DATA1:
addr = UDA134X_DATA1_ADDR;
@@ -133,27 +112,28 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg,
static inline void uda134x_reset(struct snd_soc_codec *codec)
{
- u8 reset_reg = uda134x_read_reg_cache(codec, UDA134X_STATUS0);
- uda134x_write(codec, UDA134X_STATUS0, reset_reg | (1<<6));
+ struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+ unsigned int mask = 1<<6;
+
+ regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask);
msleep(1);
- uda134x_write(codec, UDA134X_STATUS0, reset_reg & ~(1<<6));
+ regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, 0);
}
static int uda134x_mute(struct snd_soc_dai *dai, int mute)
{
- struct snd_soc_codec *codec = dai->codec;
- u8 mute_reg = uda134x_read_reg_cache(codec, UDA134X_DATA010);
+ struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(dai->codec);
+ unsigned int mask = 1<<2;
+ unsigned int val;
pr_debug("%s mute: %d\n", __func__, mute);
if (mute)
- mute_reg |= (1<<2);
+ val = mask;
else
- mute_reg &= ~(1<<2);
+ val = 0;
- uda134x_write(codec, UDA134X_DATA010, mute_reg);
-
- return 0;
+ return regmap_update_bits(uda134x->regmap, UDA134X_DATA010, mask, val);
}
static int uda134x_startup(struct snd_pcm_substream *substream,
@@ -205,7 +185,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_codec *codec = dai->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
- u8 hw_params;
+ unsigned int hw_params = 0;
if (substream == uda134x->slave_substream) {
pr_debug("%s ignoring hw_params for slave substream\n",
@@ -213,10 +193,6 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
return 0;
}
- hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0);
- hw_params &= STATUS0_SYSCLK_MASK;
- hw_params &= STATUS0_DAIFMT_MASK;
-
pr_debug("%s sysclk: %d, rate:%d\n", __func__,
uda134x->sysclk, params_rate(params));
@@ -267,9 +243,8 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- uda134x_write(codec, UDA134X_STATUS0, hw_params);
-
- return 0;
+ return regmap_update_bits(uda134x->regmap, UDA134X_STATUS0,
+ STATUS0_SYSCLK_MASK | STATUS0_DAIFMT_MASK, hw_params);
}
static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
@@ -324,10 +299,8 @@ static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int uda134x_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- struct uda134x_platform_data *pd = codec->control_data;
- int i;
- u8 *cache = codec->reg_cache;
-
+ struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+ struct uda134x_platform_data *pd = uda134x->pd;
pr_debug("%s bias level %d\n", __func__, level);
switch (level) {
@@ -337,17 +310,17 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
/* power on */
if (pd->power) {
pd->power(1);
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
- codec->driver->write(codec, i, *cache++);
+ regcache_sync(uda134x->regmap);
}
break;
case SND_SOC_BIAS_STANDBY:
break;
case SND_SOC_BIAS_OFF:
/* power off */
- if (pd->power)
+ if (pd->power) {
pd->power(0);
+ regcache_mark_dirty(uda134x->regmap);
+ }
break;
}
return 0;
@@ -478,21 +451,14 @@ static struct snd_soc_dai_driver uda134x_dai = {
static int uda134x_soc_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
- struct uda134x_priv *uda134x;
- struct uda134x_platform_data *pd = codec->component.card->dev->platform_data;
+ struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+ struct uda134x_platform_data *pd = uda134x->pd;
const struct snd_soc_dapm_widget *widgets;
unsigned num_widgets;
-
int ret;
printk(KERN_INFO "UDA134X SoC Audio Codec\n");
- if (!pd) {
- printk(KERN_ERR "UDA134X SoC codec: "
- "missing L3 bitbang function\n");
- return -ENODEV;
- }
-
switch (pd->model) {
case UDA134X_UDA1340:
case UDA134X_UDA1341:
@@ -506,13 +472,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
return -EINVAL;
}
- uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
- if (uda134x == NULL)
- return -ENOMEM;
- snd_soc_codec_set_drvdata(codec, uda134x);
-
- codec->control_data = pd;
-
if (pd->power)
pd->power(1);
@@ -530,7 +489,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
if (ret) {
printk(KERN_ERR "%s failed to register dapm controls: %d",
__func__, ret);
- kfree(uda134x);
return ret;
}
@@ -551,36 +509,19 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
default:
printk(KERN_ERR "%s unknown codec type: %d",
__func__, pd->model);
- kfree(uda134x);
return -EINVAL;
}
if (ret < 0) {
printk(KERN_ERR "UDA134X: failed to register controls\n");
- kfree(uda134x);
return ret;
}
return 0;
}
-/* power down chip */
-static int uda134x_soc_remove(struct snd_soc_codec *codec)
-{
- struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
-
- kfree(uda134x);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
.probe = uda134x_soc_probe,
- .remove = uda134x_soc_remove,
- .reg_cache_size = sizeof(uda134x_reg),
- .reg_word_size = sizeof(u8),
- .reg_cache_default = uda134x_reg,
- .reg_cache_step = 1,
- .read = uda134x_read_reg_cache,
.set_bias_level = uda134x_set_bias_level,
.suspend_bias_off = true,
@@ -590,8 +531,39 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
.num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
};
+static const struct regmap_config uda134x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = UDA134X_DATA1,
+ .reg_defaults = uda134x_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(uda134x_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+
+ .reg_write = uda134x_regmap_write,
+};
+
static int uda134x_codec_probe(struct platform_device *pdev)
{
+ struct uda134x_platform_data *pd = pdev->dev.platform_data;
+ struct uda134x_priv *uda134x;
+
+ if (!pd) {
+ dev_err(&pdev->dev, "Missing L3 bitbang function\n");
+ return -ENODEV;
+ }
+
+ uda134x = devm_kzalloc(&pdev->dev, sizeof(*uda134x), GFP_KERNEL);
+ if (!uda134x)
+ return -ENOMEM;
+
+ uda134x->pd = pd;
+ platform_set_drvdata(pdev, uda134x);
+
+ uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd,
+ &uda134x_regmap_config);
+ if (IS_ERR(uda134x->regmap))
+ return PTR_ERR(uda134x->regmap);
+
return snd_soc_register_codec(&pdev->dev,
&soc_codec_dev_uda134x, &uda134x_dai, 1);
}
diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h
index 9faae06..e41ab38 100644
--- a/sound/soc/codecs/uda134x.h
+++ b/sound/soc/codecs/uda134x.h
@@ -26,8 +26,6 @@
#define UDA134X_DATA011 13
#define UDA134X_DATA1 14
-#define UDA134X_REGS_NUM 15
-
#define STATUS0_DAIFMT_MASK (~(7<<1))
#define STATUS0_SYSCLK_MASK (~(3<<4))
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 6e159f5..35f0469 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -269,12 +269,11 @@ static DECLARE_TLV_DB_SCALE(amix_tlv, -4950, 150, 1);
* from -66 dB in 0.5 dB steps (2 dB steps, really) and
* from -52 dB in 0.25 dB steps
*/
-static const unsigned int mvol_tlv[] = {
- TLV_DB_RANGE_HEAD(3),
+static const DECLARE_TLV_DB_RANGE(mvol_tlv,
0, 15, TLV_DB_SCALE_ITEM(-8200, 100, 1),
16, 43, TLV_DB_SCALE_ITEM(-6600, 50, 0),
- 44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0),
-};
+ 44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0)
+);
/*
* from -72 dB in 1.5 dB steps (6 dB steps really),
@@ -282,13 +281,12 @@ static const unsigned int mvol_tlv[] = {
* from -60 dB in 0.5 dB steps (2 dB steps really) and
* from -46 dB in 0.25 dB steps
*/
-static const unsigned int vc_tlv[] = {
- TLV_DB_RANGE_HEAD(4),
+static const DECLARE_TLV_DB_RANGE(vc_tlv,
0, 7, TLV_DB_SCALE_ITEM(-7800, 150, 1),
8, 15, TLV_DB_SCALE_ITEM(-6600, 75, 0),
16, 43, TLV_DB_SCALE_ITEM(-6000, 50, 0),
- 44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0),
-};
+ 44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0)
+);
/* from 0 to 6 dB in 2 dB steps if SPF mode != flat */
static DECLARE_TLV_DB_SCALE(tr_tlv, 0, 200, 0);
@@ -810,7 +808,6 @@ MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
static struct i2c_driver uda1380_i2c_driver = {
.driver = {
.name = "uda1380-codec",
- .owner = THIS_MODULE,
},
.probe = uda1380_i2c_probe,
.remove = uda1380_i2c_remove,
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index 6560a66..f2c6ad4 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -953,7 +953,7 @@ static int wm0010_spi_probe(struct spi_device *spi)
trigger = IRQF_TRIGGER_FALLING;
trigger |= IRQF_ONESHOT;
- ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger | IRQF_ONESHOT,
+ ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger,
"wm0010", wm0010);
if (ret) {
dev_err(wm0010->dev, "Failed to request IRQ %d: %d\n",
@@ -1003,7 +1003,6 @@ static int wm0010_spi_remove(struct spi_device *spi)
static struct spi_driver wm0010_spi_driver = {
.driver = {
.name = "wm0010",
- .bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = wm0010_spi_probe,
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
index 048f005..ec45c5b 100644
--- a/sound/soc/codecs/wm1250-ev1.c
+++ b/sound/soc/codecs/wm1250-ev1.c
@@ -251,7 +251,6 @@ MODULE_DEVICE_TABLE(i2c, wm1250_ev1_i2c_id);
static struct i2c_driver wm1250_ev1_i2c_driver = {
.driver = {
.name = "wm1250-ev1",
- .owner = THIS_MODULE,
},
.probe = wm1250_ev1_probe,
.remove = wm1250_ev1_remove,
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 21d5402..786abd0 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -942,7 +942,6 @@ MODULE_DEVICE_TABLE(i2c, wm2000_i2c_id);
static struct i2c_driver wm2000_i2c_driver = {
.driver = {
.name = "wm2000",
- .owner = THIS_MODULE,
},
.probe = wm2000_i2c_probe,
.remove = wm2000_i2c_remove,
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index c830832..fd1439e 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -166,7 +166,7 @@ static const struct wm_adsp_region wm2200_dsp2_regions[] = {
{ .type = WMFW_ADSP1_ZM, .base = WM2200_DSP2_ZM_BASE },
};
-static struct reg_default wm2200_reg_defaults[] = {
+static const struct reg_default wm2200_reg_defaults[] = {
{ 0x000B, 0x0000 }, /* R11 - Tone Generator 1 */
{ 0x0102, 0x0000 }, /* R258 - Clocking 3 */
{ 0x0103, 0x0011 }, /* R259 - Clocking 4 */
@@ -897,7 +897,7 @@ static bool wm2200_readable_register(struct device *dev, unsigned int reg)
}
}
-static const struct reg_default wm2200_reva_patch[] = {
+static const struct reg_sequence wm2200_reva_patch[] = {
{ 0x07, 0x0003 },
{ 0x102, 0x0200 },
{ 0x203, 0x0084 },
@@ -1702,7 +1702,7 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream,
int *bclk_rates;
/* Data sizes if not using TDM */
- wl = snd_pcm_format_width(params_format(params));
+ wl = params_width(params);
if (wl < 0)
return wl;
fl = snd_soc_params_to_frame_size(params);
@@ -2481,7 +2481,7 @@ static int wm2200_runtime_resume(struct device *dev)
}
#endif
-static struct dev_pm_ops wm2200_pm = {
+static const struct dev_pm_ops wm2200_pm = {
SET_RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume,
NULL)
};
@@ -2495,7 +2495,6 @@ MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id);
static struct i2c_driver wm2200_i2c_driver = {
.driver = {
.name = "wm2200",
- .owner = THIS_MODULE,
.pm = &wm2200_pm,
},
.probe = wm2200_i2c_probe,
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 4c10cd8..c2cdcae 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -1247,7 +1247,7 @@ static const struct snd_soc_dapm_route wm5100_dapm_routes[] = {
{ "PWM2", NULL, "PWM2 Driver" },
};
-static const struct reg_default wm5100_reva_patches[] = {
+static const struct reg_sequence wm5100_reva_patches[] = {
{ WM5100_AUDIO_IF_1_10, 0 },
{ WM5100_AUDIO_IF_1_11, 1 },
{ WM5100_AUDIO_IF_1_12, 2 },
@@ -1408,7 +1408,7 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream,
base = dai->driver->base;
/* Data sizes if not using TDM */
- wl = snd_pcm_format_width(params_format(params));
+ wl = params_width(params);
if (wl < 0)
return wl;
fl = snd_soc_params_to_frame_size(params);
@@ -2570,13 +2570,11 @@ static int wm5100_i2c_probe(struct i2c_client *i2c,
if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
ret = request_threaded_irq(i2c->irq, NULL,
- wm5100_edge_irq,
- irq_flags | IRQF_ONESHOT,
+ wm5100_edge_irq, irq_flags,
"wm5100", wm5100);
else
ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq,
- irq_flags | IRQF_ONESHOT,
- "wm5100",
+ irq_flags, "wm5100",
wm5100);
if (ret != 0) {
@@ -2708,7 +2706,7 @@ static int wm5100_runtime_resume(struct device *dev)
}
#endif
-static struct dev_pm_ops wm5100_pm = {
+static const struct dev_pm_ops wm5100_pm = {
SET_RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume,
NULL)
};
@@ -2722,7 +2720,6 @@ MODULE_DEVICE_TABLE(i2c, wm5100_i2c_id);
static struct i2c_driver wm5100_i2c_driver = {
.driver = {
.name = "wm5100",
- .owner = THIS_MODULE,
.pm = &wm5100_pm,
},
.probe = wm5100_i2c_probe,
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index d097f09e5..64637d1 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -788,8 +788,7 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
-SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19),
-SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2),
SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
@@ -801,8 +800,7 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
24, 0, eq_tlv),
-SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19),
-SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2),
SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
@@ -814,8 +812,7 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
24, 0, eq_tlv),
-SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19),
-SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2),
SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
@@ -827,8 +824,7 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
24, 0, eq_tlv),
-SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19),
-SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2),
SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
@@ -851,10 +847,10 @@ ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
-SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1),
-SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1),
-SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1),
-SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1),
+ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2),
+ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
+ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
+ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
@@ -1883,7 +1879,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
ret = snd_soc_add_codec_controls(codec,
arizona_adsp2_rate_controls, 1);
if (ret)
- return ret;
+ goto err_adsp2_codec_probe;
arizona_init_spk(codec);
arizona_init_gpio(codec);
@@ -1893,6 +1889,11 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
priv->core.arizona->dapm = dapm;
return 0;
+
+err_adsp2_codec_probe:
+ wm_adsp2_codec_remove(&priv->core.adsp[0], codec);
+
+ return ret;
}
static int wm5102_codec_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 709fcc6..9756578 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -131,6 +131,25 @@ static const struct reg_default wm5110_sysclk_revd_patch[] = {
{ 0x33fb, 0xfe00 },
};
+static const struct reg_default wm5110_sysclk_reve_patch[] = {
+ { 0x3270, 0xE410 },
+ { 0x3271, 0x3078 },
+ { 0x3272, 0xE410 },
+ { 0x3273, 0x3070 },
+ { 0x3274, 0xE410 },
+ { 0x3275, 0x3066 },
+ { 0x3276, 0xE410 },
+ { 0x3277, 0x3056 },
+ { 0x327A, 0xE414 },
+ { 0x327B, 0x3078 },
+ { 0x327C, 0xE414 },
+ { 0x327D, 0x3070 },
+ { 0x327E, 0xE414 },
+ { 0x327F, 0x3066 },
+ { 0x3280, 0xE414 },
+ { 0x3281, 0x3056 },
+};
+
static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -146,7 +165,9 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
patch_size = ARRAY_SIZE(wm5110_sysclk_revd_patch);
break;
default:
- return 0;
+ patch = wm5110_sysclk_reve_patch;
+ patch_size = ARRAY_SIZE(wm5110_sysclk_reve_patch);
+ break;
}
switch (event) {
@@ -164,6 +185,249 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
return 0;
}
+static const struct reg_sequence wm5110_no_dre_left_enable[] = {
+ { 0x3024, 0xE410 },
+ { 0x3025, 0x0056 },
+ { 0x301B, 0x0224 },
+ { 0x301F, 0x4263 },
+ { 0x3021, 0x5291 },
+ { 0x3030, 0xE410 },
+ { 0x3031, 0x3066 },
+ { 0x3032, 0xE410 },
+ { 0x3033, 0x3070 },
+ { 0x3034, 0xE410 },
+ { 0x3035, 0x3078 },
+ { 0x3036, 0xE410 },
+ { 0x3037, 0x3080 },
+ { 0x3038, 0xE410 },
+ { 0x3039, 0x3080 },
+};
+
+static const struct reg_sequence wm5110_dre_left_enable[] = {
+ { 0x3024, 0x0231 },
+ { 0x3025, 0x0B00 },
+ { 0x301B, 0x0227 },
+ { 0x301F, 0x4266 },
+ { 0x3021, 0x5294 },
+ { 0x3030, 0xE231 },
+ { 0x3031, 0x0266 },
+ { 0x3032, 0x8231 },
+ { 0x3033, 0x4B15 },
+ { 0x3034, 0x8231 },
+ { 0x3035, 0x0B15 },
+ { 0x3036, 0xE231 },
+ { 0x3037, 0x5294 },
+ { 0x3038, 0x0231 },
+ { 0x3039, 0x0B00 },
+};
+
+static const struct reg_sequence wm5110_no_dre_right_enable[] = {
+ { 0x3074, 0xE414 },
+ { 0x3075, 0x0056 },
+ { 0x306B, 0x0224 },
+ { 0x306F, 0x4263 },
+ { 0x3071, 0x5291 },
+ { 0x3080, 0xE414 },
+ { 0x3081, 0x3066 },
+ { 0x3082, 0xE414 },
+ { 0x3083, 0x3070 },
+ { 0x3084, 0xE414 },
+ { 0x3085, 0x3078 },
+ { 0x3086, 0xE414 },
+ { 0x3087, 0x3080 },
+ { 0x3088, 0xE414 },
+ { 0x3089, 0x3080 },
+};
+
+static const struct reg_sequence wm5110_dre_right_enable[] = {
+ { 0x3074, 0x0231 },
+ { 0x3075, 0x0B00 },
+ { 0x306B, 0x0227 },
+ { 0x306F, 0x4266 },
+ { 0x3071, 0x5294 },
+ { 0x3080, 0xE231 },
+ { 0x3081, 0x0266 },
+ { 0x3082, 0x8231 },
+ { 0x3083, 0x4B17 },
+ { 0x3084, 0x8231 },
+ { 0x3085, 0x0B17 },
+ { 0x3086, 0xE231 },
+ { 0x3087, 0x5294 },
+ { 0x3088, 0x0231 },
+ { 0x3089, 0x0B00 },
+};
+
+static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct arizona *arizona = priv->arizona;
+ unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE);
+ const struct reg_sequence *wseq;
+ int nregs;
+
+ switch (w->shift) {
+ case ARIZONA_OUT1L_ENA_SHIFT:
+ if (val & ARIZONA_DRE1L_ENA_MASK) {
+ wseq = wm5110_dre_left_enable;
+ nregs = ARRAY_SIZE(wm5110_dre_left_enable);
+ } else {
+ wseq = wm5110_no_dre_left_enable;
+ nregs = ARRAY_SIZE(wm5110_no_dre_left_enable);
+ priv->out_up_delay += 10;
+ }
+ break;
+ case ARIZONA_OUT1R_ENA_SHIFT:
+ if (val & ARIZONA_DRE1R_ENA_MASK) {
+ wseq = wm5110_dre_right_enable;
+ nregs = ARRAY_SIZE(wm5110_dre_right_enable);
+ } else {
+ wseq = wm5110_no_dre_right_enable;
+ nregs = ARRAY_SIZE(wm5110_no_dre_right_enable);
+ priv->out_up_delay += 10;
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ return regmap_multi_reg_write(arizona->regmap, wseq, nregs);
+}
+
+static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+ unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE);
+
+ switch (w->shift) {
+ case ARIZONA_OUT1L_ENA_SHIFT:
+ if (!(val & ARIZONA_DRE1L_ENA_MASK)) {
+ snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
+ ARIZONA_WS_TRG1, ARIZONA_WS_TRG1);
+ snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
+ ARIZONA_WS_TRG1, 0);
+ priv->out_down_delay += 27;
+ }
+ break;
+ case ARIZONA_OUT1R_ENA_SHIFT:
+ if (!(val & ARIZONA_DRE1R_ENA_MASK)) {
+ snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
+ ARIZONA_WS_TRG2, ARIZONA_WS_TRG2);
+ snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
+ ARIZONA_WS_TRG2, 0);
+ priv->out_down_delay += 27;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int wm5110_hp_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ switch (priv->arizona->rev) {
+ case 0 ... 3:
+ break;
+ default:
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wm5110_hp_pre_enable(w);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wm5110_hp_pre_disable(w);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ return arizona_hp_ev(w, kcontrol, event);
+}
+
+static int wm5110_clear_pga_volume(struct arizona *arizona, int output)
+{
+ struct reg_sequence clear_pga = {
+ ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80
+ };
+ int ret;
+
+ ret = regmap_multi_reg_write_bypassed(arizona->regmap, &clear_pga, 1);
+ if (ret)
+ dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n",
+ clear_pga.reg, ret);
+
+ return ret;
+}
+
+static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int ena, dre;
+ unsigned int mask = (0x1 << mc->shift) | (0x1 << mc->rshift);
+ unsigned int lnew = (!!ucontrol->value.integer.value[0]) << mc->shift;
+ unsigned int rnew = (!!ucontrol->value.integer.value[1]) << mc->rshift;
+ unsigned int lold, rold;
+ unsigned int lena, rena;
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &ena);
+ if (ret) {
+ dev_err(arizona->dev, "Failed to read output state: %d\n", ret);
+ goto err;
+ }
+ ret = regmap_read(arizona->regmap, ARIZONA_DRE_ENABLE, &dre);
+ if (ret) {
+ dev_err(arizona->dev, "Failed to read DRE state: %d\n", ret);
+ goto err;
+ }
+
+ lold = dre & (1 << mc->shift);
+ rold = dre & (1 << mc->rshift);
+ /* Enables are channel wise swapped from the DRE enables */
+ lena = ena & (1 << mc->rshift);
+ rena = ena & (1 << mc->shift);
+
+ if ((lena && lnew != lold) || (rena && rnew != rold)) {
+ dev_err(arizona->dev, "Can't change DRE on active outputs\n");
+ ret = -EBUSY;
+ goto err;
+ }
+
+ ret = regmap_update_bits(arizona->regmap, ARIZONA_DRE_ENABLE,
+ mask, lnew | rnew);
+ if (ret) {
+ dev_err(arizona->dev, "Failed to set DRE: %d\n", ret);
+ goto err;
+ }
+
+ /* Force reset of PGA volumes, if turning DRE off */
+ if (!lnew && lold)
+ wm5110_clear_pga_volume(arizona, mc->shift);
+
+ if (!rnew && rold)
+ wm5110_clear_pga_volume(arizona, mc->rshift);
+
+err:
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return ret;
+}
+
static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
@@ -247,8 +511,7 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
-SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19),
-SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2),
SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
@@ -260,8 +523,7 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
24, 0, eq_tlv),
-SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19),
-SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2),
SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
@@ -273,8 +535,7 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
24, 0, eq_tlv),
-SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19),
-SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2),
SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
@@ -286,8 +547,7 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
24, 0, eq_tlv),
-SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19),
-SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2),
SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
@@ -314,10 +574,10 @@ ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
-SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1),
-SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1),
-SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1),
-SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1),
+ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2),
+ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
+ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
+ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
@@ -409,12 +669,15 @@ SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT,
ARIZONA_SPK2R_MUTE_SHIFT, 1, 1),
-SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
- ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0),
-SOC_DOUBLE("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE,
- ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0),
-SOC_DOUBLE("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE,
- ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0),
+SOC_DOUBLE_EXT("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
+ ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0,
+ snd_soc_get_volsw, wm5110_put_dre),
+SOC_DOUBLE_EXT("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE,
+ ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0,
+ snd_soc_get_volsw, wm5110_put_dre),
+SOC_DOUBLE_EXT("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE,
+ ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0,
+ snd_soc_get_volsw, wm5110_put_dre),
SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
@@ -904,11 +1167,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
- ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+ ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, wm5110_hp_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
- ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+ ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, wm5110_hp_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
@@ -1611,18 +1874,24 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
for (i = 0; i < WM5110_NUM_ADSP; ++i) {
ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
if (ret)
- return ret;
+ goto err_adsp2_codec_probe;
}
ret = snd_soc_add_codec_controls(codec,
arizona_adsp2_rate_controls,
WM5110_NUM_ADSP);
if (ret)
- return ret;
+ goto err_adsp2_codec_probe;
snd_soc_dapm_disable_pin(dapm, "HAPTICS");
return 0;
+
+err_adsp2_codec_probe:
+ for (--i; i >= 0; --i)
+ wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
+
+ return ret;
}
static int wm5110_codec_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 41c62c1..ffbf3df 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -394,11 +394,10 @@ static DECLARE_TLV_DB_SCALE(dac_pcm_tlv, -7163, 36, 1);
static DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -12700, 50, 1);
static DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 1);
-static const unsigned int capture_sd_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(capture_sd_tlv,
0, 12, TLV_DB_SCALE_ITEM(-3600, 300, 1),
- 13, 15, TLV_DB_SCALE_ITEM(0, 0, 0),
-};
+ 13, 15, TLV_DB_SCALE_ITEM(0, 0, 0)
+);
static const struct snd_kcontrol_new wm8350_snd_controls[] = {
SOC_ENUM("Playback Deemphasis", wm8350_enum[0]),
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index d755508..b1d346a 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -370,10 +370,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
}
/* INMIX dB values */
-static const unsigned int in_mix_tlv[] = {
- TLV_DB_RANGE_HEAD(1),
- 0,7, TLV_DB_SCALE_ITEM(-1200, 600, 0),
-};
+static const DECLARE_TLV_DB_SCALE(in_mix_tlv, -1200, 600, 0);
/* Left In PGA Connections */
static const struct snd_kcontrol_new wm8400_dapm_lin12_pga_controls[] = {
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index dac5beb..b098a83 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -598,6 +598,7 @@ static const struct of_device_id wm8510_of_match[] = {
{ .compatible = "wlf,wm8510" },
{ },
};
+MODULE_DEVICE_TABLE(of, wm8510_of_match);
static const struct regmap_config wm8510_regmap = {
.reg_bits = 7,
@@ -690,7 +691,6 @@ MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
static struct i2c_driver wm8510_i2c_driver = {
.driver = {
.name = "wm8510",
- .owner = THIS_MODULE,
.of_match_table = wm8510_of_match,
},
.probe = wm8510_i2c_probe,
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 43ea8ae..aa287a3 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -430,6 +430,7 @@ static const struct of_device_id wm8523_of_match[] = {
{ .compatible = "wlf,wm8523" },
{ },
};
+MODULE_DEVICE_TABLE(of, wm8523_of_match);
static const struct regmap_config wm8523_regmap = {
.reg_bits = 8,
@@ -534,7 +535,6 @@ MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id);
static struct i2c_driver wm8523_i2c_driver = {
.driver = {
.name = "wm8523",
- .owner = THIS_MODULE,
.of_match_table = wm8523_of_match,
},
.probe = wm8523_i2c_probe,
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 759a792..66602bf 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -916,6 +916,7 @@ static const struct of_device_id wm8580_of_match[] = {
{ .compatible = "wlf,wm8580" },
{ },
};
+MODULE_DEVICE_TABLE(of, wm8580_of_match);
static const struct regmap_config wm8580_regmap = {
.reg_bits = 7,
@@ -978,7 +979,6 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
static struct i2c_driver wm8580_i2c_driver = {
.driver = {
.name = "wm8580",
- .owner = THIS_MODULE,
.of_match_table = wm8580_of_match,
},
.probe = wm8580_i2c_probe,
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index cc8251f..44b9e0a 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -478,7 +478,6 @@ MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id);
static struct i2c_driver wm8711_i2c_driver = {
.driver = {
.name = "wm8711",
- .owner = THIS_MODULE,
.of_match_table = wm8711_of_match,
},
.probe = wm8711_i2c_probe,
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index f1a173e..cd7b024 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -319,7 +319,6 @@ MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
static struct i2c_driver wm8728_i2c_driver = {
.driver = {
.name = "wm8728",
- .owner = THIS_MODULE,
.of_match_table = wm8728_of_match,
},
.probe = wm8728_i2c_probe,
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 915ea11..ace8645 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -79,12 +79,7 @@ static bool wm8731_volatile(struct device *dev, unsigned int reg)
return reg == WM8731_RESET;
}
-static bool wm8731_writeable(struct device *dev, unsigned int reg)
-{
- return reg <= WM8731_RESET;
-}
-
-#define wm8731_reset(c) snd_soc_write(c, WM8731_RESET, 0)
+#define wm8731_reset(m) regmap_write(m, WM8731_RESET, 0)
static const char *wm8731_input_select[] = {"Line In", "Mic"};
@@ -496,8 +491,11 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
- if (wm8731->mclk)
- clk_prepare_enable(wm8731->mclk);
+ if (wm8731->mclk) {
+ ret = clk_prepare_enable(wm8731->mclk);
+ if (ret)
+ return ret;
+ }
break;
case SND_SOC_BIAS_PREPARE:
break;
@@ -571,69 +569,63 @@ static struct snd_soc_dai_driver wm8731_dai = {
.symmetric_rates = 1,
};
-static int wm8731_probe(struct snd_soc_codec *codec)
+static int wm8731_request_supplies(struct device *dev,
+ struct wm8731_priv *wm8731)
{
- struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
int ret = 0, i;
for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
wm8731->supplies[i].supply = wm8731_supply_names[i];
- ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies),
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8731->supplies),
wm8731->supplies);
if (ret != 0) {
- dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ dev_err(dev, "Failed to request supplies: %d\n", ret);
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
wm8731->supplies);
if (ret != 0) {
- dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ dev_err(dev, "Failed to enable supplies: %d\n", ret);
return ret;
}
- ret = wm8731_reset(codec);
+ return 0;
+}
+
+static int wm8731_hw_init(struct device *dev, struct wm8731_priv *wm8731)
+{
+ int ret = 0;
+
+ ret = wm8731_reset(wm8731->regmap);
if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+ dev_err(dev, "Failed to issue reset: %d\n", ret);
goto err_regulator_enable;
}
- snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ /* Clear POWEROFF, keep everything else disabled */
+ regmap_write(wm8731->regmap, WM8731_PWR, 0x7f);
/* Latch the update bits */
- snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0);
- snd_soc_update_bits(codec, WM8731_ROUT1V, 0x100, 0);
- snd_soc_update_bits(codec, WM8731_LINVOL, 0x100, 0);
- snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0);
+ regmap_update_bits(wm8731->regmap, WM8731_LOUT1V, 0x100, 0);
+ regmap_update_bits(wm8731->regmap, WM8731_ROUT1V, 0x100, 0);
+ regmap_update_bits(wm8731->regmap, WM8731_LINVOL, 0x100, 0);
+ regmap_update_bits(wm8731->regmap, WM8731_RINVOL, 0x100, 0);
/* Disable bypass path by default */
- snd_soc_update_bits(codec, WM8731_APANA, 0x8, 0);
+ regmap_update_bits(wm8731->regmap, WM8731_APANA, 0x8, 0);
- /* Regulators will have been enabled by bias management */
- regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-
- return 0;
+ regcache_mark_dirty(wm8731->regmap);
err_regulator_enable:
+ /* Regulators will be enabled by bias management */
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
return ret;
}
-/* power down chip */
-static int wm8731_remove(struct snd_soc_codec *codec)
-{
- struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
-
- regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
- .probe = wm8731_probe,
- .remove = wm8731_remove,
.set_bias_level = wm8731_set_bias_level,
.suspend_bias_off = true,
@@ -658,7 +650,6 @@ static const struct regmap_config wm8731_regmap = {
.max_register = WM8731_RESET,
.volatile_reg = wm8731_volatile,
- .writeable_reg = wm8731_writeable,
.cache_type = REGCACHE_RBTREE,
.reg_defaults = wm8731_reg_defaults,
@@ -690,6 +681,12 @@ static int wm8731_spi_probe(struct spi_device *spi)
mutex_init(&wm8731->lock);
+ spi_set_drvdata(spi, wm8731);
+
+ ret = wm8731_request_supplies(&spi->dev, wm8731);
+ if (ret != 0)
+ return ret;
+
wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap);
if (IS_ERR(wm8731->regmap)) {
ret = PTR_ERR(wm8731->regmap);
@@ -698,7 +695,9 @@ static int wm8731_spi_probe(struct spi_device *spi)
return ret;
}
- spi_set_drvdata(spi, wm8731);
+ ret = wm8731_hw_init(&spi->dev, wm8731);
+ if (ret != 0)
+ return ret;
ret = snd_soc_register_codec(&spi->dev,
&soc_codec_dev_wm8731, &wm8731_dai, 1);
@@ -754,6 +753,12 @@ static int wm8731_i2c_probe(struct i2c_client *i2c,
mutex_init(&wm8731->lock);
+ i2c_set_clientdata(i2c, wm8731);
+
+ ret = wm8731_request_supplies(&i2c->dev, wm8731);
+ if (ret != 0)
+ return ret;
+
wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap);
if (IS_ERR(wm8731->regmap)) {
ret = PTR_ERR(wm8731->regmap);
@@ -762,7 +767,9 @@ static int wm8731_i2c_probe(struct i2c_client *i2c,
return ret;
}
- i2c_set_clientdata(i2c, wm8731);
+ ret = wm8731_hw_init(&i2c->dev, wm8731);
+ if (ret != 0)
+ return ret;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8731, &wm8731_dai, 1);
@@ -789,7 +796,6 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
static struct i2c_driver wm8731_i2c_driver = {
.driver = {
.name = "wm8731",
- .owner = THIS_MODULE,
.of_match_table = wm8731_of_match,
},
.probe = wm8731_i2c_probe,
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index 6ad606f..e4a03d9 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -79,13 +79,12 @@ static int wm8737_reset(struct snd_soc_codec *codec)
return snd_soc_write(codec, WM8737_RESET, 0);
}
-static const unsigned int micboost_tlv[] = {
- TLV_DB_RANGE_HEAD(4),
+static const DECLARE_TLV_DB_RANGE(micboost_tlv,
0, 0, TLV_DB_SCALE_ITEM(1300, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(2800, 0, 0),
- 3, 3, TLV_DB_SCALE_ITEM(3300, 0, 0),
-};
+ 3, 3, TLV_DB_SCALE_ITEM(3300, 0, 0)
+);
static const DECLARE_TLV_DB_SCALE(pga_tlv, -9750, 50, 1);
static const DECLARE_TLV_DB_SCALE(adc_tlv, -600, 600, 0);
static const DECLARE_TLV_DB_SCALE(ng_tlv, -7800, 600, 0);
@@ -657,7 +656,6 @@ MODULE_DEVICE_TABLE(i2c, wm8737_i2c_id);
static struct i2c_driver wm8737_i2c_driver = {
.driver = {
.name = "wm8737",
- .owner = THIS_MODULE,
.of_match_table = wm8737_of_match,
},
.probe = wm8737_i2c_probe,
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index b346237..de42c03 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -61,25 +61,6 @@ static const struct reg_default wm8741_reg_defaults[] = {
{ 32, 0x0002 }, /* R32 - ADDITONAL_CONTROL_1 */
};
-static bool wm8741_readable(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case WM8741_DACLLSB_ATTENUATION:
- case WM8741_DACLMSB_ATTENUATION:
- case WM8741_DACRLSB_ATTENUATION:
- case WM8741_DACRMSB_ATTENUATION:
- case WM8741_VOLUME_CONTROL:
- case WM8741_FORMAT_CONTROL:
- case WM8741_FILTER_CONTROL:
- case WM8741_MODE_CONTROL_1:
- case WM8741_MODE_CONTROL_2:
- case WM8741_ADDITIONAL_CONTROL_1:
- return true;
- default:
- return false;
- }
-}
-
static int wm8741_reset(struct snd_soc_codec *codec)
{
return snd_soc_write(codec, WM8741_RESET, 0);
@@ -278,51 +259,38 @@ static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
switch (freq) {
case 0:
wm8741->sysclk_constraints = NULL;
- wm8741->sysclk = freq;
- return 0;
-
+ break;
case 11289600:
wm8741->sysclk_constraints = &constraints_11289;
- wm8741->sysclk = freq;
- return 0;
-
+ break;
case 12288000:
wm8741->sysclk_constraints = &constraints_12288;
- wm8741->sysclk = freq;
- return 0;
-
+ break;
case 16384000:
wm8741->sysclk_constraints = &constraints_16384;
- wm8741->sysclk = freq;
- return 0;
-
+ break;
case 16934400:
wm8741->sysclk_constraints = &constraints_16934;
- wm8741->sysclk = freq;
- return 0;
-
+ break;
case 18432000:
wm8741->sysclk_constraints = &constraints_18432;
- wm8741->sysclk = freq;
- return 0;
-
+ break;
case 22579200:
case 33868800:
wm8741->sysclk_constraints = &constraints_22579;
- wm8741->sysclk = freq;
- return 0;
-
+ break;
case 24576000:
wm8741->sysclk_constraints = &constraints_24576;
- wm8741->sysclk = freq;
- return 0;
-
+ break;
case 36864000:
wm8741->sysclk_constraints = &constraints_36864;
- wm8741->sysclk = freq;
- return 0;
+ break;
+ default:
+ return -EINVAL;
}
- return -EINVAL;
+
+ wm8741->sysclk = freq;
+ return 0;
}
static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
@@ -554,8 +522,6 @@ static const struct regmap_config wm8741_regmap = {
.reg_defaults = wm8741_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults),
.cache_type = REGCACHE_RBTREE,
-
- .readable_reg = wm8741_readable,
};
static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741)
@@ -633,7 +599,6 @@ MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
static struct i2c_driver wm8741_i2c_driver = {
.driver = {
.name = "wm8741",
- .owner = THIS_MODULE,
.of_match_table = wm8741_of_match,
},
.probe = wm8741_i2c_probe,
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 56d89b0..873933a 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -826,7 +826,6 @@ MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
static struct i2c_driver wm8750_i2c_driver = {
.driver = {
.name = "wm8750",
- .owner = THIS_MODULE,
.of_match_table = wm8750_of_match,
},
.probe = wm8750_i2c_probe,
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index feb2997a..a801c6d 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -138,11 +138,6 @@ static bool wm8753_volatile(struct device *dev, unsigned int reg)
return reg == WM8753_RESET;
}
-static bool wm8753_writeable(struct device *dev, unsigned int reg)
-{
- return reg <= WM8753_ADCTL2;
-}
-
/* codec private data */
struct wm8753_priv {
struct regmap *regmap;
@@ -276,12 +271,11 @@ static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0);
static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0);
static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
-static const unsigned int out_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(out_tlv,
/* 0000000 - 0101111 = "Analogue mute" */
0, 48, TLV_DB_SCALE_ITEM(-25500, 0, 0),
- 48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0),
-};
+ 48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0)
+);
static const DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0);
static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0);
static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
@@ -1510,7 +1504,6 @@ static const struct regmap_config wm8753_regmap = {
.val_bits = 9,
.max_register = WM8753_ADCTL2,
- .writeable_reg = wm8753_writeable,
.volatile_reg = wm8753_volatile,
.cache_type = REGCACHE_RBTREE,
@@ -1609,7 +1602,6 @@ MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
static struct i2c_driver wm8753_i2c_driver = {
.driver = {
.name = "wm8753",
- .owner = THIS_MODULE,
.of_match_table = wm8753_of_match,
},
.probe = wm8753_i2c_probe,
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index ece9b44..183c9a4 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -265,7 +265,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
}
/* Set word length */
- switch (snd_pcm_format_width(params_format(params))) {
+ switch (params_width(params)) {
case 16:
iface = 0;
break;
@@ -280,7 +280,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
break;
default:
dev_err(codec->dev, "Unsupported sample size: %i\n",
- snd_pcm_format_width(params_format(params)));
+ params_width(params));
return -EINVAL;
}
@@ -536,7 +536,6 @@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
static struct i2c_driver wm8776_i2c_driver = {
.driver = {
.name = "wm8776",
- .owner = THIS_MODULE,
.of_match_table = wm8776_of_match,
},
.probe = wm8776_i2c_probe,
diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c
index 6596f5f..f27464c 100644
--- a/sound/soc/codecs/wm8804-i2c.c
+++ b/sound/soc/codecs/wm8804-i2c.c
@@ -49,7 +49,6 @@ MODULE_DEVICE_TABLE(of, wm8804_of_match);
static struct i2c_driver wm8804_i2c_driver = {
.driver = {
.name = "wm8804",
- .owner = THIS_MODULE,
.pm = &wm8804_pm,
.of_match_table = wm8804_of_match,
},
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index c195c2e..8d91470 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -98,7 +98,7 @@ WM8804_REGULATOR_EVENT(0)
WM8804_REGULATOR_EVENT(1)
static const char *txsrc_text[] = { "S/PDIF RX", "AIF" };
-static const SOC_ENUM_SINGLE_DECL(txsrc, WM8804_SPDTX4, 6, txsrc_text);
+static SOC_ENUM_SINGLE_DECL(txsrc, WM8804_SPDTX4, 6, txsrc_text);
static const struct snd_kcontrol_new wm8804_tx_source_mux[] = {
SOC_DAPM_ENUM_EXT("Input Source", txsrc,
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index f3759ec..98900aa 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -1312,7 +1312,6 @@ MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id);
static struct i2c_driver wm8900_i2c_driver = {
.driver = {
.name = "wm8900",
- .owner = THIS_MODULE,
},
.probe = wm8900_i2c_probe,
.remove = wm8900_i2c_remove,
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index b5322c1..b011253 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -2193,7 +2193,6 @@ MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id);
static struct i2c_driver wm8903_i2c_driver = {
.driver = {
.name = "wm8903",
- .owner = THIS_MODULE,
.of_match_table = wm8903_of_match,
},
.probe = wm8903_i2c_probe,
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 265a4a5..b783743 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -1837,7 +1837,9 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
- clk_prepare_enable(wm8904->mclk);
+ ret = clk_prepare_enable(wm8904->mclk);
+ if (ret)
+ return ret;
break;
case SND_SOC_BIAS_PREPARE:
@@ -2292,7 +2294,6 @@ MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id);
static struct i2c_driver wm8904_i2c_driver = {
.driver = {
.name = "wm8904",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(wm8904_of_match),
},
.probe = wm8904_i2c_probe,
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 98ef0ba..f6f9395 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -787,7 +787,6 @@ MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id);
static struct i2c_driver wm8940_i2c_driver = {
.driver = {
.name = "wm8940",
- .owner = THIS_MODULE,
},
.probe = wm8940_i2c_probe,
.remove = wm8940_i2c_remove,
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 2d591c2..12e4435 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -1009,7 +1009,6 @@ MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id);
static struct i2c_driver wm8955_i2c_driver = {
.driver = {
.name = "wm8955",
- .owner = THIS_MODULE,
},
.probe = wm8955_i2c_probe,
.remove = wm8955_i2c_remove,
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 94c5c46..e3b7d0c 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -48,6 +48,9 @@
#define WM8960_DISOP 0x40
#define WM8960_DRES_MASK 0x30
+static bool is_pll_freq_available(unsigned int source, unsigned int target);
+static int wm8960_set_pll(struct snd_soc_codec *codec,
+ unsigned int freq_in, unsigned int freq_out);
/*
* wm8960 register cache
* We can't read the WM8960 register space when we are
@@ -126,9 +129,12 @@ struct wm8960_priv {
struct snd_soc_dapm_widget *rout1;
struct snd_soc_dapm_widget *out3;
bool deemph;
- int playback_fs;
+ int lrclk;
int bclk;
int sysclk;
+ int clk_id;
+ int freq_in;
+ bool is_stream_in_use[2];
struct wm8960_data pdata;
};
@@ -164,8 +170,8 @@ static int wm8960_set_deemph(struct snd_soc_codec *codec)
if (wm8960->deemph) {
best = 1;
for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
- if (abs(deemph_settings[i] - wm8960->playback_fs) <
- abs(deemph_settings[best] - wm8960->playback_fs))
+ if (abs(deemph_settings[i] - wm8960->lrclk) <
+ abs(deemph_settings[best] - wm8960->lrclk))
best = i;
}
@@ -565,6 +571,9 @@ static struct {
{ 8000, 5 },
};
+/* -1 for reserved value */
+static const int sysclk_divs[] = { 1, -1, 2, -1 };
+
/* Multiply 256 for internal 256 div */
static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 };
@@ -574,61 +583,110 @@ static const int bclk_divs[] = {
120, 160, 220, 240, 320, 320, 320
};
-static void wm8960_configure_clocking(struct snd_soc_codec *codec,
- bool tx, int lrclk)
+static int wm8960_configure_clocking(struct snd_soc_codec *codec)
{
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+ int sysclk, bclk, lrclk, freq_out, freq_in;
u16 iface1 = snd_soc_read(codec, WM8960_IFACE1);
- u16 iface2 = snd_soc_read(codec, WM8960_IFACE2);
- u32 sysclk;
- int i, j;
+ int i, j, k;
if (!(iface1 & (1<<6))) {
dev_dbg(codec->dev,
"Codec is slave mode, no need to configure clock\n");
- return;
+ return 0;
+ }
+
+ if (wm8960->clk_id != WM8960_SYSCLK_MCLK && !wm8960->freq_in) {
+ dev_err(codec->dev, "No MCLK configured\n");
+ return -EINVAL;
}
- if (!wm8960->sysclk) {
- dev_dbg(codec->dev, "No SYSCLK configured\n");
- return;
+ freq_in = wm8960->freq_in;
+ bclk = wm8960->bclk;
+ lrclk = wm8960->lrclk;
+ /*
+ * If it's sysclk auto mode, check if the MCLK can provide sysclk or
+ * not. If MCLK can provide sysclk, using MCLK to provide sysclk
+ * directly. Otherwise, auto select a available pll out frequency
+ * and set PLL.
+ */
+ if (wm8960->clk_id == WM8960_SYSCLK_AUTO) {
+ /* disable the PLL and using MCLK to provide sysclk */
+ wm8960_set_pll(codec, 0, 0);
+ freq_out = freq_in;
+ } else if (wm8960->sysclk) {
+ freq_out = wm8960->sysclk;
+ } else {
+ dev_err(codec->dev, "No SYSCLK configured\n");
+ return -EINVAL;
}
- if (!wm8960->bclk || !lrclk) {
- dev_dbg(codec->dev, "No audio clocks configured\n");
- return;
+ /* check if the sysclk frequency is available. */
+ for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
+ if (sysclk_divs[i] == -1)
+ continue;
+ sysclk = freq_out / sysclk_divs[i];
+ for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
+ if (sysclk == dac_divs[j] * lrclk) {
+ for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k)
+ if (sysclk == bclk * bclk_divs[k] / 10)
+ break;
+ if (k != ARRAY_SIZE(bclk_divs))
+ break;
+ }
+ }
+ if (j != ARRAY_SIZE(dac_divs))
+ break;
}
- for (i = 0; i < ARRAY_SIZE(dac_divs); ++i) {
- if (wm8960->sysclk == lrclk * dac_divs[i]) {
- for (j = 0; j < ARRAY_SIZE(bclk_divs); ++j) {
- sysclk = wm8960->bclk * bclk_divs[j] / 10;
- if (wm8960->sysclk == sysclk)
+ if (i != ARRAY_SIZE(sysclk_divs)) {
+ goto configure_clock;
+ } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
+ dev_err(codec->dev, "failed to configure clock\n");
+ return -EINVAL;
+ }
+ /* get a available pll out frequency and set pll */
+ for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
+ if (sysclk_divs[i] == -1)
+ continue;
+ for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
+ sysclk = lrclk * dac_divs[j];
+ freq_out = sysclk * sysclk_divs[i];
+
+ for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) {
+ if (sysclk == bclk * bclk_divs[k] / 10 &&
+ is_pll_freq_available(freq_in, freq_out)) {
+ wm8960_set_pll(codec,
+ freq_in, freq_out);
break;
+ } else {
+ continue;
+ }
}
- if(j != ARRAY_SIZE(bclk_divs))
+ if (k != ARRAY_SIZE(bclk_divs))
break;
}
+ if (j != ARRAY_SIZE(dac_divs))
+ break;
}
- if (i == ARRAY_SIZE(dac_divs)) {
- dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk);
- return;
+ if (i == ARRAY_SIZE(sysclk_divs)) {
+ dev_err(codec->dev, "failed to configure clock\n");
+ return -EINVAL;
}
- /*
- * configure frame clock. If ADCLRC configure as GPIO pin, DACLRC
- * pin is used as a frame clock for ADCs and DACs.
- */
- if (iface2 & (1<<6))
- snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3);
- else if (tx)
- snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3);
- else if (!tx)
- snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, i << 6);
+configure_clock:
+ /* configure sysclk clock */
+ snd_soc_update_bits(codec, WM8960_CLOCK1, 3 << 1, i << 1);
+
+ /* configure frame clock */
+ snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, j << 3);
+ snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, j << 6);
/* configure bit clock */
- snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, j);
+ snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, k);
+
+ return 0;
}
static int wm8960_hw_params(struct snd_pcm_substream *substream,
@@ -667,9 +725,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ wm8960->lrclk = params_rate(params);
/* Update filters for the new rate */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- wm8960->playback_fs = params_rate(params);
+ if (tx) {
wm8960_set_deemph(codec);
} else {
for (i = 0; i < ARRAY_SIZE(alc_rates); i++)
@@ -682,7 +740,23 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
/* set iface */
snd_soc_write(codec, WM8960_IFACE1, iface);
- wm8960_configure_clocking(codec, tx, params_rate(params));
+ wm8960->is_stream_in_use[tx] = true;
+
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON &&
+ !wm8960->is_stream_in_use[!tx])
+ return wm8960_configure_clocking(codec);
+
+ return 0;
+}
+
+static int wm8960_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
+ wm8960->is_stream_in_use[tx] = false;
return 0;
}
@@ -702,6 +776,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+ u16 pm2 = snd_soc_read(codec, WM8960_POWER2);
int ret;
switch (level) {
@@ -721,11 +796,22 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
}
}
+ ret = wm8960_configure_clocking(codec);
+ if (ret)
+ return ret;
+
/* Set VMID to 2x50k */
snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
break;
case SND_SOC_BIAS_ON:
+ /*
+ * If it's sysclk auto mode, and the pll is enabled,
+ * disable the pll
+ */
+ if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1))
+ wm8960_set_pll(codec, 0, 0);
+
if (!IS_ERR(wm8960->mclk))
clk_disable_unprepare(wm8960->mclk);
break;
@@ -780,6 +866,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+ u16 pm2 = snd_soc_read(codec, WM8960_POWER2);
int reg, ret;
switch (level) {
@@ -831,9 +918,21 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
return ret;
}
}
+
+ ret = wm8960_configure_clocking(codec);
+ if (ret)
+ return ret;
+
break;
case SND_SOC_BIAS_ON:
+ /*
+ * If it's sysclk auto mode, and the pll is enabled,
+ * disable the pll
+ */
+ if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1))
+ wm8960_set_pll(codec, 0, 0);
+
if (!IS_ERR(wm8960->mclk))
clk_disable_unprepare(wm8960->mclk);
@@ -892,6 +991,28 @@ struct _pll_div {
u32 k:24;
};
+static bool is_pll_freq_available(unsigned int source, unsigned int target)
+{
+ unsigned int Ndiv;
+
+ if (source == 0 || target == 0)
+ return false;
+
+ /* Scale up target to PLL operating frequency */
+ target *= 4;
+ Ndiv = target / source;
+
+ if (Ndiv < 6) {
+ source >>= 1;
+ Ndiv = target / source;
+ }
+
+ if ((Ndiv < 6) || (Ndiv > 12))
+ return false;
+
+ return true;
+}
+
/* The size in bits of the pll divide multiplied by 10
* to allow rounding later */
#define FIXED_PLL_SIZE ((1 << 24) * 10)
@@ -943,10 +1064,9 @@ static int pll_factors(unsigned int source, unsigned int target,
return 0;
}
-static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
- int source, unsigned int freq_in, unsigned int freq_out)
+static int wm8960_set_pll(struct snd_soc_codec *codec,
+ unsigned int freq_in, unsigned int freq_out)
{
- struct snd_soc_codec *codec = codec_dai->codec;
u16 reg;
static struct _pll_div pll_div;
int ret;
@@ -986,6 +1106,20 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
return 0;
}
+static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+ wm8960->freq_in = freq_in;
+
+ if (pll_id == WM8960_SYSCLK_AUTO)
+ return 0;
+
+ return wm8960_set_pll(codec, freq_in, freq_out);
+}
+
static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
int div_id, int div)
{
@@ -1043,11 +1177,14 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
snd_soc_update_bits(codec, WM8960_CLOCK1,
0x1, WM8960_SYSCLK_PLL);
break;
+ case WM8960_SYSCLK_AUTO:
+ break;
default:
return -EINVAL;
}
wm8960->sysclk = freq;
+ wm8960->clk_id = clk_id;
return 0;
}
@@ -1060,6 +1197,7 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
static const struct snd_soc_dai_ops wm8960_dai_ops = {
.hw_params = wm8960_hw_params,
+ .hw_free = wm8960_hw_free,
.digital_mute = wm8960_mute,
.set_fmt = wm8960_set_dai_fmt,
.set_clkdiv = wm8960_set_dai_clkdiv,
@@ -1216,7 +1354,6 @@ MODULE_DEVICE_TABLE(of, wm8960_of_match);
static struct i2c_driver wm8960_i2c_driver = {
.driver = {
.name = "wm8960",
- .owner = THIS_MODULE,
.of_match_table = wm8960_of_match,
},
.probe = wm8960_i2c_probe,
diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h
index 2d8163d..ab3220d 100644
--- a/sound/soc/codecs/wm8960.h
+++ b/sound/soc/codecs/wm8960.h
@@ -82,6 +82,7 @@
#define WM8960_SYSCLK_MCLK (0 << 0)
#define WM8960_SYSCLK_PLL (1 << 0)
+#define WM8960_SYSCLK_AUTO (2 << 0)
#define WM8960_DAC_DIV_1 (0 << 3)
#define WM8960_DAC_DIV_1_5 (1 << 3)
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index a057662..e30446a 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -331,13 +331,12 @@ static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
static const DECLARE_TLV_DB_SCALE(hp_sec_tlv, -700, 100, 0);
static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1);
static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0);
-static unsigned int boost_tlv[] = {
- TLV_DB_RANGE_HEAD(4),
+static const DECLARE_TLV_DB_RANGE(boost_tlv,
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(13, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(20, 0, 0),
- 3, 3, TLV_DB_SCALE_ITEM(29, 0, 0),
-};
+ 3, 3, TLV_DB_SCALE_ITEM(29, 0, 0)
+);
static const DECLARE_TLV_DB_SCALE(pga_tlv, -2325, 75, 0);
static const struct snd_kcontrol_new wm8961_snd_controls[] = {
@@ -982,7 +981,6 @@ MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id);
static struct i2c_driver wm8961_i2c_driver = {
.driver = {
.name = "wm8961",
- .owner = THIS_MODULE,
},
.probe = wm8961_i2c_probe,
.remove = wm8961_i2c_remove,
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index c5748fd..b4eb975 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -113,7 +113,7 @@ WM8962_REGULATOR_EVENT(5)
WM8962_REGULATOR_EVENT(6)
WM8962_REGULATOR_EVENT(7)
-static struct reg_default wm8962_reg[] = {
+static const struct reg_default wm8962_reg[] = {
{ 0, 0x009F }, /* R0 - Left Input volume */
{ 1, 0x049F }, /* R1 - Right Input volume */
{ 2, 0x0000 }, /* R2 - HPOUTL volume */
@@ -1456,14 +1456,13 @@ static int wm8962_reset(struct wm8962_priv *wm8962)
static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0);
static const DECLARE_TLV_DB_SCALE(mixin_tlv, -1500, 300, 0);
-static const unsigned int mixinpga_tlv[] = {
- TLV_DB_RANGE_HEAD(5),
+static const DECLARE_TLV_DB_RANGE(mixinpga_tlv,
0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
2, 2, TLV_DB_SCALE_ITEM(1300, 1300, 0),
3, 4, TLV_DB_SCALE_ITEM(1800, 200, 0),
5, 5, TLV_DB_SCALE_ITEM(2400, 0, 0),
- 6, 7, TLV_DB_SCALE_ITEM(2700, 300, 0),
-};
+ 6, 7, TLV_DB_SCALE_ITEM(2700, 300, 0)
+);
static const DECLARE_TLV_DB_SCALE(beep_tlv, -9600, 600, 1);
static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
@@ -1471,11 +1470,10 @@ static const DECLARE_TLV_DB_SCALE(inmix_tlv, -600, 600, 0);
static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
static const DECLARE_TLV_DB_SCALE(hp_tlv, -700, 100, 0);
-static const unsigned int classd_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(classd_tlv,
0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
- 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
-};
+ 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0)
+);
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static int wm8962_dsp2_write_config(struct snd_soc_codec *codec)
@@ -3495,7 +3493,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
};
/* Improve power consumption for IN4 DC measurement mode */
-static const struct reg_default wm8962_dc_measure[] = {
+static const struct reg_sequence wm8962_dc_measure[] = {
{ 0xfd, 0x1 },
{ 0xcc, 0x40 },
{ 0xfd, 0 },
@@ -3859,7 +3857,7 @@ static int wm8962_runtime_suspend(struct device *dev)
}
#endif
-static struct dev_pm_ops wm8962_pm = {
+static const struct dev_pm_ops wm8962_pm = {
SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL)
};
@@ -3878,7 +3876,6 @@ MODULE_DEVICE_TABLE(of, wm8962_of_match);
static struct i2c_driver wm8962_i2c_driver = {
.driver = {
.name = "wm8962",
- .owner = THIS_MODULE,
.of_match_table = wm8962_of_match,
.pm = &wm8962_pm,
},
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index b51184c..2cdde32 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -710,7 +710,6 @@ MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
static struct i2c_driver wm8971_i2c_driver = {
.driver = {
.name = "wm8971",
- .owner = THIS_MODULE,
},
.probe = wm8971_i2c_probe,
.remove = wm8971_i2c_remove,
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 33b16a7..0a60677 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -634,7 +634,6 @@ MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
static struct i2c_driver wm8974_i2c_driver = {
.driver = {
.name = "wm8974",
- .owner = THIS_MODULE,
},
.probe = wm8974_i2c_probe,
.remove = wm8974_i2c_remove,
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index cfc8cdf..d36d600 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -1072,7 +1072,6 @@ MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id);
static struct i2c_driver wm8978_i2c_driver = {
.driver = {
.name = "wm8978",
- .owner = THIS_MODULE,
},
.probe = wm8978_i2c_probe,
.remove = wm8978_i2c_remove,
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index 2fdd2c6..f3193fb 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -84,66 +84,6 @@ static const struct reg_default wm8983_defaults[] = {
{ 0x3D, 0x0000 }, /* R61 - BIAS CTRL */
};
-static const struct wm8983_reg_access {
- u16 read; /* Mask of readable bits */
- u16 write; /* Mask of writable bits */
-} wm8983_access_masks[WM8983_MAX_REGISTER + 1] = {
- [0x00] = { 0x0000, 0x01FF }, /* R0 - Software Reset */
- [0x01] = { 0x0000, 0x01FF }, /* R1 - Power management 1 */
- [0x02] = { 0x0000, 0x01FF }, /* R2 - Power management 2 */
- [0x03] = { 0x0000, 0x01EF }, /* R3 - Power management 3 */
- [0x04] = { 0x0000, 0x01FF }, /* R4 - Audio Interface */
- [0x05] = { 0x0000, 0x003F }, /* R5 - Companding control */
- [0x06] = { 0x0000, 0x01FD }, /* R6 - Clock Gen control */
- [0x07] = { 0x0000, 0x000F }, /* R7 - Additional control */
- [0x08] = { 0x0000, 0x003F }, /* R8 - GPIO Control */
- [0x09] = { 0x0000, 0x0070 }, /* R9 - Jack Detect Control 1 */
- [0x0A] = { 0x0000, 0x004F }, /* R10 - DAC Control */
- [0x0B] = { 0x0000, 0x01FF }, /* R11 - Left DAC digital Vol */
- [0x0C] = { 0x0000, 0x01FF }, /* R12 - Right DAC digital vol */
- [0x0D] = { 0x0000, 0x00FF }, /* R13 - Jack Detect Control 2 */
- [0x0E] = { 0x0000, 0x01FB }, /* R14 - ADC Control */
- [0x0F] = { 0x0000, 0x01FF }, /* R15 - Left ADC Digital Vol */
- [0x10] = { 0x0000, 0x01FF }, /* R16 - Right ADC Digital Vol */
- [0x12] = { 0x0000, 0x017F }, /* R18 - EQ1 - low shelf */
- [0x13] = { 0x0000, 0x017F }, /* R19 - EQ2 - peak 1 */
- [0x14] = { 0x0000, 0x017F }, /* R20 - EQ3 - peak 2 */
- [0x15] = { 0x0000, 0x017F }, /* R21 - EQ4 - peak 3 */
- [0x16] = { 0x0000, 0x007F }, /* R22 - EQ5 - high shelf */
- [0x18] = { 0x0000, 0x01FF }, /* R24 - DAC Limiter 1 */
- [0x19] = { 0x0000, 0x007F }, /* R25 - DAC Limiter 2 */
- [0x1B] = { 0x0000, 0x01FF }, /* R27 - Notch Filter 1 */
- [0x1C] = { 0x0000, 0x017F }, /* R28 - Notch Filter 2 */
- [0x1D] = { 0x0000, 0x017F }, /* R29 - Notch Filter 3 */
- [0x1E] = { 0x0000, 0x017F }, /* R30 - Notch Filter 4 */
- [0x20] = { 0x0000, 0x01BF }, /* R32 - ALC control 1 */
- [0x21] = { 0x0000, 0x00FF }, /* R33 - ALC control 2 */
- [0x22] = { 0x0000, 0x01FF }, /* R34 - ALC control 3 */
- [0x23] = { 0x0000, 0x000F }, /* R35 - Noise Gate */
- [0x24] = { 0x0000, 0x001F }, /* R36 - PLL N */
- [0x25] = { 0x0000, 0x003F }, /* R37 - PLL K 1 */
- [0x26] = { 0x0000, 0x01FF }, /* R38 - PLL K 2 */
- [0x27] = { 0x0000, 0x01FF }, /* R39 - PLL K 3 */
- [0x29] = { 0x0000, 0x000F }, /* R41 - 3D control */
- [0x2A] = { 0x0000, 0x01E7 }, /* R42 - OUT4 to ADC */
- [0x2B] = { 0x0000, 0x01BF }, /* R43 - Beep control */
- [0x2C] = { 0x0000, 0x0177 }, /* R44 - Input ctrl */
- [0x2D] = { 0x0000, 0x01FF }, /* R45 - Left INP PGA gain ctrl */
- [0x2E] = { 0x0000, 0x01FF }, /* R46 - Right INP PGA gain ctrl */
- [0x2F] = { 0x0000, 0x0177 }, /* R47 - Left ADC BOOST ctrl */
- [0x30] = { 0x0000, 0x0177 }, /* R48 - Right ADC BOOST ctrl */
- [0x31] = { 0x0000, 0x007F }, /* R49 - Output ctrl */
- [0x32] = { 0x0000, 0x01FF }, /* R50 - Left mixer ctrl */
- [0x33] = { 0x0000, 0x01FF }, /* R51 - Right mixer ctrl */
- [0x34] = { 0x0000, 0x01FF }, /* R52 - LOUT1 (HP) volume ctrl */
- [0x35] = { 0x0000, 0x01FF }, /* R53 - ROUT1 (HP) volume ctrl */
- [0x36] = { 0x0000, 0x01FF }, /* R54 - LOUT2 (SPK) volume ctrl */
- [0x37] = { 0x0000, 0x01FF }, /* R55 - ROUT2 (SPK) volume ctrl */
- [0x38] = { 0x0000, 0x004F }, /* R56 - OUT3 mixer ctrl */
- [0x39] = { 0x0000, 0x00FF }, /* R57 - OUT4 (MONO) mix ctrl */
- [0x3D] = { 0x0000, 0x0100 } /* R61 - BIAS CTRL */
-};
-
/* vol/gain update regs */
static const int vol_update_regs[] = {
WM8983_LEFT_DAC_DIGITAL_VOL,
@@ -605,12 +545,19 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static bool wm8983_readable(struct device *dev, unsigned int reg)
+static bool wm8983_writeable(struct device *dev, unsigned int reg)
{
- if (reg > WM8983_MAX_REGISTER)
- return 0;
-
- return wm8983_access_masks[reg].read != 0;
+ switch (reg) {
+ case WM8983_SOFTWARE_RESET ... WM8983_RIGHT_ADC_DIGITAL_VOL:
+ case WM8983_EQ1_LOW_SHELF ... WM8983_DAC_LIMITER_2:
+ case WM8983_NOTCH_FILTER_1 ... WM8983_NOTCH_FILTER_4:
+ case WM8983_ALC_CONTROL_1 ... WM8983_PLL_K_3:
+ case WM8983_3D_CONTROL ... WM8983_OUT4_MONO_MIX_CTRL:
+ case WM8983_BIAS_CTRL:
+ return true;
+ default:
+ return false;
+ }
}
static int wm8983_dac_mute(struct snd_soc_dai *dai, int mute)
@@ -1048,8 +995,9 @@ static const struct regmap_config wm8983_regmap = {
.reg_defaults = wm8983_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8983_defaults),
.cache_type = REGCACHE_RBTREE,
+ .max_register = WM8983_MAX_REGISTER,
- .readable_reg = wm8983_readable,
+ .writeable_reg = wm8983_writeable,
};
#if defined(CONFIG_SPI_MASTER)
@@ -1133,7 +1081,6 @@ MODULE_DEVICE_TABLE(i2c, wm8983_i2c_id);
static struct i2c_driver wm8983_i2c_driver = {
.driver = {
.name = "wm8983",
- .owner = THIS_MODULE,
},
.probe = wm8983_i2c_probe,
.remove = wm8983_i2c_remove,
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 8a85f50..9c3c151 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -1144,7 +1144,6 @@ MODULE_DEVICE_TABLE(i2c, wm8985_i2c_id);
static struct i2c_driver wm8985_i2c_driver = {
.driver = {
.name = "wm8985",
- .owner = THIS_MODULE,
},
.probe = wm8985_i2c_probe,
.remove = wm8985_i2c_remove,
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index f13a995..c88ce99 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -919,7 +919,6 @@ MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);
static struct i2c_driver wm8988_i2c_driver = {
.driver = {
.name = "wm8988",
- .owner = THIS_MODULE,
},
.probe = wm8988_i2c_probe,
.remove = wm8988_i2c_remove,
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 1993fd2..23ecd30 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -418,10 +418,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
}
/* INMIX dB values */
-static const unsigned int in_mix_tlv[] = {
- TLV_DB_RANGE_HEAD(1),
- 0, 7, TLV_DB_SCALE_ITEM(-1200, 600, 0),
-};
+static const DECLARE_TLV_DB_SCALE(in_mix_tlv, -1200, 600, 0);
/* Left In PGA Connections */
static const struct snd_kcontrol_new wm8990_dapm_lin12_pga_controls[] = {
@@ -1356,7 +1353,6 @@ MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id);
static struct i2c_driver wm8990_i2c_driver = {
.driver = {
.name = "wm8990",
- .owner = THIS_MODULE,
},
.probe = wm8990_i2c_probe,
.remove = wm8990_i2c_remove,
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 44a6777..c9ee0ac 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -111,45 +111,14 @@ static bool wm8991_volatile(struct device *dev, unsigned int reg)
}
}
-static const unsigned int rec_mix_tlv[] = {
- TLV_DB_RANGE_HEAD(1),
- 0, 7, TLV_DB_LINEAR_ITEM(-1500, 600),
-};
-
-static const unsigned int in_pga_tlv[] = {
- TLV_DB_RANGE_HEAD(1),
- 0, 0x1F, TLV_DB_LINEAR_ITEM(-1650, 3000),
-};
-
-static const unsigned int out_mix_tlv[] = {
- TLV_DB_RANGE_HEAD(1),
- 0, 7, TLV_DB_LINEAR_ITEM(0, -2100),
-};
-
-static const unsigned int out_pga_tlv[] = {
- TLV_DB_RANGE_HEAD(1),
- 0, 127, TLV_DB_LINEAR_ITEM(-7300, 600),
-};
-
-static const unsigned int out_omix_tlv[] = {
- TLV_DB_RANGE_HEAD(1),
- 0, 7, TLV_DB_LINEAR_ITEM(-600, 0),
-};
-
-static const unsigned int out_dac_tlv[] = {
- TLV_DB_RANGE_HEAD(1),
- 0, 255, TLV_DB_LINEAR_ITEM(-7163, 0),
-};
-
-static const unsigned int in_adc_tlv[] = {
- TLV_DB_RANGE_HEAD(1),
- 0, 255, TLV_DB_LINEAR_ITEM(-7163, 1763),
-};
-
-static const unsigned int out_sidetone_tlv[] = {
- TLV_DB_RANGE_HEAD(1),
- 0, 31, TLV_DB_LINEAR_ITEM(-3600, 0),
-};
+static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
+static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000);
+static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100);
+static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600);
+static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0);
+static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0);
+static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763);
+static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0);
static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -429,10 +398,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
}
/* INMIX dB values */
-static const unsigned int in_mix_tlv[] = {
- TLV_DB_RANGE_HEAD(1),
- 0, 7, TLV_DB_LINEAR_ITEM(-1200, 600),
-};
+static const DECLARE_TLV_DB_LINEAR(in_mix_tlv, -1200, 600);
/* Left In PGA Connections */
static const struct snd_kcontrol_new wm8991_dapm_lin12_pga_controls[] = {
@@ -1363,7 +1329,6 @@ MODULE_DEVICE_TABLE(i2c, wm8991_i2c_id);
static struct i2c_driver wm8991_i2c_driver = {
.driver = {
.name = "wm8991",
- .owner = THIS_MODULE,
},
.probe = wm8991_i2c_probe,
.remove = wm8991_i2c_remove,
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 8a8db86..8668c4c 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -41,7 +41,7 @@ static const char *wm8993_supply_names[WM8993_NUM_SUPPLIES] = {
"SPKVDD",
};
-static struct reg_default wm8993_reg_defaults[] = {
+static const struct reg_default wm8993_reg_defaults[] = {
{ 1, 0x0000 }, /* R1 - Power Management (1) */
{ 2, 0x6000 }, /* R2 - Power Management (2) */
{ 3, 0x0000 }, /* R3 - Power Management (3) */
@@ -628,11 +628,10 @@ static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0);
static const DECLARE_TLV_DB_SCALE(drc_comp_threash, -4500, 75, 0);
static const DECLARE_TLV_DB_SCALE(drc_comp_amp, -2250, 75, 0);
static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0);
-static const unsigned int drc_max_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(drc_max_tlv,
0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0),
- 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0),
-};
+ 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0)
+);
static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0);
static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -1800, 300, 0);
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
@@ -1595,7 +1594,7 @@ static int wm8993_resume(struct snd_soc_codec *codec)
#endif
/* Tune DC servo configuration */
-static struct reg_default wm8993_regmap_patch[] = {
+static const struct reg_sequence wm8993_regmap_patch[] = {
{ 0x44, 3 },
{ 0x56, 3 },
{ 0x44, 0 },
@@ -1742,7 +1741,6 @@ MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id);
static struct i2c_driver wm8993_i2c_driver = {
.driver = {
.name = "wm8993",
- .owner = THIS_MODULE,
},
.probe = wm8993_i2c_probe,
.remove = wm8993_i2c_remove,
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 962e1d3..2ccbb32 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -1942,14 +1942,16 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "AIF2ADCDAT", NULL, "AIF2ADC Mux" },
/* AIF3 output */
- { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC1L" },
- { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC1R" },
- { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC2L" },
- { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC2R" },
- { "AIF3ADCDAT", "AIF2ADCDAT", "AIF2ADCL" },
- { "AIF3ADCDAT", "AIF2ADCDAT", "AIF2ADCR" },
- { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACL" },
- { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACR" },
+ { "AIF3ADC Mux", "AIF1ADCDAT", "AIF1ADC1L" },
+ { "AIF3ADC Mux", "AIF1ADCDAT", "AIF1ADC1R" },
+ { "AIF3ADC Mux", "AIF1ADCDAT", "AIF1ADC2L" },
+ { "AIF3ADC Mux", "AIF1ADCDAT", "AIF1ADC2R" },
+ { "AIF3ADC Mux", "AIF2ADCDAT", "AIF2ADCL" },
+ { "AIF3ADC Mux", "AIF2ADCDAT", "AIF2ADCR" },
+ { "AIF3ADC Mux", "AIF2DACDAT", "AIF2DACL" },
+ { "AIF3ADC Mux", "AIF2DACDAT", "AIF2DACR" },
+
+ { "AIF3ADCDAT", NULL, "AIF3ADC Mux" },
/* Loopback */
{ "AIF1 Loopback", "ADCDAT", "AIF1ADCDAT" },
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 505b65f..eda52a9 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -2298,7 +2298,6 @@ MODULE_DEVICE_TABLE(i2c, wm8995_i2c_id);
static struct i2c_driver wm8995_i2c_driver = {
.driver = {
.name = "wm8995",
- .owner = THIS_MODULE,
},
.probe = wm8995_i2c_probe,
.remove = wm8995_i2c_remove,
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 3dd063f..f7ccd9f 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -117,7 +117,7 @@ WM8996_REGULATOR_EVENT(0)
WM8996_REGULATOR_EVENT(1)
WM8996_REGULATOR_EVENT(2)
-static struct reg_default wm8996_reg[] = {
+static const struct reg_default wm8996_reg[] = {
{ WM8996_POWER_MANAGEMENT_1, 0x0 },
{ WM8996_POWER_MANAGEMENT_2, 0x0 },
{ WM8996_POWER_MANAGEMENT_3, 0x0 },
@@ -1780,7 +1780,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
wm8996->rx_rate[dai->id] = params_rate(params);
/* Needs looking at for TDM */
- bits = snd_pcm_format_width(params_format(params));
+ bits = params_width(params);
if (bits < 0)
return bits;
aifdata |= (bits << WM8996_AIF1TX_WL_SHIFT) | bits;
@@ -2647,12 +2647,10 @@ static int wm8996_probe(struct snd_soc_codec *codec)
if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
ret = request_threaded_irq(i2c->irq, NULL,
wm8996_edge_irq,
- irq_flags | IRQF_ONESHOT,
- "wm8996", codec);
+ irq_flags, "wm8996", codec);
else
ret = request_threaded_irq(i2c->irq, NULL, wm8996_irq,
- irq_flags | IRQF_ONESHOT,
- "wm8996", codec);
+ irq_flags, "wm8996", codec);
if (ret == 0) {
/* Unmask the interrupt */
@@ -3100,7 +3098,6 @@ MODULE_DEVICE_TABLE(i2c, wm8996_i2c_id);
static struct i2c_driver wm8996_i2c_driver = {
.driver = {
.name = "wm8996",
- .owner = THIS_MODULE,
},
.probe = wm8996_i2c_probe,
.remove = wm8996_i2c_remove,
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index 4134dc7..b4dba3a 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -174,8 +174,7 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
-SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19),
-SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2),
SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
@@ -187,8 +186,7 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
24, 0, eq_tlv),
-SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19),
-SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2),
SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
@@ -200,8 +198,7 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
24, 0, eq_tlv),
-SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19),
-SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2),
SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
@@ -213,8 +210,7 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
24, 0, eq_tlv),
-SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19),
-SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2),
SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
@@ -242,10 +238,10 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
-SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1),
-SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1),
-SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1),
-SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1),
+ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2),
+ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
+ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
+ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 8a8b1c0..ccb3b15 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -30,7 +30,7 @@
#include <sound/wm9081.h>
#include "wm9081.h"
-static struct reg_default wm9081_reg[] = {
+static const struct reg_default wm9081_reg[] = {
{ 2, 0x00B9 }, /* R2 - Analogue Lineout */
{ 3, 0x00B9 }, /* R3 - Analogue Speaker PGA */
{ 4, 0x0001 }, /* R4 - VMID Control */
@@ -243,13 +243,12 @@ static int wm9081_reset(struct regmap *map)
static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0);
static const DECLARE_TLV_DB_SCALE(drc_out_tlv, -2250, 75, 0);
static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0);
-static unsigned int drc_max_tlv[] = {
- TLV_DB_RANGE_HEAD(4),
+static const DECLARE_TLV_DB_RANGE(drc_max_tlv,
0, 0, TLV_DB_SCALE_ITEM(1200, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
- 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0),
-};
+ 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0)
+);
static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0);
static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -300, 50, 0);
@@ -1378,7 +1377,6 @@ MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id);
static struct i2c_driver wm9081_i2c_driver = {
.driver = {
.name = "wm9081",
- .owner = THIS_MODULE,
},
.probe = wm9081_i2c_probe,
.remove = wm9081_i2c_remove,
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index 13d23fc..5d73729 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -162,23 +162,20 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec)
dev_err(codec->dev, "Timed out waiting for DC Servo\n");
}
-static const unsigned int in_tlv[] = {
- TLV_DB_RANGE_HEAD(3),
+static const DECLARE_TLV_DB_RANGE(in_tlv,
0, 0, TLV_DB_SCALE_ITEM(-600, 0, 0),
1, 3, TLV_DB_SCALE_ITEM(-350, 350, 0),
- 4, 6, TLV_DB_SCALE_ITEM(600, 600, 0),
-};
-static const unsigned int mix_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+ 4, 6, TLV_DB_SCALE_ITEM(600, 600, 0)
+);
+static const DECLARE_TLV_DB_RANGE(mix_tlv,
0, 2, TLV_DB_SCALE_ITEM(-1200, 300, 0),
- 3, 3, TLV_DB_SCALE_ITEM(0, 0, 0),
-};
+ 3, 3, TLV_DB_SCALE_ITEM(0, 0, 0)
+);
static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
-static const unsigned int spkboost_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(spkboost_tlv,
0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
- 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
-};
+ 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0)
+);
static const struct snd_kcontrol_new wm9090_controls[] = {
SOC_SINGLE_TLV("IN1A Volume", WM9090_IN1_LINE_INPUT_A_VOLUME, 0, 6, 0,
@@ -636,7 +633,6 @@ MODULE_DEVICE_TABLE(i2c, wm9090_id);
static struct i2c_driver wm9090_i2c_driver = {
.driver = {
.name = "wm9090",
- .owner = THIS_MODULE,
},
.probe = wm9090_i2c_probe,
.remove = wm9090_i2c_remove,
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index 5cc457e..744842c 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -22,6 +22,9 @@
#include "wm9705.h"
+#define WM9705_VENDOR_ID 0x574d4c05
+#define WM9705_VENDOR_ID_MASK 0xffffffff
+
/*
* WM9705 register cache
*/
@@ -293,21 +296,6 @@ static struct snd_soc_dai_driver wm9705_dai[] = {
}
};
-static int wm9705_reset(struct snd_soc_codec *codec)
-{
- struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
-
- if (soc_ac97_ops->reset) {
- soc_ac97_ops->reset(ac97);
- if (ac97_read(codec, 0) == wm9705_reg[0])
- return 0; /* Success */
- }
-
- dev_err(codec->dev, "Failed to reset: AC97 link error\n");
-
- return -EIO;
-}
-
#ifdef CONFIG_PM
static int wm9705_soc_suspend(struct snd_soc_codec *codec)
{
@@ -324,7 +312,8 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec)
int i, ret;
u16 *cache = codec->reg_cache;
- ret = wm9705_reset(codec);
+ ret = snd_ac97_reset(ac97, true, WM9705_VENDOR_ID,
+ WM9705_VENDOR_ID_MASK);
if (ret < 0)
return ret;
@@ -342,30 +331,17 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec)
static int wm9705_soc_probe(struct snd_soc_codec *codec)
{
struct snd_ac97 *ac97;
- int ret = 0;
- ac97 = snd_soc_alloc_ac97_codec(codec);
+ ac97 = snd_soc_new_ac97_codec(codec, WM9705_VENDOR_ID,
+ WM9705_VENDOR_ID_MASK);
if (IS_ERR(ac97)) {
- ret = PTR_ERR(ac97);
dev_err(codec->dev, "Failed to register AC97 codec\n");
- return ret;
+ return PTR_ERR(ac97);
}
- ret = wm9705_reset(codec);
- if (ret)
- goto err_put_device;
-
- ret = device_add(&ac97->dev);
- if (ret)
- goto err_put_device;
-
snd_soc_codec_set_drvdata(codec, ac97);
return 0;
-
-err_put_device:
- put_device(&ac97->dev);
- return ret;
}
static int wm9705_soc_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 1fda104..488a922 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -23,6 +23,9 @@
#include <sound/tlv.h>
#include "wm9712.h"
+#define WM9712_VENDOR_ID 0x574d4c12
+#define WM9712_VENDOR_ID_MASK 0xffffffff
+
struct wm9712_priv {
struct snd_ac97 *ac97;
unsigned int hp_mixer[2];
@@ -613,35 +616,14 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
-{
- struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
-
- if (try_warm && soc_ac97_ops->warm_reset) {
- soc_ac97_ops->warm_reset(wm9712->ac97);
- if (ac97_read(codec, 0) == wm9712_reg[0])
- return 1;
- }
-
- soc_ac97_ops->reset(wm9712->ac97);
- if (soc_ac97_ops->warm_reset)
- soc_ac97_ops->warm_reset(wm9712->ac97);
- if (ac97_read(codec, 0) != wm9712_reg[0])
- goto err;
- return 0;
-
-err:
- dev_err(codec->dev, "Failed to reset: AC97 link error\n");
- return -EIO;
-}
-
static int wm9712_soc_resume(struct snd_soc_codec *codec)
{
struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
int i, ret;
u16 *cache = codec->reg_cache;
- ret = wm9712_reset(codec, 1);
+ ret = snd_ac97_reset(wm9712->ac97, true, WM9712_VENDOR_ID,
+ WM9712_VENDOR_ID_MASK);
if (ret < 0)
return ret;
@@ -663,31 +645,20 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec)
static int wm9712_soc_probe(struct snd_soc_codec *codec)
{
struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
- int ret = 0;
+ int ret;
- wm9712->ac97 = snd_soc_alloc_ac97_codec(codec);
+ wm9712->ac97 = snd_soc_new_ac97_codec(codec, WM9712_VENDOR_ID,
+ WM9712_VENDOR_ID_MASK);
if (IS_ERR(wm9712->ac97)) {
ret = PTR_ERR(wm9712->ac97);
dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret);
return ret;
}
- ret = wm9712_reset(codec, 0);
- if (ret < 0)
- goto err_put_device;
-
- ret = device_add(&wm9712->ac97->dev);
- if (ret)
- goto err_put_device;
-
/* set alc mux to none */
ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);
return 0;
-
-err_put_device:
- put_device(&wm9712->ac97->dev);
- return ret;
}
static int wm9712_soc_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 89cd2d6..4083a51 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -29,6 +29,9 @@
#include "wm9713.h"
+#define WM9713_VENDOR_ID 0x574d4c13
+#define WM9713_VENDOR_ID_MASK 0xffffffff
+
struct wm9713_priv {
struct snd_ac97 *ac97;
u32 pll_in; /* PLL input frequency */
@@ -116,11 +119,10 @@ SOC_ENUM_SINGLE_VIRT(2, wm9713_micb_select), /* mic selection 19 */
static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0);
static const DECLARE_TLV_DB_SCALE(main_tlv, -3450, 150, 0);
static const DECLARE_TLV_DB_SCALE(misc_tlv, -1500, 300, 0);
-static unsigned int mic_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(mic_tlv,
0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0),
- 3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0),
-};
+ 3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0)
+);
static const struct snd_kcontrol_new wm9713_snd_ac97_controls[] = {
SOC_DOUBLE_TLV("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1, out_tlv),
@@ -1123,28 +1125,6 @@ static struct snd_soc_dai_driver wm9713_dai[] = {
},
};
-int wm9713_reset(struct snd_soc_codec *codec, int try_warm)
-{
- struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
-
- if (try_warm && soc_ac97_ops->warm_reset) {
- soc_ac97_ops->warm_reset(wm9713->ac97);
- if (ac97_read(codec, 0) == wm9713_reg[0])
- return 1;
- }
-
- soc_ac97_ops->reset(wm9713->ac97);
- if (soc_ac97_ops->warm_reset)
- soc_ac97_ops->warm_reset(wm9713->ac97);
- if (ac97_read(codec, 0) != wm9713_reg[0]) {
- dev_err(codec->dev, "Failed to reset: AC97 link error\n");
- return -EIO;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(wm9713_reset);
-
static int wm9713_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
@@ -1196,7 +1176,8 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
int i, ret;
u16 *cache = codec->reg_cache;
- ret = wm9713_reset(codec, 1);
+ ret = snd_ac97_reset(wm9713->ac97, true, WM9713_VENDOR_ID,
+ WM9713_VENDOR_ID_MASK);
if (ret < 0)
return ret;
@@ -1222,32 +1203,18 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
static int wm9713_soc_probe(struct snd_soc_codec *codec)
{
struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
- int ret = 0, reg;
+ int reg;
- wm9713->ac97 = snd_soc_alloc_ac97_codec(codec);
+ wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID,
+ WM9713_VENDOR_ID_MASK);
if (IS_ERR(wm9713->ac97))
return PTR_ERR(wm9713->ac97);
- /* do a cold reset for the controller and then try
- * a warm reset followed by an optional cold reset for codec */
- wm9713_reset(codec, 0);
- ret = wm9713_reset(codec, 1);
- if (ret < 0)
- goto err_put_device;
-
- ret = device_add(&wm9713->ac97->dev);
- if (ret)
- goto err_put_device;
-
/* unmute the adc - move to kcontrol */
reg = ac97_read(codec, AC97_CD) & 0x7fff;
ac97_write(codec, AC97_CD, reg);
return 0;
-
-err_put_device:
- put_device(&wm9713->ac97->dev);
- return ret;
}
static int wm9713_soc_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wm9713.h b/sound/soc/codecs/wm9713.h
index 793da86..53df11b 100644
--- a/sound/soc/codecs/wm9713.h
+++ b/sound/soc/codecs/wm9713.h
@@ -45,6 +45,4 @@
#define WM9713_DAI_AC97_AUX 1
#define WM9713_DAI_PCM_VOICE 2
-int wm9713_reset(struct snd_soc_codec *codec, int try_warm);
-
#endif
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index fd86bd1..624b3b9 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -38,11 +38,10 @@ static const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0);
static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0);
static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1);
static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0);
-static const unsigned int spkboost_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(spkboost_tlv,
0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
- 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
-};
+ 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0)
+);
static const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0);
static const char *speaker_ref_text[] = {
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 56cb4d9..ec98548 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -651,23 +651,15 @@ static const struct snd_soc_component_driver davinci_i2s_component = {
static int davinci_i2s_probe(struct platform_device *pdev)
{
struct davinci_mcbsp_dev *dev;
- struct resource *mem, *ioarea, *res;
+ struct resource *mem, *res;
+ void __iomem *io_base;
int *dma;
int ret;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "no mem resource?\n");
- return -ENODEV;
- }
-
- ioarea = devm_request_mem_region(&pdev->dev, mem->start,
- resource_size(mem),
- pdev->name);
- if (!ioarea) {
- dev_err(&pdev->dev, "McBSP region already claimed\n");
- return -EBUSY;
- }
+ io_base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(io_base))
+ return PTR_ERR(io_base);
dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcbsp_dev),
GFP_KERNEL);
@@ -679,12 +671,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
return -ENODEV;
clk_enable(dev->clk);
- dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
- if (!dev->base) {
- dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
- goto err_release_clk;
- }
+ dev->base = io_base;
dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
(dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG);
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index b960e62..add6bb9 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -1613,7 +1613,7 @@ static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp)
static int davinci_mcasp_probe(struct platform_device *pdev)
{
struct snd_dmaengine_dai_dma_data *dma_data;
- struct resource *mem, *ioarea, *res, *dat;
+ struct resource *mem, *res, *dat;
struct davinci_mcasp_pdata *pdata;
struct davinci_mcasp *mcasp;
char *irq_name;
@@ -1648,22 +1648,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
}
}
- ioarea = devm_request_mem_region(&pdev->dev, mem->start,
- resource_size(mem), pdev->name);
- if (!ioarea) {
- dev_err(&pdev->dev, "Audio region already claimed\n");
- return -EBUSY;
- }
+ mcasp->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(mcasp->base))
+ return PTR_ERR(mcasp->base);
pm_runtime_enable(&pdev->dev);
- mcasp->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
- if (!mcasp->base) {
- dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
- goto err;
- }
-
mcasp->op_mode = pdata->op_mode;
/* sanity check for tdm slots parameter */
if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
index fabd05f..c77d921 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/davinci/davinci-vcif.c
@@ -231,8 +231,9 @@ static int davinci_vcif_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
- ret = snd_soc_register_component(&pdev->dev, &davinci_vcif_component,
- &davinci_vcif_dai, 1);
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &davinci_vcif_component,
+ &davinci_vcif_dai, 1);
if (ret != 0) {
dev_err(&pdev->dev, "could not register dai\n");
return ret;
@@ -241,23 +242,14 @@ static int davinci_vcif_probe(struct platform_device *pdev)
ret = edma_pcm_platform_register(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
- snd_soc_unregister_component(&pdev->dev);
return ret;
}
return 0;
}
-static int davinci_vcif_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_component(&pdev->dev);
-
- return 0;
-}
-
static struct platform_driver davinci_vcif_driver = {
.probe = davinci_vcif_probe,
- .remove = davinci_vcif_remove,
.driver = {
.name = "davinci-vcif",
},
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
index e1aa3834..883087f 100644
--- a/sound/soc/fsl/eukrea-tlv320.c
+++ b/sound/soc/fsl/eukrea-tlv320.c
@@ -182,7 +182,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
);
} else {
if (np) {
- /* The eukrea,asoc-tlv320 driver was explicitely
+ /* The eukrea,asoc-tlv320 driver was explicitly
* requested (through the device tree).
*/
dev_err(&pdev->dev,
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index de43887..5aeb6ed 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -23,6 +23,7 @@
#include "../codecs/sgtl5000.h"
#include "../codecs/wm8962.h"
+#include "../codecs/wm8960.h"
#define RX 0
#define TX 1
@@ -407,6 +408,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
struct fsl_asoc_card_priv *priv;
struct i2c_client *codec_dev;
struct clk *codec_clk;
+ const char *codec_dai_name;
u32 width;
int ret;
@@ -459,6 +461,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
/* Diversify the card configurations */
if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) {
+ codec_dai_name = "cs42888";
priv->card.set_bias_level = NULL;
priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq;
priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq;
@@ -467,14 +470,22 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->cpu_priv.slot_width = 32;
priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
} else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) {
+ codec_dai_name = "sgtl5000";
priv->codec_priv.mclk_id = SGTL5000_SYSCLK;
priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) {
+ codec_dai_name = "wm8962";
priv->card.set_bias_level = fsl_asoc_card_set_bias_level;
priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK;
priv->codec_priv.fll_id = WM8962_SYSCLK_FLL;
priv->codec_priv.pll_id = WM8962_FLL;
priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+ } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8960")) {
+ codec_dai_name = "wm8960-hifi";
+ priv->card.set_bias_level = fsl_asoc_card_set_bias_level;
+ priv->codec_priv.fll_id = WM8960_SYSCLK_AUTO;
+ priv->codec_priv.pll_id = WM8960_SYSCLK_AUTO;
+ priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
} else {
dev_err(&pdev->dev, "unknown Device Tree compatible\n");
return -EINVAL;
@@ -521,7 +532,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
/* Normal DAI Link */
priv->dai_link[0].cpu_of_node = cpu_np;
priv->dai_link[0].codec_of_node = codec_np;
- priv->dai_link[0].codec_dai_name = codec_dev->name;
+ priv->dai_link[0].codec_dai_name = codec_dai_name;
priv->dai_link[0].platform_of_node = cpu_np;
priv->dai_link[0].dai_fmt = priv->dai_fmt;
priv->card.num_links = 1;
@@ -530,7 +541,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
/* DPCM DAI Links only if ASRC exsits */
priv->dai_link[1].cpu_of_node = asrc_np;
priv->dai_link[1].platform_of_node = asrc_np;
- priv->dai_link[2].codec_dai_name = codec_dev->name;
+ priv->dai_link[2].codec_dai_name = codec_dai_name;
priv->dai_link[2].codec_of_node = codec_np;
priv->dai_link[2].cpu_of_node = cpu_np;
priv->dai_link[2].dai_fmt = priv->dai_fmt;
@@ -578,6 +589,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = {
{ .compatible = "fsl,imx-audio-cs42888", },
{ .compatible = "fsl,imx-audio-sgtl5000", },
{ .compatible = "fsl,imx-audio-wm8962", },
+ { .compatible = "fsl,imx-audio-wm8960", },
{}
};
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index c068494..9f087d4 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -931,14 +931,29 @@ static int fsl_asrc_probe(struct platform_device *pdev)
static int fsl_asrc_runtime_resume(struct device *dev)
{
struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
- int i;
+ int i, ret;
- clk_prepare_enable(asrc_priv->mem_clk);
- clk_prepare_enable(asrc_priv->ipg_clk);
- for (i = 0; i < ASRC_CLK_MAX_NUM; i++)
- clk_prepare_enable(asrc_priv->asrck_clk[i]);
+ ret = clk_prepare_enable(asrc_priv->mem_clk);
+ if (ret)
+ return ret;
+ ret = clk_prepare_enable(asrc_priv->ipg_clk);
+ if (ret)
+ goto disable_mem_clk;
+ for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
+ ret = clk_prepare_enable(asrc_priv->asrck_clk[i]);
+ if (ret)
+ goto disable_asrck_clk;
+ }
return 0;
+
+disable_asrck_clk:
+ for (i--; i >= 0; i--)
+ clk_disable_unprepare(asrc_priv->asrck_clk[i]);
+ clk_disable_unprepare(asrc_priv->ipg_clk);
+disable_mem_clk:
+ clk_disable_unprepare(asrc_priv->mem_clk);
+ return ret;
}
static int fsl_asrc_runtime_suspend(struct device *dev)
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 5c75971..8c2ddc1 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -839,7 +839,7 @@ static int fsl_esai_probe(struct platform_device *pdev)
return ret;
}
- ret = imx_pcm_dma_init(pdev);
+ ret = imx_pcm_dma_init(pdev, IMX_ESAI_DMABUF_SIZE);
if (ret)
dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 5c73bea..a18fd92 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -791,7 +791,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
return ret;
if (sai->sai_on_imx)
- return imx_pcm_dma_init(pdev);
+ return imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE);
else
return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
}
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index 0662809..b95fbc3 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -13,7 +13,8 @@
#define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S20_3LE |\
- SNDRV_PCM_FMTBIT_S24_LE)
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
/* SAI Register Map Register */
#define FSL_SAI_TCSR 0x00 /* SAI Transmit Control */
@@ -45,7 +46,7 @@
#define FSL_SAI_xFR(tx) (tx ? FSL_SAI_TFR : FSL_SAI_RFR)
#define FSL_SAI_xMR(tx) (tx ? FSL_SAI_TMR : FSL_SAI_RMR)
-/* SAI Transmit/Recieve Control Register */
+/* SAI Transmit/Receive Control Register */
#define FSL_SAI_CSR_TERE BIT(31)
#define FSL_SAI_CSR_FR BIT(25)
#define FSL_SAI_CSR_SR BIT(24)
@@ -67,10 +68,10 @@
#define FSL_SAI_CSR_FRIE BIT(8)
#define FSL_SAI_CSR_FRDE BIT(0)
-/* SAI Transmit and Recieve Configuration 1 Register */
+/* SAI Transmit and Receive Configuration 1 Register */
#define FSL_SAI_CR1_RFW_MASK 0x1f
-/* SAI Transmit and Recieve Configuration 2 Register */
+/* SAI Transmit and Receive Configuration 2 Register */
#define FSL_SAI_CR2_SYNC BIT(30)
#define FSL_SAI_CR2_MSEL_MASK (0x3 << 26)
#define FSL_SAI_CR2_MSEL_BUS 0
@@ -82,12 +83,12 @@
#define FSL_SAI_CR2_BCD_MSTR BIT(24)
#define FSL_SAI_CR2_DIV_MASK 0xff
-/* SAI Transmit and Recieve Configuration 3 Register */
+/* SAI Transmit and Receive Configuration 3 Register */
#define FSL_SAI_CR3_TRCE BIT(16)
#define FSL_SAI_CR3_WDFL(x) (x)
#define FSL_SAI_CR3_WDFL_MASK 0x1f
-/* SAI Transmit and Recieve Configuration 4 Register */
+/* SAI Transmit and Receive Configuration 4 Register */
#define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16)
#define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16)
#define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8)
@@ -97,7 +98,7 @@
#define FSL_SAI_CR4_FSP BIT(1)
#define FSL_SAI_CR4_FSD_MSTR BIT(0)
-/* SAI Transmit and Recieve Configuration 5 Register */
+/* SAI Transmit and Receive Configuration 5 Register */
#define FSL_SAI_CR5_WNW(x) (((x) - 1) << 24)
#define FSL_SAI_CR5_WNW_MASK (0x1f << 24)
#define FSL_SAI_CR5_W0W(x) (((x) - 1) << 16)
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 8e93221..ab729f2 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -454,7 +454,8 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct platform_device *pdev = spdif_priv->pdev;
struct regmap *regmap = spdif_priv->regmap;
- u32 scr, mask, i;
+ u32 scr, mask;
+ int i;
int ret;
/* Reset module and interrupts only for first initialization */
@@ -482,13 +483,18 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
SCR_TXFIFO_FSEL_MASK;
- for (i = 0; i < SPDIF_TXRATE_MAX; i++)
- clk_prepare_enable(spdif_priv->txclk[i]);
+ for (i = 0; i < SPDIF_TXRATE_MAX; i++) {
+ ret = clk_prepare_enable(spdif_priv->txclk[i]);
+ if (ret)
+ goto disable_txclk;
+ }
} else {
scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC;
mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
- clk_prepare_enable(spdif_priv->rxclk);
+ ret = clk_prepare_enable(spdif_priv->rxclk);
+ if (ret)
+ goto err;
}
regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
@@ -497,6 +503,9 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
return 0;
+disable_txclk:
+ for (i--; i >= 0; i--)
+ clk_disable_unprepare(spdif_priv->txclk[i]);
err:
clk_disable_unprepare(spdif_priv->coreclk);
@@ -707,7 +716,7 @@ static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol,
return ret;
}
-/* Q-subcode infomation. The byte size is SPDIF_UBITS_SIZE/8 */
+/* Q-subcode information. The byte size is SPDIF_UBITS_SIZE/8 */
static int fsl_spdif_qinfo(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -739,7 +748,7 @@ static int fsl_spdif_qget(struct snd_kcontrol *kcontrol,
return ret;
}
-/* Valid bit infomation */
+/* Valid bit information */
static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -767,7 +776,7 @@ static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol,
return 0;
}
-/* DPLL lock infomation */
+/* DPLL lock information */
static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -1255,7 +1264,7 @@ static int fsl_spdif_probe(struct platform_device *pdev)
return ret;
}
- ret = imx_pcm_dma_init(pdev);
+ ret = imx_pcm_dma_init(pdev, IMX_SPDIF_DMABUF_SIZE);
if (ret)
dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret);
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index c0b940e..8ec6fb2 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -156,7 +156,7 @@ struct fsl_ssi_soc_data {
*
* @dbg_stats: Debugging statistics
*
- * @soc: SoC specifc data
+ * @soc: SoC specific data
*/
struct fsl_ssi_private {
struct regmap *regs;
@@ -900,14 +900,16 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
break;
default:
- return -EINVAL;
+ if (!fsl_ssi_is_ac97(ssi_private))
+ return -EINVAL;
}
stcr |= strcr;
srcr |= strcr;
- if (ssi_private->cpu_dai_drv.symmetric_rates) {
- /* Need to clear RXDIR when using SYNC mode */
+ if (ssi_private->cpu_dai_drv.symmetric_rates
+ || fsl_ssi_is_ac97(ssi_private)) {
+ /* Need to clear RXDIR when using SYNC or AC97 mode */
srcr &= ~CCSR_SSI_SRCR_RXDIR;
scr |= CCSR_SSI_SCR_SYN;
}
@@ -1101,6 +1103,7 @@ static const struct snd_soc_component_driver fsl_ssi_component = {
static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
.bus_control = true,
+ .probe = fsl_ssi_dai_probe,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
@@ -1127,10 +1130,17 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
struct regmap *regs = fsl_ac97_data->regs;
unsigned int lreg;
unsigned int lval;
+ int ret;
if (reg > 0x7f)
return;
+ ret = clk_prepare_enable(fsl_ac97_data->clk);
+ if (ret) {
+ pr_err("ac97 write clk_prepare_enable failed: %d\n",
+ ret);
+ return;
+ }
lreg = reg << 12;
regmap_write(regs, CCSR_SSI_SACADD, lreg);
@@ -1141,6 +1151,8 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
regmap_update_bits(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_RDWR_MASK,
CCSR_SSI_SACNT_WR);
udelay(100);
+
+ clk_disable_unprepare(fsl_ac97_data->clk);
}
static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
@@ -1151,6 +1163,14 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
unsigned short val = -1;
u32 reg_val;
unsigned int lreg;
+ int ret;
+
+ ret = clk_prepare_enable(fsl_ac97_data->clk);
+ if (ret) {
+ pr_err("ac97 read clk_prepare_enable failed: %d\n",
+ ret);
+ return -1;
+ }
lreg = (reg & 0x7f) << 12;
regmap_write(regs, CCSR_SSI_SACADD, lreg);
@@ -1162,6 +1182,8 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
regmap_read(regs, CCSR_SSI_SACDAT, &reg_val);
val = (reg_val >> 4) & 0xffff;
+ clk_disable_unprepare(fsl_ac97_data->clk);
+
return val;
}
@@ -1210,7 +1232,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
}
}
- /* For those SLAVE implementations, we ingore non-baudclk cases
+ /* For those SLAVE implementations, we ignore non-baudclk cases
* and, instead, abandon MASTER mode that needs baud clock.
*/
ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud");
@@ -1257,7 +1279,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
if (ret)
goto error_pcm;
} else {
- ret = imx_pcm_dma_init(pdev);
+ ret = imx_pcm_dma_init(pdev, IMX_SSI_DMABUF_SIZE);
if (ret)
goto error_pcm;
}
@@ -1320,7 +1342,11 @@ static int fsl_ssi_probe(struct platform_device *pdev)
fsl_ac97_data = ssi_private;
- snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
+ ret = snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "could not set AC'97 ops\n");
+ return ret;
+ }
} else {
/* Initialize this copy of the CPU DAI driver structure */
memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
@@ -1357,7 +1383,9 @@ static int fsl_ssi_probe(struct platform_device *pdev)
/* Are the RX and the TX clocks locked? */
if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) {
- ssi_private->cpu_dai_drv.symmetric_rates = 1;
+ if (!fsl_ssi_is_ac97(ssi_private))
+ ssi_private->cpu_dai_drv.symmetric_rates = 1;
+
ssi_private->cpu_dai_drv.symmetric_channels = 1;
ssi_private->cpu_dai_drv.symmetric_samplebits = 1;
}
@@ -1434,6 +1462,27 @@ done:
_fsl_ssi_set_dai_fmt(&pdev->dev, ssi_private,
ssi_private->dai_fmt);
+ if (fsl_ssi_is_ac97(ssi_private)) {
+ u32 ssi_idx;
+
+ ret = of_property_read_u32(np, "cell-index", &ssi_idx);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot get SSI index property\n");
+ goto error_sound_card;
+ }
+
+ ssi_private->pdev =
+ platform_device_register_data(NULL,
+ "ac97-codec", ssi_idx, NULL, 0);
+ if (IS_ERR(ssi_private->pdev)) {
+ ret = PTR_ERR(ssi_private->pdev);
+ dev_err(&pdev->dev,
+ "failed to register AC97 codec platform: %d\n",
+ ret);
+ goto error_sound_card;
+ }
+ }
+
return 0;
error_sound_card:
@@ -1458,6 +1507,9 @@ static int fsl_ssi_remove(struct platform_device *pdev)
if (ssi_private->soc->imx)
fsl_ssi_imx_clean(pdev, ssi_private);
+ if (fsl_ssi_is_ac97(ssi_private))
+ snd_soc_set_ac97_ops(NULL);
+
return 0;
}
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index 0db94f49..1fc01ed 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -40,7 +40,7 @@ static const struct snd_pcm_hardware imx_pcm_hardware = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
- .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
+ .buffer_bytes_max = IMX_DEFAULT_DMABUF_SIZE,
.period_bytes_min = 128,
.period_bytes_max = 65535, /* Limited by SDMA engine */
.periods_min = 2,
@@ -52,13 +52,30 @@ static const struct snd_dmaengine_pcm_config imx_dmaengine_pcm_config = {
.pcm_hardware = &imx_pcm_hardware,
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
.compat_filter_fn = filter,
- .prealloc_buffer_size = IMX_SSI_DMABUF_SIZE,
+ .prealloc_buffer_size = IMX_DEFAULT_DMABUF_SIZE,
};
-int imx_pcm_dma_init(struct platform_device *pdev)
+int imx_pcm_dma_init(struct platform_device *pdev, size_t size)
{
+ struct snd_dmaengine_pcm_config *config;
+ struct snd_pcm_hardware *pcm_hardware;
+
+ config = devm_kzalloc(&pdev->dev,
+ sizeof(struct snd_dmaengine_pcm_config), GFP_KERNEL);
+ *config = imx_dmaengine_pcm_config;
+ if (size)
+ config->prealloc_buffer_size = size;
+
+ pcm_hardware = devm_kzalloc(&pdev->dev,
+ sizeof(struct snd_pcm_hardware), GFP_KERNEL);
+ *pcm_hardware = imx_pcm_hardware;
+ if (size)
+ pcm_hardware->buffer_bytes_max = size;
+
+ config->pcm_hardware = pcm_hardware;
+
return devm_snd_dmaengine_pcm_register(&pdev->dev,
- &imx_dmaengine_pcm_config,
+ config,
SND_DMAENGINE_PCM_FLAG_COMPAT);
}
EXPORT_SYMBOL_GPL(imx_pcm_dma_init);
diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h
index c79cb27..133c4470a 100644
--- a/sound/soc/fsl/imx-pcm.h
+++ b/sound/soc/fsl/imx-pcm.h
@@ -20,6 +20,11 @@
*/
#define IMX_SSI_DMABUF_SIZE (64 * 1024)
+#define IMX_DEFAULT_DMABUF_SIZE (64 * 1024)
+#define IMX_SAI_DMABUF_SIZE (64 * 1024)
+#define IMX_SPDIF_DMABUF_SIZE (64 * 1024)
+#define IMX_ESAI_DMABUF_SIZE (256 * 1024)
+
static inline void
imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data,
int dma, enum sdma_peripheral_type peripheral_type)
@@ -39,9 +44,9 @@ struct imx_pcm_fiq_params {
};
#if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA)
-int imx_pcm_dma_init(struct platform_device *pdev);
+int imx_pcm_dma_init(struct platform_device *pdev, size_t size);
#else
-static inline int imx_pcm_dma_init(struct platform_device *pdev)
+static inline int imx_pcm_dma_init(struct platform_device *pdev, size_t size)
{
return -ENODEV;
}
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index 461ce27..48b2d24 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -603,7 +603,7 @@ static int imx_ssi_probe(struct platform_device *pdev)
ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx;
ssi->fiq_init = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
- ssi->dma_init = imx_pcm_dma_init(pdev);
+ ssi->dma_init = imx_pcm_dma_init(pdev, IMX_SSI_DMABUF_SIZE);
if (ssi->fiq_init && ssi->dma_init) {
ret = ssi->fiq_init;
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index d555493..3ff76d4 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -76,6 +76,7 @@ static int asoc_simple_card_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_dai *cpu_dai = rtd->cpu_dai;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props =
&priv->dai_props[rtd - rtd->card->rtd];
@@ -91,8 +92,16 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
mclk = params_rate(params) * mclk_fs;
ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP)
+ goto err;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+ SND_SOC_CLOCK_OUT);
+ if (ret && ret != -ENOTSUPP)
+ goto err;
}
+err:
return ret;
}
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index f3060a4..05fde5e6e 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -26,14 +26,9 @@ config SND_SST_IPC_ACPI
depends on ACPI
config SND_SOC_INTEL_SST
- tristate "ASoC support for Intel(R) Smart Sound Technology"
+ tristate
select SND_SOC_INTEL_SST_ACPI if ACPI
depends on (X86 || COMPILE_TEST)
- depends on DW_DMAC_CORE
- help
- This adds support for Intel(R) Smart Sound Technology (SST).
- Say Y if you have such a device
- If unsure select "N".
config SND_SOC_INTEL_SST_ACPI
tristate
@@ -46,8 +41,9 @@ config SND_SOC_INTEL_BAYTRAIL
config SND_SOC_INTEL_HASWELL_MACH
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
- depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \
- I2C_DESIGNWARE_PLATFORM
+ depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
+ depends on DW_DMAC_CORE
+ select SND_SOC_INTEL_SST
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640
help
@@ -58,7 +54,9 @@ config SND_SOC_INTEL_HASWELL_MACH
config SND_SOC_INTEL_BYT_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
- depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
+ depends on X86_INTEL_LPSS && I2C
+ depends on DW_DMAC_CORE
+ select SND_SOC_INTEL_SST
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_RT5640
help
@@ -67,7 +65,9 @@ config SND_SOC_INTEL_BYT_RT5640_MACH
config SND_SOC_INTEL_BYT_MAX98090_MACH
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
- depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
+ depends on X86_INTEL_LPSS && I2C
+ depends on DW_DMAC_CORE
+ select SND_SOC_INTEL_SST
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_MAX98090
help
@@ -76,8 +76,10 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
config SND_SOC_INTEL_BROADWELL_MACH
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
- depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \
+ depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
I2C_DESIGNWARE_PLATFORM
+ depends on DW_DMAC_CORE
+ select SND_SOC_INTEL_SST
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT286
help
@@ -132,3 +134,8 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
If unsure select "N".
+
+config SND_SOC_INTEL_SKYLAKE
+ tristate
+ select SND_HDA_EXT_CORE
+ select SND_SOC_INTEL_SST
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index 6de5d5c..2b45435 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SST) += common/
obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/
obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += atom/
+obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/
# Machine support
obj-$(CONFIG_SND_SOC) += boards/
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index 31e9b9e..d55388e 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -132,7 +132,7 @@ static int sst_send_slot_map(struct sst_data *drv)
sizeof(cmd.header) + cmd.header.length);
}
-int sst_slot_enum_info(struct snd_kcontrol *kcontrol,
+static int sst_slot_enum_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct sst_enum *e = (struct sst_enum *)kcontrol->private_value;
@@ -1298,7 +1298,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
dev_dbg(dai->dev, "Stream name=%s\n",
dai->playback_widget->name);
w = dai->playback_widget;
- list_for_each_entry(p, &w->sinks, list_source) {
+ snd_soc_dapm_widget_for_each_sink_path(w, p) {
if (p->connected && !p->connected(w, p->sink))
continue;
@@ -1317,7 +1317,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
dev_dbg(dai->dev, "Stream name=%s\n",
dai->capture_widget->name);
w = dai->capture_widget;
- list_for_each_entry(p, &w->sources, list_sink) {
+ snd_soc_dapm_widget_for_each_source_path(w, p) {
if (p->connected && !p->connected(w, p->sink))
continue;
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index 641ebe6..683e501 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -33,7 +33,6 @@
struct sst_device *sst;
static DEFINE_MUTEX(sst_lock);
-extern struct snd_compr_ops sst_platform_compr_ops;
int sst_register_dsp(struct sst_device *dev)
{
diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h
index 2409b23..cb32cc7 100644
--- a/sound/soc/intel/atom/sst-mfld-platform.h
+++ b/sound/soc/intel/atom/sst-mfld-platform.h
@@ -25,6 +25,7 @@
#include "sst-atom-controls.h"
extern struct sst_device *sst;
+extern struct snd_compr_ops sst_platform_compr_ops;
#define SST_MONO 1
#define SST_STEREO 2
diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c
index 0e0e4d9..ce689c5 100644
--- a/sound/soc/intel/atom/sst/sst_drv_interface.c
+++ b/sound/soc/intel/atom/sst/sst_drv_interface.c
@@ -151,6 +151,7 @@ static int sst_power_control(struct device *dev, bool state)
usage_count = GET_USAGE_COUNT(dev);
dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count);
if (ret < 0) {
+ pm_runtime_put_sync(dev);
dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret);
return ret;
}
@@ -204,8 +205,10 @@ static int sst_cdev_open(struct device *dev,
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
retval = pm_runtime_get_sync(ctx->dev);
- if (retval < 0)
+ if (retval < 0) {
+ pm_runtime_put_sync(ctx->dev);
return retval;
+ }
str_id = sst_get_stream(ctx, str_params);
if (str_id > 0) {
@@ -672,8 +675,10 @@ static int sst_send_byte_stream(struct device *dev,
if (NULL == bytes)
return -EINVAL;
ret_val = pm_runtime_get_sync(ctx->dev);
- if (ret_val < 0)
+ if (ret_val < 0) {
+ pm_runtime_put_sync(ctx->dev);
return ret_val;
+ }
ret_val = sst_send_byte_stream_mrfld(ctx, bytes);
sst_pm_runtime_put(ctx);
diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c
index 5a27861..3dc7358 100644
--- a/sound/soc/intel/atom/sst/sst_ipc.c
+++ b/sound/soc/intel/atom/sst/sst_ipc.c
@@ -352,10 +352,9 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
* copy from mailbox
**/
if (msg_high.part.large) {
- data = kzalloc(msg_low, GFP_KERNEL);
+ data = kmemdup((void *)msg->mailbox_data, msg_low, GFP_KERNEL);
if (!data)
return;
- memcpy(data, (void *) msg->mailbox_data, msg_low);
/* Copy command id so that we can use to put sst to reset */
dsp_hdr = (struct ipc_dsp_hdr *)data;
cmd_id = dsp_hdr->cmd_id;
diff --git a/sound/soc/intel/boards/byt-max98090.c b/sound/soc/intel/boards/byt-max98090.c
index 7ab8cc9..d9f81b8 100644
--- a/sound/soc/intel/boards/byt-max98090.c
+++ b/sound/soc/intel/boards/byt-max98090.c
@@ -126,6 +126,7 @@ static struct snd_soc_dai_link byt_max98090_dais[] = {
static struct snd_soc_card byt_max98090_card = {
.name = "byt-max98090",
+ .owner = THIS_MODULE,
.dai_link = byt_max98090_dais,
.num_links = ARRAY_SIZE(byt_max98090_dais),
.dapm_widgets = byt_max98090_widgets,
diff --git a/sound/soc/intel/boards/byt-rt5640.c b/sound/soc/intel/boards/byt-rt5640.c
index ae89b9b9..de9788a 100644
--- a/sound/soc/intel/boards/byt-rt5640.c
+++ b/sound/soc/intel/boards/byt-rt5640.c
@@ -197,6 +197,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
static struct snd_soc_card byt_rt5640_card = {
.name = "byt-rt5640",
+ .owner = THIS_MODULE,
.dai_link = byt_rt5640_dais,
.num_links = ARRAY_SIZE(byt_rt5640_dais),
.dapm_widgets = byt_rt5640_widgets,
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 7f55d59..c445312 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -185,6 +185,7 @@ static struct snd_soc_dai_link byt_dailink[] = {
/* SoC card */
static struct snd_soc_card snd_soc_card_byt = {
.name = "baytrailcraudio",
+ .owner = THIS_MODULE,
.dai_link = byt_dailink,
.num_links = ARRAY_SIZE(byt_dailink),
.dapm_widgets = byt_dapm_widgets,
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index 70f8321..49f4869 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -104,21 +104,17 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
static int cht_ti_jack_event(struct notifier_block *nb,
unsigned long event, void *data)
{
-
struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
- struct snd_soc_dai *codec_dai = jack->card->rtd->codec_dai;
- struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_dapm_context *dapm = &jack->card->dapm;
if (event & SND_JACK_MICROPHONE) {
-
- snd_soc_dapm_force_enable_pin(&codec->dapm, "SHDN");
- snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS");
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_force_enable_pin(dapm, "SHDN");
+ snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+ snd_soc_dapm_sync(dapm);
} else {
-
- snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS");
- snd_soc_dapm_disable_pin(&codec->dapm, "SHDN");
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+ snd_soc_dapm_disable_pin(dapm, "SHDN");
+ snd_soc_dapm_sync(dapm);
}
return 0;
@@ -279,6 +275,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
/* SoC card */
static struct snd_soc_card snd_soc_card_cht = {
.name = "chtmax98090",
+ .owner = THIS_MODULE,
.dai_link = cht_dailink,
.num_links = ARRAY_SIZE(cht_dailink),
.aux_dev = &cht_max98090_headset_dev,
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index bdcaf46..7be8461 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -305,6 +305,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
/* SoC card */
static struct snd_soc_card snd_soc_card_chtrt5645 = {
.name = "chtrt5645",
+ .owner = THIS_MODULE,
.dai_link = cht_dailink,
.num_links = ARRAY_SIZE(cht_dailink),
.dapm_widgets = cht_dapm_widgets,
@@ -317,6 +318,7 @@ static struct snd_soc_card snd_soc_card_chtrt5645 = {
static struct snd_soc_card snd_soc_card_chtrt5650 = {
.name = "chtrt5650",
+ .owner = THIS_MODULE,
.dai_link = cht_dailink,
.num_links = ARRAY_SIZE(cht_dailink),
.dapm_widgets = cht_dapm_widgets,
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index 2c9cc5b..23fe040 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -323,6 +323,7 @@ static int cht_resume_post(struct snd_soc_card *card)
/* SoC card */
static struct snd_soc_card snd_soc_card_cht = {
.name = "cherrytrailcraudio",
+ .owner = THIS_MODULE,
.dai_link = cht_dailink,
.num_links = ARRAY_SIZE(cht_dailink),
.dapm_widgets = cht_dapm_widgets,
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h
index 396d545..cbd568e 100644
--- a/sound/soc/intel/common/sst-dsp-priv.h
+++ b/sound/soc/intel/common/sst-dsp-priv.h
@@ -22,6 +22,8 @@
#include <linux/interrupt.h>
#include <linux/firmware.h>
+#include "../skylake/skl-sst-dsp.h"
+
struct sst_mem_block;
struct sst_module;
struct sst_fw;
@@ -258,6 +260,8 @@ struct sst_mem_block {
*/
struct sst_dsp {
+ /* Shared for all platforms */
+
/* runtime */
struct sst_dsp_device *sst_dev;
spinlock_t spinlock; /* IPC locking */
@@ -268,10 +272,6 @@ struct sst_dsp {
int irq;
u32 id;
- /* list of free and used ADSP memory blocks */
- struct list_head used_block_list;
- struct list_head free_block_list;
-
/* operations */
struct sst_ops *ops;
@@ -284,6 +284,12 @@ struct sst_dsp {
/* mailbox */
struct sst_mailbox mailbox;
+ /* HSW/Byt data */
+
+ /* list of free and used ADSP memory blocks */
+ struct list_head used_block_list;
+ struct list_head free_block_list;
+
/* SST FW files loaded and their modules */
struct list_head module_list;
struct list_head fw_list;
@@ -299,6 +305,15 @@ struct sst_dsp {
/* DMA FW loading */
struct sst_dma *dma;
bool fw_use_dma;
+
+ /* SKL data */
+
+ /* To allocate CL dma buffers */
+ struct skl_dsp_loader_ops dsp_ops;
+ struct skl_dsp_fw_ops fw_ops;
+ int sst_state;
+ struct skl_cl_dev cl_dev;
+ u32 intr_status;
};
/* Size optimised DRAM/IRAM memcpy */
diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c
index 64e9421..a627236 100644
--- a/sound/soc/intel/common/sst-dsp.c
+++ b/sound/soc/intel/common/sst-dsp.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/delay.h>
#include "sst-dsp.h"
#include "sst-dsp-priv.h"
@@ -196,6 +197,22 @@ int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked);
+/* This is for registers bits with attribute RWC */
+void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset,
+ u32 mask, u32 value)
+{
+ unsigned int old, new;
+ u32 ret;
+
+ ret = sst_dsp_shim_read_unlocked(sst, offset);
+
+ old = ret;
+ new = (old & (~mask)) | (value & mask);
+
+ sst_dsp_shim_write_unlocked(sst, offset, new);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked);
+
int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
u32 mask, u32 value)
{
@@ -222,6 +239,60 @@ int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64);
+/* This is for registers bits with attribute RWC */
+void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
+ u32 mask, u32 value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sst->spinlock, flags);
+ sst_dsp_shim_update_bits_forced_unlocked(sst, offset, mask, value);
+ spin_unlock_irqrestore(&sst->spinlock, flags);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced);
+
+int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
+ u32 target, u32 timeout, char *operation)
+{
+ int time, ret;
+ u32 reg;
+ bool done = false;
+
+ /*
+ * we will poll for couple of ms using mdelay, if not successful
+ * then go to longer sleep using usleep_range
+ */
+
+ /* check if set state successful */
+ for (time = 0; time < 5; time++) {
+ if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) {
+ done = true;
+ break;
+ }
+ mdelay(1);
+ }
+
+ if (done == false) {
+ /* sleeping in 10ms steps so adjust timeout value */
+ timeout /= 10;
+
+ for (time = 0; time < timeout; time++) {
+ if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target)
+ break;
+
+ usleep_range(5000, 10000);
+ }
+ }
+
+ reg = sst_dsp_shim_read_unlocked(ctx, offset);
+ dev_info(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation,
+ (time < timeout) ? "successful" : "timedout");
+ ret = time < timeout ? 0 : -ETIME;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_register_poll);
+
void sst_dsp_dump(struct sst_dsp *sst)
{
if (sst->ops->dump)
diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h
index 96aeb25..1f45f18 100644
--- a/sound/soc/intel/common/sst-dsp.h
+++ b/sound/soc/intel/common/sst-dsp.h
@@ -230,6 +230,8 @@ void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value);
u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset);
int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
u64 mask, u64 value);
+void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
+ u32 mask, u32 value);
/* SHIM Read / Write Unlocked for callers already holding sst lock */
void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value);
@@ -240,6 +242,8 @@ void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value);
u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset);
int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
u64 mask, u64 value);
+void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset,
+ u32 mask, u32 value);
/* Internal generic low-level SST IO functions - can be overidden */
void sst_shim32_write(void __iomem *addr, u32 offset, u32 value);
@@ -278,6 +282,8 @@ void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes);
+int sst_dsp_register_poll(struct sst_dsp *dsp, u32 offset, u32 mask,
+ u32 expected_value, u32 timeout, char *operation);
/* Debug */
void sst_dsp_dump(struct sst_dsp *sst);
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile
new file mode 100644
index 0000000..27db221
--- /dev/null
+++ b/sound/soc/intel/skylake/Makefile
@@ -0,0 +1,9 @@
+snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o
+
+obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
+
+# Skylake IPC Support
+snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \
+ skl-sst.o
+
+obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
new file mode 100644
index 0000000..826d4fd
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -0,0 +1,884 @@
+/*
+ * skl-message.c - HDA DSP interface for FW registration, Pipe and Module
+ * configurations
+ *
+ * Copyright (C) 2015 Intel Corp
+ * Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
+ * Jeeja KP <jeeja.kp@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
+#include "skl.h"
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+#include "skl-topology.h"
+#include "skl-tplg-interface.h"
+
+static int skl_alloc_dma_buf(struct device *dev,
+ struct snd_dma_buffer *dmab, size_t size)
+{
+ struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+
+ if (!bus)
+ return -ENODEV;
+
+ return bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, size, dmab);
+}
+
+static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab)
+{
+ struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+
+ if (!bus)
+ return -ENODEV;
+
+ bus->io_ops->dma_free_pages(bus, dmab);
+
+ return 0;
+}
+
+int skl_init_dsp(struct skl *skl)
+{
+ void __iomem *mmio_base;
+ struct hdac_ext_bus *ebus = &skl->ebus;
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ int irq = bus->irq;
+ struct skl_dsp_loader_ops loader_ops;
+ int ret;
+
+ loader_ops.alloc_dma_buf = skl_alloc_dma_buf;
+ loader_ops.free_dma_buf = skl_free_dma_buf;
+
+ /* enable ppcap interrupt */
+ snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true);
+ snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true);
+
+ /* read the BAR of the ADSP MMIO */
+ mmio_base = pci_ioremap_bar(skl->pci, 4);
+ if (mmio_base == NULL) {
+ dev_err(bus->dev, "ioremap error\n");
+ return -ENXIO;
+ }
+
+ ret = skl_sst_dsp_init(bus->dev, mmio_base, irq,
+ loader_ops, &skl->skl_sst);
+
+ dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
+
+ return ret;
+}
+
+void skl_free_dsp(struct skl *skl)
+{
+ struct hdac_ext_bus *ebus = &skl->ebus;
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct skl_sst *ctx = skl->skl_sst;
+
+ /* disable ppcap interrupt */
+ snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false);
+
+ skl_sst_dsp_cleanup(bus->dev, ctx);
+ if (ctx->dsp->addr.lpe)
+ iounmap(ctx->dsp->addr.lpe);
+}
+
+int skl_suspend_dsp(struct skl *skl)
+{
+ struct skl_sst *ctx = skl->skl_sst;
+ int ret;
+
+ /* if ppcap is not supported return 0 */
+ if (!skl->ebus.ppcap)
+ return 0;
+
+ ret = skl_dsp_sleep(ctx->dsp);
+ if (ret < 0)
+ return ret;
+
+ /* disable ppcap interrupt */
+ snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false);
+ snd_hdac_ext_bus_ppcap_enable(&skl->ebus, false);
+
+ return 0;
+}
+
+int skl_resume_dsp(struct skl *skl)
+{
+ struct skl_sst *ctx = skl->skl_sst;
+
+ /* if ppcap is not supported return 0 */
+ if (!skl->ebus.ppcap)
+ return 0;
+
+ /* enable ppcap interrupt */
+ snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true);
+ snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true);
+
+ return skl_dsp_wake(ctx->dsp);
+}
+
+enum skl_bitdepth skl_get_bit_depth(int params)
+{
+ switch (params) {
+ case 8:
+ return SKL_DEPTH_8BIT;
+
+ case 16:
+ return SKL_DEPTH_16BIT;
+
+ case 24:
+ return SKL_DEPTH_24BIT;
+
+ case 32:
+ return SKL_DEPTH_32BIT;
+
+ default:
+ return SKL_DEPTH_INVALID;
+
+ }
+}
+
+static u32 skl_create_channel_map(enum skl_ch_cfg ch_cfg)
+{
+ u32 config;
+
+ switch (ch_cfg) {
+ case SKL_CH_CFG_MONO:
+ config = (0xFFFFFFF0 | SKL_CHANNEL_LEFT);
+ break;
+
+ case SKL_CH_CFG_STEREO:
+ config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
+ | (SKL_CHANNEL_RIGHT << 4));
+ break;
+
+ case SKL_CH_CFG_2_1:
+ config = (0xFFFFF000 | SKL_CHANNEL_LEFT
+ | (SKL_CHANNEL_RIGHT << 4)
+ | (SKL_CHANNEL_LFE << 8));
+ break;
+
+ case SKL_CH_CFG_3_0:
+ config = (0xFFFFF000 | SKL_CHANNEL_LEFT
+ | (SKL_CHANNEL_CENTER << 4)
+ | (SKL_CHANNEL_RIGHT << 8));
+ break;
+
+ case SKL_CH_CFG_3_1:
+ config = (0xFFFF0000 | SKL_CHANNEL_LEFT
+ | (SKL_CHANNEL_CENTER << 4)
+ | (SKL_CHANNEL_RIGHT << 8)
+ | (SKL_CHANNEL_LFE << 12));
+ break;
+
+ case SKL_CH_CFG_QUATRO:
+ config = (0xFFFF0000 | SKL_CHANNEL_LEFT
+ | (SKL_CHANNEL_RIGHT << 4)
+ | (SKL_CHANNEL_LEFT_SURROUND << 8)
+ | (SKL_CHANNEL_RIGHT_SURROUND << 12));
+ break;
+
+ case SKL_CH_CFG_4_0:
+ config = (0xFFFF0000 | SKL_CHANNEL_LEFT
+ | (SKL_CHANNEL_CENTER << 4)
+ | (SKL_CHANNEL_RIGHT << 8)
+ | (SKL_CHANNEL_CENTER_SURROUND << 12));
+ break;
+
+ case SKL_CH_CFG_5_0:
+ config = (0xFFF00000 | SKL_CHANNEL_LEFT
+ | (SKL_CHANNEL_CENTER << 4)
+ | (SKL_CHANNEL_RIGHT << 8)
+ | (SKL_CHANNEL_LEFT_SURROUND << 12)
+ | (SKL_CHANNEL_RIGHT_SURROUND << 16));
+ break;
+
+ case SKL_CH_CFG_5_1:
+ config = (0xFF000000 | SKL_CHANNEL_CENTER
+ | (SKL_CHANNEL_LEFT << 4)
+ | (SKL_CHANNEL_RIGHT << 8)
+ | (SKL_CHANNEL_LEFT_SURROUND << 12)
+ | (SKL_CHANNEL_RIGHT_SURROUND << 16)
+ | (SKL_CHANNEL_LFE << 20));
+ break;
+
+ case SKL_CH_CFG_DUAL_MONO:
+ config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
+ | (SKL_CHANNEL_LEFT << 4));
+ break;
+
+ case SKL_CH_CFG_I2S_DUAL_STEREO_0:
+ config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
+ | (SKL_CHANNEL_RIGHT << 4));
+ break;
+
+ case SKL_CH_CFG_I2S_DUAL_STEREO_1:
+ config = (0xFFFF00FF | (SKL_CHANNEL_LEFT << 8)
+ | (SKL_CHANNEL_RIGHT << 12));
+ break;
+
+ default:
+ config = 0xFFFFFFFF;
+ break;
+
+ }
+
+ return config;
+}
+
+/*
+ * Each module in DSP expects a base module configuration, which consists of
+ * PCM format information, which we calculate in driver and resource values
+ * which are read from widget information passed through topology binary
+ * This is send when we create a module with INIT_INSTANCE IPC msg
+ */
+static void skl_set_base_module_format(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig,
+ struct skl_base_cfg *base_cfg)
+{
+ struct skl_module_fmt *format = &mconfig->in_fmt;
+
+ base_cfg->audio_fmt.number_of_channels = (u8)format->channels;
+
+ base_cfg->audio_fmt.s_freq = format->s_freq;
+ base_cfg->audio_fmt.bit_depth = format->bit_depth;
+ base_cfg->audio_fmt.valid_bit_depth = format->valid_bit_depth;
+ base_cfg->audio_fmt.ch_cfg = format->ch_cfg;
+
+ dev_dbg(ctx->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n",
+ format->bit_depth, format->valid_bit_depth,
+ format->ch_cfg);
+
+ base_cfg->audio_fmt.channel_map = skl_create_channel_map(
+ base_cfg->audio_fmt.ch_cfg);
+
+ base_cfg->audio_fmt.interleaving = SKL_INTERLEAVING_PER_CHANNEL;
+
+ base_cfg->cps = mconfig->mcps;
+ base_cfg->ibs = mconfig->ibs;
+ base_cfg->obs = mconfig->obs;
+}
+
+/*
+ * Copies copier capabilities into copier module and updates copier module
+ * config size.
+ */
+static void skl_copy_copier_caps(struct skl_module_cfg *mconfig,
+ struct skl_cpr_cfg *cpr_mconfig)
+{
+ if (mconfig->formats_config.caps_size == 0)
+ return;
+
+ memcpy(cpr_mconfig->gtw_cfg.config_data,
+ mconfig->formats_config.caps,
+ mconfig->formats_config.caps_size);
+
+ cpr_mconfig->gtw_cfg.config_length =
+ (mconfig->formats_config.caps_size) / 4;
+}
+
+/*
+ * Calculate the gatewat settings required for copier module, type of
+ * gateway and index of gateway to use
+ */
+static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig,
+ struct skl_cpr_cfg *cpr_mconfig)
+{
+ union skl_connector_node_id node_id = {0};
+ struct skl_pipe_params *params = mconfig->pipe->p_params;
+
+ switch (mconfig->dev_type) {
+ case SKL_DEVICE_BT:
+ node_id.node.dma_type =
+ (SKL_CONN_SOURCE == mconfig->hw_conn_type) ?
+ SKL_DMA_I2S_LINK_OUTPUT_CLASS :
+ SKL_DMA_I2S_LINK_INPUT_CLASS;
+ node_id.node.vindex = params->host_dma_id +
+ (mconfig->vbus_id << 3);
+ break;
+
+ case SKL_DEVICE_I2S:
+ node_id.node.dma_type =
+ (SKL_CONN_SOURCE == mconfig->hw_conn_type) ?
+ SKL_DMA_I2S_LINK_OUTPUT_CLASS :
+ SKL_DMA_I2S_LINK_INPUT_CLASS;
+ node_id.node.vindex = params->host_dma_id +
+ (mconfig->time_slot << 1) +
+ (mconfig->vbus_id << 3);
+ break;
+
+ case SKL_DEVICE_DMIC:
+ node_id.node.dma_type = SKL_DMA_DMIC_LINK_INPUT_CLASS;
+ node_id.node.vindex = mconfig->vbus_id +
+ (mconfig->time_slot);
+ break;
+
+ case SKL_DEVICE_HDALINK:
+ node_id.node.dma_type =
+ (SKL_CONN_SOURCE == mconfig->hw_conn_type) ?
+ SKL_DMA_HDA_LINK_OUTPUT_CLASS :
+ SKL_DMA_HDA_LINK_INPUT_CLASS;
+ node_id.node.vindex = params->link_dma_id;
+ break;
+
+ default:
+ node_id.node.dma_type =
+ (SKL_CONN_SOURCE == mconfig->hw_conn_type) ?
+ SKL_DMA_HDA_HOST_OUTPUT_CLASS :
+ SKL_DMA_HDA_HOST_INPUT_CLASS;
+ node_id.node.vindex = params->host_dma_id;
+ break;
+ }
+
+ cpr_mconfig->gtw_cfg.node_id = node_id.val;
+
+ if (SKL_CONN_SOURCE == mconfig->hw_conn_type)
+ cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs;
+ else
+ cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->ibs;
+
+ cpr_mconfig->cpr_feature_mask = 0;
+ cpr_mconfig->gtw_cfg.config_length = 0;
+
+ skl_copy_copier_caps(mconfig, cpr_mconfig);
+}
+
+static void skl_setup_out_format(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig,
+ struct skl_audio_data_format *out_fmt)
+{
+ struct skl_module_fmt *format = &mconfig->out_fmt;
+
+ out_fmt->number_of_channels = (u8)format->channels;
+ out_fmt->s_freq = format->s_freq;
+ out_fmt->bit_depth = format->bit_depth;
+ out_fmt->valid_bit_depth = format->valid_bit_depth;
+ out_fmt->ch_cfg = format->ch_cfg;
+
+ out_fmt->channel_map = skl_create_channel_map(out_fmt->ch_cfg);
+ out_fmt->interleaving = SKL_INTERLEAVING_PER_CHANNEL;
+
+ dev_dbg(ctx->dev, "copier out format chan=%d fre=%d bitdepth=%d\n",
+ out_fmt->number_of_channels, format->s_freq, format->bit_depth);
+}
+
+/*
+ * DSP needs SRC module for frequency conversion, SRC takes base module
+ * configuration and the target frequency as extra parameter passed as src
+ * config
+ */
+static void skl_set_src_format(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig,
+ struct skl_src_module_cfg *src_mconfig)
+{
+ struct skl_module_fmt *fmt = &mconfig->out_fmt;
+
+ skl_set_base_module_format(ctx, mconfig,
+ (struct skl_base_cfg *)src_mconfig);
+
+ src_mconfig->src_cfg = fmt->s_freq;
+}
+
+/*
+ * DSP needs updown module to do channel conversion. updown module take base
+ * module configuration and channel configuration
+ * It also take coefficients and now we have defaults applied here
+ */
+static void skl_set_updown_mixer_format(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig,
+ struct skl_up_down_mixer_cfg *mixer_mconfig)
+{
+ struct skl_module_fmt *fmt = &mconfig->out_fmt;
+ int i = 0;
+
+ skl_set_base_module_format(ctx, mconfig,
+ (struct skl_base_cfg *)mixer_mconfig);
+ mixer_mconfig->out_ch_cfg = fmt->ch_cfg;
+
+ /* Select F/W default coefficient */
+ mixer_mconfig->coeff_sel = 0x0;
+
+ /* User coeff, don't care since we are selecting F/W defaults */
+ for (i = 0; i < UP_DOWN_MIXER_MAX_COEFF; i++)
+ mixer_mconfig->coeff[i] = 0xDEADBEEF;
+}
+
+/*
+ * 'copier' is DSP internal module which copies data from Host DMA (HDA host
+ * dma) or link (hda link, SSP, PDM)
+ * Here we calculate the copier module parameters, like PCM format, output
+ * format, gateway settings
+ * copier_module_config is sent as input buffer with INIT_INSTANCE IPC msg
+ */
+static void skl_set_copier_format(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig,
+ struct skl_cpr_cfg *cpr_mconfig)
+{
+ struct skl_audio_data_format *out_fmt = &cpr_mconfig->out_fmt;
+ struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)cpr_mconfig;
+
+ skl_set_base_module_format(ctx, mconfig, base_cfg);
+
+ skl_setup_out_format(ctx, mconfig, out_fmt);
+ skl_setup_cpr_gateway_cfg(ctx, mconfig, cpr_mconfig);
+}
+
+static u16 skl_get_module_param_size(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig)
+{
+ u16 param_size;
+
+ switch (mconfig->m_type) {
+ case SKL_MODULE_TYPE_COPIER:
+ param_size = sizeof(struct skl_cpr_cfg);
+ param_size += mconfig->formats_config.caps_size;
+ return param_size;
+
+ case SKL_MODULE_TYPE_SRCINT:
+ return sizeof(struct skl_src_module_cfg);
+
+ case SKL_MODULE_TYPE_UPDWMIX:
+ return sizeof(struct skl_up_down_mixer_cfg);
+
+ default:
+ /*
+ * return only base cfg when no specific module type is
+ * specified
+ */
+ return sizeof(struct skl_base_cfg);
+ }
+
+ return 0;
+}
+
+/*
+ * DSP firmware supports various modules like copier, SRC, updown etc.
+ * These modules required various parameters to be calculated and sent for
+ * the module initialization to DSP. By default a generic module needs only
+ * base module format configuration
+ */
+
+static int skl_set_module_format(struct skl_sst *ctx,
+ struct skl_module_cfg *module_config,
+ u16 *module_config_size,
+ void **param_data)
+{
+ u16 param_size;
+
+ param_size = skl_get_module_param_size(ctx, module_config);
+
+ *param_data = kzalloc(param_size, GFP_KERNEL);
+ if (NULL == *param_data)
+ return -ENOMEM;
+
+ *module_config_size = param_size;
+
+ switch (module_config->m_type) {
+ case SKL_MODULE_TYPE_COPIER:
+ skl_set_copier_format(ctx, module_config, *param_data);
+ break;
+
+ case SKL_MODULE_TYPE_SRCINT:
+ skl_set_src_format(ctx, module_config, *param_data);
+ break;
+
+ case SKL_MODULE_TYPE_UPDWMIX:
+ skl_set_updown_mixer_format(ctx, module_config, *param_data);
+ break;
+
+ default:
+ skl_set_base_module_format(ctx, module_config, *param_data);
+ break;
+
+ }
+
+ dev_dbg(ctx->dev, "Module type=%d config size: %d bytes\n",
+ module_config->id.module_id, param_size);
+ print_hex_dump(KERN_DEBUG, "Module params:", DUMP_PREFIX_OFFSET, 8, 4,
+ *param_data, param_size, false);
+ return 0;
+}
+
+static int skl_get_queue_index(struct skl_module_pin *mpin,
+ struct skl_module_inst_id id, int max)
+{
+ int i;
+
+ for (i = 0; i < max; i++) {
+ if (mpin[i].id.module_id == id.module_id &&
+ mpin[i].id.instance_id == id.instance_id)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Allocates queue for each module.
+ * if dynamic, the pin_index is allocated 0 to max_pin.
+ * In static, the pin_index is fixed based on module_id and instance id
+ */
+static int skl_alloc_queue(struct skl_module_pin *mpin,
+ struct skl_module_inst_id id, int max)
+{
+ int i;
+
+ /*
+ * if pin in dynamic, find first free pin
+ * otherwise find match module and instance id pin as topology will
+ * ensure a unique pin is assigned to this so no need to
+ * allocate/free
+ */
+ for (i = 0; i < max; i++) {
+ if (mpin[i].is_dynamic) {
+ if (!mpin[i].in_use) {
+ mpin[i].in_use = true;
+ mpin[i].id.module_id = id.module_id;
+ mpin[i].id.instance_id = id.instance_id;
+ return i;
+ }
+ } else {
+ if (mpin[i].id.module_id == id.module_id &&
+ mpin[i].id.instance_id == id.instance_id)
+ return i;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static void skl_free_queue(struct skl_module_pin *mpin, int q_index)
+{
+ if (mpin[q_index].is_dynamic) {
+ mpin[q_index].in_use = false;
+ mpin[q_index].id.module_id = 0;
+ mpin[q_index].id.instance_id = 0;
+ }
+}
+
+/*
+ * A module needs to be instanataited in DSP. A mdoule is present in a
+ * collection of module referred as a PIPE.
+ * We first calculate the module format, based on module type and then
+ * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper
+ */
+int skl_init_module(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig, char *param)
+{
+ u16 module_config_size = 0;
+ void *param_data = NULL;
+ int ret;
+ struct skl_ipc_init_instance_msg msg;
+
+ dev_dbg(ctx->dev, "%s: module_id = %d instance=%d\n", __func__,
+ mconfig->id.module_id, mconfig->id.instance_id);
+
+ if (mconfig->pipe->state != SKL_PIPE_CREATED) {
+ dev_err(ctx->dev, "Pipe not created state= %d pipe_id= %d\n",
+ mconfig->pipe->state, mconfig->pipe->ppl_id);
+ return -EIO;
+ }
+
+ ret = skl_set_module_format(ctx, mconfig,
+ &module_config_size, &param_data);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to set module format ret=%d\n", ret);
+ return ret;
+ }
+
+ msg.module_id = mconfig->id.module_id;
+ msg.instance_id = mconfig->id.instance_id;
+ msg.ppl_instance_id = mconfig->pipe->ppl_id;
+ msg.param_data_size = module_config_size;
+ msg.core_id = mconfig->core_id;
+
+ ret = skl_ipc_init_instance(&ctx->ipc, &msg, param_data);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to init instance ret=%d\n", ret);
+ kfree(param_data);
+ return ret;
+ }
+ mconfig->m_state = SKL_MODULE_INIT_DONE;
+
+ return ret;
+}
+
+static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg
+ *src_module, struct skl_module_cfg *dst_module)
+{
+ dev_dbg(ctx->dev, "%s: src module_id = %d src_instance=%d\n",
+ __func__, src_module->id.module_id, src_module->id.instance_id);
+ dev_dbg(ctx->dev, "%s: dst_module=%d dst_instacne=%d\n", __func__,
+ dst_module->id.module_id, dst_module->id.instance_id);
+
+ dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n",
+ src_module->m_state, dst_module->m_state);
+}
+
+/*
+ * On module freeup, we need to unbind the module with modules
+ * it is already bind.
+ * Find the pin allocated and unbind then using bind_unbind IPC
+ */
+int skl_unbind_modules(struct skl_sst *ctx,
+ struct skl_module_cfg *src_mcfg,
+ struct skl_module_cfg *dst_mcfg)
+{
+ int ret;
+ struct skl_ipc_bind_unbind_msg msg;
+ struct skl_module_inst_id src_id = src_mcfg->id;
+ struct skl_module_inst_id dst_id = dst_mcfg->id;
+ int in_max = dst_mcfg->max_in_queue;
+ int out_max = src_mcfg->max_out_queue;
+ int src_index, dst_index;
+
+ skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
+
+ if (src_mcfg->m_state != SKL_MODULE_BIND_DONE)
+ return 0;
+
+ /*
+ * if intra module unbind, check if both modules are BIND,
+ * then send unbind
+ */
+ if ((src_mcfg->pipe->ppl_id != dst_mcfg->pipe->ppl_id) &&
+ dst_mcfg->m_state != SKL_MODULE_BIND_DONE)
+ return 0;
+ else if (src_mcfg->m_state < SKL_MODULE_INIT_DONE &&
+ dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
+ return 0;
+
+ /* get src queue index */
+ src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max);
+ if (src_index < 0)
+ return -EINVAL;
+
+ msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index;
+
+ /* get dst queue index */
+ dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max);
+ if (dst_index < 0)
+ return -EINVAL;
+
+ msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index;
+
+ msg.module_id = src_mcfg->id.module_id;
+ msg.instance_id = src_mcfg->id.instance_id;
+ msg.dst_module_id = dst_mcfg->id.module_id;
+ msg.dst_instance_id = dst_mcfg->id.instance_id;
+ msg.bind = false;
+
+ ret = skl_ipc_bind_unbind(&ctx->ipc, &msg);
+ if (!ret) {
+ src_mcfg->m_state = SKL_MODULE_UNINIT;
+ /* free queue only if unbind is success */
+ skl_free_queue(src_mcfg->m_out_pin, src_index);
+ skl_free_queue(dst_mcfg->m_in_pin, dst_index);
+ }
+
+ return ret;
+}
+
+/*
+ * Once a module is instantiated it need to be 'bind' with other modules in
+ * the pipeline. For binding we need to find the module pins which are bind
+ * together
+ * This function finds the pins and then sends bund_unbind IPC message to
+ * DSP using IPC helper
+ */
+int skl_bind_modules(struct skl_sst *ctx,
+ struct skl_module_cfg *src_mcfg,
+ struct skl_module_cfg *dst_mcfg)
+{
+ int ret;
+ struct skl_ipc_bind_unbind_msg msg;
+ struct skl_module_inst_id src_id = src_mcfg->id;
+ struct skl_module_inst_id dst_id = dst_mcfg->id;
+ int in_max = dst_mcfg->max_in_queue;
+ int out_max = src_mcfg->max_out_queue;
+ int src_index, dst_index;
+
+ skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
+
+ if (src_mcfg->m_state < SKL_MODULE_INIT_DONE &&
+ dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
+ return 0;
+
+ src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_id, out_max);
+ if (src_index < 0)
+ return -EINVAL;
+
+ msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index;
+ dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_id, in_max);
+ if (dst_index < 0) {
+ skl_free_queue(src_mcfg->m_out_pin, src_index);
+ return -EINVAL;
+ }
+
+ msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index;
+
+ dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n",
+ msg.src_queue, msg.dst_queue);
+
+ msg.module_id = src_mcfg->id.module_id;
+ msg.instance_id = src_mcfg->id.instance_id;
+ msg.dst_module_id = dst_mcfg->id.module_id;
+ msg.dst_instance_id = dst_mcfg->id.instance_id;
+ msg.bind = true;
+
+ ret = skl_ipc_bind_unbind(&ctx->ipc, &msg);
+
+ if (!ret) {
+ src_mcfg->m_state = SKL_MODULE_BIND_DONE;
+ } else {
+ /* error case , if IPC fails, clear the queue index */
+ skl_free_queue(src_mcfg->m_out_pin, src_index);
+ skl_free_queue(dst_mcfg->m_in_pin, dst_index);
+ }
+
+ return ret;
+}
+
+static int skl_set_pipe_state(struct skl_sst *ctx, struct skl_pipe *pipe,
+ enum skl_ipc_pipeline_state state)
+{
+ dev_dbg(ctx->dev, "%s: pipe_satate = %d\n", __func__, state);
+
+ return skl_ipc_set_pipeline_state(&ctx->ipc, pipe->ppl_id, state);
+}
+
+/*
+ * A pipeline is a collection of modules. Before a module in instantiated a
+ * pipeline needs to be created for it.
+ * This function creates pipeline, by sending create pipeline IPC messages
+ * to FW
+ */
+int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe)
+{
+ int ret;
+
+ dev_dbg(ctx->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id);
+
+ ret = skl_ipc_create_pipeline(&ctx->ipc, pipe->memory_pages,
+ pipe->pipe_priority, pipe->ppl_id);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to create pipeline\n");
+ return ret;
+ }
+
+ pipe->state = SKL_PIPE_CREATED;
+
+ return 0;
+}
+
+/*
+ * A pipeline needs to be deleted on cleanup. If a pipeline is running, then
+ * pause the pipeline first and then delete it
+ * The pipe delete is done by sending delete pipeline IPC. DSP will stop the
+ * DMA engines and releases resources
+ */
+int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
+{
+ int ret;
+
+ dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id);
+
+ /* If pipe is not started, do not try to stop the pipe in FW. */
+ if (pipe->state > SKL_PIPE_STARTED) {
+ ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to stop pipeline\n");
+ return ret;
+ }
+
+ pipe->state = SKL_PIPE_PAUSED;
+ } else {
+ /* If pipe was not created in FW, do not try to delete it */
+ if (pipe->state < SKL_PIPE_CREATED)
+ return 0;
+
+ ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id);
+ if (ret < 0)
+ dev_err(ctx->dev, "Failed to delete pipeline\n");
+ }
+
+ return ret;
+}
+
+/*
+ * A pipeline is also a scheduling entity in DSP which can be run, stopped
+ * For processing data the pipe need to be run by sending IPC set pipe state
+ * to DSP
+ */
+int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
+{
+ int ret;
+
+ dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id);
+
+ /* If pipe was not created in FW, do not try to pause or delete */
+ if (pipe->state < SKL_PIPE_CREATED)
+ return 0;
+
+ /* Pipe has to be paused before it is started */
+ ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to pause pipe\n");
+ return ret;
+ }
+
+ pipe->state = SKL_PIPE_PAUSED;
+
+ ret = skl_set_pipe_state(ctx, pipe, PPL_RUNNING);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to start pipe\n");
+ return ret;
+ }
+
+ pipe->state = SKL_PIPE_STARTED;
+
+ return 0;
+}
+
+/*
+ * Stop the pipeline by sending set pipe state IPC
+ * DSP doesnt implement stop so we always send pause message
+ */
+int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
+{
+ int ret;
+
+ dev_dbg(ctx->dev, "In %s pipe=%d\n", __func__, pipe->ppl_id);
+
+ /* If pipe was not created in FW, do not try to pause or delete */
+ if (pipe->state < SKL_PIPE_PAUSED)
+ return 0;
+
+ ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED);
+ if (ret < 0) {
+ dev_dbg(ctx->dev, "Failed to stop pipe\n");
+ return ret;
+ }
+
+ pipe->state = SKL_PIPE_CREATED;
+
+ return 0;
+}
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
new file mode 100644
index 0000000..13036b1
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -0,0 +1,140 @@
+/*
+ * skl-nhlt.c - Intel SKL Platform NHLT parsing
+ *
+ * Copyright (C) 2015 Intel Corp
+ * Author: Sanjiv Kumar <sanjiv.kumar@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+#include "skl.h"
+
+/* Unique identification for getting NHLT blobs */
+static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45,
+ 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53};
+
+#define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS"
+
+void __iomem *skl_nhlt_init(struct device *dev)
+{
+ acpi_handle handle;
+ union acpi_object *obj;
+ struct nhlt_resource_desc *nhlt_ptr = NULL;
+
+ if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) {
+ dev_err(dev, "Requested NHLT device not found\n");
+ return NULL;
+ }
+
+ obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL);
+ if (obj && obj->type == ACPI_TYPE_BUFFER) {
+ nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer;
+
+ return ioremap_cache(nhlt_ptr->min_addr, nhlt_ptr->length);
+ }
+
+ dev_err(dev, "device specific method to extract NHLT blob failed\n");
+ return NULL;
+}
+
+void skl_nhlt_free(void __iomem *addr)
+{
+ iounmap(addr);
+ addr = NULL;
+}
+
+static struct nhlt_specific_cfg *skl_get_specific_cfg(
+ struct device *dev, struct nhlt_fmt *fmt,
+ u8 no_ch, u32 rate, u16 bps)
+{
+ struct nhlt_specific_cfg *sp_config;
+ struct wav_fmt *wfmt;
+ struct nhlt_fmt_cfg *fmt_config = fmt->fmt_config;
+ int i;
+
+ dev_dbg(dev, "Format count =%d\n", fmt->fmt_count);
+
+ for (i = 0; i < fmt->fmt_count; i++) {
+ wfmt = &fmt_config->fmt_ext.fmt;
+ dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels,
+ wfmt->bits_per_sample, wfmt->samples_per_sec);
+ if (wfmt->channels == no_ch && wfmt->samples_per_sec == rate &&
+ wfmt->bits_per_sample == bps) {
+ sp_config = &fmt_config->config;
+
+ return sp_config;
+ }
+
+ fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps +
+ fmt_config->config.size);
+ }
+
+ return NULL;
+}
+
+static void dump_config(struct device *dev, u32 instance_id, u8 linktype,
+ u8 s_fmt, u8 num_channels, u32 s_rate, u8 dirn, u16 bps)
+{
+ dev_dbg(dev, "Input configuration\n");
+ dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", num_channels, s_fmt, s_rate);
+ dev_dbg(dev, "vbus_id=%d link_type=%d\n", instance_id, linktype);
+ dev_dbg(dev, "bits_per_sample=%d\n", bps);
+}
+
+static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
+ u32 instance_id, u8 link_type, u8 dirn)
+{
+ dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d\n",
+ epnt->virtual_bus_id, epnt->linktype, epnt->direction);
+
+ if ((epnt->virtual_bus_id == instance_id) &&
+ (epnt->linktype == link_type) &&
+ (epnt->direction == dirn))
+ return true;
+ else
+ return false;
+}
+
+struct nhlt_specific_cfg
+*skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type,
+ u8 s_fmt, u8 num_ch, u32 s_rate, u8 dirn)
+{
+ struct nhlt_fmt *fmt;
+ struct nhlt_endpoint *epnt;
+ struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+ struct device *dev = bus->dev;
+ struct nhlt_specific_cfg *sp_config;
+ struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
+ u16 bps = num_ch * s_fmt;
+ u8 j;
+
+ dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps);
+
+ epnt = (struct nhlt_endpoint *)nhlt->desc;
+
+ dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count);
+
+ for (j = 0; j < nhlt->endpoint_count; j++) {
+ if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) {
+ fmt = (struct nhlt_fmt *)(epnt->config.caps +
+ epnt->config.size);
+ sp_config = skl_get_specific_cfg(dev, fmt, num_ch, s_rate, bps);
+ if (sp_config)
+ return sp_config;
+ }
+
+ epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
+ }
+
+ return NULL;
+}
diff --git a/sound/soc/intel/skylake/skl-nhlt.h b/sound/soc/intel/skylake/skl-nhlt.h
new file mode 100644
index 0000000..3769f9f
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-nhlt.h
@@ -0,0 +1,106 @@
+/*
+ * skl-nhlt.h - Intel HDA Platform NHLT header
+ *
+ * Copyright (C) 2015 Intel Corp
+ * Author: Sanjiv Kumar <sanjiv.kumar@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+#ifndef __SKL_NHLT_H__
+#define __SKL_NHLT_H__
+
+#include <linux/acpi.h>
+
+struct wav_fmt {
+ u16 fmt_tag;
+ u16 channels;
+ u32 samples_per_sec;
+ u32 avg_bytes_per_sec;
+ u16 block_align;
+ u16 bits_per_sample;
+ u16 cb_size;
+} __packed;
+
+struct wav_fmt_ext {
+ struct wav_fmt fmt;
+ union samples {
+ u16 valid_bits_per_sample;
+ u16 samples_per_block;
+ u16 reserved;
+ } sample;
+ u32 channel_mask;
+ u8 sub_fmt[16];
+} __packed;
+
+enum nhlt_link_type {
+ NHLT_LINK_HDA = 0,
+ NHLT_LINK_DSP = 1,
+ NHLT_LINK_DMIC = 2,
+ NHLT_LINK_SSP = 3,
+ NHLT_LINK_INVALID
+};
+
+enum nhlt_device_type {
+ NHLT_DEVICE_BT = 0,
+ NHLT_DEVICE_DMIC = 1,
+ NHLT_DEVICE_I2S = 4,
+ NHLT_DEVICE_INVALID
+};
+
+struct nhlt_specific_cfg {
+ u32 size;
+ u8 caps[0];
+} __packed;
+
+struct nhlt_fmt_cfg {
+ struct wav_fmt_ext fmt_ext;
+ struct nhlt_specific_cfg config;
+} __packed;
+
+struct nhlt_fmt {
+ u8 fmt_count;
+ struct nhlt_fmt_cfg fmt_config[0];
+} __packed;
+
+struct nhlt_endpoint {
+ u32 length;
+ u8 linktype;
+ u8 instance_id;
+ u16 vendor_id;
+ u16 device_id;
+ u16 revision_id;
+ u32 subsystem_id;
+ u8 device_type;
+ u8 direction;
+ u8 virtual_bus_id;
+ struct nhlt_specific_cfg config;
+} __packed;
+
+struct nhlt_acpi_table {
+ struct acpi_table_header header;
+ u8 endpoint_count;
+ struct nhlt_endpoint desc[0];
+} __packed;
+
+struct nhlt_resource_desc {
+ u32 extra;
+ u16 flags;
+ u64 addr_spc_gra;
+ u64 min_addr;
+ u64 max_addr;
+ u64 addr_trans_offset;
+ u64 length;
+} __packed;
+
+#endif
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
new file mode 100644
index 0000000..7d617bf
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -0,0 +1,916 @@
+/*
+ * skl-pcm.c -ASoC HDA Platform driver file implementing PCM functionality
+ *
+ * Copyright (C) 2014-2015 Intel Corp
+ * Author: Jeeja KP <jeeja.kp@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "skl.h"
+
+#define HDA_MONO 1
+#define HDA_STEREO 2
+
+static struct snd_pcm_hardware azx_pcm_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_SYNC_START |
+ SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */
+ SNDRV_PCM_INFO_HAS_LINK_ATIME |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = AZX_MAX_BUF_SIZE,
+ .period_bytes_min = 128,
+ .period_bytes_max = AZX_MAX_BUF_SIZE / 2,
+ .periods_min = 2,
+ .periods_max = AZX_MAX_FRAG,
+ .fifo_size = 0,
+};
+
+static inline
+struct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream)
+{
+ return substream->runtime->private_data;
+}
+
+static struct hdac_ext_bus *get_bus_ctx(struct snd_pcm_substream *substream)
+{
+ struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+ struct hdac_stream *hstream = hdac_stream(stream);
+ struct hdac_bus *bus = hstream->bus;
+
+ return hbus_to_ebus(bus);
+}
+
+static int skl_substream_alloc_pages(struct hdac_ext_bus *ebus,
+ struct snd_pcm_substream *substream,
+ size_t size)
+{
+ struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+
+ hdac_stream(stream)->bufsize = 0;
+ hdac_stream(stream)->period_bytes = 0;
+ hdac_stream(stream)->format_val = 0;
+
+ return snd_pcm_lib_malloc_pages(substream, size);
+}
+
+static int skl_substream_free_pages(struct hdac_bus *bus,
+ struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus,
+ struct snd_pcm_runtime *runtime)
+{
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+ /* avoid wrap-around with wall-clock */
+ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
+ 20, 178000000);
+}
+
+static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus)
+{
+ if (ebus->ppcap)
+ return HDAC_EXT_STREAM_TYPE_HOST;
+ else
+ return HDAC_EXT_STREAM_TYPE_COUPLED;
+}
+
+static int skl_pcm_open(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_ext_stream *stream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct skl_dma_params *dma_params;
+ int ret;
+
+ dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
+ ret = pm_runtime_get_sync(dai->dev);
+ if (ret)
+ return ret;
+
+ stream = snd_hdac_ext_stream_assign(ebus, substream,
+ skl_get_host_stream_type(ebus));
+ if (stream == NULL)
+ return -EBUSY;
+
+ skl_set_pcm_constrains(ebus, runtime);
+
+ /*
+ * disable WALLCLOCK timestamps for capture streams
+ * until we figure out how to handle digital inputs
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */
+ runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME;
+ }
+
+ runtime->private_data = stream;
+
+ dma_params = kzalloc(sizeof(*dma_params), GFP_KERNEL);
+ if (!dma_params)
+ return -ENOMEM;
+
+ dma_params->stream_tag = hdac_stream(stream)->stream_tag;
+ snd_soc_dai_set_dma_data(dai, substream, dma_params);
+
+ dev_dbg(dai->dev, "stream tag set in dma params=%d\n",
+ dma_params->stream_tag);
+ snd_pcm_set_sync(substream);
+
+ return 0;
+}
+
+static int skl_get_format(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct skl_dma_params *dma_params;
+ struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ int format_val = 0;
+
+ if (ebus->ppcap) {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ format_val = snd_hdac_calc_stream_format(runtime->rate,
+ runtime->channels,
+ runtime->format,
+ 32, 0);
+ } else {
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ dma_params = snd_soc_dai_get_dma_data(codec_dai, substream);
+ if (dma_params)
+ format_val = dma_params->format;
+ }
+
+ return format_val;
+}
+
+static int skl_pcm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+ unsigned int format_val;
+ int err;
+
+ dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
+ if (hdac_stream(stream)->prepared) {
+ dev_dbg(dai->dev, "already stream is prepared - returning\n");
+ return 0;
+ }
+
+ format_val = skl_get_format(substream, dai);
+ dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n",
+ hdac_stream(stream)->stream_tag, format_val);
+ snd_hdac_stream_reset(hdac_stream(stream));
+
+ err = snd_hdac_stream_set_params(hdac_stream(stream), format_val);
+ if (err < 0)
+ return err;
+
+ err = snd_hdac_stream_setup(hdac_stream(stream));
+ if (err < 0)
+ return err;
+
+ hdac_stream(stream)->prepared = 1;
+
+ return err;
+}
+
+static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int ret, dma_id;
+
+ dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
+ ret = skl_substream_alloc_pages(ebus, substream,
+ params_buffer_bytes(params));
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n",
+ runtime->rate, runtime->channels, runtime->format);
+
+ dma_id = hdac_stream(stream)->stream_tag - 1;
+ dev_dbg(dai->dev, "dma_id=%d\n", dma_id);
+
+ return 0;
+}
+
+static void skl_pcm_close(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+ struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct skl_dma_params *dma_params = NULL;
+
+ dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
+
+ snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(ebus));
+
+ dma_params = snd_soc_dai_get_dma_data(dai, substream);
+ /*
+ * now we should set this to NULL as we are freeing by the
+ * dma_params
+ */
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+
+ pm_runtime_mark_last_busy(dai->dev);
+ pm_runtime_put_autosuspend(dai->dev);
+ kfree(dma_params);
+}
+
+static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+
+ dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
+
+ snd_hdac_stream_cleanup(hdac_stream(stream));
+ hdac_stream(stream)->prepared = 0;
+
+ return skl_substream_free_pages(ebus_to_hbus(ebus), substream);
+}
+
+static int skl_link_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_ext_stream *link_dev;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct skl_dma_params *dma_params;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int dma_id;
+
+ pr_debug("%s\n", __func__);
+ link_dev = snd_hdac_ext_stream_assign(ebus, substream,
+ HDAC_EXT_STREAM_TYPE_LINK);
+ if (!link_dev)
+ return -EBUSY;
+
+ snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
+
+ /* set the stream tag in the codec dai dma params */
+ dma_params = (struct skl_dma_params *)
+ snd_soc_dai_get_dma_data(codec_dai, substream);
+ if (dma_params)
+ dma_params->stream_tag = hdac_stream(link_dev)->stream_tag;
+ snd_soc_dai_set_dma_data(codec_dai, substream, (void *)dma_params);
+ dma_id = hdac_stream(link_dev)->stream_tag - 1;
+
+ return 0;
+}
+
+static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_ext_stream *link_dev =
+ snd_soc_dai_get_dma_data(dai, substream);
+ unsigned int format_val = 0;
+ struct skl_dma_params *dma_params;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_pcm_hw_params *params;
+ struct snd_interval *channels, *rate;
+ struct hdac_ext_link *link;
+
+ dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
+ if (link_dev->link_prepared) {
+ dev_dbg(dai->dev, "already stream is prepared - returning\n");
+ return 0;
+ }
+ params = devm_kzalloc(dai->dev, sizeof(*params), GFP_KERNEL);
+ if (params == NULL)
+ return -ENOMEM;
+
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ channels->min = channels->max = substream->runtime->channels;
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ rate->min = rate->max = substream->runtime->rate;
+ snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
+ SNDRV_PCM_HW_PARAM_FIRST_MASK],
+ substream->runtime->format);
+
+
+ dma_params = (struct skl_dma_params *)
+ snd_soc_dai_get_dma_data(codec_dai, substream);
+ if (dma_params)
+ format_val = dma_params->format;
+ dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n",
+ hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name);
+
+ snd_hdac_ext_link_stream_reset(link_dev);
+
+ snd_hdac_ext_link_stream_setup(link_dev, format_val);
+
+ link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
+ if (!link)
+ return -EINVAL;
+
+ snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag);
+ link_dev->link_prepared = 1;
+
+ return 0;
+}
+
+static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct hdac_ext_stream *link_dev =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ snd_hdac_ext_link_stream_start(link_dev);
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ snd_hdac_ext_link_stream_clear(link_dev);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int skl_link_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct hdac_ext_stream *link_dev =
+ snd_soc_dai_get_dma_data(dai, substream);
+ struct hdac_ext_link *link;
+
+ dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
+
+ link_dev->link_prepared = 0;
+
+ link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
+ if (!link)
+ return -EINVAL;
+
+ snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_dev)->stream_tag);
+ snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
+ return 0;
+}
+
+static int skl_hda_be_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ return pm_runtime_get_sync(dai->dev);
+}
+
+static void skl_hda_be_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ pm_runtime_mark_last_busy(dai->dev);
+ pm_runtime_put_autosuspend(dai->dev);
+}
+
+static struct snd_soc_dai_ops skl_pcm_dai_ops = {
+ .startup = skl_pcm_open,
+ .shutdown = skl_pcm_close,
+ .prepare = skl_pcm_prepare,
+ .hw_params = skl_pcm_hw_params,
+ .hw_free = skl_pcm_hw_free,
+};
+
+static struct snd_soc_dai_ops skl_dmic_dai_ops = {
+ .startup = skl_hda_be_startup,
+ .shutdown = skl_hda_be_shutdown,
+};
+
+static struct snd_soc_dai_ops skl_link_dai_ops = {
+ .startup = skl_hda_be_startup,
+ .prepare = skl_link_pcm_prepare,
+ .hw_params = skl_link_hw_params,
+ .hw_free = skl_link_hw_free,
+ .trigger = skl_link_pcm_trigger,
+ .shutdown = skl_hda_be_shutdown,
+};
+
+static struct snd_soc_dai_driver skl_platform_dai[] = {
+{
+ .name = "System Pin",
+ .ops = &skl_pcm_dai_ops,
+ .playback = {
+ .stream_name = "System Playback",
+ .channels_min = HDA_MONO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .capture = {
+ .stream_name = "System Capture",
+ .channels_min = HDA_MONO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+{
+ .name = "Reference Pin",
+ .ops = &skl_pcm_dai_ops,
+ .capture = {
+ .stream_name = "Reference Capture",
+ .channels_min = HDA_MONO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+{
+ .name = "Deepbuffer Pin",
+ .ops = &skl_pcm_dai_ops,
+ .playback = {
+ .stream_name = "Deepbuffer Playback",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+{
+ .name = "LowLatency Pin",
+ .ops = &skl_pcm_dai_ops,
+ .playback = {
+ .stream_name = "Low Latency Playback",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+/* BE CPU Dais */
+{
+ .name = "iDisp Pin",
+ .ops = &skl_link_dai_ops,
+ .playback = {
+ .stream_name = "iDisp Tx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
+{
+ .name = "DMIC01 Pin",
+ .ops = &skl_dmic_dai_ops,
+ .capture = {
+ .stream_name = "DMIC01 Rx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+{
+ .name = "DMIC23 Pin",
+ .ops = &skl_dmic_dai_ops,
+ .capture = {
+ .stream_name = "DMIC23 Rx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+{
+ .name = "HD-Codec Pin",
+ .ops = &skl_link_dai_ops,
+ .playback = {
+ .stream_name = "HD-Codec Tx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "HD-Codec Rx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
+{
+ .name = "HD-Codec-SPK Pin",
+ .ops = &skl_link_dai_ops,
+ .playback = {
+ .stream_name = "HD-Codec-SPK Tx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
+{
+ .name = "HD-Codec-AMIC Pin",
+ .ops = &skl_link_dai_ops,
+ .capture = {
+ .stream_name = "HD-Codec-AMIC Rx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
+};
+
+static int skl_platform_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+
+ dev_dbg(rtd->cpu_dai->dev, "In %s:%s\n", __func__,
+ dai_link->cpu_dai_name);
+
+ runtime = substream->runtime;
+ snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw);
+
+ return 0;
+}
+
+static int skl_pcm_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_ext_stream *stream;
+ struct snd_pcm_substream *s;
+ bool start;
+ int sbits = 0;
+ unsigned long cookie;
+ struct hdac_stream *hstr;
+
+ stream = get_hdac_ext_stream(substream);
+ hstr = hdac_stream(stream);
+
+ dev_dbg(bus->dev, "In %s cmd=%d\n", __func__, cmd);
+
+ if (!hstr->prepared)
+ return -EPIPE;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ start = true;
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ start = false;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+ stream = get_hdac_ext_stream(s);
+ sbits |= 1 << hdac_stream(stream)->index;
+ snd_pcm_trigger_done(s, substream);
+ }
+
+ spin_lock_irqsave(&bus->reg_lock, cookie);
+
+ /* first, set SYNC bits of corresponding streams */
+ snd_hdac_stream_sync_trigger(hstr, true, sbits, AZX_REG_SSYNC);
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+ stream = get_hdac_ext_stream(s);
+ if (start)
+ snd_hdac_stream_start(hdac_stream(stream), true);
+ else
+ snd_hdac_stream_stop(hdac_stream(stream));
+ }
+ spin_unlock_irqrestore(&bus->reg_lock, cookie);
+
+ snd_hdac_stream_sync(hstr, start, sbits);
+
+ spin_lock_irqsave(&bus->reg_lock, cookie);
+
+ /* reset SYNC bits */
+ snd_hdac_stream_sync_trigger(hstr, false, sbits, AZX_REG_SSYNC);
+ if (start)
+ snd_hdac_stream_timecounter_init(hstr, sbits);
+ spin_unlock_irqrestore(&bus->reg_lock, cookie);
+
+ return 0;
+}
+
+static int skl_dsp_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct hdac_ext_stream *stream;
+ int start;
+ unsigned long cookie;
+ struct hdac_stream *hstr;
+
+ dev_dbg(bus->dev, "In %s cmd=%d streamname=%s\n", __func__, cmd, cpu_dai->name);
+
+ stream = get_hdac_ext_stream(substream);
+ hstr = hdac_stream(stream);
+
+ if (!hstr->prepared)
+ return -EPIPE;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ start = 1;
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ start = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&bus->reg_lock, cookie);
+
+ if (start)
+ snd_hdac_stream_start(hdac_stream(stream), true);
+ else
+ snd_hdac_stream_stop(hdac_stream(stream));
+
+ if (start)
+ snd_hdac_stream_timecounter_init(hstr, 0);
+
+ spin_unlock_irqrestore(&bus->reg_lock, cookie);
+
+ return 0;
+}
+static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+
+ if (ebus->ppcap)
+ return skl_dsp_trigger(substream, cmd);
+ else
+ return skl_pcm_trigger(substream, cmd);
+}
+
+/* calculate runtime delay from LPIB */
+static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus,
+ struct hdac_ext_stream *sstream,
+ unsigned int pos)
+{
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_stream *hstream = hdac_stream(sstream);
+ struct snd_pcm_substream *substream = hstream->substream;
+ int stream = substream->stream;
+ unsigned int lpib_pos = snd_hdac_stream_get_pos_lpib(hstream);
+ int delay;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ delay = pos - lpib_pos;
+ else
+ delay = lpib_pos - pos;
+
+ if (delay < 0) {
+ if (delay >= hstream->delay_negative_threshold)
+ delay = 0;
+ else
+ delay += hstream->bufsize;
+ }
+
+ if (delay >= hstream->period_bytes) {
+ dev_info(bus->dev,
+ "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n",
+ delay, hstream->period_bytes);
+ delay = 0;
+ }
+
+ return bytes_to_frames(substream->runtime, delay);
+}
+
+static unsigned int skl_get_position(struct hdac_ext_stream *hstream,
+ int codec_delay)
+{
+ struct hdac_stream *hstr = hdac_stream(hstream);
+ struct snd_pcm_substream *substream = hstr->substream;
+ struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ unsigned int pos;
+ int delay;
+
+ /* use the position buffer as default */
+ pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream));
+
+ if (pos >= hdac_stream(hstream)->bufsize)
+ pos = 0;
+
+ if (substream->runtime) {
+ delay = skl_get_delay_from_lpib(ebus, hstream, pos)
+ + codec_delay;
+ substream->runtime->delay += delay;
+ }
+
+ return pos;
+}
+
+static snd_pcm_uframes_t skl_platform_pcm_pointer
+ (struct snd_pcm_substream *substream)
+{
+ struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream);
+
+ return bytes_to_frames(substream->runtime,
+ skl_get_position(hstream, 0));
+}
+
+static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream,
+ u64 nsec)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ u64 codec_frames, codec_nsecs;
+
+ if (!codec_dai->driver->ops->delay)
+ return nsec;
+
+ codec_frames = codec_dai->driver->ops->delay(substream, codec_dai);
+ codec_nsecs = div_u64(codec_frames * 1000000000LL,
+ substream->runtime->rate);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ return nsec + codec_nsecs;
+
+ return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0;
+}
+
+static int skl_get_time_info(struct snd_pcm_substream *substream,
+ struct timespec *system_ts, struct timespec *audio_ts,
+ struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
+ struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
+{
+ struct hdac_ext_stream *sstream = get_hdac_ext_stream(substream);
+ struct hdac_stream *hstr = hdac_stream(sstream);
+ u64 nsec;
+
+ if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) &&
+ (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) {
+
+ snd_pcm_gettime(substream->runtime, system_ts);
+
+ nsec = timecounter_read(&hstr->tc);
+ nsec = div_u64(nsec, 3); /* can be optimized */
+ if (audio_tstamp_config->report_delay)
+ nsec = skl_adjust_codec_delay(substream, nsec);
+
+ *audio_ts = ns_to_timespec(nsec);
+
+ audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK;
+ audio_tstamp_report->accuracy_report = 1; /* rest of struct is valid */
+ audio_tstamp_report->accuracy = 42; /* 24MHzWallClk == 42ns resolution */
+
+ } else {
+ audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
+ }
+
+ return 0;
+}
+
+static struct snd_pcm_ops skl_platform_ops = {
+ .open = skl_platform_open,
+ .ioctl = snd_pcm_lib_ioctl,
+ .trigger = skl_platform_pcm_trigger,
+ .pointer = skl_platform_pcm_pointer,
+ .get_time_info = skl_get_time_info,
+ .mmap = snd_pcm_lib_default_mmap,
+ .page = snd_pcm_sgbuf_ops_page,
+};
+
+static void skl_pcm_free(struct snd_pcm *pcm)
+{
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+#define MAX_PREALLOC_SIZE (32 * 1024 * 1024)
+
+static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *dai = rtd->cpu_dai;
+ struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct snd_pcm *pcm = rtd->pcm;
+ unsigned int size;
+ int retval = 0;
+ struct skl *skl = ebus_to_skl(ebus);
+
+ if (dai->driver->playback.channels_min ||
+ dai->driver->capture.channels_min) {
+ /* buffer pre-allocation */
+ size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
+ if (size > MAX_PREALLOC_SIZE)
+ size = MAX_PREALLOC_SIZE;
+ retval = snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_DEV_SG,
+ snd_dma_pci_data(skl->pci),
+ size, MAX_PREALLOC_SIZE);
+ if (retval) {
+ dev_err(dai->dev, "dma buffer allocationf fail\n");
+ return retval;
+ }
+ }
+
+ return retval;
+}
+
+static struct snd_soc_platform_driver skl_platform_drv = {
+ .ops = &skl_platform_ops,
+ .pcm_new = skl_pcm_new,
+ .pcm_free = skl_pcm_free,
+};
+
+static const struct snd_soc_component_driver skl_component = {
+ .name = "pcm",
+};
+
+int skl_platform_register(struct device *dev)
+{
+ int ret;
+
+ ret = snd_soc_register_platform(dev, &skl_platform_drv);
+ if (ret) {
+ dev_err(dev, "soc platform registration failed %d\n", ret);
+ return ret;
+ }
+ ret = snd_soc_register_component(dev, &skl_component,
+ skl_platform_dai,
+ ARRAY_SIZE(skl_platform_dai));
+ if (ret) {
+ dev_err(dev, "soc component registration failed %d\n", ret);
+ snd_soc_unregister_platform(dev);
+ }
+
+ return ret;
+
+}
+
+int skl_platform_unregister(struct device *dev)
+{
+ snd_soc_unregister_component(dev);
+ snd_soc_unregister_platform(dev);
+ return 0;
+}
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c
new file mode 100644
index 0000000..44748ba
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-sst-cldma.c
@@ -0,0 +1,327 @@
+/*
+ * skl-sst-cldma.c - Code Loader DMA handler
+ *
+ * Copyright (C) 2015, Intel Corporation.
+ * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/kthread.h>
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+
+static void skl_cldma_int_enable(struct sst_dsp *ctx)
+{
+ sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC,
+ SKL_ADSPIC_CL_DMA, SKL_ADSPIC_CL_DMA);
+}
+
+void skl_cldma_int_disable(struct sst_dsp *ctx)
+{
+ sst_dsp_shim_update_bits_unlocked(ctx,
+ SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0);
+}
+
+/* Code loader helper APIs */
+static void skl_cldma_setup_bdle(struct sst_dsp *ctx,
+ struct snd_dma_buffer *dmab_data,
+ u32 **bdlp, int size, int with_ioc)
+{
+ u32 *bdl = *bdlp;
+
+ ctx->cl_dev.frags = 0;
+ while (size > 0) {
+ phys_addr_t addr = virt_to_phys(dmab_data->area +
+ (ctx->cl_dev.frags * ctx->cl_dev.bufsize));
+
+ bdl[0] = cpu_to_le32(lower_32_bits(addr));
+ bdl[1] = cpu_to_le32(upper_32_bits(addr));
+
+ bdl[2] = cpu_to_le32(ctx->cl_dev.bufsize);
+
+ size -= ctx->cl_dev.bufsize;
+ bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
+
+ bdl += 4;
+ ctx->cl_dev.frags++;
+ }
+}
+
+/*
+ * Setup controller
+ * Configure the registers to update the dma buffer address and
+ * enable interrupts.
+ * Note: Using the channel 1 for transfer
+ */
+static void skl_cldma_setup_controller(struct sst_dsp *ctx,
+ struct snd_dma_buffer *dmab_bdl, unsigned int max_size,
+ u32 count)
+{
+ sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL,
+ CL_SD_BDLPLBA(dmab_bdl->addr));
+ sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU,
+ CL_SD_BDLPUBA(dmab_bdl->addr));
+
+ sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, max_size);
+ sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, count - 1);
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(1));
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(1));
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(1));
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(FW_CL_STREAM_NUMBER));
+}
+
+static void skl_cldma_setup_spb(struct sst_dsp *ctx,
+ unsigned int size, bool enable)
+{
+ if (enable)
+ sst_dsp_shim_update_bits_unlocked(ctx,
+ SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL,
+ CL_SPBFIFO_SPBFCCTL_SPIBE_MASK,
+ CL_SPBFIFO_SPBFCCTL_SPIBE(1));
+
+ sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, size);
+}
+
+static void skl_cldma_cleanup_spb(struct sst_dsp *ctx)
+{
+ sst_dsp_shim_update_bits_unlocked(ctx,
+ SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL,
+ CL_SPBFIFO_SPBFCCTL_SPIBE_MASK,
+ CL_SPBFIFO_SPBFCCTL_SPIBE(0));
+
+ sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0);
+}
+
+static void skl_cldma_trigger(struct sst_dsp *ctx, bool enable)
+{
+ if (enable)
+ sst_dsp_shim_update_bits_unlocked(ctx,
+ SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(1));
+ else
+ sst_dsp_shim_update_bits_unlocked(ctx,
+ SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(0));
+}
+
+static void skl_cldma_cleanup(struct sst_dsp *ctx)
+{
+ skl_cldma_cleanup_spb(ctx);
+
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0));
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0));
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0));
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+ CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0));
+
+ sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0));
+ sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0);
+
+ sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0);
+ sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0);
+}
+
+static int skl_cldma_wait_interruptible(struct sst_dsp *ctx)
+{
+ int ret = 0;
+
+ if (!wait_event_timeout(ctx->cl_dev.wait_queue,
+ ctx->cl_dev.wait_condition,
+ msecs_to_jiffies(SKL_WAIT_TIMEOUT))) {
+ dev_err(ctx->dev, "%s: Wait timeout\n", __func__);
+ ret = -EIO;
+ goto cleanup;
+ }
+
+ dev_dbg(ctx->dev, "%s: Event wake\n", __func__);
+ if (ctx->cl_dev.wake_status != SKL_CL_DMA_BUF_COMPLETE) {
+ dev_err(ctx->dev, "%s: DMA Error\n", __func__);
+ ret = -EIO;
+ }
+
+cleanup:
+ ctx->cl_dev.wake_status = SKL_CL_DMA_STATUS_NONE;
+ return ret;
+}
+
+static void skl_cldma_stop(struct sst_dsp *ctx)
+{
+ ctx->cl_dev.ops.cl_trigger(ctx, false);
+}
+
+static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size,
+ const void *curr_pos, bool intr_enable, bool trigger)
+{
+ dev_dbg(ctx->dev, "Size: %x, intr_enable: %d\n", size, intr_enable);
+ dev_dbg(ctx->dev, "buf_pos_index:%d, trigger:%d\n",
+ ctx->cl_dev.dma_buffer_offset, trigger);
+ dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos);
+
+ memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset,
+ curr_pos, size);
+
+ if (ctx->cl_dev.curr_spib_pos == ctx->cl_dev.bufsize)
+ ctx->cl_dev.dma_buffer_offset = 0;
+ else
+ ctx->cl_dev.dma_buffer_offset = ctx->cl_dev.curr_spib_pos;
+
+ ctx->cl_dev.wait_condition = false;
+
+ if (intr_enable)
+ skl_cldma_int_enable(ctx);
+
+ ctx->cl_dev.ops.cl_setup_spb(ctx, ctx->cl_dev.curr_spib_pos, trigger);
+ if (trigger)
+ ctx->cl_dev.ops.cl_trigger(ctx, true);
+}
+
+/*
+ * The CL dma doesn't have any way to update the transfer status until a BDL
+ * buffer is fully transferred
+ *
+ * So Copying is divided in two parts.
+ * 1. Interrupt on buffer done where the size to be transferred is more than
+ * ring buffer size.
+ * 2. Polling on fw register to identify if data left to transferred doesn't
+ * fill the ring buffer. Caller takes care of polling the required status
+ * register to identify the transfer status.
+ */
+static int
+skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size)
+{
+ int ret = 0;
+ bool start = true;
+ unsigned int excess_bytes;
+ u32 size;
+ unsigned int bytes_left = total_size;
+ const void *curr_pos = bin;
+
+ if (total_size <= 0)
+ return -EINVAL;
+
+ dev_dbg(ctx->dev, "%s: Total binary size: %u\n", __func__, bytes_left);
+
+ while (bytes_left) {
+ if (bytes_left > ctx->cl_dev.bufsize) {
+
+ /*
+ * dma transfers only till the write pointer as
+ * updated in spib
+ */
+ if (ctx->cl_dev.curr_spib_pos == 0)
+ ctx->cl_dev.curr_spib_pos = ctx->cl_dev.bufsize;
+
+ size = ctx->cl_dev.bufsize;
+ skl_cldma_fill_buffer(ctx, size, curr_pos, true, start);
+
+ start = false;
+ ret = skl_cldma_wait_interruptible(ctx);
+ if (ret < 0) {
+ skl_cldma_stop(ctx);
+ return ret;
+ }
+
+ } else {
+ skl_cldma_int_disable(ctx);
+
+ if ((ctx->cl_dev.curr_spib_pos + bytes_left)
+ <= ctx->cl_dev.bufsize) {
+ ctx->cl_dev.curr_spib_pos += bytes_left;
+ } else {
+ excess_bytes = bytes_left -
+ (ctx->cl_dev.bufsize -
+ ctx->cl_dev.curr_spib_pos);
+ ctx->cl_dev.curr_spib_pos = excess_bytes;
+ }
+
+ size = bytes_left;
+ skl_cldma_fill_buffer(ctx, size,
+ curr_pos, false, start);
+ }
+ bytes_left -= size;
+ curr_pos = curr_pos + size;
+ }
+
+ return ret;
+}
+
+void skl_cldma_process_intr(struct sst_dsp *ctx)
+{
+ u8 cl_dma_intr_status;
+
+ cl_dma_intr_status =
+ sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_CL_SD_STS);
+
+ if (!(cl_dma_intr_status & SKL_CL_DMA_SD_INT_COMPLETE))
+ ctx->cl_dev.wake_status = SKL_CL_DMA_ERR;
+ else
+ ctx->cl_dev.wake_status = SKL_CL_DMA_BUF_COMPLETE;
+
+ ctx->cl_dev.wait_condition = true;
+ wake_up(&ctx->cl_dev.wait_queue);
+}
+
+int skl_cldma_prepare(struct sst_dsp *ctx)
+{
+ int ret;
+ u32 *bdl;
+
+ ctx->cl_dev.bufsize = SKL_MAX_BUFFER_SIZE;
+
+ /* Allocate cl ops */
+ ctx->cl_dev.ops.cl_setup_bdle = skl_cldma_setup_bdle;
+ ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller;
+ ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb;
+ ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb;
+ ctx->cl_dev.ops.cl_trigger = skl_cldma_trigger;
+ ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup;
+ ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf;
+ ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop;
+
+ /* Allocate buffer*/
+ ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev,
+ &ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Alloc buffer for base fw failed: %x", ret);
+ return ret;
+ }
+ /* Setup Code loader BDL */
+ ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev,
+ &ctx->cl_dev.dmab_bdl, PAGE_SIZE);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Alloc buffer for blde failed: %x", ret);
+ ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
+ return ret;
+ }
+ bdl = (u32 *)ctx->cl_dev.dmab_bdl.area;
+
+ /* Allocate BDLs */
+ ctx->cl_dev.ops.cl_setup_bdle(ctx, &ctx->cl_dev.dmab_data,
+ &bdl, ctx->cl_dev.bufsize, 1);
+ ctx->cl_dev.ops.cl_setup_controller(ctx, &ctx->cl_dev.dmab_bdl,
+ ctx->cl_dev.bufsize, ctx->cl_dev.frags);
+
+ ctx->cl_dev.curr_spib_pos = 0;
+ ctx->cl_dev.dma_buffer_offset = 0;
+ init_waitqueue_head(&ctx->cl_dev.wait_queue);
+
+ return ret;
+}
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h
new file mode 100644
index 0000000..99e4c86
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-sst-cldma.h
@@ -0,0 +1,251 @@
+/*
+ * Intel Code Loader DMA support
+ *
+ * Copyright (C) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef SKL_SST_CLDMA_H_
+#define SKL_SST_CLDMA_H_
+
+#define FW_CL_STREAM_NUMBER 0x1
+
+#define DMA_ADDRESS_128_BITS_ALIGNMENT 7
+#define BDL_ALIGN(x) (x >> DMA_ADDRESS_128_BITS_ALIGNMENT)
+
+#define SKL_ADSPIC_CL_DMA 0x2
+#define SKL_ADSPIS_CL_DMA 0x2
+#define SKL_CL_DMA_SD_INT_DESC_ERR 0x10 /* Descriptor error interrupt */
+#define SKL_CL_DMA_SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */
+#define SKL_CL_DMA_SD_INT_COMPLETE 0x04 /* Buffer completion interrupt */
+
+/* Intel HD Audio Code Loader DMA Registers */
+
+#define HDA_ADSP_LOADER_BASE 0x80
+
+/* Stream Registers */
+#define SKL_ADSP_REG_CL_SD_CTL (HDA_ADSP_LOADER_BASE + 0x00)
+#define SKL_ADSP_REG_CL_SD_STS (HDA_ADSP_LOADER_BASE + 0x03)
+#define SKL_ADSP_REG_CL_SD_LPIB (HDA_ADSP_LOADER_BASE + 0x04)
+#define SKL_ADSP_REG_CL_SD_CBL (HDA_ADSP_LOADER_BASE + 0x08)
+#define SKL_ADSP_REG_CL_SD_LVI (HDA_ADSP_LOADER_BASE + 0x0c)
+#define SKL_ADSP_REG_CL_SD_FIFOW (HDA_ADSP_LOADER_BASE + 0x0e)
+#define SKL_ADSP_REG_CL_SD_FIFOSIZE (HDA_ADSP_LOADER_BASE + 0x10)
+#define SKL_ADSP_REG_CL_SD_FORMAT (HDA_ADSP_LOADER_BASE + 0x12)
+#define SKL_ADSP_REG_CL_SD_FIFOL (HDA_ADSP_LOADER_BASE + 0x14)
+#define SKL_ADSP_REG_CL_SD_BDLPL (HDA_ADSP_LOADER_BASE + 0x18)
+#define SKL_ADSP_REG_CL_SD_BDLPU (HDA_ADSP_LOADER_BASE + 0x1c)
+
+/* CL: Software Position Based FIFO Capability Registers */
+#define SKL_ADSP_REG_CL_SPBFIFO (HDA_ADSP_LOADER_BASE + 0x20)
+#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCH (SKL_ADSP_REG_CL_SPBFIFO + 0x0)
+#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL (SKL_ADSP_REG_CL_SPBFIFO + 0x4)
+#define SKL_ADSP_REG_CL_SPBFIFO_SPIB (SKL_ADSP_REG_CL_SPBFIFO + 0x8)
+#define SKL_ADSP_REG_CL_SPBFIFO_MAXFIFOS (SKL_ADSP_REG_CL_SPBFIFO + 0xc)
+
+/* CL: Stream Descriptor x Control */
+
+/* Stream Reset */
+#define CL_SD_CTL_SRST_SHIFT 0
+#define CL_SD_CTL_SRST_MASK (1 << CL_SD_CTL_SRST_SHIFT)
+#define CL_SD_CTL_SRST(x) \
+ ((x << CL_SD_CTL_SRST_SHIFT) & CL_SD_CTL_SRST_MASK)
+
+/* Stream Run */
+#define CL_SD_CTL_RUN_SHIFT 1
+#define CL_SD_CTL_RUN_MASK (1 << CL_SD_CTL_RUN_SHIFT)
+#define CL_SD_CTL_RUN(x) \
+ ((x << CL_SD_CTL_RUN_SHIFT) & CL_SD_CTL_RUN_MASK)
+
+/* Interrupt On Completion Enable */
+#define CL_SD_CTL_IOCE_SHIFT 2
+#define CL_SD_CTL_IOCE_MASK (1 << CL_SD_CTL_IOCE_SHIFT)
+#define CL_SD_CTL_IOCE(x) \
+ ((x << CL_SD_CTL_IOCE_SHIFT) & CL_SD_CTL_IOCE_MASK)
+
+/* FIFO Error Interrupt Enable */
+#define CL_SD_CTL_FEIE_SHIFT 3
+#define CL_SD_CTL_FEIE_MASK (1 << CL_SD_CTL_FEIE_SHIFT)
+#define CL_SD_CTL_FEIE(x) \
+ ((x << CL_SD_CTL_FEIE_SHIFT) & CL_SD_CTL_FEIE_MASK)
+
+/* Descriptor Error Interrupt Enable */
+#define CL_SD_CTL_DEIE_SHIFT 4
+#define CL_SD_CTL_DEIE_MASK (1 << CL_SD_CTL_DEIE_SHIFT)
+#define CL_SD_CTL_DEIE(x) \
+ ((x << CL_SD_CTL_DEIE_SHIFT) & CL_SD_CTL_DEIE_MASK)
+
+/* FIFO Limit Change */
+#define CL_SD_CTL_FIFOLC_SHIFT 5
+#define CL_SD_CTL_FIFOLC_MASK (1 << CL_SD_CTL_FIFOLC_SHIFT)
+#define CL_SD_CTL_FIFOLC(x) \
+ ((x << CL_SD_CTL_FIFOLC_SHIFT) & CL_SD_CTL_FIFOLC_MASK)
+
+/* Stripe Control */
+#define CL_SD_CTL_STRIPE_SHIFT 16
+#define CL_SD_CTL_STRIPE_MASK (0x3 << CL_SD_CTL_STRIPE_SHIFT)
+#define CL_SD_CTL_STRIPE(x) \
+ ((x << CL_SD_CTL_STRIPE_SHIFT) & CL_SD_CTL_STRIPE_MASK)
+
+/* Traffic Priority */
+#define CL_SD_CTL_TP_SHIFT 18
+#define CL_SD_CTL_TP_MASK (1 << CL_SD_CTL_TP_SHIFT)
+#define CL_SD_CTL_TP(x) \
+ ((x << CL_SD_CTL_TP_SHIFT) & CL_SD_CTL_TP_MASK)
+
+/* Bidirectional Direction Control */
+#define CL_SD_CTL_DIR_SHIFT 19
+#define CL_SD_CTL_DIR_MASK (1 << CL_SD_CTL_DIR_SHIFT)
+#define CL_SD_CTL_DIR(x) \
+ ((x << CL_SD_CTL_DIR_SHIFT) & CL_SD_CTL_DIR_MASK)
+
+/* Stream Number */
+#define CL_SD_CTL_STRM_SHIFT 20
+#define CL_SD_CTL_STRM_MASK (0xf << CL_SD_CTL_STRM_SHIFT)
+#define CL_SD_CTL_STRM(x) \
+ ((x << CL_SD_CTL_STRM_SHIFT) & CL_SD_CTL_STRM_MASK)
+
+/* CL: Stream Descriptor x Status */
+
+/* Buffer Completion Interrupt Status */
+#define CL_SD_STS_BCIS(x) CL_SD_CTL_IOCE(x)
+
+/* FIFO Error */
+#define CL_SD_STS_FIFOE(x) CL_SD_CTL_FEIE(x)
+
+/* Descriptor Error */
+#define CL_SD_STS_DESE(x) CL_SD_CTL_DEIE(x)
+
+/* FIFO Ready */
+#define CL_SD_STS_FIFORDY(x) CL_SD_CTL_FIFOLC(x)
+
+
+/* CL: Stream Descriptor x Last Valid Index */
+#define CL_SD_LVI_SHIFT 0
+#define CL_SD_LVI_MASK (0xff << CL_SD_LVI_SHIFT)
+#define CL_SD_LVI(x) ((x << CL_SD_LVI_SHIFT) & CL_SD_LVI_MASK)
+
+/* CL: Stream Descriptor x FIFO Eviction Watermark */
+#define CL_SD_FIFOW_SHIFT 0
+#define CL_SD_FIFOW_MASK (0x7 << CL_SD_FIFOW_SHIFT)
+#define CL_SD_FIFOW(x) \
+ ((x << CL_SD_FIFOW_SHIFT) & CL_SD_FIFOW_MASK)
+
+/* CL: Stream Descriptor x Buffer Descriptor List Pointer Lower Base Address */
+
+/* Protect Bits */
+#define CL_SD_BDLPLBA_PROT_SHIFT 0
+#define CL_SD_BDLPLBA_PROT_MASK (1 << CL_SD_BDLPLBA_PROT_SHIFT)
+#define CL_SD_BDLPLBA_PROT(x) \
+ ((x << CL_SD_BDLPLBA_PROT_SHIFT) & CL_SD_BDLPLBA_PROT_MASK)
+
+/* Buffer Descriptor List Lower Base Address */
+#define CL_SD_BDLPLBA_SHIFT 7
+#define CL_SD_BDLPLBA_MASK (0x1ffffff << CL_SD_BDLPLBA_SHIFT)
+#define CL_SD_BDLPLBA(x) \
+ ((BDL_ALIGN(lower_32_bits(x)) << CL_SD_BDLPLBA_SHIFT) & CL_SD_BDLPLBA_MASK)
+
+/* Buffer Descriptor List Upper Base Address */
+#define CL_SD_BDLPUBA_SHIFT 0
+#define CL_SD_BDLPUBA_MASK (0xffffffff << CL_SD_BDLPUBA_SHIFT)
+#define CL_SD_BDLPUBA(x) \
+ ((upper_32_bits(x) << CL_SD_BDLPUBA_SHIFT) & CL_SD_BDLPUBA_MASK)
+
+/*
+ * Code Loader - Software Position Based FIFO
+ * Capability Registers x Software Position Based FIFO Header
+ */
+
+/* Next Capability Pointer */
+#define CL_SPBFIFO_SPBFCH_PTR_SHIFT 0
+#define CL_SPBFIFO_SPBFCH_PTR_MASK (0xff << CL_SPBFIFO_SPBFCH_PTR_SHIFT)
+#define CL_SPBFIFO_SPBFCH_PTR(x) \
+ ((x << CL_SPBFIFO_SPBFCH_PTR_SHIFT) & CL_SPBFIFO_SPBFCH_PTR_MASK)
+
+/* Capability Identifier */
+#define CL_SPBFIFO_SPBFCH_ID_SHIFT 16
+#define CL_SPBFIFO_SPBFCH_ID_MASK (0xfff << CL_SPBFIFO_SPBFCH_ID_SHIFT)
+#define CL_SPBFIFO_SPBFCH_ID(x) \
+ ((x << CL_SPBFIFO_SPBFCH_ID_SHIFT) & CL_SPBFIFO_SPBFCH_ID_MASK)
+
+/* Capability Version */
+#define CL_SPBFIFO_SPBFCH_VER_SHIFT 28
+#define CL_SPBFIFO_SPBFCH_VER_MASK (0xf << CL_SPBFIFO_SPBFCH_VER_SHIFT)
+#define CL_SPBFIFO_SPBFCH_VER(x) \
+ ((x << CL_SPBFIFO_SPBFCH_VER_SHIFT) & CL_SPBFIFO_SPBFCH_VER_MASK)
+
+/* Software Position in Buffer Enable */
+#define CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0
+#define CL_SPBFIFO_SPBFCCTL_SPIBE_MASK (1 << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT)
+#define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \
+ ((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK)
+
+/* SST IPC SKL defines */
+#define SKL_WAIT_TIMEOUT 500 /* 500 msec */
+#define SKL_MAX_BUFFER_SIZE (32 * PAGE_SIZE)
+
+enum skl_cl_dma_wake_states {
+ SKL_CL_DMA_STATUS_NONE = 0,
+ SKL_CL_DMA_BUF_COMPLETE,
+ SKL_CL_DMA_ERR, /* TODO: Expand the error states */
+};
+
+struct sst_dsp;
+
+struct skl_cl_dev_ops {
+ void (*cl_setup_bdle)(struct sst_dsp *ctx,
+ struct snd_dma_buffer *dmab_data,
+ u32 **bdlp, int size, int with_ioc);
+ void (*cl_setup_controller)(struct sst_dsp *ctx,
+ struct snd_dma_buffer *dmab_bdl,
+ unsigned int max_size, u32 page_count);
+ void (*cl_setup_spb)(struct sst_dsp *ctx,
+ unsigned int size, bool enable);
+ void (*cl_cleanup_spb)(struct sst_dsp *ctx);
+ void (*cl_trigger)(struct sst_dsp *ctx, bool enable);
+ void (*cl_cleanup_controller)(struct sst_dsp *ctx);
+ int (*cl_copy_to_dmabuf)(struct sst_dsp *ctx,
+ const void *bin, u32 size);
+ void (*cl_stop_dma)(struct sst_dsp *ctx);
+};
+
+/**
+ * skl_cl_dev - holds information for code loader dma transfer
+ *
+ * @dmab_data: buffer pointer
+ * @dmab_bdl: buffer descriptor list
+ * @bufsize: ring buffer size
+ * @frags: Last valid buffer descriptor index in the BDL
+ * @curr_spib_pos: Current position in ring buffer
+ * @dma_buffer_offset: dma buffer offset
+ * @ops: operations supported on CL dma
+ * @wait_queue: wait queue to wake for wake event
+ * @wake_status: DMA wake status
+ * @wait_condition: condition to wait on wait queue
+ * @cl_dma_lock: for synchronized access to cldma
+ */
+struct skl_cl_dev {
+ struct snd_dma_buffer dmab_data;
+ struct snd_dma_buffer dmab_bdl;
+
+ unsigned int bufsize;
+ unsigned int frags;
+
+ unsigned int curr_spib_pos;
+ unsigned int dma_buffer_offset;
+ struct skl_cl_dev_ops ops;
+
+ wait_queue_head_t wait_queue;
+ int wake_status;
+ bool wait_condition;
+};
+
+#endif /* SKL_SST_CLDMA_H_ */
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c
new file mode 100644
index 0000000..94875b0
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-sst-dsp.c
@@ -0,0 +1,342 @@
+/*
+ * skl-sst-dsp.c - SKL SST library generic function
+ *
+ * Copyright (C) 2014-15, Intel Corporation.
+ * Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
+ * Jeeja KP <jeeja.kp@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <sound/pcm.h>
+
+#include "../common/sst-dsp.h"
+#include "../common/sst-ipc.h"
+#include "../common/sst-dsp-priv.h"
+#include "skl-sst-ipc.h"
+
+/* various timeout values */
+#define SKL_DSP_PU_TO 50
+#define SKL_DSP_PD_TO 50
+#define SKL_DSP_RESET_TO 50
+
+void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state)
+{
+ mutex_lock(&ctx->mutex);
+ ctx->sst_state = state;
+ mutex_unlock(&ctx->mutex);
+}
+
+static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx)
+{
+ int ret;
+
+ /* update bits */
+ sst_dsp_shim_update_bits_unlocked(ctx,
+ SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK,
+ SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK));
+
+ /* poll with timeout to check if operation successful */
+ ret = sst_dsp_register_poll(ctx,
+ SKL_ADSP_REG_ADSPCS,
+ SKL_ADSPCS_CRST_MASK,
+ SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK),
+ SKL_DSP_RESET_TO,
+ "Set reset");
+ if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
+ SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) !=
+ SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) {
+ dev_err(ctx->dev, "Set reset state failed\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx)
+{
+ int ret;
+
+ dev_dbg(ctx->dev, "In %s\n", __func__);
+
+ /* update bits */
+ sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
+ SKL_ADSPCS_CRST_MASK, 0);
+
+ /* poll with timeout to check if operation successful */
+ ret = sst_dsp_register_poll(ctx,
+ SKL_ADSP_REG_ADSPCS,
+ SKL_ADSPCS_CRST_MASK,
+ 0,
+ SKL_DSP_RESET_TO,
+ "Unset reset");
+
+ if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
+ SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != 0) {
+ dev_err(ctx->dev, "Unset reset state failed\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static bool is_skl_dsp_core_enable(struct sst_dsp *ctx)
+{
+ int val;
+ bool is_enable;
+
+ val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS);
+
+ is_enable = ((val & SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) &&
+ (val & SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)) &&
+ !(val & SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) &&
+ !(val & SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)));
+
+ dev_dbg(ctx->dev, "DSP core is enabled=%d\n", is_enable);
+ return is_enable;
+}
+
+static int skl_dsp_reset_core(struct sst_dsp *ctx)
+{
+ /* stall core */
+ sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
+ sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
+ SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK));
+
+ /* set reset state */
+ return skl_dsp_core_set_reset_state(ctx);
+}
+
+static int skl_dsp_start_core(struct sst_dsp *ctx)
+{
+ int ret;
+
+ /* unset reset state */
+ ret = skl_dsp_core_unset_reset_state(ctx);
+ if (ret < 0) {
+ dev_dbg(ctx->dev, "dsp unset reset fails\n");
+ return ret;
+ }
+
+ /* run core */
+ dev_dbg(ctx->dev, "run core...\n");
+ sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
+ sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
+ ~SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK));
+
+ if (!is_skl_dsp_core_enable(ctx)) {
+ skl_dsp_reset_core(ctx);
+ dev_err(ctx->dev, "DSP core enable failed\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int skl_dsp_core_power_up(struct sst_dsp *ctx)
+{
+ int ret;
+
+ /* update bits */
+ sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
+ SKL_ADSPCS_SPA_MASK, SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK));
+
+ /* poll with timeout to check if operation successful */
+ ret = sst_dsp_register_poll(ctx,
+ SKL_ADSP_REG_ADSPCS,
+ SKL_ADSPCS_CPA_MASK,
+ SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK),
+ SKL_DSP_PU_TO,
+ "Power up");
+
+ if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
+ SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) !=
+ SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) {
+ dev_err(ctx->dev, "DSP core power up failed\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int skl_dsp_core_power_down(struct sst_dsp *ctx)
+{
+ /* update bits */
+ sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
+ SKL_ADSPCS_SPA_MASK, 0);
+
+ /* poll with timeout to check if operation successful */
+ return sst_dsp_register_poll(ctx,
+ SKL_ADSP_REG_ADSPCS,
+ SKL_ADSPCS_SPA_MASK,
+ 0,
+ SKL_DSP_PD_TO,
+ "Power down");
+}
+
+static int skl_dsp_enable_core(struct sst_dsp *ctx)
+{
+ int ret;
+
+ /* power up */
+ ret = skl_dsp_core_power_up(ctx);
+ if (ret < 0) {
+ dev_dbg(ctx->dev, "dsp core power up failed\n");
+ return ret;
+ }
+
+ return skl_dsp_start_core(ctx);
+}
+
+int skl_dsp_disable_core(struct sst_dsp *ctx)
+{
+ int ret;
+
+ ret = skl_dsp_reset_core(ctx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "dsp core reset failed\n");
+ return ret;
+ }
+
+ /* power down core*/
+ ret = skl_dsp_core_power_down(ctx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "dsp core power down failed\n");
+ return ret;
+ }
+
+ if (is_skl_dsp_core_enable(ctx)) {
+ dev_err(ctx->dev, "DSP core disable failed\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+int skl_dsp_boot(struct sst_dsp *ctx)
+{
+ int ret;
+
+ if (is_skl_dsp_core_enable(ctx)) {
+ dev_dbg(ctx->dev, "dsp core is already enabled, so reset the dap core\n");
+ ret = skl_dsp_reset_core(ctx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "dsp reset failed\n");
+ return ret;
+ }
+
+ ret = skl_dsp_start_core(ctx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "dsp start failed\n");
+ return ret;
+ }
+ } else {
+ dev_dbg(ctx->dev, "disable and enable to make sure DSP is invalid state\n");
+ ret = skl_dsp_disable_core(ctx);
+
+ if (ret < 0) {
+ dev_err(ctx->dev, "dsp disable core failes\n");
+ return ret;
+ }
+ ret = skl_dsp_enable_core(ctx);
+ }
+
+ return ret;
+}
+
+irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id)
+{
+ struct sst_dsp *ctx = dev_id;
+ u32 val;
+ irqreturn_t result = IRQ_NONE;
+
+ spin_lock(&ctx->spinlock);
+
+ val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS);
+ ctx->intr_status = val;
+
+ if (val & SKL_ADSPIS_IPC) {
+ skl_ipc_int_disable(ctx);
+ result = IRQ_WAKE_THREAD;
+ }
+
+ if (val & SKL_ADSPIS_CL_DMA) {
+ skl_cldma_int_disable(ctx);
+ result = IRQ_WAKE_THREAD;
+ }
+
+ spin_unlock(&ctx->spinlock);
+
+ return result;
+}
+
+int skl_dsp_wake(struct sst_dsp *ctx)
+{
+ return ctx->fw_ops.set_state_D0(ctx);
+}
+EXPORT_SYMBOL_GPL(skl_dsp_wake);
+
+int skl_dsp_sleep(struct sst_dsp *ctx)
+{
+ return ctx->fw_ops.set_state_D3(ctx);
+}
+EXPORT_SYMBOL_GPL(skl_dsp_sleep);
+
+struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
+ struct sst_dsp_device *sst_dev, int irq)
+{
+ int ret;
+ struct sst_dsp *sst;
+
+ sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
+ if (sst == NULL)
+ return NULL;
+
+ spin_lock_init(&sst->spinlock);
+ mutex_init(&sst->mutex);
+ sst->dev = dev;
+ sst->sst_dev = sst_dev;
+ sst->irq = irq;
+ sst->ops = sst_dev->ops;
+ sst->thread_context = sst_dev->thread_context;
+
+ /* Initialise SST Audio DSP */
+ if (sst->ops->init) {
+ ret = sst->ops->init(sst, NULL);
+ if (ret < 0)
+ return NULL;
+ }
+
+ /* Register the ISR */
+ ret = request_threaded_irq(sst->irq, sst->ops->irq_handler,
+ sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
+ if (ret) {
+ dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n",
+ sst->irq);
+ return NULL;
+ }
+
+ return sst;
+}
+
+void skl_dsp_free(struct sst_dsp *dsp)
+{
+ skl_ipc_int_disable(dsp);
+
+ free_irq(dsp->irq, dsp);
+ skl_dsp_disable_core(dsp);
+}
+EXPORT_SYMBOL_GPL(skl_dsp_free);
+
+bool is_skl_dsp_running(struct sst_dsp *ctx)
+{
+ return (ctx->sst_state == SKL_DSP_RUNNING);
+}
+EXPORT_SYMBOL_GPL(is_skl_dsp_running);
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
new file mode 100644
index 0000000..6bfcef4
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -0,0 +1,145 @@
+/*
+ * Skylake SST DSP Support
+ *
+ * Copyright (C) 2014-15, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __SKL_SST_DSP_H__
+#define __SKL_SST_DSP_H__
+
+#include <linux/interrupt.h>
+#include <sound/memalloc.h>
+#include "skl-sst-cldma.h"
+
+struct sst_dsp;
+struct skl_sst;
+struct sst_dsp_device;
+
+/* Intel HD Audio General DSP Registers */
+#define SKL_ADSP_GEN_BASE 0x0
+#define SKL_ADSP_REG_ADSPCS (SKL_ADSP_GEN_BASE + 0x04)
+#define SKL_ADSP_REG_ADSPIC (SKL_ADSP_GEN_BASE + 0x08)
+#define SKL_ADSP_REG_ADSPIS (SKL_ADSP_GEN_BASE + 0x0C)
+#define SKL_ADSP_REG_ADSPIC2 (SKL_ADSP_GEN_BASE + 0x10)
+#define SKL_ADSP_REG_ADSPIS2 (SKL_ADSP_GEN_BASE + 0x14)
+
+/* Intel HD Audio Inter-Processor Communication Registers */
+#define SKL_ADSP_IPC_BASE 0x40
+#define SKL_ADSP_REG_HIPCT (SKL_ADSP_IPC_BASE + 0x00)
+#define SKL_ADSP_REG_HIPCTE (SKL_ADSP_IPC_BASE + 0x04)
+#define SKL_ADSP_REG_HIPCI (SKL_ADSP_IPC_BASE + 0x08)
+#define SKL_ADSP_REG_HIPCIE (SKL_ADSP_IPC_BASE + 0x0C)
+#define SKL_ADSP_REG_HIPCCTL (SKL_ADSP_IPC_BASE + 0x10)
+
+/* HIPCI */
+#define SKL_ADSP_REG_HIPCI_BUSY BIT(31)
+
+/* HIPCIE */
+#define SKL_ADSP_REG_HIPCIE_DONE BIT(30)
+
+/* HIPCCTL */
+#define SKL_ADSP_REG_HIPCCTL_DONE BIT(1)
+#define SKL_ADSP_REG_HIPCCTL_BUSY BIT(0)
+
+/* HIPCT */
+#define SKL_ADSP_REG_HIPCT_BUSY BIT(31)
+
+/* Intel HD Audio SRAM Window 1 */
+#define SKL_ADSP_SRAM1_BASE 0xA000
+
+#define SKL_ADSP_MMIO_LEN 0x10000
+
+#define SKL_ADSP_W0_STAT_SZ 0x800
+
+#define SKL_ADSP_W0_UP_SZ 0x800
+
+#define SKL_ADSP_W1_SZ 0x1000
+
+#define SKL_FW_STS_MASK 0xf
+
+#define SKL_FW_INIT 0x1
+#define SKL_FW_RFW_START 0xf
+
+#define SKL_ADSPIC_IPC 1
+#define SKL_ADSPIS_IPC 1
+
+/* ADSPCS - Audio DSP Control & Status */
+#define SKL_DSP_CORES 1
+#define SKL_DSP_CORE0_MASK 1
+#define SKL_DSP_CORES_MASK ((1 << SKL_DSP_CORES) - 1)
+
+/* Core Reset - asserted high */
+#define SKL_ADSPCS_CRST_SHIFT 0
+#define SKL_ADSPCS_CRST_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CRST_SHIFT)
+#define SKL_ADSPCS_CRST(x) ((x << SKL_ADSPCS_CRST_SHIFT) & SKL_ADSPCS_CRST_MASK)
+
+/* Core run/stall - when set to '1' core is stalled */
+#define SKL_ADSPCS_CSTALL_SHIFT 8
+#define SKL_ADSPCS_CSTALL_MASK (SKL_DSP_CORES_MASK << \
+ SKL_ADSPCS_CSTALL_SHIFT)
+#define SKL_ADSPCS_CSTALL(x) ((x << SKL_ADSPCS_CSTALL_SHIFT) & \
+ SKL_ADSPCS_CSTALL_MASK)
+
+/* Set Power Active - when set to '1' turn cores on */
+#define SKL_ADSPCS_SPA_SHIFT 16
+#define SKL_ADSPCS_SPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_SPA_SHIFT)
+#define SKL_ADSPCS_SPA(x) ((x << SKL_ADSPCS_SPA_SHIFT) & SKL_ADSPCS_SPA_MASK)
+
+/* Current Power Active - power status of cores, set by hardware */
+#define SKL_ADSPCS_CPA_SHIFT 24
+#define SKL_ADSPCS_CPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CPA_SHIFT)
+#define SKL_ADSPCS_CPA(x) ((x << SKL_ADSPCS_CPA_SHIFT) & SKL_ADSPCS_CPA_MASK)
+
+#define SST_DSP_POWER_D0 0x0 /* full On */
+#define SST_DSP_POWER_D3 0x3 /* Off */
+
+enum skl_dsp_states {
+ SKL_DSP_RUNNING = 1,
+ SKL_DSP_RESET,
+};
+
+struct skl_dsp_fw_ops {
+ int (*load_fw)(struct sst_dsp *ctx);
+ /* FW module parser/loader */
+ int (*parse_fw)(struct sst_dsp *ctx);
+ int (*set_state_D0)(struct sst_dsp *ctx);
+ int (*set_state_D3)(struct sst_dsp *ctx);
+ unsigned int (*get_fw_errcode)(struct sst_dsp *ctx);
+};
+
+struct skl_dsp_loader_ops {
+ int (*alloc_dma_buf)(struct device *dev,
+ struct snd_dma_buffer *dmab, size_t size);
+ int (*free_dma_buf)(struct device *dev,
+ struct snd_dma_buffer *dmab);
+};
+
+void skl_cldma_process_intr(struct sst_dsp *ctx);
+void skl_cldma_int_disable(struct sst_dsp *ctx);
+int skl_cldma_prepare(struct sst_dsp *ctx);
+
+void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state);
+struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
+ struct sst_dsp_device *sst_dev, int irq);
+int skl_dsp_disable_core(struct sst_dsp *ctx);
+bool is_skl_dsp_running(struct sst_dsp *ctx);
+irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id);
+int skl_dsp_wake(struct sst_dsp *ctx);
+int skl_dsp_sleep(struct sst_dsp *ctx);
+void skl_dsp_free(struct sst_dsp *dsp);
+
+int skl_dsp_boot(struct sst_dsp *ctx);
+int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
+ struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp);
+void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
+
+#endif /*__SKL_SST_DSP_H__*/
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
new file mode 100644
index 0000000..937a0a3
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -0,0 +1,771 @@
+/*
+ * skl-sst-ipc.c - Intel skl IPC Support
+ *
+ * Copyright (C) 2014-15, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <linux/device.h>
+
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
+
+
+#define IPC_IXC_STATUS_BITS 24
+
+/* Global Message - Generic */
+#define IPC_GLB_TYPE_SHIFT 24
+#define IPC_GLB_TYPE_MASK (0xf << IPC_GLB_TYPE_SHIFT)
+#define IPC_GLB_TYPE(x) ((x) << IPC_GLB_TYPE_SHIFT)
+
+/* Global Message - Reply */
+#define IPC_GLB_REPLY_STATUS_SHIFT 24
+#define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1)
+#define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT)
+
+#define IPC_TIMEOUT_MSECS 3000
+
+#define IPC_EMPTY_LIST_SIZE 8
+
+#define IPC_MSG_TARGET_SHIFT 30
+#define IPC_MSG_TARGET_MASK 0x1
+#define IPC_MSG_TARGET(x) (((x) & IPC_MSG_TARGET_MASK) \
+ << IPC_MSG_TARGET_SHIFT)
+
+#define IPC_MSG_DIR_SHIFT 29
+#define IPC_MSG_DIR_MASK 0x1
+#define IPC_MSG_DIR(x) (((x) & IPC_MSG_DIR_MASK) \
+ << IPC_MSG_DIR_SHIFT)
+/* Global Notification Message */
+#define IPC_GLB_NOTIFY_TYPE_SHIFT 16
+#define IPC_GLB_NOTIFY_TYPE_MASK 0xFF
+#define IPC_GLB_NOTIFY_TYPE(x) (((x) >> IPC_GLB_NOTIFY_TYPE_SHIFT) \
+ & IPC_GLB_NOTIFY_TYPE_MASK)
+
+#define IPC_GLB_NOTIFY_MSG_TYPE_SHIFT 24
+#define IPC_GLB_NOTIFY_MSG_TYPE_MASK 0x1F
+#define IPC_GLB_NOTIFY_MSG_TYPE(x) (((x) >> IPC_GLB_NOTIFY_MSG_TYPE_SHIFT) \
+ & IPC_GLB_NOTIFY_MSG_TYPE_MASK)
+
+#define IPC_GLB_NOTIFY_RSP_SHIFT 29
+#define IPC_GLB_NOTIFY_RSP_MASK 0x1
+#define IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> IPC_GLB_NOTIFY_RSP_SHIFT) \
+ & IPC_GLB_NOTIFY_RSP_MASK)
+
+/* Pipeline operations */
+
+/* Create pipeline message */
+#define IPC_PPL_MEM_SIZE_SHIFT 0
+#define IPC_PPL_MEM_SIZE_MASK 0x7FF
+#define IPC_PPL_MEM_SIZE(x) (((x) & IPC_PPL_MEM_SIZE_MASK) \
+ << IPC_PPL_MEM_SIZE_SHIFT)
+
+#define IPC_PPL_TYPE_SHIFT 11
+#define IPC_PPL_TYPE_MASK 0x1F
+#define IPC_PPL_TYPE(x) (((x) & IPC_PPL_TYPE_MASK) \
+ << IPC_PPL_TYPE_SHIFT)
+
+#define IPC_INSTANCE_ID_SHIFT 16
+#define IPC_INSTANCE_ID_MASK 0xFF
+#define IPC_INSTANCE_ID(x) (((x) & IPC_INSTANCE_ID_MASK) \
+ << IPC_INSTANCE_ID_SHIFT)
+
+/* Set pipeline state message */
+#define IPC_PPL_STATE_SHIFT 0
+#define IPC_PPL_STATE_MASK 0x1F
+#define IPC_PPL_STATE(x) (((x) & IPC_PPL_STATE_MASK) \
+ << IPC_PPL_STATE_SHIFT)
+
+/* Module operations primary register */
+#define IPC_MOD_ID_SHIFT 0
+#define IPC_MOD_ID_MASK 0xFFFF
+#define IPC_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \
+ << IPC_MOD_ID_SHIFT)
+
+#define IPC_MOD_INSTANCE_ID_SHIFT 16
+#define IPC_MOD_INSTANCE_ID_MASK 0xFF
+#define IPC_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \
+ << IPC_MOD_INSTANCE_ID_SHIFT)
+
+/* Init instance message extension register */
+#define IPC_PARAM_BLOCK_SIZE_SHIFT 0
+#define IPC_PARAM_BLOCK_SIZE_MASK 0xFFFF
+#define IPC_PARAM_BLOCK_SIZE(x) (((x) & IPC_PARAM_BLOCK_SIZE_MASK) \
+ << IPC_PARAM_BLOCK_SIZE_SHIFT)
+
+#define IPC_PPL_INSTANCE_ID_SHIFT 16
+#define IPC_PPL_INSTANCE_ID_MASK 0xFF
+#define IPC_PPL_INSTANCE_ID(x) (((x) & IPC_PPL_INSTANCE_ID_MASK) \
+ << IPC_PPL_INSTANCE_ID_SHIFT)
+
+#define IPC_CORE_ID_SHIFT 24
+#define IPC_CORE_ID_MASK 0x1F
+#define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \
+ << IPC_CORE_ID_SHIFT)
+
+/* Bind/Unbind message extension register */
+#define IPC_DST_MOD_ID_SHIFT 0
+#define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \
+ << IPC_DST_MOD_ID_SHIFT)
+
+#define IPC_DST_MOD_INSTANCE_ID_SHIFT 16
+#define IPC_DST_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \
+ << IPC_DST_MOD_INSTANCE_ID_SHIFT)
+
+#define IPC_DST_QUEUE_SHIFT 24
+#define IPC_DST_QUEUE_MASK 0x7
+#define IPC_DST_QUEUE(x) (((x) & IPC_DST_QUEUE_MASK) \
+ << IPC_DST_QUEUE_SHIFT)
+
+#define IPC_SRC_QUEUE_SHIFT 27
+#define IPC_SRC_QUEUE_MASK 0x7
+#define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \
+ << IPC_SRC_QUEUE_SHIFT)
+
+/* Save pipeline messgae extension register */
+#define IPC_DMA_ID_SHIFT 0
+#define IPC_DMA_ID_MASK 0x1F
+#define IPC_DMA_ID(x) (((x) & IPC_DMA_ID_MASK) \
+ << IPC_DMA_ID_SHIFT)
+/* Large Config message extension register */
+#define IPC_DATA_OFFSET_SZ_SHIFT 0
+#define IPC_DATA_OFFSET_SZ_MASK 0xFFFFF
+#define IPC_DATA_OFFSET_SZ(x) (((x) & IPC_DATA_OFFSET_SZ_MASK) \
+ << IPC_DATA_OFFSET_SZ_SHIFT)
+#define IPC_DATA_OFFSET_SZ_CLEAR ~(IPC_DATA_OFFSET_SZ_MASK \
+ << IPC_DATA_OFFSET_SZ_SHIFT)
+
+#define IPC_LARGE_PARAM_ID_SHIFT 20
+#define IPC_LARGE_PARAM_ID_MASK 0xFF
+#define IPC_LARGE_PARAM_ID(x) (((x) & IPC_LARGE_PARAM_ID_MASK) \
+ << IPC_LARGE_PARAM_ID_SHIFT)
+
+#define IPC_FINAL_BLOCK_SHIFT 28
+#define IPC_FINAL_BLOCK_MASK 0x1
+#define IPC_FINAL_BLOCK(x) (((x) & IPC_FINAL_BLOCK_MASK) \
+ << IPC_FINAL_BLOCK_SHIFT)
+
+#define IPC_INITIAL_BLOCK_SHIFT 29
+#define IPC_INITIAL_BLOCK_MASK 0x1
+#define IPC_INITIAL_BLOCK(x) (((x) & IPC_INITIAL_BLOCK_MASK) \
+ << IPC_INITIAL_BLOCK_SHIFT)
+#define IPC_INITIAL_BLOCK_CLEAR ~(IPC_INITIAL_BLOCK_MASK \
+ << IPC_INITIAL_BLOCK_SHIFT)
+
+enum skl_ipc_msg_target {
+ IPC_FW_GEN_MSG = 0,
+ IPC_MOD_MSG = 1
+};
+
+enum skl_ipc_msg_direction {
+ IPC_MSG_REQUEST = 0,
+ IPC_MSG_REPLY = 1
+};
+
+/* Global Message Types */
+enum skl_ipc_glb_type {
+ IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */
+ IPC_GLB_LOAD_MULTIPLE_MODS = 15,
+ IPC_GLB_UNLOAD_MULTIPLE_MODS = 16,
+ IPC_GLB_CREATE_PPL = 17,
+ IPC_GLB_DELETE_PPL = 18,
+ IPC_GLB_SET_PPL_STATE = 19,
+ IPC_GLB_GET_PPL_STATE = 20,
+ IPC_GLB_GET_PPL_CONTEXT_SIZE = 21,
+ IPC_GLB_SAVE_PPL = 22,
+ IPC_GLB_RESTORE_PPL = 23,
+ IPC_GLB_NOTIFY = 26,
+ IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */
+};
+
+enum skl_ipc_glb_reply {
+ IPC_GLB_REPLY_SUCCESS = 0,
+
+ IPC_GLB_REPLY_UNKNOWN_MSG_TYPE = 1,
+ IPC_GLB_REPLY_ERROR_INVALID_PARAM = 2,
+
+ IPC_GLB_REPLY_BUSY = 3,
+ IPC_GLB_REPLY_PENDING = 4,
+ IPC_GLB_REPLY_FAILURE = 5,
+ IPC_GLB_REPLY_INVALID_REQUEST = 6,
+
+ IPC_GLB_REPLY_OUT_OF_MEMORY = 7,
+ IPC_GLB_REPLY_OUT_OF_MIPS = 8,
+
+ IPC_GLB_REPLY_INVALID_RESOURCE_ID = 9,
+ IPC_GLB_REPLY_INVALID_RESOURCE_STATE = 10,
+
+ IPC_GLB_REPLY_MOD_MGMT_ERROR = 100,
+ IPC_GLB_REPLY_MOD_LOAD_CL_FAILED = 101,
+ IPC_GLB_REPLY_MOD_LOAD_INVALID_HASH = 102,
+
+ IPC_GLB_REPLY_MOD_UNLOAD_INST_EXIST = 103,
+ IPC_GLB_REPLY_MOD_NOT_INITIALIZED = 104,
+
+ IPC_GLB_REPLY_INVALID_CONFIG_PARAM_ID = 120,
+ IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121,
+ IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140,
+ IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141,
+
+ IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160,
+ IPC_GLB_REPLY_PPL_NOT_EXIST = 161,
+ IPC_GLB_REPLY_PPL_SAVE_FAILED = 162,
+ IPC_GLB_REPLY_PPL_RESTORE_FAILED = 163,
+
+ IPC_MAX_STATUS = ((1<<IPC_IXC_STATUS_BITS)-1)
+};
+
+enum skl_ipc_notification_type {
+ IPC_GLB_NOTIFY_GLITCH = 0,
+ IPC_GLB_NOTIFY_OVERRUN = 1,
+ IPC_GLB_NOTIFY_UNDERRUN = 2,
+ IPC_GLB_NOTIFY_END_STREAM = 3,
+ IPC_GLB_NOTIFY_PHRASE_DETECTED = 4,
+ IPC_GLB_NOTIFY_RESOURCE_EVENT = 5,
+ IPC_GLB_NOTIFY_LOG_BUFFER_STATUS = 6,
+ IPC_GLB_NOTIFY_TIMESTAMP_CAPTURED = 7,
+ IPC_GLB_NOTIFY_FW_READY = 8
+};
+
+/* Module Message Types */
+enum skl_ipc_module_msg {
+ IPC_MOD_INIT_INSTANCE = 0,
+ IPC_MOD_CONFIG_GET = 1,
+ IPC_MOD_CONFIG_SET = 2,
+ IPC_MOD_LARGE_CONFIG_GET = 3,
+ IPC_MOD_LARGE_CONFIG_SET = 4,
+ IPC_MOD_BIND = 5,
+ IPC_MOD_UNBIND = 6,
+ IPC_MOD_SET_DX = 7
+};
+
+static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
+ size_t tx_size)
+{
+ if (tx_size)
+ memcpy(msg->tx_data, tx_data, tx_size);
+}
+
+static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp)
+{
+ u32 hipci;
+
+ hipci = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCI);
+ return (hipci & SKL_ADSP_REG_HIPCI_BUSY);
+}
+
+/* Lock to be held by caller */
+static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
+{
+ struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header);
+
+ if (msg->tx_size)
+ sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size);
+ sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCIE,
+ header->extension);
+ sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCI,
+ header->primary | SKL_ADSP_REG_HIPCI_BUSY);
+}
+
+static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc,
+ u64 ipc_header)
+{
+ struct ipc_message *msg = NULL;
+ struct skl_ipc_header *header = (struct skl_ipc_header *)(&ipc_header);
+
+ if (list_empty(&ipc->rx_list)) {
+ dev_err(ipc->dev, "ipc: rx list is empty but received 0x%x\n",
+ header->primary);
+ goto out;
+ }
+
+ msg = list_first_entry(&ipc->rx_list, struct ipc_message, list);
+
+out:
+ return msg;
+
+}
+
+static int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
+ struct skl_ipc_header header)
+{
+ struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc);
+
+ if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
+ switch (IPC_GLB_NOTIFY_TYPE(header.primary)) {
+
+ case IPC_GLB_NOTIFY_UNDERRUN:
+ dev_err(ipc->dev, "FW Underrun %x\n", header.primary);
+ break;
+
+ case IPC_GLB_NOTIFY_RESOURCE_EVENT:
+ dev_err(ipc->dev, "MCPS Budget Violation: %x\n",
+ header.primary);
+ break;
+
+ case IPC_GLB_NOTIFY_FW_READY:
+ skl->boot_complete = true;
+ wake_up(&skl->boot_wait);
+ break;
+
+ default:
+ dev_err(ipc->dev, "ipc: Unhandled error msg=%x",
+ header.primary);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
+ struct skl_ipc_header header)
+{
+ struct ipc_message *msg;
+ u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK;
+ u64 *ipc_header = (u64 *)(&header);
+
+ msg = skl_ipc_reply_get_msg(ipc, *ipc_header);
+ if (msg == NULL) {
+ dev_dbg(ipc->dev, "ipc: rx list is empty\n");
+ return;
+ }
+
+ /* first process the header */
+ switch (reply) {
+ case IPC_GLB_REPLY_SUCCESS:
+ dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary);
+ break;
+
+ case IPC_GLB_REPLY_OUT_OF_MEMORY:
+ dev_err(ipc->dev, "ipc fw reply: %x: no memory\n", header.primary);
+ msg->errno = -ENOMEM;
+ break;
+
+ case IPC_GLB_REPLY_BUSY:
+ dev_err(ipc->dev, "ipc fw reply: %x: Busy\n", header.primary);
+ msg->errno = -EBUSY;
+ break;
+
+ default:
+ dev_err(ipc->dev, "Unknown ipc reply: 0x%x", reply);
+ msg->errno = -EINVAL;
+ break;
+ }
+
+ if (reply != IPC_GLB_REPLY_SUCCESS) {
+ dev_err(ipc->dev, "ipc FW reply: reply=%d", reply);
+ dev_err(ipc->dev, "FW Error Code: %u\n",
+ ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
+ }
+
+ list_del(&msg->list);
+ sst_ipc_tx_msg_reply_complete(ipc, msg);
+}
+
+irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context)
+{
+ struct sst_dsp *dsp = context;
+ struct skl_sst *skl = sst_dsp_get_thread_context(dsp);
+ struct sst_generic_ipc *ipc = &skl->ipc;
+ struct skl_ipc_header header = {0};
+ u32 hipcie, hipct, hipcte;
+ int ipc_irq = 0;
+
+ if (dsp->intr_status & SKL_ADSPIS_CL_DMA)
+ skl_cldma_process_intr(dsp);
+
+ /* Here we handle IPC interrupts only */
+ if (!(dsp->intr_status & SKL_ADSPIS_IPC))
+ return IRQ_NONE;
+
+ hipcie = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCIE);
+ hipct = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCT);
+
+ /* reply message from DSP */
+ if (hipcie & SKL_ADSP_REG_HIPCIE_DONE) {
+ sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL,
+ SKL_ADSP_REG_HIPCCTL_DONE, 0);
+
+ /* clear DONE bit - tell DSP we have completed the operation */
+ sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCIE,
+ SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE);
+
+ ipc_irq = 1;
+
+ /* unmask Done interrupt */
+ sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL,
+ SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE);
+ }
+
+ /* New message from DSP */
+ if (hipct & SKL_ADSP_REG_HIPCT_BUSY) {
+ hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE);
+ header.primary = hipct;
+ header.extension = hipcte;
+ dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x",
+ header.primary);
+ dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x",
+ header.extension);
+
+ if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) {
+ /* Handle Immediate reply from DSP Core */
+ skl_ipc_process_reply(ipc, header);
+ } else {
+ dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n");
+ skl_ipc_process_notification(ipc, header);
+ }
+ /* clear busy interrupt */
+ sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCT,
+ SKL_ADSP_REG_HIPCT_BUSY, SKL_ADSP_REG_HIPCT_BUSY);
+ ipc_irq = 1;
+ }
+
+ if (ipc_irq == 0)
+ return IRQ_NONE;
+
+ skl_ipc_int_enable(dsp);
+
+ /* continue to send any remaining messages... */
+ queue_kthread_work(&ipc->kworker, &ipc->kwork);
+
+ return IRQ_HANDLED;
+}
+
+void skl_ipc_int_enable(struct sst_dsp *ctx)
+{
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_ADSPIC,
+ SKL_ADSPIC_IPC, SKL_ADSPIC_IPC);
+}
+
+void skl_ipc_int_disable(struct sst_dsp *ctx)
+{
+ sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC,
+ SKL_ADSPIC_IPC, 0);
+}
+
+void skl_ipc_op_int_enable(struct sst_dsp *ctx)
+{
+ /* enable IPC DONE interrupt */
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL,
+ SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE);
+
+ /* Enable IPC BUSY interrupt */
+ sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL,
+ SKL_ADSP_REG_HIPCCTL_BUSY, SKL_ADSP_REG_HIPCCTL_BUSY);
+}
+
+bool skl_ipc_int_status(struct sst_dsp *ctx)
+{
+ return sst_dsp_shim_read_unlocked(ctx,
+ SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC;
+}
+
+int skl_ipc_init(struct device *dev, struct skl_sst *skl)
+{
+ struct sst_generic_ipc *ipc;
+ int err;
+
+ ipc = &skl->ipc;
+ ipc->dsp = skl->dsp;
+ ipc->dev = dev;
+
+ ipc->tx_data_max_size = SKL_ADSP_W1_SZ;
+ ipc->rx_data_max_size = SKL_ADSP_W0_UP_SZ;
+
+ err = sst_ipc_init(ipc);
+ if (err)
+ return err;
+
+ ipc->ops.tx_msg = skl_ipc_tx_msg;
+ ipc->ops.tx_data_copy = skl_ipc_tx_data_copy;
+ ipc->ops.is_dsp_busy = skl_ipc_is_dsp_busy;
+
+ return 0;
+}
+
+void skl_ipc_free(struct sst_generic_ipc *ipc)
+{
+ /* Disable IPC DONE interrupt */
+ sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL,
+ SKL_ADSP_REG_HIPCCTL_DONE, 0);
+
+ /* Disable IPC BUSY interrupt */
+ sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL,
+ SKL_ADSP_REG_HIPCCTL_BUSY, 0);
+
+ sst_ipc_fini(ipc);
+}
+
+int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc,
+ u16 ppl_mem_size, u8 ppl_type, u8 instance_id)
+{
+ struct skl_ipc_header header = {0};
+ u64 *ipc_header = (u64 *)(&header);
+ int ret;
+
+ header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
+ header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+ header.primary |= IPC_GLB_TYPE(IPC_GLB_CREATE_PPL);
+ header.primary |= IPC_INSTANCE_ID(instance_id);
+ header.primary |= IPC_PPL_TYPE(ppl_type);
+ header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size);
+
+ dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
+ ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
+ if (ret < 0) {
+ dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline);
+
+int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id)
+{
+ struct skl_ipc_header header = {0};
+ u64 *ipc_header = (u64 *)(&header);
+ int ret;
+
+ header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
+ header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+ header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL);
+ header.primary |= IPC_INSTANCE_ID(instance_id);
+
+ dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
+ ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
+ if (ret < 0) {
+ dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_delete_pipeline);
+
+int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc,
+ u8 instance_id, enum skl_ipc_pipeline_state state)
+{
+ struct skl_ipc_header header = {0};
+ u64 *ipc_header = (u64 *)(&header);
+ int ret;
+
+ header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
+ header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+ header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE);
+ header.primary |= IPC_INSTANCE_ID(instance_id);
+ header.primary |= IPC_PPL_STATE(state);
+
+ dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
+ ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
+ if (ret < 0) {
+ dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret);
+ return ret;
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_set_pipeline_state);
+
+int
+skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id)
+{
+ struct skl_ipc_header header = {0};
+ u64 *ipc_header = (u64 *)(&header);
+ int ret;
+
+ header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
+ header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+ header.primary |= IPC_GLB_TYPE(IPC_GLB_SAVE_PPL);
+ header.primary |= IPC_INSTANCE_ID(instance_id);
+
+ header.extension = IPC_DMA_ID(dma_id);
+ dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
+ ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
+ if (ret < 0) {
+ dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline);
+
+int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id)
+{
+ struct skl_ipc_header header = {0};
+ u64 *ipc_header = (u64 *)(&header);
+ int ret;
+
+ header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
+ header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+ header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL);
+ header.primary |= IPC_INSTANCE_ID(instance_id);
+
+ dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
+ ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
+ if (ret < 0) {
+ dev_err(ipc->dev, "ipc: restore pipeline failed, err: %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_restore_pipeline);
+
+int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id,
+ u16 module_id, struct skl_ipc_dxstate_info *dx)
+{
+ struct skl_ipc_header header = {0};
+ u64 *ipc_header = (u64 *)(&header);
+ int ret;
+
+ header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
+ header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+ header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_DX);
+ header.primary |= IPC_MOD_INSTANCE_ID(instance_id);
+ header.primary |= IPC_MOD_ID(module_id);
+
+ dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
+ header.primary, header.extension);
+ ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
+ dx, sizeof(dx), NULL, 0);
+ if (ret < 0) {
+ dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_set_dx);
+
+int skl_ipc_init_instance(struct sst_generic_ipc *ipc,
+ struct skl_ipc_init_instance_msg *msg, void *param_data)
+{
+ struct skl_ipc_header header = {0};
+ u64 *ipc_header = (u64 *)(&header);
+ int ret;
+ u32 *buffer = (u32 *)param_data;
+ /* param_block_size must be in dwords */
+ u16 param_block_size = msg->param_data_size / sizeof(u32);
+
+ print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE,
+ 16, 4, buffer, param_block_size, false);
+
+ header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
+ header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+ header.primary |= IPC_GLB_TYPE(IPC_MOD_INIT_INSTANCE);
+ header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
+ header.primary |= IPC_MOD_ID(msg->module_id);
+
+ header.extension = IPC_CORE_ID(msg->core_id);
+ header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id);
+ header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size);
+
+ dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
+ header.primary, header.extension);
+ ret = sst_ipc_tx_message_wait(ipc, *ipc_header, param_data,
+ msg->param_data_size, NULL, 0);
+
+ if (ret < 0) {
+ dev_err(ipc->dev, "ipc: init instance failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_init_instance);
+
+int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc,
+ struct skl_ipc_bind_unbind_msg *msg)
+{
+ struct skl_ipc_header header = {0};
+ u64 *ipc_header = (u64 *)(&header);
+ u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND;
+ int ret;
+
+ header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
+ header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+ header.primary |= IPC_GLB_TYPE(bind_unbind);
+ header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
+ header.primary |= IPC_MOD_ID(msg->module_id);
+
+ header.extension = IPC_DST_MOD_ID(msg->dst_module_id);
+ header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id);
+ header.extension |= IPC_DST_QUEUE(msg->dst_queue);
+ header.extension |= IPC_SRC_QUEUE(msg->src_queue);
+
+ dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary,
+ header.extension);
+ ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
+ if (ret < 0) {
+ dev_err(ipc->dev, "ipc: bind/unbind faileden");
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind);
+
+int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
+ struct skl_ipc_large_config_msg *msg, u32 *param)
+{
+ struct skl_ipc_header header = {0};
+ u64 *ipc_header = (u64 *)(&header);
+ int ret = 0;
+ size_t sz_remaining, tx_size, data_offset;
+
+ header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
+ header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+ header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_SET);
+ header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
+ header.primary |= IPC_MOD_ID(msg->module_id);
+
+ header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size);
+ header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id);
+ header.extension |= IPC_FINAL_BLOCK(0);
+ header.extension |= IPC_INITIAL_BLOCK(1);
+
+ sz_remaining = msg->param_data_size;
+ data_offset = 0;
+ while (sz_remaining != 0) {
+ tx_size = sz_remaining > SKL_ADSP_W1_SZ
+ ? SKL_ADSP_W1_SZ : sz_remaining;
+ if (tx_size == sz_remaining)
+ header.extension |= IPC_FINAL_BLOCK(1);
+
+ dev_dbg(ipc->dev, "In %s primary=%#x ext=%#x\n", __func__,
+ header.primary, header.extension);
+ dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n",
+ (unsigned)data_offset, (unsigned)tx_size);
+ ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
+ ((char *)param) + data_offset,
+ tx_size, NULL, 0);
+ if (ret < 0) {
+ dev_err(ipc->dev,
+ "ipc: set large config fail, err: %d\n", ret);
+ return ret;
+ }
+ sz_remaining -= tx_size;
+ data_offset = msg->param_data_size - sz_remaining;
+
+ /* clear the fields */
+ header.extension &= IPC_INITIAL_BLOCK_CLEAR;
+ header.extension &= IPC_DATA_OFFSET_SZ_CLEAR;
+ /* fill the fields */
+ header.extension |= IPC_INITIAL_BLOCK(0);
+ header.extension |= IPC_DATA_OFFSET_SZ(data_offset);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_set_large_config);
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
new file mode 100644
index 0000000..9f5f672
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -0,0 +1,125 @@
+/*
+ * Intel SKL IPC Support
+ *
+ * Copyright (C) 2014-15, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __SKL_IPC_H
+#define __SKL_IPC_H
+
+#include <linux/kthread.h>
+#include <linux/irqreturn.h>
+#include "../common/sst-ipc.h"
+
+struct sst_dsp;
+struct skl_sst;
+struct sst_generic_ipc;
+
+enum skl_ipc_pipeline_state {
+ PPL_INVALID_STATE = 0,
+ PPL_UNINITIALIZED = 1,
+ PPL_RESET = 2,
+ PPL_PAUSED = 3,
+ PPL_RUNNING = 4,
+ PPL_ERROR_STOP = 5,
+ PPL_SAVED = 6,
+ PPL_RESTORED = 7
+};
+
+struct skl_ipc_dxstate_info {
+ u32 core_mask;
+ u32 dx_mask;
+};
+
+struct skl_ipc_header {
+ u32 primary;
+ u32 extension;
+};
+
+struct skl_sst {
+ struct device *dev;
+ struct sst_dsp *dsp;
+
+ /* boot */
+ wait_queue_head_t boot_wait;
+ bool boot_complete;
+
+ /* IPC messaging */
+ struct sst_generic_ipc ipc;
+};
+
+struct skl_ipc_init_instance_msg {
+ u32 module_id;
+ u32 instance_id;
+ u16 param_data_size;
+ u8 ppl_instance_id;
+ u8 core_id;
+};
+
+struct skl_ipc_bind_unbind_msg {
+ u32 module_id;
+ u32 instance_id;
+ u32 dst_module_id;
+ u32 dst_instance_id;
+ u8 src_queue;
+ u8 dst_queue;
+ bool bind;
+};
+
+struct skl_ipc_large_config_msg {
+ u32 module_id;
+ u32 instance_id;
+ u32 large_param_id;
+ u32 param_data_size;
+};
+
+#define SKL_IPC_BOOT_MSECS 3000
+
+#define SKL_IPC_D3_MASK 0
+#define SKL_IPC_D0_MASK 3
+
+irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context);
+
+int skl_ipc_create_pipeline(struct sst_generic_ipc *sst_ipc,
+ u16 ppl_mem_size, u8 ppl_type, u8 instance_id);
+
+int skl_ipc_delete_pipeline(struct sst_generic_ipc *sst_ipc, u8 instance_id);
+
+int skl_ipc_set_pipeline_state(struct sst_generic_ipc *sst_ipc,
+ u8 instance_id, enum skl_ipc_pipeline_state state);
+
+int skl_ipc_save_pipeline(struct sst_generic_ipc *ipc,
+ u8 instance_id, int dma_id);
+
+int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id);
+
+int skl_ipc_init_instance(struct sst_generic_ipc *sst_ipc,
+ struct skl_ipc_init_instance_msg *msg, void *param_data);
+
+int skl_ipc_bind_unbind(struct sst_generic_ipc *sst_ipc,
+ struct skl_ipc_bind_unbind_msg *msg);
+
+int skl_ipc_set_dx(struct sst_generic_ipc *ipc,
+ u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx);
+
+int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
+ struct skl_ipc_large_config_msg *msg, u32 *param);
+
+void skl_ipc_int_enable(struct sst_dsp *dsp);
+void skl_ipc_op_int_enable(struct sst_dsp *ctx);
+void skl_ipc_int_disable(struct sst_dsp *dsp);
+
+bool skl_ipc_int_status(struct sst_dsp *dsp);
+void skl_ipc_free(struct sst_generic_ipc *ipc);
+int skl_ipc_init(struct device *dev, struct skl_sst *skl);
+
+#endif /* __SKL_IPC_H */
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
new file mode 100644
index 0000000..c18ea51
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -0,0 +1,280 @@
+/*
+ * skl-sst.c - HDA DSP library functions for SKL platform
+ *
+ * Copyright (C) 2014-15, Intel Corporation.
+ * Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
+ * Jeeja KP <jeeja.kp@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
+#include "../common/sst-ipc.h"
+#include "skl-sst-ipc.h"
+
+#define SKL_BASEFW_TIMEOUT 300
+#define SKL_INIT_TIMEOUT 1000
+
+/* Intel HD Audio SRAM Window 0*/
+#define SKL_ADSP_SRAM0_BASE 0x8000
+
+/* Firmware status window */
+#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE
+#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4)
+
+#define SKL_INSTANCE_ID 0
+#define SKL_BASE_FW_MODULE_ID 0
+
+static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status)
+{
+ u32 cur_sts;
+
+ cur_sts = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS) & SKL_FW_STS_MASK;
+
+ return (cur_sts == status);
+}
+
+static int skl_transfer_firmware(struct sst_dsp *ctx,
+ const void *basefw, u32 base_fw_size)
+{
+ int ret = 0;
+
+ ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size);
+ if (ret < 0)
+ return ret;
+
+ ret = sst_dsp_register_poll(ctx,
+ SKL_ADSP_FW_STATUS,
+ SKL_FW_STS_MASK,
+ SKL_FW_RFW_START,
+ SKL_BASEFW_TIMEOUT,
+ "Firmware boot");
+
+ ctx->cl_dev.ops.cl_stop_dma(ctx);
+
+ return ret;
+}
+
+static int skl_load_base_firmware(struct sst_dsp *ctx)
+{
+ int ret = 0, i;
+ const struct firmware *fw = NULL;
+ struct skl_sst *skl = ctx->thread_context;
+ u32 reg;
+
+ ret = request_firmware(&fw, "dsp_fw_release.bin", ctx->dev);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Request firmware failed %d\n", ret);
+ skl_dsp_disable_core(ctx);
+ return -EIO;
+ }
+
+ /* enable Interrupt */
+ skl_ipc_int_enable(ctx);
+ skl_ipc_op_int_enable(ctx);
+
+ /* check ROM Status */
+ for (i = SKL_INIT_TIMEOUT; i > 0; --i) {
+ if (skl_check_fw_status(ctx, SKL_FW_INIT)) {
+ dev_dbg(ctx->dev,
+ "ROM loaded, we can continue with FW loading\n");
+ break;
+ }
+ mdelay(1);
+ }
+ if (!i) {
+ reg = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS);
+ dev_err(ctx->dev,
+ "Timeout waiting for ROM init done, reg:0x%x\n", reg);
+ ret = -EIO;
+ goto skl_load_base_firmware_failed;
+ }
+
+ ret = skl_transfer_firmware(ctx, fw->data, fw->size);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Transfer firmware failed%d\n", ret);
+ goto skl_load_base_firmware_failed;
+ } else {
+ ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
+ msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
+ if (ret == 0) {
+ dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n");
+ ret = -EIO;
+ goto skl_load_base_firmware_failed;
+ }
+
+ dev_dbg(ctx->dev, "Download firmware successful%d\n", ret);
+ skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
+ }
+ release_firmware(fw);
+
+ return 0;
+
+skl_load_base_firmware_failed:
+ skl_dsp_disable_core(ctx);
+ release_firmware(fw);
+ return ret;
+}
+
+static int skl_set_dsp_D0(struct sst_dsp *ctx)
+{
+ int ret;
+
+ ret = skl_load_base_firmware(ctx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "unable to load firmware\n");
+ return ret;
+ }
+
+ skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
+
+ return ret;
+}
+
+static int skl_set_dsp_D3(struct sst_dsp *ctx)
+{
+ int ret;
+ struct skl_ipc_dxstate_info dx;
+ struct skl_sst *skl = ctx->thread_context;
+
+ dev_dbg(ctx->dev, "In %s:\n", __func__);
+ mutex_lock(&ctx->mutex);
+ if (!is_skl_dsp_running(ctx)) {
+ mutex_unlock(&ctx->mutex);
+ return 0;
+ }
+ mutex_unlock(&ctx->mutex);
+
+ dx.core_mask = SKL_DSP_CORE0_MASK;
+ dx.dx_mask = SKL_IPC_D3_MASK;
+ ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to set DSP to D3 state\n");
+ return ret;
+ }
+
+ ret = skl_dsp_disable_core(ctx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "disable dsp core failed ret: %d\n", ret);
+ ret = -EIO;
+ }
+ skl_dsp_set_state_locked(ctx, SKL_DSP_RESET);
+
+ return ret;
+}
+
+static unsigned int skl_get_errorcode(struct sst_dsp *ctx)
+{
+ return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE);
+}
+
+static struct skl_dsp_fw_ops skl_fw_ops = {
+ .set_state_D0 = skl_set_dsp_D0,
+ .set_state_D3 = skl_set_dsp_D3,
+ .load_fw = skl_load_base_firmware,
+ .get_fw_errcode = skl_get_errorcode,
+};
+
+static struct sst_ops skl_ops = {
+ .irq_handler = skl_dsp_sst_interrupt,
+ .write = sst_shim32_write,
+ .read = sst_shim32_read,
+ .ram_read = sst_memcpy_fromio_32,
+ .ram_write = sst_memcpy_toio_32,
+ .free = skl_dsp_free,
+};
+
+static struct sst_dsp_device skl_dev = {
+ .thread = skl_dsp_irq_thread_handler,
+ .ops = &skl_ops,
+};
+
+int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
+ struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp)
+{
+ struct skl_sst *skl;
+ struct sst_dsp *sst;
+ int ret;
+
+ skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
+ if (skl == NULL)
+ return -ENOMEM;
+
+ skl->dev = dev;
+ skl_dev.thread_context = skl;
+
+ skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq);
+ if (!skl->dsp) {
+ dev_err(skl->dev, "%s: no device\n", __func__);
+ return -ENODEV;
+ }
+
+ sst = skl->dsp;
+
+ sst->addr.lpe = mmio_base;
+ sst->addr.shim = mmio_base;
+ sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
+ SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
+
+ sst->dsp_ops = dsp_ops;
+ sst->fw_ops = skl_fw_ops;
+
+ ret = skl_ipc_init(dev, skl);
+ if (ret)
+ return ret;
+
+ skl->boot_complete = false;
+ init_waitqueue_head(&skl->boot_wait);
+
+ ret = skl_dsp_boot(sst);
+ if (ret < 0) {
+ dev_err(skl->dev, "Boot dsp core failed ret: %d", ret);
+ goto free_ipc;
+ }
+
+ ret = skl_cldma_prepare(sst);
+ if (ret < 0) {
+ dev_err(dev, "CL dma prepare failed : %d", ret);
+ goto free_ipc;
+ }
+
+
+ ret = sst->fw_ops.load_fw(sst);
+ if (ret < 0) {
+ dev_err(dev, "Load base fw failed : %d", ret);
+ return ret;
+ }
+
+ if (dsp)
+ *dsp = skl;
+
+ return 0;
+
+free_ipc:
+ skl_ipc_free(&skl->ipc);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
+
+void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
+{
+ skl_ipc_free(&ctx->ipc);
+ ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
+ ctx->dsp->ops->free(ctx->dsp);
+}
+EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Skylake IPC driver");
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
new file mode 100644
index 0000000..8c7767b
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -0,0 +1,286 @@
+/*
+ * skl_topology.h - Intel HDA Platform topology header file
+ *
+ * Copyright (C) 2014-15 Intel Corp
+ * Author: Jeeja KP <jeeja.kp@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#ifndef __SKL_TOPOLOGY_H__
+#define __SKL_TOPOLOGY_H__
+
+#include <linux/types.h>
+
+#include <sound/hdaudio_ext.h>
+#include <sound/soc.h>
+#include "skl.h"
+#include "skl-tplg-interface.h"
+
+#define BITS_PER_BYTE 8
+#define MAX_TS_GROUPS 8
+#define MAX_DMIC_TS_GROUPS 4
+#define MAX_FIXED_DMIC_PARAMS_SIZE 727
+
+/* Maximum number of coefficients up down mixer module */
+#define UP_DOWN_MIXER_MAX_COEFF 6
+
+enum skl_channel_index {
+ SKL_CHANNEL_LEFT = 0,
+ SKL_CHANNEL_RIGHT = 1,
+ SKL_CHANNEL_CENTER = 2,
+ SKL_CHANNEL_LEFT_SURROUND = 3,
+ SKL_CHANNEL_CENTER_SURROUND = 3,
+ SKL_CHANNEL_RIGHT_SURROUND = 4,
+ SKL_CHANNEL_LFE = 7,
+ SKL_CHANNEL_INVALID = 0xF,
+};
+
+enum skl_bitdepth {
+ SKL_DEPTH_8BIT = 8,
+ SKL_DEPTH_16BIT = 16,
+ SKL_DEPTH_24BIT = 24,
+ SKL_DEPTH_32BIT = 32,
+ SKL_DEPTH_INVALID
+};
+
+enum skl_interleaving {
+ /* [s1_ch1...s1_chN,...,sM_ch1...sM_chN] */
+ SKL_INTERLEAVING_PER_CHANNEL = 0,
+ /* [s1_ch1...sM_ch1,...,s1_chN...sM_chN] */
+ SKL_INTERLEAVING_PER_SAMPLE = 1,
+};
+
+enum skl_s_freq {
+ SKL_FS_8000 = 8000,
+ SKL_FS_11025 = 11025,
+ SKL_FS_12000 = 12000,
+ SKL_FS_16000 = 16000,
+ SKL_FS_22050 = 22050,
+ SKL_FS_24000 = 24000,
+ SKL_FS_32000 = 32000,
+ SKL_FS_44100 = 44100,
+ SKL_FS_48000 = 48000,
+ SKL_FS_64000 = 64000,
+ SKL_FS_88200 = 88200,
+ SKL_FS_96000 = 96000,
+ SKL_FS_128000 = 128000,
+ SKL_FS_176400 = 176400,
+ SKL_FS_192000 = 192000,
+ SKL_FS_INVALID
+};
+
+enum skl_widget_type {
+ SKL_WIDGET_VMIXER = 1,
+ SKL_WIDGET_MIXER = 2,
+ SKL_WIDGET_PGA = 3,
+ SKL_WIDGET_MUX = 4
+};
+
+struct skl_audio_data_format {
+ enum skl_s_freq s_freq;
+ enum skl_bitdepth bit_depth;
+ u32 channel_map;
+ enum skl_ch_cfg ch_cfg;
+ enum skl_interleaving interleaving;
+ u8 number_of_channels;
+ u8 valid_bit_depth;
+ u8 sample_type;
+ u8 reserved[1];
+} __packed;
+
+struct skl_base_cfg {
+ u32 cps;
+ u32 ibs;
+ u32 obs;
+ u32 is_pages;
+ struct skl_audio_data_format audio_fmt;
+};
+
+struct skl_cpr_gtw_cfg {
+ u32 node_id;
+ u32 dma_buffer_size;
+ u32 config_length;
+ /* not mandatory; required only for DMIC/I2S */
+ u32 config_data[1];
+} __packed;
+
+struct skl_cpr_cfg {
+ struct skl_base_cfg base_cfg;
+ struct skl_audio_data_format out_fmt;
+ u32 cpr_feature_mask;
+ struct skl_cpr_gtw_cfg gtw_cfg;
+} __packed;
+
+
+struct skl_src_module_cfg {
+ struct skl_base_cfg base_cfg;
+ enum skl_s_freq src_cfg;
+} __packed;
+
+struct skl_up_down_mixer_cfg {
+ struct skl_base_cfg base_cfg;
+ enum skl_ch_cfg out_ch_cfg;
+ /* This should be set to 1 if user coefficients are required */
+ u32 coeff_sel;
+ /* Pass the user coeff in this array */
+ s32 coeff[UP_DOWN_MIXER_MAX_COEFF];
+} __packed;
+
+enum skl_dma_type {
+ SKL_DMA_HDA_HOST_OUTPUT_CLASS = 0,
+ SKL_DMA_HDA_HOST_INPUT_CLASS = 1,
+ SKL_DMA_HDA_HOST_INOUT_CLASS = 2,
+ SKL_DMA_HDA_LINK_OUTPUT_CLASS = 8,
+ SKL_DMA_HDA_LINK_INPUT_CLASS = 9,
+ SKL_DMA_HDA_LINK_INOUT_CLASS = 0xA,
+ SKL_DMA_DMIC_LINK_INPUT_CLASS = 0xB,
+ SKL_DMA_I2S_LINK_OUTPUT_CLASS = 0xC,
+ SKL_DMA_I2S_LINK_INPUT_CLASS = 0xD,
+};
+
+union skl_ssp_dma_node {
+ u8 val;
+ struct {
+ u8 dual_mono:1;
+ u8 time_slot:3;
+ u8 i2s_instance:4;
+ } dma_node;
+};
+
+union skl_connector_node_id {
+ u32 val;
+ struct {
+ u32 vindex:8;
+ u32 dma_type:4;
+ u32 rsvd:20;
+ } node;
+};
+
+struct skl_module_fmt {
+ u32 channels;
+ u32 s_freq;
+ u32 bit_depth;
+ u32 valid_bit_depth;
+ u32 ch_cfg;
+};
+
+struct skl_module_inst_id {
+ u32 module_id;
+ u32 instance_id;
+};
+
+struct skl_module_pin {
+ struct skl_module_inst_id id;
+ u8 pin_index;
+ bool is_dynamic;
+ bool in_use;
+};
+
+struct skl_specific_cfg {
+ u32 caps_size;
+ u32 *caps;
+};
+
+enum skl_pipe_state {
+ SKL_PIPE_INVALID = 0,
+ SKL_PIPE_CREATED = 1,
+ SKL_PIPE_PAUSED = 2,
+ SKL_PIPE_STARTED = 3
+};
+
+struct skl_pipe_module {
+ struct snd_soc_dapm_widget *w;
+ struct list_head node;
+};
+
+struct skl_pipe_params {
+ u8 host_dma_id;
+ u8 link_dma_id;
+ u32 ch;
+ u32 s_freq;
+ u32 s_fmt;
+ u8 linktype;
+ int stream;
+};
+
+struct skl_pipe {
+ u8 ppl_id;
+ u8 pipe_priority;
+ u16 conn_type;
+ u32 memory_pages;
+ struct skl_pipe_params *p_params;
+ enum skl_pipe_state state;
+ struct list_head w_list;
+};
+
+enum skl_module_state {
+ SKL_MODULE_UNINIT = 0,
+ SKL_MODULE_INIT_DONE = 1,
+ SKL_MODULE_LOADED = 2,
+ SKL_MODULE_UNLOADED = 3,
+ SKL_MODULE_BIND_DONE = 4
+};
+
+struct skl_module_cfg {
+ struct skl_module_inst_id id;
+ struct skl_module_fmt in_fmt;
+ struct skl_module_fmt out_fmt;
+ u8 max_in_queue;
+ u8 max_out_queue;
+ u8 in_queue_mask;
+ u8 out_queue_mask;
+ u8 in_queue;
+ u8 out_queue;
+ u32 mcps;
+ u32 ibs;
+ u32 obs;
+ u8 is_loadable;
+ u8 core_id;
+ u8 dev_type;
+ u8 dma_id;
+ u8 time_slot;
+ u32 params_fixup;
+ u32 converter;
+ u32 vbus_id;
+ struct skl_module_pin *m_in_pin;
+ struct skl_module_pin *m_out_pin;
+ enum skl_module_type m_type;
+ enum skl_hw_conn_type hw_conn_type;
+ enum skl_module_state m_state;
+ struct skl_pipe *pipe;
+ struct skl_specific_cfg formats_config;
+};
+
+int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe);
+
+int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
+
+int skl_pause_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
+
+int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
+
+int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
+
+int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config,
+ char *param);
+
+int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg
+ *src_module, struct skl_module_cfg *dst_module);
+
+int skl_unbind_modules(struct skl_sst *ctx, struct skl_module_cfg
+ *src_module, struct skl_module_cfg *dst_module);
+
+enum skl_bitdepth skl_get_bit_depth(int params);
+#endif
diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h
new file mode 100644
index 0000000..a506898
--- /dev/null
+++ b/sound/soc/intel/skylake/skl-tplg-interface.h
@@ -0,0 +1,88 @@
+/*
+ * skl-tplg-interface.h - Intel DSP FW private data interface
+ *
+ * Copyright (C) 2015 Intel Corp
+ * Author: Jeeja KP <jeeja.kp@intel.com>
+ * Nilofer, Samreen <samreen.nilofer@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __HDA_TPLG_INTERFACE_H__
+#define __HDA_TPLG_INTERFACE_H__
+
+/**
+ * enum skl_ch_cfg - channel configuration
+ *
+ * @SKL_CH_CFG_MONO: One channel only
+ * @SKL_CH_CFG_STEREO: L & R
+ * @SKL_CH_CFG_2_1: L, R & LFE
+ * @SKL_CH_CFG_3_0: L, C & R
+ * @SKL_CH_CFG_3_1: L, C, R & LFE
+ * @SKL_CH_CFG_QUATRO: L, R, Ls & Rs
+ * @SKL_CH_CFG_4_0: L, C, R & Cs
+ * @SKL_CH_CFG_5_0: L, C, R, Ls & Rs
+ * @SKL_CH_CFG_5_1: L, C, R, Ls, Rs & LFE
+ * @SKL_CH_CFG_DUAL_MONO: One channel replicated in two
+ * @SKL_CH_CFG_I2S_DUAL_STEREO_0: Stereo(L,R) in 4 slots, 1st stream:[ L, R, -, - ]
+ * @SKL_CH_CFG_I2S_DUAL_STEREO_1: Stereo(L,R) in 4 slots, 2nd stream:[ -, -, L, R ]
+ * @SKL_CH_CFG_INVALID: Invalid
+ */
+enum skl_ch_cfg {
+ SKL_CH_CFG_MONO = 0,
+ SKL_CH_CFG_STEREO = 1,
+ SKL_CH_CFG_2_1 = 2,
+ SKL_CH_CFG_3_0 = 3,
+ SKL_CH_CFG_3_1 = 4,
+ SKL_CH_CFG_QUATRO = 5,
+ SKL_CH_CFG_4_0 = 6,
+ SKL_CH_CFG_5_0 = 7,
+ SKL_CH_CFG_5_1 = 8,
+ SKL_CH_CFG_DUAL_MONO = 9,
+ SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10,
+ SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11,
+ SKL_CH_CFG_INVALID
+};
+
+enum skl_module_type {
+ SKL_MODULE_TYPE_MIXER = 0,
+ SKL_MODULE_TYPE_COPIER,
+ SKL_MODULE_TYPE_UPDWMIX,
+ SKL_MODULE_TYPE_SRCINT
+};
+
+enum skl_core_affinity {
+ SKL_AFFINITY_CORE_0 = 0,
+ SKL_AFFINITY_CORE_1,
+ SKL_AFFINITY_CORE_MAX
+};
+
+enum skl_pipe_conn_type {
+ SKL_PIPE_CONN_TYPE_NONE = 0,
+ SKL_PIPE_CONN_TYPE_FE,
+ SKL_PIPE_CONN_TYPE_BE
+};
+
+enum skl_hw_conn_type {
+ SKL_CONN_NONE = 0,
+ SKL_CONN_SOURCE = 1,
+ SKL_CONN_SINK = 2
+};
+
+enum skl_dev_type {
+ SKL_DEVICE_BT = 0x0,
+ SKL_DEVICE_DMIC = 0x1,
+ SKL_DEVICE_I2S = 0x2,
+ SKL_DEVICE_SLIMBUS = 0x3,
+ SKL_DEVICE_HDALINK = 0x4,
+ SKL_DEVICE_NONE
+};
+#endif
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
new file mode 100644
index 0000000..348d094
--- /dev/null
+++ b/sound/soc/intel/skylake/skl.c
@@ -0,0 +1,536 @@
+/*
+ * skl.c - Implementation of ASoC Intel SKL HD Audio driver
+ *
+ * Copyright (C) 2014-2015 Intel Corp
+ * Author: Jeeja KP <jeeja.kp@intel.com>
+ *
+ * Derived mostly from Intel HDA driver with following copyrights:
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ * PeiSen Hou <pshou@realtek.com.tw>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include "skl.h"
+
+/*
+ * initialize the PCI registers
+ */
+static void skl_update_pci_byte(struct pci_dev *pci, unsigned int reg,
+ unsigned char mask, unsigned char val)
+{
+ unsigned char data;
+
+ pci_read_config_byte(pci, reg, &data);
+ data &= ~mask;
+ data |= (val & mask);
+ pci_write_config_byte(pci, reg, data);
+}
+
+static void skl_init_pci(struct skl *skl)
+{
+ struct hdac_ext_bus *ebus = &skl->ebus;
+
+ /*
+ * Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
+ * TCSEL == Traffic Class Select Register, which sets PCI express QOS
+ * Ensuring these bits are 0 clears playback static on some HD Audio
+ * codecs.
+ * The PCI register TCSEL is defined in the Intel manuals.
+ */
+ dev_dbg(ebus_to_hbus(ebus)->dev, "Clearing TCSEL\n");
+ skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0);
+}
+
+/* called from IRQ */
+static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
+{
+ snd_pcm_period_elapsed(hstr->substream);
+}
+
+static irqreturn_t skl_interrupt(int irq, void *dev_id)
+{
+ struct hdac_ext_bus *ebus = dev_id;
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ u32 status;
+
+ if (!pm_runtime_active(bus->dev))
+ return IRQ_NONE;
+
+ spin_lock(&bus->reg_lock);
+
+ status = snd_hdac_chip_readl(bus, INTSTS);
+ if (status == 0 || status == 0xffffffff) {
+ spin_unlock(&bus->reg_lock);
+ return IRQ_NONE;
+ }
+
+ /* clear rirb int */
+ status = snd_hdac_chip_readb(bus, RIRBSTS);
+ if (status & RIRB_INT_MASK) {
+ if (status & RIRB_INT_RESPONSE)
+ snd_hdac_bus_update_rirb(bus);
+ snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
+ }
+
+ spin_unlock(&bus->reg_lock);
+
+ return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+}
+
+static irqreturn_t skl_threaded_handler(int irq, void *dev_id)
+{
+ struct hdac_ext_bus *ebus = dev_id;
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ u32 status;
+
+ status = snd_hdac_chip_readl(bus, INTSTS);
+
+ snd_hdac_bus_handle_stream_irq(bus, status, skl_stream_update);
+
+ return IRQ_HANDLED;
+}
+
+static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect)
+{
+ struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ int ret;
+
+ ret = request_threaded_irq(skl->pci->irq, skl_interrupt,
+ skl_threaded_handler,
+ IRQF_SHARED,
+ KBUILD_MODNAME, ebus);
+ if (ret) {
+ dev_err(bus->dev,
+ "unable to grab IRQ %d, disabling device\n",
+ skl->pci->irq);
+ return ret;
+ }
+
+ bus->irq = skl->pci->irq;
+ pci_intx(skl->pci, 1);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * power management
+ */
+static int skl_suspend(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+
+ snd_hdac_bus_stop_chip(bus);
+ snd_hdac_bus_enter_link_reset(bus);
+
+ return 0;
+}
+
+static int skl_resume(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct skl *hda = ebus_to_skl(ebus);
+
+ skl_init_pci(hda);
+
+ snd_hdac_bus_init_chip(bus, 1);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int skl_runtime_suspend(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+
+ dev_dbg(bus->dev, "in %s\n", __func__);
+
+ /* enable controller wake up event */
+ snd_hdac_chip_updatew(bus, WAKEEN, 0, STATESTS_INT_MASK);
+
+ snd_hdac_bus_stop_chip(bus);
+ snd_hdac_bus_enter_link_reset(bus);
+
+ return 0;
+}
+
+static int skl_runtime_resume(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct skl *hda = ebus_to_skl(ebus);
+ int status;
+
+ dev_dbg(bus->dev, "in %s\n", __func__);
+
+ /* Read STATESTS before controller reset */
+ status = snd_hdac_chip_readw(bus, STATESTS);
+
+ skl_init_pci(hda);
+ snd_hdac_bus_init_chip(bus, true);
+ /* disable controller Wake Up event */
+ snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops skl_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume)
+ SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL)
+};
+
+/*
+ * destructor
+ */
+static int skl_free(struct hdac_ext_bus *ebus)
+{
+ struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+
+ skl->init_failed = 1; /* to be sure */
+
+ snd_hdac_ext_stop_streams(ebus);
+
+ if (bus->irq >= 0)
+ free_irq(bus->irq, (void *)bus);
+ if (bus->remap_addr)
+ iounmap(bus->remap_addr);
+
+ snd_hdac_bus_free_stream_pages(bus);
+ snd_hdac_stream_free_all(ebus);
+ snd_hdac_link_free_all(ebus);
+ pci_release_regions(skl->pci);
+ pci_disable_device(skl->pci);
+
+ snd_hdac_ext_bus_exit(ebus);
+
+ return 0;
+}
+
+static int skl_dmic_device_register(struct skl *skl)
+{
+ struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+ struct platform_device *pdev;
+ int ret;
+
+ /* SKL has one dmic port, so allocate dmic device for this */
+ pdev = platform_device_alloc("dmic-codec", -1);
+ if (!pdev) {
+ dev_err(bus->dev, "failed to allocate dmic device\n");
+ return -ENOMEM;
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ dev_err(bus->dev, "failed to add dmic device: %d\n", ret);
+ platform_device_put(pdev);
+ return ret;
+ }
+ skl->dmic_dev = pdev;
+
+ return 0;
+}
+
+static void skl_dmic_device_unregister(struct skl *skl)
+{
+ if (skl->dmic_dev)
+ platform_device_unregister(skl->dmic_dev);
+}
+
+/*
+ * Probe the given codec address
+ */
+static int probe_codec(struct hdac_ext_bus *ebus, int addr)
+{
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
+ (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
+ unsigned int res;
+
+ mutex_lock(&bus->cmd_mutex);
+ snd_hdac_bus_send_cmd(bus, cmd);
+ snd_hdac_bus_get_response(bus, addr, &res);
+ mutex_unlock(&bus->cmd_mutex);
+ if (res == -1)
+ return -EIO;
+ dev_dbg(bus->dev, "codec #%d probed OK\n", addr);
+
+ return snd_hdac_ext_bus_device_init(ebus, addr);
+}
+
+/* Codec initialization */
+static int skl_codec_create(struct hdac_ext_bus *ebus)
+{
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ int c, max_slots;
+
+ max_slots = HDA_MAX_CODECS;
+
+ /* First try to probe all given codec slots */
+ for (c = 0; c < max_slots; c++) {
+ if ((bus->codec_mask & (1 << c))) {
+ if (probe_codec(ebus, c) < 0) {
+ /*
+ * Some BIOSen give you wrong codec addresses
+ * that don't exist
+ */
+ dev_warn(bus->dev,
+ "Codec #%d probe error; disabling it...\n", c);
+ bus->codec_mask &= ~(1 << c);
+ /*
+ * More badly, accessing to a non-existing
+ * codec often screws up the controller bus,
+ * and disturbs the further communications.
+ * Thus if an error occurs during probing,
+ * better to reset the controller bus to get
+ * back to the sanity state.
+ */
+ snd_hdac_bus_stop_chip(bus);
+ snd_hdac_bus_init_chip(bus, true);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const struct hdac_bus_ops bus_core_ops = {
+ .command = snd_hdac_bus_send_cmd,
+ .get_response = snd_hdac_bus_get_response,
+};
+
+/*
+ * constructor
+ */
+static int skl_create(struct pci_dev *pci,
+ const struct hdac_io_ops *io_ops,
+ struct skl **rskl)
+{
+ struct skl *skl;
+ struct hdac_ext_bus *ebus;
+
+ int err;
+
+ *rskl = NULL;
+
+ err = pci_enable_device(pci);
+ if (err < 0)
+ return err;
+
+ skl = devm_kzalloc(&pci->dev, sizeof(*skl), GFP_KERNEL);
+ if (!skl) {
+ pci_disable_device(pci);
+ return -ENOMEM;
+ }
+ ebus = &skl->ebus;
+ snd_hdac_ext_bus_init(ebus, &pci->dev, &bus_core_ops, io_ops);
+ ebus->bus.use_posbuf = 1;
+ skl->pci = pci;
+
+ ebus->bus.bdl_pos_adj = 0;
+
+ *rskl = skl;
+
+ return 0;
+}
+
+static int skl_first_init(struct hdac_ext_bus *ebus)
+{
+ struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct pci_dev *pci = skl->pci;
+ int err;
+ unsigned short gcap;
+ int cp_streams, pb_streams, start_idx;
+
+ err = pci_request_regions(pci, "Skylake HD audio");
+ if (err < 0)
+ return err;
+
+ bus->addr = pci_resource_start(pci, 0);
+ bus->remap_addr = pci_ioremap_bar(pci, 0);
+ if (bus->remap_addr == NULL) {
+ dev_err(bus->dev, "ioremap error\n");
+ return -ENXIO;
+ }
+
+ snd_hdac_ext_bus_parse_capabilities(ebus);
+
+ if (skl_acquire_irq(ebus, 0) < 0)
+ return -EBUSY;
+
+ pci_set_master(pci);
+ synchronize_irq(bus->irq);
+
+ gcap = snd_hdac_chip_readw(bus, GCAP);
+ dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap);
+
+ /* allow 64bit DMA address if supported by H/W */
+ if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) {
+ dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64));
+ } else {
+ dma_set_mask(bus->dev, DMA_BIT_MASK(32));
+ dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32));
+ }
+
+ /* read number of streams from GCAP register */
+ cp_streams = (gcap >> 8) & 0x0f;
+ pb_streams = (gcap >> 12) & 0x0f;
+
+ if (!pb_streams && !cp_streams)
+ return -EIO;
+
+ ebus->num_streams = cp_streams + pb_streams;
+
+ /* initialize streams */
+ snd_hdac_ext_stream_init_all
+ (ebus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
+ start_idx = cp_streams;
+ snd_hdac_ext_stream_init_all
+ (ebus, start_idx, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
+
+ err = snd_hdac_bus_alloc_stream_pages(bus);
+ if (err < 0)
+ return err;
+
+ /* initialize chip */
+ skl_init_pci(skl);
+
+ snd_hdac_bus_init_chip(bus, true);
+
+ /* codec detection */
+ if (!bus->codec_mask) {
+ dev_err(bus->dev, "no codecs found!\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int skl_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ struct skl *skl;
+ struct hdac_ext_bus *ebus = NULL;
+ struct hdac_bus *bus = NULL;
+ int err;
+
+ /* we use ext core ops, so provide NULL for ops here */
+ err = skl_create(pci, NULL, &skl);
+ if (err < 0)
+ return err;
+
+ ebus = &skl->ebus;
+ bus = ebus_to_hbus(ebus);
+
+ err = skl_first_init(ebus);
+ if (err < 0)
+ goto out_free;
+
+ pci_set_drvdata(skl->pci, ebus);
+
+ /* check if dsp is there */
+ if (ebus->ppcap) {
+ /* TODO register with dsp IPC */
+ dev_dbg(bus->dev, "Register dsp\n");
+ }
+
+ if (ebus->mlcap)
+ snd_hdac_ext_bus_get_ml_capabilities(ebus);
+
+ /* create device for soc dmic */
+ err = skl_dmic_device_register(skl);
+ if (err < 0)
+ goto out_free;
+
+ /* register platform dai and controls */
+ err = skl_platform_register(bus->dev);
+ if (err < 0)
+ goto out_dmic_free;
+
+ /* create codec instances */
+ err = skl_codec_create(ebus);
+ if (err < 0)
+ goto out_unregister;
+
+ /*configure PM */
+ pm_runtime_set_autosuspend_delay(bus->dev, SKL_SUSPEND_DELAY);
+ pm_runtime_use_autosuspend(bus->dev);
+ pm_runtime_put_noidle(bus->dev);
+ pm_runtime_allow(bus->dev);
+
+ return 0;
+
+out_unregister:
+ skl_platform_unregister(bus->dev);
+out_dmic_free:
+ skl_dmic_device_unregister(skl);
+out_free:
+ skl->init_failed = 1;
+ skl_free(ebus);
+
+ return err;
+}
+
+static void skl_remove(struct pci_dev *pci)
+{
+ struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+ struct skl *skl = ebus_to_skl(ebus);
+
+ if (pci_dev_run_wake(pci))
+ pm_runtime_get_noresume(&pci->dev);
+ pci_dev_put(pci);
+ skl_platform_unregister(&pci->dev);
+ skl_dmic_device_unregister(skl);
+ skl_free(ebus);
+ dev_set_drvdata(&pci->dev, NULL);
+}
+
+/* PCI IDs */
+static const struct pci_device_id skl_ids[] = {
+ /* Sunrise Point-LP */
+ { PCI_DEVICE(0x8086, 0x9d70), 0},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, skl_ids);
+
+/* pci_driver definition */
+static struct pci_driver skl_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = skl_ids,
+ .probe = skl_probe,
+ .remove = skl_remove,
+ .driver = {
+ .pm = &skl_pm,
+ },
+};
+module_pci_driver(skl_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Skylake ASoC HDA driver");
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
new file mode 100644
index 0000000..f7fdbb0
--- /dev/null
+++ b/sound/soc/intel/skylake/skl.h
@@ -0,0 +1,84 @@
+/*
+ * skl.h - HD Audio skylake defintions.
+ *
+ * Copyright (C) 2015 Intel Corp
+ * Author: Jeeja KP <jeeja.kp@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#ifndef __SOUND_SOC_SKL_H
+#define __SOUND_SOC_SKL_H
+
+#include <sound/hda_register.h>
+#include <sound/hdaudio_ext.h>
+#include "skl-nhlt.h"
+
+#define SKL_SUSPEND_DELAY 2000
+
+/* Vendor Specific Registers */
+#define AZX_REG_VS_EM1 0x1000
+#define AZX_REG_VS_INRC 0x1004
+#define AZX_REG_VS_OUTRC 0x1008
+#define AZX_REG_VS_FIFOTRK 0x100C
+#define AZX_REG_VS_FIFOTRK2 0x1010
+#define AZX_REG_VS_EM2 0x1030
+#define AZX_REG_VS_EM3L 0x1038
+#define AZX_REG_VS_EM3U 0x103C
+#define AZX_REG_VS_EM4L 0x1040
+#define AZX_REG_VS_EM4U 0x1044
+#define AZX_REG_VS_LTRC 0x1048
+#define AZX_REG_VS_D0I3C 0x104A
+#define AZX_REG_VS_PCE 0x104B
+#define AZX_REG_VS_L2MAGC 0x1050
+#define AZX_REG_VS_L2LAHPT 0x1054
+#define AZX_REG_VS_SDXDPIB_XBASE 0x1084
+#define AZX_REG_VS_SDXDPIB_XINTERVAL 0x20
+#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094
+#define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20
+
+struct skl {
+ struct hdac_ext_bus ebus;
+ struct pci_dev *pci;
+
+ unsigned int init_failed:1; /* delayed init failed */
+ struct platform_device *dmic_dev;
+
+ void __iomem *nhlt; /* nhlt ptr */
+ struct skl_sst *skl_sst; /* sst skl ctx */
+};
+
+#define skl_to_ebus(s) (&(s)->ebus)
+#define ebus_to_skl(sbus) \
+ container_of(sbus, struct skl, sbus)
+
+/* to pass dai dma data */
+struct skl_dma_params {
+ u32 format;
+ u8 stream_tag;
+};
+
+int skl_platform_unregister(struct device *dev);
+int skl_platform_register(struct device *dev);
+
+void __iomem *skl_nhlt_init(struct device *dev);
+void skl_nhlt_free(void __iomem *addr);
+struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance,
+ u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn);
+
+int skl_init_dsp(struct skl *skl);
+void skl_free_dsp(struct skl *skl);
+int skl_suspend_dsp(struct skl *skl);
+int skl_resume_dsp(struct skl *skl);
+#endif /* __SOUND_SOC_SKL_H */
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index 4cf2245..dbfdfe9 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -148,10 +148,14 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
dram = mv_mbus_dram_info();
addr = substream->dma_buffer.addr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (priv->substream_play)
+ return -EBUSY;
priv->substream_play = substream;
kirkwood_dma_conf_mbus_windows(priv->io,
KIRKWOOD_PLAYBACK_WIN, addr, dram);
} else {
+ if (priv->substream_rec)
+ return -EBUSY;
priv->substream_rec = substream;
kirkwood_dma_conf_mbus_windows(priv->io,
KIRKWOOD_RECORD_WIN, addr, dram);
diff --git a/sound/soc/mediatek/mt8173-max98090.c b/sound/soc/mediatek/mt8173-max98090.c
index 2d2536a..684e8a7 100644
--- a/sound/soc/mediatek/mt8173-max98090.c
+++ b/sound/soc/mediatek/mt8173-max98090.c
@@ -136,6 +136,7 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = {
static struct snd_soc_card mt8173_max98090_card = {
.name = "mt8173-max98090",
+ .owner = THIS_MODULE,
.dai_link = mt8173_max98090_dais,
.num_links = ARRAY_SIZE(mt8173_max98090_dais),
.controls = mt8173_max98090_controls,
@@ -202,7 +203,6 @@ MODULE_DEVICE_TABLE(of, mt8173_max98090_dt_match);
static struct platform_driver mt8173_max98090_driver = {
.driver = {
.name = "mt8173-max98090",
- .owner = THIS_MODULE,
.of_match_table = mt8173_max98090_dt_match,
#ifdef CONFIG_PM
.pm = &snd_soc_pm_ops,
diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173-rt5650-rt5676.c
index 6f52eca..86cf975 100644
--- a/sound/soc/mediatek/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173-rt5650-rt5676.c
@@ -191,6 +191,7 @@ static struct snd_soc_codec_conf mt8173_rt5650_rt5676_codec_conf[] = {
static struct snd_soc_card mt8173_rt5650_rt5676_card = {
.name = "mtk-rt5650-rt5676",
+ .owner = THIS_MODULE,
.dai_link = mt8173_rt5650_rt5676_dais,
.num_links = ARRAY_SIZE(mt8173_rt5650_rt5676_dais),
.codec_conf = mt8173_rt5650_rt5676_codec_conf,
@@ -269,7 +270,6 @@ MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5676_dt_match);
static struct platform_driver mt8173_rt5650_rt5676_driver = {
.driver = {
.name = "mtk-rt5650-rt5676",
- .owner = THIS_MODULE,
.of_match_table = mt8173_rt5650_rt5676_dt_match,
#ifdef CONFIG_PM
.pm = &snd_soc_pm_ops,
diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h
index a88b175..cc4393c 100644
--- a/sound/soc/mediatek/mtk-afe-common.h
+++ b/sound/soc/mediatek/mtk-afe-common.h
@@ -98,12 +98,4 @@ struct mtk_afe_memif {
const struct mtk_afe_irq_data *irqdata;
};
-struct mtk_afe {
- /* address for ioremap audio hardware register */
- void __iomem *base_addr;
- struct device *dev;
- struct regmap *regmap;
- struct mtk_afe_memif memif[MTK_AFE_MEMIF_NUM];
- struct clk *clocks[MTK_CLK_NUM];
-};
#endif
diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c
index 9863da7..d190fe0 100644
--- a/sound/soc/mediatek/mtk-afe-pcm.c
+++ b/sound/soc/mediatek/mtk-afe-pcm.c
@@ -45,18 +45,21 @@
/* Memory interface */
#define AFE_DL1_BASE 0x0040
#define AFE_DL1_CUR 0x0044
+#define AFE_DL1_END 0x0048
#define AFE_DL2_BASE 0x0050
#define AFE_DL2_CUR 0x0054
#define AFE_AWB_BASE 0x0070
#define AFE_AWB_CUR 0x007c
#define AFE_VUL_BASE 0x0080
#define AFE_VUL_CUR 0x008c
+#define AFE_VUL_END 0x0088
#define AFE_DAI_BASE 0x0090
#define AFE_DAI_CUR 0x009c
#define AFE_MOD_PCM_BASE 0x0330
#define AFE_MOD_PCM_CUR 0x033c
#define AFE_HDMI_OUT_BASE 0x0374
#define AFE_HDMI_OUT_CUR 0x0378
+#define AFE_HDMI_OUT_END 0x037c
#define AFE_ADDA2_TOP_CON0 0x0600
@@ -127,6 +130,34 @@ enum afe_tdm_ch_start {
AFE_TDM_CH_ZERO,
};
+static const unsigned int mtk_afe_backup_list[] = {
+ AUDIO_TOP_CON0,
+ AFE_CONN1,
+ AFE_CONN2,
+ AFE_CONN7,
+ AFE_CONN8,
+ AFE_DAC_CON1,
+ AFE_DL1_BASE,
+ AFE_DL1_END,
+ AFE_VUL_BASE,
+ AFE_VUL_END,
+ AFE_HDMI_OUT_BASE,
+ AFE_HDMI_OUT_END,
+ AFE_HDMI_CONN0,
+ AFE_DAC_CON0,
+};
+
+struct mtk_afe {
+ /* address for ioremap audio hardware register */
+ void __iomem *base_addr;
+ struct device *dev;
+ struct regmap *regmap;
+ struct mtk_afe_memif memif[MTK_AFE_MEMIF_NUM];
+ struct clk *clocks[MTK_CLK_NUM];
+ unsigned int backup_regs[ARRAY_SIZE(mtk_afe_backup_list)];
+ bool suspended;
+};
+
static const struct snd_pcm_hardware mtk_afe_hardware = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
@@ -722,11 +753,53 @@ static const struct snd_soc_dai_ops mtk_afe_hdmi_ops = {
};
+static int mtk_afe_runtime_suspend(struct device *dev);
+static int mtk_afe_runtime_resume(struct device *dev);
+
+static int mtk_afe_dai_suspend(struct snd_soc_dai *dai)
+{
+ struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int i;
+
+ dev_dbg(afe->dev, "%s\n", __func__);
+ if (pm_runtime_status_suspended(afe->dev) || afe->suspended)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(mtk_afe_backup_list); i++)
+ regmap_read(afe->regmap, mtk_afe_backup_list[i],
+ &afe->backup_regs[i]);
+
+ afe->suspended = true;
+ mtk_afe_runtime_suspend(afe->dev);
+ return 0;
+}
+
+static int mtk_afe_dai_resume(struct snd_soc_dai *dai)
+{
+ struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int i = 0;
+
+ dev_dbg(afe->dev, "%s\n", __func__);
+ if (pm_runtime_status_suspended(afe->dev) || !afe->suspended)
+ return 0;
+
+ mtk_afe_runtime_resume(afe->dev);
+
+ for (i = 0; i < ARRAY_SIZE(mtk_afe_backup_list); i++)
+ regmap_write(afe->regmap, mtk_afe_backup_list[i],
+ afe->backup_regs[i]);
+
+ afe->suspended = false;
+ return 0;
+}
+
static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = {
/* FE DAIs: memory intefaces to CPU */
{
.name = "DL1", /* downlink 1 */
.id = MTK_AFE_MEMIF_DL1,
+ .suspend = mtk_afe_dai_suspend,
+ .resume = mtk_afe_dai_resume,
.playback = {
.stream_name = "DL1",
.channels_min = 1,
@@ -738,6 +811,8 @@ static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = {
}, {
.name = "VUL", /* voice uplink */
.id = MTK_AFE_MEMIF_VUL,
+ .suspend = mtk_afe_dai_suspend,
+ .resume = mtk_afe_dai_resume,
.capture = {
.stream_name = "VUL",
.channels_min = 1,
@@ -774,6 +849,8 @@ static struct snd_soc_dai_driver mtk_afe_hdmi_dais[] = {
{
.name = "HDMI",
.id = MTK_AFE_MEMIF_HDMI,
+ .suspend = mtk_afe_dai_suspend,
+ .resume = mtk_afe_dai_resume,
.playback = {
.stream_name = "HDMI",
.channels_min = 2,
@@ -820,10 +897,6 @@ static const struct snd_kcontrol_new mtk_afe_o10_mix[] = {
};
static const struct snd_soc_dapm_widget mtk_afe_pcm_widgets[] = {
- /* Backend DAIs */
- SND_SOC_DAPM_AIF_IN("I2S Capture", NULL, 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_AIF_OUT("I2S Playback", NULL, 0, SND_SOC_NOPM, 0, 0),
-
/* inter-connections */
SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -855,11 +928,6 @@ static const struct snd_soc_dapm_route mtk_afe_pcm_routes[] = {
{ "O10", "I18 Switch", "I18" },
};
-static const struct snd_soc_dapm_widget mtk_afe_hdmi_widgets[] = {
- /* Backend DAIs */
- SND_SOC_DAPM_AIF_OUT("HDMIO Playback", NULL, 0, SND_SOC_NOPM, 0, 0),
-};
-
static const struct snd_soc_dapm_route mtk_afe_hdmi_routes[] = {
{"HDMIO Playback", NULL, "HDMI"},
};
@@ -874,8 +942,6 @@ static const struct snd_soc_component_driver mtk_afe_pcm_dai_component = {
static const struct snd_soc_component_driver mtk_afe_hdmi_dai_component = {
.name = "mtk-afe-hdmi-dai",
- .dapm_widgets = mtk_afe_hdmi_widgets,
- .num_dapm_widgets = ARRAY_SIZE(mtk_afe_hdmi_widgets),
.dapm_routes = mtk_afe_hdmi_routes,
.num_dapm_routes = ARRAY_SIZE(mtk_afe_hdmi_routes),
};
@@ -1220,7 +1286,6 @@ static const struct dev_pm_ops mtk_afe_pm_ops = {
static struct platform_driver mtk_afe_pcm_driver = {
.driver = {
.name = "mtk-afe-pcm",
- .owner = THIS_MODULE,
.of_match_table = mtk_afe_pcm_dt_match,
.pm = &mtk_afe_pm_ops,
},
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c
index 5ae5ca1..e093261 100644
--- a/sound/soc/nuc900/nuc900-pcm.c
+++ b/sound/soc/nuc900/nuc900-pcm.c
@@ -308,13 +308,7 @@ static struct snd_soc_platform_driver nuc900_soc_platform = {
static int nuc900_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&pdev->dev, &nuc900_soc_platform);
-}
-
-static int nuc900_soc_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
+ return devm_snd_soc_register_platform(&pdev->dev, &nuc900_soc_platform);
}
static struct platform_driver nuc900_pcm_driver = {
@@ -323,7 +317,6 @@ static struct platform_driver nuc900_pcm_driver = {
},
.probe = nuc900_soc_platform_probe,
- .remove = nuc900_soc_platform_remove,
};
module_platform_driver(nuc900_pcm_driver);
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
index 68a1252..c7563e2 100644
--- a/sound/soc/omap/mcbsp.c
+++ b/sound/soc/omap/mcbsp.c
@@ -965,25 +965,15 @@ int omap_mcbsp_init(struct platform_device *pdev)
mcbsp->free = true;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
- if (!res) {
+ if (!res)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(mcbsp->dev, "invalid memory resource\n");
- return -ENOMEM;
- }
- }
- if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
- dev_name(&pdev->dev))) {
- dev_err(mcbsp->dev, "memory region already claimed\n");
- return -ENODEV;
- }
+
+ mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mcbsp->io_base))
+ return PTR_ERR(mcbsp->io_base);
mcbsp->phys_base = res->start;
mcbsp->reg_cache_size = resource_size(res);
- mcbsp->io_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!mcbsp->io_base)
- return -ENOMEM;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
if (!res)
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c
index aeef25c..584b237 100644
--- a/sound/soc/omap/omap-hdmi-audio.c
+++ b/sound/soc/omap/omap-hdmi-audio.c
@@ -81,7 +81,15 @@ static int hdmi_dai_startup(struct snd_pcm_substream *substream,
ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
if (ret < 0) {
- dev_err(dai->dev, "could not apply constraint\n");
+ dev_err(dai->dev, "Could not apply period constraint: %d\n",
+ ret);
+ return ret;
+ }
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128);
+ if (ret < 0) {
+ dev_err(dai->dev, "Could not apply buffer constraint: %d\n",
+ ret);
return ret;
}
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 076bec6..732e749 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -154,8 +154,7 @@ static const struct snd_soc_dapm_route omap3pandora_map[] = {
static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
/* All TWL4030 output pins are floating */
snd_soc_dapm_nc_pin(dapm, "EARPIECE");
@@ -174,8 +173,7 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
/* Not comnnected */
snd_soc_dapm_nc_pin(dapm, "HSMIC");
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
index 1eb45dc..51e790d 100644
--- a/sound/soc/pxa/mmp-pcm.c
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -232,13 +232,7 @@ static int mmp_pcm_probe(struct platform_device *pdev)
mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].period_bytes_max =
pdata->period_max_capture;
}
- return snd_soc_register_platform(&pdev->dev, &mmp_soc_platform);
-}
-
-static int mmp_pcm_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
+ return devm_snd_soc_register_platform(&pdev->dev, &mmp_soc_platform);
}
static struct platform_driver mmp_pcm_driver = {
@@ -247,7 +241,6 @@ static struct platform_driver mmp_pcm_driver = {
},
.probe = mmp_pcm_probe,
- .remove = mmp_pcm_remove,
};
module_platform_driver(mmp_pcm_driver);
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index fbe2e93..3da485e 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -813,14 +813,8 @@ static const struct of_device_id pxa_ssp_of_ids[] = {
static int asoc_ssp_probe(struct platform_device *pdev)
{
- return snd_soc_register_component(&pdev->dev, &pxa_ssp_component,
- &pxa_ssp_dai, 1);
-}
-
-static int asoc_ssp_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_component(&pdev->dev);
- return 0;
+ return devm_snd_soc_register_component(&pdev->dev, &pxa_ssp_component,
+ &pxa_ssp_dai, 1);
}
static struct platform_driver asoc_ssp_driver = {
@@ -830,7 +824,6 @@ static struct platform_driver asoc_ssp_driver = {
},
.probe = asoc_ssp_probe,
- .remove = asoc_ssp_remove,
};
module_platform_driver(asoc_ssp_driver);
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index e68290c..6b4e400 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -367,19 +367,12 @@ static const struct snd_soc_component_driver pxa_i2s_component = {
static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
{
- return snd_soc_register_component(&pdev->dev, &pxa_i2s_component,
- &pxa_i2s_dai, 1);
-}
-
-static int pxa2xx_i2s_drv_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_component(&pdev->dev);
- return 0;
+ return devm_snd_soc_register_component(&pdev->dev, &pxa_i2s_component,
+ &pxa_i2s_dai, 1);
}
static struct platform_driver pxa2xx_i2s_driver = {
.probe = pxa2xx_i2s_drv_probe,
- .remove = pxa2xx_i2s_drv_remove,
.driver = {
.name = "pxa2xx-i2s",
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index a51c9da..831ee37 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -124,13 +124,7 @@ static struct snd_soc_platform_driver pxa2xx_soc_platform = {
static int pxa2xx_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&pdev->dev, &pxa2xx_soc_platform);
-}
-
-static int pxa2xx_soc_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
+ return devm_snd_soc_register_platform(&pdev->dev, &pxa2xx_soc_platform);
}
#ifdef CONFIG_OF
@@ -147,7 +141,6 @@ static struct platform_driver pxa_pcm_driver = {
},
.probe = pxa2xx_soc_platform_probe,
- .remove = pxa2xx_soc_platform_remove,
};
module_platform_driver(pxa_pcm_driver);
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 807fedf..3cc252e 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -1,5 +1,6 @@
config SND_SOC_QCOM
tristate "ASoC support for QCOM platforms"
+ depends on ARCH_QCOM || COMPILE_TEST
help
Say Y or M if you want to add support to use audio devices
in Qualcomm Technologies SOC-based platforms.
@@ -14,19 +15,17 @@ config SND_SOC_LPASS_PLATFORM
config SND_SOC_LPASS_IPQ806X
tristate
- depends on SND_SOC_QCOM
select SND_SOC_LPASS_CPU
select SND_SOC_LPASS_PLATFORM
config SND_SOC_LPASS_APQ8016
tristate
- depends on SND_SOC_QCOM
select SND_SOC_LPASS_CPU
select SND_SOC_LPASS_PLATFORM
config SND_SOC_STORM
tristate "ASoC I2S support for Storm boards"
- depends on SND_SOC_QCOM && (ARCH_QCOM || COMPILE_TEST)
+ depends on SND_SOC_QCOM
select SND_SOC_LPASS_IPQ806X
select SND_SOC_MAX98357A
help
@@ -35,7 +34,7 @@ config SND_SOC_STORM
config SND_SOC_APQ8016_SBC
tristate "SoC Audio support for APQ8016 SBC platforms"
- depends on SND_SOC_QCOM && (ARCH_QCOM || COMPILE_TEST)
+ depends on SND_SOC_QCOM
select SND_SOC_LPASS_APQ8016
help
Support for Qualcomm Technologies LPASS audio block in
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 23f3d59..97bc202 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -235,7 +235,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
return ret;
}
-struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
+const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
.set_sysclk = lpass_cpu_daiops_set_sysclk,
.startup = lpass_cpu_daiops_startup,
.shutdown = lpass_cpu_daiops_shutdown,
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index 7356d3a..7a41679 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -73,7 +73,7 @@ static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
return 0;
}
-struct lpass_variant ipq806x_data = {
+static struct lpass_variant ipq806x_data = {
.i2sctrl_reg_base = 0x0010,
.i2sctrl_reg_stride = 0x04,
.i2s_ports = 5,
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index d6e86c1..0b63e2e 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -93,6 +93,6 @@ int asoc_qcom_lpass_platform_register(struct platform_device *);
int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev);
int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
-extern struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
+extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
#endif /* __LPASS_H__ */
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index e181826..58bae8e 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -14,3 +14,22 @@ config SND_SOC_ROCKCHIP_I2S
Say Y or M if you want to add support for I2S driver for
Rockchip I2S device. The device supports upto maximum of
8 channels each for play and record.
+
+config SND_SOC_ROCKCHIP_MAX98090
+ tristate "ASoC support for Rockchip boards using a MAX98090 codec"
+ depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB
+ select SND_SOC_ROCKCHIP_I2S
+ select SND_SOC_MAX98090
+ select SND_SOC_TS3A227E
+ help
+ Say Y or M here if you want to add support for SoC audio on Rockchip
+ boards using the MAX98090 codec, such as Veyron.
+
+config SND_SOC_ROCKCHIP_RT5645
+ tristate "ASoC support for Rockchip boards using a RT5645/RT5650 codec"
+ depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB
+ select SND_SOC_ROCKCHIP_I2S
+ select SND_SOC_RT5645
+ help
+ Say Y or M here if you want to add support for SoC audio on Rockchip
+ boards using the RT5645/RT5650 codec, such as Veyron.
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index b921909..1bc1dc3 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -2,3 +2,9 @@
snd-soc-i2s-objs := rockchip_i2s.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-i2s.o
+
+snd-soc-rockchip-max98090-objs := rockchip_max98090.o
+snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
+
+obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
+obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index acb5be5..b936102 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -483,16 +483,14 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
goto err_suspend;
}
- ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret) {
dev_err(&pdev->dev, "Could not register PCM\n");
- goto err_pcm_register;
+ return ret;
}
return 0;
-err_pcm_register:
- snd_dmaengine_pcm_unregister(&pdev->dev);
err_suspend:
if (!pm_runtime_status_suspended(&pdev->dev))
i2s_runtime_suspend(&pdev->dev);
@@ -512,8 +510,6 @@ static int rockchip_i2s_remove(struct platform_device *pdev)
clk_disable_unprepare(i2s->mclk);
clk_disable_unprepare(i2s->hclk);
- snd_dmaengine_pcm_unregister(&pdev->dev);
- snd_soc_unregister_component(&pdev->dev);
return 0;
}
diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
new file mode 100644
index 0000000..26567b1
--- /dev/null
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -0,0 +1,236 @@
+/*
+ * Rockchip machine ASoC driver for boards using a MAX90809 CODEC.
+ *
+ * Copyright (c) 2014, ROCKCHIP CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "rockchip_i2s.h"
+#include "../codecs/ts3a227e.h"
+
+#define DRV_NAME "rockchip-snd-max98090"
+
+static struct snd_soc_jack headset_jack;
+static struct snd_soc_jack_pin headset_jack_pins[] = {
+ {
+ .pin = "Headset Jack",
+ .mask = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ },
+};
+
+static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route rk_audio_map[] = {
+ {"IN34", NULL, "Headset Mic"},
+ {"IN34", NULL, "MICBIAS"},
+ {"MICBIAS", NULL, "Headset Mic"},
+ {"DMICL", NULL, "Int Mic"},
+ {"Headphone", NULL, "HPL"},
+ {"Headphone", NULL, "HPR"},
+ {"Speaker", NULL, "SPKL"},
+ {"Speaker", NULL, "SPKR"},
+};
+
+static const struct snd_kcontrol_new rk_mc_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int mclk;
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 48000:
+ case 96000:
+ mclk = 12288000;
+ break;
+ case 44100:
+ mclk = 11289600;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int rk_init(struct snd_soc_pcm_runtime *runtime)
+{
+ /* Enable Headset and 4 Buttons Jack detection */
+ return snd_soc_card_jack_new(runtime->card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &headset_jack,
+ headset_jack_pins,
+ ARRAY_SIZE(headset_jack_pins));
+}
+
+static int rk_98090_headset_init(struct snd_soc_component *component)
+{
+ return ts3a227e_enable_jack_detect(component, &headset_jack);
+}
+
+static struct snd_soc_ops rk_aif1_ops = {
+ .hw_params = rk_aif1_hw_params,
+};
+
+static struct snd_soc_aux_dev rk_98090_headset_dev = {
+ .name = "Headset Chip",
+ .init = rk_98090_headset_init,
+};
+
+static struct snd_soc_dai_link rk_dailink = {
+ .name = "max98090",
+ .stream_name = "Audio",
+ .codec_dai_name = "HiFi",
+ .init = rk_init,
+ .ops = &rk_aif1_ops,
+ /* set max98090 as slave */
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_card_rk = {
+ .name = "ROCKCHIP-I2S",
+ .owner = THIS_MODULE,
+ .dai_link = &rk_dailink,
+ .num_links = 1,
+ .aux_dev = &rk_98090_headset_dev,
+ .num_aux_devs = 1,
+ .dapm_widgets = rk_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rk_dapm_widgets),
+ .dapm_routes = rk_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rk_audio_map),
+ .controls = rk_mc_controls,
+ .num_controls = ARRAY_SIZE(rk_mc_controls),
+};
+
+static int snd_rk_mc_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct snd_soc_card *card = &snd_soc_card_rk;
+ struct device_node *np = pdev->dev.of_node;
+
+ /* register the soc card */
+ card->dev = &pdev->dev;
+
+ rk_dailink.codec_of_node = of_parse_phandle(np,
+ "rockchip,audio-codec", 0);
+ if (!rk_dailink.codec_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'rockchip,audio-codec' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ rk_dailink.cpu_of_node = of_parse_phandle(np,
+ "rockchip,i2s-controller", 0);
+ if (!rk_dailink.cpu_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'rockchip,i2s-controller' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ rk_dailink.platform_of_node = rk_dailink.cpu_of_node;
+
+ rk_98090_headset_dev.codec_of_node = of_parse_phandle(np,
+ "rockchip,headset-codec", 0);
+ if (!rk_98090_headset_dev.codec_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'rockchip,headset-codec' missing/invalid\n");
+ return -EINVAL;
+ }
+
+ ret = snd_soc_of_parse_card_name(card, "rockchip,model");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Soc parse card name failed %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Soc register card failed %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static const struct of_device_id rockchip_max98090_of_match[] = {
+ { .compatible = "rockchip,rockchip-audio-max98090", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_max98090_of_match);
+
+static struct platform_driver snd_rk_mc_driver = {
+ .probe = snd_rk_mc_probe,
+ .driver = {
+ .name = DRV_NAME,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = rockchip_max98090_of_match,
+ },
+};
+
+module_platform_driver(snd_rk_mc_driver);
+
+MODULE_AUTHOR("jianqun <jay.xu@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip max98090 machine ASoC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c
new file mode 100644
index 0000000..68c62e4
--- /dev/null
+++ b/sound/soc/rockchip/rockchip_rt5645.c
@@ -0,0 +1,225 @@
+/*
+ * Rockchip machine ASoC driver for boards using a RT5645/RT5650 CODEC.
+ *
+ * Copyright (c) 2015, ROCKCHIP CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "rockchip_i2s.h"
+
+#define DRV_NAME "rockchip-snd-rt5645"
+
+static struct snd_soc_jack headset_jack;
+
+/* Jack detect via rt5645 driver. */
+extern int rt5645_set_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
+ struct snd_soc_jack *btn_jack);
+
+static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphones", NULL),
+ SND_SOC_DAPM_SPK("Speakers", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route rk_audio_map[] = {
+ /* Input Lines */
+ {"DMIC L2", NULL, "Int Mic"},
+ {"DMIC R2", NULL, "Int Mic"},
+ {"RECMIXL", NULL, "Headset Mic"},
+ {"RECMIXR", NULL, "Headset Mic"},
+
+ /* Output Lines */
+ {"Headphones", NULL, "HPOR"},
+ {"Headphones", NULL, "HPOL"},
+ {"Speakers", NULL, "SPOL"},
+ {"Speakers", NULL, "SPOR"},
+};
+
+static const struct snd_kcontrol_new rk_mc_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphones"),
+ SOC_DAPM_PIN_SWITCH("Speakers"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+};
+
+static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int mclk;
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 48000:
+ case 96000:
+ mclk = 12288000;
+ break;
+ case 44100:
+ mclk = 11289600;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int rk_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_card *card = runtime->card;
+ int ret;
+
+ /* Enable Headset and 4 Buttons Jack detection */
+ ret = snd_soc_card_jack_new(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &headset_jack, NULL, 0);
+ if (ret) {
+ dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret);
+ return ret;
+ }
+
+ return rt5645_set_jack_detect(runtime->codec,
+ &headset_jack,
+ &headset_jack,
+ &headset_jack);
+}
+
+static struct snd_soc_ops rk_aif1_ops = {
+ .hw_params = rk_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link rk_dailink = {
+ .name = "rt5645",
+ .stream_name = "rt5645 PCM",
+ .codec_dai_name = "rt5645-aif1",
+ .init = rk_init,
+ .ops = &rk_aif1_ops,
+ /* set rt5645 as slave */
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_card_rk = {
+ .name = "I2S-RT5650",
+ .owner = THIS_MODULE,
+ .dai_link = &rk_dailink,
+ .num_links = 1,
+ .dapm_widgets = rk_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rk_dapm_widgets),
+ .dapm_routes = rk_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rk_audio_map),
+ .controls = rk_mc_controls,
+ .num_controls = ARRAY_SIZE(rk_mc_controls),
+};
+
+static int snd_rk_mc_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct snd_soc_card *card = &snd_soc_card_rk;
+ struct device_node *np = pdev->dev.of_node;
+
+ /* register the soc card */
+ card->dev = &pdev->dev;
+
+ rk_dailink.codec_of_node = of_parse_phandle(np,
+ "rockchip,audio-codec", 0);
+ if (!rk_dailink.codec_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'rockchip,audio-codec' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ rk_dailink.cpu_of_node = of_parse_phandle(np,
+ "rockchip,i2s-controller", 0);
+ if (!rk_dailink.cpu_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'rockchip,i2s-controller' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ rk_dailink.platform_of_node = rk_dailink.cpu_of_node;
+
+ ret = snd_soc_of_parse_card_name(card, "rockchip,model");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Soc parse card name failed %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Soc register card failed %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static const struct of_device_id rockchip_rt5645_of_match[] = {
+ { .compatible = "rockchip,rockchip-audio-rt5645", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_rt5645_of_match);
+
+static struct platform_driver snd_rk_mc_driver = {
+ .probe = snd_rk_mc_probe,
+ .driver = {
+ .name = DRV_NAME,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = rockchip_rt5645_of_match,
+ },
+};
+
+module_platform_driver(snd_rk_mc_driver);
+
+MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip rt5645 machine ASoC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c
index 8bf2e2c..ee1fda9 100644
--- a/sound/soc/samsung/arndale_rt5631.c
+++ b/sound/soc/samsung/arndale_rt5631.c
@@ -71,6 +71,7 @@ static struct snd_soc_dai_link arndale_rt5631_dai[] = {
static struct snd_soc_card arndale_rt5631 = {
.name = "Arndale RT5631",
+ .owner = THIS_MODULE,
.dai_link = arndale_rt5631_dai,
.num_links = ARRAY_SIZE(arndale_rt5631_dai),
};
@@ -116,15 +117,6 @@ static int arndale_audio_probe(struct platform_device *pdev)
return ret;
}
-static int arndale_audio_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
-
- snd_soc_unregister_card(card);
-
- return 0;
-}
-
static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = {
{ .compatible = "samsung,arndale-rt5631", },
{ .compatible = "samsung,arndale-alc5631", },
@@ -139,7 +131,6 @@ static struct platform_driver arndale_audio_driver = {
.of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
},
.probe = arndale_audio_probe,
- .remove = arndale_audio_remove,
};
module_platform_driver(arndale_audio_driver);
diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c
index 7651dc9..07ce2cf 100644
--- a/sound/soc/samsung/snow.c
+++ b/sound/soc/samsung/snow.c
@@ -56,6 +56,7 @@ static int snow_late_probe(struct snd_soc_card *card)
static struct snd_soc_card snow_snd = {
.name = "Snow-I2S",
+ .owner = THIS_MODULE,
.dai_link = snow_dai,
.num_links = ARRAY_SIZE(snow_dai),
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index fd11404..8fad444 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -327,13 +327,7 @@ static struct snd_soc_platform_driver sh7760_soc_platform = {
static int sh7760_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform);
-}
-
-static int sh7760_soc_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
+ return devm_snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform);
}
static struct platform_driver sh7760_pcm_driver = {
@@ -342,7 +336,6 @@ static struct platform_driver sh7760_pcm_driver = {
},
.probe = sh7760_soc_platform_probe,
- .remove = sh7760_soc_platform_remove,
};
module_platform_driver(sh7760_pcm_driver);
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 142c066..0215c78 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1911,7 +1911,6 @@ MODULE_DEVICE_TABLE(of, fsi_of_match);
static const struct platform_device_id fsi_id_table[] = {
{ "sh_fsi", (kernel_ulong_t)&fsi1_core },
- { "sh_fsi2", (kernel_ulong_t)&fsi2_core },
{},
};
MODULE_DEVICE_TABLE(platform, fsi_id_table);
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index f1b4451..8b258501 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,4 +1,4 @@
-snd-soc-rcar-objs := core.o gen.o dma.o src.o adg.o ssi.o dvc.o
+snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o
obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
snd-soc-rsrc-card-objs := rsrc-card.o
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index f1e5920..f3feed5 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -203,9 +203,9 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io)
}
/*
- * settting function
+ * ADINR function
*/
-u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
+u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
@@ -227,6 +227,64 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
return adinr;
}
+u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ u32 chan = runtime->channels;
+
+ switch (chan) {
+ case 1:
+ case 2:
+ case 4:
+ case 6:
+ case 8:
+ break;
+ default:
+ dev_warn(dev, "not supported channel\n");
+ chan = 0;
+ break;
+ }
+
+ return chan;
+}
+
+/*
+ * DALIGN function
+ */
+u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
+{
+ struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+ struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+ struct rsnd_mod *target = src ? src : ssi;
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ u32 val = 0x76543210;
+ u32 mask = ~0;
+
+ mask <<= runtime->channels * 4;
+ val = val & mask;
+
+ switch (runtime->sample_bits) {
+ case 16:
+ val |= 0x67452301 & ~mask;
+ break;
+ case 32:
+ val |= 0x76543210 & ~mask;
+ break;
+ }
+
+ /*
+ * exchange channeles on SRC if possible,
+ * otherwise, R/L volume settings on DVC
+ * changes inverted channels
+ */
+ if (mod == target)
+ return val;
+ else
+ return 0x76543210;
+}
+
/*
* rsnd_dai functions
*/
@@ -242,9 +300,9 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
if (val == __rsnd_mod_call_##func) { \
called = 1; \
ret = (mod)->ops->func(mod, io, param); \
- mod->status = (mod->status & ~mask) + \
- (add << __rsnd_mod_shift_##func); \
} \
+ mod->status = (mod->status & ~mask) + \
+ (add << __rsnd_mod_shift_##func); \
dev_dbg(dev, "%s[%d] 0x%08x %s\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), mod->status, \
called ? #func : ""); \
@@ -274,21 +332,21 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
static int rsnd_dai_connect(struct rsnd_mod *mod,
struct rsnd_dai_stream *io)
{
+ struct rsnd_priv *priv;
+ struct device *dev;
+
if (!mod)
return -EIO;
- if (io->mod[mod->type]) {
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
-
- dev_err(dev, "%s[%d] is not empty\n",
- rsnd_mod_name(mod),
- rsnd_mod_id(mod));
- return -EIO;
- }
+ priv = rsnd_mod_to_priv(mod);
+ dev = rsnd_priv_to_dev(priv);
io->mod[mod->type] = mod;
+ dev_dbg(dev, "%s[%d] is connected to io (%s)\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod),
+ rsnd_io_is_play(io) ? "Playback" : "Capture");
+
return 0;
}
@@ -517,7 +575,7 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
.set_fmt = rsnd_soc_dai_set_fmt,
};
-#define rsnd_path_parse(priv, io, type) \
+#define rsnd_path_add(priv, io, type) \
({ \
struct rsnd_mod *mod; \
int ret = 0; \
@@ -533,7 +591,7 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
ret; \
})
-#define rsnd_path_break(priv, io, type) \
+#define rsnd_path_remove(priv, io, type) \
{ \
struct rsnd_mod *mod; \
int id = -1; \
@@ -547,6 +605,79 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
} \
}
+void rsnd_path_parse(struct rsnd_priv *priv,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
+ struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
+ struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+ struct rsnd_mod *cmd;
+ struct device *dev = rsnd_priv_to_dev(priv);
+ u32 data;
+
+ /* Gen1 is not supported */
+ if (rsnd_is_gen1(priv))
+ return;
+
+ if (!mix && !dvc)
+ return;
+
+ if (mix) {
+ struct rsnd_dai *rdai;
+ int i;
+ u32 path[] = {
+ [0] = 0,
+ [1] = 1 << 0,
+ [2] = 0,
+ [3] = 0,
+ [4] = 0,
+ [5] = 1 << 8
+ };
+
+ /*
+ * it is assuming that integrater is well understanding about
+ * data path. Here doesn't check impossible connection,
+ * like src2 + src5
+ */
+ data = 0;
+ for_each_rsnd_dai(rdai, priv, i) {
+ io = &rdai->playback;
+ if (mix == rsnd_io_to_mod_mix(io))
+ data |= path[rsnd_mod_id(src)];
+
+ io = &rdai->capture;
+ if (mix == rsnd_io_to_mod_mix(io))
+ data |= path[rsnd_mod_id(src)];
+ }
+
+ /*
+ * We can't use ctu = rsnd_io_ctu() here.
+ * Since, ID of dvc/mix are 0 or 1 (= same as CMD number)
+ * but ctu IDs are 0 - 7 (= CTU00 - CTU13)
+ */
+ cmd = mix;
+ } else {
+ u32 path[] = {
+ [0] = 0x30000,
+ [1] = 0x30001,
+ [2] = 0x40000,
+ [3] = 0x10000,
+ [4] = 0x20000,
+ [5] = 0x40100
+ };
+
+ data = path[rsnd_mod_id(src)];
+
+ cmd = dvc;
+ }
+
+ dev_dbg(dev, "ctu/mix path = 0x%08x", data);
+
+ rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data);
+
+ rsnd_mod_write(cmd, CMD_CTRL, 0x10);
+}
+
static int rsnd_path_init(struct rsnd_priv *priv,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io)
@@ -564,18 +695,28 @@ static int rsnd_path_init(struct rsnd_priv *priv,
* using fixed path.
*/
+ /* SSI */
+ ret = rsnd_path_add(priv, io, ssi);
+ if (ret < 0)
+ return ret;
+
/* SRC */
- ret = rsnd_path_parse(priv, io, src);
+ ret = rsnd_path_add(priv, io, src);
if (ret < 0)
return ret;
- /* SSI */
- ret = rsnd_path_parse(priv, io, ssi);
+ /* CTU */
+ ret = rsnd_path_add(priv, io, ctu);
+ if (ret < 0)
+ return ret;
+
+ /* MIX */
+ ret = rsnd_path_add(priv, io, mix);
if (ret < 0)
return ret;
/* DVC */
- ret = rsnd_path_parse(priv, io, dvc);
+ ret = rsnd_path_add(priv, io, dvc);
if (ret < 0)
return ret;
@@ -589,13 +730,15 @@ static void rsnd_of_parse_dai(struct platform_device *pdev,
struct device_node *dai_node, *dai_np;
struct device_node *ssi_node, *ssi_np;
struct device_node *src_node, *src_np;
+ struct device_node *ctu_node, *ctu_np;
+ struct device_node *mix_node, *mix_np;
struct device_node *dvc_node, *dvc_np;
struct device_node *playback, *capture;
struct rsnd_dai_platform_info *dai_info;
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
struct device *dev = &pdev->dev;
int nr, i;
- int dai_i, ssi_i, src_i, dvc_i;
+ int dai_i, ssi_i, src_i, ctu_i, mix_i, dvc_i;
if (!of_data)
return;
@@ -621,6 +764,8 @@ static void rsnd_of_parse_dai(struct platform_device *pdev,
ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
+ ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
+ mix_node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
#define mod_parse(name) \
@@ -657,6 +802,8 @@ if (name##_node) { \
mod_parse(ssi);
mod_parse(src);
+ mod_parse(ctu);
+ mod_parse(mix);
mod_parse(dvc);
of_node_put(playback);
@@ -1033,8 +1180,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
/*
* remove SRC/DVC from DAI,
*/
- rsnd_path_break(priv, io, src);
- rsnd_path_break(priv, io, dvc);
+ rsnd_path_remove(priv, io, src);
+ rsnd_path_remove(priv, io, dvc);
/*
* fallback
@@ -1069,6 +1216,8 @@ static int rsnd_probe(struct platform_device *pdev)
rsnd_dma_probe,
rsnd_ssi_probe,
rsnd_src_probe,
+ rsnd_ctu_probe,
+ rsnd_mix_probe,
rsnd_dvc_probe,
rsnd_adg_probe,
rsnd_dai_probe,
@@ -1164,6 +1313,8 @@ static int rsnd_remove(struct platform_device *pdev)
struct rsnd_priv *priv) = {
rsnd_ssi_remove,
rsnd_src_remove,
+ rsnd_ctu_remove,
+ rsnd_mix_remove,
rsnd_dvc_remove,
};
int ret = 0, i;
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
new file mode 100644
index 0000000..05498bb
--- /dev/null
+++ b/sound/soc/sh/rcar/ctu.c
@@ -0,0 +1,171 @@
+/*
+ * ctu.c
+ *
+ * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "rsnd.h"
+
+#define CTU_NAME_SIZE 16
+#define CTU_NAME "ctu"
+
+struct rsnd_ctu {
+ struct rsnd_ctu_platform_info *info; /* rcar_snd.h */
+ struct rsnd_mod mod;
+};
+
+#define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
+#define for_each_rsnd_ctu(pos, priv, i) \
+ for ((i) = 0; \
+ ((i) < rsnd_ctu_nr(priv)) && \
+ ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \
+ i++)
+
+#define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1)
+#define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0)
+static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable)
+{
+ rsnd_mod_write(mod, CTU_CTUIR, enable);
+}
+
+static int rsnd_ctu_init(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ rsnd_mod_hw_start(mod);
+
+ rsnd_ctu_initialize_lock(mod);
+
+ rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io));
+
+ rsnd_ctu_initialize_unlock(mod);
+
+ return 0;
+}
+
+static int rsnd_ctu_quit(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ rsnd_mod_hw_stop(mod);
+
+ return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ctu_ops = {
+ .name = CTU_NAME,
+ .init = rsnd_ctu_init,
+ .quit = rsnd_ctu_quit,
+};
+
+struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
+{
+ if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
+ id = 0;
+
+ return &((struct rsnd_ctu *)(priv->ctu) + id)->mod;
+}
+
+static void rsnd_of_parse_ctu(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv)
+{
+ struct device_node *node;
+ struct rsnd_ctu_platform_info *ctu_info;
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct device *dev = &pdev->dev;
+ int nr;
+
+ if (!of_data)
+ return;
+
+ node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
+ if (!node)
+ return;
+
+ nr = of_get_child_count(node);
+ if (!nr)
+ goto rsnd_of_parse_ctu_end;
+
+ ctu_info = devm_kzalloc(dev,
+ sizeof(struct rsnd_ctu_platform_info) * nr,
+ GFP_KERNEL);
+ if (!ctu_info) {
+ dev_err(dev, "ctu info allocation error\n");
+ goto rsnd_of_parse_ctu_end;
+ }
+
+ info->ctu_info = ctu_info;
+ info->ctu_info_nr = nr;
+
+rsnd_of_parse_ctu_end:
+ of_node_put(node);
+
+}
+
+int rsnd_ctu_probe(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv)
+{
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_ctu *ctu;
+ struct clk *clk;
+ char name[CTU_NAME_SIZE];
+ int i, nr, ret;
+
+ /* This driver doesn't support Gen1 at this point */
+ if (rsnd_is_gen1(priv)) {
+ dev_warn(dev, "CTU is not supported on Gen1\n");
+ return -EINVAL;
+ }
+
+ rsnd_of_parse_ctu(pdev, of_data, priv);
+
+ nr = info->ctu_info_nr;
+ if (!nr)
+ return 0;
+
+ ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL);
+ if (!ctu)
+ return -ENOMEM;
+
+ priv->ctu_nr = nr;
+ priv->ctu = ctu;
+
+ for_each_rsnd_ctu(ctu, priv, i) {
+ /*
+ * CTU00, CTU01, CTU02, CTU03 => CTU0
+ * CTU10, CTU11, CTU12, CTU13 => CTU1
+ */
+ snprintf(name, CTU_NAME_SIZE, "%s.%d",
+ CTU_NAME, i / 4);
+
+ clk = devm_clk_get(dev, name);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ctu->info = &info->ctu_info[i];
+
+ ret = rsnd_mod_init(priv, &ctu->mod, &rsnd_ctu_ops,
+ clk, RSND_MOD_CTU, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+void rsnd_ctu_remove(struct platform_device *pdev,
+ struct rsnd_priv *priv)
+{
+ struct rsnd_ctu *ctu;
+ int i;
+
+ for_each_rsnd_ctu(ctu, priv, i) {
+ rsnd_mod_quit(&ctu->mod);
+ }
+}
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index d306e29..bfbb8a5 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -27,6 +27,15 @@ struct rsnd_dma_ctrl {
int dmapp_num;
};
+struct rsnd_dma_ops {
+ char *name;
+ void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+ void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+ int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
+ struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
+ void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+};
+
#define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma)
/*
@@ -168,7 +177,7 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
dma_cap_set(DMA_SLAVE, mask);
dmaen->chan = dma_request_channel(mask, shdma_chan_filter,
- (void *)id);
+ (void *)(uintptr_t)id);
}
if (IS_ERR_OR_NULL(dmaen->chan)) {
dmaen->chan = NULL;
@@ -182,7 +191,8 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- dev_dbg(dev, "dma : %pad -> %pad\n",
+ dev_dbg(dev, "%s %pad -> %pad\n",
+ dma->ops->name,
&cfg.src_addr, &cfg.dst_addr);
ret = dmaengine_slave_config(dmaen->chan, &cfg);
@@ -215,6 +225,7 @@ static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
}
static struct rsnd_dma_ops rsnd_dmaen_ops = {
+ .name = "audmac",
.start = rsnd_dmaen_start,
.stop = rsnd_dmaen_stop,
.init = rsnd_dmaen_init,
@@ -360,6 +371,7 @@ static int rsnd_dmapp_init(struct rsnd_dai_stream *io,
}
static struct rsnd_dma_ops rsnd_dmapp_ops = {
+ .name = "audmac-pp",
.start = rsnd_dmapp_start,
.stop = rsnd_dmapp_stop,
.init = rsnd_dmapp_init,
@@ -414,7 +426,9 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU);
int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod);
int use_src = !!rsnd_io_to_mod_src(io);
- int use_dvc = !!rsnd_io_to_mod_dvc(io);
+ int use_cmd = !!rsnd_io_to_mod_dvc(io) ||
+ !!rsnd_io_to_mod_mix(io) ||
+ !!rsnd_io_to_mod_ctu(io);
int id = rsnd_mod_id(mod);
struct dma_addr {
dma_addr_t out_addr;
@@ -452,7 +466,7 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
};
/* it shouldn't happen */
- if (use_dvc && !use_src)
+ if (use_cmd && !use_src)
dev_err(dev, "DVC is selected without SRC\n");
/* use SSIU or SSI ? */
@@ -460,8 +474,8 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
is_ssi++;
return (is_from) ?
- dma_addrs[is_ssi][is_play][use_src + use_dvc].out_addr :
- dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr;
+ dma_addrs[is_ssi][is_play][use_src + use_cmd].out_addr :
+ dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr;
}
static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
@@ -482,7 +496,7 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
return rsnd_gen2_dma_addr(io, mod, is_play, is_from);
}
-#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
+#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */
static void rsnd_dma_of_path(struct rsnd_dma *dma,
struct rsnd_dai_stream *io,
int is_play,
@@ -492,55 +506,81 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
struct rsnd_mod *this = rsnd_dma_to_mod(dma);
struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+ struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
+ struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
struct rsnd_mod *mod[MOD_MAX];
- int i, index;
+ struct rsnd_mod *mod_start, *mod_end;
+ struct rsnd_priv *priv = rsnd_mod_to_priv(this);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ int nr, i;
+ if (!ssi)
+ return;
- for (i = 0; i < MOD_MAX; i++)
+ nr = 0;
+ for (i = 0; i < MOD_MAX; i++) {
mod[i] = NULL;
+ nr += !!rsnd_io_to_mod(io, i);
+ }
/*
- * in play case...
+ * [S] -*-> [E]
+ * [S] -*-> SRC -o-> [E]
+ * [S] -*-> SRC -> DVC -o-> [E]
+ * [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E]
*
- * src -> dst
+ * playback [S] = mem
+ * [E] = SSI
*
- * mem -> SSI
- * mem -> SRC -> SSI
- * mem -> SRC -> DVC -> SSI
+ * capture [S] = SSI
+ * [E] = mem
+ *
+ * -*-> Audio DMAC
+ * -o-> Audio DMAC peri peri
*/
- mod[0] = NULL; /* for "mem" */
- index = 1;
- for (i = 1; i < MOD_MAX; i++) {
- if (!src) {
- mod[i] = ssi;
- } else if (!dvc) {
- mod[i] = src;
- src = NULL;
- } else {
- if ((!is_play) && (this == src))
- this = dvc;
+ mod_start = (is_play) ? NULL : ssi;
+ mod_end = (is_play) ? ssi : NULL;
- mod[i] = (is_play) ? src : dvc;
- i++;
- mod[i] = (is_play) ? dvc : src;
+ mod[0] = mod_start;
+ for (i = 1; i < nr; i++) {
+ if (src) {
+ mod[i] = src;
src = NULL;
+ } else if (ctu) {
+ mod[i] = ctu;
+ ctu = NULL;
+ } else if (mix) {
+ mod[i] = mix;
+ mix = NULL;
+ } else if (dvc) {
+ mod[i] = dvc;
dvc = NULL;
}
-
- if (mod[i] == this)
- index = i;
-
- if (mod[i] == ssi)
- break;
}
+ mod[i] = mod_end;
- if (is_play) {
- *mod_from = mod[index - 1];
- *mod_to = mod[index];
+ /*
+ * | SSI | SRC |
+ * -------------+-----+-----+
+ * is_play | o | * |
+ * !is_play | * | o |
+ */
+ if ((this == ssi) == (is_play)) {
+ *mod_from = mod[nr - 1];
+ *mod_to = mod[nr];
} else {
- *mod_from = mod[index];
- *mod_to = mod[index - 1];
+ *mod_from = mod[0];
+ *mod_to = mod[1];
+ }
+
+ dev_dbg(dev, "module connection (this is %s[%d])\n",
+ rsnd_mod_name(this), rsnd_mod_id(this));
+ for (i = 0; i <= nr; i++) {
+ dev_dbg(dev, " %s[%d]%s\n",
+ rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]),
+ (mod[i] == *mod_from) ? " from" :
+ (mod[i] == *mod_to) ? " to" : "");
}
}
@@ -568,10 +608,11 @@ void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
{
- struct rsnd_mod *mod_from;
- struct rsnd_mod *mod_to;
+ struct rsnd_mod *mod_from = NULL;
+ struct rsnd_mod *mod_to = NULL;
struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+ struct device *dev = rsnd_priv_to_dev(priv);
int is_play = rsnd_io_is_play(io);
/*
@@ -598,6 +639,11 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
if (rsnd_is_gen1(priv))
dma->ops = &rsnd_dmaen_ops;
+ dev_dbg(dev, "%s %s[%d] -> %s[%d]\n",
+ dma->ops->name,
+ rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
+ rsnd_mod_name(mod_to), rsnd_mod_id(mod_to));
+
return dma->ops->init(io, dma, id, mod_from, mod_to);
}
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 36fc020..5779638 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -24,6 +24,7 @@ struct rsnd_dvc {
struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */
};
+#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
#define rsnd_dvc_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
@@ -63,6 +64,19 @@ static const char * const dvc_ramp_rate[] = {
"0.125 dB/8192 steps", /* 10111 */
};
+static void rsnd_dvc_soft_reset(struct rsnd_mod *mod)
+{
+ rsnd_mod_write(mod, DVC_SWRSR, 0);
+ rsnd_mod_write(mod, DVC_SWRSR, 1);
+}
+
+#define rsnd_dvc_initialize_lock(mod) __rsnd_dvc_initialize_lock(mod, 1)
+#define rsnd_dvc_initialize_unlock(mod) __rsnd_dvc_initialize_lock(mod, 0)
+static void __rsnd_dvc_initialize_lock(struct rsnd_mod *mod, u32 enable)
+{
+ rsnd_mod_write(mod, DVC_DVUIR, enable);
+}
+
static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
@@ -135,49 +149,24 @@ static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
+static int rsnd_dvc_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
- struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
- struct device *dev = rsnd_priv_to_dev(priv);
- int dvc_id = rsnd_mod_id(dvc_mod);
- int src_id = rsnd_mod_id(src_mod);
- u32 route[] = {
- [0] = 0x30000,
- [1] = 0x30001,
- [2] = 0x40000,
- [3] = 0x10000,
- [4] = 0x20000,
- [5] = 0x40100
- };
-
- if (src_id >= ARRAY_SIZE(route)) {
- dev_err(dev, "DVC%d isn't connected to SRC%d\n", dvc_id, src_id);
- return -EINVAL;
- }
-
- rsnd_mod_hw_start(dvc_mod);
+ rsnd_mod_hw_start(mod);
- /*
- * fixme
- * it doesn't support CTU/MIX
- */
- rsnd_mod_write(dvc_mod, CMD_ROUTE_SLCT, route[src_id]);
+ rsnd_dvc_soft_reset(mod);
- rsnd_mod_write(dvc_mod, DVC_SWRSR, 0);
- rsnd_mod_write(dvc_mod, DVC_SWRSR, 1);
+ rsnd_dvc_initialize_lock(mod);
- rsnd_mod_write(dvc_mod, DVC_DVUIR, 1);
+ rsnd_path_parse(priv, io);
- rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod, io));
+ rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io));
/* ch0/ch1 Volume */
- rsnd_dvc_volume_update(io, dvc_mod);
+ rsnd_dvc_volume_update(io, mod);
- rsnd_mod_write(dvc_mod, DVC_DVUIR, 0);
-
- rsnd_adg_set_cmd_timsel_gen2(dvc_mod, io);
+ rsnd_adg_set_cmd_timsel_gen2(mod, io);
return 0;
}
@@ -195,6 +184,8 @@ static int rsnd_dvc_start(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
+ rsnd_dvc_initialize_unlock(mod);
+
rsnd_mod_write(mod, CMD_CTRL, 0x10);
return 0;
@@ -341,23 +332,21 @@ int rsnd_dvc_probe(struct platform_device *pdev,
char name[RSND_DVC_NAME_SIZE];
int i, nr, ret;
- rsnd_of_parse_dvc(pdev, of_data, priv);
-
- nr = info->dvc_info_nr;
- if (!nr)
- return 0;
-
/* This driver doesn't support Gen1 at this point */
if (rsnd_is_gen1(priv)) {
dev_warn(dev, "CMD is not supported on Gen1\n");
return -EINVAL;
}
+ rsnd_of_parse_dvc(pdev, of_data, priv);
+
+ nr = info->dvc_info_nr;
+ if (!nr)
+ return 0;
+
dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL);
- if (!dvc) {
- dev_err(dev, "CMD allocate failed\n");
+ if (!dvc)
return -ENOMEM;
- }
priv->dvc_nr = nr;
priv->dvc = dvc;
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 8c7dc51..f04d17b 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -103,6 +103,22 @@ void rsnd_write(struct rsnd_priv *priv,
regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
}
+void rsnd_force_write(struct rsnd_priv *priv,
+ struct rsnd_mod *mod,
+ enum rsnd_reg reg, u32 data)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+ if (!rsnd_is_accessible_reg(priv, gen, reg))
+ return;
+
+ dev_dbg(dev, "w %s[%d] - %4d : %08x\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
+
+ regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data);
+}
+
void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
enum rsnd_reg reg, u32 mask, u32 data)
{
@@ -200,12 +216,13 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
/* FIXME: it needs SSI_MODE2/3 in the future */
RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80),
RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80),
- RSND_GEN_M_REG(BUSIF_DALIGN, 0x8, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80),
RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80),
- RSND_GEN_M_REG(INT_ENABLE, 0x18, 0x80),
+ RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80),
};
struct rsnd_regmap_field_conf conf_scu[] = {
RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20),
+ RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20),
RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20),
RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20),
RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20),
@@ -223,6 +240,18 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40),
RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40),
+ RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100),
+ RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100),
+ RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40),
+ RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40),
+ RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40),
+ RSND_GEN_M_REG(MIX_MIXMR, 0xd10, 0x40),
+ RSND_GEN_M_REG(MIX_MVPDR, 0xd14, 0x40),
+ RSND_GEN_M_REG(MIX_MDBAR, 0xd18, 0x40),
+ RSND_GEN_M_REG(MIX_MDBBR, 0xd1c, 0x40),
+ RSND_GEN_M_REG(MIX_MDBCR, 0xd20, 0x40),
+ RSND_GEN_M_REG(MIX_MDBDR, 0xd24, 0x40),
+ RSND_GEN_M_REG(MIX_MDBER, 0xd28, 0x40),
RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100),
RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100),
RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100),
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
new file mode 100644
index 0000000..0d5c102
--- /dev/null
+++ b/sound/soc/sh/rcar/mix.c
@@ -0,0 +1,200 @@
+/*
+ * mix.c
+ *
+ * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "rsnd.h"
+
+#define MIX_NAME_SIZE 16
+#define MIX_NAME "mix"
+
+struct rsnd_mix {
+ struct rsnd_mix_platform_info *info; /* rcar_snd.h */
+ struct rsnd_mod mod;
+};
+
+#define rsnd_mix_nr(priv) ((priv)->mix_nr)
+#define for_each_rsnd_mix(pos, priv, i) \
+ for ((i) = 0; \
+ ((i) < rsnd_mix_nr(priv)) && \
+ ((pos) = (struct rsnd_mix *)(priv)->mix + i); \
+ i++)
+
+
+static void rsnd_mix_soft_reset(struct rsnd_mod *mod)
+{
+ rsnd_mod_write(mod, MIX_SWRSR, 0);
+ rsnd_mod_write(mod, MIX_SWRSR, 1);
+}
+
+#define rsnd_mix_initialize_lock(mod) __rsnd_mix_initialize_lock(mod, 1)
+#define rsnd_mix_initialize_unlock(mod) __rsnd_mix_initialize_lock(mod, 0)
+static void __rsnd_mix_initialize_lock(struct rsnd_mod *mod, u32 enable)
+{
+ rsnd_mod_write(mod, MIX_MIXIR, enable);
+}
+
+static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+
+ /* Disable MIX dB setting */
+ rsnd_mod_write(mod, MIX_MDBER, 0);
+
+ rsnd_mod_write(mod, MIX_MDBAR, 0);
+ rsnd_mod_write(mod, MIX_MDBBR, 0);
+ rsnd_mod_write(mod, MIX_MDBCR, 0);
+ rsnd_mod_write(mod, MIX_MDBDR, 0);
+
+ /* Enable MIX dB setting */
+ rsnd_mod_write(mod, MIX_MDBER, 1);
+}
+
+static int rsnd_mix_init(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ rsnd_mod_hw_start(mod);
+
+ rsnd_mix_soft_reset(mod);
+
+ rsnd_mix_initialize_lock(mod);
+
+ rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io));
+
+ rsnd_path_parse(priv, io);
+
+ /* volume step */
+ rsnd_mod_write(mod, MIX_MIXMR, 0);
+ rsnd_mod_write(mod, MIX_MVPDR, 0);
+
+ rsnd_mix_volume_update(io, mod);
+
+ rsnd_mix_initialize_unlock(mod);
+
+ return 0;
+}
+
+static int rsnd_mix_quit(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ rsnd_mod_hw_stop(mod);
+
+ return 0;
+}
+
+static struct rsnd_mod_ops rsnd_mix_ops = {
+ .name = MIX_NAME,
+ .init = rsnd_mix_init,
+ .quit = rsnd_mix_quit,
+};
+
+struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
+{
+ if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
+ id = 0;
+
+ return &((struct rsnd_mix *)(priv->mix) + id)->mod;
+}
+
+static void rsnd_of_parse_mix(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv)
+{
+ struct device_node *node;
+ struct rsnd_mix_platform_info *mix_info;
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct device *dev = &pdev->dev;
+ int nr;
+
+ if (!of_data)
+ return;
+
+ node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
+ if (!node)
+ return;
+
+ nr = of_get_child_count(node);
+ if (!nr)
+ goto rsnd_of_parse_mix_end;
+
+ mix_info = devm_kzalloc(dev,
+ sizeof(struct rsnd_mix_platform_info) * nr,
+ GFP_KERNEL);
+ if (!mix_info) {
+ dev_err(dev, "mix info allocation error\n");
+ goto rsnd_of_parse_mix_end;
+ }
+
+ info->mix_info = mix_info;
+ info->mix_info_nr = nr;
+
+rsnd_of_parse_mix_end:
+ of_node_put(node);
+
+}
+
+int rsnd_mix_probe(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv)
+{
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_mix *mix;
+ struct clk *clk;
+ char name[MIX_NAME_SIZE];
+ int i, nr, ret;
+
+ /* This driver doesn't support Gen1 at this point */
+ if (rsnd_is_gen1(priv)) {
+ dev_warn(dev, "MIX is not supported on Gen1\n");
+ return -EINVAL;
+ }
+
+ rsnd_of_parse_mix(pdev, of_data, priv);
+
+ nr = info->mix_info_nr;
+ if (!nr)
+ return 0;
+
+ mix = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL);
+ if (!mix)
+ return -ENOMEM;
+
+ priv->mix_nr = nr;
+ priv->mix = mix;
+
+ for_each_rsnd_mix(mix, priv, i) {
+ snprintf(name, MIX_NAME_SIZE, "%s.%d",
+ MIX_NAME, i);
+
+ clk = devm_clk_get(dev, name);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ mix->info = &info->mix_info[i];
+
+ ret = rsnd_mod_init(priv, &mix->mod, &rsnd_mix_ops,
+ clk, RSND_MOD_MIX, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+void rsnd_mix_remove(struct platform_device *pdev,
+ struct rsnd_priv *priv)
+{
+ struct rsnd_mix *mix;
+ int i;
+
+ for_each_rsnd_mix(mix, priv, i) {
+ rsnd_mod_quit(&mix->mod);
+ }
+}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 09fcc54..7a0e52b 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -47,6 +47,18 @@ enum rsnd_reg {
RSND_REG_SCU_SYS_STATUS0,
RSND_REG_SCU_SYS_INT_EN0,
RSND_REG_CMD_ROUTE_SLCT,
+ RSND_REG_CTU_CTUIR,
+ RSND_REG_CTU_ADINR,
+ RSND_REG_MIX_SWRSR,
+ RSND_REG_MIX_MIXIR,
+ RSND_REG_MIX_ADINR,
+ RSND_REG_MIX_MIXMR,
+ RSND_REG_MIX_MVPDR,
+ RSND_REG_MIX_MDBAR,
+ RSND_REG_MIX_MDBBR,
+ RSND_REG_MIX_MDBCR,
+ RSND_REG_MIX_MDBDR,
+ RSND_REG_MIX_MDBER,
RSND_REG_DVC_SWRSR,
RSND_REG_DVC_DVUIR,
RSND_REG_DVC_ADINR,
@@ -99,6 +111,7 @@ enum rsnd_reg {
RSND_REG_SHARE26,
RSND_REG_SHARE27,
RSND_REG_SHARE28,
+ RSND_REG_SHARE29,
RSND_REG_MAX,
};
@@ -119,7 +132,7 @@ enum rsnd_reg {
#define RSND_REG_SSI_CTRL RSND_REG_SHARE02
#define RSND_REG_SSI_BUSIF_MODE RSND_REG_SHARE03
#define RSND_REG_SSI_BUSIF_ADINR RSND_REG_SHARE04
-#define RSND_REG_INT_ENABLE RSND_REG_SHARE05
+#define RSND_REG_SSI_INT_ENABLE RSND_REG_SHARE05
#define RSND_REG_SRC_BSDSR RSND_REG_SHARE06
#define RSND_REG_SRC_BSISR RSND_REG_SHARE07
#define RSND_REG_DIV_EN RSND_REG_SHARE08
@@ -136,13 +149,14 @@ enum rsnd_reg {
#define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19
#define RSND_REG_CMD_CTRL RSND_REG_SHARE20
#define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21
-#define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22
+#define RSND_REG_SSI_BUSIF_DALIGN RSND_REG_SHARE22
#define RSND_REG_DVC_VRCTR RSND_REG_SHARE23
#define RSND_REG_DVC_VRPDR RSND_REG_SHARE24
#define RSND_REG_DVC_VRDBR RSND_REG_SHARE25
#define RSND_REG_SCU_SYS_STATUS1 RSND_REG_SHARE26
#define RSND_REG_SCU_SYS_INT_EN1 RSND_REG_SHARE27
#define RSND_REG_SRC_INT_ENABLE0 RSND_REG_SHARE28
+#define RSND_REG_SRC_BUSIF_DALIGN RSND_REG_SHARE29
struct rsnd_of_data;
struct rsnd_priv;
@@ -157,27 +171,28 @@ struct rsnd_dai_stream;
rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
#define rsnd_mod_write(m, r, d) \
rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
+#define rsnd_mod_force_write(m, r, d) \
+ rsnd_force_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
#define rsnd_mod_bset(m, r, s, d) \
rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
enum rsnd_reg reg, u32 data);
+void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
+ enum rsnd_reg reg, u32 data);
void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
u32 mask, u32 data);
-u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
+u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
+u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
+u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
+void rsnd_path_parse(struct rsnd_priv *priv,
+ struct rsnd_dai_stream *io);
/*
* R-Car DMA
*/
struct rsnd_dma;
-struct rsnd_dma_ops {
- void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
- void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
- int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
- struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
- void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-};
struct rsnd_dmaen {
struct dma_chan *chan;
@@ -217,6 +232,8 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
*/
enum rsnd_mod_type {
RSND_MOD_DVC = 0,
+ RSND_MOD_MIX,
+ RSND_MOD_CTU,
RSND_MOD_SRC,
RSND_MOD_SSI,
RSND_MOD_MAX,
@@ -312,7 +329,7 @@ struct rsnd_mod {
#define rsnd_mod_to_priv(mod) ((mod)->priv)
#define rsnd_mod_to_dma(mod) (&(mod)->dma)
-#define rsnd_mod_id(mod) ((mod)->id)
+#define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
#define rsnd_mod_hw_start(mod) clk_enable((mod)->clk)
#define rsnd_mod_hw_stop(mod) clk_disable((mod)->clk)
@@ -345,9 +362,12 @@ struct rsnd_dai_stream {
int byte_per_period;
int next_period_byte;
};
-#define rsnd_io_to_mod_ssi(io) ((io)->mod[RSND_MOD_SSI])
-#define rsnd_io_to_mod_src(io) ((io)->mod[RSND_MOD_SRC])
-#define rsnd_io_to_mod_dvc(io) ((io)->mod[RSND_MOD_DVC])
+#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
+#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
+#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC)
+#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU)
+#define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX)
+#define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC)
#define rsnd_io_to_rdai(io) ((io)->rdai)
#define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io)))
#define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io)
@@ -437,12 +457,6 @@ struct rsnd_priv {
void *gen;
/*
- * below value will be filled on rsnd_src_probe()
- */
- void *src;
- int src_nr;
-
- /*
* below value will be filled on rsnd_adg_probe()
*/
void *adg;
@@ -459,6 +473,24 @@ struct rsnd_priv {
int ssi_nr;
/*
+ * below value will be filled on rsnd_src_probe()
+ */
+ void *src;
+ int src_nr;
+
+ /*
+ * below value will be filled on rsnd_ctu_probe()
+ */
+ void *ctu;
+ int ctu_nr;
+
+ /*
+ * below value will be filled on rsnd_mix_probe()
+ */
+ void *mix;
+ int mix_nr;
+
+ /*
* below value will be filled on rsnd_dvc_probe()
*/
void *dvc;
@@ -531,6 +563,19 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod,
u32 max);
/*
+ * R-Car SSI
+ */
+int rsnd_ssi_probe(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv);
+void rsnd_ssi_remove(struct platform_device *pdev,
+ struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
+int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
+int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
+int rsnd_ssi_use_busif(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
+
+/*
* R-Car SRC
*/
int rsnd_src_probe(struct platform_device *pdev,
@@ -550,20 +595,27 @@ int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod);
int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod);
-#define rsnd_src_nr(priv) ((priv)->src_nr)
+/*
+ * R-Car CTU
+ */
+int rsnd_ctu_probe(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv);
+
+void rsnd_ctu_remove(struct platform_device *pdev,
+ struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
/*
- * R-Car SSI
+ * R-Car MIX
*/
-int rsnd_ssi_probe(struct platform_device *pdev,
+int rsnd_mix_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
-void rsnd_ssi_remove(struct platform_device *pdev,
+
+void rsnd_mix_remove(struct platform_device *pdev,
struct rsnd_priv *priv);
-struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
-int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
-int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
-int rsnd_ssi_use_busif(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
+struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
/*
* R-Car DVC
@@ -575,7 +627,4 @@ void rsnd_dvc_remove(struct platform_device *pdev,
struct rsnd_priv *priv);
struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
-#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
-
-
#endif
diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c
index 84e9357..d61db9c 100644
--- a/sound/soc/sh/rcar/rsrc-card.c
+++ b/sound/soc/sh/rcar/rsrc-card.c
@@ -41,6 +41,7 @@ static const struct rsrc_card_of_data routes_of_ssi0_ak4642 = {
static const struct of_device_id rsrc_card_of_match[] = {
{ .compatible = "renesas,rsrc-card,lager", .data = &routes_of_ssi0_ak4642 },
{ .compatible = "renesas,rsrc-card,koelsch", .data = &routes_of_ssi0_ak4642 },
+ { .compatible = "renesas,rsrc-card", },
{},
};
MODULE_DEVICE_TABLE(of, rsrc_card_of_match);
@@ -242,8 +243,15 @@ static int rsrc_card_parse_links(struct device_node *np,
snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
/* additional name prefix */
- priv->codec_conf.of_node = dai_link->codec_of_node;
- priv->codec_conf.name_prefix = of_data->prefix;
+ if (of_data) {
+ priv->codec_conf.of_node = dai_link->codec_of_node;
+ priv->codec_conf.name_prefix = of_data->prefix;
+ } else {
+ snd_soc_of_parse_audio_prefix(&priv->snd_card,
+ &priv->codec_conf,
+ dai_link->codec_of_node,
+ "audio-prefix");
+ }
/* set dai_name */
snprintf(dai_props->dai_name, DAI_NAME_NUM, "be.%s",
@@ -361,8 +369,14 @@ static int rsrc_card_parse_of(struct device_node *node,
priv->snd_card.num_links = num;
priv->snd_card.codec_conf = &priv->codec_conf;
priv->snd_card.num_configs = 1;
- priv->snd_card.of_dapm_routes = of_data->routes;
- priv->snd_card.num_of_dapm_routes = of_data->num_routes;
+
+ if (of_data) {
+ priv->snd_card.of_dapm_routes = of_data->routes;
+ priv->snd_card.num_of_dapm_routes = of_data->num_routes;
+ } else {
+ snd_soc_of_parse_audio_routing(&priv->snd_card,
+ "audio-routing");
+ }
/* Parse the card name from DT */
snd_soc_of_parse_card_name(&priv->snd_card, "card-name");
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index c61c171..89a18e1 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -30,6 +30,7 @@ struct rsnd_src {
#define RSND_SRC_NAME_SIZE 16
+#define rsnd_src_nr(priv) ((priv)->src_nr)
#define rsnd_enable_sync_convert(src) ((src)->sen.val)
#define rsnd_src_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
@@ -117,6 +118,20 @@ struct rsnd_src {
/*
* Gen1/Gen2 common functions
*/
+static void rsnd_src_soft_reset(struct rsnd_mod *mod)
+{
+ rsnd_mod_write(mod, SRC_SWRSR, 0);
+ rsnd_mod_write(mod, SRC_SWRSR, 1);
+}
+
+
+#define rsnd_src_initialize_lock(mod) __rsnd_src_initialize_lock(mod, 1)
+#define rsnd_src_initialize_unlock(mod) __rsnd_src_initialize_lock(mod, 0)
+static void __rsnd_src_initialize_lock(struct rsnd_mod *mod, u32 enable)
+{
+ rsnd_mod_write(mod, SRC_SRCIR, enable);
+}
+
static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
@@ -133,7 +148,6 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
int use_busif)
{
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
int ssi_id = rsnd_mod_id(ssi_mod);
/*
@@ -170,27 +184,14 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
* DMA settings for SSIU
*/
if (use_busif) {
- u32 val = 0x76543210;
- u32 mask = ~0;
+ u32 val = rsnd_get_dalign(ssi_mod, io);
rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR,
- rsnd_get_adinr(ssi_mod, io));
+ rsnd_get_adinr_bit(ssi_mod, io));
rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1);
rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1);
- mask <<= runtime->channels * 4;
- val = val & mask;
-
- switch (runtime->sample_bits) {
- case 16:
- val |= 0x67452301 & ~mask;
- break;
- case 32:
- val |= 0x76543210 & ~mask;
- break;
- }
- rsnd_mod_write(ssi_mod, BUSIF_DALIGN, val);
-
+ rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val);
}
return 0;
@@ -215,10 +216,9 @@ int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod)
return 0;
/* enable SSI interrupt if Gen2 */
- if (rsnd_ssi_is_dma_mode(ssi_mod))
- rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0e000000);
- else
- rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000);
+ rsnd_mod_write(ssi_mod, SSI_INT_ENABLE,
+ rsnd_ssi_is_dma_mode(ssi_mod) ?
+ 0x0e000000 : 0x0f000000);
return 0;
}
@@ -231,7 +231,7 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod)
return 0;
/* disable SSI interrupt if Gen2 */
- rsnd_mod_write(ssi_mod, INT_ENABLE, 0x00000000);
+ rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000);
return 0;
}
@@ -294,12 +294,8 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
if (convert_rate)
fsrate = 0x0400000 / convert_rate * runtime->rate;
- /* set/clear soft reset */
- rsnd_mod_write(mod, SRC_SWRSR, 0);
- rsnd_mod_write(mod, SRC_SWRSR, 1);
-
/* Set channel number and output bit length */
- rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod, io));
+ rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr_bit(mod, io));
/* Enable the initial value of IFS */
if (fsrate) {
@@ -358,17 +354,15 @@ static int rsnd_src_init(struct rsnd_mod *mod,
rsnd_mod_hw_start(mod);
+ rsnd_src_soft_reset(mod);
+
+ rsnd_src_initialize_lock(mod);
+
src->err = 0;
/* reset sync convert_rate */
src->sync.val = 0;
- /*
- * Initialize the operation of the SRC internal circuits
- * see rsnd_src_start()
- */
- rsnd_mod_write(mod, SRC_SRCIR, 1);
-
return 0;
}
@@ -395,11 +389,7 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
static int rsnd_src_start(struct rsnd_mod *mod)
{
- /*
- * Cancel the initialization and operate the SRC function
- * see rsnd_src_init()
- */
- rsnd_mod_write(mod, SRC_SRCIR, 0);
+ rsnd_src_initialize_unlock(mod);
return 0;
}
@@ -617,6 +607,14 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable)
int_val = 0;
}
+ /*
+ * WORKAROUND
+ *
+ * ignore over flow error when rsnd_enable_sync_convert()
+ */
+ if (rsnd_enable_sync_convert(src))
+ sys_int_val = sys_int_val & 0xffff;
+
rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val);
rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val);
rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
@@ -632,11 +630,22 @@ static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod)
static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
{
- u32 val = OUF_SRC(rsnd_mod_id(mod));
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+ u32 val0, val1;
bool ret = false;
- if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val) ||
- (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val)) {
+ val0 = val1 = OUF_SRC(rsnd_mod_id(mod));
+
+ /*
+ * WORKAROUND
+ *
+ * ignore over flow error when rsnd_enable_sync_convert()
+ */
+ if (rsnd_enable_sync_convert(src))
+ val0 = val0 & 0xffff;
+
+ if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) ||
+ (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1)) {
struct rsnd_src *src = rsnd_mod_to_src(mod);
src->err++;
@@ -652,7 +661,20 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
static int _rsnd_src_start_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io)
{
- u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11;
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+ u32 val;
+
+ val = rsnd_get_dalign(mod, io);
+
+ rsnd_mod_write(mod, SRC_BUSIF_DALIGN, val);
+
+ /*
+ * WORKAROUND
+ *
+ * Enable SRC output if you want to use sync convert together with DVC
+ */
+ val = (rsnd_io_to_mod_dvc(io) && !rsnd_enable_sync_convert(src)) ?
+ 0x01 : 0x11;
rsnd_mod_write(mod, SRC_CTRL, val);
@@ -922,13 +944,6 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
return 0;
/*
- * We can't use SRC sync convert
- * if it has DVC
- */
- if (rsnd_io_to_mod_dvc(io))
- return 0;
-
- /*
* enable sync convert
*/
ret = rsnd_kctrl_new_s(mod, io, rtd,
@@ -1047,10 +1062,8 @@ int rsnd_src_probe(struct platform_device *pdev,
return 0;
src = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL);
- if (!src) {
- dev_err(dev, "SRC allocate failed\n");
+ if (!src)
return -ENOMEM;
- }
priv->src_nr = nr;
priv->src = src;
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 2fbe59f..d45b9a7 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -770,10 +770,8 @@ int rsnd_ssi_probe(struct platform_device *pdev,
*/
nr = info->ssi_info_nr;
ssi = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL);
- if (!ssi) {
- dev_err(dev, "SSI allocate failed\n");
+ if (!ssi)
return -ENOMEM;
- }
priv->ssi = ssi;
priv->ssi_nr = nr;
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
index ab13146..89ed1b1 100644
--- a/sound/soc/sh/ssi.c
+++ b/sound/soc/sh/ssi.c
@@ -385,14 +385,9 @@ static const struct snd_soc_component_driver sh4_ssi_component = {
static int sh4_soc_dai_probe(struct platform_device *pdev)
{
- return snd_soc_register_component(&pdev->dev, &sh4_ssi_component,
- sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
-}
-
-static int sh4_soc_dai_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_component(&pdev->dev);
- return 0;
+ return devm_snd_soc_register_component(&pdev->dev, &sh4_ssi_component,
+ sh4_ssi_dai,
+ ARRAY_SIZE(sh4_ssi_dai));
}
static struct platform_driver sh4_ssi_driver = {
@@ -401,7 +396,6 @@ static struct platform_driver sh4_ssi_driver = {
},
.probe = sh4_soc_dai_probe,
- .remove = sh4_soc_dai_remove,
};
module_platform_driver(sh4_ssi_driver);
diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c
index 08d7259..d40efc9 100644
--- a/sound/soc/soc-ac97.c
+++ b/sound/soc/soc-ac97.c
@@ -85,10 +85,19 @@ EXPORT_SYMBOL(snd_soc_alloc_ac97_codec);
/**
* snd_soc_new_ac97_codec - initailise AC97 device
* @codec: audio codec
+ * @id: The expected device ID
+ * @id_mask: Mask that is applied to the device ID before comparing with @id
*
* Initialises AC97 codec resources for use by ad-hoc devices only.
+ *
+ * If @id is not 0 this function will reset the device, then read the ID from
+ * the device and check if it matches the expected ID. If it doesn't match an
+ * error will be returned and device will not be registered.
+ *
+ * Returns: A PTR_ERR() on failure or a valid snd_ac97 struct on success.
*/
-struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec)
+struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
+ unsigned int id, unsigned int id_mask)
{
struct snd_ac97 *ac97;
int ret;
@@ -97,13 +106,24 @@ struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec)
if (IS_ERR(ac97))
return ac97;
- ret = device_add(&ac97->dev);
- if (ret) {
- put_device(&ac97->dev);
- return ERR_PTR(ret);
+ if (id) {
+ ret = snd_ac97_reset(ac97, false, id, id_mask);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to reset AC97 device: %d\n",
+ ret);
+ goto err_put_device;
+ }
}
+ ret = device_add(&ac97->dev);
+ if (ret)
+ goto err_put_device;
+
return ac97;
+
+err_put_device:
+ put_device(&ac97->dev);
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 0e1e69c..6173d15 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -654,10 +654,12 @@ int snd_soc_suspend(struct device *dev)
/* suspend all CODECs */
list_for_each_entry(codec, &card->codec_dev_list, card_list) {
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
/* If there are paths active then the CODEC will be held with
* bias _ON and should not be suspended. */
if (!codec->suspended) {
- switch (codec->dapm.bias_level) {
+ switch (snd_soc_dapm_get_bias_level(dapm)) {
case SND_SOC_BIAS_STANDBY:
/*
* If the CODEC is capable of idle
@@ -665,7 +667,7 @@ int snd_soc_suspend(struct device *dev)
* means it's doing something,
* otherwise fall through.
*/
- if (codec->dapm.idle_bias_off) {
+ if (dapm->idle_bias_off) {
dev_dbg(codec->dev,
"ASoC: idle_bias_off CODEC on over suspend\n");
break;
@@ -978,7 +980,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
static void soc_remove_component(struct snd_soc_component *component)
{
- if (!component->probed)
+ if (!component->card)
return;
/* This is a HACK and will be removed soon */
@@ -991,7 +993,7 @@ static void soc_remove_component(struct snd_soc_component *component)
snd_soc_dapm_free(snd_soc_component_get_dapm(component));
soc_cleanup_component_debugfs(component);
- component->probed = 0;
+ component->card = NULL;
module_put(component->dev->driver->owner);
}
@@ -1102,16 +1104,26 @@ static int soc_probe_component(struct snd_soc_card *card,
struct snd_soc_dai *dai;
int ret;
- if (component->probed)
+ if (!strcmp(component->name, "snd-soc-dummy"))
return 0;
- component->card = card;
- dapm->card = card;
- soc_set_name_prefix(card, component);
+ if (component->card) {
+ if (component->card != card) {
+ dev_err(component->dev,
+ "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n",
+ card->name, component->card->name);
+ return -ENODEV;
+ }
+ return 0;
+ }
if (!try_module_get(component->dev->driver->owner))
return -ENODEV;
+ component->card = card;
+ dapm->card = card;
+ soc_set_name_prefix(card, component);
+
soc_init_component_debugfs(component);
if (component->dapm_widgets) {
@@ -1155,7 +1167,6 @@ static int soc_probe_component(struct snd_soc_card *card,
snd_soc_dapm_add_routes(dapm, component->dapm_routes,
component->num_dapm_routes);
- component->probed = 1;
list_add(&dapm->list, &card->dapm_list);
/* This is a HACK and will be removed soon */
@@ -1166,6 +1177,7 @@ static int soc_probe_component(struct snd_soc_card *card,
err_probe:
soc_cleanup_component_debugfs(component);
+ component->card = NULL;
module_put(component->dev->driver->owner);
return ret;
@@ -1449,7 +1461,7 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
rtd->dev_registered = 0;
}
- if (component && component->probed)
+ if (component)
soc_remove_component(component);
}
@@ -2128,7 +2140,7 @@ EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll);
/**
* snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
* @dai: DAI
- * @ratio Ratio of BCLK to Sample rate.
+ * @ratio: Ratio of BCLK to Sample rate.
*
* Configures the DAI for a preset BCLK to sample rate ratio.
*/
@@ -2652,10 +2664,7 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
component->probe = component->driver->probe;
component->remove = component->driver->remove;
- if (!component->dapm_ptr)
- component->dapm_ptr = &component->dapm;
-
- dapm = component->dapm_ptr;
+ dapm = &component->dapm;
dapm->dev = dev;
dapm->component = component;
dapm->bias_level = SND_SOC_BIAS_OFF;
@@ -2799,6 +2808,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_component);
/**
* snd_soc_unregister_component - Unregister a component from the ASoC core
*
+ * @dev: The device to unregister
*/
void snd_soc_unregister_component(struct device *dev)
{
@@ -2839,7 +2849,7 @@ static void snd_soc_platform_drv_remove(struct snd_soc_component *component)
* snd_soc_add_platform - Add a platform to the ASoC core
* @dev: The parent device for the platform
* @platform: The platform to add
- * @platform_driver: The driver for the platform
+ * @platform_drv: The driver for the platform
*/
int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
const struct snd_soc_platform_driver *platform_drv)
@@ -2878,7 +2888,8 @@ EXPORT_SYMBOL_GPL(snd_soc_add_platform);
/**
* snd_soc_register_platform - Register a platform with the ASoC core
*
- * @platform: platform to register
+ * @dev: The device for the platform
+ * @platform_drv: The driver for the platform
*/
int snd_soc_register_platform(struct device *dev,
const struct snd_soc_platform_driver *platform_drv)
@@ -2939,7 +2950,7 @@ EXPORT_SYMBOL_GPL(snd_soc_lookup_platform);
/**
* snd_soc_unregister_platform - Unregister a platform from the ASoC core
*
- * @platform: platform to unregister
+ * @dev: platform to unregister
*/
void snd_soc_unregister_platform(struct device *dev)
{
@@ -3030,13 +3041,17 @@ static int snd_soc_codec_set_bias_level(struct snd_soc_dapm_context *dapm,
/**
* snd_soc_register_codec - Register a codec with the ASoC core
*
- * @codec: codec to register
+ * @dev: The parent device for this codec
+ * @codec_drv: Codec driver
+ * @dai_drv: The associated DAI driver
+ * @num_dai: Number of DAIs
*/
int snd_soc_register_codec(struct device *dev,
const struct snd_soc_codec_driver *codec_drv,
struct snd_soc_dai_driver *dai_drv,
int num_dai)
{
+ struct snd_soc_dapm_context *dapm;
struct snd_soc_codec *codec;
struct snd_soc_dai *dai;
int ret, i;
@@ -3047,7 +3062,6 @@ int snd_soc_register_codec(struct device *dev,
if (codec == NULL)
return -ENOMEM;
- codec->component.dapm_ptr = &codec->dapm;
codec->component.codec = codec;
ret = snd_soc_component_initialize(&codec->component,
@@ -3077,12 +3091,14 @@ int snd_soc_register_codec(struct device *dev,
if (codec_drv->read)
codec->component.read = snd_soc_codec_drv_read;
codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
- codec->dapm.idle_bias_off = codec_drv->idle_bias_off;
- codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off;
+
+ dapm = snd_soc_codec_get_dapm(codec);
+ dapm->idle_bias_off = codec_drv->idle_bias_off;
+ dapm->suspend_bias_off = codec_drv->suspend_bias_off;
if (codec_drv->seq_notifier)
- codec->dapm.seq_notifier = codec_drv->seq_notifier;
+ dapm->seq_notifier = codec_drv->seq_notifier;
if (codec_drv->set_bias_level)
- codec->dapm.set_bias_level = snd_soc_codec_set_bias_level;
+ dapm->set_bias_level = snd_soc_codec_set_bias_level;
codec->dev = dev;
codec->driver = codec_drv;
codec->component.val_bytes = codec_drv->reg_word_size;
@@ -3129,7 +3145,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec);
/**
* snd_soc_unregister_codec - Unregister a codec from the ASoC core
*
- * @codec: codec to unregister
+ * @dev: codec to unregister
*/
void snd_soc_unregister_codec(struct device *dev)
{
@@ -3304,6 +3320,26 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
+void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
+ struct snd_soc_codec_conf *codec_conf,
+ struct device_node *of_node,
+ const char *propname)
+{
+ struct device_node *np = card->dev->of_node;
+ const char *str;
+ int ret;
+
+ ret = of_property_read_string(np, propname, &str);
+ if (ret < 0) {
+ /* no prefix is not error */
+ return;
+ }
+
+ codec_conf->of_node = of_node;
+ codec_conf->name_prefix = str;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix);
+
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname)
{
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index e0de807..f4bf21a 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -47,6 +47,13 @@
#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
+#define SND_SOC_DAPM_DIR_REVERSE(x) ((x == SND_SOC_DAPM_DIR_IN) ? \
+ SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN)
+
+#define snd_soc_dapm_for_each_direction(dir) \
+ for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \
+ (dir)++)
+
static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
const char *control,
@@ -167,45 +174,59 @@ static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
}
/*
- * dapm_widget_invalidate_input_paths() - Invalidate the cached number of input
- * paths
- * @w: The widget for which to invalidate the cached number of input paths
- *
- * The function resets the cached number of inputs for the specified widget and
- * all widgets that can be reached via outgoing paths from the widget.
- *
- * This function must be called if the number of input paths for a widget might
- * have changed. E.g. if the source state of a widget changes or a path is added
- * or activated with the widget as the sink.
+ * Common implementation for dapm_widget_invalidate_input_paths() and
+ * dapm_widget_invalidate_output_paths(). The function is inlined since the
+ * combined size of the two specialized functions is only marginally larger then
+ * the size of the generic function and at the same time the fast path of the
+ * specialized functions is significantly smaller than the generic function.
*/
-static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
+static __always_inline void dapm_widget_invalidate_paths(
+ struct snd_soc_dapm_widget *w, enum snd_soc_dapm_direction dir)
{
- struct snd_soc_dapm_widget *sink;
+ enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
+ struct snd_soc_dapm_widget *node;
struct snd_soc_dapm_path *p;
LIST_HEAD(list);
dapm_assert_locked(w->dapm);
- if (w->inputs == -1)
+ if (w->endpoints[dir] == -1)
return;
- w->inputs = -1;
list_add_tail(&w->work_list, &list);
+ w->endpoints[dir] = -1;
list_for_each_entry(w, &list, work_list) {
- list_for_each_entry(p, &w->sinks, list_source) {
+ snd_soc_dapm_widget_for_each_path(w, dir, p) {
if (p->is_supply || p->weak || !p->connect)
continue;
- sink = p->sink;
- if (sink->inputs != -1) {
- sink->inputs = -1;
- list_add_tail(&sink->work_list, &list);
+ node = p->node[rdir];
+ if (node->endpoints[dir] != -1) {
+ node->endpoints[dir] = -1;
+ list_add_tail(&node->work_list, &list);
}
}
}
}
/*
+ * dapm_widget_invalidate_input_paths() - Invalidate the cached number of
+ * input paths
+ * @w: The widget for which to invalidate the cached number of input paths
+ *
+ * Resets the cached number of inputs for the specified widget and all widgets
+ * that can be reached via outcoming paths from the widget.
+ *
+ * This function must be called if the number of output paths for a widget might
+ * have changed. E.g. if the source state of a widget changes or a path is added
+ * or activated with the widget as the sink.
+ */
+static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
+{
+ dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_IN);
+}
+
+/*
* dapm_widget_invalidate_output_paths() - Invalidate the cached number of
* output paths
* @w: The widget for which to invalidate the cached number of output paths
@@ -219,29 +240,7 @@ static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
*/
static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
{
- struct snd_soc_dapm_widget *source;
- struct snd_soc_dapm_path *p;
- LIST_HEAD(list);
-
- dapm_assert_locked(w->dapm);
-
- if (w->outputs == -1)
- return;
-
- w->outputs = -1;
- list_add_tail(&w->work_list, &list);
-
- list_for_each_entry(w, &list, work_list) {
- list_for_each_entry(p, &w->sources, list_sink) {
- if (p->is_supply || p->weak || !p->connect)
- continue;
- source = p->source;
- if (source->outputs != -1) {
- source->outputs = -1;
- list_add_tail(&source->work_list, &list);
- }
- }
- }
+ dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_OUT);
}
/*
@@ -270,9 +269,9 @@ static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
* endpoints is either connected or disconnected that sum won't change,
* so there is no need to re-check the path.
*/
- if (p->source->inputs != 0)
+ if (p->source->endpoints[SND_SOC_DAPM_DIR_IN] != 0)
dapm_widget_invalidate_input_paths(p->sink);
- if (p->sink->outputs != 0)
+ if (p->sink->endpoints[SND_SOC_DAPM_DIR_OUT] != 0)
dapm_widget_invalidate_output_paths(p->source);
}
@@ -283,11 +282,11 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
mutex_lock(&card->dapm_mutex);
list_for_each_entry(w, &card->widgets, list) {
- if (w->is_sink || w->is_source) {
+ if (w->is_ep) {
dapm_mark_dirty(w, "Rechecking endpoints");
- if (w->is_sink)
+ if (w->is_ep & SND_SOC_DAPM_EP_SINK)
dapm_widget_invalidate_output_paths(w);
- if (w->is_source)
+ if (w->is_ep & SND_SOC_DAPM_EP_SOURCE)
dapm_widget_invalidate_input_paths(w);
}
}
@@ -894,7 +893,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
/* add kcontrol */
for (i = 0; i < w->num_kcontrols; i++) {
/* match name */
- list_for_each_entry(path, &w->sources, list_sink) {
+ snd_soc_dapm_widget_for_each_source_path(w, path) {
/* mixer/mux paths name must match control name */
if (path->name != (char *)w->kcontrol_news[i].name)
continue;
@@ -923,18 +922,18 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
static int dapm_new_mux(struct snd_soc_dapm_widget *w)
{
struct snd_soc_dapm_context *dapm = w->dapm;
+ enum snd_soc_dapm_direction dir;
struct snd_soc_dapm_path *path;
- struct list_head *paths;
const char *type;
int ret;
switch (w->id) {
case snd_soc_dapm_mux:
- paths = &w->sources;
+ dir = SND_SOC_DAPM_DIR_OUT;
type = "mux";
break;
case snd_soc_dapm_demux:
- paths = &w->sinks;
+ dir = SND_SOC_DAPM_DIR_IN;
type = "demux";
break;
default:
@@ -948,7 +947,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
return -EINVAL;
}
- if (list_empty(paths)) {
+ if (list_empty(&w->edges[dir])) {
dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
return -EINVAL;
}
@@ -957,16 +956,9 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
if (ret < 0)
return ret;
- if (w->id == snd_soc_dapm_mux) {
- list_for_each_entry(path, &w->sources, list_sink) {
- if (path->name)
- dapm_kcontrol_add_path(w->kcontrols[0], path);
- }
- } else {
- list_for_each_entry(path, &w->sinks, list_source) {
- if (path->name)
- dapm_kcontrol_add_path(w->kcontrols[0], path);
- }
+ snd_soc_dapm_widget_for_each_path(w, dir, path) {
+ if (path->name)
+ dapm_kcontrol_add_path(w->kcontrols[0], path);
}
return 0;
@@ -1032,66 +1024,59 @@ static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
}
}
-/* add widget to list if it's not already in the list */
-static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list,
- struct snd_soc_dapm_widget *w)
+static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
+ struct list_head *widgets)
{
- struct snd_soc_dapm_widget_list *wlist;
- int wlistsize, wlistentries, i;
-
- if (*list == NULL)
- return -EINVAL;
-
- wlist = *list;
+ struct snd_soc_dapm_widget *w;
+ struct list_head *it;
+ unsigned int size = 0;
+ unsigned int i = 0;
- /* is this widget already in the list */
- for (i = 0; i < wlist->num_widgets; i++) {
- if (wlist->widgets[i] == w)
- return 0;
- }
+ list_for_each(it, widgets)
+ size++;
- /* allocate some new space */
- wlistentries = wlist->num_widgets + 1;
- wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
- wlistentries * sizeof(struct snd_soc_dapm_widget *);
- *list = krealloc(wlist, wlistsize, GFP_KERNEL);
- if (*list == NULL) {
- dev_err(w->dapm->dev, "ASoC: can't allocate widget list for %s\n",
- w->name);
+ *list = kzalloc(sizeof(**list) + size * sizeof(*w), GFP_KERNEL);
+ if (*list == NULL)
return -ENOMEM;
- }
- wlist = *list;
- /* insert the widget */
- dev_dbg(w->dapm->dev, "ASoC: added %s in widget list pos %d\n",
- w->name, wlist->num_widgets);
+ list_for_each_entry(w, widgets, work_list)
+ (*list)->widgets[i++] = w;
- wlist->widgets[wlist->num_widgets] = w;
- wlist->num_widgets++;
- return 1;
+ (*list)->num_widgets = i;
+
+ return 0;
}
/*
- * Recursively check for a completed path to an active or physically connected
- * output widget. Returns number of complete paths.
+ * Common implementation for is_connected_output_ep() and
+ * is_connected_input_ep(). The function is inlined since the combined size of
+ * the two specialized functions is only marginally larger then the size of the
+ * generic function and at the same time the fast path of the specialized
+ * functions is significantly smaller than the generic function.
*/
-static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
- struct snd_soc_dapm_widget_list **list)
+static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
+ struct list_head *list, enum snd_soc_dapm_direction dir,
+ int (*fn)(struct snd_soc_dapm_widget *, struct list_head *))
{
+ enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
struct snd_soc_dapm_path *path;
int con = 0;
- if (widget->outputs >= 0)
- return widget->outputs;
+ if (widget->endpoints[dir] >= 0)
+ return widget->endpoints[dir];
DAPM_UPDATE_STAT(widget, path_checks);
- if (widget->is_sink && widget->connected) {
- widget->outputs = snd_soc_dapm_suspend_check(widget);
- return widget->outputs;
+ /* do we need to add this widget to the list ? */
+ if (list)
+ list_add_tail(&widget->work_list, list);
+
+ if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) {
+ widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget);
+ return widget->endpoints[dir];
}
- list_for_each_entry(path, &widget->sinks, list_source) {
+ snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
DAPM_UPDATE_STAT(widget, neighbour_checks);
if (path->weak || path->is_supply)
@@ -1100,91 +1085,40 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
if (path->walking)
return 1;
- trace_snd_soc_dapm_output_path(widget, path);
+ trace_snd_soc_dapm_path(widget, dir, path);
if (path->connect) {
path->walking = 1;
-
- /* do we need to add this widget to the list ? */
- if (list) {
- int err;
- err = dapm_list_add_widget(list, path->sink);
- if (err < 0) {
- dev_err(widget->dapm->dev,
- "ASoC: could not add widget %s\n",
- widget->name);
- path->walking = 0;
- return con;
- }
- }
-
- con += is_connected_output_ep(path->sink, list);
-
+ con += fn(path->node[dir], list);
path->walking = 0;
}
}
- widget->outputs = con;
+ widget->endpoints[dir] = con;
return con;
}
/*
* Recursively check for a completed path to an active or physically connected
+ * output widget. Returns number of complete paths.
+ */
+static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
+ struct list_head *list)
+{
+ return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT,
+ is_connected_output_ep);
+}
+
+/*
+ * Recursively check for a completed path to an active or physically connected
* input widget. Returns number of complete paths.
*/
static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
- struct snd_soc_dapm_widget_list **list)
+ struct list_head *list)
{
- struct snd_soc_dapm_path *path;
- int con = 0;
-
- if (widget->inputs >= 0)
- return widget->inputs;
-
- DAPM_UPDATE_STAT(widget, path_checks);
-
- if (widget->is_source && widget->connected) {
- widget->inputs = snd_soc_dapm_suspend_check(widget);
- return widget->inputs;
- }
-
- list_for_each_entry(path, &widget->sources, list_sink) {
- DAPM_UPDATE_STAT(widget, neighbour_checks);
-
- if (path->weak || path->is_supply)
- continue;
-
- if (path->walking)
- return 1;
-
- trace_snd_soc_dapm_input_path(widget, path);
-
- if (path->connect) {
- path->walking = 1;
-
- /* do we need to add this widget to the list ? */
- if (list) {
- int err;
- err = dapm_list_add_widget(list, path->source);
- if (err < 0) {
- dev_err(widget->dapm->dev,
- "ASoC: could not add widget %s\n",
- widget->name);
- path->walking = 0;
- return con;
- }
- }
-
- con += is_connected_input_ep(path->source, list);
-
- path->walking = 0;
- }
- }
-
- widget->inputs = con;
-
- return con;
+ return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN,
+ is_connected_input_ep);
}
/**
@@ -1204,7 +1138,9 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
{
struct snd_soc_card *card = dai->component->card;
struct snd_soc_dapm_widget *w;
+ LIST_HEAD(widgets);
int paths;
+ int ret;
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
@@ -1213,14 +1149,21 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
* to reset the cached number of inputs and outputs.
*/
list_for_each_entry(w, &card->widgets, list) {
- w->inputs = -1;
- w->outputs = -1;
+ w->endpoints[SND_SOC_DAPM_DIR_IN] = -1;
+ w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1;
}
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- paths = is_connected_output_ep(dai->playback_widget, list);
+ paths = is_connected_output_ep(dai->playback_widget, &widgets);
else
- paths = is_connected_input_ep(dai->capture_widget, list);
+ paths = is_connected_input_ep(dai->capture_widget, &widgets);
+
+ /* Drop starting point */
+ list_del(widgets.next);
+
+ ret = dapm_widget_list_create(list, &widgets);
+ if (ret)
+ paths = ret;
trace_snd_soc_dapm_connected(paths, stream);
mutex_unlock(&card->dapm_mutex);
@@ -1321,7 +1264,7 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
DAPM_UPDATE_STAT(w, power_checks);
/* Check if one of our outputs is connected */
- list_for_each_entry(path, &w->sinks, list_source) {
+ snd_soc_dapm_widget_for_each_sink_path(w, path) {
DAPM_UPDATE_STAT(w, neighbour_checks);
if (path->weak)
@@ -1745,12 +1688,12 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
/* If we changed our power state perhaps our neigbours changed
* also.
*/
- list_for_each_entry(path, &w->sources, list_sink)
+ snd_soc_dapm_widget_for_each_source_path(w, path)
dapm_widget_set_peer_power(path->source, power, path->connect);
/* Supplies can't affect their outputs, only their inputs */
if (!w->is_supply) {
- list_for_each_entry(path, &w->sinks, list_source)
+ snd_soc_dapm_widget_for_each_sink_path(w, path)
dapm_widget_set_peer_power(path->sink, power,
path->connect);
}
@@ -1951,6 +1894,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
{
struct snd_soc_dapm_widget *w = file->private_data;
struct snd_soc_card *card = w->dapm->card;
+ enum snd_soc_dapm_direction dir, rdir;
char *buf;
int in, out;
ssize_t ret;
@@ -1987,25 +1931,21 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
w->sname,
w->active ? "active" : "inactive");
- list_for_each_entry(p, &w->sources, list_sink) {
- if (p->connected && !p->connected(w, p->source))
- continue;
+ snd_soc_dapm_for_each_direction(dir) {
+ rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
+ snd_soc_dapm_widget_for_each_path(w, dir, p) {
+ if (p->connected && !p->connected(w, p->node[rdir]))
+ continue;
- if (p->connect)
- ret += snprintf(buf + ret, PAGE_SIZE - ret,
- " in \"%s\" \"%s\"\n",
- p->name ? p->name : "static",
- p->source->name);
- }
- list_for_each_entry(p, &w->sinks, list_source) {
- if (p->connected && !p->connected(w, p->sink))
- continue;
+ if (!p->connect)
+ continue;
- if (p->connect)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
- " out \"%s\" \"%s\"\n",
+ " %s \"%s\" \"%s\"\n",
+ (rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out",
p->name ? p->name : "static",
- p->sink->name);
+ p->node[rdir]->name);
+ }
}
mutex_unlock(&card->dapm_mutex);
@@ -2223,14 +2163,16 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
-static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf)
+static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
+ char *buf)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
struct snd_soc_dapm_widget *w;
int count = 0;
char *state = "not set";
- list_for_each_entry(w, &codec->component.card->widgets, list) {
- if (w->dapm != &codec->dapm)
+ list_for_each_entry(w, &cmpnt->card->widgets, list) {
+ if (w->dapm != dapm)
continue;
/* only display widgets that burnm power */
@@ -2258,7 +2200,7 @@ static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf)
}
}
- switch (codec->dapm.bias_level) {
+ switch (snd_soc_dapm_get_bias_level(dapm)) {
case SND_SOC_BIAS_ON:
state = "On";
break;
@@ -2287,8 +2229,9 @@ static ssize_t dapm_widget_show(struct device *dev,
mutex_lock(&rtd->card->dapm_mutex);
for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_codec *codec = rtd->codec_dais[i]->codec;
- count += dapm_widget_show_codec(codec, buf + count);
+ struct snd_soc_component *cmpnt = rtd->codec_dais[i]->component;
+
+ count += dapm_widget_show_component(cmpnt, buf + count);
}
mutex_unlock(&rtd->card->dapm_mutex);
@@ -2305,37 +2248,43 @@ struct attribute *soc_dapm_dev_attrs[] = {
static void dapm_free_path(struct snd_soc_dapm_path *path)
{
- list_del(&path->list_sink);
- list_del(&path->list_source);
+ list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]);
+ list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]);
list_del(&path->list_kcontrol);
list_del(&path->list);
kfree(path);
}
+void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_path *p, *next_p;
+ enum snd_soc_dapm_direction dir;
+
+ list_del(&w->list);
+ /*
+ * remove source and sink paths associated to this widget.
+ * While removing the path, remove reference to it from both
+ * source and sink widgets so that path is removed only once.
+ */
+ snd_soc_dapm_for_each_direction(dir) {
+ snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p)
+ dapm_free_path(p);
+ }
+
+ kfree(w->kcontrols);
+ kfree_const(w->name);
+ kfree(w);
+}
+
/* free all dapm widgets and resources */
static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
{
struct snd_soc_dapm_widget *w, *next_w;
- struct snd_soc_dapm_path *p, *next_p;
list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
if (w->dapm != dapm)
continue;
- list_del(&w->list);
- /*
- * remove source and sink paths associated to this widget.
- * While removing the path, remove reference to it from both
- * source and sink widgets so that path is removed only once.
- */
- list_for_each_entry_safe(p, next_p, &w->sources, list_sink)
- dapm_free_path(p);
-
- list_for_each_entry_safe(p, next_p, &w->sinks, list_source)
- dapm_free_path(p);
-
- kfree(w->kcontrols);
- kfree(w->name);
- kfree(w);
+ snd_soc_dapm_free_widget(w);
}
}
@@ -2441,20 +2390,22 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
*/
static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
{
+ enum snd_soc_dapm_direction dir;
struct snd_soc_dapm_path *p;
+ unsigned int ep;
switch (w->id) {
case snd_soc_dapm_input:
/* On a fully routed card a input is never a source */
if (w->dapm->card->fully_routed)
- break;
- w->is_source = 1;
- list_for_each_entry(p, &w->sources, list_sink) {
+ return;
+ ep = SND_SOC_DAPM_EP_SOURCE;
+ snd_soc_dapm_widget_for_each_source_path(w, p) {
if (p->source->id == snd_soc_dapm_micbias ||
p->source->id == snd_soc_dapm_mic ||
p->source->id == snd_soc_dapm_line ||
p->source->id == snd_soc_dapm_output) {
- w->is_source = 0;
+ ep = 0;
break;
}
}
@@ -2462,25 +2413,30 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
case snd_soc_dapm_output:
/* On a fully routed card a output is never a sink */
if (w->dapm->card->fully_routed)
- break;
- w->is_sink = 1;
- list_for_each_entry(p, &w->sinks, list_source) {
+ return;
+ ep = SND_SOC_DAPM_EP_SINK;
+ snd_soc_dapm_widget_for_each_sink_path(w, p) {
if (p->sink->id == snd_soc_dapm_spk ||
p->sink->id == snd_soc_dapm_hp ||
p->sink->id == snd_soc_dapm_line ||
p->sink->id == snd_soc_dapm_input) {
- w->is_sink = 0;
+ ep = 0;
break;
}
}
break;
case snd_soc_dapm_line:
- w->is_sink = !list_empty(&w->sources);
- w->is_source = !list_empty(&w->sinks);
+ ep = 0;
+ snd_soc_dapm_for_each_direction(dir) {
+ if (!list_empty(&w->edges[dir]))
+ ep |= SND_SOC_DAPM_DIR_TO_EP(dir);
+ }
break;
default:
- break;
+ return;
}
+
+ w->is_ep = ep;
}
static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
@@ -2533,6 +2489,8 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
int (*connected)(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink))
{
+ struct snd_soc_dapm_widget *widgets[2];
+ enum snd_soc_dapm_direction dir;
struct snd_soc_dapm_path *path;
int ret;
@@ -2565,13 +2523,14 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
if (!path)
return -ENOMEM;
- path->source = wsource;
- path->sink = wsink;
+ path->node[SND_SOC_DAPM_DIR_IN] = wsource;
+ path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
+ widgets[SND_SOC_DAPM_DIR_IN] = wsource;
+ widgets[SND_SOC_DAPM_DIR_OUT] = wsink;
+
path->connected = connected;
INIT_LIST_HEAD(&path->list);
INIT_LIST_HEAD(&path->list_kcontrol);
- INIT_LIST_HEAD(&path->list_source);
- INIT_LIST_HEAD(&path->list_sink);
if (wsource->is_supply || wsink->is_supply)
path->is_supply = 1;
@@ -2609,14 +2568,13 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
}
list_add(&path->list, &dapm->card->paths);
- list_add(&path->list_sink, &wsink->sources);
- list_add(&path->list_source, &wsource->sinks);
-
- dapm_update_widget_flags(wsource);
- dapm_update_widget_flags(wsink);
+ snd_soc_dapm_for_each_direction(dir)
+ list_add(&path->list_node[dir], &widgets[dir]->edges[dir]);
- dapm_mark_dirty(wsource, "Route added");
- dapm_mark_dirty(wsink, "Route added");
+ snd_soc_dapm_for_each_direction(dir) {
+ dapm_update_widget_flags(widgets[dir]);
+ dapm_mark_dirty(widgets[dir], "Route added");
+ }
if (dapm->card->instantiated && path->connect)
dapm_path_invalidate(path);
@@ -2864,7 +2822,7 @@ static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
route->source, route->sink);
- list_for_each_entry(path, &source->sinks, list_source) {
+ snd_soc_dapm_widget_for_each_sink_path(source, path) {
if (path->sink == sink) {
path->weak = 1;
count++;
@@ -2918,7 +2876,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
/**
* snd_soc_dapm_new_widgets - add new dapm widgets
- * @dapm: DAPM context
+ * @card: card to be checked for new dapm widgets
*
* Checks the codec for any new dapm widgets and creates them if found.
*
@@ -3298,6 +3256,7 @@ struct snd_soc_dapm_widget *
snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget)
{
+ enum snd_soc_dapm_direction dir;
struct snd_soc_dapm_widget *w;
const char *prefix;
int ret;
@@ -3344,7 +3303,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
if (prefix)
w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
else
- w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
+ w->name = kstrdup_const(widget->name, GFP_KERNEL);
if (w->name == NULL) {
kfree(w);
return NULL;
@@ -3352,27 +3311,27 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
switch (w->id) {
case snd_soc_dapm_mic:
- w->is_source = 1;
+ w->is_ep = SND_SOC_DAPM_EP_SOURCE;
w->power_check = dapm_generic_check_power;
break;
case snd_soc_dapm_input:
if (!dapm->card->fully_routed)
- w->is_source = 1;
+ w->is_ep = SND_SOC_DAPM_EP_SOURCE;
w->power_check = dapm_generic_check_power;
break;
case snd_soc_dapm_spk:
case snd_soc_dapm_hp:
- w->is_sink = 1;
+ w->is_ep = SND_SOC_DAPM_EP_SINK;
w->power_check = dapm_generic_check_power;
break;
case snd_soc_dapm_output:
if (!dapm->card->fully_routed)
- w->is_sink = 1;
+ w->is_ep = SND_SOC_DAPM_EP_SINK;
w->power_check = dapm_generic_check_power;
break;
case snd_soc_dapm_vmid:
case snd_soc_dapm_siggen:
- w->is_source = 1;
+ w->is_ep = SND_SOC_DAPM_EP_SOURCE;
w->power_check = dapm_always_on_check_power;
break;
case snd_soc_dapm_mux:
@@ -3406,14 +3365,14 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
}
w->dapm = dapm;
- INIT_LIST_HEAD(&w->sources);
- INIT_LIST_HEAD(&w->sinks);
INIT_LIST_HEAD(&w->list);
INIT_LIST_HEAD(&w->dirty);
list_add_tail(&w->list, &dapm->card->widgets);
- w->inputs = -1;
- w->outputs = -1;
+ snd_soc_dapm_for_each_direction(dir) {
+ INIT_LIST_HEAD(&w->edges[dir]);
+ w->endpoints[dir] = -1;
+ }
/* machine layer set ups unconnected pins and insertions */
w->connected = 1;
@@ -3467,19 +3426,17 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
int ret;
if (WARN_ON(!config) ||
- WARN_ON(list_empty(&w->sources) || list_empty(&w->sinks)))
+ WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
+ list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
return -EINVAL;
/* We only support a single source and sink, pick the first */
- source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path,
- list_sink);
- sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path,
- list_source);
-
- if (WARN_ON(!source_p || !sink_p) ||
- WARN_ON(!sink_p->source || !source_p->sink) ||
- WARN_ON(!source_p->source || !sink_p->sink))
- return -EINVAL;
+ source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT],
+ struct snd_soc_dapm_path,
+ list_node[SND_SOC_DAPM_DIR_OUT]);
+ sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN],
+ struct snd_soc_dapm_path,
+ list_node[SND_SOC_DAPM_DIR_IN]);
source = source_p->source->priv;
sink = sink_p->sink->priv;
@@ -3821,11 +3778,6 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
for (i = 0; i < rtd->num_codecs; i++) {
struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
- /* there is no point in connecting BE DAI links with dummies */
- if (snd_soc_dai_is_dummy(codec_dai) ||
- snd_soc_dai_is_dummy(cpu_dai))
- continue;
-
/* connect BE DAI playback if widgets are valid */
if (codec_dai->playback_widget && cpu_dai->playback_widget) {
source = cpu_dai->playback_widget;
@@ -3856,6 +3808,7 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
int event)
{
struct snd_soc_dapm_widget *w;
+ unsigned int ep;
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
w = dai->playback_widget;
@@ -3865,12 +3818,22 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
if (w) {
dapm_mark_dirty(w, "stream event");
+ if (w->id == snd_soc_dapm_dai_in) {
+ ep = SND_SOC_DAPM_EP_SOURCE;
+ dapm_widget_invalidate_input_paths(w);
+ } else {
+ ep = SND_SOC_DAPM_EP_SINK;
+ dapm_widget_invalidate_output_paths(w);
+ }
+
switch (event) {
case SND_SOC_DAPM_STREAM_START:
w->active = 1;
+ w->is_ep = ep;
break;
case SND_SOC_DAPM_STREAM_STOP:
w->active = 0;
+ w->is_ep = 0;
break;
case SND_SOC_DAPM_STREAM_SUSPEND:
case SND_SOC_DAPM_STREAM_RESUME:
@@ -3878,14 +3841,6 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
break;
}
-
- if (w->id == snd_soc_dapm_dai_in) {
- w->is_source = w->active;
- dapm_widget_invalidate_input_paths(w);
- } else {
- w->is_sink = w->active;
- dapm_widget_invalidate_output_paths(w);
- }
}
}
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 256b9c9..70e4b9d 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1231,24 +1231,17 @@ static int widget_in_list(struct snd_soc_dapm_widget_list *list,
}
int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
- int stream, struct snd_soc_dapm_widget_list **list_)
+ int stream, struct snd_soc_dapm_widget_list **list)
{
struct snd_soc_dai *cpu_dai = fe->cpu_dai;
- struct snd_soc_dapm_widget_list *list;
int paths;
- list = kzalloc(sizeof(struct snd_soc_dapm_widget_list) +
- sizeof(struct snd_soc_dapm_widget *), GFP_KERNEL);
- if (list == NULL)
- return -ENOMEM;
-
/* get number of valid DAI paths and their widgets */
- paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list);
+ paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list);
dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
stream ? "capture" : "playback");
- *list_ = list;
return paths;
}
@@ -1306,7 +1299,12 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
switch (list->widgets[i]->id) {
case snd_soc_dapm_dai_in:
+ if (stream != SNDRV_PCM_STREAM_PLAYBACK)
+ continue;
+ break;
case snd_soc_dapm_dai_out:
+ if (stream != SNDRV_PCM_STREAM_CAPTURE)
+ continue;
break;
default:
continue;
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 31068b8..69d01cd 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -45,12 +45,12 @@
#define SOC_TPLG_PASS_VENDOR 1
#define SOC_TPLG_PASS_MIXER 2
#define SOC_TPLG_PASS_WIDGET 3
-#define SOC_TPLG_PASS_GRAPH 4
-#define SOC_TPLG_PASS_PINS 5
-#define SOC_TPLG_PASS_PCM_DAI 6
+#define SOC_TPLG_PASS_PCM_DAI 4
+#define SOC_TPLG_PASS_GRAPH 5
+#define SOC_TPLG_PASS_PINS 6
#define SOC_TPLG_PASS_START SOC_TPLG_PASS_MANIFEST
-#define SOC_TPLG_PASS_END SOC_TPLG_PASS_PCM_DAI
+#define SOC_TPLG_PASS_END SOC_TPLG_PASS_PINS
struct soc_tplg {
const struct firmware *fw;
@@ -66,10 +66,14 @@ struct soc_tplg {
u32 index; /* current block index */
u32 req_index; /* required index, only loaded/free matching blocks */
- /* kcontrol operations */
+ /* vendor specific kcontrol operations */
const struct snd_soc_tplg_kcontrol_ops *io_ops;
int io_ops_count;
+ /* vendor specific bytes ext handlers, for TLV bytes controls */
+ const struct snd_soc_tplg_bytes_ext_ops *bytes_ext_ops;
+ int bytes_ext_ops_count;
+
/* optional fw loading callbacks to component drivers */
struct snd_soc_tplg_ops *ops;
};
@@ -508,38 +512,74 @@ static void remove_pcm_dai(struct snd_soc_component *comp,
/* bind a kcontrol to it's IO handlers */
static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
struct snd_kcontrol_new *k,
- const struct snd_soc_tplg_kcontrol_ops *ops, int num_ops,
- const struct snd_soc_tplg_kcontrol_ops *bops, int num_bops)
+ const struct soc_tplg *tplg)
{
- int i;
+ const struct snd_soc_tplg_kcontrol_ops *ops;
+ const struct snd_soc_tplg_bytes_ext_ops *ext_ops;
+ int num_ops, i;
+
+ if (hdr->ops.info == SND_SOC_TPLG_CTL_BYTES
+ && k->iface & SNDRV_CTL_ELEM_IFACE_MIXER
+ && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
+ && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+ struct soc_bytes_ext *sbe;
+ struct snd_soc_tplg_bytes_control *be;
+
+ sbe = (struct soc_bytes_ext *)k->private_value;
+ be = container_of(hdr, struct snd_soc_tplg_bytes_control, hdr);
+
+ /* TLV bytes controls need standard kcontrol info handler,
+ * TLV callback and extended put/get handlers.
+ */
+ k->info = snd_soc_bytes_info;
+ k->tlv.c = snd_soc_bytes_tlv_callback;
+
+ ext_ops = tplg->bytes_ext_ops;
+ num_ops = tplg->bytes_ext_ops_count;
+ for (i = 0; i < num_ops; i++) {
+ if (!sbe->put && ext_ops[i].id == be->ext_ops.put)
+ sbe->put = ext_ops[i].put;
+ if (!sbe->get && ext_ops[i].id == be->ext_ops.get)
+ sbe->get = ext_ops[i].get;
+ }
- /* try and map standard kcontrols handler first */
+ if (sbe->put && sbe->get)
+ return 0;
+ else
+ return -EINVAL;
+ }
+
+ /* try and map vendor specific kcontrol handlers first */
+ ops = tplg->io_ops;
+ num_ops = tplg->io_ops_count;
for (i = 0; i < num_ops; i++) {
- if (ops[i].id == hdr->ops.put)
+ if (k->put == NULL && ops[i].id == hdr->ops.put)
k->put = ops[i].put;
- if (ops[i].id == hdr->ops.get)
+ if (k->get == NULL && ops[i].id == hdr->ops.get)
k->get = ops[i].get;
- if (ops[i].id == hdr->ops.info)
+ if (k->info == NULL && ops[i].id == hdr->ops.info)
k->info = ops[i].info;
}
- /* standard handlers found ? */
+ /* vendor specific handlers found ? */
if (k->put && k->get && k->info)
return 0;
- /* none found so try bespoke handlers */
- for (i = 0; i < num_bops; i++) {
+ /* none found so try standard kcontrol handlers */
+ ops = io_ops;
+ num_ops = ARRAY_SIZE(io_ops);
+ for (i = 0; i < num_ops; i++) {
- if (k->put == NULL && bops[i].id == hdr->ops.put)
- k->put = bops[i].put;
- if (k->get == NULL && bops[i].id == hdr->ops.get)
- k->get = bops[i].get;
- if (k->info == NULL && bops[i].id == hdr->ops.info)
- k->info = bops[i].info;
+ if (k->put == NULL && ops[i].id == hdr->ops.put)
+ k->put = ops[i].put;
+ if (k->get == NULL && ops[i].id == hdr->ops.get)
+ k->get = ops[i].get;
+ if (k->info == NULL && ops[i].id == hdr->ops.info)
+ k->info = ops[i].info;
}
- /* bespoke handlers found ? */
+ /* standard handlers found ? */
if (k->put && k->get && k->info)
return 0;
@@ -609,9 +649,7 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg,
if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE))
return 0;
- if (tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
- kc->tlv.c = snd_soc_bytes_tlv_callback;
- } else {
+ if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) {
tplg_tlv = &tc->tlv;
switch (tplg_tlv->type) {
case SNDRV_CTL_TLVT_DB_SCALE:
@@ -682,8 +720,7 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
INIT_LIST_HEAD(&sbe->dobj.list);
/* map io handlers */
- err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, io_ops,
- ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+ err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg);
if (err) {
soc_control_err(tplg, &be->hdr, be->hdr.name);
kfree(sbe);
@@ -777,8 +814,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
INIT_LIST_HEAD(&sm->dobj.list);
/* map io handlers */
- err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, io_ops,
- ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+ err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg);
if (err) {
soc_control_err(tplg, &mc->hdr, mc->hdr.name);
kfree(sm);
@@ -855,12 +891,12 @@ static int soc_tplg_denum_create_values(struct soc_enum *se,
if (ec->items > sizeof(*ec->values))
return -EINVAL;
- se->dobj.control.dvalues =
- kmalloc(ec->items * sizeof(u32), GFP_KERNEL);
+ se->dobj.control.dvalues = kmemdup(ec->values,
+ ec->items * sizeof(u32),
+ GFP_KERNEL);
if (!se->dobj.control.dvalues)
return -ENOMEM;
- memcpy(se->dobj.control.dvalues, ec->values, ec->items * sizeof(u32));
return 0;
}
@@ -950,8 +986,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
}
/* map io handlers */
- err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, io_ops,
- ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+ err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, tplg);
if (err) {
soc_control_err(tplg, &ec->hdr, ec->hdr.name);
kfree(se);
@@ -1093,7 +1128,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
struct snd_soc_tplg_mixer_control *mc;
int i, err;
- kc = kzalloc(sizeof(*kc) * num_kcontrols, GFP_KERNEL);
+ kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
if (kc == NULL)
return NULL;
@@ -1137,8 +1172,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
INIT_LIST_HEAD(&sm->dobj.list);
/* map io handlers */
- err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], io_ops,
- ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+ err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], tplg);
if (err) {
soc_control_err(tplg, &mc->hdr, mc->hdr.name);
kfree(sm);
@@ -1235,8 +1269,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
}
/* map io handlers */
- err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, io_ops,
- ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+ err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg);
if (err) {
soc_control_err(tplg, &ec->hdr, ec->hdr.name);
goto err_se;
@@ -1274,7 +1307,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
struct snd_kcontrol_new *kc;
int i, err;
- kc = kzalloc(sizeof(*kc) * count, GFP_KERNEL);
+ kc = kcalloc(count, sizeof(*kc), GFP_KERNEL);
if (!kc)
return NULL;
@@ -1297,7 +1330,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
"ASoC: adding bytes kcontrol %s with access 0x%x\n",
be->hdr.name, be->hdr.access);
- memset(kc, 0, sizeof(*kc));
kc[i].name = be->hdr.name;
kc[i].private_value = (long)sbe;
kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
@@ -1307,9 +1339,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
INIT_LIST_HEAD(&sbe->dobj.list);
/* map standard io handlers and check for external handlers */
- err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], io_ops,
- ARRAY_SIZE(io_ops), tplg->io_ops,
- tplg->io_ops_count);
+ err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], tplg);
if (err) {
soc_control_err(tplg, &be->hdr, be->hdr.name);
kfree(sbe);
@@ -1737,6 +1767,8 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp,
tplg.req_index = id;
tplg.io_ops = ops->io_ops;
tplg.io_ops_count = ops->io_ops_count;
+ tplg.bytes_ext_ops = ops->bytes_ext_ops;
+ tplg.bytes_ext_ops_count = ops->bytes_ext_ops_count;
return soc_tplg_load(&tplg);
}
@@ -1758,7 +1790,6 @@ void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
u32 index)
{
struct snd_soc_dapm_widget *w, *next_w;
- struct snd_soc_dapm_path *p, *next_p;
list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
@@ -1770,31 +1801,9 @@ void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
if (w->dobj.index != index &&
w->dobj.index != SND_SOC_TPLG_INDEX_ALL)
continue;
-
- list_del(&w->list);
-
- /*
- * remove source and sink paths associated to this widget.
- * While removing the path, remove reference to it from both
- * source and sink widgets so that path is removed only once.
- */
- list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
- list_del(&p->list_sink);
- list_del(&p->list_source);
- list_del(&p->list);
- kfree(p);
- }
- list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
- list_del(&p->list_sink);
- list_del(&p->list_source);
- list_del(&p->list);
- kfree(p);
- }
/* check and free and dynamic widget kcontrols */
snd_soc_tplg_widget_remove(w);
- kfree(w->kcontrols);
- kfree(w->name);
- kfree(w);
+ snd_soc_dapm_free_widget(w);
}
}
EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all);
diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c
index a402860..977a078 100644
--- a/sound/soc/spear/spdif_in.c
+++ b/sound/soc/spear/spdif_in.c
@@ -203,35 +203,25 @@ static int spdif_in_probe(struct platform_device *pdev)
struct spdif_in_dev *host;
struct spear_spdif_platform_data *pdata;
struct resource *res, *res_fifo;
+ void __iomem *io_base;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
+ io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(io_base))
+ return PTR_ERR(io_base);
res_fifo = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res_fifo)
return -EINVAL;
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), pdev->name)) {
- dev_warn(&pdev->dev, "Failed to get memory resourse\n");
- return -ENOENT;
- }
-
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
if (!host) {
dev_warn(&pdev->dev, "kzalloc fail\n");
return -ENOMEM;
}
- host->io_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!host->io_base) {
- dev_warn(&pdev->dev, "ioremap failed\n");
- return -ENOMEM;
- }
-
+ host->io_base = io_base;
host->irq = platform_get_irq(pdev, 0);
if (host->irq < 0)
return -EINVAL;
diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c
index a7dc3c5..e8476da 100644
--- a/sound/soc/spear/spear_pcm.c
+++ b/sound/soc/spear/spear_pcm.c
@@ -44,7 +44,7 @@ int devm_spear_pcm_platform_register(struct device *dev,
*config = spear_dmaengine_pcm_config;
config->compat_filter_fn = filter;
- return snd_dmaengine_pcm_register(dev, config,
+ return devm_snd_dmaengine_pcm_register(dev, config,
SND_DMAENGINE_PCM_FLAG_NO_DT |
SND_DMAENGINE_PCM_FLAG_COMPAT);
}
diff --git a/sound/soc/sti/Kconfig b/sound/soc/sti/Kconfig
new file mode 100644
index 0000000..64a6900
--- /dev/null
+++ b/sound/soc/sti/Kconfig
@@ -0,0 +1,11 @@
+#
+# STM SoC audio configuration
+#
+menuconfig SND_SOC_STI
+ tristate "SoC Audio support for STI System-On-Chip"
+ depends on SND_SOC
+ depends on ARCH_STI || COMPILE_TEST
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ help
+ Say Y if you want to enable ASoC-support for
+ any of the STI platforms (e.g. STIH416).
diff --git a/sound/soc/sti/Makefile b/sound/soc/sti/Makefile
new file mode 100644
index 0000000..4b188d2
--- /dev/null
+++ b/sound/soc/sti/Makefile
@@ -0,0 +1,4 @@
+# STI platform support
+snd-soc-sti-objs := sti_uniperif.o uniperif_player.o uniperif_reader.o
+
+obj-$(CONFIG_SND_SOC_STI) += snd-soc-sti.o
diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c
new file mode 100644
index 0000000..39bcefe
--- /dev/null
+++ b/sound/soc/sti/sti_uniperif.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
+ * for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "uniperif.h"
+
+/*
+ * sti_uniperiph_dai_create_ctrl
+ * This function is used to create Ctrl associated to DAI but also pcm device.
+ * Request is done by front end to associate ctrl with pcm device id
+ */
+static int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *uni = priv->dai_data.uni;
+ struct snd_kcontrol_new *ctrl;
+ int i;
+
+ if (!uni->num_ctrls)
+ return 0;
+
+ for (i = 0; i < uni->num_ctrls; i++) {
+ /*
+ * Several Control can have same name. Controls are indexed on
+ * Uniperipheral instance ID
+ */
+ ctrl = &uni->snd_ctrls[i];
+ ctrl->index = uni->info->id;
+ ctrl->device = uni->info->id;
+ }
+
+ return snd_soc_add_dai_controls(dai, uni->snd_ctrls, uni->num_ctrls);
+}
+
+/*
+ * DAI
+ */
+int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_dmaengine_dai_dma_data *dma_data;
+ int transfer_size;
+
+ transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES;
+
+ dma_data = snd_soc_dai_get_dma_data(dai, substream);
+ dma_data->maxburst = transfer_size;
+
+ return 0;
+}
+
+int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+
+ priv->dai_data.uni->daifmt = fmt;
+
+ return 0;
+}
+
+static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *uni = priv->dai_data.uni;
+ int ret;
+
+ /* The uniperipheral should be in stopped state */
+ if (uni->state != UNIPERIF_STATE_STOPPED) {
+ dev_err(uni->dev, "%s: invalid uni state( %d)",
+ __func__, (int)uni->state);
+ return -EBUSY;
+ }
+
+ /* Pinctrl: switch pinstate to sleep */
+ ret = pinctrl_pm_select_sleep_state(uni->dev);
+ if (ret)
+ dev_err(uni->dev, "%s: failed to select pinctrl state",
+ __func__);
+
+ return ret;
+}
+
+static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *uni = priv->dai_data.uni;
+ int ret;
+
+ if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) {
+ ret = uni_player_resume(uni);
+ if (ret)
+ return ret;
+ }
+
+ /* pinctrl: switch pinstate to default */
+ ret = pinctrl_pm_select_default_state(uni->dev);
+ if (ret)
+ dev_err(uni->dev, "%s: failed to select pinctrl state",
+ __func__);
+
+ return ret;
+}
+
+static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct sti_uniperiph_dai *dai_data = &priv->dai_data;
+
+ /* DMA settings*/
+ if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player"))
+ snd_soc_dai_init_dma_data(dai, &dai_data->dma_data, NULL);
+ else
+ snd_soc_dai_init_dma_data(dai, NULL, &dai_data->dma_data);
+
+ dai_data->dma_data.addr = dai_data->uni->fifo_phys_address;
+ dai_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+ return sti_uniperiph_dai_create_ctrl(dai);
+}
+
+static const struct snd_soc_dai_driver sti_uniperiph_dai_template = {
+ .probe = sti_uniperiph_dai_probe,
+ .suspend = sti_uniperiph_dai_suspend,
+ .resume = sti_uniperiph_dai_resume
+};
+
+static const struct snd_soc_component_driver sti_uniperiph_dai_component = {
+ .name = "sti_cpu_dai",
+};
+
+static int sti_uniperiph_cpu_dai_of(struct device_node *node,
+ struct sti_uniperiph_data *priv)
+{
+ const char *str;
+ int ret;
+ struct device *dev = &priv->pdev->dev;
+ struct sti_uniperiph_dai *dai_data = &priv->dai_data;
+ struct snd_soc_dai_driver *dai = priv->dai;
+ struct snd_soc_pcm_stream *stream;
+ struct uniperif *uni;
+
+ uni = devm_kzalloc(dev, sizeof(*uni), GFP_KERNEL);
+ if (!uni)
+ return -ENOMEM;
+
+ *dai = sti_uniperiph_dai_template;
+ ret = of_property_read_string(node, "dai-name", &str);
+ if (ret < 0) {
+ dev_err(dev, "%s: dai name missing.\n", __func__);
+ return -EINVAL;
+ }
+ dai->name = str;
+
+ /* Get resources */
+ uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0);
+
+ if (!uni->mem_region) {
+ dev_err(dev, "Failed to get memory resource");
+ return -ENODEV;
+ }
+
+ uni->base = devm_ioremap_resource(dev, uni->mem_region);
+
+ if (IS_ERR(uni->base))
+ return PTR_ERR(uni->base);
+
+ uni->fifo_phys_address = uni->mem_region->start +
+ UNIPERIF_FIFO_DATA_OFFSET(uni);
+
+ uni->irq = platform_get_irq(priv->pdev, 0);
+ if (uni->irq < 0) {
+ dev_err(dev, "Failed to get IRQ resource");
+ return -ENXIO;
+ }
+
+ dai_data->uni = uni;
+
+ if (of_device_is_compatible(node, "st,sti-uni-player")) {
+ uni_player_init(priv->pdev, uni);
+ stream = &dai->playback;
+ } else {
+ uni_reader_init(priv->pdev, uni);
+ stream = &dai->capture;
+ }
+ dai->ops = uni->dai_ops;
+
+ stream->stream_name = dai->name;
+ stream->channels_min = uni->hw->channels_min;
+ stream->channels_max = uni->hw->channels_max;
+ stream->rates = uni->hw->rates;
+ stream->formats = uni->hw->formats;
+
+ return 0;
+}
+
+static const struct snd_dmaengine_pcm_config dmaengine_pcm_config = {
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+};
+
+static int sti_uniperiph_probe(struct platform_device *pdev)
+{
+ struct sti_uniperiph_data *priv;
+ struct device_node *node = pdev->dev.of_node;
+ int ret;
+
+ /* Allocate the private data and the CPU_DAI array */
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->dai = devm_kzalloc(&pdev->dev, sizeof(*priv->dai), GFP_KERNEL);
+ if (!priv->dai)
+ return -ENOMEM;
+
+ priv->pdev = pdev;
+
+ ret = sti_uniperiph_cpu_dai_of(node, priv);
+
+ dev_set_drvdata(&pdev->dev, priv);
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &sti_uniperiph_dai_component,
+ priv->dai, 1);
+ if (ret < 0)
+ return ret;
+
+ return devm_snd_dmaengine_pcm_register(&pdev->dev,
+ &dmaengine_pcm_config, 0);
+}
+
+static const struct of_device_id snd_soc_sti_match[] = {
+ { .compatible = "st,sti-uni-player", },
+ { .compatible = "st,sti-uni-reader", },
+ {},
+};
+
+static struct platform_driver sti_uniperiph_driver = {
+ .driver = {
+ .name = "sti-uniperiph-dai",
+ .of_match_table = snd_soc_sti_match,
+ },
+ .probe = sti_uniperiph_probe,
+};
+module_platform_driver(sti_uniperiph_driver);
+
+MODULE_DESCRIPTION("uniperipheral DAI driver");
+MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h
new file mode 100644
index 0000000..f0fd5a9
--- /dev/null
+++ b/sound/soc/sti/uniperif.h
@@ -0,0 +1,1229 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
+ * for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef __SND_ST_AUD_UNIPERIF_H
+#define __SND_ST_AUD_UNIPERIF_H
+
+#include <linux/regmap.h>
+
+#include <sound/dmaengine_pcm.h>
+
+/*
+ * Register access macros
+ */
+
+#define GET_UNIPERIF_REG(ip, offset, shift, mask) \
+ ((readl_relaxed(ip->base + offset) >> shift) & mask)
+#define SET_UNIPERIF_REG(ip, offset, shift, mask, value) \
+ writel_relaxed(((readl_relaxed(ip->base + offset) & \
+ ~(mask << shift)) | (((value) & mask) << shift)), ip->base + offset)
+#define SET_UNIPERIF_BIT_REG(ip, offset, shift, mask, value) \
+ writel_relaxed((((value) & mask) << shift), ip->base + offset)
+
+/*
+ * AUD_UNIPERIF_SOFT_RST reg
+ */
+
+#define UNIPERIF_SOFT_RST_OFFSET(ip) 0x0000
+#define GET_UNIPERIF_SOFT_RST(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
+ readl_relaxed(ip->base + UNIPERIF_SOFT_RST_OFFSET(ip)) : 0)
+#define SET_UNIPERIF_SOFT_RST(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_SOFT_RST_OFFSET(ip))
+
+/* SOFT_RST */
+#define UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip) 0x0
+#define UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip) 0x1
+#define SET_UNIPERIF_SOFT_RST_SOFT_RST(ip) \
+ SET_UNIPERIF_BIT_REG(ip, \
+ UNIPERIF_SOFT_RST_OFFSET(ip), \
+ UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip), \
+ UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip), 1)
+#define GET_UNIPERIF_SOFT_RST_SOFT_RST(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_SOFT_RST_OFFSET(ip), \
+ UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip), \
+ UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip))
+
+/*
+ * AUD_UNIPERIF_FIFO_DATA reg
+ */
+
+#define UNIPERIF_FIFO_DATA_OFFSET(ip) 0x0004
+#define SET_UNIPERIF_DATA(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_FIFO_DATA_OFFSET(ip))
+
+/*
+ * AUD_UNIPERIF_CHANNEL_STA_REGN reg
+ */
+
+#define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n))
+#define GET_UNIPERIF_CHANNEL_STA_REGN(ip) \
+ readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REGN(ip, n))
+#define SET_UNIPERIF_CHANNEL_STA_REGN(ip, n, value) \
+ writel_relaxed(value, ip->base + \
+ UNIPERIF_CHANNEL_STA_REGN(ip, n))
+
+#define UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip) 0x0060
+#define GET_UNIPERIF_CHANNEL_STA_REG0(ip) \
+ readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip))
+#define SET_UNIPERIF_CHANNEL_STA_REG0(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip))
+
+#define UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip) 0x0064
+#define GET_UNIPERIF_CHANNEL_STA_REG1(ip) \
+ readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip))
+#define SET_UNIPERIF_CHANNEL_STA_REG1(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip))
+
+#define UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip) 0x0068
+#define GET_UNIPERIF_CHANNEL_STA_REG2(ip) \
+ readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip))
+#define SET_UNIPERIF_CHANNEL_STA_REG2(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip))
+
+#define UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip) 0x006C
+#define GET_UNIPERIF_CHANNEL_STA_REG3(ip) \
+ readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip))
+#define SET_UNIPERIF_CHANNEL_STA_REG3(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip))
+
+#define UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip) 0x0070
+#define GET_UNIPERIF_CHANNEL_STA_REG4(ip) \
+ readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip))
+#define SET_UNIPERIF_CHANNEL_STA_REG4(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip))
+
+#define UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip) 0x0074
+#define GET_UNIPERIF_CHANNEL_STA_REG5(ip) \
+ readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip))
+#define SET_UNIPERIF_CHANNEL_STA_REG5(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip))
+
+/*
+ * AUD_UNIPERIF_ITS reg
+ */
+
+#define UNIPERIF_ITS_OFFSET(ip) 0x000C
+#define GET_UNIPERIF_ITS(ip) \
+ readl_relaxed(ip->base + UNIPERIF_ITS_OFFSET(ip))
+
+/* MEM_BLK_READ */
+#define UNIPERIF_ITS_MEM_BLK_READ_SHIFT(ip) 5
+#define UNIPERIF_ITS_MEM_BLK_READ_MASK(ip) \
+ (BIT(UNIPERIF_ITS_MEM_BLK_READ_SHIFT(ip)))
+
+/* FIFO_ERROR */
+#define UNIPERIF_ITS_FIFO_ERROR_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8)
+#define UNIPERIF_ITS_FIFO_ERROR_MASK(ip) \
+ (BIT(UNIPERIF_ITS_FIFO_ERROR_SHIFT(ip)))
+
+/* DMA_ERROR */
+#define UNIPERIF_ITS_DMA_ERROR_SHIFT(ip) 9
+#define UNIPERIF_ITS_DMA_ERROR_MASK(ip) \
+ (BIT(UNIPERIF_ITS_DMA_ERROR_SHIFT(ip)))
+
+/* UNDERFLOW_REC_DONE */
+#define UNIPERIF_ITS_UNDERFLOW_REC_DONE_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12)
+#define UNIPERIF_ITS_UNDERFLOW_REC_DONE_MASK(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
+ 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_DONE_SHIFT(ip))))
+
+/* UNDERFLOW_REC_FAILED */
+#define UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13)
+#define UNIPERIF_ITS_UNDERFLOW_REC_FAILED_MASK(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
+ 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip))))
+
+/*
+ * AUD_UNIPERIF_ITS_BCLR reg
+ */
+
+/* FIFO_ERROR */
+#define UNIPERIF_ITS_BCLR_FIFO_ERROR_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8)
+#define UNIPERIF_ITS_BCLR_FIFO_ERROR_MASK(ip) \
+ (BIT(UNIPERIF_ITS_BCLR_FIFO_ERROR_SHIFT(ip)))
+#define SET_UNIPERIF_ITS_BCLR_FIFO_ERROR(ip) \
+ SET_UNIPERIF_ITS_BCLR(ip, \
+ UNIPERIF_ITS_BCLR_FIFO_ERROR_MASK(ip))
+
+#define UNIPERIF_ITS_BCLR_OFFSET(ip) 0x0010
+#define SET_UNIPERIF_ITS_BCLR(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_ITS_BCLR_OFFSET(ip))
+
+/*
+ * AUD_UNIPERIF_ITM reg
+ */
+
+#define UNIPERIF_ITM_OFFSET(ip) 0x0018
+#define GET_UNIPERIF_ITM(ip) \
+ readl_relaxed(ip->base + UNIPERIF_ITM_OFFSET(ip))
+
+/* FIFO_ERROR */
+#define UNIPERIF_ITM_FIFO_ERROR_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8)
+#define UNIPERIF_ITM_FIFO_ERROR_MASK(ip) \
+ (BIT(UNIPERIF_ITM_FIFO_ERROR_SHIFT(ip)))
+
+/* UNDERFLOW_REC_DONE */
+#define UNIPERIF_ITM_UNDERFLOW_REC_DONE_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12)
+#define UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
+ 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_DONE_SHIFT(ip))))
+
+/* UNDERFLOW_REC_FAILED */
+#define UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13)
+#define UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
+ 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip))))
+
+/*
+ * AUD_UNIPERIF_ITM_BCLR reg
+ */
+
+#define UNIPERIF_ITM_BCLR_OFFSET(ip) 0x001c
+#define SET_UNIPERIF_ITM_BCLR(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_ITM_BCLR_OFFSET(ip))
+
+/* FIFO_ERROR */
+#define UNIPERIF_ITM_BCLR_FIFO_ERROR_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8)
+#define UNIPERIF_ITM_BCLR_FIFO_ERROR_MASK(ip) \
+ (BIT(UNIPERIF_ITM_BCLR_FIFO_ERROR_SHIFT(ip)))
+#define SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(ip) \
+ SET_UNIPERIF_ITM_BCLR(ip, \
+ UNIPERIF_ITM_BCLR_FIFO_ERROR_MASK(ip))
+
+/* DMA_ERROR */
+#define UNIPERIF_ITM_BCLR_DMA_ERROR_SHIFT(ip) 9
+#define UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip) \
+ (BIT(UNIPERIF_ITM_BCLR_DMA_ERROR_SHIFT(ip)))
+#define SET_UNIPERIF_ITM_BCLR_DMA_ERROR(ip) \
+ SET_UNIPERIF_ITM_BCLR(ip, \
+ UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip))
+
+/*
+ * AUD_UNIPERIF_ITM_BSET reg
+ */
+
+#define UNIPERIF_ITM_BSET_OFFSET(ip) 0x0020
+#define SET_UNIPERIF_ITM_BSET(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_ITM_BSET_OFFSET(ip))
+
+/* FIFO_ERROR */
+#define UNIPERIF_ITM_BSET_FIFO_ERROR_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8)
+#define UNIPERIF_ITM_BSET_FIFO_ERROR_MASK(ip) \
+ (BIT(UNIPERIF_ITM_BSET_FIFO_ERROR_SHIFT(ip)))
+#define SET_UNIPERIF_ITM_BSET_FIFO_ERROR(ip) \
+ SET_UNIPERIF_ITM_BSET(ip, \
+ UNIPERIF_ITM_BSET_FIFO_ERROR_MASK(ip))
+
+/* MEM_BLK_READ */
+#define UNIPERIF_ITM_BSET_MEM_BLK_READ_SHIFT(ip) 5
+#define UNIPERIF_ITM_BSET_MEM_BLK_READ_MASK(ip) \
+ (BIT(UNIPERIF_ITM_BSET_MEM_BLK_READ_SHIFT(ip)))
+#define SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(ip) \
+ SET_UNIPERIF_ITM_BSET(ip, \
+ UNIPERIF_ITM_BSET_MEM_BLK_READ_MASK(ip))
+
+/* DMA_ERROR */
+#define UNIPERIF_ITM_BSET_DMA_ERROR_SHIFT(ip) 9
+#define UNIPERIF_ITM_BSET_DMA_ERROR_MASK(ip) \
+ (BIT(UNIPERIF_ITM_BSET_DMA_ERROR_SHIFT(ip)))
+#define SET_UNIPERIF_ITM_BSET_DMA_ERROR(ip) \
+ SET_UNIPERIF_ITM_BSET(ip, \
+ UNIPERIF_ITM_BSET_DMA_ERROR_MASK(ip))
+
+/* UNDERFLOW_REC_DONE */
+#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12)
+#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_MASK(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
+ 0 : (BIT(UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_SHIFT(ip))))
+#define SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(ip) \
+ SET_UNIPERIF_ITM_BSET(ip, \
+ UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_MASK(ip))
+
+/* UNDERFLOW_REC_FAILED */
+#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13)
+#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_MASK(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \
+ 0 : (BIT(UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_SHIFT(ip))))
+#define SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(ip) \
+ SET_UNIPERIF_ITM_BSET(ip, \
+ UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_MASK(ip))
+
+/*
+ * UNIPERIF_CONFIG reg
+ */
+
+#define UNIPERIF_CONFIG_OFFSET(ip) 0x0040
+#define GET_UNIPERIF_CONFIG(ip) \
+ readl_relaxed(ip->base + UNIPERIF_CONFIG_OFFSET(ip))
+#define SET_UNIPERIF_CONFIG(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_CONFIG_OFFSET(ip))
+
+/* PARITY_CNTR */
+#define UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip) 0
+#define UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip) 0x1
+#define GET_UNIPERIF_CONFIG_PARITY_CNTR(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \
+ UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip))
+#define SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_HW(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \
+ UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip), 0)
+#define SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_SW(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \
+ UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip), 1)
+
+/* CHANNEL_STA_CNTR */
+#define UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip) 1
+#define UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip) 0x1
+#define GET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \
+ UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip))
+#define SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_SW(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \
+ UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip), 0)
+#define SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_HW(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \
+ UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip), 1)
+
+/* USER_DAT_CNTR */
+#define UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip) 2
+#define UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip) 0x1
+#define GET_UNIPERIF_CONFIG_USER_DAT_CNTR(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \
+ UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip))
+#define SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_HW(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \
+ UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip), 1)
+#define SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_SW(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \
+ UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip), 0)
+
+/* VALIDITY_DAT_CNTR */
+#define UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip) 3
+#define UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip) 0x1
+#define GET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \
+ UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip))
+#define SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_SW(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \
+ UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip), 0)
+#define SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_HW(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \
+ UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip), 1)
+
+/* ONE_BIT_AUD_SUPPORT */
+#define UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip) 4
+#define UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip) 0x1
+#define GET_UNIPERIF_CONFIG_ONE_BIT_AUD(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \
+ UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip))
+#define SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \
+ UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip), 0)
+#define SET_UNIPERIF_CONFIG_ONE_BIT_AUD_ENABLE(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \
+ UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip), 1)
+
+/* MEMORY_FMT */
+#define UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip) 5
+#define UNIPERIF_CONFIG_MEM_FMT_MASK(ip) 0x1
+#define VALUE_UNIPERIF_CONFIG_MEM_FMT_16_0(ip) 0
+#define VALUE_UNIPERIF_CONFIG_MEM_FMT_16_16(ip) 1
+#define GET_UNIPERIF_CONFIG_MEM_FMT(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip), \
+ UNIPERIF_CONFIG_MEM_FMT_MASK(ip))
+#define SET_UNIPERIF_CONFIG_MEM_FMT(ip, value) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip), \
+ UNIPERIF_CONFIG_MEM_FMT_MASK(ip), value)
+#define SET_UNIPERIF_CONFIG_MEM_FMT_16_0(ip) \
+ SET_UNIPERIF_CONFIG_MEM_FMT(ip, \
+ VALUE_UNIPERIF_CONFIG_MEM_FMT_16_0(ip))
+#define SET_UNIPERIF_CONFIG_MEM_FMT_16_16(ip) \
+ SET_UNIPERIF_CONFIG_MEM_FMT(ip, \
+ VALUE_UNIPERIF_CONFIG_MEM_FMT_16_16(ip))
+
+/* REPEAT_CHL_STS */
+#define UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip) 6
+#define UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip) 0x1
+#define GET_UNIPERIF_CONFIG_REPEAT_CHL_STS(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \
+ UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip))
+#define SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_ENABLE(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \
+ UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip), 0)
+#define SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_DISABLE(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \
+ UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip), 1)
+
+/* BACK_STALL_REQ */
+#define UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 7 : -1)
+#define UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip) 0x1
+#define GET_UNIPERIF_CONFIG_BACK_STALL_REQ(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \
+ UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip))
+#define SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \
+ UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip), 0)
+#define SET_UNIPERIF_CONFIG_BACK_STALL_REQ_ENABLE(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \
+ UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip), 1)
+
+/* FDMA_TRIGGER_LIMIT */
+#define UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip) 8
+#define UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip) 0x7F
+#define GET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip), \
+ UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip))
+#define SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(ip, value) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip), \
+ UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip), value)
+
+/* CHL_STS_UPDATE */
+#define UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 16 : -1)
+#define UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip) 0x1
+#define GET_UNIPERIF_CONFIG_CHL_STS_UPDATE(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip), \
+ UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip))
+#define SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip), \
+ UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip), 1)
+
+/* IDLE_MOD */
+#define UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip) 18
+#define UNIPERIF_CONFIG_IDLE_MOD_MASK(ip) 0x1
+#define GET_UNIPERIF_CONFIG_IDLE_MOD(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \
+ UNIPERIF_CONFIG_IDLE_MOD_MASK(ip))
+#define SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \
+ UNIPERIF_CONFIG_IDLE_MOD_MASK(ip), 0)
+#define SET_UNIPERIF_CONFIG_IDLE_MOD_ENABLE(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \
+ UNIPERIF_CONFIG_IDLE_MOD_MASK(ip), 1)
+
+/* SUBFRAME_SELECTION */
+#define UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip) 19
+#define UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip) 0x1
+#define GET_UNIPERIF_CONFIG_SUBFRAME_SEL(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \
+ UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip))
+#define SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF1_SUBF0(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \
+ UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip), 1)
+#define SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF0_SUBF1(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \
+ UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip), 0)
+
+/* FULL_SW_CONTROL */
+#define UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip) 20
+#define UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip) 0x1
+#define GET_UNIPERIF_CONFIG_SPDIF_SW_CTRL(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \
+ UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip))
+#define SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_ENABLE(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \
+ UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip), 1)
+#define SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_DISABLE(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \
+ UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip), 0)
+
+/* MASTER_CLKEDGE */
+#define UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 24 : -1)
+#define UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip) 0x1
+#define GET_UNIPERIF_CONFIG_MSTR_CLKEDGE(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \
+ UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip))
+#define SET_UNIPERIF_CONFIG_MSTR_CLKEDGE_FALLING(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \
+ UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip), 1)
+#define SET_UNIPERIF_CONFIG_MSTR_CLKEDGE_RISING(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CONFIG_OFFSET(ip), \
+ UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \
+ UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip), 0)
+
+/*
+ * UNIPERIF_CTRL reg
+ */
+
+#define UNIPERIF_CTRL_OFFSET(ip) 0x0044
+#define GET_UNIPERIF_CTRL(ip) \
+ readl_relaxed(ip->base + UNIPERIF_CTRL_OFFSET(ip))
+#define SET_UNIPERIF_CTRL(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_CTRL_OFFSET(ip))
+
+/* OPERATION */
+#define UNIPERIF_CTRL_OPERATION_SHIFT(ip) 0
+#define UNIPERIF_CTRL_OPERATION_MASK(ip) 0x7
+#define GET_UNIPERIF_CTRL_OPERATION(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
+ UNIPERIF_CTRL_OPERATION_MASK(ip))
+#define VALUE_UNIPERIF_CTRL_OPERATION_OFF(ip) 0
+#define SET_UNIPERIF_CTRL_OPERATION_OFF(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
+ UNIPERIF_CTRL_OPERATION_MASK(ip), \
+ VALUE_UNIPERIF_CTRL_OPERATION_OFF(ip))
+#define VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 1 : -1)
+#define SET_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
+ UNIPERIF_CTRL_OPERATION_MASK(ip), \
+ VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip))
+#define VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 2 : -1)
+#define SET_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
+ UNIPERIF_CTRL_OPERATION_MASK(ip), \
+ VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip))
+#define VALUE_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip) 3
+#define SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
+ UNIPERIF_CTRL_OPERATION_MASK(ip), \
+ VALUE_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip))
+/* This is the same as above! */
+#define VALUE_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip) 3
+#define SET_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
+ UNIPERIF_CTRL_OPERATION_MASK(ip), \
+ VALUE_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip))
+#define VALUE_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip) 4
+#define SET_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
+ UNIPERIF_CTRL_OPERATION_MASK(ip), \
+ VALUE_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip))
+#define VALUE_UNIPERIF_CTRL_OPERATION_CD_DATA(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 5 : -1)
+#define SET_UNIPERIF_CTRL_OPERATION_CD_DATA(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
+ UNIPERIF_CTRL_OPERATION_MASK(ip), \
+ VALUE_UNIPERIF_CTRL_OPERATION_CD_DATA(ip))
+#define VALUE_UNIPERIF_CTRL_OPERATION_STANDBY(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 7)
+#define SET_UNIPERIF_CTRL_OPERATION_STANDBY(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_OPERATION_SHIFT(ip), \
+ UNIPERIF_CTRL_OPERATION_MASK(ip), \
+ VALUE_UNIPERIF_CTRL_OPERATION_STANDBY(ip))
+
+/* EXIT_STBY_ON_EOBLOCK */
+#define UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 3)
+#define UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip) 0x1
+#define GET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \
+ UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip))
+#define SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_OFF(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \
+ UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip), 0)
+#define SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_ON(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \
+ UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip), 1)
+
+/* ROUNDING */
+#define UNIPERIF_CTRL_ROUNDING_SHIFT(ip) 4
+#define UNIPERIF_CTRL_ROUNDING_MASK(ip) 0x1
+#define GET_UNIPERIF_CTRL_ROUNDING(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \
+ UNIPERIF_CTRL_ROUNDING_MASK(ip))
+#define SET_UNIPERIF_CTRL_ROUNDING_OFF(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \
+ UNIPERIF_CTRL_ROUNDING_MASK(ip), 0)
+#define SET_UNIPERIF_CTRL_ROUNDING_ON(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \
+ UNIPERIF_CTRL_ROUNDING_MASK(ip), 1)
+
+/* DIVIDER */
+#define UNIPERIF_CTRL_DIVIDER_SHIFT(ip) 5
+#define UNIPERIF_CTRL_DIVIDER_MASK(ip) 0xff
+#define GET_UNIPERIF_CTRL_DIVIDER(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_DIVIDER_SHIFT(ip), \
+ UNIPERIF_CTRL_DIVIDER_MASK(ip))
+#define SET_UNIPERIF_CTRL_DIVIDER(ip, value) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_DIVIDER_SHIFT(ip), \
+ UNIPERIF_CTRL_DIVIDER_MASK(ip), value)
+
+/* BYTE_SWAP */
+#define UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 13 : -1)
+#define UNIPERIF_CTRL_BYTE_SWP_MASK(ip) 0x1
+#define GET_UNIPERIF_CTRL_BYTE_SWP(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \
+ UNIPERIF_CTRL_BYTE_SWP_MASK(ip))
+#define SET_UNIPERIF_CTRL_BYTE_SWP_OFF(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \
+ UNIPERIF_CTRL_BYTE_SWP_MASK(ip), 0)
+#define SET_UNIPERIF_CTRL_BYTE_SWP_ON(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \
+ UNIPERIF_CTRL_BYTE_SWP_MASK(ip), 1)
+
+/* ZERO_STUFFING_HW_SW */
+#define UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 14 : -1)
+#define UNIPERIF_CTRL_ZERO_STUFF_MASK(ip) 0x1
+#define GET_UNIPERIF_CTRL_ZERO_STUFF(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \
+ UNIPERIF_CTRL_ZERO_STUFF_MASK(ip))
+#define SET_UNIPERIF_CTRL_ZERO_STUFF_HW(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \
+ UNIPERIF_CTRL_ZERO_STUFF_MASK(ip), 1)
+#define SET_UNIPERIF_CTRL_ZERO_STUFF_SW(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \
+ UNIPERIF_CTRL_ZERO_STUFF_MASK(ip), 0)
+
+/* SPDIF_LAT */
+#define UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 16 : -1)
+#define UNIPERIF_CTRL_SPDIF_LAT_MASK(ip) 0x1
+#define GET_UNIPERIF_CTRL_SPDIF_LAT(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \
+ UNIPERIF_CTRL_SPDIF_LAT_MASK(ip))
+#define SET_UNIPERIF_CTRL_SPDIF_LAT_ON(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \
+ UNIPERIF_CTRL_SPDIF_LAT_MASK(ip), 1)
+#define SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \
+ UNIPERIF_CTRL_SPDIF_LAT_MASK(ip), 0)
+
+/* EN_SPDIF_FORMATTING */
+#define UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip) 17
+#define UNIPERIF_CTRL_SPDIF_FMT_MASK(ip) 0x1
+#define GET_UNIPERIF_CTRL_SPDIF_FMT(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \
+ UNIPERIF_CTRL_SPDIF_FMT_MASK(ip))
+#define SET_UNIPERIF_CTRL_SPDIF_FMT_ON(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \
+ UNIPERIF_CTRL_SPDIF_FMT_MASK(ip), 1)
+#define SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \
+ UNIPERIF_CTRL_SPDIF_FMT_MASK(ip), 0)
+
+/* READER_OUT_SELECT */
+#define UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 18 : -1)
+#define UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip) 0x1
+#define GET_UNIPERIF_CTRL_READER_OUT_SEL(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \
+ UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip))
+#define SET_UNIPERIF_CTRL_READER_OUT_SEL_IN_MEM(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \
+ UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 0)
+#define SET_UNIPERIF_CTRL_READER_OUT_SEL_ON_I2S_LINE(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \
+ CORAUD_UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 1)
+
+/* UNDERFLOW_REC_WINDOW */
+#define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip) 20
+#define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip) 0xff
+#define GET_UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip), \
+ UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip))
+#define SET_UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW(ip, value) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_CTRL_OFFSET(ip), \
+ UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip), \
+ UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip), value)
+
+/*
+ * UNIPERIF_I2S_FMT a.k.a UNIPERIF_FORMAT reg
+ */
+
+#define UNIPERIF_I2S_FMT_OFFSET(ip) 0x0048
+#define GET_UNIPERIF_I2S_FMT(ip) \
+ readl_relaxed(ip->base + UNIPERIF_I2S_FMT_OFFSET(ip))
+#define SET_UNIPERIF_I2S_FMT(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_I2S_FMT_OFFSET(ip))
+
+/* NBIT */
+#define UNIPERIF_I2S_FMT_NBIT_SHIFT(ip) 0
+#define UNIPERIF_I2S_FMT_NBIT_MASK(ip) 0x1
+#define GET_UNIPERIF_I2S_FMT_NBIT(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_NBIT_MASK(ip))
+#define SET_UNIPERIF_I2S_FMT_NBIT_32(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_NBIT_MASK(ip), 0)
+#define SET_UNIPERIF_I2S_FMT_NBIT_16(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_NBIT_MASK(ip), 1)
+
+/* DATA_SIZE */
+#define UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip) 1
+#define UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip) 0x7
+#define GET_UNIPERIF_I2S_FMT_DATA_SIZE(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip))
+#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 0)
+#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_18(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 1)
+#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_20(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 2)
+#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 3)
+#define SET_UNIPERIF_I2S_FMTL_DATA_SIZE_28(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 4)
+#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 5)
+
+/* LR_POL */
+#define UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip) 4
+#define UNIPERIF_I2S_FMT_LR_POL_MASK(ip) 0x1
+#define VALUE_UNIPERIF_I2S_FMT_LR_POL_LOW(ip) 0x0
+#define VALUE_UNIPERIF_I2S_FMT_LR_POL_HIG(ip) 0x1
+#define GET_UNIPERIF_I2S_FMT_LR_POL(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_LR_POL_MASK(ip))
+#define SET_UNIPERIF_I2S_FMT_LR_POL(ip, value) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_LR_POL_MASK(ip), value)
+#define SET_UNIPERIF_I2S_FMT_LR_POL_LOW(ip) \
+ SET_UNIPERIF_I2S_FMT_LR_POL(ip, \
+ VALUE_UNIPERIF_I2S_FMT_LR_POL_LOW(ip))
+#define SET_UNIPERIF_I2S_FMT_LR_POL_HIG(ip) \
+ SET_UNIPERIF_I2S_FMT_LR_POL(ip, \
+ VALUE_UNIPERIF_I2S_FMT_LR_POL_HIG(ip))
+
+/* SCLK_EDGE */
+#define UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip) 5
+#define UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip) 0x1
+#define GET_UNIPERIF_I2S_FMT_SCLK_EDGE(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip))
+#define SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip), 0)
+#define SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip), 1)
+
+/* PADDING */
+#define UNIPERIF_I2S_FMT_PADDING_SHIFT(ip) 6
+#define UNIPERIF_I2S_FMT_PADDING_MASK(ip) 0x1
+#define UNIPERIF_I2S_FMT_PADDING_MASK(ip) 0x1
+#define VALUE_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip) 0x0
+#define VALUE_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip) 0x1
+#define GET_UNIPERIF_I2S_FMT_PADDING(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_PADDING_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_PADDING_MASK(ip))
+#define SET_UNIPERIF_I2S_FMT_PADDING(ip, value) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_PADDING_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_PADDING_MASK(ip), value)
+#define SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip) \
+ SET_UNIPERIF_I2S_FMT_PADDING(ip, \
+ VALUE_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip))
+#define SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip) \
+ SET_UNIPERIF_I2S_FMT_PADDING(ip, \
+ VALUE_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip))
+
+/* ALIGN */
+#define UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip) 7
+#define UNIPERIF_I2S_FMT_ALIGN_MASK(ip) 0x1
+#define GET_UNIPERIF_I2S_FMT_ALIGN(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_ALIGN_MASK(ip))
+#define SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_ALIGN_MASK(ip), 0)
+#define SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_ALIGN_MASK(ip), 1)
+
+/* ORDER */
+#define UNIPERIF_I2S_FMT_ORDER_SHIFT(ip) 8
+#define UNIPERIF_I2S_FMT_ORDER_MASK(ip) 0x1
+#define GET_UNIPERIF_I2S_FMT_ORDER(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_ORDER_MASK(ip))
+#define SET_UNIPERIF_I2S_FMT_ORDER_LSB(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_ORDER_MASK(ip), 0)
+#define SET_UNIPERIF_I2S_FMT_ORDER_MSB(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_ORDER_MASK(ip), 1)
+
+/* NUM_CH */
+#define UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip) 9
+#define UNIPERIF_I2S_FMT_NUM_CH_MASK(ip) 0x7
+#define GET_UNIPERIF_I2S_FMT_NUM_CH(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_NUM_CH_MASK(ip))
+#define SET_UNIPERIF_I2S_FMT_NUM_CH(ip, value) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_NUM_CH_MASK(ip), value)
+
+/* NO_OF_SAMPLES_TO_READ */
+#define UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip) 12
+#define UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip) 0xfffff
+#define GET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip))
+#define SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(ip, value) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_I2S_FMT_OFFSET(ip), \
+ UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip), \
+ UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip), value)
+
+/*
+ * UNIPERIF_BIT_CONTROL reg
+ */
+
+#define UNIPERIF_BIT_CONTROL_OFFSET(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0x004c)
+#define GET_UNIPERIF_BIT_CONTROL(ip) \
+ readl_relaxed(ip->base + UNIPERIF_BIT_CONTROL_OFFSET(ip))
+#define SET_UNIPERIF_BIT_CONTROL(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_BIT_CONTROL_OFFSET(ip))
+
+/* CLR_UNDERFLOW_DURATION */
+#define UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip) 0
+#define UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip) 0x1
+#define GET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_BIT_CONTROL_OFFSET(ip), \
+ UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip), \
+ UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip))
+#define SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(ip) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_BIT_CONTROL_OFFSET(ip), \
+ UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip), \
+ UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip), 1)
+
+/* CHL_STS_UPDATE */
+#define UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip) 1
+#define UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip) 0x1
+#define GET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_BIT_CONTROL_OFFSET(ip), \
+ UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip), \
+ UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip))
+#define SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(ip) \
+ SET_UNIPERIF_BIT_REG(ip, \
+ UNIPERIF_BIT_CONTROL_OFFSET(ip), \
+ UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip), \
+ UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip), 1)
+
+/*
+ * UNIPERIF_STATUS_1 reg
+ */
+
+#define UNIPERIF_STATUS_1_OFFSET(ip) 0x0050
+#define GET_UNIPERIF_STATUS_1(ip) \
+ readl_relaxed(ip->base + UNIPERIF_STATUS_1_OFFSET(ip))
+#define SET_UNIPERIF_STATUS_1(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_STATUS_1_OFFSET(ip))
+
+/* UNDERFLOW_DURATION */
+#define UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0)
+#define UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip) 0xff
+#define GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_STATUS_1_OFFSET(ip), \
+ UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip), \
+ UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip))
+#define SET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(ip, value) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_STATUS_1_OFFSET(ip), \
+ UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip), \
+ UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip), value)
+
+/*
+ * AUD_UNIPERIF_CHANNEL_STA_REGN reg
+ */
+
+#define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n))
+#define GET_UNIPERIF_CHANNEL_STA_REGN(ip) \
+ readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REGN(ip, n))
+#define SET_UNIPERIF_CHANNEL_STA_REGN(ip, n, value) \
+ writel_relaxed(value, ip->base + \
+ UNIPERIF_CHANNEL_STA_REGN(ip, n))
+
+/*
+ * AUD_UNIPERIF_USER_VALIDITY reg
+ */
+
+#define UNIPERIF_USER_VALIDITY_OFFSET(ip) 0x0090
+#define GET_UNIPERIF_USER_VALIDITY(ip) \
+ readl_relaxed(ip->base + UNIPERIF_USER_VALIDITY_OFFSET(ip))
+#define SET_UNIPERIF_USER_VALIDITY(ip, value) \
+ writel_relaxed(value, ip->base + UNIPERIF_USER_VALIDITY_OFFSET(ip))
+
+/* VALIDITY_LEFT_AND_RIGHT */
+#define UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip) 0
+#define UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip) 0x3
+#define GET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_USER_VALIDITY_OFFSET(ip), \
+ UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip), \
+ UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip))
+#define SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(ip, value) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_USER_VALIDITY_OFFSET(ip), \
+ UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip), \
+ UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip), \
+ value ? 0x3 : 0)
+
+/*
+ * UNIPERIF_DBG_STANDBY_LEFT_SP reg
+ */
+#define UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip) 0x0150
+#define UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0)
+#define UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip) \
+ ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 0xFFFFFF)
+#define GET_UNIPERIF_DBG_STANDBY_LEFT_SP(ip) \
+ GET_UNIPERIF_REG(ip, \
+ UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip), \
+ UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip), \
+ UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip))
+#define SET_UNIPERIF_DBG_STANDBY_LEFT_SP(ip, value) \
+ SET_UNIPERIF_REG(ip, \
+ UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip), \
+ UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip), \
+ UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value)
+
+/*
+ * uniperipheral IP capabilities
+ */
+
+#define UNIPERIF_FIFO_SIZE 70 /* FIFO is 70 cells deep */
+#define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */
+
+/*
+ * Uniperipheral IP revisions
+ */
+enum uniperif_version {
+ SND_ST_UNIPERIF_VERSION_UNKNOWN,
+ /* SASG1 (Orly), Newman */
+ SND_ST_UNIPERIF_VERSION_C6AUD0_UNI_1_0,
+ /* SASC1, SASG2 (Orly2) */
+ SND_ST_UNIPERIF_VERSION_UNI_PLR_1_0,
+ /* SASC1, SASG2 (Orly2), TELSS, Cannes */
+ SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0,
+ /* TELSS (SASC1) */
+ SND_ST_UNIPERIF_VERSION_TDM_PLR_1_0,
+ /* Cannes/Monaco */
+ SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0
+};
+
+enum uniperif_type {
+ SND_ST_UNIPERIF_PLAYER_TYPE_NONE,
+ SND_ST_UNIPERIF_PLAYER_TYPE_HDMI,
+ SND_ST_UNIPERIF_PLAYER_TYPE_PCM,
+ SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF
+};
+
+enum uniperif_state {
+ UNIPERIF_STATE_STOPPED,
+ UNIPERIF_STATE_STARTED,
+ UNIPERIF_STATE_STANDBY,
+ UNIPERIF_STATE_UNDERFLOW,
+ UNIPERIF_STATE_OVERFLOW = UNIPERIF_STATE_UNDERFLOW,
+ UNIPERIF_STATE_XRUN
+};
+
+enum uniperif_iec958_encoding_mode {
+ UNIPERIF_IEC958_ENCODING_MODE_PCM,
+ UNIPERIF_IEC958_ENCODING_MODE_ENCODED
+};
+
+struct uniperif_info {
+ int id; /* instance value of the uniperipheral IP */
+ enum uniperif_type player_type;
+ int underflow_enabled; /* Underflow recovery mode */
+};
+
+struct uniperif_iec958_settings {
+ enum uniperif_iec958_encoding_mode encoding_mode;
+ struct snd_aes_iec958 iec958;
+};
+
+struct uniperif {
+ /* System information */
+ struct uniperif_info *info;
+ struct device *dev;
+ int ver; /* IP version, used by register access macros */
+ struct regmap_field *clk_sel;
+
+ /* capabilities */
+ const struct snd_pcm_hardware *hw;
+
+ /* Resources */
+ struct resource *mem_region;
+ void __iomem *base;
+ unsigned long fifo_phys_address;
+ int irq;
+
+ /* Clocks */
+ struct clk *clk;
+ int mclk;
+ int clk_adj;
+
+ /* Runtime data */
+ enum uniperif_state state;
+
+ struct snd_pcm_substream *substream;
+
+ /* Specific to IEC958 player */
+ struct uniperif_iec958_settings stream_settings;
+ struct mutex ctrl_lock; /* For resource updated by stream and controls*/
+
+ /*alsa ctrl*/
+ struct snd_kcontrol_new *snd_ctrls;
+ int num_ctrls;
+
+ /* dai properties */
+ unsigned int daifmt;
+
+ /* DAI callbacks */
+ const struct snd_soc_dai_ops *dai_ops;
+};
+
+struct sti_uniperiph_dai {
+ int stream;
+ struct uniperif *uni;
+ struct snd_dmaengine_dai_dma_data dma_data;
+};
+
+struct sti_uniperiph_data {
+ struct platform_device *pdev;
+ struct snd_soc_dai_driver *dai;
+ struct sti_uniperiph_dai dai_data;
+};
+
+/* uniperiph player*/
+int uni_player_init(struct platform_device *pdev,
+ struct uniperif *uni_player);
+int uni_player_resume(struct uniperif *player);
+
+/* uniperiph reader */
+int uni_reader_init(struct platform_device *pdev,
+ struct uniperif *uni_reader);
+
+/* common */
+int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt);
+
+int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai);
+
+#endif
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c
new file mode 100644
index 0000000..f6eefe1
--- /dev/null
+++ b/sound/soc/sti/uniperif_player.c
@@ -0,0 +1,1110 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
+ * for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+
+#include <sound/asoundef.h>
+#include <sound/soc.h>
+
+#include "uniperif.h"
+
+/*
+ * Some hardware-related definitions
+ */
+
+/* sys config registers definitions */
+#define SYS_CFG_AUDIO_GLUE 0xA4
+#define SYS_CFG_AUDI0_GLUE_PCM_CLKX 8
+
+/*
+ * Driver specific types.
+ */
+#define UNIPERIF_PLAYER_TYPE_IS_HDMI(p) \
+ ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_HDMI)
+#define UNIPERIF_PLAYER_TYPE_IS_PCM(p) \
+ ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_PCM)
+#define UNIPERIF_PLAYER_TYPE_IS_SPDIF(p) \
+ ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF)
+#define UNIPERIF_PLAYER_TYPE_IS_IEC958(p) \
+ (UNIPERIF_PLAYER_TYPE_IS_HDMI(p) || \
+ UNIPERIF_PLAYER_TYPE_IS_SPDIF(p))
+
+#define UNIPERIF_PLAYER_CLK_ADJ_MIN -999999
+#define UNIPERIF_PLAYER_CLK_ADJ_MAX 1000000
+
+/*
+ * Note: snd_pcm_hardware is linked to DMA controller but is declared here to
+ * integrate DAI_CPU capability in term of rate and supported channels
+ */
+static const struct snd_pcm_hardware uni_player_pcm_hw = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE,
+
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 8000,
+ .rate_max = 192000,
+
+ .channels_min = 2,
+ .channels_max = 8,
+
+ .periods_min = 2,
+ .periods_max = 48,
+
+ .period_bytes_min = 128,
+ .period_bytes_max = 64 * PAGE_SIZE,
+ .buffer_bytes_max = 256 * PAGE_SIZE
+};
+
+static inline int reset_player(struct uniperif *player)
+{
+ int count = 10;
+
+ if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) {
+ while (GET_UNIPERIF_SOFT_RST_SOFT_RST(player) && count) {
+ udelay(5);
+ count--;
+ }
+ }
+
+ if (!count) {
+ dev_err(player->dev, "Failed to reset uniperif");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * uni_player_irq_handler
+ * In case of error audio stream is stopped; stop action is protected via PCM
+ * stream lock to avoid race condition with trigger callback.
+ */
+static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
+{
+ irqreturn_t ret = IRQ_NONE;
+ struct uniperif *player = dev_id;
+ unsigned int status;
+ unsigned int tmp;
+
+ if (player->state == UNIPERIF_STATE_STOPPED) {
+ /* Unexpected IRQ: do nothing */
+ return IRQ_NONE;
+ }
+
+ /* Get interrupt status & clear them immediately */
+ status = GET_UNIPERIF_ITS(player);
+ SET_UNIPERIF_ITS_BCLR(player, status);
+
+ /* Check for fifo error (underrun) */
+ if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) {
+ dev_err(player->dev, "FIFO underflow error detected");
+
+ /* Interrupt is just for information when underflow recovery */
+ if (player->info->underflow_enabled) {
+ /* Update state to underflow */
+ player->state = UNIPERIF_STATE_UNDERFLOW;
+
+ } else {
+ /* Disable interrupt so doesn't continually fire */
+ SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player);
+
+ /* Stop the player */
+ snd_pcm_stream_lock(player->substream);
+ snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock(player->substream);
+ }
+
+ ret = IRQ_HANDLED;
+ }
+
+ /* Check for dma error (overrun) */
+ if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) {
+ dev_err(player->dev, "DMA error detected");
+
+ /* Disable interrupt so doesn't continually fire */
+ SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player);
+
+ /* Stop the player */
+ snd_pcm_stream_lock(player->substream);
+ snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock(player->substream);
+
+ ret = IRQ_HANDLED;
+ }
+
+ /* Check for underflow recovery done */
+ if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) {
+ if (!player->info->underflow_enabled) {
+ dev_err(player->dev, "unexpected Underflow recovering");
+ return -EPERM;
+ }
+ /* Read the underflow recovery duration */
+ tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player);
+
+ /* Clear the underflow recovery duration */
+ SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player);
+
+ /* Update state to started */
+ player->state = UNIPERIF_STATE_STARTED;
+
+ ret = IRQ_HANDLED;
+ }
+
+ /* Check if underflow recovery failed */
+ if (unlikely(status &
+ UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) {
+ dev_err(player->dev, "Underflow recovery failed");
+
+ /* Stop the player */
+ snd_pcm_stream_lock(player->substream);
+ snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock(player->substream);
+
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static int uni_player_clk_set_rate(struct uniperif *player, unsigned long rate)
+{
+ int rate_adjusted, rate_achieved, delta, ret;
+ int adjustment = player->clk_adj;
+
+ /*
+ * a
+ * F = f + --------- * f = f + d
+ * 1000000
+ *
+ * a
+ * d = --------- * f
+ * 1000000
+ *
+ * where:
+ * f - nominal rate
+ * a - adjustment in ppm (parts per milion)
+ * F - rate to be set in synthesizer
+ * d - delta (difference) between f and F
+ */
+ if (adjustment < 0) {
+ /* div64_64 operates on unsigned values... */
+ delta = -1;
+ adjustment = -adjustment;
+ } else {
+ delta = 1;
+ }
+ /* 500000 ppm is 0.5, which is used to round up values */
+ delta *= (int)div64_u64((uint64_t)rate *
+ (uint64_t)adjustment + 500000, 1000000);
+ rate_adjusted = rate + delta;
+
+ /* Adjusted rate should never be == 0 */
+ if (!rate_adjusted)
+ return -EINVAL;
+
+ ret = clk_set_rate(player->clk, rate_adjusted);
+ if (ret < 0)
+ return ret;
+
+ rate_achieved = clk_get_rate(player->clk);
+ if (!rate_achieved)
+ /* If value is 0 means that clock or parent not valid */
+ return -EINVAL;
+
+ /*
+ * Using ALSA's adjustment control, we can modify the rate to be up
+ * to twice as much as requested, but no more
+ */
+ delta = rate_achieved - rate;
+ if (delta < 0) {
+ /* div64_64 operates on unsigned values... */
+ delta = -delta;
+ adjustment = -1;
+ } else {
+ adjustment = 1;
+ }
+ /* Frequency/2 is added to round up result */
+ adjustment *= (int)div64_u64((uint64_t)delta * 1000000 + rate / 2,
+ rate);
+ player->clk_adj = adjustment;
+ return 0;
+}
+
+static void uni_player_set_channel_status(struct uniperif *player,
+ struct snd_pcm_runtime *runtime)
+{
+ int n;
+ unsigned int status;
+
+ /*
+ * Some AVRs and TVs require the channel status to contain a correct
+ * sampling frequency. If no sample rate is already specified, then
+ * set one.
+ */
+ mutex_lock(&player->ctrl_lock);
+ if (runtime && (player->stream_settings.iec958.status[3]
+ == IEC958_AES3_CON_FS_NOTID)) {
+ switch (runtime->rate) {
+ case 22050:
+ player->stream_settings.iec958.status[3] =
+ IEC958_AES3_CON_FS_22050;
+ break;
+ case 44100:
+ player->stream_settings.iec958.status[3] =
+ IEC958_AES3_CON_FS_44100;
+ break;
+ case 88200:
+ player->stream_settings.iec958.status[3] =
+ IEC958_AES3_CON_FS_88200;
+ break;
+ case 176400:
+ player->stream_settings.iec958.status[3] =
+ IEC958_AES3_CON_FS_176400;
+ break;
+ case 24000:
+ player->stream_settings.iec958.status[3] =
+ IEC958_AES3_CON_FS_24000;
+ break;
+ case 48000:
+ player->stream_settings.iec958.status[3] =
+ IEC958_AES3_CON_FS_48000;
+ break;
+ case 96000:
+ player->stream_settings.iec958.status[3] =
+ IEC958_AES3_CON_FS_96000;
+ break;
+ case 192000:
+ player->stream_settings.iec958.status[3] =
+ IEC958_AES3_CON_FS_192000;
+ break;
+ case 32000:
+ player->stream_settings.iec958.status[3] =
+ IEC958_AES3_CON_FS_32000;
+ break;
+ default:
+ /* Mark as sampling frequency not indicated */
+ player->stream_settings.iec958.status[3] =
+ IEC958_AES3_CON_FS_NOTID;
+ break;
+ }
+ }
+
+ /* Audio mode:
+ * Use audio mode status to select PCM or encoded mode
+ */
+ if (player->stream_settings.iec958.status[0] & IEC958_AES0_NONAUDIO)
+ player->stream_settings.encoding_mode =
+ UNIPERIF_IEC958_ENCODING_MODE_ENCODED;
+ else
+ player->stream_settings.encoding_mode =
+ UNIPERIF_IEC958_ENCODING_MODE_PCM;
+
+ if (player->stream_settings.encoding_mode ==
+ UNIPERIF_IEC958_ENCODING_MODE_PCM)
+ /* Clear user validity bits */
+ SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0);
+ else
+ /* Set user validity bits */
+ SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 1);
+
+ /* Program the new channel status */
+ for (n = 0; n < 6; ++n) {
+ status =
+ player->stream_settings.iec958.status[0 + (n * 4)] & 0xf;
+ status |=
+ player->stream_settings.iec958.status[1 + (n * 4)] << 8;
+ status |=
+ player->stream_settings.iec958.status[2 + (n * 4)] << 16;
+ status |=
+ player->stream_settings.iec958.status[3 + (n * 4)] << 24;
+ SET_UNIPERIF_CHANNEL_STA_REGN(player, n, status);
+ }
+ mutex_unlock(&player->ctrl_lock);
+
+ /* Update the channel status */
+ if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
+ SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(player);
+ else
+ SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(player);
+}
+
+static int uni_player_prepare_iec958(struct uniperif *player,
+ struct snd_pcm_runtime *runtime)
+{
+ int clk_div;
+
+ clk_div = player->mclk / runtime->rate;
+
+ /* Oversampling must be multiple of 128 as iec958 frame is 32-bits */
+ if ((clk_div % 128) || (clk_div <= 0)) {
+ dev_err(player->dev, "%s: invalid clk_div %d",
+ __func__, clk_div);
+ return -EINVAL;
+ }
+
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ /* 16/16 memory format */
+ SET_UNIPERIF_CONFIG_MEM_FMT_16_16(player);
+ /* 16-bits per sub-frame */
+ SET_UNIPERIF_I2S_FMT_NBIT_32(player);
+ /* Set 16-bit sample precision */
+ SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ /* 16/0 memory format */
+ SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player);
+ /* 32-bits per sub-frame */
+ SET_UNIPERIF_I2S_FMT_NBIT_32(player);
+ /* Set 24-bit sample precision */
+ SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(player);
+ break;
+ default:
+ dev_err(player->dev, "format not supported");
+ return -EINVAL;
+ }
+
+ /* Set parity to be calculated by the hardware */
+ SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_HW(player);
+
+ /* Set channel status bits to be inserted by the hardware */
+ SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_HW(player);
+
+ /* Set user data bits to be inserted by the hardware */
+ SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_HW(player);
+
+ /* Set validity bits to be inserted by the hardware */
+ SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_HW(player);
+
+ /* Set full software control to disabled */
+ SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_DISABLE(player);
+
+ SET_UNIPERIF_CTRL_ZERO_STUFF_HW(player);
+
+ /* Update the channel status */
+ uni_player_set_channel_status(player, runtime);
+
+ /* Clear the user validity user bits */
+ SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0);
+
+ /* Disable one-bit audio mode */
+ SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player);
+
+ /* Enable consecutive frames repetition of Z preamble (not for HBRA) */
+ SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_ENABLE(player);
+
+ /* Change to SUF0_SUBF1 and left/right channels swap! */
+ SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF1_SUBF0(player);
+
+ /* Set data output as MSB first */
+ SET_UNIPERIF_I2S_FMT_ORDER_MSB(player);
+
+ if (player->stream_settings.encoding_mode ==
+ UNIPERIF_IEC958_ENCODING_MODE_ENCODED)
+ SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_ON(player);
+ else
+ SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_OFF(player);
+
+ SET_UNIPERIF_I2S_FMT_NUM_CH(player, runtime->channels / 2);
+
+ /* Set rounding to off */
+ SET_UNIPERIF_CTRL_ROUNDING_OFF(player);
+
+ /* Set clock divisor */
+ SET_UNIPERIF_CTRL_DIVIDER(player, clk_div / 128);
+
+ /* Set the spdif latency to not wait before starting player */
+ SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player);
+
+ /*
+ * Ensure iec958 formatting is off. It will be enabled in function
+ * uni_player_start() at the same time as the operation
+ * mode is set to work around a silicon issue.
+ */
+ if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
+ SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player);
+ else
+ SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player);
+
+ return 0;
+}
+
+static int uni_player_prepare_pcm(struct uniperif *player,
+ struct snd_pcm_runtime *runtime)
+{
+ int output_frame_size, slot_width, clk_div;
+
+ /* Force slot width to 32 in I2S mode (HW constraint) */
+ if ((player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) ==
+ SND_SOC_DAIFMT_I2S) {
+ slot_width = 32;
+ } else {
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ slot_width = 16;
+ break;
+ default:
+ slot_width = 32;
+ break;
+ }
+ }
+ output_frame_size = slot_width * runtime->channels;
+
+ clk_div = player->mclk / runtime->rate;
+ /*
+ * For 32 bits subframe clk_div must be a multiple of 128,
+ * for 16 bits must be a multiple of 64
+ */
+ if ((slot_width == 32) && (clk_div % 128)) {
+ dev_err(player->dev, "%s: invalid clk_div", __func__);
+ return -EINVAL;
+ }
+
+ if ((slot_width == 16) && (clk_div % 64)) {
+ dev_err(player->dev, "%s: invalid clk_div", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Number of bits per subframe (which is one channel sample)
+ * on output - Transfer 16 or 32 bits from FIFO
+ */
+ switch (slot_width) {
+ case 32:
+ SET_UNIPERIF_I2S_FMT_NBIT_32(player);
+ SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(player);
+ break;
+ case 16:
+ SET_UNIPERIF_I2S_FMT_NBIT_16(player);
+ SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player);
+ break;
+ default:
+ dev_err(player->dev, "subframe format not supported");
+ return -EINVAL;
+ }
+
+ /* Configure data memory format */
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ /* One data word contains two samples */
+ SET_UNIPERIF_CONFIG_MEM_FMT_16_16(player);
+ break;
+
+ case SNDRV_PCM_FORMAT_S32_LE:
+ /*
+ * Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits
+ * on the left than zeros (if less than 32 bytes)"... ;-)
+ */
+ SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player);
+ break;
+
+ default:
+ dev_err(player->dev, "format not supported");
+ return -EINVAL;
+ }
+
+ /* Set rounding to off */
+ SET_UNIPERIF_CTRL_ROUNDING_OFF(player);
+
+ /* Set clock divisor */
+ SET_UNIPERIF_CTRL_DIVIDER(player, clk_div / (2 * output_frame_size));
+
+ /* Number of channelsmust be even*/
+ if ((runtime->channels % 2) || (runtime->channels < 2) ||
+ (runtime->channels > 10)) {
+ dev_err(player->dev, "%s: invalid nb of channels", __func__);
+ return -EINVAL;
+ }
+
+ SET_UNIPERIF_I2S_FMT_NUM_CH(player, runtime->channels / 2);
+
+ /* Set 1-bit audio format to disabled */
+ SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player);
+
+ SET_UNIPERIF_I2S_FMT_ORDER_MSB(player);
+ SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player);
+
+ /* No iec958 formatting as outputting to DAC */
+ SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player);
+
+ return 0;
+}
+
+/*
+ * ALSA uniperipheral iec958 controls
+ */
+static int uni_player_ctl_iec958_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+
+ return 0;
+}
+
+static int uni_player_ctl_iec958_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *player = priv->dai_data.uni;
+ struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958;
+
+ mutex_lock(&player->ctrl_lock);
+ ucontrol->value.iec958.status[0] = iec958->status[0];
+ ucontrol->value.iec958.status[1] = iec958->status[1];
+ ucontrol->value.iec958.status[2] = iec958->status[2];
+ ucontrol->value.iec958.status[3] = iec958->status[3];
+ mutex_unlock(&player->ctrl_lock);
+ return 0;
+}
+
+static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *player = priv->dai_data.uni;
+ struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958;
+
+ mutex_lock(&player->ctrl_lock);
+ iec958->status[0] = ucontrol->value.iec958.status[0];
+ iec958->status[1] = ucontrol->value.iec958.status[1];
+ iec958->status[2] = ucontrol->value.iec958.status[2];
+ iec958->status[3] = ucontrol->value.iec958.status[3];
+ mutex_unlock(&player->ctrl_lock);
+
+ uni_player_set_channel_status(player, NULL);
+
+ return 0;
+}
+
+static struct snd_kcontrol_new uni_player_iec958_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+ .info = uni_player_ctl_iec958_info,
+ .get = uni_player_ctl_iec958_get,
+ .put = uni_player_ctl_iec958_put,
+};
+
+/*
+ * uniperif rate adjustement control
+ */
+static int snd_sti_clk_adjustment_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = UNIPERIF_PLAYER_CLK_ADJ_MIN;
+ uinfo->value.integer.max = UNIPERIF_PLAYER_CLK_ADJ_MAX;
+ uinfo->value.integer.step = 1;
+
+ return 0;
+}
+
+static int snd_sti_clk_adjustment_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *player = priv->dai_data.uni;
+
+ mutex_lock(&player->ctrl_lock);
+ ucontrol->value.integer.value[0] = player->clk_adj;
+ mutex_unlock(&player->ctrl_lock);
+
+ return 0;
+}
+
+static int snd_sti_clk_adjustment_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *player = priv->dai_data.uni;
+ int ret = 0;
+
+ if ((ucontrol->value.integer.value[0] < UNIPERIF_PLAYER_CLK_ADJ_MIN) ||
+ (ucontrol->value.integer.value[0] > UNIPERIF_PLAYER_CLK_ADJ_MAX))
+ return -EINVAL;
+
+ mutex_lock(&player->ctrl_lock);
+ player->clk_adj = ucontrol->value.integer.value[0];
+
+ if (player->mclk)
+ ret = uni_player_clk_set_rate(player, player->mclk);
+ mutex_unlock(&player->ctrl_lock);
+
+ return ret;
+}
+
+static struct snd_kcontrol_new uni_player_clk_adj_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Playback Oversampling Freq. Adjustment",
+ .info = snd_sti_clk_adjustment_info,
+ .get = snd_sti_clk_adjustment_get,
+ .put = snd_sti_clk_adjustment_put,
+};
+
+static struct snd_kcontrol_new *snd_sti_pcm_ctl[] = {
+ &uni_player_clk_adj_ctl,
+};
+
+static struct snd_kcontrol_new *snd_sti_iec_ctl[] = {
+ &uni_player_iec958_ctl,
+ &uni_player_clk_adj_ctl,
+};
+
+static int uni_player_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *player = priv->dai_data.uni;
+
+ player->clk_adj = 0;
+
+ return 0;
+}
+
+static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *player = priv->dai_data.uni;
+ int ret;
+
+ if (dir == SND_SOC_CLOCK_IN)
+ return 0;
+
+ if (clk_id != 0)
+ return -EINVAL;
+
+ mutex_lock(&player->ctrl_lock);
+ ret = uni_player_clk_set_rate(player, freq);
+ if (!ret)
+ player->mclk = freq;
+ mutex_unlock(&player->ctrl_lock);
+
+ return ret;
+}
+
+static int uni_player_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *player = priv->dai_data.uni;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int transfer_size, trigger_limit;
+ int ret;
+
+ /* The player should be stopped */
+ if (player->state != UNIPERIF_STATE_STOPPED) {
+ dev_err(player->dev, "%s: invalid player state %d", __func__,
+ player->state);
+ return -EINVAL;
+ }
+
+ /* Calculate transfer size (in fifo cells and bytes) for frame count */
+ transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES;
+
+ /* Calculate number of empty cells available before asserting DREQ */
+ if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) {
+ trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size;
+ } else {
+ /*
+ * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0
+ * FDMA_TRIGGER_LIMIT also controls when the state switches
+ * from OFF or STANDBY to AUDIO DATA.
+ */
+ trigger_limit = transfer_size;
+ }
+
+ /* Trigger limit must be an even number */
+ if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) ||
+ (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(player))) {
+ dev_err(player->dev, "invalid trigger limit %d", trigger_limit);
+ return -EINVAL;
+ }
+
+ SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit);
+
+ /* Uniperipheral setup depends on player type */
+ switch (player->info->player_type) {
+ case SND_ST_UNIPERIF_PLAYER_TYPE_HDMI:
+ ret = uni_player_prepare_iec958(player, runtime);
+ break;
+ case SND_ST_UNIPERIF_PLAYER_TYPE_PCM:
+ ret = uni_player_prepare_pcm(player, runtime);
+ break;
+ case SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF:
+ ret = uni_player_prepare_iec958(player, runtime);
+ break;
+ default:
+ dev_err(player->dev, "invalid player type");
+ return -EINVAL;
+ }
+
+ if (ret)
+ return ret;
+
+ switch (player->daifmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ SET_UNIPERIF_I2S_FMT_LR_POL_LOW(player);
+ SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(player);
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player);
+ SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(player);
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ SET_UNIPERIF_I2S_FMT_LR_POL_LOW(player);
+ SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player);
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player);
+ SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player);
+ break;
+ }
+
+ switch (player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player);
+ SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(player);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player);
+ SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player);
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(player);
+ SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player);
+ break;
+ default:
+ dev_err(player->dev, "format not supported");
+ return -EINVAL;
+ }
+
+ SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(player, 0);
+
+ /* Reset uniperipheral player */
+ SET_UNIPERIF_SOFT_RST_SOFT_RST(player);
+
+ return reset_player(player);
+}
+
+static int uni_player_start(struct uniperif *player)
+{
+ int ret;
+
+ /* The player should be stopped */
+ if (player->state != UNIPERIF_STATE_STOPPED) {
+ dev_err(player->dev, "%s: invalid player state", __func__);
+ return -EINVAL;
+ }
+
+ ret = clk_prepare_enable(player->clk);
+ if (ret) {
+ dev_err(player->dev, "%s: Failed to enable clock", __func__);
+ return ret;
+ }
+
+ /* Clear any pending interrupts */
+ SET_UNIPERIF_ITS_BCLR(player, GET_UNIPERIF_ITS(player));
+
+ /* Set the interrupt mask */
+ SET_UNIPERIF_ITM_BSET_DMA_ERROR(player);
+ SET_UNIPERIF_ITM_BSET_FIFO_ERROR(player);
+
+ /* Enable underflow recovery interrupts */
+ if (player->info->underflow_enabled) {
+ SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(player);
+ SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player);
+ }
+
+ /* Reset uniperipheral player */
+ SET_UNIPERIF_SOFT_RST_SOFT_RST(player);
+
+ ret = reset_player(player);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Does not use IEC61937 features of the uniperipheral hardware.
+ * Instead it performs IEC61937 in software and inserts it directly
+ * into the audio data stream. As such, when encoded mode is selected,
+ * linear pcm mode is still used, but with the differences of the
+ * channel status bits set for encoded mode and the validity bits set.
+ */
+ SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(player);
+
+ /*
+ * If iec958 formatting is required for hdmi or spdif, then it must be
+ * enabled after the operation mode is set. If set prior to this, it
+ * will not take affect and hang the player.
+ */
+ if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
+ if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player))
+ SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player);
+
+ /* Force channel status update (no update if clk disable) */
+ if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
+ SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(player);
+ else
+ SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(player);
+
+ /* Update state to started */
+ player->state = UNIPERIF_STATE_STARTED;
+
+ return 0;
+}
+
+static int uni_player_stop(struct uniperif *player)
+{
+ int ret;
+
+ /* The player should not be in stopped state */
+ if (player->state == UNIPERIF_STATE_STOPPED) {
+ dev_err(player->dev, "%s: invalid player state", __func__);
+ return -EINVAL;
+ }
+
+ /* Turn the player off */
+ SET_UNIPERIF_CTRL_OPERATION_OFF(player);
+
+ /* Soft reset the player */
+ SET_UNIPERIF_SOFT_RST_SOFT_RST(player);
+
+ ret = reset_player(player);
+ if (ret < 0)
+ return ret;
+
+ /* Disable interrupts */
+ SET_UNIPERIF_ITM_BCLR(player, GET_UNIPERIF_ITM(player));
+
+ /* Disable clock */
+ clk_disable_unprepare(player->clk);
+
+ /* Update state to stopped and return */
+ player->state = UNIPERIF_STATE_STOPPED;
+
+ return 0;
+}
+
+int uni_player_resume(struct uniperif *player)
+{
+ int ret;
+
+ /* Select the frequency synthesizer clock */
+ if (player->clk_sel) {
+ ret = regmap_field_write(player->clk_sel, 1);
+ if (ret) {
+ dev_err(player->dev,
+ "%s: Failed to select freq synth clock",
+ __func__);
+ return ret;
+ }
+ }
+
+ SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player);
+ SET_UNIPERIF_CTRL_ROUNDING_OFF(player);
+ SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player);
+ SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uni_player_resume);
+
+static int uni_player_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *player = priv->dai_data.uni;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ return uni_player_start(player);
+ case SNDRV_PCM_TRIGGER_STOP:
+ return uni_player_stop(player);
+ case SNDRV_PCM_TRIGGER_RESUME:
+ return uni_player_resume(player);
+ default:
+ return -EINVAL;
+ }
+}
+
+static void uni_player_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *player = priv->dai_data.uni;
+
+ if (player->state != UNIPERIF_STATE_STOPPED)
+ /* Stop the player */
+ uni_player_stop(player);
+}
+
+static int uni_player_parse_dt_clk_glue(struct platform_device *pdev,
+ struct uniperif *player)
+{
+ int bit_offset;
+ struct device_node *node = pdev->dev.of_node;
+ struct regmap *regmap;
+
+ bit_offset = SYS_CFG_AUDI0_GLUE_PCM_CLKX + player->info->id;
+
+ regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg");
+
+ if (regmap) {
+ struct reg_field regfield =
+ REG_FIELD(SYS_CFG_AUDIO_GLUE, bit_offset, bit_offset);
+
+ player->clk_sel = regmap_field_alloc(regmap, regfield);
+ } else {
+ dev_err(&pdev->dev, "sti-audio-clk-glue syscf not found\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int uni_player_parse_dt(struct platform_device *pdev,
+ struct uniperif *player)
+{
+ struct uniperif_info *info;
+ struct device *dev = &pdev->dev;
+ struct device_node *pnode = pdev->dev.of_node;
+ const char *mode;
+
+ /* Allocate memory for the info structure */
+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ of_property_read_u32(pnode, "version", &player->ver);
+ if (player->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) {
+ dev_err(dev, "Unknown uniperipheral version ");
+ return -EINVAL;
+ }
+ /* Underflow recovery is only supported on later ip revisions */
+ if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
+ info->underflow_enabled = 1;
+
+ of_property_read_u32(pnode, "uniperiph-id", &info->id);
+
+ /* Read the device mode property */
+ of_property_read_string(pnode, "mode", &mode);
+
+ if (strcasecmp(mode, "hdmi") == 0)
+ info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_HDMI;
+ else if (strcasecmp(mode, "pcm") == 0)
+ info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_PCM;
+ else if (strcasecmp(mode, "spdif") == 0)
+ info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF;
+ else
+ info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_NONE;
+
+ /* Save the info structure */
+ player->info = info;
+
+ /* Get the PCM_CLK_SEL bit from audio-glue-ctrl SoC register */
+ if (uni_player_parse_dt_clk_glue(pdev, player))
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops uni_player_dai_ops = {
+ .startup = uni_player_startup,
+ .shutdown = uni_player_shutdown,
+ .prepare = uni_player_prepare,
+ .trigger = uni_player_trigger,
+ .hw_params = sti_uniperiph_dai_hw_params,
+ .set_fmt = sti_uniperiph_dai_set_fmt,
+ .set_sysclk = uni_player_set_sysclk
+};
+
+int uni_player_init(struct platform_device *pdev,
+ struct uniperif *player)
+{
+ int ret = 0;
+
+ player->dev = &pdev->dev;
+ player->state = UNIPERIF_STATE_STOPPED;
+ player->hw = &uni_player_pcm_hw;
+ player->dai_ops = &uni_player_dai_ops;
+
+ ret = uni_player_parse_dt(pdev, player);
+
+ if (ret < 0) {
+ dev_err(player->dev, "Failed to parse DeviceTree");
+ return ret;
+ }
+
+ /* Get uniperif resource */
+ player->clk = of_clk_get(pdev->dev.of_node, 0);
+ if (IS_ERR(player->clk))
+ ret = PTR_ERR(player->clk);
+
+ /* Select the frequency synthesizer clock */
+ if (player->clk_sel) {
+ ret = regmap_field_write(player->clk_sel, 1);
+ if (ret) {
+ dev_err(player->dev,
+ "%s: Failed to select freq synth clock",
+ __func__);
+ return ret;
+ }
+ }
+
+ ret = devm_request_irq(&pdev->dev, player->irq,
+ uni_player_irq_handler, IRQF_SHARED,
+ dev_name(&pdev->dev), player);
+ if (ret < 0)
+ return ret;
+
+ mutex_init(&player->ctrl_lock);
+
+ /* Ensure that disabled by default */
+ SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player);
+ SET_UNIPERIF_CTRL_ROUNDING_OFF(player);
+ SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player);
+ SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player);
+
+ if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) {
+ /* Set default iec958 status bits */
+
+ /* Consumer, PCM, copyright, 2ch, mode 0 */
+ player->stream_settings.iec958.status[0] = 0x00;
+ /* Broadcast reception category */
+ player->stream_settings.iec958.status[1] =
+ IEC958_AES1_CON_GENERAL;
+ /* Do not take into account source or channel number */
+ player->stream_settings.iec958.status[2] =
+ IEC958_AES2_CON_SOURCE_UNSPEC;
+ /* Sampling frequency not indicated */
+ player->stream_settings.iec958.status[3] =
+ IEC958_AES3_CON_FS_NOTID;
+ /* Max sample word 24-bit, sample word length not indicated */
+ player->stream_settings.iec958.status[4] =
+ IEC958_AES4_CON_MAX_WORDLEN_24 |
+ IEC958_AES4_CON_WORDLEN_24_20;
+
+ player->num_ctrls = ARRAY_SIZE(snd_sti_iec_ctl);
+ player->snd_ctrls = snd_sti_iec_ctl[0];
+ } else {
+ player->num_ctrls = ARRAY_SIZE(snd_sti_pcm_ctl);
+ player->snd_ctrls = snd_sti_pcm_ctl[0];
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uni_player_init);
diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c
new file mode 100644
index 0000000..c502626
--- /dev/null
+++ b/sound/soc/sti/uniperif_reader.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
+ * for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <sound/soc.h>
+
+#include "uniperif.h"
+
+/*
+ * Note: snd_pcm_hardware is linked to DMA controller but is declared here to
+ * integrate unireader capability in term of rate and supported channels
+ */
+static const struct snd_pcm_hardware uni_reader_pcm_hw = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE,
+
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 8000,
+ .rate_max = 96000,
+
+ .channels_min = 2,
+ .channels_max = 8,
+
+ .periods_min = 2,
+ .periods_max = 48,
+
+ .period_bytes_min = 128,
+ .period_bytes_max = 64 * PAGE_SIZE,
+ .buffer_bytes_max = 256 * PAGE_SIZE
+};
+
+/*
+ * uni_reader_irq_handler
+ * In case of error audio stream is stopped; stop action is protected via PCM
+ * stream lock to avoid race condition with trigger callback.
+ */
+static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)
+{
+ irqreturn_t ret = IRQ_NONE;
+ struct uniperif *reader = dev_id;
+ unsigned int status;
+
+ if (reader->state == UNIPERIF_STATE_STOPPED) {
+ /* Unexpected IRQ: do nothing */
+ dev_warn(reader->dev, "unexpected IRQ ");
+ return IRQ_HANDLED;
+ }
+
+ /* Get interrupt status & clear them immediately */
+ status = GET_UNIPERIF_ITS(reader);
+ SET_UNIPERIF_ITS_BCLR(reader, status);
+
+ /* Check for fifo overflow error */
+ if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) {
+ dev_err(reader->dev, "FIFO error detected");
+
+ snd_pcm_stream_lock(reader->substream);
+ snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock(reader->substream);
+
+ return IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static int uni_reader_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *reader = priv->dai_data.uni;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int transfer_size, trigger_limit;
+ int slot_width;
+ int count = 10;
+
+ /* The reader should be stopped */
+ if (reader->state != UNIPERIF_STATE_STOPPED) {
+ dev_err(reader->dev, "%s: invalid reader state %d", __func__,
+ reader->state);
+ return -EINVAL;
+ }
+
+ /* Calculate transfer size (in fifo cells and bytes) for frame count */
+ transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES;
+
+ /* Calculate number of empty cells available before asserting DREQ */
+ if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
+ trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size;
+ else
+ /*
+ * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0
+ * FDMA_TRIGGER_LIMIT also controls when the state switches
+ * from OFF or STANDBY to AUDIO DATA.
+ */
+ trigger_limit = transfer_size;
+
+ /* Trigger limit must be an even number */
+ if ((!trigger_limit % 2) ||
+ (trigger_limit != 1 && transfer_size % 2) ||
+ (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) {
+ dev_err(reader->dev, "invalid trigger limit %d", trigger_limit);
+ return -EINVAL;
+ }
+
+ SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit);
+
+ switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ case SND_SOC_DAIFMT_NB_IF:
+ SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader);
+ break;
+ default:
+ SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader);
+ }
+
+ /* Force slot width to 32 in I2S mode */
+ if ((reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK)
+ == SND_SOC_DAIFMT_I2S) {
+ slot_width = 32;
+ } else {
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ slot_width = 16;
+ break;
+ default:
+ slot_width = 32;
+ break;
+ }
+ }
+
+ /* Number of bits per subframe (i.e one channel sample) on input. */
+ switch (slot_width) {
+ case 32:
+ SET_UNIPERIF_I2S_FMT_NBIT_32(reader);
+ SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(reader);
+ break;
+ case 16:
+ SET_UNIPERIF_I2S_FMT_NBIT_16(reader);
+ SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(reader);
+ break;
+ default:
+ dev_err(reader->dev, "subframe format not supported");
+ return -EINVAL;
+ }
+
+ /* Configure data memory format */
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ /* One data word contains two samples */
+ SET_UNIPERIF_CONFIG_MEM_FMT_16_16(reader);
+ break;
+
+ case SNDRV_PCM_FORMAT_S32_LE:
+ /*
+ * Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits
+ * on the MSB then zeros (if less than 32 bytes)"...
+ */
+ SET_UNIPERIF_CONFIG_MEM_FMT_16_0(reader);
+ break;
+
+ default:
+ dev_err(reader->dev, "format not supported");
+ return -EINVAL;
+ }
+
+ switch (reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader);
+ SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(reader);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader);
+ SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader);
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(reader);
+ SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader);
+ break;
+ default:
+ dev_err(reader->dev, "format not supported");
+ return -EINVAL;
+ }
+
+ SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader);
+
+ /* Data clocking (changing) on the rising edge */
+ SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader);
+
+ /* Number of channels must be even */
+
+ if ((runtime->channels % 2) || (runtime->channels < 2) ||
+ (runtime->channels > 10)) {
+ dev_err(reader->dev, "%s: invalid nb of channels", __func__);
+ return -EINVAL;
+ }
+
+ SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2);
+
+ /* Clear any pending interrupts */
+ SET_UNIPERIF_ITS_BCLR(reader, GET_UNIPERIF_ITS(reader));
+
+ SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(reader, 0);
+
+ /* Set the interrupt mask */
+ SET_UNIPERIF_ITM_BSET_DMA_ERROR(reader);
+ SET_UNIPERIF_ITM_BSET_FIFO_ERROR(reader);
+ SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(reader);
+
+ /* Enable underflow recovery interrupts */
+ if (reader->info->underflow_enabled) {
+ SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(reader);
+ SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(reader);
+ }
+
+ /* Reset uniperipheral reader */
+ SET_UNIPERIF_SOFT_RST_SOFT_RST(reader);
+
+ while (GET_UNIPERIF_SOFT_RST_SOFT_RST(reader)) {
+ udelay(5);
+ count--;
+ }
+ if (!count) {
+ dev_err(reader->dev, "Failed to reset uniperif");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int uni_reader_start(struct uniperif *reader)
+{
+ /* The reader should be stopped */
+ if (reader->state != UNIPERIF_STATE_STOPPED) {
+ dev_err(reader->dev, "%s: invalid reader state", __func__);
+ return -EINVAL;
+ }
+
+ /* Enable reader interrupts (and clear possible stalled ones) */
+ SET_UNIPERIF_ITS_BCLR_FIFO_ERROR(reader);
+ SET_UNIPERIF_ITM_BSET_FIFO_ERROR(reader);
+
+ /* Launch the reader */
+ SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(reader);
+
+ /* Update state to started */
+ reader->state = UNIPERIF_STATE_STARTED;
+ return 0;
+}
+
+static int uni_reader_stop(struct uniperif *reader)
+{
+ /* The reader should not be in stopped state */
+ if (reader->state == UNIPERIF_STATE_STOPPED) {
+ dev_err(reader->dev, "%s: invalid reader state", __func__);
+ return -EINVAL;
+ }
+
+ /* Turn the reader off */
+ SET_UNIPERIF_CTRL_OPERATION_OFF(reader);
+
+ /* Disable interrupts */
+ SET_UNIPERIF_ITM_BCLR(reader, GET_UNIPERIF_ITM(reader));
+
+ /* Update state to stopped and return */
+ reader->state = UNIPERIF_STATE_STOPPED;
+
+ return 0;
+}
+
+static int uni_reader_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *reader = priv->dai_data.uni;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ return uni_reader_start(reader);
+ case SNDRV_PCM_TRIGGER_STOP:
+ return uni_reader_stop(reader);
+ default:
+ return -EINVAL;
+ }
+}
+
+static void uni_reader_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
+ struct uniperif *reader = priv->dai_data.uni;
+
+ if (reader->state != UNIPERIF_STATE_STOPPED) {
+ /* Stop the reader */
+ uni_reader_stop(reader);
+ }
+}
+
+static int uni_reader_parse_dt(struct platform_device *pdev,
+ struct uniperif *reader)
+{
+ struct uniperif_info *info;
+ struct device_node *node = pdev->dev.of_node;
+
+ /* Allocate memory for the info structure */
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ of_property_read_u32(node, "version", &reader->ver);
+
+ /* Save the info structure */
+ reader->info = info;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops uni_reader_dai_ops = {
+ .shutdown = uni_reader_shutdown,
+ .prepare = uni_reader_prepare,
+ .trigger = uni_reader_trigger,
+ .hw_params = sti_uniperiph_dai_hw_params,
+ .set_fmt = sti_uniperiph_dai_set_fmt,
+};
+
+int uni_reader_init(struct platform_device *pdev,
+ struct uniperif *reader)
+{
+ int ret = 0;
+
+ reader->dev = &pdev->dev;
+ reader->state = UNIPERIF_STATE_STOPPED;
+ reader->hw = &uni_reader_pcm_hw;
+ reader->dai_ops = &uni_reader_dai_ops;
+
+ dev_err(reader->dev, "%s: enter\n", __func__);
+ ret = uni_reader_parse_dt(pdev, reader);
+ if (ret < 0) {
+ dev_err(reader->dev, "Failed to parse DeviceTree");
+ return ret;
+ }
+
+ ret = devm_request_irq(&pdev->dev, reader->irq,
+ uni_reader_irq_handler, IRQF_SHARED,
+ dev_name(&pdev->dev), reader);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to request IRQ");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uni_reader_init);
diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c
index f52600b..89add13 100644
--- a/sound/soc/tegra/tegra20_das.c
+++ b/sound/soc/tegra/tegra20_das.c
@@ -133,7 +133,7 @@ static const struct regmap_config tegra20_das_regmap_config = {
static int tegra20_das_probe(struct platform_device *pdev)
{
- struct resource *res, *region;
+ struct resource *res;
void __iomem *regs;
int ret = 0;
@@ -149,24 +149,9 @@ static int tegra20_das_probe(struct platform_device *pdev)
das->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "No memory resource\n");
- ret = -ENODEV;
- goto err;
- }
-
- region = devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), pdev->name);
- if (!region) {
- dev_err(&pdev->dev, "Memory region already claimed\n");
- ret = -EBUSY;
- goto err;
- }
-
- regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!regs) {
- dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
+ regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(regs)) {
+ ret = PTR_ERR(regs);
goto err;
}
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 05f1c6e..14106fa 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -339,7 +339,7 @@ static const struct regmap_config tegra20_i2s_regmap_config = {
static int tegra20_i2s_platform_probe(struct platform_device *pdev)
{
struct tegra20_i2s *i2s;
- struct resource *mem, *memregion;
+ struct resource *mem;
void __iomem *regs;
int ret;
@@ -362,24 +362,9 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "No memory resource\n");
- ret = -ENODEV;
- goto err_clk_put;
- }
-
- memregion = devm_request_mem_region(&pdev->dev, mem->start,
- resource_size(mem), DRV_NAME);
- if (!memregion) {
- dev_err(&pdev->dev, "Memory region already claimed\n");
- ret = -EBUSY;
- goto err_clk_put;
- }
-
- regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
- if (!regs) {
- dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
+ regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(regs)) {
+ ret = PTR_ERR(regs);
goto err_clk_put;
}
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index 9141477..a0c3640 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -265,7 +265,7 @@ static const struct regmap_config tegra20_spdif_regmap_config = {
static int tegra20_spdif_platform_probe(struct platform_device *pdev)
{
struct tegra20_spdif *spdif;
- struct resource *mem, *memregion, *dmareq;
+ struct resource *mem, *dmareq;
void __iomem *regs;
int ret;
@@ -273,45 +273,26 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!spdif) {
dev_err(&pdev->dev, "Can't allocate tegra20_spdif\n");
- ret = -ENOMEM;
- goto err;
+ return -ENOMEM;
}
dev_set_drvdata(&pdev->dev, spdif);
- spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out");
+ spdif->clk_spdif_out = devm_clk_get(&pdev->dev, "spdif_out");
if (IS_ERR(spdif->clk_spdif_out)) {
pr_err("Can't retrieve spdif clock\n");
ret = PTR_ERR(spdif->clk_spdif_out);
- goto err;
+ return ret;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "No memory resource\n");
- ret = -ENODEV;
- goto err_clk_put;
- }
+ regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!dmareq) {
dev_err(&pdev->dev, "No DMA resource\n");
- ret = -ENODEV;
- goto err_clk_put;
- }
-
- memregion = devm_request_mem_region(&pdev->dev, mem->start,
- resource_size(mem), DRV_NAME);
- if (!memregion) {
- dev_err(&pdev->dev, "Memory region already claimed\n");
- ret = -EBUSY;
- goto err_clk_put;
- }
-
- regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
- if (!regs) {
- dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
- goto err_clk_put;
+ return -ENODEV;
}
spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
@@ -319,7 +300,7 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
if (IS_ERR(spdif->regmap)) {
dev_err(&pdev->dev, "regmap init failed\n");
ret = PTR_ERR(spdif->regmap);
- goto err_clk_put;
+ return ret;
}
spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT;
@@ -335,7 +316,7 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
}
ret = snd_soc_register_component(&pdev->dev, &tegra20_spdif_component,
- &tegra20_spdif_dai, 1);
+ &tegra20_spdif_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
ret = -ENOMEM;
@@ -357,16 +338,12 @@ err_suspend:
tegra20_spdif_runtime_suspend(&pdev->dev);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
-err_clk_put:
- clk_put(spdif->clk_spdif_out);
-err:
+
return ret;
}
static int tegra20_spdif_platform_remove(struct platform_device *pdev)
{
- struct tegra20_spdif *spdif = dev_get_drvdata(&pdev->dev);
-
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
tegra20_spdif_runtime_suspend(&pdev->dev);
@@ -374,8 +351,6 @@ static int tegra20_spdif_platform_remove(struct platform_device *pdev)
tegra_pcm_platform_unregister(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
- clk_put(spdif->clk_spdif_out);
-
return 0;
}
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index bc94e5d..fef3b9a 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -521,7 +521,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
const struct tegra30_ahub_soc_data *soc_data;
struct reset_control *rst;
int i;
- struct resource *res0, *res1, *region;
+ struct resource *res0, *res1;
void __iomem *regs_apbif, *regs_ahub;
int ret = 0;
@@ -549,103 +549,67 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Can't get reset %s\n",
configlink_mods[i].rst_name);
ret = PTR_ERR(rst);
- goto err;
+ return ret;
}
ret = reset_control_deassert(rst);
reset_control_put(rst);
if (ret)
- goto err;
+ return ret;
}
ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
GFP_KERNEL);
if (!ahub) {
dev_err(&pdev->dev, "Can't allocate tegra30_ahub\n");
- ret = -ENOMEM;
- goto err;
+ return -ENOMEM;
}
dev_set_drvdata(&pdev->dev, ahub);
ahub->soc_data = soc_data;
ahub->dev = &pdev->dev;
- ahub->clk_d_audio = clk_get(&pdev->dev, "d_audio");
+ ahub->clk_d_audio = devm_clk_get(&pdev->dev, "d_audio");
if (IS_ERR(ahub->clk_d_audio)) {
dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n");
ret = PTR_ERR(ahub->clk_d_audio);
- goto err;
+ return ret;
}
- ahub->clk_apbif = clk_get(&pdev->dev, "apbif");
+ ahub->clk_apbif = devm_clk_get(&pdev->dev, "apbif");
if (IS_ERR(ahub->clk_apbif)) {
dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n");
ret = PTR_ERR(ahub->clk_apbif);
- goto err_clk_put_d_audio;
+ return ret;
}
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res0) {
- dev_err(&pdev->dev, "No apbif memory resource\n");
- ret = -ENODEV;
- goto err_clk_put_apbif;
- }
+ regs_apbif = devm_ioremap_resource(&pdev->dev, res0);
+ if (IS_ERR(regs_apbif))
+ return PTR_ERR(regs_apbif);
- region = devm_request_mem_region(&pdev->dev, res0->start,
- resource_size(res0), DRV_NAME);
- if (!region) {
- dev_err(&pdev->dev, "request region apbif failed\n");
- ret = -EBUSY;
- goto err_clk_put_apbif;
- }
ahub->apbif_addr = res0->start;
- regs_apbif = devm_ioremap(&pdev->dev, res0->start,
- resource_size(res0));
- if (!regs_apbif) {
- dev_err(&pdev->dev, "ioremap apbif failed\n");
- ret = -ENOMEM;
- goto err_clk_put_apbif;
- }
-
ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif,
&tegra30_ahub_apbif_regmap_config);
if (IS_ERR(ahub->regmap_apbif)) {
dev_err(&pdev->dev, "apbif regmap init failed\n");
ret = PTR_ERR(ahub->regmap_apbif);
- goto err_clk_put_apbif;
+ return ret;
}
regcache_cache_only(ahub->regmap_apbif, true);
res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res1) {
- dev_err(&pdev->dev, "No ahub memory resource\n");
- ret = -ENODEV;
- goto err_clk_put_apbif;
- }
-
- region = devm_request_mem_region(&pdev->dev, res1->start,
- resource_size(res1), DRV_NAME);
- if (!region) {
- dev_err(&pdev->dev, "request region ahub failed\n");
- ret = -EBUSY;
- goto err_clk_put_apbif;
- }
-
- regs_ahub = devm_ioremap(&pdev->dev, res1->start,
- resource_size(res1));
- if (!regs_ahub) {
- dev_err(&pdev->dev, "ioremap ahub failed\n");
- ret = -ENOMEM;
- goto err_clk_put_apbif;
- }
+ regs_ahub = devm_ioremap_resource(&pdev->dev, res1);
+ if (IS_ERR(regs_ahub))
+ return PTR_ERR(regs_ahub);
ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub,
&tegra30_ahub_ahub_regmap_config);
if (IS_ERR(ahub->regmap_ahub)) {
dev_err(&pdev->dev, "ahub regmap init failed\n");
ret = PTR_ERR(ahub->regmap_ahub);
- goto err_clk_put_apbif;
+ return ret;
}
regcache_cache_only(ahub->regmap_ahub, true);
@@ -662,12 +626,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
err_pm_disable:
pm_runtime_disable(&pdev->dev);
-err_clk_put_apbif:
- clk_put(ahub->clk_apbif);
-err_clk_put_d_audio:
- clk_put(ahub->clk_d_audio);
- ahub = NULL;
-err:
+
return ret;
}
@@ -680,11 +639,6 @@ static int tegra30_ahub_remove(struct platform_device *pdev)
if (!pm_runtime_status_suspended(&pdev->dev))
tegra30_ahub_runtime_suspend(&pdev->dev);
- clk_put(ahub->clk_apbif);
- clk_put(ahub->clk_d_audio);
-
- ahub = NULL;
-
return 0;
}
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index fe36375..8e55583 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -379,7 +379,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
struct tegra30_i2s *i2s;
const struct of_device_id *match;
u32 cif_ids[2];
- struct resource *mem, *memregion;
+ struct resource *mem;
void __iomem *regs;
int ret;
@@ -419,24 +419,9 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "No memory resource\n");
- ret = -ENODEV;
- goto err_clk_put;
- }
-
- memregion = devm_request_mem_region(&pdev->dev, mem->start,
- resource_size(mem), DRV_NAME);
- if (!memregion) {
- dev_err(&pdev->dev, "Memory region already claimed\n");
- ret = -EBUSY;
- goto err_clk_put;
- }
-
- regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
- if (!regs) {
- dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
+ regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(regs)) {
+ ret = PTR_ERR(regs);
goto err_clk_put;
}
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
index 88eacfd..a8f705b 100644
--- a/sound/soc/txx9/txx9aclc.c
+++ b/sound/soc/txx9/txx9aclc.c
@@ -411,13 +411,8 @@ static struct snd_soc_platform_driver txx9aclc_soc_platform = {
static int txx9aclc_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&pdev->dev, &txx9aclc_soc_platform);
-}
-
-static int txx9aclc_soc_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
+ return devm_snd_soc_register_platform(&pdev->dev,
+ &txx9aclc_soc_platform);
}
static struct platform_driver txx9aclc_pcm_driver = {
@@ -426,7 +421,6 @@ static struct platform_driver txx9aclc_pcm_driver = {
},
.probe = txx9aclc_soc_platform_probe,
- .remove = txx9aclc_soc_platform_remove,
};
module_platform_driver(txx9aclc_pcm_driver);
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index 978f2d7..f5df08d 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -773,20 +773,22 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
}
prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50);
- drvdata->pclk = clk_get(&pdev->dev, "apb_pclk");
+ drvdata->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
if (IS_ERR(drvdata->pclk)) {
ret = (int)PTR_ERR(drvdata->pclk);
- dev_err(&pdev->dev, "%s: ERROR: clk_get of pclk failed (%d)!\n",
+ dev_err(&pdev->dev,
+ "%s: ERROR: devm_clk_get of pclk failed (%d)!\n",
__func__, ret);
- goto err_pclk;
+ return ret;
}
- drvdata->clk = clk_get(&pdev->dev, NULL);
+ drvdata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(drvdata->clk)) {
ret = (int)PTR_ERR(drvdata->clk);
- dev_err(&pdev->dev, "%s: ERROR: clk_get failed (%d)!\n",
+ dev_err(&pdev->dev,
+ "%s: ERROR: devm_clk_get failed (%d)!\n",
__func__, ret);
- goto err_clk;
+ return ret;
}
ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp,
@@ -795,7 +797,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"%s: ERROR: Failed to init MSP-struct (%d)!",
__func__, ret);
- goto err_init_msp;
+ return ret;
}
dev_set_drvdata(&pdev->dev, drvdata);
@@ -804,7 +806,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n",
__func__, drvdata->msp->id);
- goto err_init_msp;
+ return ret;
}
ret = ux500_pcm_register_platform(pdev);
@@ -819,13 +821,6 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
err_reg_plat:
snd_soc_unregister_component(&pdev->dev);
-err_init_msp:
- clk_put(drvdata->clk);
-err_clk:
- clk_put(drvdata->pclk);
-err_pclk:
- devm_regulator_put(drvdata->reg_vape);
-
return ret;
}
@@ -837,12 +832,8 @@ static int ux500_msp_drv_remove(struct platform_device *pdev)
snd_soc_unregister_component(&pdev->dev);
- devm_regulator_put(drvdata->reg_vape);
prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");
- clk_put(drvdata->clk);
- clk_put(drvdata->pclk);
-
ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp);
return 0;
diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c
index 1cfb19e..8382ffa 100644
--- a/sound/soc/xtensa/xtfpga-i2s.c
+++ b/sound/soc/xtensa/xtfpga-i2s.c
@@ -75,7 +75,7 @@ struct xtfpga_i2s {
* stream in the pcm_close callback it synchronizes with the interrupt
* handler by means of synchronize_rcu call.
*/
- struct snd_pcm_substream *tx_substream;
+ struct snd_pcm_substream __rcu *tx_substream;
unsigned (*tx_fn)(struct xtfpga_i2s *i2s,
struct snd_pcm_runtime *runtime,
unsigned tx_ptr);
@@ -474,11 +474,6 @@ static int xtfpga_pcm_new(struct snd_soc_pcm_runtime *rtd)
card->dev, size, size);
}
-static void xtfpga_pcm_free(struct snd_pcm *pcm)
-{
- snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
static const struct snd_pcm_ops xtfpga_pcm_ops = {
.open = xtfpga_pcm_open,
.close = xtfpga_pcm_close,
@@ -490,7 +485,6 @@ static const struct snd_pcm_ops xtfpga_pcm_ops = {
static const struct snd_soc_platform_driver xtfpga_soc_platform = {
.pcm_new = xtfpga_pcm_new,
- .pcm_free = xtfpga_pcm_free,
.ops = &xtfpga_pcm_ops,
};
diff --git a/sound/soc/zte/zx296702-i2s.c b/sound/soc/zte/zx296702-i2s.c
index 1930c42..1cad93d 100644
--- a/sound/soc/zte/zx296702-i2s.c
+++ b/sound/soc/zte/zx296702-i2s.c
@@ -380,7 +380,7 @@ static int zx_i2s_probe(struct platform_device *pdev)
struct zx_i2s_info *zx_i2s;
int ret;
- zx_i2s = kzalloc(sizeof(*zx_i2s), GFP_KERNEL);
+ zx_i2s = devm_kzalloc(&pdev->dev, sizeof(*zx_i2s), GFP_KERNEL);
if (!zx_i2s)
return -ENOMEM;
@@ -401,8 +401,8 @@ static int zx_i2s_probe(struct platform_device *pdev)
writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL);
platform_set_drvdata(pdev, zx_i2s);
- ret = snd_soc_register_component(&pdev->dev, &zx_i2s_component,
- &zx_i2s_dai, 1);
+ ret = devm_snd_soc_register_component(&pdev->dev, &zx_i2s_component,
+ &zx_i2s_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
return ret;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index de165a1..20b56eb 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -521,6 +521,15 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
goto out_child;
}
+ /*
+ * Normally perf_session__new would do this, but it doesn't have the
+ * evlist.
+ */
+ if (rec->tool.ordered_events && !perf_evlist__sample_id_all(rec->evlist)) {
+ pr_warning("WARNING: No sample_id_all support, falling back to unordered processing\n");
+ rec->tool.ordered_events = false;
+ }
+
if (!rec->evlist->nr_groups)
perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
@@ -965,9 +974,11 @@ static struct record record = {
.tool = {
.sample = process_sample_event,
.fork = perf_event__process_fork,
+ .exit = perf_event__process_exit,
.comm = perf_event__process_comm,
.mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2,
+ .ordered_events = true,
},
};
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ecf3197..6135cc0 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -601,8 +601,8 @@ static void display_sig(int sig __maybe_unused)
static void display_setup_sig(void)
{
- signal(SIGSEGV, display_sig);
- signal(SIGFPE, display_sig);
+ signal(SIGSEGV, sighandler_dump_stack);
+ signal(SIGFPE, sighandler_dump_stack);
signal(SIGINT, display_sig);
signal(SIGQUIT, display_sig);
signal(SIGTERM, display_sig);
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 094ddae..d31fac1 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -638,7 +638,7 @@ ifndef DESTDIR
prefix ?= $(HOME)
endif
bindir_relative = bin
-bindir = $(prefix)/$(bindir_relative)
+bindir = $(abspath $(prefix)/$(bindir_relative))
mandir = share/man
infodir = share/info
perfexecdir = libexec/perf-core
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 7ff6827..f1a4c83 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1387,6 +1387,24 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
event->fork.ptid);
int err = 0;
+ if (dump_trace)
+ perf_event__fprintf_task(event, stdout);
+
+ /*
+ * There may be an existing thread that is not actually the parent,
+ * either because we are processing events out of order, or because the
+ * (fork) event that would have removed the thread was lost. Assume the
+ * latter case and continue on as best we can.
+ */
+ if (parent->pid_ != (pid_t)event->fork.ppid) {
+ dump_printf("removing erroneous parent thread %d/%d\n",
+ parent->pid_, parent->tid);
+ machine__remove_thread(machine, parent);
+ thread__put(parent);
+ parent = machine__findnew_thread(machine, event->fork.ppid,
+ event->fork.ptid);
+ }
+
/* if a thread currently exists for the thread id remove it */
if (thread != NULL) {
machine__remove_thread(machine, thread);
@@ -1395,8 +1413,6 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
thread = machine__findnew_thread(machine, event->fork.pid,
event->fork.tid);
- if (dump_trace)
- perf_event__fprintf_task(event, stdout);
if (thread == NULL || parent == NULL ||
thread__fork(thread, parent, sample->time) < 0) {
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 53e8bb7..2a5d8d7 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -85,7 +85,7 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
update_stats(&runtime_cycles_stats[ctx][cpu], count[0]);
else if (perf_stat_evsel__is(counter, CYCLES_IN_TX))
- update_stats(&runtime_transaction_stats[ctx][cpu], count[0]);
+ update_stats(&runtime_cycles_in_tx_stats[ctx][cpu], count[0]);
else if (perf_stat_evsel__is(counter, TRANSACTION_START))
update_stats(&runtime_transaction_stats[ctx][cpu], count[0]);
else if (perf_stat_evsel__is(counter, ELISION_START))
@@ -398,20 +398,18 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
" # %5.2f%% aborted cycles ",
100.0 * ((total2-avg) / total));
} else if (perf_stat_evsel__is(evsel, TRANSACTION_START) &&
- avg > 0 &&
runtime_cycles_in_tx_stats[ctx][cpu].n != 0) {
total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
- if (total)
+ if (avg)
ratio = total / avg;
fprintf(out, " # %8.0f cycles / transaction ", ratio);
} else if (perf_stat_evsel__is(evsel, ELISION_START) &&
- avg > 0 &&
runtime_cycles_in_tx_stats[ctx][cpu].n != 0) {
total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
- if (total)
+ if (avg)
ratio = total / avg;
fprintf(out, " # %8.0f cycles / elision ", ratio);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 28c4b74..0a9ae80 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -191,6 +191,12 @@ static int thread__clone_map_groups(struct thread *thread,
if (thread->pid_ == parent->pid_)
return 0;
+ if (thread->mg == parent->mg) {
+ pr_debug("broken map groups on thread %d/%d parent %d/%d\n",
+ thread->pid_, thread->tid, parent->pid_, parent->tid);
+ return 0;
+ }
+
/* But this one is new process, copy maps. */
for (i = 0; i < MAP__NR_TYPES; ++i)
if (map_groups__clone(thread->mg, parent->mg, i) < 0)
OpenPOWER on IntegriCloud