Merge remote-tracking branches 'asoc/topic/tas2552', 'asoc/topic/tas5086', 'asoc...
authorMark Brown <broonie@kernel.org>
Sun, 30 Aug 2015 14:57:34 +0000 (15:57 +0100)
committerMark Brown <broonie@kernel.org>
Sun, 30 Aug 2015 14:57:34 +0000 (15:57 +0100)
547 files changed:
.get_maintainer.ignore [new file with mode: 0644]
.mailmap
Documentation/DocBook/alsa-driver-api.tmpl
Documentation/devicetree/bindings/arm/cpus.txt
Documentation/devicetree/bindings/sound/cs4349.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/ics43432.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/max98357a.txt
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
Documentation/devicetree/bindings/sound/rockchip-max98090.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rockchip-rt5645.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt [new file with mode: 0644]
Documentation/devicetree/bindings/vendor-prefixes.txt
MAINTAINERS
Makefile
arch/arm/Makefile
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/imx6qdl.dtsi
arch/arm/boot/dts/k2e.dtsi
arch/arm/boot/dts/k2hk.dtsi
arch/arm/boot/dts/k2l.dtsi
arch/arm/boot/dts/keystone.dtsi
arch/arm/boot/dts/omap2430.dtsi
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/ste-dbx5x0.dtsi
arch/arm/kernel/entry-common.S
arch/arm/kernel/head.S
arch/arm/kernel/vdso.c
arch/arm/lib/uaccess_with_memcpy.c
arch/arm/mach-exynos/pm_domains.c
arch/arm/mach-omap2/omap-wakeupgen.c
arch/arm/vdso/Makefile
arch/arm64/kernel/vdso.c
arch/mips/kernel/genex.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/x86/entry/entry_64_compat.S
arch/x86/include/asm/sigcontext.h
arch/x86/include/asm/switch_to.h
arch/x86/include/uapi/asm/sigcontext.h
arch/x86/kernel/apic/vector.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_cqm.c
arch/x86/kernel/fpu/core.c
arch/x86/kernel/fpu/init.c
arch/x86/kernel/process.c
arch/x86/kernel/signal.c
arch/x86/kernel/step.c
arch/x86/kvm/x86.c
arch/x86/math-emu/fpu_entry.c
arch/x86/math-emu/fpu_system.h
arch/x86/math-emu/get_address.c
arch/x86/xen/Kconfig
arch/x86/xen/Makefile
arch/x86/xen/xen-ops.h
block/blk-settings.c
crypto/authencesn.c
drivers/acpi/video_detect.c
drivers/ata/ahci_brcmstb.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/libata.h
drivers/ata/sata_sx4.c
drivers/base/regmap/internal.h
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regmap.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkfront.c
drivers/block/zram/zram_drv.c
drivers/clk/pxa/clk-pxa3xx.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/timer-imx-gpt.c
drivers/cpufreq/exynos-cpufreq.c
drivers/crypto/caam/caamhash.c
drivers/crypto/nx/nx-sha256.c
drivers/crypto/nx/nx-sha512.c
drivers/dma/dmaengine.c
drivers/edac/ppc4xx_edac.c
drivers/firmware/broadcom/bcm47xx_nvram.c
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/exynos/exynos_drm_fimc.c
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i2c/adv7511.c
drivers/gpu/drm/i915/intel_atomic.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/hid/hid-input.c
drivers/hid/hid-uclogic.c
drivers/hid/wacom_sys.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/misc/drv260x.c
drivers/input/misc/drv2665.c
drivers/input/misc/drv2667.c
drivers/irqchip/irq-crossbar.c
drivers/md/dm-cache-policy-mq.c
drivers/md/dm-cache-policy-smq.c
drivers/md/dm-thin-metadata.c
drivers/md/persistent-data/dm-btree-internal.h
drivers/md/persistent-data/dm-btree-remove.c
drivers/md/persistent-data/dm-btree-spine.c
drivers/md/persistent-data/dm-btree.c
drivers/media/dvb-frontends/Kconfig
drivers/media/pci/cobalt/Kconfig
drivers/media/pci/cobalt/cobalt-irq.c
drivers/media/pci/mantis/mantis_dma.c
drivers/media/rc/ir-rc5-decoder.c
drivers/media/rc/ir-rc6-decoder.c
drivers/media/rc/nuvoton-cir.c
drivers/media/rc/nuvoton-cir.h
drivers/media/rc/rc-core-priv.h
drivers/media/rc/rc-ir-raw.c
drivers/media/rc/rc-loopback.c
drivers/media/rc/rc-main.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/memory/omap-gpmc.c
drivers/mfd/Kconfig
drivers/mfd/arizona-core.c
drivers/mfd/twl6040.c
drivers/mfd/wm5102-tables.c
drivers/mfd/wm5110-tables.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8997-tables.c
drivers/net/bonding/bond_main.c
drivers/net/ethernet/3com/3c59x.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/brocade/bna/bnad.c
drivers/net/ethernet/cavium/Kconfig
drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
drivers/net/ethernet/freescale/fs_enet/mac-fec.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar_ethtool.c
drivers/net/ethernet/intel/fm10k/fm10k_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/marvell/mvpp2.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/micrel/ks8842.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/rocker/rocker.c
drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
drivers/net/ethernet/ti/netcp.h
drivers/net/ethernet/ti/netcp_core.c
drivers/net/hamradio/mkiss.c
drivers/net/ntb_netdev.c
drivers/net/phy/phy.c
drivers/net/phy/smsc.c
drivers/net/ppp/ppp_generic.c
drivers/net/usb/qmi_wwan.c
drivers/net/virtio_net.c
drivers/net/wan/cosa.c
drivers/net/wireless/b43/tables_nphy.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
drivers/net/wireless/rsi/rsi_91x_usb_ops.c
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/rtl8723be/sw.c
drivers/net/xen-netback/interface.c
drivers/net/xen-netback/netback.c
drivers/ntb/ntb.c
drivers/ntb/ntb_transport.c
drivers/pci/Kconfig
drivers/pci/probe.c
drivers/platform/chrome/Kconfig
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libiscsi.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_pm.c
drivers/scsi/sd.c
drivers/target/iscsi/iscsi_target.c
drivers/target/target_core_configfs.c
drivers/target/target_core_hba.c
drivers/target/target_core_spc.c
drivers/thermal/cpu_cooling.c
drivers/thermal/power_allocator.c
drivers/video/console/fbcon.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/omap2/dss/dss-of.c
drivers/video/fbdev/pxa3xx-gcu.c
drivers/video/of_videomode.c
drivers/xen/events/events_base.c
drivers/xen/events/events_fifo.c
drivers/xen/events/events_internal.h
drivers/xen/xenbus/xenbus_client.c
fs/fuse/dev.c
fs/namei.c
include/drm/drm_crtc.h
include/drm/drm_edid.h
include/drm/drm_pciids.h
include/linux/ata.h
include/linux/irq.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/regmap.h
include/linux/skbuff.h
include/media/rc-core.h
include/media/videobuf2-core.h
include/scsi/scsi_eh.h
include/sound/ac97_codec.h
include/sound/rcar_snd.h
include/sound/rt298.h [new file with mode: 0644]
include/sound/soc-dapm.h
include/sound/soc-topology.h
include/sound/soc.h
include/trace/events/asoc.h
include/uapi/sound/asoc.h
ipc/sem.c
kernel/cpuset.c
kernel/events/core.c
kernel/events/ring_buffer.c
kernel/irq/chip.c
kernel/locking/qspinlock_paravirt.h
kernel/time/timer.c
mm/cma.h
mm/kasan/kasan.c
mm/kasan/report.c
mm/memory-failure.c
mm/memory_hotplug.c
mm/page_alloc.c
mm/slab.c
mm/slub.c
net/9p/client.c
net/batman-adv/distributed-arp-table.c
net/batman-adv/gateway_client.c
net/batman-adv/soft-interface.c
net/batman-adv/translation-table.c
net/bluetooth/mgmt.c
net/bridge/br_multicast.c
net/bridge/br_netlink.c
net/core/datagram.c
net/core/pktgen.c
net/core/request_sock.c
net/core/skbuff.c
net/dsa/slave.c
net/ipv4/fib_trie.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/netfilter/ipt_SYNPROXY.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/ip6_fib.c
net/ipv6/mcast_snoop.c
net/ipv6/netfilter/ip6t_SYNPROXY.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/mac80211/rc80211_minstrel.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_synproxy_core.c
net/netfilter/xt_CT.c
net/netlink/af_netlink.c
net/openvswitch/actions.c
net/rds/info.c
net/sched/act_mirred.c
net/sched/sch_fq_codel.c
scripts/kconfig/streamline_config.pl
sound/ac97_bus.c
sound/pci/hda/patch_realtek.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/au1x/dbdma2.c
sound/soc/au1x/dma.c
sound/soc/au1x/psc-i2s.c
sound/soc/bcm/bcm2835-i2s.c
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-i2s-pcm.c
sound/soc/blackfin/bfin-eval-adau1x61.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/adau1373.c
sound/soc/codecs/adau1701.c
sound/soc/codecs/adau1761-i2c.c
sound/soc/codecs/adau1781-i2c.c
sound/soc/codecs/adau1977-i2c.c
sound/soc/codecs/adav803.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/ak4642.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/alc5623.c
sound/soc/codecs/alc5632.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs35l32.c
sound/soc/codecs/cs35l32.h
sound/soc/codecs/cs4265.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs4271-i2c.c
sound/soc/codecs/cs42l51-i2c.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l56.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/cs42xx8-i2c.c
sound/soc/codecs/cs42xx8.c
sound/soc/codecs/cs42xx8.h
sound/soc/codecs/cs4349.c [new file with mode: 0644]
sound/soc/codecs/cs4349.h [new file with mode: 0644]
sound/soc/codecs/da7210.c
sound/soc/codecs/da7213.c
sound/soc/codecs/da732x.c
sound/soc/codecs/da9055.c
sound/soc/codecs/gtm601.c [new file with mode: 0644]
sound/soc/codecs/ics43432.c [new file with mode: 0644]
sound/soc/codecs/isabelle.c
sound/soc/codecs/jz4740.c
sound/soc/codecs/lm4857.c
sound/soc/codecs/lm49453.c
sound/soc/codecs/max9768.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98088.h
sound/soc/codecs/max98090.c
sound/soc/codecs/max98090.h
sound/soc/codecs/max98095.c
sound/soc/codecs/max98357a.c
sound/soc/codecs/max9850.c
sound/soc/codecs/max9877.c
sound/soc/codecs/max98925.c
sound/soc/codecs/mc13783.c
sound/soc/codecs/ml26124.c
sound/soc/codecs/pcm1681.c
sound/soc/codecs/pcm512x-i2c.c
sound/soc/codecs/rl6231.c
sound/soc/codecs/rl6231.h
sound/soc/codecs/rt286.c
sound/soc/codecs/rt298.c [new file with mode: 0644]
sound/soc/codecs/rt298.h [new file with mode: 0644]
sound/soc/codecs/rt5631.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.h
sound/soc/codecs/rt5651.c
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5677-spi.c
sound/soc/codecs/rt5677-spi.h
sound/soc/codecs/rt5677.c
sound/soc/codecs/rt5677.h
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/si476x.c
sound/soc/codecs/sirf-audio-codec.c
sound/soc/codecs/ssm2518.c
sound/soc/codecs/ssm2602-i2c.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/ssm4567.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/sta350.c
sound/soc/codecs/sta529.c
sound/soc/codecs/stac9766.c
sound/soc/codecs/sti-sas.c [new file with mode: 0644]
sound/soc/codecs/tas2552.c
sound/soc/codecs/tas2552.h
sound/soc/codecs/tas5086.c
sound/soc/codecs/tas571x.c
sound/soc/codecs/tfa9879.c
sound/soc/codecs/tlv320aic31xx.c
sound/soc/codecs/tlv320aic32x4.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/ts3a227e.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wm1250-ev1.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8711.c
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8737.c
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8804-i2c.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8983.c
sound/soc/codecs/wm8985.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8991.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm8996.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm9713.h
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-vcif.c
sound/soc/fsl/eukrea-tlv320.c
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/fsl_asrc.c
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_sai.h
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-pcm-dma.c
sound/soc/fsl/imx-pcm.h
sound/soc/fsl/imx-ssi.c
sound/soc/generic/simple-card.c
sound/soc/intel/Kconfig
sound/soc/intel/Makefile
sound/soc/intel/atom/sst-atom-controls.c
sound/soc/intel/atom/sst-mfld-platform-pcm.c
sound/soc/intel/atom/sst-mfld-platform.h
sound/soc/intel/atom/sst/sst_drv_interface.c
sound/soc/intel/atom/sst/sst_ipc.c
sound/soc/intel/boards/byt-max98090.c
sound/soc/intel/boards/byt-rt5640.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/boards/cht_bsw_rt5672.c
sound/soc/intel/common/sst-dsp-priv.h
sound/soc/intel/common/sst-dsp.c
sound/soc/intel/common/sst-dsp.h
sound/soc/intel/skylake/Makefile [new file with mode: 0644]
sound/soc/intel/skylake/skl-messages.c [new file with mode: 0644]
sound/soc/intel/skylake/skl-nhlt.c [new file with mode: 0644]
sound/soc/intel/skylake/skl-nhlt.h [new file with mode: 0644]
sound/soc/intel/skylake/skl-pcm.c [new file with mode: 0644]
sound/soc/intel/skylake/skl-sst-cldma.c [new file with mode: 0644]
sound/soc/intel/skylake/skl-sst-cldma.h [new file with mode: 0644]
sound/soc/intel/skylake/skl-sst-dsp.c [new file with mode: 0644]
sound/soc/intel/skylake/skl-sst-dsp.h [new file with mode: 0644]
sound/soc/intel/skylake/skl-sst-ipc.c [new file with mode: 0644]
sound/soc/intel/skylake/skl-sst-ipc.h [new file with mode: 0644]
sound/soc/intel/skylake/skl-sst.c [new file with mode: 0644]
sound/soc/intel/skylake/skl-topology.h [new file with mode: 0644]
sound/soc/intel/skylake/skl-tplg-interface.h [new file with mode: 0644]
sound/soc/intel/skylake/skl.c [new file with mode: 0644]
sound/soc/intel/skylake/skl.h [new file with mode: 0644]
sound/soc/kirkwood/kirkwood-dma.c
sound/soc/mediatek/mt8173-max98090.c
sound/soc/mediatek/mt8173-rt5650-rt5676.c
sound/soc/mediatek/mtk-afe-common.h
sound/soc/mediatek/mtk-afe-pcm.c
sound/soc/nuc900/nuc900-pcm.c
sound/soc/omap/mcbsp.c
sound/soc/omap/omap-hdmi-audio.c
sound/soc/omap/omap3pandora.c
sound/soc/pxa/mmp-pcm.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/qcom/Kconfig
sound/soc/qcom/lpass-cpu.c
sound/soc/qcom/lpass-ipq806x.c
sound/soc/qcom/lpass.h
sound/soc/rockchip/Kconfig
sound/soc/rockchip/Makefile
sound/soc/rockchip/rockchip_i2s.c
sound/soc/rockchip/rockchip_max98090.c [new file with mode: 0644]
sound/soc/rockchip/rockchip_rt5645.c [new file with mode: 0644]
sound/soc/samsung/arndale_rt5631.c
sound/soc/samsung/snow.c
sound/soc/sh/dma-sh7760.c
sound/soc/sh/fsi.c
sound/soc/sh/rcar/Makefile
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/ctu.c [new file with mode: 0644]
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/mix.c [new file with mode: 0644]
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/rsrc-card.c
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sh/ssi.c
sound/soc/soc-ac97.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/spear/spdif_in.c
sound/soc/spear/spear_pcm.c
sound/soc/sti/Kconfig [new file with mode: 0644]
sound/soc/sti/Makefile [new file with mode: 0644]
sound/soc/sti/sti_uniperif.c [new file with mode: 0644]
sound/soc/sti/uniperif.h [new file with mode: 0644]
sound/soc/sti/uniperif_player.c [new file with mode: 0644]
sound/soc/sti/uniperif_reader.c [new file with mode: 0644]
sound/soc/tegra/tegra20_das.c
sound/soc/tegra/tegra20_i2s.c
sound/soc/tegra/tegra20_spdif.c
sound/soc/tegra/tegra30_ahub.c
sound/soc/tegra/tegra30_i2s.c
sound/usb/card.c
tools/perf/builtin-record.c
tools/perf/builtin-top.c
tools/perf/config/Makefile
tools/perf/util/machine.c
tools/perf/util/stat-shadow.c
tools/perf/util/thread.c

diff --git a/.get_maintainer.ignore b/.get_maintainer.ignore
new file mode 100644 (file)
index 0000000..cca6d87
--- /dev/null
@@ -0,0 +1 @@
+Christoph Hellwig <hch@lst.de>
index b4091b7..4b31af5 100644 (file)
--- 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>
index 71f9246..e94a10b 100644 (file)
      <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
index d6b794c..91e6e5c 100644 (file)
@@ -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/sound/cs4349.txt b/Documentation/devicetree/bindings/sound/cs4349.txt
new file mode 100644 (file)
index 0000000..54c117b
--- /dev/null
@@ -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 (file)
index 0000000..b02e3a6
--- /dev/null
@@ -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";
+       };
index a7a149a..28645a2 100644 (file)
@@ -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:
 
index b6b3a78..1173395 100644 (file)
@@ -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>;
index c641550..962748a 100644 (file)
@@ -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 (file)
index 0000000..a805aa9
--- /dev/null
@@ -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 (file)
index 0000000..411a62b
--- /dev/null
@@ -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 (file)
index 0000000..028fa1c
--- /dev/null
@@ -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>;
+                       };
+               };
+       };
index d444757..66a33ae 100644 (file)
@@ -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
index a9ae6c1..569568f 100644 (file)
@@ -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
index 35b4c19..246053f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 2
 SUBLEVEL = 0
-EXTRAVERSION = -rc6
+EXTRAVERSION = -rc8
 NAME = Hurr durr I'ma sheep
 
 # *DOCUMENTATION*
index 07ab3d2..7451b44 100644 (file)
@@ -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)/$@
 
index 4a0718c..1e29ccf 100644 (file)
                                ranges = <0 0x2000 0x2000>;
 
                                scm_conf: scm_conf@0 {
-                                       compatible = "syscon";
+                                       compatible = "syscon", "simple-bus";
                                        reg = <0x0 0x1400>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
index e6d1359..b57033e 100644 (file)
                        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>;
index 1b6494f..675fb8e 100644 (file)
                                        <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>;
-};
index ae64724..d0810a5 100644 (file)
                        #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"
        };
 };
index 0e00748..49fd414 100644 (file)
@@ -29,7 +29,6 @@
        };
 
        soc {
-
                /include/ "k2l-clocks.dtsi"
 
                uart2: serial@02348400 {
                        #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"
        };
 };
        /* Pin muxed. Enabled and configured by Bootloader */
        status = "disabled";
 };
-
-&mdio {
-       reg = <0x26200f00 0x100>;
-};
index e7a6f6d..72816d6 100644 (file)
                                  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>;
index 11a7963..2390f38 100644 (file)
@@ -51,7 +51,8 @@
                                };
 
                                scm_conf: scm_conf@270 {
-                                       compatible = "syscon";
+                                       compatible = "syscon",
+                                                    "simple-bus";
                                        reg = <0x270 0x240>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
index 7d31c6f..abc4473 100644 (file)
                                };
 
                                omap4_padconf_global: omap4_padconf_global@5a0 {
-                                       compatible = "syscon";
+                                       compatible = "syscon",
+                                                    "simple-bus";
                                        reg = <0x5a0 0x170>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
index c8fd648..b1a1263 100644 (file)
                                };
 
                                omap5_padconf_global: omap5_padconf_global@5a0 {
-                                       compatible = "syscon";
+                                       compatible = "syscon",
+                                                    "simple-bus";
                                        reg = <0x5a0 0xec>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
index a75f328..b8f81fb 100644 (file)
 #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>;
                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>;
index 92828a1..b48dd4f 100644 (file)
@@ -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.
index bd755d9..29e2991 100644 (file)
@@ -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
index efe17dd..54a5aea 100644 (file)
@@ -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;
 
index 3e58d71..4b39af2 100644 (file)
@@ -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);
index 6001f1c..4a87e86 100644 (file)
@@ -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;
                }
 
index 8e52621..e1d2e99 100644 (file)
@@ -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,
index 9d259d9..1160434 100644 (file)
@@ -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
index ec37ab3..97bc68f 100644 (file)
@@ -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;
 
index af42e70..baa7b6f 100644 (file)
@@ -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
index ad4d446..a6f6b76 100644 (file)
@@ -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
index 446cc65..4b20106 100644 (file)
@@ -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
index 5a18447..a7e257d 100644 (file)
@@ -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
index 6fe6b18..9dfce4e 100644 (file)
@@ -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;
index 751bf4b..d7f3b3b 100644 (file)
@@ -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 */       \
index 0e8a973..40836a9 100644 (file)
@@ -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;
index f813261..2683f36 100644 (file)
@@ -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;
index b9826a9..6326ae2 100644 (file)
@@ -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)
index 63eb68b..377e8f8 100644 (file)
@@ -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);
        }
 
index 79de954..d25097c 100644 (file)
@@ -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;
index 1e173f6..d14e9ac 100644 (file)
@@ -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");
 }
 
 /*
index 397688b..c27cad7 100644 (file)
@@ -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();
        }
index 206996c..71820c4 100644 (file)
@@ -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;
 }
index 6273324..0ccb53a 100644 (file)
@@ -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];
index 5ef2560..8f0f6ec 100644 (file)
@@ -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;
index f37e84a..3d8f2e4 100644 (file)
@@ -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 */
index 9ccecb6..5e044d5 100644 (file)
 #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)
index 6ef5e99..8300db7 100644 (file)
@@ -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
index e88fda8..4841453 100644 (file)
@@ -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
index 7322755..4b6e29a 100644 (file)
@@ -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
index c20fe29..2292721 100644 (file)
@@ -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
index 12600bf..e0057d0 100644 (file)
@@ -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
index a3da677..b8efe36 100644 (file)
@@ -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;
index 815f75e..2922f1f 100644 (file)
@@ -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)
index ce1e3a8..14b7305 100644 (file)
@@ -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),
index db5d9f7..19bcb80 100644 (file)
@@ -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;
        }
 
index 7465031..cb0508a 100644 (file)
@@ -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;
 }
@@ -1629,70 +1627,6 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
        return err_mask;
 }
 
-/**
- *     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
@@ -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 " : "");
                }
 
index 641a61a..0d7f0da 100644 (file)
@@ -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
index a998a17..f840ca1 100644 (file)
@@ -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);
index 3a18a8a..fab504f 100644 (file)
@@ -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");
index b2b2849..873ddf9 100644 (file)
@@ -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 */
index 81751a4..56486d9 100644 (file)
@@ -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 */
index 7111d04..0a849ee 100644 (file)
@@ -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,13 +2379,36 @@ 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;
 }
 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));
index ced9677..954c002 100644 (file)
@@ -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;
        }
 
index 6d89ed3..7a8a73f 100644 (file)
@@ -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)
@@ -1796,6 +1792,68 @@ out_of_memory:
        return -ENOMEM;
 }
 
+/*
+ * 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);
index fb655e8..763301c 100644 (file)
@@ -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;
 
index 4b93a1e..ac03ba4 100644 (file)
@@ -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,         \
index b8ff3c6..c96de14 100644 (file)
@@ -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);
 }
index 2d59038..86c7eb6 100644 (file)
@@ -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);
 }
index ae5b2bd..fa3dd84 100644 (file)
@@ -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 = {
index dae1e80..f9c7875 100644 (file)
@@ -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);
index 08f8d5c..becb738 100644 (file)
@@ -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;
 
                /*
index aff0fe5..b6e183d 100644 (file)
@@ -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;
 
                /*
index 4a4cce1..3ff284c 100644 (file)
@@ -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);
index 3515b38..711d8ad 100644 (file)
@@ -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
index 87add3f..e415945 100644 (file)
@@ -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");
index 2f7a5ef..f5c2255 100644 (file)
@@ -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;
index f5a42ab..20e2cfd 100644 (file)
@@ -3135,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,
index 6fad1f9..ef6182b 100644 (file)
@@ -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);
index b0487c9..eb603f1 100644 (file)
@@ -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);
 
@@ -2659,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
@@ -2668,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);
        }
 }
 
index 842d6b8..2a65235 100644 (file)
@@ -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);
index 8040ed2..f1c6b76 100644 (file)
@@ -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;
index 99e2864..4a00990 100644 (file)
@@ -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)
index cae98db..4706b56 100644 (file)
@@ -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);
 }
index 2aaa3c8..00416f2 100644 (file)
@@ -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 },
index 7ed8033..8e35e0d 100644 (file)
@@ -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);
index 3dcd59e..198fc3c 100644 (file)
@@ -1075,34 +1075,15 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
        const union child_device_config *p_child;
        union child_device_config *child_dev_ptr;
        int i, child_device_num, count;
-       u8 expected_size;
-       u16 block_size;
+       u16     block_size;
 
        p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
        if (!p_defs) {
                DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
                return;
        }
-       if (bdb->version < 195) {
-               expected_size = 33;
-       } else if (bdb->version == 195) {
-               expected_size = 37;
-       } else if (bdb->version <= 197) {
-               expected_size = 38;
-       } else {
-               expected_size = 38;
-               DRM_DEBUG_DRIVER("Expected child_device_config size for BDB version %u not known; assuming %u\n",
-                                expected_size, bdb->version);
-       }
-
-       if (expected_size > sizeof(*p_child)) {
-               DRM_ERROR("child_device_config cannot fit in p_child\n");
-               return;
-       }
-
-       if (p_defs->child_dev_size != expected_size) {
-               DRM_ERROR("Size mismatch; child_device_config size=%u (expected %u); bdb->version: %u\n",
-                         p_defs->child_dev_size, expected_size, bdb->version);
+       if (p_defs->child_dev_size < sizeof(*p_child)) {
+               DRM_ERROR("General definiton block child device size is too small.\n");
                return;
        }
        /* get the block size of general definitions */
@@ -1149,7 +1130,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
 
                child_dev_ptr = dev_priv->vbt.child_dev + count;
                count++;
-               memcpy(child_dev_ptr, p_child, p_defs->child_dev_size);
+               memcpy(child_dev_ptr, p_child, sizeof(*p_child));
        }
        return;
 }
index 30e0f54..87476ff 100644 (file)
@@ -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;
 
index 6e8faa2..1df0e1f 100644 (file)
@@ -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
index 9b74ffa..7f2161a 100644 (file)
@@ -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;
index 52c22b0..e10f964 100644 (file)
@@ -165,31 +165,15 @@ gk104_fifo_context_attach(struct nvkm_object *parent,
        return 0;
 }
 
-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);
 }
index 1162bfa..171d3e4 100644 (file)
@@ -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)
index 654c8da..97ad3bc 100644 (file)
@@ -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);
index 3511bba..e3c6364 100644 (file)
@@ -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 */
index 9416731..b905d50 100644 (file)
@@ -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;
index 44958d7..01b937e 100644 (file)
@@ -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;
index c7aab48..92d5183 100644 (file)
@@ -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:
index 097d721..c6dc644 100644 (file)
@@ -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;
index e5d60ec..f5c9cf2 100644 (file)
@@ -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 },
index 0afaa33..924456e 100644 (file)
@@ -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 },
 };
index fc0fddf..047136a 100644 (file)
@@ -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 },
index 692fe2b..c12bb93 100644 (file)
@@ -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
index 3281437..aa1b41c 100644 (file)
@@ -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");
index 48a4a82..200366c 100644 (file)
@@ -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");
index 48dfe3c..6ba47cf 100644 (file)
@@ -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);
index bf2b80d..8731b6e 100644 (file)
@@ -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 */
index 9ca9ecc..4222f77 100644 (file)
@@ -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;
index 1b5e13e..0dee514 100644 (file)
@@ -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;
+}
index fdd3793..c7726ce 100644 (file)
@@ -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++) {
index 0d35f58..5ab90f3 100644 (file)
@@ -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
index 3be1b2c..6a1c008 100644 (file)
@@ -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
index dd4bff9..d1f5898 100644 (file)
@@ -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)
index 1d59c7e..87990ec 100644 (file)
@@ -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 */
index 8939ebd..84fa6e9 100644 (file)
@@ -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)
index f9c70ba..d16bc67 100644 (file)
@@ -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)
index baeb597..85af7a8 100644 (file)
@@ -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;
index 9d0e161..e1cf23c 100644 (file)
@@ -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;
index 4b994aa..b68d4f7 100644 (file)
@@ -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);
index b9e4645..b732ac6 100644 (file)
@@ -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);
index d8bdf63..63dace8 100644 (file)
@@ -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;
index 9d015db..0ff388a 100644 (file)
@@ -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);
index 93b3154..a14c428 100644 (file)
@@ -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");
 }
 
 /**
index 3a27a84..9426276 100644 (file)
@@ -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);
index 6538159..3f68dd2 100644 (file)
@@ -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
index bebf58a..0ce20ce 100644 (file)
@@ -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:
index c5265c1..583dc33 100644 (file)
@@ -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
index aeae6ec..423fb37 100644 (file)
@@ -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) {
index 12cad94..26ce14f 100644 (file)
@@ -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 },
index 53ae5af..0f4169a 100644 (file)
@@ -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;
index c0c25d7..cab2c68 100644 (file)
@@ -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 },
index e1ccefc..a98dd4f 100644 (file)
@@ -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;
 
index 2d1ce3c..753887d 100644 (file)
@@ -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)
index a90d736..f7fbdc9 100644 (file)
@@ -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;
 
index 76b9052..5907c82 100644 (file)
@@ -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;
        }
 
index 0612b19..506047c 100644 (file)
@@ -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;
index c4d6bbe..02e23e6 100644 (file)
@@ -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.
index a11485f..c3c7db4 100644 (file)
@@ -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,
index 2716e6f..00e3a6b 100644 (file)
@@ -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 {
index 6f64242..6ca693b 100644 (file)
@@ -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)
index 32e3807..271bb58 100644 (file)
@@ -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);
 
index 56316db..cf8e546 100644 (file)
@@ -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)
index b34214e..016743e 100644 (file)
@@ -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 | \
index 2b7610f..10b3bbb 100644 (file)
@@ -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);
index 3c0a8f8..5b90fcf 100644 (file)
@@ -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);
index 982fdcd..b5b2925 100644 (file)
@@ -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,
index 2f70a9b..830466c 100644 (file)
@@ -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,
index 9aa6104..ae21e0b 100644 (file)
@@ -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);
 }
 
 /**
index e71cdde..1d7b00b 100644 (file)
@@ -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);
 }
 
 /**
index 3e8b1bf..d9884fd 100644 (file)
@@ -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>
 
 /* 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);
index afad529..06e3e1e 100644 (file)
@@ -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:
index f78909a..09d2e16 100644 (file)
@@ -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;
        }
index 3df51fa..f790f61 100644 (file)
@@ -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);
index 2d8578c..2e7f9a2 100644 (file)
@@ -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);
 }
index 7e3129e..f0e4bb4 100644 (file)
@@ -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) <<
index a8a7306..bb1bb72 100644 (file)
@@ -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;
 
index 9749dfd..4755838 100644 (file)
@@ -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");
index 2ffbf13..216bfd3 100644 (file)
@@ -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 */
index 3cc316c..d8757bf 100644 (file)
@@ -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;
                }
index b2197b5..1e1fbb0 100644 (file)
@@ -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);
index c0f6479..70b0895 100644 (file)
@@ -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,
 
index 9d15566..fa8f504 100644 (file)
@@ -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);
@@ -2775,34 +2809,6 @@ init_ppp_file(struct ppp_file *pf, int kind)
        init_waitqueue_head(&pf->rwait);
 }
 
-/*
- * 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
index 9d43460..64a60af 100644 (file)
@@ -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 */
index 7fbca37..237f8e5 100644 (file)
@@ -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
index 7193b73..848ea6a 100644 (file)
@@ -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);
index 25d1cbd..b2f0d24 100644 (file)
@@ -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:
index 5000bfc..5514ad6 100644 (file)
@@ -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
index 6203c4a..9e144e7 100644 (file)
@@ -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;
 }
 
index 2b86c21..607acb5 100644 (file)
@@ -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);
        }
index b6cc9ff..1c6788a 100644 (file)
@@ -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;
 }
index 1106ce7..30c2cf7 100644 (file)
@@ -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;
 }
index 3b3a88b..585d088 100644 (file)
@@ -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,
index 1017f02..7bf88d9 100644 (file)
@@ -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");
index 1a83e19..28577a3 100644 (file)
@@ -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)
index 7d50711..3f44b52 100644 (file)
@@ -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))
index 23435f2..2e25307 100644 (file)
@@ -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;
index efe3ad4..1c6386d 100644 (file)
@@ -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;
 }
index 73de4ef..944f500 100644 (file)
@@ -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
index cefd636..b978bbf 100644 (file)
@@ -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;
        }
 }
index cb13299..3271cd1 100644 (file)
@@ -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
index 26270c3..ce129e5 100644 (file)
@@ -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: "
 
index 155b286..25436cd 100644 (file)
@@ -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);
index 1b3a094..30f9ef0 100644 (file)
@@ -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);
index c679594..2d5909c 100644 (file)
@@ -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);
index 8053f24..98d9bb6 100644 (file)
@@ -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);
 }
index cfadcce..6457a8a 100644 (file)
@@ -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);
index 9e43ae1..e4b7998 100644 (file)
@@ -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;
 }
 
index 3b2fcb4..a20da8c 100644 (file)
@@ -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);
index cd77a06..fd09290 100644 (file)
@@ -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);
index c2e9fea..860e840 100644 (file)
@@ -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);
index 62ea4e8..be9cefc 100644 (file)
@@ -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);
index b5ba1ec..f87d4ce 100644 (file)
@@ -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;
index 6509c61..620dcd4 100644 (file)
@@ -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);
index 63a448f..7006860 100644 (file)
@@ -334,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);
 
@@ -426,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;
 
@@ -468,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;
 }
 
index 658c34b..1aaf893 100644 (file)
@@ -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
index 2d98de5..f888561 100644 (file)
@@ -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
 
index 928ee63..bf407b6 100644 (file)
@@ -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;
index 86bd457..50bce45 100644 (file)
@@ -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;
 }
index 111c2d1..b5102aa 100644 (file)
@@ -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);
index 1495ecc..96093ae 100644 (file)
@@ -452,12 +452,10 @@ static void xen_free_irq(unsigned irq)
        irq_free_desc(irq);
 }
 
-static void xen_evtchn_close(unsigned int port, unsigned int cpu)
+static void xen_evtchn_close(unsigned int port)
 {
        struct evtchn_close close;
 
-       xen_evtchn_op_close(port, cpu);
-
        close.port = port;
        if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
                BUG();
@@ -546,7 +544,7 @@ out:
 
 err:
        pr_err("irq%d: Failed to set port to irq mapping (%d)\n", irq, rc);
-       xen_evtchn_close(evtchn, NR_CPUS);
+       xen_evtchn_close(evtchn);
        return 0;
 }
 
@@ -567,7 +565,7 @@ static void shutdown_pirq(struct irq_data *data)
                return;
 
        mask_evtchn(evtchn);
-       xen_evtchn_close(evtchn, cpu_from_evtchn(evtchn));
+       xen_evtchn_close(evtchn);
        xen_irq_info_cleanup(info);
 }
 
@@ -611,7 +609,7 @@ static void __unbind_from_irq(unsigned int irq)
        if (VALID_EVTCHN(evtchn)) {
                unsigned int cpu = cpu_from_irq(irq);
 
-               xen_evtchn_close(evtchn, cpu);
+               xen_evtchn_close(evtchn);
 
                switch (type_from_irq(irq)) {
                case IRQT_VIRQ:
index 6df8aac..ed673e1 100644 (file)
@@ -255,12 +255,6 @@ static void evtchn_fifo_unmask(unsigned port)
        }
 }
 
-static bool evtchn_fifo_is_linked(unsigned port)
-{
-       event_word_t *word = event_word_from_port(port);
-       return sync_test_bit(EVTCHN_FIFO_BIT(LINKED, word), BM(word));
-}
-
 static uint32_t clear_linked(volatile event_word_t *word)
 {
        event_word_t new, old, w;
@@ -287,8 +281,7 @@ static void handle_irq_for_port(unsigned port)
 
 static void consume_one_event(unsigned cpu,
                              struct evtchn_fifo_control_block *control_block,
-                             unsigned priority, unsigned long *ready,
-                             bool drop)
+                             unsigned priority, unsigned long *ready)
 {
        struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu);
        uint32_t head;
@@ -320,15 +313,13 @@ static void consume_one_event(unsigned cpu,
        if (head == 0)
                clear_bit(priority, ready);
 
-       if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port)) {
-               if (likely(!drop))
-                       handle_irq_for_port(port);
-       }
+       if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port))
+               handle_irq_for_port(port);
 
        q->head[priority] = head;
 }
 
-static void __evtchn_fifo_handle_events(unsigned cpu, bool drop)
+static void evtchn_fifo_handle_events(unsigned cpu)
 {
        struct evtchn_fifo_control_block *control_block;
        unsigned long ready;
@@ -340,16 +331,11 @@ static void __evtchn_fifo_handle_events(unsigned cpu, bool drop)
 
        while (ready) {
                q = find_first_bit(&ready, EVTCHN_FIFO_MAX_QUEUES);
-               consume_one_event(cpu, control_block, q, &ready, drop);
+               consume_one_event(cpu, control_block, q, &ready);
                ready |= xchg(&control_block->ready, 0);
        }
 }
 
-static void evtchn_fifo_handle_events(unsigned cpu)
-{
-       __evtchn_fifo_handle_events(cpu, false);
-}
-
 static void evtchn_fifo_resume(void)
 {
        unsigned cpu;
@@ -385,26 +371,6 @@ static void evtchn_fifo_resume(void)
        event_array_pages = 0;
 }
 
-static void evtchn_fifo_close(unsigned port, unsigned int cpu)
-{
-       if (cpu == NR_CPUS)
-               return;
-
-       get_online_cpus();
-       if (cpu_online(cpu)) {
-               if (WARN_ON(irqs_disabled()))
-                       goto out;
-
-               while (evtchn_fifo_is_linked(port))
-                       cpu_relax();
-       } else {
-               __evtchn_fifo_handle_events(cpu, true);
-       }
-
-out:
-       put_online_cpus();
-}
-
 static const struct evtchn_ops evtchn_ops_fifo = {
        .max_channels      = evtchn_fifo_max_channels,
        .nr_channels       = evtchn_fifo_nr_channels,
@@ -418,7 +384,6 @@ static const struct evtchn_ops evtchn_ops_fifo = {
        .unmask            = evtchn_fifo_unmask,
        .handle_events     = evtchn_fifo_handle_events,
        .resume            = evtchn_fifo_resume,
-       .close             = evtchn_fifo_close,
 };
 
 static int evtchn_fifo_alloc_control_block(unsigned cpu)
index d18e123..50c2050 100644 (file)
@@ -68,7 +68,6 @@ struct evtchn_ops {
        bool (*test_and_set_mask)(unsigned port);
        void (*mask)(unsigned port);
        void (*unmask)(unsigned port);
-       void (*close)(unsigned port, unsigned cpu);
 
        void (*handle_events)(unsigned cpu);
        void (*resume)(void);
@@ -146,12 +145,6 @@ static inline void xen_evtchn_resume(void)
                evtchn_ops->resume();
 }
 
-static inline void xen_evtchn_op_close(unsigned port, unsigned cpu)
-{
-       if (evtchn_ops->close)
-               return evtchn_ops->close(port, cpu);
-}
-
 void xen_evtchn_2l_init(void);
 int xen_evtchn_fifo_init(void);
 
index 9ad3272..e303535 100644 (file)
@@ -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);
index 80cc1b3..ebb5e37 100644 (file)
@@ -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);
index fbbcf09..1c2105e 100644 (file)
@@ -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;
 
index 57ca8cc..3b4d8a4 100644 (file)
@@ -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;
 };
 
 /**
index 7990501..53c53c4 100644 (file)
@@ -347,6 +347,25 @@ static inline int drm_eld_mnl(const uint8_t *eld)
        return (eld[DRM_ELD_CEA_EDID_VER_MNL] & DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT;
 }
 
+/**
+ * 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
index 45c39a3..8bc073d 100644 (file)
        {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}, \
index 6c78956..d2992bf 100644 (file)
@@ -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
index 92188b0..51744bc 100644 (file)
@@ -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: */
index 2e872f9..bf6f117 100644 (file)
@@ -1002,6 +1002,34 @@ static inline int page_mapped(struct page *page)
        return atomic_read(&(page)->_mapcount) >= 0;
 }
 
+/*
+ * 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
index 0038ac7..1554957 100644 (file)
@@ -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 {
index 59c55ea..4a67590 100644 (file)
@@ -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)
index d6cdd6e..9b88536 100644 (file)
@@ -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,
index 45534da..644bdc6 100644 (file)
@@ -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)
 {
index 22a44c2..c192e1b 100644 (file)
@@ -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,
index 4942710..8d1d7fa 100644 (file)
@@ -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 *);
 
index 0e9d75b..74bc854 100644 (file)
@@ -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 {
index 4cecd0c..bb7b2eb 100644 (file)
@@ -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 (file)
index 0000000..7fffeaa
--- /dev/null
@@ -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
index 37d95a8..5abba03 100644 (file)
@@ -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
index ea387ed..086cd7f 100644 (file)
@@ -152,6 +152,8 @@ struct snd_soc_tplg_ops {
        int bytes_ext_ops_count;
 };
 
+#ifdef CONFIG_SND_SOC_TOPOLOGY
+
 /* gets a pointer to data from the firmware block header */
 static inline const void *snd_soc_tplg_get_data(struct snd_soc_tplg_hdr *hdr)
 {
@@ -176,4 +178,14 @@ int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
        const struct snd_soc_tplg_widget_events *events, int num_events,
        u16 event_type);
 
+#else
+
+static inline int snd_soc_tplg_component_remove(struct snd_soc_component *comp,
+                                               u32 index)
+{
+       return 0;
+}
+
+#endif
+
 #endif
index 93df8bf..884e728 100644 (file)
@@ -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,
index 88cf39d..317a1ed 100644 (file)
@@ -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,
index 51b8066..247c50b 100644 (file)
 #include <linux/types.h>
 #include <sound/asound.h>
 
+#ifndef __KERNEL__
+#error This API is an early revision and not enabled in the current
+#error kernel release, it will be enabled in a future kernel version
+#error with incompatible changes to what is here.
+#endif
+
 /*
  * Maximum number of channels topology kcontrol can represent.
  */
index bc3d530..b471e5a 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -252,6 +252,16 @@ static void sem_rcu_free(struct rcu_head *head)
        ipc_rcu_free(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.
@@ -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++) {
index ee14e3a..f0acff0 100644 (file)
@@ -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;
 }
index d3dae34..e6feb51 100644 (file)
@@ -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);
        }
index b2be01b..c8aa3f7 100644 (file)
@@ -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)
index 27f4332..ae21682 100644 (file)
@@ -984,6 +984,23 @@ int irq_chip_set_affinity_parent(struct irq_data *data,
        return -ENOSYS;
 }
 
+/**
+ * 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;
 }
 
 /**
index 04ab181..df19ae4 100644 (file)
@@ -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.
index 5e097fa..84190f0 100644 (file)
@@ -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);
                }
        }
 
index 1132d73..17c75a4 100644 (file)
--- 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;
 }
index 6c513a6..7b28e9c 100644 (file)
@@ -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>
index 680ceed..e07c94f 100644 (file)
@@ -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>
index ea5a936..1f4446a 100644 (file)
@@ -1146,8 +1146,11 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
        }
 
        if (!PageHuge(p) && PageTransHuge(hpage)) {
-               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);
@@ -1538,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;
@@ -1567,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;
        }
index 003dbe4..6da82bc 100644 (file)
@@ -1277,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;
 
@@ -2013,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);
 
index beda417..5b5240b 100644 (file)
@@ -1343,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;
 }
@@ -3345,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;
        }
@@ -5060,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];
@@ -5123,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);
 
index 200e224..bbd0b47 100644 (file)
--- 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)) {
index 816df00..f68c0e5 100644 (file)
--- 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);
index 498454b..ea79ee9 100644 (file)
@@ -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,
index fb54e6a..6d0b471 100644 (file)
@@ -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;
 }
 
 /**
index bb01586..cffa92d 100644 (file)
@@ -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);
index c002961..a2fc843 100644 (file)
@@ -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);
index b482495..5809b39 100644 (file)
@@ -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);
                }
index 7998fb2..92720f3 100644 (file)
@@ -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);
 
index 0b39dcc..1285eaf 100644 (file)
@@ -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;
index 3da5525..4d74a06 100644 (file)
@@ -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 */
index 4967262..617088a 100644 (file)
@@ -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);
index 1ebdf1c..1cbd209 100644 (file)
@@ -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);
index 87b22c0..b42f0e2 100644 (file)
@@ -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);
                }
index b6a19ca..7b84330 100644 (file)
@@ -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);
 
index 0917123..35c47dd 100644 (file)
@@ -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);
 
index 37c4bb8..b0c6258 100644 (file)
@@ -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;
index 651cdf6..9fdfd9d 100644 (file)
@@ -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)
 {
index 60021d0..1349571 100644 (file)
@@ -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;
 }
index fe8cc18..95ea633 100644 (file)
@@ -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
index 433231c..0330ab2 100644 (file)
@@ -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
        },
        { }
 };
index d7d4c2b..0ea2e1c 100644 (file)
@@ -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;
        }
index 83aa604..1b8c5ba 100644 (file)
@@ -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)
index 55d1986..548c623 100644 (file)
@@ -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)
index df8afe5..9405b04 100644 (file)
@@ -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)
 {
index 6edb7b1..ebbb754 100644 (file)
@@ -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)) {
index 6090969..d155864 100644 (file)
@@ -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);
 
index 6748c42..7a6cea5 100644 (file)
@@ -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;
        }
index 247552a..3ece7d1 100644 (file)
@@ -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)
index 651039a..3c20d02 100644 (file)
@@ -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++)
index 71f1e9f..d7f1685 100644 (file)
@@ -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;
index c663003..43ddeee 100644 (file)
@@ -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) &&
index d8e2e39..67d2104 100644 (file)
@@ -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;
index 8a8c0b8..ee34f47 100644 (file)
@@ -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;
index 9a6b4f6..140a44a 100644 (file)
@@ -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;
        }
index a42a3b2..2685450 100644 (file)
@@ -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;
index 21ca33c..a9ba030 100644 (file)
@@ -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] = {
index 9cb8522..f3d3fb4 100755 (executable)
@@ -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;
index 2b50cbe..55791a0 100644 (file)
 #include <linux/string.h>
 #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
index 0b9847a..374ea53 100644 (file)
@@ -5190,6 +5190,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
+       SND_PCI_QUIRK(0x1028, 0x06db, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -5291,6 +5292,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2211, "Thinkpad W541", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
index 2ae9619..225bfda 100644 (file)
@@ -30,6 +30,9 @@ config SND_SOC_GENERIC_DMAENGINE_PCM
        bool
        select SND_DMAENGINE_PCM
 
+config SND_SOC_TOPOLOGY
+       bool
+
 # All the supported SoCs
 source "sound/soc/adi/Kconfig"
 source "sound/soc/atmel/Kconfig"
@@ -54,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"
index e189903..134aca1 100644 (file)
@@ -1,6 +1,9 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
 snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o
+
+ifneq ($(CONFIG_SND_SOC_TOPOLOGY),)
 snd-soc-core-objs += soc-topology.o
+endif
 
 ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
 snd-soc-core-objs += soc-generic-dmaengine-pcm.o
@@ -36,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/
index 841d059..ba8def5 100644 (file)
@@ -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 */
index dd94fea..5741c0a 100644 (file)
@@ -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);
index 24cc7f4..fcf5a9a 100644 (file)
@@ -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);
index e742ef6..38e853a 100644 (file)
@@ -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)
index 03fa1cb..8c435be 100644 (file)
@@ -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         = {
index 238913e..02ad260 100644 (file)
@@ -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);
index d95477a..6cba211 100644 (file)
@@ -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);
index 4229f76..fddfe00 100644 (file)
@@ -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,
index 38b3dad..e8bed6b 100644 (file)
@@ -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;
 }
index efaafce..0c9733e 100644 (file)
@@ -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
index cf160d9..4a32077 100644 (file)
@@ -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
index c7d243d..affb192 100644 (file)
@@ -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);
 
index 3cc69a6..9ef20db 100644 (file)
@@ -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 */
index a431602..fe1353a 100644 (file)
@@ -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,
index ff7f846..de53c0d 100644 (file)
@@ -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,
index 862796d..348ccb1 100644 (file)
@@ -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,
index 2ce4362..0e32bba 100644 (file)
@@ -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,
index 9700e8c..21e7394 100644 (file)
@@ -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,
index 66d9fce..52881fa 100644 (file)
@@ -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,
index 36d8425..198c924 100644 (file)
 
 #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,
 
index 8670861..54428c6 100644 (file)
@@ -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,
index 2d0ff45..b14176f 100644 (file)
@@ -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,
index 7c0f655..4a90143 100644 (file)
 #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,
index 0e59063..c73a9f6 100644 (file)
@@ -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,
index 0fc24e0..d2e3a3e 100644 (file)
@@ -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,
index 607a63b..4d3ba33 100644 (file)
@@ -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,
index 802e05e..8a2221a 100644 (file)
@@ -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");
index 43deb04..ada0a41 100644 (file)
@@ -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;
index 8f40025..44c30fe 100644 (file)
@@ -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,
                   },
index 31ab804..1d6c250 100644 (file)
@@ -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
 
index 8e36198..55db19d 100644 (file)
@@ -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,
index e6d4ff9..e07807d 100644 (file)
@@ -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,
index b264da0..dcb3223 100644 (file)
@@ -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,
index c40428f..9bad478 100644 (file)
@@ -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,
index 4de52c9..47b97fc 100644 (file)
@@ -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,
index 1e11ba4..7cd5f76 100644 (file)
@@ -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,
index b7853b9..42a8fd4 100644 (file)
@@ -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,
index 657dce2..800c1d5 100644 (file)
@@ -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,
index e1d4686..d562e1b 100644 (file)
@@ -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
index b2c10e5..d36c61b 100644 (file)
@@ -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 (file)
index 0000000..0ac8fc5
--- /dev/null
@@ -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 (file)
index 0000000..d58c06a
--- /dev/null
@@ -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__ */
index 21810e5..7dc52fe 100644 (file)
@@ -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 },
index 238e48a..a9c86ef 100644 (file)
 
 
 /* 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,
index 2075236..1d5a89c 100644 (file)
@@ -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,
index 66bb446..0b2ede8 100644 (file)
@@ -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 (file)
index 0000000..0b80052
--- /dev/null
@@ -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 (file)
index 0000000..dd850b9
--- /dev/null
@@ -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");
index ebd9028..be44837 100644 (file)
@@ -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,
index 9363fdb..1f5ab99 100644 (file)
@@ -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);
index 99ffc49..558de10 100644 (file)
@@ -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,
index 6600aa0..9af5640 100644 (file)
@@ -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,
index e1c196a..5b82e26 100644 (file)
@@ -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);
index d0f4534..20dcc49 100644 (file)
@@ -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,
index be89a4f..efa39bf 100644 (file)
@@ -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
index 78268f0..584aab8 100644 (file)
@@ -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),
index 21ff743..bc610d9 100644 (file)
@@ -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,
index 9a46d3d..1fedac5 100644 (file)
@@ -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,
index 3a2fda0..f5e3dce 100644 (file)
@@ -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)
index 481d58f..c14a79d 100644 (file)
@@ -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,
index 29549cd..61cc18e 100644 (file)
@@ -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,
 };
 
index aad6642..ebb648a 100644 (file)
@@ -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;
 }
 
@@ -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,
        },
index 3d44fc5..3e770cb 100644 (file)
@@ -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,
index b74118e..f561c78 100644 (file)
@@ -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,
index e7ba557..5832523 100644 (file)
@@ -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,
index dcdfac0..dbff416 100644 (file)
@@ -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,
        },
index 56650d6..aca479f 100644 (file)
  */
 
 #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;
index 0f7b057..4c77b44 100644 (file)
@@ -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__ */
index 5c43e26..bd93658 100644 (file)
@@ -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 (file)
index 0000000..3c2f0f8
--- /dev/null
@@ -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 (file)
index 0000000..31da162
--- /dev/null
@@ -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__ */
+
index 058167c..1be2bab 100644 (file)
@@ -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,
index 9bc78e5..e1ceeb8 100644 (file)
@@ -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),
        },
index 961bd7e..4972bf3 100644 (file)
@@ -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);
index 278bb9f..0e4cfc6 100644 (file)
@@ -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);
index a3506e1..1d40318 100644 (file)
@@ -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,
index a9123d4..49a9e70 100644 (file)
@@ -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,
index ef6348c..3505aaf 100644 (file)
 
 #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)
 {
index ec41b2b..662db16 100644 (file)
 #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__ */
index 31d969a..b4cd7e3 100644 (file)
 #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,
index 7eca38a..d46855a 100644 (file)
@@ -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;
index e673f6c..bfda25e 100644 (file)
@@ -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,
index 3e72964..a8402d0 100644 (file)
@@ -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,
 };
index 29cb442..6bfd25c 100644 (file)
@@ -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",
index f30de76..ddb0203 100644 (file)
@@ -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,
index 0d9779d..173ba85 100644 (file)
@@ -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,
index 69a773a..4452fea 100644 (file)
@@ -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);
index 84a4f5a..e619d56 100644 (file)
@@ -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,
index 60eff36..a9844b2 100644 (file)
@@ -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,
index bd819a3..33a4612 100644 (file)
@@ -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,
index 4f70378..2cdaca9 100644 (file)
@@ -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,
index ed4cca7..0945c51 100644 (file)
@@ -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 (file)
index 0000000..160d61a
--- /dev/null
@@ -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");
index 4f25a7d..e3a0bca 100644 (file)
@@ -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,
        },
index 5746f8f..e34752b 100644 (file)
@@ -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)
index 32942be..d49d25d 100644 (file)
@@ -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,
index 85bcc37..39307ad 100644 (file)
@@ -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) {
index aab0af6..cb5310d 100644 (file)
@@ -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,
index c4c960f..ee4def4 100644 (file)
@@ -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,
index ad6cb90..f2d3191 100644 (file)
@@ -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,
index a7cf19b..1a82b19 100644 (file)
@@ -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,
index d67a311..781398f 100644 (file)
@@ -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,
index 6fac9e0..11d85c5 100644 (file)
@@ -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,
index 12232d7..4356843 100644 (file)
 #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,
index 90f5f04..2713e18 100644 (file)
@@ -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 =
index 6e159f5..35f0469 100644 (file)
@@ -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,
index 048f005..ec45c5b 100644 (file)
@@ -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,
index 21d5402..786abd0 100644 (file)
@@ -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,
index c830832..35199fc 100644 (file)
@@ -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 },
@@ -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,
index 4c10cd8..3695b1d 100644 (file)
@@ -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 },
@@ -2708,7 +2708,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 +2722,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,
index d097f09..64637d1 100644 (file)
@@ -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)
index 709fcc6..2d1168c 100644 (file)
@@ -247,8 +247,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 +259,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 +271,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 +283,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 +310,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),
@@ -1611,18 +1607,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)
index 41c62c1..ffbf3df 100644 (file)
@@ -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]),
index d755508..b1d346a 100644 (file)
@@ -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[] = {
index dac5beb..b098a83 100644 (file)
@@ -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,
index 43ea8ae..aa287a3 100644 (file)
@@ -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,
index 759a792..66602bf 100644 (file)
@@ -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,
index cc8251f..44b9e0a 100644 (file)
@@ -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,
index f1a173e..cd7b024 100644 (file)
@@ -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,
index 915ea11..4846842 100644 (file)
@@ -789,7 +789,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,
index 6ad606f..e4a03d9 100644 (file)
@@ -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,
index b346237..430fa7d 100644 (file)
@@ -633,7 +633,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,
index 56d89b0..873933a 100644 (file)
@@ -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,
index feb2997..0e946f3 100644 (file)
@@ -276,12 +276,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);
@@ -1609,7 +1608,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,
index ece9b44..592866d 100644 (file)
@@ -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,
index 6596f5f..f27464c 100644 (file)
@@ -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,
        },
index f3759ec..98900aa 100644 (file)
@@ -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,
index b5322c1..b011253 100644 (file)
@@ -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,
index 265a4a5..145f5f9 100644 (file)
@@ -2292,7 +2292,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,
index 98ef0ba..f6f9395 100644 (file)
@@ -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,
index 2d591c2..12e4435 100644 (file)
@@ -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,
index 94c5c46..1ed0720 100644 (file)
@@ -1216,7 +1216,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,
index a057662..e30446a 100644 (file)
@@ -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,
index c5748fd..b4eb975 100644 (file)
@@ -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,
        },
index b51184c..2cdde32 100644 (file)
@@ -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,
index 33b16a7..0a60677 100644 (file)
@@ -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,
index cfc8cdf..d36d600 100644 (file)
@@ -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,
index 2fdd2c6..f6861cc 100644 (file)
@@ -1133,7 +1133,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,
index 8a85f50..9c3c151 100644 (file)
@@ -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,
index f13a995..c88ce99 100644 (file)
@@ -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,
index 1993fd2..23ecd30 100644 (file)
@@ -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,
index 44a6777..c9ee0ac 100644 (file)
@@ -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,
index 8a8db86..8668c4c 100644 (file)
@@ -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,
index 962e1d3..2ccbb32 100644 (file)
@@ -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" },
index 505b65f..eda52a9 100644 (file)
@@ -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,
index 3dd063f..66c0955 100644 (file)
@@ -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 },
@@ -3100,7 +3100,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,
index 4134dc7..b4dba3a 100644 (file)
@@ -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]),
index 8a8b1c0..ccb3b15 100644 (file)
@@ -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,
index 13d23fc..5d73729 100644 (file)
@@ -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,
index 5cc457e..744842c 100644 (file)
@@ -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)
index 1fda104..488a922 100644 (file)
@@ -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)
index 89cd2d6..4083a51 100644 (file)
@@ -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)
index 793da86..53df11b 100644 (file)
@@ -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
index fd86bd1..624b3b9 100644 (file)
@@ -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[] = {
index 56cb4d9..ec98548 100644 (file)
@@ -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);
index b960e62..add6bb9 100644 (file)
@@ -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) {
index fabd05f..c77d921 100644 (file)
@@ -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",
        },
index e1aa383..883087f 100644 (file)
@@ -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,
index de43887..5aeb6ed 100644 (file)
@@ -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", },
        {}
 };
 
index c068494..9f087d4 100644 (file)
@@ -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)
index 5c75971..8c2ddc1 100644 (file)
@@ -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);
 
index 5c73bea..a18fd92 100644 (file)
@@ -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);
 }
index 0662809..b95fbc3 100644 (file)
@@ -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)
 #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
 #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)
index 8e93221..ab729f2 100644 (file)
@@ -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);
 
index c0b940e..8ec6fb2 100644 (file)
@@ -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;
 }
 
index 0db94f4..1fc01ed 100644 (file)
@@ -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);
index c79cb27..133c447 100644 (file)
  */
 #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;
 }
index 461ce27..48b2d24 100644 (file)
@@ -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;
index d555493..3ff76d4 100644 (file)
@@ -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;
 }
 
index f3060a4..05fde5e 100644 (file)
@@ -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
index 6de5d5c..2b45435 100644 (file)
@@ -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/
index 31e9b9e..d55388e 100644 (file)
@@ -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;
 
index 641ebe6..683e501 100644 (file)
@@ -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)
 {
index 2409b23..cb32cc7 100644 (file)
@@ -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
index 0e0e4d9..ce689c5 100644 (file)
@@ -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);
index 5a27861..3dc7358 100644 (file)
@@ -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;
index 7ab8cc9..d9f81b8 100644 (file)
@@ -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,
index ae89b9b..de9788a 100644 (file)
@@ -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,
index 7f55d59..c445312 100644 (file)
@@ -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,
index 70f8321..49f4869 100644 (file)
@@ -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,
index bdcaf46..7be8461 100644 (file)
@@ -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,
index 2c9cc5b..23fe040 100644 (file)
@@ -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,
index 396d545..cbd568e 100644 (file)
@@ -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 */
index 64e9421..a627236 100644 (file)
@@ -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)
index 96aeb25..1f45f18 100644 (file)
@@ -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 (file)
index 0000000..27db221
--- /dev/null
@@ -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 (file)
index 0000000..826d4fd
--- /dev/null
@@ -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 (file)
index 0000000..13036b1
--- /dev/null
@@ -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 (file)
index 0000000..3769f9f
--- /dev/null
@@ -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 (file)
index 0000000..7d617bf
--- /dev/null
@@ -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 (file)
index 0000000..44748ba
--- /dev/null
@@ -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 (file)
index 0000000..99e4c86
--- /dev/null
@@ -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 (file)
index 0000000..94875b0
--- /dev/null
@@ -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 (file)
index 0000000..6bfcef4
--- /dev/null
@@ -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 (file)
index 0000000..937a0a3
--- /dev/null
@@ -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 (file)
index 0000000..9f5f672
--- /dev/null
@@ -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 (file)
index 0000000..c18ea51
--- /dev/null
@@ -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 (file)
index 0000000..8c7767b
--- /dev/null
@@ -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 (file)
index 0000000..a506898
--- /dev/null
@@ -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 (file)
index 0000000..348d094
--- /dev/null
@@ -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 (file)
index 0000000..f7fdbb0
--- /dev/null
@@ -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 */
index 4cf2245..dbfdfe9 100644 (file)
@@ -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);
index 2d2536a..684e8a7 100644 (file)
@@ -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,
index 6f52eca..86cf975 100644 (file)
@@ -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,
index a88b175..cc4393c 100644 (file)
@@ -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
index 9863da7..d190fe0 100644 (file)
 /* 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,
        },
index 5ae5ca1..e093261 100644 (file)
@@ -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);
index 68a1252..c7563e2 100644 (file)
@@ -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)
index aeef25c..584b237 100644 (file)
@@ -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;
        }
 
index 076bec6..732e749 100644 (file)
@@ -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");
index 1eb45dc..51e790d 100644 (file)
@@ -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);
index fbe2e93..3da485e 100644 (file)
@@ -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);
index e68290c..6b4e400 100644 (file)
@@ -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",
index a51c9da..831ee37 100644 (file)
@@ -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);
index 807fedf..3cc252e 100644 (file)
@@ -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
index 23f3d59..97bc202 100644 (file)
@@ -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,
index 7356d3a..7a41679 100644 (file)
@@ -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,
index d6e86c1..0b63e2e 100644 (file)
@@ -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__ */
index e181826..58bae8e 100644 (file)
@@ -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.
index b921909..1bc1dc3 100644 (file)
@@ -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
index acb5be5..b936102 100644 (file)
@@ -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 (file)
index 0000000..26567b1
--- /dev/null
@@ -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 (file)
index 0000000..68c62e4
--- /dev/null
@@ -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);
index 8bf2e2c..ee1fda9 100644 (file)
@@ -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);
index 7651dc9..07ce2cf 100644 (file)
@@ -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),
 
index fd11404..8fad444 100644 (file)
@@ -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);
index 142c066..0215c78 100644 (file)
@@ -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);
index f1b4451..8b25850 100644 (file)
@@ -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
index f1e5920..f3feed5 100644 (file)
@@ -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 (file)
index 0000000..05498bb
--- /dev/null
@@ -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);
+       }
+}
index d306e29..bfbb8a5 100644 (file)
@@ -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);
 }
 
index 36fc020..5779638 100644 (file)
@@ -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;
index 8c7dc51..f04d17b 100644 (file)
@@ -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 (file)
index 0000000..0d5c102
--- /dev/null
@@ -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);
+       }
+}
index 09fcc54..7a0e52b 100644 (file)
@@ -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)
@@ -436,12 +456,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()
         */
@@ -458,6 +472,24 @@ struct rsnd_priv {
        void *ssi;
        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()
         */
@@ -530,6 +562,19 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod,
                     const char * const *texts,
                     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
  */
@@ -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
index 84e9357..d61db9c 100644 (file)
@@ -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");
index c61c171..89a18e1 100644 (file)
@@ -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);
 
@@ -921,13 +943,6 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
        if (!rsnd_rdai_is_clk_master(rdai))
                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
         */
@@ -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;
index 2fbe59f..d45b9a7 100644 (file)
@@ -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;
index ab13146..89ed1b1 100644 (file)
@@ -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);
index 08d7259..d40efc9 100644 (file)
@@ -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);
 
index 0e1e69c..6173d15 100644 (file)
@@ -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)
 {
index e0de807..f4bf21a 100644 (file)
 
 #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,44 +174,58 @@ 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
@@ -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);
-               }
        }
 }
 
index 256b9c9..70e4b9d 100644 (file)
@@ -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;
index 5690b7e..69d01cd 100644 (file)
@@ -1790,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) {
 
@@ -1802,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);
index a402860..977a078 100644 (file)
@@ -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;
index a7dc3c5..e8476da 100644 (file)
@@ -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 (file)
index 0000000..64a6900
--- /dev/null
@@ -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 (file)
index 0000000..4b188d2
--- /dev/null
@@ -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 (file)
index 0000000..39bcefe
--- /dev/null
@@ -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 (file)
index 0000000..f0fd5a9
--- /dev/null
@@ -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 (file)
index 0000000..f6eefe1
--- /dev/null
@@ -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 (file)
index 0000000..c502626
--- /dev/null
@@ -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);
index f52600b..89add13 100644 (file)
@@ -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;
        }
 
index 05f1c6e..14106fa 100644 (file)
@@ -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;
        }
 
index 9141477..a0c3640 100644 (file)
@@ -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;
 }
 
index bc94e5d..fef3b9a 100644 (file)
@@ -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;
 }
 
index fe36375..8e55583 100644 (file)
@@ -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;
        }
 
index 1fab977..0450593 100644 (file)
@@ -638,7 +638,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
        int err = -ENODEV;
 
        down_read(&chip->shutdown_rwsem);
-       if (chip->probing && chip->in_pm)
+       if (chip->probing || chip->in_pm)
                err = 0;
        else if (!chip->shutdown)
                err = usb_autopm_get_interface(chip->pm_intf);
index de165a1..20b56eb 100644 (file)
@@ -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,
        },
 };
 
index ecf3197..6135cc0 100644 (file)
@@ -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);
index 094ddae..d31fac1 100644 (file)
@@ -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
index 7ff6827..f1a4c83 100644 (file)
@@ -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) {
index 53e8bb7..2a5d8d7 100644 (file)
@@ -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);
index 28c4b74..0a9ae80 100644 (file)
@@ -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)