Merge tag 'asoc-v4.2-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorTakashi Iwai <tiwai@suse.de>
Mon, 31 Aug 2015 14:25:22 +0000 (16:25 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 31 Aug 2015 14:25:22 +0000 (16:25 +0200)
ASoC: Updates for v4.3

Not many updates to the core here, but an awful lot of driver updates
this time round:

 - Factoring out of AC'97 reset code into the core
 - New drivers for Cirrus CS4349, GTM601, InvenSense ICS43432, Realtek
   RT298 and ST STI controllers.
 - Machine drivers for Rockchip systems with MAX98090 and RT5645 and
   RT5650.
 - Initial driver support for Intel Skylake devices.
 - A large number of cleanups for Lars-Peter Clausen and Axel Lin.

699 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/phy/ti-phy.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
Documentation/input/alps.txt
MAINTAINERS
Makefile
arch/arc/Kconfig
arch/arc/Makefile
arch/arc/include/asm/arcregs.h
arch/arc/include/asm/atomic.h
arch/arc/include/asm/ptrace.h
arch/arc/include/asm/spinlock.h
arch/arc/include/asm/spinlock_types.h
arch/arc/include/uapi/asm/ptrace.h
arch/arc/kernel/setup.c
arch/arc/kernel/time.c
arch/arc/lib/memcpy-archs.S
arch/arc/lib/memset-archs.S
arch/arc/plat-axs10x/axs10x.c
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/signal32.c
arch/arm64/kernel/vdso.c
arch/mips/Kconfig
arch/mips/ath79/setup.c
arch/mips/cavium-octeon/smp.c
arch/mips/include/asm/mach-bcm63xx/dma-coherence.h [deleted file]
arch/mips/include/asm/pgtable.h
arch/mips/include/asm/smp.h
arch/mips/include/asm/stackframe.h
arch/mips/kernel/genex.S
arch/mips/kernel/mips-mt-fpaff.c
arch/mips/kernel/prom.c
arch/mips/kernel/relocate_kernel.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/signal32.c
arch/mips/kernel/smp-bmips.c
arch/mips/kernel/smp.c
arch/mips/kernel/traps.c
arch/mips/kernel/unaligned.c
arch/mips/lantiq/irq.c
arch/mips/loongson64/loongson-3/smp.c
arch/mips/mm/cache.c
arch/mips/mm/fault.c
arch/mips/mti-malta/malta-int.c
arch/mips/mti-malta/malta-time.c
arch/mips/mti-sead3/sead3-time.c
arch/mips/netlogic/common/smp.c
arch/mips/paravirt/paravirt-smp.c
arch/mips/pistachio/time.c
arch/mips/pmcs-msp71xx/msp_smp.c
arch/mips/ralink/irq.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sibyte/bcm1480/smp.c
arch/mips/sibyte/sb1250/smp.c
arch/powerpc/kernel/signal_32.c
arch/s390/kvm/kvm-s390.c
arch/sparc/include/asm/visasm.h
arch/sparc/lib/NG4memcpy.S
arch/sparc/lib/VISsave.S
arch/sparc/lib/ksyms.c
arch/tile/kernel/compat_signal.c
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/mtrr.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/rbd.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkfront.c
drivers/block/zram/zram_drv.c
drivers/char/hw_random/core.c
drivers/clk/pxa/clk-pxa3xx.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/timer-imx-gpt.c
drivers/cpufreq/exynos-cpufreq.c
drivers/cpufreq/loongson2_cpufreq.c
drivers/crypto/caam/caamhash.c
drivers/crypto/ixp4xx_crypto.c
drivers/crypto/nx/nx-sha256.c
drivers/crypto/nx/nx-sha512.c
drivers/crypto/qat/qat_common/qat_algs.c
drivers/dma/dmaengine.c
drivers/edac/ppc4xx_edac.c
drivers/extcon/extcon-palmas.c
drivers/extcon/extcon.c
drivers/firmware/broadcom/bcm47xx_nvram.c
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
drivers/gpu/drm/amd/amdgpu/cik_sdma.c
drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_irq.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/i2c/tda998x_drv.c
drivers/gpu/drm/i915/intel_atomic.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dp_mst.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/hwmon/dell-smm-hwmon.c
drivers/hwmon/g762.c
drivers/hwmon/nct7904.c
drivers/i2c/busses/i2c-bfin-twi.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-slave-eeprom.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/input/joystick/turbografx.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/misc/axp20x-pek.c
drivers/input/misc/drv260x.c
drivers/input/misc/drv2665.c
drivers/input/misc/drv2667.c
drivers/input/misc/twl4030-vibra.c
drivers/input/mouse/alps.c
drivers/input/mouse/elantech.c
drivers/input/mouse/elantech.h
drivers/irqchip/irq-crossbar.c
drivers/irqchip/irq-mips-gic.c
drivers/md/dm-cache-policy-mq.c
drivers/md/dm-cache-policy-smq.c
drivers/md/dm-thin-metadata.c
drivers/md/dm.c
drivers/md/md.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/md/raid1.c
drivers/md/raid5.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/misc/eeprom/at24.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/phy/phy-sun4i-usb.c
drivers/phy/phy-ti-pipe3.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/staging/comedi/drivers/das1800.c
drivers/staging/lustre/lustre/obdclass/debug.c
drivers/staging/vt6655/device_main.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/hisi_thermal.c
drivers/thermal/power_allocator.c
drivers/thermal/samsung/Kconfig
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/thermal_core.c
drivers/usb/chipidea/core.c
drivers/usb/chipidea/host.c
drivers/usb/chipidea/host.h
drivers/usb/gadget/function/f_hid.c
drivers/usb/gadget/function/f_printer.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/udc/bdc/bdc_ep.c
drivers/usb/gadget/udc/udc-core.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-ring.c
drivers/usb/serial/option.c
drivers/usb/serial/qcserial.c
drivers/usb/serial/sierra.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/virtio/virtio_input.c
drivers/xen/balloon.c
drivers/xen/gntdev.c
drivers/xen/xenbus/xenbus_client.c
fs/btrfs/qgroup.c
fs/ceph/caps.c
fs/ceph/locks.c
fs/ceph/super.h
fs/dcache.c
fs/file_table.c
fs/fuse/dev.c
fs/hugetlbfs/inode.c
fs/namei.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/notify/mark.c
fs/ocfs2/aops.c
fs/ocfs2/dlmglue.c
fs/signalfd.c
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_edid.h
include/drm/drm_pciids.h
include/linux/ata.h
include/linux/fs.h
include/linux/irq.h
include/linux/mfd/arizona/registers.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/page-flags.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/linux/pci_regs.h
init/main.c
ipc/mqueue.c
ipc/sem.c
ipc/shm.c
kernel/cpuset.c
kernel/events/core.c
kernel/events/ring_buffer.c
kernel/irq/chip.c
kernel/kthread.c
kernel/locking/qspinlock_paravirt.h
kernel/module.c
kernel/signal.c
kernel/time/timer.c
lib/iommu-common.c
mm/cma.h
mm/huge_memory.c
mm/kasan/kasan.c
mm/kasan/report.c
mm/memory-failure.c
mm/memory_hotplug.c
mm/migrate.c
mm/page-writeback.c
mm/page_alloc.c
mm/shmem.c
mm/slab.c
mm/slab_common.c
mm/slub.c
mm/vmscan.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
security/yama/yama_lsm.c
sound/ac97_bus.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/pcm512x.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/uda134x.c
sound/soc/codecs/uda134x.h
sound/soc/codecs/uda1380.c
sound/soc/codecs/wm0010.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/wm8804.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/wm8960.h
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/soc/txx9/txx9aclc.c
sound/soc/ux500/ux500_msp_dai.c
sound/soc/xtensa/xtfpga-i2s.c
sound/soc/zte/zx296702-i2s.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 b4091b7a78fe11ccd0e5f44f0703ace69dc09707..4b31af54ccd5864359c0810f9733f3026181a631 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 71f9246127ecafb9747562136c1bce8d9a1bf697..e94a10bb4a9e9d0f6fb9ff3e1aa47af4892f11c2 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 d6b794cef0b8b9907ab5a055a6502180b4350148..91e6e5c478d006245c5a88e7ae7e304d6fa7f097 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"
index 305e3df3d9b1eb9a994c845eb28959275d2f20ed..9cf9446eaf2eac41d57251cb5853037e2b31e7c2 100644 (file)
@@ -82,6 +82,9 @@ Optional properties:
  - id: If there are multiple instance of the same type, in order to
    differentiate between each instance "id" can be used (e.g., multi-lane PCIe
    PHY). If "id" is not provided, it is set to default value of '1'.
+ - syscon-pllreset: Handle to system control region that contains the
+   CTRL_CORE_SMA_SW_0 register and register offset to the CTRL_CORE_SMA_SW_0
+   register that contains the SATA_PLL_SOFT_RESET bit. Only valid for sata_phy.
 
 This is usually a subnode of ocp2scp to which it is connected.
 
@@ -100,3 +103,16 @@ usb3phy@4a084400 {
                        "sysclk",
                        "refclk";
 };
+
+sata_phy: phy@4A096000 {
+       compatible = "ti,phy-pipe3-sata";
+       reg = <0x4A096000 0x80>, /* phy_rx */
+             <0x4A096400 0x64>, /* phy_tx */
+             <0x4A096800 0x40>; /* pll_ctrl */
+       reg-names = "phy_rx", "phy_tx", "pll_ctrl";
+       ctrl-module = <&omap_control_sata>;
+       clocks = <&sys_clkin1>, <&sata_ref_clk>;
+       clock-names = "sysclk", "refclk";
+       syscon-pllreset = <&scm_conf 0x3fc>;
+       #phy-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/cs4349.txt b/Documentation/devicetree/bindings/sound/cs4349.txt
new file mode 100644 (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 a7a149a236e55b8372b7cb3622cd6a6c664d4e2d..28645a2ff885e029de228ce9a599b21ff0ef9461 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 b6b3a786855f275b3463d8280db01af8262f6df3..1173395b5e5c16c070885b06ae06100eb0aa7ff2 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 c64155027288e20105f4741bc66de02951b7c1a3..962748a8d9194dee2101c681a80f18ed06825422 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 d444757c4d9ec3e56c261e0adf330de187251466..66a33ae5f5bcfd01e38c1ce29e0e8694f69ac5ac 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 c86f2f1ae4f6aa2d9af3e3987e8be06fd237dbef..1fec1135791d98c987105872c63b5e96589633d3 100644 (file)
@@ -119,8 +119,10 @@ ALPS Absolute Mode - Protocol Version 2
  byte 5:  0   z6   z5   z4   z3   z2   z1   z0
 
 Protocol Version 2 DualPoint devices send standard PS/2 mouse packets for
-the DualPoint Stick. For non interleaved dualpoint devices the pointingstick
-buttons get reported separately in the PSM, PSR and PSL bits.
+the DualPoint Stick. The M, R and L bits signal the combined status of both
+the pointingstick and touchpad buttons, except for Dell dualpoint devices
+where the pointingstick buttons get reported separately in the PSM, PSR
+and PSL bits.
 
 Dualpoint device -- interleaved packet format
 ---------------------------------------------
index a9ae6c105520011994801168a7841b4d713b716e..569568f6644f2092211b7bb2690c7defe49977dd 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 e79448d90f194be05c2ac9e7f969cb458643c2cc..246053f04fb5cecf72e477cd94257e052955d21f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 2
 SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc8
 NAME = Hurr durr I'ma sheep
 
 # *DOCUMENTATION*
@@ -597,6 +597,11 @@ endif # $(dot-config)
 # Defaults to vmlinux, but the arch makefile usually adds further targets
 all: vmlinux
 
+# The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default
+# values of the respective KBUILD_* variables
+ARCH_CPPFLAGS :=
+ARCH_AFLAGS :=
+ARCH_CFLAGS :=
 include arch/$(SRCARCH)/Makefile
 
 KBUILD_CFLAGS  += $(call cc-option,-fno-delete-null-pointer-checks,)
@@ -848,10 +853,10 @@ export mod_strip_cmd
 mod_compress_cmd = true
 ifdef CONFIG_MODULE_COMPRESS
   ifdef CONFIG_MODULE_COMPRESS_GZIP
-    mod_compress_cmd = gzip -n
+    mod_compress_cmd = gzip -n -f
   endif # CONFIG_MODULE_COMPRESS_GZIP
   ifdef CONFIG_MODULE_COMPRESS_XZ
-    mod_compress_cmd = xz
+    mod_compress_cmd = xz -f
   endif # CONFIG_MODULE_COMPRESS_XZ
 endif # CONFIG_MODULE_COMPRESS
 export mod_compress_cmd
index 91cf4055acab0439e564a96056012befd5fb4c36..bd4670d1b89bcabf043f13015c01b59397b73427 100644 (file)
@@ -313,11 +313,11 @@ config ARC_PAGE_SIZE_8K
 
 config ARC_PAGE_SIZE_16K
        bool "16KB"
-       depends on ARC_MMU_V3
+       depends on ARC_MMU_V3 || ARC_MMU_V4
 
 config ARC_PAGE_SIZE_4K
        bool "4KB"
-       depends on ARC_MMU_V3
+       depends on ARC_MMU_V3 || ARC_MMU_V4
 
 endchoice
 
@@ -365,6 +365,11 @@ config ARC_HAS_LLSC
        default y
        depends on !ARC_CANT_LLSC
 
+config ARC_STAR_9000923308
+       bool "Workaround for llock/scond livelock"
+       default y
+       depends on ISA_ARCV2 && SMP && ARC_HAS_LLSC
+
 config ARC_HAS_SWAPE
        bool "Insn: SWAPE (endian-swap)"
        default y
@@ -379,6 +384,10 @@ config ARC_HAS_LL64
          dest operands with 2 possible source operands.
        default y
 
+config ARC_HAS_DIV_REM
+       bool "Insn: div, divu, rem, remu"
+       default y
+
 config ARC_HAS_RTC
        bool "Local 64-bit r/o cycle counter"
        default n
index 46d87310220dadaf96be4ff08c42b240d2eb4916..8a27a48304a4c0127d97996d73c7d7dc0515d8a3 100644 (file)
@@ -36,8 +36,16 @@ cflags-$(atleast_gcc44)                      += -fsection-anchors
 cflags-$(CONFIG_ARC_HAS_LLSC)          += -mlock
 cflags-$(CONFIG_ARC_HAS_SWAPE)         += -mswape
 
+ifdef CONFIG_ISA_ARCV2
+
 ifndef CONFIG_ARC_HAS_LL64
-cflags-$(CONFIG_ISA_ARCV2)             += -mno-ll64
+cflags-y                               += -mno-ll64
+endif
+
+ifndef CONFIG_ARC_HAS_DIV_REM
+cflags-y                               += -mno-div-rem
+endif
+
 endif
 
 cflags-$(CONFIG_ARC_DW2_UNWIND)                += -fasynchronous-unwind-tables
index 070f58827a5c12c2e19469ff4280f7c69e0f36a3..c8f57b8449dcf6a36aa61cd3589b90ebba42d7ea 100644 (file)
 #define ECR_C_BIT_DTLB_LD_MISS         8
 #define ECR_C_BIT_DTLB_ST_MISS         9
 
-
 /* Auxiliary registers */
 #define AUX_IDENTITY           4
 #define AUX_INTR_VEC_BASE      0x25
-
+#define AUX_NON_VOL            0x5e
 
 /*
  * Floating Pt Registers
@@ -240,9 +239,9 @@ struct bcr_extn_xymem {
 
 struct bcr_perip {
 #ifdef CONFIG_CPU_BIG_ENDIAN
-       unsigned int start:8, pad2:8, sz:8, pad:8;
+       unsigned int start:8, pad2:8, sz:8, ver:8;
 #else
-       unsigned int pad:8, sz:8, pad2:8, start:8;
+       unsigned int ver:8, sz:8, pad2:8, start:8;
 #endif
 };
 
index 03484cb4d16d2eb4fada0095ee427726c23bd2e1..87d18ae53115596f7b64a56a4a07a572d54c3cbd 100644 (file)
 
 #define atomic_set(v, i) (((v)->counter) = (i))
 
-#ifdef CONFIG_ISA_ARCV2
-#define PREFETCHW      "       prefetchw   [%1]        \n"
-#else
-#define PREFETCHW
+#ifdef CONFIG_ARC_STAR_9000923308
+
+#define SCOND_FAIL_RETRY_VAR_DEF                                               \
+       unsigned int delay = 1, tmp;                                            \
+
+#define SCOND_FAIL_RETRY_ASM                                                   \
+       "       bz      4f                      \n"                             \
+       "   ; --- scond fail delay ---          \n"                             \
+       "       mov     %[tmp], %[delay]        \n"     /* tmp = delay */       \
+       "2:     brne.d  %[tmp], 0, 2b           \n"     /* while (tmp != 0) */  \
+       "       sub     %[tmp], %[tmp], 1       \n"     /* tmp-- */             \
+       "       rol     %[delay], %[delay]      \n"     /* delay *= 2 */        \
+       "       b       1b                      \n"     /* start over */        \
+       "4: ; --- success ---                   \n"                             \
+
+#define SCOND_FAIL_RETRY_VARS                                                  \
+         ,[delay] "+&r" (delay),[tmp] "=&r"    (tmp)                           \
+
+#else  /* !CONFIG_ARC_STAR_9000923308 */
+
+#define SCOND_FAIL_RETRY_VAR_DEF
+
+#define SCOND_FAIL_RETRY_ASM                                                   \
+       "       bnz     1b                      \n"                             \
+
+#define SCOND_FAIL_RETRY_VARS
+
 #endif
 
 #define ATOMIC_OP(op, c_op, asm_op)                                    \
 static inline void atomic_##op(int i, atomic_t *v)                     \
 {                                                                      \
-       unsigned int temp;                                              \
+       unsigned int val;                                               \
+       SCOND_FAIL_RETRY_VAR_DEF                                        \
                                                                        \
        __asm__ __volatile__(                                           \
-       "1:                             \n"                             \
-       PREFETCHW                                                       \
-       "       llock   %0, [%1]        \n"                             \
-       "       " #asm_op " %0, %0, %2  \n"                             \
-       "       scond   %0, [%1]        \n"                             \
-       "       bnz     1b              \n"                             \
-       : "=&r"(temp)   /* Early clobber, to prevent reg reuse */       \
-       : "r"(&v->counter), "ir"(i)                                     \
+       "1:     llock   %[val], [%[ctr]]                \n"             \
+       "       " #asm_op " %[val], %[val], %[i]        \n"             \
+       "       scond   %[val], [%[ctr]]                \n"             \
+       "                                               \n"             \
+       SCOND_FAIL_RETRY_ASM                                            \
+                                                                       \
+       : [val] "=&r"   (val) /* Early clobber to prevent reg reuse */  \
+         SCOND_FAIL_RETRY_VARS                                         \
+       : [ctr] "r"     (&v->counter), /* Not "m": llock only supports reg direct addr mode */  \
+         [i]   "ir"    (i)                                             \
        : "cc");                                                        \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
 static inline int atomic_##op##_return(int i, atomic_t *v)             \
 {                                                                      \
-       unsigned int temp;                                              \
+       unsigned int val;                                               \
+       SCOND_FAIL_RETRY_VAR_DEF                                        \
                                                                        \
        /*                                                              \
         * Explicit full memory barrier needed before/after as          \
@@ -58,19 +85,21 @@ static inline int atomic_##op##_return(int i, atomic_t *v)          \
        smp_mb();                                                       \
                                                                        \
        __asm__ __volatile__(                                           \
-       "1:                             \n"                             \
-       PREFETCHW                                                       \
-       "       llock   %0, [%1]        \n"                             \
-       "       " #asm_op " %0, %0, %2  \n"                             \
-       "       scond   %0, [%1]        \n"                             \
-       "       bnz     1b              \n"                             \
-       : "=&r"(temp)                                                   \
-       : "r"(&v->counter), "ir"(i)                                     \
+       "1:     llock   %[val], [%[ctr]]                \n"             \
+       "       " #asm_op " %[val], %[val], %[i]        \n"             \
+       "       scond   %[val], [%[ctr]]                \n"             \
+       "                                               \n"             \
+       SCOND_FAIL_RETRY_ASM                                            \
+                                                                       \
+       : [val] "=&r"   (val)                                           \
+         SCOND_FAIL_RETRY_VARS                                         \
+       : [ctr] "r"     (&v->counter),                                  \
+         [i]   "ir"    (i)                                             \
        : "cc");                                                        \
                                                                        \
        smp_mb();                                                       \
                                                                        \
-       return temp;                                                    \
+       return val;                                                     \
 }
 
 #else  /* !CONFIG_ARC_HAS_LLSC */
@@ -150,6 +179,9 @@ ATOMIC_OP(and, &=, and)
 #undef ATOMIC_OPS
 #undef ATOMIC_OP_RETURN
 #undef ATOMIC_OP
+#undef SCOND_FAIL_RETRY_VAR_DEF
+#undef SCOND_FAIL_RETRY_ASM
+#undef SCOND_FAIL_RETRY_VARS
 
 /**
  * __atomic_add_unless - add unless the number is a given value
index 91694ec1ce959498fd5b4431962b03bbdf4119b7..69095da1fcfd1e35f16234aaf473896194064d38 100644 (file)
 struct pt_regs {
 
        /* Real registers */
-       long bta;       /* bta_l1, bta_l2, erbta */
+       unsigned long bta;      /* bta_l1, bta_l2, erbta */
 
-       long lp_start, lp_end, lp_count;
+       unsigned long lp_start, lp_end, lp_count;
 
-       long status32;  /* status32_l1, status32_l2, erstatus */
-       long ret;       /* ilink1, ilink2 or eret */
-       long blink;
-       long fp;
-       long r26;       /* gp */
+       unsigned long status32; /* status32_l1, status32_l2, erstatus */
+       unsigned long ret;      /* ilink1, ilink2 or eret */
+       unsigned long blink;
+       unsigned long fp;
+       unsigned long r26;      /* gp */
 
-       long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
+       unsigned long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
 
-       long sp;        /* user/kernel sp depending on where we came from  */
-       long orig_r0;
+       unsigned long sp;       /* User/Kernel depending on where we came from */
+       unsigned long orig_r0;
 
        /*
         * To distinguish bet excp, syscall, irq
@@ -55,13 +55,13 @@ struct pt_regs {
                unsigned long event;
        };
 
-       long user_r25;
+       unsigned long user_r25;
 };
 #else
 
 struct pt_regs {
 
-       long orig_r0;
+       unsigned long orig_r0;
 
        union {
                struct {
@@ -76,26 +76,26 @@ struct pt_regs {
                unsigned long event;
        };
 
-       long bta;       /* bta_l1, bta_l2, erbta */
+       unsigned long bta;      /* bta_l1, bta_l2, erbta */
 
-       long user_r25;
+       unsigned long user_r25;
 
-       long r26;       /* gp */
-       long fp;
-       long sp;        /* user/kernel sp depending on where we came from  */
+       unsigned long r26;      /* gp */
+       unsigned long fp;
+       unsigned long sp;       /* user/kernel sp depending on where we came from  */
 
-       long r12;
+       unsigned long r12;
 
        /*------- Below list auto saved by h/w -----------*/
-       long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
+       unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
 
-       long blink;
-       long lp_end, lp_start, lp_count;
+       unsigned long blink;
+       unsigned long lp_end, lp_start, lp_count;
 
-       long ei, ldi, jli;
+       unsigned long ei, ldi, jli;
 
-       long ret;
-       long status32;
+       unsigned long ret;
+       unsigned long status32;
 };
 
 #endif
@@ -103,10 +103,10 @@ struct pt_regs {
 /* Callee saved registers - need to be saved only when you are scheduled out */
 
 struct callee_regs {
-       long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
+       unsigned long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
 };
 
-#define instruction_pointer(regs)      (unsigned long)((regs)->ret)
+#define instruction_pointer(regs)      ((regs)->ret)
 #define profile_pc(regs)               instruction_pointer(regs)
 
 /* return 1 if user mode or 0 if kernel mode */
@@ -142,7 +142,7 @@ struct callee_regs {
 
 static inline long regs_return_value(struct pt_regs *regs)
 {
-       return regs->r0;
+       return (long)regs->r0;
 }
 
 #endif /* !__ASSEMBLY__ */
index e1651df6a93d5bc8ab0af3a833c7c6ffd23acacc..db8c59d1eaeb760798c287a15720573ed58b9e4a 100644 (file)
 #define arch_spin_unlock_wait(x) \
        do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0)
 
+#ifdef CONFIG_ARC_HAS_LLSC
+
+/*
+ * A normal LLOCK/SCOND based system, w/o need for livelock workaround
+ */
+#ifndef CONFIG_ARC_STAR_9000923308
+
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
-       unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__;
+       unsigned int val;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[slock]]      \n"
+       "       breq    %[val], %[LOCKED], 1b   \n"     /* spin while LOCKED */
+       "       scond   %[LOCKED], [%[slock]]   \n"     /* acquire */
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [slock]       "r"     (&(lock->slock)),
+         [LOCKED]      "r"     (__ARCH_SPIN_LOCK_LOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+       unsigned int val, got_it = 0;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[slock]]      \n"
+       "       breq    %[val], %[LOCKED], 4f   \n"     /* already LOCKED, just bail */
+       "       scond   %[LOCKED], [%[slock]]   \n"     /* acquire */
+       "       bnz     1b                      \n"
+       "       mov     %[got_it], 1            \n"
+       "4:                                     \n"
+       "                                       \n"
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+       : [slock]       "r"     (&(lock->slock)),
+         [LOCKED]      "r"     (__ARCH_SPIN_LOCK_LOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+       smp_mb();
+
+       lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__;
+
+       smp_mb();
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
+ */
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * zero means writer holds the lock exclusively, deny Reader.
+        * Otherwise grant lock to first/subseq reader
+        *
+        *      if (rw->counter > 0) {
+        *              rw->counter--;
+        *              ret = 1;
+        *      }
+        */
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brls    %[val], %[WR_LOCKED], 1b\n"     /* <= 0: spin while write locked */
+       "       sub     %[val], %[val], 1       \n"     /* reader lock */
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+       unsigned int val, got_it = 0;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brls    %[val], %[WR_LOCKED], 4f\n"     /* <= 0: already write locked, bail */
+       "       sub     %[val], %[val], 1       \n"     /* counter-- */
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"     /* retry if collided with someone */
+       "       mov     %[got_it], 1            \n"
+       "                                       \n"
+       "4: ; --- done ---                      \n"
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
+        * deny writer. Otherwise if unlocked grant to writer
+        * Hence the claim that Linux rwlocks are unfair to writers.
+        * (can be starved for an indefinite time by readers).
+        *
+        *      if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
+        *              rw->counter = 0;
+        *              ret = 1;
+        *      }
+        */
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brne    %[val], %[UNLOCKED], 1b \n"     /* while !UNLOCKED spin */
+       "       mov     %[val], %[WR_LOCKED]    \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "ir"    (__ARCH_RW_LOCK_UNLOCKED__),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+       unsigned int val, got_it = 0;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brne    %[val], %[UNLOCKED], 4f \n"     /* !UNLOCKED, bail */
+       "       mov     %[val], %[WR_LOCKED]    \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"     /* retry if collided with someone */
+       "       mov     %[got_it], 1            \n"
+       "                                       \n"
+       "4: ; --- done ---                      \n"
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "ir"    (__ARCH_RW_LOCK_UNLOCKED__),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * rw->counter++;
+        */
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       add     %[val], %[val], 1       \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter))
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+       smp_mb();
+
+       rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
+
+       smp_mb();
+}
+
+#else  /* CONFIG_ARC_STAR_9000923308 */
+
+/*
+ * HS38x4 could get into a LLOCK/SCOND livelock in case of multiple overlapping
+ * coherency transactions in the SCU. The exclusive line state keeps rotating
+ * among contenting cores leading to a never ending cycle. So break the cycle
+ * by deferring the retry of failed exclusive access (SCOND). The actual delay
+ * needed is function of number of contending cores as well as the unrelated
+ * coherency traffic from other cores. To keep the code simple, start off with
+ * small delay of 1 which would suffice most cases and in case of contention
+ * double the delay. Eventually the delay is sufficient such that the coherency
+ * pipeline is drained, thus a subsequent exclusive access would succeed.
+ */
+
+#define SCOND_FAIL_RETRY_VAR_DEF                                               \
+       unsigned int delay, tmp;                                                \
+
+#define SCOND_FAIL_RETRY_ASM                                                   \
+       "   ; --- scond fail delay ---          \n"                             \
+       "       mov     %[tmp], %[delay]        \n"     /* tmp = delay */       \
+       "2:     brne.d  %[tmp], 0, 2b           \n"     /* while (tmp != 0) */  \
+       "       sub     %[tmp], %[tmp], 1       \n"     /* tmp-- */             \
+       "       rol     %[delay], %[delay]      \n"     /* delay *= 2 */        \
+       "       b       1b                      \n"     /* start over */        \
+       "                                       \n"                             \
+       "4: ; --- done ---                      \n"                             \
+
+#define SCOND_FAIL_RETRY_VARS                                                  \
+         ,[delay] "=&r" (delay), [tmp] "=&r"   (tmp)                           \
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+       unsigned int val;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[slock]]      \n"
+       "       breq    %[val], %[LOCKED], 0b   \n"     /* spin while LOCKED */
+       "       scond   %[LOCKED], [%[slock]]   \n"     /* acquire */
+       "       bz      4f                      \n"     /* done */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val)
+         SCOND_FAIL_RETRY_VARS
+       : [slock]       "r"     (&(lock->slock)),
+         [LOCKED]      "r"     (__ARCH_SPIN_LOCK_LOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+       unsigned int val, got_it = 0;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[slock]]      \n"
+       "       breq    %[val], %[LOCKED], 4f   \n"     /* already LOCKED, just bail */
+       "       scond   %[LOCKED], [%[slock]]   \n"     /* acquire */
+       "       bz.d    4f                      \n"
+       "       mov.z   %[got_it], 1            \n"     /* got it */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+         SCOND_FAIL_RETRY_VARS
+       : [slock]       "r"     (&(lock->slock)),
+         [LOCKED]      "r"     (__ARCH_SPIN_LOCK_LOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+       smp_mb();
+
+       lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__;
+
+       smp_mb();
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
+ */
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       /*
+        * zero means writer holds the lock exclusively, deny Reader.
+        * Otherwise grant lock to first/subseq reader
+        *
+        *      if (rw->counter > 0) {
+        *              rw->counter--;
+        *              ret = 1;
+        *      }
+        */
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brls    %[val], %[WR_LOCKED], 0b\n"     /* <= 0: spin while write locked */
+       "       sub     %[val], %[val], 1       \n"     /* reader lock */
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bz      4f                      \n"     /* done */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val)
+         SCOND_FAIL_RETRY_VARS
+       : [rwlock]      "r"     (&(rw->counter)),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+       unsigned int val, got_it = 0;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brls    %[val], %[WR_LOCKED], 4f\n"     /* <= 0: already write locked, bail */
+       "       sub     %[val], %[val], 1       \n"     /* counter-- */
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bz.d    4f                      \n"
+       "       mov.z   %[got_it], 1            \n"     /* got it */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+         SCOND_FAIL_RETRY_VARS
+       : [rwlock]      "r"     (&(rw->counter)),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       /*
+        * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
+        * deny writer. Otherwise if unlocked grant to writer
+        * Hence the claim that Linux rwlocks are unfair to writers.
+        * (can be starved for an indefinite time by readers).
+        *
+        *      if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
+        *              rw->counter = 0;
+        *              ret = 1;
+        *      }
+        */
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brne    %[val], %[UNLOCKED], 0b \n"     /* while !UNLOCKED spin */
+       "       mov     %[val], %[WR_LOCKED]    \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bz      4f                      \n"
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val)
+         SCOND_FAIL_RETRY_VARS
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "ir"    (__ARCH_RW_LOCK_UNLOCKED__),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+       unsigned int val, got_it = 0;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brne    %[val], %[UNLOCKED], 4f \n"     /* !UNLOCKED, bail */
+       "       mov     %[val], %[WR_LOCKED]    \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bz.d    4f                      \n"
+       "       mov.z   %[got_it], 1            \n"     /* got it */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+         SCOND_FAIL_RETRY_VARS
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "ir"    (__ARCH_RW_LOCK_UNLOCKED__),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * rw->counter++;
+        */
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       add     %[val], %[val], 1       \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter))
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
+        */
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       scond   %[UNLOCKED], [%[rwlock]]\n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "r"     (__ARCH_RW_LOCK_UNLOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+#undef SCOND_FAIL_RETRY_VAR_DEF
+#undef SCOND_FAIL_RETRY_ASM
+#undef SCOND_FAIL_RETRY_VARS
+
+#endif /* CONFIG_ARC_STAR_9000923308 */
+
+#else  /* !CONFIG_ARC_HAS_LLSC */
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+       unsigned int val = __ARCH_SPIN_LOCK_LOCKED__;
 
        /*
         * This smp_mb() is technically superfluous, we only need the one
@@ -33,7 +542,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
        __asm__ __volatile__(
        "1:     ex  %0, [%1]            \n"
        "       breq  %0, %2, 1b        \n"
-       : "+&r" (tmp)
+       : "+&r" (val)
        : "r"(&(lock->slock)), "ir"(__ARCH_SPIN_LOCK_LOCKED__)
        : "memory");
 
@@ -48,26 +557,27 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
        smp_mb();
 }
 
+/* 1 - lock taken successfully */
 static inline int arch_spin_trylock(arch_spinlock_t *lock)
 {
-       unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__;
+       unsigned int val = __ARCH_SPIN_LOCK_LOCKED__;
 
        smp_mb();
 
        __asm__ __volatile__(
        "1:     ex  %0, [%1]            \n"
-       : "+r" (tmp)
+       : "+r" (val)
        : "r"(&(lock->slock))
        : "memory");
 
        smp_mb();
 
-       return (tmp == __ARCH_SPIN_LOCK_UNLOCKED__);
+       return (val == __ARCH_SPIN_LOCK_UNLOCKED__);
 }
 
 static inline void arch_spin_unlock(arch_spinlock_t *lock)
 {
-       unsigned int tmp = __ARCH_SPIN_LOCK_UNLOCKED__;
+       unsigned int val = __ARCH_SPIN_LOCK_UNLOCKED__;
 
        /*
         * RELEASE barrier: given the instructions avail on ARCv2, full barrier
@@ -77,7 +587,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 
        __asm__ __volatile__(
        "       ex  %0, [%1]            \n"
-       : "+r" (tmp)
+       : "+r" (val)
        : "r"(&(lock->slock))
        : "memory");
 
@@ -90,19 +600,12 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 
 /*
  * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
  *
  * The spinlock itself is contained in @counter and access to it is
  * serialized with @lock_mutex.
- *
- * Unfair locking as Writers could be starved indefinitely by Reader(s)
  */
 
-/* Would read_trylock() succeed? */
-#define arch_read_can_lock(x)  ((x)->counter > 0)
-
-/* Would write_trylock() succeed? */
-#define arch_write_can_lock(x) ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__)
-
 /* 1 - lock taken successfully */
 static inline int arch_read_trylock(arch_rwlock_t *rw)
 {
@@ -173,6 +676,11 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
        arch_spin_unlock(&(rw->lock_mutex));
 }
 
+#endif
+
+#define arch_read_can_lock(x)  ((x)->counter > 0)
+#define arch_write_can_lock(x) ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__)
+
 #define arch_read_lock_flags(lock, flags)      arch_read_lock(lock)
 #define arch_write_lock_flags(lock, flags)     arch_write_lock(lock)
 
index 662627ced4f23a966c85feffb9f9d38a4f7df10a..4e1ef5f650c6f2fc74ee1fbb09957d8d23e7b7da 100644 (file)
@@ -26,7 +26,9 @@ typedef struct {
  */
 typedef struct {
        volatile unsigned int   counter;
+#ifndef CONFIG_ARC_HAS_LLSC
        arch_spinlock_t         lock_mutex;
+#endif
 } arch_rwlock_t;
 
 #define __ARCH_RW_LOCK_UNLOCKED__      0x01000000
index 76a7739aab1c5173f397c0f8a5a79c5169489f41..0b3ef63d4a03b3ef2ff119535ee3c020641e1888 100644 (file)
 */
 struct user_regs_struct {
 
-       long pad;
+       unsigned long pad;
        struct {
-               long bta, lp_start, lp_end, lp_count;
-               long status32, ret, blink, fp, gp;
-               long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
-               long sp;
+               unsigned long bta, lp_start, lp_end, lp_count;
+               unsigned long status32, ret, blink, fp, gp;
+               unsigned long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
+               unsigned long sp;
        } scratch;
-       long pad2;
+       unsigned long pad2;
        struct {
-               long r25, r24, r23, r22, r21, r20;
-               long r19, r18, r17, r16, r15, r14, r13;
+               unsigned long r25, r24, r23, r22, r21, r20;
+               unsigned long r19, r18, r17, r16, r15, r14, r13;
        } callee;
-       long efa;       /* break pt addr, for break points in delay slots */
-       long stop_pc;   /* give dbg stop_pc after ensuring brkpt trap */
+       unsigned long efa;      /* break pt addr, for break points in delay slots */
+       unsigned long stop_pc;  /* give dbg stop_pc after ensuring brkpt trap */
 };
 #endif /* !__ASSEMBLY__ */
 
index 18cc01591c96e64186a8b13c1aef5b8011091b12..cabde9dc0696479cc3a4d3074fd526cf89c85182 100644 (file)
@@ -47,6 +47,7 @@ static void read_arc_build_cfg_regs(void)
        struct bcr_perip uncached_space;
        struct bcr_generic bcr;
        struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
+       unsigned long perip_space;
        FIX_PTR(cpu);
 
        READ_BCR(AUX_IDENTITY, cpu->core);
@@ -56,7 +57,12 @@ static void read_arc_build_cfg_regs(void)
        cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);
 
        READ_BCR(ARC_REG_D_UNCACH_BCR, uncached_space);
-       BUG_ON((uncached_space.start << 24) != ARC_UNCACHED_ADDR_SPACE);
+        if (uncached_space.ver < 3)
+               perip_space = uncached_space.start << 24;
+       else
+               perip_space = read_aux_reg(AUX_NON_VOL) & 0xF0000000;
+
+       BUG_ON(perip_space != ARC_UNCACHED_ADDR_SPACE);
 
        READ_BCR(ARC_REG_MUL_BCR, cpu->extn_mpy);
 
@@ -330,6 +336,10 @@ static void arc_chk_core_config(void)
                pr_warn("CONFIG_ARC_FPU_SAVE_RESTORE needed for working apps\n");
        else if (!cpu->extn.fpu_dp && fpu_enabled)
                panic("FPU non-existent, disable CONFIG_ARC_FPU_SAVE_RESTORE\n");
+
+       if (is_isa_arcv2() && IS_ENABLED(CONFIG_SMP) && cpu->isa.atomic &&
+           !IS_ENABLED(CONFIG_ARC_STAR_9000923308))
+               panic("llock/scond livelock workaround missing\n");
 }
 
 /*
index 3364d2bbc515471bba6478b8b34a417251ffde56..4294761a2b3e7ad3b36f5eca5bc26490e31ed61f 100644 (file)
@@ -203,34 +203,24 @@ static int arc_clkevent_set_next_event(unsigned long delta,
        return 0;
 }
 
-static void arc_clkevent_set_mode(enum clock_event_mode mode,
-                                 struct clock_event_device *dev)
+static int arc_clkevent_set_periodic(struct clock_event_device *dev)
 {
-       switch (mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-                /*
-                 * At X Hz, 1 sec = 1000ms -> X cycles;
-                 *                    10ms -> X / 100 cycles
-                 */
-               arc_timer_event_setup(arc_get_core_freq() / HZ);
-               break;
-       case CLOCK_EVT_MODE_ONESHOT:
-               break;
-       default:
-               break;
-       }
-
-       return;
+       /*
+        * At X Hz, 1 sec = 1000ms -> X cycles;
+        *                    10ms -> X / 100 cycles
+        */
+       arc_timer_event_setup(arc_get_core_freq() / HZ);
+       return 0;
 }
 
 static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = {
-       .name           = "ARC Timer0",
-       .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
-       .mode           = CLOCK_EVT_MODE_UNUSED,
-       .rating         = 300,
-       .irq            = TIMER0_IRQ,   /* hardwired, no need for resources */
-       .set_next_event = arc_clkevent_set_next_event,
-       .set_mode       = arc_clkevent_set_mode,
+       .name                   = "ARC Timer0",
+       .features               = CLOCK_EVT_FEAT_ONESHOT |
+                                 CLOCK_EVT_FEAT_PERIODIC,
+       .rating                 = 300,
+       .irq                    = TIMER0_IRQ,   /* hardwired, no need for resources */
+       .set_next_event         = arc_clkevent_set_next_event,
+       .set_state_periodic     = arc_clkevent_set_periodic,
 };
 
 static irqreturn_t timer_irq_handler(int irq, void *dev_id)
@@ -240,7 +230,7 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id)
         * irq_set_chip_and_handler() asked for handle_percpu_devid_irq()
         */
        struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
-       int irq_reenable = evt->mode == CLOCK_EVT_MODE_PERIODIC;
+       int irq_reenable = clockevent_state_periodic(evt);
 
        /*
         * Any write to CTRL reg ACks the interrupt, we rewrite the
index 1b2b3acfed52df6f1fb0aad58fa834d3d689482d..0cab0b8a57c5665e6686e9bef843fbfa51f141fd 100644 (file)
@@ -206,7 +206,7 @@ unalignedOffby3:
        ld.ab   r6, [r1, 4]
        prefetch [r1, 28]       ;Prefetch the next read location
        ld.ab   r8, [r1,4]
-       prefetch [r3, 32]       ;Prefetch the next write location
+       prefetchw [r3, 32]      ;Prefetch the next write location
 
        SHIFT_1 (r7, r6, 8)
        or      r7, r7, r5
index 92d573c734b5b3d52dec2d8fcf6eb67cc96d16f6..365b183648154c70de1726955b9242e88d3cc60c 100644 (file)
 
 #undef PREALLOC_NOT_AVAIL
 
-#ifdef PREALLOC_NOT_AVAIL
-#define PREWRITE(A,B)  prefetchw [(A),(B)]
-#else
-#define PREWRITE(A,B)  prealloc [(A),(B)]
-#endif
-
 ENTRY(memset)
        prefetchw [r0]          ; Prefetch the write location
        mov.f   0, r2
@@ -51,9 +45,15 @@ ENTRY(memset)
 
 ;;; Convert len to Dwords, unfold x8
        lsr.f   lp_count, lp_count, 6
+
        lpnz    @.Lset64bytes
        ;; LOOP START
-       PREWRITE(r3, 64)        ;Prefetch the next write location
+#ifdef PREALLOC_NOT_AVAIL
+       prefetchw [r3, 64]      ;Prefetch the next write location
+#else
+       prealloc  [r3, 64]
+#endif
+#ifdef CONFIG_ARC_HAS_LL64
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
@@ -62,16 +62,45 @@ ENTRY(memset)
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
+#else
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+#endif
 .Lset64bytes:
 
        lsr.f   lp_count, r2, 5 ;Last remaining  max 124 bytes
        lpnz    .Lset32bytes
        ;; LOOP START
        prefetchw   [r3, 32]    ;Prefetch the next write location
+#ifdef CONFIG_ARC_HAS_LL64
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
+#else
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+#endif
 .Lset32bytes:
 
        and.f   lp_count, r2, 0x1F ;Last remaining 31 bytes
index 99f7da513a48462031a58815d48428509bad0848..e7769c3ab5f2b7793aff703ca5e926983b45ec29 100644 (file)
@@ -389,6 +389,21 @@ axs103_set_freq(unsigned int id, unsigned int fd, unsigned int od)
 
 static void __init axs103_early_init(void)
 {
+       /*
+        * AXS103 configurations for SMP/QUAD configurations share device tree
+        * which defaults to 90 MHz. However recent failures of Quad config
+        * revealed P&R timing violations so clamp it down to safe 50 MHz
+        * Instead of duplicating defconfig/DT for SMP/QUAD, add a small hack
+        *
+        * This hack is really hacky as of now. Fix it properly by getting the
+        * number of cores as return value of platform's early SMP callback
+        */
+#ifdef CONFIG_ARC_MCIP
+       unsigned int num_cores = (read_aux_reg(ARC_REG_MCIP_BCR) >> 16) & 0x3F;
+       if (num_cores > 2)
+               arc_set_core_freq(50 * 1000000);
+#endif
+
        switch (arc_get_core_freq()/1000000) {
        case 33:
                axs103_set_freq(1, 1, 1);
index 07ab3d203916732337f909ec5f903db4c7bb1294..7451b447cc2d2cb8cc68a9bf59f125f2dd2ce347 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 8f1e25bcecbd76273f62671e8b9afa8f193ea261..1e29ccf77ea24f56fd16f8960d2b585ccc7ce9fc 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>;
                                ctrl-module = <&omap_control_sata>;
                                clocks = <&sys_clkin1>, <&sata_ref_clk>;
                                clock-names = "sysclk", "refclk";
+                               syscon-pllreset = <&scm_conf 0x3fc>;
                                #phy-cells = <0>;
                        };
 
index e6d13592080d7c701056c2f6a73326aa11e715b5..b57033e8c633187a5f52c367a788f46196967fdc 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 1b6494fbdb91b9301c607652efbd9a9fb34a9f36..675fb8e492c6aa0478a6d5df01b30fbe1e281b7d 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 ae6472407b2277012096d733bb80951592555d03..d0810a5f296857394397c7f1c60bffa0011bb6e1 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 0e007483615e4f097bb747a2d882b2e2d3a030aa..49fd414f680c93ab50cf0dae72d2e9261181da21 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 e7a6f6deabb6c0d89d4ca1e2c2ae63639249d010..72816d65f7ec3fcf5d7c47ce792ae57db369754b 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 11a7963be0035a002fa77c2bec6809b34444e584..2390f387c27163bb76e918bb73e26966bee7fb48 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 7d31c6ff246f47b14afd5eeb332d01a955faef35..abc4473e6f8a17e51d5e66416be089ab24d7b472 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 c8fd648a7108515def0e9492936fd3760f156579..b1a1263e600168291091a963f9f56aefc87fd59e 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 a75f3289e653ab2973e2d7dd1cb12c8a12724451..b8f81fb418ce60039ad4e8e04f2892ca34d26bc8 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 92828a1dec80c1c33d051d9b76063727598495d5..b48dd4f37f8067e781ee3e135ed7aff27940371f 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 bd755d97e459d77ff05cc8a1264f336c58c1b598..29e2991465cb27b579f729deec65e2293a0a04b5 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 efe17dd9b9218b7ef16299700a0f2a6d74ca61c1..54a5aeab988d3526657b8e3089942ca8cfe4fe5e 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 3e58d710013c3ad9b377fc76e6dad58f377e88a7..4b39af2dfda9963345afe18c89131c1056a90b41 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 6001f1c9d136f45fabd7d61e97638855d0beb46a..4a87e86dec45d1546153ca0ebb7310bbd5f82d93 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 8e52621b5a6bf3ab42ddef8a5c3db79c3391fcf1..e1d2e991d17a31fc15f1c44616c9b4b7f9de3a84 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 9d259d94e429c4cc493542ad4cf238a513b13743..1160434eece0509c3797733b49e8fcb1262e42e7 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 1670f15ef69e34972986081deb9b1f87b0bb2bb3..948f0ad2de231b5e3f5efa62e204162cadf26503 100644 (file)
@@ -168,7 +168,8 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
                 * Other callers might not initialize the si_lsb field,
                 * so check explicitely for the right codes here.
                 */
-               if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
+               if (from->si_signo == SIGBUS &&
+                   (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
                        err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
 #endif
                break;
@@ -201,8 +202,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
 
 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 {
-       memset(to, 0, sizeof *to);
-
        if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) ||
            copy_from_user(to->_sifields._pad,
                           from->_sifields._pad, SI_PAD_SIZE))
index ec37ab3f524f303419d2cc3a82b79c119e61de1d..97bc68f4c689f28eac7188f5e0b792b5293c37da 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 cee5f93e5712f3120d36847dc02d74709bc21929..199a8357838cb24bde2ce5ed5dec7db62feb8d2e 100644 (file)
@@ -151,7 +151,6 @@ config BMIPS_GENERIC
        select BCM7120_L2_IRQ
        select BRCMSTB_L2_IRQ
        select IRQ_MIPS_CPU
-       select RAW_IRQ_ACCESSORS
        select DMA_NONCOHERENT
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
index 01a644f174dd08e34843ca501035b077d777bea2..1ba21204ebe021ee164a9f8f4828dd3f3c836f84 100644 (file)
@@ -190,6 +190,7 @@ int get_c0_perfcount_int(void)
 {
        return ATH79_MISC_IRQ(5);
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
index 56f5d080ef9d6cb698ba70cf7027783167000284..b7fa9ae28c3659dbf457aecd7cd17255cd34f5da 100644 (file)
@@ -42,7 +42,7 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
        cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action);
 
        if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+               generic_smp_call_function_interrupt();
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
diff --git a/arch/mips/include/asm/mach-bcm63xx/dma-coherence.h b/arch/mips/include/asm/mach-bcm63xx/dma-coherence.h
deleted file mode 100644 (file)
index 11d3b57..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __ASM_MACH_BCM63XX_DMA_COHERENCE_H
-#define __ASM_MACH_BCM63XX_DMA_COHERENCE_H
-
-#include <asm/bmips.h>
-
-#define plat_post_dma_flush    bmips_post_dma_flush
-
-#include <asm/mach-generic/dma-coherence.h>
-
-#endif /* __ASM_MACH_BCM63XX_DMA_COHERENCE_H */
index 9d810675814291d14ce004f9d4447678af2227c3..ae85694752644339af22557a5ae424cde8271400 100644 (file)
@@ -182,8 +182,39 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
                 * Make sure the buddy is global too (if it's !none,
                 * it better already be global)
                 */
+#ifdef CONFIG_SMP
+               /*
+                * For SMP, multiple CPUs can race, so we need to do
+                * this atomically.
+                */
+#ifdef CONFIG_64BIT
+#define LL_INSN "lld"
+#define SC_INSN "scd"
+#else /* CONFIG_32BIT */
+#define LL_INSN "ll"
+#define SC_INSN "sc"
+#endif
+               unsigned long page_global = _PAGE_GLOBAL;
+               unsigned long tmp;
+
+               __asm__ __volatile__ (
+                       "       .set    push\n"
+                       "       .set    noreorder\n"
+                       "1:     " LL_INSN "     %[tmp], %[buddy]\n"
+                       "       bnez    %[tmp], 2f\n"
+                       "        or     %[tmp], %[tmp], %[global]\n"
+                       "       " SC_INSN "     %[tmp], %[buddy]\n"
+                       "       beqz    %[tmp], 1b\n"
+                       "        nop\n"
+                       "2:\n"
+                       "       .set pop"
+                       : [buddy] "+m" (buddy->pte),
+                         [tmp] "=&r" (tmp)
+                       : [global] "r" (page_global));
+#else /* !CONFIG_SMP */
                if (pte_none(*buddy))
                        pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL;
+#endif /* CONFIG_SMP */
        }
 #endif
 }
index 16f1ea9ab191234ee8dc5599803b91dcc2ccf745..03722d4326a1aad05935b58805ec8d881703201e 100644 (file)
@@ -83,8 +83,6 @@ static inline void __cpu_die(unsigned int cpu)
 extern void play_dead(void);
 #endif
 
-extern asmlinkage void smp_call_function_interrupt(void);
-
 static inline void arch_send_call_function_single_ipi(int cpu)
 {
        extern struct plat_smp_ops *mp_ops;     /* private */
index 28d6d9364bd1f2c431df08c72f58262e5297ec5c..a71da576883c8f4b1a3d60279ebfaefb95798031 100644 (file)
                .set    noreorder
                bltz    k0, 8f
                 move   k1, sp
+#ifdef CONFIG_EVA
+               /*
+                * Flush interAptiv's Return Prediction Stack (RPS) by writing
+                * EntryHi. Toggling Config7.RPS is slower and less portable.
+                *
+                * The RPS isn't automatically flushed when exceptions are
+                * taken, which can result in kernel mode speculative accesses
+                * to user addresses if the RPS mispredicts. That's harmless
+                * when user and kernel share the same address space, but with
+                * EVA the same user segments may be unmapped to kernel mode,
+                * even containing sensitive MMIO regions or invalid memory.
+                *
+                * This can happen when the kernel sets the return address to
+                * ret_from_* and jr's to the exception handler, which looks
+                * more like a tail call than a function call. If nested calls
+                * don't evict the last user address in the RPS, it will
+                * mispredict the return and fetch from a user controlled
+                * address into the icache.
+                *
+                * More recent EVA-capable cores with MAAR to restrict
+                * speculative accesses aren't affected.
+                */
+               MFC0    k0, CP0_ENTRYHI
+               MTC0    k0, CP0_ENTRYHI
+#endif
                .set    reorder
                /* Called from user mode, new stack. */
                get_saved_sp
index af42e7003f12d025cd31e2a5d167f2f4b158d37a..baa7b6fc0a60b1879976c2d4158f73d01e0ca53b 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 3e4491aa6d6b2425865e1d1a3a909cf05aaa4e28..789d7bf4fef3203b3038a9ddaf20c5f70f1bc948 100644 (file)
@@ -154,7 +154,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
                                      unsigned long __user *user_mask_ptr)
 {
        unsigned int real_len;
-       cpumask_t mask;
+       cpumask_t allowed, mask;
        int retval;
        struct task_struct *p;
 
@@ -173,7 +173,8 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
        if (retval)
                goto out_unlock;
 
-       cpumask_and(&mask, &p->thread.user_cpus_allowed, cpu_possible_mask);
+       cpumask_or(&allowed, &p->thread.user_cpus_allowed, &p->cpus_allowed);
+       cpumask_and(&mask, &allowed, cpu_active_mask);
 
 out_unlock:
        read_unlock(&tasklist_lock);
index b130033838ba0c391ef4f9f0c7aa19e5a50b6eb7..5fcec3032f38f6aebdf668af3318997e4f53921f 100644 (file)
@@ -38,7 +38,7 @@ char *mips_get_machine_name(void)
        return mips_machine_name;
 }
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_USE_OF
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
        return add_memory_region(base, size, BOOT_MEM_RAM);
index 74bab9ddd0e1984c9d4e4e95c038bb1d269b60dd..c6bbf21650515d1e71eead45b41a7729f8794476 100644 (file)
@@ -24,7 +24,7 @@ LEAF(relocate_new_kernel)
 
 process_entry:
        PTR_L           s2, (s0)
-       PTR_ADD         s0, s0, SZREG
+       PTR_ADDIU       s0, s0, SZREG
 
        /*
         * In case of a kdump/crash kernel, the indirection page is not
@@ -61,9 +61,9 @@ copy_word:
        /* copy page word by word */
        REG_L           s5, (s2)
        REG_S           s5, (s4)
-       PTR_ADD         s4, s4, SZREG
-       PTR_ADD         s2, s2, SZREG
-       LONG_SUB        s6, s6, 1
+       PTR_ADDIU       s4, s4, SZREG
+       PTR_ADDIU       s2, s2, SZREG
+       LONG_ADDIU      s6, s6, -1
        beq             s6, zero, process_entry
        b               copy_word
        b               process_entry
index ad4d44635c7601162ca0dd8f1b626df28eeeafb2..a6f6b762c47a4c5a2d395e13a1d564964595abe1 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 446cc654da56c5f5fcaad749242dd98d593776e1..4b2010654c463158b7dee80194de736195c04595 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 19a7705f2a015ef4b38e1cd0a16eb22c2a2d3ca3..5d7f2634996fd4920f0a4c94e00cd42fae5934b1 100644 (file)
@@ -409,8 +409,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
 
 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 {
-       memset(to, 0, sizeof *to);
-
        if (copy_from_user(to, from, 3*sizeof(int)) ||
            copy_from_user(to->_sifields._pad,
                           from->_sifields._pad, SI_PAD_SIZE32))
index 336708ae5c5b4c74b75416058feabb4bef5e30b1..78cf8c2f1de0e8790923d25ab6e42a85e53a6fe9 100644 (file)
@@ -284,7 +284,7 @@ static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id)
        if (action == 0)
                scheduler_ipi();
        else
-               smp_call_function_interrupt();
+               generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
@@ -336,7 +336,7 @@ static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
        if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+               generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index d0744cc77ea7f7a02d94c96faf190787f7e88f64..a31896c33716d424bb30397c17b29af07c6728bb 100644 (file)
@@ -192,16 +192,6 @@ asmlinkage void start_secondary(void)
        cpu_startup_entry(CPUHP_ONLINE);
 }
 
-/*
- * Call into both interrupt handlers, as we share the IPI for them
- */
-void __irq_entry smp_call_function_interrupt(void)
-{
-       irq_enter();
-       generic_smp_call_function_interrupt();
-       irq_exit();
-}
-
 static void stop_this_cpu(void *dummy)
 {
        /*
index e207a43b5f8f0bcbf0544e5289cfc08126cbc7f5..8ea28e6ab37dead56439dc37871b6b18e8ec02d5 100644 (file)
@@ -192,6 +192,7 @@ static void show_stacktrace(struct task_struct *task,
 void show_stack(struct task_struct *task, unsigned long *sp)
 {
        struct pt_regs regs;
+       mm_segment_t old_fs = get_fs();
        if (sp) {
                regs.regs[29] = (unsigned long)sp;
                regs.regs[31] = 0;
@@ -210,7 +211,13 @@ void show_stack(struct task_struct *task, unsigned long *sp)
                        prepare_frametrace(&regs);
                }
        }
+       /*
+        * show_stack() deals exclusively with kernel mode, so be sure to access
+        * the stack in the kernel (not user) address space.
+        */
+       set_fs(KERNEL_DS);
        show_stacktrace(task, &regs);
+       set_fs(old_fs);
 }
 
 static void show_code(unsigned int __user *pc)
@@ -1519,6 +1526,7 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
        const int field = 2 * sizeof(unsigned long);
        int multi_match = regs->cp0_status & ST0_TS;
        enum ctx_state prev_state;
+       mm_segment_t old_fs = get_fs();
 
        prev_state = exception_enter();
        show_regs(regs);
@@ -1540,8 +1548,13 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
                dump_tlb_all();
        }
 
+       if (!user_mode(regs))
+               set_fs(KERNEL_DS);
+
        show_code((unsigned int __user *) regs->cp0_epc);
 
+       set_fs(old_fs);
+
        /*
         * Some chips may have other causes of machine check (e.g. SB1
         * graduation timer)
index af84bef0c90de4bc65e14669dca132ebb7147846..eb3efd137fd17cdb6e1defa163744a480ad16185 100644 (file)
@@ -438,7 +438,7 @@ do {                                                        \
                : "memory");                                \
 } while(0)
 
-#define     StoreDW(addr, value, res) \
+#define     _StoreDW(addr, value, res) \
 do {                                                        \
                __asm__ __volatile__ (                      \
                        ".set\tpush\n\t"                    \
index 6ab10573490de8a2d5a449e45c3585547c51f7c4..2c218c3bbca57be3d029cdb3320b712092bccd46 100644 (file)
@@ -293,7 +293,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
        return IRQ_HANDLED;
 }
 
@@ -466,6 +466,7 @@ int get_c0_perfcount_int(void)
 {
        return ltq_perfcount_irq;
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
index 509877c6e9d908d7bac6110982c7208ab69204af..1a4738a8f2d3906ccffb58bdf8d9b35ee4b04ef3 100644 (file)
@@ -266,8 +266,11 @@ void loongson3_ipi_interrupt(struct pt_regs *regs)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
-       if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
 
        if (action & SMP_ASK_C0COUNT) {
                BUG_ON(cpu != 0);
index 77d96db8253c422ac9e48d93e02c6b6f39b41c1b..aab218c36e0d3e2f7669c47343e583e527103169 100644 (file)
@@ -160,18 +160,18 @@ static inline void setup_protection_map(void)
                protection_map[1]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC);
                protection_map[2]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ);
                protection_map[3]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC);
-               protection_map[4]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ);
+               protection_map[4]  = __pgprot(_page_cachable_default | _PAGE_PRESENT);
                protection_map[5]  = __pgprot(_page_cachable_default | _PAGE_PRESENT);
-               protection_map[6]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ);
+               protection_map[6]  = __pgprot(_page_cachable_default | _PAGE_PRESENT);
                protection_map[7]  = __pgprot(_page_cachable_default | _PAGE_PRESENT);
 
                protection_map[8]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ);
                protection_map[9]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC);
                protection_map[10] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE | _PAGE_NO_READ);
                protection_map[11] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE);
-               protection_map[12] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ);
+               protection_map[12] = __pgprot(_page_cachable_default | _PAGE_PRESENT);
                protection_map[13] = __pgprot(_page_cachable_default | _PAGE_PRESENT);
-               protection_map[14] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE  | _PAGE_NO_READ);
+               protection_map[14] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE);
                protection_map[15] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE);
 
        } else {
index 36c0f26fac6b0780318958a59fc2665a444a10ea..852a41c6da4507080d611dce0b1fc206caf30556 100644 (file)
@@ -133,7 +133,8 @@ good_area:
 #endif
                                goto bad_area;
                        }
-                       if (!(vma->vm_flags & VM_READ)) {
+                       if (!(vma->vm_flags & VM_READ) &&
+                           exception_epc(regs) != address) {
 #if 0
                                pr_notice("Cpu%d[%s:%d:%0*lx:%ld:%0*lx] RI violation\n",
                                          raw_smp_processor_id(),
index d1392f8f5811f65ec72445026ac12c4fe15fe6b1..fa8f591f371361ba6fe3654617e6f44690a48a25 100644 (file)
@@ -222,7 +222,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index 5625b190edc061afbf2a8885e976b48014270325..b7bf721eabf5411bfb2f55b6b7d2cdc9ba887f96 100644 (file)
@@ -154,6 +154,7 @@ int get_c0_perfcount_int(void)
 
        return mips_cpu_perf_irq;
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
@@ -171,14 +172,17 @@ unsigned int get_c0_compare_int(void)
 
 static void __init init_rtc(void)
 {
-       /* stop the clock whilst setting it up */
-       CMOS_WRITE(RTC_SET | RTC_24H, RTC_CONTROL);
+       unsigned char freq, ctrl;
 
-       /* 32KHz time base */
-       CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT);
+       /* Set 32KHz time base if not already set */
+       freq = CMOS_READ(RTC_FREQ_SELECT);
+       if ((freq & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ)
+               CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT);
 
-       /* start the clock */
-       CMOS_WRITE(RTC_24H, RTC_CONTROL);
+       /* Ensure SET bit is clear so RTC can run */
+       ctrl = CMOS_READ(RTC_CONTROL);
+       if (ctrl & RTC_SET)
+               CMOS_WRITE(ctrl & ~RTC_SET, RTC_CONTROL);
 }
 
 void __init plat_time_init(void)
index e1d69895fb1de44f5d8503027f86ebb50f40d5a6..a120b7a5a8fe4e9af03ccb40fc9e7e123f88d633 100644 (file)
@@ -77,6 +77,7 @@ int get_c0_perfcount_int(void)
                return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
        return -1;
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
index dc3e327fbbac105e71c6b89a039e0f79f91e6f3d..f5fff228b347b6da07d68212fb11f4ae140548c8 100644 (file)
@@ -86,7 +86,7 @@ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc)
 {
        clear_c0_eimr(irq);
        ack_c0_eirr(irq);
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
        set_c0_eimr(irq);
 }
 
index 42181c7105df70992892ead68933bcd5375ab74b..f8d3e081b2ebc77e6752dc10a61a69e9a8172b3d 100644 (file)
@@ -114,7 +114,7 @@ static irqreturn_t paravirt_reched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t paravirt_function_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
        return IRQ_HANDLED;
 }
 
index 7c73fcb92a108799866c8d603019129d33c57ee6..8a377346f0cabbf5ce91199ca039ec013b16dda1 100644 (file)
@@ -26,6 +26,7 @@ int get_c0_perfcount_int(void)
 {
        return gic_get_c0_perfcount_int();
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 int get_c0_fdc_int(void)
 {
index 10170580a2def4501bb4f149c707d050a900246f..ffa0f7101a9773ec8e24813f37e3c270d912b5e2 100644 (file)
@@ -44,7 +44,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index 53707aacc0f86cb13134546de07ccaf71d76321d..8c624a8b9ea29f5611abceb531de09c865e46b7c 100644 (file)
@@ -89,6 +89,7 @@ int get_c0_perfcount_int(void)
 {
        return rt_perfcount_irq;
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
index 3fbaef97a1b8d31791e8999bd222e3e1b01c3701..16ec4e12daa3fb7bed3355a5cd56cdb3c87946fc 100644 (file)
@@ -107,10 +107,14 @@ static void ip27_do_irq_mask0(void)
                scheduler_ipi();
        } else if (pend0 & (1UL << CPU_CALL_A_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ);
-               smp_call_function_interrupt();
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
        } else if (pend0 & (1UL << CPU_CALL_B_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_CALL_B_IRQ);
-               smp_call_function_interrupt();
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
        } else
 #endif
        {
index af7d44edd9a8f118b79944ecf21310634f308b56..4c71aea2566372c3f3af8627c79e91fb9aede4ea 100644 (file)
@@ -29,8 +29,6 @@
 #include <asm/sibyte/bcm1480_regs.h>
 #include <asm/sibyte/bcm1480_int.h>
 
-extern void smp_call_function_interrupt(void);
-
 /*
  * These are routines for dealing with the bcm1480 smp capabilities
  * independent of board/firmware
@@ -184,6 +182,9 @@ void bcm1480_mailbox_interrupt(void)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
-       if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
 }
index c0c4b3f88a086f2c331cce0b311d9c547d3b5a6a..1cf66f5ff23d1a5afca26ffd9bc638566d8f68cb 100644 (file)
@@ -172,6 +172,9 @@ void sb1250_mailbox_interrupt(void)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
-       if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
 }
index d3a831ac0f927e17304d55c406c60029ad55a4e0..da50e0c9c57e69af8779f0df979231104704ab6e 100644 (file)
@@ -966,8 +966,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s)
 
 int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
 {
-       memset(to, 0, sizeof *to);
-
        if (copy_from_user(to, from, 3*sizeof(int)) ||
            copy_from_user(to->_sifields._pad,
                           from->_sifields._pad, SI_PAD_SIZE32))
index 2078f92d15ac90adcfec617b46df750e073b76d0..f32f843a3631359e49b88169ab8a1eed2b76b946 100644 (file)
@@ -1742,10 +1742,10 @@ static bool ibs_enabled(struct kvm_vcpu *vcpu)
 
 static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
 {
-       if (!vcpu->requests)
-               return 0;
 retry:
        kvm_s390_vcpu_request_handled(vcpu);
+       if (!vcpu->requests)
+               return 0;
        /*
         * We use MMU_RELOAD just to re-arm the ipte notifier for the
         * guest prefix page. gmap_ipte_notify will wait on the ptl lock.
index 1f0aa2024e94be341efc079f58145a2e70909052..6424249d5f785e698c4283677c1b975668393478 100644 (file)
  * Must preserve %o5 between VISEntryHalf and VISExitHalf */
 
 #define VISEntryHalf                                   \
-       rd              %fprs, %o5;                     \
-       andcc           %o5, FPRS_FEF, %g0;             \
-       be,pt           %icc, 297f;                     \
-        sethi          %hi(298f), %g7;                 \
-       sethi           %hi(VISenterhalf), %g1;         \
-       jmpl            %g1 + %lo(VISenterhalf), %g0;   \
-        or             %g7, %lo(298f), %g7;            \
-       clr             %o5;                            \
-297:   wr              %o5, FPRS_FEF, %fprs;           \
-298:
+       VISEntry
+
+#define VISExitHalf                                    \
+       VISExit
 
 #define VISEntryHalfFast(fail_label)                   \
        rd              %fprs, %o5;                     \
@@ -47,7 +41,7 @@
        ba,a,pt         %xcc, fail_label;               \
 297:   wr              %o5, FPRS_FEF, %fprs;
 
-#define VISExitHalf                                    \
+#define VISExitHalfFast                                        \
        wr              %o5, 0, %fprs;
 
 #ifndef __ASSEMBLY__
index 140527a20e7df03cc0a0dd9e6a3438f44b432177..83aeeb1dffdb3b4c29293d5924cd5259e2269ce5 100644 (file)
@@ -240,8 +240,11 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
        add             %o0, 0x40, %o0
        bne,pt          %icc, 1b
         LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
+#ifdef NON_USER_COPY
+       VISExitHalfFast
+#else
        VISExitHalf
-
+#endif
        brz,pn          %o2, .Lexit
         cmp            %o2, 19
        ble,pn          %icc, .Lsmall_unaligned
index b320ae9e2e2e8b27c7184f58ddc640b4adf6fdda..a063d84336d6384a03d7ddd8a5143f0909801ed8 100644 (file)
@@ -44,9 +44,8 @@ vis1: ldub            [%g6 + TI_FPSAVED], %g3
 
         stx            %g3, [%g6 + TI_GSR]
 2:     add             %g6, %g1, %g3
-       cmp             %o5, FPRS_DU
-       be,pn           %icc, 6f
-        sll            %g1, 3, %g1
+       mov             FPRS_DU | FPRS_DL | FPRS_FEF, %o5
+       sll             %g1, 3, %g1
        stb             %o5, [%g3 + TI_FPSAVED]
        rd              %gsr, %g2
        add             %g6, %g1, %g3
@@ -80,65 +79,3 @@ vis1:        ldub            [%g6 + TI_FPSAVED], %g3
        .align          32
 80:    jmpl            %g7 + %g0, %g0
         nop
-
-6:     ldub            [%g3 + TI_FPSAVED], %o5
-       or              %o5, FPRS_DU, %o5
-       add             %g6, TI_FPREGS+0x80, %g2
-       stb             %o5, [%g3 + TI_FPSAVED]
-
-       sll             %g1, 5, %g1
-       add             %g6, TI_FPREGS+0xc0, %g3
-       wr              %g0, FPRS_FEF, %fprs
-       membar          #Sync
-       stda            %f32, [%g2 + %g1] ASI_BLK_P
-       stda            %f48, [%g3 + %g1] ASI_BLK_P
-       membar          #Sync
-       ba,pt           %xcc, 80f
-        nop
-
-       .align          32
-80:    jmpl            %g7 + %g0, %g0
-        nop
-
-       .align          32
-VISenterhalf:
-       ldub            [%g6 + TI_FPDEPTH], %g1
-       brnz,a,pn       %g1, 1f
-        cmp            %g1, 1
-       stb             %g0, [%g6 + TI_FPSAVED]
-       stx             %fsr, [%g6 + TI_XFSR]
-       clr             %o5
-       jmpl            %g7 + %g0, %g0
-        wr             %g0, FPRS_FEF, %fprs
-
-1:     bne,pn          %icc, 2f
-        srl            %g1, 1, %g1
-       ba,pt           %xcc, vis1
-        sub            %g7, 8, %g7
-2:     addcc           %g6, %g1, %g3
-       sll             %g1, 3, %g1
-       andn            %o5, FPRS_DU, %g2
-       stb             %g2, [%g3 + TI_FPSAVED]
-
-       rd              %gsr, %g2
-       add             %g6, %g1, %g3
-       stx             %g2, [%g3 + TI_GSR]
-       add             %g6, %g1, %g2
-       stx             %fsr, [%g2 + TI_XFSR]
-       sll             %g1, 5, %g1
-3:     andcc           %o5, FPRS_DL, %g0
-       be,pn           %icc, 4f
-        add            %g6, TI_FPREGS, %g2
-
-       add             %g6, TI_FPREGS+0x40, %g3
-       membar          #Sync
-       stda            %f0, [%g2 + %g1] ASI_BLK_P
-       stda            %f16, [%g3 + %g1] ASI_BLK_P
-       membar          #Sync
-       ba,pt           %xcc, 4f
-        nop
-
-       .align          32
-4:     and             %o5, FPRS_DU, %o5
-       jmpl            %g7 + %g0, %g0
-        wr             %o5, FPRS_FEF, %fprs
index 1d649a95660c8cad57fbe90feadb7c43b9e8263f..8069ce12f20b13d514160cec8db0c0d88b64b27e 100644 (file)
@@ -135,10 +135,6 @@ EXPORT_SYMBOL(copy_user_page);
 void VISenter(void);
 EXPORT_SYMBOL(VISenter);
 
-/* CRYPTO code needs this */
-void VISenterhalf(void);
-EXPORT_SYMBOL(VISenterhalf);
-
 extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *);
 extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *,
                unsigned long *);
index e8c2c04143cda81db9b51018a449b611263ab68d..c667e104a0c251d73f02ce2b812ed09878ca79a0 100644 (file)
@@ -113,8 +113,6 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
        if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
                return -EFAULT;
 
-       memset(to, 0, sizeof(*to));
-
        err = __get_user(to->si_signo, &from->si_signo);
        err |= __get_user(to->si_errno, &from->si_errno);
        err |= __get_user(to->si_code, &from->si_code);
index 5a1844765a7aba6dab47b878daf6eb723c044c03..a7e257d9cb90b9f34ecb03180fec8c54f2afd82f 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 6fe6b182c9981dd891a9a5bc9a55b3e6591a6f9f..9dfce4e0417d92adc623d32ff93f67109316b451 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 751bf4b7bf114da12231a56f4217c2583ddeafb2..d7f3b3b78ac313ca8a871d3a53b3d118850a657d 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 0e8a973de9ee8aec0c555a5e9e8b23348e2cc10b..40836a9a7250c99a16dc5969057177f66aa57186 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 f813261d97405710c99cd0982d047a227a4c4fd3..2683f36e4e0a5e67311a7bcdbceea61c17382ec6 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 b9826a981fb20fa45a7c1255e277e9ad1cd5d150..6326ae24e4d5b4f3d228111c10f5c85df0e40d3f 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 63eb68b73589bcbbc21f9c526193adca0de2e52d..377e8f8ed39186ad4ef57b33264592ed8459a037 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 79de954626fd971f1d24553078bed1f199d52267..d25097c3fc1d1af8af35c156f05121f9f4d46a94 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 1e173f6285c73b76b2e6ab41daed7681406c5d15..d14e9ac3235a1ac73174ffb95b2990d5163d2933 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 397688beed4be5ce7d9445d7847d44613d2d84b5..c27cad7267655c3794972344adf0b7924e38c138 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 206996c1669db344aba7ff072f734552723e7938..71820c42b6ce6bc1020bbc44277967d7e23f011e 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 6273324186ac5ca7adba69be5ded69f23d8882f7..0ccb53a9fcd9361b83c7acd26e1f64601816a3d1 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 dc0a84a6f3094ac997701de74c868763e6843229..9e8bf13572e6dc3f95d33d24f079d63e256a3a7a 100644 (file)
@@ -672,16 +672,16 @@ u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
        if (iter.mtrr_disabled)
                return mtrr_disabled_type();
 
+       /* not contained in any MTRRs. */
+       if (type == -1)
+               return mtrr_default_type(mtrr_state);
+
        /*
         * We just check one page, partially covered by MTRRs is
         * impossible.
         */
        WARN_ON(iter.partial_map);
 
-       /* not contained in any MTRRs. */
-       if (type == -1)
-               return mtrr_default_type(mtrr_state);
-
        return type;
 }
 EXPORT_SYMBOL_GPL(kvm_mtrr_get_guest_memory_type);
index 5ef2560075bfb80e6fdabcdf51f71258091e4339..8f0f6eca69da1dc6db95c16782871580bf57091d 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 f37e84ab49f38e335bde57880a6cbe8640fb2c4b..3d8f2e421466a8af255eba9602748fee8753a377 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 9ccecb61a4fa129a82028b27edc18b91a2f99042..5e044d506b7aae8b17b2142966b11477cfe8e372 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 6ef5e99380f92134ba86a6a693b5ac6d3434e6d4..8300db71c2a62681006e137350961742190ec9dc 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 e88fda867a33b198bc356aded57d59f48fcfb4ee..484145368a241207d8aa80a5f758a7d0f3ef54cb 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 7322755f337af760db6086450591c584c4dcda77..4b6e29ac0968c1a76451d3ff773652bc4afed138 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 c20fe29e65f48b4706789e0ad59bb33b1a3acc18..2292721b1d103844ade9f8a7f436a649c811f77d 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 12600bfffca93f4547e2325eeda9669ff443a7a7..e0057d035200c4dd5e42d191f0395a7769489905 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 a3da6770bc9ed2bf66d59e8e74461829eeb4fe4e..b8efe36ce1142d0c6b0b8e45ec23965ec7135c40 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 815f75ef24119eab28ce3c0c2047295c6e464c58..2922f1f252d58aafd2d6c233404ae7ca21abb524 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 ce1e3a8859815ca5724e376de6d6ab0d549c9831..14b7305d2ba0b3cc24aa101e76c87e242f01f537 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 db5d9f79a247c5ceb2cb590f206927c22f6f2b7c..19bcb80b20313932021b1ee613eed97f4473e17e 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 7465031a893c60c9e61f2c911abf218b39c81d2e..cb0508af1459ac43f4aa26f1a16d94134bd9d0bc 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 641a61a59e89c00036af65d3a31fe2cf67eb22b8..0d7f0da3a26929622080f94a2a3125c63676999e 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 a998a175f9f144b50e4df782bbf7d1afd5f506cb..f840ca18a7c014f5151d22e4bc55dff9fca459de 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 3a18a8a719b4ff1fa562a515b4701da241e4aeb7..fab504fd9cfd7ace54d772927a01650373d02206 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 b2b2849fc6d3b34d1294a02ef009a10af86d49de..873ddf91c9d3ec742ceb1c3a9959ac322adc16db 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 81751a49d8bf2334612350bba52406b9af352258..56486d92c4e72bd583630baea0fba541f36c926f 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 7111d04f26218be0529f4702cb1b361ae07a0b00..0a849eeaf952aefdca5fc7793fe339a5de4b96e2 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 d94529d5c8e951378eaf62d74b708edf271a550f..bc67a93aa4f4749f10d1a219789b21661c01ee21 100644 (file)
@@ -523,6 +523,7 @@ void rbd_warn(struct rbd_device *rbd_dev, const char *fmt, ...)
 #  define rbd_assert(expr)     ((void) 0)
 #endif /* !RBD_DEBUG */
 
+static void rbd_osd_copyup_callback(struct rbd_obj_request *obj_request);
 static int rbd_img_obj_request_submit(struct rbd_obj_request *obj_request);
 static void rbd_img_parent_read(struct rbd_obj_request *obj_request);
 static void rbd_dev_remove_parent(struct rbd_device *rbd_dev);
@@ -1818,6 +1819,16 @@ static void rbd_osd_stat_callback(struct rbd_obj_request *obj_request)
        obj_request_done_set(obj_request);
 }
 
+static void rbd_osd_call_callback(struct rbd_obj_request *obj_request)
+{
+       dout("%s: obj %p\n", __func__, obj_request);
+
+       if (obj_request_img_data_test(obj_request))
+               rbd_osd_copyup_callback(obj_request);
+       else
+               obj_request_done_set(obj_request);
+}
+
 static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
                                struct ceph_msg *msg)
 {
@@ -1866,6 +1877,8 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
                rbd_osd_discard_callback(obj_request);
                break;
        case CEPH_OSD_OP_CALL:
+               rbd_osd_call_callback(obj_request);
+               break;
        case CEPH_OSD_OP_NOTIFY_ACK:
        case CEPH_OSD_OP_WATCH:
                rbd_osd_trivial_callback(obj_request);
@@ -2530,13 +2543,15 @@ out_unwind:
 }
 
 static void
-rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request)
+rbd_osd_copyup_callback(struct rbd_obj_request *obj_request)
 {
        struct rbd_img_request *img_request;
        struct rbd_device *rbd_dev;
        struct page **pages;
        u32 page_count;
 
+       dout("%s: obj %p\n", __func__, obj_request);
+
        rbd_assert(obj_request->type == OBJ_REQUEST_BIO ||
                obj_request->type == OBJ_REQUEST_NODATA);
        rbd_assert(obj_request_img_data_test(obj_request));
@@ -2563,9 +2578,7 @@ rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request)
        if (!obj_request->result)
                obj_request->xferred = obj_request->length;
 
-       /* Finish up with the normal image object callback */
-
-       rbd_img_obj_callback(obj_request);
+       obj_request_done_set(obj_request);
 }
 
 static void
@@ -2650,7 +2663,6 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
 
        /* All set, send it off. */
 
-       orig_request->callback = rbd_img_obj_copyup_callback;
        osdc = &rbd_dev->rbd_client->client->osdc;
        img_result = rbd_obj_request_submit(osdc, orig_request);
        if (!img_result)
index ced96777b677b9bcddd65bae004a7a51b5cf0dc3..954c0029fb3babc49d1a1f490f9d420934701e30 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 6d89ed35d80c0caaf8bf57ba82c7e9f3a9194bb9..7a8a73f1fc0462feab5bad706573ff6eb4536ef7 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 fb655e8d1e3b17bf4cda9fd09593bc7dc770f78d..763301c7828c72650f2abaa1c723425bdd3c73f4 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 da8faf78536a3ae01827a2ee9480c486a04297a5..5643b65cee204d950d842529e0a12123f57e92c0 100644 (file)
@@ -429,7 +429,7 @@ static int hwrng_fillfn(void *unused)
 static void start_khwrngd(void)
 {
        hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
-       if (hwrng_fill == ERR_PTR(-ENOMEM)) {
+       if (IS_ERR(hwrng_fill)) {
                pr_err("hwrng_fill thread creation failed");
                hwrng_fill = NULL;
        }
index 4b93a1efb36d11fa7171735d29bac283e4bb6d97..ac03ba49e9d1952dff14e9383ed86874690a7176 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 b8ff3c64cc452a16fc4108426fb6e5b1c54e91e8..c96de14036a0adebfc7628dc9f9cd5413b5c5495 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 2d59038dec43512e40ca46f4a0989c3b1253e0af..86c7eb66bdfb2e18628997319aa047b1aedc1da1 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 ae5b2bd3a9785c63646e3e922fbe17330678b481..fa3dd840a83771735e474a658a5c6516c62f76a0 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 e362860c2b50c49ad5289169e68b8baa2a90197c..cd593c1f66dc8af8a6208933003783e0f37b7392 100644 (file)
@@ -20,7 +20,7 @@
 #include <asm/clock.h>
 #include <asm/idle.h>
 
-#include <asm/mach-loongson/loongson.h>
+#include <asm/mach-loongson64/loongson.h>
 
 static uint nowait;
 
index dae1e8099969a192b302703ec291da96ebac3429..f9c78751989ec865491570ed13bf19dbc6b1a799 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 7ba495f7537042f898ef1cd7cdba7a6263f2059b..402631a19a112770af83f0f4228176703e1c0b44 100644 (file)
@@ -905,7 +905,6 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt)
                crypt->mode |= NPE_OP_NOT_IN_PLACE;
                /* This was never tested by Intel
                 * for more than one dst buffer, I think. */
-               BUG_ON(req->dst->length < nbytes);
                req_ctx->dst = NULL;
                if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook,
                                        flags, DMA_FROM_DEVICE))
index 08f8d5cd633491e3ff0e28ca8204d7f51be2b05b..becb738c897b1b5d93b632e3ab80ed2b146ead5a 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 aff0fe58eac0b7aba11b465a192c280ef19fdbac..b6e183d58d73d5a4e38fff2925344783e8e581bc 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 067402c7c2a93fdc02ca3242f918deba460dae91..df427c0e9e7b2c99c8ee6cbe0c91b98c1ff47c43 100644 (file)
@@ -73,7 +73,8 @@
                                       ICP_QAT_HW_CIPHER_KEY_CONVERT, \
                                       ICP_QAT_HW_CIPHER_DECRYPT)
 
-static atomic_t active_dev;
+static DEFINE_MUTEX(algs_lock);
+static unsigned int active_devs;
 
 struct qat_alg_buf {
        uint32_t len;
@@ -1280,7 +1281,10 @@ static struct crypto_alg qat_algs[] = { {
 
 int qat_algs_register(void)
 {
-       if (atomic_add_return(1, &active_dev) == 1) {
+       int ret = 0;
+
+       mutex_lock(&algs_lock);
+       if (++active_devs == 1) {
                int i;
 
                for (i = 0; i < ARRAY_SIZE(qat_algs); i++)
@@ -1289,21 +1293,25 @@ int qat_algs_register(void)
                                CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC :
                                CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
 
-               return crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs));
+               ret = crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs));
        }
-       return 0;
+       mutex_unlock(&algs_lock);
+       return ret;
 }
 
 int qat_algs_unregister(void)
 {
-       if (atomic_sub_return(1, &active_dev) == 0)
-               return crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs));
-       return 0;
+       int ret = 0;
+
+       mutex_lock(&algs_lock);
+       if (--active_devs == 0)
+               ret = crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs));
+       mutex_unlock(&algs_lock);
+       return ret;
 }
 
 int qat_algs_init(void)
 {
-       atomic_set(&active_dev, 0);
        crypto_get_default_rng();
        return 0;
 }
index 4a4cce15f25dd65c6a720d949ed0d9c922ff1cba..3ff284c8e3d5aef72f229017c883c73cbe13403f 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 3515b381c1312612f56953bc267ee7d5d23b0f84..711d8ad74f116ebdcc7fd3833fbc0672c7a6359b 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 080d5cc2705529962d2a62b17fe3f597b5bc41e3..eebdf2a33bfe4b84e1fc1886e7222641f4a56122 100644 (file)
@@ -200,7 +200,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
        status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev);
        if (status) {
                dev_err(&pdev->dev, "failed to register extcon device\n");
-               kfree(palmas_usb->edev->name);
                return status;
        }
 
@@ -214,7 +213,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
                if (status < 0) {
                        dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
                                        palmas_usb->id_irq, status);
-                       kfree(palmas_usb->edev->name);
                        return status;
                }
        }
@@ -229,7 +227,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
                if (status < 0) {
                        dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
                                        palmas_usb->vbus_irq, status);
-                       kfree(palmas_usb->edev->name);
                        return status;
                }
        }
@@ -239,15 +236,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int palmas_usb_remove(struct platform_device *pdev)
-{
-       struct palmas_usb *palmas_usb = platform_get_drvdata(pdev);
-
-       kfree(palmas_usb->edev->name);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int palmas_usb_suspend(struct device *dev)
 {
@@ -288,7 +276,6 @@ static const struct of_device_id of_palmas_match_tbl[] = {
 
 static struct platform_driver palmas_usb_driver = {
        .probe = palmas_usb_probe,
-       .remove = palmas_usb_remove,
        .driver = {
                .name = "palmas-usb",
                .of_match_table = of_palmas_match_tbl,
index 76157ab9faf3ad84a16e738a4e338ad1bded8e3c..43b57b02d050d197fe7994ea744231b7a580eb23 100644 (file)
@@ -124,25 +124,35 @@ static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id
        return -EINVAL;
 }
 
-static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
+static int find_cable_id_by_name(struct extcon_dev *edev, const char *name)
 {
-       unsigned int id = EXTCON_NONE;
+       unsigned int id = -EINVAL;
        int i = 0;
 
-       if (edev->max_supported == 0)
-               return -EINVAL;
-
-       /* Find the the number of extcon cable */
+       /* Find the id of extcon cable */
        while (extcon_name[i]) {
                if (!strncmp(extcon_name[i], name, CABLE_NAME_MAX)) {
                        id = i;
                        break;
                }
+               i++;
        }
 
-       if (id == EXTCON_NONE)
+       return id;
+}
+
+static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
+{
+       unsigned int id;
+
+       if (edev->max_supported == 0)
                return -EINVAL;
 
+       /* Find the the number of extcon cable */
+       id = find_cable_id_by_name(edev, name);
+       if (id < 0)
+               return id;
+
        return find_cable_index_by_id(edev, id);
 }
 
@@ -228,9 +238,11 @@ static ssize_t cable_state_show(struct device *dev,
        struct extcon_cable *cable = container_of(attr, struct extcon_cable,
                                                  attr_state);
 
+       int i = cable->cable_index;
+
        return sprintf(buf, "%d\n",
                       extcon_get_cable_state_(cable->edev,
-                                              cable->cable_index));
+                                              cable->edev->supported_cable[i]));
 }
 
 /**
@@ -263,20 +275,25 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
        spin_lock_irqsave(&edev->lock, flags);
 
        if (edev->state != ((edev->state & ~mask) | (state & mask))) {
+               u32 old_state;
+
                if (check_mutually_exclusive(edev, (edev->state & ~mask) |
                                                   (state & mask))) {
                        spin_unlock_irqrestore(&edev->lock, flags);
                        return -EPERM;
                }
 
-               for (index = 0; index < edev->max_supported; index++) {
-                       if (is_extcon_changed(edev->state, state, index, &attached))
-                               raw_notifier_call_chain(&edev->nh[index], attached, edev);
-               }
-
+               old_state = edev->state;
                edev->state &= ~mask;
                edev->state |= state & mask;
 
+               for (index = 0; index < edev->max_supported; index++) {
+                       if (is_extcon_changed(old_state, edev->state, index,
+                                             &attached))
+                               raw_notifier_call_chain(&edev->nh[index],
+                                                       attached, edev);
+               }
+
                /* This could be in interrupt handler */
                prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
                if (prop_buf) {
@@ -361,8 +378,13 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
  */
 int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
 {
-       return extcon_get_cable_state_(edev, find_cable_index_by_name
-                                               (edev, cable_name));
+       unsigned int id;
+
+       id = find_cable_id_by_name(edev, cable_name);
+       if (id < 0)
+               return id;
+
+       return extcon_get_cable_state_(edev, id);
 }
 EXPORT_SYMBOL_GPL(extcon_get_cable_state);
 
@@ -404,8 +426,13 @@ EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
 int extcon_set_cable_state(struct extcon_dev *edev,
                        const char *cable_name, bool cable_state)
 {
-       return extcon_set_cable_state_(edev, find_cable_index_by_name
-                                       (edev, cable_name), cable_state);
+       unsigned int id;
+
+       id = find_cable_id_by_name(edev, cable_name);
+       if (id < 0)
+               return id;
+
+       return extcon_set_cable_state_(edev, id, cable_state);
 }
 EXPORT_SYMBOL_GPL(extcon_set_cable_state);
 
index 87add3fdce529b1ad6890cb24adb345275e4655c..e41594510b978291de179182c46b0196b3a377e3 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 31b00f91cfcd5a04848be288837d6d90c0110f44..f7b49d5ce4b81d471fa3c84280560b9d0e774c78 100644 (file)
@@ -1130,6 +1130,9 @@ struct amdgpu_gfx {
        uint32_t                        me_feature_version;
        uint32_t                        ce_feature_version;
        uint32_t                        pfp_feature_version;
+       uint32_t                        rlc_feature_version;
+       uint32_t                        mec_feature_version;
+       uint32_t                        mec2_feature_version;
        struct amdgpu_ring              gfx_ring[AMDGPU_MAX_GFX_RINGS];
        unsigned                        num_gfx_rings;
        struct amdgpu_ring              compute_ring[AMDGPU_MAX_COMPUTE_RINGS];
@@ -1639,6 +1642,7 @@ struct amdgpu_sdma {
        /* SDMA firmware */
        const struct firmware   *fw;
        uint32_t                fw_version;
+       uint32_t                feature_version;
 
        struct amdgpu_ring      ring;
 };
index 9736892bcdf932c328a883473a6c3e23d560cd38..3bfe67de834904628e0e4e11677c706c4848fde7 100644 (file)
@@ -317,16 +317,17 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                        break;
                case AMDGPU_INFO_FW_GFX_RLC:
                        fw_info.ver = adev->gfx.rlc_fw_version;
-                       fw_info.feature = 0;
+                       fw_info.feature = adev->gfx.rlc_feature_version;
                        break;
                case AMDGPU_INFO_FW_GFX_MEC:
-                       if (info->query_fw.index == 0)
+                       if (info->query_fw.index == 0) {
                                fw_info.ver = adev->gfx.mec_fw_version;
-                       else if (info->query_fw.index == 1)
+                               fw_info.feature = adev->gfx.mec_feature_version;
+                       } else if (info->query_fw.index == 1) {
                                fw_info.ver = adev->gfx.mec2_fw_version;
-                       else
+                               fw_info.feature = adev->gfx.mec2_feature_version;
+                       } else
                                return -EINVAL;
-                       fw_info.feature = 0;
                        break;
                case AMDGPU_INFO_FW_SMC:
                        fw_info.ver = adev->pm.fw_version;
@@ -336,7 +337,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                        if (info->query_fw.index >= 2)
                                return -EINVAL;
                        fw_info.ver = adev->sdma[info->query_fw.index].fw_version;
-                       fw_info.feature = 0;
+                       fw_info.feature = adev->sdma[info->query_fw.index].feature_version;
                        break;
                default:
                        return -EINVAL;
index 2f7a5efa21c23ab0fda25ee0ebbb360efae966ea..f5c22556ec2c17ff145c48440dfe5e3563e67606 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 ab83cc1ca4cc04865b0bf918c410a4351496fb22..15df46c93f0a3d9e0810b9018ba761bfaa2cc418 100644 (file)
@@ -500,6 +500,7 @@ static int cik_sdma_load_microcode(struct amdgpu_device *adev)
                amdgpu_ucode_print_sdma_hdr(&hdr->header);
                fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
                adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+               adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version);
                fw_data = (const __le32 *)
                        (adev->sdma[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
                WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], 0);
index 2db6ab0a543dada20b64d3d5d89eb4d5f36a1873..0d8bf2cb195603b8be90346a58eabfee62670d23 100644 (file)
@@ -3080,6 +3080,8 @@ static int gfx_v7_0_cp_compute_load_microcode(struct amdgpu_device *adev)
        mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
        amdgpu_ucode_print_gfx_hdr(&mec_hdr->header);
        adev->gfx.mec_fw_version = le32_to_cpu(mec_hdr->header.ucode_version);
+       adev->gfx.mec_feature_version = le32_to_cpu(
+                                       mec_hdr->ucode_feature_version);
 
        gfx_v7_0_cp_compute_enable(adev, false);
 
@@ -3102,6 +3104,8 @@ static int gfx_v7_0_cp_compute_load_microcode(struct amdgpu_device *adev)
                mec2_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
                amdgpu_ucode_print_gfx_hdr(&mec2_hdr->header);
                adev->gfx.mec2_fw_version = le32_to_cpu(mec2_hdr->header.ucode_version);
+               adev->gfx.mec2_feature_version = le32_to_cpu(
+                               mec2_hdr->ucode_feature_version);
 
                /* MEC2 */
                fw_data = (const __le32 *)
@@ -4066,6 +4070,8 @@ static int gfx_v7_0_rlc_resume(struct amdgpu_device *adev)
        hdr = (const struct rlc_firmware_header_v1_0 *)adev->gfx.rlc_fw->data;
        amdgpu_ucode_print_rlc_hdr(&hdr->header);
        adev->gfx.rlc_fw_version = le32_to_cpu(hdr->header.ucode_version);
+       adev->gfx.rlc_feature_version = le32_to_cpu(
+                                       hdr->ucode_feature_version);
 
        gfx_v7_0_rlc_stop(adev);
 
@@ -5122,7 +5128,7 @@ static void gfx_v7_0_print_status(void *handle)
                dev_info(adev->dev, "  CP_HPD_EOP_CONTROL=0x%08X\n",
                         RREG32(mmCP_HPD_EOP_CONTROL));
 
-               for (queue = 0; queue < 8; i++) {
+               for (queue = 0; queue < 8; queue++) {
                        cik_srbm_select(adev, me, pipe, queue, 0);
                        dev_info(adev->dev, "  queue: %d\n", queue);
                        dev_info(adev->dev, "  CP_PQ_WPTR_POLL_CNTL=0x%08X\n",
index 9e1d4ddbf475027e10c6e0d6d77a63efb4eec3b3..20e2cfd521d5352202070f357de89234175cb800 100644 (file)
@@ -587,6 +587,7 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        int err;
        struct amdgpu_firmware_info *info = NULL;
        const struct common_firmware_header *header = NULL;
+       const struct gfx_firmware_header_v1_0 *cp_hdr;
 
        DRM_DEBUG("\n");
 
@@ -611,6 +612,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        err = amdgpu_ucode_validate(adev->gfx.pfp_fw);
        if (err)
                goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
+       adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name);
        err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
@@ -619,6 +623,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        err = amdgpu_ucode_validate(adev->gfx.me_fw);
        if (err)
                goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
+       adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name);
        err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev);
@@ -627,12 +634,18 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        err = amdgpu_ucode_validate(adev->gfx.ce_fw);
        if (err)
                goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
+       adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name);
        err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
        if (err)
                goto out;
        err = amdgpu_ucode_validate(adev->gfx.rlc_fw);
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.rlc_fw->data;
+       adev->gfx.rlc_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.rlc_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name);
        err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev);
@@ -641,6 +654,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        err = amdgpu_ucode_validate(adev->gfx.mec_fw);
        if (err)
                goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
+       adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name);
        err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
@@ -648,6 +664,12 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
                err = amdgpu_ucode_validate(adev->gfx.mec2_fw);
                if (err)
                        goto out;
+               cp_hdr = (const struct gfx_firmware_header_v1_0 *)
+                                               adev->gfx.mec2_fw->data;
+               adev->gfx.mec2_fw_version = le32_to_cpu(
+                                               cp_hdr->header.ucode_version);
+               adev->gfx.mec2_feature_version = le32_to_cpu(
+                                               cp_hdr->ucode_feature_version);
        } else {
                err = 0;
                adev->gfx.mec2_fw = NULL;
@@ -1983,6 +2005,7 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
                adev->gfx.config.max_shader_engines = 1;
                adev->gfx.config.max_tile_pipes = 2;
                adev->gfx.config.max_sh_per_se = 1;
+               adev->gfx.config.max_backends_per_se = 2;
 
                switch (adev->pdev->revision) {
                case 0xc4:
@@ -1991,7 +2014,6 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
                case 0xcc:
                        /* B10 */
                        adev->gfx.config.max_cu_per_sh = 8;
-                       adev->gfx.config.max_backends_per_se = 2;
                        break;
                case 0xc5:
                case 0x81:
@@ -2000,14 +2022,12 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
                case 0xcd:
                        /* B8 */
                        adev->gfx.config.max_cu_per_sh = 6;
-                       adev->gfx.config.max_backends_per_se = 2;
                        break;
                case 0xc6:
                case 0xca:
                case 0xce:
                        /* B6 */
                        adev->gfx.config.max_cu_per_sh = 6;
-                       adev->gfx.config.max_backends_per_se = 2;
                        break;
                case 0xc7:
                case 0x87:
@@ -2015,7 +2035,6 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
                default:
                        /* B4 */
                        adev->gfx.config.max_cu_per_sh = 4;
-                       adev->gfx.config.max_backends_per_se = 1;
                        break;
                }
 
@@ -2275,7 +2294,6 @@ static int gfx_v8_0_rlc_load_microcode(struct amdgpu_device *adev)
 
        hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data;
        amdgpu_ucode_print_rlc_hdr(&hdr->header);
-       adev->gfx.rlc_fw_version = le32_to_cpu(hdr->header.ucode_version);
 
        fw_data = (const __le32 *)(adev->gfx.rlc_fw->data +
                           le32_to_cpu(hdr->header.ucode_array_offset_bytes));
@@ -2361,12 +2379,6 @@ static int gfx_v8_0_cp_gfx_load_microcode(struct amdgpu_device *adev)
        amdgpu_ucode_print_gfx_hdr(&pfp_hdr->header);
        amdgpu_ucode_print_gfx_hdr(&ce_hdr->header);
        amdgpu_ucode_print_gfx_hdr(&me_hdr->header);
-       adev->gfx.pfp_fw_version = le32_to_cpu(pfp_hdr->header.ucode_version);
-       adev->gfx.ce_fw_version = le32_to_cpu(ce_hdr->header.ucode_version);
-       adev->gfx.me_fw_version = le32_to_cpu(me_hdr->header.ucode_version);
-       adev->gfx.me_feature_version = le32_to_cpu(me_hdr->ucode_feature_version);
-       adev->gfx.ce_feature_version = le32_to_cpu(ce_hdr->ucode_feature_version);
-       adev->gfx.pfp_feature_version = le32_to_cpu(pfp_hdr->ucode_feature_version);
 
        gfx_v8_0_cp_gfx_enable(adev, false);
 
@@ -2622,7 +2634,6 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev)
 
        mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
        amdgpu_ucode_print_gfx_hdr(&mec_hdr->header);
-       adev->gfx.mec_fw_version = le32_to_cpu(mec_hdr->header.ucode_version);
 
        fw_data = (const __le32 *)
                (adev->gfx.mec_fw->data +
@@ -2641,7 +2652,6 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev)
 
                mec2_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
                amdgpu_ucode_print_gfx_hdr(&mec2_hdr->header);
-               adev->gfx.mec2_fw_version = le32_to_cpu(mec2_hdr->header.ucode_version);
 
                fw_data = (const __le32 *)
                        (adev->gfx.mec2_fw->data +
@@ -3125,7 +3135,7 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
                                WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER,
                                       AMDGPU_DOORBELL_KIQ << 2);
                                WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER,
-                                               0x7FFFF << 2);
+                                      AMDGPU_DOORBELL_MEC_RING7 << 2);
                        }
                        tmp = RREG32(mmCP_HQD_PQ_DOORBELL_CONTROL);
                        tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
index d7895885fe0cf3b3e7cd5d1ae52f291053420b17..a988dfb1d3942e9246361bfd7b97bdabc5e5286c 100644 (file)
@@ -121,6 +121,7 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev)
        int err, i;
        struct amdgpu_firmware_info *info = NULL;
        const struct common_firmware_header *header = NULL;
+       const struct sdma_firmware_header_v1_0 *hdr;
 
        DRM_DEBUG("\n");
 
@@ -142,6 +143,9 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev)
                err = amdgpu_ucode_validate(adev->sdma[i].fw);
                if (err)
                        goto out;
+               hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
+               adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+               adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version);
 
                if (adev->firmware.smu_load) {
                        info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i];
@@ -541,8 +545,6 @@ static int sdma_v2_4_load_microcode(struct amdgpu_device *adev)
                        hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
                        amdgpu_ucode_print_sdma_hdr(&hdr->header);
                        fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
-                       adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
-
                        fw_data = (const __le32 *)
                                (adev->sdma[i].fw->data +
                                 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
index 7bb37b93993fb5312eb2d46189bf09bf789c3989..2b86569b18d3656c87975175a1ff771599c958d6 100644 (file)
@@ -159,6 +159,7 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
        int err, i;
        struct amdgpu_firmware_info *info = NULL;
        const struct common_firmware_header *header = NULL;
+       const struct sdma_firmware_header_v1_0 *hdr;
 
        DRM_DEBUG("\n");
 
@@ -183,6 +184,9 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
                err = amdgpu_ucode_validate(adev->sdma[i].fw);
                if (err)
                        goto out;
+               hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
+               adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+               adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version);
 
                if (adev->firmware.smu_load) {
                        info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i];
@@ -630,8 +634,6 @@ static int sdma_v3_0_load_microcode(struct amdgpu_device *adev)
                hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
                amdgpu_ucode_print_sdma_hdr(&hdr->header);
                fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
-               adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
-
                fw_data = (const __le32 *)
                        (adev->sdma[i].fw->data +
                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
index 6fad1f9648f38870b2162cb74a6320f50c34aabc..ef6182bc8e5eef229dc990354f6d31c18915f3bc 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 aac212297b49fb1953dab1749f23dcd77977bcb7..9dcc7280e5720255baed2786ab7d8fc11554c845 100644 (file)
@@ -196,7 +196,12 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
        }
 
        funcs = connector->helper_private;
-       new_encoder = funcs->best_encoder(connector);
+
+       if (funcs->atomic_best_encoder)
+               new_encoder = funcs->atomic_best_encoder(connector,
+                                                        connector_state);
+       else
+               new_encoder = funcs->best_encoder(connector);
 
        if (!new_encoder) {
                DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n",
@@ -229,13 +234,14 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
                }
        }
 
+       if (WARN_ON(!connector_state->crtc))
+               return -EINVAL;
+
        connector_state->best_encoder = new_encoder;
-       if (connector_state->crtc) {
-               idx = drm_crtc_index(connector_state->crtc);
+       idx = drm_crtc_index(connector_state->crtc);
 
-               crtc_state = state->crtc_states[idx];
-               crtc_state->mode_changed = true;
-       }
+       crtc_state = state->crtc_states[idx];
+       crtc_state->mode_changed = true;
 
        DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n",
                         connector->base.id,
index 778bbb6425b80c9c8affddad58d993a93755c39e..eb603f1defc2250ea158864ea4371e24655138e1 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);
 
@@ -1294,7 +1295,6 @@ retry:
                                goto retry;
                        }
                        DRM_DEBUG_KMS("failed to dpcd write %d %d\n", tosend, ret);
-                       WARN(1, "fail\n");
 
                        return -EIO;
                }
@@ -2660,7 +2660,7 @@ static void drm_dp_tx_work(struct work_struct *work)
 static void drm_dp_destroy_connector_work(struct work_struct *work)
 {
        struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
-       struct drm_connector *connector;
+       struct drm_dp_mst_port *port;
 
        /*
         * Not a regular list traverse as we have to drop the destroy
@@ -2669,15 +2669,21 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
         */
        for (;;) {
                mutex_lock(&mgr->destroy_connector_lock);
-               connector = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_connector, destroy_list);
-               if (!connector) {
+               port = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_dp_mst_port, next);
+               if (!port) {
                        mutex_unlock(&mgr->destroy_connector_lock);
                        break;
                }
-               list_del(&connector->destroy_list);
+               list_del(&port->next);
                mutex_unlock(&mgr->destroy_connector_lock);
 
-               mgr->cbs->destroy_connector(mgr, connector);
+               mgr->cbs->destroy_connector(mgr, port->connector);
+
+               drm_dp_port_teardown_pdt(port, port->pdt);
+
+               if (!port->input && port->vcpi.vcpi > 0)
+                       drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
+               kfree(port);
        }
 }
 
index f9cc68fbd2a3e18b076ad2ced71b8f1ddf002202..b50fa0afd9071f6c64c36de23253a2ee22ce7480 100644 (file)
@@ -75,7 +75,7 @@ module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600)
 module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
 
 static void store_vblank(struct drm_device *dev, int crtc,
-                        unsigned vblank_count_inc,
+                        u32 vblank_count_inc,
                         struct timeval *t_vblank)
 {
        struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
index 842d6b8dc3c435ee7d836402d4169847aef75d31..2a652359af644b51f257cde7528d70b6016897da 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 8040ed2a831f9a6f226baf8aee3ce00b213be8e6..f1c6b76c127f4db02388267775431fcd25ac7eb8 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 99e286489031c4a2931565823e0158428548aef2..4a00990e4ae4e8459b94a9a007044af1cc11af62 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 cae98db3306205e2628b2090b731cf6cfdf79d4f..4706b56902b44f5ba205b30d3aa6e53678bbad52 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 2aaa3c88999e32c0f951312b48aedded13f837e0..00416f23b5cb5fef4bbdf9ade8d2a794737d6789 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 fe1599d75f14e39b2a39364b78d088d4715c368f..424228be79ae5b2aa1557ca07331e4e49e665ef8 100644 (file)
@@ -606,8 +606,6 @@ static void
 tda998x_write_if(struct tda998x_priv *priv, uint8_t bit, uint16_t addr,
                 uint8_t *buf, size_t size)
 {
-       buf[PB(0)] = tda998x_cksum(buf, size);
-
        reg_clear(priv, REG_DIP_IF_FLAGS, bit);
        reg_write_range(priv, addr, buf, size);
        reg_set(priv, REG_DIP_IF_FLAGS, bit);
@@ -627,6 +625,8 @@ tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p)
        buf[PB(4)] = p->audio_frame[4];
        buf[PB(5)] = p->audio_frame[5] & 0xf8; /* DM_INH + LSV */
 
+       buf[PB(0)] = tda998x_cksum(buf, sizeof(buf));
+
        tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf,
                         sizeof(buf));
 }
index 7ed8033aae6097af69d90e83bb6c97f7dc6f7225..8e35e0d013df556d8ac04fc27f9ba2bd7354fae3 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 30e0f54ba19d1284107958bb6e5d49f6309b63de..87476ff181ddbef0967d948c37119cfcbd758315 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 6e8faa25379240cab60f57631adf42612f28df33..1df0e1fe235f112830a0e82a1004b0e949613c78 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 6e4cc5334f47d7105b60c0bec72fccfb4875ddac..600afdbef8c9a434f51d527c5d85e202c36bae2b 100644 (file)
@@ -357,6 +357,16 @@ intel_dp_mst_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
+static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector,
+                                                        struct drm_connector_state *state)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_dp *intel_dp = intel_connector->mst_port;
+       struct intel_crtc *crtc = to_intel_crtc(state->crtc);
+
+       return &intel_dp->mst_encoders[crtc->pipe]->base.base;
+}
+
 static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connector)
 {
        struct intel_connector *intel_connector = to_intel_connector(connector);
@@ -367,6 +377,7 @@ static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connecto
 static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = {
        .get_modes = intel_dp_mst_get_modes,
        .mode_valid = intel_dp_mst_mode_valid,
+       .atomic_best_encoder = intel_mst_atomic_best_encoder,
        .best_encoder = intel_mst_best_encoder,
 };
 
index 9b74ffae5f5a7bab8ef545525d361c29fd4c3bf6..7f2161a1ff5d4d40c7b6dca346c20518b084bf6b 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 52c22b02600598cfa7d18e424d69a99cce4879e7..e10f9644140f5d9fcd6e73446c74634d2b13906a 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 1162bfa464f3036192854f4d0f3f363eb1ee8cff..171d3e43c30cc02257df75645c6c77f0a726de33 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 654c8daeb5ab3d0dd84a2ed1d32af633d6955ac9..97ad3bcb99a75a441a54150f779415dc59236ac7 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 3511bbaba505a4524ad382297ec1e486e21e7e48..e3c63640df737d5527c6d2609622417a4e03c8d3 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 94167310e15a4c95001d339d4da3b7319f9005eb..b905d501e752d607b6fc1731ad89ff3d23ce7cd0 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 44958d79d598dfc3a7e6938a2babbf3e1fdc2188..01b937e63cf37ec1424a1aad9eee0caef682c010 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 37c16afe007a0524eaacb5edcae9399bebfae897..c8487894b31236cefd761b24cac48fb4e17e6d52 100644 (file)
@@ -929,6 +929,21 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
 
 MODULE_DEVICE_TABLE(dmi, i8k_dmi_table);
 
+static struct dmi_system_id i8k_blacklist_dmi_table[] __initdata = {
+       {
+               /*
+                * CPU fan speed going up and down on Dell Studio XPS 8100
+                * for unknown reasons.
+                */
+               .ident = "Dell Studio XPS 8100",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Studio XPS 8100"),
+               },
+       },
+       { }
+};
+
 /*
  * Probe for the presence of a supported laptop.
  */
@@ -940,7 +955,8 @@ static int __init i8k_probe(void)
        /*
         * Get DMI information
         */
-       if (!dmi_check_system(i8k_dmi_table)) {
+       if (!dmi_check_system(i8k_dmi_table) ||
+           dmi_check_system(i8k_blacklist_dmi_table)) {
                if (!ignore_dmi && !force)
                        return -ENODEV;
 
index 9b55e673b67caf1365c7452ce51a22a37510af02..85d106fe3ce8628061901b53240e546a884cbea0 100644 (file)
@@ -582,6 +582,7 @@ static const struct of_device_id g762_dt_match[] = {
        { .compatible = "gmt,g763" },
        { },
 };
+MODULE_DEVICE_TABLE(of, g762_dt_match);
 
 /*
  * Grab clock (a required property), enable it, get (fixed) clock frequency
index 6153df735e82ca4fd3d605e159510675410546fc..08ff89d222e5ff79a3c5cf37fa1b7729f70fe303 100644 (file)
@@ -575,6 +575,7 @@ static const struct i2c_device_id nct7904_id[] = {
        {"nct7904", 0},
        {}
 };
+MODULE_DEVICE_TABLE(i2c, nct7904_id);
 
 static struct i2c_driver nct7904_driver = {
        .class = I2C_CLASS_HWMON,
index af162b4c7a6d9b8b30756c53147eb3de458b3d5e..025686d4164058498216862d37af9ad114fe4fa2 100644 (file)
@@ -692,7 +692,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, iface);
 
-       dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, "
+       dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Controller, "
                "regs_base@%p\n", iface->regs_base);
 
        return 0;
@@ -735,6 +735,6 @@ subsys_initcall(i2c_bfin_twi_init);
 module_exit(i2c_bfin_twi_exit);
 
 MODULE_AUTHOR("Bryan Wu, Sonic Zhang");
-MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver");
+MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Controller Driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:i2c-bfin-twi");
index d1c22e3fdd146a34d96adcdd35b81a6e15984824..fc9bf7f30e355dfadfcadd4f7d8f187f818e9566 100644 (file)
@@ -1247,7 +1247,14 @@ static void omap_i2c_prepare_recovery(struct i2c_adapter *adap)
        u32 reg;
 
        reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+       /* enable test mode */
        reg |= OMAP_I2C_SYSTEST_ST_EN;
+       /* select SDA/SCL IO mode */
+       reg |= 3 << OMAP_I2C_SYSTEST_TMODE_SHIFT;
+       /* set SCL to high-impedance state (reset value is 0) */
+       reg |= OMAP_I2C_SYSTEST_SCL_O;
+       /* set SDA to high-impedance state (reset value is 0) */
+       reg |= OMAP_I2C_SYSTEST_SDA_O;
        omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
 }
 
@@ -1257,7 +1264,11 @@ static void omap_i2c_unprepare_recovery(struct i2c_adapter *adap)
        u32 reg;
 
        reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+       /* restore reset values */
        reg &= ~OMAP_I2C_SYSTEST_ST_EN;
+       reg &= ~OMAP_I2C_SYSTEST_TMODE_MASK;
+       reg &= ~OMAP_I2C_SYSTEST_SCL_O;
+       reg &= ~OMAP_I2C_SYSTEST_SDA_O;
        omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
 }
 
index e6d4935161e4902762f6042847838428ec34faf2..c83e4d13cfc5c402dfdea64df08f399ab486822b 100644 (file)
@@ -567,6 +567,9 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
        if (bri->prepare_recovery)
                bri->prepare_recovery(adap);
 
+       bri->set_scl(adap, val);
+       ndelay(RECOVERY_NDELAY);
+
        /*
         * By this time SCL is high, as we need to give 9 falling-rising edges
         */
@@ -597,7 +600,6 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
 
 int i2c_generic_scl_recovery(struct i2c_adapter *adap)
 {
-       adap->bus_recovery_info->set_scl(adap, 1);
        return i2c_generic_recovery(adap);
 }
 EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery);
@@ -1338,13 +1340,17 @@ static int of_dev_node_match(struct device *dev, void *data)
 struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
 {
        struct device *dev;
+       struct i2c_client *client;
 
-       dev = bus_find_device(&i2c_bus_type, NULL, node,
-                                        of_dev_node_match);
+       dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
        if (!dev)
                return NULL;
 
-       return i2c_verify_client(dev);
+       client = i2c_verify_client(dev);
+       if (!client)
+               put_device(dev);
+
+       return client;
 }
 EXPORT_SYMBOL(of_find_i2c_device_by_node);
 
@@ -1352,13 +1358,17 @@ EXPORT_SYMBOL(of_find_i2c_device_by_node);
 struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
 {
        struct device *dev;
+       struct i2c_adapter *adapter;
 
-       dev = bus_find_device(&i2c_bus_type, NULL, node,
-                                        of_dev_node_match);
+       dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
        if (!dev)
                return NULL;
 
-       return i2c_verify_adapter(dev);
+       adapter = i2c_verify_adapter(dev);
+       if (!adapter)
+               put_device(dev);
+
+       return adapter;
 }
 EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
 #else
index 8223746546093c7a08f4bdfc8425459d88fe1a52..1da44961477953038e78409169f80a3f4884f89a 100644 (file)
@@ -80,9 +80,6 @@ static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj
        struct eeprom_data *eeprom;
        unsigned long flags;
 
-       if (off + count > attr->size)
-               return -EFBIG;
-
        eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
 
        spin_lock_irqsave(&eeprom->buffer_lock, flags);
@@ -98,9 +95,6 @@ static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kob
        struct eeprom_data *eeprom;
        unsigned long flags;
 
-       if (off + count > attr->size)
-               return -EFBIG;
-
        eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
 
        spin_lock_irqsave(&eeprom->buffer_lock, flags);
index c7aab48f07cdfcdebf3efb6374416619c9095e04..92d518382a9fce90c3e1dbae45034675072da274 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 27b6a3ce18caf2e996177e6c313fff2b21a4ad19..891797ad76bccda3ae132e1fc59483b539e522ee 100644 (file)
@@ -196,7 +196,7 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
                if (n_buttons[i] < 1)
                        continue;
 
-               if (n_buttons[i] > 6) {
+               if (n_buttons[i] > ARRAY_SIZE(tgfx_buttons)) {
                        printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]);
                        err = -EINVAL;
                        goto err_unreg_devs;
index 097d7216d98ee4e4d394726e9d4c9743067d14f8..c6dc644aa5806b37cb4e0dcbbc6217d915e8a562 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 10e140af5aac1a9ea309d2b237af065cc7abf684..1ac898db303afe84edd003a03129eb0f27518837 100644 (file)
@@ -292,3 +292,4 @@ module_platform_driver(axp20x_pek_driver);
 MODULE_DESCRIPTION("axp20x Power Button");
 MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:axp20x-pek");
index e5d60ecd29a4d6adc2ae63cdfe69fea935edeb58..f5c9cf2f4073adf8671aaae0287dcf83e64d8c52 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 0afaa33de07d2d46e59e3a44d204ec4322e035ba..924456e3ca75d71af762287f28f8b15d71024692 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 fc0fddf0896a772f911f36decd1fdbadaa727f7d..047136aa646f28c9b5f52dd3d988a0d5e2b9aeef 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 fc17b9592f5435238d980cc30d266a4ee399415a..10c4e3d462f112f15ec9843093c5f988d44780b9 100644 (file)
@@ -183,7 +183,8 @@ static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
        if (pdata && pdata->coexist)
                return true;
 
-       if (of_find_node_by_name(node, "codec")) {
+       node = of_find_node_by_name(node, "codec");
+       if (node) {
                of_node_put(node);
                return true;
        }
index 113d6f1516a54956f74635f7eb51231ab5490052..4d246861d692b810f3074aa7917cda86893ac6c2 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/input/mt.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
+#include <linux/dmi.h>
 
 #include "psmouse.h"
 #include "alps.h"
@@ -99,6 +100,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
 #define ALPS_FOUR_BUTTONS      0x40    /* 4 direction button present */
 #define ALPS_PS2_INTERLEAVED   0x80    /* 3-byte PS/2 packet interleaved with
                                           6-byte ALPS packet */
+#define ALPS_DELL              0x100   /* device is a Dell laptop */
 #define ALPS_BUTTONPAD         0x200   /* device is a clickpad */
 
 static const struct alps_model_info alps_model_data[] = {
@@ -251,9 +253,9 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
                return;
        }
 
-       /* Non interleaved V2 dualpoint has separate stick button bits */
+       /* Dell non interleaved V2 dualpoint has separate stick button bits */
        if (priv->proto_version == ALPS_PROTO_V2 &&
-           priv->flags == (ALPS_PASS | ALPS_DUALPOINT)) {
+           priv->flags == (ALPS_DELL | ALPS_PASS | ALPS_DUALPOINT)) {
                left |= packet[0] & 1;
                right |= packet[0] & 2;
                middle |= packet[0] & 4;
@@ -2550,6 +2552,8 @@ static int alps_set_protocol(struct psmouse *psmouse,
        priv->byte0 = protocol->byte0;
        priv->mask0 = protocol->mask0;
        priv->flags = protocol->flags;
+       if (dmi_name_in_vendors("Dell"))
+               priv->flags |= ALPS_DELL;
 
        priv->x_max = 2000;
        priv->y_max = 1400;
index 22b9ca901f4e96c22499ce9723c0d2bd897c6fbb..2955f1d0ca6c4c9137f786028ca36bff706beab2 100644 (file)
@@ -783,19 +783,26 @@ static int elantech_packet_check_v4(struct psmouse *psmouse)
        struct elantech_data *etd = psmouse->private;
        unsigned char *packet = psmouse->packet;
        unsigned char packet_type = packet[3] & 0x03;
+       unsigned int ic_version;
        bool sanity_check;
 
        if (etd->tp_dev && (packet[3] & 0x0f) == 0x06)
                return PACKET_TRACKPOINT;
 
+       /* This represents the version of IC body. */
+       ic_version = (etd->fw_version & 0x0f0000) >> 16;
+
        /*
         * Sanity check based on the constant bits of a packet.
         * The constant bits change depending on the value of
-        * the hardware flag 'crc_enabled' but are the same for
-        * every packet, regardless of the type.
+        * the hardware flag 'crc_enabled' and the version of
+        * the IC body, but are the same for every packet,
+        * regardless of the type.
         */
        if (etd->crc_enabled)
                sanity_check = ((packet[3] & 0x08) == 0x00);
+       else if (ic_version == 7 && etd->samples[1] == 0x2A)
+               sanity_check = ((packet[3] & 0x1c) == 0x10);
        else
                sanity_check = ((packet[0] & 0x0c) == 0x04 &&
                                (packet[3] & 0x1c) == 0x10);
@@ -1116,6 +1123,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
  * Avatar AVIU-145A2       0x361f00        ?               clickpad
  * Fujitsu LIFEBOOK E544   0x470f00        d0, 12, 09      2 hw buttons
  * Fujitsu LIFEBOOK E554   0x570f01        40, 14, 0c      2 hw buttons
+ * Fujitsu T725            0x470f01        05, 12, 09      2 hw buttons
  * Fujitsu H730            0x570f00        c0, 14, 0c      3 hw buttons (**)
  * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons
  * Lenovo L430             0x350f02        b9, 15, 0c      2 hw buttons (*)
@@ -1651,6 +1659,16 @@ int elantech_init(struct psmouse *psmouse)
                     etd->capabilities[0], etd->capabilities[1],
                     etd->capabilities[2]);
 
+       if (etd->hw_version != 1) {
+               if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, etd->samples)) {
+                       psmouse_err(psmouse, "failed to query sample data\n");
+                       goto init_fail;
+               }
+               psmouse_info(psmouse,
+                            "Elan sample query result %02x, %02x, %02x\n",
+                            etd->samples[0], etd->samples[1], etd->samples[2]);
+       }
+
        if (elantech_set_absolute_mode(psmouse)) {
                psmouse_err(psmouse,
                            "failed to put touchpad into absolute mode.\n");
index f965d1569cc338059cdd540bad44ed927c6ddc3e..e1cbf409d9c8d0d4e7d21e13d57851ae6565b535 100644 (file)
@@ -129,6 +129,7 @@ struct elantech_data {
        unsigned char reg_26;
        unsigned char debug;
        unsigned char capabilities[3];
+       unsigned char samples[3];
        bool paritycheck;
        bool jumpy_cursor;
        bool reports_pressure;
index 692fe2bc81979b6b48f984ec6d88c117fbfdebdd..c12bb93334ff99e7a5ddc72d274b00c4eeb9c24c 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 b7d54d428b5e55d1520d52e68b95202593cf4b53..ff4be0515a0dc7dbb206ae0a84968f922817101e 100644 (file)
@@ -538,7 +538,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index 32814371b8d304539a2eb1cfece077510b4ca394..aa1b41ca40f778dcb4e6c0e393ab4ee33d25d388 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 48a4a826ae07649419d033b99c564b2adb9da6ea..200366c62231dd5f8f38f74284a42810c8603d19 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 48dfe3c4d6aa7968bbc1986eafcb9e965fe55950..6ba47cfb1443748ccf092819a6a5ef160bb856fd 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 ab37ae114e943c20c161f88b8c2a739206bfafab..0d7ab20c58dffc40d5c56c9427b7dd7f090c8bd3 100644 (file)
@@ -1729,7 +1729,8 @@ static int dm_merge_bvec(struct request_queue *q,
        struct mapped_device *md = q->queuedata;
        struct dm_table *map = dm_get_live_table_fast(md);
        struct dm_target *ti;
-       sector_t max_sectors, max_size = 0;
+       sector_t max_sectors;
+       int max_size = 0;
 
        if (unlikely(!map))
                goto out;
@@ -1742,18 +1743,10 @@ static int dm_merge_bvec(struct request_queue *q,
         * Find maximum amount of I/O that won't need splitting
         */
        max_sectors = min(max_io_len(bvm->bi_sector, ti),
-                         (sector_t) queue_max_sectors(q));
+                         (sector_t) BIO_MAX_SECTORS);
        max_size = (max_sectors << SECTOR_SHIFT) - bvm->bi_size;
-
-       /*
-        * FIXME: this stop-gap fix _must_ be cleaned up (by passing a sector_t
-        * to the targets' merge function since it holds sectors not bytes).
-        * Just doing this as an interim fix for stable@ because the more
-        * comprehensive cleanup of switching to sector_t will impact every
-        * DM target that implements a ->merge hook.
-        */
-       if (max_size > INT_MAX)
-               max_size = INT_MAX;
+       if (max_size < 0)
+               max_size = 0;
 
        /*
         * merge_bvec_fn() returns number of bytes
@@ -1761,13 +1754,13 @@ static int dm_merge_bvec(struct request_queue *q,
         * max is precomputed maximal io size
         */
        if (max_size && ti->type->merge)
-               max_size = ti->type->merge(ti, bvm, biovec, (int) max_size);
+               max_size = ti->type->merge(ti, bvm, biovec, max_size);
        /*
         * If the target doesn't support merge method and some of the devices
-        * provided their merge_bvec method (we know this by looking for the
-        * max_hw_sectors that dm_set_device_limits may set), then we can't
-        * allow bios with multiple vector entries.  So always set max_size
-        * to 0, and the code below allows just one page.
+        * provided their merge_bvec method (we know this by looking at
+        * queue_max_hw_sectors), then we can't allow bios with multiple vector
+        * entries.  So always set max_size to 0, and the code below allows
+        * just one page.
         */
        else if (queue_max_hw_sectors(q) <= PAGE_SIZE >> 9)
                max_size = 0;
index 0c2a4e8b873c659dbc260b2aa5484c7a5e87b176..e25f00f0138a7b4d82a5ae4f6fc7e1b6f0bb1b30 100644 (file)
@@ -5759,7 +5759,7 @@ static int get_bitmap_file(struct mddev *mddev, void __user * arg)
        char *ptr;
        int err;
 
-       file = kmalloc(sizeof(*file), GFP_NOIO);
+       file = kzalloc(sizeof(*file), GFP_NOIO);
        if (!file)
                return -ENOMEM;
 
index bf2b80d5c4707a64210b5e57deb785069dc7d921..8731b6ea026bd9b8cfbe2a21bbc06366e509181c 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 9836c0ae897c33c4e227bca77cc95026c193f73c..4222f774cf369b1eb1b031bd652854c573b224af 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;
@@ -689,6 +685,7 @@ static int remove_one(struct dm_btree_info *info, dm_block_t root,
                                             value_ptr(n, index));
 
                delete_at(n, index);
+               keys[last_level] = k + 1ull;
 
        } else
                r = -ENODATA;
index 1b5e13ec7f96a670ed7a9b5b472a5d2ee95a7dff..0dee514ba4c5f9e8d34d16e9d239ef333395c7d4 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 fdd3793e22f957ef08db71f897607c68ce6eb6a3..c7726cebc4950c24cb6f6f2b7cacfa6465bddeb6 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 94f5b55069e09610f21ea640f5dff3efd7e580ca..967a4ed73929ff44a38d9475c5e362fc2914c758 100644 (file)
@@ -1476,6 +1476,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
 {
        char b[BDEVNAME_SIZE];
        struct r1conf *conf = mddev->private;
+       unsigned long flags;
 
        /*
         * If it is not operational, then we have already marked it as dead
@@ -1495,14 +1496,13 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
                return;
        }
        set_bit(Blocked, &rdev->flags);
+       spin_lock_irqsave(&conf->device_lock, flags);
        if (test_and_clear_bit(In_sync, &rdev->flags)) {
-               unsigned long flags;
-               spin_lock_irqsave(&conf->device_lock, flags);
                mddev->degraded++;
                set_bit(Faulty, &rdev->flags);
-               spin_unlock_irqrestore(&conf->device_lock, flags);
        } else
                set_bit(Faulty, &rdev->flags);
+       spin_unlock_irqrestore(&conf->device_lock, flags);
        /*
         * if recovery is running, make sure it aborts.
         */
@@ -1568,7 +1568,10 @@ static int raid1_spare_active(struct mddev *mddev)
         * Find all failed disks within the RAID1 configuration
         * and mark them readable.
         * Called under mddev lock, so rcu protection not needed.
+        * device_lock used to avoid races with raid1_end_read_request
+        * which expects 'In_sync' flags and ->degraded to be consistent.
         */
+       spin_lock_irqsave(&conf->device_lock, flags);
        for (i = 0; i < conf->raid_disks; i++) {
                struct md_rdev *rdev = conf->mirrors[i].rdev;
                struct md_rdev *repl = conf->mirrors[conf->raid_disks + i].rdev;
@@ -1599,7 +1602,6 @@ static int raid1_spare_active(struct mddev *mddev)
                        sysfs_notify_dirent_safe(rdev->sysfs_state);
                }
        }
-       spin_lock_irqsave(&conf->device_lock, flags);
        mddev->degraded -= count;
        spin_unlock_irqrestore(&conf->device_lock, flags);
 
index 643d217bfa13ac8caa3dee9f9dd65d57f165bbe8..f757023fc4580680bfdd6e178f93acb62cb1f31e 100644 (file)
@@ -2256,7 +2256,7 @@ static int resize_stripes(struct r5conf *conf, int newsize)
 static int drop_one_stripe(struct r5conf *conf)
 {
        struct stripe_head *sh;
-       int hash = (conf->max_nr_stripes - 1) % NR_STRIPE_HASH_LOCKS;
+       int hash = (conf->max_nr_stripes - 1) & STRIPE_HASH_LOCKS_MASK;
 
        spin_lock_irq(conf->hash_locks + hash);
        sh = get_free_stripe(conf, hash);
@@ -6388,7 +6388,8 @@ static unsigned long raid5_cache_scan(struct shrinker *shrink,
 
        if (mutex_trylock(&conf->cache_size_mutex)) {
                ret= 0;
-               while (ret < sc->nr_to_scan) {
+               while (ret < sc->nr_to_scan &&
+                      conf->max_nr_stripes > conf->min_nr_stripes) {
                        if (drop_one_stripe(conf) == 0) {
                                ret = SHRINK_STOP;
                                break;
index 0d35f5850ff1ea8e9910168f55fe04f05c42600e..5ab90f36a6a687c3c64edd56f09d3f8708dba635 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 3be1b2c3c3860ec48c2e9a1e5e5cd41daf56046f..6a1c0089bb6279c6660b6154681c1c7cdeb129d4 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 dd4bff9cf3390a4f167c6e5d1a9ae4886dae9750..d1f5898d11ba1c046737b2bb2a7ba48fa7547b9d 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 1d59c7e039f7d41e989dc986cf6ac09815165747..87990ece5848957baf4af40dd5100f356466b901 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 8939ebd7439198161935f573652f25babb438840..84fa6e9b59a1acd9360364fbd30ca0a4e00d3a56 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 f9c70baf6e0cb1f071f0a6f7e2ac9e81cf131817..d16bc67af732251998fb280b86d887835cf39e1b 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 baeb5971fd52cecca1a01f436713f9f3a77c65ca..85af7a8691677a9b3965f469f37bc49b741de6b7 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 9d0e161c2a886c511d3fde3928b154b0cfb7f0db..e1cf23c3875b16ead52464d4e6ad3c479fd1e951 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 4b994aa2f2a7d1f763fd5bb7eccfb95f8ba1b6d6..b68d4f76273448fcbc98fc1e215a6656c9b6c6ec 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 b9e4645c731c087f3dea99fa652fe09ef19dc8de..b732ac6a26d8065cc26ecb3a648ced999db71367 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 d8bdf63ce9858ccfc78536fc698698e16c751670..63dace8198b0b3dbcb116108e238351fe9684a9e 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 9d015db652808fcb54fc0abfff19e9018dbad488..0ff388a1616876d50ade807ff5bff20204d1b8cd 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 93b315459098932381d61d282cdb3f04194b18ae..a14c428f70e992460ed869b492723a5a08f155b9 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 3a27a84ad3ec376a2543c1ac9568c30e5d7c131b..9426276dbe1402b1445dd7b84da6d7fca38893a6 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 653815950aa2416b277718df69213545573aa557..3f68dd251ce89304bf044960568c58c11aca8fdd 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 bebf58a06a6b2932d57798c0b5b81a31a12e9b7a..0ce20ce170c41793d88febd54302d261b92df9db 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 c5265c1262c50c3496f9142c07704d78d799a1b0..583dc33432f31ed056aa53e4e37582fefc4f7e71 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 aeae6ec123b3ad76c8d7eec6f4ba326c1419907e..423fb3730dc714f17accd85d9aa9eda9b29b8ebf 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 12cad94b40354d8d548ab8974156f8c5c625f4db..dae04dd20ff50737075cdfb6d27bb23383585edf 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 },
@@ -249,6 +249,16 @@ static const struct reg_default wm5110_revd_patch[] = {
        { 0x80, 0x0 },
 };
 
+/* Add extra headphone write sequence locations */
+static const struct reg_default wm5110_reve_patch[] = {
+       { 0x80, 0x3 },
+       { 0x80, 0x3 },
+       { 0x4b, 0x138 },
+       { 0x4c, 0x13d },
+       { 0x80, 0x0 },
+       { 0x80, 0x0 },
+};
+
 /* We use a function so we can use ARRAY_SIZE() */
 int wm5110_patch(struct arizona *arizona)
 {
@@ -266,7 +276,9 @@ int wm5110_patch(struct arizona *arizona)
                                             wm5110_revd_patch,
                                             ARRAY_SIZE(wm5110_revd_patch));
        default:
-               return 0;
+               return regmap_register_patch(arizona->regmap,
+                                            wm5110_reve_patch,
+                                            ARRAY_SIZE(wm5110_reve_patch));
        }
 }
 EXPORT_SYMBOL_GPL(wm5110_patch);
@@ -676,6 +688,7 @@ static const struct reg_default wm5110_reg_default[] = {
        { 0x00000032, 0x0100 },    /* R50    - PWM Drive 3 */
        { 0x00000040, 0x0000 },    /* R64    - Wake control */
        { 0x00000041, 0x0000 },    /* R65    - Sequence control */
+       { 0x00000042, 0x0000 },    /* R66    - Spare Triggers */
        { 0x00000061, 0x01FF },    /* R97    - Sample Rate Sequence Select 1 */
        { 0x00000062, 0x01FF },    /* R98    - Sample Rate Sequence Select 2 */
        { 0x00000063, 0x01FF },    /* R99    - Sample Rate Sequence Select 3 */
@@ -1716,6 +1729,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_PWM_DRIVE_3:
        case ARIZONA_WAKE_CONTROL:
        case ARIZONA_SEQUENCE_CONTROL:
+       case ARIZONA_SPARE_TRIGGERS:
        case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1:
        case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2:
        case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3:
index 53ae5af5d6e4f97b88c19543a3ec81df09de64da..0f4169a3a5d4c181017ab22ac40a1cb1dfd1fad2 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 c0c25d75aaccbf3a53218b71d5ea18f0b24c9d0d..cab2c68f17378eff6efd0a0da54153a094584b73 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 2d3db81be0990a1b88109aa7614f74f201930204..6ded3dc36644a31a0bd4775f36df72f1c00a7e0d 100644 (file)
@@ -438,9 +438,6 @@ static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
 {
        struct at24_data *at24;
 
-       if (unlikely(off >= attr->size))
-               return -EFBIG;
-
        at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
        return at24_write(at24, buf, off, count);
 }
index e1ccefce9a9de629505344f9fc22042ab09b9684..a98dd4f1b0e33126ca04d1a7cecb8ad1e41d8d72 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 2d1ce3c5d0dd34c9fabb1399a32c49be744afdd1..753887d02b46abc66663a24a2ea3e4e396d6b881 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 a90d7364334f9dfa3687dc813e068508a342861c..f7fbdc9d132511b72df0db2ce0b92e4df0774c44 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 76b9052a961c517978494199d74398264583508c..5907c821d131eed6fa5b6b0aa7a93dc41cca0d66 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 0612b19f6313bd3e6ffa205be2b543585262e31e..506047c386071db9472d60218faa004fe94849a8 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 c4d6bbe9458dbfe9c726fdff1e9b6c4c64b8a33f..02e23e6f142487ddc8cc2a8d4e2c512cb7e6db62 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 a11485fbb33f2b7bcd6c973324ea41601dbaf575..c3c7db41819dfad26b521008c6c70148711ee019 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 2716e6f30d9a0949633b40dc9864196c7465fa3a..00e3a6b6b82254269aa7e0bf5d165f13d358594f 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 6f642426308c67399eac3abdb20ae6160ce41d2a..6ca693b03f33abbbdb6097544f2f4ee7f3928720 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 32e3807c650ea7256b09f0c9e406a8219cb2bb78..271bb5862346ede352473f0837fb76e0a5ac7163 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 56316db6c5a674fd1d17ef20e8db3747950cf71e..cf8e54652df95266e24a5d6d64ed67c00336f67b 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 b34214e2df5f6e55bdbb29e6a8016c139e74345c..016743e355de31984d57904e802d69e6703ea5e4 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 2b7610f341b09f4ff293f9916235030487fb2a80..10b3bbbbac8e10e89c47b2d50bb661cc80ad616b 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 3c0a8f825b630148c29b4cda6ca46b9797a668be..5b90fcf96265aec4a6daa1f28135ef2fa06a0752 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 982fdcdc795b4752a2fbe65e71ed76ee197ad5de..b5b2925103ec10c1e835429c2ab7d2efee093838 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 2f70a9b152bd1789349d9c4d995852e95be1e70d..830466c49987cfbf1ad25f6d9bc01e4f7f0d0454 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 9aa6104e34ea8e2bd93994e4d8291763014162b8..ae21e0b06c3ad40a54093c8966fcfa711f188cfb 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 e71cdde9cb017aecab834d2f2d9c5d4821c3d42e..1d7b00b038a2ea8c3bdd9394ad3d4988ccee04c8 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 3e8b1bfb1f2e316212bd9b60fa06522ca4dc68db..d9884fd15b453e2486177d58b7fc40bcd5aaf7cc 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 afad529838de748efc9f9253c6fde42abbe954a3..06e3e1e54c35d6078321d792d1e0e537ec95a207 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 f78909a00f150edfd76065b2b993d9660edaebdd..09d2e16fd6b00bfdd0c20fc10c64abd03c29a935 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 3df51faf18ae3ba8ce6bb7f49e6f51e4da1be738..f790f61ea78a2b4f1008da82eca29132ff5bdcc0 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 2d8578cade03790782af7e97a1f59f9848301ae6..2e7f9a2834be320eef4a7bed44d8c787f72f3e65 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 7e3129e7f143a9990c89780a8e6638f8182e4892..f0e4bb4e3ec59f9695957dee9dec55a02d450da8 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 a8a730641bbb14e723f841b2b3c13454b53a5491..bb1bb72121c0474b8c1898540a28d21264479d6a 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 9749dfd78c434992f4041effc3c9a7314bdace3d..4755838c6137b462d6de262b38beadacdf099e98 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 2ffbf13471d09ad4c27d8c70fbb4dd3145befa75..216bfd350169a9da723035876d152e89b17c8432 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 3cc316cb7e6be792b06dfc2c520eae9809f1008b..d8757bf9ad755ed6a3114d9d0a9664e59618744a 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 b2197b506acbe86f3540d5ae1d8334129c2bbe57..1e1fbb049ec63b79c1d8255c517364f739a8d38b 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 c0f6479e19d48e51fd76c3bbce161ffdd7846842..70b08958763a129fff47ad00a1db130c1334f254 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 9d15566521a719b525a28a009f1d999c91a00da2..fa8f5046afe90627242f6d2d523178da653c9427 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 9d43460ce3c71f0b54c69b84fa5a0ec8b7341d5f..64a60afbe50cc4ca0ff12b65ad6331a5fcc5e3a7 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 7fbca37a1adffe5d46d3603e9fd44d4dbd16d331..237f8e5e493ddaae958684e8ed411c6f7f2363d6 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 7193b7304fdd3ed4b69c0125732d4a024d4a4b36..848ea6a399f236b14cc5d9a79dd38038e0331aec 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 25d1cbd34306e03ea4827e09509c345d11b5a1df..b2f0d245bcf3a0e71fb96797c47f71ad0ca736db 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 5000bfcded617f32ca177ae7a0711f13a3ce65d3..5514ad6d4e54373d2a48564ec790489dfe1808dc 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 6203c4ad9bba5d8ce3bb2f46f832c3bb4ebe85fc..9e144e71da0b5980264702a6210684cfa34edab5 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 2b86c2135de36f627b397add88628bc47aa37271..607acb53c847558793d47a528d0830f9c79c8cbf 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 b6cc9ff47fc2e59b3cc92fe4002f05e59d981e56..1c6788aecc62658fe2cc7c4961415ef4715c8dde 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 1106ce76707e1095fd523c5c541fa3740e9c9496..30c2cf7fa93b0c6015d22236c3a9189b462cb064 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 3b3a88b53b119909112a806ee71ab4d4bfa67a79..585d0883c7e58760eed503de64ced513c8331c82 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 1017f02d7bf7520868b25330493822e08f7826a0..7bf88d9dcdc3fc4732170c121ef78d5a85ca3fa9 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 1a83e190fc15e4158b5e441cc267ad149d465abe..28577a31549d1569032d63457464fe11fdf44d32 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 7d50711476fe1e88debca95beb790d770261f036..3f44b522b8311a2c64eba48e6a9b7217ea0cb3a7 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 23435f2a5486f806ee8f686fdb898d0815a68013..2e2530743831a19f2ca4db3b313d1f8b2db44ebb 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 efe3ad4122f2ee1094da78c1bb31d86642b5b3a6..1c6386d5f79c742737e4ee1a8a2b99df686ffaa0 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 73de4efcbe6edc85c8f3fb54e0c925a7ab30492b..944f50015ed07b41b2de0da464812910c411cc1a 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 cefd636681b6418ce75376879dc26fe3891bc47d..b978bbfe044c163be9cf1a0a4f35bb1edbbab783 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 e17c539e4f6fbb138c04957532f3a329a8556b4a..2dad7e820ff0b16b7447b708f0c147b2e0289f02 100644 (file)
@@ -212,6 +212,7 @@ void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled)
 
        sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2);
 }
+EXPORT_SYMBOL_GPL(sun4i_usb_phy_set_squelch_detect);
 
 static struct phy_ops sun4i_usb_phy_ops = {
        .init           = sun4i_usb_phy_init,
index 3510b81db3faabcda59a7148e31a32ce403805a5..08020dc2c7c8c3496987589841fc0ddb0b1c9ff7 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/delay.h>
 #include <linux/phy/omap_control_phy.h>
 #include <linux/of_platform.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #define        PLL_STATUS              0x00000004
 #define        PLL_GO                  0x00000008
@@ -52,6 +54,8 @@
 #define        PLL_LOCK                0x2
 #define        PLL_IDLE                0x1
 
+#define SATA_PLL_SOFT_RESET    BIT(18)
+
 /*
  * This is an Empirical value that works, need to confirm the actual
  * value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status
@@ -82,6 +86,9 @@ struct ti_pipe3 {
        struct clk              *refclk;
        struct clk              *div_clk;
        struct pipe3_dpll_map   *dpll_map;
+       struct regmap           *dpll_reset_syscon; /* ctrl. reg. acces */
+       unsigned int            dpll_reset_reg; /* reg. index within syscon */
+       bool                    sata_refclk_enabled;
 };
 
 static struct pipe3_dpll_map dpll_map_usb[] = {
@@ -249,8 +256,11 @@ static int ti_pipe3_exit(struct phy *x)
        u32 val;
        unsigned long timeout;
 
-       /* SATA DPLL can't be powered down due to Errata i783 */
-       if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
+       /* If dpll_reset_syscon is not present we wont power down SATA DPLL
+        * due to Errata i783
+        */
+       if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") &&
+           !phy->dpll_reset_syscon)
                return 0;
 
        /* PCIe doesn't have internal DPLL */
@@ -276,6 +286,14 @@ static int ti_pipe3_exit(struct phy *x)
                }
        }
 
+       /* i783: SATA needs control bit toggle after PLL unlock */
+       if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) {
+               regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg,
+                                  SATA_PLL_SOFT_RESET, SATA_PLL_SOFT_RESET);
+               regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg,
+                                  SATA_PLL_SOFT_RESET, 0);
+       }
+
        ti_pipe3_disable_clocks(phy);
 
        return 0;
@@ -350,6 +368,21 @@ static int ti_pipe3_probe(struct platform_device *pdev)
                }
        } else {
                phy->wkupclk = ERR_PTR(-ENODEV);
+               phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node,
+                                                       "syscon-pllreset");
+               if (IS_ERR(phy->dpll_reset_syscon)) {
+                       dev_info(&pdev->dev,
+                                "can't get syscon-pllreset, sata dpll won't idle\n");
+                       phy->dpll_reset_syscon = NULL;
+               } else {
+                       if (of_property_read_u32_index(node,
+                                                      "syscon-pllreset", 1,
+                                                      &phy->dpll_reset_reg)) {
+                               dev_err(&pdev->dev,
+                                       "couldn't get pllreset reg. offset\n");
+                               return -EINVAL;
+                       }
+               }
        }
 
        if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
@@ -402,10 +435,16 @@ static int ti_pipe3_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, phy);
        pm_runtime_enable(phy->dev);
-       /* Prevent auto-disable of refclk for SATA PHY due to Errata i783 */
-       if (of_device_is_compatible(node, "ti,phy-pipe3-sata"))
-               if (!IS_ERR(phy->refclk))
+
+       /*
+        * Prevent auto-disable of refclk for SATA PHY due to Errata i783
+        */
+       if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
+               if (!IS_ERR(phy->refclk)) {
                        clk_prepare_enable(phy->refclk);
+                       phy->sata_refclk_enabled = true;
+               }
+       }
 
        generic_phy = devm_phy_create(phy->dev, NULL, &ops);
        if (IS_ERR(generic_phy))
@@ -472,8 +511,18 @@ static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
 {
        if (!IS_ERR(phy->wkupclk))
                clk_disable_unprepare(phy->wkupclk);
-       if (!IS_ERR(phy->refclk))
+       if (!IS_ERR(phy->refclk)) {
                clk_disable_unprepare(phy->refclk);
+               /*
+                * SATA refclk needs an additional disable as we left it
+                * on in probe to avoid Errata i783
+                */
+               if (phy->sata_refclk_enabled) {
+                       clk_disable_unprepare(phy->refclk);
+                       phy->sata_refclk_enabled = false;
+               }
+       }
+
        if (!IS_ERR(phy->div_clk))
                clk_disable_unprepare(phy->div_clk);
 }
index cb13299195271ffed4854ed6b0b593c5e8487019..3271cd1abe7c0e6c5d2e813171aa5df494f9d977 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 26270c351624f229cf85b6069ffe53ee26d50bef..ce129e595b55b663a11600e46571a1dba0d2ccf7 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 155b286f1a9d3cc8b366a6a5b7610ae562337f62..25436cd2860cc18a63ac599ed58e3c871c264d8e 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 1b3a094734522803c7f3fecd39da5c297a1feb43..30f9ef0c0d4f8cea52b182f370a04ed1ba4a9908 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 c6795941b45d98579cd6117cc5b72f8c5c4d0bf9..2d5909c4685ca63375f5041d960effada171f5fc 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 8053f24f03499335112721cd50c2816da40393a6..98d9bb6ff725ff46621a408bdf1f208175e21daf 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 cfadccef045c5f91d9efb5f575c98d1d9c68b090..6457a8a0db9c37ed8892c28effe768a533f2e7f3 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 9e43ae1d2163dacaae769a816dc6973cfabbdca0..e4b7998379485454d26e39f6a5a91917a155ffbb 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 3b2fcb4fada0491c4500b42555fdef542b4399d2..a20da8c25b4f960224fb4d772aafea38c57e1656 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 bfa42620a3f607857978895a49451b9177964374..940781183fac4e450503c7b3cd5df6c30bde6d0c 100644 (file)
@@ -1266,6 +1266,7 @@ static const struct das1800_board *das1800_probe(struct comedi_device *dev)
                if (index == das1801hc || index == das1802hc)
                        return board;
                index = das1801hc;
+               break;
        default:
                dev_err(dev->class_dev,
                        "Board model: probe returned 0x%x (unknown, please report)\n",
index 9c934e6d2ea1114094921bd890eb0186a50f0e06..c61add46b4268b722eeaad74a0540a4a2c48f1e8 100644 (file)
@@ -40,7 +40,7 @@
 
 #define DEBUG_SUBSYSTEM D_OTHER
 
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
 
 #include "../include/obd_support.h"
 #include "../include/lustre_debug.h"
index b0c8e235b982164bb170b53655ccfc8d01378d6b..69bdc8f29b59f4c1e1cbacabf7563a7ca1d66817 100644 (file)
@@ -1483,8 +1483,9 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
-       if (changed & BSS_CHANGED_ASSOC && priv->op_mode != NL80211_IFTYPE_AP) {
-               if (conf->assoc) {
+       if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) &&
+           priv->op_mode != NL80211_IFTYPE_AP) {
+               if (conf->assoc && conf->beacon_rate) {
                        CARDbUpdateTSF(priv, conf->beacon_rate->hw_value,
                                       conf->sync_tsf);
 
index cd77a064c772f1bbe897482d2372fe5bc6434328..fd092909a4577a7c4a708516bf3344fee331ad84 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 c2e9fea90b4a4bc16a0384d79fa9684c9f4176e0..860e840461778271191ba4ee8f1a4011dba5e78c 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 62ea4e8e70a8935398f2a0e86fc44627dfa3368e..be9cefc07407e80ef5dd7dfcbd8a0d025faf97f6 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 b5ba1ec3c35476361103d7dca47a1934cdd3289f..f87d4cef6d398c072e953e7eaa6b5d9d5b469d70 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 6509c61b96484993333a4198138945f43154fdfd..620dcd405ff6eec9ae65b0af8e93c25daae15d1f 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 d5dd357ba57c4c6af785b4f915d9fccba6a4fa21..b49f97c734d00ddccb50379d3131c232651e96e5 100644 (file)
@@ -405,7 +405,6 @@ static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops,
 static struct platform_driver hisi_thermal_driver = {
        .driver = {
                .name           = "hisi_thermal",
-               .owner          = THIS_MODULE,
                .pm             = &hisi_thermal_pm_ops,
                .of_match_table = of_hisi_thermal_match,
        },
index 4672250b329f4cec54ab243b55b41b127b1c48d0..7006860f2f3693b04ee44996c5085e2f94ceae44 100644 (file)
@@ -229,7 +229,8 @@ static int allocate_power(struct thermal_zone_device *tz,
        struct thermal_instance *instance;
        struct power_allocator_params *params = tz->governor_data;
        u32 *req_power, *max_power, *granted_power, *extra_actor_power;
-       u32 total_req_power, max_allocatable_power;
+       u32 *weighted_req_power;
+       u32 total_req_power, max_allocatable_power, total_weighted_req_power;
        u32 total_granted_power, power_range;
        int i, num_actors, total_weight, ret = 0;
        int trip_max_desired_temperature = params->trip_max_desired_temperature;
@@ -247,16 +248,17 @@ static int allocate_power(struct thermal_zone_device *tz,
        }
 
        /*
-        * We need to allocate three arrays of the same size:
-        * req_power, max_power and granted_power.  They are going to
-        * be needed until this function returns.  Allocate them all
-        * in one go to simplify the allocation and deallocation
-        * logic.
+        * We need to allocate five arrays of the same size:
+        * req_power, max_power, granted_power, extra_actor_power and
+        * weighted_req_power.  They are going to be needed until this
+        * function returns.  Allocate them all in one go to simplify
+        * the allocation and deallocation logic.
         */
        BUILD_BUG_ON(sizeof(*req_power) != sizeof(*max_power));
        BUILD_BUG_ON(sizeof(*req_power) != sizeof(*granted_power));
        BUILD_BUG_ON(sizeof(*req_power) != sizeof(*extra_actor_power));
-       req_power = devm_kcalloc(&tz->device, num_actors * 4,
+       BUILD_BUG_ON(sizeof(*req_power) != sizeof(*weighted_req_power));
+       req_power = devm_kcalloc(&tz->device, num_actors * 5,
                                 sizeof(*req_power), GFP_KERNEL);
        if (!req_power) {
                ret = -ENOMEM;
@@ -266,8 +268,10 @@ static int allocate_power(struct thermal_zone_device *tz,
        max_power = &req_power[num_actors];
        granted_power = &req_power[2 * num_actors];
        extra_actor_power = &req_power[3 * num_actors];
+       weighted_req_power = &req_power[4 * num_actors];
 
        i = 0;
+       total_weighted_req_power = 0;
        total_req_power = 0;
        max_allocatable_power = 0;
 
@@ -289,13 +293,14 @@ static int allocate_power(struct thermal_zone_device *tz,
                else
                        weight = instance->weight;
 
-               req_power[i] = frac_to_int(weight * req_power[i]);
+               weighted_req_power[i] = frac_to_int(weight * req_power[i]);
 
                if (power_actor_get_max_power(cdev, tz, &max_power[i]))
                        continue;
 
                total_req_power += req_power[i];
                max_allocatable_power += max_power[i];
+               total_weighted_req_power += weighted_req_power[i];
 
                i++;
        }
@@ -303,8 +308,9 @@ static int allocate_power(struct thermal_zone_device *tz,
        power_range = pid_controller(tz, current_temp, control_temp,
                                     max_allocatable_power);
 
-       divvy_up_power(req_power, max_power, num_actors, total_req_power,
-                      power_range, granted_power, extra_actor_power);
+       divvy_up_power(weighted_req_power, max_power, num_actors,
+                      total_weighted_req_power, power_range, granted_power,
+                      extra_actor_power);
 
        total_granted_power = 0;
        i = 0;
@@ -328,7 +334,7 @@ static int allocate_power(struct thermal_zone_device *tz,
                                      max_allocatable_power, current_temp,
                                      (s32)control_temp - (s32)current_temp);
 
-       devm_kfree(&tz->device, req_power);
+       kfree(req_power);
 unlock:
        mutex_unlock(&tz->lock);
 
@@ -420,7 +426,7 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
                return -EINVAL;
        }
 
-       params = devm_kzalloc(&tz->device, sizeof(*params), GFP_KERNEL);
+       params = kzalloc(sizeof(*params), GFP_KERNEL);
        if (!params)
                return -ENOMEM;
 
@@ -462,14 +468,14 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
        return 0;
 
 free:
-       devm_kfree(&tz->device, params);
+       kfree(params);
        return ret;
 }
 
 static void power_allocator_unbind(struct thermal_zone_device *tz)
 {
        dev_dbg(&tz->device, "Unbinding from thermal zone %d\n", tz->id);
-       devm_kfree(&tz->device, tz->governor_data);
+       kfree(tz->governor_data);
        tz->governor_data = NULL;
 }
 
index c8e35c1a43dcfd19145a6d1e24b132b25b5c6169..e0da3865e0600f8f23b6368be63fd662d5dda6d1 100644 (file)
@@ -1,6 +1,6 @@
 config EXYNOS_THERMAL
        tristate "Exynos thermal management unit driver"
-       depends on OF
+       depends on THERMAL_OF
        help
          If you say yes here you get support for the TMU (Thermal Management
          Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises
index 531f4b179871f63da7fea6f32af19b27af18e9a3..c96ff10b869efd941bfe8c32384d48b70b1c348d 100644 (file)
@@ -1296,7 +1296,6 @@ static struct thermal_zone_of_device_ops exynos_sensor_ops = {
 
 static int exynos_tmu_probe(struct platform_device *pdev)
 {
-       struct exynos_tmu_platform_data *pdata;
        struct exynos_tmu_data *data;
        int ret;
 
@@ -1318,8 +1317,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
        if (ret)
                goto err_sensor;
 
-       pdata = data->pdata;
-
        INIT_WORK(&data->irq_work, exynos_tmu_work);
 
        data->clk = devm_clk_get(&pdev->dev, "tmu_apbif");
@@ -1392,6 +1389,8 @@ err_clk_sec:
        if (!IS_ERR(data->clk_sec))
                clk_unprepare(data->clk_sec);
 err_sensor:
+       if (!IS_ERR_OR_NULL(data->regulator))
+               regulator_disable(data->regulator);
        thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
 
        return ret;
index 04659bfb888b73237257b75f944bf9130bc241b6..4ca211be4c0f197825be94f70be386af1c2cc33d 100644 (file)
@@ -1333,6 +1333,7 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
        return -ENODEV;
 
 unbind:
+       device_remove_file(&tz->device, &pos->weight_attr);
        device_remove_file(&tz->device, &pos->attr);
        sysfs_remove_link(&tz->device.kobj, pos->name);
        release_idr(&tz->idr, &tz->lock, pos->id);
index 74fea4fa41b156248ce6d7116db02b54990066a9..3ad48e1c0c57e1722311c8393ad3bd21712fa1e7 100644 (file)
@@ -1024,7 +1024,18 @@ static struct platform_driver ci_hdrc_driver = {
        },
 };
 
-module_platform_driver(ci_hdrc_driver);
+static int __init ci_hdrc_platform_register(void)
+{
+       ci_hdrc_host_driver_init();
+       return platform_driver_register(&ci_hdrc_driver);
+}
+module_init(ci_hdrc_platform_register);
+
+static void __exit ci_hdrc_platform_unregister(void)
+{
+       platform_driver_unregister(&ci_hdrc_driver);
+}
+module_exit(ci_hdrc_platform_unregister);
 
 MODULE_ALIAS("platform:ci_hdrc");
 MODULE_LICENSE("GPL v2");
index 6cf87b8b13a8a606b5ccf680e4635fcbc44874a1..7161439def19aa265c9f36530d3d97d63ecc51a7 100644 (file)
@@ -249,9 +249,12 @@ int ci_hdrc_host_init(struct ci_hdrc *ci)
        rdrv->name      = "host";
        ci->roles[CI_ROLE_HOST] = rdrv;
 
+       return 0;
+}
+
+void ci_hdrc_host_driver_init(void)
+{
        ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides);
        orig_bus_suspend = ci_ehci_hc_driver.bus_suspend;
        ci_ehci_hc_driver.bus_suspend = ci_ehci_bus_suspend;
-
-       return 0;
 }
index 5707bf379bfb4b7ce98ff4a79d585619d1c64b48..0f12f131bdd3f22671eaf170476e2511950fa1be 100644 (file)
@@ -5,6 +5,7 @@
 
 int ci_hdrc_host_init(struct ci_hdrc *ci);
 void ci_hdrc_host_destroy(struct ci_hdrc *ci);
+void ci_hdrc_host_driver_init(void);
 
 #else
 
@@ -18,6 +19,11 @@ static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci)
 
 }
 
+static void ci_hdrc_host_driver_init(void)
+{
+
+}
+
 #endif
 
 #endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
index f7f35a36c09a06eab17ef2e5af013ee3de2b5b8e..6df9715a4bcd31179cb190100df45b2dd975a0d2 100644 (file)
@@ -699,6 +699,10 @@ static inline int hidg_get_minor(void)
        int ret;
 
        ret = ida_simple_get(&hidg_ida, 0, 0, GFP_KERNEL);
+       if (ret >= HIDG_MINORS) {
+               ida_simple_remove(&hidg_ida, ret);
+               ret = -ENODEV;
+       }
 
        return ret;
 }
index 44173df272739543a6b3168323073dba45239760..357f63f47b42aba69d92e24346963645227d39e2 100644 (file)
@@ -1248,7 +1248,15 @@ static struct config_item_type printer_func_type = {
 
 static inline int gprinter_get_minor(void)
 {
-       return ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL);
+       int ret;
+
+       ret = ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL);
+       if (ret >= PRINTER_MINORS) {
+               ida_simple_remove(&printer_ida, ret);
+               ret = -ENODEV;
+       }
+
+       return ret;
 }
 
 static inline void gprinter_put_minor(int minor)
index 6d3eb8b00a488446db954334e80ac12eccf0d5cf..53186154725330d4c1f710e4829d4a8b25b614cd 100644 (file)
@@ -1162,14 +1162,14 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
                        factor = 1000;
                } else {
                        ep_desc = &hs_epin_desc;
-                       factor = 125;
+                       factor = 8000;
                }
 
                /* pre-compute some values for iso_complete() */
                uac2->p_framesize = opts->p_ssize *
                                    num_channels(opts->p_chmask);
                rate = opts->p_srate * uac2->p_framesize;
-               uac2->p_interval = (1 << (ep_desc->bInterval - 1)) * factor;
+               uac2->p_interval = factor / (1 << (ep_desc->bInterval - 1));
                uac2->p_pktsize = min_t(unsigned int, rate / uac2->p_interval,
                                        prm->max_psize);
 
index b04980cf6dc42108f4861e4dfa7285dd4fe56af9..1efa61265d8d49c5116027c8e3555ae70b9cc12c 100644 (file)
@@ -779,7 +779,7 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req)
        /* The current hw dequeue pointer */
        tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(0));
        deq_ptr_64 = tmp_32;
-       tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(1));
+       tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1(0));
        deq_ptr_64 |= ((u64)tmp_32 << 32);
 
        /* we have the dma addr of next bd that will be fetched by hardware */
index 362ee8af5fce87df4a2e7779f743c2ec722d9a5c..89ed5e71a1991e0cd249c48b18bd04dd67bacf91 100644 (file)
@@ -323,6 +323,7 @@ err4:
 
 err3:
        put_device(&udc->dev);
+       device_del(&gadget->dev);
 
 err2:
        put_device(&gadget->dev);
index 3e442f77a2b9367c5bd90d2ab69beb2db841fd26..9a8c936cd42c18ef72a695d45c7e4ce2e893f8b0 100644 (file)
@@ -1792,7 +1792,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
        int size;
        int i, j, num_ports;
 
-       del_timer_sync(&xhci->cmd_timer);
+       if (timer_pending(&xhci->cmd_timer))
+               del_timer_sync(&xhci->cmd_timer);
 
        /* Free the Event Ring Segment Table and the actual Event Ring */
        size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
index 6a8fc52aed5863391885ac11c2661a407f707a30..32f4d564494a9f48cfebd328e61d3c281387d252 100644 (file)
@@ -82,7 +82,7 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
                return 0;
        /* offset in TRBs */
        segment_offset = trb - seg->trbs;
-       if (segment_offset > TRBS_PER_SEGMENT)
+       if (segment_offset >= TRBS_PER_SEGMENT)
                return 0;
        return seg->dma + (segment_offset * sizeof(*trb));
 }
index 19b85ee98a7247c46089e023676633e70eb498df..876423b8892c96f80930fa7a103f36370e519dfe 100644 (file)
@@ -1099,6 +1099,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
        { USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x68c0, 0xff),
          .driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC73xx */
+       { USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x9041, 0xff),
+         .driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC7305/MC7355 */
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
index 9c63897b3a564012ea63f99b9e5e73bc48b93d36..d156545728c2ab5b8bb81cf7537aa8a60805c08a 100644 (file)
@@ -145,7 +145,6 @@ static const struct usb_device_id id_table[] = {
        {DEVICE_SWI(0x1199, 0x901c)},   /* Sierra Wireless EM7700 */
        {DEVICE_SWI(0x1199, 0x901f)},   /* Sierra Wireless EM7355 */
        {DEVICE_SWI(0x1199, 0x9040)},   /* Sierra Wireless Modem */
-       {DEVICE_SWI(0x1199, 0x9041)},   /* Sierra Wireless MC7305/MC7355 */
        {DEVICE_SWI(0x1199, 0x9051)},   /* Netgear AirCard 340U */
        {DEVICE_SWI(0x1199, 0x9053)},   /* Sierra Wireless Modem */
        {DEVICE_SWI(0x1199, 0x9054)},   /* Sierra Wireless Modem */
@@ -158,6 +157,7 @@ static const struct usb_device_id id_table[] = {
        {DEVICE_SWI(0x413c, 0x81a4)},   /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
        {DEVICE_SWI(0x413c, 0x81a8)},   /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
        {DEVICE_SWI(0x413c, 0x81a9)},   /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
+       {DEVICE_SWI(0x413c, 0x81b1)},   /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
 
        /* Huawei devices */
        {DEVICE_HWI(0x03f0, 0x581d)},   /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
index 46179a0828ebcbad9a78c11dad8044edff27664a..07d1ecd564f79d9c51798f6941b1295d794d468c 100644 (file)
@@ -289,6 +289,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68AA, 0xFF, 0xFF, 0xFF),
          .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
        },
+       { USB_DEVICE(0x1199, 0x68AB) }, /* Sierra Wireless AR8550 */
        /* AT&T Direct IP LTE modems */
        { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68AA, 0xFF, 0xFF, 0xFF),
          .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
index 658c34bb9076f813058dfb03a47907ca48c6eb0a..1aaf89300621abc811f57f549c25b9a540a21d99 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 2d98de535e0f7374804474c58de752ffb2848aa4..f888561568d91735a3a765a772630e8b2be0a54a 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 928ee639c0c19ba3a2346737c41b44f38e82c0b5..bf407b6ba15ca0002166a0704124eeda0fb2052e 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 86bd457d039d2ad9a85e82d3f26a3630e3134da7..50bce45e7f3d47d78163058eff366b32d4f56180 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 111c2d1911d32ea38e86b11c0af753133ccfab05..b5102aa6090d111e25727f78422c8cbc183f086a 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 60e2a16775637b778a8faeb8f2b3f84810a88716..c96944b59856c10c7d28c189b5ff86dbe4b3c932 100644 (file)
@@ -313,6 +313,7 @@ err_init_vq:
 static void virtinput_remove(struct virtio_device *vdev)
 {
        struct virtio_input *vi = vdev->priv;
+       void *buf;
        unsigned long flags;
 
        spin_lock_irqsave(&vi->lock, flags);
@@ -320,6 +321,9 @@ static void virtinput_remove(struct virtio_device *vdev)
        spin_unlock_irqrestore(&vi->lock, flags);
 
        input_unregister_device(vi->idev);
+       vdev->config->reset(vdev);
+       while ((buf = virtqueue_detach_unused_buf(vi->sts)) != NULL)
+               kfree(buf);
        vdev->config->del_vqs(vdev);
        kfree(vi);
 }
index fd933695f2328f29c2493ee751f22230ec68cbb1..bf4a23c7c5918f6849e764a8376c3608cc591933 100644 (file)
@@ -472,7 +472,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
 }
 
 /*
- * We avoid multiple worker processes conflicting via the balloon mutex.
+ * As this is a work item it is guaranteed to run as a single instance only.
  * We may of course race updates of the target counts (which are protected
  * by the balloon lock), or with changes to the Xen hard limit, but we will
  * recover from these in time.
@@ -482,9 +482,10 @@ static void balloon_process(struct work_struct *work)
        enum bp_state state = BP_DONE;
        long credit;
 
-       mutex_lock(&balloon_mutex);
 
        do {
+               mutex_lock(&balloon_mutex);
+
                credit = current_credit();
 
                if (credit > 0) {
@@ -499,17 +500,15 @@ static void balloon_process(struct work_struct *work)
 
                state = update_schedule(state);
 
-#ifndef CONFIG_PREEMPT
-               if (need_resched())
-                       schedule();
-#endif
+               mutex_unlock(&balloon_mutex);
+
+               cond_resched();
+
        } while (credit && state == BP_DONE);
 
        /* Schedule more work if there is some still to be done. */
        if (state == BP_EAGAIN)
                schedule_delayed_work(&balloon_worker, balloon_stats.schedule_delay * HZ);
-
-       mutex_unlock(&balloon_mutex);
 }
 
 /* Resets the Xen limit, sets new target, and kicks off processing. */
index 67b9163db7185402b0ff3811c5363c1a1022e2c7..0dbb222daaf1c694b1f073f3e206f755f5f77cc6 100644 (file)
@@ -568,12 +568,14 @@ static int gntdev_release(struct inode *inode, struct file *flip)
 
        pr_debug("priv %p\n", priv);
 
+       mutex_lock(&priv->lock);
        while (!list_empty(&priv->maps)) {
                map = list_entry(priv->maps.next, struct grant_map, next);
                list_del(&map->next);
                gntdev_put_map(NULL /* already removed */, map);
        }
        WARN_ON(!list_empty(&priv->freeable_maps));
+       mutex_unlock(&priv->lock);
 
        if (use_ptemod)
                mmu_notifier_unregister(&priv->mn, priv->mm);
index 9ad327238ba931243967455b5790916dc6b184f1..e30353575d5da11f75e8c927ba53945a23b73d76 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 e9ace099162ce14d73d04523962465ee163b30c7..8a820295657686d634e3a5ded2ee21b5dcefc026 100644 (file)
@@ -1651,6 +1651,11 @@ static int qgroup_update_counters(struct btrfs_fs_info *fs_info,
                                /* Exclusive -> exclusive, nothing changed */
                        }
                }
+
+               /* For exclusive extent, free its reserved bytes too */
+               if (nr_old_roots == 0 && nr_new_roots == 1 &&
+                   cur_new_count == nr_new_roots)
+                       qg->reserved -= num_bytes;
                if (dirty)
                        qgroup_dirty(fs_info, qg);
        }
index dc10c9dd36c1a2ac6264ed21d3248e5f62f1e330..ddd5e94712904501db729c51b59de72cd88ddb5a 100644 (file)
@@ -1506,7 +1506,6 @@ static int __mark_caps_flushing(struct inode *inode,
 
        swap(cf, ci->i_prealloc_cap_flush);
        cf->caps = flushing;
-       cf->kick = false;
 
        spin_lock(&mdsc->cap_dirty_lock);
        list_del_init(&ci->i_dirty_item);
@@ -2123,8 +2122,7 @@ static void kick_flushing_capsnaps(struct ceph_mds_client *mdsc,
 
 static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
                                struct ceph_mds_session *session,
-                               struct ceph_inode_info *ci,
-                               bool kick_all)
+                               struct ceph_inode_info *ci)
 {
        struct inode *inode = &ci->vfs_inode;
        struct ceph_cap *cap;
@@ -2150,9 +2148,7 @@ static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
 
                for (n = rb_first(&ci->i_cap_flush_tree); n; n = rb_next(n)) {
                        cf = rb_entry(n, struct ceph_cap_flush, i_node);
-                       if (cf->tid < first_tid)
-                               continue;
-                       if (kick_all || cf->kick)
+                       if (cf->tid >= first_tid)
                                break;
                }
                if (!n) {
@@ -2161,7 +2157,6 @@ static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
                }
 
                cf = rb_entry(n, struct ceph_cap_flush, i_node);
-               cf->kick = false;
 
                first_tid = cf->tid + 1;
 
@@ -2181,8 +2176,6 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
 {
        struct ceph_inode_info *ci;
        struct ceph_cap *cap;
-       struct ceph_cap_flush *cf;
-       struct rb_node *n;
 
        dout("early_kick_flushing_caps mds%d\n", session->s_mds);
        list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) {
@@ -2205,16 +2198,11 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
                if ((cap->issued & ci->i_flushing_caps) !=
                    ci->i_flushing_caps) {
                        spin_unlock(&ci->i_ceph_lock);
-                       if (!__kick_flushing_caps(mdsc, session, ci, true))
+                       if (!__kick_flushing_caps(mdsc, session, ci))
                                continue;
                        spin_lock(&ci->i_ceph_lock);
                }
 
-               for (n = rb_first(&ci->i_cap_flush_tree); n; n = rb_next(n)) {
-                       cf = rb_entry(n, struct ceph_cap_flush, i_node);
-                       cf->kick = true;
-               }
-
                spin_unlock(&ci->i_ceph_lock);
        }
 }
@@ -2228,7 +2216,7 @@ void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
 
        dout("kick_flushing_caps mds%d\n", session->s_mds);
        list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) {
-               int delayed = __kick_flushing_caps(mdsc, session, ci, false);
+               int delayed = __kick_flushing_caps(mdsc, session, ci);
                if (delayed) {
                        spin_lock(&ci->i_ceph_lock);
                        __cap_delay_requeue(mdsc, ci);
@@ -2261,7 +2249,7 @@ static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc,
 
                spin_unlock(&ci->i_ceph_lock);
 
-               delayed = __kick_flushing_caps(mdsc, session, ci, true);
+               delayed = __kick_flushing_caps(mdsc, session, ci);
                if (delayed) {
                        spin_lock(&ci->i_ceph_lock);
                        __cap_delay_requeue(mdsc, ci);
index 4347039ecc183d538c23f32019e5213da2ebf2f4..6706bde9ad1b1e16e6a283a83ea93c4f58b6b2aa 100644 (file)
@@ -287,7 +287,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
                return 0;
 
        spin_lock(&ctx->flc_lock);
-       list_for_each_entry(lock, &ctx->flc_flock, fl_list) {
+       list_for_each_entry(lock, &ctx->flc_posix, fl_list) {
                ++seen_fcntl;
                if (seen_fcntl > num_fcntl_locks) {
                        err = -ENOSPC;
index 860cc016e70d4ff463c1f7845fc648eaf58269c4..2f2460d23a0600f8f9bf2e1cc4fe3b2286684356 100644 (file)
@@ -189,7 +189,6 @@ static inline void ceph_put_cap_snap(struct ceph_cap_snap *capsnap)
 struct ceph_cap_flush {
        u64 tid;
        int caps;
-       bool kick;
        struct rb_node g_node; // global
        union {
                struct rb_node i_node; // inode
index 5c8ea15e73a53b6b6dbe3e9660973d2eda9c7800..9b5fe503f6cb6c8d76044bb8272084fdb0474c9b 100644 (file)
@@ -3442,22 +3442,15 @@ void __init vfs_caches_init_early(void)
        inode_init_early();
 }
 
-void __init vfs_caches_init(unsigned long mempages)
+void __init vfs_caches_init(void)
 {
-       unsigned long reserve;
-
-       /* Base hash sizes on available memory, with a reserve equal to
-           150% of current kernel size */
-
-       reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);
-       mempages -= reserve;
-
        names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
                        SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 
        dcache_init();
        inode_init();
-       files_init(mempages);
+       files_init();
+       files_maxfiles_init();
        mnt_init();
        bdev_cache_init();
        chrdev_init();
index 7f9d407c759596f950335bd418ab0226f4a629f8..ad17e05ebf95f07888b15f2b09a7b37ac89b9710 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/hardirq.h>
 #include <linux/task_work.h>
 #include <linux/ima.h>
+#include <linux/swap.h>
 
 #include <linux/atomic.h>
 
@@ -308,19 +309,24 @@ void put_filp(struct file *file)
        }
 }
 
-void __init files_init(unsigned long mempages)
+void __init files_init(void)
 { 
-       unsigned long n;
-
        filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
                        SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+       percpu_counter_init(&nr_files, 0, GFP_KERNEL);
+}
 
-       /*
-        * One file with associated inode and dcache is very roughly 1K.
-        * Per default don't use more than 10% of our memory for files. 
-        */ 
+/*
+ * One file with associated inode and dcache is very roughly 1K. Per default
+ * do not use more than 10% of our memory for files.
+ */
+void __init files_maxfiles_init(void)
+{
+       unsigned long n;
+       unsigned long memreserve = (totalram_pages - nr_free_pages()) * 3/2;
+
+       memreserve = min(memreserve, totalram_pages - 1);
+       n = ((totalram_pages - memreserve) * (PAGE_SIZE / 1024)) / 10;
 
-       n = (mempages * (PAGE_SIZE / 1024)) / 10;
        files_stat.max_files = max_t(unsigned long, n, NR_FILE);
-       percpu_counter_init(&nr_files, 0, GFP_KERNEL);
 } 
index 80cc1b35d46043c16bc456e0cadf61e76c281d52..ebb5e37455a07acd86f5fbf1b76d474e99b937fb 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 0cf74df68617b8738342a5f7be7992ccc596bf0a..973c24ce59ad3ef1b62ff3ce00113d7d85cedb68 100644 (file)
@@ -1010,6 +1010,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
        inode = hugetlbfs_get_inode(sb, NULL, S_IFREG | S_IRWXUGO, 0);
        if (!inode)
                goto out_dentry;
+       if (creat_flags == HUGETLB_SHMFS_INODE)
+               inode->i_flags |= S_PRIVATE;
 
        file = ERR_PTR(-ENOMEM);
        if (hugetlb_reserve_pages(inode, 0,
index fbbcf0993312eb9c278dc1343ea2db0fe4edf959..1c2105ed20c5ef4fb390878fb5442943ceec29ae 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 6904213a436368e47628af85701a3beb68e0550b..ebf90e487c752b59270aa559588a8805468ad0f5 100644 (file)
@@ -212,6 +212,7 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
        BUG_ON(!ls->ls_file);
 
        if (nfsd4_layout_setlease(ls)) {
+               fput(ls->ls_file);
                put_nfs4_file(fp);
                kmem_cache_free(nfs4_layout_stateid_cache, ls);
                return NULL;
index 61dfb33f05593c1b19dff8a5346dee37a3539d79..95202719a1fd26bd27ea71a2fe85ec1c248e8d13 100644 (file)
@@ -4396,9 +4396,9 @@ laundromat_main(struct work_struct *laundry)
        queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ);
 }
 
-static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
+static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp)
 {
-       if (!fh_match(&fhp->fh_handle, &stp->st_stid.sc_file->fi_fhandle))
+       if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle))
                return nfserr_bad_stateid;
        return nfs_ok;
 }
@@ -4601,9 +4601,6 @@ nfs4_check_olstateid(struct svc_fh *fhp, struct nfs4_ol_stateid *ols, int flags)
 {
        __be32 status;
 
-       status = nfs4_check_fh(fhp, ols);
-       if (status)
-               return status;
        status = nfsd4_check_openowner_confirmed(ols);
        if (status)
                return status;
@@ -4690,6 +4687,9 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
                status = nfserr_bad_stateid;
                break;
        }
+       if (status)
+               goto out;
+       status = nfs4_check_fh(fhp, s);
 
 done:
        if (!status && filpp)
@@ -4798,7 +4798,7 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
        status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
        if (status)
                return status;
-       return nfs4_check_fh(current_fh, stp);
+       return nfs4_check_fh(current_fh, &stp->st_stid);
 }
 
 /* 
index 54633858733a8da5ac978fe1d19a0a055488e01d..75e0563c09d1911d927501ee52b53a3bd988940e 100644 (file)
@@ -2143,6 +2143,7 @@ nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp,
 #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
                              FATTR4_WORD0_RDATTR_ERROR)
 #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
+#define WORD2_ABSENT_FS_ATTRS 0
 
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
 static inline __be32
@@ -2171,7 +2172,7 @@ nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
 { return 0; }
 #endif
 
-static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
+static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *bmval2, u32 *rdattr_err)
 {
        /* As per referral draft:  */
        if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
@@ -2184,6 +2185,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
        }
        *bmval0 &= WORD0_ABSENT_FS_ATTRS;
        *bmval1 &= WORD1_ABSENT_FS_ATTRS;
+       *bmval2 &= WORD2_ABSENT_FS_ATTRS;
        return 0;
 }
 
@@ -2246,8 +2248,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
        BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion));
 
        if (exp->ex_fslocs.migrated) {
-               BUG_ON(bmval[2]);
-               status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
+               status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, &rdattr_err);
                if (status)
                        goto out;
        }
@@ -2286,8 +2287,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
        }
 
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-       if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) ||
-                       bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
+       if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) ||
+            bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
                err = security_inode_getsecctx(d_inode(dentry),
                                                &context, &contextlen);
                contextsupport = (err == 0);
index 92e48c70f0f05542a75804fe7aac752672abd214..39ddcaf0918f145fb3f2cb916d27aa1b866a220e 100644 (file)
@@ -412,16 +412,36 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group,
                                         unsigned int flags)
 {
        struct fsnotify_mark *lmark, *mark;
+       LIST_HEAD(to_free);
 
+       /*
+        * We have to be really careful here. Anytime we drop mark_mutex, e.g.
+        * fsnotify_clear_marks_by_inode() can come and free marks. Even in our
+        * to_free list so we have to use mark_mutex even when accessing that
+        * list. And freeing mark requires us to drop mark_mutex. So we can
+        * reliably free only the first mark in the list. That's why we first
+        * move marks to free to to_free list in one go and then free marks in
+        * to_free list one by one.
+        */
        mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
        list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
-               if (mark->flags & flags) {
-                       fsnotify_get_mark(mark);
-                       fsnotify_destroy_mark_locked(mark, group);
-                       fsnotify_put_mark(mark);
-               }
+               if (mark->flags & flags)
+                       list_move(&mark->g_list, &to_free);
        }
        mutex_unlock(&group->mark_mutex);
+
+       while (1) {
+               mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
+               if (list_empty(&to_free)) {
+                       mutex_unlock(&group->mark_mutex);
+                       break;
+               }
+               mark = list_first_entry(&to_free, struct fsnotify_mark, g_list);
+               fsnotify_get_mark(mark);
+               fsnotify_destroy_mark_locked(mark, group);
+               mutex_unlock(&group->mark_mutex);
+               fsnotify_put_mark(mark);
+       }
 }
 
 /*
index 1a35c6139656344516aacd59c7120f6fb877f2a2..0f5fd9db8194ef5d135f1896f6e2645a5f059cd8 100644 (file)
@@ -685,7 +685,7 @@ static int ocfs2_direct_IO_zero_extend(struct ocfs2_super *osb,
 
        if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN)) {
                u64 s = i_size_read(inode);
-               sector_t sector = (p_cpos << (osb->s_clustersize_bits - 9)) +
+               sector_t sector = ((u64)p_cpos << (osb->s_clustersize_bits - 9)) +
                        (do_div(s, osb->s_clustersize) >> 9);
 
                ret = blkdev_issue_zeroout(osb->sb->s_bdev, sector,
@@ -910,7 +910,7 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb,
                BUG_ON(!p_cpos || (ext_flags & OCFS2_EXT_UNWRITTEN));
 
                ret = blkdev_issue_zeroout(osb->sb->s_bdev,
-                               p_cpos << (osb->s_clustersize_bits - 9),
+                               (u64)p_cpos << (osb->s_clustersize_bits - 9),
                                zero_len_head >> 9, GFP_NOFS, false);
                if (ret < 0)
                        mlog_errno(ret);
index 8b23aa2f52ddafe31be83b730d7219693222a1c5..23157e40dd740204bc10f9eaeb55ec08f2f0dfb4 100644 (file)
@@ -4025,9 +4025,13 @@ static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb)
        osb->dc_work_sequence = osb->dc_wake_sequence;
 
        processed = osb->blocked_lock_count;
-       while (processed) {
-               BUG_ON(list_empty(&osb->blocked_lock_list));
-
+       /*
+        * blocked lock processing in this loop might call iput which can
+        * remove items off osb->blocked_lock_list. Downconvert up to
+        * 'processed' number of locks, but stop short if we had some
+        * removed in ocfs2_mark_lockres_freeing when downconverting.
+        */
+       while (processed && !list_empty(&osb->blocked_lock_list)) {
                lockres = list_entry(osb->blocked_lock_list.next,
                                     struct ocfs2_lock_res, l_blocked_list);
                list_del_init(&lockres->l_blocked_list);
index 7e412ad748363489baad12cbb644b8074d78cfeb..270221fcef42cc42fcfdbc098b587b571be65a12 100644 (file)
@@ -121,8 +121,9 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
                 * Other callers might not initialize the si_lsb field,
                 * so check explicitly for the right codes here.
                 */
-               if (kinfo->si_code == BUS_MCEERR_AR ||
-                   kinfo->si_code == BUS_MCEERR_AO)
+               if (kinfo->si_signo == SIGBUS &&
+                   (kinfo->si_code == BUS_MCEERR_AR ||
+                    kinfo->si_code == BUS_MCEERR_AO))
                        err |= __put_user((short) kinfo->si_addr_lsb,
                                          &uinfo->ssi_addr_lsb);
 #endif
index 48db6a56975f5ebc874d19054828b70a5f4aaa15..5aa519711e0b6fcb1212a517e50be5afac8ed7d7 100644 (file)
@@ -691,7 +691,7 @@ struct drm_vblank_crtc {
        struct timer_list disable_timer;                /* delayed disable timer */
 
        /* vblank counter, protected by dev->vblank_time_lock for writes */
-       unsigned long count;
+       u32 count;
        /* vblank timestamps, protected by dev->vblank_time_lock for writes */
        struct timeval time[DRM_VBLANKTIME_RBSIZE];
 
index 57ca8cc383a615344498202384b1b814911bc766..3b4d8a4a23fb760867fc7d59ede2a3459eac2375 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 c8fc187061de5fbd9fc8545f602a62baaa45b8cc..918aa68b5199d54501a2a9d68404e44388e9e04e 100644 (file)
@@ -168,6 +168,7 @@ struct drm_encoder_helper_funcs {
  * @get_modes: get mode list for this connector
  * @mode_valid: is this mode valid on the given connector? (optional)
  * @best_encoder: return the preferred encoder for this connector
+ * @atomic_best_encoder: atomic version of @best_encoder
  *
  * The helper operations are called by the mid-layer CRTC helper.
  */
@@ -176,6 +177,8 @@ struct drm_connector_helper_funcs {
        enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
                                           struct drm_display_mode *mode);
        struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
+       struct drm_encoder *(*atomic_best_encoder)(struct drm_connector *connector,
+                                                  struct drm_connector_state *connector_state);
 };
 
 extern void drm_helper_disable_unused_functions(struct drm_device *dev);
index 799050198323e852c7cbb45e3c1236cc67d386ac..53c53c459b15c8207997da61234d0ab9ea2805ae 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 45c39a37f9249562761dc9615ffecf12ec194846..8bc073d297db2a233cf389d6c0656dec78c0445a 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 6c78956aa47092440edb3a73e7b9389ac3a57558..d2992bfa17063a052a08a106b9105284ce4bfa4a 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 cc008c338f5a9bcb66076da96e929d6104697373..84b783f277f761a0ef7b940bd1fbab37db60567e 100644 (file)
@@ -55,7 +55,8 @@ struct vm_fault;
 
 extern void __init inode_init(void);
 extern void __init inode_init_early(void);
-extern void __init files_init(unsigned long);
+extern void __init files_init(void);
+extern void __init files_maxfiles_init(void);
 
 extern struct files_stat_struct files_stat;
 extern unsigned long get_max_files(void);
@@ -2245,7 +2246,7 @@ extern int ioctl_preallocate(struct file *filp, void __user *argp);
 
 /* fs/dcache.c */
 extern void __init vfs_caches_init_early(void);
-extern void __init vfs_caches_init(unsigned long);
+extern void __init vfs_caches_init(void);
 
 extern struct kmem_cache *names_cachep;
 
index 92188b0225bb31f33eba9deacc4b9b88036c1d8e..51744bcf74eec7bee678b9e1f63c3a10f247350e 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 3499d36e60672fa3c80a8f7beba87ed0b5a37b67..11affb3c2768a10b09d44e71c43cddb68bc879d4 100644 (file)
@@ -39,6 +39,7 @@
 #define ARIZONA_PWM_DRIVE_3                      0x32
 #define ARIZONA_WAKE_CONTROL                     0x40
 #define ARIZONA_SEQUENCE_CONTROL                 0x41
+#define ARIZONA_SPARE_TRIGGERS                   0x42
 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1    0x61
 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2    0x62
 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3    0x63
 #define ARIZONA_WSEQ_ENA_JD2_RISE_SHIFT               0  /* WSEQ_ENA_JD2_RISE */
 #define ARIZONA_WSEQ_ENA_JD2_RISE_WIDTH               1  /* WSEQ_ENA_JD2_RISE */
 
+/*
+ * R66 (0x42) - Spare Triggers
+ */
+#define ARIZONA_WS_TRG8                          0x0080  /* WS_TRG8 */
+#define ARIZONA_WS_TRG8_MASK                     0x0080  /* WS_TRG8 */
+#define ARIZONA_WS_TRG8_SHIFT                         7  /* WS_TRG8 */
+#define ARIZONA_WS_TRG8_WIDTH                         1  /* WS_TRG8 */
+#define ARIZONA_WS_TRG7                          0x0040  /* WS_TRG7 */
+#define ARIZONA_WS_TRG7_MASK                     0x0040  /* WS_TRG7 */
+#define ARIZONA_WS_TRG7_SHIFT                         6  /* WS_TRG7 */
+#define ARIZONA_WS_TRG7_WIDTH                         1  /* WS_TRG7 */
+#define ARIZONA_WS_TRG6                          0x0020  /* WS_TRG6 */
+#define ARIZONA_WS_TRG6_MASK                     0x0020  /* WS_TRG6 */
+#define ARIZONA_WS_TRG6_SHIFT                         5  /* WS_TRG6 */
+#define ARIZONA_WS_TRG6_WIDTH                         1  /* WS_TRG6 */
+#define ARIZONA_WS_TRG5                          0x0010  /* WS_TRG5 */
+#define ARIZONA_WS_TRG5_MASK                     0x0010  /* WS_TRG5 */
+#define ARIZONA_WS_TRG5_SHIFT                         4  /* WS_TRG5 */
+#define ARIZONA_WS_TRG5_WIDTH                         1  /* WS_TRG5 */
+#define ARIZONA_WS_TRG4                          0x0008  /* WS_TRG4 */
+#define ARIZONA_WS_TRG4_MASK                     0x0008  /* WS_TRG4 */
+#define ARIZONA_WS_TRG4_SHIFT                         3  /* WS_TRG4 */
+#define ARIZONA_WS_TRG4_WIDTH                         1  /* WS_TRG4 */
+#define ARIZONA_WS_TRG3                          0x0004  /* WS_TRG3 */
+#define ARIZONA_WS_TRG3_MASK                     0x0004  /* WS_TRG3 */
+#define ARIZONA_WS_TRG3_SHIFT                         2  /* WS_TRG3 */
+#define ARIZONA_WS_TRG3_WIDTH                         1  /* WS_TRG3 */
+#define ARIZONA_WS_TRG2                          0x0002  /* WS_TRG2 */
+#define ARIZONA_WS_TRG2_MASK                     0x0002  /* WS_TRG2 */
+#define ARIZONA_WS_TRG2_SHIFT                         1  /* WS_TRG2 */
+#define ARIZONA_WS_TRG2_WIDTH                         1  /* WS_TRG2 */
+#define ARIZONA_WS_TRG1                          0x0001  /* WS_TRG1 */
+#define ARIZONA_WS_TRG1_MASK                     0x0001  /* WS_TRG1 */
+#define ARIZONA_WS_TRG1_SHIFT                         0  /* WS_TRG1 */
+#define ARIZONA_WS_TRG1_WIDTH                         1  /* WS_TRG1 */
+
 /*
  * R97 (0x61) - Sample Rate Sequence Select 1
  */
index 2e872f92dbac0cecc2c5b3a65fbe7ff8678e48d5..bf6f117fcf4d80cb7de6147e86c6ba19fa13febd 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 0038ac7466fd26e7562a026af68632573e3bb0ea..15549578d55998e5497c5da58a50fa1531e132d8 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 f34e040b34e9ffbf0abe66b439571ec8902440ca..41c93844fb1d1ed5c0dbad77fe5a409557d66067 100644 (file)
@@ -631,15 +631,19 @@ static inline void ClearPageSlabPfmemalloc(struct page *page)
         1 << PG_private | 1 << PG_private_2 | \
         1 << PG_writeback | 1 << PG_reserved | \
         1 << PG_slab    | 1 << PG_swapcache | 1 << PG_active | \
-        1 << PG_unevictable | __PG_MLOCKED | __PG_HWPOISON | \
+        1 << PG_unevictable | __PG_MLOCKED | \
         __PG_COMPOUND_LOCK)
 
 /*
  * Flags checked when a page is prepped for return by the page allocator.
- * Pages being prepped should not have any flags set.  It they are set,
+ * Pages being prepped should not have these flags set.  It they are set,
  * there has been a kernel bug or struct page corruption.
+ *
+ * __PG_HWPOISON is exceptional because it needs to be kept beyond page's
+ * alloc-free cycle to prevent from reusing the page.
  */
-#define PAGE_FLAGS_CHECK_AT_PREP       ((1 << NR_PAGEFLAGS) - 1)
+#define PAGE_FLAGS_CHECK_AT_PREP       \
+       (((1 << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON)
 
 #define PAGE_FLAGS_PRIVATE                             \
        (1 << PG_private | 1 << PG_private_2)
index 59c55ea0f0b50c270d64bebe9dd6c25a717ca5ec..4a6759098769c6ad4902612bf3b2647fe0898f60 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 d6cdd6e87d53bcd1b4f390f61f73b1c91b076bdd..9b88536487e667b8727414e4131188db869711d4 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 45534da57759a30d4a8c281bda094c8d4921dba3..644bdc61c387581c29a29d20c0cf1c3fc5085830 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 22a44c2f596380856acb1bccf95f14d0c2144994..c192e1b46cdc27372dc56ba704aa630ff113dfd6 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 4942710ef720ea5716e8cc6ebf0df941e22500ba..8d1d7fa67ec48bad6872be07258066f9410eec6e 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 0e9d75b49bede16f09a7e96e697a6d9061677c0c..74bc85473b58c18e3bc92e2fcf7c70a232fe75d7 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 4cecd0c175f607c7f3cae2a2fb03660f81131799..bb7b2ebfee7b9380e66f793cf5c6526e1aaf937f 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 37d95a89827595f8099bd72ebec02891c15bf6d1..5abba037d2456fc2616ae5df1270fd928299c1de 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 427bc41df3aef3a3f931bd94830f027bafea2661..086cd7ff6ddcbb457ee31277baf3fee143f0181d 100644 (file)
@@ -89,6 +89,13 @@ struct snd_soc_tplg_kcontrol_ops {
                struct snd_ctl_elem_info *uinfo);
 };
 
+/* Bytes ext operations, for TLV byte controls */
+struct snd_soc_tplg_bytes_ext_ops {
+       u32 id;
+       int (*get)(unsigned int __user *bytes, unsigned int size);
+       int (*put)(const unsigned int __user *bytes, unsigned int size);
+};
+
 /*
  * DAPM widget event handlers - used to map handlers onto widgets.
  */
@@ -136,9 +143,13 @@ struct snd_soc_tplg_ops {
        int (*manifest)(struct snd_soc_component *,
                struct snd_soc_tplg_manifest *);
 
-       /* bespoke kcontrol handlers available for binding */
+       /* vendor specific kcontrol handlers available for binding */
        const struct snd_soc_tplg_kcontrol_ops *io_ops;
        int io_ops_count;
+
+       /* vendor specific bytes ext handlers available for binding */
+       const struct snd_soc_tplg_bytes_ext_ops *bytes_ext_ops;
+       int bytes_ext_ops_count;
 };
 
 #ifdef CONFIG_SND_SOC_TOPOLOGY
index 93df8bf9d54a9e1b9502836faec752b4c6aa20b0..884e728b09d9a57e8a56ac8ea224b3f873cb81c3 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 88cf39d96d0fb08704745c28a8e9d7262de68f09..317a1ed2f4acc7745c3e02955c60e8c1dc8eb7c3 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 efe3443572baa5a3650d638806fd60ef09a90f68..413417f3707bbfde6375dfc14098bc1e099b5b70 100644 (file)
 #define PCI_MSIX_PBA           8       /* Pending Bit Array offset */
 #define  PCI_MSIX_PBA_BIR      0x00000007 /* BAR index */
 #define  PCI_MSIX_PBA_OFFSET   0xfffffff8 /* Offset into specified BAR */
+#define PCI_MSIX_FLAGS_BIRMASK PCI_MSIX_PBA_BIR /* deprecated */
 #define PCI_CAP_MSIX_SIZEOF    12      /* size of MSIX registers */
 
 /* MSI-X Table entry format */
index c5d5626289cee3a46f7e1b7d2441ca0496ba4471..56506553d4d80dff814b75f45db6db280fd0dea7 100644 (file)
@@ -656,7 +656,7 @@ asmlinkage __visible void __init start_kernel(void)
        key_init();
        security_init();
        dbg_late_init();
-       vfs_caches_init(totalram_pages);
+       vfs_caches_init();
        signals_init();
        /* rootfs populating might need page-writeback */
        page_writeback_init();
index a24ba9fe5bb8892dfaa7452fe78f9ef68d1d97fc..161a1807e6efb0fe8e773c41dafc8b4a76b38f71 100644 (file)
@@ -142,7 +142,6 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info)
                if (!leaf)
                        return -ENOMEM;
                INIT_LIST_HEAD(&leaf->msg_list);
-               info->qsize += sizeof(*leaf);
        }
        leaf->priority = msg->m_type;
        rb_link_node(&leaf->rb_node, parent, p);
@@ -187,7 +186,6 @@ try_again:
                             "lazy leaf delete!\n");
                rb_erase(&leaf->rb_node, &info->msg_tree);
                if (info->node_cache) {
-                       info->qsize -= sizeof(*leaf);
                        kfree(leaf);
                } else {
                        info->node_cache = leaf;
@@ -200,7 +198,6 @@ try_again:
                if (list_empty(&leaf->msg_list)) {
                        rb_erase(&leaf->rb_node, &info->msg_tree);
                        if (info->node_cache) {
-                               info->qsize -= sizeof(*leaf);
                                kfree(leaf);
                        } else {
                                info->node_cache = leaf;
@@ -1034,7 +1031,6 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
                /* Save our speculative allocation into the cache */
                INIT_LIST_HEAD(&new_leaf->msg_list);
                info->node_cache = new_leaf;
-               info->qsize += sizeof(*new_leaf);
                new_leaf = NULL;
        } else {
                kfree(new_leaf);
@@ -1142,7 +1138,6 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
                /* Save our speculative allocation into the cache */
                INIT_LIST_HEAD(&new_leaf->msg_list);
                info->node_cache = new_leaf;
-               info->qsize += sizeof(*new_leaf);
        } else {
                kfree(new_leaf);
        }
index bc3d530cb23efacb2e5695ad85a9bd3898524fa2..b471e5a3863ddbca70f2bf4dee22f40df0345fbe 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 06e5cf2fe019faee43aa9f8ca9f17cad4973b74d..4aef24d91b633e12275cea64a380df4543fc796b 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -545,7 +545,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
                if  ((shmflg & SHM_NORESERVE) &&
                                sysctl_overcommit_memory != OVERCOMMIT_NEVER)
                        acctflag = VM_NORESERVE;
-               file = shmem_file_setup(name, size, acctflag);
+               file = shmem_kernel_file_setup(name, size, acctflag);
        }
        error = PTR_ERR(file);
        if (IS_ERR(file))
index ee14e3a35a2994399edf176e7775e778c395e592..f0acff0f66c91380412dcbc1c899c94b1d3236b0 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 d3dae3419b99566c127f1682b29f39bb184bbdb1..e6feb51141340a99a248fea0ad1dc17402b0dbdb 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 b2be01b1aa9dcb7a70792fa381c264b229a106d0..c8aa3f75bc4db8ad7a2242aae6406bfd6f86f8c5 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 27f4332c7f84ea8b3d7ec8bb3466a64f225a8487..ae216824e8ca9224c4b76f225ef58d664a3e1726 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 10e489c448fe4e934e2c203ca2aa7a8d0679bb5e..fdea0bee7b5a4d5e2fcf43ee3b92e1a37dea6c71 100644 (file)
@@ -97,6 +97,7 @@ bool kthread_should_park(void)
 {
        return test_bit(KTHREAD_SHOULD_PARK, &to_kthread(current)->flags);
 }
+EXPORT_SYMBOL_GPL(kthread_should_park);
 
 /**
  * kthread_freezable_should_stop - should this freezable kthread return now?
@@ -171,6 +172,7 @@ void kthread_parkme(void)
 {
        __kthread_parkme(to_kthread(current));
 }
+EXPORT_SYMBOL_GPL(kthread_parkme);
 
 static int kthread(void *_create)
 {
@@ -411,6 +413,7 @@ void kthread_unpark(struct task_struct *k)
        if (kthread)
                __kthread_unpark(k, kthread);
 }
+EXPORT_SYMBOL_GPL(kthread_unpark);
 
 /**
  * kthread_park - park a thread created by kthread_create().
@@ -441,6 +444,7 @@ int kthread_park(struct task_struct *k)
        }
        return ret;
 }
+EXPORT_SYMBOL_GPL(kthread_park);
 
 /**
  * kthread_stop - stop a thread created by kthread_create().
index 04ab18151cc8fa174a5859124ee07c144f33d505..df19ae4debd09c134d438b57e4ead7c71462c2b6 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 4d2b82e610e2a48f429a700f0529d6dc5942700a..b86b7bf1be388d72fe92fb6038b4a67b4710df1f 100644 (file)
@@ -602,13 +602,16 @@ const struct kernel_symbol *find_symbol(const char *name,
 }
 EXPORT_SYMBOL_GPL(find_symbol);
 
-/* Search for module by name: must hold module_mutex. */
+/*
+ * Search for module by name: must hold module_mutex (or preempt disabled
+ * for read-only access).
+ */
 static struct module *find_module_all(const char *name, size_t len,
                                      bool even_unformed)
 {
        struct module *mod;
 
-       module_assert_mutex();
+       module_assert_mutex_or_preempt();
 
        list_for_each_entry(mod, &modules, list) {
                if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
@@ -621,6 +624,7 @@ static struct module *find_module_all(const char *name, size_t len,
 
 struct module *find_module(const char *name)
 {
+       module_assert_mutex();
        return find_module_all(name, strlen(name), false);
 }
 EXPORT_SYMBOL_GPL(find_module);
index 836df8dac6ccd1230f21d20dc610429538cc59a1..0f6bbbe77b46c092d0de31e0c9eec8a0f17e6791 100644 (file)
@@ -2748,12 +2748,15 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
                 * Other callers might not initialize the si_lsb field,
                 * so check explicitly for the right codes here.
                 */
-               if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
+               if (from->si_signo == SIGBUS &&
+                   (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
                        err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
 #endif
 #ifdef SEGV_BNDERR
-               err |= __put_user(from->si_lower, &to->si_lower);
-               err |= __put_user(from->si_upper, &to->si_upper);
+               if (from->si_signo == SIGSEGV && from->si_code == SEGV_BNDERR) {
+                       err |= __put_user(from->si_lower, &to->si_lower);
+                       err |= __put_user(from->si_upper, &to->si_upper);
+               }
 #endif
                break;
        case __SI_CHLD:
@@ -3017,7 +3020,7 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo,
                        int, sig,
                        struct compat_siginfo __user *, uinfo)
 {
-       siginfo_t info;
+       siginfo_t info = {};
        int ret = copy_siginfo_from_user32(&info, uinfo);
        if (unlikely(ret))
                return ret;
@@ -3061,7 +3064,7 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo,
                        int, sig,
                        struct compat_siginfo __user *, uinfo)
 {
-       siginfo_t info;
+       siginfo_t info = {};
 
        if (copy_siginfo_from_user32(&info, uinfo))
                return -EFAULT;
index 5e097fa9faf7016470b8283931023a15d20ed97d..84190f02b521c9fc77cee6e6a6722000939ee470 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 df30632f0bef9ec1c36a48d83a6eb87cd18ee405..ff19f66d3f7fbd635a44cc03614b5fbe4485cc56 100644 (file)
@@ -119,7 +119,7 @@ unsigned long iommu_tbl_range_alloc(struct device *dev,
        unsigned long align_mask = 0;
 
        if (align_order > 0)
-               align_mask = 0xffffffffffffffffl >> (64 - align_order);
+               align_mask = ~0ul >> (BITS_PER_LONG - align_order);
 
        /* Sanity check */
        if (unlikely(npages == 0)) {
index 1132d733556dbc330d32eda5460f55e6e067b627..17c75a4246c8bbab8b56fe4d562cd85ea670a21f 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 c107094f79bae9ee895bd6bf30976d900f16c141..097c7a4bfbd9f13f4845acae80d73aa7b0e66fb2 100644 (file)
@@ -1676,12 +1676,7 @@ static void __split_huge_page_refcount(struct page *page,
                /* after clearing PageTail the gup refcount can be released */
                smp_mb__after_atomic();
 
-               /*
-                * retain hwpoison flag of the poisoned tail page:
-                *   fix for the unsuitable process killed on Guest Machine(KVM)
-                *   by the memory-failure.
-                */
-               page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP | __PG_HWPOISON;
+               page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
                page_tail->flags |= (page->flags &
                                     ((1L << PG_referenced) |
                                      (1L << PG_swapbacked) |
index 6c513a63ea84c3c7ffd41201b7a419ff7b6dfd5d..7b28e9cdf1c7686428fe49802fced44088043555 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 680ceedf810ab4c9cd08c9929f5d445de9f5aa6a..e07c94fbd0ac5a141ecf95ab7d39d046fea13e67 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 c53543d892828e75796239d6ce36afa90203085b..1f4446a90cef07c67ee1082b83f0ca87ebfefea1 100644 (file)
@@ -909,6 +909,18 @@ int get_hwpoison_page(struct page *page)
         * directly for tail pages.
         */
        if (PageTransHuge(head)) {
+               /*
+                * Non anonymous thp exists only in allocation/free time. We
+                * can't handle such a case correctly, so let's give it up.
+                * This should be better than triggering BUG_ON when kernel
+                * tries to touch the "partially handled" page.
+                */
+               if (!PageAnon(head)) {
+                       pr_err("MCE: %#lx: non anonymous thp\n",
+                               page_to_pfn(page));
+                       return 0;
+               }
+
                if (get_page_unless_zero(head)) {
                        if (PageTail(page))
                                get_page(page);
@@ -1134,17 +1146,11 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
        }
 
        if (!PageHuge(p) && PageTransHuge(hpage)) {
-               if (!PageAnon(hpage)) {
-                       pr_err("MCE: %#lx: non anonymous thp\n", pfn);
-                       if (TestClearPageHWPoison(p))
-                               atomic_long_sub(nr_pages, &num_poisoned_pages);
-                       put_page(p);
-                       if (p != hpage)
-                               put_page(hpage);
-                       return -EBUSY;
-               }
-               if (unlikely(split_huge_page(hpage))) {
-                       pr_err("MCE: %#lx: thp split failed\n", pfn);
+               if (!PageAnon(hpage) || unlikely(split_huge_page(hpage))) {
+                       if (!PageAnon(hpage))
+                               pr_err("MCE: %#lx: non anonymous thp\n", pfn);
+                       else
+                               pr_err("MCE: %#lx: thp split failed\n", pfn);
                        if (TestClearPageHWPoison(p))
                                atomic_long_sub(nr_pages, &num_poisoned_pages);
                        put_page(p);
@@ -1209,9 +1215,9 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
        if (!PageHWPoison(p)) {
                printk(KERN_ERR "MCE %#lx: just unpoisoned\n", pfn);
                atomic_long_sub(nr_pages, &num_poisoned_pages);
+               unlock_page(hpage);
                put_page(hpage);
-               res = 0;
-               goto out;
+               return 0;
        }
        if (hwpoison_filter(p)) {
                if (TestClearPageHWPoison(p))
@@ -1535,6 +1541,8 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags)
                 */
                ret = __get_any_page(page, pfn, 0);
                if (!PageLRU(page)) {
+                       /* Drop page reference which is from __get_any_page() */
+                       put_page(page);
                        pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n",
                                pfn, page->flags);
                        return -EIO;
@@ -1564,13 +1572,12 @@ static int soft_offline_huge_page(struct page *page, int flags)
        unlock_page(hpage);
 
        ret = isolate_huge_page(hpage, &pagelist);
-       if (ret) {
-               /*
-                * get_any_page() and isolate_huge_page() takes a refcount each,
-                * so need to drop one here.
-                */
-               put_page(hpage);
-       } else {
+       /*
+        * get_any_page() and isolate_huge_page() takes a refcount each,
+        * so need to drop one here.
+        */
+       put_page(hpage);
+       if (!ret) {
                pr_info("soft offline: %#lx hugepage failed to isolate\n", pfn);
                return -EBUSY;
        }
@@ -1656,6 +1663,8 @@ static int __soft_offline_page(struct page *page, int flags)
                inc_zone_page_state(page, NR_ISOLATED_ANON +
                                        page_is_file_cache(page));
                list_add(&page->lru, &pagelist);
+               if (!TestSetPageHWPoison(page))
+                       atomic_long_inc(&num_poisoned_pages);
                ret = migrate_pages(&pagelist, new_page, NULL, MPOL_MF_MOVE_ALL,
                                        MIGRATE_SYNC, MR_MEMORY_FAILURE);
                if (ret) {
@@ -1670,9 +1679,8 @@ static int __soft_offline_page(struct page *page, int flags)
                                pfn, ret, page->flags);
                        if (ret > 0)
                                ret = -EIO;
-               } else {
-                       SetPageHWPoison(page);
-                       atomic_long_inc(&num_poisoned_pages);
+                       if (TestClearPageHWPoison(page))
+                               atomic_long_dec(&num_poisoned_pages);
                }
        } else {
                pr_info("soft offline: %#lx: isolation failed: %d, page count %d, type %lx\n",
index 26fbba7d888f887c3383c1bb5829cb4f204e2040..6da82bcb0a8b66b7326c1a021a7eac3b476cd85e 100644 (file)
@@ -446,7 +446,7 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn)
        int nr_pages = PAGES_PER_SECTION;
        int nid = pgdat->node_id;
        int zone_type;
-       unsigned long flags;
+       unsigned long flags, pfn;
        int ret;
 
        zone_type = zone - pgdat->node_zones;
@@ -461,6 +461,14 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn)
        pgdat_resize_unlock(zone->zone_pgdat, &flags);
        memmap_init_zone(nr_pages, nid, zone_type,
                         phys_start_pfn, MEMMAP_HOTPLUG);
+
+       /* online_page_range is called later and expects pages reserved */
+       for (pfn = phys_start_pfn; pfn < phys_start_pfn + nr_pages; pfn++) {
+               if (!pfn_valid(pfn))
+                       continue;
+
+               SetPageReserved(pfn_to_page(pfn));
+       }
        return 0;
 }
 
@@ -1269,6 +1277,7 @@ int __ref add_memory(int nid, u64 start, u64 size)
 
        /* create new memmap entry */
        firmware_map_add_hotplug(start, start + size, "System RAM");
+       memblock_add_node(start, size, nid);
 
        goto out;
 
@@ -2005,6 +2014,8 @@ void __ref remove_memory(int nid, u64 start, u64 size)
 
        /* remove memmap entry */
        firmware_map_remove(start, start + size, "System RAM");
+       memblock_free(start, size);
+       memblock_remove(start, size);
 
        arch_remove_memory(start, size);
 
index ee401e4e5ef187c92247d03dd6d2ea0893092d1c..eb4267107d1fee9fa2a55e4076c014500e3b1edb 100644 (file)
@@ -880,7 +880,8 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
        /* Establish migration ptes or remove ptes */
        if (page_mapped(page)) {
                try_to_unmap(page,
-                       TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
+                       TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS|
+                       TTU_IGNORE_HWPOISON);
                page_was_mapped = 1;
        }
 
@@ -950,7 +951,10 @@ out:
                list_del(&page->lru);
                dec_zone_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
-               if (reason != MR_MEMORY_FAILURE)
+               /* Soft-offlined page shouldn't go through lru cache list */
+               if (reason == MR_MEMORY_FAILURE)
+                       put_page(page);
+               else
                        putback_lru_page(page);
        }
 
index 22cddd3e5de8433952e99438d3260ae9ff20bd8d..5cccc127ef81f1d64ca46f9ce9ad50f519d4ea9f 100644 (file)
@@ -2063,10 +2063,10 @@ static struct notifier_block ratelimit_nb = {
  */
 void __init page_writeback_init(void)
 {
+       BUG_ON(wb_domain_init(&global_wb_domain, GFP_KERNEL));
+
        writeback_set_ratelimit();
        register_cpu_notifier(&ratelimit_nb);
-
-       BUG_ON(wb_domain_init(&global_wb_domain, GFP_KERNEL));
 }
 
 /**
index ef19f22b2b7de1728fb4ed8d6451d29bb993a928..5b5240b7f642de179efa3552245fbf9326d7a206 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/interrupt.h>
-#include <linux/rwsem.h>
 #include <linux/pagemap.h>
 #include <linux/jiffies.h>
 #include <linux/bootmem.h>
@@ -981,21 +980,21 @@ static void __init __free_pages_boot_core(struct page *page,
 
 #if defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) || \
        defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP)
-/* Only safe to use early in boot when initialisation is single-threaded */
+
 static struct mminit_pfnnid_cache early_pfnnid_cache __meminitdata;
 
 int __meminit early_pfn_to_nid(unsigned long pfn)
 {
+       static DEFINE_SPINLOCK(early_pfn_lock);
        int nid;
 
-       /* The system will behave unpredictably otherwise */
-       BUG_ON(system_state != SYSTEM_BOOTING);
-
+       spin_lock(&early_pfn_lock);
        nid = __early_pfn_to_nid(pfn, &early_pfnnid_cache);
-       if (nid >= 0)
-               return nid;
-       /* just returns 0 */
-       return 0;
+       if (nid < 0)
+               nid = 0;
+       spin_unlock(&early_pfn_lock);
+
+       return nid;
 }
 #endif
 
@@ -1060,7 +1059,15 @@ static void __init deferred_free_range(struct page *page,
                __free_pages_boot_core(page, pfn, 0);
 }
 
-static __initdata DECLARE_RWSEM(pgdat_init_rwsem);
+/* Completion tracking for deferred_init_memmap() threads */
+static atomic_t pgdat_init_n_undone __initdata;
+static __initdata DECLARE_COMPLETION(pgdat_init_all_done_comp);
+
+static inline void __init pgdat_init_report_one_done(void)
+{
+       if (atomic_dec_and_test(&pgdat_init_n_undone))
+               complete(&pgdat_init_all_done_comp);
+}
 
 /* Initialise remaining memory on a node */
 static int __init deferred_init_memmap(void *data)
@@ -1077,7 +1084,7 @@ static int __init deferred_init_memmap(void *data)
        const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id);
 
        if (first_init_pfn == ULONG_MAX) {
-               up_read(&pgdat_init_rwsem);
+               pgdat_init_report_one_done();
                return 0;
        }
 
@@ -1177,7 +1184,8 @@ free_range:
 
        pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages,
                                        jiffies_to_msecs(jiffies - start));
-       up_read(&pgdat_init_rwsem);
+
+       pgdat_init_report_one_done();
        return 0;
 }
 
@@ -1185,14 +1193,17 @@ void __init page_alloc_init_late(void)
 {
        int nid;
 
+       /* There will be num_node_state(N_MEMORY) threads */
+       atomic_set(&pgdat_init_n_undone, num_node_state(N_MEMORY));
        for_each_node_state(nid, N_MEMORY) {
-               down_read(&pgdat_init_rwsem);
                kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid);
        }
 
        /* Block until all are initialised */
-       down_write(&pgdat_init_rwsem);
-       up_write(&pgdat_init_rwsem);
+       wait_for_completion(&pgdat_init_all_done_comp);
+
+       /* Reinit limits that are based on free pages after the kernel is up */
+       files_maxfiles_init();
 }
 #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
 
@@ -1285,6 +1296,10 @@ static inline int check_new_page(struct page *page)
                bad_reason = "non-NULL mapping";
        if (unlikely(atomic_read(&page->_count) != 0))
                bad_reason = "nonzero _count";
+       if (unlikely(page->flags & __PG_HWPOISON)) {
+               bad_reason = "HWPoisoned (hardware-corrupted)";
+               bad_flags = __PG_HWPOISON;
+       }
        if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_PREP)) {
                bad_reason = "PAGE_FLAGS_CHECK_AT_PREP flag set";
                bad_flags = PAGE_FLAGS_CHECK_AT_PREP;
@@ -1328,12 +1343,15 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
        set_page_owner(page, order, gfp_flags);
 
        /*
-        * page->pfmemalloc is set when ALLOC_NO_WATERMARKS was necessary to
+        * page is set pfmemalloc when ALLOC_NO_WATERMARKS was necessary to
         * allocate the page. The expectation is that the caller is taking
         * steps that will free more memory. The caller should avoid the page
         * being used for !PFMEMALLOC purposes.
         */
-       page->pfmemalloc = !!(alloc_flags & ALLOC_NO_WATERMARKS);
+       if (alloc_flags & ALLOC_NO_WATERMARKS)
+               set_page_pfmemalloc(page);
+       else
+               clear_page_pfmemalloc(page);
 
        return 0;
 }
@@ -3330,7 +3348,7 @@ refill:
                atomic_add(size - 1, &page->_count);
 
                /* reset page count bias and offset to start of new frag */
-               nc->pfmemalloc = page->pfmemalloc;
+               nc->pfmemalloc = page_is_pfmemalloc(page);
                nc->pagecnt_bias = size;
                nc->offset = size;
        }
@@ -5045,6 +5063,10 @@ static unsigned long __meminit zone_spanned_pages_in_node(int nid,
 {
        unsigned long zone_start_pfn, zone_end_pfn;
 
+       /* When hotadd a new node, the node should be empty */
+       if (!node_start_pfn && !node_end_pfn)
+               return 0;
+
        /* Get the start and end of the zone */
        zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type];
        zone_end_pfn = arch_zone_highest_possible_pfn[zone_type];
@@ -5108,6 +5130,10 @@ static unsigned long __meminit zone_absent_pages_in_node(int nid,
        unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type];
        unsigned long zone_start_pfn, zone_end_pfn;
 
+       /* When hotadd a new node, the node should be empty */
+       if (!node_start_pfn && !node_end_pfn)
+               return 0;
+
        zone_start_pfn = clamp(node_start_pfn, zone_low, zone_high);
        zone_end_pfn = clamp(node_end_pfn, zone_low, zone_high);
 
index 4caf8ed24d6586e32ab910f28f945c01cef6373b..dbe0c1e8349c72ac569a58289da702a841104951 100644 (file)
@@ -3363,8 +3363,8 @@ put_path:
  * shmem_kernel_file_setup - get an unlinked file living in tmpfs which must be
  *     kernel internal.  There will be NO LSM permission checks against the
  *     underlying inode.  So users of this interface must do LSM checks at a
- *     higher layer.  The one user is the big_key implementation.  LSM checks
- *     are provided at the key level rather than the inode level.
+ *     higher layer.  The users are the big_key and shm implementations.  LSM
+ *     checks are provided at the key or shm level rather than the inode.
  * @name: name for dentry (to be seen in /proc/<pid>/maps
  * @size: size to be set for the file
  * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
index 200e22412a161fc7a2232bcb923f07bc117362b8..bbd0b47dc6a97eecea7650ce6b351e88d5a17295 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 3e5f8f29c28640e44af5f5f9d1c3553986064588..86831105a09f44ffae37c074a6e5587c5b7056ce 100644 (file)
@@ -37,8 +37,7 @@ struct kmem_cache *kmem_cache;
                SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE | \
                SLAB_FAILSLAB)
 
-#define SLAB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \
-               SLAB_CACHE_DMA | SLAB_NOTRACK)
+#define SLAB_MERGE_SAME (SLAB_RECLAIM_ACCOUNT | SLAB_CACHE_DMA | SLAB_NOTRACK)
 
 /*
  * Merge control. If this is set then no merging of slab caches will occur.
index 816df0016555ad8a5cf03c8020e0b39b75b0a498..f68c0e50f3c083abe295a1dcd60668321a8f9232 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 e61445dce04e3cc83e9704e84f3d5bf9074b31db..8286938c70ded6b82d4268174c92669a90eeb674 100644 (file)
@@ -973,22 +973,18 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                 *    caller can stall after page list has been processed.
                 *
                 * 2) Global or new memcg reclaim encounters a page that is
-                *    not marked for immediate reclaim or the caller does not
-                *    have __GFP_IO. In this case mark the page for immediate
+                *    not marked for immediate reclaim, or the caller does not
+                *    have __GFP_FS (or __GFP_IO if it's simply going to swap,
+                *    not to fs). In this case mark the page for immediate
                 *    reclaim and continue scanning.
                 *
-                *    __GFP_IO is checked  because a loop driver thread might
+                *    Require may_enter_fs because we would wait on fs, which
+                *    may not have submitted IO yet. And the loop driver might
                 *    enter reclaim, and deadlock if it waits on a page for
                 *    which it is needed to do the write (loop masks off
                 *    __GFP_IO|__GFP_FS for this reason); but more thought
                 *    would probably show more reasons.
                 *
-                *    Don't require __GFP_FS, since we're not going into the
-                *    FS, just waiting on its writeback completion. Worryingly,
-                *    ext4 gfs2 and xfs allocate pages with
-                *    grab_cache_page_write_begin(,,AOP_FLAG_NOFS), so testing
-                *    may_enter_fs here is liable to OOM on them.
-                *
                 * 3) Legacy memcg encounters a page that is not already marked
                 *    PageReclaim. memcg does not have any dirty pages
                 *    throttling so we could easily OOM just because too many
@@ -1005,7 +1001,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
 
                        /* Case 2 above */
                        } else if (sane_reclaim(sc) ||
-                           !PageReclaim(page) || !(sc->gfp_mask & __GFP_IO)) {
+                           !PageReclaim(page) || !may_enter_fs) {
                                /*
                                 * This is slightly racy - end_page_writeback()
                                 * might have just cleared PageReclaim, then
index 498454b3c06c3ddf0e8c3989e23bef9360587544..ea79ee9a73489f43a88e57c2eb529fc11d894e5f 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 fb54e6aed096edd267fc211e4cd2a0139fe71f8a..6d0b471eede8639f55b33c5c4d434c8fddef6ee5 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 bb01586206289929f8c5e43153b75f9c279b9f85..cffa92dd98778bf2ffdf11107243fcc0f60cab6b 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 c002961da75d655deb813990f5706cf37fbd6d7d..a2fc843c22432e790980fa15653cf95e6c60b384 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 b4824951010ba6b42bf7d7c7eb62c529ed340158..5809b39c1922320e8dbb353de212b472199c796d 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 7998fb27916568da087b2734a017355158044a75..92720f3fe57370137f22ae3d2b76b390da09e9a1 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 0b39dcc65b94f0aa571dc22dc0c97afbf4e3d744..1285eaf5dc222e7cf75f4da796f2075f098105ae 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 3da5525eb8a2dc21e5f64638881a351a72a0d300..4d74a0639c4ccd040b6371665e6a74f8dca6f800 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 4967262b27076af66347d20eca54b65a2e61d789..617088aee21d41ba98d4ef5ebee5d6c002efe029 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 1ebdf1c0d1188c309d854bc9145c9b2f5b7b58a4..1cbd209192eacd6b7ec9a13f8180a5138760fc7e 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 87b22c0bc08c2f33fa31948b8b2604f48b8009bc..b42f0e26f89e4cf2e37a8329da549eb5cd1200c5 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 b6a19ca0f99e49c7406f1fedb6c59433bbd7fd38..7b84330e5d30693cf63fe2d04b7f64f2b8893362 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 0917123790eaf09b001c97a733039185fdb0a800..35c47ddd04f0ee3eb965fd99b06bab2ee4670774 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 37c4bb89a7082bbe36b40d928f7fd1d95bfe8252..b0c6258ffb79a7cbcaaf1296e4842db52876b5b2 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 651cdf648ec4728bff6e709b0324b7d52ffd65ed..9fdfd9deac11dde85bc62803068fbe50e45837b8 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 60021d0d9326ac691dcef21e1f9c20de5f8fe7c6..134957159c27eb9180e08b73360fe891574b4742 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 fe8cc183411e052f6e0ba4afefbeaef1e77313cd..95ea633e8356eb9b419e4027f9954810194aa23c 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 433231ccfb17fc6d01179247d1d81226803d18df..0330ab2e2b6329ced120cd9b7100a5a34f50e82b 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 d7d4c2b79cf2f516f9e3f62c6fe4415e9bc137a0..0ea2e1c5d395ac979e9a301d006867d49b866ecb 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 83aa604f9273c332c5a0e5399253d961ef92eb9a..1b8c5ba7d5f732ea2220ada929049c5c7cfd5e83 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 55d19861ab20f4a91b6b289be7ca3b0250df4531..548c6237b1e706f8ef72575a6a7dbad544b60fcc 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 df8afe5ab31e4b8e75bf2fbf844f8b3e798edbba..9405b04eecc64f478960329da93f6e01d437954e 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 6edb7b106de769728357174d0657c644f83e41e8..ebbb754c2111b73c87fe85aa58b3124e0a3032ef 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 6090969937f8b6809f74c3d03f29a0703089eff1..d15586490cecaedcc29bc821163cd6c85544b0b8 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 6748c4277affad71cd721e3a985af10c31c047ad..7a6cea5e427414062f408cfa66f57808d48382d7 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 247552a7f6c2f23a1e4bc89b647d8d37680bf2c3..3ece7d1034c81ae8749cada074fbebecbe06d57f 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 651039ad1681db0434cff21275f1bcbe3f8464bc..3c20d02aee738c5293a5b449f28ebff596c7232d 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 71f1e9fdfa18fb9b1f2f2730ca21af42dad98eea..d7f1685279034b5e3b62748284d24c52cc1f8907 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 c6630030c9121c7af27a3052ad776cd6646eb601..43ddeee404e91f97908fb9228c1e873931b75bcc 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 d8e2e3918ce2fd95637c4cba8bfc4886feb91ea6..67d2104778636c62e7d3fa94c73ce5fb2cd4cb7d 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 8a8c0b8b4f63a4bd8e5ff776250189558e6fcb1e..ee34f474ad1465087da8fd506410559abe47d81e 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 9a6b4f66187cf3e5ab533cd01344c9856834ebb7..140a44a5f7b7f1c08b3f329707b72fc75a9a81fe 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 a42a3b257226178eb5af04054a17813c04368613..268545050ddbd67245ead8394a82f44503657ea5 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 21ca33c9f0368b21cdb00fbdbbca4851c2ad87a2..a9ba030435a2a5c2ca4bea21d62c6d631c6168f4 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 9cb8522d8d22a826caaec968e82c77516339ca01..f3d3fb42b8735e76aa54bd4c433574f7afc43b0e 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 9ed32502470e9bc1d776d5d925ee48be587baa17..5ebb8968793670d6a23ee6e6d2b30df6243a63ca 100644 (file)
@@ -406,6 +406,7 @@ static __init int yama_init(void)
         */
        if (!security_module_enable("yama"))
                return 0;
+       yama_add_hooks();
 #endif
        pr_info("Yama: becoming mindful.\n");
 
index 57a6dfc4b6947e2b4f545f8e4a2dec6e22ce17c7..52e4bc54c9acac2264be07b2b517e9fbb1608333 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 1d651b8a89570404cd306f239b17e939b1d5fa81..225bfda414e98d91da49140451d8bb09e16c9f12 100644 (file)
@@ -57,6 +57,7 @@ source "sound/soc/samsung/Kconfig"
 source "sound/soc/sh/Kconfig"
 source "sound/soc/sirf/Kconfig"
 source "sound/soc/spear/Kconfig"
+source "sound/soc/sti/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
 source "sound/soc/ux500/Kconfig"
index 669648b41d3027adf29ead27eda5f72a6ed0aaf1..134aca150a50bb62ef6d9d13ddc5636b7adde463 100644 (file)
@@ -39,6 +39,7 @@ obj-$(CONFIG_SND_SOC) += samsung/
 obj-$(CONFIG_SND_SOC)  += sh/
 obj-$(CONFIG_SND_SOC)  += sirf/
 obj-$(CONFIG_SND_SOC)  += spear/
+obj-$(CONFIG_SND_SOC)  += sti/
 obj-$(CONFIG_SND_SOC)  += tegra/
 obj-$(CONFIG_SND_SOC)  += txx9/
 obj-$(CONFIG_SND_SOC)  += ux500/
index 841d05946b888fc5b905445f61611f44df685ff6..ba8def5665c458842d2f333d35e34c2974b2136e 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 dd94fea72d5d240cf8d6c37f344dbabe10b55e0f..5741c0aa6c0303607cb738668ecaa2d023044354 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 24cc7f40d87a61ba16850a57566a395455f302f2..fcf5a9adde8170e67c861ca5bd75b9d84c0833af 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 e742ef668496f5bae5674d471ec81757c37ab4b1..38e853add96ecb4236f50225e6089401a0740e22 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 03fa1cbf8ec1d2f1df3c3a68e63c77421c04f802..8c435beb263dfc02df2ee714b1abf43a6cbe6bad 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 238913e030e052955c2b95b6ea9b0a6e5d9b3d13..02ad2606fa19cb86fdcaf791bffc88c5b3076edf 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 d95477afcc671fbba088781f3657638e8015f0be..6cba211da32ee455ca0d7c5387450e65a437cb40 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 4229f76daec9f1eead184dee6cce816e11033674..fddfe00c9d69538966f378406951a8f431aef0bf 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 38b3dad9d48ac42c58e2c9d7058c094392889c7a..e8bed6b0c9dbdb26bf90d0e77ba849c02f62e642 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 efaafce8ba387340e073796a9de2c7d9b00aac81..0c9733ecd17f29a040ec3f2a4c7dfab8c59007e7 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 cf160d972cb3640b0080634fb9d67f6800252e04..4a32077954aee6aee2966ced2573991d1673b02a 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 c7d243db010ae593db892c028042a3e915bde309..affb192238a403b88dc38f3e76e0c54440779ea0 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 3cc69a626454fce289a497dd92d5c8650cca7388..9ef20dbccbe31c6fd7f82c58da18117b64187a91 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 a43160254929d5b31d7105cd75486263e14bf551..fe1353a797b9449e7b8186771c8476b2cf746021 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 ff7f846e3b765e1103c417f2590c73d65c78d7eb..de53c0d7bf101fd449e596fbf40cf8bf89e639c2 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 862796dec693baa46dc50d8ba9ac9b95eacf763e..348ccb17d3cc9c435e50cd11804e7dfb597906cd 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 2ce4362ccec159c98360e794dc12002f1572db6c..0e32bba92339b17182980c426818c0b58d2c21a7 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 9700e8c838c9dde2763108655b4287fa434260e0..21e7394a972ae2a995e1af61a91a198c6dd5b42a 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 66d9fce34e625a87e148a2dafd4dd319f935c737..52881faedcf619a5a441e76b51746a7ce39e6dec 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 36d8425707459aec9f35bcdb9009b25fc546ad1b..198c924551b78e268b8480a38d481703fe53d3a9 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 8670861e5bec8d17130976487dffeab1069e4aff..54428c64387bc0501f96eb6145b52727bf479553 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 2d0ff4595ea00f494b0846adb63e805ecef1e25c..b14176f8d884a9f05f72e667b6ac8b52ee4c90e2 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 7c0f6552c229b641ab8a81c83080411be9724ae9..4a90143d0e907b5034d0f4caa506c97000500f71 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 0e59063aeb6f7916265a66636d8debb5d02e2853..c73a9f6914b63e03e369b537df6a4a9f3c4068ae 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 0fc24e0d518c446053643a100abb3e0e2d659bb7..d2e3a3ef7499bce2d25009a811d9d94a26d4fee3 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 607a63b9705f939288c6a270e0fe46b06e6a21ab..4d3ba33eb6f928dc32146645b195d528592711c5 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 802e05eae3e9d498d643e9f97f951730b201e96f..8a2221ab3d10b97f5f7a97c21251264aa93eaa5b 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 43deb0462309e1e3547b8516b04fb38094829a83..ada0a418ff4b648034841e9b36f4df598d03fac2 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 8f40025b7e7ca457f4f65eaca2f64a59e468a4a9..44c30fe3e3151dc6621c308da5c1f4759a6d3f65 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 31ab804a22bcc19abfb517187a3a7834ee79ea01..1d6c2508cd4112f7d9b45c26f934ce57f3b3ac1b 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 8e36198474d94d59cd8b7bda10e6be434103fa55..55db19ddc5ff34a7fa1134488d972d7bc2ceeae8 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 e6d4ff9fd992015453c93746ec5018901bcdd008..e07807d96b68069b10c0e1319359b8ed52905ecc 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 b264da030340da4a7a5c429dbce1bf1c1e4af9f3..dcb3223d7d8f7cc909a357689d3292bb2a7f0ac6 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 c40428f25ba5c9b9b3d2e5e657a71020702dc12b..9bad478474fa3eda856b01b3911cefd2edb410c2 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 4de52c9957ac5a53c321b6eef5b805ad199a60b4..47b97fcefb0ba76818d6c01bcb0e24a8afa02c31 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 1e11ba45a79f01a0f2a45b538618c4a2d8e88002..7cd5f769bb614d207daaf26ca24efb51156d3aca 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 b7853b9d3a60bfe3c2273262a788b59473dfc9da..42a8fd4e1f9b3f284d6dcc01dc67cf6475d5a192 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 657dce27eade332b94696d486f566519dd8483dc..800c1d549347194a7aa80c514161eae8752ec3d7 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 e1d46862e81f15c34f284a19240e01ee1a841549..d562e1b9a5d163bb22e990280b8f2e396e584846 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 b2c10e537ef6c89a71a6239da05a13a78cf5977d..d36c61b6df74725fda9feff92d4ab9efea703840 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 21810e5f3321c863c48ec00bab4f1bbfddc203d8..7dc52fe67c80b212c06acf2a1bc296277c880f11 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 238e48a3a4fe7bbda84b0aa8b6b6639e2434bdd6..a9c86efb31878a343262a589facc4c5424522ae9 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 207523686bd55993685693793510ead04460c364..1d5a89c5164b85686f652dc8f5e13af6c1eb49e6 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 66bb446473b868532ef7bee0c117c9584f5e995f..0b2ede8db97886f3102ce1f227d389fd86bcd934 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 ebd90283c9604119f2bfe41ecba6d5051307cf09..be448373d39afa390a2c1cd444bb44cd5975c69b 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 9363fdbca9cdb1f776c035097ac8f16b5de642a4..1f5ab99956ed234d5e81c31011602002cc944ad3 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 99ffc49aa7799b03095d5593e2592f682b49b256..558de1053f73ce52934747f50ef16a702e48a0a4 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 6600aa0a33dc578afb0361bf9cd3acc6584c7edb..9af5640e3446be9b8cb770193e1dbeedef355911 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 e1c196a4193033c2cb033c6116076c4269b7dd33..5b82e26cd5d1ae506acebf9394629e03bfa73b12 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 d0f45348bfbbccd35afb992f19b11255d201374c..20dcc496d39c9d8ac01e4d49004f92823fdd37a6 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 be89a4f4aab828ad4efe941c6ce7b6a93c25b510..efa39bf467425a8b033c6063d36aa3c43fc918bb 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 78268f0514e95073e8b2006d4e2822a482fb6d3b..584aab83e4783b12232cc94000431efacbc39d95 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 21ff743f5af28d07bdc6ec4209b84b6ca2e77929..bc610d9a9ecb73fd61be71c4c6dfb5af030ad588 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 9a46d3dcf7035d781d132c453dcddafc92e15047..1fedac50355e954790a15b84ed6aab49b2bb98e3 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 3a2fda08a893c865023d61fec636e65e3c977577..f5e3dce2633a39a0a09a3ea3b5f2281a62db306d 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 481d58f1cb3f6b543b5e0fa320dd39103c992bd8..c14a79d026a10418cd7e34304dc984e0b75a4e90 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 29549cdbf4c1c6138e825e3372644aa9e3008f90..61cc18e35efb958cef806f753d3a70d3cdbca62b 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 aad664225dc3a4d0142a89bf37a51f4743a0969e..5990de3179991d94db534cf5dd721833455f23ef 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;
 }
 
@@ -432,7 +430,7 @@ static int max98925_dai_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
 
-       switch (snd_pcm_format_width(params_format(params))) {
+       switch (params_width(params)) {
        case 16:
                regmap_update_bits(max98925->regmap,
                                MAX98925_FORMAT,
@@ -523,7 +521,6 @@ static int max98925_probe(struct snd_soc_codec *codec)
        struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
 
        max98925->codec = codec;
-       codec->control_data = max98925->regmap;
        regmap_write(max98925->regmap, MAX98925_GLOBAL_ENABLE, 0x00);
        /* It's not the default but we need to set DAI_DLY */
        regmap_write(max98925->regmap,
@@ -639,7 +636,6 @@ MODULE_DEVICE_TABLE(of, max98925_of_match);
 static struct i2c_driver max98925_i2c_driver = {
        .driver = {
                .name = "max98925",
-               .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(max98925_of_match),
                .pm = NULL,
        },
index 3d44fc50e4d0c112d35627d01491e2f07674c459..3e770cbe7f0f49e63d92d2e29d413023ba52f03f 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 b74118e019fbe142572644b79085a76496c685fb..f561c78b9e0e0ca8df6e4647786009b596bc2b9b 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 e7ba557979cb2589439234d6bd0ddbbdc38985e5..58325234285c779c8c566486383dda6267795dec 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 dcdfac0ffeb15c2fbe6c91883af6bf7bfb156dc6..dbff416e38be760f20675b0a44401cb03a5d557b 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 de16429f0a43114ef9c96cdf3932f3abd32c1d5f..047c48953a20cd4075000ac294a17fe59baedcde 100644 (file)
@@ -1117,7 +1117,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
                params_rate(params),
                params_channels(params));
 
-       switch (snd_pcm_format_width(params_format(params))) {
+       switch (params_width(params)) {
        case 16:
                alen = PCM512x_ALEN_16;
                break;
@@ -1132,7 +1132,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
                break;
        default:
                dev_err(codec->dev, "Bad frame size: %d\n",
-                       snd_pcm_format_width(params_format(params)));
+                       params_width(params));
                return -EINVAL;
        }
 
index 56650d6c2f537dd1a1d3c6c693bc7fdfaf48c627..aca479fa767027174be48390fd0dc93c3802d022 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 0f7b057ed736fb685173a5a328ea62b8f3547fb0..4c77b441fba260c3c1be857ed5a76e2c4605c7f4 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 5c43e263b2c1f4a8f97bab4abe9fb64f0ee68070..bd9365885f73f508fa88de0908215473efaaddb3 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 058167c80d714ba486e1dd330e472eb871785c43..1be2bab7dee3a1b20bc30508938f5b28f02a5998 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 9bc78e57513d74e40c5a4f9bda59c34625b15715..e1ceeb885f7d64858248b07206db23796a08f084 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 961bd7e5877ee42c3e50f7a3e2e826a1ffab9cc8..4972bf3efa91c4849928f480bd08ebc3388a53db 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 278bb9f464c4120b681c7ad5c6086df89d6de3ab..0e4cfc6ac64984acb1bd395a7477b7cf21cfc020 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 a3506e193abcd26f90884bf592154a980b797f6a..1d4031818966638c7ad994ffd18bf294cc7c79bd 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 a9123d41417875a0a5788a3106b6bcd03bb10c9b..49a9e7049e2ba1457621cd549ca3722cce0a0688 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 ef6348cb9157df056450e78c9caf8c9ace0cf9ee..3505aafbade49d16d9ba4a3da17c14f03c897577 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 ec41b2b3b2ca2b22c7e917c8b63b106474d8ccc8..662db16cfb6a437faf7395c0a28adf19c41c7705 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 31d969ac11920ff419981caee098a234baf4d0f7..b4cd7e3bf5f89f9ea940528f233f017151788a4b 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 7eca38a2325566469aa96f8d019dc4fefbc9328d..d46855a42c4087c6305af06c5a1be0d16d153a0a 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 e673f6ceb5213842dcc6bb98924979a3bb3454a9..bfda25ef0dd43313f066a7afca06c11b8a8ecbe0 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 3e72964280c6e79d74918555099bb4378a95c917..a8402d0af0ea814fd9965e0c0e3d0f7e4d668dd2 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 29cb44256044c7557c6d202b503a925bc15e5d4a..6bfd25c289d1924b4cc3d33892dba97e3366a351 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 f30de7639bb9c8d60b9d477d475b445e26ee594d..ddb0203fc6495b520f4695be9e94e62a7ea56026 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 0d9779d6bfda7fced8b472d283a04ad9d91c7f75..173ba85ff59e45c65bffb6e34655a1f4c29751ba 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 69a773aeb13dbbb05906e54498b4b2300f7cba77..4452fea0b11857b7a6d004b3b1892a50aeba246f 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 84a4f5ad80645f2f45079ea35fe8ce19da901f09..e619d5651b09bbd6401cdea6734acf0a4a6f17dc 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 60eff36260cbdac1f2b2f406cd79a55811b290dd..a9844b2ac829d03ae4142a69b6b815fc9df02f44 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 bd819a3f205aeba88930d0f3e597f31d2197cc5f..33a4612f0a078747e620aeb991cb38404083fe58 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 4f70378b2cfb4095321f6793dd7d0277851c2ef0..2cdaca943a8c488fceea517165f07aa0d47c8b60 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 ed4cca7f6779937a4e92717cc29209356f9a9e5e..0945c51df003df37f415b4cbf9d9076826f1c7b6 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 4f25a7d0efa2aa952deeddf0ff027707b4b657f2..e3a0bca28bcf5fb7c454de1abf235c1c5ace347d 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 5746f8fd0afd55b3305b41df42477c87062432e8..e34752b8a29940e85593f01ee8ea997d918afb91 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 32942bed34b1e9bb67227adddd5c662b92aa2a9b..d49d25d5195796345bee582537fa3751d4eacfa6 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 85bcc374c8e8e34e99f008d0f542deebbdab9e49..39307ad41a34f34154316010c1c075c0d0038aa3 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 aab0af681e8cb3cd1b2c0ea0b5a22e32c1f08c2b..cb5310d89c0f4fd33e59d93c04eefb324f00c61e 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 c4c960f592a1fb092d43d1610d52316bb0422c97..ee4def4f819fcdd16c6d20d87328bd2c4583b7c8 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 ad6cb90e5f9b3fcc6edef66bfe295f9d8631a82e..f2d3191961e14435815a947e6b1d4455f1484c59 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 a7cf19b53fb2d44d3cdefc6ef15f058b3da44bf5..1a82b19b26442e31eb38e8fa38287d9710aa3546 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 d67a311f0e75017ea27189f362e3dd00e63fa235..781398fb2841565f20d2f7e7a4f893d840e3e7ae 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 6fac9e034c483861dc82b3e0468b9bbb362f562d..11d85c5c787addb8d8add7fc2b52ab91cc49b63d 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 12232d7db4c527703646c9713a0471629aac3971..43568435c208f60ec8c40161fc0013da38a03163 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 90f5f04eca2d89903e16b5bdb9ff949c929f9ad2..2713e1845cbcd93f71232fbc2141784a7c540223 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 913edf2832399cb5d5cb36b3bb26bf9d8364e638..e1902638053490dda1ab695cf989c91239769ea7 100644 (file)
@@ -37,74 +37,53 @@ struct uda134x_priv {
 
        struct snd_pcm_substream *master_substream;
        struct snd_pcm_substream *slave_substream;
-};
 
-/* In-data addresses are hard-coded into the reg-cache values */
-static const char uda134x_reg[UDA134X_REGS_NUM] = {
-       /* Extended address registers */
-       0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* Status, data regs */
-       0x00, 0x83, 0x00, 0x40, 0x80, 0xC0, 0x00,
+       struct regmap *regmap;
+       struct uda134x_platform_data *pd;
 };
 
-/*
- * The codec has no support for reading its registers except for peak level...
- */
-static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec,
-       unsigned int reg)
-{
-       u8 *cache = codec->reg_cache;
-
-       if (reg >= UDA134X_REGS_NUM)
-               return -1;
-       return cache[reg];
-}
-
-/*
- * Write the register cache
- */
-static inline void uda134x_write_reg_cache(struct snd_soc_codec *codec,
-       u8 reg, unsigned int value)
-{
-       u8 *cache = codec->reg_cache;
-
-       if (reg >= UDA134X_REGS_NUM)
-               return;
-       cache[reg] = value;
-}
+static const struct reg_default uda134x_reg_defaults[] = {
+       { UDA134X_EA000, 0x04 },
+       { UDA134X_EA001, 0x04 },
+       { UDA134X_EA010, 0x04 },
+       { UDA134X_EA011, 0x00 },
+       { UDA134X_EA100, 0x00 },
+       { UDA134X_EA101, 0x00 },
+       { UDA134X_EA110, 0x00 },
+       { UDA134X_EA111, 0x00 },
+       { UDA134X_STATUS0, 0x00 },
+       { UDA134X_STATUS1, 0x03 },
+       { UDA134X_DATA000, 0x00 },
+       { UDA134X_DATA001, 0x00 },
+       { UDA134X_DATA010, 0x00 },
+       { UDA134X_DATA011, 0x00 },
+       { UDA134X_DATA1, 0x00 },
+};
 
 /*
  * Write to the uda134x registers
  *
  */
-static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg,
+static int uda134x_regmap_write(void *context, unsigned int reg,
        unsigned int value)
 {
+       struct uda134x_platform_data *pd = context;
        int ret;
        u8 addr;
        u8 data = value;
-       struct uda134x_platform_data *pd = codec->control_data;
-
-       pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value);
-
-       if (reg >= UDA134X_REGS_NUM) {
-               printk(KERN_ERR "%s unknown register: reg: %u",
-                      __func__, reg);
-               return -EINVAL;
-       }
-
-       uda134x_write_reg_cache(codec, reg, value);
 
        switch (reg) {
        case UDA134X_STATUS0:
        case UDA134X_STATUS1:
                addr = UDA134X_STATUS_ADDR;
+               data |= (reg - UDA134X_STATUS0) << 7;
                break;
        case UDA134X_DATA000:
        case UDA134X_DATA001:
        case UDA134X_DATA010:
        case UDA134X_DATA011:
                addr = UDA134X_DATA0_ADDR;
+               data |= (reg - UDA134X_DATA000) << 6;
                break;
        case UDA134X_DATA1:
                addr = UDA134X_DATA1_ADDR;
@@ -133,27 +112,28 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg,
 
 static inline void uda134x_reset(struct snd_soc_codec *codec)
 {
-       u8 reset_reg = uda134x_read_reg_cache(codec, UDA134X_STATUS0);
-       uda134x_write(codec, UDA134X_STATUS0, reset_reg | (1<<6));
+       struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+       unsigned int mask = 1<<6;
+
+       regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask);
        msleep(1);
-       uda134x_write(codec, UDA134X_STATUS0, reset_reg & ~(1<<6));
+       regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, 0);
 }
 
 static int uda134x_mute(struct snd_soc_dai *dai, int mute)
 {
-       struct snd_soc_codec *codec = dai->codec;
-       u8 mute_reg = uda134x_read_reg_cache(codec, UDA134X_DATA010);
+       struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int mask = 1<<2;
+       unsigned int val;
 
        pr_debug("%s mute: %d\n", __func__, mute);
 
        if (mute)
-               mute_reg |= (1<<2);
+               val = mask;
        else
-               mute_reg &= ~(1<<2);
+               val = 0;
 
-       uda134x_write(codec, UDA134X_DATA010, mute_reg);
-
-       return 0;
+       return regmap_update_bits(uda134x->regmap, UDA134X_DATA010, mask, val);
 }
 
 static int uda134x_startup(struct snd_pcm_substream *substream,
@@ -205,7 +185,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
-       u8 hw_params;
+       unsigned int hw_params = 0;
 
        if (substream == uda134x->slave_substream) {
                pr_debug("%s ignoring hw_params for slave substream\n",
@@ -213,10 +193,6 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
                return 0;
        }
 
-       hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0);
-       hw_params &= STATUS0_SYSCLK_MASK;
-       hw_params &= STATUS0_DAIFMT_MASK;
-
        pr_debug("%s sysclk: %d, rate:%d\n", __func__,
                 uda134x->sysclk, params_rate(params));
 
@@ -267,9 +243,8 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       uda134x_write(codec, UDA134X_STATUS0, hw_params);
-
-       return 0;
+       return regmap_update_bits(uda134x->regmap, UDA134X_STATUS0,
+               STATUS0_SYSCLK_MASK | STATUS0_DAIFMT_MASK, hw_params);
 }
 
 static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
@@ -324,10 +299,8 @@ static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int uda134x_set_bias_level(struct snd_soc_codec *codec,
                                  enum snd_soc_bias_level level)
 {
-       struct uda134x_platform_data *pd = codec->control_data;
-       int i;
-       u8 *cache = codec->reg_cache;
-
+       struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+       struct uda134x_platform_data *pd = uda134x->pd;
        pr_debug("%s bias level %d\n", __func__, level);
 
        switch (level) {
@@ -337,17 +310,17 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
                /* power on */
                if (pd->power) {
                        pd->power(1);
-                       /* Sync reg_cache with the hardware */
-                       for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
-                               codec->driver->write(codec, i, *cache++);
+                       regcache_sync(uda134x->regmap);
                }
                break;
        case SND_SOC_BIAS_STANDBY:
                break;
        case SND_SOC_BIAS_OFF:
                /* power off */
-               if (pd->power)
+               if (pd->power) {
                        pd->power(0);
+                       regcache_mark_dirty(uda134x->regmap);
+               }
                break;
        }
        return 0;
@@ -478,21 +451,14 @@ static struct snd_soc_dai_driver uda134x_dai = {
 static int uda134x_soc_probe(struct snd_soc_codec *codec)
 {
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-       struct uda134x_priv *uda134x;
-       struct uda134x_platform_data *pd = codec->component.card->dev->platform_data;
+       struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+       struct uda134x_platform_data *pd = uda134x->pd;
        const struct snd_soc_dapm_widget *widgets;
        unsigned num_widgets;
-
        int ret;
 
        printk(KERN_INFO "UDA134X SoC Audio Codec\n");
 
-       if (!pd) {
-               printk(KERN_ERR "UDA134X SoC codec: "
-                      "missing L3 bitbang function\n");
-               return -ENODEV;
-       }
-
        switch (pd->model) {
        case UDA134X_UDA1340:
        case UDA134X_UDA1341:
@@ -506,13 +472,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
                return -EINVAL;
        }
 
-       uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
-       if (uda134x == NULL)
-               return -ENOMEM;
-       snd_soc_codec_set_drvdata(codec, uda134x);
-
-       codec->control_data = pd;
-
        if (pd->power)
                pd->power(1);
 
@@ -530,7 +489,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
        if (ret) {
                printk(KERN_ERR "%s failed to register dapm controls: %d",
                        __func__, ret);
-               kfree(uda134x);
                return ret;
        }
 
@@ -551,36 +509,19 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
        default:
                printk(KERN_ERR "%s unknown codec type: %d",
                        __func__, pd->model);
-               kfree(uda134x);
                return -EINVAL;
        }
 
        if (ret < 0) {
                printk(KERN_ERR "UDA134X: failed to register controls\n");
-               kfree(uda134x);
                return ret;
        }
 
        return 0;
 }
 
-/* power down chip */
-static int uda134x_soc_remove(struct snd_soc_codec *codec)
-{
-       struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
-
-       kfree(uda134x);
-       return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
        .probe =        uda134x_soc_probe,
-       .remove =       uda134x_soc_remove,
-       .reg_cache_size = sizeof(uda134x_reg),
-       .reg_word_size = sizeof(u8),
-       .reg_cache_default = uda134x_reg,
-       .reg_cache_step = 1,
-       .read = uda134x_read_reg_cache,
        .set_bias_level = uda134x_set_bias_level,
        .suspend_bias_off = true,
 
@@ -590,8 +531,39 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
        .num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
 };
 
+static const struct regmap_config uda134x_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = UDA134X_DATA1,
+       .reg_defaults = uda134x_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(uda134x_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .reg_write = uda134x_regmap_write,
+};
+
 static int uda134x_codec_probe(struct platform_device *pdev)
 {
+       struct uda134x_platform_data *pd = pdev->dev.platform_data;
+       struct uda134x_priv *uda134x;
+
+       if (!pd) {
+               dev_err(&pdev->dev, "Missing L3 bitbang function\n");
+               return -ENODEV;
+       }
+
+       uda134x = devm_kzalloc(&pdev->dev, sizeof(*uda134x), GFP_KERNEL);
+       if (!uda134x)
+               return -ENOMEM;
+
+       uda134x->pd = pd;
+       platform_set_drvdata(pdev, uda134x);
+
+       uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd,
+               &uda134x_regmap_config);
+       if (IS_ERR(uda134x->regmap))
+               return PTR_ERR(uda134x->regmap);
+
        return snd_soc_register_codec(&pdev->dev,
                        &soc_codec_dev_uda134x, &uda134x_dai, 1);
 }
index 9faae06972b32fc226cbb9450e84e86b7f6f271e..e41ab38c6f69bfbebcb1ce24e145e2f6020c2dd2 100644 (file)
@@ -26,8 +26,6 @@
 #define UDA134X_DATA011 13
 #define UDA134X_DATA1   14
 
-#define UDA134X_REGS_NUM 15
-
 #define STATUS0_DAIFMT_MASK (~(7<<1))
 #define STATUS0_SYSCLK_MASK (~(3<<4))
 
index 6e159f59d219beaba3ff75a0b4f7c7b5405d2b9b..35f0469ebb16a37af8e146bb4e16be1c5c457192 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 6560a66b3f3539ea79cfd8d9ef20f3825d2e03df..f2c6ad4b8fde03f489572e5ce2abf326dd2662b8 100644 (file)
@@ -953,7 +953,7 @@ static int wm0010_spi_probe(struct spi_device *spi)
                trigger = IRQF_TRIGGER_FALLING;
        trigger |= IRQF_ONESHOT;
 
-       ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger | IRQF_ONESHOT,
+       ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger,
                                   "wm0010", wm0010);
        if (ret) {
                dev_err(wm0010->dev, "Failed to request IRQ %d: %d\n",
@@ -1003,7 +1003,6 @@ static int wm0010_spi_remove(struct spi_device *spi)
 static struct spi_driver wm0010_spi_driver = {
        .driver = {
                .name   = "wm0010",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
        },
        .probe          = wm0010_spi_probe,
index 048f00568260a82b82b544b09c4b24625aeb2f62..ec45c5b220b100263f380800f1cc27f731861ffc 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 21d5402e343fbcdd7a433931bc9a78d0edac45e9..786abd02b1406af3a6b653d22b70742686f2650d 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 c83083285e532711406422b2f8e1619f6f4de7fa..fd1439ecb50ad312e24c9bf7e735b7728c96d6c9 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 },
@@ -1702,7 +1702,7 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream,
        int *bclk_rates;
 
        /* Data sizes if not using TDM */
-       wl = snd_pcm_format_width(params_format(params));
+       wl = params_width(params);
        if (wl < 0)
                return wl;
        fl = snd_soc_params_to_frame_size(params);
@@ -2481,7 +2481,7 @@ static int wm2200_runtime_resume(struct device *dev)
 }
 #endif
 
-static struct dev_pm_ops wm2200_pm = {
+static const struct dev_pm_ops wm2200_pm = {
        SET_RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume,
                           NULL)
 };
@@ -2495,7 +2495,6 @@ MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id);
 static struct i2c_driver wm2200_i2c_driver = {
        .driver = {
                .name = "wm2200",
-               .owner = THIS_MODULE,
                .pm = &wm2200_pm,
        },
        .probe =    wm2200_i2c_probe,
index 4c10cd88c1af66a1a54b168c34844c190e077b9d..c2cdcae18ff620e611a5fdda23f0355ca13bd58d 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 },
@@ -1408,7 +1408,7 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream,
        base = dai->driver->base;
 
        /* Data sizes if not using TDM */
-       wl = snd_pcm_format_width(params_format(params));
+       wl = params_width(params);
        if (wl < 0)
                return wl;
        fl = snd_soc_params_to_frame_size(params);
@@ -2570,13 +2570,11 @@ static int wm5100_i2c_probe(struct i2c_client *i2c,
 
                if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
                        ret = request_threaded_irq(i2c->irq, NULL,
-                                                  wm5100_edge_irq,
-                                                  irq_flags | IRQF_ONESHOT,
+                                                  wm5100_edge_irq, irq_flags,
                                                   "wm5100", wm5100);
                else
                        ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq,
-                                                  irq_flags | IRQF_ONESHOT,
-                                                  "wm5100",
+                                                  irq_flags, "wm5100",
                                                   wm5100);
 
                if (ret != 0) {
@@ -2708,7 +2706,7 @@ static int wm5100_runtime_resume(struct device *dev)
 }
 #endif
 
-static struct dev_pm_ops wm5100_pm = {
+static const struct dev_pm_ops wm5100_pm = {
        SET_RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume,
                           NULL)
 };
@@ -2722,7 +2720,6 @@ MODULE_DEVICE_TABLE(i2c, wm5100_i2c_id);
 static struct i2c_driver wm5100_i2c_driver = {
        .driver = {
                .name = "wm5100",
-               .owner = THIS_MODULE,
                .pm = &wm5100_pm,
        },
        .probe =    wm5100_i2c_probe,
index d097f09e50f2577fb711677c370d1f6014c408ac..64637d1cf4e5673f17145b13d7c12681bed21d48 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 709fcc6169d81eda5a9cfcb3f26c55a8f77f6602..9756578fc7526a3182039bad491d3388e297de57 100644 (file)
@@ -131,6 +131,25 @@ static const struct reg_default wm5110_sysclk_revd_patch[] = {
        { 0x33fb, 0xfe00 },
 };
 
+static const struct reg_default wm5110_sysclk_reve_patch[] = {
+       { 0x3270, 0xE410 },
+       { 0x3271, 0x3078 },
+       { 0x3272, 0xE410 },
+       { 0x3273, 0x3070 },
+       { 0x3274, 0xE410 },
+       { 0x3275, 0x3066 },
+       { 0x3276, 0xE410 },
+       { 0x3277, 0x3056 },
+       { 0x327A, 0xE414 },
+       { 0x327B, 0x3078 },
+       { 0x327C, 0xE414 },
+       { 0x327D, 0x3070 },
+       { 0x327E, 0xE414 },
+       { 0x327F, 0x3066 },
+       { 0x3280, 0xE414 },
+       { 0x3281, 0x3056 },
+};
+
 static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
@@ -146,7 +165,9 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
                patch_size = ARRAY_SIZE(wm5110_sysclk_revd_patch);
                break;
        default:
-               return 0;
+               patch = wm5110_sysclk_reve_patch;
+               patch_size = ARRAY_SIZE(wm5110_sysclk_reve_patch);
+               break;
        }
 
        switch (event) {
@@ -164,6 +185,249 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+static const struct reg_sequence wm5110_no_dre_left_enable[] = {
+       { 0x3024, 0xE410 },
+       { 0x3025, 0x0056 },
+       { 0x301B, 0x0224 },
+       { 0x301F, 0x4263 },
+       { 0x3021, 0x5291 },
+       { 0x3030, 0xE410 },
+       { 0x3031, 0x3066 },
+       { 0x3032, 0xE410 },
+       { 0x3033, 0x3070 },
+       { 0x3034, 0xE410 },
+       { 0x3035, 0x3078 },
+       { 0x3036, 0xE410 },
+       { 0x3037, 0x3080 },
+       { 0x3038, 0xE410 },
+       { 0x3039, 0x3080 },
+};
+
+static const struct reg_sequence wm5110_dre_left_enable[] = {
+       { 0x3024, 0x0231 },
+       { 0x3025, 0x0B00 },
+       { 0x301B, 0x0227 },
+       { 0x301F, 0x4266 },
+       { 0x3021, 0x5294 },
+       { 0x3030, 0xE231 },
+       { 0x3031, 0x0266 },
+       { 0x3032, 0x8231 },
+       { 0x3033, 0x4B15 },
+       { 0x3034, 0x8231 },
+       { 0x3035, 0x0B15 },
+       { 0x3036, 0xE231 },
+       { 0x3037, 0x5294 },
+       { 0x3038, 0x0231 },
+       { 0x3039, 0x0B00 },
+};
+
+static const struct reg_sequence wm5110_no_dre_right_enable[] = {
+       { 0x3074, 0xE414 },
+       { 0x3075, 0x0056 },
+       { 0x306B, 0x0224 },
+       { 0x306F, 0x4263 },
+       { 0x3071, 0x5291 },
+       { 0x3080, 0xE414 },
+       { 0x3081, 0x3066 },
+       { 0x3082, 0xE414 },
+       { 0x3083, 0x3070 },
+       { 0x3084, 0xE414 },
+       { 0x3085, 0x3078 },
+       { 0x3086, 0xE414 },
+       { 0x3087, 0x3080 },
+       { 0x3088, 0xE414 },
+       { 0x3089, 0x3080 },
+};
+
+static const struct reg_sequence wm5110_dre_right_enable[] = {
+       { 0x3074, 0x0231 },
+       { 0x3075, 0x0B00 },
+       { 0x306B, 0x0227 },
+       { 0x306F, 0x4266 },
+       { 0x3071, 0x5294 },
+       { 0x3080, 0xE231 },
+       { 0x3081, 0x0266 },
+       { 0x3082, 0x8231 },
+       { 0x3083, 0x4B17 },
+       { 0x3084, 0x8231 },
+       { 0x3085, 0x0B17 },
+       { 0x3086, 0xE231 },
+       { 0x3087, 0x5294 },
+       { 0x3088, 0x0231 },
+       { 0x3089, 0x0B00 },
+};
+
+static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->arizona;
+       unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE);
+       const struct reg_sequence *wseq;
+       int nregs;
+
+       switch (w->shift) {
+       case ARIZONA_OUT1L_ENA_SHIFT:
+               if (val & ARIZONA_DRE1L_ENA_MASK) {
+                       wseq = wm5110_dre_left_enable;
+                       nregs = ARRAY_SIZE(wm5110_dre_left_enable);
+               } else {
+                       wseq = wm5110_no_dre_left_enable;
+                       nregs = ARRAY_SIZE(wm5110_no_dre_left_enable);
+                       priv->out_up_delay += 10;
+               }
+               break;
+       case ARIZONA_OUT1R_ENA_SHIFT:
+               if (val & ARIZONA_DRE1R_ENA_MASK) {
+                       wseq = wm5110_dre_right_enable;
+                       nregs = ARRAY_SIZE(wm5110_dre_right_enable);
+               } else {
+                       wseq = wm5110_no_dre_right_enable;
+                       nregs = ARRAY_SIZE(wm5110_no_dre_right_enable);
+                       priv->out_up_delay += 10;
+               }
+               break;
+       default:
+               return 0;
+       }
+
+       return regmap_multi_reg_write(arizona->regmap, wseq, nregs);
+}
+
+static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE);
+
+       switch (w->shift) {
+       case ARIZONA_OUT1L_ENA_SHIFT:
+               if (!(val & ARIZONA_DRE1L_ENA_MASK)) {
+                       snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
+                                           ARIZONA_WS_TRG1, ARIZONA_WS_TRG1);
+                       snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
+                                           ARIZONA_WS_TRG1, 0);
+                       priv->out_down_delay += 27;
+               }
+               break;
+       case ARIZONA_OUT1R_ENA_SHIFT:
+               if (!(val & ARIZONA_DRE1R_ENA_MASK)) {
+                       snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
+                                           ARIZONA_WS_TRG2, ARIZONA_WS_TRG2);
+                       snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
+                                           ARIZONA_WS_TRG2, 0);
+                       priv->out_down_delay += 27;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int wm5110_hp_ev(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       switch (priv->arizona->rev) {
+       case 0 ... 3:
+               break;
+       default:
+               switch (event) {
+               case SND_SOC_DAPM_PRE_PMU:
+                       wm5110_hp_pre_enable(w);
+                       break;
+               case SND_SOC_DAPM_PRE_PMD:
+                       wm5110_hp_pre_disable(w);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       }
+
+       return arizona_hp_ev(w, kcontrol, event);
+}
+
+static int wm5110_clear_pga_volume(struct arizona *arizona, int output)
+{
+       struct reg_sequence clear_pga = {
+               ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80
+       };
+       int ret;
+
+       ret = regmap_multi_reg_write_bypassed(arizona->regmap, &clear_pga, 1);
+       if (ret)
+               dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n",
+                       clear_pga.reg, ret);
+
+       return ret;
+}
+
+static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       unsigned int ena, dre;
+       unsigned int mask = (0x1 << mc->shift) | (0x1 << mc->rshift);
+       unsigned int lnew = (!!ucontrol->value.integer.value[0]) << mc->shift;
+       unsigned int rnew = (!!ucontrol->value.integer.value[1]) << mc->rshift;
+       unsigned int lold, rold;
+       unsigned int lena, rena;
+       int ret;
+
+       snd_soc_dapm_mutex_lock(dapm);
+
+       ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &ena);
+       if (ret) {
+               dev_err(arizona->dev, "Failed to read output state: %d\n", ret);
+               goto err;
+       }
+       ret = regmap_read(arizona->regmap, ARIZONA_DRE_ENABLE, &dre);
+       if (ret) {
+               dev_err(arizona->dev, "Failed to read DRE state: %d\n", ret);
+               goto err;
+       }
+
+       lold = dre & (1 << mc->shift);
+       rold = dre & (1 << mc->rshift);
+       /* Enables are channel wise swapped from the DRE enables */
+       lena = ena & (1 << mc->rshift);
+       rena = ena & (1 << mc->shift);
+
+       if ((lena && lnew != lold) || (rena && rnew != rold)) {
+               dev_err(arizona->dev, "Can't change DRE on active outputs\n");
+               ret = -EBUSY;
+               goto err;
+       }
+
+       ret = regmap_update_bits(arizona->regmap, ARIZONA_DRE_ENABLE,
+                                mask, lnew | rnew);
+       if (ret) {
+               dev_err(arizona->dev, "Failed to set DRE: %d\n", ret);
+               goto err;
+       }
+
+       /* Force reset of PGA volumes, if turning DRE off */
+       if (!lnew && lold)
+               wm5110_clear_pga_volume(arizona, mc->shift);
+
+       if (!rnew && rold)
+               wm5110_clear_pga_volume(arizona, mc->rshift);
+
+err:
+       snd_soc_dapm_mutex_unlock(dapm);
+
+       return ret;
+}
+
 static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
 static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
 static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
@@ -247,8 +511,7 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
 
-SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19),
-SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2),
 SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
@@ -260,8 +523,7 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
 SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
               24, 0, eq_tlv),
 
-SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19),
-SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2),
 SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
@@ -273,8 +535,7 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
 SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
               24, 0, eq_tlv),
 
-SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19),
-SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2),
 SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
@@ -286,8 +547,7 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
 SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
               24, 0, eq_tlv),
 
-SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19),
-SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),
+ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2),
 SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
@@ -314,10 +574,10 @@ ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
 
-SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1),
-SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1),
-SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1),
-SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1),
+ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2),
+ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
+ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
+ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
 
 SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
 SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
@@ -409,12 +669,15 @@ SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
 SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT,
           ARIZONA_SPK2R_MUTE_SHIFT, 1, 1),
 
-SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
-          ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0),
-SOC_DOUBLE("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE,
-          ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0),
-SOC_DOUBLE("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE,
-          ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0),
+SOC_DOUBLE_EXT("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
+          ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0,
+          snd_soc_get_volsw, wm5110_put_dre),
+SOC_DOUBLE_EXT("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE,
+          ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0,
+          snd_soc_get_volsw, wm5110_put_dre),
+SOC_DOUBLE_EXT("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE,
+          ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0,
+          snd_soc_get_volsw, wm5110_put_dre),
 
 SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
 SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
@@ -904,11 +1167,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
                    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
 
 SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
-                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, wm5110_hp_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
-                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, wm5110_hp_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
@@ -1611,18 +1874,24 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
        for (i = 0; i < WM5110_NUM_ADSP; ++i) {
                ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
                if (ret)
-                       return ret;
+                       goto err_adsp2_codec_probe;
        }
 
        ret = snd_soc_add_codec_controls(codec,
                                         arizona_adsp2_rate_controls,
                                         WM5110_NUM_ADSP);
        if (ret)
-               return ret;
+               goto err_adsp2_codec_probe;
 
        snd_soc_dapm_disable_pin(dapm, "HAPTICS");
 
        return 0;
+
+err_adsp2_codec_probe:
+       for (--i; i >= 0; --i)
+               wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
+
+       return ret;
 }
 
 static int wm5110_codec_remove(struct snd_soc_codec *codec)
index 41c62c1e62db5dc5754512532e7a758025cce311..ffbf3df8ae970329cd91a317d88018b3009150f4 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 d7555085e7f473bc568569de6a9c20e7061edf6d..b1d346aa4696af67c2c082f5a3bba8f702e6ea9e 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 dac5beb4d02356f7e8eef2fbf8e464ab77aa4f6b..b098a83a44d8cafc4e82742e35239d53d8ad50a7 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 43ea8ae5f871d2ce4185c41b9a2c3384707c245e..aa287a3965e71f77bc8772969543f4344f93facb 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 759a7928ac3ee48a43ecf7f626683042d5126534..66602bf02f6e43f755306bcd6cc04f2b1514c456 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 cc8251f09f8ab8240140030302cbbe11c095ef79..44b9e0ae745181ccd2f0e3029619171999923ca5 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 f1a173e6ec33bd29db81abfeded8b3842ca08032..cd7b02413ccf2ed80e8d233ddbf4580ece621e1f 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 915ea11ad4b6337f73bf85e9536a27c7d7fa45f1..ace8645245a0c1765bde0d516a4a1067dec2a755 100644 (file)
@@ -79,12 +79,7 @@ static bool wm8731_volatile(struct device *dev, unsigned int reg)
        return reg == WM8731_RESET;
 }
 
-static bool wm8731_writeable(struct device *dev, unsigned int reg)
-{
-       return reg <= WM8731_RESET;
-}
-
-#define wm8731_reset(c)        snd_soc_write(c, WM8731_RESET, 0)
+#define wm8731_reset(m)        regmap_write(m, WM8731_RESET, 0)
 
 static const char *wm8731_input_select[] = {"Line In", "Mic"};
 
@@ -496,8 +491,11 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               if (wm8731->mclk)
-                       clk_prepare_enable(wm8731->mclk);
+               if (wm8731->mclk) {
+                       ret = clk_prepare_enable(wm8731->mclk);
+                       if (ret)
+                               return ret;
+               }
                break;
        case SND_SOC_BIAS_PREPARE:
                break;
@@ -571,69 +569,63 @@ static struct snd_soc_dai_driver wm8731_dai = {
        .symmetric_rates = 1,
 };
 
-static int wm8731_probe(struct snd_soc_codec *codec)
+static int wm8731_request_supplies(struct device *dev,
+               struct wm8731_priv *wm8731)
 {
-       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
        int ret = 0, i;
 
        for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
                wm8731->supplies[i].supply = wm8731_supply_names[i];
 
-       ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies),
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8731->supplies),
                                 wm8731->supplies);
        if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               dev_err(dev, "Failed to request supplies: %d\n", ret);
                return ret;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
                                    wm8731->supplies);
        if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               dev_err(dev, "Failed to enable supplies: %d\n", ret);
                return ret;
        }
 
-       ret = wm8731_reset(codec);
+       return 0;
+}
+
+static int wm8731_hw_init(struct device *dev, struct wm8731_priv *wm8731)
+{
+       int ret = 0;
+
+       ret = wm8731_reset(wm8731->regmap);
        if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               dev_err(dev, "Failed to issue reset: %d\n", ret);
                goto err_regulator_enable;
        }
 
-       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       /* Clear POWEROFF, keep everything else disabled */
+       regmap_write(wm8731->regmap, WM8731_PWR, 0x7f);
 
        /* Latch the update bits */
-       snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0);
-       snd_soc_update_bits(codec, WM8731_ROUT1V, 0x100, 0);
-       snd_soc_update_bits(codec, WM8731_LINVOL, 0x100, 0);
-       snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0);
+       regmap_update_bits(wm8731->regmap, WM8731_LOUT1V, 0x100, 0);
+       regmap_update_bits(wm8731->regmap, WM8731_ROUT1V, 0x100, 0);
+       regmap_update_bits(wm8731->regmap, WM8731_LINVOL, 0x100, 0);
+       regmap_update_bits(wm8731->regmap, WM8731_RINVOL, 0x100, 0);
 
        /* Disable bypass path by default */
-       snd_soc_update_bits(codec, WM8731_APANA, 0x8, 0);
+       regmap_update_bits(wm8731->regmap, WM8731_APANA, 0x8, 0);
 
-       /* Regulators will have been enabled by bias management */
-       regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-
-       return 0;
+       regcache_mark_dirty(wm8731->regmap);
 
 err_regulator_enable:
+       /* Regulators will be enabled by bias management */
        regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
 
        return ret;
 }
 
-/* power down chip */
-static int wm8731_remove(struct snd_soc_codec *codec)
-{
-       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
-
-       regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-
-       return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
-       .probe =        wm8731_probe,
-       .remove =       wm8731_remove,
        .set_bias_level = wm8731_set_bias_level,
        .suspend_bias_off = true,
 
@@ -658,7 +650,6 @@ static const struct regmap_config wm8731_regmap = {
 
        .max_register = WM8731_RESET,
        .volatile_reg = wm8731_volatile,
-       .writeable_reg = wm8731_writeable,
 
        .cache_type = REGCACHE_RBTREE,
        .reg_defaults = wm8731_reg_defaults,
@@ -690,6 +681,12 @@ static int wm8731_spi_probe(struct spi_device *spi)
 
        mutex_init(&wm8731->lock);
 
+       spi_set_drvdata(spi, wm8731);
+
+       ret = wm8731_request_supplies(&spi->dev, wm8731);
+       if (ret != 0)
+               return ret;
+
        wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap);
        if (IS_ERR(wm8731->regmap)) {
                ret = PTR_ERR(wm8731->regmap);
@@ -698,7 +695,9 @@ static int wm8731_spi_probe(struct spi_device *spi)
                return ret;
        }
 
-       spi_set_drvdata(spi, wm8731);
+       ret = wm8731_hw_init(&spi->dev, wm8731);
+       if (ret != 0)
+               return ret;
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_wm8731, &wm8731_dai, 1);
@@ -754,6 +753,12 @@ static int wm8731_i2c_probe(struct i2c_client *i2c,
 
        mutex_init(&wm8731->lock);
 
+       i2c_set_clientdata(i2c, wm8731);
+
+       ret = wm8731_request_supplies(&i2c->dev, wm8731);
+       if (ret != 0)
+               return ret;
+
        wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap);
        if (IS_ERR(wm8731->regmap)) {
                ret = PTR_ERR(wm8731->regmap);
@@ -762,7 +767,9 @@ static int wm8731_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
-       i2c_set_clientdata(i2c, wm8731);
+       ret = wm8731_hw_init(&i2c->dev, wm8731);
+       if (ret != 0)
+               return ret;
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8731, &wm8731_dai, 1);
@@ -789,7 +796,6 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
 static struct i2c_driver wm8731_i2c_driver = {
        .driver = {
                .name = "wm8731",
-               .owner = THIS_MODULE,
                .of_match_table = wm8731_of_match,
        },
        .probe =    wm8731_i2c_probe,
index 6ad606fd8b6908c2382d501da96036a942998b9f..e4a03d98aed439e3154ae027af93d42be48dba10 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 b34623786e35d0bd3d81ad2aa034128d8c6518af..de42c0388772404cf0223644a14b09521fb4ac7b 100644 (file)
@@ -61,25 +61,6 @@ static const struct reg_default wm8741_reg_defaults[] = {
        { 32, 0x0002 },     /* R32 - ADDITONAL_CONTROL_1 */
 };
 
-static bool wm8741_readable(struct device *dev, unsigned int reg)
-{
-       switch (reg) {
-       case WM8741_DACLLSB_ATTENUATION:
-       case WM8741_DACLMSB_ATTENUATION:
-       case WM8741_DACRLSB_ATTENUATION:
-       case WM8741_DACRMSB_ATTENUATION:
-       case WM8741_VOLUME_CONTROL:
-       case WM8741_FORMAT_CONTROL:
-       case WM8741_FILTER_CONTROL:
-       case WM8741_MODE_CONTROL_1:
-       case WM8741_MODE_CONTROL_2:
-       case WM8741_ADDITIONAL_CONTROL_1:
-               return true;
-       default:
-               return false;
-       }
-}
-
 static int wm8741_reset(struct snd_soc_codec *codec)
 {
        return snd_soc_write(codec, WM8741_RESET, 0);
@@ -278,51 +259,38 @@ static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        switch (freq) {
        case 0:
                wm8741->sysclk_constraints = NULL;
-               wm8741->sysclk = freq;
-               return 0;
-
+               break;
        case 11289600:
                wm8741->sysclk_constraints = &constraints_11289;
-               wm8741->sysclk = freq;
-               return 0;
-
+               break;
        case 12288000:
                wm8741->sysclk_constraints = &constraints_12288;
-               wm8741->sysclk = freq;
-               return 0;
-
+               break;
        case 16384000:
                wm8741->sysclk_constraints = &constraints_16384;
-               wm8741->sysclk = freq;
-               return 0;
-
+               break;
        case 16934400:
                wm8741->sysclk_constraints = &constraints_16934;
-               wm8741->sysclk = freq;
-               return 0;
-
+               break;
        case 18432000:
                wm8741->sysclk_constraints = &constraints_18432;
-               wm8741->sysclk = freq;
-               return 0;
-
+               break;
        case 22579200:
        case 33868800:
                wm8741->sysclk_constraints = &constraints_22579;
-               wm8741->sysclk = freq;
-               return 0;
-
+               break;
        case 24576000:
                wm8741->sysclk_constraints = &constraints_24576;
-               wm8741->sysclk = freq;
-               return 0;
-
+               break;
        case 36864000:
                wm8741->sysclk_constraints = &constraints_36864;
-               wm8741->sysclk = freq;
-               return 0;
+               break;
+       default:
+               return -EINVAL;
        }
-       return -EINVAL;
+
+       wm8741->sysclk = freq;
+       return 0;
 }
 
 static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
@@ -554,8 +522,6 @@ static const struct regmap_config wm8741_regmap = {
        .reg_defaults = wm8741_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults),
        .cache_type = REGCACHE_RBTREE,
-
-       .readable_reg = wm8741_readable,
 };
 
 static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741)
@@ -633,7 +599,6 @@ MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
 static struct i2c_driver wm8741_i2c_driver = {
        .driver = {
                .name = "wm8741",
-               .owner = THIS_MODULE,
                .of_match_table = wm8741_of_match,
        },
        .probe =    wm8741_i2c_probe,
index 56d89b0865fa6878fd6f760ec74b247455fa8fe4..873933a7966f92a6dcbc0e153192b5039ce48d79 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 feb2997a377aa0a0fe12df1c6b44384c4ff3f3fb..a801c6d754367de81e4951606a2f8df42ac35ddd 100644 (file)
@@ -138,11 +138,6 @@ static bool wm8753_volatile(struct device *dev, unsigned int reg)
        return reg == WM8753_RESET;
 }
 
-static bool wm8753_writeable(struct device *dev, unsigned int reg)
-{
-       return reg <= WM8753_ADCTL2;
-}
-
 /* codec private data */
 struct wm8753_priv {
        struct regmap *regmap;
@@ -276,12 +271,11 @@ static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0);
 static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0);
 static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
-static const unsigned int out_tlv[] = {
-       TLV_DB_RANGE_HEAD(2),
+static const DECLARE_TLV_DB_RANGE(out_tlv,
        /* 0000000 - 0101111 = "Analogue mute" */
        0, 48, TLV_DB_SCALE_ITEM(-25500, 0, 0),
-       48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0),
-};
+       48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0)
+);
 static const DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0);
 static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0);
 static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
@@ -1510,7 +1504,6 @@ static const struct regmap_config wm8753_regmap = {
        .val_bits = 9,
 
        .max_register = WM8753_ADCTL2,
-       .writeable_reg = wm8753_writeable,
        .volatile_reg = wm8753_volatile,
 
        .cache_type = REGCACHE_RBTREE,
@@ -1609,7 +1602,6 @@ MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
 static struct i2c_driver wm8753_i2c_driver = {
        .driver = {
                .name = "wm8753",
-               .owner = THIS_MODULE,
                .of_match_table = wm8753_of_match,
        },
        .probe =    wm8753_i2c_probe,
index ece9b44567676612564058557d496649be5a2265..183c9a4966c51b091f239c5fcdbaffc69d5dcfdb 100644 (file)
@@ -265,7 +265,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* Set word length */
-       switch (snd_pcm_format_width(params_format(params))) {
+       switch (params_width(params)) {
        case 16:
                iface = 0;
                break;
@@ -280,7 +280,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
                break;
        default:
                dev_err(codec->dev, "Unsupported sample size: %i\n",
-                       snd_pcm_format_width(params_format(params)));
+                       params_width(params));
                return -EINVAL;
        }
 
@@ -536,7 +536,6 @@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
 static struct i2c_driver wm8776_i2c_driver = {
        .driver = {
                .name = "wm8776",
-               .owner = THIS_MODULE,
                .of_match_table = wm8776_of_match,
        },
        .probe =    wm8776_i2c_probe,
index 6596f5f3a0c3515afba801a70e584ef5d5e46334..f27464c2c5bad53ccca78fa8ba3bd0bf3f2cfef6 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 c195c2e8af074e5fa1b6985b2cf6e85a3df4fd16..8d914702cae4a3fe2c0ca0599cd1ec79f7322c83 100644 (file)
@@ -98,7 +98,7 @@ WM8804_REGULATOR_EVENT(0)
 WM8804_REGULATOR_EVENT(1)
 
 static const char *txsrc_text[] = { "S/PDIF RX", "AIF" };
-static const SOC_ENUM_SINGLE_DECL(txsrc, WM8804_SPDTX4, 6, txsrc_text);
+static SOC_ENUM_SINGLE_DECL(txsrc, WM8804_SPDTX4, 6, txsrc_text);
 
 static const struct snd_kcontrol_new wm8804_tx_source_mux[] = {
        SOC_DAPM_ENUM_EXT("Input Source", txsrc,
index f3759ec5a8638647cd54088f560a239e58776428..98900aa66dc30cc65afa0f75af2d191799de4959 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 b5322c1544fba51e2d609b186d6fdd2ebb7b57d7..b011253459af98f57fd87b574fa02164cf38830a 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 265a4a58a2d1bf7c4e80e1b48c981af4ef878ae5..b783743dc97e5a7e82699490aab28ca2e8380950 100644 (file)
@@ -1837,7 +1837,9 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               clk_prepare_enable(wm8904->mclk);
+               ret = clk_prepare_enable(wm8904->mclk);
+               if (ret)
+                       return ret;
                break;
 
        case SND_SOC_BIAS_PREPARE:
@@ -2292,7 +2294,6 @@ MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id);
 static struct i2c_driver wm8904_i2c_driver = {
        .driver = {
                .name = "wm8904",
-               .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(wm8904_of_match),
        },
        .probe =    wm8904_i2c_probe,
index 98ef0ba5c2a45844282e6c14a6a382d01455dfdc..f6f9395ea38ef88b40b31e70dafddf27ea6f4945 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 2d591c24704be487830ab956e9f4b2ef1be02075..12e4435f00f85507340305442747119f8feb5208 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 94c5c4681ce5c0c83accd7ab8682de448c9e7b07..e3b7d0c57411870176c5e1e1398101f5641f77ad 100644 (file)
@@ -48,6 +48,9 @@
 #define WM8960_DISOP     0x40
 #define WM8960_DRES_MASK 0x30
 
+static bool is_pll_freq_available(unsigned int source, unsigned int target);
+static int wm8960_set_pll(struct snd_soc_codec *codec,
+               unsigned int freq_in, unsigned int freq_out);
 /*
  * wm8960 register cache
  * We can't read the WM8960 register space when we are
@@ -126,9 +129,12 @@ struct wm8960_priv {
        struct snd_soc_dapm_widget *rout1;
        struct snd_soc_dapm_widget *out3;
        bool deemph;
-       int playback_fs;
+       int lrclk;
        int bclk;
        int sysclk;
+       int clk_id;
+       int freq_in;
+       bool is_stream_in_use[2];
        struct wm8960_data pdata;
 };
 
@@ -164,8 +170,8 @@ static int wm8960_set_deemph(struct snd_soc_codec *codec)
        if (wm8960->deemph) {
                best = 1;
                for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
-                       if (abs(deemph_settings[i] - wm8960->playback_fs) <
-                           abs(deemph_settings[best] - wm8960->playback_fs))
+                       if (abs(deemph_settings[i] - wm8960->lrclk) <
+                           abs(deemph_settings[best] - wm8960->lrclk))
                                best = i;
                }
 
@@ -565,6 +571,9 @@ static struct {
        {  8000, 5 },
 };
 
+/* -1 for reserved value */
+static const int sysclk_divs[] = { 1, -1, 2, -1 };
+
 /* Multiply 256 for internal 256 div */
 static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 };
 
@@ -574,61 +583,110 @@ static const int bclk_divs[] = {
        120, 160, 220, 240, 320, 320, 320
 };
 
-static void wm8960_configure_clocking(struct snd_soc_codec *codec,
-               bool tx, int lrclk)
+static int wm8960_configure_clocking(struct snd_soc_codec *codec)
 {
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+       int sysclk, bclk, lrclk, freq_out, freq_in;
        u16 iface1 = snd_soc_read(codec, WM8960_IFACE1);
-       u16 iface2 = snd_soc_read(codec, WM8960_IFACE2);
-       u32 sysclk;
-       int i, j;
+       int i, j, k;
 
        if (!(iface1 & (1<<6))) {
                dev_dbg(codec->dev,
                        "Codec is slave mode, no need to configure clock\n");
-               return;
+               return 0;
+       }
+
+       if (wm8960->clk_id != WM8960_SYSCLK_MCLK && !wm8960->freq_in) {
+               dev_err(codec->dev, "No MCLK configured\n");
+               return -EINVAL;
        }
 
-       if (!wm8960->sysclk) {
-               dev_dbg(codec->dev, "No SYSCLK configured\n");
-               return;
+       freq_in = wm8960->freq_in;
+       bclk = wm8960->bclk;
+       lrclk = wm8960->lrclk;
+       /*
+        * If it's sysclk auto mode, check if the MCLK can provide sysclk or
+        * not. If MCLK can provide sysclk, using MCLK to provide sysclk
+        * directly. Otherwise, auto select a available pll out frequency
+        * and set PLL.
+        */
+       if (wm8960->clk_id == WM8960_SYSCLK_AUTO) {
+               /* disable the PLL and using MCLK to provide sysclk */
+               wm8960_set_pll(codec, 0, 0);
+               freq_out = freq_in;
+       } else if (wm8960->sysclk) {
+               freq_out = wm8960->sysclk;
+       } else {
+               dev_err(codec->dev, "No SYSCLK configured\n");
+               return -EINVAL;
        }
 
-       if (!wm8960->bclk || !lrclk) {
-               dev_dbg(codec->dev, "No audio clocks configured\n");
-               return;
+       /* check if the sysclk frequency is available. */
+       for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
+               if (sysclk_divs[i] == -1)
+                       continue;
+               sysclk = freq_out / sysclk_divs[i];
+               for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
+                       if (sysclk == dac_divs[j] * lrclk) {
+                               for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k)
+                                       if (sysclk == bclk * bclk_divs[k] / 10)
+                                               break;
+                               if (k != ARRAY_SIZE(bclk_divs))
+                                       break;
+                       }
+               }
+               if (j != ARRAY_SIZE(dac_divs))
+                       break;
        }
 
-       for (i = 0; i < ARRAY_SIZE(dac_divs); ++i) {
-               if (wm8960->sysclk == lrclk * dac_divs[i]) {
-                       for (j = 0; j < ARRAY_SIZE(bclk_divs); ++j) {
-                               sysclk = wm8960->bclk * bclk_divs[j] / 10;
-                               if (wm8960->sysclk == sysclk)
+       if (i != ARRAY_SIZE(sysclk_divs)) {
+               goto configure_clock;
+       } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
+               dev_err(codec->dev, "failed to configure clock\n");
+               return -EINVAL;
+       }
+       /* get a available pll out frequency and set pll */
+       for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
+               if (sysclk_divs[i] == -1)
+                       continue;
+               for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
+                       sysclk = lrclk * dac_divs[j];
+                       freq_out = sysclk * sysclk_divs[i];
+
+                       for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) {
+                               if (sysclk == bclk * bclk_divs[k] / 10 &&
+                                   is_pll_freq_available(freq_in, freq_out)) {
+                                       wm8960_set_pll(codec,
+                                                      freq_in, freq_out);
                                        break;
+                               } else {
+                                       continue;
+                               }
                        }
-                       if(j != ARRAY_SIZE(bclk_divs))
+                       if (k != ARRAY_SIZE(bclk_divs))
                                break;
                }
+               if (j != ARRAY_SIZE(dac_divs))
+                       break;
        }
 
-       if (i == ARRAY_SIZE(dac_divs)) {
-               dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk);
-               return;
+       if (i == ARRAY_SIZE(sysclk_divs)) {
+               dev_err(codec->dev, "failed to configure clock\n");
+               return -EINVAL;
        }
 
-       /*
-        * configure frame clock. If ADCLRC configure as GPIO pin, DACLRC
-        * pin is used as a frame clock for ADCs and DACs.
-        */
-       if (iface2 & (1<<6))
-               snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3);
-       else if (tx)
-               snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3);
-       else if (!tx)
-               snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, i << 6);
+configure_clock:
+       /* configure sysclk clock */
+       snd_soc_update_bits(codec, WM8960_CLOCK1, 3 << 1, i << 1);
+
+       /* configure frame clock */
+       snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, j << 3);
+       snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, j << 6);
 
        /* configure bit clock */
-       snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, j);
+       snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, k);
+
+       return 0;
 }
 
 static int wm8960_hw_params(struct snd_pcm_substream *substream,
@@ -667,9 +725,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       wm8960->lrclk = params_rate(params);
        /* Update filters for the new rate */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               wm8960->playback_fs = params_rate(params);
+       if (tx) {
                wm8960_set_deemph(codec);
        } else {
                for (i = 0; i < ARRAY_SIZE(alc_rates); i++)
@@ -682,7 +740,23 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
        /* set iface */
        snd_soc_write(codec, WM8960_IFACE1, iface);
 
-       wm8960_configure_clocking(codec, tx, params_rate(params));
+       wm8960->is_stream_in_use[tx] = true;
+
+       if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON &&
+           !wm8960->is_stream_in_use[!tx])
+               return wm8960_configure_clocking(codec);
+
+       return 0;
+}
+
+static int wm8960_hw_free(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
+       wm8960->is_stream_in_use[tx] = false;
 
        return 0;
 }
@@ -702,6 +776,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
                                      enum snd_soc_bias_level level)
 {
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+       u16 pm2 = snd_soc_read(codec, WM8960_POWER2);
        int ret;
 
        switch (level) {
@@ -721,11 +796,22 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
                                }
                        }
 
+                       ret = wm8960_configure_clocking(codec);
+                       if (ret)
+                               return ret;
+
                        /* Set VMID to 2x50k */
                        snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
                        break;
 
                case SND_SOC_BIAS_ON:
+                       /*
+                        * If it's sysclk auto mode, and the pll is enabled,
+                        * disable the pll
+                        */
+                       if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1))
+                               wm8960_set_pll(codec, 0, 0);
+
                        if (!IS_ERR(wm8960->mclk))
                                clk_disable_unprepare(wm8960->mclk);
                        break;
@@ -780,6 +866,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
                                         enum snd_soc_bias_level level)
 {
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+       u16 pm2 = snd_soc_read(codec, WM8960_POWER2);
        int reg, ret;
 
        switch (level) {
@@ -831,9 +918,21 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
                                        return ret;
                                }
                        }
+
+                       ret = wm8960_configure_clocking(codec);
+                       if (ret)
+                               return ret;
+
                        break;
 
                case SND_SOC_BIAS_ON:
+                       /*
+                        * If it's sysclk auto mode, and the pll is enabled,
+                        * disable the pll
+                        */
+                       if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1))
+                               wm8960_set_pll(codec, 0, 0);
+
                        if (!IS_ERR(wm8960->mclk))
                                clk_disable_unprepare(wm8960->mclk);
 
@@ -892,6 +991,28 @@ struct _pll_div {
        u32 k:24;
 };
 
+static bool is_pll_freq_available(unsigned int source, unsigned int target)
+{
+       unsigned int Ndiv;
+
+       if (source == 0 || target == 0)
+               return false;
+
+       /* Scale up target to PLL operating frequency */
+       target *= 4;
+       Ndiv = target / source;
+
+       if (Ndiv < 6) {
+               source >>= 1;
+               Ndiv = target / source;
+       }
+
+       if ((Ndiv < 6) || (Ndiv > 12))
+               return false;
+
+       return true;
+}
+
 /* The size in bits of the pll divide multiplied by 10
  * to allow rounding later */
 #define FIXED_PLL_SIZE ((1 << 24) * 10)
@@ -943,10 +1064,9 @@ static int pll_factors(unsigned int source, unsigned int target,
        return 0;
 }
 
-static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
-               int source, unsigned int freq_in, unsigned int freq_out)
+static int wm8960_set_pll(struct snd_soc_codec *codec,
+               unsigned int freq_in, unsigned int freq_out)
 {
-       struct snd_soc_codec *codec = codec_dai->codec;
        u16 reg;
        static struct _pll_div pll_div;
        int ret;
@@ -986,6 +1106,20 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
        return 0;
 }
 
+static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+       wm8960->freq_in = freq_in;
+
+       if (pll_id == WM8960_SYSCLK_AUTO)
+               return 0;
+
+       return wm8960_set_pll(codec, freq_in, freq_out);
+}
+
 static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
                int div_id, int div)
 {
@@ -1043,11 +1177,14 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
                snd_soc_update_bits(codec, WM8960_CLOCK1,
                                        0x1, WM8960_SYSCLK_PLL);
                break;
+       case WM8960_SYSCLK_AUTO:
+               break;
        default:
                return -EINVAL;
        }
 
        wm8960->sysclk = freq;
+       wm8960->clk_id = clk_id;
 
        return 0;
 }
@@ -1060,6 +1197,7 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 
 static const struct snd_soc_dai_ops wm8960_dai_ops = {
        .hw_params = wm8960_hw_params,
+       .hw_free = wm8960_hw_free,
        .digital_mute = wm8960_mute,
        .set_fmt = wm8960_set_dai_fmt,
        .set_clkdiv = wm8960_set_dai_clkdiv,
@@ -1216,7 +1354,6 @@ MODULE_DEVICE_TABLE(of, wm8960_of_match);
 static struct i2c_driver wm8960_i2c_driver = {
        .driver = {
                .name = "wm8960",
-               .owner = THIS_MODULE,
                .of_match_table = wm8960_of_match,
        },
        .probe =    wm8960_i2c_probe,
index 2d8163d7004b86a59c4f34522bd2f1d3f74a8e24..ab3220d3411d26ef8dfe0fafdc213a5728fbfd41 100644 (file)
@@ -82,6 +82,7 @@
 
 #define WM8960_SYSCLK_MCLK             (0 << 0)
 #define WM8960_SYSCLK_PLL              (1 << 0)
+#define WM8960_SYSCLK_AUTO             (2 << 0)
 
 #define WM8960_DAC_DIV_1               (0 << 3)
 #define WM8960_DAC_DIV_1_5             (1 << 3)
index a057662632ffae459a318c5d9e88189b0e8391b5..e30446a047407711ea236f14a52dd93aec2ca2d4 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 c5748fd4f2962a816308faf605f7aee7116b970a..b4eb975da981a82c66435ddcaf0ee6f656c0b927 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 b51184c4e8163ed312d92b597d3b0f64d505dd2e..2cdde32c43c634d2b6e280908a22cebd8268da5a 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 33b16a7ba82ef4adec09423dd7ffcfbf1427411e..0a60677397b3dedb0b9652e112137e9b3c03f3d4 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 cfc8cdf499707ac6827e3da1da05ab356bcef3d4..d36d6001fbb7e7a15067a34db07af1637d89cddd 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 2fdd2c6cc09d3b62d04f157042901bd33c991e18..f3193fb751cc4e6cb93555fbbcfb8678be159ede 100644 (file)
@@ -84,66 +84,6 @@ static const struct reg_default wm8983_defaults[] = {
        { 0x3D, 0x0000 },      /* R61 - BIAS CTRL */
 };
 
-static const struct wm8983_reg_access {
-       u16 read; /* Mask of readable bits */
-       u16 write; /* Mask of writable bits */
-} wm8983_access_masks[WM8983_MAX_REGISTER + 1] = {
-       [0x00] = { 0x0000, 0x01FF }, /* R0  - Software Reset */
-       [0x01] = { 0x0000, 0x01FF }, /* R1  - Power management 1 */
-       [0x02] = { 0x0000, 0x01FF }, /* R2  - Power management 2 */
-       [0x03] = { 0x0000, 0x01EF }, /* R3  - Power management 3 */
-       [0x04] = { 0x0000, 0x01FF }, /* R4  - Audio Interface */
-       [0x05] = { 0x0000, 0x003F }, /* R5  - Companding control */
-       [0x06] = { 0x0000, 0x01FD }, /* R6  - Clock Gen control */
-       [0x07] = { 0x0000, 0x000F }, /* R7  - Additional control */
-       [0x08] = { 0x0000, 0x003F }, /* R8  - GPIO Control */
-       [0x09] = { 0x0000, 0x0070 }, /* R9  - Jack Detect Control 1 */
-       [0x0A] = { 0x0000, 0x004F }, /* R10 - DAC Control */
-       [0x0B] = { 0x0000, 0x01FF }, /* R11 - Left DAC digital Vol */
-       [0x0C] = { 0x0000, 0x01FF }, /* R12 - Right DAC digital vol */
-       [0x0D] = { 0x0000, 0x00FF }, /* R13 - Jack Detect Control 2 */
-       [0x0E] = { 0x0000, 0x01FB }, /* R14 - ADC Control */
-       [0x0F] = { 0x0000, 0x01FF }, /* R15 - Left ADC Digital Vol */
-       [0x10] = { 0x0000, 0x01FF }, /* R16 - Right ADC Digital Vol */
-       [0x12] = { 0x0000, 0x017F }, /* R18 - EQ1 - low shelf */
-       [0x13] = { 0x0000, 0x017F }, /* R19 - EQ2 - peak 1 */
-       [0x14] = { 0x0000, 0x017F }, /* R20 - EQ3 - peak 2 */
-       [0x15] = { 0x0000, 0x017F }, /* R21 - EQ4 - peak 3 */
-       [0x16] = { 0x0000, 0x007F }, /* R22 - EQ5 - high shelf */
-       [0x18] = { 0x0000, 0x01FF }, /* R24 - DAC Limiter 1 */
-       [0x19] = { 0x0000, 0x007F }, /* R25 - DAC Limiter 2 */
-       [0x1B] = { 0x0000, 0x01FF }, /* R27 - Notch Filter 1 */
-       [0x1C] = { 0x0000, 0x017F }, /* R28 - Notch Filter 2 */
-       [0x1D] = { 0x0000, 0x017F }, /* R29 - Notch Filter 3 */
-       [0x1E] = { 0x0000, 0x017F }, /* R30 - Notch Filter 4 */
-       [0x20] = { 0x0000, 0x01BF }, /* R32 - ALC control 1 */
-       [0x21] = { 0x0000, 0x00FF }, /* R33 - ALC control 2 */
-       [0x22] = { 0x0000, 0x01FF }, /* R34 - ALC control 3 */
-       [0x23] = { 0x0000, 0x000F }, /* R35 - Noise Gate */
-       [0x24] = { 0x0000, 0x001F }, /* R36 - PLL N */
-       [0x25] = { 0x0000, 0x003F }, /* R37 - PLL K 1 */
-       [0x26] = { 0x0000, 0x01FF }, /* R38 - PLL K 2 */
-       [0x27] = { 0x0000, 0x01FF }, /* R39 - PLL K 3 */
-       [0x29] = { 0x0000, 0x000F }, /* R41 - 3D control */
-       [0x2A] = { 0x0000, 0x01E7 }, /* R42 - OUT4 to ADC */
-       [0x2B] = { 0x0000, 0x01BF }, /* R43 - Beep control */
-       [0x2C] = { 0x0000, 0x0177 }, /* R44 - Input ctrl */
-       [0x2D] = { 0x0000, 0x01FF }, /* R45 - Left INP PGA gain ctrl */
-       [0x2E] = { 0x0000, 0x01FF }, /* R46 - Right INP PGA gain ctrl */
-       [0x2F] = { 0x0000, 0x0177 }, /* R47 - Left ADC BOOST ctrl */
-       [0x30] = { 0x0000, 0x0177 }, /* R48 - Right ADC BOOST ctrl */
-       [0x31] = { 0x0000, 0x007F }, /* R49 - Output ctrl */
-       [0x32] = { 0x0000, 0x01FF }, /* R50 - Left mixer ctrl */
-       [0x33] = { 0x0000, 0x01FF }, /* R51 - Right mixer ctrl */
-       [0x34] = { 0x0000, 0x01FF }, /* R52 - LOUT1 (HP) volume ctrl */
-       [0x35] = { 0x0000, 0x01FF }, /* R53 - ROUT1 (HP) volume ctrl */
-       [0x36] = { 0x0000, 0x01FF }, /* R54 - LOUT2 (SPK) volume ctrl */
-       [0x37] = { 0x0000, 0x01FF }, /* R55 - ROUT2 (SPK) volume ctrl */
-       [0x38] = { 0x0000, 0x004F }, /* R56 - OUT3 mixer ctrl */
-       [0x39] = { 0x0000, 0x00FF }, /* R57 - OUT4 (MONO) mix ctrl */
-       [0x3D] = { 0x0000, 0x0100 }  /* R61 - BIAS CTRL */
-};
-
 /* vol/gain update regs */
 static const int vol_update_regs[] = {
        WM8983_LEFT_DAC_DIGITAL_VOL,
@@ -605,12 +545,19 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static bool wm8983_readable(struct device *dev, unsigned int reg)
+static bool wm8983_writeable(struct device *dev, unsigned int reg)
 {
-       if (reg > WM8983_MAX_REGISTER)
-               return 0;
-
-       return wm8983_access_masks[reg].read != 0;
+       switch (reg) {
+       case WM8983_SOFTWARE_RESET ... WM8983_RIGHT_ADC_DIGITAL_VOL:
+       case WM8983_EQ1_LOW_SHELF ... WM8983_DAC_LIMITER_2:
+       case WM8983_NOTCH_FILTER_1 ... WM8983_NOTCH_FILTER_4:
+       case WM8983_ALC_CONTROL_1 ... WM8983_PLL_K_3:
+       case WM8983_3D_CONTROL ... WM8983_OUT4_MONO_MIX_CTRL:
+       case WM8983_BIAS_CTRL:
+               return true;
+       default:
+               return false;
+       }
 }
 
 static int wm8983_dac_mute(struct snd_soc_dai *dai, int mute)
@@ -1048,8 +995,9 @@ static const struct regmap_config wm8983_regmap = {
        .reg_defaults = wm8983_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8983_defaults),
        .cache_type = REGCACHE_RBTREE,
+       .max_register = WM8983_MAX_REGISTER,
 
-       .readable_reg = wm8983_readable,
+       .writeable_reg = wm8983_writeable,
 };
 
 #if defined(CONFIG_SPI_MASTER)
@@ -1133,7 +1081,6 @@ MODULE_DEVICE_TABLE(i2c, wm8983_i2c_id);
 static struct i2c_driver wm8983_i2c_driver = {
        .driver = {
                .name = "wm8983",
-               .owner = THIS_MODULE,
        },
        .probe = wm8983_i2c_probe,
        .remove = wm8983_i2c_remove,
index 8a85f5004d41c095e3e346c046b8bf0c5e8b8217..9c3c1517a4f3a4d8afcbff6394ddc492119f509a 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 f13a995af2773441af988585c11445fb13038367..c88ce99ce9e17e144a14c51e197f280bd075d0f7 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 1993fd2a6f15b3b8217bd3fbf56e0145a99980b1..23ecd30d8bcad392204528466332eb1d4c0bf7a3 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 44a677720828e013b52ae71330d8f0c3359b3a1b..c9ee0ac6a65441fbaef3a30f95565d169e32a81b 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 8a8db8605dc2e72acd5ab0e70149834d06ba7bf0..8668c4c391b07be20309503c9f2f5568051b99cc 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 962e1d31a629bb8b6a18c47065c4fab4b6afe5cf..2ccbb322df775b803d40fe765958f439d855d41f 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 505b65f5734f102f6fe1fa4dca1a579ad828d971..eda52a96c1fa5ef4c1b802f77075158dd0619d70 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 3dd063f682b29f6fa4e1bb1dbdda1a3305c750bc..f7ccd9fc5808e56950225d2ccccd7a8ad8d2de62 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 },
@@ -1780,7 +1780,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
        wm8996->rx_rate[dai->id] = params_rate(params);
 
        /* Needs looking at for TDM */
-       bits = snd_pcm_format_width(params_format(params));
+       bits = params_width(params);
        if (bits < 0)
                return bits;
        aifdata |= (bits << WM8996_AIF1TX_WL_SHIFT) | bits;
@@ -2647,12 +2647,10 @@ static int wm8996_probe(struct snd_soc_codec *codec)
                if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
                        ret = request_threaded_irq(i2c->irq, NULL,
                                                   wm8996_edge_irq,
-                                                  irq_flags | IRQF_ONESHOT,
-                                                  "wm8996", codec);
+                                                  irq_flags, "wm8996", codec);
                else
                        ret = request_threaded_irq(i2c->irq, NULL, wm8996_irq,
-                                                  irq_flags | IRQF_ONESHOT,
-                                                  "wm8996", codec);
+                                                  irq_flags, "wm8996", codec);
 
                if (ret == 0) {
                        /* Unmask the interrupt */
@@ -3100,7 +3098,6 @@ MODULE_DEVICE_TABLE(i2c, wm8996_i2c_id);
 static struct i2c_driver wm8996_i2c_driver = {
        .driver = {
                .name = "wm8996",
-               .owner = THIS_MODULE,
        },
        .probe =    wm8996_i2c_probe,
        .remove =   wm8996_i2c_remove,
index 4134dc7e12434cb1a1e43b723eb43a9e23bcee52..b4dba3a02abafd73044724146601fade748637b4 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 8a8b1c0f9142180f0bb84d86652b1e8d2f67fd6c..ccb3b15139ad9dacd41ad801201471d1ed696997 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 13d23fc797dbb10f1f05b0523e2467d074fdc7ec..5d737290f5475f615ac9c1b536d6311602884e9d 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 5cc457ef8894f7c69ae7c4981ab7e2d6d08d135b..744842c76a60c3c76c32fa2827482d527f5b327a 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 1fda104dfc455cafcf83e13ed210302f8b825fbe..488a92224249f064922e4c019ab5065f07b87c74 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 89cd2d6f57c01d46a8eaf8dd24b81f7cb2a054fb..4083a5130cbd192a37fbfd8895b47b7cce2fc46f 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 793da863a03d94096aa130f5f88757ef5f23eb9c..53df11b1f727fae6979b071ea02691293de21c2a 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 fd86bd105460528ac3bfcf987a5e6b1db3e7d487..624b3b9cb079f772f96fd473a9dbd5b186b63bb6 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 56cb4d95637dda5443ae0766192fedb5217af1df..ec98548a5fc9282b9c0b47abd354f22d8d95cb38 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 b960e626dad9093680e2d6efcd778fee0f1d380d..add6bb99661daced09d250eb04af15b37c6ffb44 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 fabd05f24aebe9b288735177fce0f5e3a250751c..c77d9218795adba25d2ae54665a8e21b769d6ee7 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 e1aa3834b101e6cf19f4e1adac4b4e7cb1f074f0..883087f2b092b1028e279b3cf54ce87ae46954dd 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 de438871040bd43f8b1e6a05e4a479261e5ea4bd..5aeb6ed4827e821f0f0ec2cbc866ed1a99a73cc4 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 c068494bae305caaf1015f92636e32e16e475a55..9f087d4f73ed775bdfaf9bad8c562b26a657b47d 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 5c7597191e3ffc682d1f813cdd9a6da8afbde397..8c2ddc1ea954c903873b02462a42012782336d62 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 5c73bea7b11ef89ae09bb3a472ff42d420e3c11e..a18fd92c4a85c3d67306c544c1af6652789d1467 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 066280953c8503bd03d2dc1a2469004978215e1a..b95fbc3f68ebbfcae42d95c64552e87bdeec78a4 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 8e932219cb3af924398f5296ea77758313d0ca7b..ab729f2426fe3ce18ca19b3adedf0e3fe946b3b3 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 c0b940e2019f55f34bb53673a99a4594d7409ef3..8ec6fb208ea073b70bc19b27dab7a12129a035f7 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 0db94f492e97d6e7533909e841edad2fa57ecb9a..1fc01ed3279dbee0991a343c082aa6c9ea5f042b 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 c79cb27473be771d9ee355cacf52229f5da6c40d..133c4470acad67f3a94354e607b0536180cc3bb9 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 461ce27b884f0f0b22dd6bb03216a1ee05f7e0fc..48b2d24dd1f0a9a639c6bd7e7549035ed38f8e15 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 d5554939146e8c310e35b175217ac8c6a04c2551..3ff76d419436ebbac7ac194e42510495a715f183 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 f3060a4ca040b5b9339221f9c701b47ced365afc..05fde5e6e2578396aa4e4be20d84d3b35d3bc6ff 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 6de5d5cd3280a92bf9d1b0ab71a5171e82a5bb0b..2b45435e6245c6c517e98f6558d5b591576e52e6 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 31e9b9ecbb8a599100774ad6fdee346755d43b42..d55388e082e18189b71693bacf3994fdc6372a7c 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 641ebe61dc08ba507ffb99c81d7ec0aa2c6d7986..683e5011615241b026d91c4056ce3cb28e97c537 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 2409b23eeacf4d62b6ed377c13666b063c92b6ff..cb32cc7e5ec1f17484dc94f73a0a72cae38d9903 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 0e0e4d9c021ff29bdf1f19eda2827ac459e4046c..ce689c5af5abca7428afe57a88dbee3513fae1b3 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 5a278618466c5a326fd23c92f4b45ff07e3b22f3..3dc7358828b374a6a4f5e8c5f45f588a1d1daaa5 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 7ab8cc9fbfd53b33be8ad519a0d5ab5672c632c8..d9f81b8d915dfc268ac53e366d060fd86e5edea8 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 ae89b9b966d9ff3e46101777355044b2694e8815..de9788a3fd06221dd7971d3c4967ad4c0bf22b81 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 7f55d59024a88bd7b53ddd6f66a00fc8adeeaabd..c4453120b11a33c60dc08422b49096f2700ce872 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 70f832114a5aeffeeb7b0cc555f8f1b91bc40665..49f4869cec48a273595f145cae120fa1485e88e6 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 bdcaf467842ab788219689ab854048feef029f6c..7be8461e4d3bd45c32b921b96acc1817bcb3584f 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 2c9cc5be439e654bccb875df435eb651cf25163f..23fe0407514209d2ddfd67b7e076f099c5e73f5d 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 396d54510350ed8e2cac6630ee6878f53e93825f..cbd568eac033ebe3aa1af77a2b51ec92e3ccae50 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 64e94212d2d2b129ebeddf9f1e4e55ac24775826..a627236dd1f5b47e47e132c6feae996bdfcb9dc1 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 96aeb2556ad40d3d4e8bc35f9e180555d8d72873..1f45f18715c09ef44ccb0b31930f27ae875673b6 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 4cf2245950d79e91cf343ed9658f51f4fd3dc6df..dbfdfe99c69df940259363d7404e0690aa07b92f 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 2d2536af141fc9157b2ecb402a969af6c808faf6..684e8a78bed0640310e0b54e292df725b409fe22 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 6f52eca05e2600f34c5b76deb77db81ab6fb9290..86cf9752f18a343791eaeeff8ca8ab9c2c4a83e8 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 a88b17511fdf12c733974b918f04c0576c6e3ba9..cc4393cb1130fb53338a6d766b513df94be3229a 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 9863da73dfe03a0f057d9897fd89e7d4d1614194..d190fe017559b6a9ba40baff2f4dd8f05b88cb8e 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 5ae5ca15b6d6bf109b20a236f69f1b6a2900bd7a..e09326158bc2dd0be61ea69f375f37dc6f0cdbe5 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 68a1252053750a29489382ce6434ed54bd698c96..c7563e230c7dd261175c613624e16c0a7ed339ee 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 aeef25c0cb3d9fe18256955745b5d2dc4af81e81..584b2372339ef4e7f985ca0c11a77d300eb84888 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 076bec606d78aabbdecd4e398522fcc03bb2e197..732e749a1f8ed54d2ec7e3f619afb393f1d8a40d 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 1eb45dcfb8e848c2c4c26125fd30d1053486ce4e..51e790d006f5cb2bfd73df94c7d32bf3bb95d3e8 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 fbe2e93d6edca0c03f74ef66173f134fed71ff74..3da485ec1de7fa9d968f1cfd819252258a35cc46 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 e68290c15328abe7f2c48c8f7187a65fd8b3bcc4..6b4e400369107ccfac6513d28953b38e7805accd 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 a51c9da66614932bfab865d5e39635bfbe36a353..831ee37d2e3e714941855ebdef31bb3eaf15d26a 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 807fedfa1c76eb169b4abdf8652b8f448bb0a8e8..3cc252e55468eaabf529d60978eaa3c52158b25e 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 23f3d59e6d0957db55a6cd204107bf1b70400d37..97bc2023f08aa81fff0b1524b6fb0f34e992c23b 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 7356d3a766d6907d13812acbc1af0745befe0e3b..7a416795271130113a875cbf5b4fbea70e813cd9 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 d6e86c119e74909822c8e6cccd218b318f2858c2..0b63e2e5bcc925c3054096e530d454da838d5b1d 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 e18182699d83537205725a03f93507b1e88ed7f7..58bae8e2cf5ff7b9d1922feceaa0ac7347483561 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 b9219092b47fd917146ea4a25c195843ffb7c285..1bc1dc3c729a40ce715903346a8c409c319b4fb7 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 acb5be53bfb4ddbd6879437e58b7dcfe990bd201..b93610212e3df75354e34d89dcb1999930a1705a 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 8bf2e2c4bafb97f64eafab4d81a87be20e68f8f7..ee1fda92f2f42d70b4cfe5dc2b675b2fd0101435 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 7651dc92416107e74f23965f281b9a4523c6a19c..07ce2cfa484503af827c19c478d2f123830126d9 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 fd11404a3bc786f484774c28d64fa8c5a74c29da..8fad4441c87dc15248a0fe6eeb2d8f1ca1dc5e89 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 142c066eaee2ecb13dcfbee6ac01b076ce52894c..0215c78cbddf5491712c9e4d9bbcdb8e1229fa10 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 f1b445173fba7857e4dcd440ce75c5d8f21d33f3..8b258501aa357e78630bdf73a4be091fa5fb1f6c 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 f1e5920654f6ff74803b770ef31d66579fd9b8df..f3feed5ce9b65ba67d936a399a4a06f91cf77db7 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 d306e298c63dce269ec3b790a8ac225516181d1f..bfbb8a5e93bdce6c5c70092565869bf446233416 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 36fc020cbc1803cbec2a7e1a225ae8690ea84a98..57796387d482303bc84c29212dfed167685ae6fe 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 8c7dc51b1c4fd8a767a5717a651faed17e68234a..f04d17bc6e3debba80a7c69f2d6c51e3daa72ec8 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 09fcc54a8ee067589c682df1b3b0390ea463b5ed..7a0e52b4640a5a39a0bfb3f1d496d71919e0806c 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 84e935711e29e4424d560b3381b6357af6b84c00..d61db9c385eafd3bc6fca47edad10bff696b3ba2 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 c61c171801423fc03b98598a3fd1624c7eb4155c..89a18e102feb100b57350024a3d548261e91243e 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 2fbe59f7f9b5a845f5b97376de05bad6ff9c162f..d45b9a7e324efb49a5159417232c9f43815ebfed 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 ab13146e4f826cb8182ce3209e276f1af37bf418..89ed1b107ac52c5f808ba9208dc3ef45e84803e8 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 08d7259bbaabad727709281234905011e990f07d..d40efc9fe0a9b4597511b2de2ad02712aa912043 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 0e1e69c7abd56b25fab6e4ffb0eab5fd574d03d2..6173d15236c3c0c2ce53c3c31b721310f9576e9e 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 e0de8072c5144e92fce3ec9518787a4db526d726..f4bf21a5539b0e0592cc6e622f7714730c22f0ef 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 256b9c91aa94316979a270aa7459c83a0659b5da..70e4b9d8bdcdfd3fb83f37615a29fae64036d4c0 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 31068b8f3db0dd965cc2bdc6742684dc2cb8d8ea..69d01cd925ce28fb5fc5e798880f391ec207fff0 100644 (file)
 #define SOC_TPLG_PASS_VENDOR           1
 #define SOC_TPLG_PASS_MIXER            2
 #define SOC_TPLG_PASS_WIDGET           3
-#define SOC_TPLG_PASS_GRAPH            4
-#define SOC_TPLG_PASS_PINS             5
-#define SOC_TPLG_PASS_PCM_DAI          6
+#define SOC_TPLG_PASS_PCM_DAI          4
+#define SOC_TPLG_PASS_GRAPH            5
+#define SOC_TPLG_PASS_PINS             6
 
 #define SOC_TPLG_PASS_START    SOC_TPLG_PASS_MANIFEST
-#define SOC_TPLG_PASS_END      SOC_TPLG_PASS_PCM_DAI
+#define SOC_TPLG_PASS_END      SOC_TPLG_PASS_PINS
 
 struct soc_tplg {
        const struct firmware *fw;
@@ -66,10 +66,14 @@ struct soc_tplg {
        u32 index;      /* current block index */
        u32 req_index;  /* required index, only loaded/free matching blocks */
 
-       /* kcontrol operations */
+       /* vendor specific kcontrol operations */
        const struct snd_soc_tplg_kcontrol_ops *io_ops;
        int io_ops_count;
 
+       /* vendor specific bytes ext handlers, for TLV bytes controls */
+       const struct snd_soc_tplg_bytes_ext_ops *bytes_ext_ops;
+       int bytes_ext_ops_count;
+
        /* optional fw loading callbacks to component drivers */
        struct snd_soc_tplg_ops *ops;
 };
@@ -508,38 +512,74 @@ static void remove_pcm_dai(struct snd_soc_component *comp,
 /* bind a kcontrol to it's IO handlers */
 static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
        struct snd_kcontrol_new *k,
-       const struct snd_soc_tplg_kcontrol_ops *ops, int num_ops,
-       const struct snd_soc_tplg_kcontrol_ops *bops, int num_bops)
+       const struct soc_tplg *tplg)
 {
-       int i;
+       const struct snd_soc_tplg_kcontrol_ops *ops;
+       const struct snd_soc_tplg_bytes_ext_ops *ext_ops;
+       int num_ops, i;
+
+       if (hdr->ops.info == SND_SOC_TPLG_CTL_BYTES
+               && k->iface & SNDRV_CTL_ELEM_IFACE_MIXER
+               && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
+               && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+               struct soc_bytes_ext *sbe;
+               struct snd_soc_tplg_bytes_control *be;
+
+               sbe = (struct soc_bytes_ext *)k->private_value;
+               be = container_of(hdr, struct snd_soc_tplg_bytes_control, hdr);
+
+               /* TLV bytes controls need standard kcontrol info handler,
+                * TLV callback and extended put/get handlers.
+                */
+               k->info = snd_soc_bytes_info;
+               k->tlv.c = snd_soc_bytes_tlv_callback;
+
+               ext_ops = tplg->bytes_ext_ops;
+               num_ops = tplg->bytes_ext_ops_count;
+               for (i = 0; i < num_ops; i++) {
+                       if (!sbe->put && ext_ops[i].id == be->ext_ops.put)
+                               sbe->put = ext_ops[i].put;
+                       if (!sbe->get && ext_ops[i].id == be->ext_ops.get)
+                               sbe->get = ext_ops[i].get;
+               }
 
-       /* try and map standard kcontrols handler first */
+               if (sbe->put && sbe->get)
+                       return 0;
+               else
+                       return -EINVAL;
+       }
+
+       /* try and map vendor specific kcontrol handlers first */
+       ops = tplg->io_ops;
+       num_ops = tplg->io_ops_count;
        for (i = 0; i < num_ops; i++) {
 
-               if (ops[i].id == hdr->ops.put)
+               if (k->put == NULL && ops[i].id == hdr->ops.put)
                        k->put = ops[i].put;
-               if (ops[i].id == hdr->ops.get)
+               if (k->get == NULL && ops[i].id == hdr->ops.get)
                        k->get = ops[i].get;
-               if (ops[i].id == hdr->ops.info)
+               if (k->info == NULL && ops[i].id == hdr->ops.info)
                        k->info = ops[i].info;
        }
 
-       /* standard handlers found ? */
+       /* vendor specific handlers found ? */
        if (k->put && k->get && k->info)
                return 0;
 
-       /* none found so try bespoke handlers */
-       for (i = 0; i < num_bops; i++) {
+       /* none found so try standard kcontrol handlers */
+       ops = io_ops;
+       num_ops = ARRAY_SIZE(io_ops);
+       for (i = 0; i < num_ops; i++) {
 
-               if (k->put == NULL && bops[i].id == hdr->ops.put)
-                       k->put = bops[i].put;
-               if (k->get == NULL && bops[i].id == hdr->ops.get)
-                       k->get = bops[i].get;
-               if (k->info == NULL && bops[i].id == hdr->ops.info)
-                       k->info = bops[i].info;
+               if (k->put == NULL && ops[i].id == hdr->ops.put)
+                       k->put = ops[i].put;
+               if (k->get == NULL && ops[i].id == hdr->ops.get)
+                       k->get = ops[i].get;
+               if (k->info == NULL && ops[i].id == hdr->ops.info)
+                       k->info = ops[i].info;
        }
 
-       /* bespoke handlers found ? */
+       /* standard handlers found ? */
        if (k->put && k->get && k->info)
                return 0;
 
@@ -609,9 +649,7 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg,
        if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE))
                return 0;
 
-       if (tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
-               kc->tlv.c = snd_soc_bytes_tlv_callback;
-       } else {
+       if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) {
                tplg_tlv = &tc->tlv;
                switch (tplg_tlv->type) {
                case SNDRV_CTL_TLVT_DB_SCALE:
@@ -682,8 +720,7 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
                INIT_LIST_HEAD(&sbe->dobj.list);
 
                /* map io handlers */
-               err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, io_ops,
-                       ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+               err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg);
                if (err) {
                        soc_control_err(tplg, &be->hdr, be->hdr.name);
                        kfree(sbe);
@@ -777,8 +814,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
                INIT_LIST_HEAD(&sm->dobj.list);
 
                /* map io handlers */
-               err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, io_ops,
-                       ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+               err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg);
                if (err) {
                        soc_control_err(tplg, &mc->hdr, mc->hdr.name);
                        kfree(sm);
@@ -855,12 +891,12 @@ static int soc_tplg_denum_create_values(struct soc_enum *se,
        if (ec->items > sizeof(*ec->values))
                return -EINVAL;
 
-       se->dobj.control.dvalues =
-               kmalloc(ec->items * sizeof(u32), GFP_KERNEL);
+       se->dobj.control.dvalues = kmemdup(ec->values,
+                                          ec->items * sizeof(u32),
+                                          GFP_KERNEL);
        if (!se->dobj.control.dvalues)
                return -ENOMEM;
 
-       memcpy(se->dobj.control.dvalues, ec->values, ec->items * sizeof(u32));
        return 0;
 }
 
@@ -950,8 +986,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
                }
 
                /* map io handlers */
-               err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, io_ops,
-                       ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+               err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, tplg);
                if (err) {
                        soc_control_err(tplg, &ec->hdr, ec->hdr.name);
                        kfree(se);
@@ -1093,7 +1128,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
        struct snd_soc_tplg_mixer_control *mc;
        int i, err;
 
-       kc = kzalloc(sizeof(*kc) * num_kcontrols, GFP_KERNEL);
+       kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
        if (kc == NULL)
                return NULL;
 
@@ -1137,8 +1172,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
                INIT_LIST_HEAD(&sm->dobj.list);
 
                /* map io handlers */
-               err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], io_ops,
-                       ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+               err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], tplg);
                if (err) {
                        soc_control_err(tplg, &mc->hdr, mc->hdr.name);
                        kfree(sm);
@@ -1235,8 +1269,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
        }
 
        /* map io handlers */
-       err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, io_ops,
-               ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
+       err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg);
        if (err) {
                soc_control_err(tplg, &ec->hdr, ec->hdr.name);
                goto err_se;
@@ -1274,7 +1307,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
        struct snd_kcontrol_new *kc;
        int i, err;
 
-       kc = kzalloc(sizeof(*kc) * count, GFP_KERNEL);
+       kc = kcalloc(count, sizeof(*kc), GFP_KERNEL);
        if (!kc)
                return NULL;
 
@@ -1297,7 +1330,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
                        "ASoC: adding bytes kcontrol %s with access 0x%x\n",
                        be->hdr.name, be->hdr.access);
 
-               memset(kc, 0, sizeof(*kc));
                kc[i].name = be->hdr.name;
                kc[i].private_value = (long)sbe;
                kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
@@ -1307,9 +1339,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
                INIT_LIST_HEAD(&sbe->dobj.list);
 
                /* map standard io handlers and check for external handlers */
-               err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], io_ops,
-                               ARRAY_SIZE(io_ops), tplg->io_ops,
-                               tplg->io_ops_count);
+               err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], tplg);
                if (err) {
                        soc_control_err(tplg, &be->hdr, be->hdr.name);
                        kfree(sbe);
@@ -1737,6 +1767,8 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp,
        tplg.req_index = id;
        tplg.io_ops = ops->io_ops;
        tplg.io_ops_count = ops->io_ops_count;
+       tplg.bytes_ext_ops = ops->bytes_ext_ops;
+       tplg.bytes_ext_ops_count = ops->bytes_ext_ops_count;
 
        return soc_tplg_load(&tplg);
 }
@@ -1758,7 +1790,6 @@ void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
        u32 index)
 {
        struct snd_soc_dapm_widget *w, *next_w;
-       struct snd_soc_dapm_path *p, *next_p;
 
        list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
 
@@ -1770,31 +1801,9 @@ void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
                if (w->dobj.index != index &&
                        w->dobj.index != SND_SOC_TPLG_INDEX_ALL)
                        continue;
-
-               list_del(&w->list);
-
-               /*
-                * remove source and sink paths associated to this widget.
-                * While removing the path, remove reference to it from both
-                * source and sink widgets so that path is removed only once.
-                */
-               list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
-                       list_del(&p->list_sink);
-                       list_del(&p->list_source);
-                       list_del(&p->list);
-                       kfree(p);
-               }
-               list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
-                       list_del(&p->list_sink);
-                       list_del(&p->list_source);
-                       list_del(&p->list);
-                       kfree(p);
-               }
                /* check and free and dynamic widget kcontrols */
                snd_soc_tplg_widget_remove(w);
-               kfree(w->kcontrols);
-               kfree(w->name);
-               kfree(w);
+               snd_soc_dapm_free_widget(w);
        }
 }
 EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all);
index a4028601da01c40d071aa8dda5fceef6dffd4258..977a078eb92f236a005bbc232167ab862b339d07 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 a7dc3c56f44d95cfc611ca27975bf43349f90ca1..e8476da157cd2eda80cc2e572802a72d6a7368ce 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 f52600b4f3fd37d5c1aabc5c316c55922d2f9fb6..89add13c31cfc08259bd97d91555b70886117b77 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 05f1c6ee99e3614dbbe66d21e7baad907b4932ae..14106fa82bca3ed821c2a2ad9977c2856e37bbf8 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 9141477a528dda7760056878465f00778f9eb2b8..a0c3640572b98a80a48601093d3848d2341a8509 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 bc94e5d8e79a7553476da8099ed6df822e2eea5d..fef3b9a21a667304ca94579c5511c6ea3f58c073 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 fe36375ba89c5bd68dbc785ad0e15aebe10a574b..8e55583aa104e1c847b2c64700b90a564378ddf4 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 88eacfd83da6780b3d2419ab2173fa3d7e255916..a8f705bb60dc087a733e74031a777d91e20b09fe 100644 (file)
@@ -411,13 +411,8 @@ static struct snd_soc_platform_driver txx9aclc_soc_platform = {
 
 static int txx9aclc_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&pdev->dev, &txx9aclc_soc_platform);
-}
-
-static int txx9aclc_soc_platform_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_platform(&pdev->dev);
-       return 0;
+       return devm_snd_soc_register_platform(&pdev->dev,
+                                             &txx9aclc_soc_platform);
 }
 
 static struct platform_driver txx9aclc_pcm_driver = {
@@ -426,7 +421,6 @@ static struct platform_driver txx9aclc_pcm_driver = {
        },
 
        .probe = txx9aclc_soc_platform_probe,
-       .remove = txx9aclc_soc_platform_remove,
 };
 
 module_platform_driver(txx9aclc_pcm_driver);
index 978f2d7316b0651b3d3230d71d2d80738ab92bc0..f5df08ded770ef9cbafd3ec88903893bc4657344 100644 (file)
@@ -773,20 +773,22 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
        }
        prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50);
 
-       drvdata->pclk = clk_get(&pdev->dev, "apb_pclk");
+       drvdata->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
        if (IS_ERR(drvdata->pclk)) {
                ret = (int)PTR_ERR(drvdata->pclk);
-               dev_err(&pdev->dev, "%s: ERROR: clk_get of pclk failed (%d)!\n",
+               dev_err(&pdev->dev,
+                       "%s: ERROR: devm_clk_get of pclk failed (%d)!\n",
                        __func__, ret);
-               goto err_pclk;
+               return ret;
        }
 
-       drvdata->clk = clk_get(&pdev->dev, NULL);
+       drvdata->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(drvdata->clk)) {
                ret = (int)PTR_ERR(drvdata->clk);
-               dev_err(&pdev->dev, "%s: ERROR: clk_get failed (%d)!\n",
+               dev_err(&pdev->dev,
+                       "%s: ERROR: devm_clk_get failed (%d)!\n",
                        __func__, ret);
-               goto err_clk;
+               return ret;
        }
 
        ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp,
@@ -795,7 +797,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
                dev_err(&pdev->dev,
                        "%s: ERROR: Failed to init MSP-struct (%d)!",
                        __func__, ret);
-               goto err_init_msp;
+               return ret;
        }
        dev_set_drvdata(&pdev->dev, drvdata);
 
@@ -804,7 +806,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
        if (ret < 0) {
                dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n",
                        __func__, drvdata->msp->id);
-               goto err_init_msp;
+               return ret;
        }
 
        ret = ux500_pcm_register_platform(pdev);
@@ -819,13 +821,6 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
 
 err_reg_plat:
        snd_soc_unregister_component(&pdev->dev);
-err_init_msp:
-       clk_put(drvdata->clk);
-err_clk:
-       clk_put(drvdata->pclk);
-err_pclk:
-       devm_regulator_put(drvdata->reg_vape);
-
        return ret;
 }
 
@@ -837,12 +832,8 @@ static int ux500_msp_drv_remove(struct platform_device *pdev)
 
        snd_soc_unregister_component(&pdev->dev);
 
-       devm_regulator_put(drvdata->reg_vape);
        prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");
 
-       clk_put(drvdata->clk);
-       clk_put(drvdata->pclk);
-
        ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp);
 
        return 0;
index 1cfb19e12949ecd725409a1cace8122d4e6bf766..8382ffa3bcaf8b446dd67197503f3c21cef307ba 100644 (file)
@@ -75,7 +75,7 @@ struct xtfpga_i2s {
         * stream in the pcm_close callback it synchronizes with the interrupt
         * handler by means of synchronize_rcu call.
         */
-       struct snd_pcm_substream *tx_substream;
+       struct snd_pcm_substream __rcu *tx_substream;
        unsigned (*tx_fn)(struct xtfpga_i2s *i2s,
                          struct snd_pcm_runtime *runtime,
                          unsigned tx_ptr);
@@ -474,11 +474,6 @@ static int xtfpga_pcm_new(struct snd_soc_pcm_runtime *rtd)
                                                     card->dev, size, size);
 }
 
-static void xtfpga_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static const struct snd_pcm_ops xtfpga_pcm_ops = {
        .open           = xtfpga_pcm_open,
        .close          = xtfpga_pcm_close,
@@ -490,7 +485,6 @@ static const struct snd_pcm_ops xtfpga_pcm_ops = {
 
 static const struct snd_soc_platform_driver xtfpga_soc_platform = {
        .pcm_new        = xtfpga_pcm_new,
-       .pcm_free       = xtfpga_pcm_free,
        .ops            = &xtfpga_pcm_ops,
 };
 
index 1930c42e1f557ae62c30003b379088f242b0dbfe..1cad93dc1fcfdb669a876b1cfa6c2afbc625fe16 100644 (file)
@@ -380,7 +380,7 @@ static int zx_i2s_probe(struct platform_device *pdev)
        struct zx_i2s_info *zx_i2s;
        int ret;
 
-       zx_i2s =  kzalloc(sizeof(*zx_i2s), GFP_KERNEL);
+       zx_i2s = devm_kzalloc(&pdev->dev, sizeof(*zx_i2s), GFP_KERNEL);
        if (!zx_i2s)
                return -ENOMEM;
 
@@ -401,8 +401,8 @@ static int zx_i2s_probe(struct platform_device *pdev)
        writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL);
        platform_set_drvdata(pdev, zx_i2s);
 
-       ret = snd_soc_register_component(&pdev->dev, &zx_i2s_component,
-                                        &zx_i2s_dai, 1);
+       ret = devm_snd_soc_register_component(&pdev->dev, &zx_i2s_component,
+                                             &zx_i2s_dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
                return ret;
index de165a1b92402ac7a6267bd0a0c5aa30a0053c92..20b56eb987f89f21fe20e53decf8ee1fbe275a2e 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 ecf319728f25d649768e33b3e1f274d04432f3fc..6135cc07213cb0d3379d58033ea87aa8dc580878 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 094ddaee104c73d7caae22d851d79629c4715cd3..d31fac19c30b2d298ab2cf3a710b9b27c5764144 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 7ff682770fdb16e71b368af16efad0edd9443d87..f1a4c833121e306a364851328f6409cb22d779eb 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 53e8bb7bc8521a09f1347d48de2a0dd1eeb5e0bc..2a5d8d7698aedb8c82bdf8488f1fb62ded5b438a 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 28c4b746baa19bef9830814c4fe7c69f1be0b06b..0a9ae8014729c085ffd2872e2bc13871f79c9908 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)