diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 3514c2149e..ece44b7350 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -15,6 +15,10 @@ pound := \# # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o dot-target = $(dir $@).$(notdir $@) +### +# Name of target with a '.tmp_' as filename prefix. foo/bar.o => foo/.tmp_bar.o +tmp-target = $(dir $@).tmp_$(notdir $@) + ### # The temporary file to save gcc -MMD generated dependencies must not # contain a comma @@ -138,9 +142,11 @@ check-FORCE = $(if $(filter FORCE, $^),,$(warning FORCE prerequisite is missing) if-changed-cond = $(newer-prereqs)$(cmd-check)$(check-FORCE) # Execute command if command has changed or prerequisite(s) are updated. -if_changed = $(if $(if-changed-cond), \ +if_changed = $(if $(if-changed-cond),$(cmd_and_savecmd),@:) + +cmd_and_savecmd = \ $(cmd); \ - printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:) + printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd # Execute the command and also postprocess generated .d dependencies file. if_changed_dep = $(if $(if-changed-cond),$(cmd_and_fixdep),@:) diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include index 0496efd6e1..a0ccceb22c 100644 --- a/scripts/Kconfig.include +++ b/scripts/Kconfig.include @@ -25,7 +25,7 @@ failure = $(if-success,$(1),n,y) # $(cc-option,) # Return y if the compiler supports , n otherwise -cc-option = $(success,mkdir .tmp_$$$$; trap "rm -rf .tmp_$$$$" EXIT; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$$$/tmp.o) +cc-option = $(success,trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$/tmp.o) # $(ld-option,) # Return y if the linker supports , n otherwise diff --git a/scripts/Makefile b/scripts/Makefile index ce5aa9030b..f084f08ed1 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -14,8 +14,8 @@ hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include HOSTLDLIBS_sorttable = -lpthread HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include -HOSTCFLAGS_sign-file.o = $(shell pkg-config --cflags libcrypto 2> /dev/null) -HOSTLDLIBS_sign-file = $(shell pkg-config --libs libcrypto 2> /dev/null || echo -lcrypto) +HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) +HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 33c1ed5815..784f46d419 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -85,11 +85,8 @@ ifdef need-builtin targets-for-builtin += $(obj)/built-in.a endif -targets-for-modules := $(patsubst %.o, %.mod, $(filter %.o, $(obj-m))) - -ifneq ($(CONFIG_LTO_CLANG)$(CONFIG_X86_KERNEL_IBT),) -targets-for-modules += $(patsubst %.o, %.prelink.o, $(filter %.o, $(obj-m))) -endif +targets-for-modules := $(foreach x, o mod $(if $(CONFIG_TRIM_UNUSED_KSYMS), usyms), \ + $(patsubst %.o, %.$x, $(filter %.o, $(obj-m)))) ifdef need-modorder targets-for-modules += $(obj)/modules.order @@ -125,18 +122,16 @@ cmd_cpp_i_c = $(CPP) $(c_flags) -o $@ $< $(obj)/%.i: $(src)/%.c FORCE $(call if_changed_dep,cpp_i_c) +genksyms = scripts/genksyms/genksyms \ + $(if $(1), -T $(2)) \ + $(if $(KBUILD_PRESERVE), -p) \ + -r $(or $(wildcard $(2:.symtypes=.symref)), /dev/null) + # These mirror gensymtypes_S and co below, keep them in synch. -cmd_gensymtypes_c = \ - $(CPP) -D__GENKSYMS__ $(c_flags) $< | \ - scripts/genksyms/genksyms $(if $(1), -T $(2)) \ - $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \ - $(if $(KBUILD_PRESERVE),-p) \ - -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null)) +cmd_gensymtypes_c = $(CPP) -D__GENKSYMS__ $(c_flags) $< | $(genksyms) quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@ -cmd_cc_symtypes_c = \ - $(call cmd_gensymtypes_c,true,$@) >/dev/null; \ - test -s $@ || rm -f $@ + cmd_cc_symtypes_c = $(call cmd_gensymtypes_c,true,$@) >/dev/null $(obj)/%.symtypes : $(src)/%.c FORCE $(call cmd,cc_symtypes_c) @@ -153,8 +148,18 @@ $(obj)/%.ll: $(src)/%.c FORCE # The C file is compiled and updated dependency information is generated. # (See cmd_cc_o_c + relevant part of rule_cc_o_c) +is-single-obj-m = $(and $(part-of-module),$(filter $@, $(obj-m)),y) + +# When a module consists of a single object, there is no reason to keep LLVM IR. +# Make $(LD) covert LLVM IR to ELF here. +ifdef CONFIG_LTO_CLANG +cmd_ld_single_m = $(if $(is-single-obj-m), ; $(LD) $(ld_flags) -r -o $(tmp-target) $@; mv $(tmp-target) $@) +endif + quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ - cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< $(cmd_objtool) + cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< \ + $(cmd_ld_single_m) \ + $(cmd_objtool) ifdef CONFIG_MODVERSIONS # When module versioning is enabled the following steps are executed: @@ -162,35 +167,18 @@ ifdef CONFIG_MODVERSIONS # o if .o doesn't contain a __ksymtab version, i.e. does # not export symbols, it's done. # o otherwise, we calculate symbol versions using the good old -# genksyms on the preprocessed source and postprocess them in a way -# that they are usable as a linker script -# o generate .tmp_.o from .o using the linker to -# replace the unresolved symbols __crc_exported_symbol with -# the actual value of the checksum generated by genksyms -# o remove .tmp_.o to .o +# genksyms on the preprocessed source and dump them into the .cmd file. +# o modpost will extract versions from that file and create *.c files that will +# be compiled and linked to the kernel and/or modules. -ifdef CONFIG_LTO_CLANG -# Generate .o.symversions files for each .o with exported symbols, and link these -# to the kernel and/or modules at the end. -cmd_modversions_c = \ +gen_symversions = \ if $(NM) $@ 2>/dev/null | grep -q __ksymtab; then \ - $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ - > $@.symversions; \ - else \ - rm -f $@.symversions; \ - fi; -else -cmd_modversions_c = \ - if $(OBJDUMP) -h $@ | grep -q __ksymtab; then \ - $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ - > $(@D)/.tmp_$(@F:.o=.ver); \ - \ - $(LD) $(KBUILD_LDFLAGS) -r -o $(@D)/.tmp_$(@F) $@ \ - -T $(@D)/.tmp_$(@F:.o=.ver); \ - mv -f $(@D)/.tmp_$(@F) $@; \ - rm -f $(@D)/.tmp_$(@F:.o=.ver); \ + $(call cmd_gensymtypes_$(1),$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ + >> $(dot-target).cmd; \ fi -endif + +cmd_gen_symversions_c = $(call gen_symversions,c) + endif ifdef CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT @@ -222,65 +210,38 @@ cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)), $(sub_cmd_record_mcount)) endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT -ifdef CONFIG_STACK_VALIDATION - -objtool := $(objtree)/tools/objtool/objtool - -objtool_args = \ - $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \ - $(if $(part-of-module), --module) \ - $(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \ - $(if $(CONFIG_FRAME_POINTER),, --no-fp) \ - $(if $(CONFIG_GCOV_KERNEL), --no-unreachable) \ - $(if $(CONFIG_RETPOLINE), --retpoline) \ - $(if $(CONFIG_X86_SMAP), --uaccess) \ - $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \ - $(if $(CONFIG_SLS), --sls) - -cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@) -cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd) - -endif # CONFIG_STACK_VALIDATION - -ifneq ($(CONFIG_LTO_CLANG)$(CONFIG_X86_KERNEL_IBT),) - -# Skip objtool for LLVM bitcode -$(obj)/%.o: objtool-enabled := - -else - # 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file # 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file -$(obj)/%.o: objtool-enabled = $(if $(filter-out y%, \ - $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n),y) +is-standard-object = $(if $(filter-out y%, $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n),y) -endif +$(obj)/%.o: objtool-enabled = $(if $(is-standard-object),$(if $(delay-objtool),$(is-single-obj-m),y)) ifdef CONFIG_TRIM_UNUSED_KSYMS cmd_gen_ksymdeps = \ $(CONFIG_SHELL) $(srctree)/scripts/gen_ksymdeps.sh $@ >> $(dot-target).cmd - -# List module undefined symbols -undefined_syms = $(NM) $< | $(AWK) '$$1 == "U" { printf("%s%s", x++ ? " " : "", $$2) }'; endif +cmd_check_local_export = $(srctree)/scripts/check-local-export $@ + define rule_cc_o_c $(call cmd_and_fixdep,cc_o_c) $(call cmd,gen_ksymdeps) + $(call cmd,check_local_export) $(call cmd,checksrc) $(call cmd,checkdoc) $(call cmd,gen_objtooldep) - $(call cmd,modversions_c) + $(call cmd,gen_symversions_c) $(call cmd,record_mcount) endef define rule_as_o_S $(call cmd_and_fixdep,as_o_S) $(call cmd,gen_ksymdeps) + $(call cmd,check_local_export) $(call cmd,gen_objtooldep) - $(call cmd,modversions_S) + $(call cmd,gen_symversions_S) endef # Built-in and composite module parts @@ -288,33 +249,19 @@ $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE $(call if_changed_rule,cc_o_c) $(call cmd,force_checksrc) -ifneq ($(CONFIG_LTO_CLANG)$(CONFIG_X86_KERNEL_IBT),) -# Module .o files may contain LLVM bitcode, compile them into native code -# before ELF processing -quiet_cmd_cc_prelink_modules = LD [M] $@ - cmd_cc_prelink_modules = \ - $(LD) $(ld_flags) -r -o $@ \ - $(shell [ -s $(@:.prelink.o=.o.symversions) ] && \ - echo -T $(@:.prelink.o=.o.symversions)) \ - --whole-archive $(filter-out FORCE,$^) \ - $(cmd_objtool) - -# objtool was skipped for LLVM bitcode, run it now that we have compiled -# modules into native code -$(obj)/%.prelink.o: objtool-enabled = y -$(obj)/%.prelink.o: part-of-module := y +# To make this rule robust against "Argument list too long" error, +# ensure to add $(obj)/ prefix by a shell command. +cmd_mod = printf '%s\n' $(call real-search, $*.o, .o, -objs -y -m) | \ + $(AWK) '!x[$$0]++ { print("$(obj)/"$$0) }' > $@ -$(obj)/%.prelink.o: $(obj)/%.o FORCE - $(call if_changed,cc_prelink_modules) -endif +$(obj)/%.mod: FORCE + $(call if_changed,mod) -cmd_mod = { \ - echo $(if $($*-objs)$($*-y)$($*-m), $(addprefix $(obj)/, $($*-objs) $($*-y) $($*-m)), $(@:.mod=.o)); \ - $(undefined_syms) echo; \ - } > $@ +# List module undefined symbols +cmd_undefined_syms = $(NM) $< | sed -n 's/^ *U //p' > $@ -$(obj)/%.mod: $(obj)/%$(mod-prelink-ext).o FORCE - $(call if_changed,mod) +$(obj)/%.usyms: $(obj)/%.o FORCE + $(call if_changed,undefined_syms) quiet_cmd_cc_lst_c = MKLST $@ cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \ @@ -344,16 +291,10 @@ cmd_gensymtypes_S = \ $(CPP) $(a_flags) $< | \ grep "\<___EXPORT_SYMBOL\>" | \ sed 's/.*___EXPORT_SYMBOL[[:space:]]*\([a-zA-Z0-9_]*\)[[:space:]]*,.*/EXPORT_SYMBOL(\1);/' ; } | \ - $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | \ - scripts/genksyms/genksyms $(if $(1), -T $(2)) \ - $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \ - $(if $(KBUILD_PRESERVE),-p) \ - -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null)) + $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | $(genksyms) quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@ -cmd_cc_symtypes_S = \ - $(call cmd_gensymtypes_S,true,$@) >/dev/null; \ - test -s $@ || rm -f $@ + cmd_cc_symtypes_S = $(call cmd_gensymtypes_S,true,$@) >/dev/null $(obj)/%.symtypes : $(src)/%.S FORCE $(call cmd,cc_symtypes_S) @@ -373,16 +314,8 @@ ifdef CONFIG_ASM_MODVERSIONS # versioning matches the C process described above, with difference that # we parse asm-prototypes.h C header to get function definitions. -cmd_modversions_S = \ - if $(OBJDUMP) -h $@ | grep -q __ksymtab; then \ - $(call cmd_gensymtypes_S,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ - > $(@D)/.tmp_$(@F:.o=.ver); \ - \ - $(LD) $(KBUILD_LDFLAGS) -r -o $(@D)/.tmp_$(@F) $@ \ - -T $(@D)/.tmp_$(@F:.o=.ver); \ - mv -f $(@D)/.tmp_$(@F) $@; \ - rm -f $(@D)/.tmp_$(@F:.o=.ver); \ - fi +cmd_gen_symversions_S = $(call gen_symversions,S) + endif $(obj)/%.o: $(src)/%.S FORCE @@ -417,29 +350,19 @@ $(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler $(subdir-builtin): $(obj)/%/built-in.a: $(obj)/% ; $(subdir-modorder): $(obj)/%/modules.order: $(obj)/% ; -# combine symversions for later processing -ifeq ($(CONFIG_LTO_CLANG) $(CONFIG_MODVERSIONS),y y) - cmd_update_lto_symversions = \ - rm -f $@.symversions \ - $(foreach n, $(filter-out FORCE,$^), \ - $(if $(shell test -s $(n).symversions && echo y), \ - ; cat $(n).symversions >> $@.symversions)) -else - cmd_update_lto_symversions = echo >/dev/null -endif - # # Rule to compile a set of .o files into one .a file (without symbol table) # +# To make this rule robust against "Argument list too long" error, +# remove $(obj)/ prefix, and restore it by a shell command. quiet_cmd_ar_builtin = AR $@ - cmd_ar_builtin = rm -f $@; $(AR) cDPrST $@ $(real-prereqs) - -quiet_cmd_ar_and_symver = AR $@ - cmd_ar_and_symver = $(cmd_update_lto_symversions); $(cmd_ar_builtin) + cmd_ar_builtin = rm -f $@; \ + $(if $(real-prereqs), printf "$(obj)/%s " $(patsubst $(obj)/%,%,$(real-prereqs)) | xargs) \ + $(AR) cDPrST $@ $(obj)/built-in.a: $(real-obj-y) FORCE - $(call if_changed,ar_and_symver) + $(call if_changed,ar_builtin) # # Rule to create modules.order file @@ -459,32 +382,24 @@ $(obj)/modules.order: $(obj-m) FORCE # # Rule to compile a set of .o files into one .a file (with symbol table) # -quiet_cmd_ar_lib = AR $@ - cmd_ar_lib = $(cmd_update_lto_symversions); $(cmd_ar) $(obj)/lib.a: $(lib-y) FORCE - $(call if_changed,ar_lib) - -# NOTE: -# Do not replace $(filter %.o,^) with $(real-prereqs). When a single object -# module is turned into a multi object module, $^ will contain header file -# dependencies recorded in the .*.cmd file. -ifneq ($(CONFIG_LTO_CLANG)$(CONFIG_X86_KERNEL_IBT),) -quiet_cmd_link_multi-m = AR [M] $@ -cmd_link_multi-m = \ - $(cmd_update_lto_symversions); \ - rm -f $@; \ - $(AR) cDPrsT $@ $(filter %.o,$^) -else -quiet_cmd_link_multi-m = LD [M] $@ - cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(filter %.o,$^) -endif + $(call if_changed,ar) + +quiet_cmd_ld_multi_m = LD [M] $@ + cmd_ld_multi_m = $(LD) $(ld_flags) -r -o $@ @$(patsubst %.o,%.mod,$@) $(cmd_objtool) + +define rule_ld_multi_m + $(call cmd_and_savecmd,ld_multi_m) + $(call cmd,gen_objtooldep) +endef -$(multi-obj-m): FORCE - $(call if_changed,link_multi-m) +$(multi-obj-m): objtool-enabled := $(delay-objtool) +$(multi-obj-m): part-of-module := y +$(multi-obj-m): %.o: %.mod FORCE + $(call if_changed_rule,ld_multi_m) $(call multi_depend, $(multi-obj-m), .o, -objs -y -m) -targets += $(multi-obj-m) targets := $(filter-out $(PHONY), $(targets)) # Add intermediate targets: diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean index 74cb1c5c36..878cec6489 100644 --- a/scripts/Makefile.clean +++ b/scripts/Makefile.clean @@ -36,13 +36,7 @@ __clean-files := \ __clean-files := $(filter-out $(no-clean-files), $(__clean-files)) -# clean-files is given relative to the current directory, unless it -# starts with $(objtree)/ (which means "./", so do not add "./" unless -# you want to delete a file from the toplevel object directory). - -__clean-files := $(wildcard \ - $(addprefix $(obj)/, $(filter-out $(objtree)/%, $(__clean-files))) \ - $(filter $(objtree)/%, $(__clean-files))) +__clean-files := $(wildcard $(addprefix $(obj)/, $(__clean-files))) # ========================================================================== diff --git a/scripts/Makefile.compiler b/scripts/Makefile.compiler index 86ecd2ac87..94d0d40cdd 100644 --- a/scripts/Makefile.compiler +++ b/scripts/Makefile.compiler @@ -21,8 +21,8 @@ TMPOUT = $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_$$$$ # automatically cleaned up. try-run = $(shell set -e; \ TMP=$(TMPOUT)/tmp; \ - mkdir -p $(TMPOUT); \ trap "rm -rf $(TMPOUT)" EXIT; \ + mkdir -p $(TMPOUT); \ if ($(1)) >/dev/null 2>&1; \ then echo "$(2)"; \ else echo "$(3)"; \ diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index 650d0b8cee..6ae482158b 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -2,8 +2,8 @@ # ========================================================================== # make W=... settings # -# There are three warning groups enabled by W=1, W=2, W=3. -# They are independent, and can be combined like W=12 or W=123. +# There are four warning groups enabled by W=1, W=2, W=3, and W=e +# They are independent, and can be combined like W=12 or W=123e. # ========================================================================== KBUILD_CFLAGS += $(call cc-disable-warning, packed-not-aligned) @@ -47,9 +47,20 @@ else ifdef CONFIG_CC_IS_CLANG KBUILD_CFLAGS += -Wno-initializer-overrides +# Clang before clang-16 would warn on default argument promotions. +ifeq ($(shell [ $(CONFIG_CLANG_VERSION) -lt 160000 ] && echo y),y) +# Disable -Wformat KBUILD_CFLAGS += -Wno-format +# Then re-enable flags that were part of the -Wformat group that aren't +# problematic. +KBUILD_CFLAGS += -Wformat-extra-args -Wformat-invalid-specifier +KBUILD_CFLAGS += -Wformat-zero-length -Wnonnull +# Requires clang-12+. +ifeq ($(shell [ $(CONFIG_CLANG_VERSION) -ge 120000 ] && echo y),y) +KBUILD_CFLAGS += -Wformat-insufficient-args +endif +endif KBUILD_CFLAGS += -Wno-sign-compare -KBUILD_CFLAGS += -Wno-format-zero-length KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast) KBUILD_CFLAGS += -Wno-tautological-constant-out-of-range-compare KBUILD_CFLAGS += $(call cc-disable-warning, unaligned-access) @@ -94,3 +105,12 @@ KBUILD_CFLAGS += $(call cc-option, -Wpacked-bitfield-compat) KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN3 endif + +# +# W=e - error out on warnings +# +ifneq ($(findstring e, $(KBUILD_EXTRA_WARN)),) + +KBUILD_CFLAGS += -Werror + +endif diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins index f67153b260..e4deaf5fa5 100644 --- a/scripts/Makefile.gcc-plugins +++ b/scripts/Makefile.gcc-plugins @@ -4,12 +4,10 @@ gcc-plugin-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += latent_entropy_plugin.so gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) \ += -DLATENT_ENTROPY_PLUGIN ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY - DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable + DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable -ULATENT_ENTROPY_PLUGIN endif export DISABLE_LATENT_ENTROPY_PLUGIN -gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so - gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) \ += -fplugin-arg-structleak_plugin-verbose @@ -24,12 +22,6 @@ export DISABLE_STRUCTLEAK_PLUGIN gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) \ += -DSTRUCTLEAK_PLUGIN -gcc-plugin-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += randomize_layout_plugin.so -gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) \ - += -DRANDSTRUCT_PLUGIN -gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) \ - += -fplugin-arg-randomize_layout_plugin-performance-mode - gcc-plugin-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak_plugin.so gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \ += -DSTACKLEAK_PLUGIN @@ -53,13 +45,19 @@ export DISABLE_ARM_SSP_PER_TASK_PLUGIN # All the plugin CFLAGS are collected here in case a build target needs to # filter them out of the KBUILD_CFLAGS. GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) -# The sancov_plugin.so is included via CFLAGS_KCOV, so it is removed here. -GCC_PLUGINS_CFLAGS := $(filter-out %/sancov_plugin.so, $(GCC_PLUGINS_CFLAGS)) export GCC_PLUGINS_CFLAGS # Add the flags to the build! KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) -# All enabled GCC plugins are collected here for building below. -GCC_PLUGIN := $(gcc-plugin-y) +# Some plugins are enabled outside of this Makefile, but they still need to +# be included in GCC_PLUGIN so they can get built. +gcc-plugin-external-$(CONFIG_GCC_PLUGIN_SANCOV) \ + += sancov_plugin.so +gcc-plugin-external-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) \ + += randomize_layout_plugin.so + +# All enabled GCC plugins are collected here for building in +# scripts/gcc-scripts/Makefile. +GCC_PLUGIN := $(gcc-plugin-y) $(gcc-plugin-external-y) export GCC_PLUGIN diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index bc00eaab72..2bf7db80ad 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -225,20 +225,40 @@ dtc_cpp_flags = -Wp,-MMD,$(depfile).pre.tmp -nostdinc \ $(addprefix -I,$(DTC_INCLUDE)) \ -undef -D__DTS__ -ifneq ($(CONFIG_LTO_CLANG)$(CONFIG_X86_KERNEL_IBT),) -# With CONFIG_LTO_CLANG, .o files in modules might be LLVM bitcode, so we -# need to run LTO to compile them into native code (.lto.o) before further -# processing. -mod-prelink-ext := .prelink -endif +ifdef CONFIG_OBJTOOL + +objtool := $(objtree)/tools/objtool/objtool + +objtool_args = \ + $(if $(CONFIG_HAVE_JUMP_LABEL_HACK), --hacks=jump_label) \ + $(if $(CONFIG_HAVE_NOINSTR_HACK), --hacks=noinstr) \ + $(if $(CONFIG_X86_KERNEL_IBT), --ibt) \ + $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \ + $(if $(CONFIG_UNWINDER_ORC), --orc) \ + $(if $(CONFIG_RETPOLINE), --retpoline) \ + $(if $(CONFIG_RETHUNK), --rethunk) \ + $(if $(CONFIG_SLS), --sls) \ + $(if $(CONFIG_STACK_VALIDATION), --stackval) \ + $(if $(CONFIG_HAVE_STATIC_CALL_INLINE), --static-call) \ + $(if $(CONFIG_HAVE_UACCESS_VALIDATION), --uaccess) \ + $(if $(delay-objtool), --link) \ + $(if $(part-of-module), --module) \ + $(if $(CONFIG_GCOV_KERNEL), --no-unreachable) + +delay-objtool := $(or $(CONFIG_LTO_CLANG),$(CONFIG_X86_KERNEL_IBT)) + +cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@) +cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd) + +endif # CONFIG_OBJTOOL # Useful for describing the dependency of composite objects # Usage: # $(call multi_depend, multi_used_targets, suffix_to_remove, suffix_to_add) define multi_depend -$(foreach m, $(notdir $1), \ - $(eval $(obj)/$m: \ - $(addprefix $(obj)/, $(foreach s, $3, $($(m:%$(strip $2)=%$(s))))))) +$(foreach m, $1, \ + $(eval $m: \ + $(addprefix $(obj)/, $(call suffix-search, $(patsubst $(obj)/%,%,$m), $2, $3)))) endef # Copy a file diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 7f39599e9f..35100e981f 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -9,7 +9,7 @@ __modfinal: include include/config/auto.conf include $(srctree)/scripts/Kbuild.include -# for c_flags and mod-prelink-ext +# for c_flags include $(srctree)/scripts/Makefile.lib # find all modules listed in modules.order @@ -54,9 +54,8 @@ if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \ $(cmd); \ printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:) - # Re-generate module BTFs if either module's .ko or vmlinux changed -$(modules): %.ko: %$(mod-prelink-ext).o %.mod.o scripts/module.lds $(if $(KBUILD_BUILTIN),vmlinux) FORCE +$(modules): %.ko: %.o %.mod.o scripts/module.lds $(if $(KBUILD_BUILTIN),vmlinux) FORCE +$(call if_changed_except,ld_ko_o,vmlinux) ifdef CONFIG_DEBUG_INFO_BTF_MODULES +$(if $(newer-prereqs),$(call cmd,btf_ko)) diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index c2c43a0ecf..a4c987c237 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -18,6 +18,9 @@ INSTALL_MOD_DIR ?= extra dst := $(MODLIB)/$(INSTALL_MOD_DIR) endif +$(foreach x, % :, $(if $(findstring $x, $(dst)), \ + $(error module installation path cannot contain '$x'))) + suffix-y := suffix-$(CONFIG_MODULE_COMPRESS_GZIP) := .gz suffix-$(CONFIG_MODULE_COMPRESS_XZ) := .xz @@ -28,9 +31,6 @@ modules := $(patsubst $(extmod_prefix)%, $(dst)/%$(suffix-y), $(modules)) __modinst: $(modules) @: -quiet_cmd_none = - cmd_none = : - # # Installation # diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 48585c4d04..9116064963 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -41,9 +41,6 @@ __modpost: include include/config/auto.conf include $(srctree)/scripts/Kbuild.include -# for mod-prelink-ext -include $(srctree)/scripts/Makefile.lib - MODPOST = scripts/mod/modpost \ $(if $(CONFIG_MODVERSIONS),-m) \ $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \ @@ -87,8 +84,7 @@ obj := $(KBUILD_EXTMOD) src := $(obj) # Include the module's Makefile to find KBUILD_EXTRA_SYMBOLS -include $(if $(wildcard $(KBUILD_EXTMOD)/Kbuild), \ - $(KBUILD_EXTMOD)/Kbuild, $(KBUILD_EXTMOD)/Makefile) +include $(or $(wildcard $(src)/Kbuild), $(src)/Makefile) # modpost option for external modules MODPOST += -e @@ -118,8 +114,6 @@ $(input-symdump): @echo >&2 ' Modules may not have dependencies or modversions.' @echo >&2 ' You may get many unresolved symbol warnings.' -modules := $(sort $(shell cat $(MODORDER))) - # KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined symbols ifneq ($(KBUILD_MODPOST_WARN)$(filter-out $(existing-input-symdump), $(input-symdump)),) MODPOST += -w @@ -128,9 +122,9 @@ endif # Read out modules.order to pass in modpost. # Otherwise, allmodconfig would fail with "Argument list too long". quiet_cmd_modpost = MODPOST $@ - cmd_modpost = sed 's/\.ko$$/$(mod-prelink-ext)\.o/' $< | $(MODPOST) -T - + cmd_modpost = sed 's/ko$$/o/' $< | $(MODPOST) -T - -$(output-symdump): $(MODORDER) $(input-symdump) $(modules:.ko=$(mod-prelink-ext).o) FORCE +$(output-symdump): $(MODORDER) $(input-symdump) FORCE $(call if_changed,modpost) targets += $(output-symdump) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index 77b612183c..5017f6b2da 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -56,7 +56,7 @@ rpm-pkg: $(MAKE) clean $(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec $(call cmd,src_tar,$(KERNELPATH),kernel.spec) - +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz \ + +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE)-linux -ta $(KERNELPATH).tar.gz \ --define='_smp_mflags %{nil}' # binrpm-pkg @@ -66,7 +66,7 @@ binrpm-pkg: $(MAKE) -f $(srctree)/Makefile $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec +rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \ - $(UTS_MACHINE) -bb $(objtree)/binkernel.spec + $(UTS_MACHINE)-linux -bb $(objtree)/binkernel.spec PHONY += deb-pkg deb-pkg: diff --git a/scripts/adjust_autoksyms.sh b/scripts/adjust_autoksyms.sh index 59fdb875e8..f1b5ac8184 100644 --- a/scripts/adjust_autoksyms.sh +++ b/scripts/adjust_autoksyms.sh @@ -35,7 +35,7 @@ case "$KBUILD_VERBOSE" in esac # Generate a new symbol list file -$CONFIG_SHELL $srctree/scripts/gen_autoksyms.sh "$new_ksyms_file" +$CONFIG_SHELL $srctree/scripts/gen_autoksyms.sh --modorder "$new_ksyms_file" # Extract changes between old and new list and touch corresponding # dependency files. diff --git a/scripts/atomic/gen-atomic-fallback.sh b/scripts/atomic/gen-atomic-fallback.sh index 8e2da71f1d..3a07695e3c 100644 --- a/scripts/atomic/gen-atomic-fallback.sh +++ b/scripts/atomic/gen-atomic-fallback.sh @@ -164,41 +164,44 @@ gen_xchg_fallbacks() gen_try_cmpxchg_fallback() { + local cmpxchg="$1"; shift; local order="$1"; shift; cat < # ppc64le port by Breno Leitao +# riscv port by Wadim Mueller # # Usage: # objdump -d vmlinux | scripts/checkstack.pl [arch] @@ -108,6 +109,9 @@ my (@stack, $re, $dre, $sub, $x, $xs, $funcre, $min_stack); } elsif ($arch eq 'sparc' || $arch eq 'sparc64') { # f0019d10: 9d e3 bf 90 save %sp, -112, %sp $re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o; + } elsif ($arch =~ /^riscv(64)?$/) { + #ffffffff8036e868: c2010113 addi sp,sp,-992 + $re = qr/.*addi.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; } else { print("wrong or unknown architecture \"$arch\"\n"); exit diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh index 9dbab13329..f33e61aca9 100644 --- a/scripts/checksyscalls.sh +++ b/scripts/checksyscalls.sh @@ -268,4 +268,4 @@ syscall_list() { } (ignore_list && syscall_list $(dirname $0)/../arch/x86/entry/syscalls/syscall_32.tbl) | \ -$* -Wno-error -E -x c - > /dev/null +$* -Wno-error -Wno-unused-macros -E -x c - > /dev/null diff --git a/scripts/clang-tools/gen_compile_commands.py b/scripts/clang-tools/gen_compile_commands.py index 1d1bde1fd4..47da25b3ba 100644 --- a/scripts/clang-tools/gen_compile_commands.py +++ b/scripts/clang-tools/gen_compile_commands.py @@ -157,10 +157,10 @@ def cmdfiles_for_modorder(modorder): if ext != '.ko': sys.exit('{}: module path must end with .ko'.format(ko)) mod = base + '.mod' - # The first line of *.mod lists the objects that compose the module. + # Read from *.mod, to get a list of objects that compose the module. with open(mod) as m: - for obj in m.readline().split(): - yield to_cmdfile(obj) + for mod_line in m: + yield to_cmdfile(mod_line.rstrip()) def process_line(root_directory, command_prefix, file_path): diff --git a/scripts/clang-tools/run-clang-tools.py b/scripts/clang-tools/run-clang-tools.py index f754415af3..1337cedca0 100644 --- a/scripts/clang-tools/run-clang-tools.py +++ b/scripts/clang-tools/run-clang-tools.py @@ -51,6 +51,7 @@ def run_analysis(entry): checks += "linuxkernel-*" else: checks += "clang-analyzer-*" + checks += ",-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling" p = subprocess.run(["clang-tidy", "-p", args.path, checks, entry["file"]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, diff --git a/scripts/coccinelle/api/alloc/zalloc-simple.cocci b/scripts/coccinelle/api/alloc/zalloc-simple.cocci index b3d0c3c230..d66c453566 100644 --- a/scripts/coccinelle/api/alloc/zalloc-simple.cocci +++ b/scripts/coccinelle/api/alloc/zalloc-simple.cocci @@ -10,7 +10,7 @@ // Copyright: (C) 2009-2010 Julia Lawall, Nicolas Palix, DIKU. // Copyright: (C) 2009-2010 Gilles Muller, INRIA/LiP6. // Copyright: (C) 2017 Himanshu Jha -// URL: http://coccinelle.lip6.fr/rules/kzalloc.html +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --no-includes --include-headers // // Keywords: kmalloc, kzalloc diff --git a/scripts/coccinelle/api/atomic_as_refcounter.cocci b/scripts/coccinelle/api/atomic_as_refcounter.cocci index 0f78d94abc..e63d52408b 100644 --- a/scripts/coccinelle/api/atomic_as_refcounter.cocci +++ b/scripts/coccinelle/api/atomic_as_refcounter.cocci @@ -5,7 +5,7 @@ // Copyright (c) 2016-2017, Elena Reshetova, Intel Corporation // // Confidence: Moderate -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --include-headers --very-quiet virtual report diff --git a/scripts/coccinelle/api/check_bq27xxx_data.cocci b/scripts/coccinelle/api/check_bq27xxx_data.cocci index fae539ef0c..27366c6169 100644 --- a/scripts/coccinelle/api/check_bq27xxx_data.cocci +++ b/scripts/coccinelle/api/check_bq27xxx_data.cocci @@ -6,7 +6,7 @@ /// // Confidence: High // Copyright: (C) 2017 Julia Lawall, Inria/LIP6, -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Requires: 1.0.7 // Keywords: BQ27XXX_DATA diff --git a/scripts/coccinelle/api/d_find_alias.cocci b/scripts/coccinelle/api/d_find_alias.cocci index 47e050166f..3489001378 100644 --- a/scripts/coccinelle/api/d_find_alias.cocci +++ b/scripts/coccinelle/api/d_find_alias.cocci @@ -4,7 +4,7 @@ // Keywords: d_find_alias, dput // // Confidence: Moderate -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --include-headers virtual context diff --git a/scripts/coccinelle/api/err_cast.cocci b/scripts/coccinelle/api/err_cast.cocci index 0e661c8d8d..7f9dc1212c 100644 --- a/scripts/coccinelle/api/err_cast.cocci +++ b/scripts/coccinelle/api/err_cast.cocci @@ -6,7 +6,7 @@ // Copyright: (C) 2009, 2010 Nicolas Palix, DIKU. // Copyright: (C) 2009, 2010 Julia Lawall, DIKU. // Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: // // Keywords: ERR_PTR, PTR_ERR, ERR_CAST diff --git a/scripts/coccinelle/api/kstrdup.cocci b/scripts/coccinelle/api/kstrdup.cocci index 3c6dc5469e..8a61534676 100644 --- a/scripts/coccinelle/api/kstrdup.cocci +++ b/scripts/coccinelle/api/kstrdup.cocci @@ -5,7 +5,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/api/memdup.cocci b/scripts/coccinelle/api/memdup.cocci index 30b15df734..d28741c698 100644 --- a/scripts/coccinelle/api/memdup.cocci +++ b/scripts/coccinelle/api/memdup.cocci @@ -5,7 +5,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/api/memdup_user.cocci b/scripts/coccinelle/api/memdup_user.cocci index e01e951084..03e7afa09e 100644 --- a/scripts/coccinelle/api/memdup_user.cocci +++ b/scripts/coccinelle/api/memdup_user.cocci @@ -6,7 +6,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/api/pm_runtime.cocci b/scripts/coccinelle/api/pm_runtime.cocci index 1ccce3fd00..4b97788744 100644 --- a/scripts/coccinelle/api/pm_runtime.cocci +++ b/scripts/coccinelle/api/pm_runtime.cocci @@ -4,7 +4,7 @@ // Keywords: pm_runtime // Confidence: Medium // Copyright (C) 2013 Texas Instruments Incorporated - -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --include-headers virtual patch diff --git a/scripts/coccinelle/api/resource_size.cocci b/scripts/coccinelle/api/resource_size.cocci index a9a571ac04..16857072d1 100644 --- a/scripts/coccinelle/api/resource_size.cocci +++ b/scripts/coccinelle/api/resource_size.cocci @@ -7,7 +7,7 @@ // Copyright: (C) 2009, 2010 Nicolas Palix, DIKU. // Copyright: (C) 2009, 2010 Julia Lawall, DIKU. // Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: // // Keywords: resource_size diff --git a/scripts/coccinelle/free/clk_put.cocci b/scripts/coccinelle/free/clk_put.cocci index 7237b49496..3c732cb721 100644 --- a/scripts/coccinelle/free/clk_put.cocci +++ b/scripts/coccinelle/free/clk_put.cocci @@ -8,7 +8,7 @@ // Confidence: Moderate // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: diff --git a/scripts/coccinelle/free/devm_free.cocci b/scripts/coccinelle/free/devm_free.cocci index da80050b91..0880729bad 100644 --- a/scripts/coccinelle/free/devm_free.cocci +++ b/scripts/coccinelle/free/devm_free.cocci @@ -17,7 +17,7 @@ // Confidence: Moderate // Copyright: (C) 2011 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2011 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/free/iounmap.cocci b/scripts/coccinelle/free/iounmap.cocci index 63b81d0c97..90d85fa7bf 100644 --- a/scripts/coccinelle/free/iounmap.cocci +++ b/scripts/coccinelle/free/iounmap.cocci @@ -8,7 +8,7 @@ // Confidence: Moderate // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: diff --git a/scripts/coccinelle/free/kfree.cocci b/scripts/coccinelle/free/kfree.cocci index 9b6e2037c2..6338bbac2f 100644 --- a/scripts/coccinelle/free/kfree.cocci +++ b/scripts/coccinelle/free/kfree.cocci @@ -9,7 +9,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/free/kfreeaddr.cocci b/scripts/coccinelle/free/kfreeaddr.cocci index 142af6337a..85635a36f0 100644 --- a/scripts/coccinelle/free/kfreeaddr.cocci +++ b/scripts/coccinelle/free/kfreeaddr.cocci @@ -3,7 +3,7 @@ /// // Confidence: High // Copyright: (C) 2013 Julia Lawall, INRIA/LIP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/free/pci_free_consistent.cocci b/scripts/coccinelle/free/pci_free_consistent.cocci index d51e92556b..e062b9ba09 100644 --- a/scripts/coccinelle/free/pci_free_consistent.cocci +++ b/scripts/coccinelle/free/pci_free_consistent.cocci @@ -3,7 +3,7 @@ /// // Confidence: Moderate // Copyright: (C) 2013 Petr Strnad. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Keywords: pci_free_consistent, pci_alloc_consistent // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/iterators/device_node_continue.cocci b/scripts/coccinelle/iterators/device_node_continue.cocci index f8cd14dfa6..5713c9cf59 100644 --- a/scripts/coccinelle/iterators/device_node_continue.cocci +++ b/scripts/coccinelle/iterators/device_node_continue.cocci @@ -4,7 +4,7 @@ /// // Confidence: High // Copyright: (C) 2015 Julia Lawall, Inria. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --no-includes --include-headers // Requires: 1.0.4 // Keywords: for_each_child_of_node, etc. diff --git a/scripts/coccinelle/iterators/for_each_child.cocci b/scripts/coccinelle/iterators/for_each_child.cocci index bc39461594..2ea98a61a1 100644 --- a/scripts/coccinelle/iterators/for_each_child.cocci +++ b/scripts/coccinelle/iterators/for_each_child.cocci @@ -5,7 +5,7 @@ /// // Confidence: High // Copyright: (C) 2020 Sumera Priyadarsini -// URL: http://coccinelle.lip6.fr +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --no-includes --include-headers virtual patch diff --git a/scripts/coccinelle/iterators/itnull.cocci b/scripts/coccinelle/iterators/itnull.cocci index 9b362b98d7..7d34802f27 100644 --- a/scripts/coccinelle/iterators/itnull.cocci +++ b/scripts/coccinelle/iterators/itnull.cocci @@ -10,7 +10,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/iterators/list_entry_update.cocci b/scripts/coccinelle/iterators/list_entry_update.cocci index d62e8a1608..9a7593667d 100644 --- a/scripts/coccinelle/iterators/list_entry_update.cocci +++ b/scripts/coccinelle/iterators/list_entry_update.cocci @@ -8,7 +8,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/iterators/use_after_iter.cocci b/scripts/coccinelle/iterators/use_after_iter.cocci index 676edd562e..f67110ba72 100644 --- a/scripts/coccinelle/iterators/use_after_iter.cocci +++ b/scripts/coccinelle/iterators/use_after_iter.cocci @@ -10,7 +10,7 @@ // Confidence: Moderate // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LIP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/locks/call_kern.cocci b/scripts/coccinelle/locks/call_kern.cocci index 5ca0d81b00..3720f86d67 100644 --- a/scripts/coccinelle/locks/call_kern.cocci +++ b/scripts/coccinelle/locks/call_kern.cocci @@ -8,7 +8,7 @@ // Copyright: (C) 2012 Nicolas Palix. // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/locks/double_lock.cocci b/scripts/coccinelle/locks/double_lock.cocci index 9e88a57895..619cfc7144 100644 --- a/scripts/coccinelle/locks/double_lock.cocci +++ b/scripts/coccinelle/locks/double_lock.cocci @@ -7,7 +7,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/locks/flags.cocci b/scripts/coccinelle/locks/flags.cocci index 7f990cd55f..44acf20a98 100644 --- a/scripts/coccinelle/locks/flags.cocci +++ b/scripts/coccinelle/locks/flags.cocci @@ -5,7 +5,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/locks/mini_lock.cocci b/scripts/coccinelle/locks/mini_lock.cocci index c3ad098f4a..71065d8a5d 100644 --- a/scripts/coccinelle/locks/mini_lock.cocci +++ b/scripts/coccinelle/locks/mini_lock.cocci @@ -10,7 +10,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/cstptr.cocci b/scripts/coccinelle/misc/cstptr.cocci index c52e3c8ca9..74acf34bee 100644 --- a/scripts/coccinelle/misc/cstptr.cocci +++ b/scripts/coccinelle/misc/cstptr.cocci @@ -5,7 +5,7 @@ // Confidence: High // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/doubleinit.cocci b/scripts/coccinelle/misc/doubleinit.cocci index 2f80d3ab38..7dbfde3f44 100644 --- a/scripts/coccinelle/misc/doubleinit.cocci +++ b/scripts/coccinelle/misc/doubleinit.cocci @@ -7,7 +7,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: requires at least Coccinelle 0.2.4, lex or parse error otherwise // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/ifcol.cocci b/scripts/coccinelle/misc/ifcol.cocci index da0351ed57..442742467c 100644 --- a/scripts/coccinelle/misc/ifcol.cocci +++ b/scripts/coccinelle/misc/ifcol.cocci @@ -12,7 +12,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/newline_in_nl_msg.cocci b/scripts/coccinelle/misc/newline_in_nl_msg.cocci index c175886e40..9baffe55d9 100644 --- a/scripts/coccinelle/misc/newline_in_nl_msg.cocci +++ b/scripts/coccinelle/misc/newline_in_nl_msg.cocci @@ -5,7 +5,7 @@ /// // Confidence: Very High // Copyright: (C) 2020 Intel Corporation -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --no-includes --include-headers virtual context diff --git a/scripts/coccinelle/misc/noderef.cocci b/scripts/coccinelle/misc/noderef.cocci index 72de62a77a..37ee7358d7 100644 --- a/scripts/coccinelle/misc/noderef.cocci +++ b/scripts/coccinelle/misc/noderef.cocci @@ -5,7 +5,7 @@ // Confidence: High // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/orplus.cocci b/scripts/coccinelle/misc/orplus.cocci index 52203dc2ca..3a1566f1ae 100644 --- a/scripts/coccinelle/misc/orplus.cocci +++ b/scripts/coccinelle/misc/orplus.cocci @@ -6,7 +6,7 @@ // Confidence: Moderate // Copyright: (C) 2013 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2013 Gilles Muller, INRIA/LIP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/returnvar.cocci b/scripts/coccinelle/misc/returnvar.cocci index ce0d9eebc7..7ffc55bf51 100644 --- a/scripts/coccinelle/misc/returnvar.cocci +++ b/scripts/coccinelle/misc/returnvar.cocci @@ -4,7 +4,7 @@ /// // Confidence: Moderate // Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: Comments on code can be deleted if near code that is removed. // "when strict" can be removed to get more hits, but adds false // positives diff --git a/scripts/coccinelle/misc/semicolon.cocci b/scripts/coccinelle/misc/semicolon.cocci index a53edb026d..4476bf873d 100644 --- a/scripts/coccinelle/misc/semicolon.cocci +++ b/scripts/coccinelle/misc/semicolon.cocci @@ -4,7 +4,7 @@ /// // Confidence: Moderate // Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: Some false positives on empty default cases in switch statements. // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/warn.cocci b/scripts/coccinelle/misc/warn.cocci index e379661e24..b5f428035d 100644 --- a/scripts/coccinelle/misc/warn.cocci +++ b/scripts/coccinelle/misc/warn.cocci @@ -4,7 +4,7 @@ // Confidence: High // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/null/badzero.cocci b/scripts/coccinelle/null/badzero.cocci index 882dd65313..35d443825c 100644 --- a/scripts/coccinelle/null/badzero.cocci +++ b/scripts/coccinelle/null/badzero.cocci @@ -10,7 +10,7 @@ // Confidence: High // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Requires: 1.0.0 // Options: diff --git a/scripts/coccinelle/null/deref_null.cocci b/scripts/coccinelle/null/deref_null.cocci index 98f1e7faf5..fdf098d4f5 100644 --- a/scripts/coccinelle/null/deref_null.cocci +++ b/scripts/coccinelle/null/deref_null.cocci @@ -7,7 +7,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: -I ... -all_includes can give more complete results // Options: diff --git a/scripts/coccinelle/null/eno.cocci b/scripts/coccinelle/null/eno.cocci index 81584ff879..7107d6c8db 100644 --- a/scripts/coccinelle/null/eno.cocci +++ b/scripts/coccinelle/null/eno.cocci @@ -5,7 +5,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/null/kmerr.cocci b/scripts/coccinelle/null/kmerr.cocci index d0e004d4e1..68db20de62 100644 --- a/scripts/coccinelle/null/kmerr.cocci +++ b/scripts/coccinelle/null/kmerr.cocci @@ -9,7 +9,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/tests/doublebitand.cocci b/scripts/coccinelle/tests/doublebitand.cocci index 0f0b94e7de..025436a150 100644 --- a/scripts/coccinelle/tests/doublebitand.cocci +++ b/scripts/coccinelle/tests/doublebitand.cocci @@ -9,7 +9,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/tests/doubletest.cocci b/scripts/coccinelle/tests/doubletest.cocci index b35519cddb..c3d94c3195 100644 --- a/scripts/coccinelle/tests/doubletest.cocci +++ b/scripts/coccinelle/tests/doubletest.cocci @@ -8,7 +8,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/tests/odd_ptr_err.cocci b/scripts/coccinelle/tests/odd_ptr_err.cocci index 11d4e2b6de..377436abe2 100644 --- a/scripts/coccinelle/tests/odd_ptr_err.cocci +++ b/scripts/coccinelle/tests/odd_ptr_err.cocci @@ -6,7 +6,7 @@ // Confidence: High // Copyright: (C) 2012, 2015 Julia Lawall, INRIA. // Copyright: (C) 2012, 2015 Gilles Muller, INRIA. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --no-includes --include-headers virtual patch diff --git a/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci b/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci index 91e286ace5..5e188c62d8 100644 --- a/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci +++ b/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci @@ -13,7 +13,7 @@ /// // Confidence: Average // Copyright: (C) 2015 Andrzej Hajda, Samsung Electronics Co., Ltd. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --all-includes virtual context diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh index 5fbad61fe4..7075e26ab2 100644 --- a/scripts/decode_stacktrace.sh +++ b/scripts/decode_stacktrace.sh @@ -45,8 +45,13 @@ else fi fi -declare -A cache -declare -A modcache +declare aarray_support=true +declare -A cache 2>/dev/null +if [[ $? != 0 ]]; then + aarray_support=false +else + declare -A modcache +fi find_module() { if [[ -n $debuginfod ]] ; then @@ -97,7 +102,7 @@ parse_symbol() { if [[ $module == "" ]] ; then local objfile=$vmlinux - elif [[ "${modcache[$module]+isset}" == "isset" ]]; then + elif [[ $aarray_support == true && "${modcache[$module]+isset}" == "isset" ]]; then local objfile=${modcache[$module]} else local objfile=$(find_module) @@ -105,7 +110,9 @@ parse_symbol() { echo "WARNING! Modules path isn't set, but is needed to parse this symbol" >&2 return fi - modcache[$module]=$objfile + if [[ $aarray_support == true ]]; then + modcache[$module]=$objfile + fi fi # Remove the englobing parenthesis @@ -125,7 +132,7 @@ parse_symbol() { # Use 'nm vmlinux' to figure out the base address of said symbol. # It's actually faster to call it every time than to load it # all into bash. - if [[ "${cache[$module,$name]+isset}" == "isset" ]]; then + if [[ $aarray_support == true && "${cache[$module,$name]+isset}" == "isset" ]]; then local base_addr=${cache[$module,$name]} else local base_addr=$(nm "$objfile" 2>/dev/null | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}') @@ -133,7 +140,9 @@ parse_symbol() { # address not found return fi - cache[$module,$name]="$base_addr" + if [[ $aarray_support == true ]]; then + cache[$module,$name]="$base_addr" + fi fi # Let's start doing the math to get the exact address into the # symbol. First, strip out the symbol total length. @@ -149,11 +158,13 @@ parse_symbol() { # Pass it to addr2line to get filename and line number # Could get more than one result - if [[ "${cache[$module,$address]+isset}" == "isset" ]]; then + if [[ $aarray_support == true && "${cache[$module,$address]+isset}" == "isset" ]]; then local code=${cache[$module,$address]} else local code=$(${CROSS_COMPILE}addr2line -i -e "$objfile" "$address" 2>/dev/null) - cache[$module,$address]=$code + if [[ $aarray_support == true ]]; then + cache[$module,$address]=$code + fi fi # addr2line doesn't return a proper error code if it fails, so diff --git a/scripts/dtc/include-prefixes/arc b/scripts/dtc/include-prefixes/arc index 5d21b5a69a..e69de29bb2 100644 --- a/scripts/dtc/include-prefixes/arc +++ b/scripts/dtc/include-prefixes/arc @@ -1 +0,0 @@ -../../../arch/arc/boot/dts \ No newline at end of file diff --git a/scripts/dtc/include-prefixes/arm b/scripts/dtc/include-prefixes/arm index eb14d4515a..e69de29bb2 100644 --- a/scripts/dtc/include-prefixes/arm +++ b/scripts/dtc/include-prefixes/arm @@ -1 +0,0 @@ -../../../arch/arm/boot/dts \ No newline at end of file diff --git a/scripts/dtc/include-prefixes/arm64 b/scripts/dtc/include-prefixes/arm64 index 275c42c21d..e69de29bb2 100644 --- a/scripts/dtc/include-prefixes/arm64 +++ b/scripts/dtc/include-prefixes/arm64 @@ -1 +0,0 @@ -../../../arch/arm64/boot/dts \ No newline at end of file diff --git a/scripts/dtc/include-prefixes/dt-bindings b/scripts/dtc/include-prefixes/dt-bindings index 04fdbb3af0..e69de29bb2 100644 --- a/scripts/dtc/include-prefixes/dt-bindings +++ b/scripts/dtc/include-prefixes/dt-bindings @@ -1 +0,0 @@ -../../../include/dt-bindings \ No newline at end of file diff --git a/scripts/dtc/include-prefixes/microblaze b/scripts/dtc/include-prefixes/microblaze index d9830330a2..e69de29bb2 100644 --- a/scripts/dtc/include-prefixes/microblaze +++ b/scripts/dtc/include-prefixes/microblaze @@ -1 +0,0 @@ -../../../arch/microblaze/boot/dts \ No newline at end of file diff --git a/scripts/dtc/include-prefixes/mips b/scripts/dtc/include-prefixes/mips index ae8d4948dc..e69de29bb2 100644 --- a/scripts/dtc/include-prefixes/mips +++ b/scripts/dtc/include-prefixes/mips @@ -1 +0,0 @@ -../../../arch/mips/boot/dts \ No newline at end of file diff --git a/scripts/dtc/include-prefixes/nios2 b/scripts/dtc/include-prefixes/nios2 index 51772336d1..e69de29bb2 100644 --- a/scripts/dtc/include-prefixes/nios2 +++ b/scripts/dtc/include-prefixes/nios2 @@ -1 +0,0 @@ -../../../arch/nios2/boot/dts \ No newline at end of file diff --git a/scripts/dtc/include-prefixes/openrisc b/scripts/dtc/include-prefixes/openrisc index 71c3bc75c5..e69de29bb2 100644 --- a/scripts/dtc/include-prefixes/openrisc +++ b/scripts/dtc/include-prefixes/openrisc @@ -1 +0,0 @@ -../../../arch/openrisc/boot/dts \ No newline at end of file diff --git a/scripts/dtc/include-prefixes/powerpc b/scripts/dtc/include-prefixes/powerpc index 7cd6ec16e8..e69de29bb2 100644 --- a/scripts/dtc/include-prefixes/powerpc +++ b/scripts/dtc/include-prefixes/powerpc @@ -1 +0,0 @@ -../../../arch/powerpc/boot/dts \ No newline at end of file diff --git a/scripts/dtc/include-prefixes/sh b/scripts/dtc/include-prefixes/sh index 67d37808c5..e69de29bb2 100644 --- a/scripts/dtc/include-prefixes/sh +++ b/scripts/dtc/include-prefixes/sh @@ -1 +0,0 @@ -../../../arch/sh/boot/dts \ No newline at end of file diff --git a/scripts/dtc/include-prefixes/xtensa b/scripts/dtc/include-prefixes/xtensa index d1eaf6ec7a..e69de29bb2 100644 --- a/scripts/dtc/include-prefixes/xtensa +++ b/scripts/dtc/include-prefixes/xtensa @@ -1 +0,0 @@ -../../../arch/xtensa/boot/dts \ No newline at end of file diff --git a/scripts/dummy-tools/gcc b/scripts/dummy-tools/gcc index b2483149bb..1db1889f6d 100644 --- a/scripts/dummy-tools/gcc +++ b/scripts/dummy-tools/gcc @@ -59,7 +59,7 @@ fi if arg_contain -E "$@"; then # For scripts/cc-version.sh; This emulates GCC 20.0.0 if arg_contain - "$@"; then - sed -n '/^GCC/{s/__GNUC__/20/; s/__GNUC_MINOR__/0/; s/__GNUC_PATCHLEVEL__/0/; p;}' + sed -n '/^GCC/{s/__GNUC__/20/; s/__GNUC_MINOR__/0/; s/__GNUC_PATCHLEVEL__/0/; p;}; s/__LONG_DOUBLE_128__/1/ p' exit 0 else echo "no input files" >&2 @@ -96,12 +96,8 @@ fi # To set GCC_PLUGINS if arg_contain -print-file-name=plugin "$@"; then - plugin_dir=$(mktemp -d) - - mkdir -p $plugin_dir/include - touch $plugin_dir/include/plugin-version.h - - echo $plugin_dir + # Use $0 to find the in-tree dummy directory + echo "$(dirname "$(readlink -f "$0")")/dummy-plugin-dir" exit 0 fi diff --git a/scripts/dummy-tools/nm b/scripts/dummy-tools/nm index f682330504..e69de29bb2 100644 --- a/scripts/dummy-tools/nm +++ b/scripts/dummy-tools/nm @@ -1,30 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0-only - -# Dummy script that always succeeds. - -# Check if the first parameter appears in the rest. Succeeds if found. -# This helper is useful if a particular option was passed to this script. -# Typically used like this: -# arg_contain "$@" -arg_contain () -{ - search="$1" - shift - - while [ $# -gt 0 ] - do - if [ "$search" = "$1" ]; then - return 0 - fi - shift - done - - return 1 -} - -if arg_contain --version "$@" || arg_contain -v "$@"; then - progname=$(basename $0) - echo "GNU $progname (scripts/dummy-tools/$progname) 2.50" - exit 0 -fi diff --git a/scripts/dummy-tools/objcopy b/scripts/dummy-tools/objcopy index f682330504..e69de29bb2 100644 --- a/scripts/dummy-tools/objcopy +++ b/scripts/dummy-tools/objcopy @@ -1,30 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0-only - -# Dummy script that always succeeds. - -# Check if the first parameter appears in the rest. Succeeds if found. -# This helper is useful if a particular option was passed to this script. -# Typically used like this: -# arg_contain "$@" -arg_contain () -{ - search="$1" - shift - - while [ $# -gt 0 ] - do - if [ "$search" = "$1" ]; then - return 0 - fi - shift - done - - return 1 -} - -if arg_contain --version "$@" || arg_contain -v "$@"; then - progname=$(basename $0) - echo "GNU $progname (scripts/dummy-tools/$progname) 2.50" - exit 0 -fi diff --git a/scripts/faddr2line b/scripts/faddr2line index 6c6439f69a..5514c23f45 100644 --- a/scripts/faddr2line +++ b/scripts/faddr2line @@ -44,17 +44,6 @@ set -o errexit set -o nounset -READELF="${CROSS_COMPILE:-}readelf" -ADDR2LINE="${CROSS_COMPILE:-}addr2line" -SIZE="${CROSS_COMPILE:-}size" -NM="${CROSS_COMPILE:-}nm" - -command -v awk >/dev/null 2>&1 || die "awk isn't installed" -command -v ${READELF} >/dev/null 2>&1 || die "readelf isn't installed" -command -v ${ADDR2LINE} >/dev/null 2>&1 || die "addr2line isn't installed" -command -v ${SIZE} >/dev/null 2>&1 || die "size isn't installed" -command -v ${NM} >/dev/null 2>&1 || die "nm isn't installed" - usage() { echo "usage: faddr2line [--list] ..." >&2 exit 1 @@ -69,6 +58,15 @@ die() { exit 1 } +READELF="${CROSS_COMPILE:-}readelf" +ADDR2LINE="${CROSS_COMPILE:-}addr2line" +AWK="awk" +GREP="grep" + +command -v ${AWK} >/dev/null 2>&1 || die "${AWK} isn't installed" +command -v ${READELF} >/dev/null 2>&1 || die "${READELF} isn't installed" +command -v ${ADDR2LINE} >/dev/null 2>&1 || die "${ADDR2LINE} isn't installed" + # Try to figure out the source directory prefix so we can remove it from the # addr2line output. HACK ALERT: This assumes that start_kernel() is in # init/main.c! This only works for vmlinux. Otherwise it falls back to @@ -76,7 +74,7 @@ die() { find_dir_prefix() { local objfile=$1 - local start_kernel_addr=$(${READELF} -sW $objfile | awk '$8 == "start_kernel" {printf "0x%s", $2}') + local start_kernel_addr=$(${READELF} --symbols --wide $objfile | ${AWK} '$8 == "start_kernel" {printf "0x%s", $2}') [[ -z $start_kernel_addr ]] && return local file_line=$(${ADDR2LINE} -e $objfile $start_kernel_addr) @@ -97,86 +95,158 @@ __faddr2line() { local dir_prefix=$3 local print_warnings=$4 - local func=${func_addr%+*} - local offset=${func_addr#*+} - offset=${offset%/*} - local size= - [[ $func_addr =~ "/" ]] && size=${func_addr#*/} + local sym_name=${func_addr%+*} + local func_offset=${func_addr#*+} + func_offset=${func_offset%/*} + local user_size= + local file_type + local is_vmlinux=0 + [[ $func_addr =~ "/" ]] && user_size=${func_addr#*/} - if [[ -z $func ]] || [[ -z $offset ]] || [[ $func = $func_addr ]]; then + if [[ -z $sym_name ]] || [[ -z $func_offset ]] || [[ $sym_name = $func_addr ]]; then warn "bad func+offset $func_addr" DONE=1 return fi + # vmlinux uses absolute addresses in the section table rather than + # section offsets. + local file_type=$(${READELF} --file-header $objfile | + ${AWK} '$1 == "Type:" { print $2; exit }') + if [[ $file_type = "EXEC" ]] || [[ $file_type == "DYN" ]]; then + is_vmlinux=1 + fi + # Go through each of the object's symbols which match the func name. - # In rare cases there might be duplicates. - file_end=$(${SIZE} -Ax $objfile | awk '$1 == ".text" {print $2}') - while read symbol; do - local fields=($symbol) - local sym_base=0x${fields[0]} - local sym_type=${fields[1]} - local sym_end=${fields[3]} - - # calculate the size - local sym_size=$(($sym_end - $sym_base)) + # In rare cases there might be duplicates, in which case we print all + # matches. + while read line; do + local fields=($line) + local sym_addr=0x${fields[1]} + local sym_elf_size=${fields[2]} + local sym_sec=${fields[6]} + local sec_size + local sec_name + + # Get the section size: + sec_size=$(${READELF} --section-headers --wide $objfile | + sed 's/\[ /\[/' | + ${AWK} -v sec=$sym_sec '$1 == "[" sec "]" { print "0x" $6; exit }') + + if [[ -z $sec_size ]]; then + warn "bad section size: section: $sym_sec" + DONE=1 + return + fi + + # Get the section name: + sec_name=$(${READELF} --section-headers --wide $objfile | + sed 's/\[ /\[/' | + ${AWK} -v sec=$sym_sec '$1 == "[" sec "]" { print $2; exit }') + + if [[ -z $sec_name ]]; then + warn "bad section name: section: $sym_sec" + DONE=1 + return + fi + + # Calculate the symbol size. + # + # Unfortunately we can't use the ELF size, because kallsyms + # also includes the padding bytes in its size calculation. For + # kallsyms, the size calculation is the distance between the + # symbol and the next symbol in a sorted list. + local sym_size + local cur_sym_addr + local found=0 + while read line; do + local fields=($line) + cur_sym_addr=0x${fields[1]} + local cur_sym_elf_size=${fields[2]} + local cur_sym_name=${fields[7]:-} + + if [[ $cur_sym_addr = $sym_addr ]] && + [[ $cur_sym_elf_size = $sym_elf_size ]] && + [[ $cur_sym_name = $sym_name ]]; then + found=1 + continue + fi + + if [[ $found = 1 ]]; then + sym_size=$(($cur_sym_addr - $sym_addr)) + [[ $sym_size -lt $sym_elf_size ]] && continue; + found=2 + break + fi + done < <(${READELF} --symbols --wide $objfile | ${AWK} -v sec=$sym_sec '$7 == sec' | sort --key=2) + + if [[ $found = 0 ]]; then + warn "can't find symbol: sym_name: $sym_name sym_sec: $sym_sec sym_addr: $sym_addr sym_elf_size: $sym_elf_size" + DONE=1 + return + fi + + # If nothing was found after the symbol, assume it's the last + # symbol in the section. + [[ $found = 1 ]] && sym_size=$(($sec_size - $sym_addr)) + if [[ -z $sym_size ]] || [[ $sym_size -le 0 ]]; then - warn "bad symbol size: base: $sym_base end: $sym_end" + warn "bad symbol size: sym_addr: $sym_addr cur_sym_addr: $cur_sym_addr" DONE=1 return fi + sym_size=0x$(printf %x $sym_size) - # calculate the address - local addr=$(($sym_base + $offset)) + # Calculate the address from user-supplied offset: + local addr=$(($sym_addr + $func_offset)) if [[ -z $addr ]] || [[ $addr = 0 ]]; then - warn "bad address: $sym_base + $offset" + warn "bad address: $sym_addr + $func_offset" DONE=1 return fi addr=0x$(printf %x $addr) - # weed out non-function symbols - if [[ $sym_type != t ]] && [[ $sym_type != T ]]; then + # If the user provided a size, make sure it matches the symbol's size: + if [[ -n $user_size ]] && [[ $user_size -ne $sym_size ]]; then [[ $print_warnings = 1 ]] && - echo "skipping $func address at $addr due to non-function symbol of type '$sym_type'" - continue - fi - - # if the user provided a size, make sure it matches the symbol's size - if [[ -n $size ]] && [[ $size -ne $sym_size ]]; then - [[ $print_warnings = 1 ]] && - echo "skipping $func address at $addr due to size mismatch ($size != $sym_size)" + echo "skipping $sym_name address at $addr due to size mismatch ($user_size != $sym_size)" continue; fi - # make sure the provided offset is within the symbol's range - if [[ $offset -gt $sym_size ]]; then + # Make sure the provided offset is within the symbol's range: + if [[ $func_offset -gt $sym_size ]]; then [[ $print_warnings = 1 ]] && - echo "skipping $func address at $addr due to size mismatch ($offset > $sym_size)" + echo "skipping $sym_name address at $addr due to size mismatch ($func_offset > $sym_size)" continue fi - # separate multiple entries with a blank line + # In case of duplicates or multiple addresses specified on the + # cmdline, separate multiple entries with a blank line: [[ $FIRST = 0 ]] && echo FIRST=0 - # pass real address to addr2line - echo "$func+$offset/$sym_size:" - local file_lines=$(${ADDR2LINE} -fpie $objfile $addr | sed "s; $dir_prefix\(\./\)*; ;") - [[ -z $file_lines ]] && return + echo "$sym_name+$func_offset/$sym_size:" + # Pass section address to addr2line and strip absolute paths + # from the output: + local args="--functions --pretty-print --inlines --exe=$objfile" + [[ $is_vmlinux = 0 ]] && args="$args --section=$sec_name" + local output=$(${ADDR2LINE} $args $addr | sed "s; $dir_prefix\(\./\)*; ;") + [[ -z $output ]] && continue + + # Default output (non --list): if [[ $LIST = 0 ]]; then - echo "$file_lines" | while read -r line + echo "$output" | while read -r line do echo $line done DONE=1; - return + continue fi - # show each line with context - echo "$file_lines" | while read -r line + # For --list, show each line with its corresponding source code: + echo "$output" | while read -r line do echo echo $line @@ -184,12 +254,12 @@ __faddr2line() { n1=$[$n-5] n2=$[$n+5] f=$(echo $line | sed 's/.*at \(.\+\):.*/\1/g') - awk 'NR>=strtonum("'$n1'") && NR<=strtonum("'$n2'") { if (NR=='$n') printf(">%d<", NR); else printf(" %d ", NR); printf("\t%s\n", $0)}' $f + ${AWK} 'NR>=strtonum("'$n1'") && NR<=strtonum("'$n2'") { if (NR=='$n') printf(">%d<", NR); else printf(" %d ", NR); printf("\t%s\n", $0)}' $f done DONE=1 - done < <(${NM} -n $objfile | awk -v fn=$func -v end=$file_end '$3 == fn { found=1; line=$0; start=$1; next } found == 1 { found=0; print line, "0x"$1 } END {if (found == 1) print line, end; }') + done < <(${READELF} --symbols --wide $objfile | ${AWK} -v fn=$sym_name '$4 == "FUNC" && $8 == fn') } [[ $# -lt 2 ]] && usage @@ -202,6 +272,8 @@ LIST=0 [[ ! -f $objfile ]] && die "can't find objfile $objfile" shift +${READELF} --section-headers --wide $objfile | ${GREP} -q '\.debug_info' || die "CONFIG_DEBUG_INFO not enabled" + DIR_PREFIX=supercalifragilisticexpialidocious find_dir_prefix $objfile diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig index 51d81c3f03..e383cda053 100644 --- a/scripts/gcc-plugins/Kconfig +++ b/scripts/gcc-plugins/Kconfig @@ -46,44 +46,6 @@ config GCC_PLUGIN_LATENT_ENTROPY * https://grsecurity.net/ * https://pax.grsecurity.net/ -config GCC_PLUGIN_RANDSTRUCT - bool "Randomize layout of sensitive kernel structures" - select MODVERSIONS if MODULES - help - If you say Y here, the layouts of structures that are entirely - function pointers (and have not been manually annotated with - __no_randomize_layout), or structures that have been explicitly - marked with __randomize_layout, will be randomized at compile-time. - This can introduce the requirement of an additional information - exposure vulnerability for exploits targeting these structure - types. - - Enabling this feature will introduce some performance impact, - slightly increase memory usage, and prevent the use of forensic - tools like Volatility against the system (unless the kernel - source tree isn't cleaned after kernel installation). - - The seed used for compilation is located at - scripts/gcc-plugins/randomize_layout_seed.h. It remains after - a make clean to allow for external modules to be compiled with - the existing seed and will be removed by a make mrproper or - make distclean. - - This plugin was ported from grsecurity/PaX. More information at: - * https://grsecurity.net/ - * https://pax.grsecurity.net/ - -config GCC_PLUGIN_RANDSTRUCT_PERFORMANCE - bool "Use cacheline-aware structure randomization" - depends on GCC_PLUGIN_RANDSTRUCT - depends on !COMPILE_TEST # do not reduce test coverage - help - If you say Y here, the RANDSTRUCT randomization will make a - best effort at restricting randomization to cacheline-sized - groups of elements. It will further not randomize bitfields - in structures. This reduces the performance hit of RANDSTRUCT - at the cost of weakened randomization. - config GCC_PLUGIN_ARM_SSP_PER_TASK bool depends on GCC_PLUGINS && ARM diff --git a/scripts/gcc-plugins/Makefile b/scripts/gcc-plugins/Makefile index 1952d3bb80..b34d11e226 100644 --- a/scripts/gcc-plugins/Makefile +++ b/scripts/gcc-plugins/Makefile @@ -1,12 +1,17 @@ # SPDX-License-Identifier: GPL-2.0 -$(obj)/randomize_layout_plugin.so: $(objtree)/$(obj)/randomize_layout_seed.h -quiet_cmd_create_randomize_layout_seed = GENSEED $@ +$(obj)/randomize_layout_plugin.so: $(obj)/randomize_layout_seed.h +quiet_cmd_create_randomize_layout_seed = SEEDHDR $@ cmd_create_randomize_layout_seed = \ - $(CONFIG_SHELL) $(srctree)/$(src)/gen-random-seed.sh $@ $(objtree)/include/generated/randomize_layout_hash.h -$(objtree)/$(obj)/randomize_layout_seed.h: FORCE + SEED=$$(cat $(filter-out FORCE,$^) $@; \ + echo ' * This file is automatically generated. Keep it private.' >> $@; \ + echo ' * Exposing this value will expose the layout of randomized structures.' >> $@; \ + echo ' */' >> $@; \ + echo "const char *randstruct_seed = \"$$SEED\";" >> $@ +$(obj)/randomize_layout_seed.h: $(objtree)/scripts/basic/randstruct.seed FORCE $(call if_changed,create_randomize_layout_seed) -targets += randomize_layout_seed.h randomize_layout_hash.h +targets += randomize_layout_seed.h # Build rules for plugins # @@ -23,10 +28,11 @@ GCC_PLUGINS_DIR = $(shell $(CC) -print-file-name=plugin) plugin_cxxflags = -Wp,-MMD,$(depfile) $(KBUILD_HOSTCXXFLAGS) -fPIC \ -include $(srctree)/include/linux/compiler-version.h \ - -I $(GCC_PLUGINS_DIR)/include -I $(obj) -std=gnu++11 \ - -fno-rtti -fno-exceptions -fasynchronous-unwind-tables \ - -ggdb -Wno-narrowing -Wno-unused-variable \ - -Wno-format-diag + -DPLUGIN_VERSION=$(call stringify,$(KERNELVERSION)) \ + -I $(GCC_PLUGINS_DIR)/include -I $(obj) -std=gnu++11 \ + -fno-rtti -fno-exceptions -fasynchronous-unwind-tables \ + -ggdb -Wno-narrowing -Wno-unused-variable \ + -Wno-format-diag plugin_ldflags = -shared diff --git a/scripts/gcc-plugins/latent_entropy_plugin.c b/scripts/gcc-plugins/latent_entropy_plugin.c index 8425da41de..39e86be60d 100644 --- a/scripts/gcc-plugins/latent_entropy_plugin.c +++ b/scripts/gcc-plugins/latent_entropy_plugin.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2012-2016 by the PaX Team * Copyright 2016 by Emese Revfy - * Licensed under the GPL v2 * * Note: the choice of the license means that the compilation process is * NOT 'eligible' as defined by gcc's library exception to the GPL v3, @@ -82,7 +82,7 @@ __visible int plugin_is_GPL_compatible; static GTY(()) tree latent_entropy_decl; static struct plugin_info latent_entropy_plugin_info = { - .version = "201606141920vanilla", + .version = PLUGIN_VERSION, .help = "disable\tturn off latent entropy instrumentation\n", }; diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c index 334741a31d..951b74ba1b 100644 --- a/scripts/gcc-plugins/randomize_layout_plugin.c +++ b/scripts/gcc-plugins/randomize_layout_plugin.c @@ -34,29 +34,11 @@ __visible int plugin_is_GPL_compatible; static int performance_mode; static struct plugin_info randomize_layout_plugin_info = { - .version = "201402201816vanilla", + .version = PLUGIN_VERSION, .help = "disable\t\t\tdo not activate plugin\n" "performance-mode\tenable cacheline-aware layout randomization\n" }; -struct whitelist_entry { - const char *pathname; - const char *lhs; - const char *rhs; -}; - -static const struct whitelist_entry whitelist[] = { - /* NIU overloads mapping with page struct */ - { "drivers/net/ethernet/sun/niu.c", "page", "address_space" }, - /* unix_skb_parms via UNIXCB() buffer */ - { "net/unix/af_unix.c", "unix_skb_parms", "char" }, - /* big_key payload.data struct splashing */ - { "security/keys/big_key.c", "path", "void *" }, - /* walk struct security_hook_heads as an array of struct hlist_head */ - { "security/security.c", "hlist_head", "security_hook_heads" }, - { } -}; - /* from old Linux dcache.h */ static inline unsigned long partial_name_hash(unsigned long c, unsigned long prevhash) @@ -742,60 +724,6 @@ static void handle_local_var_initializers(void) } } -static bool type_name_eq(gimple stmt, const_tree type_tree, const char *wanted_name) -{ - const char *type_name; - - if (type_tree == NULL_TREE) - return false; - - switch (TREE_CODE(type_tree)) { - case RECORD_TYPE: - type_name = TYPE_NAME_POINTER(type_tree); - break; - case INTEGER_TYPE: - if (TYPE_PRECISION(type_tree) == CHAR_TYPE_SIZE) - type_name = "char"; - else { - INFORM(gimple_location(stmt), "found non-char INTEGER_TYPE cast comparison: %qT\n", type_tree); - debug_tree(type_tree); - return false; - } - break; - case POINTER_TYPE: - if (TREE_CODE(TREE_TYPE(type_tree)) == VOID_TYPE) { - type_name = "void *"; - break; - } else { - INFORM(gimple_location(stmt), "found non-void POINTER_TYPE cast comparison %qT\n", type_tree); - debug_tree(type_tree); - return false; - } - default: - INFORM(gimple_location(stmt), "unhandled cast comparison: %qT\n", type_tree); - debug_tree(type_tree); - return false; - } - - return strcmp(type_name, wanted_name) == 0; -} - -static bool whitelisted_cast(gimple stmt, const_tree lhs_tree, const_tree rhs_tree) -{ - const struct whitelist_entry *entry; - expanded_location xloc = expand_location(gimple_location(stmt)); - - for (entry = whitelist; entry->pathname; entry++) { - if (!strstr(xloc.file, entry->pathname)) - continue; - - if (type_name_eq(stmt, lhs_tree, entry->lhs) && type_name_eq(stmt, rhs_tree, entry->rhs)) - return true; - } - - return false; -} - /* * iterate over all statements to find "bad" casts: * those where the address of the start of a structure is cast @@ -872,10 +800,7 @@ static unsigned int find_bad_casts_execute(void) #ifndef __DEBUG_PLUGIN if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type))) #endif - { - if (!whitelisted_cast(stmt, ptr_lhs_type, ptr_rhs_type)) - MISMATCH(gimple_location(stmt), "rhs", ptr_lhs_type, ptr_rhs_type); - } + MISMATCH(gimple_location(stmt), "rhs", ptr_lhs_type, ptr_rhs_type); continue; } @@ -898,10 +823,7 @@ static unsigned int find_bad_casts_execute(void) #ifndef __DEBUG_PLUGIN if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type))) #endif - { - if (!whitelisted_cast(stmt, ptr_lhs_type, op0_type)) - MISMATCH(gimple_location(stmt), "op0", ptr_lhs_type, op0_type); - } + MISMATCH(gimple_location(stmt), "op0", ptr_lhs_type, op0_type); } else { const_tree ssa_name_var = SSA_NAME_VAR(rhs1); /* skip bogus type casts introduced by container_of */ @@ -911,10 +833,7 @@ static unsigned int find_bad_casts_execute(void) #ifndef __DEBUG_PLUGIN if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_rhs_type))) #endif - { - if (!whitelisted_cast(stmt, ptr_lhs_type, ptr_rhs_type)) - MISMATCH(gimple_location(stmt), "ssa", ptr_lhs_type, ptr_rhs_type); - } + MISMATCH(gimple_location(stmt), "ssa", ptr_lhs_type, ptr_rhs_type); } } diff --git a/scripts/gcc-plugins/sancov_plugin.c b/scripts/gcc-plugins/sancov_plugin.c index 23bd023a28..b76cb9c42c 100644 --- a/scripts/gcc-plugins/sancov_plugin.c +++ b/scripts/gcc-plugins/sancov_plugin.c @@ -26,7 +26,7 @@ __visible int plugin_is_GPL_compatible; tree sancov_fndecl; static struct plugin_info sancov_plugin_info = { - .version = "20160402", + .version = PLUGIN_VERSION, .help = "sancov plugin\n", }; diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/stackleak_plugin.c index 42f0252ee2..c5c2ce113c 100644 --- a/scripts/gcc-plugins/stackleak_plugin.c +++ b/scripts/gcc-plugins/stackleak_plugin.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2011-2017 by the PaX Team * Modified by Alexander Popov - * Licensed under the GPL v2 * * Note: the choice of the license means that the compilation process is * NOT 'eligible' as defined by gcc's library exception to the GPL v3, @@ -44,7 +44,7 @@ static bool verbose = false; static GTY(()) tree track_function_decl; static struct plugin_info stackleak_plugin_info = { - .version = "201707101337", + .version = PLUGIN_VERSION, .help = "track-min-size=nn\ttrack stack for functions with a stack frame size >= nn bytes\n" "arch=target_arch\tspecify target build arch\n" "disable\t\tdo not activate the plugin\n" diff --git a/scripts/gcc-plugins/structleak_plugin.c b/scripts/gcc-plugins/structleak_plugin.c index 74e3192883..d8c7442338 100644 --- a/scripts/gcc-plugins/structleak_plugin.c +++ b/scripts/gcc-plugins/structleak_plugin.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2013-2017 by PaX Team - * Licensed under the GPL v2 * * Note: the choice of the license means that the compilation process is * NOT 'eligible' as defined by gcc's library exception to the GPL v3, @@ -37,7 +37,7 @@ __visible int plugin_is_GPL_compatible; static struct plugin_info structleak_plugin_info = { - .version = "20190125vanilla", + .version = PLUGIN_VERSION, .help = "disable\tdo not activate plugin\n" "byref\tinit structs passed by reference\n" "byref-all\tinit anything passed by reference\n" diff --git a/scripts/gdb/linux/config.py b/scripts/gdb/linux/config.py index 90e1565b19..8843ab3cba 100644 --- a/scripts/gdb/linux/config.py +++ b/scripts/gdb/linux/config.py @@ -24,9 +24,9 @@ class LxConfigDump(gdb.Command): filename = arg try: - py_config_ptr = gdb.parse_and_eval("kernel_config_data + 8") - py_config_size = gdb.parse_and_eval( - "sizeof(kernel_config_data) - 1 - 8 * 2") + py_config_ptr = gdb.parse_and_eval("&kernel_config_data") + py_config_ptr_end = gdb.parse_and_eval("&kernel_config_data_end") + py_config_size = py_config_ptr_end - py_config_ptr except gdb.error as e: raise gdb.GdbError("Can't find config, enable CONFIG_IKCONFIG?") diff --git a/scripts/gdb/linux/dmesg.py b/scripts/gdb/linux/dmesg.py index d5983cf3db..c771831eb0 100644 --- a/scripts/gdb/linux/dmesg.py +++ b/scripts/gdb/linux/dmesg.py @@ -22,7 +22,6 @@ prb_desc_type = utils.CachedType("struct prb_desc") prb_desc_ring_type = utils.CachedType("struct prb_desc_ring") prb_data_ring_type = utils.CachedType("struct prb_data_ring") printk_ringbuffer_type = utils.CachedType("struct printk_ringbuffer") -atomic_long_type = utils.CachedType("atomic_long_t") class LxDmesg(gdb.Command): """Print Linux kernel log buffer.""" @@ -68,8 +67,6 @@ class LxDmesg(gdb.Command): off = prb_data_ring_type.get_type()['data'].bitpos // 8 text_data_addr = utils.read_ulong(text_data_ring, off) - counter_off = atomic_long_type.get_type()['counter'].bitpos // 8 - sv_off = prb_desc_type.get_type()['state_var'].bitpos // 8 off = prb_desc_type.get_type()['text_blk_lpos'].bitpos // 8 @@ -89,9 +86,9 @@ class LxDmesg(gdb.Command): # read in tail and head descriptor ids off = prb_desc_ring_type.get_type()['tail_id'].bitpos // 8 - tail_id = utils.read_u64(desc_ring, off + counter_off) + tail_id = utils.read_atomic_long(desc_ring, off) off = prb_desc_ring_type.get_type()['head_id'].bitpos // 8 - head_id = utils.read_u64(desc_ring, off + counter_off) + head_id = utils.read_atomic_long(desc_ring, off) did = tail_id while True: @@ -102,7 +99,7 @@ class LxDmesg(gdb.Command): desc = utils.read_memoryview(inf, desc_addr + desc_off, desc_sz).tobytes() # skip non-committed record - state = 3 & (utils.read_u64(desc, sv_off + counter_off) >> desc_flags_shift) + state = 3 & (utils.read_atomic_long(desc, sv_off) >> desc_flags_shift) if state != desc_committed and state != desc_finalized: if did == head_id: break diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py index 46f7542db0..dc07b6d12e 100644 --- a/scripts/gdb/linux/symbols.py +++ b/scripts/gdb/linux/symbols.py @@ -180,7 +180,7 @@ lx-symbols command.""" self.breakpoint.delete() self.breakpoint = None self.breakpoint = LoadModuleBreakpoint( - "kernel/module.c:do_init_module", self) + "kernel/module/main.c:do_init_module", self) else: gdb.write("Note: symbol update on module loading not supported " "with this gdb version\n") diff --git a/scripts/gdb/linux/utils.py b/scripts/gdb/linux/utils.py index ff7c1799d5..1553f68716 100644 --- a/scripts/gdb/linux/utils.py +++ b/scripts/gdb/linux/utils.py @@ -35,13 +35,12 @@ class CachedType: long_type = CachedType("long") - +atomic_long_type = CachedType("atomic_long_t") def get_long_type(): global long_type return long_type.get_type() - def offset_of(typeobj, field): element = gdb.Value(0).cast(typeobj) return int(str(element[field].address).split()[0], 16) @@ -129,6 +128,17 @@ def read_ulong(buffer, offset): else: return read_u32(buffer, offset) +atomic_long_counter_offset = atomic_long_type.get_type()['counter'].bitpos +atomic_long_counter_sizeof = atomic_long_type.get_type()['counter'].type.sizeof + +def read_atomic_long(buffer, offset): + global atomic_long_counter_offset + global atomic_long_counter_sizeof + + if atomic_long_counter_sizeof == 8: + return read_u64(buffer, offset + atomic_long_counter_offset) + else: + return read_u32(buffer, offset + atomic_long_counter_offset) target_arch = None diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py index 4136dc2c59..3e8d3669f0 100644 --- a/scripts/gdb/vmlinux-gdb.py +++ b/scripts/gdb/vmlinux-gdb.py @@ -13,7 +13,7 @@ import os -sys.path.insert(0, os.path.dirname(__file__) + "/scripts/gdb") +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)) + "/scripts/gdb") try: gdb.parse_and_eval("0") diff --git a/scripts/gen_autoksyms.sh b/scripts/gen_autoksyms.sh index 120225c541..653fadbad3 100644 --- a/scripts/gen_autoksyms.sh +++ b/scripts/gen_autoksyms.sh @@ -2,13 +2,10 @@ # SPDX-License-Identifier: GPL-2.0-only # Create an autoksyms.h header file from the list of all module's needed symbols -# as recorded on the second line of *.mod files and the user-provided symbol -# whitelist. +# as recorded in *.usyms files and the user-provided symbol whitelist. set -e -output_file="$1" - # Use "make V=1" to debug this script. case "$KBUILD_VERBOSE" in *1*) @@ -16,6 +13,15 @@ case "$KBUILD_VERBOSE" in ;; esac +read_modorder= + +if [ "$1" = --modorder ]; then + shift + read_modorder=1 +fi + +output_file="$1" + needed_symbols= # Special case for modversions (see modpost.c) @@ -41,10 +47,8 @@ cat > "$output_file" << EOT EOT -[ -f modules.order ] && modlist=modules.order || modlist=/dev/null - { - sed 's/ko$/mod/' $modlist | xargs -n1 sed -n -e '2p' + [ -n "${read_modorder}" ] && sed 's/ko$/usyms/' modules.order | xargs cat echo "$needed_symbols" [ -n "$ksym_wl" ] && cat "$ksym_wl" } | sed -e 's/ /\n/g' | sed -n -e '/^$/!p' | @@ -52,4 +56,7 @@ EOT # point addresses. sed -e 's/^\.//' | sort -u | +# Ignore __this_module. It's not an exported symbol, and will be resolved +# when the final .ko's are linked. +grep -v '^__this_module$' | sed -e 's/\(.*\)/#define __KSYM_\1 1/' >> "$output_file" diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index 4827c5abe5..f5dfdb9d80 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c @@ -33,7 +33,7 @@ char *cur_filename; int in_source_file; static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types, - flag_preserve, flag_warnings, flag_rel_crcs; + flag_preserve, flag_warnings; static int errors; static int nsyms; @@ -680,11 +680,7 @@ void export_symbol(const char *name) if (flag_dump_defs) fputs(">\n", debugfile); - /* Used as a linker script. */ - printf(!flag_rel_crcs ? "__crc_%s = 0x%08lx;\n" : - "SECTIONS { .rodata : ALIGN(4) { " - "__crc_%s = .; LONG(0x%08lx); } }\n", - name, crc); + printf("#SYMVER %s 0x%08lx\n", name, crc); } } @@ -733,7 +729,6 @@ static void genksyms_usage(void) " -q, --quiet Disable warnings (default)\n" " -h, --help Print this message\n" " -V, --version Print the release version\n" - " -R, --relative-crc Emit section relative symbol CRCs\n" #else /* __GNU_LIBRARY__ */ " -s Select symbol prefix\n" " -d Increment the debug level (repeatable)\n" @@ -745,7 +740,6 @@ static void genksyms_usage(void) " -q Disable warnings (default)\n" " -h Print this message\n" " -V Print the release version\n" - " -R Emit section relative symbol CRCs\n" #endif /* __GNU_LIBRARY__ */ , stderr); } @@ -766,14 +760,13 @@ int main(int argc, char **argv) {"preserve", 0, 0, 'p'}, {"version", 0, 0, 'V'}, {"help", 0, 0, 'h'}, - {"relative-crc", 0, 0, 'R'}, {0, 0, 0, 0} }; - while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR", + while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph", &long_opts[0], NULL)) != EOF) #else /* __GNU_LIBRARY__ */ - while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF) + while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF) #endif /* __GNU_LIBRARY__ */ switch (o) { case 'd': @@ -813,9 +806,6 @@ int main(int argc, char **argv) case 'h': genksyms_usage(); return 0; - case 'R': - flag_rel_crcs = 1; - break; default: genksyms_usage(); return 1; diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl index 1389db76cf..0ffd553124 100644 --- a/scripts/get_abi.pl +++ b/scripts/get_abi.pl @@ -981,11 +981,11 @@ __END__ =head1 NAME -abi_book.pl - parse the Linux ABI files and produce a ReST book. +get_abi.pl - parse the Linux ABI files and produce a ReST book. =head1 SYNOPSIS -B [--debug ] [--enable-lineno] [--man] [--help] +B [--debug ] [--enable-lineno] [--man] [--help] [--(no-)rst-source] [--dir=] [--show-hints] [--search-string ] [] diff --git a/scripts/get_feat.pl b/scripts/get_feat.pl index 76cfb96b59..5c5397eeb2 100644 --- a/scripts/get_feat.pl +++ b/scripts/get_feat.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl # SPDX-License-Identifier: GPL-2.0 use strict; diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 6bd5221d37..ab123b498f 100644 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -983,6 +983,7 @@ sub get_maintainers { } foreach my $email (@file_emails) { + $email = mailmap_email($email); my ($name, $address) = parse_email($email); my $tmp_email = format_email($name, $address, $email_usename); diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh index dd554bd436..4041881746 100644 --- a/scripts/headers_install.sh +++ b/scripts/headers_install.sh @@ -70,7 +70,6 @@ configs=$(sed -e ' # # The format is : in each line. config_leak_ignores=" -arch/alpha/include/uapi/asm/setup.h:CONFIG_ALPHA_LEGACY_START_ADDRESS arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_16K arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_4K arch/arc/include/uapi/asm/swab.h:CONFIG_ARC_HAS_SWAPE @@ -84,7 +83,6 @@ arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_SUPPORT arch/x86/include/uapi/asm/auxvec.h:CONFIG_IA32_EMULATION arch/x86/include/uapi/asm/auxvec.h:CONFIG_X86_64 arch/x86/include/uapi/asm/mman.h:CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS -include/uapi/asm-generic/fcntl.h:CONFIG_64BIT include/uapi/linux/atmdev.h:CONFIG_COMPAT include/uapi/linux/eventpoll.h:CONFIG_PM_SLEEP include/uapi/linux/hw_breakpoint.h:CONFIG_HAVE_MIXED_BREAKPOINTS_REGS diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 8caabddf81..f18e6dfc68 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -70,7 +70,7 @@ static unsigned char best_table_len[256]; static void usage(void) { - fprintf(stderr, "Usage: kallsyms [--all-symbols] " + fprintf(stderr, "Usage: kallsyms [--all-symbols] [--absolute-percpu] " "[--base-relative] < in.map > out.S\n"); exit(1); } @@ -111,7 +111,8 @@ static bool is_ignored_symbol(const char *name, char type) ".L", /* local labels, .LBB,.Ltmpxxx,.L__unnamed_xx,.LASANPC, etc. */ "__crc_", /* modversions */ "__efistub_", /* arm64 EFI stub namespace */ - "__kvm_nvhe_", /* arm64 non-VHE KVM namespace */ + "__kvm_nvhe_$", /* arm64 local symbols in non-VHE KVM namespace */ + "__kvm_nvhe_.L", /* arm64 local symbols in non-VHE KVM namespace */ "__AArch64ADRPThunk_", /* arm64 lld */ "__ARMV5PILongThunk_", /* arm lld */ "__ARMV7PILongThunk_", diff --git a/scripts/kconfig/gconf-cfg.sh b/scripts/kconfig/gconf-cfg.sh index 480ecd8b9f..cbd90c28c0 100644 --- a/scripts/kconfig/gconf-cfg.sh +++ b/scripts/kconfig/gconf-cfg.sh @@ -3,14 +3,14 @@ PKG="gtk+-2.0 gmodule-2.0 libglade-2.0" -if [ -z "$(command -v pkg-config)" ]; then +if [ -z "$(command -v ${HOSTPKG_CONFIG})" ]; then echo >&2 "*" - echo >&2 "* 'make gconfig' requires 'pkg-config'. Please install it." + echo >&2 "* 'make gconfig' requires '${HOSTPKG_CONFIG}'. Please install it." echo >&2 "*" exit 1 fi -if ! pkg-config --exists $PKG; then +if ! ${HOSTPKG_CONFIG} --exists $PKG; then echo >&2 "*" echo >&2 "* Unable to find the GTK+ installation. Please make sure that" echo >&2 "* the GTK+ 2.0 development package is correctly installed." @@ -19,12 +19,12 @@ if ! pkg-config --exists $PKG; then exit 1 fi -if ! pkg-config --atleast-version=2.0.0 gtk+-2.0; then +if ! ${HOSTPKG_CONFIG} --atleast-version=2.0.0 gtk+-2.0; then echo >&2 "*" echo >&2 "* GTK+ is present but version >= 2.0.0 is required." echo >&2 "*" exit 1 fi -echo cflags=\"$(pkg-config --cflags $PKG)\" -echo libs=\"$(pkg-config --libs $PKG)\" +echo cflags=\"$(${HOSTPKG_CONFIG} --cflags $PKG)\" +echo libs=\"$(${HOSTPKG_CONFIG} --libs $PKG)\" diff --git a/scripts/kconfig/mconf-cfg.sh b/scripts/kconfig/mconf-cfg.sh index b520e407a8..025b565e0b 100644 --- a/scripts/kconfig/mconf-cfg.sh +++ b/scripts/kconfig/mconf-cfg.sh @@ -4,16 +4,16 @@ PKG="ncursesw" PKG2="ncurses" -if [ -n "$(command -v pkg-config)" ]; then - if pkg-config --exists $PKG; then - echo cflags=\"$(pkg-config --cflags $PKG)\" - echo libs=\"$(pkg-config --libs $PKG)\" +if [ -n "$(command -v ${HOSTPKG_CONFIG})" ]; then + if ${HOSTPKG_CONFIG} --exists $PKG; then + echo cflags=\"$(${HOSTPKG_CONFIG} --cflags $PKG)\" + echo libs=\"$(${HOSTPKG_CONFIG} --libs $PKG)\" exit 0 fi - if pkg-config --exists $PKG2; then - echo cflags=\"$(pkg-config --cflags $PKG2)\" - echo libs=\"$(pkg-config --libs $PKG2)\" + if ${HOSTPKG_CONFIG} --exists $PKG2; then + echo cflags=\"$(${HOSTPKG_CONFIG} --cflags $PKG2)\" + echo libs=\"$(${HOSTPKG_CONFIG} --libs $PKG2)\" exit 0 fi fi @@ -46,7 +46,7 @@ echo >&2 "* Unable to find the ncurses package." echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev" echo >&2 "* depending on your distribution)." echo >&2 "*" -echo >&2 "* You may also need to install pkg-config to find the" +echo >&2 "* You may also need to install ${HOSTPKG_CONFIG} to find the" echo >&2 "* ncurses installed in a non-default location." echo >&2 "*" exit 1 diff --git a/scripts/kconfig/nconf-cfg.sh b/scripts/kconfig/nconf-cfg.sh index c212255070..3a10bac2ad 100644 --- a/scripts/kconfig/nconf-cfg.sh +++ b/scripts/kconfig/nconf-cfg.sh @@ -4,16 +4,16 @@ PKG="ncursesw menuw panelw" PKG2="ncurses menu panel" -if [ -n "$(command -v pkg-config)" ]; then - if pkg-config --exists $PKG; then - echo cflags=\"$(pkg-config --cflags $PKG)\" - echo libs=\"$(pkg-config --libs $PKG)\" +if [ -n "$(command -v ${HOSTPKG_CONFIG})" ]; then + if ${HOSTPKG_CONFIG} --exists $PKG; then + echo cflags=\"$(${HOSTPKG_CONFIG} --cflags $PKG)\" + echo libs=\"$(${HOSTPKG_CONFIG} --libs $PKG)\" exit 0 fi - if pkg-config --exists $PKG2; then - echo cflags=\"$(pkg-config --cflags $PKG2)\" - echo libs=\"$(pkg-config --libs $PKG2)\" + if ${HOSTPKG_CONFIG} --exists $PKG2; then + echo cflags=\"$(${HOSTPKG_CONFIG} --cflags $PKG2)\" + echo libs=\"$(${HOSTPKG_CONFIG} --libs $PKG2)\" exit 0 fi fi @@ -44,7 +44,7 @@ echo >&2 "* Unable to find the ncurses package." echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev" echo >&2 "* depending on your distribution)." echo >&2 "*" -echo >&2 "* You may also need to install pkg-config to find the" +echo >&2 "* You may also need to install ${HOSTPKG_CONFIG} to find the" echo >&2 "* ncurses installed in a non-default location." echo >&2 "*" exit 1 diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 7b371bd7fb..3ba8b1af39 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -52,8 +52,8 @@ static const char nconf_global_help[] = "\n" "Menu navigation keys\n" "----------------------------------------------------------------------\n" -"Linewise up \n" -"Linewise down \n" +"Linewise up \n" +"Linewise down \n" "Pagewise up \n" "Pagewise down \n" "First entry \n" @@ -1105,9 +1105,11 @@ static void conf(struct menu *menu) break; switch (res) { case KEY_DOWN: + case 'j': menu_driver(curses_menu, REQ_DOWN_ITEM); break; case KEY_UP: + case 'k': menu_driver(curses_menu, REQ_UP_ITEM); break; case KEY_NPAGE: @@ -1287,9 +1289,11 @@ static void conf_choice(struct menu *menu) break; switch (res) { case KEY_DOWN: + case 'j': menu_driver(curses_menu, REQ_DOWN_ITEM); break; case KEY_UP: + case 'k': menu_driver(curses_menu, REQ_UP_ITEM); break; case KEY_NPAGE: diff --git a/scripts/kconfig/qconf-cfg.sh b/scripts/kconfig/qconf-cfg.sh index fa564cd795..ad652cb539 100644 --- a/scripts/kconfig/qconf-cfg.sh +++ b/scripts/kconfig/qconf-cfg.sh @@ -3,22 +3,23 @@ PKG="Qt5Core Qt5Gui Qt5Widgets" -if [ -z "$(command -v pkg-config)" ]; then +if [ -z "$(command -v ${HOSTPKG_CONFIG})" ]; then echo >&2 "*" - echo >&2 "* 'make xconfig' requires 'pkg-config'. Please install it." + echo >&2 "* 'make xconfig' requires '${HOSTPKG_CONFIG}'. Please install it." echo >&2 "*" exit 1 fi -if pkg-config --exists $PKG; then - echo cflags=\"-std=c++11 -fPIC $(pkg-config --cflags $PKG)\" - echo libs=\"$(pkg-config --libs $PKG)\" - echo moc=\"$(pkg-config --variable=host_bins Qt5Core)/moc\" +if ${HOSTPKG_CONFIG} --exists $PKG; then + echo cflags=\"-std=c++11 -fPIC $(${HOSTPKG_CONFIG} --cflags $PKG)\" + echo libs=\"$(${HOSTPKG_CONFIG} --libs $PKG)\" + echo moc=\"$(${HOSTPKG_CONFIG} --variable=host_bins Qt5Core)/moc\" exit 0 fi echo >&2 "*" -echo >&2 "* Could not find Qt5 via pkg-config." +echo >&2 "* Could not find Qt5 via ${HOSTPKG_CONFIG}." echo >&2 "* Please install Qt5 and make sure it's in PKG_CONFIG_PATH" +echo >&2 "* You need $PKG" echo >&2 "*" exit 1 diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 7516949bb0..aea04365bc 100644 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -427,6 +427,13 @@ sub print_lineno { print ".. LINENO " . $lineno . "\n"; } } + +sub emit_warning { + my $location = shift; + my $msg = shift; + print STDERR "$location: warning: $msg"; + ++$warnings; +} ## # dumps section contents to arrays/hashes intended for that purpose. # @@ -451,8 +458,7 @@ sub dump_section { if (defined($sections{$name}) && ($sections{$name} ne "")) { # Only warn on user specified duplicate section names. if ($name ne $section_default) { - print STDERR "${file}:$.: warning: duplicate section name '$name'\n"; - ++$warnings; + emit_warning("${file}:$.", "duplicate section name '$name'\n"); } $sections{$name} .= $contents; } else { @@ -1094,7 +1100,7 @@ sub dump_struct($$) { if ($members) { if ($identifier ne $declaration_name) { - print STDERR "${file}:$.: warning: expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n"; + emit_warning("${file}:$.", "expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n"); return; } @@ -1298,9 +1304,9 @@ sub dump_enum($$) { if ($members) { if ($identifier ne $declaration_name) { if ($identifier eq "") { - print STDERR "${file}:$.: warning: wrong kernel-doc identifier on line:\n"; + emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n"); } else { - print STDERR "${file}:$.: warning: expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n"; + emit_warning("${file}:$.", "expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n"); } return; } @@ -1316,7 +1322,7 @@ sub dump_enum($$) { if (!$parameterdescs{$arg}) { $parameterdescs{$arg} = $undescribed; if (show_warnings("enum", $declaration_name)) { - print STDERR "${file}:$.: warning: Enum value '$arg' not described in enum '$declaration_name'\n"; + emit_warning("${file}:$.", "Enum value '$arg' not described in enum '$declaration_name'\n"); } } $_members{$arg} = 1; @@ -1325,7 +1331,7 @@ sub dump_enum($$) { while (my ($k, $v) = each %parameterdescs) { if (!exists($_members{$k})) { if (show_warnings("enum", $declaration_name)) { - print STDERR "${file}:$.: warning: Excess enum value '$k' description in '$declaration_name'\n"; + emit_warning("${file}:$.", "Excess enum value '$k' description in '$declaration_name'\n"); } } } @@ -1367,7 +1373,7 @@ sub dump_typedef($$) { $return_type =~ s/^\s+//; if ($identifier ne $declaration_name) { - print STDERR "${file}:$.: warning: expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"; + emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"); return; } @@ -1398,7 +1404,7 @@ sub dump_typedef($$) { $declaration_name = $1; if ($identifier ne $declaration_name) { - print STDERR "${file}:$.: warning: expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"; + emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"); return; } @@ -1554,9 +1560,7 @@ sub push_parameter($$$$$) { $parameterdescs{$param} = $undescribed; if (show_warnings($type, $declaration_name) && $param !~ /\./) { - print STDERR - "${file}:$.: warning: Function parameter or member '$param' not described in '$declaration_name'\n"; - ++$warnings; + emit_warning("${file}:$.", "Function parameter or member '$param' not described in '$declaration_name'\n"); } } @@ -1604,11 +1608,10 @@ sub check_sections($$$$$) { } if ($err) { if ($decl_type eq "function") { - print STDERR "${file}:$.: warning: " . + emit_warning("${file}:$.", "Excess function parameter " . "'$sects[$sx]' " . - "description in '$decl_name'\n"; - ++$warnings; + "description in '$decl_name'\n"); } } } @@ -1629,10 +1632,9 @@ sub check_return_section { if (!defined($sections{$section_return}) || $sections{$section_return} eq "") { - print STDERR "${file}:$.: warning: " . + emit_warning("${file}:$.", "No description found for return value of " . - "'$declaration_name'\n"; - ++$warnings; + "'$declaration_name'\n"); } } @@ -1714,12 +1716,12 @@ sub dump_function($$) { create_parameterlist($args, ',', $file, $declaration_name); } else { - print STDERR "${file}:$.: warning: cannot understand function prototype: '$prototype'\n"; + emit_warning("${file}:$.", "cannot understand function prototype: '$prototype'\n"); return; } if ($identifier ne $declaration_name) { - print STDERR "${file}:$.: warning: expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n"; + emit_warning("${file}:$.", "expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n"); return; } @@ -1801,8 +1803,8 @@ sub tracepoint_munge($) { $tracepointargs = $1; } if (($tracepointname eq 0) || ($tracepointargs eq 0)) { - print STDERR "${file}:$.: warning: Unrecognized tracepoint format: \n". - "$prototype\n"; + emit_warning("${file}:$.", "Unrecognized tracepoint format: \n". + "$prototype\n"); } else { $prototype = "static inline void trace_$tracepointname($tracepointargs)"; $identifier = "trace_$identifier"; @@ -2027,22 +2029,16 @@ sub process_name($$) { } if (!$is_kernel_comment) { - print STDERR "${file}:$.: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n"; - print STDERR $_; - ++$warnings; + emit_warning("${file}:$.", "This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n$_"); $state = STATE_NORMAL; } if (($declaration_purpose eq "") && $verbose) { - print STDERR "${file}:$.: warning: missing initial short description on line:\n"; - print STDERR $_; - ++$warnings; + emit_warning("${file}:$.", "missing initial short description on line:\n$_"); } if ($identifier eq "" && $decl_type ne "enum") { - print STDERR "${file}:$.: warning: wrong kernel-doc identifier on line:\n"; - print STDERR $_; - ++$warnings; + emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n$_"); $state = STATE_NORMAL; } @@ -2050,9 +2046,7 @@ sub process_name($$) { print STDERR "${file}:$.: info: Scanning doc for $decl_type $identifier\n"; } } else { - print STDERR "${file}:$.: warning: Cannot understand $_ on line $.", - " - I thought it was a doc line\n"; - ++$warnings; + emit_warning("${file}:$.", "Cannot understand $_ on line $. - I thought it was a doc line\n"); $state = STATE_NORMAL; } } @@ -2071,8 +2065,7 @@ sub process_body($$) { $section =~ s/\.\.\.$//; if ($verbose) { - print STDERR "${file}:$.: warning: Variable macro arguments should be documented without dots\n"; - ++$warnings; + emit_warning("${file}:$.", "Variable macro arguments should be documented without dots\n"); } } @@ -2101,8 +2094,7 @@ sub process_body($$) { if (($contents ne "") && ($contents ne "\n")) { if (!$in_doc_sect && $verbose) { - print STDERR "${file}:$.: warning: contents before sections\n"; - ++$warnings; + emit_warning("${file}:$.", "contents before sections\n"); } dump_section($file, $section, $contents); $section = $section_default; @@ -2128,8 +2120,7 @@ sub process_body($$) { } # look for doc_com + + doc_end: if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { - print STDERR "${file}:$.: warning: suspicious ending line: $_"; - ++$warnings; + emit_warning("${file}:$.", "suspicious ending line: $_"); } $prototype = ""; @@ -2173,8 +2164,7 @@ sub process_body($$) { } } else { # i dont know - bad line? ignore. - print STDERR "${file}:$.: warning: bad line: $_"; - ++$warnings; + emit_warning("${file}:$.", "bad line: $_"); } } @@ -2268,9 +2258,7 @@ sub process_inline($$) { } } elsif ($inline_doc_state == STATE_INLINE_NAME) { $inline_doc_state = STATE_INLINE_ERROR; - print STDERR "${file}:$.: warning: "; - print STDERR "Incorrect use of kernel-doc format: $_"; - ++$warnings; + emit_warning("${file}:$.", "Incorrect use of kernel-doc format: $_"); } } } @@ -2319,11 +2307,11 @@ sub process_file($) { if ($initial_section_counter == $section_counter && $ output_mode ne "none") { if ($output_selection == OUTPUT_INCLUDE) { - print STDERR "${file}:1: warning: '$_' not found\n" + emit_warning("${file}:1", "'$_' not found\n") for keys %function_table; } else { - print STDERR "${file}:1: warning: no structured comments found\n"; + emit_warning("${file}:1", "no structured comments found\n"); } } close IN_FILE; diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 9361a1ef02..eecc1863e5 100644 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -45,118 +45,6 @@ info() printf " %-7s %s\n" "${1}" "${2}" } -# Generate a linker script to ensure correct ordering of initcalls. -gen_initcalls() -{ - info GEN .tmp_initcalls.lds - - ${PYTHON3} ${srctree}/scripts/jobserver-exec \ - ${PERL} ${srctree}/scripts/generate_initcall_order.pl \ - ${KBUILD_VMLINUX_OBJS} ${KBUILD_VMLINUX_LIBS} \ - > .tmp_initcalls.lds -} - -# If CONFIG_LTO_CLANG is selected, collect generated symbol versions into -# .tmp_symversions.lds -gen_symversions() -{ - info GEN .tmp_symversions.lds - rm -f .tmp_symversions.lds - - for o in ${KBUILD_VMLINUX_OBJS} ${KBUILD_VMLINUX_LIBS}; do - if [ -f ${o}.symversions ]; then - cat ${o}.symversions >> .tmp_symversions.lds - fi - done -} - -# Link of vmlinux.o used for section mismatch analysis -# ${1} output file -modpost_link() -{ - local objects - local lds="" - - objects="--whole-archive \ - ${KBUILD_VMLINUX_OBJS} \ - --no-whole-archive \ - --start-group \ - ${KBUILD_VMLINUX_LIBS} \ - --end-group" - - if is_enabled CONFIG_LTO_CLANG; then - gen_initcalls - lds="-T .tmp_initcalls.lds" - - if is_enabled CONFIG_MODVERSIONS; then - gen_symversions - lds="${lds} -T .tmp_symversions.lds" - fi - - # This might take a while, so indicate that we're doing - # an LTO link - info LTO ${1} - else - info LD ${1} - fi - - ${LD} ${KBUILD_LDFLAGS} -r -o ${1} ${lds} ${objects} -} - -objtool_link() -{ - local objtoolcmd; - local objtoolopt; - - if is_enabled CONFIG_STACK_VALIDATION && \ - ( is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT ); then - - # Don't perform vmlinux validation unless explicitly requested, - # but run objtool on vmlinux.o now that we have an object file. - if is_enabled CONFIG_UNWINDER_ORC; then - objtoolcmd="orc generate" - fi - - objtoolopt="${objtoolopt} --lto" - - if is_enabled CONFIG_X86_KERNEL_IBT; then - objtoolopt="${objtoolopt} --ibt" - fi - - if is_enabled CONFIG_FTRACE_MCOUNT_USE_OBJTOOL; then - objtoolopt="${objtoolopt} --mcount" - fi - fi - - if is_enabled CONFIG_VMLINUX_VALIDATION; then - objtoolopt="${objtoolopt} --noinstr" - fi - - if [ -n "${objtoolopt}" ]; then - if [ -z "${objtoolcmd}" ]; then - objtoolcmd="check" - fi - objtoolopt="${objtoolopt} --vmlinux" - if ! is_enabled CONFIG_FRAME_POINTER; then - objtoolopt="${objtoolopt} --no-fp" - fi - if is_enabled CONFIG_GCOV_KERNEL; then - objtoolopt="${objtoolopt} --no-unreachable" - fi - if is_enabled CONFIG_RETPOLINE; then - objtoolopt="${objtoolopt} --retpoline" - fi - if is_enabled CONFIG_X86_SMAP; then - objtoolopt="${objtoolopt} --uaccess" - fi - if is_enabled CONFIG_SLS; then - objtoolopt="${objtoolopt} --sls" - fi - info OBJTOOL ${1} - tools/objtool/objtool ${objtoolcmd} ${objtoolopt} ${1} - fi -} - # Link of vmlinux # ${1} - output file # ${2}, ${3}, ... - optional extra .o files @@ -183,6 +71,10 @@ vmlinux_link() libs="${KBUILD_VMLINUX_LIBS}" fi + if is_enabled CONFIG_MODULES; then + objs="${objs} .vmlinux.export.o" + fi + if [ "${SRCARCH}" = "um" ]; then wl=-Wl, ld="${CC}" @@ -302,15 +194,11 @@ sorttable() cleanup() { rm -f .btf.* - rm -f .tmp_System.map - rm -f .tmp_initcalls.lds - rm -f .tmp_symversions.lds - rm -f .tmp_vmlinux* rm -f System.map rm -f vmlinux rm -f vmlinux.map - rm -f vmlinux.o - rm -f .vmlinux.d + rm -f .vmlinux.objs + rm -f .vmlinux.export.c } # Use "make V=1" to debug this script @@ -339,8 +227,24 @@ fi; ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init need-builtin=1 #link vmlinux.o -modpost_link vmlinux.o -objtool_link vmlinux.o +${MAKE} -f "${srctree}/scripts/Makefile.vmlinux_o" + +# Generate the list of in-tree objects in vmlinux +# +# This is used to retrieve symbol versions generated by genksyms. +for f in ${KBUILD_VMLINUX_OBJS} ${KBUILD_VMLINUX_LIBS}; do + case ${f} in + *libgcc.a) + # Some architectures do '$(CC) --print-libgcc-file-name' to + # borrow libgcc.a from the toolchain. + # There is no EXPORT_SYMBOL in external objects. Ignore this. + ;; + *.a) + ${AR} t ${f} ;; + *) + echo ${f} ;; + esac +done > .vmlinux.objs # modpost vmlinux.o to check for section mismatches ${MAKE} -f "${srctree}/scripts/Makefile.modpost" MODPOST_VMLINUX=1 @@ -352,6 +256,10 @@ info GEN modules.builtin tr '\0' '\n' < modules.builtin.modinfo | sed -n 's/^[[:alnum:]:_]*\.file=//p' | tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$/.ko/' > modules.builtin +if is_enabled CONFIG_MODULES; then + ${MAKE} -f "${srctree}/scripts/Makefile.vmlinux" .vmlinux.export.o +fi + btf_vmlinux_bin_o="" if is_enabled CONFIG_DEBUG_INFO_BTF; then btf_vmlinux_bin_o=.btf.vmlinux.bin.o diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh index 7c20252a90..250925aab1 100644 --- a/scripts/min-tool-version.sh +++ b/scripts/min-tool-version.sh @@ -24,9 +24,8 @@ icc) echo 16.0.3 ;; llvm) - # https://lore.kernel.org/r/YMtib5hKVyNknZt3@osiris/ if [ "$SRCARCH" = s390 ]; then - echo 13.0.0 + echo 14.0.0 else echo 11.0.0 fi diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 5258247d78..80d973144f 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -734,8 +734,6 @@ static int do_vio_entry(const char *filename, void *symval, return 1; } -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - static void do_input(char *alias, kernel_ulong_t *arr, unsigned int min, unsigned int max) { @@ -1391,6 +1389,15 @@ static int do_mhi_entry(const char *filename, void *symval, char *alias) return 1; } +/* Looks like: mhi_ep:S */ +static int do_mhi_ep_entry(const char *filename, void *symval, char *alias) +{ + DEF_FIELD_ADDR(symval, mhi_device_id, chan); + sprintf(alias, MHI_EP_DEVICE_MODALIAS_FMT, *chan); + + return 1; +} + /* Looks like: ishtp:{guid} */ static int do_ishtp_entry(const char *filename, void *symval, char *alias) { @@ -1519,6 +1526,7 @@ static const struct devtable devtable[] = { {"tee", SIZE_tee_client_device_id, do_tee_entry}, {"wmi", SIZE_wmi_device_id, do_wmi_entry}, {"mhi", SIZE_mhi_device_id, do_mhi_entry}, + {"mhi_ep", SIZE_mhi_device_id, do_mhi_ep_entry}, {"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry}, {"ssam", SIZE_ssam_device_id, do_ssam_entry}, {"dfl", SIZE_dfl_device_id, do_dfl_entry}, @@ -1563,9 +1571,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, zeros = calloc(1, sym->st_size); symval = zeros; } else { - symval = (void *)info->hdr - + info->sechdrs[get_secindex(info, sym)].sh_offset - + sym->st_value; + symval = sym_get_data(info, sym); } /* First handle the "special" cases */ diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index ed9d056d21..2c80da0220 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -13,6 +13,7 @@ #define _GNU_SOURCE #include +#include #include #include #include @@ -23,20 +24,20 @@ #include "../../include/linux/license.h" /* Are we using CONFIG_MODVERSIONS? */ -static int modversions = 0; +static bool modversions; /* Is CONFIG_MODULE_SRCVERSION_ALL set? */ -static int all_versions = 0; +static bool all_versions; /* If we are modposting external module set to 1 */ -static int external_module = 0; +static bool external_module; /* Only warn about unresolved symbols */ -static int warn_unresolved = 0; -/* How a symbol is exported */ -static int sec_mismatch_count = 0; -static int sec_mismatch_warn_only = true; +static bool warn_unresolved; + +static int sec_mismatch_count; +static bool sec_mismatch_warn_only = true; /* ignore missing files */ -static int ignore_missing_files; +static bool ignore_missing_files; /* If set to 1, only warn (instead of error) about missing ns imports */ -static int allow_missing_ns_imports; +static bool allow_missing_ns_imports; static bool error_occurred; @@ -47,12 +48,6 @@ static bool error_occurred; #define MAX_UNRESOLVED_REPORTS 10 static unsigned int nr_unresolved; -enum export { - export_plain, - export_gpl, - export_unknown -}; - /* In kernel, this size is defined in linux/module.h; * here we use Elf_Addr instead of long for covering cross-compile */ @@ -165,31 +160,43 @@ char *get_line(char **stringp) } /* A list of all modules we processed */ -static struct module *modules; +LIST_HEAD(modules); static struct module *find_module(const char *modname) { struct module *mod; - for (mod = modules; mod; mod = mod->next) + list_for_each_entry(mod, &modules, list) { if (strcmp(mod->name, modname) == 0) - break; - return mod; + return mod; + } + return NULL; } -static struct module *new_module(const char *modname) +static struct module *new_module(const char *name, size_t namelen) { struct module *mod; - mod = NOFAIL(malloc(sizeof(*mod) + strlen(modname) + 1)); + mod = NOFAIL(malloc(sizeof(*mod) + namelen + 1)); memset(mod, 0, sizeof(*mod)); - /* add to list */ - strcpy(mod->name, modname); - mod->is_vmlinux = (strcmp(modname, "vmlinux") == 0); - mod->gpl_compatible = -1; - mod->next = modules; - modules = mod; + INIT_LIST_HEAD(&mod->exported_symbols); + INIT_LIST_HEAD(&mod->unresolved_symbols); + INIT_LIST_HEAD(&mod->missing_namespaces); + INIT_LIST_HEAD(&mod->imported_namespaces); + + memcpy(mod->name, name, namelen); + mod->name[namelen] = '\0'; + mod->is_vmlinux = (strcmp(mod->name, "vmlinux") == 0); + + /* + * Set mod->is_gpl_compatible to true by default. If MODULE_LICENSE() + * is missing, do not check the use for EXPORT_SYMBOL_GPL() becasue + * modpost will exit wiht error anyway. + */ + mod->is_gpl_compatible = true; + + list_add_tail(&mod->list, &modules); return mod; } @@ -201,13 +208,13 @@ static struct module *new_module(const char *modname) struct symbol { struct symbol *next; + struct list_head list; /* link to module::exported_symbols or module::unresolved_symbols */ struct module *module; - unsigned int crc; - int crc_valid; char *namespace; - unsigned int weak:1; - unsigned int is_static:1; /* 1 if symbol is not global */ - enum export export; /* Type of export */ + unsigned int crc; + bool crc_valid; + bool weak; + bool is_gpl_only; /* exported by EXPORT_SYMBOL_GPL */ char name[]; }; @@ -230,32 +237,37 @@ static inline unsigned int tdb_hash(const char *name) * Allocate a new symbols for use in the hash of exported symbols or * the list of unresolved symbols per module **/ -static struct symbol *alloc_symbol(const char *name, unsigned int weak, - struct symbol *next) +static struct symbol *alloc_symbol(const char *name) { struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1)); memset(s, 0, sizeof(*s)); strcpy(s->name, name); - s->weak = weak; - s->next = next; - s->is_static = 1; + return s; } /* For the hash of exported symbols */ -static struct symbol *new_symbol(const char *name, struct module *module, - enum export export) +static void hash_add_symbol(struct symbol *sym) { unsigned int hash; - hash = tdb_hash(name) % SYMBOL_HASH_SIZE; - symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); + hash = tdb_hash(sym->name) % SYMBOL_HASH_SIZE; + sym->next = symbolhash[hash]; + symbolhash[hash] = sym; +} + +static void sym_add_unresolved(const char *name, struct module *mod, bool weak) +{ + struct symbol *sym; + + sym = alloc_symbol(name); + sym->weak = weak; - return symbolhash[hash]; + list_add_tail(&sym->list, &mod->unresolved_symbols); } -static struct symbol *find_symbol(const char *name) +static struct symbol *sym_find_with_module(const char *name, struct module *mod) { struct symbol *s; @@ -264,67 +276,44 @@ static struct symbol *find_symbol(const char *name) name++; for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) { - if (strcmp(s->name, name) == 0) + if (strcmp(s->name, name) == 0 && (!mod || s->module == mod)) return s; } return NULL; } -static bool contains_namespace(struct namespace_list *list, - const char *namespace) +static struct symbol *find_symbol(const char *name) { - for (; list; list = list->next) + return sym_find_with_module(name, NULL); +} + +struct namespace_list { + struct list_head list; + char namespace[]; +}; + +static bool contains_namespace(struct list_head *head, const char *namespace) +{ + struct namespace_list *list; + + list_for_each_entry(list, head, list) { if (!strcmp(list->namespace, namespace)) return true; + } return false; } -static void add_namespace(struct namespace_list **list, const char *namespace) +static void add_namespace(struct list_head *head, const char *namespace) { struct namespace_list *ns_entry; - if (!contains_namespace(*list, namespace)) { - ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) + + if (!contains_namespace(head, namespace)) { + ns_entry = NOFAIL(malloc(sizeof(*ns_entry) + strlen(namespace) + 1)); strcpy(ns_entry->namespace, namespace); - ns_entry->next = *list; - *list = ns_entry; - } -} - -static bool module_imports_namespace(struct module *module, - const char *namespace) -{ - return contains_namespace(module->imported_namespaces, namespace); -} - -static const struct { - const char *str; - enum export export; -} export_list[] = { - { .str = "EXPORT_SYMBOL", .export = export_plain }, - { .str = "EXPORT_SYMBOL_GPL", .export = export_gpl }, - { .str = "(unknown)", .export = export_unknown }, -}; - - -static const char *export_str(enum export ex) -{ - return export_list[ex].str; -} - -static enum export export_no(const char *s) -{ - int i; - - if (!s) - return export_unknown; - for (i = 0; export_list[i].export != export_unknown; i++) { - if (strcmp(export_list[i].str, s) == 0) - return export_list[i].export; + list_add_tail(&ns_entry->list, head); } - return export_unknown; } static void *sym_get_data_by_offset(const struct elf_info *info, @@ -332,13 +321,10 @@ static void *sym_get_data_by_offset(const struct elf_info *info, { Elf_Shdr *sechdr = &info->sechdrs[secindex]; - if (info->hdr->e_type != ET_REL) - offset -= sechdr->sh_addr; - return (void *)info->hdr + sechdr->sh_offset + offset; } -static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym) +void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym) { return sym_get_data_by_offset(info, get_secindex(info, sym), sym->st_value); @@ -350,42 +336,21 @@ static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr) sechdr->sh_name); } -static const char *sec_name(const struct elf_info *info, int secindex) +static const char *sec_name(const struct elf_info *info, unsigned int secindex) { + /* + * If sym->st_shndx is a special section index, there is no + * corresponding section header. + * Return "" if the index is out of range of info->sechdrs[] array. + */ + if (secindex >= info->num_sections) + return ""; + return sech_name(info, &info->sechdrs[secindex]); } #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) -static enum export export_from_secname(struct elf_info *elf, unsigned int sec) -{ - const char *secname = sec_name(elf, sec); - - if (strstarts(secname, "___ksymtab+")) - return export_plain; - else if (strstarts(secname, "___ksymtab_gpl+")) - return export_gpl; - else - return export_unknown; -} - -static enum export export_from_sec(struct elf_info *elf, unsigned int sec) -{ - if (sec == elf->export_sec) - return export_plain; - else if (sec == elf->export_gpl_sec) - return export_gpl; - else - return export_unknown; -} - -static const char *namespace_from_kstrtabns(const struct elf_info *info, - const Elf_Sym *sym) -{ - const char *value = sym_get_data(info, sym); - return value[0] ? value : NULL; -} - static void sym_update_namespace(const char *symname, const char *namespace) { struct symbol *s = find_symbol(symname); @@ -401,47 +366,33 @@ static void sym_update_namespace(const char *symname, const char *namespace) } free(s->namespace); - s->namespace = - namespace && namespace[0] ? NOFAIL(strdup(namespace)) : NULL; + s->namespace = namespace[0] ? NOFAIL(strdup(namespace)) : NULL; } -/** - * Add an exported symbol - it may have already been added without a - * CRC, in this case just update the CRC - **/ static struct symbol *sym_add_exported(const char *name, struct module *mod, - enum export export) + bool gpl_only) { struct symbol *s = find_symbol(name); - if (!s) { - s = new_symbol(name, mod, export); - } else if (!external_module || s->module->is_vmlinux || - s->module == mod) { - warn("%s: '%s' exported twice. Previous export was in %s%s\n", - mod->name, name, s->module->name, - s->module->is_vmlinux ? "" : ".ko"); - return s; + if (s && (!external_module || s->module->is_vmlinux || s->module == mod)) { + error("%s: '%s' exported twice. Previous export was in %s%s\n", + mod->name, name, s->module->name, + s->module->is_vmlinux ? "" : ".ko"); } + s = alloc_symbol(name); s->module = mod; - s->export = export; + s->is_gpl_only = gpl_only; + list_add_tail(&s->list, &mod->exported_symbols); + hash_add_symbol(s); + return s; } -static void sym_set_crc(const char *name, unsigned int crc) +static void sym_set_crc(struct symbol *sym, unsigned int crc) { - struct symbol *s = find_symbol(name); - - /* - * Ignore stand-alone __crc_*, which might be auto-generated symbols - * such as __*_veneer in ARM ELF. - */ - if (!s) - return; - - s->crc = crc; - s->crc_valid = 1; + sym->crc = crc; + sym->crc_valid = true; } static void *grab_file(const char *filename, size_t *size) @@ -520,6 +471,10 @@ static int parse_elf(struct elf_info *info, const char *filename) sechdrs = (void *)hdr + hdr->e_shoff; info->sechdrs = sechdrs; + /* modpost only works for relocatable objects */ + if (hdr->e_type != ET_REL) + fatal("%s: not relocatable object.", filename); + /* Check if file offset is correct */ if (hdr->e_shoff > info->size) { fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n", @@ -576,10 +531,7 @@ static int parse_elf(struct elf_info *info, const char *filename) fatal("%s has NOBITS .modinfo\n", filename); info->modinfo = (void *)hdr + sechdrs[i].sh_offset; info->modinfo_len = sechdrs[i].sh_size; - } else if (strcmp(secname, "__ksymtab") == 0) - info->export_sec = i; - else if (strcmp(secname, "__ksymtab_gpl") == 0) - info->export_gpl_sec = i; + } if (sechdrs[i].sh_type == SHT_SYMTAB) { unsigned int sh_link_idx; @@ -667,44 +619,9 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname) return 0; } -static void handle_modversion(const struct module *mod, - const struct elf_info *info, - const Elf_Sym *sym, const char *symname) -{ - unsigned int crc; - - if (sym->st_shndx == SHN_UNDEF) { - warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n" - "Is \"%s\" prototyped in ?\n", - symname, mod->name, mod->is_vmlinux ? "" : ".ko", - symname); - - return; - } - - if (sym->st_shndx == SHN_ABS) { - crc = sym->st_value; - } else { - unsigned int *crcp; - - /* symbol points to the CRC in the ELF object */ - crcp = sym_get_data(info, sym); - crc = TO_NATIVE(*crcp); - } - sym_set_crc(symname, crc); -} - static void handle_symbol(struct module *mod, struct elf_info *info, const Elf_Sym *sym, const char *symname) { - enum export export; - const char *name; - - if (strstarts(symname, "__ksymtab")) - export = export_from_secname(info, get_secindex(info, sym)); - else - export = export_from_sec(info, get_secindex(info, sym)); - switch (sym->st_shndx) { case SHN_COMMON: if (strstarts(symname, "__gnu_lto_")) { @@ -732,20 +649,26 @@ static void handle_symbol(struct module *mod, struct elf_info *info, } } - mod->unres = alloc_symbol(symname, - ELF_ST_BIND(sym->st_info) == STB_WEAK, - mod->unres); + sym_add_unresolved(symname, mod, + ELF_ST_BIND(sym->st_info) == STB_WEAK); break; default: /* All exported symbols */ if (strstarts(symname, "__ksymtab_")) { + const char *name, *secname; + name = symname + strlen("__ksymtab_"); - sym_add_exported(name, mod, export); + secname = sec_name(info, get_secindex(info, sym)); + + if (strstarts(secname, "___ksymtab_gpl+")) + sym_add_exported(name, mod, true); + else if (strstarts(secname, "___ksymtab+")) + sym_add_exported(name, mod, false); } if (strcmp(symname, "init_module") == 0) - mod->has_init = 1; + mod->has_init = true; if (strcmp(symname, "cleanup_module") == 0) - mod->has_cleanup = 1; + mod->has_cleanup = true; break; } } @@ -797,29 +720,6 @@ static char *get_modinfo(struct elf_info *info, const char *tag) return get_next_modinfo(info, tag, NULL); } -/** - * Test if string s ends in string sub - * return 0 if match - **/ -static int strrcmp(const char *s, const char *sub) -{ - int slen, sublen; - - if (!s || !sub) - return 1; - - slen = strlen(s); - sublen = strlen(sub); - - if ((slen == 0) || (sublen == 0)) - return 1; - - if (sublen > slen) - return 1; - - return memcmp(s + slen - sublen, sub, sublen); -} - static const char *sym_name(struct elf_info *elf, Elf_Sym *sym) { if (sym) @@ -828,56 +728,36 @@ static const char *sym_name(struct elf_info *elf, Elf_Sym *sym) return "(unknown)"; } -/* The pattern is an array of simple patterns. - * "foo" will match an exact string equal to "foo" - * "*foo" will match a string that ends with "foo" - * "foo*" will match a string that begins with "foo" - * "*foo*" will match a string that contains "foo" +/* + * Check whether the 'string' argument matches one of the 'patterns', + * an array of shell wildcard patterns (glob). + * + * Return true is there is a match. */ -static int match(const char *sym, const char * const pat[]) +static bool match(const char *string, const char *const patterns[]) { - const char *p; - while (*pat) { - const char *endp; - - p = *pat++; - endp = p + strlen(p) - 1; - - /* "*foo*" */ - if (*p == '*' && *endp == '*') { - char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2)); - char *here = strstr(sym, bare); + const char *pattern; - free(bare); - if (here != NULL) - return 1; - } - /* "*foo" */ - else if (*p == '*') { - if (strrcmp(sym, p + 1) == 0) - return 1; - } - /* "foo*" */ - else if (*endp == '*') { - if (strncmp(sym, p, strlen(p) - 1) == 0) - return 1; - } - /* no wildcards */ - else { - if (strcmp(p, sym) == 0) - return 1; - } + while ((pattern = *patterns++)) { + if (!fnmatch(pattern, string, 0)) + return true; } - /* no match */ - return 0; + + return false; } +/* useful to pass patterns to match() directly */ +#define PATTERNS(...) \ + ({ \ + static const char *const patterns[] = {__VA_ARGS__, NULL}; \ + patterns; \ + }) + /* sections that we do not want to do full section mismatch check on */ static const char *const section_white_list[] = { ".comment*", ".debug*", - ".cranges", /* sh64 */ ".zdebug*", /* Compressed debug sections. */ ".GCC.command.line", /* record-gcc-switches */ ".mdebug*", /* alpha, score, mips etc. */ @@ -965,28 +845,12 @@ static const char *const init_data_sections[] = /* all init sections */ static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL }; -/* All init and exit sections (code + data) */ -static const char *const init_exit_sections[] = - {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }; - /* all text sections */ static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL }; /* data section */ static const char *const data_sections[] = { DATA_SECTIONS, NULL }; - -/* symbols in .data that may refer to init/exit sections */ -#define DEFAULT_SYMBOL_WHITE_LIST \ - "*driver", \ - "*_template", /* scsi uses *_template a lot */ \ - "*_timer", /* arm uses ops structures named _timer a lot */ \ - "*_sht", /* scsi also used *_sht to some extent */ \ - "*_ops", \ - "*_probe", \ - "*_probe_one", \ - "*_console" - static const char *const head_sections[] = { ".head.text*", NULL }; static const char *const linker_symbols[] = { "__init_begin", "_sinittext", "_einittext", NULL }; @@ -1018,9 +882,6 @@ enum mismatch { * * @mismatch: Type of mismatch. * - * @symbol_white_list: Do not match a relocation to a symbol in this list - * even if it is targeting a section in @bad_to_sec. - * * @handler: Specific handler to call when a match is found. If NULL, * default_mismatch_handler() will be called. * @@ -1030,7 +891,6 @@ struct sectioncheck { const char *bad_tosec[20]; const char *good_tosec[20]; enum mismatch mismatch; - const char *symbol_white_list[20]; void (*handler)(const char *modname, struct elf_info *elf, const struct sectioncheck* const mismatch, Elf_Rela *r, Elf_Sym *sym, const char *fromsec); @@ -1050,75 +910,61 @@ static const struct sectioncheck sectioncheck[] = { .fromsec = { TEXT_SECTIONS, NULL }, .bad_tosec = { ALL_INIT_SECTIONS, NULL }, .mismatch = TEXT_TO_ANY_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { DATA_SECTIONS, NULL }, .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL }, .mismatch = DATA_TO_ANY_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { DATA_SECTIONS, NULL }, .bad_tosec = { INIT_SECTIONS, NULL }, .mismatch = DATA_TO_ANY_INIT, - .symbol_white_list = { - "*_template", "*_timer", "*_sht", "*_ops", - "*_probe", "*_probe_one", "*_console", NULL - }, }, { .fromsec = { TEXT_SECTIONS, NULL }, .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, .mismatch = TEXT_TO_ANY_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { DATA_SECTIONS, NULL }, .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, .mismatch = DATA_TO_ANY_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference init code/data from meminit code/data */ { .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, .bad_tosec = { INIT_SECTIONS, NULL }, .mismatch = XXXINIT_TO_SOME_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference exit code/data from memexit code/data */ { .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, .bad_tosec = { EXIT_SECTIONS, NULL }, .mismatch = XXXEXIT_TO_SOME_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not use exit code/data from init code */ { .fromsec = { ALL_INIT_SECTIONS, NULL }, .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, .mismatch = ANY_INIT_TO_ANY_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not use init code/data from exit code */ { .fromsec = { ALL_EXIT_SECTIONS, NULL }, .bad_tosec = { ALL_INIT_SECTIONS, NULL }, .mismatch = ANY_EXIT_TO_ANY_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { ALL_PCI_INIT_SECTIONS, NULL }, .bad_tosec = { INIT_SECTIONS, NULL }, .mismatch = ANY_INIT_TO_ANY_EXIT, - .symbol_white_list = { NULL }, }, /* Do not export init/exit functions or data */ { - .fromsec = { "__ksymtab*", NULL }, + .fromsec = { "___ksymtab*", NULL }, .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, .mismatch = EXPORT_TO_INIT_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { "__ex_table", NULL }, @@ -1136,8 +982,6 @@ static const struct sectioncheck *section_mismatch( const char *fromsec, const char *tosec) { int i; - int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck); - const struct sectioncheck *check = §ioncheck[0]; /* * The target section could be the SHT_NUL section when we're @@ -1148,14 +992,15 @@ static const struct sectioncheck *section_mismatch( if (*tosec == '\0') return NULL; - for (i = 0; i < elems; i++) { + for (i = 0; i < ARRAY_SIZE(sectioncheck); i++) { + const struct sectioncheck *check = §ioncheck[i]; + if (match(fromsec, check->fromsec)) { if (check->bad_tosec[0] && match(tosec, check->bad_tosec)) return check; if (check->good_tosec[0] && !match(tosec, check->good_tosec)) return check; } - check++; } return NULL; } @@ -1180,15 +1025,6 @@ static const struct sectioncheck *section_mismatch( * fromsec = .data* * atsym = __param_ops_* * - * Pattern 2: - * Many drivers utilise a *driver container with references to - * add, remove, probe functions etc. - * the pattern is identified by: - * tosec = init or exit section - * fromsec = data section - * atsym = *driver, *_template, *_sht, *_ops, *_probe, - * *probe_one, *_console, *_timer - * * Pattern 3: * Whitelist all references from .head.text to any init section * @@ -1237,10 +1073,22 @@ static int secref_whitelist(const struct sectioncheck *mismatch, strstarts(fromsym, "__param_ops_")) return 0; - /* Check for pattern 2 */ - if (match(tosec, init_exit_sections) && - match(fromsec, data_sections) && - match(fromsym, mismatch->symbol_white_list)) + /* symbols in data sections that may refer to any init/exit sections */ + if (match(fromsec, PATTERNS(DATA_SECTIONS)) && + match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) && + match(fromsym, PATTERNS("*_template", // scsi uses *_template a lot + "*_timer", // arm uses ops structures named _timer a lot + "*_sht", // scsi also used *_sht to some extent + "*_ops", + "*_probe", + "*_probe_one", + "*_console"))) + return 0; + + /* symbols in data sections that may refer to meminit/exit sections */ + if (match(fromsec, PATTERNS(DATA_SECTIONS)) && + match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_EXIT_SECTIONS)) && + match(fromsym, PATTERNS("*driver"))) return 0; /* Check for pattern 3 */ @@ -1267,7 +1115,8 @@ static int secref_whitelist(const struct sectioncheck *mismatch, static inline int is_arm_mapping_symbol(const char *str) { - return str[0] == '$' && strchr("axtd", str[1]) + return str[0] == '$' && + (str[1] == 'a' || str[1] == 'd' || str[1] == 't' || str[1] == 'x') && (str[2] == '\0' || str[2] == '.'); } @@ -1357,54 +1206,14 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, continue; if (!is_valid_name(elf, sym)) continue; - if (sym->st_value <= addr) { - if ((addr - sym->st_value) < distance) { - distance = addr - sym->st_value; - near = sym; - } else if ((addr - sym->st_value) == distance) { - near = sym; - } + if (sym->st_value <= addr && addr - sym->st_value <= distance) { + distance = addr - sym->st_value; + near = sym; } } return near; } -/* - * Convert a section name to the function/data attribute - * .init.text => __init - * .memexitconst => __memconst - * etc. - * - * The memory of returned value has been allocated on a heap. The user of this - * method should free it after usage. -*/ -static char *sec2annotation(const char *s) -{ - if (match(s, init_exit_sections)) { - char *p = NOFAIL(malloc(20)); - char *r = p; - - *p++ = '_'; - *p++ = '_'; - if (*s == '.') - s++; - while (*s && *s != '.') - *p++ = *s++; - *p = '\0'; - if (*s == '.') - s++; - if (strstr(s, "rodata") != NULL) - strcat(p, "const "); - else if (strstr(s, "data") != NULL) - strcat(p, "data "); - else - strcat(p, " "); - return r; - } else { - return NOFAIL(strdup("")); - } -} - static int is_function(Elf_Sym *sym) { if (sym) @@ -1413,19 +1222,6 @@ static int is_function(Elf_Sym *sym) return -1; } -static void print_section_list(const char * const list[20]) -{ - const char *const *s = list; - - while (*s) { - fprintf(stderr, "%s", *s); - s++; - if (*s) - fprintf(stderr, ", "); - } - fprintf(stderr, "\n"); -} - static inline void get_pretty_name(int is_func, const char** name, const char** name_p) { switch (is_func) { @@ -1443,141 +1239,31 @@ static inline void get_pretty_name(int is_func, const char** name, const char** static void report_sec_mismatch(const char *modname, const struct sectioncheck *mismatch, const char *fromsec, - unsigned long long fromaddr, const char *fromsym, - int from_is_func, - const char *tosec, const char *tosym, - int to_is_func) + const char *tosec, const char *tosym) { - const char *from, *from_p; - const char *to, *to_p; - char *prl_from; - char *prl_to; - sec_mismatch_count++; - get_pretty_name(from_is_func, &from, &from_p); - get_pretty_name(to_is_func, &to, &to_p); - - warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s " - "to the %s %s:%s%s\n", - modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, - tosym, to_p); - switch (mismatch->mismatch) { case TEXT_TO_ANY_INIT: - prl_from = sec2annotation(fromsec); - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The function %s%s() references\n" - "the %s %s%s%s.\n" - "This is often because %s lacks a %s\n" - "annotation or the annotation of %s is wrong.\n", - prl_from, fromsym, - to, prl_to, tosym, to_p, - fromsym, prl_to, tosym); - free(prl_from); - free(prl_to); - break; - case DATA_TO_ANY_INIT: { - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The variable %s references\n" - "the %s %s%s%s\n" - "If the reference is valid then annotate the\n" - "variable with __init* or __refdata (see linux/init.h) " - "or name the variable:\n", - fromsym, to, prl_to, tosym, to_p); - print_section_list(mismatch->symbol_white_list); - free(prl_to); - break; - } + case DATA_TO_ANY_INIT: case TEXT_TO_ANY_EXIT: - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The function %s() references a %s in an exit section.\n" - "Often the %s %s%s has valid usage outside the exit section\n" - "and the fix is to remove the %sannotation of %s.\n", - fromsym, to, to, tosym, to_p, prl_to, tosym); - free(prl_to); - break; - case DATA_TO_ANY_EXIT: { - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The variable %s references\n" - "the %s %s%s%s\n" - "If the reference is valid then annotate the\n" - "variable with __exit* (see linux/init.h) or " - "name the variable:\n", - fromsym, to, prl_to, tosym, to_p); - print_section_list(mismatch->symbol_white_list); - free(prl_to); - break; - } + case DATA_TO_ANY_EXIT: case XXXINIT_TO_SOME_INIT: case XXXEXIT_TO_SOME_EXIT: - prl_from = sec2annotation(fromsec); - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The %s %s%s%s references\n" - "a %s %s%s%s.\n" - "If %s is only used by %s then\n" - "annotate %s with a matching annotation.\n", - from, prl_from, fromsym, from_p, - to, prl_to, tosym, to_p, - tosym, fromsym, tosym); - free(prl_from); - free(prl_to); - break; case ANY_INIT_TO_ANY_EXIT: - prl_from = sec2annotation(fromsec); - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The %s %s%s%s references\n" - "a %s %s%s%s.\n" - "This is often seen when error handling " - "in the init function\n" - "uses functionality in the exit path.\n" - "The fix is often to remove the %sannotation of\n" - "%s%s so it may be used outside an exit section.\n", - from, prl_from, fromsym, from_p, - to, prl_to, tosym, to_p, - prl_to, tosym, to_p); - free(prl_from); - free(prl_to); - break; case ANY_EXIT_TO_ANY_INIT: - prl_from = sec2annotation(fromsec); - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The %s %s%s%s references\n" - "a %s %s%s%s.\n" - "This is often seen when error handling " - "in the exit function\n" - "uses functionality in the init path.\n" - "The fix is often to remove the %sannotation of\n" - "%s%s so it may be used outside an init section.\n", - from, prl_from, fromsym, from_p, - to, prl_to, tosym, to_p, - prl_to, tosym, to_p); - free(prl_from); - free(prl_to); + warn("%s: section mismatch in reference: %s (section: %s) -> %s (section: %s)\n", + modname, fromsym, fromsec, tosym, tosec); break; case EXPORT_TO_INIT_EXIT: - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The symbol %s is exported and annotated %s\n" - "Fix this by removing the %sannotation of %s " - "or drop the export.\n", - tosym, prl_to, prl_to, tosym); - free(prl_to); + warn("%s: EXPORT_SYMBOL used for init/exit symbol: %s (section: %s)\n", + modname, tosym, tosec); break; case EXTABLE_TO_NON_TEXT: - fatal("There's a special handler for this mismatch type, " - "we should never get here."); + fatal("There's a special handler for this mismatch type, we should never get here.\n"); break; } - fprintf(stderr, "\n"); } static void default_mismatch_handler(const char *modname, struct elf_info *elf, @@ -1593,9 +1279,6 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf, from = find_elf_symbol2(elf, r->r_offset, fromsec); fromsym = sym_name(elf, from); - if (strstarts(fromsym, "reference___initcall")) - return; - tosec = sec_name(elf, get_secindex(elf, sym)); to = find_elf_symbol(elf, r->r_addend, sym); tosym = sym_name(elf, to); @@ -1604,9 +1287,7 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf, if (secref_whitelist(mismatch, fromsec, fromsym, tosec, tosym)) { report_sec_mismatch(modname, mismatch, - fromsec, r->r_offset, fromsym, - is_function(from), tosec, tosym, - is_function(to)); + fromsec, fromsym, tosec, tosym); } } @@ -1762,9 +1443,6 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) break; case R_386_PC32: r->r_addend = TO_NATIVE(*location) + 4; - /* For CONFIG_RELOCATABLE=y */ - if (elf->hdr->e_type == ET_EXEC) - r->r_addend += r->r_offset; break; } return 0; @@ -1857,8 +1535,7 @@ static void section_rela(const char *modname, struct elf_info *elf, Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset; Elf_Rela *stop = (void *)start + sechdr->sh_size; - fromsec = sech_name(elf, sechdr); - fromsec += strlen(".rela"); + fromsec = sec_name(elf, sechdr->sh_info); /* if from section (name) is know good then skip it */ if (match(fromsec, section_white_list)) return; @@ -1910,8 +1587,7 @@ static void section_rel(const char *modname, struct elf_info *elf, Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset; Elf_Rel *stop = (void *)start + sechdr->sh_size; - fromsec = sech_name(elf, sechdr); - fromsec += strlen(".rel"); + fromsec = sec_name(elf, sechdr->sh_info); /* if from section (name) is know good then skip it */ if (match(fromsec, section_white_list)) return; @@ -1970,8 +1646,7 @@ static void section_rel(const char *modname, struct elf_info *elf, * to find all references to a section that reference a section that will * be discarded and warns about it. **/ -static void check_sec_ref(struct module *mod, const char *modname, - struct elf_info *elf) +static void check_sec_ref(const char *modname, struct elf_info *elf) { int i; Elf_Shdr *sechdrs = elf->sechdrs; @@ -1993,16 +1668,110 @@ static char *remove_dot(char *s) if (n && s[n]) { size_t m = strspn(s + n + 1, "0123456789"); - if (m && (s[n + m] == '.' || s[n + m] == 0)) + if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0)) s[n] = 0; - - /* strip trailing .prelink */ - if (strends(s, ".prelink")) - s[strlen(s) - 8] = '\0'; } return s; } +/* + * The CRCs are recorded in .*.cmd files in the form of: + * #SYMVER + */ +static void extract_crcs_for_object(const char *object, struct module *mod) +{ + char cmd_file[PATH_MAX]; + char *buf, *p; + const char *base; + int dirlen, ret; + + base = strrchr(object, '/'); + if (base) { + base++; + dirlen = base - object; + } else { + dirlen = 0; + base = object; + } + + ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%s.cmd", + dirlen, object, base); + if (ret >= sizeof(cmd_file)) { + error("%s: too long path was truncated\n", cmd_file); + return; + } + + buf = read_text_file(cmd_file); + p = buf; + + while ((p = strstr(p, "\n#SYMVER "))) { + char *name; + size_t namelen; + unsigned int crc; + struct symbol *sym; + + name = p + strlen("\n#SYMVER "); + + p = strchr(name, ' '); + if (!p) + break; + + namelen = p - name; + p++; + + if (!isdigit(*p)) + continue; /* skip this line */ + + crc = strtol(p, &p, 0); + if (*p != '\n') + continue; /* skip this line */ + + name[namelen] = '\0'; + + /* + * sym_find_with_module() may return NULL here. + * It typically occurs when CONFIG_TRIM_UNUSED_KSYMS=y. + * Since commit e1327a127703, genksyms calculates CRCs of all + * symbols, including trimmed ones. Ignore orphan CRCs. + */ + sym = sym_find_with_module(name, mod); + if (sym) + sym_set_crc(sym, crc); + } + + free(buf); +} + +/* + * The symbol versions (CRC) are recorded in the .*.cmd files. + * Parse them to retrieve CRCs for the current module. + */ +static void mod_set_crcs(struct module *mod) +{ + char objlist[PATH_MAX]; + char *buf, *p, *obj; + int ret; + + if (mod->is_vmlinux) { + strcpy(objlist, ".vmlinux.objs"); + } else { + /* objects for a module are listed in the *.mod file. */ + ret = snprintf(objlist, sizeof(objlist), "%s.mod", mod->name); + if (ret >= sizeof(objlist)) { + error("%s: too long path was truncated\n", objlist); + return; + } + } + + buf = read_text_file(objlist); + p = buf; + + while ((obj = strsep(&p, "\n")) && obj[0]) + extract_crcs_for_object(obj, mod); + + free(buf); +} + static void read_symbols(const char *modname) { const char *symname; @@ -2016,28 +1785,21 @@ static void read_symbols(const char *modname) if (!parse_elf(&info, modname)) return; - { - char *tmp; - - /* strip trailing .o */ - tmp = NOFAIL(strdup(modname)); - tmp[strlen(tmp) - 2] = '\0'; - /* strip trailing .prelink */ - if (strends(tmp, ".prelink")) - tmp[strlen(tmp) - 8] = '\0'; - mod = new_module(tmp); - free(tmp); + if (!strends(modname, ".o")) { + error("%s: filename must be suffixed with .o\n", modname); + return; } + /* strip trailing .o */ + mod = new_module(modname, strlen(modname) - strlen(".o")); + if (!mod->is_vmlinux) { license = get_modinfo(&info, "license"); if (!license) error("missing MODULE_LICENSE() in %s\n", modname); while (license) { - if (license_is_gpl_compatible(license)) - mod->gpl_compatible = 1; - else { - mod->gpl_compatible = 0; + if (!license_is_gpl_compatible(license)) { + mod->is_gpl_compatible = false; break; } license = get_next_modinfo(&info, "license", license); @@ -2064,29 +1826,10 @@ static void read_symbols(const char *modname) /* Apply symbol namespaces from __kstrtabns_ entries. */ if (strstarts(symname, "__kstrtabns_")) sym_update_namespace(symname + strlen("__kstrtabns_"), - namespace_from_kstrtabns(&info, - sym)); - - if (strstarts(symname, "__crc_")) - handle_modversion(mod, &info, sym, - symname + strlen("__crc_")); + sym_get_data(&info, sym)); } - // check for static EXPORT_SYMBOL_* functions && global vars - for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { - unsigned char bind = ELF_ST_BIND(sym->st_info); - - if (bind == STB_GLOBAL || bind == STB_WEAK) { - struct symbol *s = - find_symbol(remove_dot(info.strtab + - sym->st_name)); - - if (s) - s->is_static = 0; - } - } - - check_sec_ref(mod, modname, &info); + check_sec_ref(modname, &info); if (!mod->is_vmlinux) { version = get_modinfo(&info, "version"); @@ -2097,12 +1840,17 @@ static void read_symbols(const char *modname) parse_elf_finish(&info); - /* Our trick to get versioning for module struct etc. - it's - * never passed as an argument to an exported function, so - * the automatic versioning doesn't pick it up, but it's really - * important anyhow */ - if (modversions) - mod->unres = alloc_symbol("module_layout", 0, mod->unres); + if (modversions) { + /* + * Our trick to get versioning for module struct etc. - it's + * never passed as an argument to an exported function, so + * the automatic versioning doesn't pick it up, but it's really + * important anyhow. + */ + sym_add_unresolved("module_layout", mod, false); + + mod_set_crcs(mod); + } } static void read_symbols_from_files(const char *filename) @@ -2155,34 +1903,30 @@ void buf_write(struct buffer *buf, const char *s, int len) buf->pos += len; } -static void check_for_gpl_usage(enum export exp, const char *m, const char *s) -{ - switch (exp) { - case export_gpl: - error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n", - m, s); - break; - case export_plain: - case export_unknown: - /* ignore */ - break; - } -} - static void check_exports(struct module *mod) { struct symbol *s, *exp; - for (s = mod->unres; s; s = s->next) { + list_for_each_entry(s, &mod->unresolved_symbols, list) { const char *basename; exp = find_symbol(s->name); - if (!exp || exp->module == mod) { + if (!exp) { if (!s->weak && nr_unresolved++ < MAX_UNRESOLVED_REPORTS) modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR, "\"%s\" [%s.ko] undefined!\n", s->name, mod->name); continue; } + if (exp->module == mod) { + error("\"%s\" [%s.ko] was exported without definition\n", + s->name, mod->name); + continue; + } + + s->module = exp->module; + s->crc_valid = exp->crc_valid; + s->crc = exp->crc; + basename = strrchr(mod->name, '/'); if (basename) basename++; @@ -2190,15 +1934,16 @@ static void check_exports(struct module *mod) basename = mod->name; if (exp->namespace && - !module_imports_namespace(mod, exp->namespace)) { + !contains_namespace(&mod->imported_namespaces, exp->namespace)) { modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR, "module %s uses symbol %s from namespace %s, but does not import it.\n", basename, exp->name, exp->namespace); add_namespace(&mod->missing_namespaces, exp->namespace); } - if (!mod->gpl_compatible) - check_for_gpl_usage(exp->export, basename, exp->name); + if (!mod->is_gpl_compatible && exp->is_gpl_only) + error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n", + basename, exp->name); } } @@ -2228,6 +1973,7 @@ static void add_header(struct buffer *b, struct module *mod) buf_printf(b, "#define INCLUDE_VERMAGIC\n"); buf_printf(b, "#include \n"); buf_printf(b, "#include \n"); + buf_printf(b, "#include \n"); buf_printf(b, "#include \n"); buf_printf(b, "#include \n"); buf_printf(b, "\n"); @@ -2248,26 +1994,42 @@ static void add_header(struct buffer *b, struct module *mod) "#endif\n"); buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); buf_printf(b, "};\n"); -} -static void add_intree_flag(struct buffer *b, int is_intree) -{ - if (is_intree) + if (!external_module) buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); -} -/* Cannot check for assembler */ -static void add_retpoline(struct buffer *b) -{ - buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n"); - buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n"); - buf_printf(b, "#endif\n"); + buf_printf(b, + "\n" + "#ifdef CONFIG_RETPOLINE\n" + "MODULE_INFO(retpoline, \"Y\");\n" + "#endif\n"); + + if (strstarts(mod->name, "drivers/staging")) + buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); + + if (strstarts(mod->name, "tools/testing")) + buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n"); } -static void add_staging_flag(struct buffer *b, const char *name) +static void add_exported_symbols(struct buffer *buf, struct module *mod) { - if (strstarts(name, "drivers/staging")) - buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); + struct symbol *sym; + + if (!modversions) + return; + + /* record CRCs for exported symbols */ + buf_printf(buf, "\n"); + list_for_each_entry(sym, &mod->exported_symbols, list) { + if (!sym->crc_valid) + warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n" + "Is \"%s\" prototyped in ?\n", + sym->name, mod->name, mod->is_vmlinux ? "" : ".ko", + sym->name); + + buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n", + sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : ""); + } } /** @@ -2275,16 +2037,7 @@ static void add_staging_flag(struct buffer *b, const char *name) **/ static void add_versions(struct buffer *b, struct module *mod) { - struct symbol *s, *exp; - - for (s = mod->unres; s; s = s->next) { - exp = find_symbol(s->name); - if (!exp || exp->module == mod) - continue; - s->module = exp->module; - s->crc_valid = exp->crc_valid; - s->crc = exp->crc; - } + struct symbol *s; if (!modversions) return; @@ -2293,7 +2046,7 @@ static void add_versions(struct buffer *b, struct module *mod) buf_printf(b, "static const struct modversion_info ____versions[]\n"); buf_printf(b, "__used __section(\"__versions\") = {\n"); - for (s = mod->unres; s; s = s->next) { + list_for_each_entry(s, &mod->unresolved_symbols, list) { if (!s->module) continue; if (!s->crc_valid) { @@ -2319,13 +2072,14 @@ static void add_depends(struct buffer *b, struct module *mod) int first = 1; /* Clear ->seen flag of modules that own symbols needed by this. */ - for (s = mod->unres; s; s = s->next) + list_for_each_entry(s, &mod->unresolved_symbols, list) { if (s->module) s->module->seen = s->module->is_vmlinux; + } buf_printf(b, "\n"); buf_printf(b, "MODULE_INFO(depends, \""); - for (s = mod->unres; s; s = s->next) { + list_for_each_entry(s, &mod->unresolved_symbols, list) { const char *p; if (!s->module) continue; @@ -2333,7 +2087,7 @@ static void add_depends(struct buffer *b, struct module *mod) if (s->module->seen) continue; - s->module->seen = 1; + s->module->seen = true; p = strrchr(s->module->name, '/'); if (p) p++; @@ -2358,6 +2112,9 @@ static void write_buf(struct buffer *b, const char *fname) { FILE *file; + if (error_occurred) + return; + file = fopen(fname, "w"); if (!file) { perror(fname); @@ -2408,6 +2165,47 @@ static void write_if_changed(struct buffer *b, const char *fname) write_buf(b, fname); } +static void write_vmlinux_export_c_file(struct module *mod) +{ + struct buffer buf = { }; + + buf_printf(&buf, + "#include \n"); + + add_exported_symbols(&buf, mod); + write_if_changed(&buf, ".vmlinux.export.c"); + free(buf.p); +} + +/* do sanity checks, and generate *.mod.c file */ +static void write_mod_c_file(struct module *mod) +{ + struct buffer buf = { }; + char fname[PATH_MAX]; + int ret; + + check_modname_len(mod); + check_exports(mod); + + add_header(&buf, mod); + add_exported_symbols(&buf, mod); + add_versions(&buf, mod); + add_depends(&buf, mod); + add_moddevtable(&buf, mod); + add_srcversion(&buf, mod); + + ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name); + if (ret >= sizeof(fname)) { + error("%s: too long path was truncated\n", fname); + goto free; + } + + write_if_changed(&buf, fname); + +free: + free(buf.p); +} + /* parse Module.symvers file. line format: * 0x12345678symbolmoduleexportnamespace **/ @@ -2427,6 +2225,7 @@ static void read_dump(const char *fname) unsigned int crc; struct module *mod; struct symbol *s; + bool gpl_only; if (!(symname = strchr(line, '\t'))) goto fail; @@ -2444,14 +2243,23 @@ static void read_dump(const char *fname) crc = strtoul(line, &d, 16); if (*symname == '\0' || *modname == '\0' || *d != '\0') goto fail; + + if (!strcmp(export, "EXPORT_SYMBOL_GPL")) { + gpl_only = true; + } else if (!strcmp(export, "EXPORT_SYMBOL")) { + gpl_only = false; + } else { + error("%s: unknown license %s. skip", symname, export); + continue; + } + mod = find_module(modname); if (!mod) { - mod = new_module(modname); - mod->from_dump = 1; + mod = new_module(modname, strlen(modname)); + mod->from_dump = true; } - s = sym_add_exported(symname, mod, export_no(export)); - s->is_static = 0; - sym_set_crc(symname, crc); + s = sym_add_exported(symname, mod, gpl_only); + sym_set_crc(s, crc); sym_update_namespace(symname, namespace); } free(buf); @@ -2464,22 +2272,17 @@ static void read_dump(const char *fname) static void write_dump(const char *fname) { struct buffer buf = { }; - struct symbol *symbol; - const char *namespace; - int n; - - for (n = 0; n < SYMBOL_HASH_SIZE ; n++) { - symbol = symbolhash[n]; - while (symbol) { - if (!symbol->module->from_dump) { - namespace = symbol->namespace; - buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n", - symbol->crc, symbol->name, - symbol->module->name, - export_str(symbol->export), - namespace ? namespace : ""); - } - symbol = symbol->next; + struct module *mod; + struct symbol *sym; + + list_for_each_entry(mod, &modules, list) { + if (mod->from_dump) + continue; + list_for_each_entry(sym, &mod->exported_symbols, list) { + buf_printf(&buf, "0x%08x\t%s\t%s\tEXPORT_SYMBOL%s\t%s\n", + sym->crc, sym->name, mod->name, + sym->is_gpl_only ? "_GPL" : "", + sym->namespace ?: ""); } } write_buf(&buf, fname); @@ -2492,14 +2295,14 @@ static void write_namespace_deps_files(const char *fname) struct namespace_list *ns; struct buffer ns_deps_buf = {}; - for (mod = modules; mod; mod = mod->next) { + list_for_each_entry(mod, &modules, list) { - if (mod->from_dump || !mod->missing_namespaces) + if (mod->from_dump || list_empty(&mod->missing_namespaces)) continue; buf_printf(&ns_deps_buf, "%s.ko:", mod->name); - for (ns = mod->missing_namespaces; ns; ns = ns->next) + list_for_each_entry(ns, &mod->missing_namespaces, list) buf_printf(&ns_deps_buf, " %s", ns->namespace); buf_printf(&ns_deps_buf, "\n"); @@ -2510,55 +2313,52 @@ static void write_namespace_deps_files(const char *fname) } struct dump_list { - struct dump_list *next; + struct list_head list; const char *file; }; int main(int argc, char **argv) { struct module *mod; - struct buffer buf = { }; char *missing_namespace_deps = NULL; char *dump_write = NULL, *files_source = NULL; int opt; - int n; - struct dump_list *dump_read_start = NULL; - struct dump_list **dump_read_iter = &dump_read_start; + LIST_HEAD(dump_lists); + struct dump_list *dl, *dl2; while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) { switch (opt) { case 'e': - external_module = 1; + external_module = true; break; case 'i': - *dump_read_iter = - NOFAIL(calloc(1, sizeof(**dump_read_iter))); - (*dump_read_iter)->file = optarg; - dump_read_iter = &(*dump_read_iter)->next; + dl = NOFAIL(malloc(sizeof(*dl))); + dl->file = optarg; + list_add_tail(&dl->list, &dump_lists); break; case 'm': - modversions = 1; + modversions = true; break; case 'n': - ignore_missing_files = 1; + ignore_missing_files = true; break; case 'o': dump_write = optarg; break; case 'a': - all_versions = 1; + all_versions = true; break; case 'T': files_source = optarg; break; case 'w': - warn_unresolved = 1; + warn_unresolved = true; break; case 'E': sec_mismatch_warn_only = false; break; case 'N': - allow_missing_ns_imports = 1; + allow_missing_ns_imports = true; break; case 'd': missing_namespace_deps = optarg; @@ -2568,13 +2368,10 @@ int main(int argc, char **argv) } } - while (dump_read_start) { - struct dump_list *tmp; - - read_dump(dump_read_start->file); - tmp = dump_read_start->next; - free(dump_read_start); - dump_read_start = tmp; + list_for_each_entry_safe(dl, dl2, &dump_lists, list) { + read_dump(dl->file); + list_del(&dl->list); + free(dl); } while (optind < argc) @@ -2583,28 +2380,14 @@ int main(int argc, char **argv) if (files_source) read_symbols_from_files(files_source); - for (mod = modules; mod; mod = mod->next) { - char fname[PATH_MAX]; - - if (mod->is_vmlinux || mod->from_dump) + list_for_each_entry(mod, &modules, list) { + if (mod->from_dump) continue; - buf.pos = 0; - - check_modname_len(mod); - check_exports(mod); - - add_header(&buf, mod); - add_intree_flag(&buf, !external_module); - add_retpoline(&buf); - add_staging_flag(&buf, mod->name); - add_versions(&buf, mod); - add_depends(&buf, mod); - add_moddevtable(&buf, mod); - add_srcversion(&buf, mod); - - sprintf(fname, "%s.mod.c", mod->name); - write_if_changed(&buf, fname); + if (mod->is_vmlinux) + write_vmlinux_export_c_file(mod); + else + write_mod_c_file(mod); } if (missing_namespace_deps) @@ -2615,22 +2398,10 @@ int main(int argc, char **argv) if (sec_mismatch_count && !sec_mismatch_warn_only) error("Section mismatches detected.\n" "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); - for (n = 0; n < SYMBOL_HASH_SIZE; n++) { - struct symbol *s; - - for (s = symbolhash[n]; s; s = s->next) { - if (s->is_static) - error("\"%s\" [%s] is a static %s\n", - s->name, s->module->name, - export_str(s->export)); - } - } if (nr_unresolved > MAX_UNRESOLVED_REPORTS) warn("suppressed %u unresolved symbol warnings because there were too many)\n", nr_unresolved - MAX_UNRESOLVED_REPORTS); - free(buf.p); - return error_occurred ? 1 : 0; } diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 0c47ff95c0..1178f40a73 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -1,4 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#include #include #include #include @@ -10,6 +11,7 @@ #include #include +#include "list.h" #include "elfconfig.h" /* On BSD-alike OSes elf.h defines these according to host's word size */ @@ -24,7 +26,6 @@ #define Elf_Shdr Elf32_Shdr #define Elf_Sym Elf32_Sym #define Elf_Addr Elf32_Addr -#define Elf_Sword Elf64_Sword #define Elf_Section Elf32_Half #define ELF_ST_BIND ELF32_ST_BIND #define ELF_ST_TYPE ELF32_ST_TYPE @@ -39,7 +40,6 @@ #define Elf_Shdr Elf64_Shdr #define Elf_Sym Elf64_Sym #define Elf_Addr Elf64_Addr -#define Elf_Sword Elf64_Sxword #define Elf_Section Elf64_Half #define ELF_ST_BIND ELF64_ST_BIND #define ELF_ST_TYPE ELF64_ST_TYPE @@ -95,6 +95,9 @@ static inline void __endian(const void *src, void *dest, unsigned int size) #endif #define NOFAIL(ptr) do_nofail((ptr), #ptr) + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + void *do_nofail(void *ptr, const char *expr); struct buffer { @@ -109,26 +112,22 @@ buf_printf(struct buffer *buf, const char *fmt, ...); void buf_write(struct buffer *buf, const char *s, int len); -struct namespace_list { - struct namespace_list *next; - char namespace[]; -}; - struct module { - struct module *next; - int gpl_compatible; - struct symbol *unres; - int from_dump; /* 1 if module was loaded from *.symvers */ - int is_vmlinux; - int seen; - int has_init; - int has_cleanup; + struct list_head list; + struct list_head exported_symbols; + struct list_head unresolved_symbols; + bool is_gpl_compatible; + bool from_dump; /* true if module was loaded from *.symvers */ + bool is_vmlinux; + bool seen; + bool has_init; + bool has_cleanup; struct buffer dev_table_buf; char srcversion[25]; // Missing namespace dependencies - struct namespace_list *missing_namespaces; + struct list_head missing_namespaces; // Actual imported namespaces - struct namespace_list *imported_namespaces; + struct list_head imported_namespaces; char name[]; }; @@ -138,8 +137,6 @@ struct elf_info { Elf_Shdr *sechdrs; Elf_Sym *symtab_start; Elf_Sym *symtab_stop; - Elf_Section export_sec; - Elf_Section export_gpl_sec; char *strtab; char *modinfo; unsigned int modinfo_len; @@ -159,26 +156,31 @@ static inline int is_shndx_special(unsigned int i) return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; } -/* - * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of - * the way to -256..-1, to avoid conflicting with real section - * indices. - */ -#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) - /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ static inline unsigned int get_secindex(const struct elf_info *info, const Elf_Sym *sym) { - if (is_shndx_special(sym->st_shndx)) - return SPECIAL(sym->st_shndx); - if (sym->st_shndx != SHN_XINDEX) - return sym->st_shndx; - return info->symtab_shndx_start[sym - info->symtab_start]; + unsigned int index = sym->st_shndx; + + /* + * Elf{32,64}_Sym::st_shndx is 2 byte. Big section numbers are available + * in the .symtab_shndx section. + */ + if (index == SHN_XINDEX) + return info->symtab_shndx_start[sym - info->symtab_start]; + + /* + * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of + * the way to UINT_MAX-255..UINT_MAX, to avoid conflicting with real + * section indices. + */ + if (index >= SHN_LORESERVE && index <= SHN_HIRESERVE) + return index - SHN_HIRESERVE - 1; + + return index; } /* file2alias.c */ -extern unsigned int cross_build; void handle_moddevtable(struct module *mod, struct elf_info *info, Elf_Sym *sym, const char *symname); void add_moddevtable(struct buffer *buf, struct module *mod); @@ -189,6 +191,7 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen); /* from modpost.c */ char *read_text_file(const char *filename); char *get_line(char **stringp); +void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym); enum loglevel { LOG_WARN, diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c index 905c0ec291..6bf9caca09 100644 --- a/scripts/mod/sumversion.c +++ b/scripts/mod/sumversion.c @@ -290,13 +290,11 @@ static int parse_file(const char *fname, struct md4_ctx *md) return 1; } /* Check whether the file is a static library or not */ -static int is_static_library(const char *objfile) +static bool is_static_library(const char *objfile) { int len = strlen(objfile); - if (objfile[len - 2] == '.' && objfile[len - 1] == 'a') - return 1; - else - return 0; + + return objfile[len - 2] == '.' && objfile[len - 1] == 'a'; } /* We have dir/file.o. Open dir/.file.o.cmd, look for source_ and deps_ line @@ -387,7 +385,7 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md) /* Calc and record src checksum. */ void get_src_version(const char *modname, char sum[], unsigned sumlen) { - char *buf, *pos, *firstline; + char *buf; struct md4_ctx md; char *fname; char filelist[PATH_MAX + 1]; @@ -397,15 +395,8 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen) buf = read_text_file(filelist); - pos = buf; - firstline = get_line(&pos); - if (!firstline) { - warn("bad ending versions file for %s\n", modname); - goto free; - } - md4_init(&md); - while ((fname = strsep(&firstline, " "))) { + while ((fname = strsep(&buf, "\n"))) { if (!*fname) continue; if (!(is_static_library(fname)) && diff --git a/scripts/module.lds.S b/scripts/module.lds.S index 1d0e1e4dc3..3a3aa2354e 100644 --- a/scripts/module.lds.S +++ b/scripts/module.lds.S @@ -27,6 +27,8 @@ SECTIONS { .ctors 0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) } .init_array 0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) } + .altinstructions 0 : ALIGN(8) { KEEP(*(.altinstructions)) } + __bug_table 0 : ALIGN(8) { KEEP(*(__bug_table)) } __jump_table 0 : ALIGN(8) { KEEP(*(__jump_table)) } __patchable_function_entries : { *(__patchable_function_entries) } diff --git a/scripts/nsdeps b/scripts/nsdeps index 04c4b96e95..f1718cc0d7 100644 --- a/scripts/nsdeps +++ b/scripts/nsdeps @@ -34,9 +34,8 @@ generate_deps() { local mod=${1%.ko:} shift local namespaces="$*" - local mod_source_files="`cat $mod.mod | sed -n 1p \ - | sed -e 's/\.o/\.c/g' \ - | sed "s|[^ ]* *|${src_prefix}&|g"`" + local mod_source_files=$(sed "s|^\(.*\)\.o$|${src_prefix}\1.c|" $mod.mod) + for ns in $namespaces; do echo "Adding namespace $ns to module $mod.ko." generate_deps_for_ns $ns "$mod_source_files" diff --git a/scripts/objdiff b/scripts/objdiff index 72b0b63c3f..0685bc3ce3 100644 --- a/scripts/objdiff +++ b/scripts/objdiff @@ -20,10 +20,10 @@ # $ ./scripts/objdiff diff COMMIT_A COMMIT_B # $ -# And to clean up (everything is in .tmp_objdiff/*) +# And to clean up (everything is in .objdiff/*) # $ ./scripts/objdiff clean all # -# Note: 'make mrproper' will also remove .tmp_objdiff +# Note: 'make mrproper' will also remove .objdiff SRCTREE=$(cd $(git rev-parse --show-toplevel 2>/dev/null); pwd) @@ -32,7 +32,7 @@ if [ -z "$SRCTREE" ]; then exit 1 fi -TMPD=$SRCTREE/.tmp_objdiff +TMPD=$SRCTREE/.objdiff usage() { echo >&2 "Usage: $0 " diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 91a502bb97..67cd420dcf 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -67,7 +67,7 @@ deploy_kernel_headers () { ) > debian/hdrsrcfiles { - if is_enabled CONFIG_STACK_VALIDATION; then + if is_enabled CONFIG_OBJTOOL; then echo tools/objtool/objtool fi diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 7c477ca7dc..8fa7c5b8a1 100644 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -49,6 +49,9 @@ sed -e '/^DEL/d' -e 's/^\t*//' <name = stoupperx(map->name); - for (j = 0; map->perms[j]; j++) - map->perms[j] = stoupperx(map->perms[j]); - } - - isids_len = sizeof(initial_sid_to_string) / sizeof (char *); - for (i = 1; i < isids_len; i++) { - const char *s = initial_sid_to_string[i]; - - if (s) - initial_sid_to_string[i] = stoupperx(s); - } - fprintf(fout, "/* This file is automatically generated. Do not edit. */\n"); fprintf(fout, "#ifndef _SELINUX_FLASK_H_\n#define _SELINUX_FLASK_H_\n\n"); for (i = 0; secclass_map[i].name; i++) { - struct security_class_mapping *map = &secclass_map[i]; - fprintf(fout, "#define SECCLASS_%-39s %2d\n", map->name, i+1); + char *name = stoupperx(secclass_map[i].name); + + fprintf(fout, "#define SECCLASS_%-39s %2d\n", name, i+1); + free(name); } fprintf(fout, "\n"); + isids_len = sizeof(initial_sid_to_string) / sizeof(char *); for (i = 1; i < isids_len; i++) { const char *s = initial_sid_to_string[i]; - if (s) - fprintf(fout, "#define SECINITSID_%-39s %2d\n", s, i); + if (s) { + char *sidname = stoupperx(s); + + fprintf(fout, "#define SECINITSID_%-39s %2d\n", sidname, i); + free(sidname); + } } fprintf(fout, "\n#define SECINITSID_NUM %d\n", i-1); fprintf(fout, "\nstatic inline bool security_is_socket_class(u16 kern_tclass)\n"); @@ -96,10 +88,14 @@ int main(int argc, char *argv[]) fprintf(fout, "\tswitch (kern_tclass) {\n"); for (i = 0; secclass_map[i].name; i++) { static char s[] = "SOCKET"; - struct security_class_mapping *map = &secclass_map[i]; - int len = strlen(map->name), l = sizeof(s) - 1; - if (len >= l && memcmp(map->name + len - l, s, l) == 0) - fprintf(fout, "\tcase SECCLASS_%s:\n", map->name); + int len, l; + char *name = stoupperx(secclass_map[i].name); + + len = strlen(name); + l = sizeof(s) - 1; + if (len >= l && memcmp(name + len - l, s, l) == 0) + fprintf(fout, "\tcase SECCLASS_%s:\n", name); + free(name); } fprintf(fout, "\t\tsock = true;\n"); fprintf(fout, "\t\tbreak;\n"); @@ -110,33 +106,52 @@ int main(int argc, char *argv[]) fprintf(fout, "}\n"); fprintf(fout, "\n#endif\n"); - fclose(fout); + + if (fclose(fout) != 0) { + fprintf(stderr, "Could not successfully close %s: %s\n", + argv[1], strerror(errno)); + exit(4); + } fout = fopen(argv[2], "w"); if (!fout) { fprintf(stderr, "Could not open %s for writing: %s\n", argv[2], strerror(errno)); - exit(4); + exit(5); } fprintf(fout, "/* This file is automatically generated. Do not edit. */\n"); fprintf(fout, "#ifndef _SELINUX_AV_PERMISSIONS_H_\n#define _SELINUX_AV_PERMISSIONS_H_\n\n"); for (i = 0; secclass_map[i].name; i++) { - struct security_class_mapping *map = &secclass_map[i]; - int len = strlen(map->name); + const struct security_class_mapping *map = &secclass_map[i]; + int len; + char *name = stoupperx(map->name); + + len = strlen(name); for (j = 0; map->perms[j]; j++) { + char *permname; + if (j >= 32) { fprintf(stderr, "Too many permissions to fit into an access vector at (%s, %s).\n", map->name, map->perms[j]); exit(5); } - fprintf(fout, "#define %s__%-*s 0x%08xU\n", map->name, - 39-len, map->perms[j], 1U<perms[j]); + fprintf(fout, "#define %s__%-*s 0x%08xU\n", name, + 39-len, permname, 1U<name); fprintf(fout, "{\n"); for (j = 0; map->perms[j]; j++) @@ -103,7 +103,7 @@ int main(int argc, char *argv[]) #define SYSTEMLOW "s0" #define SYSTEMHIGH "s1:c0.c1" for (i = 0; secclass_map[i].name; i++) { - struct security_class_mapping *map = &secclass_map[i]; + const struct security_class_mapping *map = &secclass_map[i]; fprintf(fout, "mlsconstrain %s {\n", map->name); for (j = 0; map->perms[j]; j++) diff --git a/scripts/sign-file.c b/scripts/sign-file.c index fbd34b8e8f..598ef5465f 100644 --- a/scripts/sign-file.c +++ b/scripts/sign-file.c @@ -29,6 +29,13 @@ #include #include +/* + * OpenSSL 3.0 deprecates the OpenSSL's ENGINE API. + * + * Remove this if/when that API is no longer used + */ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + /* * Use CMS if we have openssl-1.0.0 or newer available - otherwise we have to * assume that it's not available and its header file is missing and that we @@ -107,7 +114,7 @@ static void drain_openssl_errors(void) bool __cond = (cond); \ display_openssl_errors(__LINE__); \ if (__cond) { \ - err(1, fmt, ## __VA_ARGS__); \ + errx(1, fmt, ## __VA_ARGS__); \ } \ } while(0) diff --git a/scripts/sorttable.c b/scripts/sorttable.c index d00504c5f5..fba40e99f3 100644 --- a/scripts/sorttable.c +++ b/scripts/sorttable.c @@ -60,6 +60,10 @@ #define EM_RISCV 243 #endif +#ifndef EM_LOONGARCH +#define EM_LOONGARCH 258 +#endif + static uint32_t (*r)(const uint32_t *); static uint16_t (*r2)(const uint16_t *); static uint64_t (*r8)(const uint64_t *); @@ -313,6 +317,7 @@ static int do_file(char const *const fname, void *addr) case EM_ARCOMPACT: case EM_ARCV2: case EM_ARM: + case EM_LOONGARCH: case EM_MICROBLAZE: case EM_MIPS: case EM_XTENSA: diff --git a/scripts/spdxcheck-test.sh b/scripts/spdxcheck-test.sh index cb76324756..9f6d1a74da 100644 --- a/scripts/spdxcheck-test.sh +++ b/scripts/spdxcheck-test.sh @@ -1,7 +1,7 @@ #!/bin/sh # run check on a text and a binary file -for FILE in Makefile Documentation/logo.gif; do +for FILE in Makefile Documentation/images/logo.gif; do python3 scripts/spdxcheck.py $FILE python3 scripts/spdxcheck.py - < $FILE done diff --git a/scripts/spdxcheck.py b/scripts/spdxcheck.py index f3be8ed54f..18cb9f5b3d 100644 --- a/scripts/spdxcheck.py +++ b/scripts/spdxcheck.py @@ -6,6 +6,7 @@ from argparse import ArgumentParser from ply import lex, yacc import locale import traceback +import fnmatch import sys import git import re @@ -28,6 +29,21 @@ class SPDXdata(object): self.licenses = [ ] self.exceptions = { } +class dirinfo(object): + def __init__(self): + self.missing = 0 + self.total = 0 + self.files = [] + + def update(self, fname, basedir, miss): + self.total += 1 + self.missing += miss + if miss: + fname = './' + fname + bdir = os.path.dirname(fname) + if bdir == basedir.rstrip('/'): + self.files.append(fname) + # Read the spdx data from the LICENSES directory def read_spdxdata(repo): @@ -91,11 +107,25 @@ class id_parser(object): self.parser = yacc.yacc(module = self, write_tables = False, debug = False) self.lines_checked = 0 self.checked = 0 + self.excluded = 0 self.spdx_valid = 0 self.spdx_errors = 0 + self.spdx_dirs = {} + self.dirdepth = -1 + self.basedir = '.' self.curline = 0 self.deepest = 0 + def set_dirinfo(self, basedir, dirdepth): + if dirdepth >= 0: + self.basedir = basedir + bdir = basedir.lstrip('./').rstrip('/') + if bdir != '': + parts = bdir.split('/') + else: + parts = [] + self.dirdepth = dirdepth + len(parts) + # Validate License and Exception IDs def validate(self, tok): id = tok.value.upper() @@ -167,6 +197,7 @@ class id_parser(object): def parse_lines(self, fd, maxlines, fname): self.checked += 1 self.curline = 0 + fail = 1 try: for line in fd: line = line.decode(locale.getpreferredencoding(False), errors='ignore') @@ -192,6 +223,7 @@ class id_parser(object): # Should we check for more SPDX ids in the same file and # complain if there are any? # + fail = 0 break except ParserException as pe: @@ -203,28 +235,102 @@ class id_parser(object): sys.stdout.write('%s: %d:0 %s\n' %(fname, self.curline, pe.txt)) self.spdx_errors += 1 -def scan_git_tree(tree): + if fname == '-': + return + + base = os.path.dirname(fname) + if self.dirdepth > 0: + parts = base.split('/') + i = 0 + base = '.' + while i < self.dirdepth and i < len(parts) and len(parts[i]): + base += '/' + parts[i] + i += 1 + elif self.dirdepth == 0: + base = self.basedir + else: + base = './' + base.rstrip('/') + base += '/' + + di = self.spdx_dirs.get(base, dirinfo()) + di.update(fname, base, fail) + self.spdx_dirs[base] = di + +class pattern(object): + def __init__(self, line): + self.pattern = line + self.match = self.match_file + if line == '.*': + self.match = self.match_dot + elif line.endswith('/'): + self.pattern = line[:-1] + self.match = self.match_dir + elif line.startswith('/'): + self.pattern = line[1:] + self.match = self.match_fn + + def match_dot(self, fpath): + return os.path.basename(fpath).startswith('.') + + def match_file(self, fpath): + return os.path.basename(fpath) == self.pattern + + def match_fn(self, fpath): + return fnmatch.fnmatchcase(fpath, self.pattern) + + def match_dir(self, fpath): + if self.match_fn(os.path.dirname(fpath)): + return True + return fpath.startswith(self.pattern) + +def exclude_file(fpath): + for rule in exclude_rules: + if rule.match(fpath): + return True + return False + +def scan_git_tree(tree, basedir, dirdepth): + parser.set_dirinfo(basedir, dirdepth) for el in tree.traverse(): - # Exclude stuff which would make pointless noise - # FIXME: Put this somewhere more sensible - if el.path.startswith("LICENSES"): - continue - if el.path.find("license-rules.rst") >= 0: - continue if not os.path.isfile(el.path): continue + if exclude_file(el.path): + parser.excluded += 1 + continue with open(el.path, 'rb') as fd: parser.parse_lines(fd, args.maxlines, el.path) -def scan_git_subtree(tree, path): +def scan_git_subtree(tree, path, dirdepth): for p in path.strip('/').split('/'): tree = tree[p] - scan_git_tree(tree) + scan_git_tree(tree, path.strip('/'), dirdepth) + +def read_exclude_file(fname): + rules = [] + if not fname: + return rules + with open(fname) as fd: + for line in fd: + line = line.strip() + if line.startswith('#'): + continue + if not len(line): + continue + rules.append(pattern(line)) + return rules if __name__ == '__main__': ap = ArgumentParser(description='SPDX expression checker') ap.add_argument('path', nargs='*', help='Check path or file. If not given full git tree scan. For stdin use "-"') + ap.add_argument('-d', '--dirs', action='store_true', + help='Show [sub]directory statistics.') + ap.add_argument('-D', '--depth', type=int, default=-1, + help='Directory depth for -d statistics. Default: unlimited') + ap.add_argument('-e', '--exclude', + help='File containing file patterns to exclude. Default: scripts/spdxexclude') + ap.add_argument('-f', '--files', action='store_true', + help='Show files without SPDX.') ap.add_argument('-m', '--maxlines', type=int, default=15, help='Maximum number of lines to scan in a file. Default 15') ap.add_argument('-v', '--verbose', action='store_true', help='Verbose statistics output') @@ -258,6 +364,15 @@ if __name__ == '__main__': sys.stderr.write('%s\n' %traceback.format_exc()) sys.exit(1) + try: + fname = args.exclude + if not fname: + fname = os.path.join(os.path.dirname(__file__), 'spdxexclude') + exclude_rules = read_exclude_file(fname) + except Exception as ex: + sys.stderr.write('FAIL: Reading exclude file %s: %s\n' %(fname, ex)) + sys.exit(1) + try: if len(args.path) and args.path[0] == '-': stdin = os.fdopen(sys.stdin.fileno(), 'rb') @@ -268,13 +383,21 @@ if __name__ == '__main__': if os.path.isfile(p): parser.parse_lines(open(p, 'rb'), args.maxlines, p) elif os.path.isdir(p): - scan_git_subtree(repo.head.reference.commit.tree, p) + scan_git_subtree(repo.head.reference.commit.tree, p, + args.depth) else: sys.stderr.write('path %s does not exist\n' %p) sys.exit(1) else: # Full git tree scan - scan_git_tree(repo.head.commit.tree) + scan_git_tree(repo.head.commit.tree, '.', args.depth) + + ndirs = len(parser.spdx_dirs) + dirsok = 0 + if ndirs: + for di in parser.spdx_dirs.values(): + if not di.missing: + dirsok += 1 if args.verbose: sys.stderr.write('\n') @@ -283,10 +406,38 @@ if __name__ == '__main__': sys.stderr.write('License IDs %12d\n' %len(spdx.licenses)) sys.stderr.write('Exception IDs %12d\n' %len(spdx.exceptions)) sys.stderr.write('\n') + sys.stderr.write('Files excluded: %12d\n' %parser.excluded) sys.stderr.write('Files checked: %12d\n' %parser.checked) sys.stderr.write('Lines checked: %12d\n' %parser.lines_checked) - sys.stderr.write('Files with SPDX: %12d\n' %parser.spdx_valid) + if parser.checked: + pc = int(100 * parser.spdx_valid / parser.checked) + sys.stderr.write('Files with SPDX: %12d %3d%%\n' %(parser.spdx_valid, pc)) sys.stderr.write('Files with errors: %12d\n' %parser.spdx_errors) + if ndirs: + sys.stderr.write('\n') + sys.stderr.write('Directories accounted: %8d\n' %ndirs) + pc = int(100 * dirsok / ndirs) + sys.stderr.write('Directories complete: %8d %3d%%\n' %(dirsok, pc)) + + if ndirs and ndirs != dirsok and args.dirs: + if args.verbose: + sys.stderr.write('\n') + sys.stderr.write('Incomplete directories: SPDX in Files\n') + for f in sorted(parser.spdx_dirs.keys()): + di = parser.spdx_dirs[f] + if di.missing: + valid = di.total - di.missing + pc = int(100 * valid / di.total) + sys.stderr.write(' %-80s: %5d of %5d %3d%%\n' %(f, valid, di.total, pc)) + + if ndirs and ndirs != dirsok and args.files: + if args.verbose or args.dirs: + sys.stderr.write('\n') + sys.stderr.write('Files without SPDX:\n') + for f in sorted(parser.spdx_dirs.keys()): + di = parser.spdx_dirs[f] + for f in sorted(di.files): + sys.stderr.write(' %s\n' %f) sys.exit(0) diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index f126ecbb04..ec84fc6277 100644 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -25,6 +25,7 @@ my $need_sphinx = 0; my $need_pip = 0; my $need_virtualenv = 0; my $rec_sphinx_upgrade = 0; +my $verbose_warn_install = 1; my $install = ""; my $virtenv_dir = ""; my $python_cmd = ""; @@ -103,10 +104,12 @@ sub check_missing(%) next; } - if ($is_optional) { - print "Warning: better to also install \"$prog\".\n"; - } else { - print "ERROR: please install \"$prog\", otherwise, build won't work.\n"; + if ($verbose_warn_install) { + if ($is_optional) { + print "Warning: better to also install \"$prog\".\n"; + } else { + print "ERROR: please install \"$prog\", otherwise, build won't work.\n"; + } } if (defined($map{$prog})) { $install .= " " . $map{$prog}; @@ -386,7 +389,8 @@ sub give_debian_hints() check_missing(\%map); return if (!$need && !$optional); - printf("You should run:\n\n\tsudo apt-get install $install\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n\tsudo apt-get install $install\n"); } sub give_redhat_hints() @@ -458,10 +462,12 @@ sub give_redhat_hints() if (!$old) { # dnf, for Fedora 18+ - printf("You should run:\n\n\tsudo dnf install -y $install\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n\tsudo dnf install -y $install\n"); } else { # yum, for RHEL (and clones) or Fedora version < 18 - printf("You should run:\n\n\tsudo yum install -y $install\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n\tsudo yum install -y $install\n"); } } @@ -509,7 +515,8 @@ sub give_opensuse_hints() check_missing(\%map); return if (!$need && !$optional); - printf("You should run:\n\n\tsudo zypper install --no-recommends $install\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n\tsudo zypper install --no-recommends $install\n"); } sub give_mageia_hints() @@ -553,7 +560,8 @@ sub give_mageia_hints() check_missing(\%map); return if (!$need && !$optional); - printf("You should run:\n\n\tsudo $packager_cmd $install\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n\tsudo $packager_cmd $install\n"); } sub give_arch_linux_hints() @@ -583,7 +591,8 @@ sub give_arch_linux_hints() check_missing(\%map); return if (!$need && !$optional); - printf("You should run:\n\n\tsudo pacman -S $install\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n\tsudo pacman -S $install\n"); } sub give_gentoo_hints() @@ -610,7 +619,8 @@ sub give_gentoo_hints() return if (!$need && !$optional); - printf("You should run:\n\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n"); my $imagemagick = "media-gfx/imagemagick svg png"; my $cairo = "media-gfx/graphviz cairo pdf"; @@ -700,7 +710,7 @@ sub check_distros() sub deactivate_help() { - printf "\nIf you want to exit the virtualenv, you can use:\n"; + printf "\n If you want to exit the virtualenv, you can use:\n"; printf "\tdeactivate\n"; } @@ -720,6 +730,12 @@ sub get_virtenv() next if (! -f $sphinx_cmd); my $ver = get_sphinx_version($sphinx_cmd); + + if (!$ver) { + $f =~ s#/bin/activate##; + print("Warning: virtual environment $f is not working.\nPython version upgrade? Remove it with:\n\n\trm -rf $f\n\n"); + } + if ($need_sphinx && ($ver ge $min_version)) { return ($f, $ver); } elsif ($ver gt $cur_version) { @@ -741,7 +757,7 @@ sub recommend_sphinx_upgrade() # Get the highest version from sphinx_*/bin/sphinx-build and the # corresponding command to activate the venv/virtenv - $activate_cmd = get_virtenv(); + ($activate_cmd, $venv_ver) = get_virtenv(); # Store the highest version from Sphinx existing virtualenvs if (($activate_cmd ne "") && ($venv_ver gt $cur_version)) { @@ -759,10 +775,14 @@ sub recommend_sphinx_upgrade() # Either there are already a virtual env or a new one should be created $need_pip = 1; + return if (!$latest_avail_ver); + # Return if the reason is due to an upgrade or not if ($latest_avail_ver lt $rec_version) { $rec_sphinx_upgrade = 1; } + + return $latest_avail_ver; } # @@ -775,12 +795,13 @@ sub recommend_sphinx_version($) { my $virtualenv_cmd = shift; - if ($latest_avail_ver lt $min_pdf_version) { - print "note: If you want pdf, you need at least Sphinx $min_pdf_version.\n"; - } - # Version is OK. Nothing to do. - return if ($cur_version && ($cur_version ge $rec_version)); + if ($cur_version && ($cur_version ge $rec_version)) { + if ($cur_version lt $min_pdf_version) { + print "note: If you want pdf, you need at least Sphinx $min_pdf_version.\n"; + } + return; + }; if (!$need_sphinx) { # sphinx-build is present and its version is >= $min_version @@ -820,13 +841,17 @@ sub recommend_sphinx_version($) } # Suggest newer versions if current ones are too old - if ($latest_avail_ver && $cur_version ge $min_version) { + if ($latest_avail_ver && $latest_avail_ver ge $min_version) { # If there's a good enough version, ask the user to enable it if ($latest_avail_ver ge $rec_version) { printf "\nNeed to activate Sphinx (version $latest_avail_ver) on virtualenv with:\n"; printf "\t. $activate_cmd\n"; deactivate_help(); + if ($latest_avail_ver lt $min_pdf_version) { + print "note: If you want pdf, you need at least Sphinx $min_pdf_version.\n"; + } + return; } @@ -848,7 +873,7 @@ sub recommend_sphinx_version($) print "To upgrade Sphinx, use:\n\n"; } } else { - print "Sphinx needs to be installed either as a package or via pip/pypi with:\n"; + print "\nSphinx needs to be installed either:\n1) via pip/pypi with:\n\n"; } $python_cmd = find_python_no_venv(); @@ -858,6 +883,29 @@ sub recommend_sphinx_version($) printf "\t. $virtenv_dir/bin/activate\n"; printf "\tpip install -r $requirement_file\n"; deactivate_help(); + + printf "\n2) As a package with:\n"; + + my $old_need = $need; + my $old_optional = $optional; + %missing = (); + $pdf = 0; + $optional = 0; + $install = ""; + $verbose_warn_install = 0; + + add_package("python-sphinx", 0); + check_python_module("sphinx_rtd_theme", 1); + + check_distros(); + + $need = $old_need; + $optional = $old_optional; + + printf "\n Please note that Sphinx >= 3.0 will currently produce false-positive\n"; + printf " warning when the same name is used for more than one type (functions,\n"; + printf " structs, enums,...). This is known Sphinx bug. For more details, see:\n"; + printf "\thttps://github.com/sphinx-doc/sphinx/pull/8313\n"; } sub check_needs() @@ -897,7 +945,7 @@ sub check_needs() } } - recommend_sphinx_upgrade(); + my $venv_ver = recommend_sphinx_upgrade(); my $virtualenv_cmd; diff --git a/scripts/subarch.include b/scripts/subarch.include index 776849a3c5..4bd327d0ae 100644 --- a/scripts/subarch.include +++ b/scripts/subarch.include @@ -10,4 +10,4 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ -e s/s390x/s390/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ - -e s/riscv.*/riscv/) + -e s/riscv.*/riscv/ -e s/loongarch.*/loongarch/) diff --git a/scripts/tags.sh b/scripts/tags.sh index 16d475b3e2..e137cf15aa 100644 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -25,13 +25,6 @@ else tree=${srctree}/ fi -# ignore userspace tools -if [ -n "$COMPILED_SOURCE" ]; then - ignore="$ignore ( -path ./tools ) -prune -o" -else - ignore="$ignore ( -path ${tree}tools ) -prune -o" -fi - # Detect if ALLSOURCE_ARCHS is set. If not, we assume SRCARCH if [ "${ALLSOURCE_ARCHS}" = "" ]; then ALLSOURCE_ARCHS=${SRCARCH} @@ -95,10 +88,13 @@ all_sources() all_compiled_sources() { - realpath -es $([ -z "$KBUILD_ABS_SRCTREE" ] && echo --relative-to=.) \ - include/generated/autoconf.h $(find $ignore -name "*.cmd" -exec \ - grep -Poh '(?(?=^source_.* \K).*|(?=^ \K\S).*(?= \\))' {} \+ | - awk '!a[$0]++') | sort -u + { + echo include/generated/autoconf.h + find $ignore -name "*.cmd" -exec \ + grep -Poh '(?(?=^source_.* \K).*|(?=^ \K\S).*(?= \\))' {} \+ | + awk '!a[$0]++' + } | xargs realpath -esq $([ -z "$KBUILD_ABS_SRCTREE" ] && echo --relative-to=.) | + sort -u } all_target_sources() diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py index 7011fbe003..438516bdfb 100644 --- a/scripts/tracing/draw_functrace.py +++ b/scripts/tracing/draw_functrace.py @@ -8,7 +8,7 @@ This script parses a trace provided by the function tracer in kernel/trace/trace_functions.c The resulted trace is processed into a tree to produce a more human view of the call stack by drawing textual but hierarchical tree of -calls. Only the functions's names and the the call time are provided. +calls. Only the functions's names and the call time are provided. Usage: Be sure that you have CONFIG_FUNCTION_TRACER diff --git a/security/Kconfig b/security/Kconfig index 9b2c492558..e6db09a779 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -54,17 +54,6 @@ config SECURITY_NETWORK implement socket and networking access controls. If you are unsure how to answer this question, answer N. -config PAGE_TABLE_ISOLATION - bool "Remove the kernel mapping in user mode" - default y - depends on (X86_64 || X86_PAE) && !UML - help - This feature reduces the number of hardware side channels by - ensuring that the majority of kernel addresses are not mapped - into userspace. - - See Documentation/x86/pti.rst for more details. - config SECURITY_INFINIBAND bool "Infiniband Security Hooks" depends on SECURITY && INFINIBAND @@ -160,20 +149,9 @@ config HARDENED_USERCOPY copy_from_user() functions) by rejecting memory ranges that are larger than the specified heap object, span multiple separately allocated pages, are not on the process stack, - or are part of the kernel text. This kills entire classes + or are part of the kernel text. This prevents entire classes of heap overflow exploits and similar kernel memory exposures. -config HARDENED_USERCOPY_PAGESPAN - bool "Refuse to copy allocations that span multiple pages" - depends on HARDENED_USERCOPY - depends on BROKEN - help - When a multi-page allocation is done without __GFP_COMP, - hardened usercopy will reject attempts to copy it. There are, - however, several cases of this in the kernel that have not all - been removed. This config is intended to be used only while - trying to find such users. - config FORTIFY_SOURCE bool "Harden common str/mem functions against buffer overflows" depends on ARCH_HAS_FORTIFY_SOURCE diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening index ded4d7c0d1..bd2aabb2c6 100644 --- a/security/Kconfig.hardening +++ b/security/Kconfig.hardening @@ -266,4 +266,77 @@ config ZERO_CALL_USED_REGS endmenu +config CC_HAS_RANDSTRUCT + def_bool $(cc-option,-frandomize-layout-seed-file=/dev/null) + +choice + prompt "Randomize layout of sensitive kernel structures" + default RANDSTRUCT_FULL if COMPILE_TEST && (GCC_PLUGINS || CC_HAS_RANDSTRUCT) + default RANDSTRUCT_NONE + help + If you enable this, the layouts of structures that are entirely + function pointers (and have not been manually annotated with + __no_randomize_layout), or structures that have been explicitly + marked with __randomize_layout, will be randomized at compile-time. + This can introduce the requirement of an additional information + exposure vulnerability for exploits targeting these structure + types. + + Enabling this feature will introduce some performance impact, + slightly increase memory usage, and prevent the use of forensic + tools like Volatility against the system (unless the kernel + source tree isn't cleaned after kernel installation). + + The seed used for compilation is in scripts/basic/randomize.seed. + It remains after a "make clean" to allow for external modules to + be compiled with the existing seed and will be removed by a + "make mrproper" or "make distclean". This file should not be made + public, or the structure layout can be determined. + + config RANDSTRUCT_NONE + bool "Disable structure layout randomization" + help + Build normally: no structure layout randomization. + + config RANDSTRUCT_FULL + bool "Fully randomize structure layout" + depends on CC_HAS_RANDSTRUCT || GCC_PLUGINS + select MODVERSIONS if MODULES + help + Fully randomize the member layout of sensitive + structures as much as possible, which may have both a + memory size and performance impact. + + One difference between the Clang and GCC plugin + implementations is the handling of bitfields. The GCC + plugin treats them as fully separate variables, + introducing sometimes significant padding. Clang tries + to keep adjacent bitfields together, but with their bit + ordering randomized. + + config RANDSTRUCT_PERFORMANCE + bool "Limit randomization of structure layout to cache-lines" + depends on GCC_PLUGINS + select MODVERSIONS if MODULES + help + Randomization of sensitive kernel structures will make a + best effort at restricting randomization to cacheline-sized + groups of members. It will further not randomize bitfields + in structures. This reduces the performance hit of RANDSTRUCT + at the cost of weakened randomization. +endchoice + +config RANDSTRUCT + def_bool !RANDSTRUCT_NONE + +config GCC_PLUGIN_RANDSTRUCT + def_bool GCC_PLUGINS && RANDSTRUCT + help + Use GCC plugin to randomize structure layout. + + This plugin was ported from grsecurity/PaX. More + information at: + * https://grsecurity.net/ + * https://pax.grsecurity.net/ + endmenu diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig index 348ed6cfa0..cb3496e00d 100644 --- a/security/apparmor/Kconfig +++ b/security/apparmor/Kconfig @@ -6,8 +6,6 @@ config SECURITY_APPARMOR select SECURITY_PATH select SECURITYFS select SECURITY_NETWORK - select ZLIB_INFLATE - select ZLIB_DEFLATE default n help This enables the AppArmor security module. @@ -17,29 +15,6 @@ config SECURITY_APPARMOR If you are unsure how to answer this question, answer N. -config SECURITY_APPARMOR_HASH - bool "Enable introspection of sha1 hashes for loaded profiles" - depends on SECURITY_APPARMOR - select CRYPTO - select CRYPTO_SHA1 - default y - help - This option selects whether introspection of loaded policy - is available to userspace via the apparmor filesystem. - -config SECURITY_APPARMOR_HASH_DEFAULT - bool "Enable policy hash introspection by default" - depends on SECURITY_APPARMOR_HASH - default y - help - This option selects whether sha1 hashing of loaded policy - is enabled by default. The generation of sha1 hashes for - loaded policy provide system administrators a quick way - to verify that policy in the kernel matches what is expected, - however it can slow down policy load on some devices. In - these cases policy hashing can be disabled by default and - enabled only if needed. - config SECURITY_APPARMOR_DEBUG bool "Build AppArmor with debug code" depends on SECURITY_APPARMOR @@ -69,6 +44,67 @@ config SECURITY_APPARMOR_DEBUG_MESSAGES When enabled, various debug messages will be logged to the kernel message buffer. +config SECURITY_APPARMOR_INTROSPECT_POLICY + bool "Allow loaded policy to be introspected" + depends on SECURITY_APPARMOR + default y + help + This option selects whether introspection of loaded policy + is available to userspace via the apparmor filesystem. This + adds to kernel memory usage. It is required for introspection + of loaded policy, and check point and restore support. It + can be disabled for embedded systems where reducing memory and + cpu is paramount. + +config SECURITY_APPARMOR_HASH + bool "Enable introspection of sha1 hashes for loaded profiles" + depends on SECURITY_APPARMOR_INTROSPECT_POLICY + select CRYPTO + select CRYPTO_SHA1 + default y + help + This option selects whether introspection of loaded policy + hashes is available to userspace via the apparmor + filesystem. This option provides a light weight means of + checking loaded policy. This option adds to policy load + time and can be disabled for small embedded systems. + +config SECURITY_APPARMOR_HASH_DEFAULT + bool "Enable policy hash introspection by default" + depends on SECURITY_APPARMOR_HASH + default y + help + This option selects whether sha1 hashing of loaded policy + is enabled by default. The generation of sha1 hashes for + loaded policy provide system administrators a quick way + to verify that policy in the kernel matches what is expected, + however it can slow down policy load on some devices. In + these cases policy hashing can be disabled by default and + enabled only if needed. + +config SECURITY_APPARMOR_EXPORT_BINARY + bool "Allow exporting the raw binary policy" + depends on SECURITY_APPARMOR_INTROSPECT_POLICY + select ZLIB_INFLATE + select ZLIB_DEFLATE + default y + help + This option allows reading back binary policy as it was loaded. + It increases the amount of kernel memory needed by policy and + also increases policy load time. This option is required for + checkpoint and restore support, and debugging of loaded policy. + +config SECURITY_APPARMOR_PARANOID_LOAD + bool "Perform full verification of loaded policy" + depends on SECURITY_APPARMOR + default y + help + This options allows controlling whether apparmor does a full + verification of loaded policy. This should not be disabled + except for embedded systems where the image is read only, + includes policy, and has some form of integrity check. + Disabling the check will speed up policy loads. + config SECURITY_APPARMOR_KUNIT_TEST bool "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS depends on KUNIT=y && SECURITY_APPARMOR diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 0797edb2fb..d066ccc219 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -36,6 +36,7 @@ #include "include/policy_ns.h" #include "include/resource.h" #include "include/policy_unpack.h" +#include "include/task.h" /* * The apparmor filesystem interface used for policy load and introspection @@ -70,6 +71,7 @@ struct rawdata_f_data { struct aa_loaddata *loaddata; }; +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY #define RAWDATA_F_DATA_BUF(p) (char *)(p + 1) static void rawdata_f_data_free(struct rawdata_f_data *private) @@ -94,9 +96,10 @@ static struct rawdata_f_data *rawdata_f_data_alloc(size_t size) return ret; } +#endif /** - * aa_mangle_name - mangle a profile name to std profile layout form + * mangle_name - mangle a profile name to std profile layout form * @name: profile name to mangle (NOT NULL) * @target: buffer to store mangled name, same length as @name (MAYBE NULL) * @@ -401,7 +404,7 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf, data->size = copy_size; if (copy_from_user(data->data, userbuf, copy_size)) { - kvfree(data); + aa_put_loaddata(data); return ERR_PTR(-EFAULT); } @@ -1201,7 +1204,7 @@ SEQ_NS_FOPS(name); /* policy/raw_data/ * file ops */ - +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY #define SEQ_RAWDATA_FOPS(NAME) \ static int seq_rawdata_ ##NAME ##_open(struct inode *inode, struct file *file)\ { \ @@ -1294,44 +1297,47 @@ SEQ_RAWDATA_FOPS(compressed_size); static int deflate_decompress(char *src, size_t slen, char *dst, size_t dlen) { - int error; - struct z_stream_s strm; +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY + if (aa_g_rawdata_compression_level != 0) { + int error = 0; + struct z_stream_s strm; - if (aa_g_rawdata_compression_level == 0) { - if (dlen < slen) - return -EINVAL; - memcpy(dst, src, slen); - return 0; - } + memset(&strm, 0, sizeof(strm)); - memset(&strm, 0, sizeof(strm)); + strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL); + if (!strm.workspace) + return -ENOMEM; - strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL); - if (!strm.workspace) - return -ENOMEM; - - strm.next_in = src; - strm.avail_in = slen; + strm.next_in = src; + strm.avail_in = slen; - error = zlib_inflateInit(&strm); - if (error != Z_OK) { - error = -ENOMEM; - goto fail_inflate_init; - } + error = zlib_inflateInit(&strm); + if (error != Z_OK) { + error = -ENOMEM; + goto fail_inflate_init; + } - strm.next_out = dst; - strm.avail_out = dlen; + strm.next_out = dst; + strm.avail_out = dlen; - error = zlib_inflate(&strm, Z_FINISH); - if (error != Z_STREAM_END) - error = -EINVAL; - else - error = 0; + error = zlib_inflate(&strm, Z_FINISH); + if (error != Z_STREAM_END) + error = -EINVAL; + else + error = 0; - zlib_inflateEnd(&strm); + zlib_inflateEnd(&strm); fail_inflate_init: - kvfree(strm.workspace); - return error; + kvfree(strm.workspace); + + return error; + } +#endif + + if (dlen < slen) + return -EINVAL; + memcpy(dst, src, slen); + return 0; } static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size, @@ -1492,10 +1498,12 @@ int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata) return PTR_ERR(dent); } +#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ + /** fns to setup dynamic per profile/namespace files **/ -/** +/* * * Requires: @profile->ns->lock held */ @@ -1522,7 +1530,7 @@ void __aafs_profile_rmdir(struct aa_profile *profile) } } -/** +/* * * Requires: @old->ns->lock held */ @@ -1557,6 +1565,7 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name, return dent; } +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY static int profile_depth(struct aa_profile *profile) { int depth = 0; @@ -1658,7 +1667,7 @@ static const struct inode_operations rawdata_link_abi_iops = { static const struct inode_operations rawdata_link_data_iops = { .get_link = rawdata_get_link_data, }; - +#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ /* * Requires: @profile->ns->lock held @@ -1729,15 +1738,17 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) profile->dents[AAFS_PROF_HASH] = dent; } +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY if (profile->rawdata) { - dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir, - profile->label.proxy, NULL, NULL, - &rawdata_link_sha1_iops); - if (IS_ERR(dent)) - goto fail; - aa_get_proxy(profile->label.proxy); - profile->dents[AAFS_PROF_RAW_HASH] = dent; - + if (aa_g_hash_policy) { + dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir, + profile->label.proxy, NULL, NULL, + &rawdata_link_sha1_iops); + if (IS_ERR(dent)) + goto fail; + aa_get_proxy(profile->label.proxy); + profile->dents[AAFS_PROF_RAW_HASH] = dent; + } dent = aafs_create("raw_abi", S_IFLNK | 0444, dir, profile->label.proxy, NULL, NULL, &rawdata_link_abi_iops); @@ -1754,6 +1765,7 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) aa_get_proxy(profile->label.proxy); profile->dents[AAFS_PROF_RAW_DATA] = dent; } +#endif /*CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ list_for_each_entry(child, &profile->base.profiles, base.list) { error = __aafs_profile_mkdir(child, prof_child_dir(profile)); @@ -1880,7 +1892,7 @@ static void __aa_fs_list_remove_rawdata(struct aa_ns *ns) __aa_fs_remove_rawdata(ent); } -/** +/* * * Requires: @ns->lock held */ @@ -2323,6 +2335,7 @@ static struct aa_sfs_entry aa_sfs_entry_versions[] = { AA_SFS_FILE_BOOLEAN("v6", 1), AA_SFS_FILE_BOOLEAN("v7", 1), AA_SFS_FILE_BOOLEAN("v8", 1), + AA_SFS_FILE_BOOLEAN("v9", 1), { } }; diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index f7e97c7e80..704b0c8956 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -137,7 +137,7 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, } if (AUDIT_MODE(profile) == AUDIT_QUIET || (type == AUDIT_APPARMOR_DENIED && - AUDIT_MODE(profile) == AUDIT_QUIET)) + AUDIT_MODE(profile) == AUDIT_QUIET_DENIED)) return aad(sa)->error; if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index a29e69d2c3..91689d34d2 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -119,7 +119,7 @@ static inline unsigned int match_component(struct aa_profile *profile, * @profile: profile to find perms for * @label: label to check access permissions for * @stack: whether this is a stacking request - * @start: state to start match in + * @state: state to start match in * @subns: whether to do permission checks on components in a subns * @request: permissions to request * @perms: perms struct to set @@ -466,7 +466,7 @@ static struct aa_label *find_attach(const struct linux_binprm *bprm, * xattrs, or a longer match */ candidate = profile; - candidate_len = profile->xmatch_len; + candidate_len = max(count, profile->xmatch_len); candidate_xattrs = ret; conflict = false; } @@ -1279,7 +1279,6 @@ static int change_profile_perms_wrapper(const char *op, const char *name, /** * aa_change_profile - perform a one-way profile transition * @fqname: name of profile may include namespace (NOT NULL) - * @onexec: whether this transition is to take place immediately or at exec * @flags: flags affecting change behavior * * Change to new profile @name. Unlike with hats, there is no way diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 1fbabdb565..9c3fc36a07 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -36,6 +36,7 @@ extern enum audit_mode aa_g_audit; extern bool aa_g_audit_header; extern bool aa_g_debug; extern bool aa_g_hash_policy; +extern bool aa_g_export_binary; extern int aa_g_rawdata_compression_level; extern bool aa_g_lock_policy; extern bool aa_g_logsyscall; diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index 6e14f6cecd..1e94904f68 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h @@ -114,7 +114,21 @@ int __aafs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name, struct dentry *dent); struct aa_loaddata; + +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata); int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata); +#else +static inline void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata) +{ + /* empty stub */ +} + +static inline int __aa_fs_create_rawdata(struct aa_ns *ns, + struct aa_loaddata *rawdata) +{ + return 0; +} +#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ #endif /* __AA_APPARMORFS_H */ diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 7517605a18..029cb20e32 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -142,6 +142,7 @@ static inline u16 dfa_map_xindex(u16 mask) */ #define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \ ((ACCEPT_TABLE(dfa)[state]) & 0x80000000)) +#define dfa_user_xbits(dfa, state) (((ACCEPT_TABLE(dfa)[state]) >> 7) & 0x7f) #define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f) #define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f) #define dfa_user_xindex(dfa, state) \ @@ -150,6 +151,8 @@ static inline u16 dfa_map_xindex(u16 mask) #define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \ 0x7f) | \ ((ACCEPT_TABLE(dfa)[state]) & 0x80000000)) +#define dfa_other_xbits(dfa, state) \ + ((((ACCEPT_TABLE(dfa)[state]) >> 7) >> 14) & 0x7f) #define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f) #define dfa_other_quiet(dfa, state) \ ((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f) diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h index 9cafd80f77..a1ac6ffb95 100644 --- a/security/apparmor/include/ipc.h +++ b/security/apparmor/include/ipc.h @@ -13,24 +13,6 @@ #include -struct aa_profile; - -#define AA_PTRACE_TRACE MAY_WRITE -#define AA_PTRACE_READ MAY_READ -#define AA_MAY_BE_TRACED AA_MAY_APPEND -#define AA_MAY_BE_READ AA_MAY_CREATE -#define PTRACE_PERM_SHIFT 2 - -#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \ - AA_MAY_BE_READ | AA_MAY_BE_TRACED) -#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE) - -#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \ - "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \ - "xcpu xfsz vtalrm prof winch io pwr sys emt lost" - -int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, - u32 request); int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig); #endif /* __AA_IPC_H */ diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h index 9101c2c76d..860484c6f9 100644 --- a/security/apparmor/include/label.h +++ b/security/apparmor/include/label.h @@ -92,6 +92,8 @@ enum label_flags { FLAG_STALE = 0x800, /* replaced/removed */ FLAG_RENAMED = 0x1000, /* label has renaming in it */ FLAG_REVOKED = 0x2000, /* label has revocation in it */ + FLAG_DEBUG1 = 0x4000, + FLAG_DEBUG2 = 0x8000, /* These flags must correspond with PATH_flags */ /* TODO: add new path flags */ diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index e2e8df0c6f..f42359f58e 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -22,6 +22,11 @@ */ #define DEBUG_ON (aa_g_debug) +/* + * split individual debug cases out in preparation for finer grained + * debug controls in the future. + */ +#define AA_DEBUG_LABEL DEBUG_ON #define dbg_printk(__fmt, __args...) pr_debug(__fmt, ##__args) #define AA_DEBUG(fmt, args...) \ do { \ diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h index 44a7945fbe..343189903d 100644 --- a/security/apparmor/include/path.h +++ b/security/apparmor/include/path.h @@ -17,8 +17,8 @@ enum path_flags { PATH_CHROOT_REL = 0x8, /* do path lookup relative to chroot */ PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */ - PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */ - PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */ + PATH_DELEGATE_DELETED = 0x10000, /* delegate deleted files */ + PATH_MEDIATE_DELETED = 0x20000, /* mediate deleted paths */ }; int aa_path_name(const struct path *path, int flags, char *buffer, diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index cb5ef21991..639b5b248e 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -48,6 +48,10 @@ extern const char *const aa_profile_mode_names[]; #define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT) +#define CHECK_DEBUG1(_profile) ((_profile)->label.flags & FLAG_DEBUG1) + +#define CHECK_DEBUG2(_profile) ((_profile)->label.flags & FLAG_DEBUG2) + #define profile_is_stale(_profile) (label_is_stale(&(_profile)->label)) #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) @@ -135,7 +139,7 @@ struct aa_profile { const char *attach; struct aa_dfa *xmatch; - int xmatch_len; + unsigned int xmatch_len; enum audit_mode audit; long mode; u32 path_flags; diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 3df6f80492..33d665516f 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -74,6 +74,7 @@ struct aa_ns { struct dentry *dents[AAFS_NS_SIZEOF]; }; +extern struct aa_label *kernel_t; extern struct aa_ns *root_ns; extern const char *aa_hidden_ns_name; diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h index e0e1ca7ebc..eb5f7d7f13 100644 --- a/security/apparmor/include/policy_unpack.h +++ b/security/apparmor/include/policy_unpack.h @@ -28,6 +28,8 @@ void aa_load_ent_free(struct aa_load_ent *ent); struct aa_load_ent *aa_load_ent_alloc(void); #define PACKED_FLAG_HAT 1 +#define PACKED_FLAG_DEBUG1 2 +#define PACKED_FLAG_DEBUG2 4 #define PACKED_MODE_ENFORCE 0 #define PACKED_MODE_COMPLAIN 1 diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h index 48ff1ddeca..a912a5d5d0 100644 --- a/security/apparmor/include/secid.h +++ b/security/apparmor/include/secid.h @@ -21,6 +21,9 @@ struct aa_label; /* secid value that matches any other secid */ #define AA_SECID_WILDCARD 1 +/* sysctl to enable displaying mode when converting secid to secctx */ +extern int apparmor_display_secid_mode; + struct aa_label *aa_secid_to_label(u32 secid); int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); @@ -31,6 +34,4 @@ int aa_alloc_secid(struct aa_label *label, gfp_t gfp); void aa_free_secid(u32 secid); void aa_secid_update(u32 secid, struct aa_label *label); -void aa_secids_init(void); - #endif /* __AA_SECID_H */ diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h index f13d12373b..13437d62c7 100644 --- a/security/apparmor/include/task.h +++ b/security/apparmor/include/task.h @@ -77,4 +77,22 @@ static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx) ctx->token = 0; } +#define AA_PTRACE_TRACE MAY_WRITE +#define AA_PTRACE_READ MAY_READ +#define AA_MAY_BE_TRACED AA_MAY_APPEND +#define AA_MAY_BE_READ AA_MAY_CREATE +#define PTRACE_PERM_SHIFT 2 + +#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \ + AA_MAY_BE_READ | AA_MAY_BE_TRACED) +#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE) + +#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \ + "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \ + "xcpu xfsz vtalrm prof winch io pwr sys emt lost" + +int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, + u32 request); + + #endif /* __AA_TASK_H */ diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index fe36d112aa..3dbbc59d44 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -9,7 +9,6 @@ */ #include -#include #include "include/audit.h" #include "include/capability.h" @@ -18,115 +17,6 @@ #include "include/ipc.h" #include "include/sig_names.h" -/** - * audit_ptrace_mask - convert mask to permission string - * @mask: permission mask to convert - * - * Returns: pointer to static string - */ -static const char *audit_ptrace_mask(u32 mask) -{ - switch (mask) { - case MAY_READ: - return "read"; - case MAY_WRITE: - return "trace"; - case AA_MAY_BE_READ: - return "readby"; - case AA_MAY_BE_TRACED: - return "tracedby"; - } - return ""; -} - -/* call back to audit ptrace fields */ -static void audit_ptrace_cb(struct audit_buffer *ab, void *va) -{ - struct common_audit_data *sa = va; - - if (aad(sa)->request & AA_PTRACE_PERM_MASK) { - audit_log_format(ab, " requested_mask=\"%s\"", - audit_ptrace_mask(aad(sa)->request)); - - if (aad(sa)->denied & AA_PTRACE_PERM_MASK) { - audit_log_format(ab, " denied_mask=\"%s\"", - audit_ptrace_mask(aad(sa)->denied)); - } - } - audit_log_format(ab, " peer="); - aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, - FLAGS_NONE, GFP_ATOMIC); -} - -/* assumes check for PROFILE_MEDIATES is already done */ -/* TODO: conditionals */ -static int profile_ptrace_perm(struct aa_profile *profile, - struct aa_label *peer, u32 request, - struct common_audit_data *sa) -{ - struct aa_perms perms = { }; - - aad(sa)->peer = peer; - aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request, - &perms); - aa_apply_modes_to_perms(profile, &perms); - return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); -} - -static int profile_tracee_perm(struct aa_profile *tracee, - struct aa_label *tracer, u32 request, - struct common_audit_data *sa) -{ - if (profile_unconfined(tracee) || unconfined(tracer) || - !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE)) - return 0; - - return profile_ptrace_perm(tracee, tracer, request, sa); -} - -static int profile_tracer_perm(struct aa_profile *tracer, - struct aa_label *tracee, u32 request, - struct common_audit_data *sa) -{ - if (profile_unconfined(tracer)) - return 0; - - if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) - return profile_ptrace_perm(tracer, tracee, request, sa); - - /* profile uses the old style capability check for ptrace */ - if (&tracer->label == tracee) - return 0; - - aad(sa)->label = &tracer->label; - aad(sa)->peer = tracee; - aad(sa)->request = 0; - aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, - CAP_OPT_NONE); - - return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); -} - -/** - * aa_may_ptrace - test if tracer task can trace the tracee - * @tracer: label of the task doing the tracing (NOT NULL) - * @tracee: task label to be traced - * @request: permission request - * - * Returns: %0 else error code if permission denied or error - */ -int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, - u32 request) -{ - struct aa_profile *profile; - u32 xrequest = request << PTRACE_PERM_SHIFT; - DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); - - return xcheck_labels(tracer, tracee, profile, - profile_tracer_perm(profile, tracee, request, &sa), - profile_tracee_perm(profile, tracer, xrequest, &sa)); -} - static inline int map_signal_num(int sig) { diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 0b0265da19..0f36ee9074 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -197,18 +197,18 @@ static bool vec_is_stale(struct aa_profile **vec, int n) return false; } -static bool vec_unconfined(struct aa_profile **vec, int n) +static long union_vec_flags(struct aa_profile **vec, int n, long mask) { + long u = 0; int i; AA_BUG(!vec); for (i = 0; i < n; i++) { - if (!profile_unconfined(vec[i])) - return false; + u |= vec[i]->label.flags & mask; } - return true; + return u; } static int sort_cmp(const void *a, const void *b) @@ -485,7 +485,7 @@ int aa_label_next_confined(struct aa_label *label, int i) } /** - * aa_label_next_not_in_set - return the next profile of @sub not in @set + * __aa_label_next_not_in_set - return the next profile of @sub not in @set * @I: label iterator * @set: label to test against * @sub: label to if is subset of @set @@ -1097,8 +1097,8 @@ static struct aa_label *label_merge_insert(struct aa_label *new, else if (k == b->size) return aa_get_label(b); } - if (vec_unconfined(new->vec, new->size)) - new->flags |= FLAG_UNCONFINED; + new->flags |= union_vec_flags(new->vec, new->size, FLAG_UNCONFINED | + FLAG_DEBUG1 | FLAG_DEBUG2); ls = labels_set(new); write_lock_irqsave(&ls->lock, flags); label = __label_insert(labels_set(new), new, false); @@ -1631,9 +1631,9 @@ int aa_label_snxprint(char *str, size_t size, struct aa_ns *ns, AA_BUG(!str && size != 0); AA_BUG(!label); - if (flags & FLAG_ABS_ROOT) { + if (AA_DEBUG_LABEL && (flags & FLAG_ABS_ROOT)) { ns = root_ns; - len = snprintf(str, size, "="); + len = snprintf(str, size, "_"); update_for_len(total, len, size, str); } else if (!ns) { ns = labels_ns(label); @@ -1744,7 +1744,7 @@ void aa_label_xaudit(struct audit_buffer *ab, struct aa_ns *ns, if (!use_label_hname(ns, label, flags) || display_mode(ns, label, flags)) { len = aa_label_asxprint(&name, ns, label, flags, gfp); - if (len == -1) { + if (len < 0) { AA_DEBUG("label print error"); return; } @@ -1772,7 +1772,7 @@ void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns, int len; len = aa_label_asxprint(&str, ns, label, flags, gfp); - if (len == -1) { + if (len < 0) { AA_DEBUG("label print error"); return; } @@ -1795,7 +1795,7 @@ void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags, int len; len = aa_label_asxprint(&str, ns, label, flags, gfp); - if (len == -1) { + if (len < 0) { AA_DEBUG("label print error"); return; } @@ -1895,7 +1895,8 @@ struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str, AA_BUG(!str); str = skipn_spaces(str, n); - if (str == NULL || (*str == '=' && base != &root_ns->unconfined->label)) + if (str == NULL || (AA_DEBUG_LABEL && *str == '_' && + base != &root_ns->unconfined->label)) return ERR_PTR(-EINVAL); len = label_count_strn_entries(str, end - str); @@ -2136,7 +2137,7 @@ static void __labelset_update(struct aa_ns *ns) } /** - * __aa_labelset_udate_subtree - update all labels with a stale component + * __aa_labelset_update_subtree - update all labels with a stale component * @ns: ns to start update at (NOT NULL) * * Requires: @ns lock be held diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index fa49b81eb5..1c72a61108 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -136,7 +136,7 @@ __counted char *aa_str_alloc(int size, gfp_t gfp) { struct counted_str *str; - str = kmalloc(sizeof(struct counted_str) + size, gfp); + str = kmalloc(struct_size(str, name, size), gfp); if (!str) return NULL; @@ -322,22 +322,39 @@ static u32 map_other(u32 x) ((x & 0x60) << 19); /* SETOPT/GETOPT */ } +static u32 map_xbits(u32 x) +{ + return ((x & 0x1) << 7) | + ((x & 0x7e) << 9); +} + void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, struct aa_perms *perms) { + /* This mapping is convulated due to history. + * v1-v4: only file perms + * v5: added policydb which dropped in perm user conditional to + * gain new perm bits, but had to map around the xbits because + * the userspace compiler was still munging them. + * v9: adds using the xbits in policydb because the compiler now + * supports treating policydb permission bits different. + * Unfortunately there is not way to force auditing on the + * perms represented by the xbits + */ *perms = (struct aa_perms) { - .allow = dfa_user_allow(dfa, state), + .allow = dfa_user_allow(dfa, state) | + map_xbits(dfa_user_xbits(dfa, state)), .audit = dfa_user_audit(dfa, state), - .quiet = dfa_user_quiet(dfa, state), + .quiet = dfa_user_quiet(dfa, state) | + map_xbits(dfa_other_xbits(dfa, state)), }; - /* for v5 perm mapping in the policydb, the other set is used + /* for v5-v9 perm mapping in the policydb, the other set is used * to extend the general perm set */ perms->allow |= map_other(dfa_other_allow(dfa, state)); perms->audit |= map_other(dfa_other_audit(dfa, state)); perms->quiet |= map_other(dfa_other_quiet(dfa, state)); -// perms->xindex = dfa_user_xindex(dfa, state); } /** diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 4f0eecb67d..e29cade7b6 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -354,13 +354,16 @@ static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_ } static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_dentry, - const struct path *new_dir, struct dentry *new_dentry) + const struct path *new_dir, struct dentry *new_dentry, + const unsigned int flags) { struct aa_label *label; int error = 0; if (!path_mediated_fs(old_dentry)) return 0; + if ((flags & RENAME_EXCHANGE) && !path_mediated_fs(new_dentry)) + return 0; label = begin_current_label_crit_section(); if (!unconfined(label)) { @@ -374,10 +377,27 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d d_backing_inode(old_dentry)->i_mode }; - error = aa_path_perm(OP_RENAME_SRC, label, &old_path, 0, - MAY_READ | AA_MAY_GETATTR | MAY_WRITE | - AA_MAY_SETATTR | AA_MAY_DELETE, - &cond); + if (flags & RENAME_EXCHANGE) { + struct path_cond cond_exchange = { + i_uid_into_mnt(mnt_userns, d_backing_inode(new_dentry)), + d_backing_inode(new_dentry)->i_mode + }; + + error = aa_path_perm(OP_RENAME_SRC, label, &new_path, 0, + MAY_READ | AA_MAY_GETATTR | MAY_WRITE | + AA_MAY_SETATTR | AA_MAY_DELETE, + &cond_exchange); + if (!error) + error = aa_path_perm(OP_RENAME_DEST, label, &old_path, + 0, MAY_WRITE | AA_MAY_SETATTR | + AA_MAY_CREATE, &cond_exchange); + } + + if (!error) + error = aa_path_perm(OP_RENAME_SRC, label, &old_path, 0, + MAY_READ | AA_MAY_GETATTR | MAY_WRITE | + AA_MAY_SETATTR | AA_MAY_DELETE, + &cond); if (!error) error = aa_path_perm(OP_RENAME_DEST, label, &new_path, 0, MAY_WRITE | AA_MAY_SETATTR | @@ -812,7 +832,7 @@ static void apparmor_sk_free_security(struct sock *sk) } /** - * apparmor_clone_security - clone the sk_security field + * apparmor_sk_clone_security - clone the sk_security field */ static void apparmor_sk_clone_security(const struct sock *sk, struct sock *newsk) @@ -866,10 +886,7 @@ static int apparmor_socket_post_create(struct socket *sock, int family, struct aa_label *label; if (kern) { - struct aa_ns *ns = aa_get_current_ns(); - - label = aa_get_label(ns_unconfined(ns)); - aa_put_ns(ns); + label = aa_get_label(kernel_t); } else label = aa_get_current_label(); @@ -917,7 +934,7 @@ static int apparmor_socket_connect(struct socket *sock, } /** - * apparmor_socket_list - check perms before allowing listen + * apparmor_socket_listen - check perms before allowing listen */ static int apparmor_socket_listen(struct socket *sock, int backlog) { @@ -1021,7 +1038,7 @@ static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock, } /** - * apparmor_getsockopt - check perms before getting socket options + * apparmor_socket_getsockopt - check perms before getting socket options */ static int apparmor_socket_getsockopt(struct socket *sock, int level, int optname) @@ -1031,7 +1048,7 @@ static int apparmor_socket_getsockopt(struct socket *sock, int level, } /** - * apparmor_setsockopt - check perms before setting socket options + * apparmor_socket_setsockopt - check perms before setting socket options */ static int apparmor_socket_setsockopt(struct socket *sock, int level, int optname) @@ -1050,7 +1067,7 @@ static int apparmor_socket_shutdown(struct socket *sock, int how) #ifdef CONFIG_NETWORK_SECMARK /** - * apparmor_socket_sock_recv_skb - check perms before associating skb to sk + * apparmor_socket_sock_rcv_skb - check perms before associating skb to sk * * Note: can not sleep may be called with locks held * @@ -1337,6 +1354,12 @@ bool aa_g_hash_policy = IS_ENABLED(CONFIG_SECURITY_APPARMOR_HASH_DEFAULT); module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR); #endif +/* whether policy exactly as loaded is retained for debug and checkpointing */ +bool aa_g_export_binary = IS_ENABLED(CONFIG_SECURITY_APPARMOR_EXPORT_BINARY); +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY +module_param_named(export_binary, aa_g_export_binary, aabool, 0600); +#endif + /* policy loaddata compression level */ int aa_g_rawdata_compression_level = Z_DEFAULT_COMPRESSION; module_param_named(rawdata_compression_level, aa_g_rawdata_compression_level, @@ -1379,7 +1402,7 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR); * DEPRECATED: read only as strict checking of load is always done now * that none root users (user namespaces) can load policy. */ -bool aa_g_paranoid_load = true; +bool aa_g_paranoid_load = IS_ENABLED(CONFIG_SECURITY_APPARMOR_PARANOID_LOAD); module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO); static int param_get_aaintbool(char *buffer, const struct kernel_param *kp); @@ -1741,6 +1764,14 @@ static struct ctl_table apparmor_sysctl_table[] = { .mode = 0600, .proc_handler = apparmor_dointvec, }, + { + .procname = "apparmor_display_secid_mode", + .data = &apparmor_display_secid_mode, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = apparmor_dointvec, + }, + { } }; @@ -1799,11 +1830,8 @@ static const struct nf_hook_ops apparmor_nf_ops[] = { static int __net_init apparmor_nf_register(struct net *net) { - int ret; - - ret = nf_register_net_hooks(net, apparmor_nf_ops, + return nf_register_net_hooks(net, apparmor_nf_ops, ARRAY_SIZE(apparmor_nf_ops)); - return ret; } static void __net_exit apparmor_nf_unregister(struct net *net) @@ -1837,8 +1865,6 @@ static int __init apparmor_init(void) { int error; - aa_secids_init(); - error = aa_setup_dfa_engine(); if (error) { AA_ERROR("Unable to setup dfa engine\n"); diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index aa6fcfde30..f612472418 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c @@ -217,7 +217,6 @@ static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa, .allow = dfa_user_allow(dfa, state), .audit = dfa_user_audit(dfa, state), .quiet = dfa_user_quiet(dfa, state), - .xindex = dfa_user_xindex(dfa, state), }; return perms; @@ -229,7 +228,8 @@ static const char * const mnt_info_table[] = { "failed srcname match", "failed type match", "failed flags match", - "failed data match" + "failed data match", + "failed perms check" }; /* @@ -284,8 +284,8 @@ static int do_match_mnt(struct aa_dfa *dfa, unsigned int start, return 0; } - /* failed at end of flags match */ - return 4; + /* failed at perms check, don't confuse with flags match */ + return 6; } @@ -303,7 +303,7 @@ static int path_flags(struct aa_profile *profile, const struct path *path) * @profile: the confining profile * @mntpath: for the mntpnt (NOT NULL) * @buffer: buffer to be used to lookup mntpath - * @devnme: string for the devname/src_name (MAY BE NULL OR ERRPTR) + * @devname: string for the devname/src_name (MAY BE NULL OR ERRPTR) * @type: string for the dev type (MAYBE NULL) * @flags: mount flags to match * @data: fs mount data (MAYBE NULL) @@ -358,7 +358,7 @@ static int match_mnt_path_str(struct aa_profile *profile, /** * match_mnt - handle path matching for mount * @profile: the confining profile - * @mntpath: for the mntpnt (NOT NULL) + * @path: for the mntpnt (NOT NULL) * @buffer: buffer to be used to lookup mntpath * @devpath: path devname/src_name (MAYBE NULL) * @devbuffer: buffer to be used to lookup devname/src_name @@ -718,6 +718,7 @@ int aa_pivotroot(struct aa_label *label, const struct path *old_path, aa_put_label(target); goto out; } + aa_put_label(target); } else /* already audited error */ error = PTR_ERR(target); diff --git a/security/apparmor/net.c b/security/apparmor/net.c index e0c1b50d6e..7efe4d1727 100644 --- a/security/apparmor/net.c +++ b/security/apparmor/net.c @@ -145,12 +145,13 @@ int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, struct sock *sk) { + struct aa_sk_ctx *ctx = SK_CTX(sk); int error = 0; AA_BUG(!label); AA_BUG(!sk); - if (!unconfined(label)) { + if (ctx->label != kernel_t && !unconfined(label)) { struct aa_profile *profile; DEFINE_AUDIT_SK(sa, op, sk); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index b0cbc4906c..499c0209b6 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -422,7 +422,7 @@ static struct aa_profile *__lookup_profile(struct aa_policy *base, } /** - * aa_lookup_profile - find a profile by its full or partial name + * aa_lookupn_profile - find a profile by its full or partial name * @ns: the namespace to start from (NOT NULL) * @hname: name to do lookup on. Does not contain namespace prefix (NOT NULL) * @n: size of @hname @@ -952,16 +952,18 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, mutex_lock_nested(&ns->lock, ns->level); /* check for duplicate rawdata blobs: space and file dedup */ - list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) { - if (aa_rawdata_eq(rawdata_ent, udata)) { - struct aa_loaddata *tmp; - - tmp = __aa_get_loaddata(rawdata_ent); - /* check we didn't fail the race */ - if (tmp) { - aa_put_loaddata(udata); - udata = tmp; - break; + if (!list_empty(&ns->rawdata_list)) { + list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) { + if (aa_rawdata_eq(rawdata_ent, udata)) { + struct aa_loaddata *tmp; + + tmp = __aa_get_loaddata(rawdata_ent); + /* check we didn't fail the race */ + if (tmp) { + aa_put_loaddata(udata); + udata = tmp; + break; + } } } } @@ -969,7 +971,8 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, list_for_each_entry(ent, &lh, list) { struct aa_policy *policy; - ent->new->rawdata = aa_get_loaddata(udata); + if (aa_g_export_binary) + ent->new->rawdata = aa_get_loaddata(udata); error = __lookup_replace(ns, ent->new->base.hname, !(mask & AA_MAY_REPLACE_POLICY), &ent->old, &info); @@ -1009,7 +1012,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, } /* create new fs entries for introspection if needed */ - if (!udata->dents[AAFS_LOADDATA_DIR]) { + if (!udata->dents[AAFS_LOADDATA_DIR] && aa_g_export_binary) { error = __aa_fs_create_rawdata(ns, udata); if (error) { info = "failed to create raw_data dir and files"; @@ -1037,12 +1040,14 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, /* Done with checks that may fail - do actual replacement */ __aa_bump_ns_revision(ns); - __aa_loaddata_update(udata, ns->revision); + if (aa_g_export_binary) + __aa_loaddata_update(udata, ns->revision); list_for_each_entry_safe(ent, tmp, &lh, list) { list_del_init(&ent->list); op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL; - if (ent->old && ent->old->rawdata == ent->new->rawdata) { + if (ent->old && ent->old->rawdata == ent->new->rawdata && + ent->new->rawdata) { /* dedup actual profile replacement */ audit_policy(label, op, ns_name, ent->new->base.hname, "same as current profile, skipping", diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 70921d95fb..43beaad083 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -22,6 +22,9 @@ #include "include/label.h" #include "include/policy.h" +/* kernel label */ +struct aa_label *kernel_t; + /* root profile namespace */ struct aa_ns *root_ns; const char *aa_hidden_ns_name = "---"; @@ -51,10 +54,10 @@ bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns) } /** - * aa_na_name - Find the ns name to display for @view from @curr - * @curr - current namespace (NOT NULL) - * @view - namespace attempting to view (NOT NULL) - * @subns - are subns visible + * aa_ns_name - Find the ns name to display for @view from @curr + * @curr: current namespace (NOT NULL) + * @view: namespace attempting to view (NOT NULL) + * @subns: are subns visible * * Returns: name of @view visible from @curr */ @@ -77,6 +80,23 @@ const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view, bool subns) return aa_hidden_ns_name; } +static struct aa_profile *alloc_unconfined(const char *name) +{ + struct aa_profile *profile; + + profile = aa_alloc_profile(name, NULL, GFP_KERNEL); + if (!profile) + return NULL; + + profile->label.flags |= FLAG_IX_ON_NAME_ERROR | + FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED; + profile->mode = APPARMOR_UNCONFINED; + profile->file.dfa = aa_get_dfa(nulldfa); + profile->policy.dfa = aa_get_dfa(nulldfa); + + return profile; +} + /** * alloc_ns - allocate, initialize and return a new namespace * @prefix: parent namespace name (MAYBE NULL) @@ -101,16 +121,9 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name) init_waitqueue_head(&ns->wait); /* released by aa_free_ns() */ - ns->unconfined = aa_alloc_profile("unconfined", NULL, GFP_KERNEL); + ns->unconfined = alloc_unconfined("unconfined"); if (!ns->unconfined) goto fail_unconfined; - - ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR | - FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED; - ns->unconfined->mode = APPARMOR_UNCONFINED; - ns->unconfined->file.dfa = aa_get_dfa(nulldfa); - ns->unconfined->policy.dfa = aa_get_dfa(nulldfa); - /* ns and ns->unconfined share ns->unconfined refcount */ ns->unconfined->ns = ns; @@ -187,7 +200,7 @@ struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name) /** * __aa_lookupn_ns - lookup the namespace matching @hname - * @base: base list to start looking up profile name from (NOT NULL) + * @view: namespace to search in (NOT NULL) * @hname: hierarchical ns name (NOT NULL) * @n: length of @hname * @@ -272,7 +285,7 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, } /** - * aa_create_ns - create an ns, fail if it already exists + * __aa_find_or_create_ns - create an ns, fail if it already exists * @parent: the parent of the namespace being created * @name: the name of the namespace * @dir: if not null the dir to put the ns entries in @@ -388,11 +401,22 @@ static void __ns_list_release(struct list_head *head) */ int __init aa_alloc_root_ns(void) { + struct aa_profile *kernel_p; + /* released by aa_free_root_ns - used as list ref*/ root_ns = alloc_ns(NULL, "root"); if (!root_ns) return -ENOMEM; + kernel_p = alloc_unconfined("kernel_t"); + if (!kernel_p) { + destroy_ns(root_ns); + aa_free_ns(root_ns); + return -ENOMEM; + } + kernel_t = &kernel_p->label; + root_ns->unconfined->ns = aa_get_ns(root_ns); + return 0; } @@ -405,6 +429,7 @@ void __init aa_free_root_ns(void) root_ns = NULL; + aa_label_free(kernel_t); destroy_ns(ns); aa_put_ns(ns); } diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 0acca6f2a9..55d31bac4f 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -125,15 +125,16 @@ void __aa_loaddata_update(struct aa_loaddata *data, long revision) { AA_BUG(!data); AA_BUG(!data->ns); - AA_BUG(!data->dents[AAFS_LOADDATA_REVISION]); AA_BUG(!mutex_is_locked(&data->ns->lock)); AA_BUG(data->revision > revision); data->revision = revision; - d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime = - current_time(d_inode(data->dents[AAFS_LOADDATA_DIR])); - d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime = - current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION])); + if ((data->dents[AAFS_LOADDATA_REVISION])) { + d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime = + current_time(d_inode(data->dents[AAFS_LOADDATA_DIR])); + d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime = + current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION])); + } } bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r) @@ -213,7 +214,7 @@ static void *kvmemdup(const void *src, size_t len) } /** - * aa_u16_chunck - test and do bounds checking for a u16 size based chunk + * unpack_u16_chunk - test and do bounds checking for a u16 size based chunk * @e: serialized data read head (NOT NULL) * @chunk: start address for chunk of data (NOT NULL) * @@ -456,7 +457,9 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e) ((e->pos - e->start) & 7); size_t pad = ALIGN(sz, 8) - sz; int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) | - TO_ACCEPT2_FLAG(YYTD_DATA32) | DFA_FLAG_VERIFY_STATES; + TO_ACCEPT2_FLAG(YYTD_DATA32); + if (aa_g_paranoid_load) + flags |= DFA_FLAG_VERIFY_STATES; dfa = aa_dfa_unpack(blob + pad, size - pad, flags); if (IS_ERR(dfa)) @@ -668,6 +671,7 @@ static int datacmp(struct rhashtable_compare_arg *arg, const void *obj) /** * unpack_profile - unpack a serialized profile * @e: serialized data extent information (NOT NULL) + * @ns_name: pointer of newly allocated copy of %NULL in case of error * * NOTE: unpack profile sets audit struct if there is a failure */ @@ -744,18 +748,24 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) goto fail; if (tmp & PACKED_FLAG_HAT) profile->label.flags |= FLAG_HAT; + if (tmp & PACKED_FLAG_DEBUG1) + profile->label.flags |= FLAG_DEBUG1; + if (tmp & PACKED_FLAG_DEBUG2) + profile->label.flags |= FLAG_DEBUG2; if (!unpack_u32(e, &tmp, NULL)) goto fail; - if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) + if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) { profile->mode = APPARMOR_COMPLAIN; - else if (tmp == PACKED_MODE_ENFORCE) + } else if (tmp == PACKED_MODE_ENFORCE) { profile->mode = APPARMOR_ENFORCE; - else if (tmp == PACKED_MODE_KILL) + } else if (tmp == PACKED_MODE_KILL) { profile->mode = APPARMOR_KILL; - else if (tmp == PACKED_MODE_UNCONFINED) + } else if (tmp == PACKED_MODE_UNCONFINED) { profile->mode = APPARMOR_UNCONFINED; - else + profile->label.flags |= FLAG_UNCONFINED; + } else { goto fail; + } if (!unpack_u32(e, &tmp, NULL)) goto fail; if (tmp) @@ -936,7 +946,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) } /** - * verify_head - unpack serialized stream header + * verify_header - unpack serialized stream header * @e: serialized data read head (NOT NULL) * @required: whether the header is required or optional * @ns: Returns - namespace if one is specified else NULL (NOT NULL) @@ -1052,6 +1062,7 @@ struct aa_load_ent *aa_load_ent_alloc(void) static int deflate_compress(const char *src, size_t slen, char **dst, size_t *dlen) { +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY int error; struct z_stream_s strm; void *stgbuf, *dstbuf; @@ -1123,6 +1134,10 @@ static int deflate_compress(const char *src, size_t slen, char **dst, fail_deflate: kvfree(stgbuf); goto fail_stg_alloc; +#else + *dlen = slen; + return 0; +#endif } static int compress_loaddata(struct aa_loaddata *data) @@ -1141,7 +1156,8 @@ static int compress_loaddata(struct aa_loaddata *data) if (error) return error; - kvfree(udata); + if (udata != data->data) + kvfree(udata); } else data->compressed_size = data->size; @@ -1216,9 +1232,12 @@ int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, goto fail; } } - error = compress_loaddata(udata); - if (error) - goto fail; + + if (aa_g_export_binary) { + error = compress_loaddata(udata); + if (error) + goto fail; + } return 0; fail_profile: diff --git a/security/apparmor/policy_unpack_test.c b/security/apparmor/policy_unpack_test.c index 533137f453..0a969b2e03 100644 --- a/security/apparmor/policy_unpack_test.c +++ b/security/apparmor/policy_unpack_test.c @@ -48,8 +48,8 @@ struct policy_unpack_fixture { size_t e_size; }; -struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf, - struct kunit *test, size_t buf_size) +static struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf, + struct kunit *test, size_t buf_size) { char *buf; struct aa_ext *e; @@ -177,7 +177,7 @@ static void policy_unpack_test_unpack_array_out_of_bounds(struct kunit *test) array_size = unpack_array(puf->e, name); - KUNIT_EXPECT_EQ(test, array_size, (u16)0); + KUNIT_EXPECT_EQ(test, array_size, 0); KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, puf->e->start + TEST_NAMED_ARRAY_BUF_OFFSET); } @@ -313,7 +313,7 @@ static void policy_unpack_test_unpack_strdup_out_of_bounds(struct kunit *test) size = unpack_strdup(puf->e, &string, TEST_STRING_NAME); KUNIT_EXPECT_EQ(test, size, 0); - KUNIT_EXPECT_PTR_EQ(test, string, (char *)NULL); + KUNIT_EXPECT_NULL(test, string); KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start); } @@ -391,10 +391,10 @@ static void policy_unpack_test_unpack_u16_chunk_basic(struct kunit *test) size = unpack_u16_chunk(puf->e, &chunk); - KUNIT_EXPECT_PTR_EQ(test, (void *)chunk, + KUNIT_EXPECT_PTR_EQ(test, chunk, puf->e->start + TEST_U16_OFFSET + 2); - KUNIT_EXPECT_EQ(test, size, (size_t)TEST_U16_DATA); - KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, (void *)(chunk + TEST_U16_DATA)); + KUNIT_EXPECT_EQ(test, size, TEST_U16_DATA); + KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, (chunk + TEST_U16_DATA)); } static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_1( @@ -408,8 +408,8 @@ static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_1( size = unpack_u16_chunk(puf->e, &chunk); - KUNIT_EXPECT_EQ(test, size, (size_t)0); - KUNIT_EXPECT_PTR_EQ(test, chunk, (char *)NULL); + KUNIT_EXPECT_EQ(test, size, 0); + KUNIT_EXPECT_NULL(test, chunk); KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, puf->e->end - 1); } @@ -430,8 +430,8 @@ static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_2( size = unpack_u16_chunk(puf->e, &chunk); - KUNIT_EXPECT_EQ(test, size, (size_t)0); - KUNIT_EXPECT_PTR_EQ(test, chunk, (char *)NULL); + KUNIT_EXPECT_EQ(test, size, 0); + KUNIT_EXPECT_NULL(test, chunk); KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, puf->e->start + TEST_U16_OFFSET); } @@ -439,7 +439,7 @@ static void policy_unpack_test_unpack_u32_with_null_name(struct kunit *test) { struct policy_unpack_fixture *puf = test->priv; bool success; - u32 data; + u32 data = 0; puf->e->pos += TEST_U32_BUF_OFFSET; @@ -456,7 +456,7 @@ static void policy_unpack_test_unpack_u32_with_name(struct kunit *test) struct policy_unpack_fixture *puf = test->priv; const char name[] = TEST_U32_NAME; bool success; - u32 data; + u32 data = 0; puf->e->pos += TEST_NAMED_U32_BUF_OFFSET; @@ -473,7 +473,7 @@ static void policy_unpack_test_unpack_u32_out_of_bounds(struct kunit *test) struct policy_unpack_fixture *puf = test->priv; const char name[] = TEST_U32_NAME; bool success; - u32 data; + u32 data = 0; puf->e->pos += TEST_NAMED_U32_BUF_OFFSET; puf->e->end = puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32); @@ -489,7 +489,7 @@ static void policy_unpack_test_unpack_u64_with_null_name(struct kunit *test) { struct policy_unpack_fixture *puf = test->priv; bool success; - u64 data; + u64 data = 0; puf->e->pos += TEST_U64_BUF_OFFSET; @@ -506,7 +506,7 @@ static void policy_unpack_test_unpack_u64_with_name(struct kunit *test) struct policy_unpack_fixture *puf = test->priv; const char name[] = TEST_U64_NAME; bool success; - u64 data; + u64 data = 0; puf->e->pos += TEST_NAMED_U64_BUF_OFFSET; @@ -523,7 +523,7 @@ static void policy_unpack_test_unpack_u64_out_of_bounds(struct kunit *test) struct policy_unpack_fixture *puf = test->priv; const char name[] = TEST_U64_NAME; bool success; - u64 data; + u64 data = 0; puf->e->pos += TEST_NAMED_U64_BUF_OFFSET; puf->e->end = puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64); diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index fde332e0ea..86ad26ef72 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -90,7 +90,7 @@ static char *split_token_from_name(const char *op, char *args, u64 *token) } /** - * aa_setprocattr_chagnehat - handle procattr interface to change_hat + * aa_setprocattr_changehat - handle procattr interface to change_hat * @args: args received from writing to /proc//attr/current (NOT NULL) * @size: size of the args * @flags: set of flags governing behavior diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c index ce545f9925..24a0e23f1b 100644 --- a/security/apparmor/secid.c +++ b/security/apparmor/secid.c @@ -13,9 +13,9 @@ #include #include #include -#include #include #include +#include #include "include/cred.h" #include "include/lib.h" @@ -29,8 +29,9 @@ */ #define AA_FIRST_SECID 2 -static DEFINE_IDR(aa_secids); -static DEFINE_SPINLOCK(secid_lock); +static DEFINE_XARRAY_FLAGS(aa_secids, XA_FLAGS_LOCK_IRQ | XA_FLAGS_TRACK_FREE); + +int apparmor_display_secid_mode; /* * TODO: allow policy to reserve a secid range? @@ -47,9 +48,9 @@ void aa_secid_update(u32 secid, struct aa_label *label) { unsigned long flags; - spin_lock_irqsave(&secid_lock, flags); - idr_replace(&aa_secids, label, secid); - spin_unlock_irqrestore(&secid_lock, flags); + xa_lock_irqsave(&aa_secids, flags); + __xa_store(&aa_secids, secid, label, 0); + xa_unlock_irqrestore(&aa_secids, flags); } /** @@ -58,19 +59,14 @@ void aa_secid_update(u32 secid, struct aa_label *label) */ struct aa_label *aa_secid_to_label(u32 secid) { - struct aa_label *label; - - rcu_read_lock(); - label = idr_find(&aa_secids, secid); - rcu_read_unlock(); - - return label; + return xa_load(&aa_secids, secid); } int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { /* TODO: cache secctx and ref count so we don't have to recreate */ struct aa_label *label = aa_secid_to_label(secid); + int flags = FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT; int len; AA_BUG(!seclen); @@ -78,15 +74,15 @@ int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) if (!label) return -EINVAL; + if (apparmor_display_secid_mode) + flags |= FLAG_SHOW_MODE; + if (secdata) len = aa_label_asxprint(secdata, root_ns, label, - FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | - FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT, - GFP_ATOMIC); + flags, GFP_ATOMIC); else - len = aa_label_snxprint(NULL, 0, root_ns, label, - FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | - FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT); + len = aa_label_snxprint(NULL, 0, root_ns, label, flags); + if (len < 0) return -ENOMEM; @@ -126,19 +122,16 @@ int aa_alloc_secid(struct aa_label *label, gfp_t gfp) unsigned long flags; int ret; - idr_preload(gfp); - spin_lock_irqsave(&secid_lock, flags); - ret = idr_alloc(&aa_secids, label, AA_FIRST_SECID, 0, GFP_ATOMIC); - spin_unlock_irqrestore(&secid_lock, flags); - idr_preload_end(); + xa_lock_irqsave(&aa_secids, flags); + ret = __xa_alloc(&aa_secids, &label->secid, label, + XA_LIMIT(AA_FIRST_SECID, INT_MAX), gfp); + xa_unlock_irqrestore(&aa_secids, flags); if (ret < 0) { label->secid = AA_SECID_INVALID; return ret; } - AA_BUG(ret == AA_SECID_INVALID); - label->secid = ret; return 0; } @@ -150,12 +143,7 @@ void aa_free_secid(u32 secid) { unsigned long flags; - spin_lock_irqsave(&secid_lock, flags); - idr_remove(&aa_secids, secid); - spin_unlock_irqrestore(&secid_lock, flags); -} - -void aa_secids_init(void) -{ - idr_init_base(&aa_secids, AA_FIRST_SECID); + xa_lock_irqsave(&aa_secids, flags); + __xa_erase(&aa_secids, secid); + xa_unlock_irqrestore(&aa_secids, flags); } diff --git a/security/apparmor/task.c b/security/apparmor/task.c index d17130ee67..503dc0877f 100644 --- a/security/apparmor/task.c +++ b/security/apparmor/task.c @@ -12,7 +12,12 @@ * should return to the previous cred if it has not been modified. */ +#include +#include + +#include "include/audit.h" #include "include/cred.h" +#include "include/policy.h" #include "include/task.h" /** @@ -177,3 +182,112 @@ int aa_restore_previous_label(u64 token) return 0; } + +/** + * audit_ptrace_mask - convert mask to permission string + * @mask: permission mask to convert + * + * Returns: pointer to static string + */ +static const char *audit_ptrace_mask(u32 mask) +{ + switch (mask) { + case MAY_READ: + return "read"; + case MAY_WRITE: + return "trace"; + case AA_MAY_BE_READ: + return "readby"; + case AA_MAY_BE_TRACED: + return "tracedby"; + } + return ""; +} + +/* call back to audit ptrace fields */ +static void audit_ptrace_cb(struct audit_buffer *ab, void *va) +{ + struct common_audit_data *sa = va; + + if (aad(sa)->request & AA_PTRACE_PERM_MASK) { + audit_log_format(ab, " requested_mask=\"%s\"", + audit_ptrace_mask(aad(sa)->request)); + + if (aad(sa)->denied & AA_PTRACE_PERM_MASK) { + audit_log_format(ab, " denied_mask=\"%s\"", + audit_ptrace_mask(aad(sa)->denied)); + } + } + audit_log_format(ab, " peer="); + aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, + FLAGS_NONE, GFP_ATOMIC); +} + +/* assumes check for PROFILE_MEDIATES is already done */ +/* TODO: conditionals */ +static int profile_ptrace_perm(struct aa_profile *profile, + struct aa_label *peer, u32 request, + struct common_audit_data *sa) +{ + struct aa_perms perms = { }; + + aad(sa)->peer = peer; + aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request, + &perms); + aa_apply_modes_to_perms(profile, &perms); + return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); +} + +static int profile_tracee_perm(struct aa_profile *tracee, + struct aa_label *tracer, u32 request, + struct common_audit_data *sa) +{ + if (profile_unconfined(tracee) || unconfined(tracer) || + !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE)) + return 0; + + return profile_ptrace_perm(tracee, tracer, request, sa); +} + +static int profile_tracer_perm(struct aa_profile *tracer, + struct aa_label *tracee, u32 request, + struct common_audit_data *sa) +{ + if (profile_unconfined(tracer)) + return 0; + + if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) + return profile_ptrace_perm(tracer, tracee, request, sa); + + /* profile uses the old style capability check for ptrace */ + if (&tracer->label == tracee) + return 0; + + aad(sa)->label = &tracer->label; + aad(sa)->peer = tracee; + aad(sa)->request = 0; + aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, + CAP_OPT_NONE); + + return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); +} + +/** + * aa_may_ptrace - test if tracer task can trace the tracee + * @tracer: label of the task doing the tracing (NOT NULL) + * @tracee: task label to be traced + * @request: permission request + * + * Returns: %0 else error code if permission denied or error + */ +int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, + u32 request) +{ + struct aa_profile *profile; + u32 xrequest = request << PTRACE_PERM_SHIFT; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); + + return xcheck_labels(tracer, tracee, profile, + profile_tracer_perm(profile, tracee, request, &sa), + profile_tracee_perm(profile, tracer, xrequest, &sa)); +} diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index c8c8a4a4e7..8a82a6c7f4 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -75,7 +75,8 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, /* v1 API expect signature without xattr type */ return digsig_verify(keyring, sig + 1, siglen - 1, digest, digestlen); - case 2: + case 2: /* regular file data hash based signature */ + case 3: /* struct ima_file_id data based signature */ return asymmetric_verify(keyring, sig, siglen, digest, digestlen); } diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index 0d44f41d16..f8b8c5004f 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -38,9 +38,6 @@ extern int evm_initialized; extern int evm_hmac_attrs; -extern struct crypto_shash *hmac_tfm; -extern struct crypto_shash *hash_tfm; - /* List of EVM protected security xattrs */ extern struct list_head evm_config_xattrnames; diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 0450d79afd..708de9656b 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -26,7 +26,7 @@ static unsigned char evmkey[MAX_KEY_SIZE]; static const int evmkey_len = MAX_KEY_SIZE; -struct crypto_shash *hmac_tfm; +static struct crypto_shash *hmac_tfm; static struct crypto_shash *evm_tfm[HASH_ALGO__LAST]; static DEFINE_MUTEX(mutex); @@ -75,7 +75,7 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo) { long rc; const char *algo; - struct crypto_shash **tfm, *tmp_tfm = NULL; + struct crypto_shash **tfm, *tmp_tfm; struct shash_desc *desc; if (type == EVM_XATTR_HMAC) { @@ -120,16 +120,13 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo) alloc: desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm), GFP_KERNEL); - if (!desc) { - crypto_free_shash(tmp_tfm); + if (!desc) return ERR_PTR(-ENOMEM); - } desc->tfm = *tfm; rc = crypto_shash_init(desc); if (rc) { - crypto_free_shash(tmp_tfm); kfree(desc); return ERR_PTR(rc); } diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 7d87772f0c..2e6fb6e2ff 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -36,42 +36,36 @@ static const char * const integrity_status_msg[] = { int evm_hmac_attrs; static struct xattr_list evm_config_default_xattrnames[] = { - {.name = XATTR_NAME_SELINUX, -#ifdef CONFIG_SECURITY_SELINUX - .enabled = true -#endif + { + .name = XATTR_NAME_SELINUX, + .enabled = IS_ENABLED(CONFIG_SECURITY_SELINUX) }, - {.name = XATTR_NAME_SMACK, -#ifdef CONFIG_SECURITY_SMACK - .enabled = true -#endif + { + .name = XATTR_NAME_SMACK, + .enabled = IS_ENABLED(CONFIG_SECURITY_SMACK) }, - {.name = XATTR_NAME_SMACKEXEC, -#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS - .enabled = true -#endif + { + .name = XATTR_NAME_SMACKEXEC, + .enabled = IS_ENABLED(CONFIG_EVM_EXTRA_SMACK_XATTRS) }, - {.name = XATTR_NAME_SMACKTRANSMUTE, -#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS - .enabled = true -#endif + { + .name = XATTR_NAME_SMACKTRANSMUTE, + .enabled = IS_ENABLED(CONFIG_EVM_EXTRA_SMACK_XATTRS) }, - {.name = XATTR_NAME_SMACKMMAP, -#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS - .enabled = true -#endif + { + .name = XATTR_NAME_SMACKMMAP, + .enabled = IS_ENABLED(CONFIG_EVM_EXTRA_SMACK_XATTRS) }, - {.name = XATTR_NAME_APPARMOR, -#ifdef CONFIG_SECURITY_APPARMOR - .enabled = true -#endif + { + .name = XATTR_NAME_APPARMOR, + .enabled = IS_ENABLED(CONFIG_SECURITY_APPARMOR) }, - {.name = XATTR_NAME_IMA, -#ifdef CONFIG_IMA_APPRAISE - .enabled = true -#endif + { + .name = XATTR_NAME_IMA, + .enabled = IS_ENABLED(CONFIG_IMA_APPRAISE) }, - {.name = XATTR_NAME_CAPS, + { + .name = XATTR_NAME_CAPS, .enabled = true }, }; @@ -436,7 +430,7 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry) struct inode *inode = d_backing_inode(dentry); if (!evm_key_loaded() || !S_ISREG(inode->i_mode) || evm_fixmode) - return 0; + return INTEGRITY_PASS; return evm_verify_hmac(dentry, NULL, NULL, 0, NULL); } @@ -755,13 +749,14 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) evm_update_evmxattr(dentry, xattr_name, NULL, 0); } -static int evm_attr_change(struct dentry *dentry, struct iattr *attr) +static int evm_attr_change(struct user_namespace *mnt_userns, + struct dentry *dentry, struct iattr *attr) { struct inode *inode = d_backing_inode(dentry); unsigned int ia_valid = attr->ia_valid; - if ((!(ia_valid & ATTR_UID) || uid_eq(attr->ia_uid, inode->i_uid)) && - (!(ia_valid & ATTR_GID) || gid_eq(attr->ia_gid, inode->i_gid)) && + if (!i_uid_needs_update(mnt_userns, attr, inode) && + !i_gid_needs_update(mnt_userns, attr, inode) && (!(ia_valid & ATTR_MODE) || attr->ia_mode == inode->i_mode)) return 0; @@ -775,7 +770,8 @@ static int evm_attr_change(struct dentry *dentry, struct iattr *attr) * Permit update of file attributes when files have a valid EVM signature, * except in the case of them having an immutable portable signature. */ -int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) +int evm_inode_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, + struct iattr *attr) { unsigned int ia_valid = attr->ia_valid; enum integrity_status evm_status; @@ -801,7 +797,7 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) return 0; if (evm_status == INTEGRITY_PASS_IMMUTABLE && - !evm_attr_change(dentry, attr)) + !evm_attr_change(mnt_userns, dentry, attr)) return 0; integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry), diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index f3a9cc201c..7249f16257 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -69,10 +69,9 @@ choice hash, defined as 20 bytes, and a null terminated pathname, limited to 255 characters. The 'ima-ng' measurement list template permits both larger hash digests and longer - pathnames. + pathnames. The configured default template can be replaced + by specifying "ima_template=" on the boot command line. - config IMA_TEMPLATE - bool "ima" config IMA_NG_TEMPLATE bool "ima-ng (default)" config IMA_SIG_TEMPLATE @@ -82,7 +81,6 @@ endchoice config IMA_DEFAULT_TEMPLATE string depends on IMA - default "ima" if IMA_TEMPLATE default "ima-ng" if IMA_NG_TEMPLATE default "ima-sig" if IMA_SIG_TEMPLATE @@ -102,19 +100,19 @@ choice config IMA_DEFAULT_HASH_SHA256 bool "SHA256" - depends on CRYPTO_SHA256=y && !IMA_TEMPLATE + depends on CRYPTO_SHA256=y config IMA_DEFAULT_HASH_SHA512 bool "SHA512" - depends on CRYPTO_SHA512=y && !IMA_TEMPLATE + depends on CRYPTO_SHA512=y config IMA_DEFAULT_HASH_WP512 bool "WP512" - depends on CRYPTO_WP512=y && !IMA_TEMPLATE + depends on CRYPTO_WP512=y config IMA_DEFAULT_HASH_SM3 bool "SM3" - depends on CRYPTO_SM3=y && !IMA_TEMPLATE + depends on CRYPTO_SM3=y endchoice config IMA_DEFAULT_HASH diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index c6805af462..c1e76282b5 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "ima.h" @@ -200,6 +201,32 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode, allowed_algos); } +static int ima_get_verity_digest(struct integrity_iint_cache *iint, + struct ima_max_digest_data *hash) +{ + enum hash_algo verity_alg; + int ret; + + /* + * On failure, 'measure' policy rules will result in a file data + * hash containing 0's. + */ + ret = fsverity_get_digest(iint->inode, hash->digest, &verity_alg); + if (ret) + return ret; + + /* + * Unlike in the case of actually calculating the file hash, in + * the fsverity case regardless of the hash algorithm, return + * the verity digest to be included in the measurement list. A + * mismatch between the verity algorithm and the xattr signature + * algorithm, if one exists, will be detected later. + */ + hash->hdr.algo = verity_alg; + hash->hdr.length = hash_digest_size[verity_alg]; + return 0; +} + /* * ima_collect_measurement - collect file measurement * @@ -242,16 +269,30 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, */ i_version = inode_query_iversion(inode); hash.hdr.algo = algo; + hash.hdr.length = hash_digest_size[algo]; /* Initialize hash digest to 0's in case of failure */ memset(&hash.digest, 0, sizeof(hash.digest)); - if (buf) + if (iint->flags & IMA_VERITY_REQUIRED) { + result = ima_get_verity_digest(iint, &hash); + switch (result) { + case 0: + break; + case -ENODATA: + audit_cause = "no-verity-digest"; + break; + default: + audit_cause = "invalid-verity-digest"; + break; + } + } else if (buf) { result = ima_calc_buffer_hash(buf, size, &hash.hdr); - else + } else { result = ima_calc_file_hash(file, &hash.hdr); + } - if (result && result != -EBADF && result != -EINVAL) + if (result == -ENOMEM) goto out; length = sizeof(hash.hdr) + hash.hdr.length; diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 17232bbfb9..bde74fcece 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include #include "ima.h" @@ -183,13 +185,18 @@ enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value, return ima_hash_algo; switch (xattr_value->type) { + case IMA_VERITY_DIGSIG: + sig = (typeof(sig))xattr_value; + if (sig->version != 3 || xattr_len <= sizeof(*sig) || + sig->hash_algo >= HASH_ALGO__LAST) + return ima_hash_algo; + return sig->hash_algo; case EVM_IMA_XATTR_DIGSIG: sig = (typeof(sig))xattr_value; if (sig->version != 2 || xattr_len <= sizeof(*sig) || sig->hash_algo >= HASH_ALGO__LAST) return ima_hash_algo; return sig->hash_algo; - break; case IMA_XATTR_DIGEST_NG: /* first byte contains algorithm id */ ret = xattr_value->data[0]; @@ -225,6 +232,40 @@ int ima_read_xattr(struct dentry *dentry, return ret; } +/* + * calc_file_id_hash - calculate the hash of the ima_file_id struct data + * @type: xattr type [enum evm_ima_xattr_type] + * @algo: hash algorithm [enum hash_algo] + * @digest: pointer to the digest to be hashed + * @hash: (out) pointer to the hash + * + * IMA signature version 3 disambiguates the data that is signed by + * indirectly signing the hash of the ima_file_id structure data. + * + * Signing the ima_file_id struct is currently only supported for + * IMA_VERITY_DIGSIG type xattrs. + * + * Return 0 on success, error code otherwise. + */ +static int calc_file_id_hash(enum evm_ima_xattr_type type, + enum hash_algo algo, const u8 *digest, + struct ima_digest_data *hash) +{ + struct ima_file_id file_id = { + .hash_type = IMA_VERITY_DIGSIG, .hash_algorithm = algo}; + unsigned int unused = HASH_MAX_DIGESTSIZE - hash_digest_size[algo]; + + if (type != IMA_VERITY_DIGSIG) + return -EINVAL; + + memcpy(file_id.hash, digest, hash_digest_size[algo]); + + hash->algo = algo; + hash->length = hash_digest_size[algo]; + + return ima_calc_buffer_hash(&file_id, sizeof(file_id) - unused, hash); +} + /* * xattr_verify - verify xattr digest or signature * @@ -236,7 +277,10 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, struct evm_ima_xattr_data *xattr_value, int xattr_len, enum integrity_status *status, const char **cause) { + struct ima_max_digest_data hash; + struct signature_v2_hdr *sig; int rc = -EINVAL, hash_start = 0; + int mask; switch (xattr_value->type) { case IMA_XATTR_DIGEST_NG: @@ -246,7 +290,10 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, case IMA_XATTR_DIGEST: if (*status != INTEGRITY_PASS_IMMUTABLE) { if (iint->flags & IMA_DIGSIG_REQUIRED) { - *cause = "IMA-signature-required"; + if (iint->flags & IMA_VERITY_REQUIRED) + *cause = "verity-signature-required"; + else + *cause = "IMA-signature-required"; *status = INTEGRITY_FAIL; break; } @@ -274,6 +321,20 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, break; case EVM_IMA_XATTR_DIGSIG: set_bit(IMA_DIGSIG, &iint->atomic_flags); + + mask = IMA_DIGSIG_REQUIRED | IMA_VERITY_REQUIRED; + if ((iint->flags & mask) == mask) { + *cause = "verity-signature-required"; + *status = INTEGRITY_FAIL; + break; + } + + sig = (typeof(sig))xattr_value; + if (sig->version >= 3) { + *cause = "invalid-signature-version"; + *status = INTEGRITY_FAIL; + break; + } rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, (const char *)xattr_value, xattr_len, @@ -296,6 +357,44 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, } else { *status = INTEGRITY_PASS; } + break; + case IMA_VERITY_DIGSIG: + set_bit(IMA_DIGSIG, &iint->atomic_flags); + + if (iint->flags & IMA_DIGSIG_REQUIRED) { + if (!(iint->flags & IMA_VERITY_REQUIRED)) { + *cause = "IMA-signature-required"; + *status = INTEGRITY_FAIL; + break; + } + } + + sig = (typeof(sig))xattr_value; + if (sig->version != 3) { + *cause = "invalid-signature-version"; + *status = INTEGRITY_FAIL; + break; + } + + rc = calc_file_id_hash(IMA_VERITY_DIGSIG, iint->ima_hash->algo, + iint->ima_hash->digest, &hash.hdr); + if (rc) { + *cause = "sigv3-hashing-error"; + *status = INTEGRITY_FAIL; + break; + } + + rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, + (const char *)xattr_value, + xattr_len, hash.digest, + hash.hdr.length); + if (rc) { + *cause = "invalid-verity-signature"; + *status = INTEGRITY_FAIL; + } else { + *status = INTEGRITY_PASS; + } + break; default: *status = INTEGRITY_UNKNOWN; @@ -396,8 +495,15 @@ int ima_appraise_measurement(enum ima_hooks func, if (rc && rc != -ENODATA) goto out; - cause = iint->flags & IMA_DIGSIG_REQUIRED ? - "IMA-signature-required" : "missing-hash"; + if (iint->flags & IMA_DIGSIG_REQUIRED) { + if (iint->flags & IMA_VERITY_REQUIRED) + cause = "verity-signature-required"; + else + cause = "IMA-signature-required"; + } else { + cause = "missing-hash"; + } + status = INTEGRITY_NOLABEL; if (file->f_mode & FMODE_CREATED) iint->flags |= IMA_NEW_FILE; @@ -408,7 +514,8 @@ int ima_appraise_measurement(enum ima_hooks func, goto out; } - status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint); + status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, + rc < 0 ? 0 : rc, iint); switch (status) { case INTEGRITY_PASS: case INTEGRITY_PASS_IMMUTABLE: diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index a7206cc1d7..6449905664 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -205,6 +205,7 @@ int __init ima_init_crypto(void) crypto_free_shash(ima_algo_array[i].tfm); } + kfree(ima_algo_array); out: crypto_free_shash(ima_shash_tfm); return rc; diff --git a/security/integrity/ima/ima_efi.c b/security/integrity/ima/ima_efi.c index 71786d0194..9db66fe310 100644 --- a/security/integrity/ima/ima_efi.c +++ b/security/integrity/ima/ima_efi.c @@ -67,6 +67,8 @@ const char * const *arch_get_ima_policy(void) if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot()) { if (IS_ENABLED(CONFIG_MODULE_SIG)) set_module_sig_enforced(); + if (IS_ENABLED(CONFIG_KEXEC_SIG)) + set_kexec_sig_enforced(); return sb_arch_rules; } return NULL; diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 13753136f0..419dc405c8 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -137,7 +137,7 @@ void ima_add_kexec_buffer(struct kimage *image) /* * Restore the measurement list from the previous kernel. */ -void ima_load_kexec_buffer(void) +void __init ima_load_kexec_buffer(void) { void *kexec_buffer = NULL; size_t kexec_buffer_size = 0; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 3d3f8c5c50..040b03ddc1 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -335,7 +335,7 @@ static int process_measurement(struct file *file, const struct cred *cred, hash_algo = ima_get_hash_algo(xattr_value, xattr_len); rc = ima_collect_measurement(iint, file, buf, size, hash_algo, modsig); - if (rc != 0 && rc != -EBADF && rc != -EINVAL) + if (rc == -ENOMEM) goto out_locked; if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ @@ -432,7 +432,7 @@ int ima_file_mmap(struct file *file, unsigned long prot) int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) { struct ima_template_desc *template = NULL; - struct file *file = vma->vm_file; + struct file *file; char filename[NAME_MAX]; char *pathbuf = NULL; const char *pathname = NULL; diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index eea6e92500..a8802b8da9 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -1023,6 +1023,7 @@ enum policy_opt { Opt_fowner_gt, Opt_fgroup_gt, Opt_uid_lt, Opt_euid_lt, Opt_gid_lt, Opt_egid_lt, Opt_fowner_lt, Opt_fgroup_lt, + Opt_digest_type, Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos, Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings, Opt_label, Opt_err @@ -1065,6 +1066,7 @@ static const match_table_t policy_tokens = { {Opt_egid_lt, "egid<%s"}, {Opt_fowner_lt, "fowner<%s"}, {Opt_fgroup_lt, "fgroup<%s"}, + {Opt_digest_type, "digest_type=%s"}, {Opt_appraise_type, "appraise_type=%s"}, {Opt_appraise_flag, "appraise_flag=%s"}, {Opt_appraise_algos, "appraise_algos=%s"}, @@ -1172,6 +1174,21 @@ static void check_template_modsig(const struct ima_template_desc *template) #undef MSG } +/* + * Warn if the template does not contain the given field. + */ +static void check_template_field(const struct ima_template_desc *template, + const char *field, const char *msg) +{ + int i; + + for (i = 0; i < template->num_fields; i++) + if (!strcmp(template->fields[i]->field_id, field)) + return; + + pr_notice_once("%s", msg); +} + static bool ima_validate_rule(struct ima_rule_entry *entry) { /* Ensure that the action is set and is compatible with the flags */ @@ -1214,7 +1231,8 @@ static bool ima_validate_rule(struct ima_rule_entry *entry) IMA_INMASK | IMA_EUID | IMA_PCR | IMA_FSNAME | IMA_GID | IMA_EGID | IMA_FGROUP | IMA_DIGSIG_REQUIRED | - IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS)) + IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS | + IMA_VERITY_REQUIRED)) return false; break; @@ -1292,6 +1310,18 @@ static bool ima_validate_rule(struct ima_rule_entry *entry) !(entry->flags & IMA_MODSIG_ALLOWED)) return false; + /* + * Unlike for regular IMA 'appraise' policy rules where security.ima + * xattr may contain either a file hash or signature, the security.ima + * xattr for fsverity must contain a file signature (sigv3). Ensure + * that 'appraise' rules for fsverity require file signatures by + * checking the IMA_DIGSIG_REQUIRED flag is set. + */ + if (entry->action == APPRAISE && + (entry->flags & IMA_VERITY_REQUIRED) && + !(entry->flags & IMA_DIGSIG_REQUIRED)) + return false; + return true; } @@ -1707,16 +1737,39 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) LSM_SUBJ_TYPE, AUDIT_SUBJ_TYPE); break; + case Opt_digest_type: + ima_log_string(ab, "digest_type", args[0].from); + if (entry->flags & IMA_DIGSIG_REQUIRED) + result = -EINVAL; + else if ((strcmp(args[0].from, "verity")) == 0) + entry->flags |= IMA_VERITY_REQUIRED; + else + result = -EINVAL; + break; case Opt_appraise_type: ima_log_string(ab, "appraise_type", args[0].from); - if ((strcmp(args[0].from, "imasig")) == 0) - entry->flags |= IMA_DIGSIG_REQUIRED; - else if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) && - strcmp(args[0].from, "imasig|modsig") == 0) - entry->flags |= IMA_DIGSIG_REQUIRED | + + if ((strcmp(args[0].from, "imasig")) == 0) { + if (entry->flags & IMA_VERITY_REQUIRED) + result = -EINVAL; + else + entry->flags |= IMA_DIGSIG_REQUIRED; + } else if (strcmp(args[0].from, "sigv3") == 0) { + /* Only fsverity supports sigv3 for now */ + if (entry->flags & IMA_VERITY_REQUIRED) + entry->flags |= IMA_DIGSIG_REQUIRED; + else + result = -EINVAL; + } else if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) && + strcmp(args[0].from, "imasig|modsig") == 0) { + if (entry->flags & IMA_VERITY_REQUIRED) + result = -EINVAL; + else + entry->flags |= IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED; - else + } else { result = -EINVAL; + } break; case Opt_appraise_flag: ima_log_string(ab, "appraise_flag", args[0].from); @@ -1797,6 +1850,15 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) check_template_modsig(template_desc); } + /* d-ngv2 template field recommended for unsigned fs-verity digests */ + if (!result && entry->action == MEASURE && + entry->flags & IMA_VERITY_REQUIRED) { + template_desc = entry->template ? entry->template : + ima_template_desc_current(); + check_template_field(template_desc, "d-ngv2", + "verity rules should include d-ngv2"); + } + audit_log_format(ab, "res=%d", !result); audit_log_end(ab); return result; @@ -2149,11 +2211,15 @@ int ima_policy_show(struct seq_file *m, void *v) if (entry->template) seq_printf(m, "template=%s ", entry->template->name); if (entry->flags & IMA_DIGSIG_REQUIRED) { - if (entry->flags & IMA_MODSIG_ALLOWED) + if (entry->flags & IMA_VERITY_REQUIRED) + seq_puts(m, "appraise_type=sigv3 "); + else if (entry->flags & IMA_MODSIG_ALLOWED) seq_puts(m, "appraise_type=imasig|modsig "); else seq_puts(m, "appraise_type=imasig "); } + if (entry->flags & IMA_VERITY_REQUIRED) + seq_puts(m, "digest_type=verity "); if (entry->flags & IMA_CHECK_BLACKLIST) seq_puts(m, "appraise_flag=check_blacklist "); if (entry->flags & IMA_PERMIT_DIRECTIO) @@ -2181,6 +2247,10 @@ bool ima_appraise_signature(enum kernel_read_file_id id) if (id >= READING_MAX_ID) return false; + if (id == READING_KEXEC_IMAGE && !(ima_appraise & IMA_APPRAISE_ENFORCE) + && security_locked_down(LOCKDOWN_KEXEC)) + return false; + func = read_idmap[id] ?: FILE_CHECK; rcu_read_lock(); diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index db1ad6d7a5..c25079faa2 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -20,6 +20,8 @@ static struct ima_template_desc builtin_templates[] = { {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, {.name = "ima-ng", .fmt = "d-ng|n-ng"}, {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, + {.name = "ima-ngv2", .fmt = "d-ngv2|n-ng"}, + {.name = "ima-sigv2", .fmt = "d-ngv2|n-ng|sig"}, {.name = "ima-buf", .fmt = "d-ng|n-ng|buf"}, {.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"}, {.name = "evm-sig", @@ -38,6 +40,8 @@ static const struct ima_template_field supported_fields[] = { .field_show = ima_show_template_string}, {.field_id = "d-ng", .field_init = ima_eventdigest_ng_init, .field_show = ima_show_template_digest_ng}, + {.field_id = "d-ngv2", .field_init = ima_eventdigest_ngv2_init, + .field_show = ima_show_template_digest_ngv2}, {.field_id = "n-ng", .field_init = ima_eventname_ng_init, .field_show = ima_show_template_string}, {.field_id = "sig", .field_init = ima_eventsig_init, diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 7155d17a3b..7bf9b15072 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -24,11 +24,24 @@ static bool ima_template_hash_algo_allowed(u8 algo) enum data_formats { DATA_FMT_DIGEST = 0, DATA_FMT_DIGEST_WITH_ALGO, + DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO, DATA_FMT_STRING, DATA_FMT_HEX, DATA_FMT_UINT }; +enum digest_type { + DIGEST_TYPE_IMA, + DIGEST_TYPE_VERITY, + DIGEST_TYPE__LAST +}; + +#define DIGEST_TYPE_NAME_LEN_MAX 7 /* including NUL */ +static const char * const digest_type_name[DIGEST_TYPE__LAST] = { + [DIGEST_TYPE_IMA] = "ima", + [DIGEST_TYPE_VERITY] = "verity" +}; + static int ima_write_template_field_data(const void *data, const u32 datalen, enum data_formats datafmt, struct ima_field_data *field_data) @@ -72,8 +85,9 @@ static void ima_show_template_data_ascii(struct seq_file *m, u32 buflen = field_data->len; switch (datafmt) { + case DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO: case DATA_FMT_DIGEST_WITH_ALGO: - buf_ptr = strnchr(field_data->data, buflen, ':'); + buf_ptr = strrchr(field_data->data, ':'); if (buf_ptr != field_data->data) seq_printf(m, "%s", field_data->data); @@ -178,6 +192,14 @@ void ima_show_template_digest_ng(struct seq_file *m, enum ima_show_type show, field_data); } +void ima_show_template_digest_ngv2(struct seq_file *m, enum ima_show_type show, + struct ima_field_data *field_data) +{ + ima_show_template_field_data(m, show, + DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO, + field_data); +} + void ima_show_template_string(struct seq_file *m, enum ima_show_type show, struct ima_field_data *field_data) { @@ -265,26 +287,35 @@ int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp, } static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize, - u8 hash_algo, + u8 digest_type, u8 hash_algo, struct ima_field_data *field_data) { /* * digest formats: * - DATA_FMT_DIGEST: digest - * - DATA_FMT_DIGEST_WITH_ALGO: [] + ':' + '\0' + digest, - * where is provided if the hash algorithm is not - * SHA1 or MD5 + * - DATA_FMT_DIGEST_WITH_ALGO: + ':' + '\0' + digest, + * - DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO: + * + ':' + + ':' + '\0' + digest, + * + * where 'DATA_FMT_DIGEST' is the original digest format ('d') + * with a hash size limitation of 20 bytes, + * where is either "ima" or "verity", + * where is the hash_algo_name[] string. */ - u8 buffer[CRYPTO_MAX_ALG_NAME + 2 + IMA_MAX_DIGEST_SIZE] = { 0 }; + u8 buffer[DIGEST_TYPE_NAME_LEN_MAX + CRYPTO_MAX_ALG_NAME + 2 + + IMA_MAX_DIGEST_SIZE] = { 0 }; enum data_formats fmt = DATA_FMT_DIGEST; u32 offset = 0; - if (hash_algo < HASH_ALGO__LAST) { + if (digest_type < DIGEST_TYPE__LAST && hash_algo < HASH_ALGO__LAST) { + fmt = DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO; + offset += 1 + sprintf(buffer, "%s:%s:", + digest_type_name[digest_type], + hash_algo_name[hash_algo]); + } else if (hash_algo < HASH_ALGO__LAST) { fmt = DATA_FMT_DIGEST_WITH_ALGO; - offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, "%s", - hash_algo_name[hash_algo]); - buffer[offset] = ':'; - offset += 2; + offset += 1 + sprintf(buffer, "%s:", + hash_algo_name[hash_algo]); } if (digest) @@ -292,10 +323,10 @@ static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize, else /* * If digest is NULL, the event being recorded is a violation. - * Make room for the digest by increasing the offset of - * IMA_DIGEST_SIZE. + * Make room for the digest by increasing the offset by the + * hash algorithm digest size. */ - offset += IMA_DIGEST_SIZE; + offset += hash_digest_size[hash_algo]; return ima_write_template_field_data(buffer, offset + digestsize, fmt, field_data); @@ -359,7 +390,8 @@ int ima_eventdigest_init(struct ima_event_data *event_data, cur_digestsize = hash.hdr.length; out: return ima_eventdigest_init_common(cur_digest, cur_digestsize, - HASH_ALGO__LAST, field_data); + DIGEST_TYPE__LAST, HASH_ALGO__LAST, + field_data); } /* @@ -368,8 +400,32 @@ int ima_eventdigest_init(struct ima_event_data *event_data, int ima_eventdigest_ng_init(struct ima_event_data *event_data, struct ima_field_data *field_data) { - u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1; + u8 *cur_digest = NULL, hash_algo = ima_hash_algo; + u32 cur_digestsize = 0; + + if (event_data->violation) /* recording a violation. */ + goto out; + + cur_digest = event_data->iint->ima_hash->digest; + cur_digestsize = event_data->iint->ima_hash->length; + + hash_algo = event_data->iint->ima_hash->algo; +out: + return ima_eventdigest_init_common(cur_digest, cur_digestsize, + DIGEST_TYPE__LAST, hash_algo, + field_data); +} + +/* + * This function writes the digest of an event (without size limit), + * prefixed with both the digest type and hash algorithm. + */ +int ima_eventdigest_ngv2_init(struct ima_event_data *event_data, + struct ima_field_data *field_data) +{ + u8 *cur_digest = NULL, hash_algo = ima_hash_algo; u32 cur_digestsize = 0; + u8 digest_type = DIGEST_TYPE_IMA; if (event_data->violation) /* recording a violation. */ goto out; @@ -378,9 +434,12 @@ int ima_eventdigest_ng_init(struct ima_event_data *event_data, cur_digestsize = event_data->iint->ima_hash->length; hash_algo = event_data->iint->ima_hash->algo; + if (event_data->iint->flags & IMA_VERITY_REQUIRED) + digest_type = DIGEST_TYPE_VERITY; out: return ima_eventdigest_init_common(cur_digest, cur_digestsize, - hash_algo, field_data); + digest_type, hash_algo, + field_data); } /* @@ -415,7 +474,8 @@ int ima_eventdigest_modsig_init(struct ima_event_data *event_data, } return ima_eventdigest_init_common(cur_digest, cur_digestsize, - hash_algo, field_data); + DIGEST_TYPE__LAST, hash_algo, + field_data); } static int ima_eventname_init_common(struct ima_event_data *event_data, @@ -475,7 +535,9 @@ int ima_eventsig_init(struct ima_event_data *event_data, { struct evm_ima_xattr_data *xattr_value = event_data->xattr_value; - if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG)) + if (!xattr_value || + (xattr_value->type != EVM_IMA_XATTR_DIGSIG && + xattr_value->type != IMA_VERITY_DIGSIG)) return ima_eventevmsig_init(event_data, field_data); return ima_write_template_field_data(xattr_value, event_data->xattr_len, diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h index c71f1de957..9f7c335f30 100644 --- a/security/integrity/ima/ima_template_lib.h +++ b/security/integrity/ima/ima_template_lib.h @@ -21,6 +21,8 @@ void ima_show_template_digest(struct seq_file *m, enum ima_show_type show, struct ima_field_data *field_data); void ima_show_template_digest_ng(struct seq_file *m, enum ima_show_type show, struct ima_field_data *field_data); +void ima_show_template_digest_ngv2(struct seq_file *m, enum ima_show_type show, + struct ima_field_data *field_data); void ima_show_template_string(struct seq_file *m, enum ima_show_type show, struct ima_field_data *field_data); void ima_show_template_sig(struct seq_file *m, enum ima_show_type show, @@ -38,6 +40,8 @@ int ima_eventname_init(struct ima_event_data *event_data, struct ima_field_data *field_data); int ima_eventdigest_ng_init(struct ima_event_data *event_data, struct ima_field_data *field_data); +int ima_eventdigest_ngv2_init(struct ima_event_data *event_data, + struct ima_field_data *field_data); int ima_eventdigest_modsig_init(struct ima_event_data *event_data, struct ima_field_data *field_data); int ima_eventname_ng_init(struct ima_event_data *event_data, diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 3510e413ea..7167a6e99b 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -40,6 +40,7 @@ #define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000 #define IMA_MODSIG_ALLOWED 0x20000000 #define IMA_CHECK_BLACKLIST 0x40000000 +#define IMA_VERITY_REQUIRED 0x80000000 #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ IMA_HASH | IMA_APPRAISE_SUBMASK) @@ -78,6 +79,7 @@ enum evm_ima_xattr_type { EVM_IMA_XATTR_DIGSIG, IMA_XATTR_DIGEST_NG, EVM_XATTR_PORTABLE_DIGSIG, + IMA_VERITY_DIGSIG, IMA_XATTR_LAST }; @@ -92,7 +94,7 @@ struct evm_xattr { u8 digest[SHA1_DIGEST_SIZE]; } __packed; -#define IMA_MAX_DIGEST_SIZE 64 +#define IMA_MAX_DIGEST_SIZE HASH_MAX_DIGESTSIZE struct ima_digest_data { u8 algo; @@ -121,7 +123,14 @@ struct ima_max_digest_data { } __packed; /* - * signature format v2 - for using with asymmetric keys + * signature header format v2 - for using with asymmetric keys + * + * The signature_v2_hdr struct includes a signature format version + * to simplify defining new signature formats. + * + * signature format: + * version 2: regular file data hash based signature + * version 3: struct ima_file_id data based signature */ struct signature_v2_hdr { uint8_t type; /* xattr type */ @@ -132,6 +141,20 @@ struct signature_v2_hdr { uint8_t sig[]; /* signature payload */ } __packed; +/* + * IMA signature version 3 disambiguates the data that is signed, by + * indirectly signing the hash of the ima_file_id structure data, + * containing either the fsverity_descriptor struct digest or, in the + * future, the regular IMA file hash. + * + * (The hash of the ima_file_id structure is only of the portion used.) + */ +struct ima_file_id { + __u8 hash_type; /* xattr type [enum evm_ima_xattr_type] */ + __u8 hash_algorithm; /* Digest algorithm [enum hash_algo] */ + __u8 hash[HASH_MAX_DIGESTSIZE]; +} __packed; + /* integrity data associated with an inode */ struct integrity_iint_cache { struct rb_node rb_node; /* rooted in integrity_iint_tree */ diff --git a/security/integrity/platform_certs/keyring_handler.c b/security/integrity/platform_certs/keyring_handler.c index 1db4d3b435..8a1124e4d7 100644 --- a/security/integrity/platform_certs/keyring_handler.c +++ b/security/integrity/platform_certs/keyring_handler.c @@ -16,35 +16,13 @@ static efi_guid_t efi_cert_x509_sha256_guid __initdata = EFI_CERT_X509_SHA256_GUID; static efi_guid_t efi_cert_sha256_guid __initdata = EFI_CERT_SHA256_GUID; -/* - * Blacklist a hash. - */ -static __init void uefi_blacklist_hash(const char *source, const void *data, - size_t len, const char *type, - size_t type_len) -{ - char *hash, *p; - - hash = kmalloc(type_len + len * 2 + 1, GFP_KERNEL); - if (!hash) - return; - p = memcpy(hash, type, type_len); - p += type_len; - bin2hex(p, data, len); - p += len * 2; - *p = 0; - - mark_hash_blacklisted(hash); - kfree(hash); -} - /* * Blacklist an X509 TBS hash. */ static __init void uefi_blacklist_x509_tbs(const char *source, const void *data, size_t len) { - uefi_blacklist_hash(source, data, len, "tbs:", 4); + mark_hash_blacklisted(data, len, BLACKLIST_HASH_X509_TBS); } /* @@ -53,7 +31,7 @@ static __init void uefi_blacklist_x509_tbs(const char *source, static __init void uefi_blacklist_binary(const char *source, const void *data, size_t len) { - uefi_blacklist_hash(source, data, len, "bin:", 4); + mark_hash_blacklisted(data, len, BLACKLIST_HASH_BINARY); } /* @@ -73,7 +51,7 @@ __init efi_element_handler_t get_handler_for_db(const efi_guid_t *sig_type) { if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0) return add_to_platform_keyring; - return 0; + return NULL; } /* @@ -88,7 +66,7 @@ __init efi_element_handler_t get_handler_for_mok(const efi_guid_t *sig_type) else return add_to_platform_keyring; } - return 0; + return NULL; } /* @@ -103,5 +81,5 @@ __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type) return uefi_blacklist_binary; if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0) return uefi_revocation_list_x509; - return 0; + return NULL; } diff --git a/security/integrity/platform_certs/keyring_handler.h b/security/integrity/platform_certs/keyring_handler.h index 284558f304..212d894a8c 100644 --- a/security/integrity/platform_certs/keyring_handler.h +++ b/security/integrity/platform_certs/keyring_handler.h @@ -35,3 +35,11 @@ efi_element_handler_t get_handler_for_mok(const efi_guid_t *sig_type); efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type); #endif + +#ifndef UEFI_QUIRK_SKIP_CERT +#define UEFI_QUIRK_SKIP_CERT(vendor, product) \ + .matches = { \ + DMI_MATCH(DMI_BOARD_VENDOR, vendor), \ + DMI_MATCH(DMI_PRODUCT_NAME, product), \ + }, +#endif diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c index 5f45c3c07d..093894a640 100644 --- a/security/integrity/platform_certs/load_uefi.c +++ b/security/integrity/platform_certs/load_uefi.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -12,6 +13,31 @@ #include "../integrity.h" #include "keyring_handler.h" +/* + * On T2 Macs reading the db and dbx efi variables to load UEFI Secure Boot + * certificates causes occurrence of a page fault in Apple's firmware and + * a crash disabling EFI runtime services. The following quirk skips reading + * these variables. + */ +static const struct dmi_system_id uefi_skip_cert[] = { + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,1") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,2") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,3") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,4") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,1") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,2") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,3") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,4") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir8,1") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir8,2") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir9,1") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacMini8,1") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacPro7,1") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMac20,1") }, + { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMac20,2") }, + { } +}; + /* * Look to see if a UEFI variable called MokIgnoreDB exists and return true if * it does. @@ -138,6 +164,13 @@ static int __init load_uefi_certs(void) unsigned long dbsize = 0, dbxsize = 0, mokxsize = 0; efi_status_t status; int rc = 0; + const struct dmi_system_id *dmi_id; + + dmi_id = dmi_first_match(uefi_skip_cert); + if (dmi_id) { + pr_err("Reading UEFI Secure Boot Certs is not supported on T2 Macs.\n"); + return false; + } if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) return false; diff --git a/security/keys/Kconfig b/security/keys/Kconfig index 0e30b361e1..abb03a1b2a 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig @@ -70,23 +70,19 @@ config BIG_KEYS config TRUSTED_KEYS tristate "TRUSTED KEYS" - depends on KEYS && TCG_TPM - select CRYPTO - select CRYPTO_HMAC - select CRYPTO_SHA1 - select CRYPTO_HASH_INFO - select ASN1_ENCODER - select OID_REGISTRY - select ASN1 + depends on KEYS help This option provides support for creating, sealing, and unsealing keys in the kernel. Trusted keys are random number symmetric keys, - generated and RSA-sealed by the TPM. The TPM only unseals the keys, - if the boot PCRs and other criteria match. Userspace will only ever - see encrypted blobs. + generated and sealed by a trust source selected at kernel boot-time. + Userspace will only ever see encrypted blobs. If you are unsure as to whether this is required, answer N. +if TRUSTED_KEYS +source "security/keys/trusted-keys/Kconfig" +endif + config ENCRYPTED_KEYS tristate "ENCRYPTED KEYS" depends on KEYS diff --git a/security/keys/big_key.c b/security/keys/big_key.c index d17e5f09ee..c3367622c6 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c @@ -20,12 +20,13 @@ /* * Layout of key payload words. */ -enum { - big_key_data, - big_key_path, - big_key_path_2nd_part, - big_key_len, +struct big_key_payload { + u8 *data; + struct path path; + size_t length; }; +#define to_big_key_payload(payload) \ + (struct big_key_payload *)((payload).data) /* * If the data is under this limit, there's no point creating a shm file to @@ -55,7 +56,7 @@ struct key_type key_type_big_key = { */ int big_key_preparse(struct key_preparsed_payload *prep) { - struct path *path = (struct path *)&prep->payload.data[big_key_path]; + struct big_key_payload *payload = to_big_key_payload(prep->payload); struct file *file; u8 *buf, *enckey; ssize_t written; @@ -63,13 +64,15 @@ int big_key_preparse(struct key_preparsed_payload *prep) size_t enclen = datalen + CHACHA20POLY1305_AUTHTAG_SIZE; int ret; + BUILD_BUG_ON(sizeof(*payload) != sizeof(prep->payload.data)); + if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data) return -EINVAL; /* Set an arbitrary quota */ prep->quotalen = 16; - prep->payload.data[big_key_len] = (void *)(unsigned long)datalen; + payload->length = datalen; if (datalen > BIG_KEY_FILE_THRESHOLD) { /* Create a shmem file to store the data in. This will permit the data @@ -117,9 +120,9 @@ int big_key_preparse(struct key_preparsed_payload *prep) /* Pin the mount and dentry to the key so that we can open it again * later */ - prep->payload.data[big_key_data] = enckey; - *path = file->f_path; - path_get(path); + payload->data = enckey; + payload->path = file->f_path; + path_get(&payload->path); fput(file); kvfree_sensitive(buf, enclen); } else { @@ -129,7 +132,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) if (!data) return -ENOMEM; - prep->payload.data[big_key_data] = data; + payload->data = data; memcpy(data, prep->data, prep->datalen); } return 0; @@ -148,12 +151,11 @@ int big_key_preparse(struct key_preparsed_payload *prep) */ void big_key_free_preparse(struct key_preparsed_payload *prep) { - if (prep->datalen > BIG_KEY_FILE_THRESHOLD) { - struct path *path = (struct path *)&prep->payload.data[big_key_path]; + struct big_key_payload *payload = to_big_key_payload(prep->payload); - path_put(path); - } - kfree_sensitive(prep->payload.data[big_key_data]); + if (prep->datalen > BIG_KEY_FILE_THRESHOLD) + path_put(&payload->path); + kfree_sensitive(payload->data); } /* @@ -162,13 +164,12 @@ void big_key_free_preparse(struct key_preparsed_payload *prep) */ void big_key_revoke(struct key *key) { - struct path *path = (struct path *)&key->payload.data[big_key_path]; + struct big_key_payload *payload = to_big_key_payload(key->payload); /* clear the quota */ key_payload_reserve(key, 0); - if (key_is_positive(key) && - (size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD) - vfs_truncate(path, 0); + if (key_is_positive(key) && payload->length > BIG_KEY_FILE_THRESHOLD) + vfs_truncate(&payload->path, 0); } /* @@ -176,17 +177,15 @@ void big_key_revoke(struct key *key) */ void big_key_destroy(struct key *key) { - size_t datalen = (size_t)key->payload.data[big_key_len]; - - if (datalen > BIG_KEY_FILE_THRESHOLD) { - struct path *path = (struct path *)&key->payload.data[big_key_path]; + struct big_key_payload *payload = to_big_key_payload(key->payload); - path_put(path); - path->mnt = NULL; - path->dentry = NULL; + if (payload->length > BIG_KEY_FILE_THRESHOLD) { + path_put(&payload->path); + payload->path.mnt = NULL; + payload->path.dentry = NULL; } - kfree_sensitive(key->payload.data[big_key_data]); - key->payload.data[big_key_data] = NULL; + kfree_sensitive(payload->data); + payload->data = NULL; } /* @@ -211,14 +210,14 @@ int big_key_update(struct key *key, struct key_preparsed_payload *prep) */ void big_key_describe(const struct key *key, struct seq_file *m) { - size_t datalen = (size_t)key->payload.data[big_key_len]; + struct big_key_payload *payload = to_big_key_payload(key->payload); seq_puts(m, key->description); if (key_is_positive(key)) seq_printf(m, ": %zu [%s]", - datalen, - datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff"); + payload->length, + payload->length > BIG_KEY_FILE_THRESHOLD ? "file" : "buff"); } /* @@ -227,16 +226,16 @@ void big_key_describe(const struct key *key, struct seq_file *m) */ long big_key_read(const struct key *key, char *buffer, size_t buflen) { - size_t datalen = (size_t)key->payload.data[big_key_len]; + struct big_key_payload *payload = to_big_key_payload(key->payload); + size_t datalen = payload->length; long ret; if (!buffer || buflen < datalen) return datalen; if (datalen > BIG_KEY_FILE_THRESHOLD) { - struct path *path = (struct path *)&key->payload.data[big_key_path]; struct file *file; - u8 *buf, *enckey = (u8 *)key->payload.data[big_key_data]; + u8 *buf, *enckey = payload->data; size_t enclen = datalen + CHACHA20POLY1305_AUTHTAG_SIZE; loff_t pos = 0; @@ -244,7 +243,7 @@ long big_key_read(const struct key *key, char *buffer, size_t buflen) if (!buf) return -ENOMEM; - file = dentry_open(path, O_RDONLY, current_cred()); + file = dentry_open(&payload->path, O_RDONLY, current_cred()); if (IS_ERR(file)) { ret = PTR_ERR(file); goto error; @@ -274,7 +273,7 @@ long big_key_read(const struct key *key, char *buffer, size_t buflen) kvfree_sensitive(buf, enclen); } else { ret = datalen; - memcpy(buffer, key->payload.data[big_key_data], datalen); + memcpy(buffer, payload->data, datalen); } return ret; diff --git a/security/keys/trusted-keys/Makefile b/security/keys/trusted-keys/Makefile index feb8b6c3cc..735aa0bc08 100644 --- a/security/keys/trusted-keys/Makefile +++ b/security/keys/trusted-keys/Makefile @@ -5,10 +5,12 @@ obj-$(CONFIG_TRUSTED_KEYS) += trusted.o trusted-y += trusted_core.o -trusted-y += trusted_tpm1.o +trusted-$(CONFIG_TRUSTED_KEYS_TPM) += trusted_tpm1.o $(obj)/trusted_tpm2.o: $(obj)/tpm2key.asn1.h -trusted-y += trusted_tpm2.o -trusted-y += tpm2key.asn1.o +trusted-$(CONFIG_TRUSTED_KEYS_TPM) += trusted_tpm2.o +trusted-$(CONFIG_TRUSTED_KEYS_TPM) += tpm2key.asn1.o -trusted-$(CONFIG_TEE) += trusted_tee.o +trusted-$(CONFIG_TRUSTED_KEYS_TEE) += trusted_tee.o + +trusted-$(CONFIG_TRUSTED_KEYS_CAAM) += trusted_caam.o diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trusted-keys/trusted_core.c index 9b9d3ef79c..c6fc50d672 100644 --- a/security/keys/trusted-keys/trusted_core.c +++ b/security/keys/trusted-keys/trusted_core.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,23 +17,31 @@ #include #include #include +#include #include #include #include #include #include +static char *trusted_rng = "default"; +module_param_named(rng, trusted_rng, charp, 0); +MODULE_PARM_DESC(rng, "Select trusted key RNG"); + static char *trusted_key_source; module_param_named(source, trusted_key_source, charp, 0); -MODULE_PARM_DESC(source, "Select trusted keys source (tpm or tee)"); +MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee or caam)"); static const struct trusted_key_source trusted_key_sources[] = { -#if IS_REACHABLE(CONFIG_TCG_TPM) +#if defined(CONFIG_TRUSTED_KEYS_TPM) { "tpm", &trusted_key_tpm_ops }, #endif -#if IS_REACHABLE(CONFIG_TEE) +#if defined(CONFIG_TRUSTED_KEYS_TEE) { "tee", &trusted_key_tee_ops }, #endif +#if defined(CONFIG_TRUSTED_KEYS_CAAM) + { "caam", &trusted_key_caam_ops }, +#endif }; DEFINE_STATIC_CALL_NULL(trusted_key_init, *trusted_key_sources[0].ops->init); @@ -312,8 +321,14 @@ struct key_type key_type_trusted = { }; EXPORT_SYMBOL_GPL(key_type_trusted); +static int kernel_get_random(unsigned char *key, size_t key_len) +{ + return get_random_bytes_wait(key, key_len) ?: key_len; +} + static int __init init_trusted(void) { + int (*get_random)(unsigned char *key, size_t key_len); int i, ret = 0; for (i = 0; i < ARRAY_SIZE(trusted_key_sources); i++) { @@ -322,6 +337,28 @@ static int __init init_trusted(void) strlen(trusted_key_sources[i].name))) continue; + /* + * We always support trusted.rng="kernel" and "default" as + * well as trusted.rng=$trusted.source if the trust source + * defines its own get_random callback. + */ + get_random = trusted_key_sources[i].ops->get_random; + if (trusted_rng && strcmp(trusted_rng, "default")) { + if (!strcmp(trusted_rng, "kernel")) { + get_random = kernel_get_random; + } else if (strcmp(trusted_rng, trusted_key_sources[i].name) || + !get_random) { + pr_warn("Unsupported RNG. Supported: kernel"); + if (get_random) + pr_cont(", %s", trusted_key_sources[i].name); + pr_cont(", default\n"); + return -EINVAL; + } + } + + if (!get_random) + get_random = kernel_get_random; + static_call_update(trusted_key_init, trusted_key_sources[i].ops->init); static_call_update(trusted_key_seal, @@ -329,7 +366,7 @@ static int __init init_trusted(void) static_call_update(trusted_key_unseal, trusted_key_sources[i].ops->unseal); static_call_update(trusted_key_get_random, - trusted_key_sources[i].ops->get_random); + get_random); static_call_update(trusted_key_exit, trusted_key_sources[i].ops->exit); migratable = trusted_key_sources[i].ops->migratable; diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c index 0165da3862..2b2c8eb258 100644 --- a/security/keys/trusted-keys/trusted_tpm2.c +++ b/security/keys/trusted-keys/trusted_tpm2.c @@ -283,8 +283,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip, /* key properties */ flags = 0; flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH; - flags |= payload->migratable ? (TPM2_OA_FIXED_TPM | - TPM2_OA_FIXED_PARENT) : 0; + flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | + TPM2_OA_FIXED_PARENT); tpm_buf_append_u32(&buf, flags); /* policy */ diff --git a/security/landlock/cred.c b/security/landlock/cred.c index 6725af24c6..ec6c37f04a 100644 --- a/security/landlock/cred.c +++ b/security/landlock/cred.c @@ -15,7 +15,7 @@ #include "setup.h" static int hook_cred_prepare(struct cred *const new, - const struct cred *const old, const gfp_t gfp) + const struct cred *const old, const gfp_t gfp) { struct landlock_ruleset *const old_dom = landlock_cred(old)->domain; @@ -42,5 +42,5 @@ static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = { __init void landlock_add_cred_hooks(void) { security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), - LANDLOCK_NAME); + LANDLOCK_NAME); } diff --git a/security/landlock/cred.h b/security/landlock/cred.h index 5f99d3deca..af89ab00e6 100644 --- a/security/landlock/cred.h +++ b/security/landlock/cred.h @@ -20,8 +20,8 @@ struct landlock_cred_security { struct landlock_ruleset *domain; }; -static inline struct landlock_cred_security *landlock_cred( - const struct cred *cred) +static inline struct landlock_cred_security * +landlock_cred(const struct cred *cred) { return cred->security + landlock_blob_sizes.lbs_cred; } @@ -34,8 +34,8 @@ static inline const struct landlock_ruleset *landlock_get_current_domain(void) /* * The call needs to come from an RCU read-side critical section. */ -static inline const struct landlock_ruleset *landlock_get_task_domain( - const struct task_struct *const task) +static inline const struct landlock_ruleset * +landlock_get_task_domain(const struct task_struct *const task) { return landlock_cred(__task_cred(task))->domain; } diff --git a/security/landlock/fs.c b/security/landlock/fs.c index 97b8e421f6..a9dbd99d9e 100644 --- a/security/landlock/fs.c +++ b/security/landlock/fs.c @@ -4,6 +4,7 @@ * * Copyright © 2016-2020 Mickaël Salaün * Copyright © 2018-2020 ANSSI + * Copyright © 2021-2022 Microsoft Corporation */ #include @@ -141,29 +142,44 @@ static struct landlock_object *get_inode_object(struct inode *const inode) } /* All access rights that can be tied to files. */ +/* clang-format off */ #define ACCESS_FILE ( \ LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \ LANDLOCK_ACCESS_FS_READ_FILE) +/* clang-format on */ + +/* + * All access rights that are denied by default whether they are handled or not + * by a ruleset/layer. This must be ORed with all ruleset->fs_access_masks[] + * entries when we need to get the absolute handled access masks. + */ +/* clang-format off */ +#define ACCESS_INITIALLY_DENIED ( \ + LANDLOCK_ACCESS_FS_REFER) +/* clang-format on */ /* * @path: Should have been checked by get_path_from_fd(). */ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset, - const struct path *const path, u32 access_rights) + const struct path *const path, + access_mask_t access_rights) { int err; struct landlock_object *object; /* Files only get access rights that make sense. */ - if (!d_is_dir(path->dentry) && (access_rights | ACCESS_FILE) != - ACCESS_FILE) + if (!d_is_dir(path->dentry) && + (access_rights | ACCESS_FILE) != ACCESS_FILE) return -EINVAL; if (WARN_ON_ONCE(ruleset->num_layers != 1)) return -EINVAL; /* Transforms relative access rights to absolute ones. */ - access_rights |= LANDLOCK_MASK_ACCESS_FS & ~ruleset->fs_access_masks[0]; + access_rights |= + LANDLOCK_MASK_ACCESS_FS & + ~(ruleset->fs_access_masks[0] | ACCESS_INITIALLY_DENIED); object = get_inode_object(d_backing_inode(path->dentry)); if (IS_ERR(object)) return PTR_ERR(object); @@ -180,84 +196,346 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset, /* Access-control management */ -static inline u64 unmask_layers( - const struct landlock_ruleset *const domain, - const struct path *const path, const u32 access_request, - u64 layer_mask) +/* + * The lifetime of the returned rule is tied to @domain. + * + * Returns NULL if no rule is found or if @dentry is negative. + */ +static inline const struct landlock_rule * +find_rule(const struct landlock_ruleset *const domain, + const struct dentry *const dentry) { const struct landlock_rule *rule; const struct inode *inode; - size_t i; - if (d_is_negative(path->dentry)) - /* Ignore nonexistent leafs. */ - return layer_mask; - inode = d_backing_inode(path->dentry); + /* Ignores nonexistent leafs. */ + if (d_is_negative(dentry)) + return NULL; + + inode = d_backing_inode(dentry); rcu_read_lock(); - rule = landlock_find_rule(domain, - rcu_dereference(landlock_inode(inode)->object)); + rule = landlock_find_rule( + domain, rcu_dereference(landlock_inode(inode)->object)); rcu_read_unlock(); + return rule; +} + +/* + * @layer_masks is read and may be updated according to the access request and + * the matching rule. + * + * Returns true if the request is allowed (i.e. relevant layer masks for the + * request are empty). + */ +static inline bool +unmask_layers(const struct landlock_rule *const rule, + const access_mask_t access_request, + layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]) +{ + size_t layer_level; + + if (!access_request || !layer_masks) + return true; if (!rule) - return layer_mask; + return false; /* * An access is granted if, for each policy layer, at least one rule - * encountered on the pathwalk grants the requested accesses, - * regardless of their position in the layer stack. We must then check + * encountered on the pathwalk grants the requested access, + * regardless of its position in the layer stack. We must then check * the remaining layers for each inode, from the first added layer to - * the last one. + * the last one. When there is multiple requested accesses, for each + * policy layer, the full set of requested accesses may not be granted + * by only one rule, but by the union (binary OR) of multiple rules. + * E.g. /a/b + /a => /a/b */ - for (i = 0; i < rule->num_layers; i++) { - const struct landlock_layer *const layer = &rule->layers[i]; - const u64 layer_level = BIT_ULL(layer->level - 1); + for (layer_level = 0; layer_level < rule->num_layers; layer_level++) { + const struct landlock_layer *const layer = + &rule->layers[layer_level]; + const layer_mask_t layer_bit = BIT_ULL(layer->level - 1); + const unsigned long access_req = access_request; + unsigned long access_bit; + bool is_empty; - /* Checks that the layer grants access to the full request. */ - if ((layer->access & access_request) == access_request) { - layer_mask &= ~layer_level; - - if (layer_mask == 0) - return layer_mask; + /* + * Records in @layer_masks which layer grants access to each + * requested access. + */ + is_empty = true; + for_each_set_bit(access_bit, &access_req, + ARRAY_SIZE(*layer_masks)) { + if (layer->access & BIT_ULL(access_bit)) + (*layer_masks)[access_bit] &= ~layer_bit; + is_empty = is_empty && !(*layer_masks)[access_bit]; } + if (is_empty) + return true; } - return layer_mask; + return false; } -static int check_access_path(const struct landlock_ruleset *const domain, - const struct path *const path, u32 access_request) +/* + * Allows access to pseudo filesystems that will never be mountable (e.g. + * sockfs, pipefs), but can still be reachable through + * /proc//fd/ + */ +static inline bool is_nouser_or_private(const struct dentry *dentry) { - bool allowed = false; - struct path walker_path; - u64 layer_mask; - size_t i; + return (dentry->d_sb->s_flags & SB_NOUSER) || + (d_is_positive(dentry) && + unlikely(IS_PRIVATE(d_backing_inode(dentry)))); +} - /* Make sure all layers can be checked. */ - BUILD_BUG_ON(BITS_PER_TYPE(layer_mask) < LANDLOCK_MAX_NUM_LAYERS); +static inline access_mask_t +get_handled_accesses(const struct landlock_ruleset *const domain) +{ + access_mask_t access_dom = ACCESS_INITIALLY_DENIED; + size_t layer_level; + for (layer_level = 0; layer_level < domain->num_layers; layer_level++) + access_dom |= domain->fs_access_masks[layer_level]; + return access_dom & LANDLOCK_MASK_ACCESS_FS; +} + +static inline access_mask_t +init_layer_masks(const struct landlock_ruleset *const domain, + const access_mask_t access_request, + layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]) +{ + access_mask_t handled_accesses = 0; + size_t layer_level; + + memset(layer_masks, 0, sizeof(*layer_masks)); + /* An empty access request can happen because of O_WRONLY | O_RDWR. */ if (!access_request) return 0; + + /* Saves all handled accesses per layer. */ + for (layer_level = 0; layer_level < domain->num_layers; layer_level++) { + const unsigned long access_req = access_request; + unsigned long access_bit; + + for_each_set_bit(access_bit, &access_req, + ARRAY_SIZE(*layer_masks)) { + /* + * Artificially handles all initially denied by default + * access rights. + */ + if (BIT_ULL(access_bit) & + (domain->fs_access_masks[layer_level] | + ACCESS_INITIALLY_DENIED)) { + (*layer_masks)[access_bit] |= + BIT_ULL(layer_level); + handled_accesses |= BIT_ULL(access_bit); + } + } + } + return handled_accesses; +} + +/* + * Check that a destination file hierarchy has more restrictions than a source + * file hierarchy. This is only used for link and rename actions. + * + * @layer_masks_child2: Optional child masks. + */ +static inline bool no_more_access( + const layer_mask_t (*const layer_masks_parent1)[LANDLOCK_NUM_ACCESS_FS], + const layer_mask_t (*const layer_masks_child1)[LANDLOCK_NUM_ACCESS_FS], + const bool child1_is_directory, + const layer_mask_t (*const layer_masks_parent2)[LANDLOCK_NUM_ACCESS_FS], + const layer_mask_t (*const layer_masks_child2)[LANDLOCK_NUM_ACCESS_FS], + const bool child2_is_directory) +{ + unsigned long access_bit; + + for (access_bit = 0; access_bit < ARRAY_SIZE(*layer_masks_parent2); + access_bit++) { + /* Ignores accesses that only make sense for directories. */ + const bool is_file_access = + !!(BIT_ULL(access_bit) & ACCESS_FILE); + + if (child1_is_directory || is_file_access) { + /* + * Checks if the destination restrictions are a + * superset of the source ones (i.e. inherited access + * rights without child exceptions): + * restrictions(parent2) >= restrictions(child1) + */ + if ((((*layer_masks_parent1)[access_bit] & + (*layer_masks_child1)[access_bit]) | + (*layer_masks_parent2)[access_bit]) != + (*layer_masks_parent2)[access_bit]) + return false; + } + + if (!layer_masks_child2) + continue; + if (child2_is_directory || is_file_access) { + /* + * Checks inverted restrictions for RENAME_EXCHANGE: + * restrictions(parent1) >= restrictions(child2) + */ + if ((((*layer_masks_parent2)[access_bit] & + (*layer_masks_child2)[access_bit]) | + (*layer_masks_parent1)[access_bit]) != + (*layer_masks_parent1)[access_bit]) + return false; + } + } + return true; +} + +/* + * Removes @layer_masks accesses that are not requested. + * + * Returns true if the request is allowed, false otherwise. + */ +static inline bool +scope_to_request(const access_mask_t access_request, + layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]) +{ + const unsigned long access_req = access_request; + unsigned long access_bit; + + if (WARN_ON_ONCE(!layer_masks)) + return true; + + for_each_clear_bit(access_bit, &access_req, ARRAY_SIZE(*layer_masks)) + (*layer_masks)[access_bit] = 0; + return !memchr_inv(layer_masks, 0, sizeof(*layer_masks)); +} + +/* + * Returns true if there is at least one access right different than + * LANDLOCK_ACCESS_FS_REFER. + */ +static inline bool +is_eacces(const layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS], + const access_mask_t access_request) +{ + unsigned long access_bit; + /* LANDLOCK_ACCESS_FS_REFER alone must return -EXDEV. */ + const unsigned long access_check = access_request & + ~LANDLOCK_ACCESS_FS_REFER; + + if (!layer_masks) + return false; + + for_each_set_bit(access_bit, &access_check, ARRAY_SIZE(*layer_masks)) { + if ((*layer_masks)[access_bit]) + return true; + } + return false; +} + +/** + * check_access_path_dual - Check accesses for requests with a common path + * + * @domain: Domain to check against. + * @path: File hierarchy to walk through. + * @access_request_parent1: Accesses to check, once @layer_masks_parent1 is + * equal to @layer_masks_parent2 (if any). This is tied to the unique + * requested path for most actions, or the source in case of a refer action + * (i.e. rename or link), or the source and destination in case of + * RENAME_EXCHANGE. + * @layer_masks_parent1: Pointer to a matrix of layer masks per access + * masks, identifying the layers that forbid a specific access. Bits from + * this matrix can be unset according to the @path walk. An empty matrix + * means that @domain allows all possible Landlock accesses (i.e. not only + * those identified by @access_request_parent1). This matrix can + * initially refer to domain layer masks and, when the accesses for the + * destination and source are the same, to requested layer masks. + * @dentry_child1: Dentry to the initial child of the parent1 path. This + * pointer must be NULL for non-refer actions (i.e. not link nor rename). + * @access_request_parent2: Similar to @access_request_parent1 but for a + * request involving a source and a destination. This refers to the + * destination, except in case of RENAME_EXCHANGE where it also refers to + * the source. Must be set to 0 when using a simple path request. + * @layer_masks_parent2: Similar to @layer_masks_parent1 but for a refer + * action. This must be NULL otherwise. + * @dentry_child2: Dentry to the initial child of the parent2 path. This + * pointer is only set for RENAME_EXCHANGE actions and must be NULL + * otherwise. + * + * This helper first checks that the destination has a superset of restrictions + * compared to the source (if any) for a common path. Because of + * RENAME_EXCHANGE actions, source and destinations may be swapped. It then + * checks that the collected accesses and the remaining ones are enough to + * allow the request. + * + * Returns: + * - 0 if the access request is granted; + * - -EACCES if it is denied because of access right other than + * LANDLOCK_ACCESS_FS_REFER; + * - -EXDEV if the renaming or linking would be a privileged escalation + * (according to each layered policies), or if LANDLOCK_ACCESS_FS_REFER is + * not allowed by the source or the destination. + */ +static int check_access_path_dual( + const struct landlock_ruleset *const domain, + const struct path *const path, + const access_mask_t access_request_parent1, + layer_mask_t (*const layer_masks_parent1)[LANDLOCK_NUM_ACCESS_FS], + const struct dentry *const dentry_child1, + const access_mask_t access_request_parent2, + layer_mask_t (*const layer_masks_parent2)[LANDLOCK_NUM_ACCESS_FS], + const struct dentry *const dentry_child2) +{ + bool allowed_parent1 = false, allowed_parent2 = false, is_dom_check, + child1_is_directory = true, child2_is_directory = true; + struct path walker_path; + access_mask_t access_masked_parent1, access_masked_parent2; + layer_mask_t _layer_masks_child1[LANDLOCK_NUM_ACCESS_FS], + _layer_masks_child2[LANDLOCK_NUM_ACCESS_FS]; + layer_mask_t(*layer_masks_child1)[LANDLOCK_NUM_ACCESS_FS] = NULL, + (*layer_masks_child2)[LANDLOCK_NUM_ACCESS_FS] = NULL; + + if (!access_request_parent1 && !access_request_parent2) + return 0; if (WARN_ON_ONCE(!domain || !path)) return 0; - /* - * Allows access to pseudo filesystems that will never be mountable - * (e.g. sockfs, pipefs), but can still be reachable through - * /proc//fd/ . - */ - if ((path->dentry->d_sb->s_flags & SB_NOUSER) || - (d_is_positive(path->dentry) && - unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))) + if (is_nouser_or_private(path->dentry)) return 0; - if (WARN_ON_ONCE(domain->num_layers < 1)) + if (WARN_ON_ONCE(domain->num_layers < 1 || !layer_masks_parent1)) return -EACCES; - /* Saves all layers handling a subset of requested accesses. */ - layer_mask = 0; - for (i = 0; i < domain->num_layers; i++) { - if (domain->fs_access_masks[i] & access_request) - layer_mask |= BIT_ULL(i); + if (unlikely(layer_masks_parent2)) { + if (WARN_ON_ONCE(!dentry_child1)) + return -EACCES; + /* + * For a double request, first check for potential privilege + * escalation by looking at domain handled accesses (which are + * a superset of the meaningful requested accesses). + */ + access_masked_parent1 = access_masked_parent2 = + get_handled_accesses(domain); + is_dom_check = true; + } else { + if (WARN_ON_ONCE(dentry_child1 || dentry_child2)) + return -EACCES; + /* For a simple request, only check for requested accesses. */ + access_masked_parent1 = access_request_parent1; + access_masked_parent2 = access_request_parent2; + is_dom_check = false; + } + + if (unlikely(dentry_child1)) { + unmask_layers(find_rule(domain, dentry_child1), + init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS, + &_layer_masks_child1), + &_layer_masks_child1); + layer_masks_child1 = &_layer_masks_child1; + child1_is_directory = d_is_dir(dentry_child1); + } + if (unlikely(dentry_child2)) { + unmask_layers(find_rule(domain, dentry_child2), + init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS, + &_layer_masks_child2), + &_layer_masks_child2); + layer_masks_child2 = &_layer_masks_child2; + child2_is_directory = d_is_dir(dentry_child2); } - /* An access request not handled by the domain is allowed. */ - if (layer_mask == 0) - return 0; walker_path = *path; path_get(&walker_path); @@ -267,15 +545,54 @@ static int check_access_path(const struct landlock_ruleset *const domain, */ while (true) { struct dentry *parent_dentry; + const struct landlock_rule *rule; - layer_mask = unmask_layers(domain, &walker_path, - access_request, layer_mask); - if (layer_mask == 0) { - /* Stops when a rule from each layer grants access. */ - allowed = true; - break; + /* + * If at least all accesses allowed on the destination are + * already allowed on the source, respectively if there is at + * least as much as restrictions on the destination than on the + * source, then we can safely refer files from the source to + * the destination without risking a privilege escalation. + * This also applies in the case of RENAME_EXCHANGE, which + * implies checks on both direction. This is crucial for + * standalone multilayered security policies. Furthermore, + * this helps avoid policy writers to shoot themselves in the + * foot. + */ + if (unlikely(is_dom_check && + no_more_access( + layer_masks_parent1, layer_masks_child1, + child1_is_directory, layer_masks_parent2, + layer_masks_child2, + child2_is_directory))) { + allowed_parent1 = scope_to_request( + access_request_parent1, layer_masks_parent1); + allowed_parent2 = scope_to_request( + access_request_parent2, layer_masks_parent2); + + /* Stops when all accesses are granted. */ + if (allowed_parent1 && allowed_parent2) + break; + + /* + * Now, downgrades the remaining checks from domain + * handled accesses to requested accesses. + */ + is_dom_check = false; + access_masked_parent1 = access_request_parent1; + access_masked_parent2 = access_request_parent2; } + rule = find_rule(domain, walker_path.dentry); + allowed_parent1 = unmask_layers(rule, access_masked_parent1, + layer_masks_parent1); + allowed_parent2 = unmask_layers(rule, access_masked_parent2, + layer_masks_parent2); + + /* Stops when a rule from each layer grants access. */ + if (allowed_parent1 && allowed_parent2) + break; + jump_up: if (walker_path.dentry == walker_path.mnt->mnt_root) { if (follow_up(&walker_path)) { @@ -286,7 +603,6 @@ static int check_access_path(const struct landlock_ruleset *const domain, * Stops at the real root. Denies access * because not all layers have granted access. */ - allowed = false; break; } } @@ -296,7 +612,8 @@ static int check_access_path(const struct landlock_ruleset *const domain, * access to internal filesystems (e.g. nsfs, which is * reachable through /proc//ns/). */ - allowed = !!(walker_path.mnt->mnt_flags & MNT_INTERNAL); + allowed_parent1 = allowed_parent2 = + !!(walker_path.mnt->mnt_flags & MNT_INTERNAL); break; } parent_dentry = dget_parent(walker_path.dentry); @@ -304,11 +621,40 @@ static int check_access_path(const struct landlock_ruleset *const domain, walker_path.dentry = parent_dentry; } path_put(&walker_path); - return allowed ? 0 : -EACCES; + + if (allowed_parent1 && allowed_parent2) + return 0; + + /* + * This prioritizes EACCES over EXDEV for all actions, including + * renames with RENAME_EXCHANGE. + */ + if (likely(is_eacces(layer_masks_parent1, access_request_parent1) || + is_eacces(layer_masks_parent2, access_request_parent2))) + return -EACCES; + + /* + * Gracefully forbids reparenting if the destination directory + * hierarchy is not a superset of restrictions of the source directory + * hierarchy, or if LANDLOCK_ACCESS_FS_REFER is not allowed by the + * source or the destination. + */ + return -EXDEV; +} + +static inline int check_access_path(const struct landlock_ruleset *const domain, + const struct path *const path, + access_mask_t access_request) +{ + layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; + + access_request = init_layer_masks(domain, access_request, &layer_masks); + return check_access_path_dual(domain, path, access_request, + &layer_masks, NULL, 0, NULL, NULL); } static inline int current_check_access_path(const struct path *const path, - const u32 access_request) + const access_mask_t access_request) { const struct landlock_ruleset *const dom = landlock_get_current_domain(); @@ -318,6 +664,235 @@ static inline int current_check_access_path(const struct path *const path, return check_access_path(dom, path, access_request); } +static inline access_mask_t get_mode_access(const umode_t mode) +{ + switch (mode & S_IFMT) { + case S_IFLNK: + return LANDLOCK_ACCESS_FS_MAKE_SYM; + case 0: + /* A zero mode translates to S_IFREG. */ + case S_IFREG: + return LANDLOCK_ACCESS_FS_MAKE_REG; + case S_IFDIR: + return LANDLOCK_ACCESS_FS_MAKE_DIR; + case S_IFCHR: + return LANDLOCK_ACCESS_FS_MAKE_CHAR; + case S_IFBLK: + return LANDLOCK_ACCESS_FS_MAKE_BLOCK; + case S_IFIFO: + return LANDLOCK_ACCESS_FS_MAKE_FIFO; + case S_IFSOCK: + return LANDLOCK_ACCESS_FS_MAKE_SOCK; + default: + WARN_ON_ONCE(1); + return 0; + } +} + +static inline access_mask_t maybe_remove(const struct dentry *const dentry) +{ + if (d_is_negative(dentry)) + return 0; + return d_is_dir(dentry) ? LANDLOCK_ACCESS_FS_REMOVE_DIR : + LANDLOCK_ACCESS_FS_REMOVE_FILE; +} + +/** + * collect_domain_accesses - Walk through a file path and collect accesses + * + * @domain: Domain to check against. + * @mnt_root: Last directory to check. + * @dir: Directory to start the walk from. + * @layer_masks_dom: Where to store the collected accesses. + * + * This helper is useful to begin a path walk from the @dir directory to a + * @mnt_root directory used as a mount point. This mount point is the common + * ancestor between the source and the destination of a renamed and linked + * file. While walking from @dir to @mnt_root, we record all the domain's + * allowed accesses in @layer_masks_dom. + * + * This is similar to check_access_path_dual() but much simpler because it only + * handles walking on the same mount point and only check one set of accesses. + * + * Returns: + * - true if all the domain access rights are allowed for @dir; + * - false if the walk reached @mnt_root. + */ +static bool collect_domain_accesses( + const struct landlock_ruleset *const domain, + const struct dentry *const mnt_root, struct dentry *dir, + layer_mask_t (*const layer_masks_dom)[LANDLOCK_NUM_ACCESS_FS]) +{ + unsigned long access_dom; + bool ret = false; + + if (WARN_ON_ONCE(!domain || !mnt_root || !dir || !layer_masks_dom)) + return true; + if (is_nouser_or_private(dir)) + return true; + + access_dom = init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS, + layer_masks_dom); + + dget(dir); + while (true) { + struct dentry *parent_dentry; + + /* Gets all layers allowing all domain accesses. */ + if (unmask_layers(find_rule(domain, dir), access_dom, + layer_masks_dom)) { + /* + * Stops when all handled accesses are allowed by at + * least one rule in each layer. + */ + ret = true; + break; + } + + /* We should not reach a root other than @mnt_root. */ + if (dir == mnt_root || WARN_ON_ONCE(IS_ROOT(dir))) + break; + + parent_dentry = dget_parent(dir); + dput(dir); + dir = parent_dentry; + } + dput(dir); + return ret; +} + +/** + * current_check_refer_path - Check if a rename or link action is allowed + * + * @old_dentry: File or directory requested to be moved or linked. + * @new_dir: Destination parent directory. + * @new_dentry: Destination file or directory. + * @removable: Sets to true if it is a rename operation. + * @exchange: Sets to true if it is a rename operation with RENAME_EXCHANGE. + * + * Because of its unprivileged constraints, Landlock relies on file hierarchies + * (and not only inodes) to tie access rights to files. Being able to link or + * rename a file hierarchy brings some challenges. Indeed, moving or linking a + * file (i.e. creating a new reference to an inode) can have an impact on the + * actions allowed for a set of files if it would change its parent directory + * (i.e. reparenting). + * + * To avoid trivial access right bypasses, Landlock first checks if the file or + * directory requested to be moved would gain new access rights inherited from + * its new hierarchy. Before returning any error, Landlock then checks that + * the parent source hierarchy and the destination hierarchy would allow the + * link or rename action. If it is not the case, an error with EACCES is + * returned to inform user space that there is no way to remove or create the + * requested source file type. If it should be allowed but the new inherited + * access rights would be greater than the source access rights, then the + * kernel returns an error with EXDEV. Prioritizing EACCES over EXDEV enables + * user space to abort the whole operation if there is no way to do it, or to + * manually copy the source to the destination if this remains allowed, e.g. + * because file creation is allowed on the destination directory but not direct + * linking. + * + * To achieve this goal, the kernel needs to compare two file hierarchies: the + * one identifying the source file or directory (including itself), and the + * destination one. This can be seen as a multilayer partial ordering problem. + * The kernel walks through these paths and collects in a matrix the access + * rights that are denied per layer. These matrices are then compared to see + * if the destination one has more (or the same) restrictions as the source + * one. If this is the case, the requested action will not return EXDEV, which + * doesn't mean the action is allowed. The parent hierarchy of the source + * (i.e. parent directory), and the destination hierarchy must also be checked + * to verify that they explicitly allow such action (i.e. referencing, + * creation and potentially removal rights). The kernel implementation is then + * required to rely on potentially four matrices of access rights: one for the + * source file or directory (i.e. the child), a potentially other one for the + * other source/destination (in case of RENAME_EXCHANGE), one for the source + * parent hierarchy and a last one for the destination hierarchy. These + * ephemeral matrices take some space on the stack, which limits the number of + * layers to a deemed reasonable number: 16. + * + * Returns: + * - 0 if access is allowed; + * - -EXDEV if @old_dentry would inherit new access rights from @new_dir; + * - -EACCES if file removal or creation is denied. + */ +static int current_check_refer_path(struct dentry *const old_dentry, + const struct path *const new_dir, + struct dentry *const new_dentry, + const bool removable, const bool exchange) +{ + const struct landlock_ruleset *const dom = + landlock_get_current_domain(); + bool allow_parent1, allow_parent2; + access_mask_t access_request_parent1, access_request_parent2; + struct path mnt_dir; + layer_mask_t layer_masks_parent1[LANDLOCK_NUM_ACCESS_FS], + layer_masks_parent2[LANDLOCK_NUM_ACCESS_FS]; + + if (!dom) + return 0; + if (WARN_ON_ONCE(dom->num_layers < 1)) + return -EACCES; + if (unlikely(d_is_negative(old_dentry))) + return -ENOENT; + if (exchange) { + if (unlikely(d_is_negative(new_dentry))) + return -ENOENT; + access_request_parent1 = + get_mode_access(d_backing_inode(new_dentry)->i_mode); + } else { + access_request_parent1 = 0; + } + access_request_parent2 = + get_mode_access(d_backing_inode(old_dentry)->i_mode); + if (removable) { + access_request_parent1 |= maybe_remove(old_dentry); + access_request_parent2 |= maybe_remove(new_dentry); + } + + /* The mount points are the same for old and new paths, cf. EXDEV. */ + if (old_dentry->d_parent == new_dir->dentry) { + /* + * The LANDLOCK_ACCESS_FS_REFER access right is not required + * for same-directory referer (i.e. no reparenting). + */ + access_request_parent1 = init_layer_masks( + dom, access_request_parent1 | access_request_parent2, + &layer_masks_parent1); + return check_access_path_dual(dom, new_dir, + access_request_parent1, + &layer_masks_parent1, NULL, 0, + NULL, NULL); + } + + access_request_parent1 |= LANDLOCK_ACCESS_FS_REFER; + access_request_parent2 |= LANDLOCK_ACCESS_FS_REFER; + + /* Saves the common mount point. */ + mnt_dir.mnt = new_dir->mnt; + mnt_dir.dentry = new_dir->mnt->mnt_root; + + /* new_dir->dentry is equal to new_dentry->d_parent */ + allow_parent1 = collect_domain_accesses(dom, mnt_dir.dentry, + old_dentry->d_parent, + &layer_masks_parent1); + allow_parent2 = collect_domain_accesses( + dom, mnt_dir.dentry, new_dir->dentry, &layer_masks_parent2); + + if (allow_parent1 && allow_parent2) + return 0; + + /* + * To be able to compare source and destination domain access rights, + * take into account the @old_dentry access rights aggregated with its + * parent access rights. This will be useful to compare with the + * destination parent access rights. + */ + return check_access_path_dual(dom, &mnt_dir, access_request_parent1, + &layer_masks_parent1, old_dentry, + access_request_parent2, + &layer_masks_parent2, + exchange ? new_dentry : NULL); +} + /* Inode hooks */ static void hook_inode_free_security(struct inode *const inode) @@ -436,8 +1011,8 @@ static void hook_sb_delete(struct super_block *const sb) if (prev_inode) iput(prev_inode); /* Waits for pending iput() in release_inode(). */ - wait_var_event(&landlock_superblock(sb)->inode_refs, !atomic_long_read( - &landlock_superblock(sb)->inode_refs)); + wait_var_event(&landlock_superblock(sb)->inode_refs, + !atomic_long_read(&landlock_superblock(sb)->inode_refs)); } /* @@ -459,8 +1034,8 @@ static void hook_sb_delete(struct super_block *const sb) * a dedicated user space option would be required (e.g. as a ruleset flag). */ static int hook_sb_mount(const char *const dev_name, - const struct path *const path, const char *const type, - const unsigned long flags, void *const data) + const struct path *const path, const char *const type, + const unsigned long flags, void *const data) { if (!landlock_get_current_domain()) return 0; @@ -468,7 +1043,7 @@ static int hook_sb_mount(const char *const dev_name, } static int hook_move_mount(const struct path *const from_path, - const struct path *const to_path) + const struct path *const to_path) { if (!landlock_get_current_domain()) return 0; @@ -502,7 +1077,7 @@ static int hook_sb_remount(struct super_block *const sb, void *const mnt_opts) * view of the filesystem. */ static int hook_sb_pivotroot(const struct path *const old_path, - const struct path *const new_path) + const struct path *const new_path) { if (!landlock_get_current_domain()) return 0; @@ -511,97 +1086,34 @@ static int hook_sb_pivotroot(const struct path *const old_path, /* Path hooks */ -static inline u32 get_mode_access(const umode_t mode) -{ - switch (mode & S_IFMT) { - case S_IFLNK: - return LANDLOCK_ACCESS_FS_MAKE_SYM; - case 0: - /* A zero mode translates to S_IFREG. */ - case S_IFREG: - return LANDLOCK_ACCESS_FS_MAKE_REG; - case S_IFDIR: - return LANDLOCK_ACCESS_FS_MAKE_DIR; - case S_IFCHR: - return LANDLOCK_ACCESS_FS_MAKE_CHAR; - case S_IFBLK: - return LANDLOCK_ACCESS_FS_MAKE_BLOCK; - case S_IFIFO: - return LANDLOCK_ACCESS_FS_MAKE_FIFO; - case S_IFSOCK: - return LANDLOCK_ACCESS_FS_MAKE_SOCK; - default: - WARN_ON_ONCE(1); - return 0; - } -} - -/* - * Creating multiple links or renaming may lead to privilege escalations if not - * handled properly. Indeed, we must be sure that the source doesn't gain more - * privileges by being accessible from the destination. This is getting more - * complex when dealing with multiple layers. The whole picture can be seen as - * a multilayer partial ordering problem. A future version of Landlock will - * deal with that. - */ static int hook_path_link(struct dentry *const old_dentry, - const struct path *const new_dir, - struct dentry *const new_dentry) -{ - const struct landlock_ruleset *const dom = - landlock_get_current_domain(); - - if (!dom) - return 0; - /* The mount points are the same for old and new paths, cf. EXDEV. */ - if (old_dentry->d_parent != new_dir->dentry) - /* Gracefully forbids reparenting. */ - return -EXDEV; - if (unlikely(d_is_negative(old_dentry))) - return -ENOENT; - return check_access_path(dom, new_dir, - get_mode_access(d_backing_inode(old_dentry)->i_mode)); -} - -static inline u32 maybe_remove(const struct dentry *const dentry) + const struct path *const new_dir, + struct dentry *const new_dentry) { - if (d_is_negative(dentry)) - return 0; - return d_is_dir(dentry) ? LANDLOCK_ACCESS_FS_REMOVE_DIR : - LANDLOCK_ACCESS_FS_REMOVE_FILE; + return current_check_refer_path(old_dentry, new_dir, new_dentry, false, + false); } static int hook_path_rename(const struct path *const old_dir, - struct dentry *const old_dentry, - const struct path *const new_dir, - struct dentry *const new_dentry) + struct dentry *const old_dentry, + const struct path *const new_dir, + struct dentry *const new_dentry, + const unsigned int flags) { - const struct landlock_ruleset *const dom = - landlock_get_current_domain(); - - if (!dom) - return 0; - /* The mount points are the same for old and new paths, cf. EXDEV. */ - if (old_dir->dentry != new_dir->dentry) - /* Gracefully forbids reparenting. */ - return -EXDEV; - if (unlikely(d_is_negative(old_dentry))) - return -ENOENT; - /* RENAME_EXCHANGE is handled because directories are the same. */ - return check_access_path(dom, old_dir, maybe_remove(old_dentry) | - maybe_remove(new_dentry) | - get_mode_access(d_backing_inode(old_dentry)->i_mode)); + /* old_dir refers to old_dentry->d_parent and new_dir->mnt */ + return current_check_refer_path(old_dentry, new_dir, new_dentry, true, + !!(flags & RENAME_EXCHANGE)); } static int hook_path_mkdir(const struct path *const dir, - struct dentry *const dentry, const umode_t mode) + struct dentry *const dentry, const umode_t mode) { return current_check_access_path(dir, LANDLOCK_ACCESS_FS_MAKE_DIR); } static int hook_path_mknod(const struct path *const dir, - struct dentry *const dentry, const umode_t mode, - const unsigned int dev) + struct dentry *const dentry, const umode_t mode, + const unsigned int dev) { const struct landlock_ruleset *const dom = landlock_get_current_domain(); @@ -612,28 +1124,29 @@ static int hook_path_mknod(const struct path *const dir, } static int hook_path_symlink(const struct path *const dir, - struct dentry *const dentry, const char *const old_name) + struct dentry *const dentry, + const char *const old_name) { return current_check_access_path(dir, LANDLOCK_ACCESS_FS_MAKE_SYM); } static int hook_path_unlink(const struct path *const dir, - struct dentry *const dentry) + struct dentry *const dentry) { return current_check_access_path(dir, LANDLOCK_ACCESS_FS_REMOVE_FILE); } static int hook_path_rmdir(const struct path *const dir, - struct dentry *const dentry) + struct dentry *const dentry) { return current_check_access_path(dir, LANDLOCK_ACCESS_FS_REMOVE_DIR); } /* File hooks */ -static inline u32 get_file_access(const struct file *const file) +static inline access_mask_t get_file_access(const struct file *const file) { - u32 access = 0; + access_mask_t access = 0; if (file->f_mode & FMODE_READ) { /* A directory can only be opened in read mode. */ @@ -688,5 +1201,5 @@ static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = { __init void landlock_add_fs_hooks(void) { security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), - LANDLOCK_NAME); + LANDLOCK_NAME); } diff --git a/security/landlock/fs.h b/security/landlock/fs.h index 187284b421..8db7acf910 100644 --- a/security/landlock/fs.h +++ b/security/landlock/fs.h @@ -50,14 +50,14 @@ struct landlock_superblock_security { atomic_long_t inode_refs; }; -static inline struct landlock_inode_security *landlock_inode( - const struct inode *const inode) +static inline struct landlock_inode_security * +landlock_inode(const struct inode *const inode) { return inode->i_security + landlock_blob_sizes.lbs_inode; } -static inline struct landlock_superblock_security *landlock_superblock( - const struct super_block *const superblock) +static inline struct landlock_superblock_security * +landlock_superblock(const struct super_block *const superblock) { return superblock->s_security + landlock_blob_sizes.lbs_superblock; } @@ -65,6 +65,7 @@ static inline struct landlock_superblock_security *landlock_superblock( __init void landlock_add_fs_hooks(void); int landlock_append_fs_rule(struct landlock_ruleset *const ruleset, - const struct path *const path, u32 access_hierarchy); + const struct path *const path, + access_mask_t access_hierarchy); #endif /* _SECURITY_LANDLOCK_FS_H */ diff --git a/security/landlock/limits.h b/security/landlock/limits.h index 2a0a1095ee..b54184ab94 100644 --- a/security/landlock/limits.h +++ b/security/landlock/limits.h @@ -9,13 +9,19 @@ #ifndef _SECURITY_LANDLOCK_LIMITS_H #define _SECURITY_LANDLOCK_LIMITS_H +#include #include #include -#define LANDLOCK_MAX_NUM_LAYERS 64 +/* clang-format off */ + +#define LANDLOCK_MAX_NUM_LAYERS 16 #define LANDLOCK_MAX_NUM_RULES U32_MAX -#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_MAKE_SYM +#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_REFER #define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1) +#define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS) + +/* clang-format on */ #endif /* _SECURITY_LANDLOCK_LIMITS_H */ diff --git a/security/landlock/object.c b/security/landlock/object.c index d674fdf9ff..1f50612f01 100644 --- a/security/landlock/object.c +++ b/security/landlock/object.c @@ -17,9 +17,9 @@ #include "object.h" -struct landlock_object *landlock_create_object( - const struct landlock_object_underops *const underops, - void *const underobj) +struct landlock_object * +landlock_create_object(const struct landlock_object_underops *const underops, + void *const underobj) { struct landlock_object *new_object; diff --git a/security/landlock/object.h b/security/landlock/object.h index 3f80674c6c..5f28c35e8a 100644 --- a/security/landlock/object.h +++ b/security/landlock/object.h @@ -76,9 +76,9 @@ struct landlock_object { }; }; -struct landlock_object *landlock_create_object( - const struct landlock_object_underops *const underops, - void *const underobj); +struct landlock_object * +landlock_create_object(const struct landlock_object_underops *const underops, + void *const underobj); void landlock_put_object(struct landlock_object *const object); diff --git a/security/landlock/ptrace.c b/security/landlock/ptrace.c index f55b82446d..4c5b9cd712 100644 --- a/security/landlock/ptrace.c +++ b/security/landlock/ptrace.c @@ -30,7 +30,7 @@ * means a subset of) the @child domain. */ static bool domain_scope_le(const struct landlock_ruleset *const parent, - const struct landlock_ruleset *const child) + const struct landlock_ruleset *const child) { const struct landlock_hierarchy *walker; @@ -48,7 +48,7 @@ static bool domain_scope_le(const struct landlock_ruleset *const parent, } static bool task_is_scoped(const struct task_struct *const parent, - const struct task_struct *const child) + const struct task_struct *const child) { bool is_scoped; const struct landlock_ruleset *dom_parent, *dom_child; @@ -62,7 +62,7 @@ static bool task_is_scoped(const struct task_struct *const parent, } static int task_ptrace(const struct task_struct *const parent, - const struct task_struct *const child) + const struct task_struct *const child) { /* Quick return for non-landlocked tasks. */ if (!landlocked(parent)) @@ -86,7 +86,7 @@ static int task_ptrace(const struct task_struct *const parent, * granted, -errno if denied. */ static int hook_ptrace_access_check(struct task_struct *const child, - const unsigned int mode) + const unsigned int mode) { return task_ptrace(current, child); } @@ -116,5 +116,5 @@ static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = { __init void landlock_add_ptrace_hooks(void) { security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), - LANDLOCK_NAME); + LANDLOCK_NAME); } diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c index ec72b9262b..996484f98b 100644 --- a/security/landlock/ruleset.c +++ b/security/landlock/ruleset.c @@ -28,8 +28,9 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers) { struct landlock_ruleset *new_ruleset; - new_ruleset = kzalloc(struct_size(new_ruleset, fs_access_masks, - num_layers), GFP_KERNEL_ACCOUNT); + new_ruleset = + kzalloc(struct_size(new_ruleset, fs_access_masks, num_layers), + GFP_KERNEL_ACCOUNT); if (!new_ruleset) return ERR_PTR(-ENOMEM); refcount_set(&new_ruleset->usage, 1); @@ -44,7 +45,8 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers) return new_ruleset; } -struct landlock_ruleset *landlock_create_ruleset(const u32 fs_access_mask) +struct landlock_ruleset * +landlock_create_ruleset(const access_mask_t fs_access_mask) { struct landlock_ruleset *new_ruleset; @@ -66,11 +68,10 @@ static void build_check_rule(void) BUILD_BUG_ON(rule.num_layers < LANDLOCK_MAX_NUM_LAYERS); } -static struct landlock_rule *create_rule( - struct landlock_object *const object, - const struct landlock_layer (*const layers)[], - const u32 num_layers, - const struct landlock_layer *const new_layer) +static struct landlock_rule * +create_rule(struct landlock_object *const object, + const struct landlock_layer (*const layers)[], const u32 num_layers, + const struct landlock_layer *const new_layer) { struct landlock_rule *new_rule; u32 new_num_layers; @@ -85,7 +86,7 @@ static struct landlock_rule *create_rule( new_num_layers = num_layers; } new_rule = kzalloc(struct_size(new_rule, layers, new_num_layers), - GFP_KERNEL_ACCOUNT); + GFP_KERNEL_ACCOUNT); if (!new_rule) return ERR_PTR(-ENOMEM); RB_CLEAR_NODE(&new_rule->node); @@ -94,7 +95,7 @@ static struct landlock_rule *create_rule( new_rule->num_layers = new_num_layers; /* Copies the original layer stack. */ memcpy(new_rule->layers, layers, - flex_array_size(new_rule, layers, num_layers)); + flex_array_size(new_rule, layers, num_layers)); if (new_layer) /* Adds a copy of @new_layer on the layer stack. */ new_rule->layers[new_rule->num_layers - 1] = *new_layer; @@ -142,9 +143,9 @@ static void build_check_ruleset(void) * access rights. */ static int insert_rule(struct landlock_ruleset *const ruleset, - struct landlock_object *const object, - const struct landlock_layer (*const layers)[], - size_t num_layers) + struct landlock_object *const object, + const struct landlock_layer (*const layers)[], + size_t num_layers) { struct rb_node **walker_node; struct rb_node *parent_node = NULL; @@ -156,8 +157,8 @@ static int insert_rule(struct landlock_ruleset *const ruleset, return -ENOENT; walker_node = &(ruleset->root.rb_node); while (*walker_node) { - struct landlock_rule *const this = rb_entry(*walker_node, - struct landlock_rule, node); + struct landlock_rule *const this = + rb_entry(*walker_node, struct landlock_rule, node); if (this->object != object) { parent_node = *walker_node; @@ -194,7 +195,7 @@ static int insert_rule(struct landlock_ruleset *const ruleset, * ruleset and a domain. */ new_rule = create_rule(object, &this->layers, this->num_layers, - &(*layers)[0]); + &(*layers)[0]); if (IS_ERR(new_rule)) return PTR_ERR(new_rule); rb_replace_node(&this->node, &new_rule->node, &ruleset->root); @@ -228,13 +229,14 @@ static void build_check_layer(void) /* @ruleset must be locked by the caller. */ int landlock_insert_rule(struct landlock_ruleset *const ruleset, - struct landlock_object *const object, const u32 access) + struct landlock_object *const object, + const access_mask_t access) { - struct landlock_layer layers[] = {{ + struct landlock_layer layers[] = { { .access = access, /* When @level is zero, insert_rule() extends @ruleset. */ .level = 0, - }}; + } }; build_check_layer(); return insert_rule(ruleset, object, &layers, ARRAY_SIZE(layers)); @@ -257,7 +259,7 @@ static void put_hierarchy(struct landlock_hierarchy *hierarchy) } static int merge_ruleset(struct landlock_ruleset *const dst, - struct landlock_ruleset *const src) + struct landlock_ruleset *const src) { struct landlock_rule *walker_rule, *next_rule; int err = 0; @@ -282,11 +284,11 @@ static int merge_ruleset(struct landlock_ruleset *const dst, dst->fs_access_masks[dst->num_layers - 1] = src->fs_access_masks[0]; /* Merges the @src tree. */ - rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, - &src->root, node) { - struct landlock_layer layers[] = {{ + rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, &src->root, + node) { + struct landlock_layer layers[] = { { .level = dst->num_layers, - }}; + } }; if (WARN_ON_ONCE(walker_rule->num_layers != 1)) { err = -EINVAL; @@ -298,7 +300,7 @@ static int merge_ruleset(struct landlock_ruleset *const dst, } layers[0].access = walker_rule->layers[0].access; err = insert_rule(dst, walker_rule->object, &layers, - ARRAY_SIZE(layers)); + ARRAY_SIZE(layers)); if (err) goto out_unlock; } @@ -310,7 +312,7 @@ static int merge_ruleset(struct landlock_ruleset *const dst, } static int inherit_ruleset(struct landlock_ruleset *const parent, - struct landlock_ruleset *const child) + struct landlock_ruleset *const child) { struct landlock_rule *walker_rule, *next_rule; int err = 0; @@ -325,9 +327,10 @@ static int inherit_ruleset(struct landlock_ruleset *const parent, /* Copies the @parent tree. */ rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, - &parent->root, node) { + &parent->root, node) { err = insert_rule(child, walker_rule->object, - &walker_rule->layers, walker_rule->num_layers); + &walker_rule->layers, + walker_rule->num_layers); if (err) goto out_unlock; } @@ -338,7 +341,7 @@ static int inherit_ruleset(struct landlock_ruleset *const parent, } /* Copies the parent layer stack and leaves a space for the new layer. */ memcpy(child->fs_access_masks, parent->fs_access_masks, - flex_array_size(parent, fs_access_masks, parent->num_layers)); + flex_array_size(parent, fs_access_masks, parent->num_layers)); if (WARN_ON_ONCE(!parent->hierarchy)) { err = -EINVAL; @@ -358,8 +361,7 @@ static void free_ruleset(struct landlock_ruleset *const ruleset) struct landlock_rule *freeme, *next; might_sleep(); - rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root, - node) + rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root, node) free_rule(freeme); put_hierarchy(ruleset->hierarchy); kfree(ruleset); @@ -397,9 +399,9 @@ void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset) * Returns the intersection of @parent and @ruleset, or returns @parent if * @ruleset is empty, or returns a duplicate of @ruleset if @parent is empty. */ -struct landlock_ruleset *landlock_merge_ruleset( - struct landlock_ruleset *const parent, - struct landlock_ruleset *const ruleset) +struct landlock_ruleset * +landlock_merge_ruleset(struct landlock_ruleset *const parent, + struct landlock_ruleset *const ruleset) { struct landlock_ruleset *new_dom; u32 num_layers; @@ -421,8 +423,8 @@ struct landlock_ruleset *landlock_merge_ruleset( new_dom = create_ruleset(num_layers); if (IS_ERR(new_dom)) return new_dom; - new_dom->hierarchy = kzalloc(sizeof(*new_dom->hierarchy), - GFP_KERNEL_ACCOUNT); + new_dom->hierarchy = + kzalloc(sizeof(*new_dom->hierarchy), GFP_KERNEL_ACCOUNT); if (!new_dom->hierarchy) { err = -ENOMEM; goto out_put_dom; @@ -449,9 +451,9 @@ struct landlock_ruleset *landlock_merge_ruleset( /* * The returned access has the same lifetime as @ruleset. */ -const struct landlock_rule *landlock_find_rule( - const struct landlock_ruleset *const ruleset, - const struct landlock_object *const object) +const struct landlock_rule * +landlock_find_rule(const struct landlock_ruleset *const ruleset, + const struct landlock_object *const object) { const struct rb_node *node; @@ -459,8 +461,8 @@ const struct landlock_rule *landlock_find_rule( return NULL; node = ruleset->root.rb_node; while (node) { - struct landlock_rule *this = rb_entry(node, - struct landlock_rule, node); + struct landlock_rule *this = + rb_entry(node, struct landlock_rule, node); if (this->object == object) return this; diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h index 2d3ed7ec5a..d43231b783 100644 --- a/security/landlock/ruleset.h +++ b/security/landlock/ruleset.h @@ -9,13 +9,26 @@ #ifndef _SECURITY_LANDLOCK_RULESET_H #define _SECURITY_LANDLOCK_RULESET_H +#include +#include #include #include #include #include +#include "limits.h" #include "object.h" +typedef u16 access_mask_t; +/* Makes sure all filesystem access rights can be stored. */ +static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS); +/* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */ +static_assert(sizeof(unsigned long) >= sizeof(access_mask_t)); + +typedef u16 layer_mask_t; +/* Makes sure all layers can be checked. */ +static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS); + /** * struct landlock_layer - Access rights for a given layer */ @@ -28,7 +41,7 @@ struct landlock_layer { * @access: Bitfield of allowed actions on the kernel object. They are * relative to the object type (e.g. %LANDLOCK_ACTION_FS_READ). */ - u16 access; + access_mask_t access; }; /** @@ -135,26 +148,28 @@ struct landlock_ruleset { * layers are set once and never changed for the * lifetime of the ruleset. */ - u16 fs_access_masks[]; + access_mask_t fs_access_masks[]; }; }; }; -struct landlock_ruleset *landlock_create_ruleset(const u32 fs_access_mask); +struct landlock_ruleset * +landlock_create_ruleset(const access_mask_t fs_access_mask); void landlock_put_ruleset(struct landlock_ruleset *const ruleset); void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset); int landlock_insert_rule(struct landlock_ruleset *const ruleset, - struct landlock_object *const object, const u32 access); + struct landlock_object *const object, + const access_mask_t access); -struct landlock_ruleset *landlock_merge_ruleset( - struct landlock_ruleset *const parent, - struct landlock_ruleset *const ruleset); +struct landlock_ruleset * +landlock_merge_ruleset(struct landlock_ruleset *const parent, + struct landlock_ruleset *const ruleset); -const struct landlock_rule *landlock_find_rule( - const struct landlock_ruleset *const ruleset, - const struct landlock_object *const object); +const struct landlock_rule * +landlock_find_rule(const struct landlock_ruleset *const ruleset, + const struct landlock_object *const object); static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset) { diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c index 7e27ce3940..735a0865ea 100644 --- a/security/landlock/syscalls.c +++ b/security/landlock/syscalls.c @@ -43,9 +43,10 @@ * @src: User space pointer or NULL. * @usize: (Alleged) size of the data pointed to by @src. */ -static __always_inline int copy_min_struct_from_user(void *const dst, - const size_t ksize, const size_t ksize_min, - const void __user *const src, const size_t usize) +static __always_inline int +copy_min_struct_from_user(void *const dst, const size_t ksize, + const size_t ksize_min, const void __user *const src, + const size_t usize) { /* Checks buffer inconsistencies. */ BUILD_BUG_ON(!dst); @@ -93,7 +94,7 @@ static void build_check_abi(void) /* Ruleset handling */ static int fop_ruleset_release(struct inode *const inode, - struct file *const filp) + struct file *const filp) { struct landlock_ruleset *ruleset = filp->private_data; @@ -102,15 +103,15 @@ static int fop_ruleset_release(struct inode *const inode, } static ssize_t fop_dummy_read(struct file *const filp, char __user *const buf, - const size_t size, loff_t *const ppos) + const size_t size, loff_t *const ppos) { /* Dummy handler to enable FMODE_CAN_READ. */ return -EINVAL; } static ssize_t fop_dummy_write(struct file *const filp, - const char __user *const buf, const size_t size, - loff_t *const ppos) + const char __user *const buf, const size_t size, + loff_t *const ppos) { /* Dummy handler to enable FMODE_CAN_WRITE. */ return -EINVAL; @@ -128,7 +129,7 @@ static const struct file_operations ruleset_fops = { .write = fop_dummy_write, }; -#define LANDLOCK_ABI_VERSION 1 +#define LANDLOCK_ABI_VERSION 2 /** * sys_landlock_create_ruleset - Create a new ruleset @@ -168,22 +169,23 @@ SYSCALL_DEFINE3(landlock_create_ruleset, return -EOPNOTSUPP; if (flags) { - if ((flags == LANDLOCK_CREATE_RULESET_VERSION) - && !attr && !size) + if ((flags == LANDLOCK_CREATE_RULESET_VERSION) && !attr && + !size) return LANDLOCK_ABI_VERSION; return -EINVAL; } /* Copies raw user space buffer. */ err = copy_min_struct_from_user(&ruleset_attr, sizeof(ruleset_attr), - offsetofend(typeof(ruleset_attr), handled_access_fs), - attr, size); + offsetofend(typeof(ruleset_attr), + handled_access_fs), + attr, size); if (err) return err; /* Checks content (and 32-bits cast). */ if ((ruleset_attr.handled_access_fs | LANDLOCK_MASK_ACCESS_FS) != - LANDLOCK_MASK_ACCESS_FS) + LANDLOCK_MASK_ACCESS_FS) return -EINVAL; /* Checks arguments and transforms to kernel struct. */ @@ -193,7 +195,7 @@ SYSCALL_DEFINE3(landlock_create_ruleset, /* Creates anonymous FD referring to the ruleset. */ ruleset_fd = anon_inode_getfd("[landlock-ruleset]", &ruleset_fops, - ruleset, O_RDWR | O_CLOEXEC); + ruleset, O_RDWR | O_CLOEXEC); if (ruleset_fd < 0) landlock_put_ruleset(ruleset); return ruleset_fd; @@ -204,7 +206,7 @@ SYSCALL_DEFINE3(landlock_create_ruleset, * landlock_put_ruleset() on the return value. */ static struct landlock_ruleset *get_ruleset_from_fd(const int fd, - const fmode_t mode) + const fmode_t mode) { struct fd ruleset_f; struct landlock_ruleset *ruleset; @@ -244,8 +246,8 @@ static int get_path_from_fd(const s32 fd, struct path *const path) struct fd f; int err = 0; - BUILD_BUG_ON(!__same_type(fd, - ((struct landlock_path_beneath_attr *)NULL)->parent_fd)); + BUILD_BUG_ON(!__same_type( + fd, ((struct landlock_path_beneath_attr *)NULL)->parent_fd)); /* Handles O_PATH. */ f = fdget_raw(fd); @@ -257,10 +259,10 @@ static int get_path_from_fd(const s32 fd, struct path *const path) * pipefs). */ if ((f.file->f_op == &ruleset_fops) || - (f.file->f_path.mnt->mnt_flags & MNT_INTERNAL) || - (f.file->f_path.dentry->d_sb->s_flags & SB_NOUSER) || - d_is_negative(f.file->f_path.dentry) || - IS_PRIVATE(d_backing_inode(f.file->f_path.dentry))) { + (f.file->f_path.mnt->mnt_flags & MNT_INTERNAL) || + (f.file->f_path.dentry->d_sb->s_flags & SB_NOUSER) || + d_is_negative(f.file->f_path.dentry) || + IS_PRIVATE(d_backing_inode(f.file->f_path.dentry))) { err = -EBADFD; goto out_fdput; } @@ -290,19 +292,18 @@ static int get_path_from_fd(const s32 fd, struct path *const path) * * - EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time; * - EINVAL: @flags is not 0, or inconsistent access in the rule (i.e. - * &landlock_path_beneath_attr.allowed_access is not a subset of the rule's - * accesses); + * &landlock_path_beneath_attr.allowed_access is not a subset of the + * ruleset handled accesses); * - ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access); * - EBADF: @ruleset_fd is not a file descriptor for the current thread, or a * member of @rule_attr is not a file descriptor as expected; * - EBADFD: @ruleset_fd is not a ruleset file descriptor, or a member of - * @rule_attr is not the expected file descriptor type (e.g. file open - * without O_PATH); + * @rule_attr is not the expected file descriptor type; * - EPERM: @ruleset_fd has no write access to the underlying ruleset; * - EFAULT: @rule_attr inconsistency. */ -SYSCALL_DEFINE4(landlock_add_rule, - const int, ruleset_fd, const enum landlock_rule_type, rule_type, +SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd, + const enum landlock_rule_type, rule_type, const void __user *const, rule_attr, const __u32, flags) { struct landlock_path_beneath_attr path_beneath_attr; @@ -317,20 +318,24 @@ SYSCALL_DEFINE4(landlock_add_rule, if (flags) return -EINVAL; - if (rule_type != LANDLOCK_RULE_PATH_BENEATH) - return -EINVAL; - - /* Copies raw user space buffer, only one type for now. */ - res = copy_from_user(&path_beneath_attr, rule_attr, - sizeof(path_beneath_attr)); - if (res) - return -EFAULT; - /* Gets and checks the ruleset. */ ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_WRITE); if (IS_ERR(ruleset)) return PTR_ERR(ruleset); + if (rule_type != LANDLOCK_RULE_PATH_BENEATH) { + err = -EINVAL; + goto out_put_ruleset; + } + + /* Copies raw user space buffer, only one type for now. */ + res = copy_from_user(&path_beneath_attr, rule_attr, + sizeof(path_beneath_attr)); + if (res) { + err = -EFAULT; + goto out_put_ruleset; + } + /* * Informs about useless rule: empty allowed_access (i.e. deny rules) * are ignored in path walks. @@ -344,7 +349,7 @@ SYSCALL_DEFINE4(landlock_add_rule, * (ruleset->fs_access_masks[0] is automatically upgraded to 64-bits). */ if ((path_beneath_attr.allowed_access | ruleset->fs_access_masks[0]) != - ruleset->fs_access_masks[0]) { + ruleset->fs_access_masks[0]) { err = -EINVAL; goto out_put_ruleset; } @@ -356,7 +361,7 @@ SYSCALL_DEFINE4(landlock_add_rule, /* Imports the new rule. */ err = landlock_append_fs_rule(ruleset, &path, - path_beneath_attr.allowed_access); + path_beneath_attr.allowed_access); path_put(&path); out_put_ruleset: @@ -389,8 +394,8 @@ SYSCALL_DEFINE4(landlock_add_rule, * - E2BIG: The maximum number of stacked rulesets is reached for the current * thread. */ -SYSCALL_DEFINE2(landlock_restrict_self, - const int, ruleset_fd, const __u32, flags) +SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32, + flags) { struct landlock_ruleset *new_dom, *ruleset; struct cred *new_cred; @@ -400,18 +405,18 @@ SYSCALL_DEFINE2(landlock_restrict_self, if (!landlock_initialized) return -EOPNOTSUPP; - /* No flag for now. */ - if (flags) - return -EINVAL; - /* * Similar checks as for seccomp(2), except that an -EPERM may be * returned. */ if (!task_no_new_privs(current) && - !ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN)) + !ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN)) return -EPERM; + /* No flag for now. */ + if (flags) + return -EINVAL; + /* Gets and checks the ruleset. */ ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_READ); if (IS_ERR(ruleset)) diff --git a/security/loadpin/Kconfig b/security/loadpin/Kconfig index 91be65dec2..70e7985b25 100644 --- a/security/loadpin/Kconfig +++ b/security/loadpin/Kconfig @@ -18,3 +18,19 @@ config SECURITY_LOADPIN_ENFORCE If selected, LoadPin will enforce pinning at boot. If not selected, it can be enabled at boot with the kernel parameter "loadpin.enforce=1". + +config SECURITY_LOADPIN_VERITY + bool "Allow reading files from certain other filesystems that use dm-verity" + depends on SECURITY_LOADPIN && DM_VERITY=y && SECURITYFS + help + If selected LoadPin can allow reading files from filesystems + that use dm-verity. LoadPin maintains a list of verity root + digests it considers trusted. A verity backed filesystem is + considered trusted if its root digest is found in the list + of trusted digests. + + The list of trusted verity can be populated through an ioctl + on the LoadPin securityfs entry 'dm-verity'. The ioctl + expects a file descriptor of a file with verity digests as + parameter. The file must be located on the pinned root and + contain a comma separated list of digests. diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index b12f7d986b..44521582dc 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -18,6 +18,8 @@ #include #include /* current */ #include +#include +#include static void report_load(const char *origin, struct file *file, char *operation) { @@ -43,6 +45,9 @@ static char *exclude_read_files[READING_MAX_ID]; static int ignore_read_file_id[READING_MAX_ID] __ro_after_init; static struct super_block *pinned_root; static DEFINE_SPINLOCK(pinned_root_spinlock); +#ifdef CONFIG_SECURITY_LOADPIN_VERITY +static bool deny_reading_verity_digests; +#endif #ifdef CONFIG_SYSCTL @@ -78,11 +83,8 @@ static void check_pinning_enforcement(struct super_block *mnt_sb) * device, allow sysctl to change modes for testing. */ if (mnt_sb->s_bdev) { - char bdev[BDEVNAME_SIZE]; - ro = bdev_read_only(mnt_sb->s_bdev); - bdevname(mnt_sb->s_bdev, bdev); - pr_info("%s (%u:%u): %s\n", bdev, + pr_info("%pg (%u:%u): %s\n", mnt_sb->s_bdev, MAJOR(mnt_sb->s_bdev->bd_dev), MINOR(mnt_sb->s_bdev->bd_dev), ro ? "read-only" : "writable"); @@ -174,7 +176,8 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id, spin_unlock(&pinned_root_spinlock); } - if (IS_ERR_OR_NULL(pinned_root) || load_root != pinned_root) { + if (IS_ERR_OR_NULL(pinned_root) || + ((load_root != pinned_root) && !dm_verity_loadpin_is_bdev_trusted(load_root->s_bdev))) { if (unlikely(!enforce)) { report_load(origin, file, "pinning-ignored"); return 0; @@ -240,6 +243,7 @@ static int __init loadpin_init(void) enforce ? "" : "not "); parse_exclude(); security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin"); + return 0; } @@ -248,6 +252,162 @@ DEFINE_LSM(loadpin) = { .init = loadpin_init, }; +#ifdef CONFIG_SECURITY_LOADPIN_VERITY + +enum loadpin_securityfs_interface_index { + LOADPIN_DM_VERITY, +}; + +static int read_trusted_verity_root_digests(unsigned int fd) +{ + struct fd f; + void *data; + int rc; + char *p, *d; + + if (deny_reading_verity_digests) + return -EPERM; + + /* The list of trusted root digests can only be set up once */ + if (!list_empty(&dm_verity_loadpin_trusted_root_digests)) + return -EPERM; + + f = fdget(fd); + if (!f.file) + return -EINVAL; + + data = kzalloc(SZ_4K, GFP_KERNEL); + if (!data) { + rc = -ENOMEM; + goto err; + } + + rc = kernel_read_file(f.file, 0, (void **)&data, SZ_4K - 1, NULL, READING_POLICY); + if (rc < 0) + goto err; + + p = data; + p[rc] = '\0'; + p = strim(p); + + p = strim(data); + while ((d = strsep(&p, "\n")) != NULL) { + int len = strlen(d); + struct dm_verity_loadpin_trusted_root_digest *trd; + + if (len % 2) { + rc = -EPROTO; + goto err; + } + + len /= 2; + + trd = kzalloc(struct_size(trd, data, len), GFP_KERNEL); + if (!trd) { + rc = -ENOMEM; + goto err; + } + + if (hex2bin(trd->data, d, len)) { + kfree(trd); + rc = -EPROTO; + goto err; + } + + trd->len = len; + + list_add_tail(&trd->node, &dm_verity_loadpin_trusted_root_digests); + } + + if (list_empty(&dm_verity_loadpin_trusted_root_digests)) { + rc = -EPROTO; + goto err; + } + + kfree(data); + fdput(f); + + return 0; + +err: + kfree(data); + + /* any failure in loading/parsing invalidates the entire list */ + { + struct dm_verity_loadpin_trusted_root_digest *trd, *tmp; + + list_for_each_entry_safe(trd, tmp, &dm_verity_loadpin_trusted_root_digests, node) { + list_del(&trd->node); + kfree(trd); + } + } + + /* disallow further attempts after reading a corrupt/invalid file */ + deny_reading_verity_digests = true; + + fdput(f); + + return rc; +} + +/******************************** securityfs ********************************/ + +static long dm_verity_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + void __user *uarg = (void __user *)arg; + unsigned int fd; + + switch (cmd) { + case LOADPIN_IOC_SET_TRUSTED_VERITY_DIGESTS: + if (copy_from_user(&fd, uarg, sizeof(fd))) + return -EFAULT; + + return read_trusted_verity_root_digests(fd); + + default: + return -EINVAL; + } +} + +static const struct file_operations loadpin_dm_verity_ops = { + .unlocked_ioctl = dm_verity_ioctl, + .compat_ioctl = compat_ptr_ioctl, +}; + +/** + * init_loadpin_securityfs - create the securityfs directory for LoadPin + * + * We can not put this method normally under the loadpin_init() code path since + * the security subsystem gets initialized before the vfs caches. + * + * Returns 0 if the securityfs directory creation was successful. + */ +static int __init init_loadpin_securityfs(void) +{ + struct dentry *loadpin_dir, *dentry; + + loadpin_dir = securityfs_create_dir("loadpin", NULL); + if (IS_ERR(loadpin_dir)) { + pr_err("LoadPin: could not create securityfs dir: %ld\n", + PTR_ERR(loadpin_dir)); + return PTR_ERR(loadpin_dir); + } + + dentry = securityfs_create_file("dm-verity", 0600, loadpin_dir, + (void *)LOADPIN_DM_VERITY, &loadpin_dm_verity_ops); + if (IS_ERR(dentry)) { + pr_err("LoadPin: could not create securityfs entry 'dm-verity': %ld\n", + PTR_ERR(dentry)); + return PTR_ERR(dentry); + } + + return 0; +} + +fs_initcall(init_loadpin_securityfs); + +#endif /* CONFIG_SECURITY_LOADPIN_VERITY */ + /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */ module_param(enforce, int, 0); MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning"); diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 1897cbf6fc..78a278f28e 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -433,6 +433,9 @@ static void dump_common_audit_data(struct audit_buffer *ab, audit_log_format(ab, " lockdown_reason=\"%s\"", lockdown_reasons[a->u.reason]); break; + case LSM_AUDIT_DATA_ANONINODE: + audit_log_format(ab, " anonclass=%s", a->u.anonclass); + break; } /* switch (a->type) */ } diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c index 963f4ad9cb..e806739f78 100644 --- a/security/safesetid/lsm.c +++ b/security/safesetid/lsm.c @@ -97,15 +97,9 @@ static int safesetid_security_capable(const struct cred *cred, return 0; /* - * If CAP_SET{U/G}ID is currently used for a setid() syscall, we want to - * let it go through here; the real security check happens later, in the - * task_fix_set{u/g}id hook. - * - * NOTE: - * Until we add support for restricting setgroups() calls, GID security - * policies offer no meaningful security since we always return 0 here - * when called from within the setgroups() syscall and there is no - * additional hook later on to enforce security policies for setgroups(). + * If CAP_SET{U/G}ID is currently used for a setid or setgroups syscall, we + * want to let it go through here; the real security check happens later, in + * the task_fix_set{u/g}id or task_fix_setgroups hooks. */ if ((opts & CAP_OPT_INSETID) != 0) return 0; @@ -241,9 +235,36 @@ static int safesetid_task_fix_setgid(struct cred *new, return -EACCES; } +static int safesetid_task_fix_setgroups(struct cred *new, const struct cred *old) +{ + int i; + + /* Do nothing if there are no setgid restrictions for our old RGID. */ + if (setid_policy_lookup((kid_t){.gid = old->gid}, INVALID_ID, GID) == SIDPOL_DEFAULT) + return 0; + + get_group_info(new->group_info); + for (i = 0; i < new->group_info->ngroups; i++) { + if (!id_permitted_for_cred(old, (kid_t){.gid = new->group_info->gid[i]}, GID)) { + put_group_info(new->group_info); + /* + * Kill this process to avoid potential security vulnerabilities + * that could arise from a missing allowlist entry preventing a + * privileged process from dropping to a lesser-privileged one. + */ + force_sig(SIGKILL); + return -EACCES; + } + } + + put_group_info(new->group_info); + return 0; +} + static struct security_hook_list safesetid_security_hooks[] = { LSM_HOOK_INIT(task_fix_setuid, safesetid_task_fix_setuid), LSM_HOOK_INIT(task_fix_setgid, safesetid_task_fix_setgid), + LSM_HOOK_INIT(task_fix_setgroups, safesetid_task_fix_setgroups), LSM_HOOK_INIT(capable, safesetid_security_capable) }; diff --git a/security/security.c b/security/security.c index b7cf5cbfdc..4b95de24bc 100644 --- a/security/security.c +++ b/security/security.c @@ -59,10 +59,12 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = { [LOCKDOWN_DEBUGFS] = "debugfs access", [LOCKDOWN_XMON_WR] = "xmon write access", [LOCKDOWN_BPF_WRITE_USER] = "use of bpf to write user RAM", + [LOCKDOWN_DBG_WRITE_KERNEL] = "use of kgdb/kdb to write kernel RAM", [LOCKDOWN_INTEGRITY_MAX] = "integrity", [LOCKDOWN_KCORE] = "/proc/kcore access", [LOCKDOWN_KPROBES] = "use of kprobes", [LOCKDOWN_BPF_READ_KERNEL] = "use of bpf to read kernel RAM", + [LOCKDOWN_DBG_READ_KERNEL] = "use of kgdb/kdb to read kernel RAM", [LOCKDOWN_PERF] = "unsafe use of perf", [LOCKDOWN_TRACEFS] = "use of tracefs", [LOCKDOWN_XMON_RW] = "xmon read and write access", @@ -365,13 +367,12 @@ static void __init ordered_lsm_init(void) int __init early_security_init(void) { - int i; - struct hlist_head *list = (struct hlist_head *) &security_hook_heads; struct lsm_info *lsm; - for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct hlist_head); - i++) - INIT_HLIST_HEAD(&list[i]); +#define LSM_HOOK(RET, DEFAULT, NAME, ...) \ + INIT_HLIST_HEAD(&security_hook_heads.NAME); +#include "linux/lsm_hook_defs.h" +#undef LSM_HOOK for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) { if (!lsm->enabled) @@ -478,7 +479,7 @@ static int lsm_append(const char *new, char **result) * Each LSM has to register its hooks with the infrastructure. */ void __init security_add_hooks(struct security_hook_list *hooks, int count, - char *lsm) + const char *lsm) { int i; @@ -1197,15 +1198,8 @@ int security_path_rename(const struct path *old_dir, struct dentry *old_dentry, (d_is_positive(new_dentry) && IS_PRIVATE(d_backing_inode(new_dentry))))) return 0; - if (flags & RENAME_EXCHANGE) { - int err = call_int_hook(path_rename, 0, new_dir, new_dentry, - old_dir, old_dentry); - if (err) - return err; - } - return call_int_hook(path_rename, 0, old_dir, old_dentry, new_dir, - new_dentry); + new_dentry, flags); } EXPORT_SYMBOL(security_path_rename); @@ -1330,7 +1324,8 @@ int security_inode_permission(struct inode *inode, int mask) return call_int_hook(inode_permission, 0, inode, mask); } -int security_inode_setattr(struct dentry *dentry, struct iattr *attr) +int security_inode_setattr(struct user_namespace *mnt_userns, + struct dentry *dentry, struct iattr *attr) { int ret; @@ -1339,7 +1334,7 @@ int security_inode_setattr(struct dentry *dentry, struct iattr *attr) ret = call_int_hook(inode_setattr, 0, dentry, attr); if (ret) return ret; - return evm_inode_setattr(dentry, attr); + return evm_inode_setattr(mnt_userns, dentry, attr); } EXPORT_SYMBOL_GPL(security_inode_setattr); @@ -1809,6 +1804,11 @@ int security_task_fix_setgid(struct cred *new, const struct cred *old, return call_int_hook(task_fix_setgid, 0, new, old, flags); } +int security_task_fix_setgroups(struct cred *new, const struct cred *old) +{ + return call_int_hook(task_fix_setgroups, 0, new, old); +} + int security_task_setpgid(struct task_struct *p, pid_t pgid) { return call_int_hook(task_setpgid, 0, p, pgid); @@ -2660,4 +2660,8 @@ int security_uring_sqpoll(void) { return call_int_hook(uring_sqpoll, 0); } +int security_uring_cmd(struct io_uring_cmd *ioucmd) +{ + return call_int_hook(uring_cmd, 0, ioucmd); +} #endif /* CONFIG_IO_URING */ diff --git a/security/selinux/avc.c b/security/selinux/avc.c index abcd9740d1..9a43af0ebd 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -668,7 +668,7 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) struct common_audit_data *ad = a; struct selinux_audit_data *sad = ad->selinux_audit_data; u32 av = sad->audited; - const char **perms; + const char *const *perms; int i, perm; audit_log_format(ab, "avc: %s ", sad->denied ? "denied" : "granted"); @@ -1059,7 +1059,7 @@ int avc_has_extended_perms(struct selinux_state *state, node = avc_lookup(state->avc, ssid, tsid, tclass); if (unlikely(!node)) { - node = avc_compute_av(state, ssid, tsid, tclass, &avd, xp_node); + avc_compute_av(state, ssid, tsid, tclass, &avd, xp_node); } else { memcpy(&avd, &node->ae.avd, sizeof(avd)); xp_node = node->ae.xp_node; @@ -1151,7 +1151,7 @@ inline int avc_has_perm_noaudit(struct selinux_state *state, node = avc_lookup(state->avc, ssid, tsid, tclass); if (unlikely(!node)) - node = avc_compute_av(state, ssid, tsid, tclass, avd, &xp_node); + avc_compute_av(state, ssid, tsid, tclass, avd, &xp_node); else memcpy(avd, &node->ae.avd, sizeof(*avd)); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e9e959343d..03bca97c8b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -91,6 +91,7 @@ #include #include #include +#include #include "avc.h" #include "objsec.h" @@ -145,7 +146,7 @@ static int __init checkreqprot_setup(char *str) if (!kstrtoul(str, 0, &checkreqprot)) { selinux_checkreqprot_boot = checkreqprot ? 1 : 0; if (checkreqprot) - pr_warn("SELinux: checkreqprot set to 1 via kernel parameter. This is deprecated and will be rejected in a future kernel release.\n"); + pr_err("SELinux: checkreqprot set to 1 via kernel parameter. This is deprecated and will be rejected in a future kernel release.\n"); } return 1; } @@ -640,7 +641,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, * we need to skip the double mount verification. * * This does open a hole in which we will not notice if the first - * mount using this sb set explict options and a second mount using + * mount using this sb set explicit options and a second mount using * this sb does not set any security options. (The first options * will be used for both mounts) */ @@ -944,10 +945,12 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, return rc; } +/* + * NOTE: the caller is resposible for freeing the memory even if on error. + */ static int selinux_add_opt(int token, const char *s, void **mnt_opts) { struct selinux_mnt_opts *opts = *mnt_opts; - bool is_alloc_opts = false; u32 *dst_sid; int rc; @@ -955,7 +958,7 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts) /* eaten and completely ignored */ return 0; if (!s) - return -ENOMEM; + return -EINVAL; if (!selinux_initialized(&selinux_state)) { pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n"); @@ -967,7 +970,6 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts) if (!opts) return -ENOMEM; *mnt_opts = opts; - is_alloc_opts = true; } switch (token) { @@ -1002,10 +1004,6 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts) return rc; err: - if (is_alloc_opts) { - kfree(opts); - *mnt_opts = NULL; - } pr_warn(SEL_MOUNT_FAIL_MSG); return -EINVAL; } @@ -1019,7 +1017,7 @@ static int show_sid(struct seq_file *m, u32 sid) rc = security_sid_to_context(&selinux_state, sid, &context, &len); if (!rc) { - bool has_comma = context && strchr(context, ','); + bool has_comma = strchr(context, ','); seq_putc(m, '='); if (has_comma) @@ -2600,8 +2598,9 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts) } } rc = selinux_add_opt(token, arg, mnt_opts); + kfree(arg); + arg = NULL; if (unlikely(rc)) { - kfree(arg); goto free_opt; } } else { @@ -2792,17 +2791,13 @@ static int selinux_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) { struct fs_parse_result result; - int opt, rc; + int opt; opt = fs_parse(fc, selinux_fs_parameters, param, &result); if (opt < 0) return opt; - rc = selinux_add_opt(opt, param->string, &fc->security); - if (!rc) - param->string = NULL; - - return rc; + return selinux_add_opt(opt, param->string, &fc->security); } /* inode security operations */ @@ -2964,8 +2959,8 @@ static int selinux_inode_init_security_anon(struct inode *inode, * allowed to actually create this type of anonymous inode. */ - ad.type = LSM_AUDIT_DATA_INODE; - ad.u.inode = inode; + ad.type = LSM_AUDIT_DATA_ANONINODE; + ad.u.anonclass = name ? (const char *)name->name : "?"; return avc_has_perm(&selinux_state, tsec->sid, @@ -6487,7 +6482,6 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) goto abort_change; /* Only allow single threaded processes to change context */ - error = -EPERM; if (!current_is_single_threaded()) { error = security_bounded_transition(&selinux_state, tsec->sid, sid); @@ -6796,7 +6790,7 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode) } /* This function will check the file pass through unix socket or binder to see - * if it is a bpf related object. And apply correspinding checks on the bpf + * if it is a bpf related object. And apply corresponding checks on the bpf * object based on the type. The bpf maps and programs, not like other files and * socket, are using a shared anonymous inode inside the kernel as their inode. * So checking that inode cannot identify if the process have privilege to @@ -6994,6 +6988,28 @@ static int selinux_uring_sqpoll(void) return avc_has_perm(&selinux_state, sid, sid, SECCLASS_IO_URING, IO_URING__SQPOLL, NULL); } + +/** + * selinux_uring_cmd - check if IORING_OP_URING_CMD is allowed + * @ioucmd: the io_uring command structure + * + * Check to see if the current domain is allowed to execute an + * IORING_OP_URING_CMD against the device/file specified in @ioucmd. + * + */ +static int selinux_uring_cmd(struct io_uring_cmd *ioucmd) +{ + struct file *file = ioucmd->file; + struct inode *inode = file_inode(file); + struct inode_security_struct *isec = selinux_inode(inode); + struct common_audit_data ad; + + ad.type = LSM_AUDIT_DATA_FILE; + ad.u.file = file; + + return avc_has_perm(&selinux_state, current_sid(), isec->sid, + SECCLASS_IO_URING, IO_URING__CMD, &ad); +} #endif /* CONFIG_IO_URING */ /* @@ -7238,6 +7254,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { #ifdef CONFIG_IO_URING LSM_HOOK_INIT(uring_override_creds, selinux_uring_override_creds), LSM_HOOK_INIT(uring_sqpoll, selinux_uring_sqpoll), + LSM_HOOK_INIT(uring_cmd, selinux_uring_cmd), #endif /* @@ -7294,6 +7311,8 @@ static __init int selinux_init(void) memset(&selinux_state, 0, sizeof(selinux_state)); enforcing_set(&selinux_state, selinux_enforcing_boot); + if (CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE) + pr_err("SELinux: CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE is non-zero. This is deprecated and will be rejected in a future kernel release.\n"); checkreqprot_set(&selinux_state, selinux_checkreqprot_boot); selinux_avc_init(&selinux_state.avc); mutex_init(&selinux_state.status_lock); diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h index 073a3d34a0..406bceb90c 100644 --- a/security/selinux/include/audit.h +++ b/security/selinux/include/audit.h @@ -12,10 +12,13 @@ #ifndef _SELINUX_AUDIT_H #define _SELINUX_AUDIT_H +#include +#include + /** * selinux_audit_rule_init - alloc/init an selinux audit rule structure. * @field: the field this rule refers to - * @op: the operater the rule uses + * @op: the operator the rule uses * @rulestr: the text "target" of the rule * @rule: pointer to the new rule structure returned via this * @@ -51,7 +54,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule); * @rule: rule to be checked * Returns 1 if there are selinux fields specified in the rule, 0 otherwise. */ -int selinux_audit_rule_known(struct audit_krule *krule); +int selinux_audit_rule_known(struct audit_krule *rule); #endif /* _SELINUX_AUDIT_H */ diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 00f78be482..5525b94fd2 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -53,7 +53,7 @@ struct selinux_audit_data { u32 denied; int result; struct selinux_state *state; -}; +} __randomize_layout; /* * AVC operations @@ -104,6 +104,7 @@ int slow_avc_audit(struct selinux_state *state, /** * avc_audit - Audit the granting or denial of permissions. + * @state: SELinux state * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h index 88c384c5c0..42912c917f 100644 --- a/security/selinux/include/avc_ss.h +++ b/security/selinux/include/avc_ss.h @@ -7,7 +7,7 @@ #ifndef _SELINUX_AVC_SS_H_ #define _SELINUX_AVC_SS_H_ -#include "flask.h" +#include struct selinux_avc; int avc_ss_reset(struct selinux_avc *avc, u32 seqno); @@ -18,7 +18,7 @@ struct security_class_mapping { const char *perms[sizeof(u32) * 8 + 1]; }; -extern struct security_class_mapping secclass_map[]; +extern const struct security_class_mapping secclass_map[]; #endif /* _SELINUX_AVC_SS_H_ */ diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 35aac62a66..1c2f41ff4e 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -38,7 +38,7 @@ * Note: The name for any socket class should be suffixed by "socket", * and doesn't contain more than one substr of "socket". */ -struct security_class_mapping secclass_map[] = { +const struct security_class_mapping secclass_map[] = { { "security", { "compute_av", "compute_create", "compute_member", "check_context", "load_policy", "compute_relabel", @@ -253,7 +253,7 @@ struct security_class_mapping secclass_map[] = { { "anon_inode", { COMMON_FILE_PERMS, NULL } }, { "io_uring", - { "override_creds", "sqpoll", NULL } }, + { "override_creds", "sqpoll", "cmd", NULL } }, { NULL } }; diff --git a/security/selinux/include/ibpkey.h b/security/selinux/include/ibpkey.h index e6ac1d2332..c992f83b0a 100644 --- a/security/selinux/include/ibpkey.h +++ b/security/selinux/include/ibpkey.h @@ -14,6 +14,8 @@ #ifndef _SELINUX_IB_PKEY_H #define _SELINUX_IB_PKEY_H +#include + #ifdef CONFIG_SECURITY_INFINIBAND void sel_ib_pkey_flush(void); int sel_ib_pkey_sid(u64 subnet_prefix, u16 pkey, u32 *sid); diff --git a/security/selinux/include/initial_sid_to_string.h b/security/selinux/include/initial_sid_to_string.h index 5d332aeb8b..60820517aa 100644 --- a/security/selinux/include/initial_sid_to_string.h +++ b/security/selinux/include/initial_sid_to_string.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -static const char *initial_sid_to_string[] = -{ +static const char *const initial_sid_to_string[] = { NULL, "kernel", "security", diff --git a/security/selinux/include/netnode.h b/security/selinux/include/netnode.h index e3f784a858..9b8b655a8c 100644 --- a/security/selinux/include/netnode.h +++ b/security/selinux/include/netnode.h @@ -17,6 +17,8 @@ #ifndef _SELINUX_NETNODE_H #define _SELINUX_NETNODE_H +#include + void sel_netnode_flush(void); int sel_netnode_sid(void *addr, u16 family, u32 *sid); diff --git a/security/selinux/include/netport.h b/security/selinux/include/netport.h index 31bc16e29c..9096a82899 100644 --- a/security/selinux/include/netport.h +++ b/security/selinux/include/netport.h @@ -16,6 +16,8 @@ #ifndef _SELINUX_NETPORT_H #define _SELINUX_NETPORT_H +#include + void sel_netport_flush(void); int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid); diff --git a/security/selinux/include/policycap.h b/security/selinux/include/policycap.h index 2680aa2120..f35d3458e7 100644 --- a/security/selinux/include/policycap.h +++ b/security/selinux/include/policycap.h @@ -16,6 +16,6 @@ enum { }; #define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1) -extern const char *selinux_policycap_names[__POLICYDB_CAP_MAX]; +extern const char *const selinux_policycap_names[__POLICYDB_CAP_MAX]; #endif /* _SELINUX_POLICYCAP_H_ */ diff --git a/security/selinux/include/policycap_names.h b/security/selinux/include/policycap_names.h index 100da7d043..2a87fc3702 100644 --- a/security/selinux/include/policycap_names.h +++ b/security/selinux/include/policycap_names.h @@ -5,7 +5,7 @@ #include "policycap.h" /* Policy capability names */ -const char *selinux_policycap_names[__POLICYDB_CAP_MAX] = { +const char *const selinux_policycap_names[__POLICYDB_CAP_MAX] = { "network_peer_controls", "open_perms", "extended_socket_class", diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index ace4bd13e8..393aff41d3 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include "flask.h" #include "policycap.h" @@ -150,6 +152,8 @@ static inline bool checkreqprot_get(const struct selinux_state *state) static inline void checkreqprot_set(struct selinux_state *state, bool value) { + if (value) + pr_err("SELinux: https://github.com/SELinuxProject/selinux-kernel/wiki/DEPRECATE-checkreqprot\n"); WRITE_ONCE(state->checkreqprot, value); } diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 74159400ee..c758398602 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -8,7 +8,9 @@ #ifndef _SELINUX_XFRM_H_ #define _SELINUX_XFRM_H_ +#include #include +#include int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *uctx, diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index d8ceee9e0d..2ee7b4ed43 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -25,8 +25,7 @@ struct nlmsg_perm { u32 perm; }; -static const struct nlmsg_perm nlmsg_route_perms[] = -{ +static const struct nlmsg_perm nlmsg_route_perms[] = { { RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, { RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, { RTM_GETLINK, NETLINK_ROUTE_SOCKET__NLMSG_READ }, @@ -97,16 +96,14 @@ static const struct nlmsg_perm nlmsg_route_perms[] = { RTM_GETTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, }; -static const struct nlmsg_perm nlmsg_tcpdiag_perms[] = -{ +static const struct nlmsg_perm nlmsg_tcpdiag_perms[] = { { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, { SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, { SOCK_DESTROY, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE }, }; -static const struct nlmsg_perm nlmsg_xfrm_perms[] = -{ +static const struct nlmsg_perm nlmsg_xfrm_perms[] = { { XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_GETSA, NETLINK_XFRM_SOCKET__NLMSG_READ }, @@ -134,8 +131,7 @@ static const struct nlmsg_perm nlmsg_xfrm_perms[] = { XFRM_MSG_GETDEFAULT, NETLINK_XFRM_SOCKET__NLMSG_READ }, }; -static const struct nlmsg_perm nlmsg_audit_perms[] = -{ +static const struct nlmsg_perm nlmsg_audit_perms[] = { { AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, { AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, { AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV }, diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 097c6d866e..8fcdd494af 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -293,6 +293,8 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf, * kernel releases until eventually it is removed */ pr_err("SELinux: Runtime disable is deprecated, use selinux=0 on the kernel cmdline.\n"); + pr_err("SELinux: https://github.com/SELinuxProject/selinux-kernel/wiki/DEPRECATE-runtime-disable\n"); + ssleep(5); if (count >= PAGE_SIZE) return -ENOMEM; @@ -755,11 +757,13 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, char comm[sizeof(current->comm)]; memcpy(comm, current->comm, sizeof(comm)); - pr_warn_once("SELinux: %s (%d) set checkreqprot to 1. This is deprecated and will be rejected in a future kernel release.\n", - comm, current->pid); + pr_err("SELinux: %s (%d) set checkreqprot to 1. This is deprecated and will be rejected in a future kernel release.\n", + comm, current->pid); } checkreqprot_set(fsi->state, (new_value ? 1 : 0)); + if (new_value) + ssleep(5); length = count; selinux_ima_measure_state(fsi->state); diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index cfdae20792..8480ec6c6e 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -40,15 +40,15 @@ static inline int avtab_hash(const struct avtab_key *keyp, u32 mask) u32 hash = 0; -#define mix(input) { \ - u32 v = input; \ - v *= c1; \ - v = (v << r1) | (v >> (32 - r1)); \ - v *= c2; \ - hash ^= v; \ - hash = (hash << r2) | (hash >> (32 - r2)); \ - hash = hash * m + n; \ -} +#define mix(input) do { \ + u32 v = input; \ + v *= c1; \ + v = (v << r1) | (v >> (32 - r1)); \ + v *= c2; \ + hash ^= v; \ + hash = (hash << r2) | (hash >> (32 - r2)); \ + hash = hash * m + n; \ + } while (0) mix(keyp->target_class); mix(keyp->target_type); @@ -385,7 +385,7 @@ void avtab_hash_eval(struct avtab *h, char *tag) chain2_len_sum); } -static uint16_t spec_order[] = { +static const uint16_t spec_order[] = { AVTAB_ALLOWED, AVTAB_AUDITDENY, AVTAB_AUDITALLOW, diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 0ae4e4e57a..3fb8f9026e 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -179,7 +179,8 @@ int hashtab_duplicate(struct hashtab *new, struct hashtab *orig, kmem_cache_free(hashtab_node_cachep, cur); } } - kmem_cache_free(hashtab_node_cachep, new); + kfree(new->htable); + memset(new, 0, sizeof(*new)); return -ENOMEM; } diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index d036e1238e..adcfb63b35 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -61,7 +61,7 @@ struct policydb_compat_info { }; /* These need to be updated if SYM_NUM or OCON_NUM changes */ -static struct policydb_compat_info policydb_compat[] = { +static const struct policydb_compat_info policydb_compat[] = { { .version = POLICYDB_VERSION_BASE, .sym_num = SYM_NUM - 3, @@ -159,18 +159,16 @@ static struct policydb_compat_info policydb_compat[] = { }, }; -static struct policydb_compat_info *policydb_lookup_compat(int version) +static const struct policydb_compat_info *policydb_lookup_compat(int version) { int i; - struct policydb_compat_info *info = NULL; for (i = 0; i < ARRAY_SIZE(policydb_compat); i++) { - if (policydb_compat[i].version == version) { - info = &policydb_compat[i]; - break; - } + if (policydb_compat[i].version == version) + return &policydb_compat[i]; } - return info; + + return NULL; } /* @@ -314,8 +312,7 @@ static int cat_destroy(void *key, void *datum, void *p) return 0; } -static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = -{ +static int (*const destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = { common_destroy, cls_destroy, role_destroy, @@ -670,8 +667,7 @@ static int cat_index(void *key, void *datum, void *datap) return 0; } -static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = -{ +static int (*const index_f[SYM_NUM]) (void *key, void *datum, void *datap) = { common_index, class_index, role_index, @@ -1639,8 +1635,8 @@ static int cat_read(struct policydb *p, struct symtab *s, void *fp) return rc; } -static int (*read_f[SYM_NUM]) (struct policydb *p, struct symtab *s, void *fp) = -{ +static int (*const read_f[SYM_NUM]) (struct policydb *p, + struct symtab *s, void *fp) = { common_read, class_read, role_read, @@ -2211,7 +2207,7 @@ static int genfs_read(struct policydb *p, void *fp) return rc; } -static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, +static int ocontext_read(struct policydb *p, const struct policydb_compat_info *info, void *fp) { int i, j, rc; @@ -2407,7 +2403,7 @@ int policydb_read(struct policydb *p, void *fp) u32 len, nprim, nel, perm; char *policydb_str; - struct policydb_compat_info *info; + const struct policydb_compat_info *info; policydb_init(p); @@ -3241,9 +3237,7 @@ static int user_write(void *vkey, void *datum, void *ptr) return 0; } -static int (*write_f[SYM_NUM]) (void *key, void *datum, - void *datap) = -{ +static int (*const write_f[SYM_NUM]) (void *key, void *datum, void *datap) = { common_write, class_write, role_write, @@ -3254,7 +3248,7 @@ static int (*write_f[SYM_NUM]) (void *key, void *datum, cat_write, }; -static int ocontext_write(struct policydb *p, struct policydb_compat_info *info, +static int ocontext_write(struct policydb *p, const struct policydb_compat_info *info, void *fp) { unsigned int i, j, rc; @@ -3611,7 +3605,7 @@ int policydb_write(struct policydb *p, void *fp) __le32 buf[4]; u32 config; size_t len; - struct policydb_compat_info *info; + const struct policydb_compat_info *info; /* * refuse to write policy older than compressed avtab diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index c24d4e1063..ffc4e7bad2 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -370,6 +370,8 @@ static inline int put_entry(const void *buf, size_t bytes, int num, struct polic { size_t len = bytes * num; + if (len > fp->len) + return -EINVAL; memcpy(fp->data, buf, len); fp->data += len; fp->len -= len; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 6901dc0768..fe5fcf571c 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -99,7 +99,7 @@ static void context_struct_compute_av(struct policydb *policydb, struct extended_perms *xperms); static int selinux_set_mapping(struct policydb *pol, - struct security_class_mapping *map, + const struct security_class_mapping *map, struct selinux_map *out_map) { u16 i, j; @@ -121,7 +121,7 @@ static int selinux_set_mapping(struct policydb *pol, /* Store the raw class and permission values */ j = 0; while (map[j].name) { - struct security_class_mapping *p_in = map + (j++); + const struct security_class_mapping *p_in = map + (j++); struct selinux_mapping *p_out = out_map->mapping + j; /* An empty class string skips ahead */ @@ -358,27 +358,27 @@ static int constraint_expr_eval(struct policydb *policydb, l2 = &(tcontext->range.level[1]); goto mls_ops; mls_ops: - switch (e->op) { - case CEXPR_EQ: - s[++sp] = mls_level_eq(l1, l2); - continue; - case CEXPR_NEQ: - s[++sp] = !mls_level_eq(l1, l2); - continue; - case CEXPR_DOM: - s[++sp] = mls_level_dom(l1, l2); - continue; - case CEXPR_DOMBY: - s[++sp] = mls_level_dom(l2, l1); - continue; - case CEXPR_INCOMP: - s[++sp] = mls_level_incomp(l2, l1); - continue; - default: - BUG(); - return 0; - } - break; + switch (e->op) { + case CEXPR_EQ: + s[++sp] = mls_level_eq(l1, l2); + continue; + case CEXPR_NEQ: + s[++sp] = !mls_level_eq(l1, l2); + continue; + case CEXPR_DOM: + s[++sp] = mls_level_dom(l1, l2); + continue; + case CEXPR_DOMBY: + s[++sp] = mls_level_dom(l2, l1); + continue; + case CEXPR_INCOMP: + s[++sp] = mls_level_incomp(l2, l1); + continue; + default: + BUG(); + return 0; + } + break; default: BUG(); return 0; @@ -2980,7 +2980,6 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb) } retry: - rc = 0; rcu_read_lock(); policy = rcu_dereference(state->policy); policydb = &policy->policydb; @@ -4049,6 +4048,7 @@ int security_read_policy(struct selinux_state *state, int security_read_state_kernel(struct selinux_state *state, void **data, size_t *len) { + int err; struct selinux_policy *policy; policy = rcu_dereference_protected( @@ -4061,5 +4061,11 @@ int security_read_state_kernel(struct selinux_state *state, if (!*data) return -ENOMEM; - return __security_read_policy(policy, *data, len); + err = __security_read_policy(policy, *data, len); + if (err) { + vfree(*data); + *data = NULL; + *len = 0; + } + return err; } diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index d2186e2757..585e5e3571 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -465,12 +465,9 @@ char *smk_parse_smack(const char *string, int len) if (i == 0 || i >= SMK_LONGLABEL) return ERR_PTR(-EINVAL); - smack = kzalloc(i + 1, GFP_NOFS); - if (smack == NULL) + smack = kstrndup(string, i, GFP_NOFS); + if (!smack) return ERR_PTR(-ENOMEM); - - strncpy(smack, string, i); - return smack; } diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 6207762dbd..bffccdc494 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "smack.h" #define TRANS_TRUE "TRUE" @@ -766,13 +767,6 @@ static int smack_set_mnt_opts(struct super_block *sb, if (sp->smk_flags & SMK_SB_INITIALIZED) return 0; - if (inode->i_security == NULL) { - int rc = lsm_inode_alloc(inode); - - if (rc) - return rc; - } - if (!smack_privileged(CAP_MAC_ADMIN)) { /* * Unprivileged mounts don't get to specify Smack values. @@ -4739,6 +4733,36 @@ static int smack_uring_sqpoll(void) return -EPERM; } +/** + * smack_uring_cmd - check on file operations for io_uring + * @ioucmd: the command in question + * + * Make a best guess about whether a io_uring "command" should + * be allowed. Use the same logic used for determining if the + * file could be opened for read in the absence of better criteria. + */ +static int smack_uring_cmd(struct io_uring_cmd *ioucmd) +{ + struct file *file = ioucmd->file; + struct smk_audit_info ad; + struct task_smack *tsp; + struct inode *inode; + int rc; + + if (!file) + return -EINVAL; + + tsp = smack_cred(file->f_cred); + inode = file_inode(file); + + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); + smk_ad_setfield_u_fs_path(&ad, file->f_path); + rc = smk_tskacc(tsp, smk_of_inode(inode), MAY_READ, &ad); + rc = smk_bu_credfile(file->f_cred, file, MAY_READ, rc); + + return rc; +} + #endif /* CONFIG_IO_URING */ struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = { @@ -4896,6 +4920,7 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { #ifdef CONFIG_IO_URING LSM_HOOK_INIT(uring_override_creds, smack_uring_override_creds), LSM_HOOK_INIT(uring_sqpoll, smack_uring_sqpoll), + LSM_HOOK_INIT(uring_cmd, smack_uring_cmd), #endif }; diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 658eab0559..4b58526450 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "smack.h" @@ -1192,7 +1193,6 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf, rc = -EINVAL; goto free_out; } - m = BEBITS; masks = 32; } if (masks > BEBITS) { diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index b6a31901f2..71e82d855e 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -264,17 +264,26 @@ static int tomoyo_path_link(struct dentry *old_dentry, const struct path *new_di * @old_dentry: Pointer to "struct dentry". * @new_parent: Pointer to "struct path". * @new_dentry: Pointer to "struct dentry". + * @flags: Rename options. * * Returns 0 on success, negative value otherwise. */ static int tomoyo_path_rename(const struct path *old_parent, struct dentry *old_dentry, const struct path *new_parent, - struct dentry *new_dentry) + struct dentry *new_dentry, + const unsigned int flags) { struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry }; struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry }; + if (flags & RENAME_EXCHANGE) { + const int err = tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path2, + &path1); + + if (err) + return err; + } return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); } diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c index 0d31a6d714..045330883a 100644 --- a/sound/ac97/bus.c +++ b/sound/ac97/bus.c @@ -460,7 +460,7 @@ static ssize_t vendor_id_show(struct device *dev, { struct ac97_codec_device *codec = to_ac97_device(dev); - return sprintf(buf, "%08x", codec->vendor_id); + return sysfs_emit(buf, "%08x", codec->vendor_id); } DEVICE_ATTR_RO(vendor_id); diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c index dead310568..e87b28428b 100644 --- a/sound/aoa/soundbus/sysfs.c +++ b/sound/aoa/soundbus/sysfs.c @@ -10,19 +10,13 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, { struct soundbus_dev *sdev = to_soundbus_device(dev); struct platform_device *of = &sdev->ofdev; - int length; - if (*sdev->modalias) { - strscpy(buf, sdev->modalias, sizeof(sdev->modalias) + 1); - strcat(buf, "\n"); - length = strlen(buf); - } else { - length = sprintf(buf, "of:N%pOFn%c%s\n", - of->dev.of_node, 'T', - of_node_get_device_type(of->dev.of_node)); - } - - return length; + if (*sdev->modalias) + return sysfs_emit(buf, "%s\n", sdev->modalias); + else + return sysfs_emit(buf, "of:N%pOFn%c%s\n", + of->dev.of_node, 'T', + of_node_get_device_type(of->dev.of_node)); } static DEVICE_ATTR_RO(modalias); @@ -32,7 +26,7 @@ static ssize_t name_show(struct device *dev, struct soundbus_dev *sdev = to_soundbus_device(dev); struct platform_device *of = &sdev->ofdev; - return sprintf(buf, "%pOFn\n", of->dev.of_node); + return sysfs_emit(buf, "%pOFn\n", of->dev.of_node); } static DEVICE_ATTR_RO(name); @@ -42,7 +36,7 @@ static ssize_t type_show(struct device *dev, struct soundbus_dev *sdev = to_soundbus_device(dev); struct platform_device *of = &sdev->ofdev; - return sprintf(buf, "%s\n", of_node_get_device_type(of->dev.of_node)); + return sysfs_emit(buf, "%s\n", of_node_get_device_type(of->dev.of_node)); } static DEVICE_ATTR_RO(type); diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index 58274b4a1f..e55c042171 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c @@ -17,12 +17,13 @@ #include #include #include +#include #include -#include -#include -#include +#include + +#include "pxa2xx-ac97-regs.h" static DEFINE_MUTEX(car_mutex); static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); @@ -30,6 +31,7 @@ static volatile long gsr_bits; static struct clk *ac97_clk; static struct clk *ac97conf_clk; static int reset_gpio; +static void __iomem *ac97_reg_base; extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio); @@ -46,7 +48,7 @@ extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio); int pxa2xx_ac97_read(int slot, unsigned short reg) { int val = -ENODEV; - volatile u32 *reg_addr; + u32 __iomem *reg_addr; if (slot > 0) return -ENODEV; @@ -55,31 +57,33 @@ int pxa2xx_ac97_read(int slot, unsigned short reg) /* set up primary or secondary codec space */ if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS) - reg_addr = slot ? &SMC_REG_BASE : &PMC_REG_BASE; + reg_addr = ac97_reg_base + + (slot ? SMC_REG_BASE : PMC_REG_BASE); else - reg_addr = slot ? &SAC_REG_BASE : &PAC_REG_BASE; + reg_addr = ac97_reg_base + + (slot ? SAC_REG_BASE : PAC_REG_BASE); reg_addr += (reg >> 1); /* start read access across the ac97 link */ - GSR = GSR_CDONE | GSR_SDONE; + writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR); gsr_bits = 0; - val = (*reg_addr & 0xffff); + val = (readl(reg_addr) & 0xffff); if (reg == AC97_GPIO_STATUS) goto out; - if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 && - !((GSR | gsr_bits) & GSR_SDONE)) { + if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1) <= 0 && + !((readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE)) { printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n", - __func__, reg, GSR | gsr_bits); + __func__, reg, readl(ac97_reg_base + GSR) | gsr_bits); val = -ETIMEDOUT; goto out; } /* valid data now */ - GSR = GSR_CDONE | GSR_SDONE; + writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR); gsr_bits = 0; - val = (*reg_addr & 0xffff); + val = (readl(reg_addr) & 0xffff); /* but we've just started another cycle... */ - wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); + wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1); out: mutex_unlock(&car_mutex); return val; @@ -88,25 +92,27 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_read); int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val) { - volatile u32 *reg_addr; + u32 __iomem *reg_addr; int ret = 0; mutex_lock(&car_mutex); /* set up primary or secondary codec space */ if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS) - reg_addr = slot ? &SMC_REG_BASE : &PMC_REG_BASE; + reg_addr = ac97_reg_base + + (slot ? SMC_REG_BASE : PMC_REG_BASE); else - reg_addr = slot ? &SAC_REG_BASE : &PAC_REG_BASE; + reg_addr = ac97_reg_base + + (slot ? SAC_REG_BASE : PAC_REG_BASE); reg_addr += (reg >> 1); - GSR = GSR_CDONE | GSR_SDONE; + writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR); gsr_bits = 0; - *reg_addr = val; - if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 && - !((GSR | gsr_bits) & GSR_CDONE)) { + writel(val, reg_addr); + if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_CDONE, 1) <= 0 && + !((readl(ac97_reg_base + GSR) | gsr_bits) & GSR_CDONE)) { printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n", - __func__, reg, GSR | gsr_bits); + __func__, reg, readl(ac97_reg_base + GSR) | gsr_bits); ret = -EIO; } @@ -120,17 +126,17 @@ static inline void pxa_ac97_warm_pxa25x(void) { gsr_bits = 0; - GCR |= GCR_WARM_RST; + writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR); } static inline void pxa_ac97_cold_pxa25x(void) { - GCR &= GCR_COLD_RST; /* clear everything but nCRST */ - GCR &= ~GCR_COLD_RST; /* then assert nCRST */ + writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR); /* clear everything but nCRST */ + writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR); /* then assert nCRST */ gsr_bits = 0; - GCR = GCR_COLD_RST; + writel(GCR_COLD_RST, ac97_reg_base + GCR); } #endif @@ -142,15 +148,15 @@ static inline void pxa_ac97_warm_pxa27x(void) /* warm reset broken on Bulverde, so manually keep AC97 reset high */ pxa27x_configure_ac97reset(reset_gpio, true); udelay(10); - GCR |= GCR_WARM_RST; + writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR); pxa27x_configure_ac97reset(reset_gpio, false); udelay(500); } static inline void pxa_ac97_cold_pxa27x(void) { - GCR &= GCR_COLD_RST; /* clear everything but nCRST */ - GCR &= ~GCR_COLD_RST; /* then assert nCRST */ + writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR); /* clear everything but nCRST */ + writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR); /* then assert nCRST */ gsr_bits = 0; @@ -158,7 +164,7 @@ static inline void pxa_ac97_cold_pxa27x(void) clk_prepare_enable(ac97conf_clk); udelay(5); clk_disable_unprepare(ac97conf_clk); - GCR = GCR_COLD_RST | GCR_WARM_RST; + writel(GCR_COLD_RST | GCR_WARM_RST, ac97_reg_base + GCR); } #endif @@ -168,26 +174,26 @@ static inline void pxa_ac97_warm_pxa3xx(void) gsr_bits = 0; /* Can't use interrupts */ - GCR |= GCR_WARM_RST; + writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR); } static inline void pxa_ac97_cold_pxa3xx(void) { /* Hold CLKBPB for 100us */ - GCR = 0; - GCR = GCR_CLKBPB; + writel(0, ac97_reg_base + GCR); + writel(GCR_CLKBPB, ac97_reg_base + GCR); udelay(100); - GCR = 0; + writel(0, ac97_reg_base + GCR); - GCR &= GCR_COLD_RST; /* clear everything but nCRST */ - GCR &= ~GCR_COLD_RST; /* then assert nCRST */ + writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR); /* clear everything but nCRST */ + writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR); /* then assert nCRST */ gsr_bits = 0; /* Can't use interrupts on PXA3xx */ - GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); + writel(readl(ac97_reg_base + GCR) & (~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN)), ac97_reg_base + GCR); - GCR = GCR_WARM_RST | GCR_COLD_RST; + writel(GCR_WARM_RST | GCR_COLD_RST, ac97_reg_base + GCR); } #endif @@ -213,10 +219,10 @@ bool pxa2xx_ac97_try_warm_reset(void) #endif snd_BUG(); - while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) + while (!((readl(ac97_reg_base + GSR) | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) mdelay(1); - gsr = GSR | gsr_bits; + gsr = readl(ac97_reg_base + GSR) | gsr_bits; if (!(gsr & (GSR_PCR | GSR_SCR))) { printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", __func__, gsr); @@ -250,10 +256,10 @@ bool pxa2xx_ac97_try_cold_reset(void) #endif snd_BUG(); - while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) + while (!((readl(ac97_reg_base + GSR) | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) mdelay(1); - gsr = GSR | gsr_bits; + gsr = readl(ac97_reg_base + GSR) | gsr_bits; if (!(gsr & (GSR_PCR | GSR_SCR))) { printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n", __func__, gsr); @@ -268,8 +274,10 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset); void pxa2xx_ac97_finish_reset(void) { - GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); - GCR |= GCR_SDONE_IE|GCR_CDONE_IE; + u32 gcr = readl(ac97_reg_base + GCR); + gcr &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); + gcr |= GCR_SDONE_IE|GCR_CDONE_IE; + writel(gcr, ac97_reg_base + GCR); } EXPORT_SYMBOL_GPL(pxa2xx_ac97_finish_reset); @@ -277,9 +285,9 @@ static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) { long status; - status = GSR; + status = readl(ac97_reg_base + GSR); if (status) { - GSR = status; + writel(status, ac97_reg_base + GSR); gsr_bits |= status; wake_up(&gsr_wq); @@ -287,9 +295,9 @@ static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) since they tend to spuriously trigger when MMC is used (hardware bug? go figure)... */ if (cpu_is_pxa27x()) { - MISR = MISR_EOC; - PISR = PISR_EOC; - MCSR = MCSR_EOC; + writel(MISR_EOC, ac97_reg_base + MISR); + writel(PISR_EOC, ac97_reg_base + PISR); + writel(MCSR_EOC, ac97_reg_base + MCSR); } return IRQ_HANDLED; @@ -301,7 +309,7 @@ static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) #ifdef CONFIG_PM int pxa2xx_ac97_hw_suspend(void) { - GCR |= GCR_ACLINK_OFF; + writel(readl(ac97_reg_base + GCR) | (GCR_ACLINK_OFF), ac97_reg_base + GCR); clk_disable_unprepare(ac97_clk); return 0; } @@ -318,8 +326,15 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume); int pxa2xx_ac97_hw_probe(struct platform_device *dev) { int ret; + int irq; pxa2xx_audio_ops_t *pdata = dev->dev.platform_data; + ac97_reg_base = devm_platform_ioremap_resource(dev, 0); + if (IS_ERR(ac97_reg_base)) { + dev_err(&dev->dev, "Missing MMIO resource\n"); + return PTR_ERR(ac97_reg_base); + } + if (pdata) { switch (pdata->reset_gpio) { case 95: @@ -386,14 +401,18 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev) if (ret) goto err_clk2; - ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL); + irq = platform_get_irq(dev, 0); + if (!irq) + goto err_irq; + + ret = request_irq(irq, pxa2xx_ac97_irq, 0, "AC97", NULL); if (ret < 0) goto err_irq; return 0; err_irq: - GCR |= GCR_ACLINK_OFF; + writel(readl(ac97_reg_base + GCR) | (GCR_ACLINK_OFF), ac97_reg_base + GCR); err_clk2: clk_put(ac97_clk); ac97_clk = NULL; @@ -411,8 +430,8 @@ void pxa2xx_ac97_hw_remove(struct platform_device *dev) { if (cpu_is_pxa27x()) gpio_free(reset_gpio); - GCR |= GCR_ACLINK_OFF; - free_irq(IRQ_AC97, NULL); + writel(readl(ac97_reg_base + GCR) | (GCR_ACLINK_OFF), ac97_reg_base + GCR); + free_irq(platform_get_irq(dev, 0), NULL); if (ac97conf_clk) { clk_put(ac97conf_clk); ac97conf_clk = NULL; @@ -423,6 +442,24 @@ void pxa2xx_ac97_hw_remove(struct platform_device *dev) } EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_remove); +u32 pxa2xx_ac97_read_modr(void) +{ + if (!ac97_reg_base) + return 0; + + return readl(ac97_reg_base + MODR); +} +EXPORT_SYMBOL_GPL(pxa2xx_ac97_read_modr); + +u32 pxa2xx_ac97_read_misr(void) +{ + if (!ac97_reg_base) + return 0; + + return readl(ac97_reg_base + MISR); +} +EXPORT_SYMBOL_GPL(pxa2xx_ac97_read_misr); + MODULE_AUTHOR("Nicolas Pitre"); MODULE_DESCRIPTION("Intel/Marvell PXA sound library"); MODULE_LICENSE("GPL"); diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index c17a19fe59..c162086455 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -21,8 +21,7 @@ #include #include -#include -#include +#include static void pxa2xx_ac97_legacy_reset(struct snd_ac97 *ac97) { diff --git a/sound/core/Kconfig b/sound/core/Kconfig index dd7b407347..12990d9a4d 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -154,6 +154,16 @@ config SND_VERBOSE_PRINTK You don't need this unless you're debugging ALSA. +config SND_CTL_FAST_LOOKUP + bool "Fast lookup of control elements" if EXPERT + default y + select XARRAY_MULTI + help + This option enables the faster lookup of control elements. + It will consume more memory because of the additional Xarray. + If you want to choose the memory footprint over the performance + inevitably, turn this off. + config SND_DEBUG bool "Debug" help @@ -178,14 +188,29 @@ config SND_PCM_XRUN_DEBUG sound clicking when system is loaded, it may help to determine the process or driver which causes the scheduling gaps. -config SND_CTL_VALIDATION - bool "Perform sanity-checks for each control element access" +config SND_CTL_INPUT_VALIDATION + bool "Validate input data to control API" + help + Say Y to enable the additional validation for the input data to + each control element, including the value range checks. + An error is returned from ALSA core for invalid inputs without + passing to the driver. This is a kind of hardening for drivers + that have no proper error checks, at the cost of a slight + performance overhead. + +config SND_CTL_DEBUG + bool "Enable debugging feature for control API" depends on SND_DEBUG help - Say Y to enable the additional validation of each control element - access, including sanity-checks like whether the values returned - from the driver are in the proper ranges or the check of the invalid - access at out-of-array areas. + Say Y to enable the debugging feature for ALSA control API. + It performs the additional sanity-checks for each control element + read access, such as whether the values returned from the driver + are in the proper ranges or the check of the invalid access at + out-of-array areas. The error is printed when the driver gives + such unexpected values. + When you develop a driver that deals with control elements, it's + strongly recommended to try this one once and verify whether you see + any relevant errors or not. config SND_JACK_INJECTION_DEBUG bool "Sound jack injection interface via debugfs" diff --git a/sound/core/Makefile b/sound/core/Makefile index 350d704ced..2762f03d9b 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -9,9 +9,7 @@ ifneq ($(CONFIG_SND_PROC_FS),) snd-y += info.o snd-$(CONFIG_SND_OSSEMUL) += info_oss.o endif -ifneq ($(CONFIG_M68K),y) snd-$(CONFIG_ISA_DMA_API) += isadma.o -endif snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o snd-$(CONFIG_SND_VMASTER) += vmaster.o snd-$(CONFIG_SND_JACK) += ctljack.o jack.o diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index de514ec8c8..243acad89f 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -810,7 +810,7 @@ static void error_delayed_work(struct work_struct *work) mutex_unlock(&stream->device->lock); } -/* +/** * snd_compr_stop_error: Report a fatal error on a stream * @stream: pointer to stream * @state: state to transition the stream to @@ -818,6 +818,8 @@ static void error_delayed_work(struct work_struct *work) * Stop the stream and set its state. * * Should be called with compressed device lock held. + * + * Return: zero if successful, or a negative error code */ int snd_compr_stop_error(struct snd_compr_stream *stream, snd_pcm_state_t state) @@ -1157,12 +1159,15 @@ static int snd_compress_dev_free(struct snd_device *device) return 0; } -/* +/** * snd_compress_new: create new compress device * @card: sound card pointer * @device: device number * @dirn: device direction, should be of type enum snd_compr_direction + * @id: ID string * @compr: compress device pointer + * + * Return: zero if successful, or a negative error code */ int snd_compress_new(struct snd_card *card, int device, int dirn, const char *id, struct snd_compr *compr) diff --git a/sound/core/control.c b/sound/core/control.c index a25c0d64d1..a7271927d8 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -127,6 +127,7 @@ static int snd_ctl_release(struct inode *inode, struct file *file) if (control->vd[idx].owner == ctl) control->vd[idx].owner = NULL; up_write(&card->controls_rwsem); + snd_fasync_free(ctl->fasync); snd_ctl_empty_read_queue(ctl); put_pid(ctl->pid); kfree(ctl); @@ -181,7 +182,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, _found: wake_up(&ctl->change_sleep); spin_unlock(&ctl->read_lock); - kill_fasync(&ctl->fasync, SIGIO, POLL_IN); + snd_kill_fasync(ctl->fasync, SIGIO, POLL_IN); } read_unlock_irqrestore(&card->ctl_files_rwlock, flags); } @@ -364,6 +365,93 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count) return 0; } +/* check whether the given id is contained in the given kctl */ +static bool elem_id_matches(const struct snd_kcontrol *kctl, + const struct snd_ctl_elem_id *id) +{ + return kctl->id.iface == id->iface && + kctl->id.device == id->device && + kctl->id.subdevice == id->subdevice && + !strncmp(kctl->id.name, id->name, sizeof(kctl->id.name)) && + kctl->id.index <= id->index && + kctl->id.index + kctl->count > id->index; +} + +#ifdef CONFIG_SND_CTL_FAST_LOOKUP +/* Compute a hash key for the corresponding ctl id + * It's for the name lookup, hence the numid is excluded. + * The hash key is bound in LONG_MAX to be used for Xarray key. + */ +#define MULTIPLIER 37 +static unsigned long get_ctl_id_hash(const struct snd_ctl_elem_id *id) +{ + int i; + unsigned long h; + + h = id->iface; + h = MULTIPLIER * h + id->device; + h = MULTIPLIER * h + id->subdevice; + for (i = 0; i < SNDRV_CTL_ELEM_ID_NAME_MAXLEN && id->name[i]; i++) + h = MULTIPLIER * h + id->name[i]; + h = MULTIPLIER * h + id->index; + h &= LONG_MAX; + return h; +} + +/* add hash entries to numid and ctl xarray tables */ +static void add_hash_entries(struct snd_card *card, + struct snd_kcontrol *kcontrol) +{ + struct snd_ctl_elem_id id = kcontrol->id; + int i; + + xa_store_range(&card->ctl_numids, kcontrol->id.numid, + kcontrol->id.numid + kcontrol->count - 1, + kcontrol, GFP_KERNEL); + + for (i = 0; i < kcontrol->count; i++) { + id.index = kcontrol->id.index + i; + if (xa_insert(&card->ctl_hash, get_ctl_id_hash(&id), + kcontrol, GFP_KERNEL)) { + /* skip hash for this entry, noting we had collision */ + card->ctl_hash_collision = true; + dev_dbg(card->dev, "ctl_hash collision %d:%s:%d\n", + id.iface, id.name, id.index); + } + } +} + +/* remove hash entries that have been added */ +static void remove_hash_entries(struct snd_card *card, + struct snd_kcontrol *kcontrol) +{ + struct snd_ctl_elem_id id = kcontrol->id; + struct snd_kcontrol *matched; + unsigned long h; + int i; + + for (i = 0; i < kcontrol->count; i++) { + xa_erase(&card->ctl_numids, id.numid); + h = get_ctl_id_hash(&id); + matched = xa_load(&card->ctl_hash, h); + if (matched && (matched == kcontrol || + elem_id_matches(matched, &id))) + xa_erase(&card->ctl_hash, h); + id.index++; + id.numid++; + } +} +#else /* CONFIG_SND_CTL_FAST_LOOKUP */ +static inline void add_hash_entries(struct snd_card *card, + struct snd_kcontrol *kcontrol) +{ +} +static inline void remove_hash_entries(struct snd_card *card, + struct snd_kcontrol *kcontrol) +{ +} +#endif /* CONFIG_SND_CTL_FAST_LOOKUP */ + enum snd_ctl_add_mode { CTL_ADD_EXCLUSIVE, CTL_REPLACE, CTL_ADD_ON_REPLACE, }; @@ -408,6 +496,8 @@ static int __snd_ctl_add_replace(struct snd_card *card, kcontrol->id.numid = card->last_numid + 1; card->last_numid += kcontrol->count; + add_hash_entries(card, kcontrol); + for (idx = 0; idx < kcontrol->count; idx++) snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_ADD, kcontrol, idx); @@ -479,6 +569,26 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL(snd_ctl_replace); +static int __snd_ctl_remove(struct snd_card *card, + struct snd_kcontrol *kcontrol, + bool remove_hash) +{ + unsigned int idx; + + if (snd_BUG_ON(!card || !kcontrol)) + return -EINVAL; + list_del(&kcontrol->list); + + if (remove_hash) + remove_hash_entries(card, kcontrol); + + card->controls_count -= kcontrol->count; + for (idx = 0; idx < kcontrol->count; idx++) + snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx); + snd_ctl_free_one(kcontrol); + return 0; +} + /** * snd_ctl_remove - remove the control from the card and release it * @card: the card instance @@ -492,16 +602,7 @@ EXPORT_SYMBOL(snd_ctl_replace); */ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol) { - unsigned int idx; - - if (snd_BUG_ON(!card || !kcontrol)) - return -EINVAL; - list_del(&kcontrol->list); - card->controls_count -= kcontrol->count; - for (idx = 0; idx < kcontrol->count; idx++) - snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx); - snd_ctl_free_one(kcontrol); - return 0; + return __snd_ctl_remove(card, kcontrol, true); } EXPORT_SYMBOL(snd_ctl_remove); @@ -642,14 +743,30 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id, up_write(&card->controls_rwsem); return -ENOENT; } + remove_hash_entries(card, kctl); kctl->id = *dst_id; kctl->id.numid = card->last_numid + 1; card->last_numid += kctl->count; + add_hash_entries(card, kctl); up_write(&card->controls_rwsem); return 0; } EXPORT_SYMBOL(snd_ctl_rename_id); +#ifndef CONFIG_SND_CTL_FAST_LOOKUP +static struct snd_kcontrol * +snd_ctl_find_numid_slow(struct snd_card *card, unsigned int numid) +{ + struct snd_kcontrol *kctl; + + list_for_each_entry(kctl, &card->controls, list) { + if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid) + return kctl; + } + return NULL; +} +#endif /* !CONFIG_SND_CTL_FAST_LOOKUP */ + /** * snd_ctl_find_numid - find the control instance with the given number-id * @card: the card instance @@ -665,15 +782,13 @@ EXPORT_SYMBOL(snd_ctl_rename_id); */ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid) { - struct snd_kcontrol *kctl; - if (snd_BUG_ON(!card || !numid)) return NULL; - list_for_each_entry(kctl, &card->controls, list) { - if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid) - return kctl; - } - return NULL; +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + return xa_load(&card->ctl_numids, numid); +#else + return snd_ctl_find_numid_slow(card, numid); +#endif } EXPORT_SYMBOL(snd_ctl_find_numid); @@ -699,21 +814,18 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, return NULL; if (id->numid != 0) return snd_ctl_find_numid(card, id->numid); - list_for_each_entry(kctl, &card->controls, list) { - if (kctl->id.iface != id->iface) - continue; - if (kctl->id.device != id->device) - continue; - if (kctl->id.subdevice != id->subdevice) - continue; - if (strncmp(kctl->id.name, id->name, sizeof(kctl->id.name))) - continue; - if (kctl->id.index > id->index) - continue; - if (kctl->id.index + kctl->count <= id->index) - continue; +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + kctl = xa_load(&card->ctl_hash, get_ctl_id_hash(id)); + if (kctl && elem_id_matches(kctl, id)) return kctl; - } + if (!card->ctl_hash_collision) + return NULL; /* we can rely on only hash table */ +#endif + /* no matching in hash table - try all as the last resort */ + list_for_each_entry(kctl, &card->controls, list) + if (elem_id_matches(kctl, id)) + return kctl; + return NULL; } EXPORT_SYMBOL(snd_ctl_find_id); @@ -855,7 +967,6 @@ static const unsigned int value_sizes[] = { [SNDRV_CTL_ELEM_TYPE_INTEGER64] = sizeof(long long), }; -#ifdef CONFIG_SND_CTL_VALIDATION /* fill the remaining snd_ctl_elem_value data with the given pattern */ static void fill_remaining_elem_value(struct snd_ctl_elem_value *control, struct snd_ctl_elem_info *info, @@ -872,7 +983,7 @@ static void fill_remaining_elem_value(struct snd_ctl_elem_value *control, static int sanity_check_int_value(struct snd_card *card, const struct snd_ctl_elem_value *control, const struct snd_ctl_elem_info *info, - int i) + int i, bool print_error) { long long lval, lmin, lmax, lstep; u64 rem; @@ -906,21 +1017,23 @@ static int sanity_check_int_value(struct snd_card *card, } if (lval < lmin || lval > lmax) { - dev_err(card->dev, - "control %i:%i:%i:%s:%i: value out of range %lld (%lld/%lld) at count %i\n", - control->id.iface, control->id.device, - control->id.subdevice, control->id.name, - control->id.index, lval, lmin, lmax, i); + if (print_error) + dev_err(card->dev, + "control %i:%i:%i:%s:%i: value out of range %lld (%lld/%lld) at count %i\n", + control->id.iface, control->id.device, + control->id.subdevice, control->id.name, + control->id.index, lval, lmin, lmax, i); return -EINVAL; } if (lstep) { div64_u64_rem(lval, lstep, &rem); if (rem) { - dev_err(card->dev, - "control %i:%i:%i:%s:%i: unaligned value %lld (step %lld) at count %i\n", - control->id.iface, control->id.device, - control->id.subdevice, control->id.name, - control->id.index, lval, lstep, i); + if (print_error) + dev_err(card->dev, + "control %i:%i:%i:%s:%i: unaligned value %lld (step %lld) at count %i\n", + control->id.iface, control->id.device, + control->id.subdevice, control->id.name, + control->id.index, lval, lstep, i); return -EINVAL; } } @@ -928,15 +1041,13 @@ static int sanity_check_int_value(struct snd_card *card, return 0; } -/* perform sanity checks to the given snd_ctl_elem_value object */ -static int sanity_check_elem_value(struct snd_card *card, - const struct snd_ctl_elem_value *control, - const struct snd_ctl_elem_info *info, - u32 pattern) +/* check whether the all input values are valid for the given elem value */ +static int sanity_check_input_values(struct snd_card *card, + const struct snd_ctl_elem_value *control, + const struct snd_ctl_elem_info *info, + bool print_error) { - size_t offset; - int i, ret = 0; - u32 *p; + int i, ret; switch (info->type) { case SNDRV_CTL_ELEM_TYPE_BOOLEAN: @@ -944,7 +1055,8 @@ static int sanity_check_elem_value(struct snd_card *card, case SNDRV_CTL_ELEM_TYPE_INTEGER64: case SNDRV_CTL_ELEM_TYPE_ENUMERATED: for (i = 0; i < info->count; i++) { - ret = sanity_check_int_value(card, control, info, i); + ret = sanity_check_int_value(card, control, info, i, + print_error); if (ret < 0) return ret; } @@ -953,6 +1065,23 @@ static int sanity_check_elem_value(struct snd_card *card, break; } + return 0; +} + +/* perform sanity checks to the given snd_ctl_elem_value object */ +static int sanity_check_elem_value(struct snd_card *card, + const struct snd_ctl_elem_value *control, + const struct snd_ctl_elem_info *info, + u32 pattern) +{ + size_t offset; + int ret; + u32 *p; + + ret = sanity_check_input_values(card, control, info, true); + if (ret < 0) + return ret; + /* check whether the remaining area kept untouched */ offset = value_sizes[info->type] * info->count; offset = DIV_ROUND_UP(offset, sizeof(u32)); @@ -967,21 +1096,6 @@ static int sanity_check_elem_value(struct snd_card *card, return ret; } -#else -static inline void fill_remaining_elem_value(struct snd_ctl_elem_value *control, - struct snd_ctl_elem_info *info, - u32 pattern) -{ -} - -static inline int sanity_check_elem_value(struct snd_card *card, - struct snd_ctl_elem_value *control, - struct snd_ctl_elem_info *info, - u32 pattern) -{ - return 0; -} -#endif static int __snd_ctl_elem_info(struct snd_card *card, struct snd_kcontrol *kctl, @@ -1077,7 +1191,7 @@ static int snd_ctl_elem_read(struct snd_card *card, snd_ctl_build_ioff(&control->id, kctl, index_offset); -#ifdef CONFIG_SND_CTL_VALIDATION +#ifdef CONFIG_SND_CTL_DEBUG /* info is needed only for validation */ memset(&info, 0, sizeof(info)); info.id = control->id; @@ -1154,6 +1268,17 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, snd_ctl_build_ioff(&control->id, kctl, index_offset); result = snd_power_ref_and_wait(card); + /* validate input values */ + if (IS_ENABLED(CONFIG_SND_CTL_INPUT_VALIDATION) && !result) { + struct snd_ctl_elem_info info; + + memset(&info, 0, sizeof(info)); + info.id = control->id; + result = __snd_ctl_elem_info(card, kctl, &info, NULL); + if (!result) + result = sanity_check_input_values(card, control, &info, + false); + } if (!result) result = kctl->put(kctl, control); snd_power_unref(card); @@ -1930,6 +2055,8 @@ static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head * * @fcn: ioctl callback function * * called from each device manager like pcm.c, hwdep.c, etc. + * + * Return: zero if successful, or a negative error code */ int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn) { @@ -1942,6 +2069,8 @@ EXPORT_SYMBOL(snd_ctl_register_ioctl); * snd_ctl_register_ioctl_compat - register the device-specific 32bit compat * control-ioctls * @fcn: ioctl callback function + * + * Return: zero if successful, or a negative error code */ int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn) { @@ -1977,6 +2106,8 @@ static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, /** * snd_ctl_unregister_ioctl - de-register the device-specific control-ioctls * @fcn: ioctl callback function to unregister + * + * Return: zero if successful, or a negative error code */ int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn) { @@ -1989,6 +2120,8 @@ EXPORT_SYMBOL(snd_ctl_unregister_ioctl); * snd_ctl_unregister_ioctl_compat - de-register the device-specific compat * 32bit control-ioctls * @fcn: ioctl callback function to unregister + * + * Return: zero if successful, or a negative error code */ int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn) { @@ -2002,7 +2135,7 @@ static int snd_ctl_fasync(int fd, struct file * file, int on) struct snd_ctl_file *ctl; ctl = file->private_data; - return fasync_helper(fd, file, on, &ctl->fasync); + return snd_fasync_helper(fd, file, on, &ctl->fasync); } /* return the preferred subdevice number if already assigned; @@ -2044,7 +2177,7 @@ EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice); * snd_ctl_request_layer - request to use the layer * @module_name: Name of the kernel module (NULL == build-in) * - * Return an error code when the module cannot be loaded. + * Return: zero if successful, or an error code when the module cannot be loaded */ int snd_ctl_request_layer(const char *module_name) { @@ -2170,7 +2303,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) read_lock_irqsave(&card->ctl_files_rwlock, flags); list_for_each_entry(ctl, &card->ctl_files, list) { wake_up(&ctl->change_sleep); - kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); + snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR); } read_unlock_irqrestore(&card->ctl_files_rwlock, flags); @@ -2195,8 +2328,13 @@ static int snd_ctl_dev_free(struct snd_device *device) down_write(&card->controls_rwsem); while (!list_empty(&card->controls)) { control = snd_kcontrol(card->controls.next); - snd_ctl_remove(card, control); + __snd_ctl_remove(card, control, false); } + +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + xa_destroy(&card->ctl_numids); + xa_destroy(&card->ctl_hash); +#endif up_write(&card->controls_rwsem); put_device(&card->ctl_dev); return 0; @@ -2241,6 +2379,8 @@ int snd_ctl_create(struct snd_card *card) * * This is a function that can be used as info callback for a standard * boolean control with a single mono channel. + * + * Return: Zero (always successful) */ int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -2261,6 +2401,8 @@ EXPORT_SYMBOL(snd_ctl_boolean_mono_info); * * This is a function that can be used as info callback for a standard * boolean control with stereo two channels. + * + * Return: Zero (always successful) */ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -2284,7 +2426,7 @@ EXPORT_SYMBOL(snd_ctl_boolean_stereo_info); * If the control's accessibility is not the default (readable and writable), * the caller has to fill @info->access. * - * Return: Zero. + * Return: Zero (always successful) */ int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels, unsigned int items, const char *const names[]) diff --git a/sound/core/control_led.c b/sound/core/control_led.c index 207828f309..f975cc8577 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -405,7 +405,7 @@ static ssize_t mode_show(struct device *dev, case MODE_ON: str = "on"; break; case MODE_OFF: str = "off"; break; } - return sprintf(buf, "%s\n", str); + return sysfs_emit(buf, "%s\n", str); } static ssize_t mode_store(struct device *dev, @@ -443,7 +443,7 @@ static ssize_t brightness_show(struct device *dev, { struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); - return sprintf(buf, "%u\n", ledtrig_audio_get(led->trigger_type)); + return sysfs_emit(buf, "%u\n", ledtrig_audio_get(led->trigger_type)); } static DEVICE_ATTR_RW(mode); @@ -618,8 +618,7 @@ static ssize_t list_show(struct device *dev, struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); struct snd_card *card; struct snd_ctl_led_ctl *lctl; - char *buf2 = buf; - size_t l; + size_t l = 0; card = snd_card_ref(led_card->number); if (!card) @@ -627,23 +626,19 @@ static ssize_t list_show(struct device *dev, down_read(&card->controls_rwsem); mutex_lock(&snd_ctl_led_mutex); if (snd_ctl_led_card_valid[led_card->number]) { - list_for_each_entry(lctl, &led_card->led->controls, list) - if (lctl->card == card) { - if (buf2 - buf > PAGE_SIZE - 16) - break; - if (buf2 != buf) - *buf2++ = ' '; - l = scnprintf(buf2, 15, "%u", - lctl->kctl->id.numid + - lctl->index_offset); - buf2[l] = '\0'; - buf2 += l + 1; - } + list_for_each_entry(lctl, &led_card->led->controls, list) { + if (lctl->card != card) + continue; + if (l) + l += sysfs_emit_at(buf, l, " "); + l += sysfs_emit_at(buf, l, "%u", + lctl->kctl->id.numid + lctl->index_offset); + } } mutex_unlock(&snd_ctl_led_mutex); up_read(&card->controls_rwsem); snd_card_unref(card); - return buf2 - buf; + return l; } static DEVICE_ATTR_WO(attach); diff --git a/sound/core/device.c b/sound/core/device.c index bf0b04a7ee..b57d80a170 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -247,6 +247,8 @@ void snd_device_free_all(struct snd_card *card) * device, either @SNDRV_DEV_BUILD, @SNDRV_DEV_REGISTERED or * @SNDRV_DEV_DISCONNECTED is returned. * Or for a non-existing device, -1 is returned as an error. + * + * Return: the current state, or -1 if not found */ int snd_device_get_state(struct snd_card *card, void *device_data) { diff --git a/sound/core/info.c b/sound/core/info.c index 782fba87cc..0b2f04dcb5 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -111,9 +111,9 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) entry = data->entry; mutex_lock(&entry->access); if (entry->c.ops->llseek) { - offset = entry->c.ops->llseek(entry, - data->file_private_data, - file, offset, orig); + ret = entry->c.ops->llseek(entry, + data->file_private_data, + file, offset, orig); goto out; } @@ -868,6 +868,8 @@ EXPORT_SYMBOL(snd_info_register); * * This proc file entry will be registered via snd_card_register() call, and * it will be removed automatically at the card removal, too. + * + * Return: zero if successful, or a negative error code */ int snd_card_rw_proc_new(struct snd_card *card, const char *name, void *private_data, diff --git a/sound/core/init.c b/sound/core/init.c index 726a835320..193dae361f 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -215,6 +215,8 @@ static void __snd_card_release(struct device *dev, void *data) * via snd_card_free() call in the error; otherwise it may lead to UAF due to * devres call orders. You can use snd_card_free_on_error() helper for * handling it more easily. + * + * Return: zero if successful, or a negative error code */ int snd_devm_card_new(struct device *parent, int idx, const char *xid, struct module *module, size_t extra_size, @@ -249,6 +251,8 @@ EXPORT_SYMBOL_GPL(snd_devm_card_new); * This function handles the explicit snd_card_free() call at the error from * the probe callback. It's just a small helper for simplifying the error * handling with the managed devices. + * + * Return: zero if successful, or a negative error code */ int snd_card_free_on_error(struct device *dev, int ret) { @@ -310,6 +314,10 @@ static int snd_card_init(struct snd_card *card, struct device *parent, rwlock_init(&card->ctl_files_rwlock); INIT_LIST_HEAD(&card->controls); INIT_LIST_HEAD(&card->ctl_files); +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + xa_init(&card->ctl_numids); + xa_init(&card->ctl_hash); +#endif spin_lock_init(&card->files_lock); INIT_LIST_HEAD(&card->files_list); mutex_init(&card->memory_mutex); @@ -366,6 +374,8 @@ static int snd_card_init(struct snd_card *card, struct device *parent, * * Returns a card object corresponding to the given index or NULL if not found. * Release the object via snd_card_unref(). + * + * Return: a card object or NULL */ struct snd_card *snd_card_ref(int idx) { @@ -604,6 +614,8 @@ static int snd_card_do_free(struct snd_card *card) * resource immediately, but tries to disconnect at first. When the card * is still in use, the function returns before freeing the resources. * The card resources will be freed when the refcount gets to zero. + * + * Return: zero if successful, or a negative error code */ int snd_card_free_when_closed(struct snd_card *card) { @@ -772,7 +784,7 @@ static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_card *card = container_of(dev, struct snd_card, card_dev); - return scnprintf(buf, PAGE_SIZE, "%s\n", card->id); + return sysfs_emit(buf, "%s\n", card->id); } static ssize_t id_store(struct device *dev, struct device_attribute *attr, @@ -810,7 +822,7 @@ static ssize_t number_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_card *card = container_of(dev, struct snd_card, card_dev); - return scnprintf(buf, PAGE_SIZE, "%i\n", card->number); + return sysfs_emit(buf, "%i\n", card->number); } static DEVICE_ATTR_RO(number); @@ -829,6 +841,8 @@ static const struct attribute_group card_dev_attr_group = { * snd_card_add_dev_attr - Append a new sysfs attribute group to card * @card: card instance * @group: attribute group to append + * + * Return: zero if successful, or a negative error code */ int snd_card_add_dev_attr(struct snd_card *card, const struct attribute_group *group) diff --git a/sound/core/isadma.c b/sound/core/isadma.c index 1f45ede023..28768061d7 100644 --- a/sound/core/isadma.c +++ b/sound/core/isadma.c @@ -12,8 +12,8 @@ #undef HAVE_REALLY_SLOW_DMA_CONTROLLER #include +#include #include -#include /** * snd_dma_program - program an ISA DMA transfer @@ -116,8 +116,9 @@ static void __snd_release_dma(struct device *dev, void *data) * @dma: the dma number * @name: the name string of the requester * - * Returns zero on success, or a negative error code. * The requested DMA will be automatically released at unbinding via devres. + * + * Return: zero on success, or a negative error code */ int snd_devm_request_dma(struct device *dev, int dma, const char *name) { diff --git a/sound/core/jack.c b/sound/core/jack.c index d1e3055f2b..88493cc319 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -42,8 +42,11 @@ static int snd_jack_dev_disconnect(struct snd_device *device) #ifdef CONFIG_SND_JACK_INPUT_DEV struct snd_jack *jack = device->device_data; - if (!jack->input_dev) + mutex_lock(&jack->input_dev_lock); + if (!jack->input_dev) { + mutex_unlock(&jack->input_dev_lock); return 0; + } /* If the input device is registered with the input subsystem * then we need to use a different deallocator. */ @@ -52,6 +55,7 @@ static int snd_jack_dev_disconnect(struct snd_device *device) else input_free_device(jack->input_dev); jack->input_dev = NULL; + mutex_unlock(&jack->input_dev_lock); #endif /* CONFIG_SND_JACK_INPUT_DEV */ return 0; } @@ -90,8 +94,11 @@ static int snd_jack_dev_register(struct snd_device *device) snprintf(jack->name, sizeof(jack->name), "%s %s", card->shortname, jack->id); - if (!jack->input_dev) + mutex_lock(&jack->input_dev_lock); + if (!jack->input_dev) { + mutex_unlock(&jack->input_dev_lock); return 0; + } jack->input_dev->name = jack->name; @@ -116,6 +123,7 @@ static int snd_jack_dev_register(struct snd_device *device) if (err == 0) jack->registered = 1; + mutex_unlock(&jack->input_dev_lock); return err; } #endif /* CONFIG_SND_JACK_INPUT_DEV */ @@ -517,9 +525,11 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, return -ENOMEM; } - /* don't creat input device for phantom jack */ - if (!phantom_jack) { #ifdef CONFIG_SND_JACK_INPUT_DEV + mutex_init(&jack->input_dev_lock); + + /* don't create input device for phantom jack */ + if (!phantom_jack) { int i; jack->input_dev = input_allocate_device(); @@ -537,8 +547,8 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, input_set_capability(jack->input_dev, EV_SW, jack_switch_types[i]); -#endif /* CONFIG_SND_JACK_INPUT_DEV */ } +#endif /* CONFIG_SND_JACK_INPUT_DEV */ err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); if (err < 0) @@ -578,10 +588,14 @@ EXPORT_SYMBOL(snd_jack_new); void snd_jack_set_parent(struct snd_jack *jack, struct device *parent) { WARN_ON(jack->registered); - if (!jack->input_dev) + mutex_lock(&jack->input_dev_lock); + if (!jack->input_dev) { + mutex_unlock(&jack->input_dev_lock); return; + } jack->input_dev->dev.parent = parent; + mutex_unlock(&jack->input_dev_lock); } EXPORT_SYMBOL(snd_jack_set_parent); @@ -629,6 +643,8 @@ EXPORT_SYMBOL(snd_jack_set_key); /** * snd_jack_report - Report the current status of a jack + * Note: This function uses mutexes and should be called from a + * context which can sleep (such as a workqueue). * * @jack: The jack to report status for * @status: The current status of the jack @@ -654,8 +670,11 @@ void snd_jack_report(struct snd_jack *jack, int status) status & jack_kctl->mask_bits); #ifdef CONFIG_SND_JACK_INPUT_DEV - if (!jack->input_dev) + mutex_lock(&jack->input_dev_lock); + if (!jack->input_dev) { + mutex_unlock(&jack->input_dev_lock); return; + } for (i = 0; i < ARRAY_SIZE(jack->key); i++) { int testbit = ((SND_JACK_BTN_0 >> i) & ~mask_bits); @@ -675,6 +694,7 @@ void snd_jack_report(struct snd_jack *jack, int status) } input_sync(jack->input_dev); + mutex_unlock(&jack->input_dev_lock); #endif /* CONFIG_SND_JACK_INPUT_DEV */ } EXPORT_SYMBOL(snd_jack_report); diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 15dc7160ba..b665ac66cc 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -20,6 +20,13 @@ static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab); +#ifdef CONFIG_SND_DMA_SGBUF +static void *do_alloc_fallback_pages(struct device *dev, size_t size, + dma_addr_t *addr, bool wc); +static void do_free_fallback_pages(void *p, size_t size, bool wc); +static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size); +#endif + /* a cast to gfp flag from the dev pointer; for CONTINUOUS and VMALLOC types */ static inline gfp_t snd_mem_get_gfp_flags(const struct snd_dma_buffer *dmab, gfp_t default_gfp) @@ -147,7 +154,7 @@ static void __snd_release_pages(struct device *dev, void *res) * hence it can't work with SNDRV_DMA_TYPE_CONTINUOUS or * SNDRV_DMA_TYPE_VMALLOC type. * - * The function returns the snd_dma_buffer object at success, or NULL if failed. + * Return: the snd_dma_buffer object at success, or NULL if failed */ struct snd_dma_buffer * snd_devm_alloc_dir_pages(struct device *dev, int type, @@ -179,6 +186,8 @@ EXPORT_SYMBOL_GPL(snd_devm_alloc_dir_pages); * snd_dma_buffer_mmap - perform mmap of the given DMA buffer * @dmab: buffer allocation information * @area: VM area information + * + * Return: zero if successful, or a negative error code */ int snd_dma_buffer_mmap(struct snd_dma_buffer *dmab, struct vm_area_struct *area) @@ -219,6 +228,8 @@ EXPORT_SYMBOL_GPL(snd_dma_buffer_sync); * snd_sgbuf_get_addr - return the physical address at the corresponding offset * @dmab: buffer allocation information * @offset: offset in the ring buffer + * + * Return: the physical address */ dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab, size_t offset) { @@ -235,6 +246,8 @@ EXPORT_SYMBOL(snd_sgbuf_get_addr); * snd_sgbuf_get_page - return the physical page at the corresponding offset * @dmab: buffer allocation information * @offset: offset in the ring buffer + * + * Return: the page pointer */ struct page *snd_sgbuf_get_page(struct snd_dma_buffer *dmab, size_t offset) { @@ -253,6 +266,8 @@ EXPORT_SYMBOL(snd_sgbuf_get_page); * @dmab: buffer allocation information * @ofs: offset in the ring buffer * @size: the requested size + * + * Return: the chunk size */ unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab, unsigned int ofs, unsigned int size) @@ -269,16 +284,21 @@ EXPORT_SYMBOL(snd_sgbuf_get_chunk_size); /* * Continuous pages allocator */ -static void *snd_dma_continuous_alloc(struct snd_dma_buffer *dmab, size_t size) +static void *do_alloc_pages(size_t size, dma_addr_t *addr, gfp_t gfp) { - gfp_t gfp = snd_mem_get_gfp_flags(dmab, GFP_KERNEL); void *p = alloc_pages_exact(size, gfp); if (p) - dmab->addr = page_to_phys(virt_to_page(p)); + *addr = page_to_phys(virt_to_page(p)); return p; } +static void *snd_dma_continuous_alloc(struct snd_dma_buffer *dmab, size_t size) +{ + return do_alloc_pages(size, &dmab->addr, + snd_mem_get_gfp_flags(dmab, GFP_KERNEL)); +} + static void snd_dma_continuous_free(struct snd_dma_buffer *dmab) { free_pages_exact(dmab->area, dmab->bytes); @@ -431,33 +451,17 @@ static const struct snd_malloc_ops snd_dma_iram_ops = { */ static void *snd_dma_dev_alloc(struct snd_dma_buffer *dmab, size_t size) { - void *p; - - p = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, DEFAULT_GFP); -#ifdef CONFIG_X86 - if (p && dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC) - set_memory_wc((unsigned long)p, PAGE_ALIGN(size) >> PAGE_SHIFT); -#endif - return p; + return dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, DEFAULT_GFP); } static void snd_dma_dev_free(struct snd_dma_buffer *dmab) { -#ifdef CONFIG_X86 - if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC) - set_memory_wb((unsigned long)dmab->area, - PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT); -#endif dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); } static int snd_dma_dev_mmap(struct snd_dma_buffer *dmab, struct vm_area_struct *area) { -#ifdef CONFIG_X86 - if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC) - area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); -#endif return dma_mmap_coherent(dmab->dev.dev, area, dmab->area, dmab->addr, dmab->bytes); } @@ -471,10 +475,25 @@ static const struct snd_malloc_ops snd_dma_dev_ops = { /* * Write-combined pages */ -#ifdef CONFIG_X86 -/* On x86, share the same ops as the standard dev ops */ -#define snd_dma_wc_ops snd_dma_dev_ops -#else /* CONFIG_X86 */ +/* x86-specific allocations */ +#ifdef CONFIG_SND_DMA_SGBUF +static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size) +{ + return do_alloc_fallback_pages(dmab->dev.dev, size, &dmab->addr, true); +} + +static void snd_dma_wc_free(struct snd_dma_buffer *dmab) +{ + do_free_fallback_pages(dmab->area, dmab->bytes, true); +} + +static int snd_dma_wc_mmap(struct snd_dma_buffer *dmab, + struct vm_area_struct *area) +{ + area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); + return snd_dma_continuous_mmap(dmab, area); +} +#else static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size) { return dma_alloc_wc(dmab->dev.dev, size, &dmab->addr, DEFAULT_GFP); @@ -491,17 +510,13 @@ static int snd_dma_wc_mmap(struct snd_dma_buffer *dmab, return dma_mmap_wc(dmab->dev.dev, area, dmab->area, dmab->addr, dmab->bytes); } +#endif /* CONFIG_SND_DMA_SGBUF */ static const struct snd_malloc_ops snd_dma_wc_ops = { .alloc = snd_dma_wc_alloc, .free = snd_dma_wc_free, .mmap = snd_dma_wc_mmap, }; -#endif /* CONFIG_X86 */ - -#ifdef CONFIG_SND_DMA_SGBUF -static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size); -#endif /* * Non-contiguous pages allocator @@ -682,6 +697,37 @@ static const struct snd_malloc_ops snd_dma_sg_wc_ops = { .get_chunk_size = snd_dma_noncontig_get_chunk_size, }; +/* manual page allocations with wc setup */ +static void *do_alloc_fallback_pages(struct device *dev, size_t size, + dma_addr_t *addr, bool wc) +{ + gfp_t gfp = GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN; + void *p; + + again: + p = do_alloc_pages(size, addr, gfp); + if (!p || (*addr + size - 1) & ~dev->coherent_dma_mask) { + if (IS_ENABLED(CONFIG_ZONE_DMA32) && !(gfp & GFP_DMA32)) { + gfp |= GFP_DMA32; + goto again; + } + if (IS_ENABLED(CONFIG_ZONE_DMA) && !(gfp & GFP_DMA)) { + gfp = (gfp & ~GFP_DMA32) | GFP_DMA; + goto again; + } + } + if (p && wc) + set_memory_wc((unsigned long)(p), size >> PAGE_SHIFT); + return p; +} + +static void do_free_fallback_pages(void *p, size_t size, bool wc) +{ + if (wc) + set_memory_wb((unsigned long)(p), size >> PAGE_SHIFT); + free_pages_exact(p, size); +} + /* Fallback SG-buffer allocations for x86 */ struct snd_dma_sg_fallback { size_t count; @@ -692,14 +738,11 @@ struct snd_dma_sg_fallback { static void __snd_dma_sg_fallback_free(struct snd_dma_buffer *dmab, struct snd_dma_sg_fallback *sgbuf) { + bool wc = dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK; size_t i; - if (sgbuf->count && dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK) - set_pages_array_wb(sgbuf->pages, sgbuf->count); for (i = 0; i < sgbuf->count && sgbuf->pages[i]; i++) - dma_free_coherent(dmab->dev.dev, PAGE_SIZE, - page_address(sgbuf->pages[i]), - sgbuf->addrs[i]); + do_free_fallback_pages(page_address(sgbuf->pages[i]), PAGE_SIZE, wc); kvfree(sgbuf->pages); kvfree(sgbuf->addrs); kfree(sgbuf); @@ -711,6 +754,7 @@ static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size) struct page **pages; size_t i, count; void *p; + bool wc = dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK; sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL); if (!sgbuf) @@ -725,15 +769,13 @@ static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size) goto error; for (i = 0; i < count; sgbuf->count++, i++) { - p = dma_alloc_coherent(dmab->dev.dev, PAGE_SIZE, - &sgbuf->addrs[i], DEFAULT_GFP); + p = do_alloc_fallback_pages(dmab->dev.dev, PAGE_SIZE, + &sgbuf->addrs[i], wc); if (!p) goto error; sgbuf->pages[i] = virt_to_page(p); } - if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK) - set_pages_array_wc(pages, count); p = vmap(pages, count, VM_MAP, PAGE_KERNEL); if (!p) goto error; diff --git a/sound/core/misc.c b/sound/core/misc.c index 50e4aaa627..d32a19976a 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #ifdef CONFIG_SND_DEBUG @@ -145,3 +146,96 @@ snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) } EXPORT_SYMBOL(snd_pci_quirk_lookup); #endif + +/* + * Deferred async signal helpers + * + * Below are a few helper functions to wrap the async signal handling + * in the deferred work. The main purpose is to avoid the messy deadlock + * around tasklist_lock and co at the kill_fasync() invocation. + * fasync_helper() and kill_fasync() are replaced with snd_fasync_helper() + * and snd_kill_fasync(), respectively. In addition, snd_fasync_free() has + * to be called at releasing the relevant file object. + */ +struct snd_fasync { + struct fasync_struct *fasync; + int signal; + int poll; + int on; + struct list_head list; +}; + +static DEFINE_SPINLOCK(snd_fasync_lock); +static LIST_HEAD(snd_fasync_list); + +static void snd_fasync_work_fn(struct work_struct *work) +{ + struct snd_fasync *fasync; + + spin_lock_irq(&snd_fasync_lock); + while (!list_empty(&snd_fasync_list)) { + fasync = list_first_entry(&snd_fasync_list, struct snd_fasync, list); + list_del_init(&fasync->list); + spin_unlock_irq(&snd_fasync_lock); + if (fasync->on) + kill_fasync(&fasync->fasync, fasync->signal, fasync->poll); + spin_lock_irq(&snd_fasync_lock); + } + spin_unlock_irq(&snd_fasync_lock); +} + +static DECLARE_WORK(snd_fasync_work, snd_fasync_work_fn); + +int snd_fasync_helper(int fd, struct file *file, int on, + struct snd_fasync **fasyncp) +{ + struct snd_fasync *fasync = NULL; + + if (on) { + fasync = kzalloc(sizeof(*fasync), GFP_KERNEL); + if (!fasync) + return -ENOMEM; + INIT_LIST_HEAD(&fasync->list); + } + + spin_lock_irq(&snd_fasync_lock); + if (*fasyncp) { + kfree(fasync); + fasync = *fasyncp; + } else { + if (!fasync) { + spin_unlock_irq(&snd_fasync_lock); + return 0; + } + *fasyncp = fasync; + } + fasync->on = on; + spin_unlock_irq(&snd_fasync_lock); + return fasync_helper(fd, file, on, &fasync->fasync); +} +EXPORT_SYMBOL_GPL(snd_fasync_helper); + +void snd_kill_fasync(struct snd_fasync *fasync, int signal, int poll) +{ + unsigned long flags; + + if (!fasync || !fasync->on) + return; + spin_lock_irqsave(&snd_fasync_lock, flags); + fasync->signal = signal; + fasync->poll = poll; + list_move(&fasync->list, &snd_fasync_list); + schedule_work(&snd_fasync_work); + spin_unlock_irqrestore(&snd_fasync_lock, flags); +} +EXPORT_SYMBOL_GPL(snd_kill_fasync); + +void snd_fasync_free(struct snd_fasync *fasync) +{ + if (!fasync) + return; + fasync->on = 0; + flush_work(&snd_fasync_work); + kfree(fasync); +} +EXPORT_SYMBOL_GPL(snd_fasync_free); diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 977d54320a..82925709fa 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -216,6 +216,8 @@ static const char * const snd_pcm_format_names[] = { /** * snd_pcm_format_name - Return a name string for the given PCM format * @format: PCM format + * + * Return: the format name string */ const char *snd_pcm_format_name(snd_pcm_format_t format) { @@ -1005,6 +1007,7 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) substream->runtime = NULL; } mutex_destroy(&runtime->buffer_mutex); + snd_fasync_free(runtime->fasync); kfree(runtime); put_pid(substream->pid); substream->pid = NULL; @@ -1028,7 +1031,7 @@ static ssize_t pcm_class_show(struct device *dev, str = "none"; else str = strs[pcm->dev_class]; - return sprintf(buf, "%s\n", str); + return sysfs_emit(buf, "%s\n", str); } static DEVICE_ATTR_RO(pcm_class); @@ -1138,6 +1141,8 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) * This adds the given notifier to the global list so that the callback is * called for each registered PCM devices. This exists only for PCM OSS * emulation, so far. + * + * Return: zero if successful, or a negative error code */ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) { diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index af6f717e1e..5b2ca028f5 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -48,6 +48,8 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_chan); * * This function can be used to initialize a dma_slave_config from a substream * and hw_params in a dmaengine based PCM driver implementation. + * + * Return: zero if successful, or a negative error code */ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream, const struct snd_pcm_hw_params *params, @@ -175,10 +177,10 @@ static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream) * @substream: PCM substream * @cmd: Trigger command * - * Returns 0 on success, a negative error code otherwise. - * * This function can be used as the PCM trigger callback for dmaengine based PCM * driver implementations. + * + * Return: 0 on success, a negative error code otherwise */ int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { @@ -223,6 +225,8 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger); * * This function is deprecated and should not be used by new drivers, as its * results may be unreliable. + * + * Return: PCM position in frames */ snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream) { @@ -237,6 +241,8 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer_no_residue); * * This function can be used as the PCM pointer callback for dmaengine based PCM * driver implementations. + * + * Return: PCM position in frames */ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream) { @@ -266,9 +272,9 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); * @filter_fn: Filter function used to request the DMA channel * @filter_data: Data passed to the DMA filter function * - * Returns NULL or the requested DMA channel. - * * This function request a DMA channel for usage with dmaengine PCM. + * + * Return: NULL or the requested DMA channel */ struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn, void *filter_data) @@ -288,11 +294,11 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel); * @substream: PCM substream * @chan: DMA channel to use for data transfers * - * Returns 0 on success, a negative error code otherwise. - * * The function should usually be called from the pcm open callback. Note that * this function will use private_data field of the substream's runtime. So it * is not available to your pcm driver implementation. + * + * Return: 0 on success, a negative error code otherwise */ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, struct dma_chan *chan) @@ -326,12 +332,12 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open); * @filter_fn: Filter function used to request the DMA channel * @filter_data: Data passed to the DMA filter function * - * Returns 0 on success, a negative error code otherwise. - * * This function will request a DMA channel using the passed filter function and * data. The function should usually be called from the pcm open callback. Note * that this function will use private_data field of the substream's runtime. So * it is not available to your pcm driver implementation. + * + * Return: 0 on success, a negative error code otherwise */ int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, dma_filter_fn filter_fn, void *filter_data) @@ -344,6 +350,8 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan); /** * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream * @substream: PCM substream + * + * Return: 0 on success, a negative error code otherwise */ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream) { @@ -362,6 +370,8 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); * @substream: PCM substream * * Releases the DMA channel associated with the PCM substream. + * + * Return: zero if successful, or a negative error code */ int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream) { @@ -382,10 +392,10 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan); * @hw: PCM hw params * @chan: DMA channel to use for data transfers * - * Returns 0 on success, a negative error code otherwise. - * * This function will query DMA capability, then refine the pcm hardware * parameters. + * + * Return: 0 on success, a negative error code otherwise */ int snd_dmaengine_pcm_refine_runtime_hwparams( struct snd_pcm_substream *substream, diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 1fc7c50ffa..40751e5aff 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1822,7 +1822,7 @@ void snd_pcm_period_elapsed_under_stream_lock(struct snd_pcm_substream *substrea snd_timer_interrupt(substream->timer, 1); #endif _end: - kill_fasync(&runtime->fasync, SIGIO, POLL_IN); + snd_kill_fasync(runtime->fasync, SIGIO, POLL_IN); } EXPORT_SYMBOL(snd_pcm_period_elapsed_under_stream_lock); diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 8848d2f316..7bde7fb640 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -350,6 +350,8 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); * SNDRV_DMA_TYPE_VMALLOC type. * * Upon successful buffer allocation and setup, the function returns 0. + * + * Return: zero if successful, or a negative error code */ int snd_pcm_set_managed_buffer(struct snd_pcm_substream *substream, int type, struct device *data, size_t size, size_t max) @@ -369,6 +371,8 @@ EXPORT_SYMBOL(snd_pcm_set_managed_buffer); * * Do pre-allocation to all substreams of the given pcm for the specified DMA * type and size, and set the managed_buffer_alloc flag to each substream. + * + * Return: zero if successful, or a negative error code */ int snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type, struct device *data, @@ -453,7 +457,6 @@ EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); */ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) { - struct snd_card *card = substream->pcm->card; struct snd_pcm_runtime *runtime; if (PCM_RUNTIME_CHECK(substream)) @@ -462,6 +465,8 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) if (runtime->dma_area == NULL) return 0; if (runtime->dma_buffer_p != &substream->dma_buffer) { + struct snd_card *card = substream->pcm->card; + /* it's a newly allocated buffer. release it now. */ do_free_pages(card, runtime->dma_buffer_p); kfree(runtime->dma_buffer_p); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 4adaee62ef..ad0541e9e8 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3412,6 +3412,8 @@ static long snd_pcm_ioctl(struct file *file, unsigned int cmd, * The function is provided primarily for OSS layer and USB gadget drivers, * and it allows only the limited set of ioctls (hw_params, sw_params, * prepare, start, drain, drop, forward). + * + * Return: zero if successful, or a negative error code */ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) @@ -3810,6 +3812,8 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = { * * This is the default mmap handler for PCM data. When mmap pcm_ops is NULL, * this function is invoked implicitly. + * + * Return: zero if successful, or a negative error code */ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *area) @@ -3836,6 +3840,8 @@ EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap); * When your hardware uses the iomapped pages as the hardware buffer and * wants to mmap it, pass this function as mmap pcm_ops. Note that this * is supposed to work only on limited architectures. + * + * Return: zero if successful, or a negative error code */ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_struct *area) @@ -3945,7 +3951,7 @@ static int snd_pcm_fasync(int fd, struct file * file, int on) runtime = substream->runtime; if (runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; - return fasync_helper(fd, file, on, &runtime->fasync); + return snd_fasync_helper(fd, file, on, &runtime->fasync); } /* diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index befa9809ff..6963d5a487 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -102,13 +102,12 @@ static inline bool __snd_rawmidi_ready(struct snd_rawmidi_runtime *runtime) static bool snd_rawmidi_ready(struct snd_rawmidi_substream *substream) { - struct snd_rawmidi_runtime *runtime = substream->runtime; unsigned long flags; bool ready; - spin_lock_irqsave(&runtime->lock, flags); - ready = __snd_rawmidi_ready(runtime); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); + ready = __snd_rawmidi_ready(substream->runtime); + spin_unlock_irqrestore(&substream->lock, flags); return ready; } @@ -130,7 +129,7 @@ static void snd_rawmidi_input_event_work(struct work_struct *work) runtime->event(runtime->substream); } -/* buffer refcount management: call with runtime->lock held */ +/* buffer refcount management: call with substream->lock held */ static inline void snd_rawmidi_buffer_ref(struct snd_rawmidi_runtime *runtime) { runtime->buffer_ref++; @@ -141,6 +140,23 @@ static inline void snd_rawmidi_buffer_unref(struct snd_rawmidi_runtime *runtime) runtime->buffer_ref--; } +static void snd_rawmidi_buffer_ref_sync(struct snd_rawmidi_substream *substream) +{ + int loop = HZ; + + spin_lock_irq(&substream->lock); + while (substream->runtime->buffer_ref) { + spin_unlock_irq(&substream->lock); + if (!--loop) { + rmidi_err(substream->rmidi, "Buffer ref sync timeout\n"); + return; + } + schedule_timeout_uninterruptible(1); + spin_lock_irq(&substream->lock); + } + spin_unlock_irq(&substream->lock); +} + static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime; @@ -149,7 +165,6 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) if (!runtime) return -ENOMEM; runtime->substream = substream; - spin_lock_init(&runtime->lock); init_waitqueue_head(&runtime->sleep); INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work); runtime->event = NULL; @@ -203,35 +218,48 @@ static void __reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime, runtime->avail = is_input ? 0 : runtime->buffer_size; } -static void reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime, +static void reset_runtime_ptrs(struct snd_rawmidi_substream *substream, bool is_input) { unsigned long flags; - spin_lock_irqsave(&runtime->lock, flags); - __reset_runtime_ptrs(runtime, is_input); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); + if (substream->opened && substream->runtime) + __reset_runtime_ptrs(substream->runtime, is_input); + spin_unlock_irqrestore(&substream->lock, flags); } int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) { snd_rawmidi_output_trigger(substream, 0); - reset_runtime_ptrs(substream->runtime, false); + reset_runtime_ptrs(substream, false); return 0; } EXPORT_SYMBOL(snd_rawmidi_drop_output); int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) { - int err; + int err = 0; long timeout; - struct snd_rawmidi_runtime *runtime = substream->runtime; + struct snd_rawmidi_runtime *runtime; + + spin_lock_irq(&substream->lock); + runtime = substream->runtime; + if (!substream->opened || !runtime || !runtime->buffer) { + err = -EINVAL; + } else { + snd_rawmidi_buffer_ref(runtime); + runtime->drain = 1; + } + spin_unlock_irq(&substream->lock); + if (err < 0) + return err; - err = 0; - runtime->drain = 1; timeout = wait_event_interruptible_timeout(runtime->sleep, (runtime->avail >= runtime->buffer_size), 10*HZ); + + spin_lock_irq(&substream->lock); if (signal_pending(current)) err = -ERESTARTSYS; if (runtime->avail < runtime->buffer_size && !timeout) { @@ -241,6 +269,8 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) err = -EIO; } runtime->drain = 0; + spin_unlock_irq(&substream->lock); + if (err != -ERESTARTSYS) { /* we need wait a while to make sure that Tx FIFOs are empty */ if (substream->ops->drain) @@ -249,6 +279,11 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) msleep(50); snd_rawmidi_drop_output(substream); } + + spin_lock_irq(&substream->lock); + snd_rawmidi_buffer_unref(runtime); + spin_unlock_irq(&substream->lock); + return err; } EXPORT_SYMBOL(snd_rawmidi_drain_output); @@ -256,7 +291,7 @@ EXPORT_SYMBOL(snd_rawmidi_drain_output); int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream) { snd_rawmidi_input_trigger(substream, 0); - reset_runtime_ptrs(substream->runtime, true); + reset_runtime_ptrs(substream, true); return 0; } EXPORT_SYMBOL(snd_rawmidi_drain_input); @@ -311,12 +346,14 @@ static int open_substream(struct snd_rawmidi *rmidi, snd_rawmidi_runtime_free(substream); return err; } + spin_lock_irq(&substream->lock); substream->opened = 1; substream->active_sensing = 0; if (mode & SNDRV_RAWMIDI_LFLG_APPEND) substream->append = 1; substream->pid = get_pid(task_pid(current)); rmidi->streams[substream->stream].substream_opened++; + spin_unlock_irq(&substream->lock); } substream->use_count++; return 0; @@ -521,13 +558,16 @@ static void close_substream(struct snd_rawmidi *rmidi, if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS) snd_rawmidi_output_trigger(substream, 0); } + snd_rawmidi_buffer_ref_sync(substream); } + spin_lock_irq(&substream->lock); + substream->opened = 0; + substream->append = 0; + spin_unlock_irq(&substream->lock); substream->ops->close(substream); if (substream->runtime->private_free) substream->runtime->private_free(substream); snd_rawmidi_runtime_free(substream); - substream->opened = 0; - substream->append = 0; put_pid(substream->pid); substream->pid = NULL; rmidi->streams[substream->stream].substream_opened--; @@ -676,10 +716,11 @@ static int snd_rawmidi_info_select_user(struct snd_card *card, return 0; } -static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, +static int resize_runtime_buffer(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params *params, bool is_input) { + struct snd_rawmidi_runtime *runtime = substream->runtime; char *newbuf, *oldbuf; unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK; @@ -693,9 +734,9 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, newbuf = kvzalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); if (runtime->buffer_ref) { - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); kvfree(newbuf); return -EBUSY; } @@ -703,7 +744,7 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; __reset_runtime_ptrs(runtime, is_input); - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); kvfree(oldbuf); } runtime->avail_min = params->avail_min; @@ -713,11 +754,19 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params *params) { - if (substream->append && substream->use_count > 1) - return -EBUSY; + int err; + snd_rawmidi_drain_output(substream); - substream->active_sensing = !params->no_active_sensing; - return resize_runtime_buffer(substream->runtime, params, false); + mutex_lock(&substream->rmidi->open_mutex); + if (substream->append && substream->use_count > 1) + err = -EBUSY; + else + err = resize_runtime_buffer(substream, params, false); + + if (!err) + substream->active_sensing = !params->no_active_sensing; + mutex_unlock(&substream->rmidi->open_mutex); + return err; } EXPORT_SYMBOL(snd_rawmidi_output_params); @@ -728,19 +777,22 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, unsigned int clock_type = params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK; int err; + snd_rawmidi_drain_input(substream); + mutex_lock(&substream->rmidi->open_mutex); if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE) - return -EINVAL; + err = -EINVAL; else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW) - return -EINVAL; - if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) - return -EINVAL; - snd_rawmidi_drain_input(substream); - err = resize_runtime_buffer(substream->runtime, params, true); - if (err < 0) - return err; + err = -EINVAL; + else if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) + err = -EINVAL; + else + err = resize_runtime_buffer(substream, params, true); - substream->framing = framing; - substream->clock_type = clock_type; + if (!err) { + substream->framing = framing; + substream->clock_type = clock_type; + } + mutex_unlock(&substream->rmidi->open_mutex); return 0; } EXPORT_SYMBOL(snd_rawmidi_input_params); @@ -752,9 +804,9 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, memset(status, 0, sizeof(*status)); status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); status->avail = runtime->avail; - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return 0; } @@ -765,11 +817,11 @@ static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream, memset(status, 0, sizeof(*status)); status->stream = SNDRV_RAWMIDI_STREAM_INPUT; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); status->avail = runtime->avail; status->xruns = runtime->xruns; runtime->xruns = 0; - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return 0; } @@ -1064,17 +1116,21 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, unsigned long flags; struct timespec64 ts64 = get_framing_tstamp(substream); int result = 0, count1; - struct snd_rawmidi_runtime *runtime = substream->runtime; + struct snd_rawmidi_runtime *runtime; - if (!substream->opened) - return -EBADFD; - if (runtime->buffer == NULL) { + spin_lock_irqsave(&substream->lock, flags); + if (!substream->opened) { + result = -EBADFD; + goto unlock; + } + runtime = substream->runtime; + if (!runtime || !runtime->buffer) { rmidi_dbg(substream->rmidi, "snd_rawmidi_receive: input is not active!!!\n"); - return -EINVAL; + result = -EINVAL; + goto unlock; } - spin_lock_irqsave(&runtime->lock, flags); if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) { result = receive_with_tstamp_framing(substream, buffer, count, &ts64); } else if (count == 1) { /* special case, faster code */ @@ -1121,7 +1177,8 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, else if (__snd_rawmidi_ready(runtime)) wake_up(&runtime->sleep); } - spin_unlock_irqrestore(&runtime->lock, flags); + unlock: + spin_unlock_irqrestore(&substream->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_receive); @@ -1136,7 +1193,7 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, unsigned long appl_ptr; int err = 0; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); snd_rawmidi_buffer_ref(runtime); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; @@ -1154,11 +1211,11 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, if (kernelbuf) memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1); if (userbuf) { - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); if (copy_to_user(userbuf + result, runtime->buffer + appl_ptr, count1)) err = -EFAULT; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); if (err) goto out; } @@ -1167,7 +1224,7 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, } out: snd_rawmidi_buffer_unref(runtime); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return result > 0 ? result : err; } @@ -1196,31 +1253,31 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun snd_rawmidi_input_trigger(substream, 1); result = 0; while (count > 0) { - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); while (!__snd_rawmidi_ready(runtime)) { wait_queue_entry_t wait; if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return result > 0 ? result : -EAGAIN; } init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); schedule(); remove_wait_queue(&runtime->sleep, &wait); if (rfile->rmidi->card->shutdown) return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); if (!runtime->avail) { - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return result > 0 ? result : -EIO; } } - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); count1 = snd_rawmidi_kernel_read1(substream, (unsigned char __user *)buf, NULL/*kernelbuf*/, @@ -1242,23 +1299,25 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun */ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) { - struct snd_rawmidi_runtime *runtime = substream->runtime; + struct snd_rawmidi_runtime *runtime; int result; unsigned long flags; - if (runtime->buffer == NULL) { + spin_lock_irqsave(&substream->lock, flags); + runtime = substream->runtime; + if (!substream->opened || !runtime || !runtime->buffer) { rmidi_dbg(substream->rmidi, "snd_rawmidi_transmit_empty: output is not active!!!\n"); - return 1; + result = 1; + } else { + result = runtime->avail >= runtime->buffer_size; } - spin_lock_irqsave(&runtime->lock, flags); - result = runtime->avail >= runtime->buffer_size; - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_transmit_empty); -/** +/* * __snd_rawmidi_transmit_peek - copy data from the internal buffer * @substream: the rawmidi substream * @buffer: the buffer pointer @@ -1266,8 +1325,8 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_empty); * * This is a variant of snd_rawmidi_transmit_peek() without spinlock. */ -int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, - unsigned char *buffer, int count) +static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, + unsigned char *buffer, int count) { int result, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -1304,7 +1363,6 @@ int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, __skip: return result; } -EXPORT_SYMBOL(__snd_rawmidi_transmit_peek); /** * snd_rawmidi_transmit_peek - copy data from the internal buffer @@ -1323,25 +1381,28 @@ EXPORT_SYMBOL(__snd_rawmidi_transmit_peek); int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) { - struct snd_rawmidi_runtime *runtime = substream->runtime; int result; unsigned long flags; - spin_lock_irqsave(&runtime->lock, flags); - result = __snd_rawmidi_transmit_peek(substream, buffer, count); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); + if (!substream->opened || !substream->runtime) + result = -EBADFD; + else + result = __snd_rawmidi_transmit_peek(substream, buffer, count); + spin_unlock_irqrestore(&substream->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_transmit_peek); -/** +/* * __snd_rawmidi_transmit_ack - acknowledge the transmission * @substream: the rawmidi substream * @count: the transferred count * * This is a variant of __snd_rawmidi_transmit_ack() without spinlock. */ -int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) +static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, + int count) { struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -1361,7 +1422,6 @@ int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int coun } return count; } -EXPORT_SYMBOL(__snd_rawmidi_transmit_ack); /** * snd_rawmidi_transmit_ack - acknowledge the transmission @@ -1376,13 +1436,15 @@ EXPORT_SYMBOL(__snd_rawmidi_transmit_ack); */ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) { - struct snd_rawmidi_runtime *runtime = substream->runtime; int result; unsigned long flags; - spin_lock_irqsave(&runtime->lock, flags); - result = __snd_rawmidi_transmit_ack(substream, count); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); + if (!substream->opened || !substream->runtime) + result = -EBADFD; + else + result = __snd_rawmidi_transmit_ack(substream, count); + spin_unlock_irqrestore(&substream->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_transmit_ack); @@ -1400,11 +1462,10 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack); int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) { - struct snd_rawmidi_runtime *runtime = substream->runtime; int result; unsigned long flags; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); if (!substream->opened) result = -EBADFD; else { @@ -1414,7 +1475,7 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, else result = __snd_rawmidi_transmit_ack(substream, count); } - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_transmit); @@ -1427,16 +1488,18 @@ EXPORT_SYMBOL(snd_rawmidi_transmit); */ int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream) { - struct snd_rawmidi_runtime *runtime = substream->runtime; + struct snd_rawmidi_runtime *runtime; unsigned long flags; int count = 0; - spin_lock_irqsave(&runtime->lock, flags); - if (runtime->avail < runtime->buffer_size) { + spin_lock_irqsave(&substream->lock, flags); + runtime = substream->runtime; + if (substream->opened && runtime && + runtime->avail < runtime->buffer_size) { count = runtime->buffer_size - runtime->avail; __snd_rawmidi_transmit_ack(substream, count); } - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return count; } EXPORT_SYMBOL(snd_rawmidi_proceed); @@ -1457,10 +1520,10 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, return -EINVAL; result = 0; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); if (substream->append) { if ((long)runtime->avail < count) { - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return -EAGAIN; } } @@ -1482,14 +1545,14 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, memcpy(runtime->buffer + appl_ptr, kernelbuf + result, count1); else if (userbuf) { - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); if (copy_from_user(runtime->buffer + appl_ptr, userbuf + result, count1)) { - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); result = result > 0 ? result : -EFAULT; goto __end; } - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); } result += count1; count -= count1; @@ -1497,7 +1560,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, __end: count1 = runtime->avail < runtime->buffer_size; snd_rawmidi_buffer_unref(runtime); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); if (count1) snd_rawmidi_output_trigger(substream, 1); return result; @@ -1527,31 +1590,31 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, return -EIO; result = 0; while (count > 0) { - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); while (!snd_rawmidi_ready_append(substream, count)) { wait_queue_entry_t wait; if (file->f_flags & O_NONBLOCK) { - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return result > 0 ? result : -EAGAIN; } init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); timeout = schedule_timeout(30 * HZ); remove_wait_queue(&runtime->sleep, &wait); if (rfile->rmidi->card->shutdown) return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); if (!runtime->avail && !timeout) { - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return result > 0 ? result : -EIO; } } - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); count1 = snd_rawmidi_kernel_write1(substream, buf, NULL, count); if (count1 < 0) return result > 0 ? result : count1; @@ -1562,7 +1625,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, count -= count1; } if (file->f_flags & O_DSYNC) { - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); while (runtime->avail != runtime->buffer_size) { wait_queue_entry_t wait; unsigned int last_avail = runtime->avail; @@ -1570,16 +1633,16 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); timeout = schedule_timeout(30 * HZ); remove_wait_queue(&runtime->sleep, &wait); if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (runtime->avail == last_avail && !timeout) return result > 0 ? result : -EIO; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); } - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); } return result; } @@ -1650,10 +1713,10 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, " Owner PID : %d\n", pid_vnr(substream->pid)); runtime = substream->runtime; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); buffer_size = runtime->buffer_size; avail = runtime->avail; - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); snd_iprintf(buffer, " Mode : %s\n" " Buffer size : %lu\n" @@ -1677,11 +1740,11 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, " Owner PID : %d\n", pid_vnr(substream->pid)); runtime = substream->runtime; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); buffer_size = runtime->buffer_size; avail = runtime->avail; xruns = runtime->xruns; - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); snd_iprintf(buffer, " Buffer size : %lu\n" " Avail : %lu\n" @@ -1733,6 +1796,7 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, substream->number = idx; substream->rmidi = rmidi; substream->pstr = stream; + spin_lock_init(&substream->lock); list_add_tail(&substream->list, &stream->substreams); stream->substream_count++; } diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 1e3bf086f8..07efb38f58 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -270,7 +270,9 @@ snd_seq_oss_midi_clear_all(void) void snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp) { + spin_lock_irq(®ister_lock); dp->max_mididev = max_midi_devs; + spin_unlock_irq(®ister_lock); } /* diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 2e9d695d33..2d707afa1e 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -121,13 +121,13 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid) spin_unlock_irqrestore(&clients_lock, flags); #ifdef CONFIG_MODULES if (!in_interrupt()) { - static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS]; - static char card_requested[SNDRV_CARDS]; + static DECLARE_BITMAP(client_requested, SNDRV_SEQ_GLOBAL_CLIENTS); + static DECLARE_BITMAP(card_requested, SNDRV_CARDS); + if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) { int idx; - if (!client_requested[clientid]) { - client_requested[clientid] = 1; + if (!test_and_set_bit(clientid, client_requested)) { for (idx = 0; idx < 15; idx++) { if (seq_client_load[idx] < 0) break; @@ -142,10 +142,8 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid) int card = (clientid - SNDRV_SEQ_GLOBAL_CLIENTS) / SNDRV_SEQ_CLIENTS_PER_CARD; if (card < snd_ecards_limit) { - if (! card_requested[card]) { - card_requested[card] = 1; + if (!test_and_set_bit(card, card_requested)) snd_request_card(card); - } snd_seq_device_load_drivers(); } } diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 84d7863046..25fcf5a2c7 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -139,7 +139,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, port_subs_info_init(&new_port->c_dest); snd_use_lock_use(&new_port->use_lock); - num = port >= 0 ? port : 0; + num = max(port, 0); mutex_lock(&client->ports_mutex); write_lock_irq(&client->ports_lock); list_for_each_entry(p, &client->ports_list_head, list) { diff --git a/sound/core/timer.c b/sound/core/timer.c index b3214baa89..e08a37c23a 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -83,7 +83,7 @@ struct snd_timer_user { unsigned int filter; struct timespec64 tstamp; /* trigger tstamp */ wait_queue_head_t qchange_sleep; - struct fasync_struct *fasync; + struct snd_fasync *fasync; struct mutex ioctl_lock; }; @@ -1345,7 +1345,7 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri, } __wake: spin_unlock(&tu->qlock); - kill_fasync(&tu->fasync, SIGIO, POLL_IN); + snd_kill_fasync(tu->fasync, SIGIO, POLL_IN); wake_up(&tu->qchange_sleep); } @@ -1383,7 +1383,7 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, spin_lock_irqsave(&tu->qlock, flags); snd_timer_user_append_to_tqueue(tu, &r1); spin_unlock_irqrestore(&tu->qlock, flags); - kill_fasync(&tu->fasync, SIGIO, POLL_IN); + snd_kill_fasync(tu->fasync, SIGIO, POLL_IN); wake_up(&tu->qchange_sleep); } @@ -1453,7 +1453,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, spin_unlock(&tu->qlock); if (append == 0) return; - kill_fasync(&tu->fasync, SIGIO, POLL_IN); + snd_kill_fasync(tu->fasync, SIGIO, POLL_IN); wake_up(&tu->qchange_sleep); } @@ -1521,6 +1521,7 @@ static int snd_timer_user_release(struct inode *inode, struct file *file) snd_timer_instance_free(tu->timeri); } mutex_unlock(&tu->ioctl_lock); + snd_fasync_free(tu->fasync); kfree(tu->queue); kfree(tu->tqueue); kfree(tu); @@ -2135,7 +2136,7 @@ static int snd_timer_user_fasync(int fd, struct file * file, int on) struct snd_timer_user *tu; tu = file->private_data; - return fasync_helper(fd, file, on, &tu->fasync); + return snd_fasync_helper(fd, file, on, &tu->fasync); } static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index ab36f98987..d0f11f3788 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -494,7 +494,8 @@ EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster); * @arg: optional function argument * * Apply the function @func to each follower kctl of the given vmaster kctl. - * Returns 0 if successful, or a negative error code. + * + * Return: 0 if successful, or a negative error code */ int snd_ctl_apply_vmaster_followers(struct snd_kcontrol *kctl, int (*func)(struct snd_kcontrol *vfollower, diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index ca4cdf666f..be3009746f 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -165,6 +165,24 @@ config SND_SERIAL_U16550 To compile this driver as a module, choose M here: the module will be called snd-serial-u16550. +config SND_SERIAL_GENERIC + tristate "Generic serial MIDI driver" + depends on SERIAL_DEV_BUS + depends on OF + select SND_RAWMIDI + help + To include support for mapping generic serial devices as raw + ALSA MIDI devices, say Y here. The driver only supports setting + the serial port to standard baudrates. To attain the standard MIDI + baudrate of 31.25 kBaud, configure the clock of the underlying serial + device so that a requested 38.4 kBaud will result in the standard speed. + + Use this devicetree binding to configure serial port mapping + + + To compile this driver as a module, choose M here: the module + will be called snd-serial-generic. + config SND_MPU401 tristate "Generic MPU-401 UART driver" select SND_MPU401_UART diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index c0fe4eccda..b60303180a 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile @@ -10,6 +10,7 @@ snd-mtpav-objs := mtpav.o snd-mts64-objs := mts64.o snd-portman2x4-objs := portman2x4.o snd-serial-u16550-objs := serial-u16550.o +snd-serial-generic-objs := serial-generic.o snd-virmidi-objs := virmidi.o # Toplevel Module Dependency @@ -17,6 +18,7 @@ obj-$(CONFIG_SND_DUMMY) += snd-dummy.o obj-$(CONFIG_SND_ALOOP) += snd-aloop.o obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o +obj-$(CONFIG_SND_SERIAL_GENERIC) += snd-serial-generic.o obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o obj-$(CONFIG_SND_MTS64) += snd-mts64.o obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index b072392725..a42f66f561 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -14,13 +14,6 @@ #include #include -/* - * maximum HDAC capablities we should parse to avoid endless looping: - * currently we have 4 extended caps, so this is future proof for now. - * extend when this limit is seen meeting in real HW - */ -#define HDAC_MAX_CAPS 10 - /* * processing pipe helpers - these helpers are useful for dealing with HDA * new capability of processing pipelines diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index 71db8592b3..d497414a55 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -183,7 +183,7 @@ static void snd_hdac_bus_process_unsol_events(struct work_struct *work) if (!(caddr & (1 << 4))) /* no unsolicited event? */ continue; codec = bus->caddr_tbl[caddr & 0x0f]; - if (!codec || !codec->dev.driver) + if (!codec || !codec->registered) continue; spin_unlock_irq(&bus->reg_lock); drv = drv_to_hdac_driver(codec->dev.driver); diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index f7bd6e2db0..9a60bfdb39 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -474,11 +474,8 @@ static void azx_int_disable(struct hdac_bus *bus) list_for_each_entry(azx_dev, &bus->stream_list, list) snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0); - /* disable SIE for all streams */ - snd_hdac_chip_writeb(bus, INTCTL, 0); - - /* disable controller CIE and GIE */ - snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN, 0); + /* disable SIE for all streams & disable controller CIE and GIE */ + snd_hdac_chip_writel(bus, INTCTL, 0); } /* clear interrupts */ diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index 3e9e9ac804..b7e5032b61 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -660,6 +660,7 @@ static const struct hda_vendor_id hda_vendor_ids[] = { { 0x14f1, "Conexant" }, { 0x17e8, "Chrontel" }, { 0x1854, "LG" }, + { 0x19e5, "Huawei" }, { 0x1aec, "Wolfson Microelectronics" }, { 0x1af4, "QEMU" }, { 0x434d, "C-Media" }, diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 3f35972e1c..161a9711cd 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -119,21 +119,18 @@ static int i915_component_master_match(struct device *dev, int subcomponent, /* check whether Intel graphics is present and reachable */ static int i915_gfx_present(struct pci_dev *hdac_pci) { - unsigned int class = PCI_BASE_CLASS_DISPLAY << 16; struct pci_dev *display_dev = NULL; - bool match = false; - do { - display_dev = pci_get_class(class, display_dev); - - if (display_dev && display_dev->vendor == PCI_VENDOR_ID_INTEL && + for_each_pci_dev(display_dev) { + if (display_dev->vendor == PCI_VENDOR_ID_INTEL && + (display_dev->class >> 16) == PCI_BASE_CLASS_DISPLAY && connectivity_check(display_dev, hdac_pci)) { pci_dev_put(display_dev); - match = true; + return true; } - } while (!match && display_dev); + } - return match; + return false; } /** diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c index 0d7771fca9..e47de49a32 100644 --- a/sound/hda/hdac_sysfs.c +++ b/sound/hda/hdac_sysfs.c @@ -22,7 +22,7 @@ static ssize_t type##_show(struct device *dev, \ char *buf) \ { \ struct hdac_device *codec = dev_to_hdac_dev(dev); \ - return sprintf(buf, "0x%x\n", codec->type); \ + return sysfs_emit(buf, "0x%x\n", codec->type); \ } \ static DEVICE_ATTR_RO(type) @@ -32,8 +32,8 @@ static ssize_t type##_show(struct device *dev, \ char *buf) \ { \ struct hdac_device *codec = dev_to_hdac_dev(dev); \ - return sprintf(buf, "%s\n", \ - codec->type ? codec->type : ""); \ + return sysfs_emit(buf, "%s\n", \ + codec->type ? codec->type : ""); \ } \ static DEVICE_ATTR_RO(type) @@ -161,7 +161,7 @@ static struct kobj_type widget_ktype = { static ssize_t caps_show(struct hdac_device *codec, hda_nid_t nid, struct widget_attribute *attr, char *buf) { - return sprintf(buf, "0x%08x\n", get_wcaps(codec, nid)); + return sysfs_emit(buf, "0x%08x\n", get_wcaps(codec, nid)); } static ssize_t pin_caps_show(struct hdac_device *codec, hda_nid_t nid, @@ -169,8 +169,8 @@ static ssize_t pin_caps_show(struct hdac_device *codec, hda_nid_t nid, { if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) return 0; - return sprintf(buf, "0x%08x\n", - snd_hdac_read_parm(codec, nid, AC_PAR_PIN_CAP)); + return sysfs_emit(buf, "0x%08x\n", + snd_hdac_read_parm(codec, nid, AC_PAR_PIN_CAP)); } static ssize_t pin_cfg_show(struct hdac_device *codec, hda_nid_t nid, @@ -182,7 +182,7 @@ static ssize_t pin_cfg_show(struct hdac_device *codec, hda_nid_t nid, return 0; if (snd_hdac_read(codec, nid, AC_VERB_GET_CONFIG_DEFAULT, 0, &val)) return 0; - return sprintf(buf, "0x%08x\n", val); + return sysfs_emit(buf, "0x%08x\n", val); } static bool has_pcm_cap(struct hdac_device *codec, hda_nid_t nid) @@ -203,8 +203,8 @@ static ssize_t pcm_caps_show(struct hdac_device *codec, hda_nid_t nid, { if (!has_pcm_cap(codec, nid)) return 0; - return sprintf(buf, "0x%08x\n", - snd_hdac_read_parm(codec, nid, AC_PAR_PCM)); + return sysfs_emit(buf, "0x%08x\n", + snd_hdac_read_parm(codec, nid, AC_PAR_PCM)); } static ssize_t pcm_formats_show(struct hdac_device *codec, hda_nid_t nid, @@ -212,8 +212,8 @@ static ssize_t pcm_formats_show(struct hdac_device *codec, hda_nid_t nid, { if (!has_pcm_cap(codec, nid)) return 0; - return sprintf(buf, "0x%08x\n", - snd_hdac_read_parm(codec, nid, AC_PAR_STREAM)); + return sysfs_emit(buf, "0x%08x\n", + snd_hdac_read_parm(codec, nid, AC_PAR_STREAM)); } static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid, @@ -221,8 +221,8 @@ static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid, { if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) return 0; - return sprintf(buf, "0x%08x\n", - snd_hdac_read_parm(codec, nid, AC_PAR_AMP_IN_CAP)); + return sysfs_emit(buf, "0x%08x\n", + snd_hdac_read_parm(codec, nid, AC_PAR_AMP_IN_CAP)); } static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid, @@ -230,8 +230,8 @@ static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid, { if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) return 0; - return sprintf(buf, "0x%08x\n", - snd_hdac_read_parm(codec, nid, AC_PAR_AMP_OUT_CAP)); + return sysfs_emit(buf, "0x%08x\n", + snd_hdac_read_parm(codec, nid, AC_PAR_AMP_OUT_CAP)); } static ssize_t power_caps_show(struct hdac_device *codec, hda_nid_t nid, @@ -239,15 +239,15 @@ static ssize_t power_caps_show(struct hdac_device *codec, hda_nid_t nid, { if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_POWER)) return 0; - return sprintf(buf, "0x%08x\n", - snd_hdac_read_parm(codec, nid, AC_PAR_POWER_STATE)); + return sysfs_emit(buf, "0x%08x\n", + snd_hdac_read_parm(codec, nid, AC_PAR_POWER_STATE)); } static ssize_t gpio_caps_show(struct hdac_device *codec, hda_nid_t nid, struct widget_attribute *attr, char *buf) { - return sprintf(buf, "0x%08x\n", - snd_hdac_read_parm(codec, nid, AC_PAR_GPIO_CAP)); + return sysfs_emit(buf, "0x%08x\n", + snd_hdac_read_parm(codec, nid, AC_PAR_GPIO_CAP)); } static ssize_t connections_show(struct hdac_device *codec, hda_nid_t nid, @@ -261,8 +261,8 @@ static ssize_t connections_show(struct hdac_device *codec, hda_nid_t nid, if (nconns <= 0) return nconns; for (i = 0; i < nconns; i++) - ret += sprintf(buf + ret, "%s0x%02x", i ? " " : "", list[i]); - ret += sprintf(buf + ret, "\n"); + ret += sysfs_emit_at(buf, ret, "%s0x%02x", i ? " " : "", list[i]); + ret += sysfs_emit_at(buf, ret, "\n"); return ret; } diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index a8fe01764b..d84ffdf472 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -196,6 +196,12 @@ static const struct config_entry config_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), } }, + { + .ident = "UP-WHL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), + } + }, {} } }, @@ -358,6 +364,12 @@ static const struct config_entry config_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), } }, + { + .ident = "UPX-TGL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), + } + }, {} } }, @@ -401,6 +413,11 @@ static const struct config_entry config_table[] = { .device = 0x7a50, }, /* Alderlake-P */ + { + .flags = FLAG_SOF, + .device = 0x51c8, + .codec_hid = &essx_83x6, + }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = 0x51c8, diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index 4063da3782..13bb0ccfb3 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -55,20 +55,26 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) /* find max number of channels based on format_configuration */ if (fmt_configs->fmt_count) { - dev_dbg(dev, "%s: found %d format definitions\n", - __func__, fmt_configs->fmt_count); + struct nhlt_fmt_cfg *fmt_cfg = fmt_configs->fmt_config; + + dev_dbg(dev, "found %d format definitions\n", + fmt_configs->fmt_count); for (i = 0; i < fmt_configs->fmt_count; i++) { struct wav_fmt_ext *fmt_ext; - fmt_ext = &fmt_configs->fmt_config[i].fmt_ext; + fmt_ext = &fmt_cfg->fmt_ext; if (fmt_ext->fmt.channels > max_ch) max_ch = fmt_ext->fmt.channels; + + /* Move to the next nhlt_fmt_cfg */ + fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps + + fmt_cfg->config.size); } - dev_dbg(dev, "%s: max channels found %d\n", __func__, max_ch); + dev_dbg(dev, "max channels found %d\n", max_ch); } else { - dev_dbg(dev, "%s: No format information found\n", __func__); + dev_dbg(dev, "No format information found\n"); } if (cfg->device_config.config_type != NHLT_CONFIG_TYPE_MIC_ARRAY) { @@ -95,17 +101,16 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) } if (dmic_geo > 0) { - dev_dbg(dev, "%s: Array with %d dmics\n", __func__, dmic_geo); + dev_dbg(dev, "Array with %d dmics\n", dmic_geo); } if (max_ch > dmic_geo) { - dev_dbg(dev, "%s: max channels %d exceed dmic number %d\n", - __func__, max_ch, dmic_geo); + dev_dbg(dev, "max channels %d exceed dmic number %d\n", + max_ch, dmic_geo); } } } - dev_dbg(dev, "%s: dmic number %d max_ch %d\n", - __func__, dmic_geo, max_ch); + dev_dbg(dev, "dmic number %d max_ch %d\n", dmic_geo, max_ch); return dmic_geo; } diff --git a/sound/hda/trace.h b/sound/hda/trace.h index 70af6c8150..2cc493434a 100644 --- a/sound/hda/trace.h +++ b/sound/hda/trace.h @@ -19,37 +19,48 @@ struct hdac_codec; TRACE_EVENT(hda_send_cmd, TP_PROTO(struct hdac_bus *bus, unsigned int cmd), TP_ARGS(bus, cmd), - TP_STRUCT__entry(__dynamic_array(char, msg, HDAC_MSG_MAX)), + TP_STRUCT__entry( + __string(name, dev_name((bus)->dev)) + __field(u32, cmd) + ), TP_fast_assign( - snprintf(__get_str(msg), HDAC_MSG_MAX, - "[%s:%d] val=0x%08x", - dev_name((bus)->dev), (cmd) >> 28, cmd); + __assign_str(name, dev_name((bus)->dev)); + __entry->cmd = cmd; ), - TP_printk("%s", __get_str(msg)) + TP_printk("[%s:%d] val=0x%08x", __get_str(name), __entry->cmd >> 28, __entry->cmd) ); TRACE_EVENT(hda_get_response, TP_PROTO(struct hdac_bus *bus, unsigned int addr, unsigned int res), TP_ARGS(bus, addr, res), - TP_STRUCT__entry(__dynamic_array(char, msg, HDAC_MSG_MAX)), + TP_STRUCT__entry( + __string(name, dev_name((bus)->dev)) + __field(u32, addr) + __field(u32, res) + ), TP_fast_assign( - snprintf(__get_str(msg), HDAC_MSG_MAX, - "[%s:%d] val=0x%08x", - dev_name((bus)->dev), addr, res); + __assign_str(name, dev_name((bus)->dev)); + __entry->addr = addr; + __entry->res = res; ), - TP_printk("%s", __get_str(msg)) + TP_printk("[%s:%d] val=0x%08x", __get_str(name), __entry->addr, __entry->res) ); TRACE_EVENT(hda_unsol_event, TP_PROTO(struct hdac_bus *bus, u32 res, u32 res_ex), TP_ARGS(bus, res, res_ex), - TP_STRUCT__entry(__dynamic_array(char, msg, HDAC_MSG_MAX)), + TP_STRUCT__entry( + __string(name, dev_name((bus)->dev)) + __field(u32, res) + __field(u32, res_ex) + ), TP_fast_assign( - snprintf(__get_str(msg), HDAC_MSG_MAX, - "[%s:%d] res=0x%08x, res_ex=0x%08x", - dev_name((bus)->dev), res_ex & 0x0f, res, res_ex); + __assign_str(name, dev_name((bus)->dev)); + __entry->res = res; + __entry->res_ex = res_ex; ), - TP_printk("%s", __get_str(msg)) + TP_printk("[%s:%d] res=0x%08x, res_ex=0x%08x", __get_str(name), + __entry->res_ex & 0x0f, __entry->res, __entry->res_ex) ); DECLARE_EVENT_CLASS(hdac_stream, diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 570b88e0b2..6ffa48dd59 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -22,7 +22,7 @@ config SND_SB16_DSP menuconfig SND_ISA bool "ISA sound devices" depends on ISA || COMPILE_TEST - depends on ISA_DMA_API && !M68K + depends on ISA_DMA_API default y help Support for sound devices connected via the ISA bus. diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index 69cbc79fbb..13ce96148f 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -581,8 +581,6 @@ demunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes) int i; unsigned char *end = src + src_bytes; - end = src + src_bytes; - /* NOTE: src and dst *CAN* point to the same address */ for (i = 0; src != end; i++) { @@ -1094,7 +1092,8 @@ wavefront_send_sample (snd_wavefront_t *dev, if (dataptr < data_end) { - __get_user (sample_short, dataptr); + if (get_user(sample_short, dataptr)) + return -EFAULT; dataptr += skip; if (data_is_unsigned) { /* GUS ? */ diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c index aa4d063531..88d902997b 100644 --- a/sound/pci/asihpi/hpi6000.c +++ b/sound/pci/asihpi/hpi6000.c @@ -388,7 +388,7 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr) /* SUBSYSTEM */ /* create an adapter object and initialise it based on resource information - * passed in in the message + * passed in the message * NOTE - you cannot use this function AND the FindAdapters function at the * same time, the application must use only one of them to get the adapters */ diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c index 3d6914c64c..27e11b5f70 100644 --- a/sound/pci/asihpi/hpi6205.c +++ b/sound/pci/asihpi/hpi6205.c @@ -445,7 +445,7 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr) /* SUBSYSTEM */ /** Create an adapter object and initialise it based on resource information - * passed in in the message + * passed in the message * *** NOTE - you cannot use this function AND the FindAdapters function at the * same time, the application must use only one of them to get the adapters *** */ diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index bd60308769..8634004a60 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -74,36 +74,36 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci, err = snd_cs46xx_create(card, pci, external_amp[dev], thinkpad[dev]); if (err < 0) - return err; + goto error; card->private_data = chip; chip->accept_valid = mmap_valid[dev]; err = snd_cs46xx_pcm(chip, 0); if (err < 0) - return err; + goto error; #ifdef CONFIG_SND_CS46XX_NEW_DSP err = snd_cs46xx_pcm_rear(chip, 1); if (err < 0) - return err; + goto error; err = snd_cs46xx_pcm_iec958(chip, 2); if (err < 0) - return err; + goto error; #endif err = snd_cs46xx_mixer(chip, 2); if (err < 0) - return err; + goto error; #ifdef CONFIG_SND_CS46XX_NEW_DSP if (chip->nr_ac97_codecs ==2) { err = snd_cs46xx_pcm_center_lfe(chip, 3); if (err < 0) - return err; + goto error; } #endif err = snd_cs46xx_midi(chip, 0); if (err < 0) - return err; + goto error; err = snd_cs46xx_start_dsp(chip); if (err < 0) - return err; + goto error; snd_cs46xx_gameport(chip); @@ -117,11 +117,15 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci, err = snd_card_register(card); if (err < 0) - return err; + goto error; pci_set_drvdata(pci, card); dev++; return 0; + + error: + snd_card_free(card); + return err; } static struct pci_driver cs46xx_driver = { diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 5ff10fec7b..0db24cc4d9 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -129,7 +129,7 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au, return 0; /* the u32 cast is okay because in snd*create we successfully told - pci alloc that we're only 32 bit capable so the uppper will be 0 */ + pci alloc that we're only 32 bit capable so the upper will be 0 */ addr = (u32) substream->runtime->dma_addr; desc_addr = (u32) dma->desc_buf.addr; for (i = 0; i < periods; i++) { diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 78f35e88ae..fbdb8a3d5b 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -36,6 +36,7 @@ | ((IEC958_AES3_CON_FS_48000) << 24)) static const struct snd_pci_quirk subsys_20k1_list[] = { + SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0021, "SB046x", CTSB046X), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X), @@ -64,6 +65,7 @@ static const struct snd_pci_quirk subsys_20k2_list[] = { static const char *ct_subsys_name[NUM_CTCARDS] = { /* 20k1 models */ + [CTSB046X] = "SB046x", [CTSB055X] = "SB055x", [CTSB073X] = "SB073x", [CTUAA] = "UAA", diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h index f406b626a2..2875cec83b 100644 --- a/sound/pci/ctxfi/cthardware.h +++ b/sound/pci/ctxfi/cthardware.h @@ -26,8 +26,9 @@ enum CHIPTYP { enum CTCARDS { /* 20k1 models */ + CTSB046X, + CT20K1_MODEL_FIRST = CTSB046X, CTSB055X, - CT20K1_MODEL_FIRST = CTSB055X, CTSB073X, CTUAA, CT20K1_UNKNOWN, diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 0cea4982ed..9edbf5d8c3 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -1916,7 +1916,7 @@ static int hw_card_start(struct hw *hw) } - /* Switch to X-Fi mode from UAA mode if neeeded */ + /* Switch to X-Fi mode from UAA mode if needed */ if (hw->model == CTUAA) { err = uaa_to_xfi(pci); if (err) diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index 7be5c3327b..47b2c023ee 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -124,7 +124,6 @@ static int midi_service_irq(struct echoaudio *chip) return 0; /* Get the MIDI data from the comm page */ - i = 1; received = 0; for (i = 1; i <= count; i++) { /* Get the MIDI byte */ diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 86cc1ca025..3880f359e6 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1751,11 +1751,8 @@ static void snd_emu10k1_detect_iommu(struct snd_emu10k1 *emu) emu->iommu_workaround = false; - if (!iommu_present(emu->card->dev->bus)) - return; - domain = iommu_get_domain_for_dev(emu->card->dev); - if (domain && domain->type == IOMMU_DOMAIN_IDENTITY) + if (!domain || domain->type == IOMMU_DOMAIN_IDENTITY) return; dev_notice(emu->card->dev, diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 9d26535f3f..edb3f17637 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -324,7 +324,7 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst return NULL; } /* fill buffer addresses but pointers are not stored so that - * snd_free_pci_page() is not called in in synth_free() + * snd_free_pci_page() is not called in synth_free() */ idx = 0; for (page = blk->first_page; page <= blk->last_page; page++, idx++) { diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 94efe347a9..89210b2c73 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -8,7 +8,7 @@ /* Power-Management-Code ( CONFIG_PM ) * for ens1371 only ( FIXME ) * derived from cs4281.c, atiixp.c and via82xx.c - * using http://www.alsa-project.org/~tiwai/writing-an-alsa-driver/ + * using https://www.kernel.org/doc/html/latest/sound/kernel-api/writing-an-alsa-driver.html * by Kurt J. Bosch */ diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 9f6c99c1d8..a8e8cf98be 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -93,15 +93,21 @@ config SND_HDA_PATCH_LOADER config SND_HDA_SCODEC_CS35L41 tristate + select SND_HDA_GENERIC + select REGMAP_IRQ + +config SND_HDA_CS_DSP_CONTROLS + tristate + select CS_DSP config SND_HDA_SCODEC_CS35L41_I2C tristate "Build CS35L41 HD-audio side codec support for I2C Bus" depends on I2C depends on ACPI depends on SND_SOC - select SND_HDA_GENERIC select SND_SOC_CS35L41_LIB select SND_HDA_SCODEC_CS35L41 + select SND_HDA_CS_DSP_CONTROLS help Say Y or M here to include CS35L41 I2C HD-audio side codec support in snd-hda-intel driver, such as ALC287. @@ -114,9 +120,9 @@ config SND_HDA_SCODEC_CS35L41_SPI depends on SPI_MASTER depends on ACPI depends on SND_SOC - select SND_HDA_GENERIC select SND_SOC_CS35L41_LIB select SND_HDA_SCODEC_CS35L41 + select SND_HDA_CS_DSP_CONTROLS help Say Y or M here to include CS35L41 SPI HD-audio side codec support in snd-hda-intel driver, such as ALC287. diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 3e7bc608d4..00d3061044 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -31,6 +31,7 @@ snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o snd-hda-scodec-cs35l41-objs := cs35l41_hda.o snd-hda-scodec-cs35l41-i2c-objs := cs35l41_hda_i2c.o snd-hda-scodec-cs35l41-spi-objs := cs35l41_hda_spi.o +snd-hda-cs-dsp-ctls-objs := hda_cs_dsp_ctl.o # common driver obj-$(CONFIG_SND_HDA) := snd-hda-codec.o @@ -54,6 +55,7 @@ obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o +obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o # this must be the last entry after codec drivers; # otherwise the codec patches won't be hooked before the PCI probe diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 7185953808..15e2a00090 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -8,181 +8,828 @@ #include #include +#include #include +#include +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" #include "hda_generic.h" #include "hda_component.h" #include "cs35l41_hda.h" +#include "hda_cs_dsp_ctl.h" + +#define CS35L41_FIRMWARE_ROOT "cirrus/" +#define CS35L41_PART "cs35l41" + +#define HALO_STATE_DSP_CTL_NAME "HALO_STATE" +#define HALO_STATE_DSP_CTL_TYPE 5 +#define HALO_STATE_DSP_CTL_ALG 262308 +#define CAL_R_DSP_CTL_NAME "CAL_R" +#define CAL_STATUS_DSP_CTL_NAME "CAL_STATUS" +#define CAL_CHECKSUM_DSP_CTL_NAME "CAL_CHECKSUM" +#define CAL_AMBIENT_DSP_CTL_NAME "CAL_AMBIENT" +#define CAL_DSP_CTL_TYPE 5 +#define CAL_DSP_CTL_ALG 205 + +static bool firmware_autostart = 1; +module_param(firmware_autostart, bool, 0444); +MODULE_PARM_DESC(firmware_autostart, "Allow automatic firmware download on boot" + "(0=Disable, 1=Enable) (default=1); "); static const struct reg_sequence cs35l41_hda_config[] = { - { CS35L41_PLL_CLK_CTRL, 0x00000430 }, // 3200000Hz, BCLK Input, PLL_REFCLK_EN = 1 + { CS35L41_PLL_CLK_CTRL, 0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1 + { CS35L41_DSP_CLK_CTRL, 0x00000003 }, // DSP CLK EN { CS35L41_GLOBAL_CLK_CTRL, 0x00000003 }, // GLOBAL_FS = 48 kHz { CS35L41_SP_ENABLES, 0x00010000 }, // ASP_RX1_EN = 1 { CS35L41_SP_RATE_CTRL, 0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz - { CS35L41_SP_FORMAT, 0x20200200 }, // 24 bits, I2S, BCLK Slave, FSYNC Slave + { CS35L41_SP_FORMAT, 0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer + { CS35L41_SP_HIZ_CTRL, 0x00000002 }, // Hi-Z unused + { CS35L41_SP_TX_WL, 0x00000018 }, // 24 cycles/slot + { CS35L41_SP_RX_WL, 0x00000018 }, // 24 cycles/slot { CS35L41_DAC_PCM1_SRC, 0x00000008 }, // DACPCM1_SRC = ASPRX1 + { CS35L41_ASP_TX1_SRC, 0x00000018 }, // ASPTX1 SRC = VMON + { CS35L41_ASP_TX2_SRC, 0x00000019 }, // ASPTX2 SRC = IMON + { CS35L41_ASP_TX3_SRC, 0x00000032 }, // ASPTX3 SRC = ERRVOL + { CS35L41_ASP_TX4_SRC, 0x00000033 }, // ASPTX4 SRC = CLASSH_TGT + { CS35L41_DSP1_RX1_SRC, 0x00000008 }, // DSP1RX1 SRC = ASPRX1 + { CS35L41_DSP1_RX2_SRC, 0x00000009 }, // DSP1RX2 SRC = ASPRX2 + { CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON + { CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON + { CS35L41_DSP1_RX5_SRC, 0x00000020 }, // DSP1RX5 SRC = ERRVOL { CS35L41_AMP_DIG_VOL_CTRL, 0x00000000 }, // AMP_VOL_PCM 0.0 dB { CS35L41_AMP_GAIN_CTRL, 0x00000084 }, // AMP_GAIN_PCM 4.5 dB - { CS35L41_PWR_CTRL2, 0x00000001 }, // AMP_EN = 1 }; -static const struct reg_sequence cs35l41_hda_start_bst[] = { - { CS35L41_PWR_CTRL2, 0x00000021 }, // BST_EN = 10, AMP_EN = 1 - { CS35L41_PWR_CTRL1, 0x00000001, 3000}, // set GLOBAL_EN = 1 +static const struct reg_sequence cs35l41_hda_config_dsp[] = { + { CS35L41_PLL_CLK_CTRL, 0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1 + { CS35L41_DSP_CLK_CTRL, 0x00000003 }, // DSP CLK EN + { CS35L41_GLOBAL_CLK_CTRL, 0x00000003 }, // GLOBAL_FS = 48 kHz + { CS35L41_SP_ENABLES, 0x00010001 }, // ASP_RX1_EN = 1, ASP_TX1_EN = 1 + { CS35L41_SP_RATE_CTRL, 0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz + { CS35L41_SP_FORMAT, 0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer + { CS35L41_SP_HIZ_CTRL, 0x00000003 }, // Hi-Z unused/disabled + { CS35L41_SP_TX_WL, 0x00000018 }, // 24 cycles/slot + { CS35L41_SP_RX_WL, 0x00000018 }, // 24 cycles/slot + { CS35L41_DAC_PCM1_SRC, 0x00000032 }, // DACPCM1_SRC = ERR_VOL + { CS35L41_ASP_TX1_SRC, 0x00000018 }, // ASPTX1 SRC = VMON + { CS35L41_ASP_TX2_SRC, 0x00000019 }, // ASPTX2 SRC = IMON + { CS35L41_ASP_TX3_SRC, 0x00000028 }, // ASPTX3 SRC = VPMON + { CS35L41_ASP_TX4_SRC, 0x00000029 }, // ASPTX4 SRC = VBSTMON + { CS35L41_DSP1_RX1_SRC, 0x00000008 }, // DSP1RX1 SRC = ASPRX1 + { CS35L41_DSP1_RX2_SRC, 0x00000008 }, // DSP1RX2 SRC = ASPRX1 + { CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON + { CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON + { CS35L41_DSP1_RX5_SRC, 0x00000029 }, // DSP1RX5 SRC = VBSTMON + { CS35L41_AMP_DIG_VOL_CTRL, 0x00000000 }, // AMP_VOL_PCM 0.0 dB + { CS35L41_AMP_GAIN_CTRL, 0x00000233 }, // AMP_GAIN_PCM = 17.5dB AMP_GAIN_PDM = 19.5dB }; -static const struct reg_sequence cs35l41_hda_stop_bst[] = { - { CS35L41_PWR_CTRL1, 0x00000000, 3000}, // set GLOBAL_EN = 0 +static const struct reg_sequence cs35l41_hda_mute[] = { + { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, // AMP_GAIN_PCM 0.5 dB + { CS35L41_AMP_DIG_VOL_CTRL, 0x0000A678 }, // AMP_VOL_PCM Mute }; -// only on amps where GPIO1 is used to control ext. VSPK switch -static const struct reg_sequence cs35l41_start_ext_vspk[] = { - { 0x00000040, 0x00000055 }, - { 0x00000040, 0x000000AA }, - { 0x00007438, 0x00585941 }, - { 0x00007414, 0x08C82222 }, - { 0x0000742C, 0x00000009 }, - { 0x00011008, 0x00008001 }, - { 0x0000742C, 0x0000000F }, - { 0x0000742C, 0x00000079 }, - { 0x00007438, 0x00585941 }, - { CS35L41_PWR_CTRL1, 0x00000001, 3000}, // set GLOBAL_EN = 1 - { 0x0000742C, 0x000000F9 }, - { 0x00007438, 0x00580941 }, - { 0x00000040, 0x000000CC }, - { 0x00000040, 0x00000033 }, -}; +static int cs35l41_control_add(struct cs_dsp_coeff_ctl *cs_ctl) +{ + struct cs35l41_hda *cs35l41 = container_of(cs_ctl->dsp, struct cs35l41_hda, cs_dsp); + struct hda_cs_dsp_ctl_info info; -//only on amps where GPIO1 is used to control ext. VSPK switch -static const struct reg_sequence cs35l41_stop_ext_vspk[] = { - { 0x00000040, 0x00000055 }, - { 0x00000040, 0x000000AA }, - { 0x00007438, 0x00585941 }, - { 0x00002014, 0x00000000, 3000}, // set GLOBAL_EN = 0 - { 0x0000742C, 0x00000009 }, - { 0x00007438, 0x00580941 }, - { 0x00011008, 0x00000001 }, - { 0x0000393C, 0x000000C0, 6000}, - { 0x0000393C, 0x00000000 }, - { 0x00007414, 0x00C82222 }, - { 0x0000742C, 0x00000000 }, - { 0x00000040, 0x000000CC }, - { 0x00000040, 0x00000033 }, -}; + info.device_name = cs35l41->amp_name; + info.fw_type = cs35l41->firmware_type; + info.card = cs35l41->codec->card; -static const struct reg_sequence cs35l41_safe_to_active[] = { - { 0x00000040, 0x00000055 }, - { 0x00000040, 0x000000AA }, - { 0x0000742C, 0x0000000F }, - { 0x0000742C, 0x00000079 }, - { 0x00007438, 0x00585941 }, - { CS35L41_PWR_CTRL1, 0x00000001, 2000 }, // GLOBAL_EN = 1 - { 0x0000742C, 0x000000F9 }, - { 0x00007438, 0x00580941 }, - { 0x00000040, 0x000000CC }, - { 0x00000040, 0x00000033 }, -}; + return hda_cs_dsp_control_add(cs_ctl, &info); +} -static const struct reg_sequence cs35l41_active_to_safe[] = { - { 0x00000040, 0x00000055 }, - { 0x00000040, 0x000000AA }, - { 0x00007438, 0x00585941 }, - { CS35L41_AMP_DIG_VOL_CTRL, 0x0000A678 }, // AMP_VOL_PCM Mute - { CS35L41_PWR_CTRL2, 0x00000000 }, // AMP_EN = 0 - { CS35L41_PWR_CTRL1, 0x00000000 }, - { 0x0000742C, 0x00000009, 2000 }, - { 0x00007438, 0x00580941 }, - { 0x00000040, 0x000000CC }, - { 0x00000040, 0x00000033 }, +static const struct cs_dsp_client_ops client_ops = { + .control_add = cs35l41_control_add, + .control_remove = hda_cs_dsp_control_remove, }; -static const struct reg_sequence cs35l41_reset_to_safe[] = { - { 0x00000040, 0x00000055 }, - { 0x00000040, 0x000000AA }, - { 0x00007438, 0x00585941 }, - { 0x00007414, 0x08C82222 }, - { 0x0000742C, 0x00000009 }, - { 0x00000040, 0x000000CC }, - { 0x00000040, 0x00000033 }, -}; +static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41, + const struct firmware **firmware, char **filename, + const char *dir, const char *ssid, const char *amp_name, + int spkid, const char *filetype) +{ + const char * const dsp_name = cs35l41->cs_dsp.name; + char *s, c; + int ret = 0; -static const struct cs35l41_hda_reg_sequence cs35l41_hda_reg_seq_no_bst = { - .probe = cs35l41_reset_to_safe, - .num_probe = ARRAY_SIZE(cs35l41_reset_to_safe), - .open = cs35l41_hda_config, - .num_open = ARRAY_SIZE(cs35l41_hda_config), - .prepare = cs35l41_safe_to_active, - .num_prepare = ARRAY_SIZE(cs35l41_safe_to_active), - .cleanup = cs35l41_active_to_safe, - .num_cleanup = ARRAY_SIZE(cs35l41_active_to_safe), -}; + if (spkid > -1 && ssid && amp_name) + *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-spkid%d-%s.%s", dir, CS35L41_PART, + dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + ssid, spkid, amp_name, filetype); + else if (spkid > -1 && ssid) + *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-spkid%d.%s", dir, CS35L41_PART, + dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + ssid, spkid, filetype); + else if (ssid && amp_name) + *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, CS35L41_PART, + dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + ssid, amp_name, filetype); + else if (ssid) + *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, CS35L41_PART, + dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + ssid, filetype); + else + *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, CS35L41_PART, + dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + filetype); + + if (*filename == NULL) + return -ENOMEM; -static const struct cs35l41_hda_reg_sequence cs35l41_hda_reg_seq_ext_bst = { - .open = cs35l41_hda_config, - .num_open = ARRAY_SIZE(cs35l41_hda_config), - .prepare = cs35l41_start_ext_vspk, - .num_prepare = ARRAY_SIZE(cs35l41_start_ext_vspk), - .cleanup = cs35l41_stop_ext_vspk, - .num_cleanup = ARRAY_SIZE(cs35l41_stop_ext_vspk), -}; + /* + * Make sure that filename is lower-case and any non alpha-numeric + * characters except full stop and '/' are replaced with hyphens. + */ + s = *filename; + while (*s) { + c = *s; + if (isalnum(c)) + *s = tolower(c); + else if (c != '.' && c != '/') + *s = '-'; + s++; + } -static const struct cs35l41_hda_reg_sequence cs35l41_hda_reg_seq_int_bst = { - .open = cs35l41_hda_config, - .num_open = ARRAY_SIZE(cs35l41_hda_config), - .prepare = cs35l41_hda_start_bst, - .num_prepare = ARRAY_SIZE(cs35l41_hda_start_bst), - .cleanup = cs35l41_hda_stop_bst, - .num_cleanup = ARRAY_SIZE(cs35l41_hda_stop_bst), -}; + ret = firmware_request_nowarn(firmware, *filename, cs35l41->dev); + if (ret != 0) { + dev_dbg(cs35l41->dev, "Failed to request '%s'\n", *filename); + kfree(*filename); + *filename = NULL; + } + + return ret; +} + +static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41, + const struct firmware **wmfw_firmware, + char **wmfw_filename, + const struct firmware **coeff_firmware, + char **coeff_filename) +{ + int ret; + + /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.wmfw */ + ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, + CS35L41_FIRMWARE_ROOT, + cs35l41->acpi_subsystem_id, cs35l41->amp_name, + cs35l41->speaker_id, "wmfw"); + if (!ret) { + /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */ + cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, + CS35L41_FIRMWARE_ROOT, + cs35l41->acpi_subsystem_id, cs35l41->amp_name, + cs35l41->speaker_id, "bin"); + return 0; + } + + /* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */ + ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, + CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, + cs35l41->amp_name, -1, "wmfw"); + if (!ret) { + /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */ + cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, + CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, + cs35l41->amp_name, cs35l41->speaker_id, "bin"); + return 0; + } + + /* try cirrus/part-dspN-fwtype-sub<-spkidN>.wmfw */ + ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, + CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, + NULL, cs35l41->speaker_id, "wmfw"); + if (!ret) { + /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */ + ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, + CS35L41_FIRMWARE_ROOT, + cs35l41->acpi_subsystem_id, + cs35l41->amp_name, cs35l41->speaker_id, "bin"); + if (ret) + /* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */ + cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, + CS35L41_FIRMWARE_ROOT, + cs35l41->acpi_subsystem_id, + NULL, cs35l41->speaker_id, "bin"); + return 0; + } + + /* try cirrus/part-dspN-fwtype-sub.wmfw */ + ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, + CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, + NULL, -1, "wmfw"); + if (!ret) { + /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */ + ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, + CS35L41_FIRMWARE_ROOT, + cs35l41->acpi_subsystem_id, + cs35l41->amp_name, cs35l41->speaker_id, "bin"); + if (ret) + /* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */ + cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, + CS35L41_FIRMWARE_ROOT, + cs35l41->acpi_subsystem_id, + NULL, cs35l41->speaker_id, "bin"); + return 0; + } + + /* fallback try cirrus/part-dspN-fwtype.wmfw */ + ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, + CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "wmfw"); + if (!ret) { + /* fallback try cirrus/part-dspN-fwtype.bin */ + cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, + CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "bin"); + return 0; + } + + dev_warn(cs35l41->dev, "Failed to request firmware\n"); + + return ret; +} + +static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41, + const struct firmware **wmfw_firmware, + char **wmfw_filename, + const struct firmware **coeff_firmware, + char **coeff_filename) +{ + int ret; + + if (cs35l41->speaker_id > -1) + return cs35l41_request_firmware_files_spkid(cs35l41, wmfw_firmware, wmfw_filename, + coeff_firmware, coeff_filename); + + /* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */ + ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, + CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, + cs35l41->amp_name, -1, "wmfw"); + if (!ret) { + /* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */ + cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, + CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, + cs35l41->amp_name, -1, "bin"); + return 0; + } + + /* try cirrus/part-dspN-fwtype-sub.wmfw */ + ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, + CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, + NULL, -1, "wmfw"); + if (!ret) { + /* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */ + ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, + CS35L41_FIRMWARE_ROOT, + cs35l41->acpi_subsystem_id, + cs35l41->amp_name, -1, "bin"); + if (ret) + /* try cirrus/part-dspN-fwtype-sub.bin */ + cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, + CS35L41_FIRMWARE_ROOT, + cs35l41->acpi_subsystem_id, + NULL, -1, "bin"); + return 0; + } + + /* fallback try cirrus/part-dspN-fwtype.wmfw */ + ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, + CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "wmfw"); + if (!ret) { + /* fallback try cirrus/part-dspN-fwtype.bin */ + cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, + CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "bin"); + return 0; + } + + dev_warn(cs35l41->dev, "Failed to request firmware\n"); + + return ret; +} + +#if IS_ENABLED(CONFIG_EFI) +static int cs35l41_apply_calibration(struct cs35l41_hda *cs35l41, unsigned int ambient, + unsigned int r0, unsigned int status, unsigned int checksum) +{ + int ret; + + ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_AMBIENT_DSP_CTL_NAME, CAL_DSP_CTL_TYPE, + CAL_DSP_CTL_ALG, &ambient, 4); + if (ret) { + dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_AMBIENT_DSP_CTL_NAME, + ret); + return ret; + } + ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_R_DSP_CTL_NAME, CAL_DSP_CTL_TYPE, + CAL_DSP_CTL_ALG, &r0, 4); + if (ret) { + dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_R_DSP_CTL_NAME, ret); + return ret; + } + ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_STATUS_DSP_CTL_NAME, CAL_DSP_CTL_TYPE, + CAL_DSP_CTL_ALG, &status, 4); + if (ret) { + dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_STATUS_DSP_CTL_NAME, + ret); + return ret; + } + ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_CHECKSUM_DSP_CTL_NAME, CAL_DSP_CTL_TYPE, + CAL_DSP_CTL_ALG, &checksum, 4); + if (ret) { + dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_CHECKSUM_DSP_CTL_NAME, + ret); + return ret; + } + + return 0; +} + +static int cs35l41_save_calibration(struct cs35l41_hda *cs35l41) +{ + static efi_guid_t efi_guid = EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, + 0x5a, 0xa3, 0x5d, 0xb3); + static efi_char16_t efi_name[] = L"CirrusSmartAmpCalibrationData"; + const struct cs35l41_amp_efi_data *efi_data; + const struct cs35l41_amp_cal_data *cl; + unsigned long data_size = 0; + efi_status_t status; + int ret = 0; + u8 *data = NULL; + u32 attr; + + /* Get real size of UEFI variable */ + status = efi.get_variable(efi_name, &efi_guid, &attr, &data_size, data); + if (status == EFI_BUFFER_TOO_SMALL) { + ret = -ENODEV; + /* Allocate data buffer of data_size bytes */ + data = vmalloc(data_size); + if (!data) + return -ENOMEM; + /* Get variable contents into buffer */ + status = efi.get_variable(efi_name, &efi_guid, &attr, &data_size, data); + if (status == EFI_SUCCESS) { + efi_data = (struct cs35l41_amp_efi_data *)data; + dev_dbg(cs35l41->dev, "Calibration: Size=%d, Amp Count=%d\n", + efi_data->size, efi_data->count); + if (efi_data->count > cs35l41->index) { + cl = &efi_data->data[cs35l41->index]; + dev_dbg(cs35l41->dev, + "Calibration: Ambient=%02x, Status=%02x, R0=%d\n", + cl->calAmbient, cl->calStatus, cl->calR); + + /* Calibration can only be applied whilst the DSP is not running */ + ret = cs35l41_apply_calibration(cs35l41, + cpu_to_be32(cl->calAmbient), + cpu_to_be32(cl->calR), + cpu_to_be32(cl->calStatus), + cpu_to_be32(cl->calR + 1)); + } + } + vfree(data); + } + return ret; +} +#else +static int cs35l41_save_calibration(struct cs35l41_hda *cs35l41) +{ + dev_warn(cs35l41->dev, "Calibration not supported without EFI support.\n"); + return 0; +} +#endif + +static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41) +{ + const struct firmware *coeff_firmware = NULL; + const struct firmware *wmfw_firmware = NULL; + struct cs_dsp *dsp = &cs35l41->cs_dsp; + char *coeff_filename = NULL; + char *wmfw_filename = NULL; + int ret; + + if (!cs35l41->halo_initialized) { + cs35l41_configure_cs_dsp(cs35l41->dev, cs35l41->regmap, dsp); + dsp->client_ops = &client_ops; + + ret = cs_dsp_halo_init(&cs35l41->cs_dsp); + if (ret) + return ret; + cs35l41->halo_initialized = true; + } + + ret = cs35l41_request_firmware_files(cs35l41, &wmfw_firmware, &wmfw_filename, + &coeff_firmware, &coeff_filename); + if (ret < 0) + return ret; + + dev_dbg(cs35l41->dev, "Loading WMFW Firmware: %s\n", wmfw_filename); + if (coeff_filename) + dev_dbg(cs35l41->dev, "Loading Coefficient File: %s\n", coeff_filename); + else + dev_warn(cs35l41->dev, "No Coefficient File available.\n"); + + ret = cs_dsp_power_up(dsp, wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename, + hda_cs_dsp_fw_ids[cs35l41->firmware_type]); + if (ret) + goto err_release; + + ret = cs35l41_save_calibration(cs35l41); + +err_release: + release_firmware(wmfw_firmware); + release_firmware(coeff_firmware); + kfree(wmfw_filename); + kfree(coeff_filename); + + return ret; +} + +static void cs35l41_shutdown_dsp(struct cs35l41_hda *cs35l41) +{ + struct cs_dsp *dsp = &cs35l41->cs_dsp; + + cs_dsp_stop(dsp); + cs_dsp_power_down(dsp); + cs35l41->firmware_running = false; + dev_dbg(cs35l41->dev, "Unloaded Firmware\n"); +} + +static void cs35l41_remove_dsp(struct cs35l41_hda *cs35l41) +{ + struct cs_dsp *dsp = &cs35l41->cs_dsp; + + cancel_work_sync(&cs35l41->fw_load_work); + cs35l41_shutdown_dsp(cs35l41); + cs_dsp_remove(dsp); + cs35l41->halo_initialized = false; +} + +/* Protection release cycle to get the speaker out of Safe-Mode */ +static void cs35l41_error_release(struct device *dev, struct regmap *regmap, unsigned int mask) +{ + regmap_write(regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_set_bits(regmap, CS35L41_PROTECT_REL_ERR_IGN, mask); + regmap_clear_bits(regmap, CS35L41_PROTECT_REL_ERR_IGN, mask); +} + +/* Clear all errors to release safe mode. Global Enable must be cleared first. */ +static void cs35l41_irq_release(struct cs35l41_hda *cs35l41) +{ + cs35l41_error_release(cs35l41->dev, cs35l41->regmap, cs35l41->irq_errors); + cs35l41->irq_errors = 0; +} static void cs35l41_hda_playback_hook(struct device *dev, int action) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); - const struct cs35l41_hda_reg_sequence *reg_seq = cs35l41->reg_seq; struct regmap *reg = cs35l41->regmap; int ret = 0; + mutex_lock(&cs35l41->fw_mutex); + switch (action) { case HDA_GEN_PCM_ACT_OPEN: - if (reg_seq->open) - ret = regmap_multi_reg_write(reg, reg_seq->open, reg_seq->num_open); + cs35l41->playback_started = true; + if (cs35l41->firmware_running) { + regmap_multi_reg_write(reg, cs35l41_hda_config_dsp, + ARRAY_SIZE(cs35l41_hda_config_dsp)); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK, + 1 << CS35L41_VMON_EN_SHIFT | 1 << CS35L41_IMON_EN_SHIFT); + cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, + CSPL_MBOX_CMD_RESUME); + } else { + regmap_multi_reg_write(reg, cs35l41_hda_config, + ARRAY_SIZE(cs35l41_hda_config)); + } + ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2, + CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT); + if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) + regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001); break; case HDA_GEN_PCM_ACT_PREPARE: - if (reg_seq->prepare) - ret = regmap_multi_reg_write(reg, reg_seq->prepare, reg_seq->num_prepare); + ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 1); break; case HDA_GEN_PCM_ACT_CLEANUP: - if (reg_seq->cleanup) - ret = regmap_multi_reg_write(reg, reg_seq->cleanup, reg_seq->num_cleanup); + regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute)); + ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 0); break; case HDA_GEN_PCM_ACT_CLOSE: - if (reg_seq->close) - ret = regmap_multi_reg_write(reg, reg_seq->close, reg_seq->num_close); + ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2, + CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT); + if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) + regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001); + if (cs35l41->firmware_running) { + cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, + CSPL_MBOX_CMD_PAUSE); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK, + 0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT); + } + cs35l41_irq_release(cs35l41); + cs35l41->playback_started = false; break; default: - ret = -EINVAL; + dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action); break; } + mutex_unlock(&cs35l41->fw_mutex); + if (ret) - dev_warn(cs35l41->dev, "Failed to apply multi reg write: %d\n", ret); + dev_err(cs35l41->dev, "Regmap access fail: %d\n", ret); } static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsigned int *tx_slot, unsigned int rx_num, unsigned int *rx_slot) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + static const char * const channel_name[] = { "L", "R" }; + + if (!cs35l41->amp_name) { + if (*rx_slot >= ARRAY_SIZE(channel_name)) + return -EINVAL; + + cs35l41->amp_name = devm_kasprintf(cs35l41->dev, GFP_KERNEL, "%s%d", + channel_name[*rx_slot], cs35l41->channel_index); + if (!cs35l41->amp_name) + return -ENOMEM; + } return cs35l41_set_channels(cs35l41->dev, cs35l41->regmap, tx_num, tx_slot, rx_num, rx_slot); } +static int cs35l41_runtime_suspend(struct device *dev) +{ + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + + dev_dbg(cs35l41->dev, "Suspend\n"); + + if (!cs35l41->firmware_running) + return 0; + + if (cs35l41_enter_hibernate(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type) < 0) + return 0; + + regcache_cache_only(cs35l41->regmap, true); + regcache_mark_dirty(cs35l41->regmap); + + return 0; +} + +static int cs35l41_runtime_resume(struct device *dev) +{ + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + int ret; + + dev_dbg(cs35l41->dev, "Resume.\n"); + + if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) { + dev_dbg(cs35l41->dev, "System does not support Resume\n"); + return 0; + } + + if (!cs35l41->firmware_running) + return 0; + + regcache_cache_only(cs35l41->regmap, false); + + ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap); + if (ret) { + regcache_cache_only(cs35l41->regmap, true); + return ret; + } + + /* Test key needs to be unlocked to allow the OTP settings to re-apply */ + cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap); + ret = regcache_sync(cs35l41->regmap); + cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap); + if (ret) { + dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret); + return ret; + } + + if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) + cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg); + + return 0; +} + +static int cs35l41_hda_suspend_hook(struct device *dev) +{ + dev_dbg(dev, "Request Suspend\n"); + pm_runtime_mark_last_busy(dev); + return pm_runtime_put_autosuspend(dev); +} + +static int cs35l41_hda_resume_hook(struct device *dev) +{ + dev_dbg(dev, "Request Resume\n"); + return pm_runtime_get_sync(dev); +} + +static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41) +{ + int halo_sts; + int ret; + + ret = cs35l41_init_dsp(cs35l41); + if (ret) { + dev_warn(cs35l41->dev, "Cannot Initialize Firmware. Error: %d\n", ret); + goto clean_dsp; + } + + ret = cs35l41_write_fs_errata(cs35l41->dev, cs35l41->regmap); + if (ret) { + dev_err(cs35l41->dev, "Cannot Write FS Errata: %d\n", ret); + goto clean_dsp; + } + + ret = cs_dsp_run(&cs35l41->cs_dsp); + if (ret) { + dev_err(cs35l41->dev, "Fail to start dsp: %d\n", ret); + goto clean_dsp; + } + + ret = read_poll_timeout(hda_cs_dsp_read_ctl, ret, + be32_to_cpu(halo_sts) == HALO_STATE_CODE_RUN, + 1000, 15000, false, &cs35l41->cs_dsp, HALO_STATE_DSP_CTL_NAME, + HALO_STATE_DSP_CTL_TYPE, HALO_STATE_DSP_CTL_ALG, + &halo_sts, sizeof(halo_sts)); + + if (ret) { + dev_err(cs35l41->dev, "Timeout waiting for HALO Core to start. State: %d\n", + halo_sts); + goto clean_dsp; + } + + cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, CSPL_MBOX_CMD_PAUSE); + cs35l41->firmware_running = true; + + return 0; + +clean_dsp: + cs35l41_shutdown_dsp(cs35l41); + return ret; +} + +static void cs35l41_load_firmware(struct cs35l41_hda *cs35l41, bool load) +{ + pm_runtime_get_sync(cs35l41->dev); + + if (cs35l41->firmware_running && !load) { + dev_dbg(cs35l41->dev, "Unloading Firmware\n"); + cs35l41_shutdown_dsp(cs35l41); + } else if (!cs35l41->firmware_running && load) { + dev_dbg(cs35l41->dev, "Loading Firmware\n"); + cs35l41_smart_amp(cs35l41); + } else { + dev_dbg(cs35l41->dev, "Unable to Load firmware.\n"); + } + + pm_runtime_mark_last_busy(cs35l41->dev); + pm_runtime_put_autosuspend(cs35l41->dev); +} + +static int cs35l41_fw_load_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = cs35l41->request_fw_load; + return 0; +} + +static void cs35l41_fw_load_work(struct work_struct *work) +{ + struct cs35l41_hda *cs35l41 = container_of(work, struct cs35l41_hda, fw_load_work); + + mutex_lock(&cs35l41->fw_mutex); + + /* Recheck if playback is ongoing, mutex will block playback during firmware loading */ + if (cs35l41->playback_started) + dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback\n"); + else + cs35l41_load_firmware(cs35l41, cs35l41->request_fw_load); + + cs35l41->fw_request_ongoing = false; + mutex_unlock(&cs35l41->fw_mutex); +} + +static int cs35l41_fw_load_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol); + unsigned int ret = 0; + + mutex_lock(&cs35l41->fw_mutex); + + if (cs35l41->request_fw_load == ucontrol->value.integer.value[0]) + goto err; + + if (cs35l41->fw_request_ongoing) { + dev_dbg(cs35l41->dev, "Existing request not complete\n"); + ret = -EBUSY; + goto err; + } + + /* Check if playback is ongoing when initial request is made */ + if (cs35l41->playback_started) { + dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback\n"); + ret = -EBUSY; + goto err; + } + + cs35l41->fw_request_ongoing = true; + cs35l41->request_fw_load = ucontrol->value.integer.value[0]; + schedule_work(&cs35l41->fw_load_work); + +err: + mutex_unlock(&cs35l41->fw_mutex); + + return ret; +} + +static int cs35l41_fw_type_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = cs35l41->firmware_type; + + return 0; +} + +static int cs35l41_fw_type_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol); + + if (ucontrol->value.enumerated.item[0] < HDA_CS_DSP_NUM_FW) { + cs35l41->firmware_type = ucontrol->value.enumerated.item[0]; + return 0; + } + + return -EINVAL; +} + +static int cs35l41_fw_type_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(hda_cs_dsp_fw_ids), hda_cs_dsp_fw_ids); +} + +static int cs35l41_create_controls(struct cs35l41_hda *cs35l41) +{ + char fw_type_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + char fw_load_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + struct snd_kcontrol_new fw_type_ctl = { + .name = fw_type_ctl_name, + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .info = cs35l41_fw_type_ctl_info, + .get = cs35l41_fw_type_ctl_get, + .put = cs35l41_fw_type_ctl_put, + }; + struct snd_kcontrol_new fw_load_ctl = { + .name = fw_load_ctl_name, + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .info = snd_ctl_boolean_mono_info, + .get = cs35l41_fw_load_ctl_get, + .put = cs35l41_fw_load_ctl_put, + }; + int ret; + + scnprintf(fw_type_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s DSP1 Firmware Type", + cs35l41->amp_name); + scnprintf(fw_load_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s DSP1 Firmware Load", + cs35l41->amp_name); + + ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_type_ctl, cs35l41)); + if (ret) { + dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", fw_type_ctl.name, ret); + return ret; + } + + dev_dbg(cs35l41->dev, "Added Control %s\n", fw_type_ctl.name); + + ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_load_ctl, cs35l41)); + if (ret) { + dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", fw_load_ctl.name, ret); + return ret; + } + + dev_dbg(cs35l41->dev, "Added Control %s\n", fw_load_ctl.name); + + return 0; +} + static int cs35l41_hda_bind(struct device *dev, struct device *master, void *master_data) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); struct hda_component *comps = master_data; + int ret = 0; if (!comps || cs35l41->index < 0 || cs35l41->index >= HDA_MAX_COMPONENTS) return -EINVAL; @@ -191,12 +838,38 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas if (comps->dev) return -EBUSY; + pm_runtime_get_sync(dev); + comps->dev = dev; + if (!cs35l41->acpi_subsystem_id) + cs35l41->acpi_subsystem_id = devm_kasprintf(dev, GFP_KERNEL, "%.8x", + comps->codec->core.subsystem_id); + cs35l41->codec = comps->codec; strscpy(comps->name, dev_name(dev), sizeof(comps->name)); + + cs35l41->firmware_type = HDA_CS_DSP_FW_SPK_PROT; + + if (firmware_autostart) { + dev_dbg(cs35l41->dev, "Firmware Autostart.\n"); + cs35l41->request_fw_load = true; + mutex_lock(&cs35l41->fw_mutex); + if (cs35l41_smart_amp(cs35l41) < 0) + dev_warn(cs35l41->dev, "Cannot Run Firmware, reverting to dsp bypass...\n"); + mutex_unlock(&cs35l41->fw_mutex); + } else { + dev_dbg(cs35l41->dev, "Firmware Autostart is disabled.\n"); + } + + ret = cs35l41_create_controls(cs35l41); + comps->playback_hook = cs35l41_hda_playback_hook; - comps->set_channel_map = cs35l41_hda_channel_map; + comps->suspend_hook = cs35l41_hda_suspend_hook; + comps->resume_hook = cs35l41_hda_resume_hook; - return 0; + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return ret; } static void cs35l41_hda_unbind(struct device *dev, struct device *master, void *master_data) @@ -213,67 +886,300 @@ static const struct component_ops cs35l41_hda_comp_ops = { .unbind = cs35l41_hda_unbind, }; -static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41, - const struct cs35l41_hda_hw_config *hw_cfg) +static irqreturn_t cs35l41_bst_short_err(int irq, void *data) { - bool internal_boost = false; - int ret; + struct cs35l41_hda *cs35l41 = data; - if (!hw_cfg) { - cs35l41->reg_seq = &cs35l41_hda_reg_seq_no_bst; - return 0; - } + dev_crit_ratelimited(cs35l41->dev, "LBST Error\n"); + set_bit(CS35L41_BST_SHORT_ERR_RLS_SHIFT, &cs35l41->irq_errors); - if (hw_cfg->bst_ind || hw_cfg->bst_cap || hw_cfg->bst_ipk) - internal_boost = true; + return IRQ_HANDLED; +} - switch (hw_cfg->gpio1_func) { - case CS35L41_NOT_USED: - break; - case CS35l41_VSPK_SWITCH: - regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL, - CS35L41_GPIO1_CTRL_MASK, 1 << CS35L41_GPIO1_CTRL_SHIFT); - break; - case CS35l41_SYNC: - regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL, - CS35L41_GPIO1_CTRL_MASK, 2 << CS35L41_GPIO1_CTRL_SHIFT); - break; - default: - dev_err(cs35l41->dev, "Invalid function %d for GPIO1\n", hw_cfg->gpio1_func); - return -EINVAL; - } +static irqreturn_t cs35l41_bst_dcm_uvp_err(int irq, void *data) +{ + struct cs35l41_hda *cs35l41 = data; - switch (hw_cfg->gpio2_func) { - case CS35L41_NOT_USED: - break; - case CS35L41_INTERRUPT: - regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL, - CS35L41_GPIO2_CTRL_MASK, 2 << CS35L41_GPIO2_CTRL_SHIFT); - break; - default: - dev_err(cs35l41->dev, "Invalid function %d for GPIO2\n", hw_cfg->gpio2_func); + dev_crit_ratelimited(cs35l41->dev, "DCM VBST Under Voltage Error\n"); + set_bit(CS35L41_BST_UVP_ERR_RLS_SHIFT, &cs35l41->irq_errors); + + return IRQ_HANDLED; +} + +static irqreturn_t cs35l41_bst_ovp_err(int irq, void *data) +{ + struct cs35l41_hda *cs35l41 = data; + + dev_crit_ratelimited(cs35l41->dev, "VBST Over Voltage error\n"); + set_bit(CS35L41_BST_OVP_ERR_RLS_SHIFT, &cs35l41->irq_errors); + + return IRQ_HANDLED; +} + +static irqreturn_t cs35l41_temp_err(int irq, void *data) +{ + struct cs35l41_hda *cs35l41 = data; + + dev_crit_ratelimited(cs35l41->dev, "Over temperature error\n"); + set_bit(CS35L41_TEMP_ERR_RLS_SHIFT, &cs35l41->irq_errors); + + return IRQ_HANDLED; +} + +static irqreturn_t cs35l41_temp_warn(int irq, void *data) +{ + struct cs35l41_hda *cs35l41 = data; + + dev_crit_ratelimited(cs35l41->dev, "Over temperature warning\n"); + set_bit(CS35L41_TEMP_WARN_ERR_RLS_SHIFT, &cs35l41->irq_errors); + + return IRQ_HANDLED; +} + +static irqreturn_t cs35l41_amp_short(int irq, void *data) +{ + struct cs35l41_hda *cs35l41 = data; + + dev_crit_ratelimited(cs35l41->dev, "Amp short error\n"); + set_bit(CS35L41_AMP_SHORT_ERR_RLS_SHIFT, &cs35l41->irq_errors); + + return IRQ_HANDLED; +} + +static const struct cs35l41_irq cs35l41_irqs[] = { + CS35L41_IRQ(BST_OVP_ERR, "Boost Overvoltage Error", cs35l41_bst_ovp_err), + CS35L41_IRQ(BST_DCM_UVP_ERR, "Boost Undervoltage Error", cs35l41_bst_dcm_uvp_err), + CS35L41_IRQ(BST_SHORT_ERR, "Boost Inductor Short Error", cs35l41_bst_short_err), + CS35L41_IRQ(TEMP_WARN, "Temperature Warning", cs35l41_temp_warn), + CS35L41_IRQ(TEMP_ERR, "Temperature Error", cs35l41_temp_err), + CS35L41_IRQ(AMP_SHORT_ERR, "Amp Short", cs35l41_amp_short), +}; + +static const struct regmap_irq cs35l41_reg_irqs[] = { + CS35L41_REG_IRQ(IRQ1_STATUS1, BST_OVP_ERR), + CS35L41_REG_IRQ(IRQ1_STATUS1, BST_DCM_UVP_ERR), + CS35L41_REG_IRQ(IRQ1_STATUS1, BST_SHORT_ERR), + CS35L41_REG_IRQ(IRQ1_STATUS1, TEMP_WARN), + CS35L41_REG_IRQ(IRQ1_STATUS1, TEMP_ERR), + CS35L41_REG_IRQ(IRQ1_STATUS1, AMP_SHORT_ERR), +}; + +static struct regmap_irq_chip cs35l41_regmap_irq_chip = { + .name = "cs35l41 IRQ1 Controller", + .status_base = CS35L41_IRQ1_STATUS1, + .mask_base = CS35L41_IRQ1_MASK1, + .ack_base = CS35L41_IRQ1_STATUS1, + .num_regs = 4, + .irqs = cs35l41_reg_irqs, + .num_irqs = ARRAY_SIZE(cs35l41_reg_irqs), + .runtime_pm = true, +}; + +static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41) +{ + struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; + bool using_irq = false; + int irq, irq_pol; + int ret; + int i; + + if (!cs35l41->hw_cfg.valid) return -EINVAL; + + ret = cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, hw_cfg); + if (ret) + return ret; + + if (hw_cfg->gpio1.valid) { + switch (hw_cfg->gpio1.func) { + case CS35L41_NOT_USED: + break; + case CS35l41_VSPK_SWITCH: + hw_cfg->gpio1.func = CS35L41_GPIO1_GPIO; + hw_cfg->gpio1.out_en = true; + break; + case CS35l41_SYNC: + hw_cfg->gpio1.func = CS35L41_GPIO1_MDSYNC; + break; + default: + dev_err(cs35l41->dev, "Invalid function %d for GPIO1\n", + hw_cfg->gpio1.func); + return -EINVAL; + } } - if (internal_boost) { - cs35l41->reg_seq = &cs35l41_hda_reg_seq_int_bst; - if (!(hw_cfg->bst_ind && hw_cfg->bst_cap && hw_cfg->bst_ipk)) + if (hw_cfg->gpio2.valid) { + switch (hw_cfg->gpio2.func) { + case CS35L41_NOT_USED: + break; + case CS35L41_INTERRUPT: + using_irq = true; + hw_cfg->gpio2.func = CS35L41_GPIO2_INT_OPEN_DRAIN; + break; + default: + dev_err(cs35l41->dev, "Invalid GPIO2 function %d\n", hw_cfg->gpio2.func); return -EINVAL; - ret = cs35l41_boost_config(cs35l41->dev, cs35l41->regmap, - hw_cfg->bst_ind, hw_cfg->bst_cap, hw_cfg->bst_ipk); + } + } + + irq_pol = cs35l41_gpio_config(cs35l41->regmap, hw_cfg); + + if (cs35l41->irq && using_irq) { + ret = devm_regmap_add_irq_chip(cs35l41->dev, cs35l41->regmap, cs35l41->irq, + IRQF_ONESHOT | IRQF_SHARED | irq_pol, + 0, &cs35l41_regmap_irq_chip, &cs35l41->irq_data); if (ret) return ret; + + for (i = 0; i < ARRAY_SIZE(cs35l41_irqs); i++) { + irq = regmap_irq_get_virq(cs35l41->irq_data, cs35l41_irqs[i].irq); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(cs35l41->dev, irq, NULL, + cs35l41_irqs[i].handler, + IRQF_ONESHOT | IRQF_SHARED | irq_pol, + cs35l41_irqs[i].name, cs35l41); + if (ret) + return ret; + } + } + + return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos); +} + +static int cs35l41_get_acpi_sub_string(struct device *dev, struct acpi_device *adev, + const char **subsysid) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + int ret = 0; + + status = acpi_evaluate_object(adev->handle, "_SUB", NULL, &buffer); + if (ACPI_SUCCESS(status)) { + obj = buffer.pointer; + if (obj->type == ACPI_TYPE_STRING) { + *subsysid = devm_kstrdup(dev, obj->string.pointer, GFP_KERNEL); + if (*subsysid == NULL) { + dev_err(dev, "Cannot allocate Subsystem ID"); + ret = -ENOMEM; + } + } else { + dev_warn(dev, "Warning ACPI _SUB did not return a string\n"); + ret = -ENODEV; + } + acpi_os_free(buffer.pointer); + } else { + dev_dbg(dev, "Warning ACPI _SUB failed: %#x\n", status); + ret = -ENODEV; + } + + return ret; +} + +static int cs35l41_get_speaker_id(struct device *dev, int amp_index, + int num_amps, int fixed_gpio_id) +{ + struct gpio_desc *speaker_id_desc; + int speaker_id = -ENODEV; + + if (fixed_gpio_id >= 0) { + dev_dbg(dev, "Found Fixed Speaker ID GPIO (index = %d)\n", fixed_gpio_id); + speaker_id_desc = gpiod_get_index(dev, NULL, fixed_gpio_id, GPIOD_IN); + if (IS_ERR(speaker_id_desc)) { + speaker_id = PTR_ERR(speaker_id_desc); + return speaker_id; + } + speaker_id = gpiod_get_value_cansleep(speaker_id_desc); + gpiod_put(speaker_id_desc); + dev_dbg(dev, "Speaker ID = %d\n", speaker_id); + } else { + int base_index; + int gpios_per_amp; + int count; + int tmp; + int i; + + count = gpiod_count(dev, "spk-id"); + if (count > 0) { + speaker_id = 0; + gpios_per_amp = count / num_amps; + base_index = gpios_per_amp * amp_index; + + if (count % num_amps) + return -EINVAL; + + dev_dbg(dev, "Found %d Speaker ID GPIOs per Amp\n", gpios_per_amp); + + for (i = 0; i < gpios_per_amp; i++) { + speaker_id_desc = gpiod_get_index(dev, "spk-id", i + base_index, + GPIOD_IN); + if (IS_ERR(speaker_id_desc)) { + speaker_id = PTR_ERR(speaker_id_desc); + break; + } + tmp = gpiod_get_value_cansleep(speaker_id_desc); + gpiod_put(speaker_id_desc); + if (tmp < 0) { + speaker_id = tmp; + break; + } + speaker_id |= tmp << i; + } + dev_dbg(dev, "Speaker ID = %d\n", speaker_id); + } + } + return speaker_id; +} + +/* + * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work. + * And devices created by serial-multi-instantiate don't have their device struct + * pointing to the correct fwnode, so acpi_dev must be used here. + * And devm functions expect that the device requesting the resource has the correct + * fwnode. + */ +static int cs35l41_no_acpi_dsd(struct cs35l41_hda *cs35l41, struct device *physdev, int id, + const char *hid) +{ + struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; + + /* check I2C address to assign the index */ + cs35l41->index = id == 0x40 ? 0 : 1; + cs35l41->channel_index = 0; + cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH); + cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2); + hw_cfg->spk_pos = cs35l41->index; + hw_cfg->gpio2.func = CS35L41_INTERRUPT; + hw_cfg->gpio2.valid = true; + hw_cfg->valid = true; + put_device(physdev); + + if (strncmp(hid, "CLSA0100", 8) == 0) { + hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH; + } else if (strncmp(hid, "CLSA0101", 8) == 0) { + hw_cfg->bst_type = CS35L41_EXT_BOOST; + hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH; + hw_cfg->gpio1.valid = true; } else { - cs35l41->reg_seq = &cs35l41_hda_reg_seq_ext_bst; + /* + * Note: CLSA010(0/1) are special cases which use a slightly different design. + * All other HIDs e.g. CSC3551 require valid ACPI _DSD properties to be supported. + */ + dev_err(cs35l41->dev, "Error: ACPI _DSD Properties are missing for HID %s.\n", hid); + hw_cfg->valid = false; + hw_cfg->gpio1.valid = false; + hw_cfg->gpio2.valid = false; + return -EINVAL; } - return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, (unsigned int *)&hw_cfg->spk_pos); + return 0; } -static struct cs35l41_hda_hw_config *cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, - const char *hid, int id) +static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id) { - struct cs35l41_hda_hw_config *hw_cfg; + struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; u32 values[HDA_MAX_COMPONENTS]; struct acpi_device *adev; struct device *physdev; @@ -284,16 +1190,22 @@ static struct cs35l41_hda_hw_config *cs35l41_hda_read_acpi(struct cs35l41_hda *c adev = acpi_dev_get_first_match_dev(hid, NULL, -1); if (!adev) { dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid); - return ERR_PTR(-ENODEV); + return -ENODEV; } physdev = get_device(acpi_get_first_physical_node(adev)); acpi_dev_put(adev); + ret = cs35l41_get_acpi_sub_string(cs35l41->dev, adev, &cs35l41->acpi_subsystem_id); + if (ret) + dev_info(cs35l41->dev, "No Subsystem ID found in ACPI: %d", ret); + else + dev_dbg(cs35l41->dev, "Subsystem ID %s found", cs35l41->acpi_subsystem_id); + property = "cirrus,dev-index"; ret = device_property_count_u32(physdev, property); if (ret <= 0) - goto no_acpi_dsd; + return cs35l41_no_acpi_dsd(cs35l41, physdev, id, hid); if (ret > ARRAY_SIZE(values)) { ret = -EINVAL; @@ -321,88 +1233,84 @@ static struct cs35l41_hda_hw_config *cs35l41_hda_read_acpi(struct cs35l41_hda *c /* To use the same release code for all laptop variants we can't use devm_ version of * gpiod_get here, as CLSA010* don't have a fully functional bios with an _DSD node */ - cs35l41->reset_gpio = fwnode_gpiod_get_index(&adev->fwnode, "reset", cs35l41->index, + cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(adev), "reset", cs35l41->index, GPIOD_OUT_LOW, "cs35l41-reset"); - hw_cfg = kzalloc(sizeof(*hw_cfg), GFP_KERNEL); - if (!hw_cfg) { - ret = -ENOMEM; - goto err; - } - property = "cirrus,speaker-position"; ret = device_property_read_u32_array(physdev, property, values, nval); if (ret) - goto err_free; + goto err; hw_cfg->spk_pos = values[cs35l41->index]; + cs35l41->channel_index = 0; + for (i = 0; i < cs35l41->index; i++) + if (values[i] == hw_cfg->spk_pos) + cs35l41->channel_index++; + property = "cirrus,gpio1-func"; ret = device_property_read_u32_array(physdev, property, values, nval); if (ret) - goto err_free; - hw_cfg->gpio1_func = values[cs35l41->index]; + goto err; + hw_cfg->gpio1.func = values[cs35l41->index]; + hw_cfg->gpio1.valid = true; property = "cirrus,gpio2-func"; ret = device_property_read_u32_array(physdev, property, values, nval); if (ret) - goto err_free; - hw_cfg->gpio2_func = values[cs35l41->index]; + goto err; + hw_cfg->gpio2.func = values[cs35l41->index]; + hw_cfg->gpio2.valid = true; property = "cirrus,boost-peak-milliamp"; ret = device_property_read_u32_array(physdev, property, values, nval); if (ret == 0) hw_cfg->bst_ipk = values[cs35l41->index]; + else + hw_cfg->bst_ipk = -1; property = "cirrus,boost-ind-nanohenry"; ret = device_property_read_u32_array(physdev, property, values, nval); if (ret == 0) hw_cfg->bst_ind = values[cs35l41->index]; + else + hw_cfg->bst_ind = -1; property = "cirrus,boost-cap-microfarad"; ret = device_property_read_u32_array(physdev, property, values, nval); if (ret == 0) hw_cfg->bst_cap = values[cs35l41->index]; + else + hw_cfg->bst_cap = -1; - put_device(physdev); + cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, nval, -1); - return hw_cfg; + if (hw_cfg->bst_ind > 0 || hw_cfg->bst_cap > 0 || hw_cfg->bst_ipk > 0) + hw_cfg->bst_type = CS35L41_INT_BOOST; + else + hw_cfg->bst_type = CS35L41_EXT_BOOST; -err_free: - kfree(hw_cfg); -err: + hw_cfg->valid = true; put_device(physdev); - dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret); - return ERR_PTR(ret); - -no_acpi_dsd: - /* - * Device CLSA0100 doesn't have _DSD so a gpiod_get by the label reset won't work. - * And devices created by i2c-multi-instantiate don't have their device struct pointing to - * the correct fwnode, so acpi_dev must be used here. - * And devm functions expect that the device requesting the resource has the correct - * fwnode. - */ - if (strncmp(hid, "CLSA0100", 8) != 0) - return ERR_PTR(-EINVAL); + return 0; - /* check I2C address to assign the index */ - cs35l41->index = id == 0x40 ? 0 : 1; - cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH); - cs35l41->vspk_always_on = true; +err: put_device(physdev); + dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret); - return NULL; + return ret; } int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq, struct regmap *regmap) { unsigned int int_sts, regid, reg_revid, mtl_revid, chipid, int_status; - struct cs35l41_hda_hw_config *acpi_hw_cfg; struct cs35l41_hda *cs35l41; int ret; + BUILD_BUG_ON(ARRAY_SIZE(cs35l41_irqs) != ARRAY_SIZE(cs35l41_reg_irqs)); + BUILD_BUG_ON(ARRAY_SIZE(cs35l41_irqs) != CS35L41_NUM_IRQ); + if (IS_ERR(regmap)) return PTR_ERR(regmap); @@ -415,9 +1323,9 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i cs35l41->regmap = regmap; dev_set_drvdata(dev, cs35l41); - acpi_hw_cfg = cs35l41_hda_read_acpi(cs35l41, device_name, id); - if (IS_ERR(acpi_hw_cfg)) - return PTR_ERR(acpi_hw_cfg); + ret = cs35l41_hda_read_acpi(cs35l41, device_name, id); + if (ret) + return dev_err_probe(cs35l41->dev, ret, "Platform not supported\n"); if (IS_ERR(cs35l41->reset_gpio)) { ret = PTR_ERR(cs35l41->reset_gpio); @@ -425,7 +1333,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i if (ret == -EBUSY) { dev_info(cs35l41->dev, "Reset line busy, assuming shared reset\n"); } else { - dev_err_probe(cs35l41->dev, ret, "Failed to get reset GPIO: %d\n", ret); + dev_err_probe(cs35l41->dev, ret, "Failed to get reset GPIO\n"); goto err; } } @@ -490,24 +1398,26 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i if (ret) goto err; - ret = cs35l41_hda_apply_properties(cs35l41, acpi_hw_cfg); + INIT_WORK(&cs35l41->fw_load_work, cs35l41_fw_load_work); + mutex_init(&cs35l41->fw_mutex); + + pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000); + pm_runtime_use_autosuspend(cs35l41->dev); + pm_runtime_mark_last_busy(cs35l41->dev); + pm_runtime_set_active(cs35l41->dev); + pm_runtime_get_noresume(cs35l41->dev); + pm_runtime_enable(cs35l41->dev); + + ret = cs35l41_hda_apply_properties(cs35l41); if (ret) - goto err; - kfree(acpi_hw_cfg); - acpi_hw_cfg = NULL; - - if (cs35l41->reg_seq->probe) { - ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41->reg_seq->probe, - cs35l41->reg_seq->num_probe); - if (ret) { - dev_err(cs35l41->dev, "Fail to apply probe reg patch: %d\n", ret); - goto err; - } - } + goto err_pm; + + pm_runtime_put_autosuspend(cs35l41->dev); ret = component_add(cs35l41->dev, &cs35l41_hda_comp_ops); if (ret) { dev_err(cs35l41->dev, "Register component failed: %d\n", ret); + pm_runtime_disable(cs35l41->dev); goto err; } @@ -515,9 +1425,12 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i return 0; +err_pm: + pm_runtime_disable(cs35l41->dev); + pm_runtime_put_noidle(cs35l41->dev); + err: - kfree(acpi_hw_cfg); - if (!cs35l41->vspk_always_on) + if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type)) gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); gpiod_put(cs35l41->reset_gpio); @@ -529,14 +1442,28 @@ void cs35l41_hda_remove(struct device *dev) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + pm_runtime_get_sync(cs35l41->dev); + pm_runtime_disable(cs35l41->dev); + + if (cs35l41->halo_initialized) + cs35l41_remove_dsp(cs35l41); + component_del(cs35l41->dev, &cs35l41_hda_comp_ops); - if (!cs35l41->vspk_always_on) + pm_runtime_put_noidle(cs35l41->dev); + + if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type)) gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); gpiod_put(cs35l41->reset_gpio); } EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41); +const struct dev_pm_ops cs35l41_hda_pm_ops = { + RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, NULL) +}; +EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41); + MODULE_DESCRIPTION("CS35L41 HDA Driver"); +MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS); MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, "); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/pci/hda/cs35l41_hda.h index 7495100150..bdb35f3be6 100644 --- a/sound/pci/hda/cs35l41_hda.h +++ b/sound/pci/hda/cs35l41_hda.h @@ -10,11 +10,29 @@ #ifndef __CS35L41_HDA_H__ #define __CS35L41_HDA_H__ +#include #include #include #include #include +#include +#include + +struct cs35l41_amp_cal_data { + u32 calTarget[2]; + u32 calTime[2]; + s8 calAmbient; + u8 calStatus; + u16 calR; +} __packed; + +struct cs35l41_amp_efi_data { + u32 size; + u32 count; + struct cs35l41_amp_cal_data data[]; +} __packed; + enum cs35l41_hda_spk_pos { CS35l41_LEFT, CS35l41_RIGHT, @@ -27,41 +45,41 @@ enum cs35l41_hda_gpio_function { CS35l41_SYNC, }; -struct cs35l41_hda_reg_sequence { - const struct reg_sequence *probe; - unsigned int num_probe; - const struct reg_sequence *open; - unsigned int num_open; - const struct reg_sequence *prepare; - unsigned int num_prepare; - const struct reg_sequence *cleanup; - unsigned int num_cleanup; - const struct reg_sequence *close; - unsigned int num_close; -}; - -struct cs35l41_hda_hw_config { - unsigned int spk_pos; - unsigned int gpio1_func; - unsigned int gpio2_func; - int bst_ind; - int bst_ipk; - int bst_cap; -}; - struct cs35l41_hda { struct device *dev; struct regmap *regmap; struct gpio_desc *reset_gpio; - const struct cs35l41_hda_reg_sequence *reg_seq; + struct cs35l41_hw_cfg hw_cfg; + struct hda_codec *codec; int irq; int index; + int channel_index; + unsigned volatile long irq_errors; + const char *amp_name; + const char *acpi_subsystem_id; + int firmware_type; + int speaker_id; + struct mutex fw_mutex; + struct work_struct fw_load_work; - /* Don't put the AMP in reset of VSPK can not be turned off */ - bool vspk_always_on; + struct regmap_irq_chip_data *irq_data; + bool firmware_running; + bool request_fw_load; + bool fw_request_ongoing; + bool halo_initialized; + bool playback_started; + struct cs_dsp cs_dsp; }; +enum halo_state { + HALO_STATE_CODE_INIT_DOWNLOAD = 0, + HALO_STATE_CODE_START, + HALO_STATE_CODE_RUN +}; + +extern const struct dev_pm_ops cs35l41_hda_pm_ops; + int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq, struct regmap *regmap); void cs35l41_hda_remove(struct device *dev); diff --git a/sound/pci/hda/cs35l41_hda_i2c.c b/sound/pci/hda/cs35l41_hda_i2c.c index e810b278fb..5baacfde4f 100644 --- a/sound/pci/hda/cs35l41_hda_i2c.c +++ b/sound/pci/hda/cs35l41_hda_i2c.c @@ -1,14 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 // -// cs35l41.c -- CS35l41 HDA I2C driver +// CS35l41 HDA I2C driver // // Copyright 2021 Cirrus Logic, Inc. // // Author: Lucas Tanure +#include #include #include -#include #include "cs35l41_hda.h" @@ -16,11 +16,14 @@ static int cs35l41_hda_i2c_probe(struct i2c_client *clt, const struct i2c_device { const char *device_name; - /* Compare against the device name so it works for I2C, normal ACPI - * and for ACPI by i2c-multi-instantiate matching cases + /* + * Compare against the device name so it works for SPI, normal ACPI + * and for ACPI by serial-multi-instantiate matching cases. */ if (strstr(dev_name(&clt->dev), "CLSA0100")) device_name = "CLSA0100"; + else if (strstr(dev_name(&clt->dev), "CLSA0101")) + device_name = "CLSA0101"; else if (strstr(dev_name(&clt->dev), "CSC3551")) device_name = "CSC3551"; else @@ -42,19 +45,19 @@ static const struct i2c_device_id cs35l41_hda_i2c_id[] = { {} }; -#ifdef CONFIG_ACPI static const struct acpi_device_id cs35l41_acpi_hda_match[] = { {"CLSA0100", 0 }, + {"CLSA0101", 0 }, {"CSC3551", 0 }, - { }, + {} }; MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_hda_match); -#endif static struct i2c_driver cs35l41_i2c_driver = { .driver = { .name = "cs35l41-hda", - .acpi_match_table = ACPI_PTR(cs35l41_acpi_hda_match), + .acpi_match_table = cs35l41_acpi_hda_match, + .pm = &cs35l41_hda_pm_ops, }, .id_table = cs35l41_hda_i2c_id, .probe = cs35l41_hda_i2c_probe, diff --git a/sound/pci/hda/cs35l41_hda_spi.c b/sound/pci/hda/cs35l41_hda_spi.c index 50eb6c0e66..71979cfb4d 100644 --- a/sound/pci/hda/cs35l41_hda_spi.c +++ b/sound/pci/hda/cs35l41_hda_spi.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 // -// cs35l41.c -- CS35l41 HDA SPI driver +// CS35l41 HDA SPI driver // // Copyright 2021 Cirrus Logic, Inc. // // Author: Lucas Tanure -#include +#include #include #include @@ -16,8 +16,9 @@ static int cs35l41_hda_spi_probe(struct spi_device *spi) { const char *device_name; - /* Compare against the device name so it works for SPI, normal ACPI - * and for ACPI by spi-multi-instantiate matching cases + /* + * Compare against the device name so it works for SPI, normal ACPI + * and for ACPI by serial-multi-instantiate matching cases. */ if (strstr(dev_name(&spi->dev), "CSC3551")) device_name = "CSC3551"; @@ -38,18 +39,17 @@ static const struct spi_device_id cs35l41_hda_spi_id[] = { {} }; -#ifdef CONFIG_ACPI static const struct acpi_device_id cs35l41_acpi_hda_match[] = { { "CSC3551", 0 }, - {}, + {} }; MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_hda_match); -#endif static struct spi_driver cs35l41_spi_driver = { .driver = { - .name = "cs35l41_hda", - .acpi_match_table = ACPI_PTR(cs35l41_acpi_hda_match), + .name = "cs35l41-hda", + .acpi_match_table = cs35l41_acpi_hda_match, + .pm = &cs35l41_hda_pm_ops, }, .id_table = cs35l41_hda_spi_id, .probe = cs35l41_hda_spi_probe, diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index cd1db943b7..7c6b1fe8df 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -819,7 +819,7 @@ static void set_pin_targets(struct hda_codec *codec, snd_hda_set_pin_ctl_cache(codec, cfg->nid, cfg->val); } -static void apply_fixup(struct hda_codec *codec, int id, int action, int depth) +void __snd_hda_apply_fixup(struct hda_codec *codec, int id, int action, int depth) { const char *modelname = codec->fixup_name; @@ -829,7 +829,7 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth) if (++depth > 10) break; if (fix->chained_before) - apply_fixup(codec, fix->chain_id, action, depth + 1); + __snd_hda_apply_fixup(codec, fix->chain_id, action, depth + 1); switch (fix->type) { case HDA_FIXUP_PINS: @@ -870,6 +870,7 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth) id = fix->chain_id; } } +EXPORT_SYMBOL_GPL(__snd_hda_apply_fixup); /** * snd_hda_apply_fixup - Apply the fixup chain with the given action @@ -879,7 +880,7 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth) void snd_hda_apply_fixup(struct hda_codec *codec, int action) { if (codec->fixup_list) - apply_fixup(codec, codec->fixup_id, action, 0); + __snd_hda_apply_fixup(codec, codec->fixup_id, action, 0); } EXPORT_SYMBOL_GPL(snd_hda_apply_fixup); diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index c572fb5886..cae9a975cb 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -248,6 +248,13 @@ static bool is_likely_hdmi_codec(struct hda_codec *codec) { hda_nid_t nid; + /* + * For ASoC users, if snd_hda_hdmi_codec module is denylisted and any + * event causes i915 enumeration to fail, ->wcaps remains uninitialized. + */ + if (!codec->wcaps) + return true; + for_each_hda_codec_node(nid, codec) { unsigned int wcaps = get_wcaps(codec, nid); switch (get_wcaps_type(wcaps)) { diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5cbac315db..384426d7e9 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -772,11 +772,11 @@ static void codec_release_pcms(struct hda_codec *codec) */ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec) { - if (codec->registered) { + if (codec->core.registered) { /* pm_runtime_put() is called in snd_hdac_device_exit() */ pm_runtime_get_noresume(hda_codec_dev(codec)); pm_runtime_disable(hda_codec_dev(codec)); - codec->registered = 0; + codec->core.registered = 0; } snd_hda_codec_disconnect_pcms(codec); @@ -825,14 +825,14 @@ void snd_hda_codec_display_power(struct hda_codec *codec, bool enable) */ void snd_hda_codec_register(struct hda_codec *codec) { - if (codec->registered) + if (codec->core.registered) return; if (device_is_registered(hda_codec_dev(codec))) { snd_hda_codec_display_power(codec, true); pm_runtime_enable(hda_codec_dev(codec)); /* it was powered up in snd_hda_codec_new(), now all done */ snd_hda_power_down(codec); - codec->registered = 1; + codec->core.registered = 1; } } EXPORT_SYMBOL_GPL(snd_hda_codec_register); @@ -950,6 +950,7 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, unsigned int codec_addr, struct hda_codec **codecp) { struct hda_codec *codec; + int ret; codec = snd_hda_codec_device_init(bus, codec_addr, "hdaudioC%dD%d", card->number, codec_addr); @@ -957,7 +958,11 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, return PTR_ERR(codec); *codecp = codec; - return snd_hda_codec_device_new(bus, card, codec_addr, *codecp, true); + ret = snd_hda_codec_device_new(bus, card, codec_addr, *codecp, true); + if (ret) + put_device(hda_codec_dev(*codecp)); + + return ret; } EXPORT_SYMBOL_GPL(snd_hda_codec_new); @@ -1012,19 +1017,17 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card, if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); - if (!codec->modelname) { - err = -ENOMEM; - goto error; - } + if (!codec->modelname) + return -ENOMEM; } fg = codec->core.afg ? codec->core.afg : codec->core.mfg; err = read_widget_caps(codec, fg); if (err < 0) - goto error; + return err; err = read_pin_defaults(codec); if (err < 0) - goto error; + return err; /* power-up all before initialization */ hda_set_power_state(codec, AC_PWRST_D0); @@ -1042,17 +1045,19 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card, /* ASoC features component management instead */ err = snd_device_new(card, SNDRV_DEV_CODEC, codec, &dev_ops); if (err < 0) - goto error; + return err; } +#ifdef CONFIG_PM /* PM runtime needs to be enabled later after binding codec */ - pm_runtime_forbid(&codec->core.dev); + if (codec->core.dev.power.runtime_auto) + pm_runtime_forbid(&codec->core.dev); + else + /* Keep the usage_count consistent across subsequent probing */ + pm_runtime_get_noresume(&codec->core.dev); +#endif return 0; - - error: - put_device(hda_codec_dev(codec)); - return err; } EXPORT_SYMBOL_GPL(snd_hda_codec_device_new); @@ -2936,12 +2941,18 @@ static int hda_codec_runtime_suspend(struct device *dev) return 0; cancel_delayed_work_sync(&codec->jackpoll_work); + state = hda_call_codec_suspend(codec); if (codec->link_down_at_suspend || (codec_has_clkstop(codec) && codec_has_epss(codec) && (state & AC_PWRST_CLK_STOP_OK))) snd_hdac_codec_link_down(&codec->core); snd_hda_codec_display_power(codec, false); + + if (codec->bus->jackpoll_in_suspend && + (dev->power.power_state.event != PM_EVENT_SUSPEND)) + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); return 0; } @@ -2965,6 +2976,9 @@ static int hda_codec_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int hda_codec_pm_prepare(struct device *dev) { + struct hda_codec *codec = dev_to_hda_codec(dev); + + cancel_delayed_work_sync(&codec->jackpoll_work); dev->power.power_state = PMSG_SUSPEND; return pm_runtime_suspended(dev); } @@ -2996,6 +3010,9 @@ static int hda_codec_pm_resume(struct device *dev) static int hda_codec_pm_freeze(struct device *dev) { + struct hda_codec *codec = dev_to_hda_codec(dev); + + cancel_delayed_work_sync(&codec->jackpoll_work); dev->power.power_state = PMSG_FREEZE; return pm_runtime_force_suspend(dev); } @@ -3035,9 +3052,10 @@ void snd_hda_codec_shutdown(struct hda_codec *codec) struct hda_pcm *cpcm; /* Skip the shutdown if codec is not registered */ - if (!codec->registered) + if (!codec->core.registered) return; + cancel_delayed_work_sync(&codec->jackpoll_work); list_for_each_entry(cpcm, &codec->pcm_list_head, list) snd_pcm_suspend_all(cpcm->pcm); diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h index 2e52be6db9..1223621bd6 100644 --- a/sound/pci/hda/hda_component.h +++ b/sound/pci/hda/hda_component.h @@ -14,7 +14,8 @@ struct hda_component { struct device *dev; char name[HDA_MAX_NAME_SIZE]; + struct hda_codec *codec; void (*playback_hook)(struct device *dev, int action); - int (*set_channel_map)(struct device *dev, unsigned int rx_num, unsigned int *rx_slot, - unsigned int tx_num, unsigned int *tx_slot); + int (*suspend_hook)(struct device *dev); + int (*resume_hook)(struct device *dev); }; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 0a83eb6b88..a77165bd92 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2525,6 +2525,9 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, { PCI_DEVICE(0x8086, 0x51cf), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + /* Meteorlake-P */ + { PCI_DEVICE(0x8086, 0x7e28), + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, /* Broxton-P(Apollolake) */ { PCI_DEVICE(0x8086, 0x5a98), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index aca5926518..682dca2057 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -348,6 +348,7 @@ void snd_hda_apply_verbs(struct hda_codec *codec); void snd_hda_apply_pincfgs(struct hda_codec *codec, const struct hda_pintbl *cfg); void snd_hda_apply_fixup(struct hda_codec *codec, int action); +void __snd_hda_apply_fixup(struct hda_codec *codec, int id, int action, int depth); void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_model_fixup *models, const struct snd_pci_quirk *quirk, diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index d5ffcba794..bf951c10ae 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -33,7 +33,7 @@ static ssize_t power_on_acct_show(struct device *dev, { struct hda_codec *codec = dev_get_drvdata(dev); snd_hda_update_power_acct(codec); - return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct)); + return sysfs_emit(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct)); } static ssize_t power_off_acct_show(struct device *dev, @@ -42,7 +42,7 @@ static ssize_t power_off_acct_show(struct device *dev, { struct hda_codec *codec = dev_get_drvdata(dev); snd_hda_update_power_acct(codec); - return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct)); + return sysfs_emit(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct)); } static DEVICE_ATTR_RO(power_on_acct); @@ -55,7 +55,7 @@ static ssize_t type##_show(struct device *dev, \ char *buf) \ { \ struct hda_codec *codec = dev_get_drvdata(dev); \ - return sprintf(buf, "0x%x\n", codec->field); \ + return sysfs_emit(buf, "0x%x\n", codec->field); \ } #define CODEC_INFO_STR_SHOW(type, field) \ @@ -64,8 +64,8 @@ static ssize_t type##_show(struct device *dev, \ char *buf) \ { \ struct hda_codec *codec = dev_get_drvdata(dev); \ - return sprintf(buf, "%s\n", \ - codec->field ? codec->field : ""); \ + return sysfs_emit(buf, "%s\n", \ + codec->field ? codec->field : ""); \ } CODEC_INFO_SHOW(vendor_id, core.vendor_id); @@ -85,8 +85,8 @@ static ssize_t pin_configs_show(struct hda_codec *codec, int i, len = 0; mutex_lock(&codec->user_mutex); snd_array_for_each(list, i, pin) { - len += sprintf(buf + len, "0x%02x 0x%08x\n", - pin->nid, pin->cfg); + len += sysfs_emit_at(buf, len, "0x%02x 0x%08x\n", + pin->nid, pin->cfg); } mutex_unlock(&codec->user_mutex); return len; @@ -222,9 +222,8 @@ static ssize_t init_verbs_show(struct device *dev, int i, len = 0; mutex_lock(&codec->user_mutex); snd_array_for_each(&codec->init_verbs, i, v) { - len += scnprintf(buf + len, PAGE_SIZE - len, - "0x%02x 0x%03x 0x%04x\n", - v->nid, v->verb, v->param); + len += sysfs_emit_at(buf, len, "0x%02x 0x%03x 0x%04x\n", + v->nid, v->verb, v->param); } mutex_unlock(&codec->user_mutex); return len; @@ -272,8 +271,8 @@ static ssize_t hints_show(struct device *dev, int i, len = 0; mutex_lock(&codec->user_mutex); snd_array_for_each(&codec->hints, i, hint) { - len += scnprintf(buf + len, PAGE_SIZE - len, - "%s = %s\n", hint->key, hint->val); + len += sysfs_emit_at(buf, len, "%s = %s\n", + hint->key, hint->val); } mutex_unlock(&codec->user_mutex); return len; diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 2347d0304f..7debb2c76a 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -420,6 +420,7 @@ static int hda_tegra_create(struct snd_card *card, chip->driver_caps = driver_caps; chip->driver_type = driver_caps & 0xff; chip->dev_index = 0; + chip->jackpoll_interval = msecs_to_jiffies(5000); INIT_LIST_HEAD(&chip->pcm_list); chip->codec_probe_mask = -1; @@ -436,6 +437,7 @@ static int hda_tegra_create(struct snd_card *card, chip->bus.core.sync_write = 0; chip->bus.core.needs_damn_long_delay = 1; chip->bus.core.aligned_mmio = 1; + chip->bus.jackpoll_in_suspend = 1; err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 678fbcaf2a..6807b4708a 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -395,6 +395,7 @@ static const struct snd_pci_quirk cs420x_fixup_tbl[] = { /* codec SSID */ SND_PCI_QUIRK(0x106b, 0x0600, "iMac 14,1", CS420X_IMAC27_122), + SND_PCI_QUIRK(0x106b, 0x0900, "iMac 12,1", CS420X_IMAC27_122), SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81), SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122), SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101), diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 0515137a75..7b1a30a551 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -222,6 +222,7 @@ enum { CXT_PINCFG_LEMOTE_A1205, CXT_PINCFG_COMPAQ_CQ60, CXT_FIXUP_STEREO_DMIC, + CXT_PINCFG_LENOVO_NOTEBOOK, CXT_FIXUP_INC_MIC_BOOST, CXT_FIXUP_HEADPHONE_MIC_PIN, CXT_FIXUP_HEADPHONE_MIC, @@ -772,6 +773,14 @@ static const struct hda_fixup cxt_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = cxt_fixup_stereo_dmic, }, + [CXT_PINCFG_LENOVO_NOTEBOOK] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x05d71030 }, + { } + }, + .chain_id = CXT_FIXUP_STEREO_DMIC, + }, [CXT_FIXUP_INC_MIC_BOOST] = { .type = HDA_FIXUP_FUNC, .v.func = cxt5066_increase_mic_boost, @@ -944,6 +953,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x82b4, "HP ProDesk 600 G3", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK), @@ -970,7 +980,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), - SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), + SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_PINCFG_LENOVO_NOTEBOOK), SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI), @@ -1052,6 +1062,13 @@ static int patch_conexant_auto(struct hda_codec *codec) snd_hda_pick_fixup(codec, cxt5051_fixup_models, cxt5051_fixups, cxt_fixups); break; + case 0x14f15098: + codec->pin_amp_workaround = 1; + spec->gen.mixer_nid = 0x22; + spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO; + snd_hda_pick_fixup(codec, cxt5066_fixup_models, + cxt5066_fixups, cxt_fixups); + break; case 0x14f150f2: codec->power_save_node = 1; fallthrough; @@ -1072,11 +1089,11 @@ static int patch_conexant_auto(struct hda_codec *codec) if (err < 0) goto error; - err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); + err = cx_auto_parse_beep(codec); if (err < 0) goto error; - err = cx_auto_parse_beep(codec); + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) goto error; @@ -1105,6 +1122,7 @@ static int patch_conexant_auto(struct hda_codec *codec) static const struct hda_device_id snd_hda_id_conexant[] = { HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto), diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/pci/hda/patch_cs8409-tables.c index 74c50ec040..b288874e40 100644 --- a/sound/pci/hda/patch_cs8409-tables.c +++ b/sound/pci/hda/patch_cs8409-tables.c @@ -68,7 +68,7 @@ const struct hda_verb cs8409_cs42l42_init_verbs[] = { {} /* terminator */ }; -const struct hda_pintbl cs8409_cs42l42_pincfgs[] = { +static const struct hda_pintbl cs8409_cs42l42_pincfgs[] = { { CS8409_PIN_ASP1_TRANSMITTER_A, 0x042120f0 }, /* ASP-1-TX */ { CS8409_PIN_ASP1_RECEIVER_A, 0x04a12050 }, /* ASP-1-RX */ { CS8409_PIN_ASP2_TRANSMITTER_A, 0x901000f0 }, /* ASP-2-TX */ @@ -76,67 +76,74 @@ const struct hda_pintbl cs8409_cs42l42_pincfgs[] = { {} /* terminator */ }; +static const struct hda_pintbl cs8409_cs42l42_pincfgs_no_dmic[] = { + { CS8409_PIN_ASP1_TRANSMITTER_A, 0x042120f0 }, /* ASP-1-TX */ + { CS8409_PIN_ASP1_RECEIVER_A, 0x04a12050 }, /* ASP-1-RX */ + { CS8409_PIN_ASP2_TRANSMITTER_A, 0x901000f0 }, /* ASP-2-TX */ + {} /* terminator */ +}; + /* Vendor specific HW configuration for CS42L42 */ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = { - { 0x1010, 0xB0 }, - { 0x1D01, 0x00 }, + { CS42L42_I2C_TIMEOUT, 0xB0 }, + { CS42L42_ADC_CTL, 0x00 }, { 0x1D02, 0x06 }, - { 0x1D03, 0x9F }, - { 0x1107, 0x01 }, - { 0x1009, 0x02 }, - { 0x1007, 0x03 }, - { 0x1201, 0x00 }, - { 0x1208, 0x13 }, - { 0x1205, 0xFF }, - { 0x1206, 0x00 }, - { 0x1207, 0x20 }, - { 0x1202, 0x0D }, - { 0x2A02, 0x02 }, - { 0x2A03, 0x00 }, - { 0x2A04, 0x00 }, - { 0x2A05, 0x02 }, - { 0x2A06, 0x00 }, - { 0x2A07, 0x20 }, - { 0x2A08, 0x02 }, - { 0x2A09, 0x00 }, - { 0x2A0A, 0x80 }, - { 0x2A0B, 0x02 }, - { 0x2A0C, 0x00 }, - { 0x2A0D, 0xA0 }, - { 0x2A01, 0x0C }, - { 0x2902, 0x01 }, - { 0x2903, 0x02 }, - { 0x2904, 0x00 }, - { 0x2905, 0x00 }, - { 0x2901, 0x01 }, - { 0x1101, 0x0A }, - { 0x1102, 0x84 }, - { 0x2301, 0x3F }, - { 0x2303, 0x3F }, - { 0x2302, 0x3f }, - { 0x2001, 0x03 }, - { 0x1B75, 0xB6 }, - { 0x1B73, 0xC2 }, - { 0x1129, 0x01 }, - { 0x1121, 0xF3 }, - { 0x1103, 0x20 }, - { 0x1105, 0x00 }, - { 0x1112, 0x00 }, - { 0x1113, 0x80 }, - { 0x1C03, 0xC0 }, - { 0x1101, 0x02 }, - { 0x1316, 0xff }, - { 0x1317, 0xff }, - { 0x1318, 0xff }, - { 0x1319, 0xff }, - { 0x131a, 0xff }, - { 0x131b, 0xff }, - { 0x131c, 0xff }, - { 0x131e, 0xff }, - { 0x131f, 0xff }, - { 0x1320, 0xff }, - { 0x1b79, 0xff }, - { 0x1b7a, 0xff }, + { CS42L42_ADC_VOLUME, 0x9F }, + { CS42L42_OSC_SWITCH, 0x01 }, + { CS42L42_MCLK_CTL, 0x02 }, + { CS42L42_SRC_CTL, 0x03 }, + { CS42L42_MCLK_SRC_SEL, 0x00 }, + { CS42L42_ASP_FRM_CFG, 0x13 }, + { CS42L42_FSYNC_P_LOWER, 0xFF }, + { CS42L42_FSYNC_P_UPPER, 0x00 }, + { CS42L42_ASP_CLK_CFG, 0x20 }, + { CS42L42_SPDIF_CLK_CFG, 0x0D }, + { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x02 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x02 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x20 }, + { CS42L42_ASP_RX_DAI0_CH3_AP_RES, 0x02 }, + { CS42L42_ASP_RX_DAI0_CH3_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH3_BIT_LSB, 0x80 }, + { CS42L42_ASP_RX_DAI0_CH4_AP_RES, 0x02 }, + { CS42L42_ASP_RX_DAI0_CH4_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH4_BIT_LSB, 0xA0 }, + { CS42L42_ASP_RX_DAI0_EN, 0x0C }, + { CS42L42_ASP_TX_CH_EN, 0x01 }, + { CS42L42_ASP_TX_CH_AP_RES, 0x02 }, + { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_TX_SZ_EN, 0x01 }, + { CS42L42_PWR_CTL1, 0x0A }, + { CS42L42_PWR_CTL2, 0x84 }, + { CS42L42_MIXER_CHA_VOL, 0x3F }, + { CS42L42_MIXER_CHB_VOL, 0x3F }, + { CS42L42_MIXER_ADC_VOL, 0x3f }, + { CS42L42_HP_CTL, 0x03 }, + { CS42L42_MIC_DET_CTL1, 0xB6 }, + { CS42L42_TIPSENSE_CTL, 0xC2 }, + { CS42L42_HS_CLAMP_DISABLE, 0x01 }, + { CS42L42_HS_SWITCH_CTL, 0xF3 }, + { CS42L42_PWR_CTL3, 0x20 }, + { CS42L42_RSENSE_CTL2, 0x00 }, + { CS42L42_RSENSE_CTL3, 0x00 }, + { CS42L42_TSENSE_CTL, 0x80 }, + { CS42L42_HS_BIAS_CTL, 0xC0 }, + { CS42L42_PWR_CTL1, 0x02 }, + { CS42L42_ADC_OVFL_INT_MASK, 0xff }, + { CS42L42_MIXER_INT_MASK, 0xff }, + { CS42L42_SRC_INT_MASK, 0xff }, + { CS42L42_ASP_RX_INT_MASK, 0xff }, + { CS42L42_ASP_TX_INT_MASK, 0xff }, + { CS42L42_CODEC_INT_MASK, 0xff }, + { CS42L42_SRCPL_INT_MASK, 0xff }, + { CS42L42_VPMON_INT_MASK, 0xff }, + { CS42L42_PLL_LOCK_INT_MASK, 0xff }, + { CS42L42_TSRS_PLUG_INT_MASK, 0xff }, + { CS42L42_DET_INT1_MASK, 0xff }, + { CS42L42_DET_INT2_MASK, 0xff }, }; /* Vendor specific hw configuration for CS8409 */ @@ -252,7 +259,6 @@ struct sub_codec cs8409_cs42l42_codec = { .init_seq_num = ARRAY_SIZE(cs42l42_init_reg_seq), .hp_jack_in = 0, .mic_jack_in = 0, - .force_status_change = 1, .paged = 1, .suspended = 1, .no_type_dect = 0, @@ -273,7 +279,7 @@ const struct hda_verb dolphin_init_verbs[] = { {} /* terminator */ }; -const struct hda_pintbl dolphin_pincfgs[] = { +static const struct hda_pintbl dolphin_pincfgs[] = { { 0x24, 0x022210f0 }, /* ASP-1-TX-A */ { 0x25, 0x010240f0 }, /* ASP-1-TX-B */ { 0x34, 0x02a21050 }, /* ASP-1-RX */ @@ -282,115 +288,115 @@ const struct hda_pintbl dolphin_pincfgs[] = { /* Vendor specific HW configuration for CS42L42 */ static const struct cs8409_i2c_param dolphin_c0_init_reg_seq[] = { - { 0x1010, 0xB0 }, - { 0x1D01, 0x00 }, + { CS42L42_I2C_TIMEOUT, 0xB0 }, + { CS42L42_ADC_CTL, 0x00 }, { 0x1D02, 0x06 }, - { 0x1D03, 0x9F }, - { 0x1107, 0x01 }, - { 0x1009, 0x02 }, - { 0x1007, 0x03 }, - { 0x1201, 0x00 }, - { 0x1208, 0x13 }, - { 0x1205, 0xFF }, - { 0x1206, 0x00 }, - { 0x1207, 0x20 }, - { 0x1202, 0x0D }, - { 0x2A02, 0x02 }, - { 0x2A03, 0x00 }, - { 0x2A04, 0x00 }, - { 0x2A05, 0x02 }, - { 0x2A06, 0x00 }, - { 0x2A07, 0x20 }, - { 0x2A01, 0x0C }, - { 0x2902, 0x01 }, - { 0x2903, 0x02 }, - { 0x2904, 0x00 }, - { 0x2905, 0x00 }, - { 0x2901, 0x01 }, - { 0x1101, 0x0A }, - { 0x1102, 0x84 }, - { 0x2001, 0x03 }, - { 0x2301, 0x3F }, - { 0x2303, 0x3F }, - { 0x2302, 0x3f }, - { 0x1B75, 0xB6 }, - { 0x1B73, 0xC2 }, - { 0x1129, 0x01 }, - { 0x1121, 0xF3 }, - { 0x1103, 0x20 }, - { 0x1105, 0x00 }, - { 0x1112, 0x00 }, - { 0x1113, 0x80 }, - { 0x1C03, 0xC0 }, - { 0x1101, 0x02 }, - { 0x1316, 0xff }, - { 0x1317, 0xff }, - { 0x1318, 0xff }, - { 0x1319, 0xff }, - { 0x131a, 0xff }, - { 0x131b, 0xff }, - { 0x131c, 0xff }, - { 0x131e, 0xff }, - { 0x131f, 0xff }, - { 0x1320, 0xff }, - { 0x1b79, 0xff }, - { 0x1b7a, 0xff } + { CS42L42_ADC_VOLUME, 0x9F }, + { CS42L42_OSC_SWITCH, 0x01 }, + { CS42L42_MCLK_CTL, 0x02 }, + { CS42L42_SRC_CTL, 0x03 }, + { CS42L42_MCLK_SRC_SEL, 0x00 }, + { CS42L42_ASP_FRM_CFG, 0x13 }, + { CS42L42_FSYNC_P_LOWER, 0xFF }, + { CS42L42_FSYNC_P_UPPER, 0x00 }, + { CS42L42_ASP_CLK_CFG, 0x20 }, + { CS42L42_SPDIF_CLK_CFG, 0x0D }, + { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x02 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x02 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x20 }, + { CS42L42_ASP_RX_DAI0_EN, 0x0C }, + { CS42L42_ASP_TX_CH_EN, 0x01 }, + { CS42L42_ASP_TX_CH_AP_RES, 0x02 }, + { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_TX_SZ_EN, 0x01 }, + { CS42L42_PWR_CTL1, 0x0A }, + { CS42L42_PWR_CTL2, 0x84 }, + { CS42L42_HP_CTL, 0x03 }, + { CS42L42_MIXER_CHA_VOL, 0x3F }, + { CS42L42_MIXER_CHB_VOL, 0x3F }, + { CS42L42_MIXER_ADC_VOL, 0x3f }, + { CS42L42_MIC_DET_CTL1, 0xB6 }, + { CS42L42_TIPSENSE_CTL, 0xC2 }, + { CS42L42_HS_CLAMP_DISABLE, 0x01 }, + { CS42L42_HS_SWITCH_CTL, 0xF3 }, + { CS42L42_PWR_CTL3, 0x20 }, + { CS42L42_RSENSE_CTL2, 0x00 }, + { CS42L42_RSENSE_CTL3, 0x00 }, + { CS42L42_TSENSE_CTL, 0x80 }, + { CS42L42_HS_BIAS_CTL, 0xC0 }, + { CS42L42_PWR_CTL1, 0x02 }, + { CS42L42_ADC_OVFL_INT_MASK, 0xff }, + { CS42L42_MIXER_INT_MASK, 0xff }, + { CS42L42_SRC_INT_MASK, 0xff }, + { CS42L42_ASP_RX_INT_MASK, 0xff }, + { CS42L42_ASP_TX_INT_MASK, 0xff }, + { CS42L42_CODEC_INT_MASK, 0xff }, + { CS42L42_SRCPL_INT_MASK, 0xff }, + { CS42L42_VPMON_INT_MASK, 0xff }, + { CS42L42_PLL_LOCK_INT_MASK, 0xff }, + { CS42L42_TSRS_PLUG_INT_MASK, 0xff }, + { CS42L42_DET_INT1_MASK, 0xff }, + { CS42L42_DET_INT2_MASK, 0xff } }; static const struct cs8409_i2c_param dolphin_c1_init_reg_seq[] = { - { 0x1010, 0xB0 }, - { 0x1D01, 0x00 }, + { CS42L42_I2C_TIMEOUT, 0xB0 }, + { CS42L42_ADC_CTL, 0x00 }, { 0x1D02, 0x06 }, - { 0x1D03, 0x9F }, - { 0x1107, 0x01 }, - { 0x1009, 0x02 }, - { 0x1007, 0x03 }, - { 0x1201, 0x00 }, - { 0x1208, 0x13 }, - { 0x1205, 0xFF }, - { 0x1206, 0x00 }, - { 0x1207, 0x20 }, - { 0x1202, 0x0D }, - { 0x2A02, 0x02 }, - { 0x2A03, 0x00 }, - { 0x2A04, 0x80 }, - { 0x2A05, 0x02 }, - { 0x2A06, 0x00 }, - { 0x2A07, 0xA0 }, - { 0x2A01, 0x0C }, - { 0x2902, 0x00 }, - { 0x2903, 0x02 }, - { 0x2904, 0x00 }, - { 0x2905, 0x00 }, - { 0x2901, 0x00 }, - { 0x1101, 0x0E }, - { 0x1102, 0x84 }, - { 0x2001, 0x01 }, - { 0x2301, 0x3F }, - { 0x2303, 0x3F }, - { 0x2302, 0x3f }, - { 0x1B75, 0xB6 }, - { 0x1B73, 0xC2 }, - { 0x1129, 0x01 }, - { 0x1121, 0xF3 }, - { 0x1103, 0x20 }, - { 0x1105, 0x00 }, - { 0x1112, 0x00 }, - { 0x1113, 0x80 }, - { 0x1C03, 0xC0 }, - { 0x1101, 0x06 }, - { 0x1316, 0xff }, - { 0x1317, 0xff }, - { 0x1318, 0xff }, - { 0x1319, 0xff }, - { 0x131a, 0xff }, - { 0x131b, 0xff }, - { 0x131c, 0xff }, - { 0x131e, 0xff }, - { 0x131f, 0xff }, - { 0x1320, 0xff }, - { 0x1b79, 0xff }, - { 0x1b7a, 0xff } + { CS42L42_ADC_VOLUME, 0x9F }, + { CS42L42_OSC_SWITCH, 0x01 }, + { CS42L42_MCLK_CTL, 0x02 }, + { CS42L42_SRC_CTL, 0x03 }, + { CS42L42_MCLK_SRC_SEL, 0x00 }, + { CS42L42_ASP_FRM_CFG, 0x13 }, + { CS42L42_FSYNC_P_LOWER, 0xFF }, + { CS42L42_FSYNC_P_UPPER, 0x00 }, + { CS42L42_ASP_CLK_CFG, 0x20 }, + { CS42L42_SPDIF_CLK_CFG, 0x0D }, + { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x02 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x80 }, + { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x02 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0xA0 }, + { CS42L42_ASP_RX_DAI0_EN, 0x0C }, + { CS42L42_ASP_TX_CH_EN, 0x00 }, + { CS42L42_ASP_TX_CH_AP_RES, 0x02 }, + { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_TX_SZ_EN, 0x00 }, + { CS42L42_PWR_CTL1, 0x0E }, + { CS42L42_PWR_CTL2, 0x84 }, + { CS42L42_HP_CTL, 0x01 }, + { CS42L42_MIXER_CHA_VOL, 0x3F }, + { CS42L42_MIXER_CHB_VOL, 0x3F }, + { CS42L42_MIXER_ADC_VOL, 0x3f }, + { CS42L42_MIC_DET_CTL1, 0xB6 }, + { CS42L42_TIPSENSE_CTL, 0xC2 }, + { CS42L42_HS_CLAMP_DISABLE, 0x01 }, + { CS42L42_HS_SWITCH_CTL, 0xF3 }, + { CS42L42_PWR_CTL3, 0x20 }, + { CS42L42_RSENSE_CTL2, 0x00 }, + { CS42L42_RSENSE_CTL3, 0x00 }, + { CS42L42_TSENSE_CTL, 0x80 }, + { CS42L42_HS_BIAS_CTL, 0xC0 }, + { CS42L42_PWR_CTL1, 0x06 }, + { CS42L42_ADC_OVFL_INT_MASK, 0xff }, + { CS42L42_MIXER_INT_MASK, 0xff }, + { CS42L42_SRC_INT_MASK, 0xff }, + { CS42L42_ASP_RX_INT_MASK, 0xff }, + { CS42L42_ASP_TX_INT_MASK, 0xff }, + { CS42L42_CODEC_INT_MASK, 0xff }, + { CS42L42_SRCPL_INT_MASK, 0xff }, + { CS42L42_VPMON_INT_MASK, 0xff }, + { CS42L42_PLL_LOCK_INT_MASK, 0xff }, + { CS42L42_TSRS_PLUG_INT_MASK, 0xff }, + { CS42L42_DET_INT1_MASK, 0xff }, + { CS42L42_DET_INT2_MASK, 0xff } }; /* Vendor specific hw configuration for CS8409 */ @@ -444,7 +450,6 @@ struct sub_codec dolphin_cs42l42_0 = { .init_seq_num = ARRAY_SIZE(dolphin_c0_init_reg_seq), .hp_jack_in = 0, .mic_jack_in = 0, - .force_status_change = 1, .paged = 1, .suspended = 1, .no_type_dect = 0, @@ -458,7 +463,6 @@ struct sub_codec dolphin_cs42l42_1 = { .init_seq_num = ARRAY_SIZE(dolphin_c1_init_reg_seq), .hp_jack_in = 0, .mic_jack_in = 0, - .force_status_change = 1, .paged = 1, .suspended = 1, .no_type_dect = 1, @@ -521,6 +525,11 @@ const struct snd_pci_quirk cs8409_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0B95, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC), SND_PCI_QUIRK(0x1028, 0x0B96, "Warlock MLK", CS8409_WARLOCK_MLK), SND_PCI_QUIRK(0x1028, 0x0B97, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC), + SND_PCI_QUIRK(0x1028, 0x0BA5, "Odin", CS8409_ODIN), + SND_PCI_QUIRK(0x1028, 0x0BA6, "Odin", CS8409_ODIN), + SND_PCI_QUIRK(0x1028, 0x0BA8, "Odin", CS8409_ODIN), + SND_PCI_QUIRK(0x1028, 0x0BAA, "Odin", CS8409_ODIN), + SND_PCI_QUIRK(0x1028, 0x0BAE, "Odin", CS8409_ODIN), SND_PCI_QUIRK(0x1028, 0x0BB2, "Warlock MLK", CS8409_WARLOCK_MLK), SND_PCI_QUIRK(0x1028, 0x0BB3, "Warlock MLK", CS8409_WARLOCK_MLK), SND_PCI_QUIRK(0x1028, 0x0BB4, "Warlock MLK", CS8409_WARLOCK_MLK), @@ -537,6 +546,10 @@ const struct snd_pci_quirk cs8409_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0BD6, "Dolphin", CS8409_DOLPHIN), SND_PCI_QUIRK(0x1028, 0x0BD7, "Dolphin", CS8409_DOLPHIN), SND_PCI_QUIRK(0x1028, 0x0BD8, "Dolphin", CS8409_DOLPHIN), + SND_PCI_QUIRK(0x1028, 0x0C43, "Dolphin", CS8409_DOLPHIN), + SND_PCI_QUIRK(0x1028, 0x0C50, "Dolphin", CS8409_DOLPHIN), + SND_PCI_QUIRK(0x1028, 0x0C51, "Dolphin", CS8409_DOLPHIN), + SND_PCI_QUIRK(0x1028, 0x0C52, "Dolphin", CS8409_DOLPHIN), {} /* terminator */ }; @@ -548,6 +561,7 @@ const struct hda_model_fixup cs8409_models[] = { { .id = CS8409_WARLOCK_MLK_DUAL_MIC, .name = "warlock mlk dual mic" }, { .id = CS8409_CYBORG, .name = "cyborg" }, { .id = CS8409_DOLPHIN, .name = "dolphin" }, + { .id = CS8409_ODIN, .name = "odin" }, {} }; @@ -596,4 +610,10 @@ const struct hda_fixup cs8409_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = dolphin_fixups, }, + [CS8409_ODIN] = { + .type = HDA_FIXUP_PINS, + .v.pins = cs8409_cs42l42_pincfgs_no_dmic, + .chained = true, + .chain_id = CS8409_FIXUPS, + }, }; diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c index 343fabc438..754aa8ddd2 100644 --- a/sound/pci/hda/patch_cs8409.c +++ b/sound/pci/hda/patch_cs8409.c @@ -419,6 +419,39 @@ static void cs8409_fix_caps(struct hda_codec *codec, unsigned int nid) snd_hda_override_wcaps(codec, nid, (get_wcaps(codec, nid) | AC_WCAP_UNSOL_CAP)); } +static int cs8409_spk_sw_gpio_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cs8409_spec *spec = codec->spec; + + ucontrol->value.integer.value[0] = !!(spec->gpio_data & spec->speaker_pdn_gpio); + return 0; +} + +static int cs8409_spk_sw_gpio_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cs8409_spec *spec = codec->spec; + unsigned int gpio_data; + + gpio_data = (spec->gpio_data & ~spec->speaker_pdn_gpio) | + (ucontrol->value.integer.value[0] ? spec->speaker_pdn_gpio : 0); + if (gpio_data == spec->gpio_data) + return 0; + spec->gpio_data = gpio_data; + snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data); + return 1; +} + +static const struct snd_kcontrol_new cs8409_spk_sw_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = snd_ctl_boolean_mono_info, + .get = cs8409_spk_sw_gpio_get, + .put = cs8409_spk_sw_gpio_put, +}; + /****************************************************************************** * CS42L42 Specific Functions ******************************************************************************/ @@ -481,26 +514,26 @@ static void cs42l42_mute(struct sub_codec *cs42l42, int vol_type, if (mute) { if (vol_type == CS42L42_VOL_DAC) { if (chs & BIT(0)) - cs8409_i2c_write(cs42l42, CS42L42_REG_HS_VOL_CHA, 0x3f); + cs8409_i2c_write(cs42l42, CS42L42_MIXER_CHA_VOL, 0x3f); if (chs & BIT(1)) - cs8409_i2c_write(cs42l42, CS42L42_REG_HS_VOL_CHB, 0x3f); + cs8409_i2c_write(cs42l42, CS42L42_MIXER_CHB_VOL, 0x3f); } else if (vol_type == CS42L42_VOL_ADC) { if (chs & BIT(0)) - cs8409_i2c_write(cs42l42, CS42L42_REG_AMIC_VOL, 0x9f); + cs8409_i2c_write(cs42l42, CS42L42_ADC_VOLUME, 0x9f); } } else { if (vol_type == CS42L42_VOL_DAC) { if (chs & BIT(0)) - cs8409_i2c_write(cs42l42, CS42L42_REG_HS_VOL_CHA, + cs8409_i2c_write(cs42l42, CS42L42_MIXER_CHA_VOL, -(cs42l42->vol[CS42L42_DAC_CH0_VOL_OFFSET]) - & CS42L42_REG_HS_VOL_MASK); + & CS42L42_MIXER_CH_VOL_MASK); if (chs & BIT(1)) - cs8409_i2c_write(cs42l42, CS42L42_REG_HS_VOL_CHB, + cs8409_i2c_write(cs42l42, CS42L42_MIXER_CHB_VOL, -(cs42l42->vol[CS42L42_DAC_CH1_VOL_OFFSET]) - & CS42L42_REG_HS_VOL_MASK); + & CS42L42_MIXER_CH_VOL_MASK); } else if (vol_type == CS42L42_VOL_ADC) { if (chs & BIT(0)) - cs8409_i2c_write(cs42l42, CS42L42_REG_AMIC_VOL, + cs8409_i2c_write(cs42l42, CS42L42_ADC_VOLUME, cs42l42->vol[CS42L42_ADC_VOL_OFFSET] & CS42L42_REG_AMIC_VOL_MASK); } @@ -601,76 +634,167 @@ static void cs42l42_capture_pcm_hook(struct hda_pcm_stream *hinfo, /* Configure CS42L42 slave codec for jack autodetect */ static void cs42l42_enable_jack_detect(struct sub_codec *cs42l42) { - cs8409_i2c_write(cs42l42, 0x1b70, cs42l42->hsbias_hiz); + cs8409_i2c_write(cs42l42, CS42L42_HSBIAS_SC_AUTOCTL, cs42l42->hsbias_hiz); /* Clear WAKE# */ - cs8409_i2c_write(cs42l42, 0x1b71, 0x00C1); + cs8409_i2c_write(cs42l42, CS42L42_WAKE_CTL, 0x00C1); /* Wait ~2.5ms */ usleep_range(2500, 3000); /* Set mode WAKE# output follows the combination logic directly */ - cs8409_i2c_write(cs42l42, 0x1b71, 0x00C0); + cs8409_i2c_write(cs42l42, CS42L42_WAKE_CTL, 0x00C0); /* Clear interrupts status */ - cs8409_i2c_read(cs42l42, 0x130f); + cs8409_i2c_read(cs42l42, CS42L42_TSRS_PLUG_STATUS); /* Enable interrupt */ - cs8409_i2c_write(cs42l42, 0x1320, 0xF3); + cs8409_i2c_write(cs42l42, CS42L42_TSRS_PLUG_INT_MASK, 0xF3); } /* Enable and run CS42L42 slave codec jack auto detect */ static void cs42l42_run_jack_detect(struct sub_codec *cs42l42) { /* Clear interrupts */ - cs8409_i2c_read(cs42l42, 0x1308); - cs8409_i2c_read(cs42l42, 0x1b77); - cs8409_i2c_write(cs42l42, 0x1320, 0xFF); - cs8409_i2c_read(cs42l42, 0x130f); - - cs8409_i2c_write(cs42l42, 0x1102, 0x87); - cs8409_i2c_write(cs42l42, 0x1f06, 0x86); - cs8409_i2c_write(cs42l42, 0x1b74, 0x07); - cs8409_i2c_write(cs42l42, 0x131b, 0xFD); - cs8409_i2c_write(cs42l42, 0x1120, 0x80); + cs8409_i2c_read(cs42l42, CS42L42_CODEC_STATUS); + cs8409_i2c_read(cs42l42, CS42L42_DET_STATUS1); + cs8409_i2c_write(cs42l42, CS42L42_TSRS_PLUG_INT_MASK, 0xFF); + cs8409_i2c_read(cs42l42, CS42L42_TSRS_PLUG_STATUS); + + cs8409_i2c_write(cs42l42, CS42L42_PWR_CTL2, 0x87); + cs8409_i2c_write(cs42l42, CS42L42_DAC_CTL2, 0x86); + cs8409_i2c_write(cs42l42, CS42L42_MISC_DET_CTL, 0x07); + cs8409_i2c_write(cs42l42, CS42L42_CODEC_INT_MASK, 0xFD); + cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2, 0x80); /* Wait ~20ms*/ usleep_range(20000, 25000); - cs8409_i2c_write(cs42l42, 0x111f, 0x77); - cs8409_i2c_write(cs42l42, 0x1120, 0xc0); + cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL1, 0x77); + cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2, 0xc0); } -static int cs42l42_handle_tip_sense(struct sub_codec *cs42l42, unsigned int reg_ts_status) +static int cs42l42_manual_hs_det(struct sub_codec *cs42l42) { - int status_changed = cs42l42->force_status_change; + unsigned int hs_det_status; + unsigned int hs_det_comp1; + unsigned int hs_det_comp2; + unsigned int hs_det_sw; + unsigned int hs_type; - cs42l42->force_status_change = 0; + /* Set hs detect to manual, active mode */ + cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2, + (1 << CS42L42_HSDET_CTRL_SHIFT) | + (0 << CS42L42_HSDET_SET_SHIFT) | + (0 << CS42L42_HSBIAS_REF_SHIFT) | + (0 << CS42L42_HSDET_AUTO_TIME_SHIFT)); - /* TIP_SENSE INSERT/REMOVE */ - switch (reg_ts_status) { - case CS42L42_JACK_INSERTED: - if (!cs42l42->hp_jack_in) { - if (cs42l42->no_type_dect) { - status_changed = 1; - cs42l42->hp_jack_in = 1; - cs42l42->mic_jack_in = 0; - } else { - cs42l42_run_jack_detect(cs42l42); - } - } + /* Configure HS DET comparator reference levels. */ + cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL1, + (CS42L42_HSDET_COMP1_LVL_VAL << CS42L42_HSDET_COMP1_LVL_SHIFT) | + (CS42L42_HSDET_COMP2_LVL_VAL << CS42L42_HSDET_COMP2_LVL_SHIFT)); + + /* Open the SW_HSB_HS3 switch and close SW_HSB_HS4 for a Type 1 headset. */ + cs8409_i2c_write(cs42l42, CS42L42_HS_SWITCH_CTL, CS42L42_HSDET_SW_COMP1); + + msleep(100); + + hs_det_status = cs8409_i2c_read(cs42l42, CS42L42_HS_DET_STATUS); + + hs_det_comp1 = (hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK) >> + CS42L42_HSDET_COMP1_OUT_SHIFT; + hs_det_comp2 = (hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK) >> + CS42L42_HSDET_COMP2_OUT_SHIFT; + + /* Close the SW_HSB_HS3 switch for a Type 2 headset. */ + cs8409_i2c_write(cs42l42, CS42L42_HS_SWITCH_CTL, CS42L42_HSDET_SW_COMP2); + + msleep(100); + + hs_det_status = cs8409_i2c_read(cs42l42, CS42L42_HS_DET_STATUS); + + hs_det_comp1 |= ((hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK) >> + CS42L42_HSDET_COMP1_OUT_SHIFT) << 1; + hs_det_comp2 |= ((hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK) >> + CS42L42_HSDET_COMP2_OUT_SHIFT) << 1; + + /* Use Comparator 1 with 1.25V Threshold. */ + switch (hs_det_comp1) { + case CS42L42_HSDET_COMP_TYPE1: + hs_type = CS42L42_PLUG_CTIA; + hs_det_sw = CS42L42_HSDET_SW_TYPE1; + break; + case CS42L42_HSDET_COMP_TYPE2: + hs_type = CS42L42_PLUG_OMTP; + hs_det_sw = CS42L42_HSDET_SW_TYPE2; break; + default: + /* Fallback to Comparator 2 with 1.75V Threshold. */ + switch (hs_det_comp2) { + case CS42L42_HSDET_COMP_TYPE1: + hs_type = CS42L42_PLUG_CTIA; + hs_det_sw = CS42L42_HSDET_SW_TYPE1; + break; + case CS42L42_HSDET_COMP_TYPE2: + hs_type = CS42L42_PLUG_OMTP; + hs_det_sw = CS42L42_HSDET_SW_TYPE2; + break; + case CS42L42_HSDET_COMP_TYPE3: + hs_type = CS42L42_PLUG_HEADPHONE; + hs_det_sw = CS42L42_HSDET_SW_TYPE3; + break; + default: + hs_type = CS42L42_PLUG_INVALID; + hs_det_sw = CS42L42_HSDET_SW_TYPE4; + break; + } + } + + /* Set Switches */ + cs8409_i2c_write(cs42l42, CS42L42_HS_SWITCH_CTL, hs_det_sw); + + /* Set HSDET mode to Manual—Disabled */ + cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2, + (0 << CS42L42_HSDET_CTRL_SHIFT) | + (0 << CS42L42_HSDET_SET_SHIFT) | + (0 << CS42L42_HSBIAS_REF_SHIFT) | + (0 << CS42L42_HSDET_AUTO_TIME_SHIFT)); - case CS42L42_JACK_REMOVED: - if (cs42l42->hp_jack_in || cs42l42->mic_jack_in) { + /* Configure HS DET comparator reference levels. */ + cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL1, + (CS42L42_HSDET_COMP1_LVL_DEFAULT << CS42L42_HSDET_COMP1_LVL_SHIFT) | + (CS42L42_HSDET_COMP2_LVL_DEFAULT << CS42L42_HSDET_COMP2_LVL_SHIFT)); + + return hs_type; +} + +static int cs42l42_handle_tip_sense(struct sub_codec *cs42l42, unsigned int reg_ts_status) +{ + int status_changed = 0; + + /* TIP_SENSE INSERT/REMOVE */ + switch (reg_ts_status) { + case CS42L42_TS_PLUG: + if (cs42l42->no_type_dect) { status_changed = 1; - cs42l42->hp_jack_in = 0; + cs42l42->hp_jack_in = 1; cs42l42->mic_jack_in = 0; + } else { + cs42l42_run_jack_detect(cs42l42); } break; + + case CS42L42_TS_UNPLUG: + status_changed = 1; + cs42l42->hp_jack_in = 0; + cs42l42->mic_jack_in = 0; + break; default: /* jack in transition */ break; } + codec_dbg(cs42l42->codec, "Tip Sense Detection: (%d)\n", reg_ts_status); + return status_changed; } static int cs42l42_jack_unsol_event(struct sub_codec *cs42l42) { + int current_plug_status; int status_changed = 0; int reg_cdc_status; int reg_hs_status; @@ -678,46 +802,65 @@ static int cs42l42_jack_unsol_event(struct sub_codec *cs42l42) int type; /* Read jack detect status registers */ - reg_cdc_status = cs8409_i2c_read(cs42l42, 0x1308); - reg_hs_status = cs8409_i2c_read(cs42l42, 0x1124); - reg_ts_status = cs8409_i2c_read(cs42l42, 0x130f); + reg_cdc_status = cs8409_i2c_read(cs42l42, CS42L42_CODEC_STATUS); + reg_hs_status = cs8409_i2c_read(cs42l42, CS42L42_HS_DET_STATUS); + reg_ts_status = cs8409_i2c_read(cs42l42, CS42L42_TSRS_PLUG_STATUS); /* If status values are < 0, read error has occurred. */ if (reg_cdc_status < 0 || reg_hs_status < 0 || reg_ts_status < 0) return -EIO; + current_plug_status = (reg_ts_status & (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) + >> CS42L42_TS_PLUG_SHIFT; + /* HSDET_AUTO_DONE */ - if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) { + if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE_MASK) { /* Disable HSDET_AUTO_DONE */ - cs8409_i2c_write(cs42l42, 0x131b, 0xFF); + cs8409_i2c_write(cs42l42, CS42L42_CODEC_INT_MASK, 0xFF); + + type = (reg_hs_status & CS42L42_HSDET_TYPE_MASK) >> CS42L42_HSDET_TYPE_SHIFT; - type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1); + /* Configure the HSDET mode. */ + cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2, 0x80); if (cs42l42->no_type_dect) { - status_changed = cs42l42_handle_tip_sense(cs42l42, reg_ts_status); - } else if (type == 4) { - /* Type 4 not supported */ - status_changed = cs42l42_handle_tip_sense(cs42l42, CS42L42_JACK_REMOVED); + status_changed = cs42l42_handle_tip_sense(cs42l42, current_plug_status); } else { - if (!cs42l42->hp_jack_in) { - status_changed = 1; - cs42l42->hp_jack_in = 1; + if (type == CS42L42_PLUG_INVALID || type == CS42L42_PLUG_HEADPHONE) { + codec_dbg(cs42l42->codec, + "Auto detect value not valid (%d), running manual det\n", + type); + type = cs42l42_manual_hs_det(cs42l42); } - /* type = 3 has no mic */ - if ((!cs42l42->mic_jack_in) && (type != 3)) { + + switch (type) { + case CS42L42_PLUG_CTIA: + case CS42L42_PLUG_OMTP: status_changed = 1; + cs42l42->hp_jack_in = 1; cs42l42->mic_jack_in = 1; + break; + case CS42L42_PLUG_HEADPHONE: + status_changed = 1; + cs42l42->hp_jack_in = 1; + cs42l42->mic_jack_in = 0; + break; + default: + status_changed = 1; + cs42l42->hp_jack_in = 0; + cs42l42->mic_jack_in = 0; + break; } + codec_dbg(cs42l42->codec, "Detection done (%d)\n", type); } - /* Configure the HSDET mode. */ - cs8409_i2c_write(cs42l42, 0x1120, 0x80); + /* Enable the HPOUT ground clamp and configure the HP pull-down */ - cs8409_i2c_write(cs42l42, 0x1F06, 0x02); + cs8409_i2c_write(cs42l42, CS42L42_DAC_CTL2, 0x02); /* Re-Enable Tip Sense Interrupt */ - cs8409_i2c_write(cs42l42, 0x1320, 0xF3); + cs8409_i2c_write(cs42l42, CS42L42_TSRS_PLUG_INT_MASK, 0xF3); } else { - status_changed = cs42l42_handle_tip_sense(cs42l42, reg_ts_status); + status_changed = cs42l42_handle_tip_sense(cs42l42, current_plug_status); } return status_changed; @@ -726,19 +869,19 @@ static int cs42l42_jack_unsol_event(struct sub_codec *cs42l42) static void cs42l42_resume(struct sub_codec *cs42l42) { struct hda_codec *codec = cs42l42->codec; - unsigned int gpio_data; + struct cs8409_spec *spec = codec->spec; struct cs8409_i2c_param irq_regs[] = { - { 0x1308, 0x00 }, - { 0x1309, 0x00 }, - { 0x130A, 0x00 }, - { 0x130F, 0x00 }, + { CS42L42_CODEC_STATUS, 0x00 }, + { CS42L42_DET_INT_STATUS1, 0x00 }, + { CS42L42_DET_INT_STATUS2, 0x00 }, + { CS42L42_TSRS_PLUG_STATUS, 0x00 }, }; int fsv_old, fsv_new; /* Bring CS42L42 out of Reset */ - gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0); - gpio_data |= cs42l42->reset_gpio; - snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, gpio_data); + spec->gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0); + spec->gpio_data |= cs42l42->reset_gpio; + snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data); usleep_range(10000, 15000); cs42l42->suspended = 0; @@ -750,13 +893,13 @@ static void cs42l42_resume(struct sub_codec *cs42l42) /* Clear interrupts, by reading interrupt status registers */ cs8409_i2c_bulk_read(cs42l42, irq_regs, ARRAY_SIZE(irq_regs)); - fsv_old = cs8409_i2c_read(cs42l42, 0x2001); + fsv_old = cs8409_i2c_read(cs42l42, CS42L42_HP_CTL); if (cs42l42->full_scale_vol == CS42L42_FULL_SCALE_VOL_0DB) fsv_new = fsv_old & ~CS42L42_FULL_SCALE_VOL_MASK; else fsv_new = fsv_old & CS42L42_FULL_SCALE_VOL_MASK; if (fsv_new != fsv_old) - cs8409_i2c_write(cs42l42, 0x2001, fsv_new); + cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv_new); /* we have to explicitly allow unsol event handling even during the * resume phase so that the jack event is processed properly @@ -770,41 +913,40 @@ static void cs42l42_resume(struct sub_codec *cs42l42) static void cs42l42_suspend(struct sub_codec *cs42l42) { struct hda_codec *codec = cs42l42->codec; - unsigned int gpio_data; + struct cs8409_spec *spec = codec->spec; int reg_cdc_status = 0; const struct cs8409_i2c_param cs42l42_pwr_down_seq[] = { - { 0x1F06, 0x02 }, - { 0x1129, 0x00 }, - { 0x2301, 0x3F }, - { 0x2302, 0x3F }, - { 0x2303, 0x3F }, - { 0x2001, 0x0F }, - { 0x2A01, 0x00 }, - { 0x1207, 0x00 }, - { 0x1101, 0xFE }, - { 0x1102, 0x8C }, - { 0x1101, 0xFF }, + { CS42L42_DAC_CTL2, 0x02 }, + { CS42L42_HS_CLAMP_DISABLE, 0x00 }, + { CS42L42_MIXER_CHA_VOL, 0x3F }, + { CS42L42_MIXER_ADC_VOL, 0x3F }, + { CS42L42_MIXER_CHB_VOL, 0x3F }, + { CS42L42_HP_CTL, 0x0F }, + { CS42L42_ASP_RX_DAI0_EN, 0x00 }, + { CS42L42_ASP_CLK_CFG, 0x00 }, + { CS42L42_PWR_CTL1, 0xFE }, + { CS42L42_PWR_CTL2, 0x8C }, + { CS42L42_PWR_CTL1, 0xFF }, }; cs8409_i2c_bulk_write(cs42l42, cs42l42_pwr_down_seq, ARRAY_SIZE(cs42l42_pwr_down_seq)); if (read_poll_timeout(cs8409_i2c_read, reg_cdc_status, (reg_cdc_status & 0x1), CS42L42_PDN_SLEEP_US, CS42L42_PDN_TIMEOUT_US, - true, cs42l42, 0x1308) < 0) + true, cs42l42, CS42L42_CODEC_STATUS) < 0) codec_warn(codec, "Timeout waiting for PDN_DONE for CS42L42\n"); /* Power down CS42L42 ASP/EQ/MIX/HP */ - cs8409_i2c_write(cs42l42, 0x1102, 0x9C); + cs8409_i2c_write(cs42l42, CS42L42_PWR_CTL2, 0x9C); cs42l42->suspended = 1; cs42l42->last_page = 0; cs42l42->hp_jack_in = 0; cs42l42->mic_jack_in = 0; - cs42l42->force_status_change = 1; /* Put CS42L42 into Reset */ - gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0); - gpio_data &= ~cs42l42->reset_gpio; - snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, gpio_data); + spec->gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0); + spec->gpio_data &= ~cs42l42->reset_gpio; + snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data); } #endif @@ -918,6 +1060,10 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec) /* DMIC1_MO=00b, DMIC1/2_SR=1 */ cs8409_vendor_coef_set(codec, CS8409_DMIC_CFG, 0x0003); break; + case CS8409_ODIN: + /* ASP1/2_xxx_EN=1, ASP1/2_MCLK_EN=0, DMIC1_SCL_EN=0 */ + cs8409_vendor_coef_set(codec, CS8409_PAD_CFG_SLW_RATE_CTRL, 0xfc00); + break; default: break; } @@ -994,6 +1140,8 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, spec->gen.no_primary_hp = 1; spec->gen.suppress_vmaster = 1; + spec->speaker_pdn_gpio = 0; + /* GPIO 5 out, 3,4 in */ spec->gpio_dir = spec->scodecs[CS8409_CODEC0]->reset_gpio; spec->gpio_data = 0; @@ -1005,20 +1153,35 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, cs8409_fix_caps(codec, CS8409_CS42L42_HP_PIN_NID); cs8409_fix_caps(codec, CS8409_CS42L42_AMIC_PIN_NID); - /* Set HSBIAS_SENSE_EN and Full Scale volume for some variants. */ + spec->scodecs[CS8409_CODEC0]->hsbias_hiz = 0x0020; + switch (codec->fixup_id) { + case CS8409_CYBORG: + spec->scodecs[CS8409_CODEC0]->full_scale_vol = + CS42L42_FULL_SCALE_VOL_MINUS6DB; + spec->speaker_pdn_gpio = CS8409_CYBORG_SPEAKER_PDN; + break; + case CS8409_ODIN: + spec->scodecs[CS8409_CODEC0]->full_scale_vol = CS42L42_FULL_SCALE_VOL_0DB; + spec->speaker_pdn_gpio = CS8409_CYBORG_SPEAKER_PDN; + break; case CS8409_WARLOCK_MLK: case CS8409_WARLOCK_MLK_DUAL_MIC: - spec->scodecs[CS8409_CODEC0]->hsbias_hiz = 0x0020; spec->scodecs[CS8409_CODEC0]->full_scale_vol = CS42L42_FULL_SCALE_VOL_0DB; + spec->speaker_pdn_gpio = CS8409_WARLOCK_SPEAKER_PDN; break; default: - spec->scodecs[CS8409_CODEC0]->hsbias_hiz = 0x0020; spec->scodecs[CS8409_CODEC0]->full_scale_vol = CS42L42_FULL_SCALE_VOL_MINUS6DB; + spec->speaker_pdn_gpio = CS8409_WARLOCK_SPEAKER_PDN; break; } + if (spec->speaker_pdn_gpio > 0) { + spec->gpio_dir |= spec->speaker_pdn_gpio; + spec->gpio_data |= spec->speaker_pdn_gpio; + } + break; case HDA_FIXUP_ACT_PROBE: /* Fix Sample Rate to 48kHz */ @@ -1027,13 +1190,17 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, /* add hooks */ spec->gen.pcm_playback_hook = cs42l42_playback_pcm_hook; spec->gen.pcm_capture_hook = cs42l42_capture_pcm_hook; - /* Set initial DMIC volume to -26 dB */ - snd_hda_codec_amp_init_stereo(codec, CS8409_CS42L42_DMIC_ADC_PIN_NID, - HDA_INPUT, 0, 0xff, 0x19); + if (codec->fixup_id != CS8409_ODIN) + /* Set initial DMIC volume to -26 dB */ + snd_hda_codec_amp_init_stereo(codec, CS8409_CS42L42_DMIC_ADC_PIN_NID, + HDA_INPUT, 0, 0xff, 0x19); snd_hda_gen_add_kctl(&spec->gen, "Headphone Playback Volume", &cs42l42_dac_volume_mixer); snd_hda_gen_add_kctl(&spec->gen, "Mic Capture Volume", &cs42l42_adc_volume_mixer); + if (spec->speaker_pdn_gpio > 0) + snd_hda_gen_add_kctl(&spec->gen, "Speaker Playback Switch", + &cs8409_spk_sw_ctrl); /* Disable Unsolicited Response during boot */ cs8409_enable_ur(codec, 0); snd_hda_codec_set_name(codec, "CS8409/CS42L42"); diff --git a/sound/pci/hda/patch_cs8409.h b/sound/pci/hda/patch_cs8409.h index 7df46bd8d2..2a8dfb4ff0 100644 --- a/sound/pci/hda/patch_cs8409.h +++ b/sound/pci/hda/patch_cs8409.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "hda_local.h" #include "hda_auto_parser.h" @@ -222,15 +223,8 @@ enum cs8409_coefficient_index_registers { #define CS42L42_HP_VOL_REAL_MAX (0) #define CS42L42_AMIC_VOL_REAL_MIN (-97) #define CS42L42_AMIC_VOL_REAL_MAX (12) -#define CS42L42_REG_HS_VOL_CHA (0x2301) -#define CS42L42_REG_HS_VOL_CHB (0x2303) -#define CS42L42_REG_HS_VOL_MASK (0x003F) -#define CS42L42_REG_AMIC_VOL (0x1D03) #define CS42L42_REG_AMIC_VOL_MASK (0x00FF) -#define CS42L42_HSDET_AUTO_DONE (0x02) #define CS42L42_HSTYPE_MASK (0x03) -#define CS42L42_JACK_INSERTED (0x0C) -#define CS42L42_JACK_REMOVED (0x00) #define CS42L42_I2C_TIMEOUT_US (20000) #define CS42L42_I2C_SLEEP_US (2000) #define CS42L42_PDN_TIMEOUT_US (250000) @@ -244,6 +238,8 @@ enum cs8409_coefficient_index_registers { #define CS42L42_I2C_ADDR (0x48 << 1) #define CS8409_CS42L42_RESET GENMASK(5, 5) /* CS8409_GPIO5 */ #define CS8409_CS42L42_INT GENMASK(4, 4) /* CS8409_GPIO4 */ +#define CS8409_CYBORG_SPEAKER_PDN GENMASK(2, 2) /* CS8409_GPIO2 */ +#define CS8409_WARLOCK_SPEAKER_PDN GENMASK(1, 1) /* CS8409_GPIO1 */ #define CS8409_CS42L42_HP_PIN_NID CS8409_PIN_ASP1_TRANSMITTER_A #define CS8409_CS42L42_SPK_PIN_NID CS8409_PIN_ASP2_TRANSMITTER_A #define CS8409_CS42L42_AMIC_PIN_NID CS8409_PIN_ASP1_RECEIVER_A @@ -273,6 +269,7 @@ enum { CS8409_FIXUPS, CS8409_DOLPHIN, CS8409_DOLPHIN_FIXUPS, + CS8409_ODIN, }; enum { @@ -310,7 +307,6 @@ struct sub_codec { unsigned int hp_jack_in:1; unsigned int mic_jack_in:1; - unsigned int force_status_change:1; unsigned int suspended:1; unsigned int paged:1; unsigned int last_page; @@ -332,6 +328,8 @@ struct cs8409_spec { unsigned int gpio_dir; unsigned int gpio_data; + int speaker_pdn_gpio; + struct mutex i2c_mux; unsigned int i2c_clck_enabled; unsigned int dev_addr; @@ -360,13 +358,11 @@ extern const struct snd_pci_quirk cs8409_fixup_tbl[]; extern const struct hda_model_fixup cs8409_models[]; extern const struct hda_fixup cs8409_fixups[]; extern const struct hda_verb cs8409_cs42l42_init_verbs[]; -extern const struct hda_pintbl cs8409_cs42l42_pincfgs[]; extern const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[]; extern const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[]; extern struct sub_codec cs8409_cs42l42_codec; extern const struct hda_verb dolphin_init_verbs[]; -extern const struct hda_pintbl dolphin_pincfgs[]; extern const struct cs8409_cir_param dolphin_hw_cfg[]; extern struct sub_codec dolphin_cs42l42_0; extern struct sub_codec dolphin_cs42l42_1; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 31fe417955..6c209cd26c 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -4554,6 +4554,7 @@ HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi), HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi), HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi), HDA_CODEC_ENTRY(0x8086281f, "Raptorlake-P HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x8086281d, "Meteorlake HDMI", patch_i915_adlp_hdmi), HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi), HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index cf531c1efa..38930cf5aa 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -443,6 +443,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0245: case 0x10ec0255: case 0x10ec0256: + case 0x19e58326: case 0x10ec0257: case 0x10ec0282: case 0x10ec0283: @@ -580,6 +581,7 @@ static void alc_shutup_pins(struct hda_codec *codec) switch (codec->core.vendor_id) { case 0x10ec0236: case 0x10ec0256: + case 0x19e58326: case 0x10ec0283: case 0x10ec0286: case 0x10ec0288: @@ -937,6 +939,9 @@ static int alc_init(struct hda_codec *codec) return 0; } +#define alc_free snd_hda_gen_free + +#ifdef CONFIG_PM static inline void alc_shutup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -950,9 +955,6 @@ static inline void alc_shutup(struct hda_codec *codec) alc_shutup_pins(codec); } -#define alc_free snd_hda_gen_free - -#ifdef CONFIG_PM static void alc_power_eapd(struct hda_codec *codec) { alc_auto_setup_eapd(codec, false); @@ -966,9 +968,7 @@ static int alc_suspend(struct hda_codec *codec) spec->power_hook(codec); return 0; } -#endif -#ifdef CONFIG_PM static int alc_resume(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1983,6 +1983,7 @@ enum { ALC1220_FIXUP_CLEVO_PB51ED_PINS, ALC887_FIXUP_ASUS_AUDIO, ALC887_FIXUP_ASUS_HMIC, + ALCS1200A_FIXUP_MIC_VREF, }; static void alc889_fixup_coef(struct hda_codec *codec, @@ -2528,6 +2529,14 @@ static const struct hda_fixup alc882_fixups[] = { .chained = true, .chain_id = ALC887_FIXUP_ASUS_AUDIO, }, + [ALCS1200A_FIXUP_MIC_VREF] = { + .type = HDA_FIXUP_PINCTLS, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, PIN_VREF50 }, /* rear mic */ + { 0x19, PIN_VREF50 }, /* front mic */ + {} + } + }, }; static const struct snd_pci_quirk alc882_fixup_tbl[] = { @@ -2565,6 +2574,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601), SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS), SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3), + SND_PCI_QUIRK(0x1043, 0x8797, "ASUS TUF B550M-PLUS", ALCS1200A_FIXUP_MIC_VREF), SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP), SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), @@ -2624,6 +2634,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x67f1, "Clevo PC70H[PRS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x67f5, "Clevo PD70PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170SM", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x7715, "Clevo X170KM-G", ALC1220_FIXUP_CLEVO_PB51ED), @@ -3133,6 +3144,7 @@ enum { ALC269_TYPE_ALC257, ALC269_TYPE_ALC215, ALC269_TYPE_ALC225, + ALC269_TYPE_ALC245, ALC269_TYPE_ALC287, ALC269_TYPE_ALC294, ALC269_TYPE_ALC300, @@ -3170,6 +3182,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) case ALC269_TYPE_ALC257: case ALC269_TYPE_ALC215: case ALC269_TYPE_ALC225: + case ALC269_TYPE_ALC245: case ALC269_TYPE_ALC287: case ALC269_TYPE_ALC294: case ALC269_TYPE_ALC300: @@ -3237,6 +3250,7 @@ static void alc_disable_headset_jack_key(struct hda_codec *codec) case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: + case 0x19e58326: alc_write_coef_idx(codec, 0x48, 0x0); alc_update_coef_idx(codec, 0x49, 0x0045, 0x0); break; @@ -3265,6 +3279,7 @@ static void alc_enable_headset_jack_key(struct hda_codec *codec) case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: + case 0x19e58326: alc_write_coef_idx(codec, 0x48, 0xd011); alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045); break; @@ -3697,7 +3712,8 @@ static void alc225_init(struct hda_codec *codec) hda_nid_t hp_pin = alc_get_hp_pin(spec); bool hp1_pin_sense, hp2_pin_sense; - if (spec->codec_variant != ALC269_TYPE_ALC287) + if (spec->codec_variant != ALC269_TYPE_ALC287 && + spec->codec_variant != ALC269_TYPE_ALC245) /* required only at boot or S3 and S4 resume time */ if (!spec->done_hp_init || is_s3_resume(codec) || @@ -4005,15 +4021,22 @@ static void alc5505_dsp_init(struct hda_codec *codec) static int alc269_suspend(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + int i; if (spec->has_alc5505_dsp) alc5505_dsp_suspend(codec); + + for (i = 0; i < HDA_MAX_COMPONENTS; i++) + if (spec->comps[i].suspend_hook) + spec->comps[i].suspend_hook(spec->comps[i].dev); + return alc_suspend(codec); } static int alc269_resume(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + int i; if (spec->codec_variant == ALC269_TYPE_ALC269VB) alc269vb_toggle_power_output(codec, 0); @@ -4044,6 +4067,10 @@ static int alc269_resume(struct hda_codec *codec) if (spec->has_alc5505_dsp) alc5505_dsp_resume(codec); + for (i = 0; i < HDA_MAX_COMPONENTS; i++) + if (spec->comps[i].resume_hook) + spec->comps[i].resume_hook(spec->comps[i].dev); + return 0; } #endif /* CONFIG_PM */ @@ -4673,6 +4700,48 @@ static void alc236_fixup_hp_mute_led_micmute_vref(struct hda_codec *codec, alc236_fixup_hp_micmute_led_vref(codec, fix, action); } +static inline void alc298_samsung_write_coef_pack(struct hda_codec *codec, + const unsigned short coefs[2]) +{ + alc_write_coef_idx(codec, 0x23, coefs[0]); + alc_write_coef_idx(codec, 0x25, coefs[1]); + alc_write_coef_idx(codec, 0x26, 0xb011); +} + +struct alc298_samsung_amp_desc { + unsigned char nid; + unsigned short init_seq[2][2]; +}; + +static void alc298_fixup_samsung_amp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + int i, j; + static const unsigned short init_seq[][2] = { + { 0x19, 0x00 }, { 0x20, 0xc0 }, { 0x22, 0x44 }, { 0x23, 0x08 }, + { 0x24, 0x85 }, { 0x25, 0x41 }, { 0x35, 0x40 }, { 0x36, 0x01 }, + { 0x38, 0x81 }, { 0x3a, 0x03 }, { 0x3b, 0x81 }, { 0x40, 0x3e }, + { 0x41, 0x07 }, { 0x400, 0x1 } + }; + static const struct alc298_samsung_amp_desc amps[] = { + { 0x3a, { { 0x18, 0x1 }, { 0x26, 0x0 } } }, + { 0x39, { { 0x18, 0x2 }, { 0x26, 0x1 } } } + }; + + if (action != HDA_FIXUP_ACT_INIT) + return; + + for (i = 0; i < ARRAY_SIZE(amps); i++) { + alc_write_coef_idx(codec, 0x22, amps[i].nid); + + for (j = 0; j < ARRAY_SIZE(amps[i].init_seq); j++) + alc298_samsung_write_coef_pack(codec, amps[i].init_seq[j]); + + for (j = 0; j < ARRAY_SIZE(init_seq); j++) + alc298_samsung_write_coef_pack(codec, init_seq[j]); + } +} + #if IS_REACHABLE(CONFIG_INPUT) static void gpio2_mic_hotkey_event(struct hda_codec *codec, struct hda_jack_callback *event) @@ -4899,6 +4968,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: + case 0x19e58326: alc_process_coef_fw(codec, coef0256); break; case 0x10ec0234: @@ -5014,6 +5084,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: + case 0x19e58326: alc_write_coef_idx(codec, 0x45, 0xc489); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); alc_process_coef_fw(codec, coef0256); @@ -5164,6 +5235,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: + case 0x19e58326: alc_write_coef_idx(codec, 0x1b, 0x0e4b); alc_write_coef_idx(codec, 0x45, 0xc089); msleep(50); @@ -5263,6 +5335,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: + case 0x19e58326: alc_process_coef_fw(codec, coef0256); break; case 0x10ec0234: @@ -5377,6 +5450,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: + case 0x19e58326: alc_process_coef_fw(codec, coef0256); break; case 0x10ec0234: @@ -5478,6 +5552,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: + case 0x19e58326: alc_write_coef_idx(codec, 0x1b, 0x0e4b); alc_write_coef_idx(codec, 0x06, 0x6104); alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3); @@ -5772,6 +5847,7 @@ static void alc255_set_default_jack_type(struct hda_codec *codec) case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: + case 0x19e58326: alc_process_coef_fw(codec, alc256fw); break; } @@ -6374,6 +6450,7 @@ static void alc_combo_jack_hp_jd_restart(struct hda_codec *codec) case 0x10ec0236: case 0x10ec0255: case 0x10ec0256: + case 0x19e58326: alc_update_coef_idx(codec, 0x1b, 0x8000, 1 << 15); /* Reset HP JD */ alc_update_coef_idx(codec, 0x1b, 0x8000, 0 << 15); break; @@ -6582,24 +6659,24 @@ static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec, } } -static int find_comp_by_dev_name(struct alc_spec *spec, const char *name) -{ - int i; - - for (i = 0; i < HDA_MAX_COMPONENTS; i++) { - if (strcmp(spec->comps[i].name, name) == 0) - return i; - } - - return -ENODEV; -} - static int comp_bind(struct device *dev) { struct hda_codec *cdc = dev_to_hda_codec(dev); struct alc_spec *spec = cdc->spec; + int ret, i; + + ret = component_bind_all(dev, spec->comps); + if (ret) + return ret; + + if (snd_hdac_is_power_on(&cdc->core)) { + codec_dbg(cdc, "Resuming after bind.\n"); + for (i = 0; i < HDA_MAX_COMPONENTS; i++) + if (spec->comps[i].resume_hook) + spec->comps[i].resume_hook(spec->comps[i].dev); + } - return component_bind_all(dev, spec->comps); + return 0; } static void comp_unbind(struct device *dev) @@ -6642,6 +6719,7 @@ static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char "%s-%s:00-cs35l41-hda.%d", bus, hid, i); if (!name) return; + spec->comps[i].codec = cdc; component_match_add(dev, &spec->match, component_compare_dev_name, name); } ret = component_master_add_with_match(dev, &comp_master_ops, spec->match); @@ -6668,50 +6746,16 @@ static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fix cs35l41_generic_fixup(codec, action, "spi0", "CSC3551", 4); } -static void alc287_legion_16achg6_playback_hook(struct hda_pcm_stream *hinfo, struct hda_codec *cdc, - struct snd_pcm_substream *sub, int action) +static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix, + int action) { - struct alc_spec *spec = cdc->spec; - unsigned int rx_slot; - int i; - - switch (action) { - case HDA_GEN_PCM_ACT_PREPARE: - rx_slot = 0; - i = find_comp_by_dev_name(spec, "i2c-CLSA0100:00-cs35l41-hda.0"); - if (i >= 0) - spec->comps[i].set_channel_map(spec->comps[i].dev, 0, NULL, 1, &rx_slot); - - rx_slot = 1; - i = find_comp_by_dev_name(spec, "i2c-CLSA0100:00-cs35l41-hda.1"); - if (i >= 0) - spec->comps[i].set_channel_map(spec->comps[i].dev, 0, NULL, 1, &rx_slot); - break; - } - - comp_generic_playback_hook(hinfo, cdc, sub, action); + cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0100", 2); } -static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix, +static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { - struct device *dev = hda_codec_dev(cdc); - struct alc_spec *spec = cdc->spec; - int ret; - - switch (action) { - case HDA_FIXUP_ACT_PRE_PROBE: - component_match_add(dev, &spec->match, component_compare_dev_name, - "i2c-CLSA0100:00-cs35l41-hda.0"); - component_match_add(dev, &spec->match, component_compare_dev_name, - "i2c-CLSA0100:00-cs35l41-hda.1"); - ret = component_master_add_with_match(dev, &comp_master_ops, spec->match); - if (ret) - codec_err(cdc, "Fail to register component aggregator %d\n", ret); - else - spec->gen.pcm_playback_hook = alc287_legion_16achg6_playback_hook; - break; - } + cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0101", 2); } /* for alc295_fixup_hp_top_speakers */ @@ -6780,6 +6824,78 @@ static void alc256_fixup_mic_no_presence_and_resume(struct hda_codec *codec, } } +static void alc_fixup_dell4_mic_no_presence_quiet(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct alc_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->gen.input_mux; + int i; + + alc269_fixup_limit_int_mic_boost(codec, fix, action); + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + /** + * Set the vref of pin 0x19 (Headset Mic) and pin 0x1b (Headphone Mic) + * to Hi-Z to avoid pop noises at startup and when plugging and + * unplugging headphones. + */ + snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ); + snd_hda_codec_set_pin_target(codec, 0x1b, PIN_VREFHIZ); + break; + case HDA_FIXUP_ACT_PROBE: + /** + * Make the internal mic (0x12) the default input source to + * prevent pop noises on cold boot. + */ + for (i = 0; i < imux->num_items; i++) { + if (spec->gen.imux_pins[i] == 0x12) { + spec->gen.cur_mux[0] = i; + break; + } + } + break; + } +} + +static void alc287_fixup_yoga9_14iap7_bass_spk_pin(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + /* + * The Pin Complex 0x17 for the bass speakers is wrongly reported as + * unconnected. + */ + static const struct hda_pintbl pincfgs[] = { + { 0x17, 0x90170121 }, + { } + }; + /* + * Avoid DAC 0x06 and 0x08, as they have no volume controls. + * DAC 0x02 and 0x03 would be fine. + */ + static const hda_nid_t conn[] = { 0x02, 0x03 }; + /* + * Prefer both speakerbar (0x14) and bass speakers (0x17) connected to DAC 0x02. + * Headphones (0x21) are connected to DAC 0x03. + */ + static const hda_nid_t preferred_pairs[] = { + 0x14, 0x02, + 0x17, 0x02, + 0x21, 0x03, + 0 + }; + struct alc_spec *spec = codec->spec; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_apply_pincfgs(codec, pincfgs); + snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn); + spec->gen.preferred_dacs = preferred_pairs; + break; + } +} + enum { ALC269_FIXUP_GPIO2, ALC269_FIXUP_SONY_VAIO, @@ -6821,6 +6937,7 @@ enum { ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, + ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET, ALC269_FIXUP_HEADSET_MODE, ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC, ALC269_FIXUP_ASPIRE_HEADSET_MIC, @@ -6834,6 +6951,7 @@ enum { ALC269_FIXUP_LIMIT_INT_MIC_BOOST, ALC269VB_FIXUP_ASUS_ZENBOOK, ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A, + ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE, ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED, ALC269VB_FIXUP_ORDISSIMO_EVE2, ALC283_FIXUP_CHROME_BOOK, @@ -6893,6 +7011,7 @@ enum { ALC298_FIXUP_LENOVO_SPK_VOLUME, ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER, ALC269_FIXUP_ATIV_BOOK_8, + ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE, ALC221_FIXUP_HP_MIC_NO_PRESENCE, ALC256_FIXUP_ASUS_HEADSET_MODE, ALC256_FIXUP_ASUS_MIC, @@ -6953,6 +7072,7 @@ enum { ALC236_FIXUP_HP_GPIO_LED, ALC236_FIXUP_HP_MUTE_LED, ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF, + ALC298_FIXUP_SAMSUNG_AMP, ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, ALC295_FIXUP_ASUS_MIC_NO_PRESENCE, @@ -6997,6 +7117,7 @@ enum { ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS, ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE, ALC287_FIXUP_YOGA7_14ITL_SPEAKERS, + ALC298_FIXUP_LENOVO_C940_DUET7, ALC287_FIXUP_13S_GEN2_SPEAKERS, ALC256_FIXUP_SET_COEF_DEFAULTS, ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE, @@ -7012,8 +7133,29 @@ enum { ALC245_FIXUP_CS35L41_SPI_4, ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED, ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED, + ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE, + ALC287_FIXUP_LEGION_16ITHG6, + ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK, + ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, }; +/* A special fixup for Lenovo C940 and Yoga Duet 7; + * both have the very same PCI SSID, and we need to apply different fixups + * depending on the codec ID + */ +static void alc298_fixup_lenovo_c940_duet7(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + int id; + + if (codec->core.vendor_id == 0x10ec0298) + id = ALC298_FIXUP_LENOVO_SPK_VOLUME; /* C940 */ + else + id = ALC287_FIXUP_YOGA7_14ITL_SPEAKERS; /* Duet 7 */ + __snd_hda_apply_fixup(codec, id, action, 0); +} + static const struct hda_fixup alc269_fixups[] = { [ALC269_FIXUP_GPIO2] = { .type = HDA_FIXUP_FUNC, @@ -7399,6 +7541,15 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269VB_FIXUP_ASUS_ZENBOOK, }, + [ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, 0x01a110f0 }, /* use as headset mic */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MIC + }, [ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED] = { .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_limit_int_mic_boost, @@ -7810,6 +7961,16 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_NO_SHUTUP }, + [ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { 0x1a, 0x01813030 }, /* use as headphone mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE + }, [ALC221_FIXUP_HP_MIC_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -8278,6 +8439,12 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc236_fixup_hp_mute_led_micmute_vref, }, + [ALC298_FIXUP_SAMSUNG_AMP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc298_fixup_samsung_amp, + .chained = true, + .chain_id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET + }, [ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -8713,6 +8880,10 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_HEADSET_MODE, }, + [ALC298_FIXUP_LENOVO_C940_DUET7] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc298_fixup_lenovo_c940_duet7, + }, [ALC287_FIXUP_13S_GEN2_SPEAKERS] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -8808,6 +8979,93 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC285_FIXUP_HP_MUTE_LED, }, + [ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_dell4_mic_no_presence_quiet, + .chained = true, + .chain_id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, + }, + [ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x02a1112c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC + }, + [ALC287_FIXUP_LEGION_16ITHG6] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc287_fixup_legion_16ithg6_speakers, + }, + [ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + // enable left speaker + { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x41 }, + + { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xc }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x1a }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, + + { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xf }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x42 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, + + { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x10 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x40 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, + + { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x2 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, + + // enable right speaker + { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x46 }, + + { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xc }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x2a }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, + + { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xf }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x46 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, + + { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x10 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x44 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, + + { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x2 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, + + { }, + }, + }, + [ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc287_fixup_yoga9_14iap7_bass_spk_pin, + .chained = true, + .chain_id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -8840,6 +9098,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x129c, "Acer SWIFT SF314-55", ALC256_FIXUP_ACER_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x129d, "Acer SWIFT SF313-51", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1300, "Acer SWIFT SF314-56", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1308, "Acer Aspire Z24-890", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x132a, "Acer TravelMate B114-21", ALC233_FIXUP_ACER_HEADSET_MIC), @@ -8849,6 +9108,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS), SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05be, "Dell Latitude E6540", ALC292_FIXUP_DELL_E7X), @@ -8898,11 +9158,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x09bf, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0a2e, "Dell", ALC236_FIXUP_DELL_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1028, 0x0a30, "Dell", ALC236_FIXUP_DELL_AIO_HEADSET_MIC), + SND_PCI_QUIRK(0x1028, 0x0a38, "Dell Latitude 7520", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET), SND_PCI_QUIRK(0x1028, 0x0a58, "Dell", ALC255_FIXUP_DELL_HEADSET_MIC), SND_PCI_QUIRK(0x1028, 0x0a61, "Dell XPS 15 9510", ALC289_FIXUP_DUAL_SPK), SND_PCI_QUIRK(0x1028, 0x0a62, "Dell Precision 5560", ALC289_FIXUP_DUAL_SPK), SND_PCI_QUIRK(0x1028, 0x0a9d, "Dell Latitude 5430", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0a9e, "Dell Latitude 5430", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0b19, "Dell XPS 15 9520", ALC289_FIXUP_DUAL_SPK), SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), @@ -8962,6 +9224,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2b5e, "HP 288 Pro G2 MT", ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x802e, "HP Z240 SFF", ALC221_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x802f, "HP Z240", ALC221_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8077, "HP", ALC256_FIXUP_HP_HEADSET_MIC), @@ -8982,6 +9245,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO), + SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), + SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x8720, "HP EliteBook x360 1040 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED), @@ -8997,6 +9262,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x8783, "HP ZBook Fury 15 G7 Mobile Workstation", ALC285_FIXUP_HP_GPIO_AMP_INIT), + SND_PCI_QUIRK(0x103c, 0x8786, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x8787, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x8788, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), @@ -9040,11 +9307,19 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8995, "HP EliteBook 855 G9", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x89a4, "HP ProBook 440 G9", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x89a6, "HP ProBook 450 G9", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x89aa, "HP EliteBook 630 G9", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x89ac, "HP EliteBook 640 G9", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x89ae, "HP EliteBook 650 G9", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x89c3, "Zbook Studio G9", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8aa8, "HP EliteBook 640 G9 (MB 8AA6)", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8aab, "HP EliteBook 650 G9 (MB 8AA9)", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -9057,8 +9332,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x12af, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC), + SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), @@ -9076,6 +9353,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x19e1, "ASUS UX581LV", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), SND_PCI_QUIRK(0x1043, 0x1a30, "ASUS X705UD", ALC256_FIXUP_ASUS_MIC), + SND_PCI_QUIRK(0x1043, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1b11, "ASUS UX431DA", ALC294_FIXUP_ASUS_COEF_1B), SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), @@ -9113,13 +9391,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), - SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), - SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), - SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), - SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), + SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), - SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), - SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), + SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), @@ -9134,6 +9412,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x4018, "Clevo NV40M[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x4019, "Clevo NV40MZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x4020, "Clevo NV40MB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x4041, "Clevo NV4[15]PZ", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x40a1, "Clevo NL40GU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x40c1, "Clevo NL40[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x40d1, "Clevo NL41DU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -9160,6 +9439,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x70f3, "Clevo NH77DPQ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x70f4, "Clevo NH77EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x70f6, "Clevo NH77DPQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x7716, "Clevo NS50PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x7717, "Clevo NS70PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x7718, "Clevo L140PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8228, "Clevo NR40BU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8520, "Clevo NH50D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8521, "Clevo NH77D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -9244,8 +9526,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3176, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x3178, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340), + SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), + SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS), - SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940", ALC298_FIXUP_LENOVO_SPK_VOLUME), + SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7), SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3820, "Yoga Duet 7 13ITL6", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3824, "Legion Y9000X 2020", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS), @@ -9257,6 +9541,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x384a, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3852, "Lenovo Yoga 7 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), + SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6), + SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI), @@ -9290,13 +9576,23 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802), SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X), SND_PCI_QUIRK(0x1d05, 0x1132, "TongFang PHxTxX1", ALC256_FIXUP_SET_COEF_DEFAULTS), + SND_PCI_QUIRK(0x1d05, 0x1096, "TongFang GMxMRxx", ALC269_FIXUP_NO_SHUTUP), + SND_PCI_QUIRK(0x1d05, 0x1100, "TongFang GKxNRxx", ALC269_FIXUP_NO_SHUTUP), + SND_PCI_QUIRK(0x1d05, 0x1111, "TongFang GMxZGxx", ALC269_FIXUP_NO_SHUTUP), + SND_PCI_QUIRK(0x1d05, 0x1119, "TongFang GMxZGxx", ALC269_FIXUP_NO_SHUTUP), + SND_PCI_QUIRK(0x1d05, 0x1129, "TongFang GMxZGxx", ALC269_FIXUP_NO_SHUTUP), + SND_PCI_QUIRK(0x1d05, 0x1147, "TongFang GMxTGxx", ALC269_FIXUP_NO_SHUTUP), + SND_PCI_QUIRK(0x1d05, 0x115c, "TongFang GMxTGxx", ALC269_FIXUP_NO_SHUTUP), + SND_PCI_QUIRK(0x1d05, 0x121b, "TongFang GMxAGxx", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC), SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC), SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED), SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10), + SND_PCI_QUIRK(0xf111, 0x0001, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE), #if 0 /* Below is a quirk table taken from the old code. @@ -9469,7 +9765,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC299_FIXUP_PREDATOR_SPK, .name = "predator-spk"}, {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"}, {.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"}, - {.id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc298-samsung-headphone"}, + {.id = ALC298_FIXUP_SAMSUNG_AMP, .name = "alc298-samsung-amp"}, {.id = ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc256-samsung-headphone"}, {.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"}, {.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"}, @@ -9478,6 +9774,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"}, {.id = ALC285_FIXUP_HP_SPECTRE_X360_EB1, .name = "alc285-hp-spectre-x360-eb1"}, {.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"}, + {.id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, .name = "alc287-yoga9-bass-spk-pin"}, {.id = ALC623_FIXUP_LENOVO_THINKSTATION_P340, .name = "alc623-lenovo-thinkstation-p340"}, {.id = ALC255_FIXUP_ACER_HEADPHONE_AND_MIC, .name = "alc255-acer-headphone-and-mic"}, {.id = ALC285_FIXUP_HP_GPIO_AMP_INIT, .name = "alc285-hp-amp-init"}, @@ -10072,6 +10369,7 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: + case 0x19e58326: spec->codec_variant = ALC269_TYPE_ALC256; spec->shutup = alc256_shutup; spec->init_hook = alc256_init; @@ -10087,7 +10385,10 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0245: case 0x10ec0285: case 0x10ec0289: - spec->codec_variant = ALC269_TYPE_ALC215; + if (alc_get_coef0(codec) & 0x0010) + spec->codec_variant = ALC269_TYPE_ALC245; + else + spec->codec_variant = ALC269_TYPE_ALC215; spec->shutup = alc225_shutup; spec->init_hook = alc225_init; spec->gen.mixer_nid = 0; @@ -10696,6 +10997,7 @@ enum { ALC668_FIXUP_MIC_DET_COEF, ALC897_FIXUP_LENOVO_HEADSET_MIC, ALC897_FIXUP_HEADSET_MIC_PIN, + ALC897_FIXUP_HP_HSMIC_VERB, }; static const struct hda_fixup alc662_fixups[] = { @@ -11115,6 +11417,13 @@ static const struct hda_fixup alc662_fixups[] = { .chained = true, .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC }, + [ALC897_FIXUP_HP_HSMIC_VERB] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { } + }, + }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { @@ -11140,7 +11449,9 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), + SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB), SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2), + SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2), SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2), SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50), @@ -11519,6 +11830,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882), HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882), HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882), + HDA_CODEC_ENTRY(0x19e58326, "HW8326", patch_alc269), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek); diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 773a136161..aea7fae2ca 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -449,8 +449,6 @@ static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); snd_hda_codec_set_pincfg(codec, nid, def_conf); } - - return; } static int vt1708_jack_detect_get(struct snd_kcontrol *kcontrol, @@ -520,11 +518,11 @@ static int via_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); + err = auto_parse_beep(codec); if (err < 0) return err; - err = auto_parse_beep(codec); + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) return err; diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c index 0dfa093f7d..20b3e8f947 100644 --- a/sound/pci/ice1712/quartet.c +++ b/sound/pci/ice1712/quartet.c @@ -566,7 +566,7 @@ static int qtet_ain12_sw_put(struct snd_kcontrol *kcontrol, { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned int old, new, tmp, masked_old; - old = new = get_scr(ice); + old = get_scr(ice); masked_old = old & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0); tmp = ucontrol->value.integer.value[0]; if (tmp == 2) diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c index 738ec98700..32193fae97 100644 --- a/sound/pci/lola/lola_pcm.c +++ b/sound/pci/lola/lola_pcm.c @@ -561,8 +561,9 @@ static snd_pcm_uframes_t lola_pcm_pointer(struct snd_pcm_substream *substream) void lola_pcm_update(struct lola *chip, struct lola_pcm *pcm, unsigned int bits) { int i; + u8 num_streams = min_t(u8, pcm->num_streams, ARRAY_SIZE(pcm->streams)); - for (i = 0; bits && i < pcm->num_streams; i++) { + for (i = 0; bits && i < num_streams; i++) { if (bits & (1 << i)) { struct lola_stream *str = &pcm->streams[i]; if (str->substream && str->running) diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 3db641318d..dcc43a81ae 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -3314,7 +3314,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) if (hdsp->io_type == RPM) { /* RPM Bypass, Disconnect and Input switches */ for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_rpm_controls); idx++) { - err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_rpm_controls[idx], hdsp)); + err = snd_ctl_add(card, snd_ctl_new1(&snd_hdsp_rpm_controls[idx], hdsp)); if (err < 0) return err; } diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 5dcf77af07..7d4747b6ba 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -14,7 +14,7 @@ menuconfig SND_SOC If you want ASoC support, you should say Y here and also to the specific driver for your SoC platform below. - + ASoC provides power efficient ALSA support for embedded battery powered SoC based systems like PDA's, Phones and Personal Media Players. @@ -55,6 +55,13 @@ config SND_SOC_TOPOLOGY_KUNIT_TEST userspace applications such as pulseaudio, to prevent unnecessary problems. +config SND_SOC_UTILS_KUNIT_TEST + tristate "KUnit tests for SoC utils" + depends on KUNIT + default KUNIT_ALL_TESTS + help + If you want to perform tests on ALSA SoC utils library say Y here. + config SND_SOC_ACPI tristate diff --git a/sound/soc/Makefile b/sound/soc/Makefile index a7b37c06dc..453181ef6c 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -9,7 +9,12 @@ endif ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST),) # snd-soc-test-objs := soc-topology-test.o -obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) := soc-topology-test.o +obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) += soc-topology-test.o +endif + +ifneq ($(CONFIG_SND_SOC_UTILS_KUNIT_TEST),) +# snd-soc-test-objs := soc-utils-test.o +obj-$(CONFIG_SND_SOC_UTILS_KUNIT_TEST) += soc-utils-test.o endif ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c index 1289cb4e29..b1342351bf 100644 --- a/sound/soc/adi/axi-i2s.c +++ b/sound/soc/adi/axi-i2s.c @@ -161,6 +161,7 @@ static struct snd_soc_dai_driver axi_i2s_dai = { static const struct snd_soc_component_driver axi_i2s_component = { .name = "axi-i2s", + .legacy_dai_naming = 1, }; static const struct regmap_config axi_i2s_regmap_config = { diff --git a/sound/soc/adi/axi-spdif.c b/sound/soc/adi/axi-spdif.c index 8d4a6cb4e5..51b968ea21 100644 --- a/sound/soc/adi/axi-spdif.c +++ b/sound/soc/adi/axi-spdif.c @@ -167,6 +167,7 @@ static struct snd_soc_dai_driver axi_spdif_dai = { static const struct snd_soc_component_driver axi_spdif_component = { .name = "axi-spdif", + .legacy_dai_naming = 1, }; static const struct regmap_config axi_spdif_regmap_config = { diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 1381aec230..08f5289dac 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -23,6 +23,18 @@ config SND_SOC_AMD_CZ_RT5645_MACH help This option enables machine driver for rt5645. +config SND_SOC_AMD_ST_ES8336_MACH + tristate "AMD ST support for ES8336" + select SND_SOC_ACPI if ACPI + select SND_SOC_ES8316 + depends on SND_SOC_AMD_ACP && ACPI + depends on I2C + help + This option enables machine driver for Jadeite platform + using es8336 codec. + Say m if you have such a device. + If unsure select "N". + config SND_SOC_AMD_ACP3x tristate "AMD Audio Coprocessor-v3.x support" depends on X86 && PCI @@ -105,3 +117,13 @@ config SND_AMD_ACP_CONFIG driver modules to use source "sound/soc/amd/acp/Kconfig" + +config SND_SOC_AMD_RPL_ACP6x + tristate "AMD Audio Coprocessor-v6.2 RPL support" + depends on X86 && PCI + help + This option enables Audio Coprocessor i.e ACP v6.2 support on + AMD RPL platform. By enabling this flag build will be + triggered for ACP PCI driver. + Say m if you have such a device. + If unsure select "N". diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile index 4b1f77930a..0592e7c5c4 100644 --- a/sound/soc/amd/Makefile +++ b/sound/soc/amd/Makefile @@ -2,12 +2,14 @@ acp_audio_dma-objs := acp-pcm-dma.o snd-soc-acp-da7219mx98357-mach-objs := acp-da7219-max98357a.o snd-soc-acp-rt5645-mach-objs := acp-rt5645.o +snd-soc-acp-es8336-mach-objs := acp-es8336.o snd-soc-acp-rt5682-mach-objs := acp3x-rt5682-max9836.o snd-acp-config-objs := acp-config.o obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o +obj-$(CONFIG_SND_SOC_AMD_ST_ES8336_MACH) += snd-soc-acp-es8336-mach.o obj-$(CONFIG_SND_SOC_AMD_ACP3x) += raven/ obj-$(CONFIG_SND_SOC_AMD_RV_RT5682_MACH) += snd-soc-acp-rt5682-mach.o obj-$(CONFIG_SND_SOC_AMD_RENOIR) += renoir/ @@ -15,3 +17,4 @@ obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/ obj-$(CONFIG_SND_SOC_AMD_ACP6x) += yc/ obj-$(CONFIG_SND_SOC_AMD_ACP_COMMON) += acp/ obj-$(CONFIG_SND_AMD_ACP_CONFIG) += snd-acp-config.o +obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += rpl/ diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index 5cbc82eca4..0932473b63 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -130,4 +130,34 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines); +struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[] = { + { + .id = "AMDI1019", + .drv_name = "rmb-dsp", + .pdata = &acp_quirk_data, + .fw_filename = "sof-rmb.ri", + .sof_tplg_filename = "sof-acp-rmb.tplg", + }, + { + .id = "10508825", + .drv_name = "nau8825-max", + .pdata = &acp_quirk_data, + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_max, + .fw_filename = "sof-rmb.ri", + .sof_tplg_filename = "sof-rmb-nau8825-max98360.tplg", + }, + { + .id = "RTL5682", + .drv_name = "rt5682s-hs-rt1019", + .pdata = &acp_quirk_data, + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_rt1019, + .fw_filename = "sof-rmb.ri", + .sof_tplg_filename = "sof-rmb-rt5682s-rt1019.tplg", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_rmb_sof_machines); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 3bf86c2424..ef1b4cefc2 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -71,7 +71,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &cz_jack, NULL, 0); + &cz_jack); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; @@ -151,7 +151,7 @@ static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd) SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &cz_jack, NULL, 0); + &cz_jack); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index 1cd2e70a57..198358d28e 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -433,6 +433,7 @@ static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num, bool is_circular) case I2S_TO_ACP_DMA_CH_NUM: case ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM: case I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM: + case ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM: dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK; break; default: @@ -710,6 +711,13 @@ static irqreturn_t dma_irq_handler(int irq, void *arg) acp_mmio, mmACP_EXTERNAL_INTR_STAT); } + if ((intr_flag & BIT(ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM)) != 0) { + valid_irq = true; + snd_pcm_period_elapsed(irq_data->play_i2s_micsp_stream); + acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM)) << 16, + acp_mmio, mmACP_EXTERNAL_INTR_STAT); + } + if ((intr_flag & BIT(ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM)) != 0) { valid_irq = true; snd_pcm_period_elapsed(irq_data->play_i2sbt_stream); @@ -807,7 +815,8 @@ static int acp_dma_open(struct snd_soc_component *component, * stream is not closed */ if (!intr_data->play_i2ssp_stream && !intr_data->capture_i2ssp_stream && - !intr_data->play_i2sbt_stream && !intr_data->capture_i2sbt_stream) + !intr_data->play_i2sbt_stream && !intr_data->capture_i2sbt_stream && + !intr_data->play_i2s_micsp_stream) acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -867,6 +876,9 @@ static int acp_dma_hw_params(struct snd_soc_component *component, case I2S_BT_INSTANCE: val |= ACP_I2S_BT_16BIT_RESOLUTION_EN; break; + case I2S_MICSP_INSTANCE: + val |= ACP_I2S_MICSP_16BIT_RESOLUTION_EN; + break; case I2S_SP_INSTANCE: default: val |= ACP_I2S_SP_16BIT_RESOLUTION_EN; @@ -876,6 +888,7 @@ static int acp_dma_hw_params(struct snd_soc_component *component, case I2S_BT_INSTANCE: val |= ACP_I2S_BT_16BIT_RESOLUTION_EN; break; + case I2S_MICSP_INSTANCE: case I2S_SP_INSTANCE: default: val |= ACP_I2S_MIC_16BIT_RESOLUTION_EN; @@ -901,6 +914,27 @@ static int acp_dma_hw_params(struct snd_soc_component *component, mmACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW; adata->play_i2sbt_stream = substream; break; + case I2S_MICSP_INSTANCE: + switch (adata->asic_type) { + case CHIP_STONEY: + rtd->pte_offset = ACP_ST_PLAYBACK_PTE_OFFSET; + break; + default: + rtd->pte_offset = ACP_PLAYBACK_PTE_OFFSET; + } + rtd->ch1 = SYSRAM_TO_ACP_MICSP_INSTANCE_CH_NUM; + rtd->ch2 = ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM; + rtd->sram_bank = ACP_SRAM_BANK_1_ADDRESS; + rtd->destination = TO_ACP_I2S_2; + rtd->dma_dscr_idx_1 = PLAYBACK_START_DMA_DESCR_CH4; + rtd->dma_dscr_idx_2 = PLAYBACK_START_DMA_DESCR_CH5; + rtd->byte_cnt_high_reg_offset = + mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH; + rtd->byte_cnt_low_reg_offset = + mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW; + + adata->play_i2s_micsp_stream = substream; + break; case I2S_SP_INSTANCE: default: switch (adata->asic_type) { @@ -939,6 +973,7 @@ static int acp_dma_hw_params(struct snd_soc_component *component, rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_11; adata->capture_i2sbt_stream = substream; break; + case I2S_MICSP_INSTANCE: case I2S_SP_INSTANCE: default: rtd->pte_offset = ACP_CAPTURE_PTE_OFFSET; @@ -1160,6 +1195,9 @@ static int acp_dma_close(struct snd_soc_component *component, case I2S_BT_INSTANCE: adata->play_i2sbt_stream = NULL; break; + case I2S_MICSP_INSTANCE: + adata->play_i2s_micsp_stream = NULL; + break; case I2S_SP_INSTANCE: default: adata->play_i2ssp_stream = NULL; @@ -1181,6 +1219,7 @@ static int acp_dma_close(struct snd_soc_component *component, case I2S_BT_INSTANCE: adata->capture_i2sbt_stream = NULL; break; + case I2S_MICSP_INSTANCE: case I2S_SP_INSTANCE: default: adata->capture_i2ssp_stream = NULL; @@ -1197,7 +1236,8 @@ static int acp_dma_close(struct snd_soc_component *component, * another stream is also not active. */ if (!adata->play_i2ssp_stream && !adata->capture_i2ssp_stream && - !adata->play_i2sbt_stream && !adata->capture_i2sbt_stream) + !adata->play_i2sbt_stream && !adata->capture_i2sbt_stream && + !adata->play_i2s_micsp_stream) acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); kfree(rtd); return 0; @@ -1245,6 +1285,7 @@ static int acp_audio_probe(struct platform_device *pdev) audio_drv_data->capture_i2ssp_stream = NULL; audio_drv_data->play_i2sbt_stream = NULL; audio_drv_data->capture_i2sbt_stream = NULL; + audio_drv_data->play_i2s_micsp_stream = NULL; audio_drv_data->asic_type = *pdata; @@ -1333,6 +1374,11 @@ static int acp_pcm_resume(struct device *dev) config_acp_dma(adata->acp_mmio, rtd, adata->asic_type); } if (adata->asic_type != CHIP_CARRIZO) { + if (adata->play_i2s_micsp_stream && + adata->play_i2s_micsp_stream->runtime) { + rtd = adata->play_i2s_micsp_stream->runtime->private_data; + config_acp_dma(adata->acp_mmio, rtd, adata->asic_type); + } if (adata->play_i2sbt_stream && adata->play_i2sbt_stream->runtime) { rtd = adata->play_i2sbt_stream->runtime->private_data; diff --git a/sound/soc/amd/acp-rt5645.c b/sound/soc/amd/acp-rt5645.c index a79a46646d..532aa98a22 100644 --- a/sound/soc/amd/acp-rt5645.c +++ b/sound/soc/amd/acp-rt5645.c @@ -80,7 +80,7 @@ static int cz_init(struct snd_soc_pcm_runtime *rtd) SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &cz_jack, NULL, 0); + &cz_jack); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h index db80a73aa5..b29bef90f8 100644 --- a/sound/soc/amd/acp.h +++ b/sound/soc/amd/acp.h @@ -55,6 +55,7 @@ #define I2S_SP_INSTANCE 0x01 #define I2S_BT_INSTANCE 0x02 +#define I2S_MICSP_INSTANCE 0x03 #define CAP_CHANNEL0 0x00 #define CAP_CHANNEL1 0x01 @@ -85,6 +86,10 @@ #define I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM 10 #define ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM 11 +/* Playback DMA channels for I2S MICSP instance */ +#define SYSRAM_TO_ACP_MICSP_INSTANCE_CH_NUM 4 +#define ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM 5 + #define NUM_DSCRS_PER_CHANNEL 2 #define PLAYBACK_START_DMA_DESCR_CH12 0 @@ -108,8 +113,15 @@ #define CAPTURE_START_DMA_DESCR_CH11 14 #define CAPTURE_END_DMA_DESCR_CH11 15 +/* I2S MICSP Instance DMA Descriptors */ +#define PLAYBACK_START_DMA_DESCR_CH4 0 +#define PLAYBACK_END_DMA_DESCR_CH4 1 +#define PLAYBACK_START_DMA_DESCR_CH5 2 +#define PLAYBACK_END_DMA_DESCR_CH5 3 + #define mmACP_I2S_16BIT_RESOLUTION_EN 0x5209 #define ACP_I2S_MIC_16BIT_RESOLUTION_EN 0x01 +#define ACP_I2S_MICSP_16BIT_RESOLUTION_EN 0x01 #define ACP_I2S_SP_16BIT_RESOLUTION_EN 0x02 #define ACP_I2S_BT_16BIT_RESOLUTION_EN 0x04 #define ACP_BT_UART_PAD_SELECT_MASK 0x1 @@ -149,6 +161,7 @@ struct audio_drv_data { struct snd_pcm_substream *capture_i2ssp_stream; struct snd_pcm_substream *play_i2sbt_stream; struct snd_pcm_substream *capture_i2sbt_stream; + struct snd_pcm_substream *play_i2s_micsp_stream; void __iomem *acp_mmio; u32 asic_type; snd_pcm_sframes_t delay; diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 626e4a5cb0..ce00378107 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -40,28 +40,40 @@ config SND_AMD_ASOC_RENOIR help This option enables Renoir I2S support on AMD platform. +config SND_AMD_ASOC_REMBRANDT + tristate "AMD ACP ASOC Rembrandt Support" + select SND_SOC_AMD_ACP_PCM + select SND_SOC_AMD_ACP_I2S + select SND_SOC_AMD_ACP_PDM + depends on X86 && PCI + help + This option enables Rembrandt I2S support on AMD platform. + Say Y if you want to enable AUDIO on Rembrandt + If unsure select "N". + config SND_SOC_AMD_MACH_COMMON tristate - depends on X86 && PCI && I2C && GPIOLIB + depends on X86 && PCI && I2C select CLK_FIXED_FCH select SND_SOC_RT5682_I2C select SND_SOC_DMIC select SND_SOC_RT1019 select SND_SOC_MAX98357A select SND_SOC_RT5682S + select SND_SOC_NAU8825 help This option enables common Machine driver module for ACP. config SND_SOC_AMD_LEGACY_MACH tristate "AMD Legacy Machine Driver Support" - depends on X86 && PCI && I2C && GPIOLIB + depends on X86 && PCI && I2C select SND_SOC_AMD_MACH_COMMON help This option enables legacy sound card support for ACP audio. config SND_SOC_AMD_SOF_MACH tristate "AMD SOF Machine Driver Support" - depends on X86 && PCI && I2C && GPIOLIB + depends on X86 && PCI && I2C select SND_SOC_AMD_MACH_COMMON help This option enables SOF sound card support for ACP audio. diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile index 657ddfadf0..d9abb0ee52 100644 --- a/sound/soc/amd/acp/Makefile +++ b/sound/soc/amd/acp/Makefile @@ -12,6 +12,7 @@ snd-acp-pci-objs := acp-pci.o #platform specific driver snd-acp-renoir-objs := acp-renoir.o +snd-acp-rembrandt-objs := acp-rembrandt.o #machine specific driver snd-acp-mach-objs := acp-mach-common.o @@ -24,6 +25,7 @@ obj-$(CONFIG_SND_SOC_AMD_ACP_PDM) += snd-acp-pdm.o obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o +obj-$(CONFIG_SND_AMD_ASOC_REMBRANDT) += snd-acp-rembrandt.o obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index ce9aca8dd6..393f729ef5 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -30,11 +30,14 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ { struct device *dev = dai->component->dev; struct acp_dev_data *adata; + struct acp_resource *rsrc; u32 val; u32 xfer_resolution; u32 reg_val; + u32 lrclk_div_val, bclk_div_val; adata = snd_soc_dai_get_drvdata(dai); + rsrc = adata->rsrc; /* These values are as per Hardware Spec */ switch (params_format(params)) { @@ -63,6 +66,9 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ case I2S_SP_INSTANCE: reg_val = ACP_I2STDM_ITER; break; + case I2S_HS_INSTANCE: + reg_val = ACP_HSTDM_ITER; + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -75,6 +81,9 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ case I2S_SP_INSTANCE: reg_val = ACP_I2STDM_IRER; break; + case I2S_HS_INSTANCE: + reg_val = ACP_HSTDM_IRER; + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -86,6 +95,74 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ val = val | (xfer_resolution << 3); writel(val, adata->acp_base + reg_val); + if (rsrc->soc_mclk) { + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + switch (params_rate(params)) { + case 8000: + bclk_div_val = 768; + break; + case 16000: + bclk_div_val = 384; + break; + case 24000: + bclk_div_val = 256; + break; + case 32000: + bclk_div_val = 192; + break; + case 44100: + case 48000: + bclk_div_val = 128; + break; + case 88200: + case 96000: + bclk_div_val = 64; + break; + case 192000: + bclk_div_val = 32; + break; + default: + return -EINVAL; + } + lrclk_div_val = 32; + break; + case SNDRV_PCM_FORMAT_S32_LE: + switch (params_rate(params)) { + case 8000: + bclk_div_val = 384; + break; + case 16000: + bclk_div_val = 192; + break; + case 24000: + bclk_div_val = 128; + break; + case 32000: + bclk_div_val = 96; + break; + case 44100: + case 48000: + bclk_div_val = 64; + break; + case 88200: + case 96000: + bclk_div_val = 32; + break; + case 192000: + bclk_div_val = 16; + break; + default: + return -EINVAL; + } + lrclk_div_val = 64; + break; + default: + return -EINVAL; + } + adata->lrclk_div = lrclk_div_val; + adata->bclk_div = bclk_div_val; + } return 0; } @@ -94,6 +171,7 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct struct acp_stream *stream = substream->runtime->private_data; struct device *dev = dai->component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_resource *rsrc = adata->rsrc; u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg; period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size); @@ -118,6 +196,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct ier_val = ACP_I2STDM_IER; buf_reg = ACP_I2S_TX_RINGBUFSIZE; break; + case I2S_HS_INSTANCE: + water_val = ACP_HS_TX_INTR_WATERMARK_SIZE; + reg_val = ACP_HSTDM_ITER; + ier_val = ACP_HSTDM_IER; + buf_reg = ACP_HS_TX_RINGBUFSIZE; + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -136,6 +220,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct ier_val = ACP_I2STDM_IER; buf_reg = ACP_I2S_RX_RINGBUFSIZE; break; + case I2S_HS_INSTANCE: + water_val = ACP_HS_RX_INTR_WATERMARK_SIZE; + reg_val = ACP_HSTDM_IRER; + ier_val = ACP_HSTDM_IER; + buf_reg = ACP_HS_RX_RINGBUFSIZE; + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -147,6 +237,8 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct val = val | BIT(0); writel(val, adata->acp_base + reg_val); writel(1, adata->acp_base + ier_val); + if (rsrc->soc_mclk) + acp_set_i2s_clk(adata, dai->driver->id); return 0; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: @@ -159,6 +251,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct case I2S_SP_INSTANCE: reg_val = ACP_I2STDM_ITER; break; + case I2S_HS_INSTANCE: + reg_val = ACP_HSTDM_ITER; + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -172,6 +267,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct case I2S_SP_INSTANCE: reg_val = ACP_I2STDM_IRER; break; + case I2S_HS_INSTANCE: + reg_val = ACP_HSTDM_IRER; + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -187,6 +285,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) && !(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0))) writel(0, adata->acp_base + ACP_I2STDM_IER); + if (!(readl(adata->acp_base + ACP_HSTDM_ITER) & BIT(0)) && + !(readl(adata->acp_base + ACP_HSTDM_IRER) & BIT(0))) + writel(0, adata->acp_base + ACP_HSTDM_IER); return 0; default: return -EINVAL; @@ -199,6 +300,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d { struct device *dev = dai->component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_resource *rsrc = adata->rsrc; struct acp_stream *stream = substream->runtime->private_data; u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0; u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl; @@ -208,7 +310,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d case I2S_SP_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { reg_dma_size = ACP_I2S_TX_DMA_SIZE; - acp_fifo_addr = ACP_SRAM_PTE_OFFSET + + acp_fifo_addr = rsrc->sram_pte_offset + SP_PB_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_I2S_TX_FIFOADDR; reg_fifo_size = ACP_I2S_TX_FIFOSIZE; @@ -217,7 +319,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR); } else { reg_dma_size = ACP_I2S_RX_DMA_SIZE; - acp_fifo_addr = ACP_SRAM_PTE_OFFSET + + acp_fifo_addr = rsrc->sram_pte_offset + SP_CAPT_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_I2S_RX_FIFOADDR; reg_fifo_size = ACP_I2S_RX_FIFOSIZE; @@ -228,7 +330,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d case I2S_BT_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { reg_dma_size = ACP_BT_TX_DMA_SIZE; - acp_fifo_addr = ACP_SRAM_PTE_OFFSET + + acp_fifo_addr = rsrc->sram_pte_offset + BT_PB_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_BT_TX_FIFOADDR; reg_fifo_size = ACP_BT_TX_FIFOSIZE; @@ -237,7 +339,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR); } else { reg_dma_size = ACP_BT_RX_DMA_SIZE; - acp_fifo_addr = ACP_SRAM_PTE_OFFSET + + acp_fifo_addr = rsrc->sram_pte_offset + BT_CAPT_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_BT_RX_FIFOADDR; reg_fifo_size = ACP_BT_RX_FIFOSIZE; @@ -246,6 +348,27 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR); } break; + case I2S_HS_INSTANCE: + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + reg_dma_size = ACP_HS_TX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + HS_PB_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_HS_TX_FIFOADDR; + reg_fifo_size = ACP_HS_TX_FIFOSIZE; + + phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR); + } else { + reg_dma_size = ACP_HS_RX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + HS_CAPT_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_HS_RX_FIFOADDR; + reg_fifo_size = ACP_HS_RX_FIFOSIZE; + + phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR); + } + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -255,11 +378,15 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr); writel(FIFO_SIZE, adata->acp_base + reg_fifo_size); - ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL); - ext_int_ctrl |= BIT(I2S_RX_THRESHOLD) | BIT(BT_RX_THRESHOLD) - | BIT(I2S_TX_THRESHOLD) | BIT(BT_TX_THRESHOLD); + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) | + BIT(BT_RX_THRESHOLD(rsrc->offset)) | + BIT(I2S_TX_THRESHOLD(rsrc->offset)) | + BIT(BT_TX_THRESHOLD(rsrc->offset)) | + BIT(HS_RX_THRESHOLD(rsrc->offset)) | + BIT(HS_TX_THRESHOLD(rsrc->offset)); - writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL); + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); return 0; } @@ -268,32 +395,45 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d { struct acp_stream *stream = substream->runtime->private_data; struct device *dev = dai->component->dev; + struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_resource *rsrc = adata->rsrc; unsigned int dir = substream->stream; unsigned int irq_bit = 0; switch (dai->driver->id) { case I2S_SP_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - irq_bit = BIT(I2S_TX_THRESHOLD); + irq_bit = BIT(I2S_TX_THRESHOLD(rsrc->offset)); stream->pte_offset = ACP_SRAM_SP_PB_PTE_OFFSET; stream->fifo_offset = SP_PB_FIFO_ADDR_OFFSET; } else { - irq_bit = BIT(I2S_RX_THRESHOLD); + irq_bit = BIT(I2S_RX_THRESHOLD(rsrc->offset)); stream->pte_offset = ACP_SRAM_SP_CP_PTE_OFFSET; stream->fifo_offset = SP_CAPT_FIFO_ADDR_OFFSET; } break; case I2S_BT_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - irq_bit = BIT(BT_TX_THRESHOLD); + irq_bit = BIT(BT_TX_THRESHOLD(rsrc->offset)); stream->pte_offset = ACP_SRAM_BT_PB_PTE_OFFSET; stream->fifo_offset = BT_PB_FIFO_ADDR_OFFSET; } else { - irq_bit = BIT(BT_RX_THRESHOLD); + irq_bit = BIT(BT_RX_THRESHOLD(rsrc->offset)); stream->pte_offset = ACP_SRAM_BT_CP_PTE_OFFSET; stream->fifo_offset = BT_CAPT_FIFO_ADDR_OFFSET; } break; + case I2S_HS_INSTANCE: + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + irq_bit = BIT(HS_TX_THRESHOLD(rsrc->offset)); + stream->pte_offset = ACP_SRAM_HS_PB_PTE_OFFSET; + stream->fifo_offset = HS_PB_FIFO_ADDR_OFFSET; + } else { + irq_bit = BIT(HS_RX_THRESHOLD(rsrc->offset)); + stream->pte_offset = ACP_SRAM_HS_CP_PTE_OFFSET; + stream->fifo_offset = HS_CAPT_FIFO_ADDR_OFFSET; + } + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -319,6 +459,7 @@ int asoc_acp_i2s_probe(struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_resource *rsrc = adata->rsrc; unsigned int val; if (!adata->acp_base) { @@ -326,8 +467,8 @@ int asoc_acp_i2s_probe(struct snd_soc_dai *dai) return -EINVAL; } - val = readl(adata->acp_base + ACP_I2S_PIN_CONFIG); - if (val != I2S_MODE) { + val = readl(adata->acp_base + rsrc->i2s_pin_cfg_offset); + if (val != rsrc->i2s_mode) { dev_err(dev, "I2S Mode not supported val %x\n", val); return -EINVAL; } diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c index 5d276365d6..1f4878ff7d 100644 --- a/sound/soc/amd/acp/acp-legacy-mach.c +++ b/sound/soc/amd/acp/acp-legacy-mach.c @@ -27,7 +27,6 @@ static struct acp_card_drvdata rt5682_rt1019_data = { .hs_codec_id = RT5682, .amp_codec_id = RT1019, .dmic_codec_id = DMIC, - .gpio_spkr_en = EN_SPKR_GPIO_GB, }; static struct acp_card_drvdata rt5682s_max_data = { @@ -37,7 +36,6 @@ static struct acp_card_drvdata rt5682s_max_data = { .hs_codec_id = RT5682S, .amp_codec_id = MAX98360A, .dmic_codec_id = DMIC, - .gpio_spkr_en = EN_SPKR_GPIO_NONE, }; static struct acp_card_drvdata rt5682s_rt1019_data = { @@ -47,7 +45,28 @@ static struct acp_card_drvdata rt5682s_rt1019_data = { .hs_codec_id = RT5682S, .amp_codec_id = RT1019, .dmic_codec_id = DMIC, - .gpio_spkr_en = EN_SPKR_GPIO_NONE, +}; + +static struct acp_card_drvdata max_nau8825_data = { + .hs_cpu_id = I2S_HS, + .amp_cpu_id = I2S_HS, + .dmic_cpu_id = DMIC, + .hs_codec_id = NAU8825, + .amp_codec_id = MAX98360A, + .dmic_codec_id = DMIC, + .soc_mclk = true, + .platform = REMBRANDT, +}; + +static struct acp_card_drvdata rt5682s_rt1019_rmb_data = { + .hs_cpu_id = I2S_HS, + .amp_cpu_id = I2S_HS, + .dmic_cpu_id = DMIC, + .hs_codec_id = RT5682S, + .amp_codec_id = RT1019, + .dmic_codec_id = DMIC, + .soc_mclk = true, + .platform = REMBRANDT, }; static const struct snd_kcontrol_new acp_controls[] = { @@ -62,16 +81,15 @@ static const struct snd_kcontrol_new acp_controls[] = { static const struct snd_soc_dapm_widget acp_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", event_spkr_handler), - SND_SOC_DAPM_SPK("Left Spk", event_spkr_handler), - SND_SOC_DAPM_SPK("Right Spk", event_spkr_handler), + SND_SOC_DAPM_SPK("Spk", NULL), + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), }; static int acp_asoc_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; struct device *dev = &pdev->dev; - unsigned int spkr_gpio; int ret; if (!pdev->id_entry) @@ -89,20 +107,9 @@ static int acp_asoc_probe(struct platform_device *pdev) card->controls = acp_controls; card->num_controls = ARRAY_SIZE(acp_controls); card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data; - spkr_gpio = ((struct acp_card_drvdata *)(card->drvdata))->gpio_spkr_en; acp_legacy_dai_links_create(card); - if (gpio_is_valid(spkr_gpio)) { - ret = devm_gpio_request(dev, spkr_gpio, "spkren"); - if (ret) { - dev_err(dev, "(%s) gpio request failed: %d\n", - __func__, ret); - return ret; - } - gpio_direction_output(spkr_gpio, 0); - } - ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { dev_err(&pdev->dev, @@ -127,10 +134,19 @@ static const struct platform_device_id board_ids[] = { .name = "acp3xalc5682s1019", .driver_data = (kernel_ulong_t)&rt5682s_rt1019_data, }, + { + .name = "rmb-nau8825-max", + .driver_data = (kernel_ulong_t)&max_nau8825_data, + }, + { + .name = "rmb-rt5682s-rt1019", + .driver_data = (kernel_ulong_t)&rt5682s_rt1019_rmb_data, + }, { } }; static struct platform_driver acp_asoc_audio = { .driver = { + .pm = &snd_soc_pm_ops, .name = "acp_mach", }, .probe = acp_asoc_probe, @@ -144,4 +160,6 @@ MODULE_DESCRIPTION("ACP chrome audio support"); MODULE_ALIAS("platform:acp3xalc56821019"); MODULE_ALIAS("platform:acp3xalc5682sm98360"); MODULE_ALIAS("platform:acp3xalc5682s1019"); +MODULE_ALIAS("platform:rmb-nau8825-max"); +MODULE_ALIAS("platform:rmb-rt5682s-rt1019"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index caa202f786..f0c49127aa 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -24,6 +24,7 @@ #include "../../codecs/rt5682.h" #include "../../codecs/rt1019.h" #include "../../codecs/rt5682s.h" +#include "../../codecs/nau8825.h" #include "acp-mach.h" #define PCO_PLAT_CLK 48000000 @@ -71,31 +72,6 @@ static const struct snd_soc_dapm_route rt5682_map[] = { { "IN1P", NULL, "Headset Mic" }, }; -int event_spkr_handler(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct acp_card_drvdata *drvdata = snd_soc_card_get_drvdata(card); - - if (!gpio_is_valid(drvdata->gpio_spkr_en)) - return 0; - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - gpio_set_value(drvdata->gpio_spkr_en, 1); - break; - case SND_SOC_DAPM_PRE_PMD: - gpio_set_value(drvdata->gpio_spkr_en, 0); - break; - default: - dev_warn(card->dev, "%s invalid setting\n", __func__); - break; - } - return 0; -} -EXPORT_SYMBOL_NS_GPL(event_spkr_handler, SND_SOC_AMD_MACH); - /* Define card ops for RT5682 CODEC */ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd) { @@ -145,7 +121,7 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd) SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack, NULL, 0); + &pco_jack); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; @@ -173,9 +149,14 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream) struct acp_card_drvdata *drvdata = card->drvdata; struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); int ret; + unsigned int fmt; - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBP_CFP); + if (drvdata->soc_mclk) + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + else + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + + ret = snd_soc_dai_set_fmt(codec_dai, fmt); if (ret < 0) { dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); return ret; @@ -186,10 +167,13 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream) &constraints_channels); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - ret = acp_clk_enable(drvdata); - if (ret < 0) - dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret); + if (!drvdata->soc_mclk) { + ret = acp_clk_enable(drvdata); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret); + return ret; + } + } return ret; } @@ -200,7 +184,8 @@ static void acp_card_shutdown(struct snd_pcm_substream *substream) struct snd_soc_card *card = rtd->card; struct acp_card_drvdata *drvdata = card->drvdata; - clk_disable_unprepare(drvdata->wclk); + if (!drvdata->soc_mclk) + clk_disable_unprepare(drvdata->wclk); } static const struct snd_soc_ops acp_card_rt5682_ops = { @@ -224,6 +209,7 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) struct acp_card_drvdata *drvdata = card->drvdata; struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct snd_soc_component *component = codec_dai->component; + unsigned int fmt; int ret; dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); @@ -231,8 +217,12 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) if (drvdata->hs_codec_id != RT5682S) return -EINVAL; - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBP_CFP); + if (drvdata->soc_mclk) + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + else + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + + ret = snd_soc_dai_set_fmt(codec_dai, fmt); if (ret < 0) { dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); return ret; @@ -259,14 +249,16 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) return ret; } - drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); - drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); + if (!drvdata->soc_mclk) { + drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); + drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); + } ret = snd_soc_card_jack_new(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack, NULL, 0); + &pco_jack); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; @@ -388,7 +380,7 @@ static int acp_card_amp_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct acp_card_drvdata *drvdata = card->drvdata; - int ret; + int ret = 0; runtime->hw.channels_max = DUAL_CHANNEL; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, @@ -396,10 +388,13 @@ static int acp_card_amp_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - ret = acp_clk_enable(drvdata); - if (ret < 0) - dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret); - + if (!drvdata->soc_mclk) { + ret = acp_clk_enable(drvdata); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret); + return ret; + } + } return ret; } @@ -434,6 +429,104 @@ static const struct snd_soc_ops acp_card_maxim_ops = { .shutdown = acp_card_shutdown, }; +/* Declare nau8825 codec components */ +SND_SOC_DAILINK_DEF(nau8825, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi"))); + +static const struct snd_soc_dapm_route nau8825_map[] = { + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, +}; + +static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct acp_card_drvdata *drvdata = card->drvdata; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + unsigned int fmt; + int ret; + + dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); + + if (drvdata->hs_codec_id != NAU8825) + return -EINVAL; + + if (drvdata->soc_mclk) + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + else + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); + return ret; + } + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pco_jack); + if (ret) { + dev_err(card->dev, "HP jack creation failed %d\n", ret); + return ret; + } + + snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + if (ret) { + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + + return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8825_map, ARRAY_SIZE(nau8825_map)); +} + +static int acp_nau8825_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, + (48000 * 256), SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, params_rate(params), + params_rate(params) * 256); + if (ret < 0) { + dev_err(rtd->dev, "can't set FLL: %d\n", ret); + return ret; + } + + return ret; +} + +static int acp_nau8825_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + return 0; +} + +static const struct snd_soc_ops acp_card_nau8825_ops = { + .startup = acp_nau8825_startup, + .hw_params = acp_nau8825_hw_params, +}; + /* Declare DMIC codec components */ SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); @@ -452,6 +545,12 @@ static struct snd_soc_dai_link_component platform_component[] = { } }; +static struct snd_soc_dai_link_component platform_rmb_component[] = { + { + .name = "acp_asoc_rembrandt.0", + } +}; + static struct snd_soc_dai_link_component sof_component[] = { { .name = "0000:04:00.5", @@ -460,8 +559,12 @@ static struct snd_soc_dai_link_component sof_component[] = { SND_SOC_DAILINK_DEF(i2s_sp, DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-sp"))); +SND_SOC_DAILINK_DEF(i2s_hs, + DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-hs"))); SND_SOC_DAILINK_DEF(sof_sp, DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp"))); +SND_SOC_DAILINK_DEF(sof_hs, + DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs"))); SND_SOC_DAILINK_DEF(sof_dmic, DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic"))); SND_SOC_DAILINK_DEF(pdm_dmic, @@ -516,6 +619,37 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) i++; } + if (drv_data->hs_cpu_id == I2S_HS) { + links[i].name = "acp-headset-codec"; + links[i].id = HEADSET_BE_ID; + links[i].cpus = sof_hs; + links[i].num_cpus = ARRAY_SIZE(sof_hs); + links[i].platforms = sof_component; + links[i].num_platforms = ARRAY_SIZE(sof_component); + links[i].dpcm_playback = 1; + links[i].dpcm_capture = 1; + links[i].nonatomic = true; + links[i].no_pcm = 1; + if (!drv_data->hs_codec_id) { + /* Use dummy codec if codec id not specified */ + links[i].codecs = dummy_codec; + links[i].num_codecs = ARRAY_SIZE(dummy_codec); + } + if (drv_data->hs_codec_id == NAU8825) { + links[i].codecs = nau8825; + links[i].num_codecs = ARRAY_SIZE(nau8825); + links[i].init = acp_card_nau8825_init; + links[i].ops = &acp_card_nau8825_ops; + } + if (drv_data->hs_codec_id == RT5682S) { + links[i].codecs = rt5682s; + links[i].num_codecs = ARRAY_SIZE(rt5682s); + links[i].init = acp_card_rt5682s_init; + links[i].ops = &acp_card_rt5682s_ops; + } + i++; + } + if (drv_data->amp_cpu_id == I2S_SP) { links[i].name = "acp-amp-codec"; links[i].id = AMP_BE_ID; @@ -548,6 +682,38 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) i++; } + if (drv_data->amp_cpu_id == I2S_HS) { + links[i].name = "acp-amp-codec"; + links[i].id = AMP_BE_ID; + links[i].cpus = sof_hs; + links[i].num_cpus = ARRAY_SIZE(sof_hs); + links[i].platforms = sof_component; + links[i].num_platforms = ARRAY_SIZE(sof_component); + links[i].dpcm_playback = 1; + links[i].nonatomic = true; + links[i].no_pcm = 1; + if (!drv_data->amp_codec_id) { + /* Use dummy codec if codec id not specified */ + links[i].codecs = dummy_codec; + links[i].num_codecs = ARRAY_SIZE(dummy_codec); + } + if (drv_data->amp_codec_id == MAX98360A) { + links[i].codecs = max98360a; + links[i].num_codecs = ARRAY_SIZE(max98360a); + links[i].ops = &acp_card_maxim_ops; + links[i].init = acp_card_maxim_init; + } + if (drv_data->amp_codec_id == RT1019) { + links[i].codecs = rt1019; + links[i].num_codecs = ARRAY_SIZE(rt1019); + links[i].ops = &acp_card_rt1019_ops; + links[i].init = acp_card_rt1019_init; + card->codec_conf = rt1019_conf; + card->num_configs = ARRAY_SIZE(rt1019_conf); + } + i++; + } + if (drv_data->dmic_cpu_id == DMIC) { links[i].name = "acp-dmic-codec"; links[i].id = DMIC_BE_ID; @@ -616,6 +782,40 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) i++; } + if (drv_data->hs_cpu_id == I2S_HS) { + links[i].name = "acp-headset-codec"; + links[i].id = HEADSET_BE_ID; + links[i].cpus = i2s_hs; + links[i].num_cpus = ARRAY_SIZE(i2s_hs); + if (drv_data->platform == REMBRANDT) { + links[i].platforms = platform_rmb_component; + links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); + } else { + links[i].platforms = platform_component; + links[i].num_platforms = ARRAY_SIZE(platform_component); + } + links[i].dpcm_playback = 1; + links[i].dpcm_capture = 1; + if (!drv_data->hs_codec_id) { + /* Use dummy codec if codec id not specified */ + links[i].codecs = dummy_codec; + links[i].num_codecs = ARRAY_SIZE(dummy_codec); + } + if (drv_data->hs_codec_id == NAU8825) { + links[i].codecs = nau8825; + links[i].num_codecs = ARRAY_SIZE(nau8825); + links[i].init = acp_card_nau8825_init; + links[i].ops = &acp_card_nau8825_ops; + } + if (drv_data->hs_codec_id == RT5682S) { + links[i].codecs = rt5682s; + links[i].num_codecs = ARRAY_SIZE(rt5682s); + links[i].init = acp_card_rt5682s_init; + links[i].ops = &acp_card_rt5682s_ops; + } + i++; + } + if (drv_data->amp_cpu_id == I2S_SP) { links[i].name = "acp-amp-codec"; links[i].id = AMP_BE_ID; @@ -646,6 +846,41 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) i++; } + if (drv_data->amp_cpu_id == I2S_HS) { + links[i].name = "acp-amp-codec"; + links[i].id = AMP_BE_ID; + links[i].cpus = i2s_hs; + links[i].num_cpus = ARRAY_SIZE(i2s_hs); + if (drv_data->platform == REMBRANDT) { + links[i].platforms = platform_rmb_component; + links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); + } else { + links[i].platforms = platform_component; + links[i].num_platforms = ARRAY_SIZE(platform_component); + } + links[i].dpcm_playback = 1; + if (!drv_data->amp_codec_id) { + /* Use dummy codec if codec id not specified */ + links[i].codecs = dummy_codec; + links[i].num_codecs = ARRAY_SIZE(dummy_codec); + } + if (drv_data->amp_codec_id == MAX98360A) { + links[i].codecs = max98360a; + links[i].num_codecs = ARRAY_SIZE(max98360a); + links[i].ops = &acp_card_maxim_ops; + links[i].init = acp_card_maxim_init; + } + if (drv_data->amp_codec_id == RT1019) { + links[i].codecs = rt1019; + links[i].num_codecs = ARRAY_SIZE(rt1019); + links[i].ops = &acp_card_rt1019_ops; + links[i].init = acp_card_rt1019_init; + card->codec_conf = rt1019_conf; + card->num_configs = ARRAY_SIZE(rt1019_conf); + } + i++; + } + if (drv_data->dmic_cpu_id == DMIC) { links[i].name = "acp-dmic-codec"; links[i].id = DMIC_BE_ID; @@ -659,8 +894,13 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) } links[i].cpus = pdm_dmic; links[i].num_cpus = ARRAY_SIZE(pdm_dmic); - links[i].platforms = platform_component; - links[i].num_platforms = ARRAY_SIZE(platform_component); + if (drv_data->platform == REMBRANDT) { + links[i].platforms = platform_rmb_component; + links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); + } else { + links[i].platforms = platform_component; + links[i].num_platforms = ARRAY_SIZE(platform_component); + } links[i].ops = &acp_card_dmic_ops; links[i].dpcm_capture = 1; } diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h index c855f50d6b..20583ef902 100644 --- a/sound/soc/amd/acp/acp-mach.h +++ b/sound/soc/amd/acp/acp-mach.h @@ -17,11 +17,6 @@ #include #include #include -#include -#include - -#define EN_SPKR_GPIO_GB 0x11F -#define EN_SPKR_GPIO_NONE -EINVAL enum be_id { HEADSET_BE_ID = 0, @@ -31,6 +26,7 @@ enum be_id { enum cpu_endpoints { NONE = 0, + I2S_HS, I2S_SP, I2S_BT, DMIC, @@ -42,6 +38,12 @@ enum codec_endpoints { RT1019, MAX98360A, RT5682S, + NAU8825, +}; + +enum platform_end_point { + RENOIR = 0, + REMBRANDT, }; struct acp_card_drvdata { @@ -52,13 +54,13 @@ struct acp_card_drvdata { unsigned int amp_codec_id; unsigned int dmic_codec_id; unsigned int dai_fmt; + unsigned int platform; struct clk *wclk; struct clk *bclk; - unsigned int gpio_spkr_en; + bool soc_mclk; }; int acp_sofdsp_dai_links_create(struct snd_soc_card *card); int acp_legacy_dai_links_create(struct snd_soc_card *card); -int event_spkr_handler(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event); + #endif diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index 340e39d7f4..2c8e960cc9 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "amd.h" #include "../mach-config.h" @@ -28,7 +29,7 @@ static struct platform_device *dmic_dev; static struct platform_device *pdev; -static const struct resource acp3x_res[] = { +static const struct resource acp_res[] = { { .start = 0, .end = ACP3x_REG_END - ACP3x_REG_START, @@ -69,36 +70,49 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id ret = pci_request_regions(pci, "AMD ACP3x audio"); if (ret < 0) { dev_err(&pci->dev, "pci_request_regions failed\n"); - return -ENOMEM; + ret = -ENOMEM; + goto disable_pci; } pci_set_master(pci); + res_acp = acp_res; + num_res = ARRAY_SIZE(acp_res); + switch (pci->revision) { case 0x01: - res_acp = acp3x_res; - num_res = ARRAY_SIZE(acp3x_res); chip->name = "acp_asoc_renoir"; chip->acp_rev = ACP3X_DEV; break; + case 0x6f: + chip->name = "acp_asoc_rembrandt"; + chip->acp_rev = ACP6X_DEV; + break; default: dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision); - return -EINVAL; + ret = -EINVAL; + goto release_regions; } dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(dmic_dev)) { dev_err(dev, "failed to create DMIC device\n"); - return PTR_ERR(dmic_dev); + ret = PTR_ERR(dmic_dev); + goto release_regions; } addr = pci_resource_start(pci, 0); chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0)); + if (!chip->base) { + ret = -ENOMEM; + goto release_regions; + } res = devm_kzalloc(&pci->dev, sizeof(struct resource) * num_res, GFP_KERNEL); if (!res) { platform_device_unregister(dmic_dev); - return -ENOMEM; + ret = -ENOMEM; + goto release_regions; } for (i = 0; i < num_res; i++, res_acp++) { @@ -127,8 +141,16 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name); platform_device_unregister(dmic_dev); ret = PTR_ERR(pdev); + goto release_regions; } + return ret; + +release_regions: + pci_release_regions(pci); +disable_pci: + pci_disable_device(pci); + return ret; }; diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c index 424c6e0bb9..66ec6b6a59 100644 --- a/sound/soc/amd/acp/acp-pdm.c +++ b/sound/soc/amd/acp/acp-pdm.c @@ -160,9 +160,9 @@ static int acp_dmic_dai_startup(struct snd_pcm_substream *substream, stream->reg_offset = ACP_REGION2_OFFSET; /* Enable DMIC Interrupts */ - ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL); + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0)); ext_int_ctrl |= PDM_DMA_INTR_MASK; - writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL); + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0)); return 0; } @@ -174,10 +174,10 @@ static void acp_dmic_dai_shutdown(struct snd_pcm_substream *substream, struct acp_dev_data *adata = dev_get_drvdata(dev); u32 ext_int_ctrl; - /* Disable DMIC interrrupts */ - ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL); + /* Disable DMIC interrupts */ + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0)); ext_int_ctrl |= ~PDM_DMA_INTR_MASK; - writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL); + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0)); } const struct snd_soc_dai_ops acp_dmic_dai_ops = { diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index 65a809e2c2..f561d39b33 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -91,25 +91,38 @@ EXPORT_SYMBOL_NS_GPL(acp_machine_select, SND_SOC_ACP_COMMON); static irqreturn_t i2s_irq_handler(int irq, void *data) { struct acp_dev_data *adata = data; + struct acp_resource *rsrc = adata->rsrc; struct acp_stream *stream; u16 i2s_flag = 0; - u32 val, i; + u32 ext_intr_stat, ext_intr_stat1, i; if (!adata) return IRQ_NONE; - val = readl(adata->acp_base + ACP_EXTERNAL_INTR_STAT); + if (adata->rsrc->no_of_ctrls == 2) + ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1))); + + ext_intr_stat = readl(ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); for (i = 0; i < ACP_MAX_STREAM; i++) { stream = adata->stream[i]; - if (stream && (val & stream->irq_bit)) { - writel(stream->irq_bit, adata->acp_base + ACP_EXTERNAL_INTR_STAT); + if (stream && (ext_intr_stat & stream->irq_bit)) { + writel(stream->irq_bit, + ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); snd_pcm_period_elapsed(stream->substream); i2s_flag = 1; break; } + if (adata->rsrc->no_of_ctrls == 2) { + if (stream && (ext_intr_stat1 & stream->irq_bit)) { + writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(adata, + (rsrc->irqp_used - 1))); + snd_pcm_period_elapsed(stream->substream); + i2s_flag = 1; + break; + } + } } - if (i2s_flag) return IRQ_HANDLED; @@ -118,6 +131,7 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream) { + struct acp_resource *rsrc = adata->rsrc; u32 pte_reg, pte_size, reg_val; /* Use ATU base Group5 */ @@ -126,15 +140,17 @@ static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream stream->reg_offset = 0x02000000; /* Group Enable */ - reg_val = ACP_SRAM_PTE_OFFSET; + reg_val = rsrc->sram_pte_offset; writel(reg_val | BIT(31), adata->acp_base + pte_reg); writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + pte_size); + writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); } static void config_acp_dma(struct acp_dev_data *adata, int cpu_id, int size) { struct acp_stream *stream = adata->stream[cpu_id]; struct snd_pcm_substream *substream = stream->substream; + struct acp_resource *rsrc = adata->rsrc; dma_addr_t addr = substream->dma_buffer.addr; int num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT); u32 low, high, val; @@ -146,9 +162,9 @@ static void config_acp_dma(struct acp_dev_data *adata, int cpu_id, int size) /* Load the low address of page int ACP SRAM through SRBM */ low = lower_32_bits(addr); high = upper_32_bits(addr); - writel(low, adata->acp_base + ACP_SCRATCH_REG_0 + val); + writel(low, adata->acp_base + rsrc->scratch_reg_offset + val); high |= BIT(31); - writel(high, adata->acp_base + ACP_SCRATCH_REG_0 + val + 4); + writel(high, adata->acp_base + rsrc->scratch_reg_offset + val + 4); /* Move to next physically contiguous page */ val += 8; @@ -187,7 +203,7 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs } runtime->private_data = stream; - writel(1, adata->acp_base + ACP_EXTERNAL_INTR_ENB); + writel(1, ACP_EXTERNAL_INTR_ENB(adata)); return ret; } @@ -242,13 +258,6 @@ static int acp_dma_new(struct snd_soc_component *component, return 0; } -static int acp_dma_mmap(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - return snd_pcm_lib_default_mmap(substream, vma); -} - static int acp_dma_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -267,13 +276,13 @@ static int acp_dma_close(struct snd_soc_component *component, } static const struct snd_soc_component_driver acp_pcm_component = { - .name = DRV_NAME, - .open = acp_dma_open, - .close = acp_dma_close, - .hw_params = acp_dma_hw_params, - .pointer = acp_dma_pointer, - .mmap = acp_dma_mmap, - .pcm_construct = acp_dma_new, + .name = DRV_NAME, + .open = acp_dma_open, + .close = acp_dma_close, + .hw_params = acp_dma_hw_params, + .pointer = acp_dma_pointer, + .pcm_construct = acp_dma_new, + .legacy_dai_naming = 1, }; int acp_platform_register(struct device *dev) diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index 75c9229ece..2a89a0d2e6 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -39,6 +39,17 @@ #define ACP_ERROR_MASK 0x20000000 #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF +static struct acp_resource rsrc = { + .offset = 20, + .no_of_ctrls = 1, + .irqp_used = 0, + .irq_reg_offset = 0x1800, + .i2s_pin_cfg_offset = 0x1400, + .i2s_mode = 0x04, + .scratch_reg_offset = 0x12800, + .sram_pte_offset = 0x02052800, +}; + static struct snd_soc_acpi_codecs amp_rt1019 = { .num_codecs = 1, .codecs = {"10EC1019"} @@ -186,20 +197,24 @@ static int acp3x_reset(void __iomem *base) return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT); } -static void acp3x_enable_interrupts(void __iomem *base) +static void acp3x_enable_interrupts(struct acp_dev_data *adata) { + struct acp_resource *rsrc = adata->rsrc; u32 ext_intr_ctrl; - writel(0x01, base + ACP_EXTERNAL_INTR_ENB); - ext_intr_ctrl = readl(base + ACP_EXTERNAL_INTR_CNTL); + writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); + ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); ext_intr_ctrl |= ACP_ERROR_MASK; - writel(ext_intr_ctrl, base + ACP_EXTERNAL_INTR_CNTL); + writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); } -static void acp3x_disable_interrupts(void __iomem *base) +static void acp3x_disable_interrupts(struct acp_dev_data *adata) { - writel(ACP_EXT_INTR_STAT_CLEAR_MASK, base + ACP_EXTERNAL_INTR_STAT); - writel(0x00, base + ACP_EXTERNAL_INTR_ENB); + struct acp_resource *rsrc = adata->rsrc; + + writel(ACP_EXT_INTR_STAT_CLEAR_MASK, + ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); + writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); } static int rn_acp_init(void __iomem *base) @@ -218,8 +233,6 @@ static int rn_acp_init(void __iomem *base) if (ret) return ret; - acp3x_enable_interrupts(base); - return 0; } @@ -227,8 +240,6 @@ static int rn_acp_deinit(void __iomem *base) { int ret = 0; - acp3x_disable_interrupts(base); - /* Reset */ ret = acp3x_reset(base); if (ret) @@ -290,11 +301,13 @@ static int renoir_audio_probe(struct platform_device *pdev) adata->dev = dev; adata->dai_driver = acp_renoir_dai; adata->num_dai = ARRAY_SIZE(acp_renoir_dai); + adata->rsrc = &rsrc; adata->machines = snd_soc_acpi_amd_acp_machines; acp_machine_select(adata); dev_set_drvdata(dev, adata); + acp3x_enable_interrupts(adata); acp_platform_register(dev); return 0; @@ -303,20 +316,17 @@ static int renoir_audio_probe(struct platform_device *pdev) static int renoir_audio_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct acp_dev_data *adata = dev_get_drvdata(dev); struct acp_chip_info *chip; int ret; chip = dev_get_platdata(&pdev->dev); - if (!chip || !chip->base) { - dev_err(&pdev->dev, "ACP chip data is NULL\n"); - return -ENODEV; - } + + acp3x_disable_interrupts(adata); ret = rn_acp_deinit(chip->base); - if (ret) { - dev_err(&pdev->dev, "ACP de-init Failed\n"); - return -EINVAL; - } + if (ret) + dev_err(&pdev->dev, "ACP de-init Failed (%pe)\n", ERR_PTR(ret)); acp_platform_unregister(dev); return 0; diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c index 3346677949..f19f064a75 100644 --- a/sound/soc/amd/acp/acp-sof-mach.c +++ b/sound/soc/amd/acp/acp-sof-mach.c @@ -27,7 +27,6 @@ static struct acp_card_drvdata sof_rt5682_rt1019_data = { .hs_codec_id = RT5682, .amp_codec_id = RT1019, .dmic_codec_id = DMIC, - .gpio_spkr_en = EN_SPKR_GPIO_GB, }; static struct acp_card_drvdata sof_rt5682_max_data = { @@ -37,7 +36,6 @@ static struct acp_card_drvdata sof_rt5682_max_data = { .hs_codec_id = RT5682, .amp_codec_id = MAX98360A, .dmic_codec_id = DMIC, - .gpio_spkr_en = EN_SPKR_GPIO_NONE, }; static struct acp_card_drvdata sof_rt5682s_rt1019_data = { @@ -56,7 +54,26 @@ static struct acp_card_drvdata sof_rt5682s_max_data = { .hs_codec_id = RT5682S, .amp_codec_id = MAX98360A, .dmic_codec_id = DMIC, - .gpio_spkr_en = EN_SPKR_GPIO_NONE, +}; + +static struct acp_card_drvdata sof_nau8825_data = { + .hs_cpu_id = I2S_HS, + .amp_cpu_id = I2S_HS, + .dmic_cpu_id = DMIC, + .hs_codec_id = NAU8825, + .amp_codec_id = MAX98360A, + .dmic_codec_id = DMIC, + .soc_mclk = true, +}; + +static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = { + .hs_cpu_id = I2S_HS, + .amp_cpu_id = I2S_HS, + .dmic_cpu_id = DMIC, + .hs_codec_id = RT5682S, + .amp_codec_id = RT1019, + .dmic_codec_id = DMIC, + .soc_mclk = true, }; static const struct snd_kcontrol_new acp_controls[] = { @@ -70,16 +87,15 @@ static const struct snd_kcontrol_new acp_controls[] = { static const struct snd_soc_dapm_widget acp_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", event_spkr_handler), - SND_SOC_DAPM_SPK("Left Spk", event_spkr_handler), - SND_SOC_DAPM_SPK("Right Spk", event_spkr_handler), + SND_SOC_DAPM_SPK("Spk", NULL), + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), }; static int acp_sof_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; struct device *dev = &pdev->dev; - unsigned int spkr_gpio; int ret; if (!pdev->id_entry) @@ -97,20 +113,9 @@ static int acp_sof_probe(struct platform_device *pdev) card->controls = acp_controls; card->num_controls = ARRAY_SIZE(acp_controls); card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data; - spkr_gpio = ((struct acp_card_drvdata *)(card->drvdata))->gpio_spkr_en; acp_sofdsp_dai_links_create(card); - if (gpio_is_valid(spkr_gpio)) { - ret = devm_gpio_request(dev, spkr_gpio, "spkren"); - if (ret) { - dev_err(dev, "(%s) gpio request failed: %d\n", - __func__, ret); - return ret; - } - gpio_direction_output(spkr_gpio, 0); - } - ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { dev_err(&pdev->dev, @@ -139,11 +144,20 @@ static const struct platform_device_id board_ids[] = { .name = "rt5682s-rt1019", .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data }, + { + .name = "nau8825-max", + .driver_data = (kernel_ulong_t)&sof_nau8825_data + }, + { + .name = "rt5682s-hs-rt1019", + .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data + }, { } }; static struct platform_driver acp_asoc_audio = { .driver = { .name = "sof_mach", + .pm = &snd_soc_pm_ops, }, .probe = acp_sof_probe, .id_table = board_ids, @@ -157,4 +171,6 @@ MODULE_ALIAS("platform:rt5682-rt1019"); MODULE_ALIAS("platform:rt5682-max"); MODULE_ALIAS("platform:rt5682s-max"); MODULE_ALIAS("platform:rt5682s-rt1019"); +MODULE_ALIAS("platform:nau8825-max"); +MODULE_ALIAS("platform:rt5682s-hs-rt1019"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 8fd38bf4d3..af9603724a 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -19,10 +19,12 @@ #include "chip_offset_byte.h" #define ACP3X_DEV 3 +#define ACP6X_DEV 6 #define I2S_SP_INSTANCE 0x00 #define I2S_BT_INSTANCE 0x01 #define DMIC_INSTANCE 0x02 +#define I2S_HS_INSTANCE 0x03 #define MEM_WINDOW_START 0x4080000 @@ -32,30 +34,37 @@ #define ACP3x_I2STDM_REG_END 0x1242410 #define ACP3x_BT_TDM_REG_START 0x1242800 #define ACP3x_BT_TDM_REG_END 0x1242810 -#define I2S_MODE 0x04 -#define I2S_RX_THRESHOLD 27 -#define I2S_TX_THRESHOLD 28 -#define BT_TX_THRESHOLD 26 -#define BT_RX_THRESHOLD 25 -#define ACP_SRAM_PTE_OFFSET 0x02052800 +#define THRESHOLD(bit, base) ((bit) + (base)) +#define I2S_RX_THRESHOLD(base) THRESHOLD(7, base) +#define I2S_TX_THRESHOLD(base) THRESHOLD(8, base) +#define BT_TX_THRESHOLD(base) THRESHOLD(6, base) +#define BT_RX_THRESHOLD(base) THRESHOLD(5, base) +#define HS_TX_THRESHOLD(base) THRESHOLD(4, base) +#define HS_RX_THRESHOLD(base) THRESHOLD(3, base) #define ACP_SRAM_SP_PB_PTE_OFFSET 0x0 #define ACP_SRAM_SP_CP_PTE_OFFSET 0x100 #define ACP_SRAM_BT_PB_PTE_OFFSET 0x200 #define ACP_SRAM_BT_CP_PTE_OFFSET 0x300 #define ACP_SRAM_PDM_PTE_OFFSET 0x400 +#define ACP_SRAM_HS_PB_PTE_OFFSET 0x500 +#define ACP_SRAM_HS_CP_PTE_OFFSET 0x600 #define PAGE_SIZE_4K_ENABLE 0x2 #define I2S_SP_TX_MEM_WINDOW_START 0x4000000 #define I2S_SP_RX_MEM_WINDOW_START 0x4020000 #define I2S_BT_TX_MEM_WINDOW_START 0x4040000 #define I2S_BT_RX_MEM_WINDOW_START 0x4060000 +#define I2S_HS_TX_MEM_WINDOW_START 0x40A0000 +#define I2S_HS_RX_MEM_WINDOW_START 0x40C0000 #define SP_PB_FIFO_ADDR_OFFSET 0x500 #define SP_CAPT_FIFO_ADDR_OFFSET 0x700 #define BT_PB_FIFO_ADDR_OFFSET 0x900 #define BT_CAPT_FIFO_ADDR_OFFSET 0xB00 +#define HS_PB_FIFO_ADDR_OFFSET 0xD00 +#define HS_CAPT_FIFO_ADDR_OFFSET 0xF00 #define PLAYBACK_MIN_NUM_PERIODS 2 #define PLAYBACK_MAX_NUM_PERIODS 8 #define PLAYBACK_MAX_PERIOD_SIZE 8192 @@ -73,7 +82,7 @@ #define ACP3x_ITER_IRER_SAMP_LEN_MASK 0x38 -#define ACP_MAX_STREAM 6 +#define ACP_MAX_STREAM 8 struct acp_chip_info { char *name; /* Platform name */ @@ -92,6 +101,18 @@ struct acp_stream { u32 fifo_offset; }; +struct acp_resource { + int offset; + int no_of_ctrls; + int irqp_used; + bool soc_mclk; + u32 irq_reg_offset; + u32 i2s_pin_cfg_offset; + int i2s_mode; + u64 scratch_reg_offset; + u64 sram_pte_offset; +}; + struct acp_dev_data { char *name; struct device *dev; @@ -106,6 +127,22 @@ struct acp_dev_data { struct snd_soc_acpi_mach *machines; struct platform_device *mach_dev; + + u32 bclk_div; + u32 lrclk_div; + + struct acp_resource *rsrc; +}; + +union acp_i2stdm_mstrclkgen { + struct { + u32 i2stdm_master_mode : 1; + u32 i2stdm_format_mode : 1; + u32 i2stdm_lrclk_div_val : 9; + u32 i2stdm_bclk_div_val : 11; + u32:10; + } bitfields, bits; + u32 u32_all; }; extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops; @@ -134,6 +171,10 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int high = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH); low = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW); break; + case I2S_HS_INSTANCE: + high = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_HIGH); + low = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_LOW); + break; default: dev_err(adata->dev, "Invalid dai id %x\n", dai_id); return -EINVAL; @@ -148,6 +189,10 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int high = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH); low = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW); break; + case I2S_HS_INSTANCE: + high = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_HIGH); + low = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_LOW); + break; case DMIC_INSTANCE: high = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH); low = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW); @@ -163,4 +208,31 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int return byte_count; } +static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id) +{ + union acp_i2stdm_mstrclkgen mclkgen; + u32 master_reg; + + switch (dai_id) { + case I2S_SP_INSTANCE: + master_reg = ACP_I2STDM0_MSTRCLKGEN; + break; + case I2S_BT_INSTANCE: + master_reg = ACP_I2STDM1_MSTRCLKGEN; + break; + case I2S_HS_INSTANCE: + master_reg = ACP_I2STDM2_MSTRCLKGEN; + break; + default: + master_reg = ACP_I2STDM0_MSTRCLKGEN; + break; + } + + mclkgen.bits.i2stdm_master_mode = 0x1; + mclkgen.bits.i2stdm_format_mode = 0x00; + + mclkgen.bits.i2stdm_bclk_div_val = adata->bclk_div; + mclkgen.bits.i2stdm_lrclk_div_val = adata->lrclk_div; + writel(mclkgen.u32_all, adata->acp_base + master_reg); +} #endif diff --git a/sound/soc/amd/acp/chip_offset_byte.h b/sound/soc/amd/acp/chip_offset_byte.h index 88f6fa597c..ce3948e067 100644 --- a/sound/soc/amd/acp/chip_offset_byte.h +++ b/sound/soc/amd/acp/chip_offset_byte.h @@ -20,11 +20,13 @@ #define ACP_SOFT_RESET 0x1000 #define ACP_CONTROL 0x1004 -#define ACP_EXTERNAL_INTR_ENB 0x1800 -#define ACP_EXTERNAL_INTR_CNTL 0x1804 -#define ACP_EXTERNAL_INTR_STAT 0x1808 -#define ACP_I2S_PIN_CONFIG 0x1400 -#define ACP_SCRATCH_REG_0 0x12800 +#define ACP_EXTERNAL_INTR_REG_ADDR(adata, offset, ctrl) \ + (adata->acp_base + adata->rsrc->irq_reg_offset + offset + (ctrl * 0x04)) + +#define ACP_EXTERNAL_INTR_ENB(adata) ACP_EXTERNAL_INTR_REG_ADDR(adata, 0x0, 0x0) +#define ACP_EXTERNAL_INTR_CNTL(adata, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(adata, 0x4, ctrl) +#define ACP_EXTERNAL_INTR_STAT(adata, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(adata, \ + (0x4 + (adata->rsrc->no_of_ctrls * 0x04)), ctrl) /* Registers from ACP_AUDIO_BUFFERS block */ @@ -64,6 +66,24 @@ #define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x2084 #define ACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x2088 #define ACP_BT_TX_INTR_WATERMARK_SIZE 0x208C +#define ACP_HS_RX_RINGBUFADDR 0x3A90 +#define ACP_HS_RX_RINGBUFSIZE 0x3A94 +#define ACP_HS_RX_LINKPOSITIONCNTR 0x3A98 +#define ACP_HS_RX_FIFOADDR 0x3A9C +#define ACP_HS_RX_FIFOSIZE 0x3AA0 +#define ACP_HS_RX_DMA_SIZE 0x3AA4 +#define ACP_HS_RX_LINEARPOSITIONCNTR_HIGH 0x3AA8 +#define ACP_HS_RX_LINEARPOSITIONCNTR_LOW 0x3AAC +#define ACP_HS_RX_INTR_WATERMARK_SIZE 0x3AB0 +#define ACP_HS_TX_RINGBUFADDR 0x3AB4 +#define ACP_HS_TX_RINGBUFSIZE 0x3AB8 +#define ACP_HS_TX_LINKPOSITIONCNTR 0x3ABC +#define ACP_HS_TX_FIFOADDR 0x3AC0 +#define ACP_HS_TX_FIFOSIZE 0x3AC4 +#define ACP_HS_TX_DMA_SIZE 0x3AC8 +#define ACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x3ACC +#define ACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x3AD0 +#define ACP_HS_TX_INTR_WATERMARK_SIZE 0x3AD4 #define ACP_I2STDM_IER 0x2400 #define ACP_I2STDM_IRER 0x2404 @@ -79,6 +99,13 @@ #define ACP_BTTDM_ITER 0x280C #define ACP_BTTDM_TXFRMT 0x2810 +/* Registers from ACP_HS_TDM block */ +#define ACP_HSTDM_IER 0x2814 +#define ACP_HSTDM_IRER 0x2818 +#define ACP_HSTDM_RXFRMT 0x281C +#define ACP_HSTDM_ITER 0x2820 +#define ACP_HSTDM_TXFRMT 0x2824 + /* Registers from ACP_WOV_PDM block */ #define ACP_WOV_PDM_ENABLE 0x2C04 @@ -99,4 +126,7 @@ #define ACP_PDM_VAD_DYNAMIC_CLK_GATING_EN 0x2C64 #define ACP_WOV_ERROR_STATUS_REGISTER 0x2C68 +#define ACP_I2STDM0_MSTRCLKGEN 0x2414 +#define ACP_I2STDM1_MSTRCLKGEN 0x2418 +#define ACP_I2STDM2_MSTRCLKGEN 0x241C #endif diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c index dad70436d0..0543dda75b 100644 --- a/sound/soc/amd/acp3x-rt5682-max9836.c +++ b/sound/soc/amd/acp3x-rt5682-max9836.c @@ -90,7 +90,7 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd) SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack, NULL, 0); + &pco_jack); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 0a54567a28..7b4c625da4 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -19,6 +19,7 @@ #define ACP_PCI_DEV_ID 0x15E2 extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[]; struct config_entry { u32 flags; diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c index de6f70d7ef..aa38cef177 100644 --- a/sound/soc/amd/raven/acp3x-i2s.c +++ b/sound/soc/amd/raven/acp3x-i2s.c @@ -257,7 +257,8 @@ static const struct snd_soc_dai_ops acp3x_i2s_dai_ops = { }; static const struct snd_soc_component_driver acp3x_dai_component = { - .name = DRV_NAME, + .name = DRV_NAME, + .legacy_dai_naming = 1, }; static struct snd_soc_dai_driver acp3x_i2s_dai = { diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c index 8c42345ee4..7203c6488d 100644 --- a/sound/soc/amd/renoir/acp3x-pdm-dma.c +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -363,12 +363,13 @@ static struct snd_soc_dai_driver acp_pdm_dai_driver = { }; static const struct snd_soc_component_driver acp_pdm_component = { - .name = DRV_NAME, - .open = acp_pdm_dma_open, - .close = acp_pdm_dma_close, - .hw_params = acp_pdm_dma_hw_params, - .pointer = acp_pdm_dma_pointer, - .pcm_construct = acp_pdm_dma_new, + .name = DRV_NAME, + .open = acp_pdm_dma_open, + .close = acp_pdm_dma_close, + .hw_params = acp_pdm_dma_hw_params, + .pointer = acp_pdm_dma_pointer, + .pcm_construct = acp_pdm_dma_new, + .legacy_dai_naming = 1, }; static int acp_pdm_audio_probe(struct platform_device *pdev) diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c index 59a98f89a6..773e96f1b4 100644 --- a/sound/soc/amd/vangogh/acp5x-i2s.c +++ b/sound/soc/amd/vangogh/acp5x-i2s.c @@ -37,10 +37,10 @@ static int acp5x_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } mode = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; switch (mode) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: adata->master_mode = I2S_MASTER_MODE_ENABLE; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: adata->master_mode = I2S_MASTER_MODE_DISABLE; break; } @@ -345,6 +345,7 @@ static const struct snd_soc_dai_ops acp5x_i2s_dai_ops = { static const struct snd_soc_component_driver acp5x_dai_component = { .name = "acp5x-i2s", + .legacy_dai_naming = 1, }; static struct snd_soc_dai_driver acp5x_i2s_dai = { diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c index 1551546c30..af3737ef97 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -17,10 +17,8 @@ #include #include #include -#include #include #include -#include #include #include @@ -61,10 +59,10 @@ static int acp5x_8821_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &vg_headset, acp5x_nau8821_jack_pins, - ARRAY_SIZE(acp5x_nau8821_jack_pins)); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &vg_headset, acp5x_nau8821_jack_pins, + ARRAY_SIZE(acp5x_nau8821_jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); return ret; @@ -180,8 +178,7 @@ static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream, ret = 0; for (i = 0; i < num_codecs; i++) { codec_dai = asoc_rtd_to_codec(rtd, i); - if ((strcmp(codec_dai->name, "spi-VLV1776:00") == 0) || - (strcmp(codec_dai->name, "spi-VLV1776:01") == 0)) { + if (strcmp(codec_dai->name, "cs35l41-pcm") == 0) { switch (params_rate(params)) { case 48000: bclk_val = 1536000; diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index 9a767f47b8..e0b24e1dae 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "acp6x.h" @@ -45,111 +46,129 @@ static struct snd_soc_card acp6x_card = { static const struct dmi_system_id yc_acp_quirk_table[] = { { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "21D2"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "21D3"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "21D4"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "21D5"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "21CF"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "21CG"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "21CQ"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "21CR"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21AW"), + DMI_MATCH(DMI_PRODUCT_NAME, "21CM"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21AX"), + DMI_MATCH(DMI_PRODUCT_NAME, "21CN"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21BN"), + DMI_MATCH(DMI_PRODUCT_NAME, "21CH"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21BQ"), + DMI_MATCH(DMI_PRODUCT_NAME, "21CJ"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21CH"), + DMI_MATCH(DMI_PRODUCT_NAME, "21CK"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21CJ"), + DMI_MATCH(DMI_PRODUCT_NAME, "21CL"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21CK"), + DMI_MATCH(DMI_PRODUCT_NAME, "21EM"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21CL"), + DMI_MATCH(DMI_PRODUCT_NAME, "21EN"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21D8"), + DMI_MATCH(DMI_PRODUCT_NAME, "21J5"), } }, { + .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21D9"), + DMI_MATCH(DMI_PRODUCT_NAME, "21J6"), } }, {} @@ -157,18 +176,33 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { static int acp6x_probe(struct platform_device *pdev) { + const struct dmi_system_id *dmi_id; struct acp6x_pdm *machine = NULL; struct snd_soc_card *card; + struct acpi_device *adev; int ret; - const struct dmi_system_id *dmi_id; + /* check the parent device's firmware node has _DSD or not */ + adev = ACPI_COMPANION(pdev->dev.parent); + if (adev) { + const union acpi_object *obj; + + if (!acpi_dev_get_property(adev, "AcpDmicConnected", ACPI_TYPE_INTEGER, &obj) && + obj->integer.value == 1) + platform_set_drvdata(pdev, &acp6x_card); + } + + /* check for any DMI overrides */ dmi_id = dmi_first_match(yc_acp_quirk_table); - if (!dmi_id) + if (dmi_id) + platform_set_drvdata(pdev, dmi_id->driver_data); + + card = platform_get_drvdata(pdev); + if (!card) return -ENODEV; - card = &acp6x_card; + dev_info(&pdev->dev, "Enabling ACP DMIC support via %s", dmi_id ? "DMI" : "ACPI"); acp6x_card.dev = &pdev->dev; - platform_set_drvdata(pdev, card); snd_soc_card_set_drvdata(card, machine); ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c index 7e66393e41..acecd6a4ec 100644 --- a/sound/soc/amd/yc/acp6x-pdm-dma.c +++ b/sound/soc/amd/yc/acp6x-pdm-dma.c @@ -335,12 +335,13 @@ static struct snd_soc_dai_driver acp6x_pdm_dai_driver = { }; static const struct snd_soc_component_driver acp6x_pdm_component = { - .name = DRV_NAME, - .open = acp6x_pdm_dma_open, - .close = acp6x_pdm_dma_close, - .hw_params = acp6x_pdm_dma_hw_params, - .pointer = acp6x_pdm_dma_pointer, - .pcm_construct = acp6x_pdm_dma_new, + .name = DRV_NAME, + .open = acp6x_pdm_dma_open, + .close = acp6x_pdm_dma_close, + .hw_params = acp6x_pdm_dma_hw_params, + .pointer = acp6x_pdm_dma_pointer, + .pcm_construct = acp6x_pdm_dma_new, + .legacy_dai_naming = 1, }; static int acp6x_pdm_audio_probe(struct platform_device *pdev) diff --git a/sound/soc/amd/yc/pci-acp6x.c b/sound/soc/amd/yc/pci-acp6x.c index 7e9a9a9d8d..77c5fa1f7a 100644 --- a/sound/soc/amd/yc/pci-acp6x.c +++ b/sound/soc/amd/yc/pci-acp6x.c @@ -154,9 +154,14 @@ static int snd_acp6x_probe(struct pci_dev *pci, irqflags = IRQF_SHARED; /* Yellow Carp device check */ - if (pci->revision != 0x60) + switch (pci->revision) { + case 0x60: + case 0x6f: + break; + default: + dev_dbg(&pci->dev, "acp6x pci device not found\n"); return -ENODEV; - + } if (pci_enable_device(pci)) { dev_err(&pci->dev, "pci_enable_device failed\n"); return -ENODEV; diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 795c0b0b52..5d59e00be8 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -42,9 +42,9 @@ config SND_ATMEL_SOC_SSC_DMA config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" depends on ARCH_AT91 || COMPILE_TEST - depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI + depends on ATMEL_SSC && I2C select SND_ATMEL_SOC_SSC_PDC - select SND_SOC_WM8731 + select SND_SOC_WM8731_I2C help Say Y if you want to add support for SoC audio on WM8731-based AT91sam9g20 evaluation board. diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index a9f9f449c4..87d6d6ed02 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -458,7 +458,7 @@ static const struct snd_soc_component_driver atmel_classd_cpu_dai_component = { .num_controls = ARRAY_SIZE(atmel_classd_snd_controls), .idle_bias_on = 1, .use_pmdown_time = 1, - .endianness = 1, + .legacy_dai_naming = 1, }; /* ASoC sound card */ diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c index 1934767690..425d66edbf 100644 --- a/sound/soc/atmel/atmel-i2s.c +++ b/sound/soc/atmel/atmel-i2s.c @@ -343,7 +343,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream, } switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: /* codec is slave, so cpu is master */ mr |= ATMEL_I2SC_MR_MODE_MASTER; ret = atmel_i2s_get_gck_param(dev, params_rate(params)); @@ -351,7 +351,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream, return ret; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: /* codec is master, so cpu is slave */ mr |= ATMEL_I2SC_MR_MODE_SLAVE; dev->gck_param = NULL; @@ -564,7 +564,8 @@ static struct snd_soc_dai_driver atmel_i2s_dai = { }; static const struct snd_soc_component_driver atmel_i2s_component = { - .name = "atmel-i2s", + .name = "atmel-i2s", + .legacy_dai_naming = 1, }; static int atmel_i2s_sama5d2_mck_init(struct atmel_i2s_dev *dev, diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c index 42117de299..77ff12baea 100644 --- a/sound/soc/atmel/atmel-pdmic.c +++ b/sound/soc/atmel/atmel-pdmic.c @@ -481,7 +481,7 @@ static const struct snd_soc_component_driver atmel_pdmic_cpu_dai_component = { .num_controls = ARRAY_SIZE(atmel_pdmic_snd_controls), .idle_bias_on = 1, .use_pmdown_time = 1, - .endianness = 1, + .legacy_dai_naming = 1, }; /* ASoC sound card */ diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index c1dea8d624..e868b7e028 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -210,7 +210,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, return frame_size; switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE) && ssc->clk_from_rk_pin) /* Receiver Frame Synchro (i.e. capture) @@ -220,7 +220,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, mck_div = 3; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK) && !ssc->clk_from_rk_pin) /* Transmit Frame Synchro (i.e. playback) @@ -233,7 +233,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, } switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: r.num = ssc_p->mck_rate / mck_div / frame_size; ret = snd_interval_ratnum(i, 1, &r, &num, &den); @@ -243,8 +243,8 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, } break; - case SND_SOC_DAIFMT_CBP_CFC: - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FP: + case SND_SOC_DAIFMT_BC_FC: t.min = 8000; t.max = ssc_p->mck_rate / mck_div / frame_size; t.openmin = t.openmax = 0; @@ -433,8 +433,8 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p) { switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFC: - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BC_FP: + case SND_SOC_DAIFMT_BP_FP: return 1; } return 0; @@ -444,8 +444,8 @@ static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p) static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p) { switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFP: - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FC: + case SND_SOC_DAIFMT_BP_FP: return 1; } return 0; @@ -762,7 +762,6 @@ static int atmel_ssc_trigger(struct snd_pcm_substream *substream, return 0; } -#ifdef CONFIG_PM static int atmel_ssc_suspend(struct snd_soc_component *component) { struct atmel_ssc_info *ssc_p; @@ -821,10 +820,6 @@ static int atmel_ssc_resume(struct snd_soc_component *component) return 0; } -#else /* CONFIG_PM */ -# define atmel_ssc_suspend NULL -# define atmel_ssc_resume NULL -#endif /* CONFIG_PM */ #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) @@ -858,9 +853,10 @@ static struct snd_soc_dai_driver atmel_ssc_dai = { }; static const struct snd_soc_component_driver atmel_ssc_component = { - .name = "atmel-ssc", - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, + .name = "atmel-ssc", + .suspend = pm_ptr(atmel_ssc_suspend), + .resume = pm_ptr(atmel_ssc_resume), + .legacy_dai_naming = 1, }; static int asoc_ssc_init(struct device *dev) diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 6d1227a1d6..6dfb96c576 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -350,7 +350,7 @@ static int mchp_i2s_mcc_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; /* We can't generate only FSYNC */ - if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_CBP_CFC) + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_BC_FP) return -EINVAL; /* We can only reconfigure the IP when it's stopped */ @@ -547,19 +547,19 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, } switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: /* cpu is BCLK and LRC master */ mra |= MCHP_I2SMCC_MRA_MODE_MASTER; if (dev->sysclk) mra |= MCHP_I2SMCC_MRA_IMCKMODE_GEN; set_divs = 1; break; - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BP_FC: /* cpu is BCLK master */ mrb |= MCHP_I2SMCC_MRB_CLKSEL_INT; set_divs = 1; fallthrough; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: /* cpu is slave */ mra |= MCHP_I2SMCC_MRA_MODE_SLAVE; if (dev->sysclk) @@ -928,7 +928,8 @@ static struct snd_soc_dai_driver mchp_i2s_mcc_dai = { }; static const struct snd_soc_component_driver mchp_i2s_mcc_component = { - .name = "mchp-i2s-mcc", + .name = "mchp-i2s-mcc", + .legacy_dai_naming = 1, }; #ifdef CONFIG_OF diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c index a3856c73e2..44aefbd5b6 100644 --- a/sound/soc/atmel/mchp-pdmc.c +++ b/sound/soc/atmel/mchp-pdmc.c @@ -423,6 +423,7 @@ static const struct snd_soc_component_driver mchp_pdmc_dai_component = { .num_controls = ARRAY_SIZE(mchp_pdmc_snd_controls), .open = &mchp_pdmc_open, .close = &mchp_pdmc_close, + .legacy_dai_naming = 1, }; static const unsigned int mchp_pdmc_1mic[] = {1}; @@ -492,8 +493,8 @@ static int mchp_pdmc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int fmt_format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; /* IP needs to be bitclock master */ - if (fmt_master != SND_SOC_DAIFMT_CBS_CFS && - fmt_master != SND_SOC_DAIFMT_CBS_CFM) + if (fmt_master != SND_SOC_DAIFMT_BP_FP && + fmt_master != SND_SOC_DAIFMT_BP_FC) return -EINVAL; /* IP supports only PDM interface */ @@ -984,7 +985,7 @@ static int mchp_pdmc_probe(struct platform_device *pdev) return -ENOMEM; dd->dev = &pdev->dev; - ret = mchp_pdmc_dt_init(dd); + ret = mchp_pdmc_dt_init(dd); if (ret < 0) return ret; diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c index 5fc968483f..ec0705cc40 100644 --- a/sound/soc/atmel/mchp-spdifrx.c +++ b/sound/soc/atmel/mchp-spdifrx.c @@ -221,11 +221,11 @@ struct mchp_spdifrx_user_data { }; struct mchp_spdifrx_mixer_control { - struct mchp_spdifrx_ch_stat ch_stat[SPDIFRX_CHANNELS]; - struct mchp_spdifrx_user_data user_data[SPDIFRX_CHANNELS]; - bool ulock; - bool badf; - bool signal; + struct mchp_spdifrx_ch_stat ch_stat[SPDIFRX_CHANNELS]; + struct mchp_spdifrx_user_data user_data[SPDIFRX_CHANNELS]; + bool ulock; + bool badf; + bool signal; }; struct mchp_spdifrx_dev { @@ -288,15 +288,17 @@ static void mchp_spdifrx_isr_blockend_en(struct mchp_spdifrx_dev *dev) spin_unlock_irqrestore(&dev->blockend_lock, flags); } -/* called from atomic context only */ +/* called from atomic/non-atomic context */ static void mchp_spdifrx_isr_blockend_dis(struct mchp_spdifrx_dev *dev) { - spin_lock(&dev->blockend_lock); + unsigned long flags; + + spin_lock_irqsave(&dev->blockend_lock, flags); dev->blockend_refcount--; /* don't enable BLOCKEND interrupt if it's already enabled */ if (dev->blockend_refcount == 0) regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_BLOCKEND); - spin_unlock(&dev->blockend_lock); + spin_unlock_irqrestore(&dev->blockend_lock, flags); } static irqreturn_t mchp_spdif_interrupt(int irq, void *dev_id) @@ -575,6 +577,7 @@ static int mchp_spdifrx_subcode_ch_get(struct mchp_spdifrx_dev *dev, if (ret <= 0) { dev_dbg(dev->dev, "user data for channel %d timeout\n", channel); + mchp_spdifrx_isr_blockend_dis(dev); return ret; } @@ -846,7 +849,8 @@ static struct snd_soc_dai_driver mchp_spdifrx_dai = { }; static const struct snd_soc_component_driver mchp_spdifrx_component = { - .name = "mchp-spdifrx", + .name = "mchp-spdifrx", + .legacy_dai_naming = 1, }; static const struct of_device_id mchp_spdifrx_dt_ids[] = { diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index d243800464..4850a17780 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -196,7 +196,6 @@ struct mchp_spdiftx_dev { struct clk *pclk; struct clk *gclk; unsigned int fmt; - const struct mchp_i2s_caps *caps; int gclk_enabled:1; }; @@ -341,12 +340,10 @@ static int mchp_spdiftx_trigger(struct snd_pcm_substream *substream, int cmd, ret = regmap_write(dev->regmap, SPDIFTX_MR, mr); spin_unlock(&ctrl->lock); - if (ret) { + if (ret) dev_err(dev->dev, "unable to disable TX: %d\n", ret); - return ret; - } - return 0; + return ret; } static int mchp_spdiftx_hw_params(struct snd_pcm_substream *substream, @@ -753,7 +750,8 @@ static struct snd_soc_dai_driver mchp_spdiftx_dai = { }; static const struct snd_soc_component_driver mchp_spdiftx_component = { - .name = "mchp-spdiftx", + .name = "mchp-spdiftx", + .legacy_dai_naming = 1, }; static const struct of_device_id mchp_spdiftx_dt_ids[] = { @@ -762,12 +760,10 @@ static const struct of_device_id mchp_spdiftx_dt_ids[] = { }, { /* sentinel */ } }; - MODULE_DEVICE_TABLE(of, mchp_spdiftx_dt_ids); + static int mchp_spdiftx_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; - const struct of_device_id *match; struct mchp_spdiftx_dev *dev; struct resource *mem; struct regmap *regmap; @@ -781,11 +777,6 @@ static int mchp_spdiftx_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; - /* Get hardware capabilities. */ - match = of_match_node(mchp_spdiftx_dt_ids, np); - if (match) - dev->caps = match->data; - /* Map I/O registers. */ base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(base)) @@ -847,12 +838,10 @@ static int mchp_spdiftx_probe(struct platform_device *pdev) err = devm_snd_soc_register_component(&pdev->dev, &mchp_spdiftx_component, &mchp_spdiftx_dai, 1); - if (err) { + if (err) dev_err(&pdev->dev, "failed to register component: %d\n", err); - return err; - } - return 0; + return err; } static struct platform_driver mchp_spdiftx_driver = { diff --git a/sound/soc/atmel/mikroe-proto.c b/sound/soc/atmel/mikroe-proto.c index ce46d8a0b7..954460719a 100644 --- a/sound/soc/atmel/mikroe-proto.c +++ b/sound/soc/atmel/mikroe-proto.c @@ -157,7 +157,9 @@ static int snd_proto_probe(struct platform_device *pdev) static int snd_proto_remove(struct platform_device *pdev) { - return snd_soc_unregister_card(&snd_proto); + snd_soc_unregister_card(&snd_proto); + + return 0; } static const struct of_device_id snd_proto_of_match[] = { diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 0d639a33ad..4d25fb61c6 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -127,8 +127,8 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev) ret = atmel_ssc_set_audio(0); if (ret) { - dev_err(&pdev->dev, "ssc channel is not valid\n"); - return -EINVAL; + dev_err(&pdev->dev, "ssc channel is not valid: %d\n", ret); + return ret; } card->dev = &pdev->dev; @@ -148,7 +148,8 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev) codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); if (!codec_np) { dev_err(&pdev->dev, "codec info missing\n"); - return -EINVAL; + ret = -EINVAL; + goto err; } at91sam9g20ek_dai.codecs->of_node = codec_np; @@ -159,7 +160,8 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev) if (!cpu_np) { dev_err(&pdev->dev, "dai and pcm info missing\n"); of_node_put(codec_np); - return -EINVAL; + ret = -EINVAL; + goto err; } at91sam9g20ek_dai.cpus->of_node = cpu_np; at91sam9g20ek_dai.platforms->of_node = cpu_np; @@ -169,10 +171,12 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev) ret = snd_soc_register_card(card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card() failed\n"); + dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card() failed: %d\n", ret); + goto err; } - return ret; + return 0; err: atmel_ssc_put_audio(0); diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig index 38de7c0efb..8a78809e87 100644 --- a/sound/soc/au1x/Kconfig +++ b/sound/soc/au1x/Kconfig @@ -58,7 +58,7 @@ config SND_SOC_DB1200 select SND_SOC_AC97_CODEC select SND_SOC_WM9712 select SND_SOC_AU1XPSC_I2S - select SND_SOC_WM8731 + select SND_SOC_WM8731_I2C help Select this option to enable audio (AC97 and I2S) on the Alchemy/AMD/RMI/NetLogic Db1200, Db1550 and Db1300 evaluation boards. diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index 3b1700e665..b18512ca25 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -223,7 +223,8 @@ static struct snd_soc_dai_driver au1xac97c_dai_driver = { }; static const struct snd_soc_component_driver au1xac97c_component = { - .name = "au1xac97c", + .name = "au1xac97c", + .legacy_dai_naming = 1, }; static int au1xac97c_drvprobe(struct platform_device *pdev) diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c index 740d4e052e..b15c8baa9e 100644 --- a/sound/soc/au1x/i2sc.c +++ b/sound/soc/au1x/i2sc.c @@ -121,7 +121,7 @@ static int au1xi2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) /* I2S controller only supports provider */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: /* CODEC consumer */ + case SND_SOC_DAIFMT_BP_FP: /* CODEC consumer */ break; default: goto out; @@ -227,7 +227,8 @@ static struct snd_soc_dai_driver au1xi2s_dai_driver = { }; static const struct snd_soc_component_driver au1xi2s_component = { - .name = "au1xi2s", + .name = "au1xi2s", + .legacy_dai_naming = 1, }; static int au1xi2s_drvprobe(struct platform_device *pdev) diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 05eb36991f..b536394b9c 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -356,7 +356,8 @@ static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { }; static const struct snd_soc_component_driver au1xpsc_ac97_component = { - .name = "au1xpsc-ac97", + .name = "au1xpsc-ac97", + .legacy_dai_naming = 1, }; static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index b2b8896bb5..79b5ae4e49 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -91,10 +91,10 @@ static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: /* CODEC provider */ + case SND_SOC_DAIFMT_BC_FC: /* CODEC provider */ ct |= PSC_I2SCFG_MS; /* PSC I2S consumer mode */ break; - case SND_SOC_DAIFMT_CBC_CFC: /* CODEC consumer */ + case SND_SOC_DAIFMT_BP_FP: /* CODEC consumer */ ct &= ~PSC_I2SCFG_MS; /* PSC I2S provider mode */ break; default: @@ -286,7 +286,8 @@ static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = { }; static const struct snd_soc_component_driver au1xpsc_i2s_component = { - .name = "au1xpsc-i2s", + .name = "au1xpsc-i2s", + .legacy_dai_naming = 1, }; static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig index c85714895f..c865ad6f50 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig @@ -324,3 +324,10 @@ config SND_RPI_WM8804_SOUNDCARD help Say Y or M if you want to add support for the Raspberry Pi generic driver for WM8804 based soundcards. + +config SND_DACBERRY400 + tristate "Support for DACBERRY400 Soundcard" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_TLV320AIC3X_I2C + help + Say Y or M if you want to add support for tlv320aic3x add-on diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile index 1efb734f1c..46d1ece070 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile @@ -48,6 +48,7 @@ snd-soc-rpi-simple-soundcard-objs := rpi-simple-soundcard.o snd-soc-rpi-wm8804-soundcard-objs := rpi-wm8804-soundcard.o snd-soc-pifi-40-objs := pifi-40.o snd-soc-chipdip-dac-objs := chipdip-dac.o +snd-soc-dacberry400-objs := dacberry400.o obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o @@ -80,3 +81,4 @@ obj-$(CONFIG_SND_RPI_SIMPLE_SOUNDCARD) += snd-soc-rpi-simple-soundcard.o obj-$(CONFIG_SND_RPI_WM8804_SOUNDCARD) += snd-soc-rpi-wm8804-soundcard.o obj-$(CONFIG_SND_BCM2708_SOC_PIFI_40) += snd-soc-pifi-40.o obj-$(CONFIG_SND_BCM2708_SOC_CHIPDIP_DAC) += snd-soc-chipdip-dac.o +obj-$(CONFIG_SND_DACBERRY400) += snd-soc-dacberry400.o diff --git a/sound/soc/bcm/allo-boss-dac.c b/sound/soc/bcm/allo-boss-dac.c index 22564e895b..b86ddd4113 100644 --- a/sound/soc/bcm/allo-boss-dac.c +++ b/sound/soc/bcm/allo-boss-dac.c @@ -430,7 +430,8 @@ static int snd_allo_boss_probe(struct platform_device *pdev) static int snd_allo_boss_remove(struct platform_device *pdev) { snd_allo_boss_gpio_mute(&snd_allo_boss); - return snd_soc_unregister_card(&snd_allo_boss); + snd_soc_unregister_card(&snd_allo_boss); + return 0; } static const struct of_device_id snd_allo_boss_of_match[] = { diff --git a/sound/soc/bcm/allo-boss2-dac.c b/sound/soc/bcm/allo-boss2-dac.c index 5ad7f16964..bdc8a76d18 100644 --- a/sound/soc/bcm/allo-boss2-dac.c +++ b/sound/soc/bcm/allo-boss2-dac.c @@ -618,30 +618,30 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk, case CS43130_ASP_PCM_DAI: case CS43130_ASP_DOP_DAI: regmap_write(cs43130->regmap, CS43130_ASP_DEN_1, - (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >> + (clk_gen->v.denominator & CS43130_SP_M_LSB_DATA_MASK) >> CS43130_SP_M_LSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_ASP_DEN_2, - (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >> + (clk_gen->v.denominator & CS43130_SP_M_MSB_DATA_MASK) >> CS43130_SP_M_MSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_ASP_NUM_1, - (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >> + (clk_gen->v.numerator & CS43130_SP_N_LSB_DATA_MASK) >> CS43130_SP_N_LSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_ASP_NUM_2, - (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >> + (clk_gen->v.numerator & CS43130_SP_N_MSB_DATA_MASK) >> CS43130_SP_N_MSB_DATA_SHIFT); break; case CS43130_XSP_DOP_DAI: regmap_write(cs43130->regmap, CS43130_XSP_DEN_1, - (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >> + (clk_gen->v.denominator & CS43130_SP_M_LSB_DATA_MASK) >> CS43130_SP_M_LSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_XSP_DEN_2, - (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >> + (clk_gen->v.denominator & CS43130_SP_M_MSB_DATA_MASK) >> CS43130_SP_M_MSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_XSP_NUM_1, - (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >> + (clk_gen->v.numerator & CS43130_SP_N_LSB_DATA_MASK) >> CS43130_SP_N_LSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_XSP_NUM_2, - (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >> + (clk_gen->v.numerator & CS43130_SP_N_MSB_DATA_MASK) >> CS43130_SP_N_MSB_DATA_SHIFT); break; default: @@ -955,7 +955,6 @@ static struct snd_soc_component_driver cs43130_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs43130_regmap = { diff --git a/sound/soc/bcm/allo-piano-dac-plus.c b/sound/soc/bcm/allo-piano-dac-plus.c index 3efc898c60..0fde3fd32c 100644 --- a/sound/soc/bcm/allo-piano-dac-plus.c +++ b/sound/soc/bcm/allo-piano-dac-plus.c @@ -1036,7 +1036,8 @@ static int snd_allo_piano_dac_remove(struct platform_device *pdev) kfree(&card->drvdata); snd_allo_piano_gpio_mute(&snd_allo_piano_dac); - return snd_soc_unregister_card(&snd_allo_piano_dac); + snd_soc_unregister_card(&snd_allo_piano_dac); + return 0; } static const struct of_device_id snd_allo_piano_dac_of_match[] = { diff --git a/sound/soc/bcm/audiosense-pi.c b/sound/soc/bcm/audiosense-pi.c index b76d97488a..870d24bf67 100644 --- a/sound/soc/bcm/audiosense-pi.c +++ b/sound/soc/bcm/audiosense-pi.c @@ -219,8 +219,8 @@ static int audiosense_pi_card_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - return snd_soc_unregister_card(card); - + snd_soc_unregister_card(card); + return 0; } static const struct of_device_id audiosense_pi_card_of_match[] = { diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index e3fc4bee8c..f4d84774da 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -133,8 +133,8 @@ static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev) return; switch (provider) { - case SND_SOC_DAIFMT_CBC_CFC: - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_BP_FC: clk_prepare_enable(dev->clk); dev->clk_prepared = true; break; @@ -385,12 +385,12 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, /* Check if CPU is bit clock provider */ switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_BP_FC: bit_clock_provider = true; break; - case SND_SOC_DAIFMT_CBP_CFC: - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FP: + case SND_SOC_DAIFMT_BC_FC: bit_clock_provider = false; break; default: @@ -399,12 +399,12 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, /* Check if CPU is frame sync provider */ switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BP_FP: + case SND_SOC_DAIFMT_BC_FP: frame_sync_provider = true; break; - case SND_SOC_DAIFMT_CBC_CFP: - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BP_FC: + case SND_SOC_DAIFMT_BC_FC: frame_sync_provider = false; break; default: @@ -821,7 +821,8 @@ static const struct regmap_config bcm2835_regmap_config = { }; static const struct snd_soc_component_driver bcm2835_i2s_component = { - .name = "bcm2835-i2s-comp", + .name = "bcm2835-i2s-comp", + .legacy_dai_naming = 1, }; static int bcm2835_i2s_probe(struct platform_device *pdev) diff --git a/sound/soc/bcm/bcm63xx-i2s-whistler.c b/sound/soc/bcm/bcm63xx-i2s-whistler.c index 527caf4307..2da1384ffe 100644 --- a/sound/soc/bcm/bcm63xx-i2s-whistler.c +++ b/sound/soc/bcm/bcm63xx-i2s-whistler.c @@ -218,6 +218,7 @@ static struct snd_soc_dai_driver bcm63xx_i2s_dai = { static const struct snd_soc_component_driver bcm63xx_i2s_component = { .name = "bcm63xx", + .legacy_dai_naming = 1, }; static int bcm63xx_i2s_dev_probe(struct platform_device *pdev) diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c index 3abeaf0f1b..8f488f9293 100644 --- a/sound/soc/bcm/cygnus-pcm.c +++ b/sound/soc/bcm/cygnus-pcm.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2015 Broadcom Corporation - * - * 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. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014-2015 Broadcom Corporation #include #include #include diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index 9698f4531c..2a92e33e1f 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2015 Broadcom Corporation - * - * 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. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014-2015 Broadcom Corporation #include #include #include @@ -849,11 +839,11 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) ssp_newcfg = 0; switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: ssp_newcfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE); aio->is_slave = 1; break; - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: ssp_newcfg &= ~BIT(I2S_OUT_CFGX_SLAVE_MODE); aio->is_slave = 0; break; @@ -1201,9 +1191,10 @@ static const struct snd_soc_dai_driver cygnus_spdif_dai_info = { static struct snd_soc_dai_driver cygnus_ssp_dai[CYGNUS_MAX_PORTS]; static const struct snd_soc_component_driver cygnus_ssp_component = { - .name = "cygnus-audio", - .suspend = cygnus_ssp_suspend, - .resume = cygnus_ssp_resume, + .name = "cygnus-audio", + .suspend = cygnus_ssp_suspend, + .resume = cygnus_ssp_resume, + .legacy_dai_naming = 1, }; /* diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h index 33dd343059..74152b2d77 100644 --- a/sound/soc/bcm/cygnus-ssp.h +++ b/sound/soc/bcm/cygnus-ssp.h @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2015 Broadcom Corporation - * - * 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. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2014-2015 Broadcom Corporation */ #ifndef __CYGNUS_SSP_H__ #define __CYGNUS_SSP_H__ diff --git a/sound/soc/bcm/i-sabre-q2m.c b/sound/soc/bcm/i-sabre-q2m.c index 6809232e28..bbb7c79693 100644 --- a/sound/soc/bcm/i-sabre-q2m.c +++ b/sound/soc/bcm/i-sabre-q2m.c @@ -133,7 +133,8 @@ static int snd_rpi_i_sabre_q2m_probe(struct platform_device *pdev) static int snd_rpi_i_sabre_q2m_remove(struct platform_device *pdev) { - return snd_soc_unregister_card(&snd_rpi_i_sabre_q2m); + snd_soc_unregister_card(&snd_rpi_i_sabre_q2m); + return 0; } static const struct of_device_id snd_rpi_i_sabre_q2m_of_match[] = { diff --git a/sound/soc/bcm/iqaudio-codec.c b/sound/soc/bcm/iqaudio-codec.c index ea431ae185..527592e285 100644 --- a/sound/soc/bcm/iqaudio-codec.c +++ b/sound/soc/bcm/iqaudio-codec.c @@ -245,7 +245,8 @@ static int snd_rpi_iqaudio_codec_probe(struct platform_device *pdev) static int snd_rpi_iqaudio_codec_remove(struct platform_device *pdev) { - return snd_soc_unregister_card(&snd_rpi_iqaudio_codec); + snd_soc_unregister_card(&snd_rpi_iqaudio_codec); + return 0; } static const struct of_device_id iqaudio_of_match[] = { diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c index 62f64c8432..f65eda9b40 100644 --- a/sound/soc/bcm/iqaudio-dac.c +++ b/sound/soc/bcm/iqaudio-dac.c @@ -197,7 +197,8 @@ static int snd_rpi_iqaudio_dac_remove(struct platform_device *pdev) { snd_rpi_iqaudio_gpio_mute(&snd_rpi_iqaudio_dac); - return snd_soc_unregister_card(&snd_rpi_iqaudio_dac); + snd_soc_unregister_card(&snd_rpi_iqaudio_dac); + return 0; } static const struct of_device_id iqaudio_of_match[] = { diff --git a/sound/soc/bcm/justboom-both.c b/sound/soc/bcm/justboom-both.c index 471ecebddc..dddb0a3cbd 100644 --- a/sound/soc/bcm/justboom-both.c +++ b/sound/soc/bcm/justboom-both.c @@ -240,7 +240,8 @@ static int snd_rpi_justboom_both_probe(struct platform_device *pdev) static int snd_rpi_justboom_both_remove(struct platform_device *pdev) { - return snd_soc_unregister_card(&snd_rpi_justboom_both); + snd_soc_unregister_card(&snd_rpi_justboom_both); + return 0; } static const struct of_device_id snd_rpi_justboom_both_of_match[] = { diff --git a/sound/soc/bcm/pifi-40.c b/sound/soc/bcm/pifi-40.c index ae699fb048..550908ca6e 100644 --- a/sound/soc/bcm/pifi-40.c +++ b/sound/soc/bcm/pifi-40.c @@ -254,7 +254,8 @@ static int snd_pifi_40_remove(struct platform_device *pdev) kfree(&card->drvdata); snd_pifi_40_pdn(&snd_pifi_40, 0); - return snd_soc_unregister_card(&snd_pifi_40); + snd_soc_unregister_card(&snd_pifi_40); + return 0; } static const struct of_device_id snd_pifi_40_of_match[] = { diff --git a/sound/soc/bcm/pisound.c b/sound/soc/bcm/pisound.c index 629dde0e99..20b197a9e3 100644 --- a/sound/soc/bcm/pisound.c +++ b/sound/soc/bcm/pisound.c @@ -1218,7 +1218,8 @@ static int pisnd_remove(struct platform_device *pdev) gpiod_set_value(reset, false); pisnd_uninit_gpio(); - return snd_soc_unregister_card(&pisnd_card); + snd_soc_unregister_card(&pisnd_card); + return 0; } MODULE_DEVICE_TABLE(of, pisound_of_match); diff --git a/sound/soc/bcm/rpi-simple-soundcard.c b/sound/soc/bcm/rpi-simple-soundcard.c index c25351e6ee..85ef1a2207 100644 --- a/sound/soc/bcm/rpi-simple-soundcard.c +++ b/sound/soc/bcm/rpi-simple-soundcard.c @@ -145,6 +145,26 @@ static struct snd_soc_ops snd_rpi_simple_ops = { .hw_params = snd_rpi_simple_hw_params, }; +static int snd_merus_amp_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int rate; + + rate = params_rate(params); + if (rate > 48000) { + dev_err(rtd->card->dev, + "Unsupported samplerate %d\n", + rate); + return -EINVAL; + } + return 0; +} + +static struct snd_soc_ops snd_merus_amp_ops = { + .hw_params = snd_merus_amp_hw_params, +}; + enum adau1977_clk_id { ADAU1977_SYSCLK, }; @@ -253,6 +273,28 @@ static struct snd_rpi_simple_drvdata drvdata_hifiberry_amp = { .fixed_bclk_ratio = 64, }; +SND_SOC_DAILINK_DEFS(hifiberry_amp3, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC("ma120x0p.1-0020", "ma120x0p-amp")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link snd_hifiberry_amp3_dai[] = { + { + .name = "HifiberryAmp3", + .stream_name = "Hifiberry Amp3", + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(hifiberry_amp3), + }, +}; + +static struct snd_rpi_simple_drvdata drvdata_hifiberry_amp3 = { + .card_name = "snd_rpi_hifiberry_amp3", + .dai = snd_hifiberry_amp3_dai, + .fixed_bclk_ratio = 64, +}; + SND_SOC_DAILINK_DEFS(hifiberry_dac, DAILINK_COMP_ARRAY(COMP_EMPTY()), DAILINK_COMP_ARRAY(COMP_CODEC("pcm5102a-codec", "pcm5102a-hifi")), @@ -274,6 +316,27 @@ static struct snd_rpi_simple_drvdata drvdata_hifiberry_dac = { .dai = snd_hifiberry_dac_dai, }; +SND_SOC_DAILINK_DEFS(dionaudio_kiwi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC("pcm1794a-codec", "pcm1794a-hifi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link snd_dionaudio_kiwi_dai[] = { +{ + .name = "DionAudio KIWI", + .stream_name = "DionAudio KIWI STREAMER", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(dionaudio_kiwi), +}, +}; + +static struct snd_rpi_simple_drvdata drvdata_dionaudio_kiwi = { + .card_name = "snd_rpi_dionaudio_kiwi", + .dai = snd_dionaudio_kiwi_dai, + .fixed_bclk_ratio = 64, +}; + SND_SOC_DAILINK_DEFS(rpi_dac, DAILINK_COMP_ARRAY(COMP_EMPTY()), DAILINK_COMP_ARRAY(COMP_CODEC("pcm1794a-codec", "pcm1794a-hifi")), @@ -297,13 +360,14 @@ static struct snd_rpi_simple_drvdata drvdata_rpi_dac = { SND_SOC_DAILINK_DEFS(merus_amp, DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC("ma120x0p.1-0020","ma120x0p-amp")), + DAILINK_COMP_ARRAY(COMP_CODEC("ma120x0p.1-0020", "ma120x0p-amp")), DAILINK_COMP_ARRAY(COMP_EMPTY())); static struct snd_soc_dai_link snd_merus_amp_dai[] = { { .name = "MerusAmp", .stream_name = "Merus Audio Amp", + .ops = &snd_merus_amp_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, @@ -349,8 +413,12 @@ static const struct of_device_id snd_rpi_simple_of_match[] = { .data = (void *) &drvdata_hifiberrydacplusdsp }, { .compatible = "hifiberry,hifiberry-amp", .data = (void *) &drvdata_hifiberry_amp }, + { .compatible = "hifiberry,hifiberry-amp3", + .data = (void *) &drvdata_hifiberry_amp3 }, { .compatible = "hifiberry,hifiberry-dac", .data = (void *) &drvdata_hifiberry_dac }, + { .compatible = "dionaudio,dionaudio-kiwi", + .data = (void *) &drvdata_dionaudio_kiwi }, { .compatible = "rpi,rpi-dac", &drvdata_rpi_dac}, { .compatible = "merus,merus-amp", .data = (void *) &drvdata_merus_amp }, diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c index 16f9bb283b..37593abe60 100644 --- a/sound/soc/cirrus/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c @@ -355,7 +355,8 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = { }; static const struct snd_soc_component_driver ep93xx_ac97_component = { - .name = "ep93xx-ac97", + .name = "ep93xx-ac97", + .legacy_dai_naming = 1, }; static int ep93xx_ac97_probe(struct platform_device *pdev) diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 2c8cd843d0..982151330c 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -246,12 +246,12 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, } switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: /* CPU is provider */ clk_cfg |= EP93XX_I2S_CLKCFG_MASTER; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: /* Codec is provider */ clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER; break; @@ -422,9 +422,10 @@ static struct snd_soc_dai_driver ep93xx_i2s_dai = { }; static const struct snd_soc_component_driver ep93xx_i2s_component = { - .name = "ep93xx-i2s", - .suspend = ep93xx_i2s_suspend, - .resume = ep93xx_i2s_resume, + .name = "ep93xx-i2s", + .suspend = ep93xx_i2s_suspend, + .resume = ep93xx_i2s_resume, + .legacy_dai_naming = 1, }; static int ep93xx_i2s_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index c6043fa58c..fc65283031 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -1345,7 +1345,6 @@ static const struct snd_soc_component_driver soc_component_dev_pm860x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int pm860x_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 858b17e425..47812faf0f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -65,6 +65,8 @@ config SND_SOC_ALL_CODECS imply SND_SOC_CS35L36 imply SND_SOC_CS35L41_SPI imply SND_SOC_CS35L41_I2C + imply SND_SOC_CS35L45_I2C + imply SND_SOC_CS35L45_SPI imply SND_SOC_CS42L42 imply SND_SOC_CS42L51_I2C imply SND_SOC_CS42L52 @@ -129,6 +131,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_MAX98373_I2C imply SND_SOC_MAX98373_SDW imply SND_SOC_MAX98390 + imply SND_SOC_MAX98396 imply SND_SOC_MAX9850 imply SND_SOC_MAX9860 imply SND_SOC_MAX9759 @@ -171,6 +174,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT1011 imply SND_SOC_RT1015 imply SND_SOC_RT1015P + imply SND_SOC_RT1016 imply SND_SOC_RT1019 imply SND_SOC_RT1305 imply SND_SOC_RT1308 @@ -218,6 +222,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TAS2562 imply SND_SOC_TAS2764 imply SND_SOC_TAS2770 + imply SND_SOC_TAS2780 imply SND_SOC_TAS5086 imply SND_SOC_TAS571X imply SND_SOC_TAS5720 @@ -269,7 +274,8 @@ config SND_SOC_ALL_CODECS imply SND_SOC_WM8711 imply SND_SOC_WM8727 imply SND_SOC_WM8728 - imply SND_SOC_WM8731 + imply SND_SOC_WM8731_I2C + imply SND_SOC_WM8731_SPI imply SND_SOC_WM8737 imply SND_SOC_WM8741 imply SND_SOC_WM8750 @@ -307,6 +313,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_WM9712 imply SND_SOC_WM9713 imply SND_SOC_WSA881X + imply SND_SOC_WSA883X imply SND_SOC_ZL38060 help Normally ASoC codec drivers are only built if a machine driver which @@ -659,6 +666,34 @@ config SND_SOC_CS35L41_I2C select SND_SOC_CS35L41 select REGMAP_I2C +config SND_SOC_CS35L45_TABLES + tristate + +config SND_SOC_CS35L45 + tristate + +config SND_SOC_CS35L45_SPI + tristate "Cirrus Logic CS35L45 CODEC (SPI)" + depends on SPI_MASTER + select REGMAP + select REGMAP_SPI + select SND_SOC_CS35L45_TABLES + select SND_SOC_CS35L45 + help + Enable support for Cirrus Logic CS35L45 smart speaker amplifier + with SPI control. + +config SND_SOC_CS35L45_I2C + tristate "Cirrus Logic CS35L45 CODEC (I2C)" + depends on I2C + select REGMAP + select REGMAP_I2C + select SND_SOC_CS35L45_TABLES + select SND_SOC_CS35L45 + help + Enable support for Cirrus Logic CS35L45 smart speaker amplifier + with I2C control. + config SND_SOC_CS42L42 tristate "Cirrus Logic CS42L42 CODEC" depends on I2C @@ -908,6 +943,16 @@ config SND_SOC_HDAC_HDA tristate select SND_HDA +config SND_SOC_HDA + tristate "HD-Audio codec driver" + select SND_HDA_EXT_CORE + select SND_HDA + help + This enables HD-Audio codec support in ASoC subsystem. Compared + to SND_SOC_HDAC_HDA, driver's behavior is identical to HD-Audio + legacy solution - including the dynamic resource allocation + based on actual codec capabilities. + config SND_SOC_ICS43432 tristate "ICS43423 and compatible i2s microphones" @@ -964,7 +1009,6 @@ config SND_SOC_MAX98095 config SND_SOC_MAX98357A tristate "Maxim MAX98357A CODEC" - depends on GPIOLIB config SND_SOC_MAX98371 tristate @@ -1026,6 +1070,15 @@ config SND_SOC_MAX98390 tristate "Maxim Integrated MAX98390 Speaker Amplifier" depends on I2C +config SND_SOC_MAX98396 + tristate "Analog Devices MAX98396 Speaker Amplifier" + depends on I2C + help + Enable support for Analog Devices MAX98396 audio + amplifier. The device provides a PCM interface for + audio data and a standard I2C interface for control + data communication. + config SND_SOC_MAX9850 tristate depends on I2C @@ -1224,7 +1277,10 @@ config SND_SOC_RT1015 config SND_SOC_RT1015P tristate - depends on GPIOLIB + +config SND_SOC_RT1016 + tristate + depends on I2C config SND_SOC_RT1019 tristate @@ -1495,6 +1551,13 @@ config SND_SOC_TAS2770 tristate "Texas Instruments TAS2770 speaker amplifier" depends on I2C +config SND_SOC_TAS2780 + tristate "Texas Instruments TAS2780 Mono Audio amplifier" + depends on I2C + help + Enable support for Texas Instruments TAS2780 high-efficiency + digital input mono Class-D audio power amplifiers. + config SND_SOC_TAS5086 tristate "Texas Instruments TAS5086 speaker amplifier" depends on I2C @@ -1771,8 +1834,19 @@ config SND_SOC_WM8728 depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8731 - tristate "Wolfson Microelectronics WM8731 CODEC" - depends on SND_SOC_I2C_AND_SPI + tristate + +config SND_SOC_WM8731_I2C + tristate "Wolfson Microelectronics WM8731 CODEC with I2C" + depends on I2C + select REGMAP + select SND_SOC_WM8731 + +config SND_SOC_WM8731_SPI + tristate "Wolfson Microelectronics WM8731 CODEC with SPI" + depends on SPI + select REGMAP + select SND_SOC_WM8731 config SND_SOC_WM8737 tristate "Wolfson Microelectronics WM8737 ADC" @@ -1829,7 +1903,7 @@ config SND_SOC_WM8904 depends on I2C config SND_SOC_WM8940 - tristate + tristate "Wolfson Microelectronics WM8940 codec" depends on I2C config SND_SOC_WM8955 @@ -1938,6 +2012,15 @@ config SND_SOC_WSA881X This enables support for Qualcomm WSA8810/WSA8815 Class-D Smart Speaker Amplifier. +config SND_SOC_WSA883X + tristate "WSA883X Codec" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + tristate + help + This enables support for Qualcomm WSA8830/WSA8835 Class-D + Smart Speaker Amplifier. + config SND_SOC_ZL38060 tristate "Microsemi ZL38060 Connected Home Audio Processor" depends on SPI_MASTER diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index a971c327bc..679aeba86e 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -60,6 +60,10 @@ snd-soc-cs35l41-lib-objs := cs35l41-lib.o snd-soc-cs35l41-objs := cs35l41.o snd-soc-cs35l41-spi-objs := cs35l41-spi.o snd-soc-cs35l41-i2c-objs := cs35l41-i2c.o +snd-soc-cs35l45-tables-objs := cs35l45-tables.o +snd-soc-cs35l45-objs := cs35l45.o +snd-soc-cs35l45-spi-objs := cs35l45-spi.o +snd-soc-cs35l45-i2c-objs := cs35l45-i2c.o snd-soc-cs42l42-objs := cs42l42.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o @@ -102,6 +106,7 @@ snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-gtm601-objs := gtm601.o snd-soc-hdac-hdmi-objs := hdac_hdmi.o snd-soc-hdac-hda-objs := hdac_hda.o +snd-soc-hda-codec-objs := hda.o hda-dai.o snd-soc-ics43432-objs := ics43432.o snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-isabelle-objs := isabelle.o @@ -137,6 +142,7 @@ snd-soc-max98373-objs := max98373.o snd-soc-max98373-i2c-objs := max98373-i2c.o snd-soc-max98373-sdw-objs := max98373-sdw.o snd-soc-max98390-objs := max98390.o +snd-soc-max98396-objs := max98396.o snd-soc-max9850-objs := max9850.o snd-soc-max9860-objs := max9860.o snd-soc-mc13783-objs := mc13783.o @@ -184,6 +190,7 @@ snd-soc-rl6347a-objs := rl6347a.o snd-soc-rt1011-objs := rt1011.o snd-soc-rt1015-objs := rt1015.o snd-soc-rt1015p-objs := rt1015p.o +snd-soc-rt1016-objs := rt1016.o snd-soc-rt1019-objs := rt1019.o snd-soc-rt1305-objs := rt1305.o snd-soc-rt1308-objs := rt1308.o @@ -294,6 +301,8 @@ snd-soc-wm8711-objs := wm8711.o snd-soc-wm8727-objs := wm8727.o snd-soc-wm8728-objs := wm8728.o snd-soc-wm8731-objs := wm8731.o +snd-soc-wm8731-i2c-objs := wm8731-i2c.o +snd-soc-wm8731-spi-objs := wm8731-spi.o snd-soc-wm8737-objs := wm8737.o snd-soc-wm8741-objs := wm8741.o snd-soc-wm8750-objs := wm8750.o @@ -333,6 +342,7 @@ snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o snd-soc-wm-hubs-objs := wm_hubs.o snd-soc-wsa881x-objs := wsa881x.o +snd-soc-wsa883x-objs := wsa883x.o snd-soc-zl38060-objs := zl38060.o # Amp snd-soc-max9877-objs := max9877.o @@ -342,6 +352,7 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o snd-soc-tas2552-objs := tas2552.o snd-soc-tas2562-objs := tas2562.o snd-soc-tas2764-objs := tas2764.o +snd-soc-tas2780-objs := tas2780.o # Mux snd-soc-simple-mux-objs := simple-mux.o @@ -408,6 +419,10 @@ obj-$(CONFIG_SND_SOC_CS35L41) += snd-soc-cs35l41.o obj-$(CONFIG_SND_SOC_CS35L41_LIB) += snd-soc-cs35l41-lib.o obj-$(CONFIG_SND_SOC_CS35L41_SPI) += snd-soc-cs35l41-spi.o obj-$(CONFIG_SND_SOC_CS35L41_I2C) += snd-soc-cs35l41-i2c.o +obj-$(CONFIG_SND_SOC_CS35L45_TABLES) += snd-soc-cs35l45-tables.o +obj-$(CONFIG_SND_SOC_CS35L45) += snd-soc-cs35l45.o +obj-$(CONFIG_SND_SOC_CS35L45_SPI) += snd-soc-cs35l45-spi.o +obj-$(CONFIG_SND_SOC_CS35L45_I2C) += snd-soc-cs35l45-i2c.o obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o @@ -450,6 +465,7 @@ obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o +obj-$(CONFIG_SND_SOC_HDA) += snd-soc-hda-codec.o obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o @@ -480,6 +496,7 @@ obj-$(CONFIG_SND_SOC_MAX98373) += snd-soc-max98373.o obj-$(CONFIG_SND_SOC_MAX98373_I2C) += snd-soc-max98373-i2c.o obj-$(CONFIG_SND_SOC_MAX98373_SDW) += snd-soc-max98373-sdw.o obj-$(CONFIG_SND_SOC_MAX98390) += snd-soc-max98390.o +obj-$(CONFIG_SND_SOC_MAX98396) += snd-soc-max98396.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o @@ -527,6 +544,7 @@ obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o obj-$(CONFIG_SND_SOC_RT1015P) += snd-soc-rt1015p.o +obj-$(CONFIG_SND_SOC_RT1016) += snd-soc-rt1016.o obj-$(CONFIG_SND_SOC_RT1019) += snd-soc-rt1019.o obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o @@ -582,6 +600,7 @@ obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS2562) += snd-soc-tas2562.o obj-$(CONFIG_SND_SOC_TAS2764) += snd-soc-tas2764.o +obj-$(CONFIG_SND_SOC_TAS2780) += snd-soc-tas2780.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o @@ -640,6 +659,8 @@ obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o +obj-$(CONFIG_SND_SOC_WM8731_I2C) += snd-soc-wm8731-i2c.o +obj-$(CONFIG_SND_SOC_WM8731_SPI) += snd-soc-wm8731-spi.o obj-$(CONFIG_SND_SOC_WM8737) += snd-soc-wm8737.o obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o @@ -680,6 +701,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o +obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o # Amp diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index aefafb0b7b..6834291741 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -12,8 +12,6 @@ * Mikko Sarmanne , * Jarmo K. Kuronen , * for ST-Ericsson. - * - * License terms: */ #include @@ -2525,7 +2523,6 @@ static const struct snd_soc_component_driver ab8500_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ab8500_codec_driver_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ab8500-codec.h b/sound/soc/codecs/ab8500-codec.h index 0ac87d0446..2a6f6409f1 100644 --- a/sound/soc/codecs/ab8500-codec.h +++ b/sound/soc/codecs/ab8500-codec.h @@ -11,8 +11,6 @@ * Mikko J. Lehto , * Mikko Sarmanne , * for ST-Ericsson. - * - * License terms: */ #ifndef AB8500_CODEC_REGISTERS_H diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 6ad9c9443b..cc12052e19 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -119,7 +119,6 @@ static const struct snd_soc_component_driver soc_component_dev_ac97 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ac97_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 29e1689da6..2c64df96b5 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -332,7 +332,6 @@ static const struct snd_soc_component_driver soc_component_dev_ad1836 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct reg_default ad1836_reg_defaults[] = { diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c index 3d509a65e4..4cb8d87f90 100644 --- a/sound/soc/codecs/ad193x-i2c.c +++ b/sound/soc/codecs/ad193x-i2c.c @@ -20,10 +20,10 @@ static const struct i2c_device_id ad193x_id[] = { }; MODULE_DEVICE_TABLE(i2c, ad193x_id); -static int ad193x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ad193x_i2c_probe(struct i2c_client *client) { struct regmap_config config; + const struct i2c_device_id *id = i2c_match_id(ad193x_id, client); config = ad193x_regmap_config; config.val_bits = 8; @@ -38,7 +38,7 @@ static struct i2c_driver ad193x_i2c_driver = { .driver = { .name = "ad193x", }, - .probe = ad193x_i2c_probe, + .probe_new = ad193x_i2c_probe, .id_table = ad193x_id, }; module_i2c_driver(ad193x_i2c_driver); diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 30b98b4267..1d3c4d94b4 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -523,7 +523,6 @@ static const struct snd_soc_component_driver soc_component_dev_ad193x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; const struct regmap_config ad193x_regmap_config = { diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 9fd2023da2..5e777d7fd5 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -302,7 +302,6 @@ static const struct snd_soc_component_driver soc_component_dev_ad1980 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ad1980_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index b98bf19f59..f6090ac57e 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -58,7 +58,6 @@ static const struct snd_soc_component_driver soc_component_dev_ad73311 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ad73311_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c index fc87a76ff1..8ed0ffdedb 100644 --- a/sound/soc/codecs/adau1372-i2c.c +++ b/sound/soc/codecs/adau1372-i2c.c @@ -14,7 +14,7 @@ #include "adau1372.h" -static int adau1372_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int adau1372_i2c_probe(struct i2c_client *client) { return adau1372_probe(&client->dev, devm_regmap_init_i2c(client, &adau1372_regmap_config), NULL); @@ -30,7 +30,7 @@ static struct i2c_driver adau1372_i2c_driver = { .driver = { .name = "adau1372", }, - .probe = adau1372_i2c_probe, + .probe_new = adau1372_i2c_probe, .id_table = adau1372_i2c_ids, }; module_i2c_driver(adau1372_i2c_driver); diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c index 1faa4c4263..a9f89e8565 100644 --- a/sound/soc/codecs/adau1372.c +++ b/sound/soc/codecs/adau1372.c @@ -859,6 +859,7 @@ static const struct snd_soc_component_driver adau1372_driver = { .num_dapm_widgets = ARRAY_SIZE(adau1372_dapm_widgets), .dapm_routes = adau1372_dapm_routes, .num_dapm_routes = ARRAY_SIZE(adau1372_dapm_routes), + .endianness = 1, }; static const struct snd_soc_dai_ops adau1372_dai_ops = { diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 46128aacea..7f832d00ab 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1470,11 +1470,9 @@ static const struct snd_soc_component_driver adau1373_component_driver = { .num_dapm_routes = ARRAY_SIZE(adau1373_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int adau1373_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adau1373_i2c_probe(struct i2c_client *client) { struct adau1373 *adau1373; int ret; @@ -1508,7 +1506,7 @@ static struct i2c_driver adau1373_i2c_driver = { .driver = { .name = "adau1373", }, - .probe = adau1373_i2c_probe, + .probe_new = adau1373_i2c_probe, .id_table = adau1373_i2c_id, }; diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index dba9af7531..135a7db7fc 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -772,7 +772,6 @@ static const struct snd_soc_component_driver adau1701_component_drv = { .set_sysclk = adau1701_set_sysclk, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config adau1701_regmap = { @@ -785,8 +784,7 @@ static const struct regmap_config adau1701_regmap = { .reg_read = adau1701_reg_read, }; -static int adau1701_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adau1701_i2c_probe(struct i2c_client *client) { struct adau1701 *adau1701; struct device *dev = &client->dev; @@ -878,7 +876,7 @@ static struct i2c_driver adau1701_i2c_driver = { .name = "adau1701", .of_match_table = of_match_ptr(adau1701_dt_ids), }, - .probe = adau1701_i2c_probe, + .probe_new = adau1701_i2c_probe, .id_table = adau1701_i2c_id, }; diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c index c8fce37e5c..0683caf86a 100644 --- a/sound/soc/codecs/adau1761-i2c.c +++ b/sound/soc/codecs/adau1761-i2c.c @@ -14,10 +14,12 @@ #include "adau1761.h" -static int adau1761_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id adau1761_i2c_ids[]; + +static int adau1761_i2c_probe(struct i2c_client *client) { struct regmap_config config; + const struct i2c_device_id *id = i2c_match_id(adau1761_i2c_ids, client); config = adau1761_regmap_config; config.val_bits = 8; @@ -59,7 +61,7 @@ static struct i2c_driver adau1761_i2c_driver = { .name = "adau1761", .of_match_table = of_match_ptr(adau1761_i2c_dt_ids), }, - .probe = adau1761_i2c_probe, + .probe_new = adau1761_i2c_probe, .remove = adau1761_i2c_remove, .id_table = adau1761_i2c_ids, }; diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index fb006fc816..3ccc7acac2 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -556,8 +556,6 @@ static const struct snd_soc_dapm_route adau1761_dapm_routes[] = { { "Left DAC", NULL, "Interpolator Resync Clock" }, { "Right DAC", NULL, "Interpolator Resync Clock" }, - { "DSP", NULL, "Digital Clock 0" }, - { "Slew Clock", NULL, "Digital Clock 0" }, { "Right Playback Mixer", NULL, "Slew Clock" }, { "Left Playback Mixer", NULL, "Slew Clock" }, @@ -569,6 +567,56 @@ static const struct snd_soc_dapm_route adau1761_dapm_routes[] = { { "Digital Clock 1", NULL, "SYSCLK" }, }; +static const struct snd_soc_dapm_route adau1761_dapm_dsp_routes[] = { + { "DSP", NULL, "Digital Clock 0" }, +}; + +static int adau1761_compatibility_probe(struct device *dev) +{ + struct adau *adau = dev_get_drvdata(dev); + struct regmap *regmap = adau->regmap; + int val, ret = 0; + + /* Only consider compatibility mode when ADAU1361 was specified. */ + if (adau->type != ADAU1361) + return 0; + + regcache_cache_bypass(regmap, true); + + /* + * This will enable the core clock and bypass the PLL, + * so that we can access the registers for probing purposes + * (without having to set up the PLL). + */ + regmap_write(regmap, ADAU17X1_CLOCK_CONTROL, + ADAU17X1_CLOCK_CONTROL_SYSCLK_EN); + + /* + * ADAU17X1_SERIAL_SAMPLING_RATE doesn't exist in non-DSP chips; + * reading it results in zero at all times, and write is a no-op. + * Use this register to probe for ADAU1761. + */ + regmap_write(regmap, ADAU17X1_SERIAL_SAMPLING_RATE, 1); + ret = regmap_read(regmap, ADAU17X1_SERIAL_SAMPLING_RATE, &val); + if (ret) + goto exit; + if (val != 1) + goto exit; + regmap_write(regmap, ADAU17X1_SERIAL_SAMPLING_RATE, 0); + ret = regmap_read(regmap, ADAU17X1_SERIAL_SAMPLING_RATE, &val); + if (ret) + goto exit; + if (val != 0) + goto exit; + + adau->type = ADAU1761_AS_1361; +exit: + /* Disable core clock after probing. */ + regmap_write(regmap, ADAU17X1_CLOCK_CONTROL, 0); + regcache_cache_bypass(regmap, false); + return ret; +} + static int adau1761_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { @@ -823,7 +871,11 @@ static int adau1761_component_probe(struct snd_soc_component *component) if (ret) return ret; - if (adau->type == ADAU1761) { + /* + * If we've got an ADAU1761, or an ADAU1761 operating as an + * ADAU1361, we need these non-DSP related DAPM widgets and routes. + */ + if (adau->type == ADAU1761 || adau->type == ADAU1761_AS_1361) { ret = snd_soc_dapm_new_controls(dapm, adau1761_dapm_widgets, ARRAY_SIZE(adau1761_dapm_widgets)); if (ret) @@ -834,7 +886,29 @@ static int adau1761_component_probe(struct snd_soc_component *component) if (ret) return ret; } - + /* + * These routes are DSP related and only used when we have a + * bona fide ADAU1761. + */ + if (adau->type == ADAU1761) { + ret = snd_soc_dapm_add_routes(dapm, adau1761_dapm_dsp_routes, + ARRAY_SIZE(adau1761_dapm_dsp_routes)); + if (ret) + return ret; + } + /* + * In the ADAU1761, by default, the AIF is routed to the DSP, whereas + * for the ADAU1361, the AIF is permanently routed to the ADC and DAC. + * Thus, if we have an ADAU1761 masquerading as an ADAU1361, + * we need to explicitly route the AIF to the ADC and DAC. + * For the ADAU1761, this is normally done by set_tdm_slot, but this + * function is not necessarily called during stream setup, so set up + * the compatible AIF routings here from the start. + */ + if (adau->type == ADAU1761_AS_1361) { + regmap_write(adau->regmap, ADAU17X1_SERIAL_INPUT_ROUTE, 0x01); + regmap_write(adau->regmap, ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x01); + } ret = adau17x1_add_routes(component); if (ret < 0) return ret; @@ -856,7 +930,6 @@ static const struct snd_soc_component_driver adau1761_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ @@ -919,6 +992,10 @@ int adau1761_probe(struct device *dev, struct regmap *regmap, if (ret) return ret; + ret = adau1761_compatibility_probe(dev); + if (ret) + return ret; + /* Enable cache only mode as we could miss writes before bias level * reaches standby and the core clock is enabled */ regcache_cache_only(regmap, true); diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c index 1c476429ad..e046de0ebc 100644 --- a/sound/soc/codecs/adau1781-i2c.c +++ b/sound/soc/codecs/adau1781-i2c.c @@ -14,10 +14,12 @@ #include "adau1781.h" -static int adau1781_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id adau1781_i2c_ids[]; + +static int adau1781_i2c_probe(struct i2c_client *client) { struct regmap_config config; + const struct i2c_device_id *id = i2c_match_id(adau1781_i2c_ids, client); config = adau1781_regmap_config; config.val_bits = 8; @@ -55,7 +57,7 @@ static struct i2c_driver adau1781_i2c_driver = { .name = "adau1781", .of_match_table = of_match_ptr(adau1781_i2c_dt_ids), }, - .probe = adau1781_i2c_probe, + .probe_new = adau1781_i2c_probe, .remove = adau1781_i2c_remove, .id_table = adau1781_i2c_ids, }; diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index 74dc3344b2..ff6be24863 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c @@ -439,7 +439,6 @@ static const struct snd_soc_component_driver adau1781_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #define ADAU1781_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index af05463af4..c0f44ecef6 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -334,6 +334,17 @@ static bool adau17x1_has_dsp(struct adau *adau) } } +/* Chip has a DSP but we're pretending it doesn't. */ +static bool adau17x1_has_disused_dsp(struct adau *adau) +{ + switch (adau->type) { + case ADAU1761_AS_1361: + return true; + default: + return false; + } +} + static bool adau17x1_has_safeload(struct adau *adau) { switch (adau->type) { @@ -516,10 +527,11 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0, ADAU17X1_CONVERTER0_CONVSR_MASK, div); - if (adau17x1_has_dsp(adau)) { + + if (adau17x1_has_dsp(adau) || adau17x1_has_disused_dsp(adau)) regmap_write(adau->regmap, ADAU17X1_SERIAL_SAMPLING_RATE, div); + if (adau17x1_has_dsp(adau)) regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div); - } if (adau->sigmadsp) { ret = adau17x1_setup_firmware(component, params_rate(params)); @@ -663,7 +675,7 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai, switch (slot_width * slots) { case 32: - if (adau->type == ADAU1761) + if (adau->type == ADAU1761 || adau->type == ADAU1761_AS_1361) return -EINVAL; ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK32; @@ -738,7 +750,7 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai, regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1, ADAU17X1_SERIAL_PORT1_BCLK_MASK, ser_ctrl1); - if (!adau17x1_has_dsp(adau)) + if (!adau17x1_has_dsp(adau) && !adau17x1_has_disused_dsp(adau)) return 0; if (adau->dsp_bypass[SNDRV_PCM_STREAM_PLAYBACK]) { diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index 98a3b6f5bc..5e58abfffc 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h @@ -10,6 +10,7 @@ enum adau17x1_type { ADAU1361, ADAU1761, + ADAU1761_AS_1361, ADAU1381, ADAU1781, }; diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c index 82a49c85d5..9f137a0634 100644 --- a/sound/soc/codecs/adau1977-i2c.c +++ b/sound/soc/codecs/adau1977-i2c.c @@ -14,10 +14,12 @@ #include "adau1977.h" -static int adau1977_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id adau1977_i2c_ids[]; + +static int adau1977_i2c_probe(struct i2c_client *client) { struct regmap_config config; + const struct i2c_device_id *id = i2c_match_id(adau1977_i2c_ids, client); config = adau1977_regmap_config; config.val_bits = 8; @@ -40,7 +42,7 @@ static struct i2c_driver adau1977_i2c_driver = { .driver = { .name = "adau1977", }, - .probe = adau1977_i2c_probe, + .probe_new = adau1977_i2c_probe, .id_table = adau1977_i2c_ids, }; module_i2c_driver(adau1977_i2c_driver); diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index 5fcbdf2ec3..7a9672f94f 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -876,7 +876,6 @@ static const struct snd_soc_component_driver adau1977_component_driver = { .num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int adau1977_setup_micbias(struct adau1977 *adau1977) diff --git a/sound/soc/codecs/adau7002.c b/sound/soc/codecs/adau7002.c index 0e00de6ce3..401bafabc8 100644 --- a/sound/soc/codecs/adau7002.c +++ b/sound/soc/codecs/adau7002.c @@ -91,7 +91,6 @@ static const struct snd_soc_component_driver adau7002_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int adau7002_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/adau7118-i2c.c b/sound/soc/codecs/adau7118-i2c.c index aa7afb3b82..afed48401b 100644 --- a/sound/soc/codecs/adau7118-i2c.c +++ b/sound/soc/codecs/adau7118-i2c.c @@ -48,8 +48,7 @@ static const struct regmap_config adau7118_regmap_config = { .volatile_reg = adau7118_volatile, }; -static int adau7118_probe_i2c(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int adau7118_probe_i2c(struct i2c_client *i2c) { struct regmap *map; @@ -79,7 +78,7 @@ static struct i2c_driver adau7118_driver = { .name = "adau7118", .of_match_table = adau7118_of_match, }, - .probe = adau7118_probe_i2c, + .probe_new = adau7118_probe_i2c, .id_table = adau7118_id, }; module_i2c_driver(adau7118_driver); diff --git a/sound/soc/codecs/adau7118.c b/sound/soc/codecs/adau7118.c index 841229dcbc..bbb0972498 100644 --- a/sound/soc/codecs/adau7118.c +++ b/sound/soc/codecs/adau7118.c @@ -442,7 +442,6 @@ static const struct snd_soc_component_driver adau7118_component_driver = { .num_dapm_widgets = ARRAY_SIZE(adau7118_widgets), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static void adau7118_regulator_disable(void *data) diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c index 0f565b851e..bf181bbaab 100644 --- a/sound/soc/codecs/adav803.c +++ b/sound/soc/codecs/adav803.c @@ -19,8 +19,7 @@ static const struct i2c_device_id adav803_id[] = { }; MODULE_DEVICE_TABLE(i2c, adav803_id); -static int adav803_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adav803_probe(struct i2c_client *client) { return adav80x_bus_probe(&client->dev, devm_regmap_init_i2c(client, &adav80x_regmap_config)); @@ -30,7 +29,7 @@ static struct i2c_driver adav803_driver = { .driver = { .name = "adav803", }, - .probe = adav803_probe, + .probe_new = adav803_probe, .id_table = adav803_id, }; module_i2c_driver(adav803_driver); diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 90f3a5e9e3..fcff35f26c 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -842,7 +842,6 @@ static const struct snd_soc_component_driver adav80x_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; int adav80x_bus_probe(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c index 1d07e2699f..44aa06e034 100644 --- a/sound/soc/codecs/ads117x.c +++ b/sound/soc/codecs/ads117x.c @@ -62,7 +62,6 @@ static const struct snd_soc_component_driver soc_component_dev_ads117x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ads117x_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index dc4747c77a..ce99f30b46 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -248,7 +248,6 @@ static const struct snd_soc_component_driver soc_component_device_ak4104 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4104_regmap = { diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c index 2e6bafd2a8..b6d9a10bdc 100644 --- a/sound/soc/codecs/ak4118.c +++ b/sound/soc/codecs/ak4118.c @@ -342,7 +342,6 @@ static const struct snd_soc_component_driver soc_component_drv_ak4118 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4118_regmap = { @@ -356,8 +355,7 @@ static const struct regmap_config ak4118_regmap = { .max_register = AK4118_REG_MAX - 1, }; -static int ak4118_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ak4118_i2c_probe(struct i2c_client *i2c) { struct ak4118_priv *ak4118; int ret; @@ -416,7 +414,7 @@ static struct i2c_driver ak4118_i2c_driver = { .of_match_table = of_match_ptr(ak4118_of_match), }, .id_table = ak4118_id_table, - .probe = ak4118_i2c_probe, + .probe_new = ak4118_i2c_probe, }; module_i2c_driver(ak4118_i2c_driver); diff --git a/sound/soc/codecs/ak4375.c b/sound/soc/codecs/ak4375.c index 9a7b662016..1ed004ba7c 100644 --- a/sound/soc/codecs/ak4375.c +++ b/sound/soc/codecs/ak4375.c @@ -473,7 +473,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak4375 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4375_regmap = { diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index baa9ff5d0c..ea33cc83c8 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -725,7 +725,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak4458 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_component_driver soc_codec_dev_ak4497 = { @@ -740,7 +739,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak4497 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4458_regmap = { diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 91e7a57c43..8c8c93eea7 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -402,11 +402,9 @@ static const struct snd_soc_component_driver soc_component_dev_ak4535 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int ak4535_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ak4535_i2c_probe(struct i2c_client *i2c) { struct ak4535_priv *ak4535; int ret; @@ -441,7 +439,7 @@ static struct i2c_driver ak4535_i2c_driver = { .driver = { .name = "ak4535", }, - .probe = ak4535_i2c_probe, + .probe_new = ak4535_i2c_probe, .id_table = ak4535_i2c_id, }; diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c index 8e60e2b56a..b9607de5a1 100644 --- a/sound/soc/codecs/ak4554.c +++ b/sound/soc/codecs/ak4554.c @@ -67,7 +67,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4554 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ak4554_soc_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 034195c83b..f75c19ef35 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -10,11 +10,97 @@ // Based on ak4535.c by Richard Purdie // Based on wm8753.c by Liam Girdwood +/* + * +-------+ + * |AK4613 | + * SDTO1 <-| | + * | | + * SDTI1 ->| | + * SDTI2 ->| | + * SDTI3 ->| | + * +-------+ + * + * +---+ + * clk | |___________________________________________... + * + * [TDM512] + * SDTO1 [L1][R1][L2][R2] + * SDTI1 [L1][R1][L2][R2][L3][R3][L4][R4][L5][R5][L6][R6] + * + * [TDM256] + * SDTO1 [L1][R1][L2][R2] + * SDTI1 [L1][R1][L2][R2][L3][R3][L4][R4] + * SDTI2 [L5][R5][L6][R6] + * + * [TDM128] + * SDTO1 [L1][R1][L2][R2] + * SDTI1 [L1][R1][L2][R2] + * SDTI2 [L3][R3][L4][R4] + * SDTI3 [L5][R5][L6][R6] + * + * [STEREO] + * Playback 2ch : SDTI1 + * Capture 2ch : SDTO1 + * + * [TDM512] + * Playback 12ch : SDTI1 + * Capture 4ch : SDTO1 + * + * [TDM256] + * Playback 12ch : SDTI1 + SDTI2 + * Playback 8ch : SDTI1 + * Capture 4ch : SDTO1 + * + * [TDM128] + * Playback 12ch : SDTI1 + SDTI2 + SDTI3 + * Playback 8ch : SDTI1 + SDTI2 + * Playback 4ch : SDTI1 + * Capture 4ch : SDTO1 + * + * + * !!! NOTE !!! + * + * Renesas is the only user of ak4613 on upstream so far, + * but the chip connection is like below. + * Thus, Renesas can't test all connection case. + * Tested TDM is very limited. + * + * +-----+ +-----------+ + * | SoC | | AK4613 | + * | |<-----|SDTO1 IN1|<-- Mic + * | | | IN2| + * | | | | + * | |----->|SDTI1 OUT1|--> Headphone + * +-----+ |SDTI2 OUT2| + * |SDTI3 OUT3| + * | OUT4| + * | OUT5| + * | OUT6| + * +-----------+ + * + * Renesas SoC can handle [2, 6,8] channels. + * Ak4613 can handle [2,4, 8,12] channels. + * + * Because of above HW connection and available channels number, + * Renesas could test are ... + * + * [STEREO] Playback 2ch : SDTI1 + * Capture 2ch : SDTO1 + * [TDM256] Playback 8ch : SDTI1 (*) + * + * (*) it used 8ch data between SoC <-> AK4613 on TDM256 mode, + * but could confirm is only first 2ch because only 1 + * Headphone is connected. + * + * see + * AK4613_ENABLE_TDM_TEST + */ #include #include #include #include #include +#include #include #include #include @@ -78,29 +164,74 @@ /* OCTRL */ #define OCTRL_MASK (0x3F) -struct ak4613_formats { - unsigned int width; - unsigned int fmt; -}; +/* + * configs + * + * 0x000000BA + * + * B : AK4613_CONFIG_SDTI_x + * A : AK4613_CONFIG_MODE_x + */ +#define AK4613_CONFIG_SET(priv, x) priv->configs |= AK4613_CONFIG_##x +#define AK4613_CONFIG_GET(priv, x) (priv->configs & AK4613_CONFIG_##x##_MASK) + +/* + * AK4613_CONFIG_SDTI_x + * + * It indicates how many SDTIx is connected. + */ +#define AK4613_CONFIG_SDTI_MASK (0xF << 4) +#define AK4613_CONFIG_SDTI(x) (((x) & 0xF) << 4) +#define AK4613_CONFIG_SDTI_set(priv, x) AK4613_CONFIG_SET(priv, SDTI(x)) +#define AK4613_CONFIG_SDTI_get(priv) ((AK4613_CONFIG_GET(priv, SDTI) >> 4) & 0xF) + +/* + * AK4613_CONFIG_MODE_x + * + * Same as Ctrl1 :: TDM1/TDM0 + * No shift is requested + * see + * AK4613_CTRL1_TO_MODE() + * Table 11/12/13/14 + */ +#define AK4613_CONFIG_MODE_MASK (0xF) +#define AK4613_CONFIG_MODE_STEREO (0x0) +#define AK4613_CONFIG_MODE_TDM512 (0x1) +#define AK4613_CONFIG_MODE_TDM256 (0x2) +#define AK4613_CONFIG_MODE_TDM128 (0x3) + +/* + * !!!! FIXME !!!! + * + * Because of testable HW limitation, TDM256 8ch TDM was only tested. + * This driver uses AK4613_ENABLE_TDM_TEST instead of new DT property so far. + * Don't hesitate to update driver, you don't need to care compatible + * with Renesas. + * + * #define AK4613_ENABLE_TDM_TEST + */ struct ak4613_interface { - struct ak4613_formats capture; - struct ak4613_formats playback; + unsigned int width; + unsigned int fmt; + u8 dif; }; struct ak4613_priv { struct mutex lock; - const struct ak4613_interface *iface; - struct snd_pcm_hw_constraint_list constraint; + struct snd_pcm_hw_constraint_list constraint_rates; + struct snd_pcm_hw_constraint_list constraint_channels; struct work_struct dummy_write_work; struct snd_soc_component *component; unsigned int rate; unsigned int sysclk; unsigned int fmt; + unsigned int configs; + int cnt; + u8 ctrl1; u8 oc; u8 ic; - int cnt; }; /* @@ -137,14 +268,24 @@ static const struct reg_default ak4613_reg[] = { { 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 }, }; -#define AUDIO_IFACE_TO_VAL(fmts) ((fmts - ak4613_iface) << 3) -#define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt } +/* + * CTRL1 register + * see + * Table 11/12/13/14 + */ +#define AUDIO_IFACE(_dif, _width, _fmt) \ + { \ + .dif = _dif, \ + .width = _width, \ + .fmt = SND_SOC_DAIFMT_##_fmt,\ + } static const struct ak4613_interface ak4613_iface[] = { - /* capture */ /* playback */ - /* [0] - [2] are not supported */ - [3] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(24, LEFT_J) }, - [4] = { AUDIO_IFACE(24, I2S), AUDIO_IFACE(24, I2S) }, + /* It doesn't support asymmetric format */ + + AUDIO_IFACE(0x03, 24, LEFT_J), + AUDIO_IFACE(0x04, 24, I2S), }; +#define AK4613_CTRL1_TO_MODE(priv) ((priv)->ctrl1 >> 6) /* AK4613_CONFIG_MODE_x */ static const struct regmap_config ak4613_regmap_cfg = { .reg_bits = 8, @@ -250,13 +391,14 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream, priv->cnt = 0; } if (!priv->cnt) - priv->iface = NULL; + priv->ctrl1 = 0; mutex_unlock(&priv->lock); } static void ak4613_hw_constraints(struct ak4613_priv *priv, - struct snd_pcm_runtime *runtime) + struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; static const unsigned int ak4613_rates[] = { 32000, 44100, @@ -267,10 +409,36 @@ static void ak4613_hw_constraints(struct ak4613_priv *priv, 176400, 192000, }; - struct snd_pcm_hw_constraint_list *constraint = &priv->constraint; +#define AK4613_CHANNEL_2 0 +#define AK4613_CHANNEL_4 1 +#define AK4613_CHANNEL_8 2 +#define AK4613_CHANNEL_12 3 +#define AK4613_CHANNEL_NONE -1 + static const unsigned int ak4613_channels[] = { + [AK4613_CHANNEL_2] = 2, + [AK4613_CHANNEL_4] = 4, + [AK4613_CHANNEL_8] = 8, + [AK4613_CHANNEL_12] = 12, + }; +#define MODE_MAX 4 +#define SDTx_MAX 4 +#define MASK(x) (1 << AK4613_CHANNEL_##x) + static const int mask_list[MODE_MAX][SDTx_MAX] = { + /* SDTO SDTIx1 SDTIx2 SDTIx3 */ + [AK4613_CONFIG_MODE_STEREO] = { MASK(2), MASK(2), MASK(2), MASK(2)}, + [AK4613_CONFIG_MODE_TDM512] = { MASK(4), MASK(12), MASK(12), MASK(12)}, + [AK4613_CONFIG_MODE_TDM256] = { MASK(4), MASK(8), MASK(8)|MASK(12), MASK(8)|MASK(12)}, + [AK4613_CONFIG_MODE_TDM128] = { MASK(4), MASK(4), MASK(4)|MASK(8), MASK(4)|MASK(8)|MASK(12)}, + }; + struct snd_pcm_hw_constraint_list *constraint; + unsigned int mask; + unsigned int mode; unsigned int fs; + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + int sdti_num; int i; + constraint = &priv->constraint_rates; constraint->list = ak4613_rates; constraint->mask = 0; constraint->count = 0; @@ -296,6 +464,41 @@ static void ak4613_hw_constraints(struct ak4613_priv *priv, snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, constraint); + + + sdti_num = AK4613_CONFIG_SDTI_get(priv); + if (WARN_ON(sdti_num >= SDTx_MAX)) + return; + + if (priv->cnt) { + /* + * If it was already working, + * the constraint is same as working mode. + */ + mode = AK4613_CTRL1_TO_MODE(priv); + mask = 0; /* no default */ + } else { + /* + * It is not yet working, + * the constraint is based on board configs. + * STEREO mask is default + */ + mode = AK4613_CONFIG_GET(priv, MODE); + mask = mask_list[AK4613_CONFIG_MODE_STEREO][is_play * sdti_num]; + } + + if (WARN_ON(mode >= MODE_MAX)) + return; + + /* add each mode mask */ + mask |= mask_list[mode][is_play * sdti_num]; + + constraint = &priv->constraint_channels; + constraint->list = ak4613_channels; + constraint->mask = mask; + constraint->count = sizeof(ak4613_channels); + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, constraint); } static int ak4613_dai_startup(struct snd_pcm_substream *substream, @@ -304,9 +507,10 @@ static int ak4613_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); + mutex_lock(&priv->lock); + ak4613_hw_constraints(priv, substream); priv->cnt++; - - ak4613_hw_constraints(priv, substream->runtime); + mutex_unlock(&priv->lock); return 0; } @@ -322,13 +526,13 @@ static int ak4613_dai_set_sysclk(struct snd_soc_dai *codec_dai, return 0; } -static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int format) { struct snd_soc_component *component = dai->component; struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); + unsigned int fmt; - fmt &= SND_SOC_DAIFMT_FORMAT_MASK; - + fmt = format & SND_SOC_DAIFMT_FORMAT_MASK; switch (fmt) { case SND_SOC_DAIFMT_LEFT_J: case SND_SOC_DAIFMT_I2S: @@ -338,24 +542,20 @@ static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - return 0; -} - -static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface, - int is_play, - unsigned int fmt, unsigned int width) -{ - const struct ak4613_formats *fmts; - - fmts = (is_play) ? &iface->playback : &iface->capture; - - if (fmts->fmt != fmt) - return false; - - if (fmts->width != width) - return false; + fmt = format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; + switch (fmt) { + case SND_SOC_DAIFMT_CBC_CFC: + break; + default: + /* + * SUPPORTME + * + * "clock provider" is not yet supperted + */ + return -EINVAL; + } - return true; + return 0; } static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, @@ -364,14 +564,12 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); - const struct ak4613_interface *iface; struct device *dev = component->dev; unsigned int width = params_width(params); unsigned int fmt = priv->fmt; unsigned int rate; - int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int i, ret; - u8 fmt_ctrl, ctrl2; + u8 ctrl2; rate = params_rate(params); switch (rate) { @@ -397,40 +595,51 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, /* * FIXME * - * It doesn't support TDM at this point + * It doesn't have full TDM suppert yet */ - fmt_ctrl = NO_FMT; ret = -EINVAL; - iface = NULL; mutex_lock(&priv->lock); - if (priv->iface) { - if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width)) - iface = priv->iface; + if (priv->cnt > 1) { + /* + * If it was already working, use current priv->ctrl1 + */ + ret = 0; } else { + /* + * It is not yet working, + */ + unsigned int channel = params_channels(params); + u8 tdm; + + /* STEREO or TDM */ + if (channel == 2) + tdm = AK4613_CONFIG_MODE_STEREO; + else + tdm = AK4613_CONFIG_GET(priv, MODE); + for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) { - if (!ak4613_dai_fmt_matching(ak4613_iface + i, - is_play, - fmt, width)) - continue; - iface = ak4613_iface + i; - break; + const struct ak4613_interface *iface = ak4613_iface + i; + + if ((iface->fmt == fmt) && (iface->width == width)) { + /* + * Ctrl1 + * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | + * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE| + * < tdm > < iface->dif > + */ + priv->ctrl1 = (tdm << 6) | (iface->dif << 3); + ret = 0; + break; + } } } - - if ((priv->iface == NULL) || - (priv->iface == iface)) { - priv->iface = iface; - ret = 0; - } mutex_unlock(&priv->lock); if (ret < 0) goto hw_params_end; - fmt_ctrl = AUDIO_IFACE_TO_VAL(iface); - - snd_soc_component_update_bits(component, CTRL1, FMT_MASK, fmt_ctrl); + snd_soc_component_update_bits(component, CTRL1, FMT_MASK, priv->ctrl1); snd_soc_component_update_bits(component, CTRL2, DFS_MASK, ctrl2); snd_soc_component_update_bits(component, ICTRL, ICTRL_MASK, priv->ic); @@ -574,14 +783,14 @@ static struct snd_soc_dai_driver ak4613_dai = { .playback = { .stream_name = "Playback", .channels_min = 2, - .channels_max = 2, + .channels_max = 12, .rates = AK4613_PCM_RATE, .formats = AK4613_PCM_FMTBIT, }, .capture = { .stream_name = "Capture", .channels_min = 2, - .channels_max = 2, + .channels_max = 4, .rates = AK4613_PCM_RATE, .formats = AK4613_PCM_FMTBIT, }, @@ -618,7 +827,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4613 = { .num_dapm_routes = ARRAY_SIZE(ak4613_intercon), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static void ak4613_parse_of(struct ak4613_priv *priv, @@ -626,6 +834,7 @@ static void ak4613_parse_of(struct ak4613_priv *priv, { struct device_node *np = dev->of_node; char prop[32]; + int sdti_num; int i; /* Input 1 - 2 */ @@ -641,10 +850,34 @@ static void ak4613_parse_of(struct ak4613_priv *priv, if (!of_get_property(np, prop, NULL)) priv->oc |= 1 << i; } + + /* + * enable TDM256 test + * + * !!! FIXME !!! + * + * It should be configured by DT or other way + * if it was full supported. + * But it is using ifdef style for now for test + * purpose. + */ +#if defined(AK4613_ENABLE_TDM_TEST) + AK4613_CONFIG_SET(priv, MODE_TDM256); +#endif + + /* + * connected STDI + * TDM support is assuming it is probed via Audio-Graph-Card style here. + * Default is SDTIx1 if it was probed via Simple-Audio-Card for now. + */ + sdti_num = of_graph_get_endpoint_count(np); + if ((sdti_num >= SDTx_MAX) || (sdti_num < 1)) + sdti_num = 1; + + AK4613_CONFIG_SDTI_set(priv, sdti_num); } -static int ak4613_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ak4613_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct device_node *np = dev->of_node; @@ -655,8 +888,11 @@ static int ak4613_i2c_probe(struct i2c_client *i2c, regmap_cfg = NULL; if (np) regmap_cfg = of_device_get_match_data(dev); - else + else { + const struct i2c_device_id *id = + i2c_match_id(ak4613_i2c_id, i2c); regmap_cfg = (const struct regmap_config *)id->driver_data; + } if (!regmap_cfg) return -EINVAL; @@ -667,7 +903,7 @@ static int ak4613_i2c_probe(struct i2c_client *i2c, ak4613_parse_of(priv, dev); - priv->iface = NULL; + priv->ctrl1 = 0; priv->cnt = 0; priv->sysclk = 0; INIT_WORK(&priv->dummy_write_work, ak4613_dummy_write); @@ -684,18 +920,12 @@ static int ak4613_i2c_probe(struct i2c_client *i2c, &ak4613_dai, 1); } -static int ak4613_i2c_remove(struct i2c_client *client) -{ - return 0; -} - static struct i2c_driver ak4613_i2c_driver = { .driver = { .name = "ak4613-codec", .of_match_table = ak4613_of_match, }, - .probe = ak4613_i2c_probe, - .remove = ak4613_i2c_remove, + .probe_new = ak4613_i2c_probe, .id_table = ak4613_i2c_id, }; diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 04aef0e72a..88851e94b0 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -535,7 +535,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4641 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4641_regmap = { @@ -548,8 +547,7 @@ static const struct regmap_config ak4641_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int ak4641_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ak4641_i2c_probe(struct i2c_client *i2c) { struct ak4641_platform_data *pdata = i2c->dev.platform_data; struct ak4641_priv *ak4641; @@ -632,7 +630,7 @@ static struct i2c_driver ak4641_i2c_driver = { .driver = { .name = "ak4641", }, - .probe = ak4641_i2c_probe, + .probe_new = ak4641_i2c_probe, .remove = ak4641_i2c_remove, .id_table = ak4641_i2c_id, }; diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index c284dcc5af..914d5b1969 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -559,7 +559,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4642 = { .num_dapm_routes = ARRAY_SIZE(ak4642_intercon), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4642_regmap = { @@ -630,8 +629,8 @@ static struct clk *ak4642_of_parse_mcko(struct device *dev) #endif static const struct of_device_id ak4642_of_match[]; -static int ak4642_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id ak4642_i2c_id[]; +static int ak4642_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct device_node *np = dev->of_node; @@ -651,6 +650,8 @@ static int ak4642_i2c_probe(struct i2c_client *i2c, if (of_id) drvdata = of_id->data; } else { + const struct i2c_device_id *id = + i2c_match_id(ak4642_i2c_id, i2c); drvdata = (const struct ak4642_drvdata *)id->driver_data; } @@ -697,7 +698,7 @@ static struct i2c_driver ak4642_i2c_driver = { .name = "ak4642-codec", .of_match_table = ak4642_of_match, }, - .probe = ak4642_i2c_probe, + .probe_new = ak4642_i2c_probe, .id_table = ak4642_i2c_id, }; diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index e9d1251c42..cd76765f8c 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -616,7 +616,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4671 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4671_regmap = { @@ -629,8 +628,7 @@ static const struct regmap_config ak4671_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int ak4671_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ak4671_i2c_probe(struct i2c_client *client) { struct regmap *regmap; int ret; @@ -657,7 +655,7 @@ static struct i2c_driver ak4671_i2c_driver = { .driver = { .name = "ak4671-codec", }, - .probe = ak4671_i2c_probe, + .probe_new = ak4671_i2c_probe, .id_table = ak4671_i2c_id, }; diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c index c76bfff246..0c5e00679c 100644 --- a/sound/soc/codecs/ak5386.c +++ b/sound/soc/codecs/ak5386.c @@ -77,7 +77,6 @@ static const struct snd_soc_component_driver soc_component_ak5386 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai, diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index c94cfde3e4..887d2c04d6 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -393,7 +393,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak5558 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_component_driver soc_codec_dev_ak5552 = { @@ -408,7 +407,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak5552 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak5558_regmap = { diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index b10357a6d6..9ef01b1dd2 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -956,7 +956,6 @@ static const struct snd_soc_component_driver soc_component_device_alc5623 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config alc5623_regmap = { @@ -968,14 +967,21 @@ static const struct regmap_config alc5623_regmap = { .cache_type = REGCACHE_RBTREE, }; +static const struct i2c_device_id alc5623_i2c_table[] = { + {"alc5621", 0x21}, + {"alc5622", 0x22}, + {"alc5623", 0x23}, + {} +}; +MODULE_DEVICE_TABLE(i2c, alc5623_i2c_table); + /* * ALC5623 2 wire address is determined by A1 pin * state during powerup. * low = 0x1a * high = 0x1b */ -static int alc5623_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int alc5623_i2c_probe(struct i2c_client *client) { struct alc5623_platform_data *pdata; struct alc5623_priv *alc5623; @@ -983,6 +989,7 @@ static int alc5623_i2c_probe(struct i2c_client *client, unsigned int vid1, vid2; int ret; u32 val32; + const struct i2c_device_id *id; alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), GFP_KERNEL); @@ -1009,6 +1016,8 @@ static int alc5623_i2c_probe(struct i2c_client *client, } vid2 >>= 8; + id = i2c_match_id(alc5623_i2c_table, client); + if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) { dev_err(&client->dev, "unknown or wrong codec\n"); dev_err(&client->dev, "Expected %x:%lx, got %x:%x\n", @@ -1060,14 +1069,6 @@ static int alc5623_i2c_probe(struct i2c_client *client, return ret; } -static const struct i2c_device_id alc5623_i2c_table[] = { - {"alc5621", 0x21}, - {"alc5622", 0x22}, - {"alc5623", 0x23}, - {} -}; -MODULE_DEVICE_TABLE(i2c, alc5623_i2c_table); - #ifdef CONFIG_OF static const struct of_device_id alc5623_of_match[] = { { .compatible = "realtek,alc5623", }, @@ -1082,7 +1083,7 @@ static struct i2c_driver alc5623_i2c_driver = { .name = "alc562x-codec", .of_match_table = of_match_ptr(alc5623_of_match), }, - .probe = alc5623_i2c_probe, + .probe_new = alc5623_i2c_probe, .id_table = alc5623_i2c_table, }; diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 6d7af3736a..a770704a4e 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -1078,7 +1078,6 @@ static const struct snd_soc_component_driver soc_component_device_alc5632 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config alc5632_regmap = { @@ -1092,18 +1091,24 @@ static const struct regmap_config alc5632_regmap = { .cache_type = REGCACHE_RBTREE, }; +static const struct i2c_device_id alc5632_i2c_table[] = { + {"alc5632", 0x5c}, + {} +}; +MODULE_DEVICE_TABLE(i2c, alc5632_i2c_table); + /* * alc5632 2 wire address is determined by A1 pin * state during powerup. * low = 0x1a * high = 0x1b */ -static int alc5632_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int alc5632_i2c_probe(struct i2c_client *client) { struct alc5632_priv *alc5632; int ret, ret1, ret2; unsigned int vid1, vid2; + const struct i2c_device_id *id; alc5632 = devm_kzalloc(&client->dev, sizeof(struct alc5632_priv), GFP_KERNEL); @@ -1129,6 +1134,8 @@ static int alc5632_i2c_probe(struct i2c_client *client, vid2 >>= 8; + id = i2c_match_id(alc5632_i2c_table, client); + if ((vid1 != 0x10EC) || (vid2 != id->driver_data)) { dev_err(&client->dev, "Device is not a ALC5632: VID1=0x%x, VID2=0x%x\n", vid1, vid2); @@ -1161,12 +1168,6 @@ static int alc5632_i2c_probe(struct i2c_client *client, return ret; } -static const struct i2c_device_id alc5632_i2c_table[] = { - {"alc5632", 0x5c}, - {} -}; -MODULE_DEVICE_TABLE(i2c, alc5632_i2c_table); - #ifdef CONFIG_OF static const struct of_device_id alc5632_of_match[] = { { .compatible = "realtek,alc5632", }, @@ -1181,7 +1182,7 @@ static struct i2c_driver alc5632_i2c_driver = { .name = "alc5632", .of_match_table = of_match_ptr(alc5632_of_match), }, - .probe = alc5632_i2c_probe, + .probe_new = alc5632_i2c_probe, .id_table = alc5632_i2c_table, }; diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e32871b3f6..7434aeeda2 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1760,8 +1760,8 @@ static bool arizona_aif_cfg_changed(struct snd_soc_component *component, if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK)) return true; - val = snd_soc_component_read(component, base + ARIZONA_AIF_TX_BCLK_RATE); - if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK)) + val = snd_soc_component_read(component, base + ARIZONA_AIF_RX_BCLK_RATE); + if (lrclk != (val & ARIZONA_AIF1RX_BCPF_MASK)) return true; val = snd_soc_component_read(component, base + ARIZONA_AIF_FRAME_CTRL_1); diff --git a/sound/soc/codecs/bd28623.c b/sound/soc/codecs/bd28623.c index a6267cb86d..82a94211d0 100644 --- a/sound/soc/codecs/bd28623.c +++ b/sound/soc/codecs/bd28623.c @@ -161,7 +161,6 @@ static const struct snd_soc_component_driver soc_codec_bd = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver soc_dai_bd = { diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c index cf17b9741b..4086b6a53d 100644 --- a/sound/soc/codecs/bt-sco.c +++ b/sound/soc/codecs/bt-sco.c @@ -69,7 +69,6 @@ static const struct snd_soc_component_driver soc_component_dev_bt_sco = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int bt_sco_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c index ffdf8b615e..4f9dabd9d7 100644 --- a/sound/soc/codecs/cpcap.c +++ b/sound/soc/codecs/cpcap.c @@ -1660,7 +1660,6 @@ static struct snd_soc_component_driver soc_codec_dev_cpcap = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cpcap_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 0aae579022..14403b76c7 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -126,7 +126,6 @@ static const struct snd_soc_component_driver soc_component_dev_cq93vc = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cq93vc_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 9b92e1a0d1..11e7b3f6d4 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -232,11 +232,11 @@ static int i2s_rx_hw_params(struct snd_pcm_substream *substream, if (params_rate(params) != 48000) return -EINVAL; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: depth = EC_CODEC_I2S_RX_SAMPLE_DEPTH_16; break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: depth = EC_CODEC_I2S_RX_SAMPLE_DEPTH_24; break; default: @@ -387,6 +387,7 @@ static const struct snd_soc_component_driver i2s_rx_component_driver = { .num_dapm_widgets = ARRAY_SIZE(i2s_rx_dapm_widgets), .dapm_routes = i2s_rx_dapm_routes, .num_dapm_routes = ARRAY_SIZE(i2s_rx_dapm_routes), + .endianness = 1, }; static void *wov_map_shm(struct cros_ec_codec_priv *priv, @@ -994,6 +995,7 @@ static int cros_ec_codec_platform_probe(struct platform_device *pdev) dev_dbg(dev, "ap_shm_phys_addr=%#llx len=%#x\n", priv->ap_shm_phys_addr, priv->ap_shm_len); } + of_node_put(node); } #endif diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 933e3d627e..8ff6f66be8 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -236,7 +236,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l32 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; /* Current and threshold powerup sequence Pg37 in datasheet */ @@ -346,8 +345,7 @@ static int cs35l32_handle_of_data(struct i2c_client *i2c_client, return 0; } -static int cs35l32_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs35l32_i2c_probe(struct i2c_client *i2c_client) { struct cs35l32_private *cs35l32; struct cs35l32_platform_data *pdata = @@ -576,7 +574,7 @@ static struct i2c_driver cs35l32_i2c_driver = { .of_match_table = cs35l32_of_match, }, .id_table = cs35l32_id, - .probe = cs35l32_i2c_probe, + .probe_new = cs35l32_i2c_probe, .remove = cs35l32_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index 2a6f5e46d0..082025fa03 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -840,7 +840,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l33 = { .num_dapm_routes = ARRAY_SIZE(cs35l33_audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs35l33_regmap = { @@ -1116,8 +1115,7 @@ static int cs35l33_of_get_pdata(struct device *dev, return 0; } -static int cs35l33_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs35l33_i2c_probe(struct i2c_client *i2c_client) { struct cs35l33_private *cs35l33; struct cs35l33_pdata *pdata = dev_get_platdata(&i2c_client->dev); @@ -1286,7 +1284,7 @@ static struct i2c_driver cs35l33_i2c_driver = { }, .id_table = cs35l33_id, - .probe = cs35l33_i2c_probe, + .probe_new = cs35l33_i2c_probe, .remove = cs35l33_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index ed678241c2..472ac98277 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -787,7 +787,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l34 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct regmap_config cs35l34_regmap = { @@ -994,8 +993,7 @@ static const char * const cs35l34_core_supplies[] = { "VP", }; -static int cs35l34_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs35l34_i2c_probe(struct i2c_client *i2c_client) { struct cs35l34_private *cs35l34; struct cs35l34_platform_data *pdata = @@ -1217,7 +1215,7 @@ static struct i2c_driver cs35l34_i2c_driver = { }, .id_table = cs35l34_id, - .probe = cs35l34_i2c_probe, + .probe_new = cs35l34_i2c_probe, .remove = cs35l34_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 961a3e07e7..714a759dca 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1087,7 +1087,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l35 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct regmap_config cs35l35_regmap = { @@ -1466,8 +1465,7 @@ static const struct reg_sequence cs35l35_errata_patch[] = { { 0x7F, 0x00 }, }; -static int cs35l35_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs35l35_i2c_probe(struct i2c_client *i2c_client) { struct cs35l35_private *cs35l35; struct device *dev = &i2c_client->dev; @@ -1658,7 +1656,7 @@ static struct i2c_driver cs35l35_i2c_driver = { .of_match_table = cs35l35_of_match, }, .id_table = cs35l35_id, - .probe = cs35l35_i2c_probe, + .probe_new = cs35l35_i2c_probe, .remove = cs35l35_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index d83c1b318c..4dc13e6f48 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -444,7 +444,8 @@ static bool cs35l36_volatile_reg(struct device *dev, unsigned int reg) } } -static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 25, 0); +static const DECLARE_TLV_DB_RANGE(dig_vol_tlv, 0, 912, + TLV_DB_MINMAX_ITEM(-10200, 1200)); static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); static const char * const cs35l36_pcm_sftramp_text[] = { @@ -1299,7 +1300,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l36 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct regmap_config cs35l36_regmap = { @@ -1700,8 +1700,7 @@ static const struct reg_sequence cs35l36_revb0_errata_patch[] = { { CS35L36_TESTKEY_CTRL, CS35L36_TEST_LOCK2 }, }; -static int cs35l36_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs35l36_i2c_probe(struct i2c_client *i2c_client) { struct cs35l36_private *cs35l36; struct device *dev = &i2c_client->dev; @@ -1804,7 +1803,7 @@ static int cs35l36_i2c_probe(struct i2c_client *i2c_client, if (ret < 0) { dev_err(&i2c_client->dev, "Failed to read otp_id Register %d\n", ret); - return ret; + goto err; } if ((l37_id_reg & CS35L36_OTP_REV_MASK) == CS35L36_OTP_REV_L37) @@ -1947,7 +1946,7 @@ static struct i2c_driver cs35l36_i2c_driver = { .of_match_table = cs35l36_of_match, }, .id_table = cs35l36_id, - .probe = cs35l36_i2c_probe, + .probe_new = cs35l36_i2c_probe, .remove = cs35l36_i2c_remove, }; module_i2c_driver(cs35l36_i2c_driver); diff --git a/sound/soc/codecs/cs35l41-i2c.c b/sound/soc/codecs/cs35l41-i2c.c index faad5c638c..37c703c08f 100644 --- a/sound/soc/codecs/cs35l41-i2c.c +++ b/sound/soc/codecs/cs35l41-i2c.c @@ -29,12 +29,11 @@ static const struct i2c_device_id cs35l41_id_i2c[] = { MODULE_DEVICE_TABLE(i2c, cs35l41_id_i2c); -static int cs35l41_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cs35l41_i2c_probe(struct i2c_client *client) { struct cs35l41_private *cs35l41; struct device *dev = &client->dev; - struct cs35l41_platform_data *pdata = dev_get_platdata(dev); + struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(dev); const struct regmap_config *regmap_config = &cs35l41_regmap_i2c; int ret; @@ -54,7 +53,7 @@ static int cs35l41_i2c_probe(struct i2c_client *client, return ret; } - return cs35l41_probe(cs35l41, pdata); + return cs35l41_probe(cs35l41, hw_cfg); } static int cs35l41_i2c_remove(struct i2c_client *client) @@ -91,7 +90,7 @@ static struct i2c_driver cs35l41_i2c_driver = { .acpi_match_table = ACPI_PTR(cs35l41_acpi_match), }, .id_table = cs35l41_id_i2c, - .probe = cs35l41_i2c_probe, + .probe_new = cs35l41_i2c_probe, .remove = cs35l41_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index aa6823fbd1..04be714354 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -36,8 +37,8 @@ static const struct reg_default cs35l41_reg[] = { { CS35L41_DAC_PCM1_SRC, 0x00000008 }, { CS35L41_ASP_TX1_SRC, 0x00000018 }, { CS35L41_ASP_TX2_SRC, 0x00000019 }, - { CS35L41_ASP_TX3_SRC, 0x00000020 }, - { CS35L41_ASP_TX4_SRC, 0x00000021 }, + { CS35L41_ASP_TX3_SRC, 0x00000000 }, + { CS35L41_ASP_TX4_SRC, 0x00000000 }, { CS35L41_DSP1_RX1_SRC, 0x00000008 }, { CS35L41_DSP1_RX2_SRC, 0x00000009 }, { CS35L41_DSP1_RX3_SRC, 0x00000018 }, @@ -422,7 +423,7 @@ static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) } } -static const struct cs35l41_otp_packed_element_t otp_map_1[CS35L41_NUM_OTP_ELEM] = { +static const struct cs35l41_otp_packed_element_t otp_map_1[] = { /* addr shift size */ { 0x00002030, 0, 4 }, /*TRIM_OSC_FREQ_TRIM*/ { 0x00002030, 7, 1 }, /*TRIM_OSC_TRIM_DONE*/ @@ -525,7 +526,7 @@ static const struct cs35l41_otp_packed_element_t otp_map_1[CS35L41_NUM_OTP_ELEM] { 0x00017044, 0, 24 }, /*LOT_NUMBER*/ }; -static const struct cs35l41_otp_packed_element_t otp_map_2[CS35L41_NUM_OTP_ELEM] = { +static const struct cs35l41_otp_packed_element_t otp_map_2[] = { /* addr shift size */ { 0x00002030, 0, 4 }, /*TRIM_OSC_FREQ_TRIM*/ { 0x00002030, 7, 1 }, /*TRIM_OSC_TRIM_DONE*/ @@ -643,6 +644,8 @@ static const struct reg_sequence cs35l41_reva0_errata_patch[] = { { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, { CS35L41_PWR_CTRL2, 0x00000000 }, { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, + { CS35L41_ASP_TX3_SRC, 0x00000000 }, + { CS35L41_ASP_TX4_SRC, 0x00000000 }, }; static const struct reg_sequence cs35l41_revb0_errata_patch[] = { @@ -654,6 +657,8 @@ static const struct reg_sequence cs35l41_revb0_errata_patch[] = { { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, { CS35L41_PWR_CTRL2, 0x00000000 }, { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, + { CS35L41_ASP_TX3_SRC, 0x00000000 }, + { CS35L41_ASP_TX4_SRC, 0x00000000 }, }; static const struct reg_sequence cs35l41_revb2_errata_patch[] = { @@ -665,41 +670,62 @@ static const struct reg_sequence cs35l41_revb2_errata_patch[] = { { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, { CS35L41_PWR_CTRL2, 0x00000000 }, { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, + { CS35L41_ASP_TX3_SRC, 0x00000000 }, + { CS35L41_ASP_TX4_SRC, 0x00000000 }, +}; + +static const struct reg_sequence cs35l41_fs_errata_patch[] = { + { CS35L41_DSP1_RX1_RATE, 0x00000001 }, + { CS35L41_DSP1_RX2_RATE, 0x00000001 }, + { CS35L41_DSP1_RX3_RATE, 0x00000001 }, + { CS35L41_DSP1_RX4_RATE, 0x00000001 }, + { CS35L41_DSP1_RX5_RATE, 0x00000001 }, + { CS35L41_DSP1_RX6_RATE, 0x00000001 }, + { CS35L41_DSP1_RX7_RATE, 0x00000001 }, + { CS35L41_DSP1_RX8_RATE, 0x00000001 }, + { CS35L41_DSP1_TX1_RATE, 0x00000001 }, + { CS35L41_DSP1_TX2_RATE, 0x00000001 }, + { CS35L41_DSP1_TX3_RATE, 0x00000001 }, + { CS35L41_DSP1_TX4_RATE, 0x00000001 }, + { CS35L41_DSP1_TX5_RATE, 0x00000001 }, + { CS35L41_DSP1_TX6_RATE, 0x00000001 }, + { CS35L41_DSP1_TX7_RATE, 0x00000001 }, + { CS35L41_DSP1_TX8_RATE, 0x00000001 }, }; static const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[] = { { .id = 0x01, .map = otp_map_1, - .num_elements = CS35L41_NUM_OTP_ELEM, + .num_elements = ARRAY_SIZE(otp_map_1), .bit_offset = 16, .word_offset = 2, }, { .id = 0x02, .map = otp_map_2, - .num_elements = CS35L41_NUM_OTP_ELEM, + .num_elements = ARRAY_SIZE(otp_map_2), .bit_offset = 16, .word_offset = 2, }, { .id = 0x03, .map = otp_map_2, - .num_elements = CS35L41_NUM_OTP_ELEM, + .num_elements = ARRAY_SIZE(otp_map_2), .bit_offset = 16, .word_offset = 2, }, { .id = 0x06, .map = otp_map_2, - .num_elements = CS35L41_NUM_OTP_ELEM, + .num_elements = ARRAY_SIZE(otp_map_2), .bit_offset = 16, .word_offset = 2, }, { .id = 0x08, .map = otp_map_1, - .num_elements = CS35L41_NUM_OTP_ELEM, + .num_elements = ARRAY_SIZE(otp_map_1), .bit_offset = 16, .word_offset = 2, }, @@ -822,7 +848,7 @@ int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap) word_offset = otp_map_match->word_offset; for (i = 0; i < otp_map_match->num_elements; i++) { - dev_dbg(dev, "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d otp_map[i].size = %d\n", + dev_dbg(dev, "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d, otp_map[i].size = %u\n", bit_offset, word_offset, bit_sum % 32, otp_map[i].size); if (bit_offset + otp_map[i].size - 1 >= 32) { otp_val = (otp_mem[word_offset] & @@ -956,9 +982,8 @@ static const unsigned char cs35l41_bst_slope_table[4] = { 0x75, 0x6B, 0x3B, 0x28 }; - -int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_ind, int boost_cap, - int boost_ipk) +static int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_ind, + int boost_cap, int boost_ipk) { unsigned char bst_lbst_val, bst_cbst_range, bst_ipk_scaled; int ret; @@ -994,10 +1019,20 @@ int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_in case 101 ... 200: bst_cbst_range = 3; break; - default: /* 201 uF and greater */ + default: + if (boost_cap < 0) { + dev_err(dev, "Invalid boost capacitor value: %d nH\n", boost_cap); + return -EINVAL; + } + /* 201 uF and greater */ bst_cbst_range = 4; } + if (boost_ipk < 1600 || boost_ipk > 4500) { + dev_err(dev, "Invalid boost inductor peak current: %d mA\n", boost_ipk); + return -EINVAL; + } + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF, CS35L41_BST_K1_MASK | CS35L41_BST_K2_MASK, cs35l41_bst_k1_table[bst_lbst_val][bst_cbst_range] @@ -1019,10 +1054,6 @@ int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_in return ret; } - if (boost_ipk < 1600 || boost_ipk > 4500) { - dev_err(dev, "Invalid boost inductor peak current: %d mA\n", boost_ipk); - return -EINVAL; - } bst_ipk_scaled = ((boost_ipk - 1600) / 50) + 0x10; ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_PEAK_CUR, CS35L41_BST_IPK_MASK, @@ -1032,9 +1063,349 @@ int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_in return ret; } + regmap_update_bits(regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK, + CS35L41_BST_EN_DEFAULT << CS35L41_BST_EN_SHIFT); + + return 0; +} + +static const struct reg_sequence cs35l41_safe_to_reset[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x0000393C, 0x000000C0, 6000}, + { 0x0000393C, 0x00000000 }, + { 0x00007414, 0x00C82222 }, + { 0x0000742C, 0x00000000 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, +}; + +static const struct reg_sequence cs35l41_active_to_safe[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x00007438, 0x00585941 }, + { CS35L41_PWR_CTRL1, 0x00000000 }, + { 0x0000742C, 0x00000009, 3000 }, + { 0x00007438, 0x00580941 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, +}; + +static const struct reg_sequence cs35l41_safe_to_active[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x0000742C, 0x0000000F }, + { 0x0000742C, 0x00000079 }, + { 0x00007438, 0x00585941 }, + { CS35L41_PWR_CTRL1, 0x00000001, 3000 }, // GLOBAL_EN = 1 + { 0x0000742C, 0x000000F9 }, + { 0x00007438, 0x00580941 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, +}; + +static const struct reg_sequence cs35l41_reset_to_safe[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x00007438, 0x00585941 }, + { 0x00007414, 0x08C82222 }, + { 0x0000742C, 0x00000009 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, +}; + +int cs35l41_init_boost(struct device *dev, struct regmap *regmap, + struct cs35l41_hw_cfg *hw_cfg) +{ + int ret; + + switch (hw_cfg->bst_type) { + case CS35L41_INT_BOOST: + ret = cs35l41_boost_config(dev, regmap, hw_cfg->bst_ind, + hw_cfg->bst_cap, hw_cfg->bst_ipk); + if (ret) + dev_err(dev, "Error in Boost DT config: %d\n", ret); + break; + case CS35L41_EXT_BOOST: + case CS35L41_EXT_BOOST_NO_VSPK_SWITCH: + /* Only CLSA0100 doesn't use GPIO as VSPK switch, but even on that laptop we can + * toggle GPIO1 as is not connected to anything. + * There will be no other device without VSPK switch. + */ + regmap_write(regmap, CS35L41_GPIO1_CTRL1, 0x00000001); + regmap_multi_reg_write(regmap, cs35l41_reset_to_safe, + ARRAY_SIZE(cs35l41_reset_to_safe)); + ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK, + CS35L41_BST_DIS_FET_OFF << CS35L41_BST_EN_SHIFT); + break; + default: + dev_err(dev, "Boost type %d not supported\n", hw_cfg->bst_type); + ret = -EINVAL; + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(cs35l41_init_boost); + +bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type) +{ + switch (b_type) { + /* There is only one laptop that doesn't have VSPK switch. */ + case CS35L41_EXT_BOOST_NO_VSPK_SWITCH: + return false; + case CS35L41_EXT_BOOST: + regmap_write(regmap, CS35L41_GPIO1_CTRL1, 0x00000001); + regmap_multi_reg_write(regmap, cs35l41_safe_to_reset, + ARRAY_SIZE(cs35l41_safe_to_reset)); + return true; + default: + return true; + } +} +EXPORT_SYMBOL_GPL(cs35l41_safe_reset); + +int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable) +{ + int ret; + + switch (b_type) { + case CS35L41_INT_BOOST: + ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL1, CS35L41_GLOBAL_EN_MASK, + enable << CS35L41_GLOBAL_EN_SHIFT); + usleep_range(3000, 3100); + break; + case CS35L41_EXT_BOOST: + case CS35L41_EXT_BOOST_NO_VSPK_SWITCH: + if (enable) + ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active, + ARRAY_SIZE(cs35l41_safe_to_active)); + else + ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe, + ARRAY_SIZE(cs35l41_active_to_safe)); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(cs35l41_global_enable); + +int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg) +{ + struct cs35l41_gpio_cfg *gpio1 = &hw_cfg->gpio1; + struct cs35l41_gpio_cfg *gpio2 = &hw_cfg->gpio2; + int irq_pol = IRQF_TRIGGER_NONE; + + regmap_update_bits(regmap, CS35L41_GPIO1_CTRL1, + CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK, + gpio1->pol_inv << CS35L41_GPIO_POL_SHIFT | + !gpio1->out_en << CS35L41_GPIO_DIR_SHIFT); + + regmap_update_bits(regmap, CS35L41_GPIO2_CTRL1, + CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK, + gpio2->pol_inv << CS35L41_GPIO_POL_SHIFT | + !gpio2->out_en << CS35L41_GPIO_DIR_SHIFT); + + if (gpio1->valid) + regmap_update_bits(regmap, CS35L41_GPIO_PAD_CONTROL, CS35L41_GPIO1_CTRL_MASK, + gpio1->func << CS35L41_GPIO1_CTRL_SHIFT); + + if (gpio2->valid) { + regmap_update_bits(regmap, CS35L41_GPIO_PAD_CONTROL, CS35L41_GPIO2_CTRL_MASK, + gpio2->func << CS35L41_GPIO2_CTRL_SHIFT); + + switch (gpio2->func) { + case CS35L41_GPIO2_INT_PUSH_PULL_LOW: + case CS35L41_GPIO2_INT_OPEN_DRAIN: + irq_pol = IRQF_TRIGGER_LOW; + break; + case CS35L41_GPIO2_INT_PUSH_PULL_HIGH: + irq_pol = IRQF_TRIGGER_HIGH; + break; + default: + break; + } + } + + return irq_pol; +} +EXPORT_SYMBOL_GPL(cs35l41_gpio_config); + +static const struct cs_dsp_region cs35l41_dsp1_regions[] = { + { .type = WMFW_HALO_PM_PACKED, .base = CS35L41_DSP1_PMEM_0 }, + { .type = WMFW_HALO_XM_PACKED, .base = CS35L41_DSP1_XMEM_PACK_0 }, + { .type = WMFW_HALO_YM_PACKED, .base = CS35L41_DSP1_YMEM_PACK_0 }, + {. type = WMFW_ADSP2_XM, .base = CS35L41_DSP1_XMEM_UNPACK24_0}, + {. type = WMFW_ADSP2_YM, .base = CS35L41_DSP1_YMEM_UNPACK24_0}, +}; + +void cs35l41_configure_cs_dsp(struct device *dev, struct regmap *reg, struct cs_dsp *dsp) +{ + dsp->num = 1; + dsp->type = WMFW_HALO; + dsp->rev = 0; + dsp->dev = dev; + dsp->regmap = reg; + dsp->base = CS35L41_DSP1_CTRL_BASE; + dsp->base_sysinfo = CS35L41_DSP1_SYS_ID; + dsp->mem = cs35l41_dsp1_regions; + dsp->num_mems = ARRAY_SIZE(cs35l41_dsp1_regions); + dsp->lock_regions = 0xFFFFFFFF; +} +EXPORT_SYMBOL_GPL(cs35l41_configure_cs_dsp); + +static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd, + enum cs35l41_cspl_mbox_status sts) +{ + switch (cmd) { + case CSPL_MBOX_CMD_NONE: + case CSPL_MBOX_CMD_UNKNOWN_CMD: + return true; + case CSPL_MBOX_CMD_PAUSE: + case CSPL_MBOX_CMD_OUT_OF_HIBERNATE: + return (sts == CSPL_MBOX_STS_PAUSED); + case CSPL_MBOX_CMD_RESUME: + return (sts == CSPL_MBOX_STS_RUNNING); + case CSPL_MBOX_CMD_REINIT: + return (sts == CSPL_MBOX_STS_RUNNING); + case CSPL_MBOX_CMD_STOP_PRE_REINIT: + return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT); + default: + return false; + } +} + +int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap, + enum cs35l41_cspl_mbox_cmd cmd) +{ + unsigned int sts = 0, i; + int ret; + + // Set mailbox cmd + ret = regmap_write(regmap, CS35L41_DSP_VIRT1_MBOX_1, cmd); + if (ret < 0) { + if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE) + dev_err(dev, "Failed to write MBOX: %d\n", ret); + return ret; + } + + // Read mailbox status and verify it is appropriate for the given cmd + for (i = 0; i < 5; i++) { + usleep_range(1000, 1100); + + ret = regmap_read(regmap, CS35L41_DSP_MBOX_2, &sts); + if (ret < 0) { + dev_err(dev, "Failed to read MBOX STS: %d\n", ret); + continue; + } + + if (!cs35l41_check_cspl_mbox_sts(cmd, sts)) + dev_dbg(dev, "[%u] cmd %u returned invalid sts %u", i, cmd, sts); + else + return 0; + } + + if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE) + dev_err(dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts); + + return -ENOMSG; +} +EXPORT_SYMBOL_GPL(cs35l41_set_cspl_mbox_cmd); + +int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap) +{ + int ret; + + ret = regmap_multi_reg_write(regmap, cs35l41_fs_errata_patch, + ARRAY_SIZE(cs35l41_fs_errata_patch)); + if (ret < 0) + dev_err(dev, "Failed to write fs errata: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(cs35l41_write_fs_errata); + +int cs35l41_enter_hibernate(struct device *dev, struct regmap *regmap, + enum cs35l41_boost_type b_type) +{ + if (!cs35l41_safe_reset(regmap, b_type)) { + dev_dbg(dev, "System does not support Suspend\n"); + return -EINVAL; + } + + dev_dbg(dev, "Enter hibernate\n"); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188); + + // Don't wait for ACK since bus activity would wake the device + regmap_write(regmap, CS35L41_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE); + return 0; } -EXPORT_SYMBOL_GPL(cs35l41_boost_config); +EXPORT_SYMBOL_GPL(cs35l41_enter_hibernate); + +static void cs35l41_wait_for_pwrmgt_sts(struct device *dev, struct regmap *regmap) +{ + const int pwrmgt_retries = 10; + unsigned int sts; + int i, ret; + + for (i = 0; i < pwrmgt_retries; i++) { + ret = regmap_read(regmap, CS35L41_PWRMGT_STS, &sts); + if (ret) + dev_err(dev, "Failed to read PWRMGT_STS: %d\n", ret); + else if (!(sts & CS35L41_WR_PEND_STS_MASK)) + return; + + udelay(20); + } + + dev_err(dev, "Timed out reading PWRMGT_STS\n"); +} + +int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap) +{ + const int wake_retries = 20; + const int sleep_retries = 5; + int ret, i, j; + + for (i = 0; i < sleep_retries; i++) { + dev_dbg(dev, "Exit hibernate\n"); + + for (j = 0; j < wake_retries; j++) { + ret = cs35l41_set_cspl_mbox_cmd(dev, regmap, + CSPL_MBOX_CMD_OUT_OF_HIBERNATE); + if (!ret) + break; + + usleep_range(100, 200); + } + + if (j < wake_retries) { + dev_dbg(dev, "Wake success at cycle: %d\n", j); + return 0; + } + + dev_err(dev, "Wake failed, re-enter hibernate: %d\n", ret); + + cs35l41_wait_for_pwrmgt_sts(dev, regmap); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088); + + cs35l41_wait_for_pwrmgt_sts(dev, regmap); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188); + + cs35l41_wait_for_pwrmgt_sts(dev, regmap); + regmap_write(regmap, CS35L41_PWRMGT_CTL, 0x3); + } + + dev_err(dev, "Timed out waking device\n"); + + return -ETIMEDOUT; +} +EXPORT_SYMBOL_GPL(cs35l41_exit_hibernate); MODULE_DESCRIPTION("CS35L41 library"); MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, "); diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c index 169221a5b0..5c8bb24909 100644 --- a/sound/soc/codecs/cs35l41-spi.c +++ b/sound/soc/codecs/cs35l41-spi.c @@ -30,7 +30,7 @@ MODULE_DEVICE_TABLE(spi, cs35l41_id_spi); static int cs35l41_spi_probe(struct spi_device *spi) { const struct regmap_config *regmap_config = &cs35l41_regmap_spi; - struct cs35l41_platform_data *pdata = dev_get_platdata(&spi->dev); + struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(&spi->dev); struct cs35l41_private *cs35l41; int ret; @@ -52,7 +52,7 @@ static int cs35l41_spi_probe(struct spi_device *spi) cs35l41->dev = &spi->dev; cs35l41->irq = spi->irq; - return cs35l41_probe(cs35l41, pdata); + return cs35l41_probe(cs35l41, hw_cfg); } static void cs35l41_spi_remove(struct spi_device *spi) @@ -74,6 +74,7 @@ MODULE_DEVICE_TABLE(of, cs35l41_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id cs35l41_acpi_match[] = { { "CSC3541", 0 }, /* Cirrus Logic PnP ID + part ID */ + { "CLSA3541", 0 }, /* Cirrus Logic PnP ID + part ID */ {}, }; MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match); diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 6b784a62df..c223d83e02 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -6,6 +6,7 @@ // // Author: David Rhodes +#include #include #include #include @@ -208,67 +209,6 @@ static int cs35l41_dsp_preload_ev(struct snd_soc_dapm_widget *w, } } -static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd, - enum cs35l41_cspl_mbox_status sts) -{ - switch (cmd) { - case CSPL_MBOX_CMD_NONE: - case CSPL_MBOX_CMD_UNKNOWN_CMD: - return true; - case CSPL_MBOX_CMD_PAUSE: - case CSPL_MBOX_CMD_OUT_OF_HIBERNATE: - return (sts == CSPL_MBOX_STS_PAUSED); - case CSPL_MBOX_CMD_RESUME: - return (sts == CSPL_MBOX_STS_RUNNING); - case CSPL_MBOX_CMD_REINIT: - return (sts == CSPL_MBOX_STS_RUNNING); - case CSPL_MBOX_CMD_STOP_PRE_REINIT: - return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT); - default: - return false; - } -} - -static int cs35l41_set_cspl_mbox_cmd(struct cs35l41_private *cs35l41, - enum cs35l41_cspl_mbox_cmd cmd) -{ - unsigned int sts = 0, i; - int ret; - - // Set mailbox cmd - ret = regmap_write(cs35l41->regmap, CS35L41_DSP_VIRT1_MBOX_1, cmd); - if (ret < 0) { - if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE) - dev_err(cs35l41->dev, "Failed to write MBOX: %d\n", ret); - return ret; - } - - // Read mailbox status and verify it is appropriate for the given cmd - for (i = 0; i < 5; i++) { - usleep_range(1000, 1100); - - ret = regmap_read(cs35l41->regmap, CS35L41_DSP_MBOX_2, &sts); - if (ret < 0) { - dev_err(cs35l41->dev, "Failed to read MBOX STS: %d\n", ret); - continue; - } - - if (!cs35l41_check_cspl_mbox_sts(cmd, sts)) { - dev_dbg(cs35l41->dev, - "[%u] cmd %u returned invalid sts %u", - i, cmd, sts); - } else { - return 0; - } - } - - dev_err(cs35l41->dev, - "Failed to set mailbox cmd %u (status %u)\n", - cmd, sts); - - return -ENOMSG; -} - static int cs35l41_dsp_audio_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -299,9 +239,11 @@ static int cs35l41_dsp_audio_ev(struct snd_soc_dapm_widget *w, return -EINVAL; } - return cs35l41_set_cspl_mbox_cmd(cs35l41, CSPL_MBOX_CMD_RESUME); + return cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, + CSPL_MBOX_CMD_RESUME); case SND_SOC_DAPM_PRE_PMD: - return cs35l41_set_cspl_mbox_cmd(cs35l41, CSPL_MBOX_CMD_PAUSE); + return cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, + CSPL_MBOX_CMD_PAUSE); default: return 0; } @@ -392,7 +334,7 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = { SOC_SINGLE("HW Noise Gate Enable", CS35L41_NG_CFG, 8, 63, 0), SOC_SINGLE("HW Noise Gate Delay", CS35L41_NG_CFG, 4, 7, 0), SOC_SINGLE("HW Noise Gate Threshold", CS35L41_NG_CFG, 0, 7, 0), - SOC_SINGLE("Aux Noise Gate CH1 Enable", + SOC_SINGLE("Aux Noise Gate CH1 Switch", CS35L41_MIXER_NGATE_CH1_CFG, 16, 1, 0), SOC_SINGLE("Aux Noise Gate CH1 Entry Delay", CS35L41_MIXER_NGATE_CH1_CFG, 8, 15, 0), @@ -400,15 +342,15 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = { CS35L41_MIXER_NGATE_CH1_CFG, 0, 7, 0), SOC_SINGLE("Aux Noise Gate CH2 Entry Delay", CS35L41_MIXER_NGATE_CH2_CFG, 8, 15, 0), - SOC_SINGLE("Aux Noise Gate CH2 Enable", + SOC_SINGLE("Aux Noise Gate CH2 Switch", CS35L41_MIXER_NGATE_CH2_CFG, 16, 1, 0), SOC_SINGLE("Aux Noise Gate CH2 Threshold", CS35L41_MIXER_NGATE_CH2_CFG, 0, 7, 0), - SOC_SINGLE("SCLK Force", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0), - SOC_SINGLE("LRCLK Force", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0), - SOC_SINGLE("Invert Class D", CS35L41_AMP_DIG_VOL_CTRL, + SOC_SINGLE("SCLK Force Switch", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0), + SOC_SINGLE("LRCLK Force Switch", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0), + SOC_SINGLE("Invert Class D Switch", CS35L41_AMP_DIG_VOL_CTRL, CS35L41_AMP_INV_PCM_SHIFT, 1, 0), - SOC_SINGLE("Amp Gain ZC", CS35L41_AMP_GAIN_CTRL, + SOC_SINGLE("Amp Gain ZC Switch", CS35L41_AMP_GAIN_CTRL, CS35L41_AMP_GAIN_ZC_SHIFT, 1, 0), WM_ADSP2_PRELOAD_SWITCH("DSP1", 1), WM_ADSP_FW_CONTROL("DSP1", 0), @@ -578,15 +520,10 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, cs35l41_pup_patch, ARRAY_SIZE(cs35l41_pup_patch)); - regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1, - CS35L41_GLOBAL_EN_MASK, - 1 << CS35L41_GLOBAL_EN_SHIFT); - - usleep_range(1000, 1100); + cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 1); break; case SND_SOC_DAPM_POST_PMD: - regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1, - CS35L41_GLOBAL_EN_MASK, 0); + cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0); ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS1, val, val & CS35L41_PDN_DONE_MASK, @@ -744,14 +681,6 @@ static const struct snd_soc_dapm_route cs35l41_audio_map[] = { {"CLASS H", NULL, "PCM Source"}, }; -static const struct cs_dsp_region cs35l41_dsp1_regions[] = { - { .type = WMFW_HALO_PM_PACKED, .base = CS35L41_DSP1_PMEM_0 }, - { .type = WMFW_HALO_XM_PACKED, .base = CS35L41_DSP1_XMEM_PACK_0 }, - { .type = WMFW_HALO_YM_PACKED, .base = CS35L41_DSP1_YMEM_PACK_0 }, - {. type = WMFW_ADSP2_XM, .base = CS35L41_DSP1_XMEM_UNPACK24_0}, - {. type = WMFW_ADSP2_YM, .base = CS35L41_DSP1_YMEM_UNPACK24_0}, -}; - static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_n, unsigned int *tx_slot, unsigned int rx_n, unsigned int *rx_slot) { @@ -995,69 +924,53 @@ static int cs35l41_dai_set_sysclk(struct snd_soc_dai *dai, static int cs35l41_set_pdata(struct cs35l41_private *cs35l41) { + struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; int ret; - /* Set Platform Data */ - /* Required */ - if (cs35l41->pdata.bst_ipk && - cs35l41->pdata.bst_ind && cs35l41->pdata.bst_cap) { - ret = cs35l41_boost_config(cs35l41->dev, cs35l41->regmap, cs35l41->pdata.bst_ind, - cs35l41->pdata.bst_cap, cs35l41->pdata.bst_ipk); - if (ret) { - dev_err(cs35l41->dev, "Error in Boost DT config: %d\n", ret); - return ret; - } - } else { - dev_err(cs35l41->dev, "Incomplete Boost component DT config\n"); + if (!hw_cfg->valid) return -EINVAL; - } + + if (hw_cfg->bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) + return -EINVAL; + + /* Required */ + ret = cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, hw_cfg); + if (ret) + return ret; /* Optional */ - if (cs35l41->pdata.dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK && - cs35l41->pdata.dout_hiz >= 0) - regmap_update_bits(cs35l41->regmap, CS35L41_SP_HIZ_CTRL, - CS35L41_ASP_DOUT_HIZ_MASK, - cs35l41->pdata.dout_hiz); + if (hw_cfg->dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK && hw_cfg->dout_hiz >= 0) + regmap_update_bits(cs35l41->regmap, CS35L41_SP_HIZ_CTRL, CS35L41_ASP_DOUT_HIZ_MASK, + hw_cfg->dout_hiz); return 0; } -static int cs35l41_irq_gpio_config(struct cs35l41_private *cs35l41) -{ - struct cs35l41_irq_cfg *irq_gpio_cfg1 = &cs35l41->pdata.irq_config1; - struct cs35l41_irq_cfg *irq_gpio_cfg2 = &cs35l41->pdata.irq_config2; - int irq_pol = IRQF_TRIGGER_NONE; - - regmap_update_bits(cs35l41->regmap, CS35L41_GPIO1_CTRL1, - CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK, - irq_gpio_cfg1->irq_pol_inv << CS35L41_GPIO_POL_SHIFT | - !irq_gpio_cfg1->irq_out_en << CS35L41_GPIO_DIR_SHIFT); - - regmap_update_bits(cs35l41->regmap, CS35L41_GPIO2_CTRL1, - CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK, - irq_gpio_cfg2->irq_pol_inv << CS35L41_GPIO_POL_SHIFT | - !irq_gpio_cfg2->irq_out_en << CS35L41_GPIO_DIR_SHIFT); - - regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL, - CS35L41_GPIO1_CTRL_MASK | CS35L41_GPIO2_CTRL_MASK, - irq_gpio_cfg1->irq_src_sel << CS35L41_GPIO1_CTRL_SHIFT | - irq_gpio_cfg2->irq_src_sel << CS35L41_GPIO2_CTRL_SHIFT); - - if ((irq_gpio_cfg2->irq_src_sel == - (CS35L41_GPIO_CTRL_ACTV_LO | CS35L41_VALID_PDATA)) || - (irq_gpio_cfg2->irq_src_sel == - (CS35L41_GPIO_CTRL_OPEN_INT | CS35L41_VALID_PDATA))) - irq_pol = IRQF_TRIGGER_LOW; - else if (irq_gpio_cfg2->irq_src_sel == - (CS35L41_GPIO_CTRL_ACTV_HI | CS35L41_VALID_PDATA)) - irq_pol = IRQF_TRIGGER_HIGH; - - return irq_pol; -} +static const struct snd_soc_dapm_route cs35l41_ext_bst_routes[] = { + {"Main AMP", NULL, "VSPK"}, +}; + +static const struct snd_soc_dapm_widget cs35l41_ext_bst_widget[] = { + SND_SOC_DAPM_SUPPLY("VSPK", CS35L41_GPIO1_CTRL1, CS35L41_GPIO_LVL_SHIFT, 0, NULL, 0), +}; static int cs35l41_component_probe(struct snd_soc_component *component) { struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int ret; + + if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) { + ret = snd_soc_dapm_new_controls(dapm, cs35l41_ext_bst_widget, + ARRAY_SIZE(cs35l41_ext_bst_widget)); + if (ret) + return ret; + + ret = snd_soc_dapm_add_routes(dapm, cs35l41_ext_bst_routes, + ARRAY_SIZE(cs35l41_ext_bst_routes)); + if (ret) + return ret; + } return wm_adsp2_component_probe(&cs35l41->dsp, component); } @@ -1113,75 +1026,68 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l41 = { .controls = cs35l41_aud_controls, .num_controls = ARRAY_SIZE(cs35l41_aud_controls), .set_sysclk = cs35l41_component_set_sysclk, + + .endianness = 1, }; -static int cs35l41_handle_pdata(struct device *dev, struct cs35l41_platform_data *pdata) +static int cs35l41_handle_pdata(struct device *dev, struct cs35l41_hw_cfg *hw_cfg) { - struct cs35l41_irq_cfg *irq_gpio1_config = &pdata->irq_config1; - struct cs35l41_irq_cfg *irq_gpio2_config = &pdata->irq_config2; + struct cs35l41_gpio_cfg *gpio1 = &hw_cfg->gpio1; + struct cs35l41_gpio_cfg *gpio2 = &hw_cfg->gpio2; unsigned int val; int ret; + ret = device_property_read_u32(dev, "cirrus,boost-type", &val); + if (ret >= 0) + hw_cfg->bst_type = val; + ret = device_property_read_u32(dev, "cirrus,boost-peak-milliamp", &val); if (ret >= 0) - pdata->bst_ipk = val; + hw_cfg->bst_ipk = val; + else + hw_cfg->bst_ipk = -1; ret = device_property_read_u32(dev, "cirrus,boost-ind-nanohenry", &val); if (ret >= 0) - pdata->bst_ind = val; + hw_cfg->bst_ind = val; + else + hw_cfg->bst_ind = -1; ret = device_property_read_u32(dev, "cirrus,boost-cap-microfarad", &val); if (ret >= 0) - pdata->bst_cap = val; + hw_cfg->bst_cap = val; + else + hw_cfg->bst_cap = -1; ret = device_property_read_u32(dev, "cirrus,asp-sdout-hiz", &val); if (ret >= 0) - pdata->dout_hiz = val; + hw_cfg->dout_hiz = val; else - pdata->dout_hiz = -1; + hw_cfg->dout_hiz = -1; /* GPIO1 Pin Config */ - irq_gpio1_config->irq_pol_inv = device_property_read_bool(dev, - "cirrus,gpio1-polarity-invert"); - irq_gpio1_config->irq_out_en = device_property_read_bool(dev, - "cirrus,gpio1-output-enable"); - ret = device_property_read_u32(dev, "cirrus,gpio1-src-select", - &val); - if (ret >= 0) - irq_gpio1_config->irq_src_sel = val | CS35L41_VALID_PDATA; + gpio1->pol_inv = device_property_read_bool(dev, "cirrus,gpio1-polarity-invert"); + gpio1->out_en = device_property_read_bool(dev, "cirrus,gpio1-output-enable"); + ret = device_property_read_u32(dev, "cirrus,gpio1-src-select", &val); + if (ret >= 0) { + gpio1->func = val; + gpio1->valid = true; + } /* GPIO2 Pin Config */ - irq_gpio2_config->irq_pol_inv = device_property_read_bool(dev, - "cirrus,gpio2-polarity-invert"); - irq_gpio2_config->irq_out_en = device_property_read_bool(dev, - "cirrus,gpio2-output-enable"); - ret = device_property_read_u32(dev, "cirrus,gpio2-src-select", - &val); - if (ret >= 0) - irq_gpio2_config->irq_src_sel = val | CS35L41_VALID_PDATA; + gpio2->pol_inv = device_property_read_bool(dev, "cirrus,gpio2-polarity-invert"); + gpio2->out_en = device_property_read_bool(dev, "cirrus,gpio2-output-enable"); + ret = device_property_read_u32(dev, "cirrus,gpio2-src-select", &val); + if (ret >= 0) { + gpio2->func = val; + gpio2->valid = true; + } + + hw_cfg->valid = true; return 0; } -static const struct reg_sequence cs35l41_fs_errata_patch[] = { - { CS35L41_DSP1_RX1_RATE, 0x00000001 }, - { CS35L41_DSP1_RX2_RATE, 0x00000001 }, - { CS35L41_DSP1_RX3_RATE, 0x00000001 }, - { CS35L41_DSP1_RX4_RATE, 0x00000001 }, - { CS35L41_DSP1_RX5_RATE, 0x00000001 }, - { CS35L41_DSP1_RX6_RATE, 0x00000001 }, - { CS35L41_DSP1_RX7_RATE, 0x00000001 }, - { CS35L41_DSP1_RX8_RATE, 0x00000001 }, - { CS35L41_DSP1_TX1_RATE, 0x00000001 }, - { CS35L41_DSP1_TX2_RATE, 0x00000001 }, - { CS35L41_DSP1_TX3_RATE, 0x00000001 }, - { CS35L41_DSP1_TX4_RATE, 0x00000001 }, - { CS35L41_DSP1_TX5_RATE, 0x00000001 }, - { CS35L41_DSP1_TX6_RATE, 0x00000001 }, - { CS35L41_DSP1_TX7_RATE, 0x00000001 }, - { CS35L41_DSP1_TX8_RATE, 0x00000001 }, -}; - static int cs35l41_dsp_init(struct cs35l41_private *cs35l41) { struct wm_adsp *dsp; @@ -1189,25 +1095,14 @@ static int cs35l41_dsp_init(struct cs35l41_private *cs35l41) dsp = &cs35l41->dsp; dsp->part = "cs35l41"; - dsp->cs_dsp.num = 1; - dsp->cs_dsp.type = WMFW_HALO; - dsp->cs_dsp.rev = 0; dsp->fw = 9; /* 9 is WM_ADSP_FW_SPK_PROT in wm_adsp.c */ dsp->toggle_preload = true; - dsp->cs_dsp.dev = cs35l41->dev; - dsp->cs_dsp.regmap = cs35l41->regmap; - dsp->cs_dsp.base = CS35L41_DSP1_CTRL_BASE; - dsp->cs_dsp.base_sysinfo = CS35L41_DSP1_SYS_ID; - dsp->cs_dsp.mem = cs35l41_dsp1_regions; - dsp->cs_dsp.num_mems = ARRAY_SIZE(cs35l41_dsp1_regions); - dsp->cs_dsp.lock_regions = 0xFFFFFFFF; - - ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_fs_errata_patch, - ARRAY_SIZE(cs35l41_fs_errata_patch)); - if (ret < 0) { - dev_err(cs35l41->dev, "Failed to write fs errata: %d\n", ret); + + cs35l41_configure_cs_dsp(cs35l41->dev, cs35l41->regmap, &dsp->cs_dsp); + + ret = cs35l41_write_fs_errata(cs35l41->dev, cs35l41->regmap); + if (ret < 0) return ret; - } ret = wm_halo_init(dsp); if (ret) { @@ -1248,17 +1143,40 @@ static int cs35l41_dsp_init(struct cs35l41_private *cs35l41) return ret; } -int cs35l41_probe(struct cs35l41_private *cs35l41, - struct cs35l41_platform_data *pdata) +static int cs35l41_acpi_get_name(struct cs35l41_private *cs35l41) +{ + acpi_handle handle = ACPI_HANDLE(cs35l41->dev); + const char *sub; + + /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */ + if (!handle) + return 0; + + sub = acpi_get_subsystem_id(handle); + if (IS_ERR(sub)) { + /* If bad ACPI, return 0 and fallback to legacy firmware path, otherwise fail */ + if (PTR_ERR(sub) == -ENODATA) + return 0; + else + return PTR_ERR(sub); + } + + cs35l41->dsp.system_name = sub; + dev_dbg(cs35l41->dev, "Subsystem ID: %s\n", cs35l41->dsp.system_name); + + return 0; +} + +int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg) { u32 regid, reg_revid, i, mtl_revid, int_status, chipid_match; int irq_pol = 0; int ret; - if (pdata) { - cs35l41->pdata = *pdata; + if (hw_cfg) { + cs35l41->hw_cfg = *hw_cfg; } else { - ret = cs35l41_handle_pdata(cs35l41->dev, &cs35l41->pdata); + ret = cs35l41_handle_pdata(cs35l41->dev, &cs35l41->hw_cfg); if (ret != 0) return ret; } @@ -1357,7 +1275,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap); - irq_pol = cs35l41_irq_gpio_config(cs35l41); + irq_pol = cs35l41_gpio_config(cs35l41->regmap, &cs35l41->hw_cfg); /* Set interrupt masks for critical errors */ regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, @@ -1377,6 +1295,10 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, goto err; } + ret = cs35l41_acpi_get_name(cs35l41); + if (ret < 0) + goto err; + ret = cs35l41_dsp_init(cs35l41); if (ret < 0) goto err; @@ -1409,6 +1331,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, wm_adsp2_remove(&cs35l41->dsp); err: + cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type); regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); @@ -1422,7 +1345,9 @@ void cs35l41_remove(struct cs35l41_private *cs35l41) pm_runtime_disable(cs35l41->dev); regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF); + kfree(cs35l41->dsp.system_name); wm_adsp2_remove(&cs35l41->dsp); + cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type); pm_runtime_put_noidle(cs35l41->dev); @@ -1440,14 +1365,7 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev) if (!cs35l41->dsp.preloaded || !cs35l41->dsp.cs_dsp.running) return 0; - dev_dbg(cs35l41->dev, "Enter hibernate\n"); - - regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088); - regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188); - - // Don't wait for ACK since bus activity would wake the device - regmap_write(cs35l41->regmap, CS35L41_DSP_VIRT1_MBOX_1, - CSPL_MBOX_CMD_HIBERNATE); + cs35l41_enter_hibernate(dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type); regcache_cache_only(cs35l41->regmap, true); regcache_mark_dirty(cs35l41->regmap); @@ -1455,65 +1373,6 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev) return 0; } -static void cs35l41_wait_for_pwrmgt_sts(struct cs35l41_private *cs35l41) -{ - const int pwrmgt_retries = 10; - unsigned int sts; - int i, ret; - - for (i = 0; i < pwrmgt_retries; i++) { - ret = regmap_read(cs35l41->regmap, CS35L41_PWRMGT_STS, &sts); - if (ret) - dev_err(cs35l41->dev, "Failed to read PWRMGT_STS: %d\n", ret); - else if (!(sts & CS35L41_WR_PEND_STS_MASK)) - return; - - udelay(20); - } - - dev_err(cs35l41->dev, "Timed out reading PWRMGT_STS\n"); -} - -static int cs35l41_exit_hibernate(struct cs35l41_private *cs35l41) -{ - const int wake_retries = 20; - const int sleep_retries = 5; - int ret, i, j; - - for (i = 0; i < sleep_retries; i++) { - dev_dbg(cs35l41->dev, "Exit hibernate\n"); - - for (j = 0; j < wake_retries; j++) { - ret = cs35l41_set_cspl_mbox_cmd(cs35l41, - CSPL_MBOX_CMD_OUT_OF_HIBERNATE); - if (!ret) - break; - - usleep_range(100, 200); - } - - if (j < wake_retries) { - dev_dbg(cs35l41->dev, "Wake success at cycle: %d\n", j); - return 0; - } - - dev_err(cs35l41->dev, "Wake failed, re-enter hibernate: %d\n", ret); - - cs35l41_wait_for_pwrmgt_sts(cs35l41); - regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088); - - cs35l41_wait_for_pwrmgt_sts(cs35l41); - regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188); - - cs35l41_wait_for_pwrmgt_sts(cs35l41); - regmap_write(cs35l41->regmap, CS35L41_PWRMGT_CTL, 0x3); - } - - dev_err(cs35l41->dev, "Timed out waking device\n"); - - return -ETIMEDOUT; -} - static int __maybe_unused cs35l41_runtime_resume(struct device *dev) { struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); @@ -1526,7 +1385,7 @@ static int __maybe_unused cs35l41_runtime_resume(struct device *dev) regcache_cache_only(cs35l41->regmap, false); - ret = cs35l41_exit_hibernate(cs35l41); + ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap); if (ret) return ret; @@ -1538,6 +1397,7 @@ static int __maybe_unused cs35l41_runtime_resume(struct device *dev) dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret); return ret; } + cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg); return 0; } diff --git a/sound/soc/codecs/cs35l41.h b/sound/soc/codecs/cs35l41.h index 88a3d6e343..c85cbc1dd3 100644 --- a/sound/soc/codecs/cs35l41.h +++ b/sound/soc/codecs/cs35l41.h @@ -23,28 +23,10 @@ extern const struct dev_pm_ops cs35l41_pm_ops; -enum cs35l41_cspl_mbox_status { - CSPL_MBOX_STS_RUNNING = 0, - CSPL_MBOX_STS_PAUSED = 1, - CSPL_MBOX_STS_RDY_FOR_REINIT = 2, -}; - -enum cs35l41_cspl_mbox_cmd { - CSPL_MBOX_CMD_NONE = 0, - CSPL_MBOX_CMD_PAUSE = 1, - CSPL_MBOX_CMD_RESUME = 2, - CSPL_MBOX_CMD_REINIT = 3, - CSPL_MBOX_CMD_STOP_PRE_REINIT = 4, - CSPL_MBOX_CMD_HIBERNATE = 5, - CSPL_MBOX_CMD_OUT_OF_HIBERNATE = 6, - CSPL_MBOX_CMD_UNKNOWN_CMD = -1, - CSPL_MBOX_CMD_INVALID_SEQUENCE = -2, -}; - struct cs35l41_private { struct wm_adsp dsp; /* needs to be first member */ struct snd_soc_codec *codec; - struct cs35l41_platform_data pdata; + struct cs35l41_hw_cfg hw_cfg; struct device *dev; struct regmap *regmap; struct regulator_bulk_data supplies[CS35L41_NUM_SUPPLIES]; @@ -53,8 +35,7 @@ struct cs35l41_private { struct gpio_desc *reset_gpio; }; -int cs35l41_probe(struct cs35l41_private *cs35l41, - struct cs35l41_platform_data *pdata); +int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg); void cs35l41_remove(struct cs35l41_private *cs35l41); #endif /*__CS35L41_H__*/ diff --git a/sound/soc/codecs/cs4234.c b/sound/soc/codecs/cs4234.c index 20126cc675..b49a3cf21e 100644 --- a/sound/soc/codecs/cs4234.c +++ b/sound/soc/codecs/cs4234.c @@ -660,9 +660,9 @@ static const struct snd_soc_component_driver soc_component_cs4234 = { .controls = cs4234_snd_controls, .num_controls = ARRAY_SIZE(cs4234_snd_controls), .set_bias_level = cs4234_set_bias_level, - .non_legacy_dai_naming = 1, .idle_bias_on = 1, .suspend_bias_off = 1, + .endianness = 1, }; static const struct regmap_config cs4234_regmap = { @@ -731,7 +731,7 @@ static int cs4234_powerup(struct cs4234 *cs4234) return 0; } -static int cs4234_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) +static int cs4234_i2c_probe(struct i2c_client *i2c_client) { struct cs4234 *cs4234; struct device *dev = &i2c_client->dev; @@ -908,7 +908,7 @@ static struct i2c_driver cs4234_i2c_driver = { .pm = &cs4234_pm, .of_match_table = cs4234_of_match, }, - .probe = cs4234_i2c_probe, + .probe_new = cs4234_i2c_probe, .remove = cs4234_i2c_remove, }; module_i2c_driver(cs4234_i2c_driver); diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 4415fb364d..76c19802d5 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -553,7 +553,6 @@ static const struct snd_soc_component_driver soc_component_cs4265 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs4265_regmap = { @@ -568,8 +567,7 @@ static const struct regmap_config cs4265_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int cs4265_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs4265_i2c_probe(struct i2c_client *i2c_client) { struct cs4265_private *cs4265; int ret; @@ -653,7 +651,7 @@ static struct i2c_driver cs4265_i2c_driver = { .of_match_table = cs4265_of_match, }, .id_table = cs4265_id, - .probe = cs4265_i2c_probe, + .probe_new = cs4265_i2c_probe, .remove = cs4265_i2c_remove, }; diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 2d239e983a..ba67e43edf 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -32,18 +32,9 @@ #include #include -/* - * The codec isn't really big-endian or little-endian, since the I2S - * interface requires data to be sent serially with the MSbit first. - * However, to support BE and LE I2S devices, we specify both here. That - * way, ALSA will always match the bit patterns. - */ -#define CS4270_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) +#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) /* CS4270 registers addresses */ #define CS4270_CHIPID 0x01 /* Chip ID */ @@ -628,7 +619,6 @@ static const struct snd_soc_component_driver soc_component_device_cs4270 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; /* @@ -672,13 +662,11 @@ static int cs4270_i2c_remove(struct i2c_client *i2c_client) /** * cs4270_i2c_probe - initialize the I2C interface of the CS4270 * @i2c_client: the I2C client object - * @id: the I2C device ID (ignored) * * This function is called whenever the I2C subsystem finds a device that * matches the device ID given via a prior call to i2c_add_driver(). */ -static int cs4270_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs4270_i2c_probe(struct i2c_client *i2c_client) { struct cs4270_private *cs4270; unsigned int val; @@ -765,7 +753,7 @@ static struct i2c_driver cs4270_i2c_driver = { .of_match_table = cs4270_of_match, }, .id_table = cs4270_id, - .probe = cs4270_i2c_probe, + .probe_new = cs4270_i2c_probe, .remove = cs4270_i2c_remove, }; diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c index 0a174236f5..0e8a7cf0da 100644 --- a/sound/soc/codecs/cs4271-i2c.c +++ b/sound/soc/codecs/cs4271-i2c.c @@ -11,8 +11,7 @@ #include #include "cs4271.h" -static int cs4271_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cs4271_i2c_probe(struct i2c_client *client) { struct regmap_config config; @@ -35,7 +34,7 @@ static struct i2c_driver cs4271_i2c_driver = { .name = "cs4271", .of_match_table = of_match_ptr(cs4271_dt_ids), }, - .probe = cs4271_i2c_probe, + .probe_new = cs4271_i2c_probe, .id_table = cs4271_i2c_id, }; module_i2c_driver(cs4271_i2c_driver); diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 7663f89ac6..2021cf4426 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -642,7 +642,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs4271 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs4271_common_probe(struct device *dev, diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index c8409d50e9..d545a593a2 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -581,7 +581,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l42 = { .num_controls = ARRAY_SIZE(cs42l42_snd_controls), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; /* Switch to SCLK. Atomic delay after the write to allow the switch to complete. */ @@ -1701,8 +1700,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) break; default: - if (cs42l42->plug_state != CS42L42_TS_TRANS) - cs42l42->plug_state = CS42L42_TS_TRANS; + cs42l42->plug_state = CS42L42_TS_TRANS; } } @@ -2194,8 +2192,7 @@ static int __maybe_unused cs42l42_resume(struct device *dev) return 0; } -static int cs42l42_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs42l42_i2c_probe(struct i2c_client *i2c_client) { struct cs42l42_private *cs42l42; int ret, i, devid; @@ -2399,7 +2396,7 @@ static struct i2c_driver cs42l42_i2c_driver = { .acpi_match_table = ACPI_PTR(cs42l42_acpi_match), }, .id_table = cs42l42_id, - .probe = cs42l42_i2c_probe, + .probe_new = cs42l42_i2c_probe, .remove = cs42l42_i2c_remove, }; diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 60d3bdf5d7..5f50970375 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -2,7 +2,7 @@ /* * cs42l42.h -- CS42L42 ALSA SoC audio driver header * - * Copyright 2016 Cirrus Logic, Inc. + * Copyright 2016-2022 Cirrus Logic, Inc. * * Author: James Schulman * Author: Brian Austin @@ -14,829 +14,7 @@ #include #include - -#define CS42L42_PAGE_REGISTER 0x00 /* Page Select Register */ -#define CS42L42_WIN_START 0x00 -#define CS42L42_WIN_LEN 0x100 -#define CS42L42_RANGE_MIN 0x00 -#define CS42L42_RANGE_MAX 0x7F - -#define CS42L42_PAGE_10 0x1000 -#define CS42L42_PAGE_11 0x1100 -#define CS42L42_PAGE_12 0x1200 -#define CS42L42_PAGE_13 0x1300 -#define CS42L42_PAGE_15 0x1500 -#define CS42L42_PAGE_19 0x1900 -#define CS42L42_PAGE_1B 0x1B00 -#define CS42L42_PAGE_1C 0x1C00 -#define CS42L42_PAGE_1D 0x1D00 -#define CS42L42_PAGE_1F 0x1F00 -#define CS42L42_PAGE_20 0x2000 -#define CS42L42_PAGE_21 0x2100 -#define CS42L42_PAGE_23 0x2300 -#define CS42L42_PAGE_24 0x2400 -#define CS42L42_PAGE_25 0x2500 -#define CS42L42_PAGE_26 0x2600 -#define CS42L42_PAGE_28 0x2800 -#define CS42L42_PAGE_29 0x2900 -#define CS42L42_PAGE_2A 0x2A00 -#define CS42L42_PAGE_30 0x3000 - -#define CS42L42_CHIP_ID 0x42A42 - -/* Page 0x10 Global Registers */ -#define CS42L42_DEVID_AB (CS42L42_PAGE_10 + 0x01) -#define CS42L42_DEVID_CD (CS42L42_PAGE_10 + 0x02) -#define CS42L42_DEVID_E (CS42L42_PAGE_10 + 0x03) -#define CS42L42_FABID (CS42L42_PAGE_10 + 0x04) -#define CS42L42_REVID (CS42L42_PAGE_10 + 0x05) -#define CS42L42_FRZ_CTL (CS42L42_PAGE_10 + 0x06) - -#define CS42L42_SRC_CTL (CS42L42_PAGE_10 + 0x07) -#define CS42L42_SRC_BYPASS_DAC_SHIFT 1 -#define CS42L42_SRC_BYPASS_DAC_MASK (1 << CS42L42_SRC_BYPASS_DAC_SHIFT) - -#define CS42L42_MCLK_STATUS (CS42L42_PAGE_10 + 0x08) - -#define CS42L42_MCLK_CTL (CS42L42_PAGE_10 + 0x09) -#define CS42L42_INTERNAL_FS_SHIFT 1 -#define CS42L42_INTERNAL_FS_MASK (1 << CS42L42_INTERNAL_FS_SHIFT) - -#define CS42L42_SFTRAMP_RATE (CS42L42_PAGE_10 + 0x0A) -#define CS42L42_SLOW_START_ENABLE (CS42L42_PAGE_10 + 0x0B) -#define CS42L42_SLOW_START_EN_MASK GENMASK(6, 4) -#define CS42L42_SLOW_START_EN_SHIFT 4 -#define CS42L42_I2C_DEBOUNCE (CS42L42_PAGE_10 + 0x0E) -#define CS42L42_I2C_STRETCH (CS42L42_PAGE_10 + 0x0F) -#define CS42L42_I2C_TIMEOUT (CS42L42_PAGE_10 + 0x10) - -/* Page 0x11 Power and Headset Detect Registers */ -#define CS42L42_PWR_CTL1 (CS42L42_PAGE_11 + 0x01) -#define CS42L42_ASP_DAO_PDN_SHIFT 7 -#define CS42L42_ASP_DAO_PDN_MASK (1 << CS42L42_ASP_DAO_PDN_SHIFT) -#define CS42L42_ASP_DAI_PDN_SHIFT 6 -#define CS42L42_ASP_DAI_PDN_MASK (1 << CS42L42_ASP_DAI_PDN_SHIFT) -#define CS42L42_MIXER_PDN_SHIFT 5 -#define CS42L42_MIXER_PDN_MASK (1 << CS42L42_MIXER_PDN_SHIFT) -#define CS42L42_EQ_PDN_SHIFT 4 -#define CS42L42_EQ_PDN_MASK (1 << CS42L42_EQ_PDN_SHIFT) -#define CS42L42_HP_PDN_SHIFT 3 -#define CS42L42_HP_PDN_MASK (1 << CS42L42_HP_PDN_SHIFT) -#define CS42L42_ADC_PDN_SHIFT 2 -#define CS42L42_ADC_PDN_MASK (1 << CS42L42_ADC_PDN_SHIFT) -#define CS42L42_PDN_ALL_SHIFT 0 -#define CS42L42_PDN_ALL_MASK (1 << CS42L42_PDN_ALL_SHIFT) - -#define CS42L42_PWR_CTL2 (CS42L42_PAGE_11 + 0x02) -#define CS42L42_ADC_SRC_PDNB_SHIFT 0 -#define CS42L42_ADC_SRC_PDNB_MASK (1 << CS42L42_ADC_SRC_PDNB_SHIFT) -#define CS42L42_DAC_SRC_PDNB_SHIFT 1 -#define CS42L42_DAC_SRC_PDNB_MASK (1 << CS42L42_DAC_SRC_PDNB_SHIFT) -#define CS42L42_ASP_DAI1_PDN_SHIFT 2 -#define CS42L42_ASP_DAI1_PDN_MASK (1 << CS42L42_ASP_DAI1_PDN_SHIFT) -#define CS42L42_SRC_PDN_OVERRIDE_SHIFT 3 -#define CS42L42_SRC_PDN_OVERRIDE_MASK (1 << CS42L42_SRC_PDN_OVERRIDE_SHIFT) -#define CS42L42_DISCHARGE_FILT_SHIFT 4 -#define CS42L42_DISCHARGE_FILT_MASK (1 << CS42L42_DISCHARGE_FILT_SHIFT) - -#define CS42L42_PWR_CTL3 (CS42L42_PAGE_11 + 0x03) -#define CS42L42_RING_SENSE_PDNB_SHIFT 1 -#define CS42L42_RING_SENSE_PDNB_MASK (1 << \ - CS42L42_RING_SENSE_PDNB_SHIFT) -#define CS42L42_VPMON_PDNB_SHIFT 2 -#define CS42L42_VPMON_PDNB_MASK (1 << \ - CS42L42_VPMON_PDNB_SHIFT) -#define CS42L42_SW_CLK_STP_STAT_SEL_SHIFT 5 -#define CS42L42_SW_CLK_STP_STAT_SEL_MASK (3 << \ - CS42L42_SW_CLK_STP_STAT_SEL_SHIFT) - -#define CS42L42_RSENSE_CTL1 (CS42L42_PAGE_11 + 0x04) -#define CS42L42_RS_TRIM_R_SHIFT 0 -#define CS42L42_RS_TRIM_R_MASK (1 << \ - CS42L42_RS_TRIM_R_SHIFT) -#define CS42L42_RS_TRIM_T_SHIFT 1 -#define CS42L42_RS_TRIM_T_MASK (1 << \ - CS42L42_RS_TRIM_T_SHIFT) -#define CS42L42_HPREF_RS_SHIFT 2 -#define CS42L42_HPREF_RS_MASK (1 << \ - CS42L42_HPREF_RS_SHIFT) -#define CS42L42_HSBIAS_FILT_REF_RS_SHIFT 3 -#define CS42L42_HSBIAS_FILT_REF_RS_MASK (1 << \ - CS42L42_HSBIAS_FILT_REF_RS_SHIFT) -#define CS42L42_RING_SENSE_PU_HIZ_SHIFT 6 -#define CS42L42_RING_SENSE_PU_HIZ_MASK (1 << \ - CS42L42_RING_SENSE_PU_HIZ_SHIFT) - -#define CS42L42_RSENSE_CTL2 (CS42L42_PAGE_11 + 0x05) -#define CS42L42_TS_RS_GATE_SHIFT 7 -#define CS42L42_TS_RS_GATE_MAS (1 << CS42L42_TS_RS_GATE_SHIFT) - -#define CS42L42_OSC_SWITCH (CS42L42_PAGE_11 + 0x07) -#define CS42L42_SCLK_PRESENT_SHIFT 0 -#define CS42L42_SCLK_PRESENT_MASK (1 << CS42L42_SCLK_PRESENT_SHIFT) - -#define CS42L42_OSC_SWITCH_STATUS (CS42L42_PAGE_11 + 0x09) -#define CS42L42_OSC_SW_SEL_STAT_SHIFT 0 -#define CS42L42_OSC_SW_SEL_STAT_MASK (3 << CS42L42_OSC_SW_SEL_STAT_SHIFT) -#define CS42L42_OSC_PDNB_STAT_SHIFT 2 -#define CS42L42_OSC_PDNB_STAT_MASK (1 << CS42L42_OSC_SW_SEL_STAT_SHIFT) - -#define CS42L42_RSENSE_CTL3 (CS42L42_PAGE_11 + 0x12) -#define CS42L42_RS_RISE_DBNCE_TIME_SHIFT 0 -#define CS42L42_RS_RISE_DBNCE_TIME_MASK (7 << \ - CS42L42_RS_RISE_DBNCE_TIME_SHIFT) -#define CS42L42_RS_FALL_DBNCE_TIME_SHIFT 3 -#define CS42L42_RS_FALL_DBNCE_TIME_MASK (7 << \ - CS42L42_RS_FALL_DBNCE_TIME_SHIFT) -#define CS42L42_RS_PU_EN_SHIFT 6 -#define CS42L42_RS_PU_EN_MASK (1 << \ - CS42L42_RS_PU_EN_SHIFT) -#define CS42L42_RS_INV_SHIFT 7 -#define CS42L42_RS_INV_MASK (1 << \ - CS42L42_RS_INV_SHIFT) - -#define CS42L42_TSENSE_CTL (CS42L42_PAGE_11 + 0x13) -#define CS42L42_TS_RISE_DBNCE_TIME_SHIFT 0 -#define CS42L42_TS_RISE_DBNCE_TIME_MASK (7 << \ - CS42L42_TS_RISE_DBNCE_TIME_SHIFT) -#define CS42L42_TS_FALL_DBNCE_TIME_SHIFT 3 -#define CS42L42_TS_FALL_DBNCE_TIME_MASK (7 << \ - CS42L42_TS_FALL_DBNCE_TIME_SHIFT) -#define CS42L42_TS_INV_SHIFT 7 -#define CS42L42_TS_INV_MASK (1 << \ - CS42L42_TS_INV_SHIFT) - -#define CS42L42_TSRS_INT_DISABLE (CS42L42_PAGE_11 + 0x14) -#define CS42L42_D_RS_PLUG_DBNC_SHIFT 0 -#define CS42L42_D_RS_PLUG_DBNC_MASK (1 << CS42L42_D_RS_PLUG_DBNC_SHIFT) -#define CS42L42_D_RS_UNPLUG_DBNC_SHIFT 1 -#define CS42L42_D_RS_UNPLUG_DBNC_MASK (1 << CS42L42_D_RS_UNPLUG_DBNC_SHIFT) -#define CS42L42_D_TS_PLUG_DBNC_SHIFT 2 -#define CS42L42_D_TS_PLUG_DBNC_MASK (1 << CS42L42_D_TS_PLUG_DBNC_SHIFT) -#define CS42L42_D_TS_UNPLUG_DBNC_SHIFT 3 -#define CS42L42_D_TS_UNPLUG_DBNC_MASK (1 << CS42L42_D_TS_UNPLUG_DBNC_SHIFT) - -#define CS42L42_TRSENSE_STATUS (CS42L42_PAGE_11 + 0x15) -#define CS42L42_RS_PLUG_DBNC_SHIFT 0 -#define CS42L42_RS_PLUG_DBNC_MASK (1 << CS42L42_RS_PLUG_DBNC_SHIFT) -#define CS42L42_RS_UNPLUG_DBNC_SHIFT 1 -#define CS42L42_RS_UNPLUG_DBNC_MASK (1 << CS42L42_RS_UNPLUG_DBNC_SHIFT) -#define CS42L42_TS_PLUG_DBNC_SHIFT 2 -#define CS42L42_TS_PLUG_DBNC_MASK (1 << CS42L42_TS_PLUG_DBNC_SHIFT) -#define CS42L42_TS_UNPLUG_DBNC_SHIFT 3 -#define CS42L42_TS_UNPLUG_DBNC_MASK (1 << CS42L42_TS_UNPLUG_DBNC_SHIFT) - -#define CS42L42_HSDET_CTL1 (CS42L42_PAGE_11 + 0x1F) -#define CS42L42_HSDET_COMP1_LVL_SHIFT 0 -#define CS42L42_HSDET_COMP1_LVL_MASK (15 << CS42L42_HSDET_COMP1_LVL_SHIFT) -#define CS42L42_HSDET_COMP2_LVL_SHIFT 4 -#define CS42L42_HSDET_COMP2_LVL_MASK (15 << CS42L42_HSDET_COMP2_LVL_SHIFT) - -#define CS42L42_HSDET_COMP1_LVL_VAL 12 /* 1.25V Comparator */ -#define CS42L42_HSDET_COMP2_LVL_VAL 2 /* 1.75V Comparator */ -#define CS42L42_HSDET_COMP1_LVL_DEFAULT 7 /* 1V Comparator */ -#define CS42L42_HSDET_COMP2_LVL_DEFAULT 7 /* 2V Comparator */ - -#define CS42L42_HSDET_CTL2 (CS42L42_PAGE_11 + 0x20) -#define CS42L42_HSDET_AUTO_TIME_SHIFT 0 -#define CS42L42_HSDET_AUTO_TIME_MASK (3 << CS42L42_HSDET_AUTO_TIME_SHIFT) -#define CS42L42_HSBIAS_REF_SHIFT 3 -#define CS42L42_HSBIAS_REF_MASK (1 << CS42L42_HSBIAS_REF_SHIFT) -#define CS42L42_HSDET_SET_SHIFT 4 -#define CS42L42_HSDET_SET_MASK (3 << CS42L42_HSDET_SET_SHIFT) -#define CS42L42_HSDET_CTRL_SHIFT 6 -#define CS42L42_HSDET_CTRL_MASK (3 << CS42L42_HSDET_CTRL_SHIFT) - -#define CS42L42_HS_SWITCH_CTL (CS42L42_PAGE_11 + 0x21) -#define CS42L42_SW_GNDHS_HS4_SHIFT 0 -#define CS42L42_SW_GNDHS_HS4_MASK (1 << CS42L42_SW_GNDHS_HS4_SHIFT) -#define CS42L42_SW_GNDHS_HS3_SHIFT 1 -#define CS42L42_SW_GNDHS_HS3_MASK (1 << CS42L42_SW_GNDHS_HS3_SHIFT) -#define CS42L42_SW_HSB_HS4_SHIFT 2 -#define CS42L42_SW_HSB_HS4_MASK (1 << CS42L42_SW_HSB_HS4_SHIFT) -#define CS42L42_SW_HSB_HS3_SHIFT 3 -#define CS42L42_SW_HSB_HS3_MASK (1 << CS42L42_SW_HSB_HS3_SHIFT) -#define CS42L42_SW_HSB_FILT_HS4_SHIFT 4 -#define CS42L42_SW_HSB_FILT_HS4_MASK (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) -#define CS42L42_SW_HSB_FILT_HS3_SHIFT 5 -#define CS42L42_SW_HSB_FILT_HS3_MASK (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) -#define CS42L42_SW_REF_HS4_SHIFT 6 -#define CS42L42_SW_REF_HS4_MASK (1 << CS42L42_SW_REF_HS4_SHIFT) -#define CS42L42_SW_REF_HS3_SHIFT 7 -#define CS42L42_SW_REF_HS3_MASK (1 << CS42L42_SW_REF_HS3_SHIFT) - -#define CS42L42_HS_DET_STATUS (CS42L42_PAGE_11 + 0x24) -#define CS42L42_HSDET_TYPE_SHIFT 0 -#define CS42L42_HSDET_TYPE_MASK (3 << CS42L42_HSDET_TYPE_SHIFT) -#define CS42L42_HSDET_COMP1_OUT_SHIFT 6 -#define CS42L42_HSDET_COMP1_OUT_MASK (1 << CS42L42_HSDET_COMP1_OUT_SHIFT) -#define CS42L42_HSDET_COMP2_OUT_SHIFT 7 -#define CS42L42_HSDET_COMP2_OUT_MASK (1 << CS42L42_HSDET_COMP2_OUT_SHIFT) -#define CS42L42_PLUG_CTIA 0 -#define CS42L42_PLUG_OMTP 1 -#define CS42L42_PLUG_HEADPHONE 2 -#define CS42L42_PLUG_INVALID 3 - -#define CS42L42_HSDET_SW_COMP1 ((0 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ - (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ - (1 << CS42L42_SW_HSB_HS4_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS3_SHIFT) | \ - (0 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ - (0 << CS42L42_SW_REF_HS4_SHIFT) | \ - (1 << CS42L42_SW_REF_HS3_SHIFT)) -#define CS42L42_HSDET_SW_COMP2 ((1 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ - (0 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS4_SHIFT) | \ - (1 << CS42L42_SW_HSB_HS3_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ - (0 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ - (1 << CS42L42_SW_REF_HS4_SHIFT) | \ - (0 << CS42L42_SW_REF_HS3_SHIFT)) -#define CS42L42_HSDET_SW_TYPE1 ((0 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ - (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ - (1 << CS42L42_SW_HSB_HS4_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS3_SHIFT) | \ - (0 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ - (0 << CS42L42_SW_REF_HS4_SHIFT) | \ - (1 << CS42L42_SW_REF_HS3_SHIFT)) -#define CS42L42_HSDET_SW_TYPE2 ((1 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ - (0 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS4_SHIFT) | \ - (1 << CS42L42_SW_HSB_HS3_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ - (0 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ - (1 << CS42L42_SW_REF_HS4_SHIFT) | \ - (0 << CS42L42_SW_REF_HS3_SHIFT)) -#define CS42L42_HSDET_SW_TYPE3 ((1 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ - (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS4_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS3_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ - (1 << CS42L42_SW_REF_HS4_SHIFT) | \ - (1 << CS42L42_SW_REF_HS3_SHIFT)) -#define CS42L42_HSDET_SW_TYPE4 ((0 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ - (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ - (1 << CS42L42_SW_HSB_HS4_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS3_SHIFT) | \ - (0 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ - (0 << CS42L42_SW_REF_HS4_SHIFT) | \ - (1 << CS42L42_SW_REF_HS3_SHIFT)) - -#define CS42L42_HSDET_COMP_TYPE1 1 -#define CS42L42_HSDET_COMP_TYPE2 2 -#define CS42L42_HSDET_COMP_TYPE3 0 -#define CS42L42_HSDET_COMP_TYPE4 3 - -#define CS42L42_HS_CLAMP_DISABLE (CS42L42_PAGE_11 + 0x29) -#define CS42L42_HS_CLAMP_DISABLE_SHIFT 0 -#define CS42L42_HS_CLAMP_DISABLE_MASK (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT) - -/* Page 0x12 Clocking Registers */ -#define CS42L42_MCLK_SRC_SEL (CS42L42_PAGE_12 + 0x01) -#define CS42L42_MCLKDIV_SHIFT 1 -#define CS42L42_MCLKDIV_MASK (1 << CS42L42_MCLKDIV_SHIFT) -#define CS42L42_MCLK_SRC_SEL_SHIFT 0 -#define CS42L42_MCLK_SRC_SEL_MASK (1 << CS42L42_MCLK_SRC_SEL_SHIFT) - -#define CS42L42_SPDIF_CLK_CFG (CS42L42_PAGE_12 + 0x02) -#define CS42L42_FSYNC_PW_LOWER (CS42L42_PAGE_12 + 0x03) - -#define CS42L42_FSYNC_PW_UPPER (CS42L42_PAGE_12 + 0x04) -#define CS42L42_FSYNC_PULSE_WIDTH_SHIFT 0 -#define CS42L42_FSYNC_PULSE_WIDTH_MASK (0xff << \ - CS42L42_FSYNC_PULSE_WIDTH_SHIFT) - -#define CS42L42_FSYNC_P_LOWER (CS42L42_PAGE_12 + 0x05) - -#define CS42L42_FSYNC_P_UPPER (CS42L42_PAGE_12 + 0x06) -#define CS42L42_FSYNC_PERIOD_SHIFT 0 -#define CS42L42_FSYNC_PERIOD_MASK (0xff << CS42L42_FSYNC_PERIOD_SHIFT) - -#define CS42L42_ASP_CLK_CFG (CS42L42_PAGE_12 + 0x07) -#define CS42L42_ASP_SCLK_EN_SHIFT 5 -#define CS42L42_ASP_SCLK_EN_MASK (1 << CS42L42_ASP_SCLK_EN_SHIFT) -#define CS42L42_ASP_MASTER_MODE 0x01 -#define CS42L42_ASP_SLAVE_MODE 0x00 -#define CS42L42_ASP_MODE_SHIFT 4 -#define CS42L42_ASP_MODE_MASK (1 << CS42L42_ASP_MODE_SHIFT) -#define CS42L42_ASP_SCPOL_SHIFT 2 -#define CS42L42_ASP_SCPOL_MASK (3 << CS42L42_ASP_SCPOL_SHIFT) -#define CS42L42_ASP_SCPOL_NOR 3 -#define CS42L42_ASP_LCPOL_SHIFT 0 -#define CS42L42_ASP_LCPOL_MASK (3 << CS42L42_ASP_LCPOL_SHIFT) -#define CS42L42_ASP_LCPOL_INV 3 - -#define CS42L42_ASP_FRM_CFG (CS42L42_PAGE_12 + 0x08) -#define CS42L42_ASP_STP_SHIFT 4 -#define CS42L42_ASP_STP_MASK (1 << CS42L42_ASP_STP_SHIFT) -#define CS42L42_ASP_5050_SHIFT 3 -#define CS42L42_ASP_5050_MASK (1 << CS42L42_ASP_5050_SHIFT) -#define CS42L42_ASP_FSD_SHIFT 0 -#define CS42L42_ASP_FSD_MASK (7 << CS42L42_ASP_FSD_SHIFT) -#define CS42L42_ASP_FSD_0_5 1 -#define CS42L42_ASP_FSD_1_0 2 -#define CS42L42_ASP_FSD_1_5 3 -#define CS42L42_ASP_FSD_2_0 4 - -#define CS42L42_FS_RATE_EN (CS42L42_PAGE_12 + 0x09) -#define CS42L42_FS_EN_SHIFT 0 -#define CS42L42_FS_EN_MASK (0xf << CS42L42_FS_EN_SHIFT) -#define CS42L42_FS_EN_IASRC_96K 0x1 -#define CS42L42_FS_EN_OASRC_96K 0x2 - -#define CS42L42_IN_ASRC_CLK (CS42L42_PAGE_12 + 0x0A) -#define CS42L42_CLK_IASRC_SEL_SHIFT 0 -#define CS42L42_CLK_IASRC_SEL_MASK (1 << CS42L42_CLK_IASRC_SEL_SHIFT) -#define CS42L42_CLK_IASRC_SEL_6 0 -#define CS42L42_CLK_IASRC_SEL_12 1 - -#define CS42L42_OUT_ASRC_CLK (CS42L42_PAGE_12 + 0x0B) -#define CS42L42_CLK_OASRC_SEL_SHIFT 0 -#define CS42L42_CLK_OASRC_SEL_MASK (1 << CS42L42_CLK_OASRC_SEL_SHIFT) -#define CS42L42_CLK_OASRC_SEL_12 1 - -#define CS42L42_PLL_DIV_CFG1 (CS42L42_PAGE_12 + 0x0C) -#define CS42L42_SCLK_PREDIV_SHIFT 0 -#define CS42L42_SCLK_PREDIV_MASK (3 << CS42L42_SCLK_PREDIV_SHIFT) - -/* Page 0x13 Interrupt Registers */ -/* Interrupts */ -#define CS42L42_ADC_OVFL_STATUS (CS42L42_PAGE_13 + 0x01) -#define CS42L42_MIXER_STATUS (CS42L42_PAGE_13 + 0x02) -#define CS42L42_SRC_STATUS (CS42L42_PAGE_13 + 0x03) -#define CS42L42_ASP_RX_STATUS (CS42L42_PAGE_13 + 0x04) -#define CS42L42_ASP_TX_STATUS (CS42L42_PAGE_13 + 0x05) -#define CS42L42_CODEC_STATUS (CS42L42_PAGE_13 + 0x08) -#define CS42L42_DET_INT_STATUS1 (CS42L42_PAGE_13 + 0x09) -#define CS42L42_DET_INT_STATUS2 (CS42L42_PAGE_13 + 0x0A) -#define CS42L42_SRCPL_INT_STATUS (CS42L42_PAGE_13 + 0x0B) -#define CS42L42_VPMON_STATUS (CS42L42_PAGE_13 + 0x0D) -#define CS42L42_PLL_LOCK_STATUS (CS42L42_PAGE_13 + 0x0E) -#define CS42L42_TSRS_PLUG_STATUS (CS42L42_PAGE_13 + 0x0F) -/* Masks */ -#define CS42L42_ADC_OVFL_INT_MASK (CS42L42_PAGE_13 + 0x16) -#define CS42L42_ADC_OVFL_SHIFT 0 -#define CS42L42_ADC_OVFL_MASK (1 << CS42L42_ADC_OVFL_SHIFT) -#define CS42L42_ADC_OVFL_VAL_MASK CS42L42_ADC_OVFL_MASK - -#define CS42L42_MIXER_INT_MASK (CS42L42_PAGE_13 + 0x17) -#define CS42L42_MIX_CHB_OVFL_SHIFT 0 -#define CS42L42_MIX_CHB_OVFL_MASK (1 << CS42L42_MIX_CHB_OVFL_SHIFT) -#define CS42L42_MIX_CHA_OVFL_SHIFT 1 -#define CS42L42_MIX_CHA_OVFL_MASK (1 << CS42L42_MIX_CHA_OVFL_SHIFT) -#define CS42L42_EQ_OVFL_SHIFT 2 -#define CS42L42_EQ_OVFL_MASK (1 << CS42L42_EQ_OVFL_SHIFT) -#define CS42L42_EQ_BIQUAD_OVFL_SHIFT 3 -#define CS42L42_EQ_BIQUAD_OVFL_MASK (1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT) -#define CS42L42_MIXER_VAL_MASK (CS42L42_MIX_CHB_OVFL_MASK | \ - CS42L42_MIX_CHA_OVFL_MASK | \ - CS42L42_EQ_OVFL_MASK | \ - CS42L42_EQ_BIQUAD_OVFL_MASK) - -#define CS42L42_SRC_INT_MASK (CS42L42_PAGE_13 + 0x18) -#define CS42L42_SRC_ILK_SHIFT 0 -#define CS42L42_SRC_ILK_MASK (1 << CS42L42_SRC_ILK_SHIFT) -#define CS42L42_SRC_OLK_SHIFT 1 -#define CS42L42_SRC_OLK_MASK (1 << CS42L42_SRC_OLK_SHIFT) -#define CS42L42_SRC_IUNLK_SHIFT 2 -#define CS42L42_SRC_IUNLK_MASK (1 << CS42L42_SRC_IUNLK_SHIFT) -#define CS42L42_SRC_OUNLK_SHIFT 3 -#define CS42L42_SRC_OUNLK_MASK (1 << CS42L42_SRC_OUNLK_SHIFT) -#define CS42L42_SRC_VAL_MASK (CS42L42_SRC_ILK_MASK | \ - CS42L42_SRC_OLK_MASK | \ - CS42L42_SRC_IUNLK_MASK | \ - CS42L42_SRC_OUNLK_MASK) - -#define CS42L42_ASP_RX_INT_MASK (CS42L42_PAGE_13 + 0x19) -#define CS42L42_ASPRX_NOLRCK_SHIFT 0 -#define CS42L42_ASPRX_NOLRCK_MASK (1 << CS42L42_ASPRX_NOLRCK_SHIFT) -#define CS42L42_ASPRX_EARLY_SHIFT 1 -#define CS42L42_ASPRX_EARLY_MASK (1 << CS42L42_ASPRX_EARLY_SHIFT) -#define CS42L42_ASPRX_LATE_SHIFT 2 -#define CS42L42_ASPRX_LATE_MASK (1 << CS42L42_ASPRX_LATE_SHIFT) -#define CS42L42_ASPRX_ERROR_SHIFT 3 -#define CS42L42_ASPRX_ERROR_MASK (1 << CS42L42_ASPRX_ERROR_SHIFT) -#define CS42L42_ASPRX_OVLD_SHIFT 4 -#define CS42L42_ASPRX_OVLD_MASK (1 << CS42L42_ASPRX_OVLD_SHIFT) -#define CS42L42_ASP_RX_VAL_MASK (CS42L42_ASPRX_NOLRCK_MASK | \ - CS42L42_ASPRX_EARLY_MASK | \ - CS42L42_ASPRX_LATE_MASK | \ - CS42L42_ASPRX_ERROR_MASK | \ - CS42L42_ASPRX_OVLD_MASK) - -#define CS42L42_ASP_TX_INT_MASK (CS42L42_PAGE_13 + 0x1A) -#define CS42L42_ASPTX_NOLRCK_SHIFT 0 -#define CS42L42_ASPTX_NOLRCK_MASK (1 << CS42L42_ASPTX_NOLRCK_SHIFT) -#define CS42L42_ASPTX_EARLY_SHIFT 1 -#define CS42L42_ASPTX_EARLY_MASK (1 << CS42L42_ASPTX_EARLY_SHIFT) -#define CS42L42_ASPTX_LATE_SHIFT 2 -#define CS42L42_ASPTX_LATE_MASK (1 << CS42L42_ASPTX_LATE_SHIFT) -#define CS42L42_ASPTX_SMERROR_SHIFT 3 -#define CS42L42_ASPTX_SMERROR_MASK (1 << CS42L42_ASPTX_SMERROR_SHIFT) -#define CS42L42_ASP_TX_VAL_MASK (CS42L42_ASPTX_NOLRCK_MASK | \ - CS42L42_ASPTX_EARLY_MASK | \ - CS42L42_ASPTX_LATE_MASK | \ - CS42L42_ASPTX_SMERROR_MASK) - -#define CS42L42_CODEC_INT_MASK (CS42L42_PAGE_13 + 0x1B) -#define CS42L42_PDN_DONE_SHIFT 0 -#define CS42L42_PDN_DONE_MASK (1 << CS42L42_PDN_DONE_SHIFT) -#define CS42L42_HSDET_AUTO_DONE_SHIFT 1 -#define CS42L42_HSDET_AUTO_DONE_MASK (1 << CS42L42_HSDET_AUTO_DONE_SHIFT) -#define CS42L42_CODEC_VAL_MASK (CS42L42_PDN_DONE_MASK | \ - CS42L42_HSDET_AUTO_DONE_MASK) - -#define CS42L42_SRCPL_INT_MASK (CS42L42_PAGE_13 + 0x1C) -#define CS42L42_SRCPL_ADC_LK_SHIFT 0 -#define CS42L42_SRCPL_ADC_LK_MASK (1 << CS42L42_SRCPL_ADC_LK_SHIFT) -#define CS42L42_SRCPL_DAC_LK_SHIFT 2 -#define CS42L42_SRCPL_DAC_LK_MASK (1 << CS42L42_SRCPL_DAC_LK_SHIFT) -#define CS42L42_SRCPL_ADC_UNLK_SHIFT 5 -#define CS42L42_SRCPL_ADC_UNLK_MASK (1 << CS42L42_SRCPL_ADC_UNLK_SHIFT) -#define CS42L42_SRCPL_DAC_UNLK_SHIFT 6 -#define CS42L42_SRCPL_DAC_UNLK_MASK (1 << CS42L42_SRCPL_DAC_UNLK_SHIFT) -#define CS42L42_SRCPL_VAL_MASK (CS42L42_SRCPL_ADC_LK_MASK | \ - CS42L42_SRCPL_DAC_LK_MASK | \ - CS42L42_SRCPL_ADC_UNLK_MASK | \ - CS42L42_SRCPL_DAC_UNLK_MASK) - -#define CS42L42_VPMON_INT_MASK (CS42L42_PAGE_13 + 0x1E) -#define CS42L42_VPMON_SHIFT 0 -#define CS42L42_VPMON_MASK (1 << CS42L42_VPMON_SHIFT) -#define CS42L42_VPMON_VAL_MASK CS42L42_VPMON_MASK - -#define CS42L42_PLL_LOCK_INT_MASK (CS42L42_PAGE_13 + 0x1F) -#define CS42L42_PLL_LOCK_SHIFT 0 -#define CS42L42_PLL_LOCK_MASK (1 << CS42L42_PLL_LOCK_SHIFT) -#define CS42L42_PLL_LOCK_VAL_MASK CS42L42_PLL_LOCK_MASK - -#define CS42L42_TSRS_PLUG_INT_MASK (CS42L42_PAGE_13 + 0x20) -#define CS42L42_RS_PLUG_SHIFT 0 -#define CS42L42_RS_PLUG_MASK (1 << CS42L42_RS_PLUG_SHIFT) -#define CS42L42_RS_UNPLUG_SHIFT 1 -#define CS42L42_RS_UNPLUG_MASK (1 << CS42L42_RS_UNPLUG_SHIFT) -#define CS42L42_TS_PLUG_SHIFT 2 -#define CS42L42_TS_PLUG_MASK (1 << CS42L42_TS_PLUG_SHIFT) -#define CS42L42_TS_UNPLUG_SHIFT 3 -#define CS42L42_TS_UNPLUG_MASK (1 << CS42L42_TS_UNPLUG_SHIFT) -#define CS42L42_TSRS_PLUG_VAL_MASK (CS42L42_RS_PLUG_MASK | \ - CS42L42_RS_UNPLUG_MASK | \ - CS42L42_TS_PLUG_MASK | \ - CS42L42_TS_UNPLUG_MASK) -#define CS42L42_TS_PLUG 3 -#define CS42L42_TS_UNPLUG 0 -#define CS42L42_TS_TRANS 1 - -/* - * NOTE: PLL_START must be 0 while both ADC_PDN=1 and HP_PDN=1. - * Otherwise it will prevent FILT+ from charging properly. - */ -#define CS42L42_PLL_CTL1 (CS42L42_PAGE_15 + 0x01) -#define CS42L42_PLL_START_SHIFT 0 -#define CS42L42_PLL_START_MASK (1 << CS42L42_PLL_START_SHIFT) - -#define CS42L42_PLL_DIV_FRAC0 (CS42L42_PAGE_15 + 0x02) -#define CS42L42_PLL_DIV_FRAC_SHIFT 0 -#define CS42L42_PLL_DIV_FRAC_MASK (0xff << CS42L42_PLL_DIV_FRAC_SHIFT) - -#define CS42L42_PLL_DIV_FRAC1 (CS42L42_PAGE_15 + 0x03) -#define CS42L42_PLL_DIV_FRAC2 (CS42L42_PAGE_15 + 0x04) - -#define CS42L42_PLL_DIV_INT (CS42L42_PAGE_15 + 0x05) -#define CS42L42_PLL_DIV_INT_SHIFT 0 -#define CS42L42_PLL_DIV_INT_MASK (0xff << CS42L42_PLL_DIV_INT_SHIFT) - -#define CS42L42_PLL_CTL3 (CS42L42_PAGE_15 + 0x08) -#define CS42L42_PLL_DIVOUT_SHIFT 0 -#define CS42L42_PLL_DIVOUT_MASK (0xff << CS42L42_PLL_DIVOUT_SHIFT) - -#define CS42L42_PLL_CAL_RATIO (CS42L42_PAGE_15 + 0x0A) -#define CS42L42_PLL_CAL_RATIO_SHIFT 0 -#define CS42L42_PLL_CAL_RATIO_MASK (0xff << CS42L42_PLL_CAL_RATIO_SHIFT) - -#define CS42L42_PLL_CTL4 (CS42L42_PAGE_15 + 0x1B) -#define CS42L42_PLL_MODE_SHIFT 0 -#define CS42L42_PLL_MODE_MASK (3 << CS42L42_PLL_MODE_SHIFT) - -/* Page 0x19 HP Load Detect Registers */ -#define CS42L42_LOAD_DET_RCSTAT (CS42L42_PAGE_19 + 0x25) -#define CS42L42_RLA_STAT_SHIFT 0 -#define CS42L42_RLA_STAT_MASK (3 << CS42L42_RLA_STAT_SHIFT) -#define CS42L42_RLA_STAT_15_OHM 0 - -#define CS42L42_LOAD_DET_DONE (CS42L42_PAGE_19 + 0x26) -#define CS42L42_HPLOAD_DET_DONE_SHIFT 0 -#define CS42L42_HPLOAD_DET_DONE_MASK (1 << CS42L42_HPLOAD_DET_DONE_SHIFT) - -#define CS42L42_LOAD_DET_EN (CS42L42_PAGE_19 + 0x27) -#define CS42L42_HP_LD_EN_SHIFT 0 -#define CS42L42_HP_LD_EN_MASK (1 << CS42L42_HP_LD_EN_SHIFT) - -/* Page 0x1B Headset Interface Registers */ -#define CS42L42_HSBIAS_SC_AUTOCTL (CS42L42_PAGE_1B + 0x70) -#define CS42L42_HSBIAS_SENSE_TRIP_SHIFT 0 -#define CS42L42_HSBIAS_SENSE_TRIP_MASK (7 << \ - CS42L42_HSBIAS_SENSE_TRIP_SHIFT) -#define CS42L42_TIP_SENSE_EN_SHIFT 5 -#define CS42L42_TIP_SENSE_EN_MASK (1 << \ - CS42L42_TIP_SENSE_EN_SHIFT) -#define CS42L42_AUTO_HSBIAS_HIZ_SHIFT 6 -#define CS42L42_AUTO_HSBIAS_HIZ_MASK (1 << \ - CS42L42_AUTO_HSBIAS_HIZ_SHIFT) -#define CS42L42_HSBIAS_SENSE_EN_SHIFT 7 -#define CS42L42_HSBIAS_SENSE_EN_MASK (1 << \ - CS42L42_HSBIAS_SENSE_EN_SHIFT) - -#define CS42L42_WAKE_CTL (CS42L42_PAGE_1B + 0x71) -#define CS42L42_WAKEB_CLEAR_SHIFT 0 -#define CS42L42_WAKEB_CLEAR_MASK (1 << CS42L42_WAKEB_CLEAR_SHIFT) -#define CS42L42_WAKEB_MODE_SHIFT 5 -#define CS42L42_WAKEB_MODE_MASK (1 << CS42L42_WAKEB_MODE_SHIFT) -#define CS42L42_M_HP_WAKE_SHIFT 6 -#define CS42L42_M_HP_WAKE_MASK (1 << CS42L42_M_HP_WAKE_SHIFT) -#define CS42L42_M_MIC_WAKE_SHIFT 7 -#define CS42L42_M_MIC_WAKE_MASK (1 << CS42L42_M_MIC_WAKE_SHIFT) - -#define CS42L42_ADC_DISABLE_MUTE (CS42L42_PAGE_1B + 0x72) -#define CS42L42_ADC_DISABLE_S0_MUTE_SHIFT 7 -#define CS42L42_ADC_DISABLE_S0_MUTE_MASK (1 << \ - CS42L42_ADC_DISABLE_S0_MUTE_SHIFT) - -#define CS42L42_TIPSENSE_CTL (CS42L42_PAGE_1B + 0x73) -#define CS42L42_TIP_SENSE_DEBOUNCE_SHIFT 0 -#define CS42L42_TIP_SENSE_DEBOUNCE_MASK (3 << \ - CS42L42_TIP_SENSE_DEBOUNCE_SHIFT) -#define CS42L42_TIP_SENSE_INV_SHIFT 5 -#define CS42L42_TIP_SENSE_INV_MASK (1 << \ - CS42L42_TIP_SENSE_INV_SHIFT) -#define CS42L42_TIP_SENSE_CTRL_SHIFT 6 -#define CS42L42_TIP_SENSE_CTRL_MASK (3 << \ - CS42L42_TIP_SENSE_CTRL_SHIFT) - -/* - * NOTE: DETECT_MODE must be 0 while both ADC_PDN=1 and HP_PDN=1. - * Otherwise it will prevent FILT+ from charging properly. - */ -#define CS42L42_MISC_DET_CTL (CS42L42_PAGE_1B + 0x74) -#define CS42L42_PDN_MIC_LVL_DET_SHIFT 0 -#define CS42L42_PDN_MIC_LVL_DET_MASK (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT) -#define CS42L42_HSBIAS_CTL_SHIFT 1 -#define CS42L42_HSBIAS_CTL_MASK (3 << CS42L42_HSBIAS_CTL_SHIFT) -#define CS42L42_DETECT_MODE_SHIFT 3 -#define CS42L42_DETECT_MODE_MASK (3 << CS42L42_DETECT_MODE_SHIFT) - -#define CS42L42_MIC_DET_CTL1 (CS42L42_PAGE_1B + 0x75) -#define CS42L42_HS_DET_LEVEL_SHIFT 0 -#define CS42L42_HS_DET_LEVEL_MASK (0x3F << CS42L42_HS_DET_LEVEL_SHIFT) -#define CS42L42_EVENT_STAT_SEL_SHIFT 6 -#define CS42L42_EVENT_STAT_SEL_MASK (1 << CS42L42_EVENT_STAT_SEL_SHIFT) -#define CS42L42_LATCH_TO_VP_SHIFT 7 -#define CS42L42_LATCH_TO_VP_MASK (1 << CS42L42_LATCH_TO_VP_SHIFT) - -#define CS42L42_MIC_DET_CTL2 (CS42L42_PAGE_1B + 0x76) -#define CS42L42_DEBOUNCE_TIME_SHIFT 5 -#define CS42L42_DEBOUNCE_TIME_MASK (0x07 << CS42L42_DEBOUNCE_TIME_SHIFT) - -#define CS42L42_DET_STATUS1 (CS42L42_PAGE_1B + 0x77) -#define CS42L42_HSBIAS_HIZ_MODE_SHIFT 6 -#define CS42L42_HSBIAS_HIZ_MODE_MASK (1 << CS42L42_HSBIAS_HIZ_MODE_SHIFT) -#define CS42L42_TIP_SENSE_SHIFT 7 -#define CS42L42_TIP_SENSE_MASK (1 << CS42L42_TIP_SENSE_SHIFT) - -#define CS42L42_DET_STATUS2 (CS42L42_PAGE_1B + 0x78) -#define CS42L42_SHORT_TRUE_SHIFT 0 -#define CS42L42_SHORT_TRUE_MASK (1 << CS42L42_SHORT_TRUE_SHIFT) -#define CS42L42_HS_TRUE_SHIFT 1 -#define CS42L42_HS_TRUE_MASK (1 << CS42L42_HS_TRUE_SHIFT) - -#define CS42L42_DET_INT1_MASK (CS42L42_PAGE_1B + 0x79) -#define CS42L42_TIP_SENSE_UNPLUG_SHIFT 5 -#define CS42L42_TIP_SENSE_UNPLUG_MASK (1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT) -#define CS42L42_TIP_SENSE_PLUG_SHIFT 6 -#define CS42L42_TIP_SENSE_PLUG_MASK (1 << CS42L42_TIP_SENSE_PLUG_SHIFT) -#define CS42L42_HSBIAS_SENSE_SHIFT 7 -#define CS42L42_HSBIAS_SENSE_MASK (1 << CS42L42_HSBIAS_SENSE_SHIFT) -#define CS42L42_DET_INT_VAL1_MASK (CS42L42_TIP_SENSE_UNPLUG_MASK | \ - CS42L42_TIP_SENSE_PLUG_MASK | \ - CS42L42_HSBIAS_SENSE_MASK) - -#define CS42L42_DET_INT2_MASK (CS42L42_PAGE_1B + 0x7A) -#define CS42L42_M_SHORT_DET_SHIFT 0 -#define CS42L42_M_SHORT_DET_MASK (1 << \ - CS42L42_M_SHORT_DET_SHIFT) -#define CS42L42_M_SHORT_RLS_SHIFT 1 -#define CS42L42_M_SHORT_RLS_MASK (1 << \ - CS42L42_M_SHORT_RLS_SHIFT) -#define CS42L42_M_HSBIAS_HIZ_SHIFT 2 -#define CS42L42_M_HSBIAS_HIZ_MASK (1 << \ - CS42L42_M_HSBIAS_HIZ_SHIFT) -#define CS42L42_M_DETECT_FT_SHIFT 6 -#define CS42L42_M_DETECT_FT_MASK (1 << \ - CS42L42_M_DETECT_FT_SHIFT) -#define CS42L42_M_DETECT_TF_SHIFT 7 -#define CS42L42_M_DETECT_TF_MASK (1 << \ - CS42L42_M_DETECT_TF_SHIFT) -#define CS42L42_DET_INT_VAL2_MASK (CS42L42_M_SHORT_DET_MASK | \ - CS42L42_M_SHORT_RLS_MASK | \ - CS42L42_M_HSBIAS_HIZ_MASK | \ - CS42L42_M_DETECT_FT_MASK | \ - CS42L42_M_DETECT_TF_MASK) - -/* Page 0x1C Headset Bias Registers */ -#define CS42L42_HS_BIAS_CTL (CS42L42_PAGE_1C + 0x03) -#define CS42L42_HSBIAS_RAMP_SHIFT 0 -#define CS42L42_HSBIAS_RAMP_MASK (3 << CS42L42_HSBIAS_RAMP_SHIFT) -#define CS42L42_HSBIAS_PD_SHIFT 4 -#define CS42L42_HSBIAS_PD_MASK (1 << CS42L42_HSBIAS_PD_SHIFT) -#define CS42L42_HSBIAS_CAPLESS_SHIFT 7 -#define CS42L42_HSBIAS_CAPLESS_MASK (1 << CS42L42_HSBIAS_CAPLESS_SHIFT) - -/* Page 0x1D ADC Registers */ -#define CS42L42_ADC_CTL (CS42L42_PAGE_1D + 0x01) -#define CS42L42_ADC_NOTCH_DIS_SHIFT 5 -#define CS42L42_ADC_FORCE_WEAK_VCM_SHIFT 4 -#define CS42L42_ADC_INV_SHIFT 2 -#define CS42L42_ADC_DIG_BOOST_SHIFT 0 - -#define CS42L42_ADC_VOLUME (CS42L42_PAGE_1D + 0x03) -#define CS42L42_ADC_VOL_SHIFT 0 - -#define CS42L42_ADC_WNF_HPF_CTL (CS42L42_PAGE_1D + 0x04) -#define CS42L42_ADC_WNF_CF_SHIFT 4 -#define CS42L42_ADC_WNF_EN_SHIFT 3 -#define CS42L42_ADC_HPF_CF_SHIFT 1 -#define CS42L42_ADC_HPF_EN_SHIFT 0 - -/* Page 0x1F DAC Registers */ -#define CS42L42_DAC_CTL1 (CS42L42_PAGE_1F + 0x01) -#define CS42L42_DACB_INV_SHIFT 1 -#define CS42L42_DACA_INV_SHIFT 0 - -#define CS42L42_DAC_CTL2 (CS42L42_PAGE_1F + 0x06) -#define CS42L42_HPOUT_PULLDOWN_SHIFT 4 -#define CS42L42_HPOUT_PULLDOWN_MASK (15 << CS42L42_HPOUT_PULLDOWN_SHIFT) -#define CS42L42_HPOUT_LOAD_SHIFT 3 -#define CS42L42_HPOUT_LOAD_MASK (1 << CS42L42_HPOUT_LOAD_SHIFT) -#define CS42L42_HPOUT_CLAMP_SHIFT 2 -#define CS42L42_HPOUT_CLAMP_MASK (1 << CS42L42_HPOUT_CLAMP_SHIFT) -#define CS42L42_DAC_HPF_EN_SHIFT 1 -#define CS42L42_DAC_HPF_EN_MASK (1 << CS42L42_DAC_HPF_EN_SHIFT) -#define CS42L42_DAC_MON_EN_SHIFT 0 -#define CS42L42_DAC_MON_EN_MASK (1 << CS42L42_DAC_MON_EN_SHIFT) - -/* Page 0x20 HP CTL Registers */ -#define CS42L42_HP_CTL (CS42L42_PAGE_20 + 0x01) -#define CS42L42_HP_ANA_BMUTE_SHIFT 3 -#define CS42L42_HP_ANA_BMUTE_MASK (1 << CS42L42_HP_ANA_BMUTE_SHIFT) -#define CS42L42_HP_ANA_AMUTE_SHIFT 2 -#define CS42L42_HP_ANA_AMUTE_MASK (1 << CS42L42_HP_ANA_AMUTE_SHIFT) -#define CS42L42_HP_FULL_SCALE_VOL_SHIFT 1 -#define CS42L42_HP_FULL_SCALE_VOL_MASK (1 << CS42L42_HP_FULL_SCALE_VOL_SHIFT) - -/* Page 0x21 Class H Registers */ -#define CS42L42_CLASSH_CTL (CS42L42_PAGE_21 + 0x01) - -/* Page 0x23 Mixer Volume Registers */ -#define CS42L42_MIXER_CHA_VOL (CS42L42_PAGE_23 + 0x01) -#define CS42L42_MIXER_ADC_VOL (CS42L42_PAGE_23 + 0x02) - -#define CS42L42_MIXER_CHB_VOL (CS42L42_PAGE_23 + 0x03) -#define CS42L42_MIXER_CH_VOL_SHIFT 0 -#define CS42L42_MIXER_CH_VOL_MASK (0x3f << CS42L42_MIXER_CH_VOL_SHIFT) - -/* Page 0x24 EQ Registers */ -#define CS42L42_EQ_COEF_IN0 (CS42L42_PAGE_24 + 0x01) -#define CS42L42_EQ_COEF_IN1 (CS42L42_PAGE_24 + 0x02) -#define CS42L42_EQ_COEF_IN2 (CS42L42_PAGE_24 + 0x03) -#define CS42L42_EQ_COEF_IN3 (CS42L42_PAGE_24 + 0x04) -#define CS42L42_EQ_COEF_RW (CS42L42_PAGE_24 + 0x06) -#define CS42L42_EQ_COEF_OUT0 (CS42L42_PAGE_24 + 0x07) -#define CS42L42_EQ_COEF_OUT1 (CS42L42_PAGE_24 + 0x08) -#define CS42L42_EQ_COEF_OUT2 (CS42L42_PAGE_24 + 0x09) -#define CS42L42_EQ_COEF_OUT3 (CS42L42_PAGE_24 + 0x0A) -#define CS42L42_EQ_INIT_STAT (CS42L42_PAGE_24 + 0x0B) -#define CS42L42_EQ_START_FILT (CS42L42_PAGE_24 + 0x0C) -#define CS42L42_EQ_MUTE_CTL (CS42L42_PAGE_24 + 0x0E) - -/* Page 0x25 Audio Port Registers */ -#define CS42L42_SP_RX_CH_SEL (CS42L42_PAGE_25 + 0x01) -#define CS42L42_SP_RX_CHB_SEL_SHIFT 2 -#define CS42L42_SP_RX_CHB_SEL_MASK (3 << CS42L42_SP_RX_CHB_SEL_SHIFT) - -#define CS42L42_SP_RX_ISOC_CTL (CS42L42_PAGE_25 + 0x02) -#define CS42L42_SP_RX_RSYNC_SHIFT 6 -#define CS42L42_SP_RX_RSYNC_MASK (1 << CS42L42_SP_RX_RSYNC_SHIFT) -#define CS42L42_SP_RX_NSB_POS_SHIFT 3 -#define CS42L42_SP_RX_NSB_POS_MASK (7 << CS42L42_SP_RX_NSB_POS_SHIFT) -#define CS42L42_SP_RX_NFS_NSBB_SHIFT 2 -#define CS42L42_SP_RX_NFS_NSBB_MASK (1 << CS42L42_SP_RX_NFS_NSBB_SHIFT) -#define CS42L42_SP_RX_ISOC_MODE_SHIFT 0 -#define CS42L42_SP_RX_ISOC_MODE_MASK (3 << CS42L42_SP_RX_ISOC_MODE_SHIFT) - -#define CS42L42_SP_RX_FS (CS42L42_PAGE_25 + 0x03) -#define CS42l42_SPDIF_CH_SEL (CS42L42_PAGE_25 + 0x04) -#define CS42L42_SP_TX_ISOC_CTL (CS42L42_PAGE_25 + 0x05) -#define CS42L42_SP_TX_FS (CS42L42_PAGE_25 + 0x06) -#define CS42L42_SPDIF_SW_CTL1 (CS42L42_PAGE_25 + 0x07) - -/* Page 0x26 SRC Registers */ -#define CS42L42_SRC_SDIN_FS (CS42L42_PAGE_26 + 0x01) -#define CS42L42_SRC_SDIN_FS_SHIFT 0 -#define CS42L42_SRC_SDIN_FS_MASK (0x1f << CS42L42_SRC_SDIN_FS_SHIFT) - -#define CS42L42_SRC_SDOUT_FS (CS42L42_PAGE_26 + 0x09) - -/* Page 0x28 S/PDIF Registers */ -#define CS42L42_SPDIF_CTL1 (CS42L42_PAGE_28 + 0x01) -#define CS42L42_SPDIF_CTL2 (CS42L42_PAGE_28 + 0x02) -#define CS42L42_SPDIF_CTL3 (CS42L42_PAGE_28 + 0x03) -#define CS42L42_SPDIF_CTL4 (CS42L42_PAGE_28 + 0x04) - -/* Page 0x29 Serial Port TX Registers */ -#define CS42L42_ASP_TX_SZ_EN (CS42L42_PAGE_29 + 0x01) -#define CS42L42_ASP_TX_EN_SHIFT 0 -#define CS42L42_ASP_TX_CH_EN (CS42L42_PAGE_29 + 0x02) -#define CS42L42_ASP_TX0_CH2_SHIFT 1 -#define CS42L42_ASP_TX0_CH1_SHIFT 0 - -#define CS42L42_ASP_TX_CH_AP_RES (CS42L42_PAGE_29 + 0x03) -#define CS42L42_ASP_TX_CH1_AP_SHIFT 7 -#define CS42L42_ASP_TX_CH1_AP_MASK (1 << CS42L42_ASP_TX_CH1_AP_SHIFT) -#define CS42L42_ASP_TX_CH2_AP_SHIFT 6 -#define CS42L42_ASP_TX_CH2_AP_MASK (1 << CS42L42_ASP_TX_CH2_AP_SHIFT) -#define CS42L42_ASP_TX_CH2_RES_SHIFT 2 -#define CS42L42_ASP_TX_CH2_RES_MASK (3 << CS42L42_ASP_TX_CH2_RES_SHIFT) -#define CS42L42_ASP_TX_CH1_RES_SHIFT 0 -#define CS42L42_ASP_TX_CH1_RES_MASK (3 << CS42L42_ASP_TX_CH1_RES_SHIFT) -#define CS42L42_ASP_TX_CH1_BIT_MSB (CS42L42_PAGE_29 + 0x04) -#define CS42L42_ASP_TX_CH1_BIT_LSB (CS42L42_PAGE_29 + 0x05) -#define CS42L42_ASP_TX_HIZ_DLY_CFG (CS42L42_PAGE_29 + 0x06) -#define CS42L42_ASP_TX_CH2_BIT_MSB (CS42L42_PAGE_29 + 0x0A) -#define CS42L42_ASP_TX_CH2_BIT_LSB (CS42L42_PAGE_29 + 0x0B) - -/* Page 0x2A Serial Port RX Registers */ -#define CS42L42_ASP_RX_DAI0_EN (CS42L42_PAGE_2A + 0x01) -#define CS42L42_ASP_RX0_CH_EN_SHIFT 2 -#define CS42L42_ASP_RX0_CH_EN_MASK (0xf << CS42L42_ASP_RX0_CH_EN_SHIFT) -#define CS42L42_ASP_RX0_CH1_SHIFT 2 -#define CS42L42_ASP_RX0_CH2_SHIFT 3 -#define CS42L42_ASP_RX0_CH3_SHIFT 4 -#define CS42L42_ASP_RX0_CH4_SHIFT 5 - -#define CS42L42_ASP_RX_DAI0_CH1_AP_RES (CS42L42_PAGE_2A + 0x02) -#define CS42L42_ASP_RX_DAI0_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x03) -#define CS42L42_ASP_RX_DAI0_CH1_BIT_LSB (CS42L42_PAGE_2A + 0x04) -#define CS42L42_ASP_RX_DAI0_CH2_AP_RES (CS42L42_PAGE_2A + 0x05) -#define CS42L42_ASP_RX_DAI0_CH2_BIT_MSB (CS42L42_PAGE_2A + 0x06) -#define CS42L42_ASP_RX_DAI0_CH2_BIT_LSB (CS42L42_PAGE_2A + 0x07) -#define CS42L42_ASP_RX_DAI0_CH3_AP_RES (CS42L42_PAGE_2A + 0x08) -#define CS42L42_ASP_RX_DAI0_CH3_BIT_MSB (CS42L42_PAGE_2A + 0x09) -#define CS42L42_ASP_RX_DAI0_CH3_BIT_LSB (CS42L42_PAGE_2A + 0x0A) -#define CS42L42_ASP_RX_DAI0_CH4_AP_RES (CS42L42_PAGE_2A + 0x0B) -#define CS42L42_ASP_RX_DAI0_CH4_BIT_MSB (CS42L42_PAGE_2A + 0x0C) -#define CS42L42_ASP_RX_DAI0_CH4_BIT_LSB (CS42L42_PAGE_2A + 0x0D) -#define CS42L42_ASP_RX_DAI1_CH1_AP_RES (CS42L42_PAGE_2A + 0x0E) -#define CS42L42_ASP_RX_DAI1_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x0F) -#define CS42L42_ASP_RX_DAI1_CH1_BIT_LSB (CS42L42_PAGE_2A + 0x10) -#define CS42L42_ASP_RX_DAI1_CH2_AP_RES (CS42L42_PAGE_2A + 0x11) -#define CS42L42_ASP_RX_DAI1_CH2_BIT_MSB (CS42L42_PAGE_2A + 0x12) -#define CS42L42_ASP_RX_DAI1_CH2_BIT_LSB (CS42L42_PAGE_2A + 0x13) - -#define CS42L42_ASP_RX_CH_AP_SHIFT 6 -#define CS42L42_ASP_RX_CH_AP_MASK (1 << CS42L42_ASP_RX_CH_AP_SHIFT) -#define CS42L42_ASP_RX_CH_AP_LOW 0 -#define CS42L42_ASP_RX_CH_AP_HI 1 -#define CS42L42_ASP_RX_CH_RES_SHIFT 0 -#define CS42L42_ASP_RX_CH_RES_MASK (3 << CS42L42_ASP_RX_CH_RES_SHIFT) -#define CS42L42_ASP_RX_CH_RES_32 3 -#define CS42L42_ASP_RX_CH_RES_16 1 -#define CS42L42_ASP_RX_CH_BIT_ST_SHIFT 0 -#define CS42L42_ASP_RX_CH_BIT_ST_MASK (0xff << CS42L42_ASP_RX_CH_BIT_ST_SHIFT) - -/* Page 0x30 ID Registers */ -#define CS42L42_SUB_REVID (CS42L42_PAGE_30 + 0x14) -#define CS42L42_MAX_REGISTER (CS42L42_PAGE_30 + 0x14) - -/* Defines for fracturing values spread across multiple registers */ -#define CS42L42_FRAC0_VAL(val) ((val) & 0x0000ff) -#define CS42L42_FRAC1_VAL(val) (((val) & 0x00ff00) >> 8) -#define CS42L42_FRAC2_VAL(val) (((val) & 0xff0000) >> 16) - -#define CS42L42_NUM_SUPPLIES 5 -#define CS42L42_BOOT_TIME_US 3000 -#define CS42L42_PLL_DIVOUT_TIME_US 800 -#define CS42L42_CLOCK_SWITCH_DELAY_US 150 -#define CS42L42_PLL_LOCK_POLL_US 250 -#define CS42L42_PLL_LOCK_TIMEOUT_US 1250 -#define CS42L42_HP_ADC_EN_TIME_US 20000 -#define CS42L42_PDN_DONE_POLL_US 1000 -#define CS42L42_PDN_DONE_TIMEOUT_US 200000 -#define CS42L42_PDN_DONE_TIME_MS 100 -#define CS42L42_FILT_DISCHARGE_TIME_MS 46 +#include static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = { "VA", diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c index 3cb21a2ba2..3613fb12d6 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -19,8 +19,7 @@ static struct i2c_device_id cs42l51_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id); -static int cs42l51_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int cs42l51_i2c_probe(struct i2c_client *i2c) { struct regmap_config config; @@ -46,7 +45,7 @@ static struct i2c_driver cs42l51_i2c_driver = { .of_match_table = cs42l51_of_match, .pm = &cs42l51_pm_ops, }, - .probe = cs42l51_i2c_probe, + .probe_new = cs42l51_i2c_probe, .remove = cs42l51_i2c_remove, .id_table = cs42l51_i2c_id, }; diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index e9c3cb4e2b..51721edd8f 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -51,11 +51,8 @@ struct cs42l51_private { struct regmap *regmap; }; -#define CS42L51_FORMATS ( \ - 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_LE | SNDRV_PCM_FMTBIT_S24_BE) +#define CS42L51_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -146,7 +143,7 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = { 0, 0xA0, 96, adc_att_tlv), SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L51_ALC_PGA_CTL, CS42L51_ALC_PGB_CTL, - 0, 0x1A, 30, pga_tlv), + 0, 0x19, 30, pga_tlv), SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0), SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0), SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0), @@ -603,7 +600,6 @@ static const struct snd_soc_component_driver soc_component_device_cs42l51 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static bool cs42l51_writeable_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 80161151b3..90bf535fc5 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -137,7 +137,9 @@ static DECLARE_TLV_DB_SCALE(mic_tlv, 1600, 100, 0); static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0); -static DECLARE_TLV_DB_SCALE(mix_tlv, -50, 50, 0); +static DECLARE_TLV_DB_SCALE(pass_tlv, -6000, 50, 0); + +static DECLARE_TLV_DB_SCALE(mix_tlv, -5150, 50, 0); static DECLARE_TLV_DB_SCALE(beep_tlv, -56, 200, 0); @@ -351,7 +353,7 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { CS42L52_SPKB_VOL, 0, 0x40, 0xC0, hl_tlv), SOC_DOUBLE_R_SX_TLV("Bypass Volume", CS42L52_PASSTHRUA_VOL, - CS42L52_PASSTHRUB_VOL, 0, 0x88, 0x90, pga_tlv), + CS42L52_PASSTHRUB_VOL, 0, 0x88, 0x90, pass_tlv), SOC_DOUBLE("Bypass Mute", CS42L52_MISC_CTL, 4, 5, 1, 0), @@ -364,7 +366,7 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { CS42L52_ADCB_VOL, 0, 0xA0, 0x78, ipd_tlv), SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L52_ADCA_MIXER_VOL, CS42L52_ADCB_MIXER_VOL, - 0, 0x19, 0x7F, ipd_tlv), + 0, 0x19, 0x7F, mix_tlv), SOC_DOUBLE("ADC Switch", CS42L52_ADC_MISC_CTL, 0, 1, 1, 0), @@ -1059,7 +1061,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l52 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; /* Current and threshold powerup sequence Pg37 */ @@ -1086,8 +1087,7 @@ static const struct regmap_config cs42l52_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int cs42l52_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs42l52_i2c_probe(struct i2c_client *i2c_client) { struct cs42l52_private *cs42l52; struct cs42l52_platform_data *pdata = dev_get_platdata(&i2c_client->dev); @@ -1226,7 +1226,7 @@ static struct i2c_driver cs42l52_i2c_driver = { .of_match_table = cs42l52_of_match, }, .id_table = cs42l52_id, - .probe = cs42l52_i2c_probe, + .probe_new = cs42l52_i2c_probe, }; module_i2c_driver(cs42l52_i2c_driver); diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 3cf8a0b447..03e2540a0b 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -391,9 +391,9 @@ static const struct snd_kcontrol_new cs42l56_snd_controls[] = { SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1), SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME, - CS42L56_HPB_VOLUME, 0, 0x84, 0x48, hl_tlv), + CS42L56_HPB_VOLUME, 0, 0x44, 0x48, hl_tlv), SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME, - CS42L56_LOB_VOLUME, 0, 0x84, 0x48, hl_tlv), + CS42L56_LOB_VOLUME, 0, 0x44, 0x48, hl_tlv), SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL, 0, 0x00, 1, tone_tlv), @@ -1114,7 +1114,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l56 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs42l56_regmap = { @@ -1167,8 +1166,7 @@ static int cs42l56_handle_of_data(struct i2c_client *i2c_client, return 0; } -static int cs42l56_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs42l56_i2c_probe(struct i2c_client *i2c_client) { struct cs42l56_private *cs42l56; struct cs42l56_platform_data *pdata = @@ -1246,7 +1244,7 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, ®); if (ret) { dev_err(&i2c_client->dev, "Failed to read chip ID: %d\n", ret); - return ret; + goto err_enable; } devid = reg & CS42L56_CHIP_ID_MASK; @@ -1350,7 +1348,7 @@ static struct i2c_driver cs42l56_i2c_driver = { .of_match_table = cs42l56_of_match, }, .id_table = cs42l56_id, - .probe = cs42l56_i2c_probe, + .probe_new = cs42l56_i2c_probe, .remove = cs42l56_i2c_remove, }; diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 018463f34e..0a14631975 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1256,7 +1256,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l73 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs42l73_regmap = { @@ -1274,8 +1273,7 @@ static const struct regmap_config cs42l73_regmap = { .use_single_write = true, }; -static int cs42l73_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs42l73_i2c_probe(struct i2c_client *i2c_client) { struct cs42l73_private *cs42l73; struct cs42l73_platform_data *pdata = dev_get_platdata(&i2c_client->dev); @@ -1386,7 +1384,7 @@ static struct i2c_driver cs42l73_i2c_driver = { .of_match_table = cs42l73_of_match, }, .id_table = cs42l73_id, - .probe = cs42l73_i2c_probe, + .probe_new = cs42l73_i2c_probe, }; diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c index b8b15b886c..986e30109c 100644 --- a/sound/soc/codecs/cs42xx8-i2c.c +++ b/sound/soc/codecs/cs42xx8-i2c.c @@ -17,8 +17,7 @@ #include "cs42xx8.h" -static int cs42xx8_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int cs42xx8_i2c_probe(struct i2c_client *i2c) { int ret = cs42xx8_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config)); @@ -58,7 +57,7 @@ static struct i2c_driver cs42xx8_i2c_driver = { .pm = &cs42xx8_pm, .of_match_table = cs42xx8_i2c_of_match, }, - .probe = cs42xx8_i2c_probe, + .probe_new = cs42xx8_i2c_probe, .remove = cs42xx8_i2c_remove, .id_table = cs42xx8_i2c_id, }; diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 7d840313bc..a56a7ff93f 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -497,7 +497,6 @@ static const struct snd_soc_component_driver cs42xx8_driver = { .num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; const struct cs42xx8_driver_data cs42448_data = { diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index 44b20c1ef8..ca4d47cc9c 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -712,30 +712,30 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk, case CS43130_ASP_PCM_DAI: case CS43130_ASP_DOP_DAI: regmap_write(cs43130->regmap, CS43130_ASP_DEN_1, - (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >> + (clk_gen->v.denominator & CS43130_SP_M_LSB_DATA_MASK) >> CS43130_SP_M_LSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_ASP_DEN_2, - (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >> + (clk_gen->v.denominator & CS43130_SP_M_MSB_DATA_MASK) >> CS43130_SP_M_MSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_ASP_NUM_1, - (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >> + (clk_gen->v.numerator & CS43130_SP_N_LSB_DATA_MASK) >> CS43130_SP_N_LSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_ASP_NUM_2, - (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >> + (clk_gen->v.numerator & CS43130_SP_N_MSB_DATA_MASK) >> CS43130_SP_N_MSB_DATA_SHIFT); break; case CS43130_XSP_DOP_DAI: regmap_write(cs43130->regmap, CS43130_XSP_DEN_1, - (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >> + (clk_gen->v.denominator & CS43130_SP_M_LSB_DATA_MASK) >> CS43130_SP_M_LSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_XSP_DEN_2, - (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >> + (clk_gen->v.denominator & CS43130_SP_M_MSB_DATA_MASK) >> CS43130_SP_M_MSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_XSP_NUM_1, - (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >> + (clk_gen->v.numerator & CS43130_SP_N_LSB_DATA_MASK) >> CS43130_SP_N_LSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_XSP_NUM_2, - (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >> + (clk_gen->v.numerator & CS43130_SP_N_MSB_DATA_MASK) >> CS43130_SP_N_MSB_DATA_SHIFT); break; default: @@ -2303,7 +2303,7 @@ static int cs43130_probe(struct snd_soc_component *component) } ret = snd_soc_card_jack_new(card, "Headphone", CS43130_JACK_MASK, - &cs43130->jack, NULL, 0); + &cs43130->jack); if (ret < 0) { dev_err(component->dev, "Cannot create jack\n"); return ret; @@ -2345,7 +2345,6 @@ static struct snd_soc_component_driver soc_component_dev_cs43130 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs43130_regmap = { @@ -2418,8 +2417,7 @@ static int cs43130_handle_device_data(struct i2c_client *i2c_client, return 0; } -static int cs43130_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cs43130_i2c_probe(struct i2c_client *client) { struct cs43130_private *cs43130; int ret; @@ -2702,7 +2700,7 @@ static struct i2c_driver cs43130_i2c_driver = { .pm = &cs43130_runtime_pm, }, .id_table = cs43130_i2c_id, - .probe = cs43130_i2c_probe, + .probe_new = cs43130_i2c_probe, .remove = cs43130_i2c_remove, }; diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h index e62d671e95..1dd8936743 100644 --- a/sound/soc/codecs/cs43130.h +++ b/sound/soc/codecs/cs43130.h @@ -10,6 +10,8 @@ #ifndef __CS43130_H__ #define __CS43130_H__ +#include + /* CS43130 registers addresses */ /* all reg address is shifted by a byte for control byte to be LSB */ #define CS43130_FIRSTREG 0x010000 @@ -372,97 +374,96 @@ enum cs43130_dai_id { }; struct cs43130_clk_gen { - unsigned int mclk_int; - int fs; - u16 den; - u16 num; + unsigned int mclk_int; + int fs; + struct u16_fract v; }; /* frm_size = 16 */ static const struct cs43130_clk_gen cs43130_16_clk_gen[] = { - {22579200, 32000, 441, 10,}, - {22579200, 44100, 32, 1,}, - {22579200, 48000, 147, 5,}, - {22579200, 88200, 16, 1,}, - {22579200, 96000, 147, 10,}, - {22579200, 176400, 8, 1,}, - {22579200, 192000, 147, 20,}, - {22579200, 352800, 4, 1,}, - {22579200, 384000, 147, 40,}, - {24576000, 32000, 48, 1,}, - {24576000, 44100, 5120, 147,}, - {24576000, 48000, 32, 1,}, - {24576000, 88200, 2560, 147,}, - {24576000, 96000, 16, 1,}, - {24576000, 176400, 1280, 147,}, - {24576000, 192000, 8, 1,}, - {24576000, 352800, 640, 147,}, - {24576000, 384000, 4, 1,}, + { 22579200, 32000, .v = { 441, 10, }, }, + { 22579200, 44100, .v = { 32, 1, }, }, + { 22579200, 48000, .v = { 147, 5, }, }, + { 22579200, 88200, .v = { 16, 1, }, }, + { 22579200, 96000, .v = { 147, 10, }, }, + { 22579200, 176400, .v = { 8, 1, }, }, + { 22579200, 192000, .v = { 147, 20, }, }, + { 22579200, 352800, .v = { 4, 1, }, }, + { 22579200, 384000, .v = { 147, 40, }, }, + { 24576000, 32000, .v = { 48, 1, }, }, + { 24576000, 44100, .v = { 5120, 147, }, }, + { 24576000, 48000, .v = { 32, 1, }, }, + { 24576000, 88200, .v = { 2560, 147, }, }, + { 24576000, 96000, .v = { 16, 1, }, }, + { 24576000, 176400, .v = { 1280, 147, }, }, + { 24576000, 192000, .v = { 8, 1, }, }, + { 24576000, 352800, .v = { 640, 147, }, }, + { 24576000, 384000, .v = { 4, 1, }, }, }; /* frm_size = 32 */ static const struct cs43130_clk_gen cs43130_32_clk_gen[] = { - {22579200, 32000, 441, 20,}, - {22579200, 44100, 16, 1,}, - {22579200, 48000, 147, 10,}, - {22579200, 88200, 8, 1,}, - {22579200, 96000, 147, 20,}, - {22579200, 176400, 4, 1,}, - {22579200, 192000, 147, 40,}, - {22579200, 352800, 2, 1,}, - {22579200, 384000, 147, 80,}, - {24576000, 32000, 24, 1,}, - {24576000, 44100, 2560, 147,}, - {24576000, 48000, 16, 1,}, - {24576000, 88200, 1280, 147,}, - {24576000, 96000, 8, 1,}, - {24576000, 176400, 640, 147,}, - {24576000, 192000, 4, 1,}, - {24576000, 352800, 320, 147,}, - {24576000, 384000, 2, 1,}, + { 22579200, 32000, .v = { 441, 20, }, }, + { 22579200, 44100, .v = { 16, 1, }, }, + { 22579200, 48000, .v = { 147, 10, }, }, + { 22579200, 88200, .v = { 8, 1, }, }, + { 22579200, 96000, .v = { 147, 20, }, }, + { 22579200, 176400, .v = { 4, 1, }, }, + { 22579200, 192000, .v = { 147, 40, }, }, + { 22579200, 352800, .v = { 2, 1, }, }, + { 22579200, 384000, .v = { 147, 80, }, }, + { 24576000, 32000, .v = { 24, 1, }, }, + { 24576000, 44100, .v = { 2560, 147, }, }, + { 24576000, 48000, .v = { 16, 1, }, }, + { 24576000, 88200, .v = { 1280, 147, }, }, + { 24576000, 96000, .v = { 8, 1, }, }, + { 24576000, 176400, .v = { 640, 147, }, }, + { 24576000, 192000, .v = { 4, 1, }, }, + { 24576000, 352800, .v = { 320, 147, }, }, + { 24576000, 384000, .v = { 2, 1, }, }, }; /* frm_size = 48 */ static const struct cs43130_clk_gen cs43130_48_clk_gen[] = { - {22579200, 32000, 147, 100,}, - {22579200, 44100, 32, 3,}, - {22579200, 48000, 49, 5,}, - {22579200, 88200, 16, 3,}, - {22579200, 96000, 49, 10,}, - {22579200, 176400, 8, 3,}, - {22579200, 192000, 49, 20,}, - {22579200, 352800, 4, 3,}, - {22579200, 384000, 49, 40,}, - {24576000, 32000, 16, 1,}, - {24576000, 44100, 5120, 441,}, - {24576000, 48000, 32, 3,}, - {24576000, 88200, 2560, 441,}, - {24576000, 96000, 16, 3,}, - {24576000, 176400, 1280, 441,}, - {24576000, 192000, 8, 3,}, - {24576000, 352800, 640, 441,}, - {24576000, 384000, 4, 3,}, + { 22579200, 32000, .v = { 147, 100, }, }, + { 22579200, 44100, .v = { 32, 3, }, }, + { 22579200, 48000, .v = { 49, 5, }, }, + { 22579200, 88200, .v = { 16, 3, }, }, + { 22579200, 96000, .v = { 49, 10, }, }, + { 22579200, 176400, .v = { 8, 3, }, }, + { 22579200, 192000, .v = { 49, 20, }, }, + { 22579200, 352800, .v = { 4, 3, }, }, + { 22579200, 384000, .v = { 49, 40, }, }, + { 24576000, 32000, .v = { 16, 1, }, }, + { 24576000, 44100, .v = { 5120, 441, }, }, + { 24576000, 48000, .v = { 32, 3, }, }, + { 24576000, 88200, .v = { 2560, 441, }, }, + { 24576000, 96000, .v = { 16, 3, }, }, + { 24576000, 176400, .v = { 1280, 441, }, }, + { 24576000, 192000, .v = { 8, 3, }, }, + { 24576000, 352800, .v = { 640, 441, }, }, + { 24576000, 384000, .v = { 4, 3, }, }, }; /* frm_size = 64 */ static const struct cs43130_clk_gen cs43130_64_clk_gen[] = { - {22579200, 32000, 441, 40,}, - {22579200, 44100, 8, 1,}, - {22579200, 48000, 147, 20,}, - {22579200, 88200, 4, 1,}, - {22579200, 96000, 147, 40,}, - {22579200, 176400, 2, 1,}, - {22579200, 192000, 147, 80,}, - {22579200, 352800, 1, 1,}, - {24576000, 32000, 12, 1,}, - {24576000, 44100, 1280, 147,}, - {24576000, 48000, 8, 1,}, - {24576000, 88200, 640, 147,}, - {24576000, 96000, 4, 1,}, - {24576000, 176400, 320, 147,}, - {24576000, 192000, 2, 1,}, - {24576000, 352800, 160, 147,}, - {24576000, 384000, 1, 1,}, + { 22579200, 32000, .v = { 441, 40, }, }, + { 22579200, 44100, .v = { 8, 1, }, }, + { 22579200, 48000, .v = { 147, 20, }, }, + { 22579200, 88200, .v = { 4, 1, }, }, + { 22579200, 96000, .v = { 147, 40, }, }, + { 22579200, 176400, .v = { 2, 1, }, }, + { 22579200, 192000, .v = { 147, 80, }, }, + { 22579200, 352800, .v = { 1, 1, }, }, + { 24576000, 32000, .v = { 12, 1, }, }, + { 24576000, 44100, .v = { 1280, 147, }, }, + { 24576000, 48000, .v = { 8, 1, }, }, + { 24576000, 88200, .v = { 640, 147, }, }, + { 24576000, 96000, .v = { 4, 1, }, }, + { 24576000, 176400, .v = { 320, 147, }, }, + { 24576000, 192000, .v = { 2, 1, }, }, + { 24576000, 352800, .v = { 160, 147, }, }, + { 24576000, 384000, .v = { 1, 1, }, }, }; struct cs43130_bitwidth_map { diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c index 29d05e32d3..ac16960348 100644 --- a/sound/soc/codecs/cs4341.c +++ b/sound/soc/codecs/cs4341.c @@ -202,7 +202,6 @@ static const struct snd_soc_component_driver soc_component_cs4341 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id __maybe_unused cs4341_dt_ids[] = { @@ -225,8 +224,7 @@ static int cs4341_probe(struct device *dev) } #if IS_ENABLED(CONFIG_I2C) -static int cs4341_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int cs4341_i2c_probe(struct i2c_client *i2c) { struct cs4341_priv *cs4341; @@ -260,7 +258,7 @@ static struct i2c_driver cs4341_i2c_driver = { .name = "cs4341-i2c", .of_match_table = of_match_ptr(cs4341_dt_ids), }, - .probe = cs4341_i2c_probe, + .probe_new = cs4341_i2c_probe, .id_table = cs4341_i2c_id, }; #endif diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 786c69a8ec..f7c5c2fd43 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -223,12 +223,9 @@ static const struct snd_soc_dapm_route cs4349_routes[] = { {"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 | \ +#define CS4349_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE) #define CS4349_PCM_RATES SNDRV_PCM_RATE_8000_192000 @@ -263,7 +260,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs4349 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs4349_regmap = { @@ -278,8 +274,7 @@ static const struct regmap_config cs4349_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int cs4349_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cs4349_i2c_probe(struct i2c_client *client) { struct cs4349_private *cs4349; int ret; @@ -382,7 +377,7 @@ static struct i2c_driver cs4349_i2c_driver = { .pm = &cs4349_runtime_pm, }, .id_table = cs4349_i2c_id, - .probe = cs4349_i2c_probe, + .probe_new = cs4349_i2c_probe, .remove = cs4349_i2c_remove, }; diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c index 391fd7da33..06c4214382 100644 --- a/sound/soc/codecs/cs47l15.c +++ b/sound/soc/codecs/cs47l15.c @@ -122,6 +122,9 @@ static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol, snd_soc_kcontrol_component(kcontrol); struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + if (!!ucontrol->value.integer.value[0] == cs47l15->in1_lp_mode) + return 0; + switch (ucontrol->value.integer.value[0]) { case 0: /* Set IN1 to normal mode */ @@ -150,7 +153,7 @@ static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol, break; } - return 0; + return 1; } static const struct snd_kcontrol_new cs47l15_snd_controls[] = { @@ -1353,7 +1356,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l15 = { .num_dapm_routes = ARRAY_SIZE(cs47l15_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs47l15_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 6356f81aaf..f9a2b865d7 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1203,7 +1203,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l24 = { .num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs47l24_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index db2f844b8b..c1032d6c91 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -1638,7 +1638,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l35 = { .num_dapm_routes = ARRAY_SIZE(cs47l35_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs47l35_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c index d4fedc5ad5..215d8211aa 100644 --- a/sound/soc/codecs/cs47l85.c +++ b/sound/soc/codecs/cs47l85.c @@ -2582,7 +2582,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l85 = { .num_dapm_routes = ARRAY_SIZE(cs47l85_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs47l85_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index 5aec937a24..1ad6526c78 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -2497,7 +2497,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l90 = { .num_dapm_routes = ARRAY_SIZE(cs47l90_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs47l90_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c index a1b8dcdb9f..fe576d64e0 100644 --- a/sound/soc/codecs/cs47l92.c +++ b/sound/soc/codecs/cs47l92.c @@ -119,7 +119,13 @@ static int cs47l92_put_demux(struct snd_kcontrol *kcontrol, end: snd_soc_dapm_mutex_unlock(dapm); - return snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); + ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); + if (ret < 0) { + dev_err(madera->dev, "Failed to update demux power state: %d\n", ret); + return ret; + } + + return change; } static SOC_ENUM_SINGLE_DECL(cs47l92_outdemux_enum, @@ -1958,7 +1964,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l92 = { .num_dapm_routes = ARRAY_SIZE(cs47l92_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs47l92_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index f2087bd38d..8796d8e84b 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -348,22 +348,22 @@ static const struct snd_kcontrol_new cs53l30_snd_controls[] = { SOC_ENUM("ADC2 NG Delay", adc2_ng_delay_enum), SOC_SINGLE_SX_TLV("ADC1A PGA Volume", - CS53L30_ADC1A_AFE_CTL, 0, 0x34, 0x18, pga_tlv), + CS53L30_ADC1A_AFE_CTL, 0, 0x34, 0x24, pga_tlv), SOC_SINGLE_SX_TLV("ADC1B PGA Volume", - CS53L30_ADC1B_AFE_CTL, 0, 0x34, 0x18, pga_tlv), + CS53L30_ADC1B_AFE_CTL, 0, 0x34, 0x24, pga_tlv), SOC_SINGLE_SX_TLV("ADC2A PGA Volume", - CS53L30_ADC2A_AFE_CTL, 0, 0x34, 0x18, pga_tlv), + CS53L30_ADC2A_AFE_CTL, 0, 0x34, 0x24, pga_tlv), SOC_SINGLE_SX_TLV("ADC2B PGA Volume", - CS53L30_ADC2B_AFE_CTL, 0, 0x34, 0x18, pga_tlv), + CS53L30_ADC2B_AFE_CTL, 0, 0x34, 0x24, pga_tlv), SOC_SINGLE_SX_TLV("ADC1A Digital Volume", - CS53L30_ADC1A_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv), + CS53L30_ADC1A_DIG_VOL, 0, 0xA0, 0x6C, dig_tlv), SOC_SINGLE_SX_TLV("ADC1B Digital Volume", - CS53L30_ADC1B_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv), + CS53L30_ADC1B_DIG_VOL, 0, 0xA0, 0x6C, dig_tlv), SOC_SINGLE_SX_TLV("ADC2A Digital Volume", - CS53L30_ADC2A_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv), + CS53L30_ADC2A_DIG_VOL, 0, 0xA0, 0x6C, dig_tlv), SOC_SINGLE_SX_TLV("ADC2B Digital Volume", - CS53L30_ADC2B_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv), + CS53L30_ADC2B_DIG_VOL, 0, 0xA0, 0x6C, dig_tlv), }; static const struct snd_soc_dapm_widget cs53l30_dapm_widgets[] = { @@ -899,7 +899,6 @@ static const struct snd_soc_component_driver cs53l30_driver = { .num_dapm_routes = ARRAY_SIZE(cs53l30_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct regmap_config cs53l30_regmap = { @@ -918,8 +917,7 @@ static struct regmap_config cs53l30_regmap = { .use_single_write = true, }; -static int cs53l30_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cs53l30_i2c_probe(struct i2c_client *client) { const struct device_node *np = client->dev.of_node; struct device *dev = &client->dev; @@ -1125,7 +1123,7 @@ static struct i2c_driver cs53l30_i2c_driver = { .pm = &cs53l30_runtime_pm, }, .id_table = cs53l30_id, - .probe = cs53l30_i2c_probe, + .probe_new = cs53l30_i2c_probe, .remove = cs53l30_i2c_remove, }; diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 1af0bf5f1e..43c0cac0ec 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -411,7 +411,6 @@ static const struct snd_soc_component_driver cx20442_component_dev = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cx20442_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 1f5c57fab1..b6667e8a60 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -710,22 +710,19 @@ static int cx2072x_config_i2spcm(struct cx2072x_priv *cx2072x) regdbt2.ulval = 0xac; - /* set master/slave */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: reg2.r.tx_master = 1; reg3.r.rx_master = 1; - dev_dbg(dev, "Sets Master mode\n"); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg2.r.tx_master = 0; reg3.r.rx_master = 0; - dev_dbg(dev, "Sets Slave mode\n"); break; default: - dev_err(dev, "Unsupported DAI master mode\n"); + dev_err(dev, "Unsupported DAI clocking mode\n"); return -EINVAL; } @@ -1009,9 +1006,9 @@ static int cx2072x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) dev_dbg(dev, "set_dai_fmt- %08x\n", fmt); /* set master/slave */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_CBC_CFC: break; default: @@ -1527,6 +1524,7 @@ static const struct snd_soc_component_driver soc_codec_driver_cx2072x = { .num_dapm_widgets = ARRAY_SIZE(cx2072x_dapm_widgets), .dapm_routes = cx2072x_intercon, .num_dapm_routes = ARRAY_SIZE(cx2072x_intercon), + .endianness = 1, }; /* @@ -1626,8 +1624,7 @@ static int __maybe_unused cx2072x_runtime_resume(struct device *dev) return clk_prepare_enable(cx2072x->mclk); } -static int cx2072x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int cx2072x_i2c_probe(struct i2c_client *i2c) { struct cx2072x_priv *cx2072x; unsigned int ven_id, rev_id; @@ -1710,7 +1707,7 @@ static struct i2c_driver cx2072x_i2c_driver = { .acpi_match_table = ACPI_PTR(cx2072x_acpi_match), .pm = &cx2072x_runtime_pm, }, - .probe = cx2072x_i2c_probe, + .probe_new = cx2072x_i2c_probe, .remove = cx2072x_i2c_remove, .id_table = cx2072x_i2c_id, }; diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 8af344b2fd..f838466bfe 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1173,7 +1173,6 @@ static const struct snd_soc_component_driver soc_component_dev_da7210 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #if IS_ENABLED(CONFIG_I2C) @@ -1206,8 +1205,7 @@ static const struct regmap_config da7210_regmap_config_i2c = { .cache_type = REGCACHE_RBTREE, }; -static int da7210_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da7210_i2c_probe(struct i2c_client *i2c) { struct da7210_priv *da7210; int ret; @@ -1250,7 +1248,7 @@ static struct i2c_driver da7210_i2c_driver = { .driver = { .name = "da7210", }, - .probe = da7210_i2c_probe, + .probe_new = da7210_i2c_probe, .id_table = da7210_i2c_id, }; #endif @@ -1336,6 +1334,8 @@ static int __init da7210_modinit(void) int ret = 0; #if IS_ENABLED(CONFIG_I2C) ret = i2c_add_driver(&da7210_i2c_driver); + if (ret) + return ret; #endif #if defined(CONFIG_SPI_MASTER) ret = spi_register_driver(&da7210_spi_driver); diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 3ab89387b4..544ccbcfc8 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1922,7 +1922,6 @@ static const struct snd_soc_component_driver soc_component_dev_da7213 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config da7213_regmap_config = { @@ -1946,8 +1945,7 @@ static const char *da7213_supply_names[DA7213_NUM_SUPPLIES] = { [DA7213_SUPPLY_VDDIO] = "VDDIO", }; -static int da7213_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da7213_i2c_probe(struct i2c_client *i2c) { struct da7213_priv *da7213; int i, ret; @@ -2040,7 +2038,7 @@ static struct i2c_driver da7213_i2c_driver = { .acpi_match_table = ACPI_PTR(da7213_acpi_match), .pm = &da7213_pm, }, - .probe = da7213_i2c_probe, + .probe_new = da7213_i2c_probe, .id_table = da7213_i2c_id, }; diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index ea426d986d..91372909d1 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -3040,7 +3040,6 @@ static const struct snd_soc_component_driver soc_component_dev_da7218 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; @@ -3258,8 +3257,19 @@ static const struct regmap_config da7218_regmap_config = { * I2C layer */ -static int da7218_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id da7218_i2c_id[]; + +static inline int da7218_i2c_get_id(struct i2c_client *i2c) +{ + const struct i2c_device_id *id = i2c_match_id(da7218_i2c_id, i2c); + + if (id) + return (uintptr_t)id->driver_data; + else + return -EINVAL; +} + +static int da7218_i2c_probe(struct i2c_client *i2c) { struct da7218_priv *da7218; int ret; @@ -3273,7 +3283,7 @@ static int da7218_i2c_probe(struct i2c_client *i2c, if (i2c->dev.of_node) da7218->dev_id = da7218_of_get_id(&i2c->dev); else - da7218->dev_id = id->driver_data; + da7218->dev_id = da7218_i2c_get_id(i2c); if ((da7218->dev_id != DA7217_DEV_ID) && (da7218->dev_id != DA7218_DEV_ID)) { @@ -3311,7 +3321,7 @@ static struct i2c_driver da7218_i2c_driver = { .name = "da7218", .of_match_table = da7218_of_match, }, - .probe = da7218_i2c_probe, + .probe_new = da7218_i2c_probe, .id_table = da7218_i2c_id, }; diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 7998fdd3b3..bba73c44c2 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -60,6 +60,9 @@ static void da7219_aad_btn_det_work(struct work_struct *work) bool micbias_up = false; int retries = 0; + /* Disable ground switch */ + snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00); + /* Drive headphones/lineout */ snd_soc_component_update_bits(component, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK, @@ -153,6 +156,9 @@ static void da7219_aad_hptest_work(struct work_struct *work) tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC); } + /* Disable ground switch */ + snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00); + /* Ensure gain ramping at fastest rate */ gain_ramp_ctrl = snd_soc_component_read(component, DA7219_GAIN_RAMP_CTRL); snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8); @@ -428,6 +434,10 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data) mask |= DA7219_AAD_REPORT_ALL_MASK; da7219_aad->jack_inserted = false; + /* Cancel any pending work */ + cancel_work_sync(&da7219_aad->btn_det_work); + cancel_work_sync(&da7219_aad->hptest_work); + /* Un-drive headphones/lineout */ snd_soc_component_update_bits(component, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK, 0); @@ -444,9 +454,8 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data) snd_soc_dapm_disable_pin(dapm, "Mic Bias"); snd_soc_dapm_sync(dapm); - /* Cancel any pending work */ - cancel_work_sync(&da7219_aad->btn_det_work); - cancel_work_sync(&da7219_aad->hptest_work); + /* Enable ground switch */ + snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01); } } @@ -899,6 +908,9 @@ int da7219_aad_init(struct snd_soc_component *component) snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, DA7219_BUTTON_CONFIG_MASK, 0); + /* Enable ground switch */ + snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01); + INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work); INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work); diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index c7493549a9..50ecf30e61 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -2647,7 +2647,6 @@ static const struct snd_soc_component_driver soc_component_dev_da7219 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; @@ -2655,8 +2654,7 @@ static const struct snd_soc_component_driver soc_component_dev_da7219 = { * I2C layer */ -static int da7219_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da7219_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct da7219_priv *da7219; @@ -2694,11 +2692,6 @@ static int da7219_i2c_probe(struct i2c_client *i2c, return ret; } -static int da7219_i2c_remove(struct i2c_client *client) -{ - return 0; -} - static const struct i2c_device_id da7219_i2c_id[] = { { "da7219", }, { } @@ -2711,8 +2704,7 @@ static struct i2c_driver da7219_i2c_driver = { .of_match_table = of_match_ptr(da7219_of_match), .acpi_match_table = ACPI_PTR(da7219_acpi_match), }, - .probe = da7219_i2c_probe, - .remove = da7219_i2c_remove, + .probe_new = da7219_i2c_probe, .id_table = da7219_i2c_id, }; diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 42d6a3fc3a..2c5b0b7420 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1503,11 +1503,9 @@ static const struct snd_soc_component_driver soc_component_dev_da732x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int da732x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da732x_i2c_probe(struct i2c_client *i2c) { struct da732x_priv *da732x; unsigned int reg; @@ -1547,11 +1545,6 @@ static int da732x_i2c_probe(struct i2c_client *i2c, return ret; } -static int da732x_i2c_remove(struct i2c_client *client) -{ - return 0; -} - static const struct i2c_device_id da732x_i2c_id[] = { { "da7320", 0}, { } @@ -1562,8 +1555,7 @@ static struct i2c_driver da732x_i2c_driver = { .driver = { .name = "da7320", }, - .probe = da732x_i2c_probe, - .remove = da732x_i2c_remove, + .probe_new = da732x_i2c_probe, .id_table = da732x_i2c_id, }; diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index a9676b2611..28043b4530 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -1460,7 +1460,6 @@ static const struct snd_soc_component_driver soc_component_dev_da9055 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config da9055_regmap_config = { @@ -1473,8 +1472,7 @@ static const struct regmap_config da9055_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int da9055_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da9055_i2c_probe(struct i2c_client *i2c) { struct da9055_priv *da9055; struct da9055_platform_data *pdata = dev_get_platdata(&i2c->dev); @@ -1533,7 +1531,7 @@ static struct i2c_driver da9055_i2c_driver = { .name = "da9055-codec", .of_match_table = of_match_ptr(da9055_of_match), }, - .probe = da9055_i2c_probe, + .probe_new = da9055_i2c_probe, .id_table = da9055_i2c_id, }; diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 5d079d90fd..4fd6f97e5a 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -82,7 +82,10 @@ static struct snd_soc_dai_driver dmic_dai = { .rates = SNDRV_PCM_RATE_CONTINUOUS, .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE - | SNDRV_PCM_FMTBIT_S16_LE, + | SNDRV_PCM_FMTBIT_S16_LE + | SNDRV_PCM_FMTBIT_DSD_U8 + | SNDRV_PCM_FMTBIT_DSD_U16_LE + | SNDRV_PCM_FMTBIT_DSD_U32_LE, }, .ops = &dmic_dai_ops, }; @@ -137,7 +140,6 @@ static const struct snd_soc_component_driver soc_dmic = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int dmic_dev_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c index f443351677..f5150d2f95 100644 --- a/sound/soc/codecs/es7134.c +++ b/sound/soc/codecs/es7134.c @@ -213,7 +213,6 @@ static const struct snd_soc_component_driver es7134_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver es7154_dai = { diff --git a/sound/soc/codecs/es7241.c b/sound/soc/codecs/es7241.c index 0baa86241c..339553cfbb 100644 --- a/sound/soc/codecs/es7241.c +++ b/sound/soc/codecs/es7241.c @@ -232,7 +232,6 @@ static const struct snd_soc_component_driver es7241_component_driver = { .num_dapm_routes = ARRAY_SIZE(es7241_dapm_routes), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static void es7241_parse_fmt(struct device *dev, struct es7241_data *priv) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index ff33eab6f9..de7185f73e 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -401,10 +401,8 @@ static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai, u8 clksw; u8 mask; - if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { - dev_err(component->dev, "Codec driver only supports consumer mode\n"); - return -EINVAL; - } + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBP_CFP) + serdata1 |= ES8316_SERDATA1_MASTER; if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) { dev_err(component->dev, "Codec driver only supports I2S format\n"); @@ -464,6 +462,8 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); u8 wordlen = 0; + u8 bclk_divider; + u16 lrck_divider; int i; /* Validate supported sample rates that are autodetected from MCLK */ @@ -477,19 +477,24 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream, } if (i == NR_SUPPORTED_MCLK_LRCK_RATIOS) return -EINVAL; - + lrck_divider = es8316->sysclk / params_rate(params); + bclk_divider = lrck_divider / 4; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: wordlen = ES8316_SERDATA2_LEN_16; + bclk_divider /= 16; break; case SNDRV_PCM_FORMAT_S20_3LE: wordlen = ES8316_SERDATA2_LEN_20; + bclk_divider /= 20; break; case SNDRV_PCM_FORMAT_S24_LE: wordlen = ES8316_SERDATA2_LEN_24; + bclk_divider /= 24; break; case SNDRV_PCM_FORMAT_S32_LE: wordlen = ES8316_SERDATA2_LEN_32; + bclk_divider /= 32; break; default: return -EINVAL; @@ -499,6 +504,11 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream, ES8316_SERDATA2_LEN_MASK, wordlen); snd_soc_component_update_bits(component, ES8316_SERDATA_ADC, ES8316_SERDATA2_LEN_MASK, wordlen); + snd_soc_component_update_bits(component, ES8316_SERDATA1, 0x1f, bclk_divider); + snd_soc_component_update_bits(component, ES8316_CLKMGR_ADCDIV1, 0x0f, lrck_divider >> 8); + snd_soc_component_update_bits(component, ES8316_CLKMGR_ADCDIV2, 0xff, lrck_divider & 0xff); + snd_soc_component_update_bits(component, ES8316_CLKMGR_DACDIV1, 0x0f, lrck_divider >> 8); + snd_soc_component_update_bits(component, ES8316_CLKMGR_DACDIV2, 0xff, lrck_divider & 0xff); return 0; } @@ -769,7 +779,6 @@ static const struct snd_soc_component_driver soc_component_dev_es8316 = { .num_dapm_routes = ARRAY_SIZE(es8316_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_range es8316_volatile_ranges[] = { @@ -789,8 +798,7 @@ static const struct regmap_config es8316_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int es8316_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int es8316_i2c_probe(struct i2c_client *i2c_client) { struct device *dev = &i2c_client->dev; struct es8316_priv *es8316; @@ -852,7 +860,7 @@ static struct i2c_driver es8316_i2c_driver = { .acpi_match_table = ACPI_PTR(es8316_acpi_match), .of_match_table = of_match_ptr(es8316_of_match), }, - .probe = es8316_i2c_probe, + .probe_new = es8316_i2c_probe, .id_table = es8316_i2c_id, }; module_i2c_driver(es8316_i2c_driver); diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c index 6b0df0d750..68072e99fc 100644 --- a/sound/soc/codecs/es8328-i2c.c +++ b/sound/soc/codecs/es8328-i2c.c @@ -29,8 +29,7 @@ static const struct of_device_id es8328_of_match[] = { }; MODULE_DEVICE_TABLE(of, es8328_of_match); -static int es8328_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int es8328_i2c_probe(struct i2c_client *i2c) { return es8328_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &es8328_regmap_config)); @@ -41,7 +40,7 @@ static struct i2c_driver es8328_i2c_driver = { .name = "es8328", .of_match_table = es8328_of_match, }, - .probe = es8328_i2c_probe, + .probe_new = es8328_i2c_probe, .id_table = es8328_id, }; diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 3f00ead970..160adc706c 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -161,13 +161,16 @@ static int es8328_put_deemph(struct snd_kcontrol *kcontrol, if (deemph > 1) return -EINVAL; + if (es8328->deemph == deemph) + return 0; + ret = es8328_set_deemph(component); if (ret < 0) return ret; es8328->deemph = deemph; - return 0; + return 1; } @@ -841,7 +844,6 @@ static const struct snd_soc_component_driver es8328_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; int es8328_probe(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c index e1235e695b..c6b1e77ffc 100644 --- a/sound/soc/codecs/gtm601.c +++ b/sound/soc/codecs/gtm601.c @@ -73,7 +73,6 @@ static const struct snd_soc_component_driver soc_component_dev_gtm601 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int gtm601_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index a9f61c7e44..8debcee592 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -571,13 +571,14 @@ static const struct snd_soc_dapm_widget hdac_hda_dapm_widgets[] = { }; static const struct snd_soc_component_driver hdac_hda_codec = { - .probe = hdac_hda_codec_probe, - .remove = hdac_hda_codec_remove, - .idle_bias_on = false, - .dapm_widgets = hdac_hda_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(hdac_hda_dapm_widgets), - .dapm_routes = hdac_hda_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(hdac_hda_dapm_routes), + .probe = hdac_hda_codec_probe, + .remove = hdac_hda_codec_remove, + .dapm_widgets = hdac_hda_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(hdac_hda_dapm_widgets), + .dapm_routes = hdac_hda_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(hdac_hda_dapm_routes), + .idle_bias_on = false, + .endianness = 1, }; static int hdac_hda_dev_probe(struct hdac_device *hdev) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 66408a9829..cb23650ad5 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2058,7 +2058,6 @@ static const struct snd_soc_component_driver hdmi_hda_codec = { .remove = hdmi_codec_remove, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static void hdac_hdmi_get_chmap(struct hdac_device *hdev, int pcm_idx, diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index b07607a9ec..5679102de9 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -606,18 +606,18 @@ static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, /* Reset daifmt */ memset(cf, 0, sizeof(*cf)); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - cf->bit_clk_master = 1; - cf->frame_clk_master = 1; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + cf->bit_clk_provider = 1; + cf->frame_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBS_CFM: - cf->frame_clk_master = 1; + case SND_SOC_DAIFMT_CBC_CFP: + cf->frame_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBM_CFS: - cf->bit_clk_master = 1; + case SND_SOC_DAIFMT_CBP_CFC: + cf->bit_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -727,10 +727,8 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ SNDRV_PCM_RATE_192000) -#define SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ - 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) +#define SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) /* * This list is only for formats allowed on the I2S bus. So there is @@ -740,12 +738,9 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { * problems, we should add the video side driver an option to disable * them. */ -#define I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ - 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 | SNDRV_PCM_FMTBIT_S32_BE |\ - SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) +#define I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) static struct snd_kcontrol_new hdmi_codec_controls[] = { { @@ -982,7 +977,6 @@ static const struct snd_soc_component_driver hdmi_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, .set_jack = hdmi_codec_set_jack, }; diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c index de4c8460ab..58a3822547 100644 --- a/sound/soc/codecs/ics43432.c +++ b/sound/soc/codecs/ics43432.c @@ -41,7 +41,6 @@ static const struct snd_soc_component_driver ics43432_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ics43432_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c index ca0f4c1911..8222cde6e3 100644 --- a/sound/soc/codecs/inno_rk3036.c +++ b/sound/soc/codecs/inno_rk3036.c @@ -387,7 +387,6 @@ static const struct snd_soc_component_driver rk3036_codec_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rk3036_codec_regmap_config = { diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 1d86b6a0eb..50105d72b2 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -1095,7 +1095,6 @@ static const struct snd_soc_component_driver soc_component_dev_isabelle = { .num_dapm_routes = ARRAY_SIZE(isabelle_intercon), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config isabelle_regmap_config = { @@ -1108,8 +1107,7 @@ static const struct regmap_config isabelle_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int isabelle_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int isabelle_i2c_probe(struct i2c_client *i2c) { struct regmap *isabelle_regmap; int ret = 0; @@ -1144,7 +1142,7 @@ static struct i2c_driver isabelle_i2c_driver = { .driver = { .name = "isabelle", }, - .probe = isabelle_i2c_probe, + .probe_new = isabelle_i2c_probe, .id_table = isabelle_i2c_id, }; diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 081485f784..7c25acf6ff 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -291,8 +291,6 @@ static const struct snd_soc_component_driver soc_codec_dev_jz4740_codec = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, - }; static const struct regmap_config jz4740_codec_regmap_config = { diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index 300b325e2f..dba161305d 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -115,8 +115,7 @@ static const struct regmap_config lm4857_regmap_config = { .num_reg_defaults = ARRAY_SIZE(lm4857_default_regs), }; -static int lm4857_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int lm4857_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; @@ -138,7 +137,7 @@ static struct i2c_driver lm4857_i2c_driver = { .driver = { .name = "lm4857", }, - .probe = lm4857_i2c_probe, + .probe_new = lm4857_i2c_probe, .id_table = lm4857_i2c_id, }; diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 973d781b4b..a2e782cc42 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1399,7 +1399,6 @@ static const struct snd_soc_component_driver soc_component_dev_lm49453 = { .num_dapm_routes = ARRAY_SIZE(lm49453_audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config lm49453_regmap_config = { @@ -1412,8 +1411,7 @@ static const struct regmap_config lm49453_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int lm49453_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int lm49453_i2c_probe(struct i2c_client *i2c) { struct lm49453_priv *lm49453; int ret = 0; @@ -1443,11 +1441,6 @@ static int lm49453_i2c_probe(struct i2c_client *i2c, return ret; } -static int lm49453_i2c_remove(struct i2c_client *client) -{ - return 0; -} - static const struct i2c_device_id lm49453_i2c_id[] = { { "lm49453", 0 }, { } @@ -1458,8 +1451,7 @@ static struct i2c_driver lm49453_i2c_driver = { .driver = { .name = "lm49453", }, - .probe = lm49453_i2c_probe, - .remove = lm49453_i2c_remove, + .probe_new = lm49453_i2c_probe, .id_table = lm49453_i2c_id, }; diff --git a/sound/soc/codecs/lochnagar-sc.c b/sound/soc/codecs/lochnagar-sc.c index 54426a90bc..13fbd8830b 100644 --- a/sound/soc/codecs/lochnagar-sc.c +++ b/sound/soc/codecs/lochnagar-sc.c @@ -212,12 +212,12 @@ static struct snd_soc_dai_driver lochnagar_sc_dai[] = { }; static const struct snd_soc_component_driver lochnagar_sc_driver = { - .non_legacy_dai_naming = 1, - .dapm_widgets = lochnagar_sc_widgets, .num_dapm_widgets = ARRAY_SIZE(lochnagar_sc_widgets), .dapm_routes = lochnagar_sc_routes, .num_dapm_routes = ARRAY_SIZE(lochnagar_sc_routes), + + .endianness = 1, }; static int lochnagar_sc_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c index 6cede75ed3..1b9082d237 100644 --- a/sound/soc/codecs/lpass-macro-common.c +++ b/sound/soc/codecs/lpass-macro-common.c @@ -24,42 +24,45 @@ struct lpass_macro *lpass_macro_pds_init(struct device *dev) return ERR_PTR(-ENOMEM); l_pds->macro_pd = dev_pm_domain_attach_by_name(dev, "macro"); - if (IS_ERR_OR_NULL(l_pds->macro_pd)) - return NULL; - - ret = pm_runtime_get_sync(l_pds->macro_pd); - if (ret < 0) { - pm_runtime_put_noidle(l_pds->macro_pd); + if (IS_ERR_OR_NULL(l_pds->macro_pd)) { + ret = l_pds->macro_pd ? PTR_ERR(l_pds->macro_pd) : -ENODATA; goto macro_err; } + ret = pm_runtime_resume_and_get(l_pds->macro_pd); + if (ret < 0) + goto macro_sync_err; + l_pds->dcodec_pd = dev_pm_domain_attach_by_name(dev, "dcodec"); - if (IS_ERR_OR_NULL(l_pds->dcodec_pd)) + if (IS_ERR_OR_NULL(l_pds->dcodec_pd)) { + ret = l_pds->dcodec_pd ? PTR_ERR(l_pds->dcodec_pd) : -ENODATA; goto dcodec_err; + } - ret = pm_runtime_get_sync(l_pds->dcodec_pd); - if (ret < 0) { - pm_runtime_put_noidle(l_pds->dcodec_pd); + ret = pm_runtime_resume_and_get(l_pds->dcodec_pd); + if (ret < 0) goto dcodec_sync_err; - } return l_pds; dcodec_sync_err: dev_pm_domain_detach(l_pds->dcodec_pd, false); dcodec_err: pm_runtime_put(l_pds->macro_pd); -macro_err: +macro_sync_err: dev_pm_domain_detach(l_pds->macro_pd, false); +macro_err: return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(lpass_macro_pds_init); void lpass_macro_pds_exit(struct lpass_macro *pds) { - pm_runtime_put(pds->macro_pd); - dev_pm_domain_detach(pds->macro_pd, false); - pm_runtime_put(pds->dcodec_pd); - dev_pm_domain_detach(pds->dcodec_pd, false); + if (pds) { + pm_runtime_put(pds->macro_pd); + dev_pm_domain_detach(pds->macro_pd, false); + pm_runtime_put(pds->dcodec_pd); + dev_pm_domain_detach(pds->dcodec_pd, false); + } } EXPORT_SYMBOL_GPL(lpass_macro_pds_exit); diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index d18b56e604..1ea10dc707 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -199,6 +199,7 @@ struct va_macro { struct clk *mclk; struct clk *macro; struct clk *dcodec; + struct clk *fsgen; struct clk_hw hw; struct lpass_macro *pds; @@ -467,9 +468,9 @@ static int va_macro_mclk_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - return va_macro_mclk_enable(va, true); + return clk_prepare_enable(va->fsgen); case SND_SOC_DAPM_POST_PMD: - return va_macro_mclk_enable(va, false); + clk_disable_unprepare(va->fsgen); } return 0; @@ -1473,6 +1474,12 @@ static int va_macro_probe(struct platform_device *pdev) if (ret) goto err_clkout; + va->fsgen = clk_hw_get_clk(&va->hw, "fsgen"); + if (IS_ERR(va->fsgen)) { + ret = PTR_ERR(va->fsgen); + goto err_clkout; + } + ret = devm_snd_soc_register_component(dev, &va_macro_component_drv, va_macro_dais, ARRAY_SIZE(va_macro_dais)); diff --git a/sound/soc/codecs/ma120x0p.c b/sound/soc/codecs/ma120x0p.c index ac812e8317..2434305635 100644 --- a/sound/soc/codecs/ma120x0p.c +++ b/sound/soc/codecs/ma120x0p.c @@ -894,13 +894,13 @@ static SOC_VALUE_ENUM_SINGLE_DECL(pwr_mode_ctrl, pwr_mode_values); static const DECLARE_TLV_DB_SCALE(ma120x0p_vol_tlv, -5000, 100, 0); -static const DECLARE_TLV_DB_SCALE(ma120x0p_lim_tlv, -5000, 100, 0); +static const DECLARE_TLV_DB_SCALE(ma120x0p_lim_tlv, -14400, 100, 0); static const DECLARE_TLV_DB_SCALE(ma120x0p_lr_tlv, -5000, 100, 0); static const struct snd_kcontrol_new ma120x0p_snd_controls[] = { //Master Volume SOC_SINGLE_RANGE_TLV("A.Mstr Vol Volume", - ma_vol_db_master__a, 0, 0x18, 0x4a, 1, ma120x0p_vol_tlv), + ma_vol_db_master__a, 0, 0x18, 0xa8, 1, ma120x0p_vol_tlv), //L-R Volume ch0 SOC_SINGLE_RANGE_TLV("B.L Vol Volume", @@ -1179,7 +1179,6 @@ static const struct snd_soc_component_driver ma120x0p_component_driver = { .num_controls = ARRAY_SIZE(ma120x0p_snd_controls), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; //I2C Driver diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c index 272041c623..b9f19fbd29 100644 --- a/sound/soc/codecs/madera.c +++ b/sound/soc/codecs/madera.c @@ -618,7 +618,13 @@ int madera_out1_demux_put(struct snd_kcontrol *kcontrol, end: snd_soc_dapm_mutex_unlock(dapm); - return snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); + ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); + if (ret < 0) { + dev_err(madera->dev, "Failed to update demux power state: %d\n", ret); + return ret; + } + + return change; } EXPORT_SYMBOL_GPL(madera_out1_demux_put); @@ -893,7 +899,7 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; const int adsp_num = e->shift_l; const unsigned int item = ucontrol->value.enumerated.item[0]; - int ret; + int ret = 0; if (item >= e->items) return -EINVAL; @@ -910,10 +916,10 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol, "Cannot change '%s' while in use by active audio paths\n", kcontrol->id.name); ret = -EBUSY; - } else { + } else if (priv->adsp_rate_cache[adsp_num] != e->values[item]) { /* Volatile register so defer until the codec is powered up */ priv->adsp_rate_cache[adsp_num] = e->values[item]; - ret = 0; + ret = 1; } mutex_unlock(&priv->rate_lock); diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index 39dda1b03b..d711eb1da0 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -167,8 +167,7 @@ static const struct regmap_config max9768_i2c_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int max9768_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max9768_i2c_probe(struct i2c_client *client) { struct max9768 *max9768; struct max9768_pdata *pdata = client->dev.platform_data; @@ -215,7 +214,7 @@ static struct i2c_driver max9768_i2c_driver = { .driver = { .name = "max9768", }, - .probe = max9768_i2c_probe, + .probe_new = max9768_i2c_probe, .id_table = max9768_i2c_id, }; module_i2c_driver(max9768_i2c_driver); diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 429717d4ac..5435a49604 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1734,46 +1734,46 @@ static const struct snd_soc_component_driver soc_component_dev_max98088 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int max98088_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id max98088_i2c_id[] = { + { "max98088", MAX98088 }, + { "max98089", MAX98089 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); + +static int max98088_i2c_probe(struct i2c_client *i2c) { - struct max98088_priv *max98088; - int ret; + struct max98088_priv *max98088; + int ret; + const struct i2c_device_id *id; - max98088 = devm_kzalloc(&i2c->dev, sizeof(struct max98088_priv), - GFP_KERNEL); - if (max98088 == NULL) - return -ENOMEM; + max98088 = devm_kzalloc(&i2c->dev, sizeof(struct max98088_priv), + GFP_KERNEL); + if (max98088 == NULL) + return -ENOMEM; - max98088->regmap = devm_regmap_init_i2c(i2c, &max98088_regmap); - if (IS_ERR(max98088->regmap)) - return PTR_ERR(max98088->regmap); + max98088->regmap = devm_regmap_init_i2c(i2c, &max98088_regmap); + if (IS_ERR(max98088->regmap)) + return PTR_ERR(max98088->regmap); max98088->mclk = devm_clk_get(&i2c->dev, "mclk"); if (IS_ERR(max98088->mclk)) if (PTR_ERR(max98088->mclk) == -EPROBE_DEFER) return PTR_ERR(max98088->mclk); - max98088->devtype = id->driver_data; + id = i2c_match_id(max98088_i2c_id, i2c); + max98088->devtype = id->driver_data; - i2c_set_clientdata(i2c, max98088); - max98088->pdata = i2c->dev.platform_data; + i2c_set_clientdata(i2c, max98088); + max98088->pdata = i2c->dev.platform_data; - ret = devm_snd_soc_register_component(&i2c->dev, - &soc_component_dev_max98088, &max98088_dai[0], 2); - return ret; + ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_max98088, + &max98088_dai[0], 2); + return ret; } -static const struct i2c_device_id max98088_i2c_id[] = { - { "max98088", MAX98088 }, - { "max98089", MAX98089 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); - #if defined(CONFIG_OF) static const struct of_device_id max98088_of_match[] = { { .compatible = "maxim,max98088" }, @@ -1788,7 +1788,7 @@ static struct i2c_driver max98088_i2c_driver = { .name = "max98088", .of_match_table = of_match_ptr(max98088_of_match), }, - .probe = max98088_i2c_probe, + .probe_new = max98088_i2c_probe, .id_table = max98088_i2c_id, }; diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 62b41ca050..142083b13a 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -393,9 +393,11 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int mask = (1 << fls(mc->max)) - 1; - unsigned int sel = ucontrol->value.integer.value[0]; + int sel_unchecked = ucontrol->value.integer.value[0]; + unsigned int sel; unsigned int val = snd_soc_component_read(component, mc->reg); unsigned int *select; + int change; switch (mc->reg) { case M98090_REG_MIC1_INPUT_LEVEL: @@ -413,9 +415,11 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol, val = (val >> mc->shift) & mask; - if (sel < 0 || sel > mc->max) + if (sel_unchecked < 0 || sel_unchecked > mc->max) return -EINVAL; + sel = sel_unchecked; + change = *select != sel; *select = sel; /* Setting a volume is only valid if it is already On */ @@ -430,7 +434,7 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol, mask << mc->shift, sel << mc->shift); - return *select != val; + return change; } static const char *max98090_perf_pwr_text[] = @@ -1587,9 +1591,9 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, cdata->fmt = fmt; regval = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* Set to slave mode PLL - MAS mode off */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + /* Set to consumer mode PLL - MAS mode off */ snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_MSB, 0x00); snd_soc_component_write(component, @@ -1598,8 +1602,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, M98090_USE_M1_MASK, 0); max98090->master = false; break; - case SND_SOC_DAIFMT_CBM_CFM: - /* Set to master mode */ + case SND_SOC_DAIFMT_CBP_CFP: + /* Set to provider mode */ if (max98090->tdm_slots == 4) { /* TDM */ regval |= M98090_MAS_MASK | @@ -1615,8 +1619,6 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, } max98090->master = true; break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: default: dev_err(component->dev, "DAI clock mode unsupported"); return -EINVAL; @@ -2517,7 +2519,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98090 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98090_regmap = { @@ -2532,8 +2533,14 @@ static const struct regmap_config max98090_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max98090_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *i2c_id) +static const struct i2c_device_id max98090_i2c_id[] = { + { "max98090", MAX98090 }, + { "max98091", MAX98091 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); + +static int max98090_i2c_probe(struct i2c_client *i2c) { struct max98090_priv *max98090; const struct acpi_device_id *acpi_id; @@ -2555,7 +2562,9 @@ static int max98090_i2c_probe(struct i2c_client *i2c, return -EINVAL; } driver_data = acpi_id->driver_data; - } else if (i2c_id) { + } else { + const struct i2c_device_id *i2c_id = + i2c_match_id(max98090_i2c_id, i2c); driver_data = i2c_id->driver_data; } @@ -2662,13 +2671,6 @@ static const struct dev_pm_ops max98090_pm = { SET_SYSTEM_SLEEP_PM_OPS(NULL, max98090_resume) }; -static const struct i2c_device_id max98090_i2c_id[] = { - { "max98090", MAX98090 }, - { "max98091", MAX98091 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); - #ifdef CONFIG_OF static const struct of_device_id max98090_of_match[] = { { .compatible = "maxim,max98090", }, @@ -2693,7 +2695,7 @@ static struct i2c_driver max98090_i2c_driver = { .of_match_table = of_match_ptr(max98090_of_match), .acpi_match_table = ACPI_PTR(max98090_acpi_match), }, - .probe = max98090_i2c_probe, + .probe_new = max98090_i2c_probe, .shutdown = max98090_i2c_shutdown, .remove = max98090_i2c_remove, .id_table = max98090_i2c_id, diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 4977b00ddf..44aa58fcc2 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -2103,14 +2103,19 @@ static const struct snd_soc_component_driver soc_component_dev_max98095 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int max98095_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id max98095_i2c_id[] = { + { "max98095", MAX98095 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max98095_i2c_id); + +static int max98095_i2c_probe(struct i2c_client *i2c) { struct max98095_priv *max98095; int ret; + const struct i2c_device_id *id; max98095 = devm_kzalloc(&i2c->dev, sizeof(struct max98095_priv), GFP_KERNEL); @@ -2126,6 +2131,7 @@ static int max98095_i2c_probe(struct i2c_client *i2c, return ret; } + id = i2c_match_id(max98095_i2c_id, i2c); max98095->devtype = id->driver_data; i2c_set_clientdata(i2c, max98095); max98095->pdata = i2c->dev.platform_data; @@ -2136,12 +2142,6 @@ static int max98095_i2c_probe(struct i2c_client *i2c, return ret; } -static const struct i2c_device_id max98095_i2c_id[] = { - { "max98095", MAX98095 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, max98095_i2c_id); - #ifdef CONFIG_OF static const struct of_device_id max98095_of_match[] = { { .compatible = "maxim,max98095", }, @@ -2155,7 +2155,7 @@ static struct i2c_driver max98095_i2c_driver = { .name = "max98095", .of_match_table = of_match_ptr(max98095_of_match), }, - .probe = max98095_i2c_probe, + .probe_new = max98095_i2c_probe, .id_table = max98095_i2c_id, }; diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index 9188127638..2a2b286f17 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -93,7 +93,6 @@ static const struct snd_soc_component_driver max98357a_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops max98357a_dai_ops = { diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c index 8d42f523e4..bac9d1bcf6 100644 --- a/sound/soc/codecs/max98371.c +++ b/sound/soc/codecs/max98371.c @@ -351,7 +351,6 @@ static const struct snd_soc_component_driver max98371_component = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98371_regmap = { @@ -365,8 +364,7 @@ static const struct regmap_config max98371_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max98371_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98371_i2c_probe(struct i2c_client *i2c) { struct max98371_priv *max98371; int ret, reg; @@ -421,7 +419,7 @@ static struct i2c_driver max98371_i2c_driver = { .name = "max98371", .of_match_table = of_match_ptr(max98371_of_match), }, - .probe = max98371_i2c_probe, + .probe_new = max98371_i2c_probe, .id_table = max98371_i2c_id, }; diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c index ddb6436835..3e04c7f0cc 100644 --- a/sound/soc/codecs/max98373-i2c.c +++ b/sound/soc/codecs/max98373-i2c.c @@ -442,7 +442,6 @@ static bool max98373_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case MAX98373_R2000_SW_RESET ... MAX98373_R2009_INT_FLAG3: - case MAX98373_R203E_AMP_PATH_GAIN: case MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK: case MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK: case MAX98373_R20B6_BDE_CUR_STATE_READBACK: @@ -516,8 +515,7 @@ static const struct regmap_config max98373_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max98373_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98373_i2c_probe(struct i2c_client *i2c) { int ret = 0; int reg = 0; @@ -622,7 +620,7 @@ static struct i2c_driver max98373_i2c_driver = { .acpi_match_table = ACPI_PTR(max98373_acpi_match), .pm = &max98373_pm, }, - .probe = max98373_i2c_probe, + .probe_new = max98373_i2c_probe, .id_table = max98373_i2c_id, }; diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index f47e956d4f..97b64477dd 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -862,6 +862,16 @@ static int max98373_sdw_probe(struct sdw_slave *slave, return max98373_init(slave, regmap); } +static int max98373_sdw_remove(struct sdw_slave *slave) +{ + struct max98373_priv *max98373 = dev_get_drvdata(&slave->dev); + + if (max98373->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + #if defined(CONFIG_OF) static const struct of_device_id max98373_of_match[] = { { .compatible = "maxim,max98373", }, @@ -893,7 +903,7 @@ static struct sdw_driver max98373_sdw_driver = { .pm = &max98373_pm, }, .probe = max98373_sdw_probe, - .remove = NULL, + .remove = max98373_sdw_remove, .ops = &max98373_slave_ops, .id_table = max98373_id, }; diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index e14fe98349..f90a6a7ba8 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -436,12 +437,22 @@ const struct snd_soc_component_driver soc_codec_dev_max98373 = { .num_dapm_routes = ARRAY_SIZE(max98373_audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; EXPORT_SYMBOL_GPL(soc_codec_dev_max98373); +static int max98373_sdw_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + const struct snd_soc_component_driver soc_codec_dev_max98373_sdw = { - .probe = NULL, + .probe = max98373_sdw_probe, .controls = max98373_snd_controls, .num_controls = ARRAY_SIZE(max98373_snd_controls), .dapm_widgets = max98373_dapm_widgets, @@ -450,7 +461,6 @@ const struct snd_soc_component_driver soc_codec_dev_max98373_sdw = { .num_dapm_routes = ARRAY_SIZE(max98373_audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; EXPORT_SYMBOL_GPL(soc_codec_dev_max98373_sdw); diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index 40fd6f363f..5c08166a8d 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -983,7 +983,6 @@ static const struct snd_soc_component_driver soc_codec_dev_max98390 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98390_regmap = { @@ -1014,14 +1013,14 @@ static void max98390_slot_config(struct i2c_client *i2c, max98390->i_l_slot = 1; } -static int max98390_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98390_i2c_probe(struct i2c_client *i2c) { int ret = 0; int reg = 0; struct max98390_priv *max98390 = NULL; struct i2c_adapter *adapter = i2c->adapter; + struct gpio_desc *reset_gpio; ret = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE @@ -1073,6 +1072,17 @@ static int max98390_i2c_probe(struct i2c_client *i2c, return ret; } + reset_gpio = devm_gpiod_get_optional(&i2c->dev, + "reset", GPIOD_OUT_HIGH); + + /* Power on device */ + if (reset_gpio) { + usleep_range(1000, 2000); + /* bring out of reset */ + gpiod_set_value_cansleep(reset_gpio, 0); + usleep_range(1000, 2000); + } + /* Check Revision ID */ ret = regmap_read(max98390->regmap, MAX98390_R24FF_REV_ID, ®); @@ -1121,7 +1131,7 @@ static struct i2c_driver max98390_i2c_driver = { .acpi_match_table = ACPI_PTR(max98390_acpi_match), .pm = &max98390_pm, }, - .probe = max98390_i2c_probe, + .probe_new = max98390_i2c_probe, .id_table = max98390_i2c_id, }; diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index e073f0e029..a6733396b0 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -296,11 +296,9 @@ static const struct snd_soc_component_driver soc_component_dev_max9850 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int max9850_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max9850_i2c_probe(struct i2c_client *i2c) { struct max9850_priv *max9850; int ret; @@ -331,7 +329,7 @@ static struct i2c_driver max9850_i2c_driver = { .driver = { .name = "max9850", }, - .probe = max9850_i2c_probe, + .probe_new = max9850_i2c_probe, .id_table = max9850_i2c_id, }; diff --git a/sound/soc/codecs/max98504.c b/sound/soc/codecs/max98504.c index a5aa124c4a..0daa2a3dd6 100644 --- a/sound/soc/codecs/max98504.c +++ b/sound/soc/codecs/max98504.c @@ -291,6 +291,7 @@ static const struct snd_soc_component_driver max98504_component_driver = { .num_dapm_widgets = ARRAY_SIZE(max98504_dapm_widgets), .dapm_routes = max98504_dapm_routes, .num_dapm_routes = ARRAY_SIZE(max98504_dapm_routes), + .endianness = 1, }; static const struct regmap_config max98504_regmap = { @@ -304,8 +305,7 @@ static const struct regmap_config max98504_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max98504_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max98504_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device_node *node = dev->of_node; @@ -371,7 +371,7 @@ static struct i2c_driver max98504_i2c_driver = { .name = "max98504", .of_match_table = of_match_ptr(max98504_of_match), }, - .probe = max98504_i2c_probe, + .probe_new = max98504_i2c_probe, .id_table = max98504_i2c_id, }; module_i2c_driver(max98504_i2c_driver); diff --git a/sound/soc/codecs/max98520.c b/sound/soc/codecs/max98520.c index bb8649cd42..5edd6f90f8 100644 --- a/sound/soc/codecs/max98520.c +++ b/sound/soc/codecs/max98520.c @@ -657,7 +657,6 @@ static const struct snd_soc_component_driver soc_codec_dev_max98520 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98520_regmap = { @@ -677,7 +676,7 @@ static void max98520_power_on(struct max98520_priv *max98520, bool poweron) gpiod_set_value_cansleep(max98520->reset_gpio, !poweron); } -static int max98520_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +static int max98520_i2c_probe(struct i2c_client *i2c) { int ret; int reg = 0; @@ -757,7 +756,7 @@ static struct i2c_driver max98520_i2c_driver = { .of_match_table = of_match_ptr(max98520_of_match), .pm = &max98520_pm, }, - .probe = max98520_i2c_probe, + .probe_new = max98520_i2c_probe, .id_table = max98520_i2c_id, }; diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c index 82f20a8e27..771b3dcd6c 100644 --- a/sound/soc/codecs/max9860.c +++ b/sound/soc/codecs/max9860.c @@ -448,9 +448,9 @@ static int max9860_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct snd_soc_component *component = dai->component; struct max9860_priv *max9860 = snd_soc_component_get_drvdata(component); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_CBC_CFC: max9860->fmt = fmt; return 0; @@ -537,7 +537,6 @@ static const struct snd_soc_component_driver max9860_component_driver = { .num_dapm_routes = ARRAY_SIZE(max9860_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #ifdef CONFIG_PM diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index c2b1151c75..6d2941a9db 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -589,7 +589,6 @@ static const struct snd_soc_component_driver max9867_component = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static bool max9867_volatile_register(struct device *dev, unsigned int reg) @@ -613,8 +612,7 @@ static const struct regmap_config max9867_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max9867_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max9867_i2c_probe(struct i2c_client *i2c) { struct max9867_priv *max9867; int ret, reg; @@ -662,7 +660,7 @@ static struct i2c_driver max9867_i2c_driver = { .name = "max9867", .of_match_table = of_match_ptr(max9867_of_match), }, - .probe = max9867_i2c_probe, + .probe_new = max9867_i2c_probe, .id_table = max9867_i2c_id, }; diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 71fede9224..3bf86328d5 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -133,8 +133,7 @@ static const struct regmap_config max9877_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max9877_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max9877_i2c_probe(struct i2c_client *client) { struct regmap *regmap; int i; @@ -161,7 +160,7 @@ static struct i2c_driver max9877_i2c_driver = { .driver = { .name = "max9877", }, - .probe = max9877_i2c_probe, + .probe_new = max9877_i2c_probe, .id_table = max9877_i2c_id, }; diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index f34fa274ae..c24d9f2c88 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -544,7 +544,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98925 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98925_regmap = { @@ -558,8 +557,7 @@ static const struct regmap_config max98925_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max98925_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98925_i2c_probe(struct i2c_client *i2c) { int ret, reg; u32 value; @@ -637,7 +635,7 @@ static struct i2c_driver max98925_i2c_driver = { .name = "max98925", .of_match_table = of_match_ptr(max98925_of_match), }, - .probe = max98925_i2c_probe, + .probe_new = max98925_i2c_probe, .id_table = max98925_i2c_id, }; diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 1fbbc62bb0..bffd56e240 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -496,7 +496,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98926 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98926_regmap = { @@ -510,8 +509,7 @@ static const struct regmap_config max98926_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max98926_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98926_i2c_probe(struct i2c_client *i2c) { int ret, reg; u32 value; @@ -584,7 +582,7 @@ static struct i2c_driver max98926_i2c_driver = { .name = "max98926", .of_match_table = of_match_ptr(max98926_of_match), }, - .probe = max98926_i2c_probe, + .probe_new = max98926_i2c_probe, .id_table = max98926_i2c_id, }; diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index bf78d3c985..9cce7c0f01 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -832,7 +832,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98927 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98927_regmap = { @@ -863,8 +862,7 @@ static void max98927_slot_config(struct i2c_client *i2c, max98927->i_l_slot = 1; } -static int max98927_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98927_i2c_probe(struct i2c_client *i2c) { int ret = 0, value; @@ -977,7 +975,7 @@ static struct i2c_driver max98927_i2c_driver = { .acpi_match_table = ACPI_PTR(max98927_acpi_match), .pm = &max98927_pm, }, - .probe = max98927_i2c_probe, + .probe_new = max98927_i2c_probe, .remove = max98927_i2c_remove, .id_table = max98927_i2c_id, }; diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 08517547e6..71490f11d9 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -727,7 +727,6 @@ static const struct snd_soc_component_driver soc_component_dev_mc13783 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int __init mc13783_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 0823527e4a..3c6ac77379 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -537,7 +537,6 @@ static const struct snd_soc_component_driver soc_component_dev_ml26124 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ml26124_i2c_regmap = { @@ -550,8 +549,7 @@ static const struct regmap_config ml26124_i2c_regmap = { .write_flag_mask = 0x01, }; -static int ml26124_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ml26124_i2c_probe(struct i2c_client *i2c) { struct ml26124_priv *priv; int ret; @@ -583,7 +581,7 @@ static struct i2c_driver ml26124_i2c_driver = { .driver = { .name = "ml26124", }, - .probe = ml26124_i2c_probe, + .probe_new = ml26124_i2c_probe, .id_table = ml26124_i2c_id, }; diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index e52a559c52..78e543eb3c 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -1128,7 +1128,6 @@ static const struct snd_soc_component_driver pm8916_wcd_analog = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int pm8916_wcd_analog_parse_dt(struct device *dev, diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 20a07c92b2..d490a0f186 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -328,8 +328,8 @@ static const struct snd_kcontrol_new rx1_mix2_inp1_mux = SOC_DAPM_ENUM( static const struct snd_kcontrol_new rx2_mix2_inp1_mux = SOC_DAPM_ENUM( "RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum); -/* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */ -static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0); +/* Digital Gain control -84 dB to +40 dB in 1 dB steps */ +static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400); /* Cutoff Freq for High Pass Filter at -3dB */ static const char * const hpf_cutoff_text[] = { @@ -510,15 +510,15 @@ static int wcd_iir_filter_info(struct snd_kcontrol *kcontrol, static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = { SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_S8_TLV("TX1 Digital Volume", LPASS_CDC_TX1_VOL_CTL_GAIN, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_S8_TLV("TX2 Digital Volume", LPASS_CDC_TX2_VOL_CTL_GAIN, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_ENUM("TX1 HPF Cutoff", tx1_hpf_cutoff_enum), SOC_ENUM("TX2 HPF Cutoff", tx2_hpf_cutoff_enum), SOC_SINGLE("TX1 HPF Switch", LPASS_CDC_TX1_MUX_CTL, 3, 1, 0), @@ -553,22 +553,22 @@ static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = { WCD_IIR_FILTER_CTL("IIR2 Band3", IIR2, BAND3), WCD_IIR_FILTER_CTL("IIR2 Band4", IIR2, BAND4), WCD_IIR_FILTER_CTL("IIR2 Band5", IIR2, BAND5), - SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", LPASS_CDC_IIR1_GAIN_B1_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", LPASS_CDC_IIR1_GAIN_B2_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", LPASS_CDC_IIR1_GAIN_B3_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP4 Volume", LPASS_CDC_IIR1_GAIN_B4_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR2 INP1 Volume", LPASS_CDC_IIR2_GAIN_B1_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR2 INP2 Volume", LPASS_CDC_IIR2_GAIN_B2_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR2 INP3 Volume", LPASS_CDC_IIR2_GAIN_B3_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR2 INP4 Volume", LPASS_CDC_IIR2_GAIN_B4_CTL, - 0, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", LPASS_CDC_IIR1_GAIN_B1_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", LPASS_CDC_IIR1_GAIN_B2_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", LPASS_CDC_IIR1_GAIN_B3_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", LPASS_CDC_IIR1_GAIN_B4_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR2 INP1 Volume", LPASS_CDC_IIR2_GAIN_B1_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR2 INP2 Volume", LPASS_CDC_IIR2_GAIN_B2_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR2 INP3 Volume", LPASS_CDC_IIR2_GAIN_B3_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR2 INP4 Volume", LPASS_CDC_IIR2_GAIN_B4_CTL, + -84, 40, digital_gain), }; @@ -1155,7 +1155,6 @@ static const struct snd_soc_component_driver msm8916_wcd_digital = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config msm8916_codec_regmap_config = { diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c index 5c0536eb10..d2cf4847ee 100644 --- a/sound/soc/codecs/mt6351.c +++ b/sound/soc/codecs/mt6351.c @@ -282,12 +282,9 @@ static const struct snd_soc_dai_ops mt6351_codec_dai_ops = { .hw_params = mt6351_codec_dai_hw_params, }; -#define MT6351_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ - SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ - SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE) +#define MT6351_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) static struct snd_soc_dai_driver mt6351_dai_driver[] = { { @@ -1448,6 +1445,7 @@ static const struct snd_soc_component_driver mt6351_soc_component_driver = { .num_dapm_widgets = ARRAY_SIZE(mt6351_dapm_widgets), .dapm_routes = mt6351_dapm_routes, .num_dapm_routes = ARRAY_SIZE(mt6351_dapm_routes), + .endianness = 1, }; static int mt6351_codec_driver_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index 4c7b5d9407..93f35e8d26 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -2340,12 +2340,9 @@ static const struct snd_soc_dai_ops mt6358_codec_dai_ops = { .hw_params = mt6358_codec_dai_hw_params, }; -#define MT6358_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ - SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ - SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE) +#define MT6358_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) static struct snd_soc_dai_driver mt6358_dai_driver[] = { { @@ -2433,6 +2430,7 @@ static const struct snd_soc_component_driver mt6358_soc_component_driver = { .num_dapm_widgets = ARRAY_SIZE(mt6358_dapm_widgets), .dapm_routes = mt6358_dapm_routes, .num_dapm_routes = ARRAY_SIZE(mt6358_dapm_routes), + .endianness = 1, }; static void mt6358_parse_dt(struct mt6358_priv *priv) @@ -2481,6 +2479,7 @@ static int mt6358_platform_driver_probe(struct platform_device *pdev) static const struct of_device_id mt6358_of_match[] = { {.compatible = "mediatek,mt6358-sound",}, + {.compatible = "mediatek,mt6366-sound",}, {} }; MODULE_DEVICE_TABLE(of, mt6358_of_match); diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c index 6d3d170144..c190628e29 100644 --- a/sound/soc/codecs/mt6359-accdet.c +++ b/sound/soc/codecs/mt6359-accdet.c @@ -675,6 +675,7 @@ static int mt6359_accdet_parse_dt(struct mt6359_accdet *priv) sizeof(struct three_key_threshold)); } + of_node_put(node); dev_warn(priv->dev, "accdet caps=%x\n", priv->caps); return 0; diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c index f8532aa7e4..c9a453ce8a 100644 --- a/sound/soc/codecs/mt6359.c +++ b/sound/soc/codecs/mt6359.c @@ -2576,12 +2576,9 @@ static const struct snd_soc_dai_ops mt6359_codec_dai_ops = { .shutdown = mt6359_codec_dai_shutdown, }; -#define MT6359_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ - SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ - SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE) +#define MT6359_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) static struct snd_soc_dai_driver mt6359_dai_driver[] = { { @@ -2739,6 +2736,7 @@ static const struct snd_soc_component_driver mt6359_soc_component_driver = { .num_dapm_widgets = ARRAY_SIZE(mt6359_dapm_widgets), .dapm_routes = mt6359_dapm_routes, .num_dapm_routes = ARRAY_SIZE(mt6359_dapm_routes), + .endianness = 1, }; static int mt6359_parse_dt(struct mt6359_priv *priv) @@ -2780,6 +2778,7 @@ static int mt6359_parse_dt(struct mt6359_priv *priv) ret = of_property_read_u32(np, "mediatek,mic-type-2", &priv->mux_select[MUX_MIC_TYPE_2]); + of_node_put(np); if (ret) { dev_info(priv->dev, "%s() failed to read mic-type-2, use default (%d)\n", diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c index 3a881523c3..ba11555796 100644 --- a/sound/soc/codecs/mt6660.c +++ b/sound/soc/codecs/mt6660.c @@ -323,6 +323,7 @@ static const struct snd_soc_component_driver mt6660_component_driver = { .num_dapm_routes = ARRAY_SIZE(mt6660_component_dapm_routes), .idle_bias_on = false, /* idle_bias_off = true */ + .endianness = 1, }; static int mt6660_component_aif_hw_params(struct snd_pcm_substream *substream, @@ -456,8 +457,7 @@ static int _mt6660_read_chip_revision(struct mt6660_chip *chip) return 0; } -static int mt6660_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mt6660_i2c_probe(struct i2c_client *client) { struct mt6660_chip *chip = NULL; int ret; @@ -567,7 +567,7 @@ static struct i2c_driver mt6660_i2c_driver = { .of_match_table = of_match_ptr(mt6660_of_id), .pm = &mt6660_dev_pm_ops, }, - .probe = mt6660_i2c_probe, + .probe_new = mt6660_i2c_probe, .remove = mt6660_i2c_remove, .id_table = mt6660_i2c_id, }; diff --git a/sound/soc/codecs/nau8315.c b/sound/soc/codecs/nau8315.c index 2b66e3f7a8..ad4dce9e50 100644 --- a/sound/soc/codecs/nau8315.c +++ b/sound/soc/codecs/nau8315.c @@ -93,7 +93,6 @@ static const struct snd_soc_component_driver nau8315_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops nau8315_dai_ops = { diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index ace96995fe..58f70a02f1 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -806,7 +806,6 @@ static const struct snd_soc_component_driver nau8540_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config nau8540_regmap_config = { @@ -823,8 +822,7 @@ static const struct regmap_config nau8540_regmap_config = { .num_reg_defaults = ARRAY_SIZE(nau8540_reg_defaults), }; -static int nau8540_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8540_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8540 *nau8540 = dev_get_platdata(dev); @@ -874,7 +872,7 @@ static struct i2c_driver nau8540_i2c_driver = { .name = "nau8540", .of_match_table = of_match_ptr(nau8540_of_ids), }, - .probe = nau8540_i2c_probe, + .probe_new = nau8540_i2c_probe, .id_table = nau8540_i2c_ids, }; module_i2c_driver(nau8540_i2c_driver); diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index 13676b544f..ccb512c21d 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -866,11 +866,9 @@ static const struct snd_soc_component_driver nau8810_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int nau8810_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8810_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8810 *nau8810 = dev_get_platdata(dev); @@ -916,7 +914,7 @@ static struct i2c_driver nau8810_i2c_driver = { .name = "nau8810", .of_match_table = of_match_ptr(nau8810_of_match), }, - .probe = nau8810_i2c_probe, + .probe_new = nau8810_i2c_probe, .id_table = nau8810_i2c_id, }; diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c index d67dc27890..2d21339932 100644 --- a/sound/soc/codecs/nau8821.c +++ b/sound/soc/codecs/nau8821.c @@ -29,11 +29,14 @@ #define NAU_FVCO_MAX 100000000 #define NAU_FVCO_MIN 90000000 +#define NAU8821_BUTTON SND_JACK_BTN_0 + /* the maximum frequency of CLK_ADC and CLK_DAC */ #define CLK_DA_AD_MAX 6144000 static int nau8821_configure_sysclk(struct nau8821 *nau8821, int clk_id, unsigned int freq); +static bool nau8821_is_jack_inserted(struct regmap *regmap); struct nau8821_fll { int mclk_src; @@ -493,7 +496,33 @@ static int nau8821_output_dac_event(struct snd_soc_dapm_widget *w, return 0; } +static int system_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + dev_dbg(nau8821->dev, "system clock control : POWER OFF\n"); + /* Set clock source to disable or internal clock before the + * playback or capture end. Codec needs clock for Jack + * detection and button press if jack inserted; otherwise, + * the clock should be closed. + */ + if (nau8821_is_jack_inserted(nau8821->regmap)) { + nau8821_configure_sysclk(nau8821, + NAU8821_CLK_INTERNAL, 0); + } else { + nau8821_configure_sysclk(nau8821, NAU8821_CLK_DIS, 0); + } + } + return 0; +} + static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("System Clock", SND_SOC_NOPM, 0, 0, + system_clock_control, SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("MICBIAS", NAU8821_R74_MIC_BIAS, NAU8821_MICBIAS_POWERUP_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DMIC Clock", SND_SOC_NOPM, 0, 0, @@ -605,6 +634,9 @@ static const struct snd_soc_dapm_route nau8821_dapm_routes[] = { {"AIFTX", NULL, "ADCL Digital path"}, {"AIFTX", NULL, "ADCR Digital path"}, + {"AIFTX", NULL, "System Clock"}, + {"AIFRX", NULL, "System Clock"}, + {"DDACL", NULL, "AIFRX"}, {"DDACR", NULL, "AIFRX"}, @@ -911,6 +943,20 @@ static void nau8821_eject_jack(struct nau8821 *nau8821) /* Recover to normal channel input */ regmap_update_bits(regmap, NAU8821_R2B_ADC_RATE, NAU8821_ADC_R_SRC_EN, 0); + if (nau8821->key_enable) { + regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, + NAU8821_IRQ_KEY_RELEASE_EN | + NAU8821_IRQ_KEY_PRESS_EN, + NAU8821_IRQ_KEY_RELEASE_EN | + NAU8821_IRQ_KEY_PRESS_EN); + regmap_update_bits(regmap, + NAU8821_R12_INTERRUPT_DIS_CTRL, + NAU8821_IRQ_KEY_RELEASE_DIS | + NAU8821_IRQ_KEY_PRESS_DIS, + NAU8821_IRQ_KEY_RELEASE_DIS | + NAU8821_IRQ_KEY_PRESS_DIS); + } + } static void nau8821_jdet_work(struct work_struct *work) @@ -940,6 +986,15 @@ static void nau8821_jdet_work(struct work_struct *work) */ regmap_update_bits(regmap, NAU8821_R2B_ADC_RATE, NAU8821_ADC_R_SRC_EN, NAU8821_ADC_R_SRC_EN); + if (nau8821->key_enable) { + regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, + NAU8821_IRQ_KEY_RELEASE_EN | + NAU8821_IRQ_KEY_PRESS_EN, 0); + regmap_update_bits(regmap, + NAU8821_R12_INTERRUPT_DIS_CTRL, + NAU8821_IRQ_KEY_RELEASE_DIS | + NAU8821_IRQ_KEY_PRESS_DIS, 0); + } } else { dev_dbg(nau8821->dev, "Headphone connected\n"); event |= SND_JACK_HEADPHONE; @@ -999,6 +1054,13 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) nau8821_eject_jack(nau8821); event_mask |= SND_JACK_HEADSET; clear_irq = NAU8821_JACK_EJECT_IRQ_MASK; + } else if (active_irq & NAU8821_KEY_SHORT_PRESS_IRQ) { + event |= NAU8821_BUTTON; + event_mask |= NAU8821_BUTTON; + clear_irq = NAU8821_KEY_SHORT_PRESS_IRQ; + } else if (active_irq & NAU8821_KEY_RELEASE_IRQ) { + event_mask = NAU8821_BUTTON; + clear_irq = NAU8821_KEY_RELEASE_IRQ; } else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) == NAU8821_JACK_INSERT_DETECTED) { regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1, @@ -1430,7 +1492,6 @@ static const struct snd_soc_component_driver nau8821_component_driver = { .dapm_routes = nau8821_dapm_routes, .num_dapm_routes = ARRAY_SIZE(nau8821_dapm_routes), .suspend_bias_off = 1, - .non_legacy_dai_naming = 1, .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, @@ -1490,6 +1551,7 @@ static void nau8821_print_device_properties(struct nau8821 *nau8821) nau8821->jack_eject_debounce); dev_dbg(dev, "dmic-clk-threshold: %d\n", nau8821->dmic_clk_threshold); + dev_dbg(dev, "key_enable: %d\n", nau8821->key_enable); } static int nau8821_read_device_properties(struct device *dev, @@ -1503,6 +1565,8 @@ static int nau8821_read_device_properties(struct device *dev, "nuvoton,jkdet-pull-enable"); nau8821->jkdet_pull_up = device_property_read_bool(dev, "nuvoton,jkdet-pull-up"); + nau8821->key_enable = device_property_read_bool(dev, + "nuvoton,key-enable"); ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity", &nau8821->jkdet_polarity); if (ret) @@ -1626,8 +1690,7 @@ static int nau8821_setup_irq(struct nau8821 *nau8821) return 0; } -static int nau8821_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8821_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8821 *nau8821 = dev_get_platdata(&i2c->dev); @@ -1666,15 +1729,6 @@ static int nau8821_i2c_probe(struct i2c_client *i2c, return ret; } -static int nau8821_i2c_remove(struct i2c_client *i2c_client) -{ - struct nau8821 *nau8821 = i2c_get_clientdata(i2c_client); - - devm_free_irq(nau8821->dev, nau8821->irq, nau8821); - - return 0; -} - static const struct i2c_device_id nau8821_i2c_ids[] = { { "nau8821", 0 }, { } @@ -1703,8 +1757,7 @@ static struct i2c_driver nau8821_driver = { .of_match_table = of_match_ptr(nau8821_of_ids), .acpi_match_table = ACPI_PTR(nau8821_acpi_match), }, - .probe = nau8821_i2c_probe, - .remove = nau8821_i2c_remove, + .probe_new = nau8821_i2c_probe, .id_table = nau8821_i2c_ids, }; module_i2c_driver(nau8821_driver); diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h index a92edfeb9d..c44251f54d 100644 --- a/sound/soc/codecs/nau8821.h +++ b/sound/soc/codecs/nau8821.h @@ -525,6 +525,7 @@ struct nau8821 { int jack_eject_debounce; int fs; int dmic_clk_threshold; + int key_enable; }; int nau8821_enable_jack_detect(struct snd_soc_component *component, diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c index 58123390c7..1aef281a99 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c @@ -726,6 +726,17 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, struct nau8822_pll *pll_param = &nau8822->pll; int ret, fs; + if (freq_in == pll_param->freq_in && + freq_out == pll_param->freq_out) + return 0; + + if (freq_out == 0) { + dev_dbg(component->dev, "PLL disabled\n"); + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_OFF); + return 0; + } + fs = freq_out / 256; ret = nau8822_calc_pll(freq_in, fs, pll_param); @@ -740,6 +751,8 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, pll_param->pll_int, pll_param->pll_frac, pll_param->mclk_scaler, pll_param->pre_factor); + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_OFF); snd_soc_component_update_bits(component, NAU8822_REG_PLL_N, NAU8822_PLLMCLK_DIV2 | NAU8822_PLLN_MASK, (pll_param->pre_factor ? NAU8822_PLLMCLK_DIV2 : 0) | @@ -757,6 +770,11 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, pll_param->mclk_scaler << NAU8822_MCLKSEL_SFT); snd_soc_component_update_bits(component, NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, NAU8822_CLKM_PLL); + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_ON); + + pll_param->freq_in = freq_in; + pll_param->freq_out = freq_out; return 0; } @@ -1065,7 +1083,6 @@ static const struct snd_soc_component_driver soc_component_dev_nau8822 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config nau8822_regmap_config = { @@ -1083,8 +1100,7 @@ static const struct regmap_config nau8822_regmap_config = { .num_reg_defaults = ARRAY_SIZE(nau8822_reg_defaults), }; -static int nau8822_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8822_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8822 *nau8822 = dev_get_platdata(dev); @@ -1141,7 +1157,7 @@ static struct i2c_driver nau8822_i2c_driver = { .name = "nau8822", .of_match_table = of_match_ptr(nau8822_of_match), }, - .probe = nau8822_i2c_probe, + .probe_new = nau8822_i2c_probe, .id_table = nau8822_i2c_id, }; module_i2c_driver(nau8822_i2c_driver); diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h index 489191ff18..547ec057f8 100644 --- a/sound/soc/codecs/nau8822.h +++ b/sound/soc/codecs/nau8822.h @@ -90,6 +90,9 @@ #define NAU8822_REFIMP_3K 0x3 #define NAU8822_IOBUF_EN (0x1 << 2) #define NAU8822_ABIAS_EN (0x1 << 3) +#define NAU8822_PLL_EN_MASK (0x1 << 5) +#define NAU8822_PLL_ON (0x1 << 5) +#define NAU8822_PLL_OFF (0x0 << 5) /* NAU8822_REG_AUDIO_INTERFACE (0x4) */ #define NAU8822_AIFMT_MASK (0x3 << 3) @@ -195,6 +198,8 @@ struct nau8822_pll { int mclk_scaler; int pll_frac; int pll_int; + int freq_in; + int freq_out; }; /* Codec Private Data */ diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index d0dd1542f7..ad54d70f7d 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -1544,7 +1544,6 @@ static const struct snd_soc_component_driver nau8824_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops nau8824_dai_ops = { @@ -1910,8 +1909,7 @@ const char *nau8824_components(void) } EXPORT_SYMBOL_GPL(nau8824_components); -static int nau8824_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8824_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8824 *nau8824 = dev_get_platdata(dev); @@ -1985,7 +1983,7 @@ static struct i2c_driver nau8824_i2c_driver = { .of_match_table = of_match_ptr(nau8824_of_ids), .acpi_match_table = ACPI_PTR(nau8824_acpi_match), }, - .probe = nau8824_i2c_probe, + .probe_new = nau8824_i2c_probe, .id_table = nau8824_i2c_ids, }; module_i2c_driver(nau8824_i2c_driver); diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 7734bc35ab..54ef7b0fa8 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1440,7 +1440,7 @@ static struct snd_soc_dai_driver nau8825_dai = { .capture = { .stream_name = "Capture", .channels_min = 1, - .channels_max = 1, + .channels_max = 2, /* Only 1 channel of data */ .rates = NAU8825_RATES, .formats = NAU8825_FORMATS, }, @@ -2478,7 +2478,6 @@ static const struct snd_soc_component_driver nau8825_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static void nau8825_reset_chip(struct regmap *regmap) @@ -2613,8 +2612,7 @@ static int nau8825_setup_irq(struct nau8825 *nau8825) return 0; } -static int nau8825_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8825_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8825 *nau8825 = dev_get_platdata(&i2c->dev); @@ -2703,7 +2701,7 @@ static struct i2c_driver nau8825_driver = { .of_match_table = of_match_ptr(nau8825_of_ids), .acpi_match_table = ACPI_PTR(nau8825_acpi_match), }, - .probe = nau8825_i2c_probe, + .probe_new = nau8825_i2c_probe, .remove = nau8825_i2c_remove, .id_table = nau8825_i2c_ids, }; diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 9eb65f94fc..3591f6f539 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -290,7 +290,6 @@ static const struct snd_soc_component_driver soc_component_dev_pcm1681 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct i2c_device_id pcm1681_i2c_id[] = { @@ -299,8 +298,7 @@ static const struct i2c_device_id pcm1681_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, pcm1681_i2c_id); -static int pcm1681_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pcm1681_i2c_probe(struct i2c_client *client) { int ret; struct pcm1681_private *priv; @@ -329,7 +327,7 @@ static struct i2c_driver pcm1681_i2c_driver = { .of_match_table = of_match_ptr(pcm1681_dt_ids), }, .id_table = pcm1681_i2c_id, - .probe = pcm1681_i2c_probe, + .probe_new = pcm1681_i2c_probe, }; module_i2c_driver(pcm1681_i2c_driver); diff --git a/sound/soc/codecs/pcm1789-i2c.c b/sound/soc/codecs/pcm1789-i2c.c index 7a6be45f81..1d2f7480a6 100644 --- a/sound/soc/codecs/pcm1789-i2c.c +++ b/sound/soc/codecs/pcm1789-i2c.c @@ -12,8 +12,7 @@ #include "pcm1789.h" -static int pcm1789_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pcm1789_i2c_probe(struct i2c_client *client) { struct regmap *regmap; int ret; @@ -30,7 +29,9 @@ static int pcm1789_i2c_probe(struct i2c_client *client, static int pcm1789_i2c_remove(struct i2c_client *client) { - return pcm1789_common_exit(&client->dev); + pcm1789_common_exit(&client->dev); + + return 0; } #ifdef CONFIG_OF @@ -53,7 +54,7 @@ static struct i2c_driver pcm1789_i2c_driver = { .of_match_table = of_match_ptr(pcm1789_of_match), }, .id_table = pcm1789_i2c_ids, - .probe = pcm1789_i2c_probe, + .probe_new = pcm1789_i2c_probe, .remove = pcm1789_i2c_remove, }; diff --git a/sound/soc/codecs/pcm1789.c b/sound/soc/codecs/pcm1789.c index 620dec172c..3ab381e9a8 100644 --- a/sound/soc/codecs/pcm1789.c +++ b/sound/soc/codecs/pcm1789.c @@ -229,7 +229,6 @@ static const struct snd_soc_component_driver soc_component_dev_pcm1789 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; int pcm1789_common_init(struct device *dev, struct regmap *regmap) @@ -259,13 +258,11 @@ int pcm1789_common_init(struct device *dev, struct regmap *regmap) } EXPORT_SYMBOL_GPL(pcm1789_common_init); -int pcm1789_common_exit(struct device *dev) +void pcm1789_common_exit(struct device *dev) { struct pcm1789_private *priv = dev_get_drvdata(dev); flush_work(&priv->work); - - return 0; } EXPORT_SYMBOL_GPL(pcm1789_common_exit); diff --git a/sound/soc/codecs/pcm1789.h b/sound/soc/codecs/pcm1789.h index c446d789ed..79439c8322 100644 --- a/sound/soc/codecs/pcm1789.h +++ b/sound/soc/codecs/pcm1789.h @@ -12,6 +12,6 @@ extern const struct regmap_config pcm1789_regmap_config; int pcm1789_common_init(struct device *dev, struct regmap *regmap); -int pcm1789_common_exit(struct device *dev); +void pcm1789_common_exit(struct device *dev); #endif diff --git a/sound/soc/codecs/pcm179x-i2c.c b/sound/soc/codecs/pcm179x-i2c.c index 34a3d596f2..e20fe3a85a 100644 --- a/sound/soc/codecs/pcm179x-i2c.c +++ b/sound/soc/codecs/pcm179x-i2c.c @@ -14,8 +14,7 @@ #include "pcm179x.h" -static int pcm179x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pcm179x_i2c_probe(struct i2c_client *client) { struct regmap *regmap; int ret; @@ -50,7 +49,7 @@ static struct i2c_driver pcm179x_i2c_driver = { .of_match_table = of_match_ptr(pcm179x_of_match), }, .id_table = pcm179x_i2c_ids, - .probe = pcm179x_i2c_probe, + .probe_new = pcm179x_i2c_probe, }; module_i2c_driver(pcm179x_i2c_driver); diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c index ee60373d7d..f52ff66b6e 100644 --- a/sound/soc/codecs/pcm179x.c +++ b/sound/soc/codecs/pcm179x.c @@ -207,7 +207,6 @@ static const struct snd_soc_component_driver soc_component_dev_pcm179x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; int pcm179x_common_init(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/pcm186x-i2c.c b/sound/soc/codecs/pcm186x-i2c.c index f8382b7439..932c8d41c3 100644 --- a/sound/soc/codecs/pcm186x-i2c.c +++ b/sound/soc/codecs/pcm186x-i2c.c @@ -22,9 +22,18 @@ static const struct of_device_id pcm186x_of_match[] = { }; MODULE_DEVICE_TABLE(of, pcm186x_of_match); -static int pcm186x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id pcm186x_i2c_id[] = { + { "pcm1862", PCM1862 }, + { "pcm1863", PCM1863 }, + { "pcm1864", PCM1864 }, + { "pcm1865", PCM1865 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcm186x_i2c_id); + +static int pcm186x_i2c_probe(struct i2c_client *i2c) { + const struct i2c_device_id *id = i2c_match_id(pcm186x_i2c_id, i2c); const enum pcm186x_type type = (enum pcm186x_type)id->driver_data; int irq = i2c->irq; struct regmap *regmap; @@ -36,17 +45,8 @@ static int pcm186x_i2c_probe(struct i2c_client *i2c, return pcm186x_probe(&i2c->dev, type, irq, regmap); } -static const struct i2c_device_id pcm186x_i2c_id[] = { - { "pcm1862", PCM1862 }, - { "pcm1863", PCM1863 }, - { "pcm1864", PCM1864 }, - { "pcm1865", PCM1865 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, pcm186x_i2c_id); - static struct i2c_driver pcm186x_i2c_driver = { - .probe = pcm186x_i2c_probe, + .probe_new = pcm186x_i2c_probe, .id_table = pcm186x_i2c_id, .driver = { .name = "pcm186x", diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c index 2c78dccb3f..dd21803ba1 100644 --- a/sound/soc/codecs/pcm186x.c +++ b/sound/soc/codecs/pcm186x.c @@ -534,19 +534,14 @@ static int pcm186x_power_on(struct snd_soc_component *component) static int pcm186x_power_off(struct snd_soc_component *component) { struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component); - int ret; snd_soc_component_update_bits(component, PCM186X_POWER_CTRL, PCM186X_PWR_CTRL_PWRDN, PCM186X_PWR_CTRL_PWRDN); regcache_cache_only(priv->regmap, true); - ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies), + return regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); - if (ret) - return ret; - - return 0; } static int pcm186x_set_bias_level(struct snd_soc_component *component, @@ -583,7 +578,6 @@ static struct snd_soc_component_driver soc_codec_dev_pcm1863 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_component_driver soc_codec_dev_pcm1865 = { @@ -598,7 +592,6 @@ static struct snd_soc_component_driver soc_codec_dev_pcm1865 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static bool pcm186x_volatile(struct device *dev, unsigned int reg) diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index aef40ec40a..09c6c13268 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -102,7 +102,6 @@ static const struct snd_soc_component_driver soc_component_dev_pcm3008 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int pcm3008_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/pcm3060-i2c.c b/sound/soc/codecs/pcm3060-i2c.c index abcdeb9222..2388098eec 100644 --- a/sound/soc/codecs/pcm3060-i2c.c +++ b/sound/soc/codecs/pcm3060-i2c.c @@ -10,8 +10,7 @@ #include "pcm3060.h" -static int pcm3060_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int pcm3060_i2c_probe(struct i2c_client *i2c) { struct pcm3060_priv *priv; @@ -50,7 +49,7 @@ static struct i2c_driver pcm3060_i2c_driver = { #endif /* CONFIG_OF */ }, .id_table = pcm3060_i2c_id, - .probe = pcm3060_i2c_probe, + .probe_new = pcm3060_i2c_probe, }; module_i2c_driver(pcm3060_i2c_driver); diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c index 4e3bfb9fa4..586ec8c724 100644 --- a/sound/soc/codecs/pcm3060.c +++ b/sound/soc/codecs/pcm3060.c @@ -255,6 +255,7 @@ static const struct snd_soc_component_driver pcm3060_soc_comp_driver = { .num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets), .dapm_routes = pcm3060_dapm_map, .num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map), + .endianness = 1, }; /* regmap */ diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c index 1f75933e74..c0fa0dc80e 100644 --- a/sound/soc/codecs/pcm3168a-i2c.c +++ b/sound/soc/codecs/pcm3168a-i2c.c @@ -15,8 +15,7 @@ #include "pcm3168a.h" -static int pcm3168a_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int pcm3168a_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; @@ -47,7 +46,7 @@ static const struct of_device_id pcm3168a_of_match[] = { MODULE_DEVICE_TABLE(of, pcm3168a_of_match); static struct i2c_driver pcm3168a_i2c_driver = { - .probe = pcm3168a_i2c_probe, + .probe_new = pcm3168a_i2c_probe, .remove = pcm3168a_i2c_remove, .id_table = pcm3168a_i2c_id, .driver = { diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index cf27f05dc4..9d6431338f 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -716,7 +716,6 @@ static const struct snd_soc_component_driver pcm3168a_driver = { .num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; int pcm3168a_probe(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c index f39f98bbc9..3401a25341 100644 --- a/sound/soc/codecs/pcm5102a.c +++ b/sound/soc/codecs/pcm5102a.c @@ -28,7 +28,6 @@ static struct snd_soc_component_driver soc_component_dev_pcm5102a = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int pcm5102a_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c index 633f7ebe29..81754e141a 100644 --- a/sound/soc/codecs/pcm512x-i2c.c +++ b/sound/soc/codecs/pcm512x-i2c.c @@ -13,8 +13,7 @@ #include "pcm512x.h" -static int pcm512x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int pcm512x_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; struct regmap_config config = pcm512x_regmap; @@ -68,7 +67,7 @@ MODULE_DEVICE_TABLE(acpi, pcm512x_acpi_match); #endif static struct i2c_driver pcm512x_i2c_driver = { - .probe = pcm512x_i2c_probe, + .probe_new = pcm512x_i2c_probe, .remove = pcm512x_i2c_remove, .id_table = pcm512x_i2c_id, .driver = { diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index db5067bed2..c6cb2d6200 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1512,7 +1512,6 @@ static const struct snd_soc_component_driver pcm512x_component_driver = { .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_range_cfg pcm512x_range = { diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index 758d439e8c..1d523bfd9d 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -69,11 +69,11 @@ static int rk3328_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) snd_soc_component_get_drvdata(dai->component); unsigned int val; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: val = PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: val = PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER; break; default: @@ -481,7 +481,7 @@ static int rk3328_platform_probe(struct platform_device *pdev) ret = clk_prepare_enable(rk3328->pclk); if (ret < 0) { dev_err(&pdev->dev, "failed to enable acodec pclk\n"); - return ret; + goto err_unprepare_mclk; } base = devm_platform_ioremap_resource(pdev, 0); diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c index cce6f4e799..2a5b274bfc 100644 --- a/sound/soc/codecs/rk817_codec.c +++ b/sound/soc/codecs/rk817_codec.c @@ -444,7 +444,6 @@ static const struct snd_soc_component_driver soc_codec_dev_rk817 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, .controls = rk817_volume_controls, .num_controls = ARRAY_SIZE(rk817_volume_controls), .dapm_routes = rk817_dapm_routes, diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index b62301a628..c156821612 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -2176,7 +2176,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1011 = { .set_pll = rt1011_set_component_pll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt1011_regmap = { @@ -2433,8 +2432,7 @@ static int rt1011_parse_dp(struct rt1011_priv *rt1011, struct device *dev) return 0; } -static int rt1011_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt1011_i2c_probe(struct i2c_client *i2c) { struct rt1011_priv *rt1011; int ret; @@ -2485,7 +2483,7 @@ static struct i2c_driver rt1011_i2c_driver = { .of_match_table = of_match_ptr(rt1011_of_match), .acpi_match_table = ACPI_PTR(rt1011_acpi_match) }, - .probe = rt1011_i2c_probe, + .probe_new = rt1011_i2c_probe, .shutdown = rt1011_i2c_shutdown, .id_table = rt1011_i2c_id, }; diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 6a27dfacd8..57d0f1c69e 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -1071,7 +1071,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1015 = { .set_pll = rt1015_set_component_pll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt1015_regmap = { @@ -1113,8 +1112,7 @@ static void rt1015_parse_dt(struct rt1015_priv *rt1015, struct device *dev) &rt1015->pdata.power_up_delay_ms); } -static int rt1015_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt1015_i2c_probe(struct i2c_client *i2c) { struct rt1015_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt1015_priv *rt1015; @@ -1172,7 +1170,7 @@ static struct i2c_driver rt1015_i2c_driver = { .of_match_table = of_match_ptr(rt1015_of_match), .acpi_match_table = ACPI_PTR(rt1015_acpi_match), }, - .probe = rt1015_i2c_probe, + .probe_new = rt1015_i2c_probe, .shutdown = rt1015_i2c_shutdown, .id_table = rt1015_i2c_id, }; diff --git a/sound/soc/codecs/rt1015p.c b/sound/soc/codecs/rt1015p.c index 415cfb3b2f..06800dad87 100644 --- a/sound/soc/codecs/rt1015p.c +++ b/sound/soc/codecs/rt1015p.c @@ -89,7 +89,6 @@ static const struct snd_soc_component_driver rt1015p_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver rt1015p_dai_driver = { diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c index 9845cdddcb..37eeec650f 100644 --- a/sound/soc/codecs/rt1016.c +++ b/sound/soc/codecs/rt1016.c @@ -595,7 +595,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1016 = { .set_pll = rt1016_set_component_pll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt1016_regmap = { @@ -631,8 +630,7 @@ static const struct acpi_device_id rt1016_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt1016_acpi_match); #endif -static int rt1016_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt1016_i2c_probe(struct i2c_client *i2c) { struct rt1016_priv *rt1016; int ret; @@ -685,7 +683,7 @@ static struct i2c_driver rt1016_i2c_driver = { .of_match_table = of_match_ptr(rt1016_of_match), .acpi_match_table = ACPI_PTR(rt1016_acpi_match), }, - .probe = rt1016_i2c_probe, + .probe_new = rt1016_i2c_probe, .shutdown = rt1016_i2c_shutdown, .id_table = rt1016_i2c_id, }; diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c index 80b7ca0e4e..b66bfecbb8 100644 --- a/sound/soc/codecs/rt1019.c +++ b/sound/soc/codecs/rt1019.c @@ -515,14 +515,14 @@ static struct snd_soc_dai_driver rt1019_dai[] = { }; static const struct snd_soc_component_driver soc_component_dev_rt1019 = { - .probe = rt1019_probe, + .probe = rt1019_probe, .controls = rt1019_snd_controls, .num_controls = ARRAY_SIZE(rt1019_snd_controls), .dapm_widgets = rt1019_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(rt1019_dapm_widgets), .dapm_routes = rt1019_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt1019_dapm_routes), - .non_legacy_dai_naming = 1, + .endianness = 1, }; static const struct regmap_config rt1019_regmap = { @@ -558,8 +558,7 @@ static const struct acpi_device_id rt1019_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt1019_acpi_match); #endif -static int rt1019_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt1019_i2c_probe(struct i2c_client *i2c) { struct rt1019_priv *rt1019; int ret; @@ -599,7 +598,7 @@ static struct i2c_driver rt1019_i2c_driver = { .of_match_table = of_match_ptr(rt1019_of_match), .acpi_match_table = ACPI_PTR(rt1019_acpi_match), }, - .probe = rt1019_i2c_probe, + .probe_new = rt1019_i2c_probe, .id_table = rt1019_i2c_id, }; module_i2c_driver(rt1019_i2c_driver); diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c index a9c473537a..5b39a440b6 100644 --- a/sound/soc/codecs/rt1305.c +++ b/sound/soc/codecs/rt1305.c @@ -946,7 +946,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1305 = { .set_pll = rt1305_set_component_pll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt1305_regmap = { @@ -1117,8 +1116,7 @@ static void rt1305_calibrate(struct rt1305_priv *rt1305) regcache_cache_bypass(rt1305->regmap, false); } -static int rt1305_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt1305_i2c_probe(struct i2c_client *i2c) { struct rt1305_priv *rt1305; int ret; @@ -1172,7 +1170,7 @@ static struct i2c_driver rt1305_i2c_driver = { .acpi_match_table = ACPI_PTR(rt1305_acpi_match) #endif }, - .probe = rt1305_i2c_probe, + .probe_new = rt1305_i2c_probe, .shutdown = rt1305_i2c_shutdown, .id_table = rt1305_i2c_id, }; diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 1ef836a68a..0be6e72ff5 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -608,13 +608,26 @@ static const struct sdw_slave_ops rt1308_slave_ops = { .bus_config = rt1308_bus_config, }; +static int rt1308_sdw_component_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_component_sdw_rt1308 = { + .probe = rt1308_sdw_component_probe, .controls = rt1308_snd_controls, .num_controls = ARRAY_SIZE(rt1308_snd_controls), .dapm_widgets = rt1308_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(rt1308_dapm_widgets), .dapm_routes = rt1308_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt1308_dapm_routes), + .endianness = 1, }; static const struct snd_soc_dai_ops rt1308_aif_dai_ops = { @@ -690,6 +703,16 @@ static int rt1308_sdw_probe(struct sdw_slave *slave, return 0; } +static int rt1308_sdw_remove(struct sdw_slave *slave) +{ + struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev); + + if (rt1308->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + static const struct sdw_device_id rt1308_id[] = { SDW_SLAVE_ENTRY_EXT(0x025d, 0x1308, 0x2, 0, 0), {}, @@ -749,6 +772,7 @@ static struct sdw_driver rt1308_sdw_driver = { .pm = &rt1308_pm, }, .probe = rt1308_sdw_probe, + .remove = rt1308_sdw_remove, .ops = &rt1308_slave_ops, .id_table = rt1308_id, }; diff --git a/sound/soc/codecs/rt1308-sdw.h b/sound/soc/codecs/rt1308-sdw.h index c5ce75666d..6668e19d85 100644 --- a/sound/soc/codecs/rt1308-sdw.h +++ b/sound/soc/codecs/rt1308-sdw.h @@ -140,6 +140,7 @@ static const struct reg_default rt1308_reg_defaults[] = { { 0x3008, 0x02 }, { 0x300a, 0x00 }, { 0xc003 | (RT1308_DAC_SET << 4), 0x00 }, + { 0xc000 | (RT1308_POWER << 4), 0x00 }, { 0xc001 | (RT1308_POWER << 4), 0x00 }, { 0xc002 | (RT1308_POWER << 4), 0x00 }, }; diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index c555b77b3c..d2a8e9fe3e 100644 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -765,7 +765,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1308 = { .set_pll = rt1308_set_component_pll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt1308_regmap = { @@ -814,8 +813,7 @@ static void rt1308_efuse(struct rt1308_priv *rt1308) regmap_write(rt1308->regmap, RT1308_PVDD_OFFSET_CTL, 0x10000000); } -static int rt1308_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt1308_i2c_probe(struct i2c_client *i2c) { struct rt1308_priv *rt1308; int ret; @@ -864,7 +862,7 @@ static struct i2c_driver rt1308_i2c_driver = { .of_match_table = of_match_ptr(rt1308_of_match), .acpi_match_table = ACPI_PTR(rt1308_acpi_match), }, - .probe = rt1308_i2c_probe, + .probe_new = rt1308_i2c_probe, .shutdown = rt1308_i2c_shutdown, .id_table = rt1308_i2c_id, }; diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index c66d7b20cb..e53396606a 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -590,13 +590,26 @@ static struct sdw_slave_ops rt1316_slave_ops = { .update_status = rt1316_update_status, }; +static int rt1316_sdw_component_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_component_sdw_rt1316 = { + .probe = rt1316_sdw_component_probe, .controls = rt1316_snd_controls, .num_controls = ARRAY_SIZE(rt1316_snd_controls), .dapm_widgets = rt1316_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(rt1316_dapm_widgets), .dapm_routes = rt1316_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt1316_dapm_routes), + .endianness = 1, }; static const struct snd_soc_dai_ops rt1316_aif_dai_ops = { @@ -675,6 +688,16 @@ static int rt1316_sdw_probe(struct sdw_slave *slave, return rt1316_sdw_init(&slave->dev, regmap, slave); } +static int rt1316_sdw_remove(struct sdw_slave *slave) +{ + struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev); + + if (rt1316->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + static const struct sdw_device_id rt1316_id[] = { SDW_SLAVE_ENTRY_EXT(0x025d, 0x1316, 0x3, 0x1, 0), {}, @@ -734,6 +757,7 @@ static struct sdw_driver rt1316_sdw_driver = { .pm = &rt1316_pm, }, .probe = rt1316_sdw_probe, + .remove = rt1316_sdw_remove, .ops = &rt1316_slave_ops, .id_table = rt1316_id, }; diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index 0d3773c576..f2c50b11e4 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -980,14 +980,11 @@ static int rt274_probe(struct snd_soc_component *component) struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component); rt274->component = component; + INIT_DELAYED_WORK(&rt274->jack_detect_work, rt274_jack_detect_work); - if (rt274->i2c->irq) { - INIT_DELAYED_WORK(&rt274->jack_detect_work, - rt274_jack_detect_work); + if (rt274->i2c->irq) schedule_delayed_work(&rt274->jack_detect_work, - msecs_to_jiffies(1250)); - } - + msecs_to_jiffies(1250)); return 0; } @@ -996,6 +993,7 @@ static void rt274_remove(struct snd_soc_component *component) struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component); cancel_delayed_work_sync(&rt274->jack_detect_work); + rt274->component = NULL; } #ifdef CONFIG_PM @@ -1075,7 +1073,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt274 = { .num_dapm_routes = ARRAY_SIZE(rt274_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt274_regmap = { @@ -1114,8 +1111,7 @@ static const struct acpi_device_id rt274_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt274_acpi_match); #endif -static int rt274_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt274_i2c_probe(struct i2c_client *i2c) { struct rt274_priv *rt274; @@ -1227,7 +1223,7 @@ static struct i2c_driver rt274_i2c_driver = { .of_match_table = of_match_ptr(rt274_of_match), #endif }, - .probe = rt274_i2c_probe, + .probe_new = rt274_i2c_probe, .remove = rt274_i2c_remove, .id_table = rt274_i2c_id, }; diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index caa720884e..c4f7c4c2d7 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -311,7 +311,8 @@ static void rt286_jack_detect_work(struct work_struct *work) SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); } -int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack) +static int rt286_mic_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component); @@ -335,7 +336,6 @@ int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *j return 0; } -EXPORT_SYMBOL_GPL(rt286_mic_detect); static int is_mclk_mode(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) @@ -947,17 +947,11 @@ static int rt286_probe(struct snd_soc_component *component) struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component); rt286->component = component; + INIT_DELAYED_WORK(&rt286->jack_detect_work, rt286_jack_detect_work); - if (rt286->i2c->irq) { - regmap_update_bits(rt286->regmap, - RT286_IRQ_CTRL, 0x2, 0x2); - - INIT_DELAYED_WORK(&rt286->jack_detect_work, - rt286_jack_detect_work); + if (rt286->i2c->irq) schedule_delayed_work(&rt286->jack_detect_work, - msecs_to_jiffies(1250)); - } - + msecs_to_jiffies(50)); return 0; } @@ -966,6 +960,7 @@ static void rt286_remove(struct snd_soc_component *component) struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component); cancel_delayed_work_sync(&rt286->jack_detect_work); + rt286->component = NULL; } #ifdef CONFIG_PM @@ -1055,6 +1050,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt286 = { .suspend = rt286_suspend, .resume = rt286_resume, .set_bias_level = rt286_set_bias_level, + .set_jack = rt286_mic_detect, .controls = rt286_snd_controls, .num_controls = ARRAY_SIZE(rt286_snd_controls), .dapm_widgets = rt286_dapm_widgets, @@ -1063,7 +1059,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt286 = { .num_dapm_routes = ARRAY_SIZE(rt286_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt286_regmap = { @@ -1134,8 +1129,7 @@ static const struct dmi_system_id dmi_dell[] = { { } }; -static int rt286_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt286_i2c_probe(struct i2c_client *i2c) { struct rt286_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt286_priv *rt286; @@ -1271,7 +1265,7 @@ static struct i2c_driver rt286_i2c_driver = { .name = "rt286", .acpi_match_table = ACPI_PTR(rt286_acpi_match), }, - .probe = rt286_i2c_probe, + .probe_new = rt286_i2c_probe, .remove = rt286_i2c_remove, .id_table = rt286_i2c_id, }; diff --git a/sound/soc/codecs/rt286.h b/sound/soc/codecs/rt286.h index f27a4e71d5..4b7a3bd604 100644 --- a/sound/soc/codecs/rt286.h +++ b/sound/soc/codecs/rt286.h @@ -196,7 +196,5 @@ enum { RT286_AIFS, }; -int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack); - #endif /* __RT286_H__ */ diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index c592c40a7a..b0b53d4f07 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -326,39 +326,37 @@ static void rt298_jack_detect_work(struct work_struct *work) SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); } -int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack) +static int rt298_mic_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) { + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component); - struct snd_soc_dapm_context *dapm; - bool hp = false; - bool mic = false; - int status = 0; - /* If jack in NULL, disable HS jack */ - if (!jack) { + rt298->jack = jack; + + if (jack) { + /* Enable IRQ */ + if (rt298->jack->status & SND_JACK_HEADPHONE) + snd_soc_dapm_force_enable_pin(dapm, "LDO1"); + if (rt298->jack->status & SND_JACK_MICROPHONE) { + snd_soc_dapm_force_enable_pin(dapm, "HV"); + snd_soc_dapm_force_enable_pin(dapm, "VREF"); + } + regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); + /* Send an initial empty report */ + snd_soc_jack_report(rt298->jack, rt298->jack->status, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + } else { + /* Disable IRQ */ regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x0); - dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_disable_pin(dapm, "HV"); + snd_soc_dapm_disable_pin(dapm, "VREF"); snd_soc_dapm_disable_pin(dapm, "LDO1"); - snd_soc_dapm_sync(dapm); - return 0; } - - rt298->jack = jack; - regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); - - rt298_jack_detect(rt298, &hp, &mic); - if (hp) - status |= SND_JACK_HEADPHONE; - - if (mic) - status |= SND_JACK_MICROPHONE; - - snd_soc_jack_report(rt298->jack, status, - SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + snd_soc_dapm_sync(dapm); 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) @@ -1011,17 +1009,11 @@ static int rt298_probe(struct snd_soc_component *component) struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component); rt298->component = component; + INIT_DELAYED_WORK(&rt298->jack_detect_work, rt298_jack_detect_work); - 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); + if (rt298->i2c->irq) schedule_delayed_work(&rt298->jack_detect_work, - msecs_to_jiffies(1250)); - } - + msecs_to_jiffies(1250)); return 0; } @@ -1030,6 +1022,7 @@ static void rt298_remove(struct snd_soc_component *component) struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component); cancel_delayed_work_sync(&rt298->jack_detect_work); + rt298->component = NULL; } #ifdef CONFIG_PM @@ -1120,6 +1113,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt298 = { .suspend = rt298_suspend, .resume = rt298_resume, .set_bias_level = rt298_set_bias_level, + .set_jack = rt298_mic_detect, .controls = rt298_snd_controls, .num_controls = ARRAY_SIZE(rt298_snd_controls), .dapm_widgets = rt298_dapm_widgets, @@ -1128,7 +1122,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt298 = { .num_dapm_routes = ARRAY_SIZE(rt298_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt298_regmap = { @@ -1176,8 +1169,7 @@ static const struct dmi_system_id force_combo_jack_table[] = { { } }; -static int rt298_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt298_i2c_probe(struct i2c_client *i2c) { struct rt298_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt298_priv *rt298; @@ -1314,7 +1306,7 @@ static struct i2c_driver rt298_i2c_driver = { .name = "rt298", .acpi_match_table = ACPI_PTR(rt298_acpi_match), }, - .probe = rt298_i2c_probe, + .probe_new = rt298_i2c_probe, .remove = rt298_i2c_remove, .id_table = rt298_i2c_id, }; diff --git a/sound/soc/codecs/rt298.h b/sound/soc/codecs/rt298.h index ed2b8fd87f..f1be9c1354 100644 --- a/sound/soc/codecs/rt298.h +++ b/sound/soc/codecs/rt298.h @@ -207,7 +207,5 @@ enum { RT298_AIFS, }; -int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack); - #endif /* __RT298_H__ */ diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 577680df70..b9bcf04d4d 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -419,7 +419,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, } } - return 0; + return 1; } static const struct snd_kcontrol_new rt5514_snd_controls[] = { @@ -1173,7 +1173,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5514 = { .num_dapm_routes = ARRAY_SIZE(rt5514_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5514_i2c_regmap = { @@ -1252,8 +1251,7 @@ static __maybe_unused int rt5514_i2c_resume(struct device *dev) return 0; } -static int rt5514_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5514_i2c_probe(struct i2c_client *i2c) { struct rt5514_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5514_priv *rt5514; @@ -1330,7 +1328,7 @@ static struct i2c_driver rt5514_i2c_driver = { .of_match_table = of_match_ptr(rt5514_of_match), .pm = &rt5514_i2_pm_ops, }, - .probe = rt5514_i2c_probe, + .probe_new = rt5514_i2c_probe, .id_table = rt5514_i2c_id, }; module_i2c_driver(rt5514_i2c_driver); diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index 8e6414468a..970d6c4a35 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1304,7 +1304,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5616 = { .num_dapm_routes = ARRAY_SIZE(rt5616_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5616_regmap = { @@ -1337,8 +1336,7 @@ static const struct of_device_id rt5616_of_match[] = { MODULE_DEVICE_TABLE(of, rt5616_of_match); #endif -static int rt5616_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5616_i2c_probe(struct i2c_client *i2c) { struct rt5616_priv *rt5616; unsigned int val; @@ -1408,7 +1406,7 @@ static struct i2c_driver rt5616_i2c_driver = { .name = "rt5616", .of_match_table = of_match_ptr(rt5616_of_match), }, - .probe = rt5616_i2c_probe, + .probe_new = rt5616_i2c_probe, .remove = rt5616_i2c_remove, .shutdown = rt5616_i2c_shutdown, .id_table = rt5616_i2c_id, diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 38356ea2bd..957f6b19be 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1666,7 +1666,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5631 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct i2c_device_id rt5631_i2c_id[] = { @@ -1699,8 +1698,7 @@ static const struct regmap_config rt5631_regmap_config = { .use_single_write = true, }; -static int rt5631_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5631_i2c_probe(struct i2c_client *i2c) { struct rt5631_priv *rt5631; int ret; @@ -1732,7 +1730,7 @@ static struct i2c_driver rt5631_i2c_driver = { .name = "rt5631", .of_match_table = of_match_ptr(rt5631_i2c_dt_ids), }, - .probe = rt5631_i2c_probe, + .probe_new = rt5631_i2c_probe, .remove = rt5631_i2c_remove, .id_table = rt5631_i2c_id, }; diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 30c2e7cb7e..5a84432980 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1984,7 +1984,12 @@ static int rt5640_set_bias_level(struct snd_soc_component *component, snd_soc_component_write(component, RT5640_PWR_DIG2, 0x0000); snd_soc_component_write(component, RT5640_PWR_VOL, 0x0000); snd_soc_component_write(component, RT5640_PWR_MIXER, 0x0000); - snd_soc_component_write(component, RT5640_PWR_ANLG1, 0x0000); + if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) + snd_soc_component_write(component, RT5640_PWR_ANLG1, + 0x2818); + else + snd_soc_component_write(component, RT5640_PWR_ANLG1, + 0x0000); snd_soc_component_write(component, RT5640_PWR_ANLG2, 0x0000); break; @@ -2094,12 +2099,14 @@ EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src); void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); snd_soc_dapm_mutex_lock(dapm); snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2"); snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1"); /* OVCD is unreliable when used with RCCLK as sysclk-source */ - snd_soc_dapm_force_enable_pin_unlocked(dapm, "Platform Clock"); + if (rt5640->use_platform_clock) + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Platform Clock"); snd_soc_dapm_sync_unlocked(dapm); snd_soc_dapm_mutex_unlock(dapm); } @@ -2108,9 +2115,11 @@ EXPORT_SYMBOL_GPL(rt5640_enable_micbias1_for_ovcd); void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); snd_soc_dapm_mutex_lock(dapm); - snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock"); + if (rt5640->use_platform_clock) + snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock"); snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1"); snd_soc_dapm_disable_pin_unlocked(dapm, "LDO2"); snd_soc_dapm_sync_unlocked(dapm); @@ -2389,9 +2398,15 @@ static void rt5640_jack_work(struct work_struct *work) static irqreturn_t rt5640_irq(int irq, void *data) { struct rt5640_priv *rt5640 = data; + int delay = 0; + + if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) { + cancel_delayed_work_sync(&rt5640->jack_work); + delay = 100; + } if (rt5640->jack) - queue_delayed_work(system_long_wq, &rt5640->jack_work, 0); + queue_delayed_work(system_long_wq, &rt5640->jack_work, delay); return IRQ_HANDLED; } @@ -2535,6 +2550,9 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, rt5640->jd_gpio_irq_requested = true; } + if (jack_data && jack_data->use_platform_clock) + rt5640->use_platform_clock = jack_data->use_platform_clock; + ret = request_irq(rt5640->irq, rt5640_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rt5640", rt5640); @@ -2549,10 +2567,18 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, queue_delayed_work(system_long_wq, &rt5640->jack_work, 0); } +static const struct snd_soc_dapm_route rt5640_hda_jack_dapm_routes[] = { + {"IN1P", NULL, "MICBIAS1"}, + {"IN2P", NULL, "MICBIAS1"}, + {"IN3P", NULL, "MICBIAS1"}, +}; + static void rt5640_enable_hda_jack_detect( struct snd_soc_component *component, struct snd_soc_jack *jack) { struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); int ret; /* Select JD1 for Mic */ @@ -2573,6 +2599,13 @@ static void rt5640_enable_hda_jack_detect( snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x400, 0x0); + snd_soc_component_update_bits(component, RT5640_PWR_ANLG1, + RT5640_PWR_VREF2 | RT5640_PWR_MB | RT5640_PWR_BG, + RT5640_PWR_VREF2 | RT5640_PWR_MB | RT5640_PWR_BG); + usleep_range(10000, 15000); + snd_soc_component_update_bits(component, RT5640_PWR_ANLG1, + RT5640_PWR_FV2, RT5640_PWR_FV2); + rt5640->jack = jack; ret = request_irq(rt5640->irq, rt5640_irq, @@ -2585,6 +2618,9 @@ static void rt5640_enable_hda_jack_detect( /* sync initial jack state */ queue_delayed_work(system_long_wq, &rt5640->jack_work, 0); + + snd_soc_dapm_add_routes(dapm, rt5640_hda_jack_dapm_routes, + ARRAY_SIZE(rt5640_hda_jack_dapm_routes)); } static int rt5640_set_jack(struct snd_soc_component *component, @@ -2689,16 +2725,13 @@ static int rt5640_probe(struct snd_soc_component *component) if (device_property_read_u32(component->dev, "realtek,jack-detect-source", &val) == 0) { - if (val <= RT5640_JD_SRC_GPIO4) { + if (val <= RT5640_JD_SRC_GPIO4) rt5640->jd_src = val << RT5640_JD_SFT; - } else if (val == RT5640_JD_SRC_HDA_HEADER) { + else if (val == RT5640_JD_SRC_HDA_HEADER) rt5640->jd_src = RT5640_JD_SRC_HDA_HEADER; - snd_soc_component_update_bits(component, RT5640_DUMMY1, - 0x0300, 0x0); - } else { + else dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n", val); - } } if (!device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted")) @@ -2860,8 +2893,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5640 = { .num_dapm_routes = ARRAY_SIZE(rt5640_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, - }; static const struct regmap_config rt5640_regmap = { @@ -2927,8 +2958,7 @@ static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np) return 0; } -static int rt5640_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5640_i2c_probe(struct i2c_client *i2c) { struct rt5640_priv *rt5640; int ret; @@ -3006,7 +3036,7 @@ static struct i2c_driver rt5640_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5640_acpi_match), .of_match_table = of_match_ptr(rt5640_of_match), }, - .probe = rt5640_i2c_probe, + .probe_new = rt5640_i2c_probe, .id_table = rt5640_i2c_id, }; module_i2c_driver(rt5640_i2c_driver); diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 9e49b9a0cc..505c935140 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -2155,11 +2155,13 @@ struct rt5640_priv { bool jd_inverted; unsigned int ovcd_th; unsigned int ovcd_sf; + bool use_platform_clock; }; struct rt5640_set_jack_data { int codec_irq_override; struct gpio_desc *jd_gpio; + bool use_platform_clock; }; int rt5640_dmic_enable(struct snd_soc_component *component, diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 197c560479..8635bc6567 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3534,7 +3534,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5645 = { .num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5645_regmap = { @@ -3855,8 +3854,7 @@ static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev) return 0; } -static int rt5645_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5645_i2c_probe(struct i2c_client *i2c) { struct rt5645_platform_data *pdata = NULL; const struct dmi_system_id *dmi_data; @@ -3944,7 +3942,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, ret = PTR_ERR(regmap); dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n", ret); - return ret; + goto err_enable; } /* @@ -3975,7 +3973,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, ret = PTR_ERR(rt5645->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - return ret; + goto err_enable; } regmap_write(rt5645->regmap, RT5645_RESET, 0); @@ -4154,9 +4152,14 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) if (i2c->irq) free_irq(i2c->irq, rt5645); + /* + * Since the rt5645_btn_check_callback() can queue jack_detect_work, + * the timer need to be delted first + */ + del_timer_sync(&rt5645->btn_check_timer); + cancel_delayed_work_sync(&rt5645->jack_detect_work); cancel_delayed_work_sync(&rt5645->rcclock_work); - del_timer_sync(&rt5645->btn_check_timer); regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies); @@ -4183,7 +4186,7 @@ static struct i2c_driver rt5645_i2c_driver = { .of_match_table = of_match_ptr(rt5645_of_match), .acpi_match_table = ACPI_PTR(rt5645_acpi_match), }, - .probe = rt5645_i2c_probe, + .probe_new = rt5645_i2c_probe, .remove = rt5645_i2c_remove, .shutdown = rt5645_i2c_shutdown, .id_table = rt5645_i2c_id, diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index f302c25688..df90af9065 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2161,7 +2161,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5651 = { .num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5651_regmap = { @@ -2209,8 +2208,7 @@ MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id); * Note this function MUST not look at device-properties, see the comment * above rt5651_apply_properties(). */ -static int rt5651_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5651_i2c_probe(struct i2c_client *i2c) { struct rt5651_priv *rt5651; int ret; @@ -2281,7 +2279,7 @@ static struct i2c_driver rt5651_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5651_acpi_match), .of_match_table = of_match_ptr(rt5651_of_match), }, - .probe = rt5651_i2c_probe, + .probe_new = rt5651_i2c_probe, .id_table = rt5651_i2c_id, }; module_i2c_driver(rt5651_i2c_driver); diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index e1503c2eee..5e21e3c37a 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -3801,7 +3801,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5659 = { .set_pll = rt5659_set_component_pll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; @@ -4093,8 +4092,7 @@ static void rt5659_intel_hd_header_probe_setup(struct rt5659_priv *rt5659) RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_EN); } -static int rt5659_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5659_i2c_probe(struct i2c_client *i2c) { struct rt5659_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5659_priv *rt5659; @@ -4342,7 +4340,7 @@ static struct i2c_driver rt5659_i2c_driver = { .of_match_table = of_match_ptr(rt5659_of_match), .acpi_match_table = ACPI_PTR(rt5659_acpi_match), }, - .probe = rt5659_i2c_probe, + .probe_new = rt5659_i2c_probe, .shutdown = rt5659_i2c_shutdown, .id_table = rt5659_i2c_id, }; diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 3b50fb2986..341baa29fd 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1208,7 +1208,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5660 = { .num_dapm_routes = ARRAY_SIZE(rt5660_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5660_regmap = { @@ -1266,8 +1265,7 @@ static int rt5660_parse_dt(struct rt5660_priv *rt5660, struct device *dev) return 0; } -static int rt5660_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5660_i2c_probe(struct i2c_client *i2c) { struct rt5660_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5660_priv *rt5660; @@ -1343,7 +1341,7 @@ static struct i2c_driver rt5660_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5660_acpi_match), .of_match_table = of_match_ptr(rt5660_of_match), }, - .probe = rt5660_i2c_probe, + .probe_new = rt5660_i2c_probe, .id_table = rt5660_i2c_id, }; module_i2c_driver(rt5660_i2c_driver); diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 3a8fba101b..ca981b374b 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3258,7 +3258,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5663 = { .set_jack = rt5663_set_jack_detect, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5663_v2_regmap = { @@ -3490,8 +3489,7 @@ static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev) return 0; } -static int rt5663_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5663_i2c_probe(struct i2c_client *i2c) { struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5663_priv *rt5663; @@ -3737,7 +3735,7 @@ static struct i2c_driver rt5663_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5663_acpi_match), .of_match_table = of_match_ptr(rt5663_of_match), }, - .probe = rt5663_i2c_probe, + .probe_new = rt5663_i2c_probe, .remove = rt5663_i2c_remove, .shutdown = rt5663_i2c_shutdown, .id_table = rt5663_i2c_id, diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 33e889802f..6e66cc218f 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4617,7 +4617,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5665 = { .set_jack = rt5665_set_jack_detect, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; @@ -4757,8 +4756,7 @@ static void rt5665_calibrate_handler(struct work_struct *work) rt5665_calibrate(rt5665); } -static int rt5665_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5665_i2c_probe(struct i2c_client *i2c) { struct rt5665_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5665_priv *rt5665; @@ -4970,7 +4968,7 @@ static struct i2c_driver rt5665_i2c_driver = { .of_match_table = of_match_ptr(rt5665_of_match), .acpi_match_table = ACPI_PTR(rt5665_acpi_match), }, - .probe = rt5665_i2c_probe, + .probe_new = rt5665_i2c_probe, .shutdown = rt5665_i2c_shutdown, .id_table = rt5665_i2c_id, }; diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index 5b12cbf2ba..beb0951ff6 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2362,7 +2362,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5668 = { .set_jack = rt5668_set_jack_detect, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5668_regmap = { @@ -2453,8 +2452,7 @@ static void rt5668_calibrate(struct rt5668_priv *rt5668) } -static int rt5668_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5668_i2c_probe(struct i2c_client *i2c) { struct rt5668_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5668_priv *rt5668; @@ -2620,7 +2618,7 @@ static struct i2c_driver rt5668_i2c_driver = { .of_match_table = of_match_ptr(rt5668_of_match), .acpi_match_table = ACPI_PTR(rt5668_acpi_match), }, - .probe = rt5668_i2c_probe, + .probe_new = rt5668_i2c_probe, .shutdown = rt5668_i2c_shutdown, .id_table = rt5668_i2c_id, }; diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index ce7684752b..60dbfa2a54 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2852,7 +2852,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5670 = { .num_dapm_routes = ARRAY_SIZE(rt5670_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5670_regmap = { @@ -3046,8 +3045,7 @@ const char *rt5670_components(void) } EXPORT_SYMBOL_GPL(rt5670_components); -static int rt5670_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5670_i2c_probe(struct i2c_client *i2c) { struct rt5670_priv *rt5670; int ret; @@ -3334,7 +3332,7 @@ static struct i2c_driver rt5670_i2c_driver = { .name = "rt5670", .acpi_match_table = ACPI_PTR(rt5670_acpi_match), }, - .probe = rt5670_i2c_probe, + .probe_new = rt5670_i2c_probe, .remove = rt5670_i2c_remove, .id_table = rt5670_i2c_id, }; diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 4a8c267d4f..31a2dd0aaf 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5189,7 +5189,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5677 = { .num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5677_regmap_physical = { diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index 20fc0f3766..3f72f60934 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -118,8 +118,7 @@ static void rt5682_i2c_disable_regulators(void *data) regulator_bulk_disable(ARRAY_SIZE(rt5682->supplies), rt5682->supplies); } -static int rt5682_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5682_i2c_probe(struct i2c_client *i2c) { struct rt5682_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5682_priv *rt5682; @@ -335,7 +334,7 @@ static struct i2c_driver rt5682_i2c_driver = { .acpi_match_table = rt5682_acpi_match, .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe = rt5682_i2c_probe, + .probe_new = rt5682_i2c_probe, .remove = rt5682_i2c_remove, .shutdown = rt5682_i2c_shutdown, .id_table = rt5682_i2c_id, diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 248257a2e4..f04e18c324 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -719,9 +719,12 @@ static int rt5682_sdw_remove(struct sdw_slave *slave) { struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev); - if (rt5682 && rt5682->hw_init) + if (rt5682->hw_init) cancel_delayed_work_sync(&rt5682->jack_detect_work); + if (rt5682->first_hw_init) + pm_runtime_disable(&slave->dev); + return 0; } diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 2b6c6d6b97..2df95e7929 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -3064,7 +3064,6 @@ const struct snd_soc_component_driver rt5682_soc_component_dev = { .set_jack = rt5682_set_jack_detect, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; EXPORT_SYMBOL_GPL(rt5682_soc_component_dev); diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index b55f3ac3a2..eb47e7cd48 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -42,8 +42,8 @@ static const struct rt5682s_platform_data i2s_default_platform_data = { }; static const char *rt5682s_supply_names[RT5682S_NUM_SUPPLIES] = { - "AVDD", - "MICVDD", + [RT5682S_SUPPLY_AVDD] = "AVDD", + [RT5682S_SUPPLY_MICVDD] = "MICVDD", }; static const struct reg_sequence patch_list[] = { @@ -2893,7 +2893,6 @@ static const struct snd_soc_component_driver rt5682s_soc_component_dev = { .set_jack = rt5682s_set_jack_detect, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev) @@ -3022,12 +3021,21 @@ static struct snd_soc_dai_driver rt5682s_dai[] = { static void rt5682s_i2c_disable_regulators(void *data) { struct rt5682s_priv *rt5682s = data; + struct device *dev = regmap_get_device(rt5682s->regmap); + int ret; + + ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_AVDD].consumer); + if (ret) + dev_err(dev, "Failed to disable supply AVDD: %d\n", ret); - regulator_bulk_disable(ARRAY_SIZE(rt5682s->supplies), rt5682s->supplies); + usleep_range(1000, 1500); + + ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_MICVDD].consumer); + if (ret) + dev_err(dev, "Failed to disable supply MICVDD: %d\n", ret); } -static int rt5682s_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5682s_i2c_probe(struct i2c_client *i2c) { struct rt5682s_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5682s_priv *rt5682s; @@ -3068,9 +3076,16 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c, if (ret) return ret; - ret = regulator_bulk_enable(ARRAY_SIZE(rt5682s->supplies), rt5682s->supplies); + ret = regulator_enable(rt5682s->supplies[RT5682S_SUPPLY_MICVDD].consumer); + if (ret) { + dev_err(&i2c->dev, "Failed to enable supply MICVDD: %d\n", ret); + return ret; + } + usleep_range(1000, 1500); + + ret = regulator_enable(rt5682s->supplies[RT5682S_SUPPLY_AVDD].consumer); if (ret) { - dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + dev_err(&i2c->dev, "Failed to enable supply AVDD: %d\n", ret); return ret; } @@ -3211,7 +3226,7 @@ static struct i2c_driver rt5682s_i2c_driver = { .acpi_match_table = rt5682s_acpi_match, .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe = rt5682s_i2c_probe, + .probe_new = rt5682s_i2c_probe, .remove = rt5682s_i2c_remove, .shutdown = rt5682s_i2c_shutdown, .id_table = rt5682s_i2c_id, diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h index 397a2531b6..7353831c73 100644 --- a/sound/soc/codecs/rt5682s.h +++ b/sound/soc/codecs/rt5682s.h @@ -1434,7 +1434,11 @@ struct pll_calc_map { bool sel_ps; }; -#define RT5682S_NUM_SUPPLIES 2 +enum { + RT5682S_SUPPLY_AVDD, + RT5682S_SUPPLY_MICVDD, + RT5682S_NUM_SUPPLIES, +}; struct rt5682s_priv { struct snd_soc_component *component; diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index bda5948996..f7439e40ca 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include "rt700.h" @@ -463,11 +464,14 @@ static int rt700_sdw_remove(struct sdw_slave *slave) { struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev); - if (rt700 && rt700->hw_init) { + if (rt700->hw_init) { cancel_delayed_work_sync(&rt700->jack_detect_work); cancel_delayed_work_sync(&rt700->jack_btn_check_work); } + if (rt700->first_hw_init) + pm_runtime_disable(&slave->dev); + return 0; } diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index e61a8257bf..055c3ae974 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -162,7 +162,7 @@ static void rt700_jack_detect_handler(struct work_struct *work) if (!rt700->hs_jack) return; - if (!rt700->component->card->instantiated) + if (!rt700->component->card || !rt700->component->card->instantiated) return; reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT; @@ -315,17 +315,27 @@ static int rt700_set_jack_detect(struct snd_soc_component *component, struct snd_soc_jack *hs_jack, void *data) { struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + int ret; rt700->hs_jack = hs_jack; - if (!rt700->hw_init) { - dev_dbg(&rt700->slave->dev, - "%s hw_init not ready yet\n", __func__); + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + if (ret != -EACCES) { + dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret); + return ret; + } + + /* pm_runtime not enabled yet */ + dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__); return 0; } rt700_jack_init(rt700); + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + return 0; } @@ -808,9 +818,14 @@ static const struct snd_soc_dapm_route rt700_audio_map[] = { static int rt700_probe(struct snd_soc_component *component) { struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + int ret; rt700->component = component; + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + return 0; } @@ -853,6 +868,7 @@ static const struct snd_soc_component_driver soc_codec_dev_rt700 = { .dapm_routes = rt700_audio_map, .num_dapm_routes = ARRAY_SIZE(rt700_audio_map), .set_jack = rt700_set_jack_detect, + .endianness = 1, }; static int rt700_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, @@ -1114,6 +1130,11 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap, mutex_init(&rt700->disable_irq_lock); + INIT_DELAYED_WORK(&rt700->jack_detect_work, + rt700_jack_detect_handler); + INIT_DELAYED_WORK(&rt700->jack_btn_check_work, + rt700_btn_check_handler); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1208,13 +1229,6 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) /* Finish Initial Settings, set power to D3 */ regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - if (!rt700->first_hw_init) { - INIT_DELAYED_WORK(&rt700->jack_detect_work, - rt700_jack_detect_handler); - INIT_DELAYED_WORK(&rt700->jack_btn_check_work, - rt700_btn_check_handler); - } - /* * if set_jack callback occurred early than io_init, * we set up the jack detection function now diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index aaf5af153d..a085b2f530 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "rt711-sdca.h" #include "rt711-sdca-sdw.h" @@ -364,11 +365,17 @@ static int rt711_sdca_sdw_remove(struct sdw_slave *slave) { struct rt711_sdca_priv *rt711 = dev_get_drvdata(&slave->dev); - if (rt711 && rt711->hw_init) { + if (rt711->hw_init) { cancel_delayed_work_sync(&rt711->jack_detect_work); cancel_delayed_work_sync(&rt711->jack_btn_check_work); } + if (rt711->first_hw_init) + pm_runtime_disable(&slave->dev); + + mutex_destroy(&rt711->calibrate_mutex); + mutex_destroy(&rt711->disable_irq_lock); + return 0; } diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index bdb1375f03..9252681219 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -34,7 +34,7 @@ static int rt711_sdca_index_write(struct rt711_sdca_priv *rt711, ret = regmap_write(regmap, addr, value); if (ret < 0) - dev_err(rt711->component->dev, + dev_err(&rt711->slave->dev, "Failed to set private value: %06x <= %04x ret=%d\n", addr, value, ret); @@ -50,7 +50,7 @@ static int rt711_sdca_index_read(struct rt711_sdca_priv *rt711, ret = regmap_read(regmap, addr, value); if (ret < 0) - dev_err(rt711->component->dev, + dev_err(&rt711->slave->dev, "Failed to get private value: %06x => %04x ret=%d\n", addr, *value, ret); @@ -294,7 +294,7 @@ static void rt711_sdca_jack_detect_handler(struct work_struct *work) if (!rt711->hs_jack) return; - if (!rt711->component->card->instantiated) + if (!rt711->component->card || !rt711->component->card->instantiated) return; /* SDW_SCP_SDCA_INT_SDCA_0 is used for jack detection */ @@ -487,16 +487,27 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component, struct snd_soc_jack *hs_jack, void *data) { struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + int ret; rt711->hs_jack = hs_jack; - if (!rt711->hw_init) { - dev_dbg(&rt711->slave->dev, - "%s hw_init not ready yet\n", __func__); + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + if (ret != -EACCES) { + dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret); + return ret; + } + + /* pm_runtime not enabled yet */ + dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__); return 0; } rt711_sdca_jack_init(rt711); + + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + return 0; } @@ -1183,19 +1194,16 @@ static int rt711_sdca_parse_dt(struct rt711_sdca_priv *rt711, struct device *dev static int rt711_sdca_probe(struct snd_soc_component *component) { struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + int ret; rt711_sdca_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; - return 0; -} - -static void rt711_sdca_remove(struct snd_soc_component *component) -{ - struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; - regcache_cache_only(rt711->regmap, true); - regcache_cache_only(rt711->mbq_regmap, true); + return 0; } static const struct snd_soc_component_driver soc_sdca_dev_rt711 = { @@ -1207,7 +1215,7 @@ static const struct snd_soc_component_driver soc_sdca_dev_rt711 = { .dapm_routes = rt711_sdca_audio_map, .num_dapm_routes = ARRAY_SIZE(rt711_sdca_audio_map), .set_jack = rt711_sdca_set_jack_detect, - .remove = rt711_sdca_remove, + .endianness = 1, }; static int rt711_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, @@ -1411,8 +1419,12 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap, rt711->regmap = regmap; rt711->mbq_regmap = mbq_regmap; + mutex_init(&rt711->calibrate_mutex); mutex_init(&rt711->disable_irq_lock); + INIT_DELAYED_WORK(&rt711->jack_detect_work, rt711_sdca_jack_detect_handler); + INIT_DELAYED_WORK(&rt711->jack_btn_check_work, rt711_sdca_btn_check_handler); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1544,14 +1556,6 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave) rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x20, 0x00); - if (!rt711->first_hw_init) { - INIT_DELAYED_WORK(&rt711->jack_detect_work, - rt711_sdca_jack_detect_handler); - INIT_DELAYED_WORK(&rt711->jack_btn_check_work, - rt711_sdca_btn_check_handler); - mutex_init(&rt711->calibrate_mutex); - } - /* calibration */ ret = rt711_sdca_calibration(rt711); if (ret < 0) diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index bda2cc9439..4fe68bcf2a 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include "rt711.h" @@ -464,12 +465,18 @@ static int rt711_sdw_remove(struct sdw_slave *slave) { struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); - if (rt711 && rt711->hw_init) { + if (rt711->hw_init) { cancel_delayed_work_sync(&rt711->jack_detect_work); cancel_delayed_work_sync(&rt711->jack_btn_check_work); cancel_work_sync(&rt711->calibration_work); } + if (rt711->first_hw_init) + pm_runtime_disable(&slave->dev); + + mutex_destroy(&rt711->calibrate_mutex); + mutex_destroy(&rt711->disable_irq_lock); + return 0; } diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index ea25fd58d4..1bf6180891 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -242,7 +242,7 @@ static void rt711_jack_detect_handler(struct work_struct *work) if (!rt711->hs_jack) return; - if (!rt711->component->card->instantiated) + if (!rt711->component->card || !rt711->component->card->instantiated) return; if (pm_runtime_status_suspended(rt711->slave->dev.parent)) { @@ -457,17 +457,27 @@ static int rt711_set_jack_detect(struct snd_soc_component *component, struct snd_soc_jack *hs_jack, void *data) { struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + int ret; rt711->hs_jack = hs_jack; - if (!rt711->hw_init) { - dev_dbg(&rt711->slave->dev, - "%s hw_init not ready yet\n", __func__); + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + if (ret != -EACCES) { + dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret); + return ret; + } + + /* pm_runtime not enabled yet */ + dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__); return 0; } rt711_jack_init(rt711); + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + return 0; } @@ -925,18 +935,16 @@ static int rt711_parse_dt(struct rt711_priv *rt711, struct device *dev) static int rt711_probe(struct snd_soc_component *component) { struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + int ret; rt711_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; - return 0; -} - -static void rt711_remove(struct snd_soc_component *component) -{ - struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; - regcache_cache_only(rt711->regmap, true); + return 0; } static const struct snd_soc_component_driver soc_codec_dev_rt711 = { @@ -949,7 +957,7 @@ static const struct snd_soc_component_driver soc_codec_dev_rt711 = { .dapm_routes = rt711_audio_map, .num_dapm_routes = ARRAY_SIZE(rt711_audio_map), .set_jack = rt711_set_jack_detect, - .remove = rt711_remove, + .endianness = 1, }; static int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, @@ -1203,8 +1211,13 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, rt711->sdw_regmap = sdw_regmap; rt711->regmap = regmap; + mutex_init(&rt711->calibrate_mutex); mutex_init(&rt711->disable_irq_lock); + INIT_DELAYED_WORK(&rt711->jack_detect_work, rt711_jack_detect_handler); + INIT_DELAYED_WORK(&rt711->jack_btn_check_work, rt711_btn_check_handler); + INIT_WORK(&rt711->calibration_work, rt711_calibration_work); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1312,15 +1325,8 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->first_hw_init) rt711_calibration(rt711); - else { - INIT_DELAYED_WORK(&rt711->jack_detect_work, - rt711_jack_detect_handler); - INIT_DELAYED_WORK(&rt711->jack_btn_check_work, - rt711_btn_check_handler); - mutex_init(&rt711->calibrate_mutex); - INIT_WORK(&rt711->calibration_work, rt711_calibration_work); + else schedule_work(&rt711->calibration_work); - } /* * if set_jack callback occurred early than io_init, diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c index a5c673f43d..13e731d166 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.c +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include "rt715-sdca.h" @@ -181,8 +182,6 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave, { struct regmap *mbq_regmap, *regmap; - slave->ops = &rt715_sdca_slave_ops; - /* Regmap Initialization */ mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt715_sdca_mbq_regmap); if (IS_ERR(mbq_regmap)) @@ -195,6 +194,16 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave, return rt715_sdca_init(&slave->dev, mbq_regmap, regmap, slave); } +static int rt715_sdca_sdw_remove(struct sdw_slave *slave) +{ + struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev); + + if (rt715->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + static const struct sdw_device_id rt715_sdca_id[] = { SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x3, 0x1, 0), SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x3, 0x1, 0), @@ -269,6 +278,7 @@ static struct sdw_driver rt715_sdw_driver = { .pm = &rt715_pm, }, .probe = rt715_sdca_sdw_probe, + .remove = rt715_sdca_sdw_remove, .ops = &rt715_sdca_slave_ops, .id_table = rt715_sdca_id, }; diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index bfa536bd71..ce8bbc7619 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -758,13 +758,26 @@ static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = { {"ADC 25 Mux", "DMIC4", "DMIC4"}, }; +static int rt715_sdca_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_codec_dev_rt715_sdca = { + .probe = rt715_sdca_probe, .controls = rt715_sdca_snd_controls, .num_controls = ARRAY_SIZE(rt715_sdca_snd_controls), .dapm_widgets = rt715_sdca_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(rt715_sdca_dapm_widgets), .dapm_routes = rt715_sdca_audio_map, .num_dapm_routes = ARRAY_SIZE(rt715_sdca_audio_map), + .endianness = 1, }; static int rt715_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index a7b21b03c0..b047bf87a1 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -514,6 +515,16 @@ static int rt715_sdw_probe(struct sdw_slave *slave, return 0; } +static int rt715_sdw_remove(struct sdw_slave *slave) +{ + struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev); + + if (rt715->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + static const struct sdw_device_id rt715_id[] = { SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x2, 0, 0), SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x2, 0, 0), @@ -575,6 +586,7 @@ static struct sdw_driver rt715_sdw_driver = { .pm = &rt715_pm, }, .probe = rt715_sdw_probe, + .remove = rt715_sdw_remove, .ops = &rt715_slave_ops, .id_table = rt715_id, }; diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index a64d11a747..e93240521c 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -737,7 +737,19 @@ static int rt715_set_bias_level(struct snd_soc_component *component, return 0; } +static int rt715_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_codec_dev_rt715 = { + .probe = rt715_probe, .set_bias_level = rt715_set_bias_level, .controls = rt715_snd_controls, .num_controls = ARRAY_SIZE(rt715_snd_controls), @@ -745,6 +757,7 @@ static const struct snd_soc_component_driver soc_codec_dev_rt715 = { .num_dapm_widgets = ARRAY_SIZE(rt715_dapm_widgets), .dapm_routes = rt715_audio_map, .num_dapm_routes = ARRAY_SIZE(rt715_audio_map), + .endianness = 1, }; static int rt715_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c index 6e0d7cf0c8..da495bdc84 100644 --- a/sound/soc/codecs/rt9120.c +++ b/sound/soc/codecs/rt9120.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,7 @@ enum { struct rt9120_data { struct device *dev; struct regmap *regmap; + struct gpio_desc *pwdnn_gpio; int chip_idx; }; @@ -160,6 +162,8 @@ static int rt9120_codec_probe(struct snd_soc_component *comp) snd_soc_component_init_regmap(comp, data->regmap); + pm_runtime_get_sync(comp->dev); + /* Internal setting */ if (data->chip_idx == CHIP_IDX_RT9120S) { snd_soc_component_write(comp, RT9120_REG_INTERCFG, 0xde); @@ -167,6 +171,9 @@ static int rt9120_codec_probe(struct snd_soc_component *comp) } else snd_soc_component_write(comp, RT9120_REG_INTERNAL0, 0x04); + pm_runtime_mark_last_busy(comp->dev); + pm_runtime_put(comp->dev); + return 0; } @@ -178,6 +185,7 @@ static const struct snd_soc_component_driver rt9120_component_driver = { .num_dapm_widgets = ARRAY_SIZE(rt9120_dapm_widgets), .dapm_routes = rt9120_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt9120_dapm_routes), + .endianness = 1, }; static int rt9120_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) @@ -337,6 +345,18 @@ static const struct regmap_access_table rt9120_wr_table = { .n_yes_ranges = ARRAY_SIZE(rt9120_wr_yes_ranges), }; +static bool rt9120_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00 ... 0x01: + case 0x10: + case 0x30 ... 0x40: + return true; + default: + return false; + } +} + static int rt9120_get_reg_size(unsigned int reg) { switch (reg) { @@ -371,7 +391,7 @@ static int rt9120_reg_read(void *context, unsigned int reg, unsigned int *val) *val = be32_to_cpup((__be32 *)raw); break; case 3: - *val = raw[0] << 16 | raw[1] << 8 | raw[0]; + *val = raw[0] << 16 | raw[1] << 8 | raw[2]; break; case 2: *val = be16_to_cpup((__be16 *)raw); @@ -396,14 +416,49 @@ static int rt9120_reg_write(void *context, unsigned int reg, unsigned int val) return i2c_smbus_write_i2c_block_data(i2c, reg, size, rawp + offs); } +static const struct reg_default rt9120_reg_defaults[] = { + { .reg = 0x02, .def = 0x02 }, + { .reg = 0x03, .def = 0xf2 }, + { .reg = 0x04, .def = 0x01 }, + { .reg = 0x05, .def = 0xc0 }, + { .reg = 0x06, .def = 0x28 }, + { .reg = 0x07, .def = 0x04 }, + { .reg = 0x08, .def = 0xff }, + { .reg = 0x09, .def = 0x01 }, + { .reg = 0x0a, .def = 0x01 }, + { .reg = 0x0b, .def = 0x00 }, + { .reg = 0x0c, .def = 0x04 }, + { .reg = 0x11, .def = 0x30 }, + { .reg = 0x12, .def = 0x08 }, + { .reg = 0x13, .def = 0x12 }, + { .reg = 0x14, .def = 0x09 }, + { .reg = 0x15, .def = 0x00 }, + { .reg = 0x20, .def = 0x7ff }, + { .reg = 0x21, .def = 0x180 }, + { .reg = 0x22, .def = 0x180 }, + { .reg = 0x23, .def = 0x00 }, + { .reg = 0x24, .def = 0x80 }, + { .reg = 0x25, .def = 0x180 }, + { .reg = 0x26, .def = 0x640 }, + { .reg = 0x27, .def = 0x180 }, + { .reg = 0x63, .def = 0x5e }, + { .reg = 0x65, .def = 0x66 }, + { .reg = 0x6c, .def = 0xe0 }, + { .reg = 0xf8, .def = 0x44 }, +}; + static const struct regmap_config rt9120_regmap_config = { .reg_bits = 8, .val_bits = 32, .max_register = RT9120_REG_DIGCFG, + .reg_defaults = rt9120_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt9120_reg_defaults), + .cache_type = REGCACHE_RBTREE, .reg_read = rt9120_reg_read, .reg_write = rt9120_reg_write, + .volatile_reg = rt9120_volatile_reg, .wr_table = &rt9120_wr_table, .rd_table = &rt9120_rd_table, }; @@ -449,7 +504,6 @@ static int rt9120_do_register_reset(struct rt9120_data *data) static int rt9120_probe(struct i2c_client *i2c) { struct rt9120_data *data; - struct gpio_desc *pwdnn_gpio; struct regulator *dvdd_supply; int dvdd_supply_volt, ret; @@ -460,12 +514,12 @@ static int rt9120_probe(struct i2c_client *i2c) data->dev = &i2c->dev; i2c_set_clientdata(i2c, data); - pwdnn_gpio = devm_gpiod_get_optional(&i2c->dev, "pwdnn", - GPIOD_OUT_HIGH); - if (IS_ERR(pwdnn_gpio)) { + data->pwdnn_gpio = devm_gpiod_get_optional(&i2c->dev, "pwdnn", + GPIOD_OUT_HIGH); + if (IS_ERR(data->pwdnn_gpio)) { dev_err(&i2c->dev, "Failed to initialize 'pwdnn' gpio\n"); - return PTR_ERR(pwdnn_gpio); - } else if (pwdnn_gpio) { + return PTR_ERR(data->pwdnn_gpio); + } else if (data->pwdnn_gpio) { dev_dbg(&i2c->dev, "'pwdnn' from low to high, wait chip on\n"); msleep(RT9120_CHIPON_WAITMS); } @@ -507,11 +561,55 @@ static int rt9120_probe(struct i2c_client *i2c) } } + pm_runtime_set_autosuspend_delay(&i2c->dev, 1000); + pm_runtime_use_autosuspend(&i2c->dev); + pm_runtime_set_active(&i2c->dev); + pm_runtime_mark_last_busy(&i2c->dev); + pm_runtime_enable(&i2c->dev); + return devm_snd_soc_register_component(&i2c->dev, &rt9120_component_driver, &rt9120_dai, 1); } +static int rt9120_remove(struct i2c_client *i2c) +{ + pm_runtime_disable(&i2c->dev); + pm_runtime_set_suspended(&i2c->dev); + return 0; +} + +static int __maybe_unused rt9120_runtime_suspend(struct device *dev) +{ + struct rt9120_data *data = dev_get_drvdata(dev); + + if (data->pwdnn_gpio) { + regcache_cache_only(data->regmap, true); + regcache_mark_dirty(data->regmap); + gpiod_set_value(data->pwdnn_gpio, 0); + } + + return 0; +} + +static int __maybe_unused rt9120_runtime_resume(struct device *dev) +{ + struct rt9120_data *data = dev_get_drvdata(dev); + + if (data->pwdnn_gpio) { + gpiod_set_value(data->pwdnn_gpio, 1); + msleep(RT9120_CHIPON_WAITMS); + regcache_cache_only(data->regmap, false); + regcache_sync(data->regmap); + } + + return 0; +} + +static const struct dev_pm_ops rt9120_pm_ops = { + SET_RUNTIME_PM_OPS(rt9120_runtime_suspend, rt9120_runtime_resume, NULL) +}; + static const struct of_device_id __maybe_unused rt9120_device_table[] = { { .compatible = "richtek,rt9120", }, { } @@ -522,8 +620,10 @@ static struct i2c_driver rt9120_driver = { .driver = { .name = "rt9120", .of_match_table = rt9120_device_table, + .pm = &rt9120_pm_ops, }, .probe_new = rt9120_probe, + .remove = rt9120_remove, }; module_i2c_driver(rt9120_driver); diff --git a/sound/soc/codecs/sdw-mockup.c b/sound/soc/codecs/sdw-mockup.c index 7c612aaf31..288b55368d 100644 --- a/sound/soc/codecs/sdw-mockup.c +++ b/sound/soc/codecs/sdw-mockup.c @@ -38,6 +38,7 @@ static void sdw_mockup_component_remove(struct snd_soc_component *component) static const struct snd_soc_component_driver snd_soc_sdw_mockup_component = { .probe = sdw_mockup_component_probe, .remove = sdw_mockup_component_remove, + .endianness = 1, }; static int sdw_mockup_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 8eebf27d0e..3fafd9fc5c 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1536,7 +1536,6 @@ static const struct snd_soc_component_driver sgtl5000_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config sgtl5000_regmap = { @@ -1579,8 +1578,7 @@ static void sgtl5000_fill_defaults(struct i2c_client *client) } } -static int sgtl5000_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sgtl5000_i2c_probe(struct i2c_client *client) { struct sgtl5000_priv *sgtl5000; int ret, reg, rev; @@ -1796,6 +1794,9 @@ static int sgtl5000_i2c_remove(struct i2c_client *client) { struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client); + regmap_write(sgtl5000->regmap, SGTL5000_CHIP_DIG_POWER, SGTL5000_DIG_POWER_DEFAULT); + regmap_write(sgtl5000->regmap, SGTL5000_CHIP_ANA_POWER, SGTL5000_ANA_POWER_DEFAULT); + clk_disable_unprepare(sgtl5000->mclk); regulator_bulk_disable(sgtl5000->num_supplies, sgtl5000->supplies); regulator_bulk_free(sgtl5000->num_supplies, sgtl5000->supplies); @@ -1803,6 +1804,11 @@ static int sgtl5000_i2c_remove(struct i2c_client *client) return 0; } +static void sgtl5000_i2c_shutdown(struct i2c_client *client) +{ + sgtl5000_i2c_remove(client); +} + static const struct i2c_device_id sgtl5000_id[] = { {"sgtl5000", 0}, {}, @@ -1821,8 +1827,9 @@ static struct i2c_driver sgtl5000_i2c_driver = { .name = "sgtl5000", .of_match_table = sgtl5000_dt_ids, }, - .probe = sgtl5000_i2c_probe, + .probe_new = sgtl5000_i2c_probe, .remove = sgtl5000_i2c_remove, + .shutdown = sgtl5000_i2c_shutdown, .id_table = sgtl5000_id, }; diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h index 56ec5863f2..3a808c7622 100644 --- a/sound/soc/codecs/sgtl5000.h +++ b/sound/soc/codecs/sgtl5000.h @@ -80,6 +80,7 @@ /* * SGTL5000_CHIP_DIG_POWER */ +#define SGTL5000_DIG_POWER_DEFAULT 0x0000 #define SGTL5000_ADC_EN 0x0040 #define SGTL5000_DAC_EN 0x0020 #define SGTL5000_DAP_POWERUP 0x0010 diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 8bd2edf70f..d87141ba84 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -239,7 +239,6 @@ static const struct snd_soc_component_driver soc_component_dev_si476x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int si476x_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c index 276db978e5..862e0b654a 100644 --- a/sound/soc/codecs/spdif_receiver.c +++ b/sound/soc/codecs/spdif_receiver.c @@ -43,7 +43,6 @@ static struct snd_soc_component_driver soc_codec_spdif_dir = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver dir_stub_dai = { diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c index 2c8cebfc66..7365189215 100644 --- a/sound/soc/codecs/spdif_transmitter.c +++ b/sound/soc/codecs/spdif_transmitter.c @@ -43,7 +43,6 @@ static struct snd_soc_component_driver soc_codec_spdif_dit = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver dit_stub_dai = { diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 09449c6c40..6d88478482 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -409,8 +409,8 @@ static int ssm2518_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) bool invert_fclk; int ret; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -721,7 +721,6 @@ static const struct snd_soc_component_driver ssm2518_component_driver = { .num_dapm_routes = ARRAY_SIZE(ssm2518_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ssm2518_regmap_config = { @@ -735,8 +734,7 @@ static const struct regmap_config ssm2518_regmap_config = { .num_reg_defaults = ARRAY_SIZE(ssm2518_reg_defaults), }; -static int ssm2518_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ssm2518_i2c_probe(struct i2c_client *i2c) { struct ssm2518_platform_data *pdata = i2c->dev.platform_data; struct ssm2518 *ssm2518; @@ -815,7 +813,7 @@ static struct i2c_driver ssm2518_driver = { .name = "ssm2518", .of_match_table = of_match_ptr(ssm2518_dt_ids), }, - .probe = ssm2518_i2c_probe, + .probe_new = ssm2518_i2c_probe, .id_table = ssm2518_i2c_ids, }; module_i2c_driver(ssm2518_driver); diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c index afab81383d..3c85772901 100644 --- a/sound/soc/codecs/ssm2602-i2c.c +++ b/sound/soc/codecs/ssm2602-i2c.c @@ -13,15 +13,17 @@ #include "ssm2602.h" +static const struct i2c_device_id ssm2602_i2c_id[]; + /* * ssm2602 2 wire address is determined by GPIO5 * state during powerup. * low = 0x1a * high = 0x1b */ -static int ssm2602_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ssm2602_i2c_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_match_id(ssm2602_i2c_id, client); return ssm2602_probe(&client->dev, id->driver_data, devm_regmap_init_i2c(client, &ssm2602_regmap_config)); } @@ -47,7 +49,7 @@ static struct i2c_driver ssm2602_i2c_driver = { .name = "ssm2602", .of_match_table = ssm2602_of_match, }, - .probe = ssm2602_i2c_probe, + .probe_new = ssm2602_i2c_probe, .id_table = ssm2602_i2c_id, }; module_i2c_driver(ssm2602_i2c_driver); diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 7964e922b0..cbbe83b85a 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -411,11 +411,11 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int iface = 0; /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface |= 0x0040; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -624,7 +624,6 @@ static const struct snd_soc_component_driver soc_component_dev_ssm2602 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static bool ssm2602_register_volatile(struct device *dev, unsigned int reg) diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 811b1a2c40..4b0265617c 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -278,8 +278,8 @@ static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int ctrl1 = 0; bool invert_fclk; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -427,7 +427,6 @@ static const struct snd_soc_component_driver ssm4567_component_driver = { .num_dapm_routes = ARRAY_SIZE(ssm4567_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ssm4567_regmap_config = { @@ -444,8 +443,7 @@ static const struct regmap_config ssm4567_regmap_config = { .num_reg_defaults = ARRAY_SIZE(ssm4567_reg_defaults), }; -static int ssm4567_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ssm4567_i2c_probe(struct i2c_client *i2c) { struct ssm4567 *ssm4567; int ret; @@ -502,7 +500,7 @@ static struct i2c_driver ssm4567_driver = { .of_match_table = of_match_ptr(ssm4567_of_match), .acpi_match_table = ACPI_PTR(ssm4567_acpi_match), }, - .probe = ssm4567_i2c_probe, + .probe_new = ssm4567_i2c_probe, .id_table = ssm4567_i2c_ids, }; module_i2c_driver(ssm4567_driver); diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 86528b930d..8c86b578eb 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -48,12 +48,9 @@ SNDRV_PCM_RATE_192000) #define STA32X_FORMATS \ - (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 | SNDRV_PCM_FMTBIT_S32_BE) + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) /* Power-up register defaults */ static const struct reg_default sta32x_regs[] = { @@ -604,8 +601,8 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai, struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component); u8 confb = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -1017,7 +1014,6 @@ static const struct snd_soc_component_driver sta32x_component = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config sta32x_regmap = { @@ -1094,8 +1090,7 @@ static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x) } #endif -static int sta32x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int sta32x_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct sta32x_priv *sta32x; @@ -1175,7 +1170,7 @@ static struct i2c_driver sta32x_i2c_driver = { .name = "sta32x", .of_match_table = of_match_ptr(st32x_dt_ids), }, - .probe = sta32x_i2c_probe, + .probe_new = sta32x_i2c_probe, .id_table = sta32x_i2c_id, }; diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index 75d3b0618a..7b2c5b57d5 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -48,12 +48,9 @@ SNDRV_PCM_RATE_192000) #define STA350_FORMATS \ - (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 | SNDRV_PCM_FMTBIT_S32_BE) + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) /* Power-up register defaults */ static const struct reg_default sta350_regs[] = { @@ -633,8 +630,8 @@ static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai, struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component); unsigned int confb = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -1060,7 +1057,6 @@ static const struct snd_soc_component_driver sta350_component = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config sta350_regmap = { @@ -1187,8 +1183,7 @@ static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350) } #endif -static int sta350_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int sta350_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct sta350_priv *sta350; @@ -1263,7 +1258,7 @@ static struct i2c_driver sta350_i2c_driver = { .name = "sta350", .of_match_table = of_match_ptr(st350_dt_ids), }, - .probe = sta350_i2c_probe, + .probe_new = sta350_i2c_probe, .remove = sta350_i2c_remove, .id_table = sta350_i2c_id, }; diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 97b5f34027..3139570991 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -322,7 +322,6 @@ static const struct snd_soc_component_driver sta529_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config sta529_regmap = { @@ -337,8 +336,7 @@ static const struct regmap_config sta529_regmap = { .num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults), }; -static int sta529_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int sta529_i2c_probe(struct i2c_client *i2c) { struct sta529 *sta529; int ret; @@ -381,7 +379,7 @@ static struct i2c_driver sta529_i2c_driver = { .name = "sta529", .of_match_table = sta529_of_match, }, - .probe = sta529_i2c_probe, + .probe_new = sta529_i2c_probe, .id_table = sta529_i2c_id, }; diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index d99f6e466d..1824a71fe0 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -313,8 +313,6 @@ static const struct snd_soc_component_driver soc_component_dev_stac9766 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, - }; static int stac9766_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 3be4940e3c..f076878908 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -199,10 +199,10 @@ static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) 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) { + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { dev_err(dai->component->dev, - "%s: ERROR: Unsupporter master mask 0x%x\n", - __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); + "%s: ERROR: Unsupported clocking mask 0x%x\n", + __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK); return -EINVAL; } @@ -398,7 +398,6 @@ static struct snd_soc_component_driver sti_sas_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id sti_sas_dev_match[] = { diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 700baa6314..8bd667da87 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -347,17 +347,17 @@ static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct tas2552_data *tas2552 = dev_get_drvdata(component->dev); u8 serial_format; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: serial_format = 0x00; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: serial_format = TAS2552_WCLKDIR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: serial_format = TAS2552_BCLKDIR; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR); break; default: @@ -581,7 +581,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) gpiod_set_value(tas2552->enable_gpio, 1); - ret = pm_runtime_get_sync(component->dev); + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { dev_err(component->dev, "Enabling device failed: %d\n", ret); @@ -668,7 +668,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2552 = { .num_dapm_routes = ARRAY_SIZE(tas2552_audio_map), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config tas2552_regmap_config = { @@ -681,8 +680,7 @@ static const struct regmap_config tas2552_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int tas2552_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tas2552_probe(struct i2c_client *client) { struct device *dev; struct tas2552_data *data; @@ -764,7 +762,7 @@ static struct i2c_driver tas2552_i2c_driver = { .of_match_table = of_match_ptr(tas2552_of_match), .pm = &tas2552_pm, }, - .probe = tas2552_probe, + .probe_new = tas2552_probe, .remove = tas2552_i2c_remove, .id_table = tas2552_id, }; diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c index 1030255219..dc088a1c67 100644 --- a/sound/soc/codecs/tas2562.c +++ b/sound/soc/codecs/tas2562.c @@ -589,7 +589,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2110 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dapm_widget tas2562_dapm_widgets[] = { @@ -629,7 +628,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2562 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops tas2562_speaker_dai_ops = { @@ -754,17 +752,27 @@ static int tas2562_parse_dt(struct tas2562_data *tas2562) return ret; } -static int tas2562_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id tas2562_id[] = { + { "tas2562", TAS2562 }, + { "tas2563", TAS2563 }, + { "tas2564", TAS2564 }, + { "tas2110", TAS2110 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas2562_id); + +static int tas2562_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tas2562_data *data; int ret; + const struct i2c_device_id *id; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + id = i2c_match_id(tas2562_id, client); data->client = client; data->dev = &client->dev; data->model_id = id->driver_data; @@ -792,15 +800,6 @@ static int tas2562_probe(struct i2c_client *client, } -static const struct i2c_device_id tas2562_id[] = { - { "tas2562", TAS2562 }, - { "tas2563", TAS2563 }, - { "tas2564", TAS2564 }, - { "tas2110", TAS2110 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tas2562_id); - #ifdef CONFIG_OF static const struct of_device_id tas2562_of_match[] = { { .compatible = "ti,tas2562", }, @@ -817,7 +816,7 @@ static struct i2c_driver tas2562_i2c_driver = { .name = "tas2562", .of_match_table = of_match_ptr(tas2562_of_match), }, - .probe = tas2562_probe, + .probe_new = tas2562_probe, .id_table = tas2562_id, }; diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index 9265af41c2..846d9d3ecc 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -42,10 +42,12 @@ static void tas2764_reset(struct tas2764_priv *tas2764) gpiod_set_value_cansleep(tas2764->reset_gpio, 0); msleep(20); gpiod_set_value_cansleep(tas2764->reset_gpio, 1); + usleep_range(1000, 2000); } snd_soc_component_write(tas2764->component, TAS2764_SW_RST, TAS2764_RST); + usleep_range(1000, 2000); } static int tas2764_set_bias_level(struct snd_soc_component *component, @@ -107,8 +109,10 @@ static int tas2764_codec_resume(struct snd_soc_component *component) struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); int ret; - if (tas2764->sdz_gpio) + if (tas2764->sdz_gpio) { gpiod_set_value_cansleep(tas2764->sdz_gpio, 1); + usleep_range(1000, 2000); + } ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, TAS2764_PWR_CTRL_MASK, @@ -131,7 +135,8 @@ static const char * const tas2764_ASI1_src[] = { }; static SOC_ENUM_SINGLE_DECL( - tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, 4, tas2764_ASI1_src); + tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, TAS2764_TDM_CFG2_SCFG_SHIFT, + tas2764_ASI1_src); static const struct snd_kcontrol_new tas2764_asi1_mux = SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum); @@ -329,20 +334,22 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_component *component = dai->component; struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); - u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; - int iface; + u8 tdm_rx_start_slot = 0, asi_cfg_0 = 0, asi_cfg_1 = 0; int ret; switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START; + fallthrough; case SND_SOC_DAIFMT_NB_NF: asi_cfg_1 = TAS2764_TDM_CFG1_RX_RISING; break; + case SND_SOC_DAIFMT_IB_IF: + asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START; + fallthrough; case SND_SOC_DAIFMT_IB_NF: asi_cfg_1 = TAS2764_TDM_CFG1_RX_FALLING; break; - default: - dev_err(tas2764->dev, "ASI format Inverse is not found\n"); - return -EINVAL; } ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1, @@ -353,13 +360,13 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: + asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START; + fallthrough; case SND_SOC_DAIFMT_DSP_A: - iface = TAS2764_TDM_CFG2_SCFG_I2S; tdm_rx_start_slot = 1; break; case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_LEFT_J: - iface = TAS2764_TDM_CFG2_SCFG_LEFT_J; tdm_rx_start_slot = 0; break; default: @@ -368,14 +375,15 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1, - TAS2764_TDM_CFG1_MASK, - (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT)); + ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG0, + TAS2764_TDM_CFG0_FRAME_START, + asi_cfg_0); if (ret < 0) return ret; - ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG2, - TAS2764_TDM_CFG2_SCFG_MASK, iface); + ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1, + TAS2764_TDM_CFG1_MASK, + (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT)); if (ret < 0) return ret; @@ -501,8 +509,10 @@ static int tas2764_codec_probe(struct snd_soc_component *component) tas2764->component = component; - if (tas2764->sdz_gpio) + if (tas2764->sdz_gpio) { gpiod_set_value_cansleep(tas2764->sdz_gpio, 1); + usleep_range(1000, 2000); + } tas2764_reset(tas2764); @@ -526,12 +536,12 @@ static int tas2764_codec_probe(struct snd_soc_component *component) } static DECLARE_TLV_DB_SCALE(tas2764_digital_tlv, 1100, 50, 0); -static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10000, 50, 0); +static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10050, 50, 1); static const struct snd_kcontrol_new tas2764_snd_controls[] = { SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0, TAS2764_DVC_MAX, 1, tas2764_playback_volume), - SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 0, 0x14, 0, + SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0, tas2764_digital_tlv), }; @@ -548,7 +558,6 @@ static const struct snd_soc_component_driver soc_component_driver_tas2764 = { .num_dapm_routes = ARRAY_SIZE(tas2764_audio_map), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct reg_default tas2764_reg_defaults[] = { @@ -556,7 +565,7 @@ static const struct reg_default tas2764_reg_defaults[] = { { TAS2764_SW_RST, 0x00 }, { TAS2764_PWR_CTRL, 0x1a }, { TAS2764_DVC, 0x00 }, - { TAS2764_CHNL_0, 0x00 }, + { TAS2764_CHNL_0, 0x28 }, { TAS2764_TDM_CFG0, 0x09 }, { TAS2764_TDM_CFG1, 0x02 }, { TAS2764_TDM_CFG2, 0x0a }, @@ -621,8 +630,7 @@ static int tas2764_parse_dt(struct device *dev, struct tas2764_priv *tas2764) return 0; } -static int tas2764_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tas2764_i2c_probe(struct i2c_client *client) { struct tas2764_priv *tas2764; int result; @@ -678,7 +686,7 @@ static struct i2c_driver tas2764_i2c_driver = { .name = "tas2764", .of_match_table = of_match_ptr(tas2764_of_match), }, - .probe = tas2764_i2c_probe, + .probe_new = tas2764_i2c_probe, .id_table = tas2764_i2c_id, }; module_i2c_driver(tas2764_i2c_driver); diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h index 67d6fd903c..f015f22a08 100644 --- a/sound/soc/codecs/tas2764.h +++ b/sound/soc/codecs/tas2764.h @@ -47,6 +47,7 @@ #define TAS2764_TDM_CFG0_MASK GENMASK(3, 1) #define TAS2764_TDM_CFG0_44_1_48KHZ BIT(3) #define TAS2764_TDM_CFG0_88_2_96KHZ (BIT(3) | BIT(1)) +#define TAS2764_TDM_CFG0_FRAME_START BIT(0) /* TDM Configuration Reg1 */ #define TAS2764_TDM_CFG1 TAS2764_REG(0X0, 0x09) @@ -66,10 +67,7 @@ #define TAS2764_TDM_CFG2_RXS_16BITS 0x0 #define TAS2764_TDM_CFG2_RXS_24BITS BIT(0) #define TAS2764_TDM_CFG2_RXS_32BITS BIT(1) -#define TAS2764_TDM_CFG2_SCFG_MASK GENMASK(5, 4) -#define TAS2764_TDM_CFG2_SCFG_I2S 0x0 -#define TAS2764_TDM_CFG2_SCFG_LEFT_J BIT(4) -#define TAS2764_TDM_CFG2_SCFG_RIGHT_J BIT(5) +#define TAS2764_TDM_CFG2_SCFG_SHIFT 4 /* TDM Configuration Reg3 */ #define TAS2764_TDM_CFG3 TAS2764_REG(0X0, 0x0c) diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index c5ea3b1159..bb653b6641 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -46,34 +46,22 @@ static void tas2770_reset(struct tas2770_priv *tas2770) usleep_range(1000, 2000); } -static int tas2770_set_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) +static int tas2770_update_pwr_ctrl(struct tas2770_priv *tas2770) { - struct tas2770_priv *tas2770 = - snd_soc_component_get_drvdata(component); + struct snd_soc_component *component = tas2770->component; + unsigned int val; + int ret; - switch (level) { - case SND_SOC_BIAS_ON: - snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_ACTIVE); - break; - case SND_SOC_BIAS_STANDBY: - case SND_SOC_BIAS_PREPARE: - snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_MUTE); - break; - case SND_SOC_BIAS_OFF: - snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_SHUTDOWN); - break; + if (tas2770->dac_powered) + val = tas2770->unmuted ? + TAS2770_PWR_CTRL_ACTIVE : TAS2770_PWR_CTRL_MUTE; + else + val = TAS2770_PWR_CTRL_SHUTDOWN; - default: - dev_err(tas2770->dev, "wrong power level setting %d\n", level); - return -EINVAL; - } + ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, + TAS2770_PWR_CTRL_MASK, val); + if (ret < 0) + return ret; return 0; } @@ -114,9 +102,7 @@ static int tas2770_codec_resume(struct snd_soc_component *component) gpiod_set_value_cansleep(tas2770->sdz_gpio, 1); usleep_range(1000, 2000); } else { - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_ACTIVE); + ret = tas2770_update_pwr_ctrl(tas2770); if (ret < 0) return ret; } @@ -152,24 +138,19 @@ static int tas2770_dac_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_MUTE); + tas2770->dac_powered = 1; + ret = tas2770_update_pwr_ctrl(tas2770); break; case SND_SOC_DAPM_PRE_PMD: - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_SHUTDOWN); + tas2770->dac_powered = 0; + ret = tas2770_update_pwr_ctrl(tas2770); break; default: dev_err(tas2770->dev, "Not supported evevt\n"); return -EINVAL; } - if (ret < 0) - return ret; - - return 0; + return ret; } static const struct snd_kcontrol_new isense_switch = @@ -203,21 +184,11 @@ static const struct snd_soc_dapm_route tas2770_audio_map[] = { static int tas2770_mute(struct snd_soc_dai *dai, int mute, int direction) { struct snd_soc_component *component = dai->component; - int ret; - - if (mute) - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_MUTE); - else - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_ACTIVE); - - if (ret < 0) - return ret; + struct tas2770_priv *tas2770 = + snd_soc_component_get_drvdata(component); - return 0; + tas2770->unmuted = !mute; + return tas2770_update_pwr_ctrl(tas2770); } static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth) @@ -337,21 +308,27 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct snd_soc_component *component = dai->component; struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component); - u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; + u8 tdm_rx_start_slot = 0, invert_fpol = 0, fpol_preinv = 0, asi_cfg_1 = 0; int ret; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: - dev_err(tas2770->dev, "ASI format master is not found\n"); + dev_err(tas2770->dev, "ASI invalid DAI clocking\n"); return -EINVAL; } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + invert_fpol = 1; + fallthrough; case SND_SOC_DAIFMT_NB_NF: asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_RSING; break; + case SND_SOC_DAIFMT_IB_IF: + invert_fpol = 1; + fallthrough; case SND_SOC_DAIFMT_IB_NF: asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_FALING; break; @@ -369,15 +346,19 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: tdm_rx_start_slot = 1; + fpol_preinv = 0; break; case SND_SOC_DAIFMT_DSP_A: tdm_rx_start_slot = 0; + fpol_preinv = 1; break; case SND_SOC_DAIFMT_DSP_B: tdm_rx_start_slot = 1; + fpol_preinv = 1; break; case SND_SOC_DAIFMT_LEFT_J: tdm_rx_start_slot = 0; + fpol_preinv = 1; break; default: dev_err(tas2770->dev, @@ -391,6 +372,14 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) if (ret < 0) return ret; + ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_FPOL_MASK, + (fpol_preinv ^ invert_fpol) + ? TAS2770_TDM_CFG_REG0_FPOL_RSING + : TAS2770_TDM_CFG_REG0_FPOL_FALING); + if (ret < 0) + return ret; + return 0; } @@ -489,7 +478,7 @@ static struct snd_soc_dai_driver tas2770_dai_driver[] = { .id = 0, .playback = { .stream_name = "ASI1 Playback", - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = TAS2770_RATES, .formats = TAS2770_FORMATS, @@ -537,7 +526,6 @@ static const struct snd_soc_component_driver soc_component_driver_tas2770 = { .probe = tas2770_codec_probe, .suspend = tas2770_codec_suspend, .resume = tas2770_codec_resume, - .set_bias_level = tas2770_set_bias_level, .controls = tas2770_snd_controls, .num_controls = ARRAY_SIZE(tas2770_snd_controls), .dapm_widgets = tas2770_dapm_widgets, @@ -546,7 +534,6 @@ static const struct snd_soc_component_driver soc_component_driver_tas2770 = { .num_dapm_routes = ARRAY_SIZE(tas2770_audio_map), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int tas2770_register_codec(struct tas2770_priv *tas2770) @@ -672,8 +659,7 @@ static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *tas2770) return 0; } -static int tas2770_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tas2770_i2c_probe(struct i2c_client *client) { struct tas2770_priv *tas2770; int result; @@ -739,7 +725,7 @@ static struct i2c_driver tas2770_i2c_driver = { .name = "tas2770", .of_match_table = of_match_ptr(tas2770_of_match), }, - .probe = tas2770_i2c_probe, + .probe_new = tas2770_i2c_probe, .id_table = tas2770_i2c_id, }; module_i2c_driver(tas2770_i2c_driver); diff --git a/sound/soc/codecs/tas2770.h b/sound/soc/codecs/tas2770.h index d156666bcc..f75f40781a 100644 --- a/sound/soc/codecs/tas2770.h +++ b/sound/soc/codecs/tas2770.h @@ -41,6 +41,9 @@ #define TAS2770_TDM_CFG_REG0_31_44_1_48KHZ 0x6 #define TAS2770_TDM_CFG_REG0_31_88_2_96KHZ 0x8 #define TAS2770_TDM_CFG_REG0_31_176_4_192KHZ 0xa +#define TAS2770_TDM_CFG_REG0_FPOL_MASK BIT(0) +#define TAS2770_TDM_CFG_REG0_FPOL_RSING 0 +#define TAS2770_TDM_CFG_REG0_FPOL_FALING 1 /* TDM Configuration Reg1 */ #define TAS2770_TDM_CFG_REG1 TAS2770_REG(0X0, 0x0B) #define TAS2770_TDM_CFG_REG1_MASK GENMASK(5, 1) @@ -135,6 +138,8 @@ struct tas2770_priv { struct device *dev; int v_sense_slot; int i_sense_slot; + bool dac_powered; + bool unmuted; }; #endif /* __TAS2770__ */ diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 7831c96d0d..a864984225 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -318,7 +318,7 @@ static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai, struct tas5086_private *priv = snd_soc_component_get_drvdata(component); /* The TAS5086 can only be slave to all clocks */ - if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + if ((format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { dev_err(component->dev, "Invalid clocking mode\n"); return -EINVAL; } @@ -888,7 +888,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas5086 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct i2c_device_id tas5086_i2c_id[] = { @@ -911,8 +910,7 @@ static const struct regmap_config tas5086_regmap = { .reg_write = tas5086_reg_write, }; -static int tas5086_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int tas5086_i2c_probe(struct i2c_client *i2c) { struct tas5086_private *priv; struct device *dev = &i2c->dev; @@ -994,7 +992,7 @@ static struct i2c_driver tas5086_i2c_driver = { .of_match_table = of_match_ptr(tas5086_dt_ids), }, .id_table = tas5086_i2c_id, - .probe = tas5086_i2c_probe, + .probe_new = tas5086_i2c_probe, .remove = tas5086_i2c_remove, }; diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index a3e6823769..4e7f20db57 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -756,7 +756,6 @@ static const struct snd_soc_component_driver tas571x_component = { .num_dapm_routes = ARRAY_SIZE(tas571x_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver tas571x_dai = { @@ -774,9 +773,9 @@ static struct snd_soc_dai_driver tas571x_dai = { }; static const struct of_device_id tas571x_of_match[] __maybe_unused; +static const struct i2c_device_id tas571x_i2c_id[]; -static int tas571x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tas571x_i2c_probe(struct i2c_client *client) { struct tas571x_private *priv; struct device *dev = &client->dev; @@ -791,8 +790,11 @@ static int tas571x_i2c_probe(struct i2c_client *client, of_id = of_match_device(tas571x_of_match, dev); if (of_id) priv->chip = of_id->data; - else + else { + const struct i2c_device_id *id = + i2c_match_id(tas571x_i2c_id, client); priv->chip = (void *) id->driver_data; + } priv->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) { @@ -830,7 +832,8 @@ static int tas571x_i2c_probe(struct i2c_client *client, if (IS_ERR(priv->pdn_gpio)) { dev_err(dev, "error requesting pdn_gpio: %ld\n", PTR_ERR(priv->pdn_gpio)); - return PTR_ERR(priv->pdn_gpio); + ret = PTR_ERR(priv->pdn_gpio); + goto disable_regs; } priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", @@ -838,7 +841,8 @@ static int tas571x_i2c_probe(struct i2c_client *client, if (IS_ERR(priv->reset_gpio)) { dev_err(dev, "error requesting reset_gpio: %ld\n", PTR_ERR(priv->reset_gpio)); - return PTR_ERR(priv->reset_gpio); + ret = PTR_ERR(priv->reset_gpio); + goto disable_regs; } else if (priv->reset_gpio) { /* pulse the active low reset line for ~100us */ usleep_range(100, 200); @@ -914,7 +918,7 @@ static struct i2c_driver tas571x_i2c_driver = { .name = "tas571x", .of_match_table = of_match_ptr(tas571x_of_match), }, - .probe = tas571x_i2c_probe, + .probe_new = tas571x_i2c_probe, .remove = tas571x_i2c_remove, .id_table = tas571x_i2c_id, }; diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index 9ff644ddb4..3885c0bf0b 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -89,8 +89,8 @@ static int tas5720_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) u8 serial_format; int ret; - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { - dev_vdbg(component->dev, "DAI Format master is not found\n"); + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { + dev_vdbg(component->dev, "DAI clocking invalid\n"); return -EINVAL; } @@ -572,7 +572,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas5720 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_component_driver soc_component_dev_tas5722 = { @@ -589,7 +588,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas5722 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; /* PCM rates supported by the TAS5720 driver */ @@ -633,12 +631,19 @@ static struct snd_soc_dai_driver tas5720_dai[] = { }, }; -static int tas5720_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id tas5720_id[] = { + { "tas5720", TAS5720 }, + { "tas5722", TAS5722 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas5720_id); + +static int tas5720_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tas5720_data *data; const struct regmap_config *regmap_config; + const struct i2c_device_id *id; int ret; int i; @@ -646,6 +651,7 @@ static int tas5720_probe(struct i2c_client *client, if (!data) return -ENOMEM; + id = i2c_match_id(tas5720_id, client); data->tas5720_client = client; data->devtype = id->driver_data; @@ -704,13 +710,6 @@ static int tas5720_probe(struct i2c_client *client, return 0; } -static const struct i2c_device_id tas5720_id[] = { - { "tas5720", TAS5720 }, - { "tas5722", TAS5722 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tas5720_id); - #if IS_ENABLED(CONFIG_OF) static const struct of_device_id tas5720_of_match[] = { { .compatible = "ti,tas5720", }, @@ -725,7 +724,7 @@ static struct i2c_driver tas5720_i2c_driver = { .name = "tas5720", .of_match_table = of_match_ptr(tas5720_of_match), }, - .probe = tas5720_probe, + .probe_new = tas5720_probe, .id_table = tas5720_id, }; diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c index fa0e81ec87..b1bb614534 100644 --- a/sound/soc/codecs/tas5805m.c +++ b/sound/soc/codecs/tas5805m.c @@ -367,7 +367,6 @@ static const struct snd_soc_component_driver soc_codec_dev_tas5805m = { .num_dapm_routes = ARRAY_SIZE(tas5805m_audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int tas5805m_mute(struct snd_soc_dai *dai, int mute, int direction) diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index 59543d3921..63d2983c3f 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -160,11 +160,11 @@ static int tas6424_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) dev_dbg(component->dev, "%s() fmt=0x%0x\n", __func__, fmt); /* clock masters */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: - dev_err(component->dev, "Invalid DAI master/slave interface\n"); + dev_err(component->dev, "Invalid DAI clocking\n"); return -EINVAL; } @@ -375,7 +375,6 @@ static struct snd_soc_component_driver soc_codec_dev_tas6424 = { .num_dapm_routes = ARRAY_SIZE(tas6424_audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = { @@ -682,8 +681,7 @@ static const struct of_device_id tas6424_of_ids[] = { MODULE_DEVICE_TABLE(of, tas6424_of_ids); #endif -static int tas6424_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tas6424_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tas6424_data *tas6424; @@ -757,7 +755,7 @@ static int tas6424_i2c_probe(struct i2c_client *client, TAS6424_RESET, TAS6424_RESET); if (ret) { dev_err(dev, "unable to reset device: %d\n", ret); - return ret; + goto disable_regs; } INIT_DELAYED_WORK(&tas6424->fault_check_work, tas6424_fault_check_work); @@ -766,10 +764,14 @@ static int tas6424_i2c_probe(struct i2c_client *client, tas6424_dai, ARRAY_SIZE(tas6424_dai)); if (ret < 0) { dev_err(dev, "unable to register codec: %d\n", ret); - return ret; + goto disable_regs; } return 0; + +disable_regs: + regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies), tas6424->supplies); + return ret; } static int tas6424_i2c_remove(struct i2c_client *client) @@ -786,10 +788,8 @@ static int tas6424_i2c_remove(struct i2c_client *client) ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies), tas6424->supplies); - if (ret < 0) { + if (ret < 0) dev_err(dev, "unable to disable supplies: %d\n", ret); - return ret; - } return 0; } @@ -805,7 +805,7 @@ static struct i2c_driver tas6424_i2c_driver = { .name = "tas6424", .of_match_table = of_match_ptr(tas6424_of_ids), }, - .probe = tas6424_i2c_probe, + .probe_new = tas6424_i2c_probe, .remove = tas6424_i2c_remove, .id_table = tas6424_i2c_ids, }; diff --git a/sound/soc/codecs/tda7419.c b/sound/soc/codecs/tda7419.c index 83d220054c..d964e52075 100644 --- a/sound/soc/codecs/tda7419.c +++ b/sound/soc/codecs/tda7419.c @@ -571,8 +571,7 @@ static const struct snd_soc_component_driver tda7419_component_driver = { .num_dapm_routes = ARRAY_SIZE(tda7419_dapm_routes), }; -static int tda7419_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int tda7419_probe(struct i2c_client *i2c) { struct tda7419_data *tda7419; int i, ret; @@ -630,7 +629,7 @@ static struct i2c_driver tda7419_driver = { .name = "tda7419", .of_match_table = tda7419_of_match, }, - .probe = tda7419_probe, + .probe_new = tda7419_probe, .id_table = tda7419_i2c_id, }; diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c index 3d8e8c2276..9f7902ec40 100644 --- a/sound/soc/codecs/tfa9879.c +++ b/sound/soc/codecs/tfa9879.c @@ -111,8 +111,8 @@ static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) int i2s_set; int sck_pol; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -235,7 +235,6 @@ static const struct snd_soc_component_driver tfa9879_component = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config tfa9879_regmap = { diff --git a/sound/soc/codecs/tfa989x.c b/sound/soc/codecs/tfa989x.c index dc86852752..1c27429b9a 100644 --- a/sound/soc/codecs/tfa989x.c +++ b/sound/soc/codecs/tfa989x.c @@ -40,12 +40,14 @@ #define TFA989X_I2S_SEL_REG 0x0a #define TFA989X_I2S_SEL_REG_SPKR_MSK GENMASK(10, 9) /* speaker impedance */ #define TFA989X_I2S_SEL_REG_DCFG_MSK GENMASK(14, 11) /* DCDC compensation */ +#define TFA989X_HIDE_UNHIDE_KEY 0x40 #define TFA989X_PWM_CONTROL 0x41 #define TFA989X_CURRENTSENSE1 0x46 #define TFA989X_CURRENTSENSE2 0x47 #define TFA989X_CURRENTSENSE3 0x48 #define TFA989X_CURRENTSENSE4 0x49 +#define TFA9890_REVISION 0x80 #define TFA9895_REVISION 0x12 #define TFA9897_REVISION 0x97 @@ -136,7 +138,6 @@ static const struct snd_soc_component_driver tfa989x_component = { .num_dapm_routes = ARRAY_SIZE(tfa989x_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const unsigned int tfa989x_rates[] = { @@ -188,6 +189,33 @@ static struct snd_soc_dai_driver tfa989x_dai = { .ops = &tfa989x_dai_ops, }; +static int tfa9890_init(struct regmap *regmap) +{ + int ret; + + /* unhide keys to allow updating them */ + ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x5a6b); + if (ret) + return ret; + + /* update PLL registers */ + ret = regmap_set_bits(regmap, 0x59, 0x3); + if (ret) + return ret; + + /* hide keys again */ + ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x0000); + if (ret) + return ret; + + return regmap_write(regmap, TFA989X_CURRENTSENSE2, 0x7BE1); +} + +static const struct tfa989x_rev tfa9890_rev = { + .rev = TFA9890_REVISION, + .init = tfa9890_init, +}; + static const struct reg_sequence tfa9895_reg_init[] = { /* some other registers must be set for optimal amplifier behaviour */ { TFA989X_BAT_PROT, 0x13ab }, @@ -376,6 +404,7 @@ static int tfa989x_i2c_probe(struct i2c_client *i2c) } static const struct of_device_id tfa989x_of_match[] = { + { .compatible = "nxp,tfa9890", .data = &tfa9890_rev }, { .compatible = "nxp,tfa9895", .data = &tfa9895_rev }, { .compatible = "nxp,tfa9897", .data = &tfa9897_rev }, { } diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c index ae18982ac3..748998e48a 100644 --- a/sound/soc/codecs/tlv320adc3xxx.c +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -1152,20 +1152,20 @@ static int adc3xxx_hw_params(struct snd_pcm_substream *substream, return i; /* select data word length */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: iface_len = ADC3XXX_IFACE_16BITS; width = 16; break; - case SNDRV_PCM_FORMAT_S20_3LE: + case 20: iface_len = ADC3XXX_IFACE_20BITS; width = 20; break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: iface_len = ADC3XXX_IFACE_24BITS; width = 24; break; - case SNDRV_PCM_FORMAT_S32_LE: + case 32: iface_len = ADC3XXX_IFACE_32BITS; width = 32; break; @@ -1252,8 +1252,7 @@ static int adc3xxx_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) int master = 0; int ret; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { case SND_SOC_DAIFMT_CBP_CFP: master = 1; clkdir = ADC3XXX_BCLK_MASTER | ADC3XXX_WCLK_MASTER; @@ -1335,13 +1334,21 @@ static const struct snd_soc_component_driver soc_component_dev_adc3xxx = { .num_dapm_widgets = ARRAY_SIZE(adc3xxx_dapm_widgets), .dapm_routes = adc3xxx_intercon, .num_dapm_routes = ARRAY_SIZE(adc3xxx_intercon), + .endianness = 1, }; -static int adc3xxx_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id adc3xxx_i2c_id[] = { + { "tlv320adc3001", ADC3001 }, + { "tlv320adc3101", ADC3101 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, adc3xxx_i2c_id); + +static int adc3xxx_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct adc3xxx *adc3xxx = NULL; + const struct i2c_device_id *id; int ret; adc3xxx = devm_kzalloc(dev, sizeof(struct adc3xxx), GFP_KERNEL); @@ -1394,6 +1401,7 @@ static int adc3xxx_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, adc3xxx); + id = i2c_match_id(adc3xxx_i2c_id, i2c); adc3xxx->type = id->driver_data; /* Reset codec chip */ @@ -1436,19 +1444,12 @@ static const struct of_device_id tlv320adc3xxx_of_match[] = { }; MODULE_DEVICE_TABLE(of, tlv320adc3xxx_of_match); -static const struct i2c_device_id adc3xxx_i2c_id[] = { - { "tlv320adc3001", ADC3001 }, - { "tlv320adc3101", ADC3101 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, adc3xxx_i2c_id); - static struct i2c_driver adc3xxx_i2c_driver = { .driver = { .name = "tlv320adc3xxx-codec", .of_match_table = tlv320adc3xxx_of_match, }, - .probe = adc3xxx_i2c_probe, + .probe_new = adc3xxx_i2c_probe, .remove = adc3xxx_i2c_remove, .id_table = adc3xxx_i2c_id, }; diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 32b120d624..2844a9d2bc 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -33,7 +33,6 @@ struct adcx140_priv { bool micbias_vg; unsigned int dai_fmt; - unsigned int tdm_delay; unsigned int slot_width; }; @@ -713,16 +712,14 @@ static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai, bool inverted_bclk = false; /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface_reg2 |= ADCX140_BCLK_FSYNC_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: default: - dev_err(component->dev, "Invalid DAI master/slave interface\n"); + dev_err(component->dev, "Invalid DAI clock provider\n"); return -EINVAL; } @@ -792,12 +789,13 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai, { struct snd_soc_component *component = codec_dai->component; struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component); - unsigned int lsb; - /* TDM based on DSP mode requires slots to be adjacent */ - lsb = __ffs(tx_mask); - if ((lsb + 1) != __fls(tx_mask)) { - dev_err(component->dev, "Invalid mask, slots must be adjacent\n"); + /* + * The chip itself supports arbitrary masks, but the driver currently + * only supports adjacent slots beginning at the first slot. + */ + if (tx_mask != GENMASK(__fls(tx_mask), 0)) { + dev_err(component->dev, "Only lower adjacent slots are supported\n"); return -EINVAL; } @@ -812,7 +810,6 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai, return -EINVAL; } - adcx140->tdm_delay = lsb; adcx140->slot_width = slot_width; return 0; @@ -1055,7 +1052,6 @@ static const struct snd_soc_component_driver soc_codec_driver_adcx140 = { .idle_bias_on = 0, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver adcx140_dai_driver[] = { @@ -1083,8 +1079,14 @@ static const struct of_device_id tlv320adcx140_of_match[] = { MODULE_DEVICE_TABLE(of, tlv320adcx140_of_match); #endif -static int adcx140_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static void adcx140_disable_regulator(void *arg) +{ + struct adcx140_priv *adcx140 = arg; + + regulator_disable(adcx140->supply_areg); +} + +static int adcx140_i2c_probe(struct i2c_client *i2c) { struct adcx140_priv *adcx140; int ret; @@ -1113,6 +1115,10 @@ static int adcx140_i2c_probe(struct i2c_client *i2c, dev_err(adcx140->dev, "Failed to enable areg\n"); return ret; } + + ret = devm_add_action_or_reset(&i2c->dev, adcx140_disable_regulator, adcx140); + if (ret) + return ret; } adcx140->regmap = devm_regmap_init_i2c(i2c, &adcx140_i2c_regmap); @@ -1143,7 +1149,7 @@ static struct i2c_driver adcx140_i2c_driver = { .name = "tlv320adcx140-codec", .of_match_table = of_match_ptr(tlv320adcx140_of_match), }, - .probe = adcx140_i2c_probe, + .probe_new = adcx140_i2c_probe, .id_table = adcx140_i2c_id, }; module_i2c_driver(adcx140_i2c_driver); diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c index dbb8f96927..1f97673a1c 100644 --- a/sound/soc/codecs/tlv320aic23-i2c.c +++ b/sound/soc/codecs/tlv320aic23-i2c.c @@ -16,8 +16,7 @@ #include "tlv320aic23.h" -static int tlv320aic23_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *i2c_id) +static int tlv320aic23_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; @@ -48,7 +47,7 @@ static struct i2c_driver tlv320aic23_i2c_driver = { .name = "tlv320aic23-codec", .of_match_table = of_match_ptr(tlv320aic23_of_match), }, - .probe = tlv320aic23_i2c_probe, + .probe_new = tlv320aic23_i2c_probe, .id_table = tlv320aic23_id, }; diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 2400093e2c..c47aa4d416 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -429,12 +429,11 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai, iface_reg = snd_soc_component_read(component, TLV320AIC23_DIGT_FMT) & (~0x03); - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface_reg |= TLV320AIC23_MS_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: iface_reg &= ~TLV320AIC23_MS_MASTER; break; default: @@ -587,7 +586,6 @@ static const struct snd_soc_component_driver soc_component_dev_tlv320aic23 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; int tlv320aic23_probe(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 077415a572..8bae4b4750 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -32,7 +32,7 @@ struct aic26 { struct spi_device *spi; struct regmap *regmap; struct snd_soc_component *component; - int master; + int clock_provider; int datfm; int mclk; @@ -117,8 +117,8 @@ static int aic26_hw_params(struct snd_pcm_substream *substream, reg = dval << 2; snd_soc_component_write(component, AIC26_REG_PLL_PROG2, reg); - /* Audio Control 3 (master mode, fsref rate) */ - if (aic26->master) + /* Audio Control 3 (clock provider mode, fsref rate) */ + if (aic26->clock_provider) reg = 0x0800; if (fsref == 48000) reg = 0x2000; @@ -178,10 +178,9 @@ static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n", codec_dai, fmt); - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: aic26->master = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: aic26->master = 0; break; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: aic26->clock_provider = 1; break; + case SND_SOC_DAIFMT_CBC_CFC: aic26->clock_provider = 0; break; default: dev_dbg(&aic26->spi->dev, "bad master\n"); return -EINVAL; } @@ -332,7 +331,6 @@ static const struct snd_soc_component_driver aic26_soc_component_dev = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config aic26_regmap = { @@ -363,7 +361,7 @@ static int aic26_spi_probe(struct spi_device *spi) /* Initialize the driver data */ aic26->spi = spi; dev_set_drvdata(&spi->dev, aic26); - aic26->master = 1; + aic26->clock_provider = 1; ret = devm_snd_soc_register_component(&spi->dev, &aic26_soc_component_dev, &aic26_dai, 1); diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 8331dc26bc..0847302121 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1033,8 +1033,8 @@ static int aic31xx_clock_master_routes(struct snd_soc_component *component, struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component); int ret; - fmt &= SND_SOC_DAIFMT_MASTER_MASK; - if (fmt == SND_SOC_DAIFMT_CBS_CFS && + fmt &= SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; + if (fmt == SND_SOC_DAIFMT_CBC_CFC && aic31xx->master_dapm_route_applied) { /* * Remove the DAPM route(s) for codec clock master modes, @@ -1051,7 +1051,7 @@ static int aic31xx_clock_master_routes(struct snd_soc_component *component, return ret; aic31xx->master_dapm_route_applied = false; - } else if (fmt != SND_SOC_DAIFMT_CBS_CFS && + } else if (fmt != SND_SOC_DAIFMT_CBC_CFC && !aic31xx->master_dapm_route_applied) { /* * Add the needed DAPM route(s) for codec clock master modes, @@ -1083,21 +1083,20 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, dev_dbg(component->dev, "## %s: fmt = 0x%x\n", __func__, fmt); - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: iface_reg1 |= AIC31XX_WCLK_MASTER; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: iface_reg1 |= AIC31XX_BCLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: - dev_err(component->dev, "Invalid DAI master/slave interface\n"); + dev_err(component->dev, "Invalid DAI clock provider\n"); return -EINVAL; } @@ -1418,7 +1417,6 @@ static const struct snd_soc_component_driver soc_codec_driver_aic31xx = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops aic31xx_dai_ops = { @@ -1628,11 +1626,24 @@ static void aic31xx_configure_ocmv(struct aic31xx_priv *priv) } } -static int aic31xx_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id aic31xx_i2c_id[] = { + { "tlv320aic310x", AIC3100 }, + { "tlv320aic311x", AIC3110 }, + { "tlv320aic3100", AIC3100 }, + { "tlv320aic3110", AIC3110 }, + { "tlv320aic3120", AIC3120 }, + { "tlv320aic3111", AIC3111 }, + { "tlv320dac3100", DAC3100 }, + { "tlv320dac3101", DAC3101 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); + +static int aic31xx_i2c_probe(struct i2c_client *i2c) { struct aic31xx_priv *aic31xx; unsigned int micbias_value = MICBIAS_2_0V; + const struct i2c_device_id *id = i2c_match_id(aic31xx_i2c_id, i2c); int i, ret; dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__, @@ -1729,26 +1740,13 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, ARRAY_SIZE(aic31xx_dai_driver)); } -static const struct i2c_device_id aic31xx_i2c_id[] = { - { "tlv320aic310x", AIC3100 }, - { "tlv320aic311x", AIC3110 }, - { "tlv320aic3100", AIC3100 }, - { "tlv320aic3110", AIC3110 }, - { "tlv320aic3120", AIC3120 }, - { "tlv320aic3111", AIC3111 }, - { "tlv320dac3100", DAC3100 }, - { "tlv320dac3101", DAC3101 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); - static struct i2c_driver aic31xx_i2c_driver = { .driver = { .name = "tlv320aic31xx-codec", .of_match_table = of_match_ptr(tlv320aic31xx_of_match), .acpi_match_table = ACPI_PTR(aic31xx_acpi_match), }, - .probe = aic31xx_i2c_probe, + .probe_new = aic31xx_i2c_probe, .id_table = aic31xx_i2c_id, }; module_i2c_driver(aic31xx_i2c_driver); diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c index ed70e3d9ba..0645239901 100644 --- a/sound/soc/codecs/tlv320aic32x4-i2c.c +++ b/sound/soc/codecs/tlv320aic32x4-i2c.c @@ -17,9 +17,9 @@ #include "tlv320aic32x4.h" static const struct of_device_id aic32x4_of_id[]; +static const struct i2c_device_id aic32x4_i2c_id[]; -static int aic32x4_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int aic32x4_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; struct regmap_config config; @@ -35,7 +35,10 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, oid = of_match_node(aic32x4_of_id, i2c->dev.of_node); dev_set_drvdata(&i2c->dev, (void *)oid->data); - } else if (id) { + } else { + const struct i2c_device_id *id; + + id = i2c_match_id(aic32x4_i2c_id, i2c); dev_set_drvdata(&i2c->dev, (void *)id->driver_data); } @@ -70,7 +73,7 @@ static struct i2c_driver aic32x4_i2c_driver = { .name = "tlv320aic32x4", .of_match_table = aic32x4_of_id, }, - .probe = aic32x4_i2c_probe, + .probe_new = aic32x4_i2c_probe, .remove = aic32x4_i2c_remove, .id_table = aic32x4_i2c_id, }; diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 8f42fd7bc0..ffe1828a4b 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -49,6 +49,8 @@ struct aic32x4_priv { struct aic32x4_setup_data *setup; struct device *dev; enum aic32x4_type type; + + unsigned int fmt; }; static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w, @@ -611,19 +613,19 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_component *component = codec_dai->component; + struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); u8 iface_reg_1 = 0; u8 iface_reg_2 = 0; u8 iface_reg_3 = 0; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface_reg_1 |= AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: - printk(KERN_ERR "aic32x4: invalid DAI master/slave interface\n"); + printk(KERN_ERR "aic32x4: invalid clock provider\n"); return -EINVAL; } @@ -654,6 +656,8 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } + aic32x4->fmt = fmt; + snd_soc_component_update_bits(component, AIC32X4_IFACE1, AIC32X4_IFACE1_DATATYPE_MASK | AIC32X4_IFACE1_MASTER_MASK, iface_reg_1); @@ -758,6 +762,10 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, return -EINVAL; } + /* PCM over I2S is always 2-channel */ + if ((aic32x4->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) + channels = 2; + madc = DIV_ROUND_UP((32 * adc_resource_class), aosr); max_dosr = (AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment) * dosr_increment; @@ -1078,7 +1086,6 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = { @@ -1200,7 +1207,6 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 = .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, diff --git a/sound/soc/codecs/tlv320aic3x-i2c.c b/sound/soc/codecs/tlv320aic3x-i2c.c index 2f272bc3f5..7bd9ce08bb 100644 --- a/sound/soc/codecs/tlv320aic3x-i2c.c +++ b/sound/soc/codecs/tlv320aic3x-i2c.c @@ -17,10 +17,21 @@ #include "tlv320aic3x.h" -static int aic3x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +static const struct i2c_device_id aic3x_i2c_id[] = { + { "tlv320aic3x", AIC3X_MODEL_3X }, + { "tlv320aic33", AIC3X_MODEL_33 }, + { "tlv320aic3007", AIC3X_MODEL_3007 }, + { "tlv320aic3104", AIC3X_MODEL_3104 }, + { "tlv320aic3106", AIC3X_MODEL_3106 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); + +static int aic3x_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; struct regmap_config config; + const struct i2c_device_id *id = i2c_match_id(aic3x_i2c_id, i2c); config = aic3x_regmap; config.reg_bits = 8; @@ -37,16 +48,6 @@ static int aic3x_i2c_remove(struct i2c_client *i2c) return 0; } -static const struct i2c_device_id aic3x_i2c_id[] = { - { "tlv320aic3x", AIC3X_MODEL_3X }, - { "tlv320aic33", AIC3X_MODEL_33 }, - { "tlv320aic3007", AIC3X_MODEL_3007 }, - { "tlv320aic3104", AIC3X_MODEL_3104 }, - { "tlv320aic3106", AIC3X_MODEL_3106 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); - static const struct of_device_id aic3x_of_id[] = { { .compatible = "ti,tlv320aic3x", }, { .compatible = "ti,tlv320aic33" }, @@ -62,7 +63,7 @@ static struct i2c_driver aic3x_i2c_driver = { .name = "tlv320aic3x", .of_match_table = aic3x_of_id, }, - .probe = aic3x_i2c_probe, + .probe_new = aic3x_i2c_probe, .remove = aic3x_i2c_remove, .id_table = aic3x_i2c_id, }; diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index d53037b150..08938801da 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1253,22 +1253,21 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, iface_areg = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLA) & 0x3f; iface_breg = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLB) & 0x3f; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: aic3x->master = 1; iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: aic3x->master = 0; iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER); break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: aic3x->master = 1; iface_areg |= BIT_CLK_MASTER; iface_areg &= ~WORD_CLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: aic3x->master = 1; iface_areg |= WORD_CLK_MASTER; iface_areg &= ~BIT_CLK_MASTER; @@ -1698,7 +1697,6 @@ static const struct snd_soc_component_driver soc_component_dev_aic3x = { .num_dapm_routes = ARRAY_SIZE(intercon), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static void aic3x_configure_ocmv(struct device *dev, struct aic3x_priv *aic3x) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 48572d66cb..17ae3b1d96 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1317,16 +1317,14 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, aictrl_a = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_A); aictrl_b = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B); - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - /* Codec Master */ + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: aictrl_a |= (DAC33_MSBCLK | DAC33_MSWCLK); break; - case SND_SOC_DAIFMT_CBS_CFS: - /* Codec Slave */ + case SND_SOC_DAIFMT_CBC_CFC: if (dac33->fifo_mode) { - dev_err(component->dev, "FIFO mode requires master mode\n"); + dev_err(component->dev, "FIFO mode requires provider mode\n"); return -EINVAL; } else aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK); @@ -1433,7 +1431,6 @@ static const struct snd_soc_component_driver soc_component_dev_tlv320dac33 = { .num_dapm_routes = ARRAY_SIZE(audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #define DAC33_RATES (SNDRV_PCM_RATE_44100 | \ @@ -1463,8 +1460,7 @@ static struct snd_soc_dai_driver dac33_dai = { .ops = &dac33_dai_ops, }; -static int dac33_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int dac33_i2c_probe(struct i2c_client *client) { struct tlv320dac33_platform_data *pdata; struct tlv320dac33_priv *dac33; @@ -1566,7 +1562,7 @@ static struct i2c_driver tlv320dac33_i2c_driver = { .driver = { .name = "tlv320dac33-codec", }, - .probe = dac33_i2c_probe, + .probe_new = dac33_i2c_probe, .remove = dac33_i2c_remove, .id_table = tlv320dac33_i2c_id, }; diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index e2d7ae615c..8c00db3299 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -209,13 +209,20 @@ static const struct regmap_config tpa6130a2_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int tpa6130a2_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id tpa6130a2_id[] = { + { "tpa6130a2", TPA6130A2 }, + { "tpa6140a2", TPA6140A2 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tpa6130a2_id); + +static int tpa6130a2_probe(struct i2c_client *client) { struct device *dev; struct tpa6130a2_data *data; struct tpa6130a2_platform_data *pdata = client->dev.platform_data; struct device_node *np = client->dev.of_node; + const struct i2c_device_id *id; const char *regulator; unsigned int version; int ret; @@ -244,6 +251,7 @@ static int tpa6130a2_probe(struct i2c_client *client, i2c_set_clientdata(client, data); + id = i2c_match_id(tpa6130a2_id, client); data->id = id->driver_data; if (data->power_gpio >= 0) { @@ -297,13 +305,6 @@ static int tpa6130a2_probe(struct i2c_client *client, &tpa6130a2_component_driver, NULL, 0); } -static const struct i2c_device_id tpa6130a2_id[] = { - { "tpa6130a2", TPA6130A2 }, - { "tpa6140a2", TPA6140A2 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tpa6130a2_id); - #if IS_ENABLED(CONFIG_OF) static const struct of_device_id tpa6130a2_of_match[] = { { .compatible = "ti,tpa6130a2", }, @@ -318,7 +319,7 @@ static struct i2c_driver tpa6130a2_i2c_driver = { .name = "tpa6130a2", .of_match_table = of_match_ptr(tpa6130a2_of_match), }, - .probe = tpa6130a2_probe, + .probe_new = tpa6130a2_probe, .id_table = tpa6130a2_id, }; diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 962f5d4837..d8ab0810fc 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -282,8 +282,7 @@ static int ts3a227e_parse_device_property(struct ts3a227e *ts3a227e, return 0; } -static int ts3a227e_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ts3a227e_i2c_probe(struct i2c_client *i2c) { struct ts3a227e *ts3a227e; struct device *dev = &i2c->dev; @@ -389,7 +388,7 @@ static struct i2c_driver ts3a227e_driver = { .of_match_table = of_match_ptr(ts3a227e_of_match), .acpi_match_table = ACPI_PTR(ts3a227e_acpi_match), }, - .probe = ts3a227e_i2c_probe, + .probe_new = ts3a227e_i2c_probe, .id_table = ts3a227e_i2c_ids, }; module_i2c_driver(ts3a227e_driver); diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index 5b63e017a4..fa0c525189 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -1358,7 +1358,6 @@ static const struct snd_soc_component_driver soc_codec_dev_tscs42xx = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static inline void init_coeff_ram_cache(struct tscs42xx *tscs42xx) @@ -1409,8 +1408,7 @@ static const struct reg_sequence tscs42xx_patch[] = { static char const * const src_names[TSCS42XX_PLL_SRC_CNT] = { "xtal", "mclk1", "mclk2"}; -static int tscs42xx_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int tscs42xx_i2c_probe(struct i2c_client *i2c) { struct tscs42xx *tscs42xx; int src; @@ -1505,7 +1503,7 @@ static struct i2c_driver tscs42xx_i2c_driver = { .name = "tscs42xx", .of_match_table = tscs42xx_of_match, }, - .probe = tscs42xx_i2c_probe, + .probe_new = tscs42xx_i2c_probe, .id_table = tscs42xx_i2c_id, }; diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c index 7e1826d6f0..38622bc247 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -3120,18 +3120,17 @@ static int set_aif_sample_format(struct snd_soc_component *component, unsigned int width; int ret; - switch (format) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (snd_pcm_format_width(format)) { + case 16: width = FV_WL_16; break; - case SNDRV_PCM_FORMAT_S20_3LE: + case 20: width = FV_WL_20; break; - case SNDRV_PCM_FORMAT_S24_3LE: + case 24: width = FV_WL_24; break; - case SNDRV_PCM_FORMAT_S24_LE: - case SNDRV_PCM_FORMAT_S32_LE: + case 32: width = FV_WL_32; break; default: @@ -3326,6 +3325,7 @@ static const struct snd_soc_component_driver soc_component_dev_tscs454 = { .num_dapm_routes = ARRAY_SIZE(tscs454_intercon), .controls = tscs454_snd_controls, .num_controls = ARRAY_SIZE(tscs454_snd_controls), + .endianness = 1, }; #define TSCS454_RATES SNDRV_PCM_RATE_8000_96000 @@ -3400,8 +3400,7 @@ static struct snd_soc_dai_driver tscs454_dais[] = { static char const * const src_names[] = { "xtal", "mclk1", "mclk2", "bclk"}; -static int tscs454_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int tscs454_i2c_probe(struct i2c_client *i2c) { struct tscs454 *tscs454; int src; @@ -3474,7 +3473,7 @@ static struct i2c_driver tscs454_i2c_driver = { .name = "tscs454", .of_match_table = tscs454_of_match, }, - .probe = tscs454_i2c_probe, + .probe_new = tscs454_i2c_probe, .id_table = tscs454_i2c_id, }; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 0ba3546ef8..e48768233e 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -34,6 +34,14 @@ #define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1) +struct twl4030_board_params { + unsigned int digimic_delay; /* in ms */ + unsigned int ramp_delay_value; + unsigned int offset_cncl_path; + unsigned int hs_extmute:1; + int hs_extmute_gpio; +}; + /* codec private data */ struct twl4030_priv { unsigned int codec_powered; @@ -58,7 +66,7 @@ struct twl4030_priv { u8 carkitl_enabled, carkitr_enabled; u8 ctl_cache[TWL4030_REG_PRECKR_CTL - TWL4030_REG_EAR_CTL + 1]; - struct twl4030_codec_data *pdata; + struct twl4030_board_params *board_params; }; static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030) @@ -193,73 +201,71 @@ static void twl4030_codec_enable(struct snd_soc_component *component, int enable udelay(10); } -static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata, - struct device_node *node) +static void +twl4030_get_board_param_values(struct twl4030_board_params *board_params, + struct device_node *node) { int value; - of_property_read_u32(node, "ti,digimic_delay", - &pdata->digimic_delay); - of_property_read_u32(node, "ti,ramp_delay_value", - &pdata->ramp_delay_value); - of_property_read_u32(node, "ti,offset_cncl_path", - &pdata->offset_cncl_path); + of_property_read_u32(node, "ti,digimic_delay", &board_params->digimic_delay); + of_property_read_u32(node, "ti,ramp_delay_value", &board_params->ramp_delay_value); + of_property_read_u32(node, "ti,offset_cncl_path", &board_params->offset_cncl_path); if (!of_property_read_u32(node, "ti,hs_extmute", &value)) - pdata->hs_extmute = value; + board_params->hs_extmute = value; - pdata->hs_extmute_gpio = of_get_named_gpio(node, - "ti,hs_extmute_gpio", 0); - if (gpio_is_valid(pdata->hs_extmute_gpio)) - pdata->hs_extmute = 1; + board_params->hs_extmute_gpio = of_get_named_gpio(node, "ti,hs_extmute_gpio", 0); + if (gpio_is_valid(board_params->hs_extmute_gpio)) + board_params->hs_extmute = 1; } -static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_component *component) +static struct twl4030_board_params* +twl4030_get_board_params(struct snd_soc_component *component) { - struct twl4030_codec_data *pdata = dev_get_platdata(component->dev); + struct twl4030_board_params *board_params = NULL; struct device_node *twl4030_codec_node = NULL; twl4030_codec_node = of_get_child_by_name(component->dev->parent->of_node, "codec"); - if (!pdata && twl4030_codec_node) { - pdata = devm_kzalloc(component->dev, - sizeof(struct twl4030_codec_data), - GFP_KERNEL); - if (!pdata) { + if (twl4030_codec_node) { + board_params = devm_kzalloc(component->dev, + sizeof(struct twl4030_board_params), + GFP_KERNEL); + if (!board_params) { of_node_put(twl4030_codec_node); return NULL; } - twl4030_setup_pdata_of(pdata, twl4030_codec_node); + twl4030_get_board_param_values(board_params, twl4030_codec_node); of_node_put(twl4030_codec_node); } - return pdata; + return board_params; } static void twl4030_init_chip(struct snd_soc_component *component) { - struct twl4030_codec_data *pdata; + struct twl4030_board_params *board_params; struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); u8 reg, byte; int i = 0; - pdata = twl4030_get_pdata(component); + board_params = twl4030_get_board_params(component); - if (pdata && pdata->hs_extmute) { - if (gpio_is_valid(pdata->hs_extmute_gpio)) { + if (board_params && board_params->hs_extmute) { + if (gpio_is_valid(board_params->hs_extmute_gpio)) { int ret; - if (!pdata->hs_extmute_gpio) + if (!board_params->hs_extmute_gpio) dev_warn(component->dev, "Extmute GPIO is 0 is this correct?\n"); - ret = gpio_request_one(pdata->hs_extmute_gpio, + ret = gpio_request_one(board_params->hs_extmute_gpio, GPIOF_OUT_INIT_LOW, "hs_extmute"); if (ret) { dev_err(component->dev, "Failed to get hs_extmute GPIO\n"); - pdata->hs_extmute_gpio = -1; + board_params->hs_extmute_gpio = -1; } } else { u8 pin_mux; @@ -290,14 +296,14 @@ static void twl4030_init_chip(struct snd_soc_component *component) twl4030_write(component, TWL4030_REG_ARXR2_APGA_CTL, 0x32); /* Machine dependent setup */ - if (!pdata) + if (!board_params) return; - twl4030->pdata = pdata; + twl4030->board_params = board_params; reg = twl4030_read(component, TWL4030_REG_HS_POPN_SET); reg &= ~TWL4030_RAMP_DELAY; - reg |= (pdata->ramp_delay_value << 2); + reg |= (board_params->ramp_delay_value << 2); twl4030_write(component, TWL4030_REG_HS_POPN_SET, reg); /* initiate offset cancellation */ @@ -305,7 +311,7 @@ static void twl4030_init_chip(struct snd_soc_component *component) reg = twl4030_read(component, TWL4030_REG_ANAMICL); reg &= ~TWL4030_OFFSET_CNCL_SEL; - reg |= pdata->offset_cncl_path; + reg |= board_params->offset_cncl_path; twl4030_write(component, TWL4030_REG_ANAMICL, reg | TWL4030_CNCL_OFFSET_START); @@ -692,7 +698,7 @@ static void headset_ramp(struct snd_soc_component *component, int ramp) { unsigned char hs_gain, hs_pop; struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); - struct twl4030_codec_data *pdata = twl4030->pdata; + struct twl4030_board_params *board_params = twl4030->board_params; /* Base values for ramp delay calculation: 2^19 - 2^26 */ unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864}; @@ -705,9 +711,9 @@ static void headset_ramp(struct snd_soc_component *component, int ramp) /* Enable external mute control, this dramatically reduces * the pop-noise */ - if (pdata && pdata->hs_extmute) { - if (gpio_is_valid(pdata->hs_extmute_gpio)) { - gpio_set_value(pdata->hs_extmute_gpio, 1); + if (board_params && board_params->hs_extmute) { + if (gpio_is_valid(board_params->hs_extmute_gpio)) { + gpio_set_value(board_params->hs_extmute_gpio, 1); } else { hs_pop |= TWL4030_EXTMUTE; twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop); @@ -741,9 +747,9 @@ static void headset_ramp(struct snd_soc_component *component, int ramp) } /* Disable external mute */ - if (pdata && pdata->hs_extmute) { - if (gpio_is_valid(pdata->hs_extmute_gpio)) { - gpio_set_value(pdata->hs_extmute_gpio, 0); + if (board_params && board_params->hs_extmute) { + if (gpio_is_valid(board_params->hs_extmute_gpio)) { + gpio_set_value(board_params->hs_extmute_gpio, 0); } else { hs_pop &= ~TWL4030_EXTMUTE; twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop); @@ -806,10 +812,10 @@ static int digimic_event(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); - struct twl4030_codec_data *pdata = twl4030->pdata; + struct twl4030_board_params *board_params = twl4030->board_params; - if (pdata && pdata->digimic_delay) - twl4030_wait_ms(pdata->digimic_delay); + if (board_params && board_params->digimic_delay) + twl4030_wait_ms(board_params->digimic_delay); return 0; } @@ -2168,10 +2174,11 @@ static int twl4030_soc_probe(struct snd_soc_component *component) static void twl4030_soc_remove(struct snd_soc_component *component) { struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); - struct twl4030_codec_data *pdata = twl4030->pdata; + struct twl4030_board_params *board_params = twl4030->board_params; - if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio)) - gpio_free(pdata->hs_extmute_gpio); + if (board_params && board_params->hs_extmute && + gpio_is_valid(board_params->hs_extmute_gpio)) + gpio_free(board_params->hs_extmute_gpio); } static const struct snd_soc_component_driver soc_component_dev_twl4030 = { @@ -2188,7 +2195,6 @@ static const struct snd_soc_component_driver soc_component_dev_twl4030 = { .num_dapm_routes = ARRAY_SIZE(intercon), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int twl4030_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index b37203336c..dd5ee5dc0c 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1153,7 +1153,6 @@ static const struct snd_soc_component_driver soc_component_dev_twl6040 = { .suspend_bias_off = 1, .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int twl6040_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/uda1334.c b/sound/soc/codecs/uda1334.c index 8670a2a05a..eace965336 100644 --- a/sound/soc/codecs/uda1334.c +++ b/sound/soc/codecs/uda1334.c @@ -169,7 +169,7 @@ static int uda1334_set_dai_sysclk(struct snd_soc_dai *codec_dai, static int uda1334_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK | - SND_SOC_DAIFMT_MASTER_MASK); + SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK); if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC)) { @@ -236,7 +236,6 @@ static const struct snd_soc_component_driver soc_component_dev_uda1334 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id uda1334_of_match[] = { diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 037833c509..2db3d8a60c 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -527,7 +527,6 @@ static const struct snd_soc_component_driver soc_component_dev_uda134x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config uda134x_regmap_config = { diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 13060a9a23..fdaaee8451 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -736,11 +736,9 @@ static const struct snd_soc_component_driver soc_component_dev_uda1380 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int uda1380_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int uda1380_i2c_probe(struct i2c_client *i2c) { struct uda1380_platform_data *pdata = i2c->dev.platform_data; struct uda1380_priv *uda1380; @@ -800,7 +798,7 @@ static struct i2c_driver uda1380_i2c_driver = { .name = "uda1380-codec", .of_match_table = uda1380_of_match, }, - .probe = uda1380_i2c_probe, + .probe_new = uda1380_i2c_probe, .id_table = uda1380_i2c_id, }; diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index c53c2ef33e..98baef594b 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -714,12 +714,11 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) struct snd_soc_component *component = mbhc->component; int ret; - ret = pm_runtime_get_sync(component->dev); + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0 && ret != -EACCES) { dev_err_ratelimited(component->dev, - "pm_runtime_get_sync failed in %s, ret %d\n", + "pm_runtime_resume_and_get failed in %s, ret %d\n", __func__, ret); - pm_runtime_put_noidle(component->dev); return ret; } @@ -1097,12 +1096,11 @@ static void wcd_correct_swch_plug(struct work_struct *work) mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch); component = mbhc->component; - ret = pm_runtime_get_sync(component->dev); + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0 && ret != -EACCES) { dev_err_ratelimited(component->dev, - "pm_runtime_get_sync failed in %s, ret %d\n", + "pm_runtime_resume_and_get failed in %s, ret %d\n", __func__, ret); - pm_runtime_put_noidle(component->dev); return; } micbias_mv = wcd_mbhc_get_micbias(mbhc); @@ -1306,7 +1304,7 @@ static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data) { struct wcd_mbhc *mbhc = data; - u8 clamp_state = 0; + u8 clamp_state; u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY; /* diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 1e60db4056..beeeb35e80 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -24,6 +24,8 @@ #include "wcd9335.h" #include "wcd-clsh-v2.h" +#include + #define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) @@ -203,17 +205,6 @@ enum wcd9335_sido_voltage { SIDO_VOLTAGE_NOMINAL_MV = 1100, }; -enum { - AIF1_PB = 0, - AIF1_CAP, - AIF2_PB, - AIF2_CAP, - AIF3_PB, - AIF3_CAP, - AIF4_PB, - NUM_CODEC_DAIS, -}; - enum { COMPANDER_1, /* HPH_L */ COMPANDER_2, /* HPH_R */ @@ -342,7 +333,7 @@ struct wcd9335_codec { struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; unsigned int rx_port_value[WCD9335_RX_MAX]; - unsigned int tx_port_value; + unsigned int tx_port_value[WCD9335_TX_MAX]; int hph_l_gain; int hph_r_gain; u32 rx_bias_count; @@ -1287,11 +1278,17 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc, struct snd_soc_dapm_update *update = NULL; u32 port_id = w->shift; + if (wcd->rx_port_value[port_id] == ucontrol->value.enumerated.item[0]) + return 0; + wcd->rx_port_value[port_id] = ucontrol->value.enumerated.item[0]; + /* Remove channel from any list it's in before adding it to a new one */ + list_del_init(&wcd->rx_chs[port_id].list); + switch (wcd->rx_port_value[port_id]) { case 0: - list_del_init(&wcd->rx_chs[port_id].list); + /* Channel already removed from lists. Nothing to do here */ break; case 1: list_add_tail(&wcd->rx_chs[port_id].list, @@ -1328,8 +1325,13 @@ static int slim_tx_mixer_get(struct snd_kcontrol *kc, struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc); struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev); + struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc); + struct soc_mixer_control *mixer = + (struct soc_mixer_control *)kc->private_value; + int dai_id = widget->shift; + int port_id = mixer->shift; - ucontrol->value.integer.value[0] = wcd->tx_port_value; + ucontrol->value.integer.value[0] = wcd->tx_port_value[port_id] == dai_id; return 0; } @@ -1352,12 +1354,12 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc, case AIF2_CAP: case AIF3_CAP: /* only add to the list if value not set */ - if (enable && !(wcd->tx_port_value & BIT(port_id))) { - wcd->tx_port_value |= BIT(port_id); + if (enable && wcd->tx_port_value[port_id] != dai_id) { + wcd->tx_port_value[port_id] = dai_id; list_add_tail(&wcd->tx_chs[port_id].list, &wcd->dai[dai_id].slim_ch_list); - } else if (!enable && (wcd->tx_port_value & BIT(port_id))) { - wcd->tx_port_value &= ~BIT(port_id); + } else if (!enable && wcd->tx_port_value[port_id] == dai_id) { + wcd->tx_port_value[port_id] = -1; list_del_init(&wcd->tx_chs[port_id].list); } break; @@ -1807,11 +1809,11 @@ static int wcd9335_set_decimator_rate(struct snd_soc_dai *dai, tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0; shift = (tx_port << 1); shift_val = 0x03; - } else if ((tx_port >= 4) && (tx_port < 8)) { + } else if (tx_port < 8) { tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1; shift = ((tx_port - 4) << 1); shift_val = 0x03; - } else if ((tx_port >= 8) && (tx_port < 11)) { + } else if (tx_port < 11) { tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2; shift = ((tx_port - 8) << 1); shift_val = 0x03; @@ -2253,51 +2255,42 @@ static int wcd9335_rx_hph_mode_put(struct snd_kcontrol *kc, static const struct snd_kcontrol_new wcd9335_snd_controls[] = { /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume", - WCD9335_CDC_RX0_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume", - WCD9335_CDC_RX1_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume", - WCD9335_CDC_RX2_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume", - WCD9335_CDC_RX3_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume", - WCD9335_CDC_RX4_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume", - WCD9335_CDC_RX5_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume", - WCD9335_CDC_RX6_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume", - WCD9335_CDC_RX7_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume", - WCD9335_CDC_RX8_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX0 Mix Digital Volume", WCD9335_CDC_RX0_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX1 Mix Digital Volume", WCD9335_CDC_RX1_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Mix Digital Volume", WCD9335_CDC_RX2_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Mix Digital Volume", WCD9335_CDC_RX3_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX4 Mix Digital Volume", WCD9335_CDC_RX4_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX5 Mix Digital Volume", WCD9335_CDC_RX5_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX6 Mix Digital Volume", WCD9335_CDC_RX6_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX7 Mix Digital Volume", WCD9335_CDC_RX7_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX8 Mix Digital Volume", WCD9335_CDC_RX8_RX_VOL_MIX_CTL, + -84, 40, digital_gain), SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum), SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum), SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum), @@ -4924,6 +4917,7 @@ static const struct snd_soc_component_driver wcd9335_component_drv = { .num_dapm_widgets = ARRAY_SIZE(wcd9335_dapm_widgets), .dapm_routes = wcd9335_audio_map, .num_dapm_routes = ARRAY_SIZE(wcd9335_audio_map), + .endianness = 1, }; static int wcd9335_probe(struct wcd9335_codec *wcd) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 6298ebe96e..f56907d094 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -5847,6 +5847,7 @@ static const struct snd_soc_component_driver wcd934x_component_drv = { .dapm_routes = wcd934x_audio_map, .num_dapm_routes = ARRAY_SIZE(wcd934x_audio_map), .set_jack = wcd934x_codec_set_jack, + .endianness = 1, }; static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 898b2887fa..781ae569be 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -2519,6 +2519,9 @@ static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; int path = e->shift_l; + if (wcd938x->tx_mode[path] == ucontrol->value.enumerated.item[0]) + return 0; + wcd938x->tx_mode[path] = ucontrol->value.enumerated.item[0]; return 1; @@ -2541,6 +2544,9 @@ static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + if (wcd938x->hph_mode == ucontrol->value.enumerated.item[0]) + return 0; + wcd938x->hph_mode = ucontrol->value.enumerated.item[0]; return 1; @@ -2632,6 +2638,9 @@ static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + if (wcd938x->ldoh == ucontrol->value.integer.value[0]) + return 0; + wcd938x->ldoh = ucontrol->value.integer.value[0]; return 1; @@ -2654,6 +2663,9 @@ static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + if (wcd938x->bcs_dis == ucontrol->value.integer.value[0]) + return 0; + wcd938x->bcs_dis = ucontrol->value.integer.value[0]; return 1; @@ -4168,6 +4180,7 @@ static const struct snd_soc_component_driver soc_codec_dev_wcd938x = { .dapm_routes = wcd938x_audio_map, .num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map), .set_jack = wcd938x_codec_set_jack, + .endianness = 1, }; static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_priv *wcd) diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index 02232f6411..626278e4c9 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -475,7 +475,6 @@ static const struct snd_soc_component_driver soc_component_dev_wl1273 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wl1273_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 1bef1c500c..034a4e858c 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -789,7 +789,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm0010 = { .num_dapm_routes = ARRAY_SIZE(wm0010_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #define WM0010_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index d6ffe99550..9834362607 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c @@ -144,7 +144,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm1250_ev1 = { .set_bias_level = wm1250_ev1_set_bias_level, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm1250_ev1_pdata(struct i2c_client *i2c) @@ -192,8 +191,7 @@ static void wm1250_ev1_free(struct i2c_client *i2c) gpio_free_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios)); } -static int wm1250_ev1_probe(struct i2c_client *i2c, - const struct i2c_device_id *i2c_id) +static int wm1250_ev1_probe(struct i2c_client *i2c) { int id, board, rev, ret; @@ -247,7 +245,7 @@ static struct i2c_driver wm1250_ev1_i2c_driver = { .driver = { .name = "wm1250-ev1", }, - .probe = wm1250_ev1_probe, + .probe_new = wm1250_ev1_probe, .remove = wm1250_ev1_remove, .id_table = wm1250_ev1_i2c_id, }; diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 72e165cc64..14b4fd9748 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -536,7 +536,7 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000, { struct i2c_client *i2c = wm2000->i2c; int i, j; - int ret; + int ret = 0; if (wm2000->anc_mode == mode) return 0; @@ -566,13 +566,13 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000, ret = anc_transitions[i].step[j](i2c, anc_transitions[i].analogue); if (ret != 0) - return ret; + break; } if (anc_transitions[i].dest == ANC_OFF) clk_disable_unprepare(wm2000->mclk); - return 0; + return ret; } static int wm2000_anc_set_mode(struct wm2000_priv *wm2000) @@ -803,12 +803,9 @@ static const struct snd_soc_component_driver soc_component_dev_wm2000 = { .num_dapm_routes = ARRAY_SIZE(wm2000_audio_map), .idle_bias_on = 1, .use_pmdown_time = 1, - .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int wm2000_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *i2c_id) +static int wm2000_i2c_probe(struct i2c_client *i2c) { struct wm2000_priv *wm2000; struct wm2000_platform_data *pdata; @@ -941,7 +938,7 @@ static struct i2c_driver wm2000_i2c_driver = { .driver = { .name = "wm2000", }, - .probe = wm2000_i2c_probe, + .probe_new = wm2000_i2c_probe, .id_table = wm2000_i2c_id, }; diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 8863b533f9..7b4e162a29 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2104,7 +2104,6 @@ static const struct snd_soc_component_driver soc_component_wm2200 = { .dapm_routes = wm2200_dapm_routes, .num_dapm_routes = ARRAY_SIZE(wm2200_dapm_routes), .endianness = 1, - .non_legacy_dai_naming = 1, }; static irqreturn_t wm2200_irq(int irq, void *data) @@ -2176,8 +2175,7 @@ static const unsigned int wm2200_mic_ctrl_reg[] = { WM2200_IN3L_CONTROL, }; -static int wm2200_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm2200_i2c_probe(struct i2c_client *i2c) { struct wm2200_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm2200_priv *wm2200; @@ -2489,7 +2487,7 @@ static struct i2c_driver wm2200_i2c_driver = { .name = "wm2200", .pm = &wm2200_pm, }, - .probe = wm2200_i2c_probe, + .probe_new = wm2200_i2c_probe, .remove = wm2200_i2c_remove, .id_table = wm2200_i2c_id, }; diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 9cab01ee4e..35a85ce6b4 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2389,7 +2389,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm5100 = { .num_dapm_routes = ARRAY_SIZE(wm5100_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm5100_regmap = { @@ -2411,8 +2410,7 @@ static const unsigned int wm5100_mic_ctrl_reg[] = { WM5100_IN4L_CONTROL, }; -static int wm5100_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm5100_i2c_probe(struct i2c_client *i2c) { struct wm5100_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm5100_priv *wm5100; @@ -2713,7 +2711,7 @@ static struct i2c_driver wm5100_i2c_driver = { .name = "wm5100", .pm = &wm5100_pm, }, - .probe = wm5100_i2c_probe, + .probe_new = wm5100_i2c_probe, .remove = wm5100_i2c_remove, .id_table = wm5100_i2c_id, }; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index da2f8998df..af7d324e33 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -680,12 +680,17 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct arizona *arizona = dev_get_drvdata(component->dev->parent); + uint16_t dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data); + int ret = 0; mutex_lock(&arizona->dac_comp_lock); - arizona->dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data); + if (arizona->dac_comp_coeff != dac_comp_coeff) { + arizona->dac_comp_coeff = dac_comp_coeff; + ret = 1; + } mutex_unlock(&arizona->dac_comp_lock); - return 0; + return ret; } static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol, @@ -706,12 +711,20 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct arizona *arizona = dev_get_drvdata(component->dev->parent); + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + int ret = 0; + + if (ucontrol->value.integer.value[0] > mc->max) + return -EINVAL; mutex_lock(&arizona->dac_comp_lock); - arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; + if (arizona->dac_comp_enabled != ucontrol->value.integer.value[0]) { + arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; + ret = 1; + } mutex_unlock(&arizona->dac_comp_lock); - return 0; + return ret; } static const char * const wm5102_osr_text[] = { @@ -2015,7 +2028,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm5102 = { .num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm5102_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 4973ba1ed7..f3f4a10bf0 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -413,6 +413,7 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol, unsigned int rnew = (!!ucontrol->value.integer.value[1]) << mc->rshift; unsigned int lold, rold; unsigned int lena, rena; + bool change = false; int ret; snd_soc_dapm_mutex_lock(dapm); @@ -440,8 +441,8 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol, goto err; } - ret = regmap_update_bits(arizona->regmap, ARIZONA_DRE_ENABLE, - mask, lnew | rnew); + ret = regmap_update_bits_check(arizona->regmap, ARIZONA_DRE_ENABLE, + mask, lnew | rnew, &change); if (ret) { dev_err(arizona->dev, "Failed to set DRE: %d\n", ret); goto err; @@ -454,6 +455,9 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol, if (!rnew && rold) wm5110_clear_pga_volume(arizona, mc->rshift); + if (change) + ret = 1; + err: snd_soc_dapm_mutex_unlock(dapm); @@ -2381,7 +2385,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm5110 = { .num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm5110_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 41504ce2a6..66bd281095 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1613,7 +1613,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8350 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8350_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index bf5e77c86a..19ce839f6e 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1322,7 +1322,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8400 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8400_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index a18e2290b8..e13f9780a1 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -592,7 +592,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8510 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8510_of_match[] = { @@ -646,8 +645,7 @@ static struct spi_driver wm8510_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8510_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8510_i2c_probe(struct i2c_client *i2c) { struct wm8510_priv *wm8510; int ret; @@ -680,7 +678,7 @@ static struct i2c_driver wm8510_i2c_driver = { .name = "wm8510", .of_match_table = wm8510_of_match, }, - .probe = wm8510_i2c_probe, + .probe_new = wm8510_i2c_probe, .id_table = wm8510_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index c8b50aac6c..66f6371d8a 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -422,7 +422,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8523 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8523_of_match[] = { @@ -443,8 +442,7 @@ static const struct regmap_config wm8523_regmap = { .volatile_reg = wm8523_volatile_register, }; -static int wm8523_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8523_i2c_probe(struct i2c_client *i2c) { struct wm8523_priv *wm8523; unsigned int val; @@ -529,7 +527,7 @@ static struct i2c_driver wm8523_i2c_driver = { .name = "wm8523", .of_match_table = wm8523_of_match, }, - .probe = wm8523_i2c_probe, + .probe_new = wm8523_i2c_probe, .id_table = wm8523_i2c_id, }; diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c index 81f858f6bd..b56dcac602 100644 --- a/sound/soc/codecs/wm8524.c +++ b/sound/soc/codecs/wm8524.c @@ -203,7 +203,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8524 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8524_of_match[] = { diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 85ad2f03cf..ca796aa0ae 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -966,7 +966,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8580 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8580_regmap = { @@ -996,8 +995,7 @@ static const struct of_device_id wm8580_of_match[] = { }; MODULE_DEVICE_TABLE(of, wm8580_of_match); -static int wm8580_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8580_i2c_probe(struct i2c_client *i2c) { const struct of_device_id *of_id; struct wm8580_priv *wm8580; @@ -1051,7 +1049,7 @@ static struct i2c_driver wm8580_i2c_driver = { .name = "wm8580", .of_match_table = wm8580_of_match, }, - .probe = wm8580_i2c_probe, + .probe_new = wm8580_i2c_probe, .id_table = wm8580_i2c_id, }; diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index bc4d161c59..383c6796e8 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -378,7 +378,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8711 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8711_of_match[] = { @@ -432,8 +431,7 @@ static struct spi_driver wm8711_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8711_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int wm8711_i2c_probe(struct i2c_client *client) { struct wm8711_priv *wm8711; int ret; @@ -466,7 +464,7 @@ static struct i2c_driver wm8711_i2c_driver = { .name = "wm8711", .of_match_table = wm8711_of_match, }, - .probe = wm8711_i2c_probe, + .probe_new = wm8711_i2c_probe, .id_table = wm8711_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c index 1a118b75b5..d6b0a570dd 100644 --- a/sound/soc/codecs/wm8727.c +++ b/sound/soc/codecs/wm8727.c @@ -55,7 +55,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8727 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8727_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 2cd58d1338..a3dbdbf407 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -221,7 +221,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8728 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8728_of_match[] = { @@ -273,8 +272,7 @@ static struct spi_driver wm8728_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8728_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8728_i2c_probe(struct i2c_client *i2c) { struct wm8728_priv *wm8728; int ret; @@ -307,7 +305,7 @@ static struct i2c_driver wm8728_i2c_driver = { .name = "wm8728", .of_match_table = wm8728_of_match, }, - .probe = wm8728_i2c_probe, + .probe_new = wm8728_i2c_probe, .id_table = wm8728_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index b14c6d104e..d5ab3ba126 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -15,13 +15,9 @@ #include #include #include -#include #include #include #include -#include -#include -#include #include #include #include @@ -32,7 +28,6 @@ #include "wm8731.h" -#define WM8731_NUM_SUPPLIES 4 static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = { "AVDD", "HPVDD", @@ -40,21 +35,6 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = { "DBVDD", }; -/* codec private data */ -struct wm8731_priv { - struct regmap *regmap; - struct clk *mclk; - struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; - const struct snd_pcm_hw_constraint_list *constraints; - unsigned int sysclk; - int sysclk_type; - int playback_fs; - bool deemph; - - struct mutex lock; -}; - - /* * wm8731 register cache */ @@ -429,12 +409,11 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_component *component = codec_dai->component; u16 iface = 0; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface |= 0x0040; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -570,59 +549,6 @@ static struct snd_soc_dai_driver wm8731_dai = { .symmetric_rate = 1, }; -static int wm8731_request_supplies(struct device *dev, - struct wm8731_priv *wm8731) -{ - 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(dev, ARRAY_SIZE(wm8731->supplies), - wm8731->supplies); - if (ret != 0) { - 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(dev, "Failed to enable supplies: %d\n", ret); - return ret; - } - - 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(dev, "Failed to issue reset: %d\n", ret); - goto err; - } - - /* Clear POWEROFF, keep everything else disabled */ - regmap_write(wm8731->regmap, WM8731_PWR, 0x7f); - - /* Latch the update bits */ - 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 */ - regmap_update_bits(wm8731->regmap, WM8731_APANA, 0x8, 0); - - regcache_mark_dirty(wm8731->regmap); - -err: - return ret; -} - static const struct snd_soc_component_driver soc_component_dev_wm8731 = { .set_bias_level = wm8731_set_bias_level, .controls = wm8731_snd_controls, @@ -635,139 +561,67 @@ static const struct snd_soc_component_driver soc_component_dev_wm8731 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, -}; - -static const struct of_device_id wm8731_of_match[] = { - { .compatible = "wlf,wm8731", }, - { } }; -MODULE_DEVICE_TABLE(of, wm8731_of_match); - -static const struct regmap_config wm8731_regmap = { - .reg_bits = 7, - .val_bits = 9, - - .max_register = WM8731_RESET, - .volatile_reg = wm8731_volatile, - - .cache_type = REGCACHE_RBTREE, - .reg_defaults = wm8731_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(wm8731_reg_defaults), -}; - -#if defined(CONFIG_SPI_MASTER) -static int wm8731_spi_probe(struct spi_device *spi) +int wm8731_init(struct device *dev, struct wm8731_priv *wm8731) { - struct wm8731_priv *wm8731; - int ret; - - wm8731 = devm_kzalloc(&spi->dev, sizeof(*wm8731), GFP_KERNEL); - if (wm8731 == NULL) - return -ENOMEM; + int ret = 0, i; - wm8731->mclk = devm_clk_get(&spi->dev, "mclk"); + wm8731->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(wm8731->mclk)) { ret = PTR_ERR(wm8731->mclk); if (ret == -ENOENT) { wm8731->mclk = NULL; - dev_warn(&spi->dev, "Assuming static MCLK\n"); + dev_warn(dev, "Assuming static MCLK\n"); } else { - dev_err(&spi->dev, "Failed to get MCLK: %d\n", - ret); + dev_err(dev, "Failed to get MCLK: %d\n", ret); return ret; } } mutex_init(&wm8731->lock); - spi_set_drvdata(spi, wm8731); - - ret = wm8731_request_supplies(&spi->dev, wm8731); - if (ret != 0) - return ret; + for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++) + wm8731->supplies[i].supply = wm8731_supply_names[i]; - wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); - if (IS_ERR(wm8731->regmap)) { - ret = PTR_ERR(wm8731->regmap); - dev_err(&spi->dev, "Failed to allocate register map: %d\n", - ret); + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8731->supplies), + wm8731->supplies); + if (ret != 0) { + dev_err(dev, "Failed to request supplies: %d\n", ret); return ret; } - ret = wm8731_hw_init(&spi->dev, wm8731); - if (ret != 0) - return ret; - - ret = devm_snd_soc_register_component(&spi->dev, - &soc_component_dev_wm8731, &wm8731_dai, 1); + ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies), + wm8731->supplies); if (ret != 0) { - dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret); + dev_err(dev, "Failed to enable supplies: %d\n", ret); return ret; } - return 0; -} - -static struct spi_driver wm8731_spi_driver = { - .driver = { - .name = "wm8731", - .of_match_table = wm8731_of_match, - }, - .probe = wm8731_spi_probe, -}; -#endif /* CONFIG_SPI_MASTER */ - -#if IS_ENABLED(CONFIG_I2C) -static int wm8731_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct wm8731_priv *wm8731; - int ret; - - wm8731 = devm_kzalloc(&i2c->dev, sizeof(struct wm8731_priv), - GFP_KERNEL); - if (wm8731 == NULL) - return -ENOMEM; - - wm8731->mclk = devm_clk_get(&i2c->dev, "mclk"); - if (IS_ERR(wm8731->mclk)) { - ret = PTR_ERR(wm8731->mclk); - if (ret == -ENOENT) { - wm8731->mclk = NULL; - dev_warn(&i2c->dev, "Assuming static MCLK\n"); - } else { - dev_err(&i2c->dev, "Failed to get MCLK: %d\n", - ret); - return ret; - } + ret = wm8731_reset(wm8731->regmap); + if (ret < 0) { + dev_err(dev, "Failed to issue reset: %d\n", ret); + goto err_regulator_enable; } - mutex_init(&wm8731->lock); - - i2c_set_clientdata(i2c, wm8731); + /* Clear POWEROFF, keep everything else disabled */ + regmap_write(wm8731->regmap, WM8731_PWR, 0x7f); - ret = wm8731_request_supplies(&i2c->dev, wm8731); - if (ret != 0) - return ret; + /* Latch the update bits */ + 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); - wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap); - if (IS_ERR(wm8731->regmap)) { - ret = PTR_ERR(wm8731->regmap); - dev_err(&i2c->dev, "Failed to allocate register map: %d\n", - ret); - goto err_regulator_enable; - } + /* Disable bypass path by default */ + regmap_update_bits(wm8731->regmap, WM8731_APANA, 0x8, 0); - ret = wm8731_hw_init(&i2c->dev, wm8731); - if (ret != 0) - goto err_regulator_enable; + regcache_mark_dirty(wm8731->regmap); - ret = devm_snd_soc_register_component(&i2c->dev, + ret = devm_snd_soc_register_component(dev, &soc_component_dev_wm8731, &wm8731_dai, 1); if (ret != 0) { - dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); + dev_err(dev, "Failed to register CODEC: %d\n", ret); goto err_regulator_enable; } @@ -779,54 +633,20 @@ static int wm8731_i2c_probe(struct i2c_client *i2c, return ret; } +EXPORT_SYMBOL_GPL(wm8731_init); -static const struct i2c_device_id wm8731_i2c_id[] = { - { "wm8731", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); - -static struct i2c_driver wm8731_i2c_driver = { - .driver = { - .name = "wm8731", - .of_match_table = wm8731_of_match, - }, - .probe = wm8731_i2c_probe, - .id_table = wm8731_i2c_id, -}; -#endif +const struct regmap_config wm8731_regmap = { + .reg_bits = 7, + .val_bits = 9, -static int __init wm8731_modinit(void) -{ - int ret = 0; -#if IS_ENABLED(CONFIG_I2C) - ret = i2c_add_driver(&wm8731_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n", - ret); - } -#endif -#if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&wm8731_spi_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8731 SPI driver: %d\n", - ret); - } -#endif - return ret; -} -module_init(wm8731_modinit); + .max_register = WM8731_RESET, + .volatile_reg = wm8731_volatile, -static void __exit wm8731_exit(void) -{ -#if IS_ENABLED(CONFIG_I2C) - i2c_del_driver(&wm8731_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&wm8731_spi_driver); -#endif -} -module_exit(wm8731_exit); + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm8731_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8731_reg_defaults), +}; +EXPORT_SYMBOL_GPL(wm8731_regmap); MODULE_DESCRIPTION("ASoC WM8731 driver"); MODULE_AUTHOR("Richard Purdie"); diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h index 4fcf1226d7..8d5a7a9ca6 100644 --- a/sound/soc/codecs/wm8731.h +++ b/sound/soc/codecs/wm8731.h @@ -12,6 +12,13 @@ #ifndef _WM8731_H #define _WM8731_H +#include +#include +#include + +struct clk; +struct snd_pcm_hw_constraint_list; + /* WM8731 register space */ #define WM8731_LINVOL 0x00 @@ -33,4 +40,24 @@ #define WM8731_DAI 0 +#define WM8731_NUM_SUPPLIES 4 + +/* codec private data */ +struct wm8731_priv { + struct regmap *regmap; + struct clk *mclk; + struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; + const struct snd_pcm_hw_constraint_list *constraints; + unsigned int sysclk; + int sysclk_type; + int playback_fs; + bool deemph; + + struct mutex lock; +}; + +extern const struct regmap_config wm8731_regmap; + +int wm8731_init(struct device *dev, struct wm8731_priv *wm8731); + #endif diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 7a3f9fbe8d..90b5434337 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -583,7 +583,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8737 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8737_of_match[] = { @@ -606,8 +605,7 @@ static const struct regmap_config wm8737_regmap = { }; #if IS_ENABLED(CONFIG_I2C) -static int wm8737_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8737_i2c_probe(struct i2c_client *i2c) { struct wm8737_priv *wm8737; int ret, i; @@ -651,7 +649,7 @@ static struct i2c_driver wm8737_i2c_driver = { .name = "wm8737", .of_match_table = wm8737_of_match, }, - .probe = wm8737_i2c_probe, + .probe_new = wm8737_i2c_probe, .id_table = wm8737_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 0e39943269..c7afa4f279 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -528,7 +528,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8741 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8741_of_match[] = { @@ -565,8 +564,7 @@ static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741) } #if IS_ENABLED(CONFIG_I2C) -static int wm8741_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8741_i2c_probe(struct i2c_client *i2c) { struct wm8741_priv *wm8741; int ret, i; @@ -618,7 +616,7 @@ static struct i2c_driver wm8741_i2c_driver = { .name = "wm8741", .of_match_table = wm8741_of_match, }, - .probe = wm8741_i2c_probe, + .probe_new = wm8741_i2c_probe, .id_table = wm8741_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 9491817020..2f6ee8d663 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -719,7 +719,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8750 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8750_of_match[] = { @@ -780,8 +779,7 @@ static struct spi_driver wm8750_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8750_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8750_i2c_probe(struct i2c_client *i2c) { struct wm8750_priv *wm8750; struct regmap *regmap; @@ -815,7 +813,7 @@ static struct i2c_driver wm8750_i2c_driver = { .name = "wm8750", .of_match_table = wm8750_of_match, }, - .probe = wm8750_i2c_probe, + .probe_new = wm8750_i2c_probe, .id_table = wm8750_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index deaa54be62..bb18f58dc6 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1492,7 +1492,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8753 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8753_of_match[] = { @@ -1552,8 +1551,7 @@ static struct spi_driver wm8753_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8753_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8753_i2c_probe(struct i2c_client *i2c) { struct wm8753_priv *wm8753; int ret; @@ -1592,7 +1590,7 @@ static struct i2c_driver wm8753_i2c_driver = { .name = "wm8753", .of_match_table = wm8753_of_match, }, - .probe = wm8753_i2c_probe, + .probe_new = wm8753_i2c_probe, .id_table = wm8753_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 5f39406503..e03fee8869 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -617,7 +617,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8770 = { .num_dapm_routes = ARRAY_SIZE(wm8770_intercon), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8770_of_match[] = { diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 554acf5613..936ea24621 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -436,7 +436,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8776 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8776_of_match[] = { @@ -490,8 +489,7 @@ static struct spi_driver wm8776_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8776_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8776_i2c_probe(struct i2c_client *i2c) { struct wm8776_priv *wm8776; int ret; @@ -525,7 +523,7 @@ static struct i2c_driver wm8776_i2c_driver = { .name = "wm8776", .of_match_table = wm8776_of_match, }, - .probe = wm8776_i2c_probe, + .probe_new = wm8776_i2c_probe, .id_table = wm8776_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c index f89855c616..95ff4339d1 100644 --- a/sound/soc/codecs/wm8782.c +++ b/sound/soc/codecs/wm8782.c @@ -99,7 +99,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8782 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8782_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c index f97a75e641..04dc9fb5af 100644 --- a/sound/soc/codecs/wm8804-i2c.c +++ b/sound/soc/codecs/wm8804-i2c.c @@ -14,8 +14,7 @@ #include "wm8804.h" -static int wm8804_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8804_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; @@ -62,7 +61,7 @@ static struct i2c_driver wm8804_i2c_driver = { .of_match_table = of_match_ptr(wm8804_of_match), .acpi_match_table = ACPI_PTR(wm8804_acpi_match), }, - .probe = wm8804_i2c_probe, + .probe_new = wm8804_i2c_probe, .remove = wm8804_i2c_remove, .id_table = wm8804_i2c_id }; diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 21bf0cfa1e..0b234bae48 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -546,7 +546,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8804 = { .num_dapm_routes = ARRAY_SIZE(wm8804_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; const struct regmap_config wm8804_regmap_config = { diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index bf3a4415a8..d6420df350 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1214,7 +1214,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8900 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8900_regmap = { @@ -1261,8 +1260,7 @@ static struct spi_driver wm8900_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8900_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8900_i2c_probe(struct i2c_client *i2c) { struct wm8900_priv *wm8900; int ret; @@ -1299,7 +1297,7 @@ static struct i2c_driver wm8900_i2c_driver = { .driver = { .name = "wm8900", }, - .probe = wm8900_i2c_probe, + .probe_new = wm8900_i2c_probe, .remove = wm8900_i2c_remove, .id_table = wm8900_i2c_id, }; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 75f30154c8..54e0a7628c 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1893,7 +1893,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8903 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8903_regmap = { @@ -1981,8 +1980,7 @@ static int wm8903_set_pdata_from_of(struct i2c_client *i2c, return 0; } -static int wm8903_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8903_i2c_probe(struct i2c_client *i2c) { struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev); struct wm8903_priv *wm8903; @@ -2132,7 +2130,7 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, if (ret != 0) { dev_err(wm8903->dev, "Failed to request IRQ: %d\n", ret); - return ret; + goto err; } /* Enable write sequencer interrupts */ @@ -2214,7 +2212,7 @@ static struct i2c_driver wm8903_i2c_driver = { .name = "wm8903", .of_match_table = wm8903_of_match, }, - .probe = wm8903_i2c_probe, + .probe_new = wm8903_i2c_probe, .remove = wm8903_i2c_remove, .id_table = wm8903_i2c_id, }; diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index a02a77fef3..ca6a01a230 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2131,7 +2131,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8904 = { .set_bias_level = wm8904_set_bias_level, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8904_regmap = { @@ -2162,8 +2161,9 @@ static const struct of_device_id wm8904_of_match[] = { MODULE_DEVICE_TABLE(of, wm8904_of_match); #endif -static int wm8904_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id wm8904_i2c_id[]; + +static int wm8904_i2c_probe(struct i2c_client *i2c) { struct wm8904_priv *wm8904; unsigned int val; @@ -2197,6 +2197,8 @@ static int wm8904_i2c_probe(struct i2c_client *i2c, return -EINVAL; wm8904->devtype = (enum wm8904_type)match->data; } else { + const struct i2c_device_id *id = + i2c_match_id(wm8904_i2c_id, i2c); wm8904->devtype = id->driver_data; } @@ -2328,7 +2330,7 @@ static struct i2c_driver wm8904_i2c_driver = { .name = "wm8904", .of_match_table = of_match_ptr(wm8904_of_match), }, - .probe = wm8904_i2c_probe, + .probe_new = wm8904_i2c_probe, .id_table = wm8904_i2c_id, }; diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 440d048ef0..8dac9fd885 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -734,7 +734,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8940 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8940_regmap = { @@ -750,8 +749,7 @@ static const struct regmap_config wm8940_regmap = { .volatile_reg = wm8940_volatile_register, }; -static int wm8940_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8940_i2c_probe(struct i2c_client *i2c) { struct wm8940_priv *wm8940; int ret; @@ -779,11 +777,18 @@ static const struct i2c_device_id wm8940_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id); +static const struct of_device_id wm8940_of_match[] = { + { .compatible = "wlf,wm8940", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8940_of_match); + static struct i2c_driver wm8940_i2c_driver = { .driver = { .name = "wm8940", + .of_match_table = wm8940_of_match, }, - .probe = wm8940_i2c_probe, + .probe_new = wm8940_i2c_probe, .id_table = wm8940_i2c_id, }; diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 513df47bd8..05ef45672e 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -952,7 +952,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8955 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8955_regmap = { @@ -968,8 +967,7 @@ static const struct regmap_config wm8955_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8955_reg_defaults), }; -static int wm8955_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8955_i2c_probe(struct i2c_client *i2c) { struct wm8955_priv *wm8955; int ret; @@ -1005,7 +1003,7 @@ static struct i2c_driver wm8955_i2c_driver = { .driver = { .name = "wm8955", }, - .probe = wm8955_i2c_probe, + .probe_new = wm8955_i2c_probe, .id_table = wm8955_i2c_id, }; diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index ca7660f4bb..37956516d9 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1377,7 +1378,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8960 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8960_regmap = { @@ -1410,8 +1410,7 @@ static void wm8960_set_pdata_from_of(struct i2c_client *i2c, ARRAY_SIZE(pdata->hp_cfg)); } -static int wm8960_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8960_i2c_probe(struct i2c_client *i2c) { struct wm8960_data *pdata = dev_get_platdata(&i2c->dev); struct wm8960_priv *wm8960; @@ -1498,18 +1497,30 @@ static const struct i2c_device_id wm8960_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); +#if defined(CONFIG_OF) static const struct of_device_id wm8960_of_match[] = { { .compatible = "wlf,wm8960", }, { } }; MODULE_DEVICE_TABLE(of, wm8960_of_match); +#endif + +#if defined(CONFIG_ACPI) +static const struct acpi_device_id wm8960_acpi_match[] = { + { "1AEC8960", 0 }, /* Wolfson PCI ID + part ID */ + { "10138960", 0 }, /* Cirrus Logic PCI ID + part ID */ + { }, +}; +MODULE_DEVICE_TABLE(acpi, wm8960_acpi_match); +#endif static struct i2c_driver wm8960_i2c_driver = { .driver = { .name = "wm8960", - .of_match_table = wm8960_of_match, + .of_match_table = of_match_ptr(wm8960_of_match), + .acpi_match_table = ACPI_PTR(wm8960_acpi_match), }, - .probe = wm8960_i2c_probe, + .probe_new = wm8960_i2c_probe, .remove = wm8960_i2c_remove, .id_table = wm8960_i2c_id, }; diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index ef80d9fc1e..7dc6aaf655 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -895,7 +895,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8961 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8961_regmap = { @@ -911,8 +910,7 @@ static const struct regmap_config wm8961_regmap = { .readable_reg = wm8961_readable, }; -static int wm8961_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8961_i2c_probe(struct i2c_client *i2c) { struct wm8961_priv *wm8961; unsigned int val; @@ -977,7 +975,7 @@ static struct i2c_driver wm8961_i2c_driver = { .driver = { .name = "wm8961", }, - .probe = wm8961_i2c_probe, + .probe_new = wm8961_i2c_probe, .id_table = wm8961_i2c_id, }; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 2c41d31956..398c448ea8 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2896,9 +2896,8 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s reinit_completion(&wm8962->fll_lock); - ret = pm_runtime_get_sync(component->dev); + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { - pm_runtime_put_noidle(component->dev); dev_err(component->dev, "Failed to resume device: %d\n", ret); return ret; } @@ -3030,9 +3029,8 @@ static irqreturn_t wm8962_irq(int irq, void *data) unsigned int active; int reg, ret; - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) { - pm_runtime_put_noidle(dev); dev_err(dev, "Failed to resume: %d\n", ret); return IRQ_NONE; } @@ -3504,7 +3502,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8962 = { .set_pll = wm8962_set_fll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; /* Improve power consumption for IN4 DC measurement mode */ @@ -3555,8 +3552,7 @@ static int wm8962_set_pdata_from_of(struct i2c_client *i2c, return PTR_ERR_OR_ZERO(pdata->mclk); } -static int wm8962_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8962_i2c_probe(struct i2c_client *i2c) { struct wm8962_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm8962_priv *wm8962; @@ -3871,6 +3867,7 @@ static int wm8962_runtime_suspend(struct device *dev) #endif static const struct dev_pm_ops wm8962_pm = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL) }; @@ -3892,7 +3889,7 @@ static struct i2c_driver wm8962_i2c_driver = { .of_match_table = wm8962_of_match, .pm = &wm8962_pm, }, - .probe = wm8962_i2c_probe, + .probe_new = wm8962_i2c_probe, .remove = wm8962_i2c_remove, .id_table = wm8962_i2c_id, }; diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index ddf0e2f5e6..4db9248de5 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -659,7 +659,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8971 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8971_regmap = { @@ -672,8 +671,7 @@ static const struct regmap_config wm8971_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int wm8971_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8971_i2c_probe(struct i2c_client *i2c) { struct wm8971_priv *wm8971; @@ -702,7 +700,7 @@ static struct i2c_driver wm8971_i2c_driver = { .driver = { .name = "wm8971", }, - .probe = wm8971_i2c_probe, + .probe_new = wm8971_i2c_probe, .id_table = wm8971_i2c_id, }; diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index fdc68ab497..010a394c70 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -682,11 +682,9 @@ static const struct snd_soc_component_driver soc_component_dev_wm8974 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int wm8974_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8974_i2c_probe(struct i2c_client *i2c) { struct wm8974_priv *priv; struct regmap *regmap; @@ -725,7 +723,7 @@ static struct i2c_driver wm8974_i2c_driver = { .name = "wm8974", .of_match_table = wm8974_of_match, }, - .probe = wm8974_i2c_probe, + .probe_new = wm8974_i2c_probe, .id_table = wm8974_i2c_id, }; diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 7091e1a9d5..a682f8020e 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -1005,7 +1005,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8978 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8978_regmap_config = { @@ -1020,8 +1019,7 @@ static const struct regmap_config wm8978_regmap_config = { .num_reg_defaults = ARRAY_SIZE(wm8978_reg_defaults), }; -static int wm8978_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8978_i2c_probe(struct i2c_client *i2c) { struct wm8978_priv *wm8978; int ret; @@ -1074,7 +1072,7 @@ static struct i2c_driver wm8978_i2c_driver = { .name = "wm8978", .of_match_table = wm8978_of_match, }, - .probe = wm8978_i2c_probe, + .probe_new = wm8978_i2c_probe, .id_table = wm8978_i2c_id, }; diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index d8ed22a9ca..50e6ac6ccb 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -987,7 +987,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8983 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8983_regmap = { @@ -1035,8 +1034,7 @@ static struct spi_driver wm8983_spi_driver = { #endif #if IS_ENABLED(CONFIG_I2C) -static int wm8983_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8983_i2c_probe(struct i2c_client *i2c) { struct wm8983_priv *wm8983; int ret; @@ -1070,7 +1068,7 @@ static struct i2c_driver wm8983_i2c_driver = { .driver = { .name = "wm8983", }, - .probe = wm8983_i2c_probe, + .probe_new = wm8983_i2c_probe, .id_table = wm8983_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index a7e01106fb..751aa67308 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -1116,7 +1116,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8985 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8985_regmap = { @@ -1167,10 +1166,12 @@ static struct spi_driver wm8985_spi_driver = { #endif #if IS_ENABLED(CONFIG_I2C) -static int wm8985_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id wm8985_i2c_id[]; + +static int wm8985_i2c_probe(struct i2c_client *i2c) { struct wm8985_priv *wm8985; + const struct i2c_device_id *id = i2c_match_id(wm8985_i2c_id, i2c); int ret; wm8985 = devm_kzalloc(&i2c->dev, sizeof *wm8985, GFP_KERNEL); @@ -1205,7 +1206,7 @@ static struct i2c_driver wm8985_i2c_driver = { .driver = { .name = "wm8985", }, - .probe = wm8985_i2c_probe, + .probe_new = wm8985_i2c_probe, .id_table = wm8985_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 1d2f881bbc..5dbdf647cd 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -823,7 +823,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8988 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8988_regmap = { @@ -872,8 +871,7 @@ static struct spi_driver wm8988_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8988_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8988_i2c_probe(struct i2c_client *i2c) { struct wm8988_priv *wm8988; int ret; @@ -907,7 +905,7 @@ static struct i2c_driver wm8988_i2c_driver = { .driver = { .name = "wm8988", }, - .probe = wm8988_i2c_probe, + .probe_new = wm8988_i2c_probe, .id_table = wm8988_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 938940777e..589af286f1 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1217,11 +1217,9 @@ static const struct snd_soc_component_driver soc_component_dev_wm8990 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int wm8990_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8990_i2c_probe(struct i2c_client *i2c) { struct wm8990_priv *wm8990; int ret; @@ -1249,7 +1247,7 @@ static struct i2c_driver wm8990_i2c_driver = { .driver = { .name = "wm8990", }, - .probe = wm8990_i2c_probe, + .probe_new = wm8990_i2c_probe, .id_table = wm8990_i2c_id, }; diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 16bc8609d0..30121993b7 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1243,7 +1243,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8991 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8991_regmap = { @@ -1257,8 +1256,7 @@ static const struct regmap_config wm8991_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int wm8991_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8991_i2c_probe(struct i2c_client *i2c) { struct wm8991_priv *wm8991; unsigned int val; @@ -1325,7 +1323,7 @@ static struct i2c_driver wm8991_i2c_driver = { .driver = { .name = "wm8991", }, - .probe = wm8991_i2c_probe, + .probe_new = wm8991_i2c_probe, .id_table = wm8991_i2c_id, }; diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index c4f41692b8..8db98b5a06 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1621,11 +1621,9 @@ static const struct snd_soc_component_driver soc_component_dev_wm8993 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int wm8993_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8993_i2c_probe(struct i2c_client *i2c) { struct wm8993_priv *wm8993; unsigned int reg; @@ -1745,7 +1743,7 @@ static struct i2c_driver wm8993_i2c_driver = { .driver = { .name = "wm8993", }, - .probe = wm8993_i2c_probe, + .probe_new = wm8993_i2c_probe, .remove = wm8993_i2c_remove, .id_table = wm8993_i2c_id, }; diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index f117ec0c48..d3cfd3788f 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -4614,7 +4614,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8994 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8994_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index b896d9c5be..eed48bf339 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2182,7 +2182,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8995 = { .num_dapm_routes = ARRAY_SIZE(wm8995_intercon), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8995_regmap = { @@ -2231,8 +2230,7 @@ static struct spi_driver wm8995_spi_driver = { #endif #if IS_ENABLED(CONFIG_I2C) -static int wm8995_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8995_i2c_probe(struct i2c_client *i2c) { struct wm8995_priv *wm8995; int ret; @@ -2270,7 +2268,7 @@ static struct i2c_driver wm8995_i2c_driver = { .driver = { .name = "wm8995", }, - .probe = wm8995_i2c_probe, + .probe_new = wm8995_i2c_probe, .id_table = wm8995_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 197ae7d84a..17f307a310 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2695,8 +2695,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8996 = { .set_pll = wm8996_set_fll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, - }; #define WM8996_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ @@ -2755,8 +2753,7 @@ static struct snd_soc_dai_driver wm8996_dai[] = { }, }; -static int wm8996_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8996_i2c_probe(struct i2c_client *i2c) { struct wm8996_priv *wm8996; int ret, i; @@ -3091,7 +3088,7 @@ static struct i2c_driver wm8996_i2c_driver = { .driver = { .name = "wm8996", }, - .probe = wm8996_i2c_probe, + .probe_new = wm8996_i2c_probe, .remove = wm8996_i2c_remove, .id_table = wm8996_i2c_id, }; diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 38ef631d1a..210ad662fc 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1105,7 +1105,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8997 = { .num_dapm_routes = ARRAY_SIZE(wm8997_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8997_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 00b59fc9b1..79fc6bbaa3 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -108,6 +108,7 @@ static int wm8998_inmux_put(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int mode_reg, mode_index; unsigned int mux, inmode, src_val, mode_val; + int change, ret; mux = ucontrol->value.enumerated.item[0]; if (mux > 1) @@ -137,14 +138,20 @@ static int wm8998_inmux_put(struct snd_kcontrol *kcontrol, snd_soc_component_update_bits(component, mode_reg, ARIZONA_IN1_MODE_MASK, mode_val); - snd_soc_component_update_bits(component, e->reg, - ARIZONA_IN1L_SRC_MASK | - ARIZONA_IN1L_SRC_SE_MASK, - src_val); + change = snd_soc_component_update_bits(component, e->reg, + ARIZONA_IN1L_SRC_MASK | + ARIZONA_IN1L_SRC_SE_MASK, + src_val); - return snd_soc_dapm_mux_update_power(dapm, kcontrol, - ucontrol->value.enumerated.item[0], - e, NULL); + ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, + ucontrol->value.enumerated.item[0], + e, NULL); + if (ret < 0) { + dev_err(arizona->dev, "Failed to update demux power state: %d\n", ret); + return ret; + } + + return change; } static const char * const wm8998_inmux_texts[] = { @@ -1325,7 +1332,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8998 = { .num_dapm_routes = ARRAY_SIZE(wm8998_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8998_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 4a667ee82f..d5151877d0 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1284,7 +1284,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9081 = { .num_dapm_routes = ARRAY_SIZE(wm9081_audio_paths), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm9081_regmap = { @@ -1299,8 +1298,7 @@ static const struct regmap_config wm9081_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int wm9081_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm9081_i2c_probe(struct i2c_client *i2c) { struct wm9081_priv *wm9081; unsigned int reg; @@ -1373,7 +1371,7 @@ static struct i2c_driver wm9081_i2c_driver = { .driver = { .name = "wm9081", }, - .probe = wm9081_i2c_probe, + .probe_new = wm9081_i2c_probe, .remove = wm9081_i2c_remove, .id_table = wm9081_i2c_id, }; diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index e0231a5460..ef3524c3f0 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -543,8 +543,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9090 = { .suspend_bias_off = 1, .idle_bias_on = 1, .use_pmdown_time = 1, - .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm9090_regmap = { @@ -561,8 +559,7 @@ static const struct regmap_config wm9090_regmap = { }; -static int wm9090_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm9090_i2c_probe(struct i2c_client *i2c) { struct wm9090_priv *wm9090; unsigned int reg; @@ -619,7 +616,7 @@ static struct i2c_driver wm9090_i2c_driver = { .driver = { .name = "wm9090", }, - .probe = wm9090_i2c_probe, + .probe_new = wm9090_i2c_probe, .id_table = wm9090_id, }; diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 99fe8f3166..d04902ef1d 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -368,7 +368,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9705 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm9705_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 7515c9d400..df9b798070 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -692,7 +692,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9712 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm9712_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index e0ce32dd4a..5d2e54e06e 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1257,7 +1257,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9713 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm9713_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index e32c8ded18..cfaa45ede9 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -97,13 +97,13 @@ struct wm_adsp_system_config_xm_hdr { __be32 wdma[8]; __be32 build_job_name[3]; __be32 build_job_number; -}; +} __packed; struct wm_halo_system_config_xm_hdr { __be32 halo_heartbeat; __be32 build_job_name[3]; __be32 build_job_number; -}; +} __packed; struct wm_adsp_alg_xm_struct { __be32 magic; @@ -114,13 +114,13 @@ struct wm_adsp_alg_xm_struct { __be32 high_water_mark; __be32 low_water_mark; __be64 smoothed_power; -}; +} __packed; struct wm_adsp_host_buf_coeff_v1 { __be32 host_buf_ptr; /* Host buffer pointer */ __be32 versions; /* Version numbers */ __be32 name[4]; /* The buffer name */ -}; +} __packed; struct wm_adsp_buffer { __be32 buf1_base; /* Base addr of first buffer area */ @@ -141,7 +141,7 @@ struct wm_adsp_buffer { __be32 min_free; /* min free space since stream start */ __be32 blocks_written[2]; /* total blocks written (64 bit) */ __be32 words_written[2]; /* total words written (64 bit) */ -}; +} __packed; struct wm_adsp_compr; @@ -333,7 +333,7 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct wm_adsp *dsp = snd_soc_component_get_drvdata(component); - int ret = 0; + int ret = 1; if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw) return 0; @@ -675,21 +675,12 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len) { - struct cs_dsp_coeff_ctl *cs_ctl; + struct cs_dsp_coeff_ctl *cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg); struct wm_coeff_ctl *ctl; struct snd_kcontrol *kcontrol; char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int ret; - cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg); - if (!cs_ctl) - return -EINVAL; - - ctl = cs_ctl->priv; - - if (len > cs_ctl->len) - return -EINVAL; - ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len); if (ret) return ret; @@ -697,6 +688,8 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, if (cs_ctl->flags & WMFW_CTL_FLAG_SYS) return 0; + ctl = cs_ctl->priv; + if (dsp->component->name_prefix) snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s", dsp->component->name_prefix, ctl->name); @@ -720,16 +713,8 @@ EXPORT_SYMBOL_GPL(wm_adsp_write_ctl); int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len) { - struct cs_dsp_coeff_ctl *cs_ctl; - - cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg); - if (!cs_ctl) - return -EINVAL; - - if (len > cs_ctl->len) - return -EINVAL; - - return cs_dsp_coeff_read_ctrl(cs_ctl, 0, buf, len); + return cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg), + 0, buf, len); } EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); @@ -997,7 +982,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, snd_soc_dapm_sync(dapm); } - return 0; + return 1; } EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 616b26c70c..6c8b1db649 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -749,11 +749,9 @@ static int wsa881x_put_pa_gain(struct snd_kcontrol *kc, unsigned int mask = (1 << fls(max)) - 1; int val, ret, min_gain, max_gain; - ret = pm_runtime_get_sync(comp->dev); - if (ret < 0 && ret != -EACCES) { - pm_runtime_put_noidle(comp->dev); + ret = pm_runtime_resume_and_get(comp->dev); + if (ret < 0 && ret != -EACCES) return ret; - } max_gain = (max - ucontrol->value.integer.value[0]) & mask; /* @@ -1066,6 +1064,7 @@ static const struct snd_soc_component_driver wsa881x_component_drv = { .num_dapm_widgets = ARRAY_SIZE(wsa881x_dapm_widgets), .dapm_routes = wsa881x_audio_map, .num_dapm_routes = ARRAY_SIZE(wsa881x_audio_map), + .endianness = 1, }; static int wsa881x_update_status(struct sdw_slave *slave, @@ -1174,11 +1173,17 @@ static int __maybe_unused wsa881x_runtime_resume(struct device *dev) struct sdw_slave *slave = dev_to_sdw_dev(dev); struct regmap *regmap = dev_get_regmap(dev, NULL); struct wsa881x_priv *wsa881x = dev_get_drvdata(dev); + unsigned long time; gpiod_direction_output(wsa881x->sd_n, 1); - wait_for_completion_timeout(&slave->initialization_complete, - msecs_to_jiffies(WSA881X_PROBE_TIMEOUT)); + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(WSA881X_PROBE_TIMEOUT)); + if (!time) { + dev_err(dev, "Initialization not complete, timed out\n"); + gpiod_direction_output(wsa881x->sd_n, 0); + return -ETIMEDOUT; + } regcache_cache_only(regmap, false); regcache_sync(regmap); diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c index 6cae0fb080..c3d0a2a7c3 100644 --- a/sound/soc/codecs/zl38060.c +++ b/sound/soc/codecs/zl38060.c @@ -385,7 +385,6 @@ static const struct snd_soc_component_driver zl38_component_dev = { .dapm_routes = zl38_dapm_routes, .num_dapm_routes = ARRAY_SIZE(zl38_dapm_routes), .endianness = 1, - .non_legacy_dai_naming = 1, }; static void chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val) diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 1edac3e10f..7f7dd07c63 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -357,20 +357,20 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) int ret = 0; switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: if (dev->capability & DW_I2S_SLAVE) ret = 0; else ret = -EINVAL; break; - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: if (dev->capability & DW_I2S_MASTER) ret = 0; else ret = -EINVAL; break; - case SND_SOC_DAIFMT_CBP_CFC: - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BC_FP: + case SND_SOC_DAIFMT_BP_FC: ret = -EINVAL; break; default: @@ -449,9 +449,10 @@ static int dw_i2s_resume(struct snd_soc_component *component) #endif static const struct snd_soc_component_driver dw_i2s_component = { - .name = "dw-i2s", - .suspend = dw_i2s_suspend, - .resume = dw_i2s_resume, + .name = "dw-i2s", + .suspend = dw_i2s_suspend, + .resume = dw_i2s_resume, + .legacy_dai_naming = 1, }; /* diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 10fa387534..614eceda6b 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -19,6 +19,7 @@ config SND_SOC_FSL_SAI select REGMAP_MMIO select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_SOC_FSL_UTILS help Say Y if you want to add Synchronous Audio Interface (SAI) support for the Freescale CPUs. @@ -59,6 +60,7 @@ config SND_SOC_FSL_SPDIF select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC) select BITREVERSE + select SND_SOC_FSL_UTILS help Say Y if you want to add Sony/Philips Digital Interface (SPDIF) support for the Freescale CPUs. @@ -80,6 +82,7 @@ config SND_SOC_FSL_MICFIL select REGMAP_MMIO select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_SOC_FSL_UTILS help Say Y if you want to add Pulse Density Modulation microphone interface (MICFIL) support for NXP. diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index d9a0d4768c..c836848ef0 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -537,6 +537,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) struct device *codec_dev = NULL; const char *codec_dai_name; const char *codec_dev_name; + u32 asrc_fmt = 0; u32 width; int ret; @@ -829,8 +830,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) goto asrc_fail; } - ret = of_property_read_u32(asrc_np, "fsl,asrc-format", - &priv->asrc_format); + ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &asrc_fmt); + priv->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { /* Fallback to old binding; translate to asrc_format */ ret = of_property_read_u32(asrc_np, "fsl,asrc-width", diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index d7d1536a4f..aa5edf32d9 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -1066,6 +1066,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) struct resource *res; void __iomem *regs; int irq, ret, i; + u32 asrc_fmt = 0; u32 map_idx; char tmp[16]; u32 width; @@ -1174,7 +1175,8 @@ static int fsl_asrc_probe(struct platform_device *pdev) return ret; } - ret = of_property_read_u32(np, "fsl,asrc-format", &asrc->asrc_format); + ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt); + asrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { ret = of_property_read_u32(np, "fsl,asrc-width", &width); if (ret) { @@ -1197,7 +1199,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) } } - if (!(FSL_ASRC_FORMATS & (1ULL << asrc->asrc_format))) { + if (!(FSL_ASRC_FORMATS & pcm_format_to_bits(asrc->asrc_format))) { dev_warn(&pdev->dev, "unsupported width, use default S24_LE\n"); asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; } @@ -1211,11 +1213,9 @@ static int fsl_asrc_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - pm_runtime_put_noidle(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) goto err_pm_get_sync; - } ret = fsl_asrc_init(asrc); if (ret) { diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index cd9b36ec0e..12ddf2320f 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include @@ -114,8 +114,8 @@ static int fsl_asrc_dma_trigger(struct snd_soc_component *component, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - dmaengine_terminate_all(pair->dma_chan[OUT]); - dmaengine_terminate_all(pair->dma_chan[IN]); + dmaengine_terminate_async(pair->dma_chan[OUT]); + dmaengine_terminate_async(pair->dma_chan[IN]); break; default: return -EINVAL; @@ -129,6 +129,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, struct snd_pcm_hw_params *params) { enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + enum sdma_peripheral_type be_peripheral_type = IMX_DMATYPE_SSI; struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL; @@ -139,6 +140,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, struct snd_soc_component *component_be = NULL; struct fsl_asrc *asrc = pair->asrc; struct dma_slave_config config_fe, config_be; + struct sdma_peripheral_config audio_config; enum asrc_pair_index index = pair->index; struct device *dev = component->dev; struct device_node *of_dma_node; @@ -221,6 +223,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, /* Get DMA request of Back-End */ tmp_data = tmp_chan->private; pair->dma_data.dma_request = tmp_data->dma_request; + be_peripheral_type = tmp_data->peripheral_type; if (!be_chan) dma_release_channel(tmp_chan); @@ -268,6 +271,17 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, config_be.dst_addr_width = buswidth; config_be.dst_maxburst = dma_params_be->maxburst; + memset(&audio_config, 0, sizeof(audio_config)); + config_be.peripheral_config = &audio_config; + config_be.peripheral_size = sizeof(audio_config); + + if (tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL || + be_peripheral_type == IMX_DMATYPE_SPDIF)) + audio_config.n_fifos_dst = 2; + if (!tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL || + be_peripheral_type == IMX_DMATYPE_SPDIF)) + audio_config.n_fifos_src = 2; + if (tx) { config_be.src_addr = asrc->paddr + asrc->get_fifo_addr(OUT, index); config_be.dst_addr = dma_params_be->addr; @@ -441,5 +455,6 @@ struct snd_soc_component_driver fsl_asrc_component = { .close = fsl_asrc_dma_shutdown, .pointer = fsl_asrc_dma_pcm_pointer, .pcm_construct = fsl_asrc_dma_pcm_new, + .legacy_dai_naming = 1, }; EXPORT_SYMBOL_GPL(fsl_asrc_component); diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index 422922146f..873295f59a 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -103,7 +103,8 @@ static struct snd_soc_dai_driver fsl_aud2htx_dai = { }; static const struct snd_soc_component_driver fsl_aud2htx_component = { - .name = "fsl-aud2htx", + .name = "fsl-aud2htx", + .legacy_dai_naming = 1, }; static const struct reg_default fsl_aud2htx_reg_defaults[] = { diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index 6dbb8c99f6..43857b7a81 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -259,8 +259,8 @@ static int fsl_audmix_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* For playback the AUDMIX is consumer, and for record is provider */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_BP_FP: break; default: return -EINVAL; @@ -317,7 +317,7 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd, } static const struct snd_soc_dai_ops fsl_audmix_dai_ops = { - .set_fmt = fsl_audmix_dai_set_fmt, + .set_fmt = fsl_audmix_dai_set_fmt, .trigger = fsl_audmix_dai_trigger, }; diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index be14f84796..3153d19136 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -476,7 +476,8 @@ static int fsl_easrc_prefilter_config(struct fsl_asrc *easrc, struct fsl_asrc_pair *ctx; struct device *dev; u32 inrate, outrate, offset = 0; - u32 in_s_rate, out_s_rate, in_s_fmt, out_s_fmt; + u32 in_s_rate, out_s_rate; + snd_pcm_format_t in_s_fmt, out_s_fmt; int ret, i; if (!easrc) @@ -1572,9 +1573,10 @@ static struct snd_soc_dai_driver fsl_easrc_dai = { }; static const struct snd_soc_component_driver fsl_easrc_component = { - .name = "fsl-easrc-dai", - .controls = fsl_easrc_snd_controls, - .num_controls = ARRAY_SIZE(fsl_easrc_snd_controls), + .name = "fsl-easrc-dai", + .controls = fsl_easrc_snd_controls, + .num_controls = ARRAY_SIZE(fsl_easrc_snd_controls), + .legacy_dai_naming = 1, }; static const struct reg_default fsl_easrc_reg_defaults[] = { @@ -1873,6 +1875,7 @@ static int fsl_easrc_probe(struct platform_device *pdev) struct resource *res; struct device_node *np; void __iomem *regs; + u32 asrc_fmt = 0; int ret, irq; easrc = devm_kzalloc(dev, sizeof(*easrc), GFP_KERNEL); @@ -1933,13 +1936,14 @@ static int fsl_easrc_probe(struct platform_device *pdev) return ret; } - ret = of_property_read_u32(np, "fsl,asrc-format", &easrc->asrc_format); + ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt); + easrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { dev_err(dev, "failed to asrc format\n"); return ret; } - if (!(FSL_EASRC_FORMATS & (1ULL << easrc->asrc_format))) { + if (!(FSL_EASRC_FORMATS & (pcm_format_to_bits(easrc->asrc_format)))) { dev_warn(dev, "unsupported format, switching to S24_LE\n"); easrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; } diff --git a/sound/soc/fsl/fsl_easrc.h b/sound/soc/fsl/fsl_easrc.h index 30620d5625..7c70dac527 100644 --- a/sound/soc/fsl/fsl_easrc.h +++ b/sound/soc/fsl/fsl_easrc.h @@ -7,7 +7,7 @@ #define _FSL_EASRC_H #include -#include +#include #include "fsl_asrc_common.h" @@ -569,7 +569,7 @@ struct fsl_easrc_io_params { unsigned int access_len; unsigned int fifo_wtmk; unsigned int sample_rate; - unsigned int sample_format; + snd_pcm_format_t sample_format; unsigned int norm_rate; }; diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index ed444e8f1d..5c21fc490f 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -480,16 +480,16 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* DAI clock provider masks */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: esai_priv->consumer_mode = true; break; - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BP_FC: xccr |= ESAI_xCCR_xCKD; break; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: xccr |= ESAI_xCCR_xFSD; break; - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD; break; default: @@ -824,7 +824,8 @@ static struct snd_soc_dai_driver fsl_esai_dai = { }; static const struct snd_soc_component_driver fsl_esai_component = { - .name = "fsl-esai", + .name = "fsl-esai", + .legacy_dai_naming = 1, }; static const struct reg_default fsl_esai_reg_defaults[] = { @@ -1050,11 +1051,9 @@ static int fsl_esai_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - pm_runtime_put_noidle(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) goto err_pm_get_sync; - } ret = fsl_esai_hw_init(esai_priv); if (ret) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 9f90989ac5..79ef4e269b 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright 2018 NXP +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -22,10 +24,18 @@ #include #include "fsl_micfil.h" -#include "imx-pcm.h" +#include "fsl_utils.h" -#define FSL_MICFIL_RATES SNDRV_PCM_RATE_8000_48000 -#define FSL_MICFIL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) +#define MICFIL_OSR_DEFAULT 16 + +enum quality { + QUALITY_HIGH, + QUALITY_MEDIUM, + QUALITY_LOW, + QUALITY_VLOW0, + QUALITY_VLOW1, + QUALITY_VLOW2, +}; struct fsl_micfil { struct platform_device *pdev; @@ -33,14 +43,15 @@ struct fsl_micfil { const struct fsl_micfil_soc_data *soc; struct clk *busclk; struct clk *mclk; + struct clk *pll8k_clk; + struct clk *pll11k_clk; struct snd_dmaengine_dai_dma_data dma_params_rx; + struct sdma_peripheral_config sdmacfg; unsigned int dataline; char name[32]; int irq[MICFIL_IRQ_LINES]; - unsigned int mclk_streams; - int quality; /*QUALITY 2-0 bits */ - bool slave_mode; - int channel_gain[8]; + enum quality quality; + int dc_remover; }; struct fsl_micfil_soc_data { @@ -48,6 +59,7 @@ struct fsl_micfil_soc_data { unsigned int fifo_depth; unsigned int dataline; bool imx; + u64 formats; }; static struct fsl_micfil_soc_data fsl_micfil_imx8mm = { @@ -55,37 +67,91 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mm = { .fifos = 8, .fifo_depth = 8, .dataline = 0xf, + .formats = SNDRV_PCM_FMTBIT_S16_LE, +}; + +static struct fsl_micfil_soc_data fsl_micfil_imx8mp = { + .imx = true, + .fifos = 8, + .fifo_depth = 32, + .dataline = 0xf, + .formats = SNDRV_PCM_FMTBIT_S32_LE, }; static const struct of_device_id fsl_micfil_dt_ids[] = { { .compatible = "fsl,imx8mm-micfil", .data = &fsl_micfil_imx8mm }, + { .compatible = "fsl,imx8mp-micfil", .data = &fsl_micfil_imx8mp }, {} }; MODULE_DEVICE_TABLE(of, fsl_micfil_dt_ids); -/* Table 5. Quality Modes - * Medium 0 0 0 - * High 0 0 1 - * Very Low 2 1 0 0 - * Very Low 1 1 0 1 - * Very Low 0 1 1 0 - * Low 1 1 1 - */ static const char * const micfil_quality_select_texts[] = { - "Medium", "High", - "N/A", "N/A", - "VLow2", "VLow1", - "VLow0", "Low", + [QUALITY_HIGH] = "High", + [QUALITY_MEDIUM] = "Medium", + [QUALITY_LOW] = "Low", + [QUALITY_VLOW0] = "VLow0", + [QUALITY_VLOW1] = "Vlow1", + [QUALITY_VLOW2] = "Vlow2", }; static const struct soc_enum fsl_micfil_quality_enum = - SOC_ENUM_SINGLE(REG_MICFIL_CTRL2, - MICFIL_CTRL2_QSEL_SHIFT, - ARRAY_SIZE(micfil_quality_select_texts), - micfil_quality_select_texts); + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_quality_select_texts), + micfil_quality_select_texts); static DECLARE_TLV_DB_SCALE(gain_tlv, 0, 100, 0); +static int micfil_set_quality(struct fsl_micfil *micfil) +{ + u32 qsel; + + switch (micfil->quality) { + case QUALITY_HIGH: + qsel = MICFIL_QSEL_HIGH_QUALITY; + break; + case QUALITY_MEDIUM: + qsel = MICFIL_QSEL_MEDIUM_QUALITY; + break; + case QUALITY_LOW: + qsel = MICFIL_QSEL_LOW_QUALITY; + break; + case QUALITY_VLOW0: + qsel = MICFIL_QSEL_VLOW0_QUALITY; + break; + case QUALITY_VLOW1: + qsel = MICFIL_QSEL_VLOW1_QUALITY; + break; + case QUALITY_VLOW2: + qsel = MICFIL_QSEL_VLOW2_QUALITY; + break; + } + + return regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, + MICFIL_CTRL2_QSEL, + FIELD_PREP(MICFIL_CTRL2_QSEL, qsel)); +} + +static int micfil_quality_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt); + + ucontrol->value.integer.value[0] = micfil->quality; + + return 0; +} + +static int micfil_quality_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt); + + micfil->quality = ucontrol->value.integer.value[0]; + + return micfil_set_quality(micfil); +} + static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL, MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0x7, gain_tlv), @@ -105,64 +171,9 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0x7, gain_tlv), SOC_ENUM_EXT("MICFIL Quality Select", fsl_micfil_quality_enum, - snd_soc_get_enum_double, snd_soc_put_enum_double), + micfil_quality_get, micfil_quality_set), }; -static inline int get_pdm_clk(struct fsl_micfil *micfil, - unsigned int rate) -{ - u32 ctrl2_reg; - int qsel, osr; - int bclk; - - regmap_read(micfil->regmap, REG_MICFIL_CTRL2, &ctrl2_reg); - osr = 16 - ((ctrl2_reg & MICFIL_CTRL2_CICOSR_MASK) - >> MICFIL_CTRL2_CICOSR_SHIFT); - - regmap_read(micfil->regmap, REG_MICFIL_CTRL2, &ctrl2_reg); - qsel = ctrl2_reg & MICFIL_CTRL2_QSEL_MASK; - - switch (qsel) { - case MICFIL_HIGH_QUALITY: - bclk = rate * 8 * osr / 2; /* kfactor = 0.5 */ - break; - case MICFIL_MEDIUM_QUALITY: - case MICFIL_VLOW0_QUALITY: - bclk = rate * 4 * osr * 1; /* kfactor = 1 */ - break; - case MICFIL_LOW_QUALITY: - case MICFIL_VLOW1_QUALITY: - bclk = rate * 2 * osr * 2; /* kfactor = 2 */ - break; - case MICFIL_VLOW2_QUALITY: - bclk = rate * osr * 4; /* kfactor = 4 */ - break; - default: - dev_err(&micfil->pdev->dev, - "Please make sure you select a valid quality.\n"); - bclk = -1; - break; - } - - return bclk; -} - -static inline int get_clk_div(struct fsl_micfil *micfil, - unsigned int rate) -{ - u32 ctrl2_reg; - long mclk_rate; - int clk_div; - - regmap_read(micfil->regmap, REG_MICFIL_CTRL2, &ctrl2_reg); - - mclk_rate = clk_get_rate(micfil->mclk); - - clk_div = mclk_rate / (get_pdm_clk(micfil, rate) * 2); - - return clk_div; -} - /* The SRES is a self-negated bit which provides the CPU with the * capability to initialize the PDM Interface module through the * slave-bus interface. This bit always reads as zero, and this @@ -173,45 +184,19 @@ static int fsl_micfil_reset(struct device *dev) struct fsl_micfil *micfil = dev_get_drvdata(dev); int ret; - ret = regmap_update_bits(micfil->regmap, - REG_MICFIL_CTRL1, - MICFIL_CTRL1_MDIS_MASK, - 0); - if (ret) { - dev_err(dev, "failed to clear MDIS bit %d\n", ret); + ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_MDIS); + if (ret) return ret; - } - ret = regmap_update_bits(micfil->regmap, - REG_MICFIL_CTRL1, - MICFIL_CTRL1_SRES_MASK, - MICFIL_CTRL1_SRES); - if (ret) { - dev_err(dev, "failed to reset MICFIL: %d\n", ret); + ret = regmap_set_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_SRES); + if (ret) return ret; - } return 0; } -static int fsl_micfil_set_mclk_rate(struct fsl_micfil *micfil, - unsigned int freq) -{ - struct device *dev = &micfil->pdev->dev; - int ret; - - clk_disable_unprepare(micfil->mclk); - - ret = clk_set_rate(micfil->mclk, freq * 1024); - if (ret) - dev_warn(dev, "failed to set rate (%u): %d\n", - freq * 1024, ret); - - clk_prepare_enable(micfil->mclk); - - return ret; -} - static int fsl_micfil_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -249,42 +234,32 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, * 11 - reserved */ ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_DISEL_MASK, - (1 << MICFIL_CTRL1_DISEL_SHIFT)); - if (ret) { - dev_err(dev, "failed to update DISEL bits\n"); + MICFIL_CTRL1_DISEL, + FIELD_PREP(MICFIL_CTRL1_DISEL, MICFIL_CTRL1_DISEL_DMA)); + if (ret) return ret; - } /* Enable the module */ - ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_PDMIEN_MASK, - MICFIL_CTRL1_PDMIEN); - if (ret) { - dev_err(dev, "failed to enable the module\n"); + ret = regmap_set_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_PDMIEN); + if (ret) return ret; - } break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* Disable the module */ - ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_PDMIEN_MASK, - 0); - if (ret) { - dev_err(dev, "failed to enable the module\n"); + ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_PDMIEN); + if (ret) return ret; - } ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_DISEL_MASK, - (0 << MICFIL_CTRL1_DISEL_SHIFT)); - if (ret) { - dev_err(dev, "failed to update DISEL bits\n"); + MICFIL_CTRL1_DISEL, + FIELD_PREP(MICFIL_CTRL1_DISEL, MICFIL_CTRL1_DISEL_DISABLE)); + if (ret) return ret; - } break; default: return -EINVAL; @@ -292,37 +267,25 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static int fsl_set_clock_params(struct device *dev, unsigned int rate) +static int fsl_micfil_reparent_rootclk(struct fsl_micfil *micfil, unsigned int sample_rate) { - struct fsl_micfil *micfil = dev_get_drvdata(dev); - int clk_div; + struct device *dev = &micfil->pdev->dev; + u64 ratio = sample_rate; + struct clk *clk; int ret; - ret = fsl_micfil_set_mclk_rate(micfil, rate); - if (ret < 0) - dev_err(dev, "failed to set mclk[%lu] to rate %u\n", - clk_get_rate(micfil->mclk), rate); - - /* set CICOSR */ - ret |= regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, - MICFIL_CTRL2_CICOSR_MASK, - MICFIL_CTRL2_OSR_DEFAULT); - if (ret) - dev_err(dev, "failed to set CICOSR in reg 0x%X\n", - REG_MICFIL_CTRL2); - - /* set CLK_DIV */ - clk_div = get_clk_div(micfil, rate); - if (clk_div < 0) - ret = -EINVAL; + /* Get root clock */ + clk = micfil->mclk; - ret |= regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, - MICFIL_CTRL2_CLKDIV_MASK, clk_div); + /* Disable clock first, for it was enabled by pm_runtime */ + clk_disable_unprepare(clk); + fsl_asoc_reparent_pll_clocks(dev, clk, micfil->pll8k_clk, + micfil->pll11k_clk, ratio); + ret = clk_prepare_enable(clk); if (ret) - dev_err(dev, "failed to set CLKDIV in reg 0x%X\n", - REG_MICFIL_CTRL2); + return ret; - return ret; + return 0; } static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, @@ -332,97 +295,86 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); unsigned int channels = params_channels(params); unsigned int rate = params_rate(params); - struct device *dev = &micfil->pdev->dev; + int clk_div = 8; + int osr = MICFIL_OSR_DEFAULT; int ret; /* 1. Disable the module */ - ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_PDMIEN_MASK, 0); - if (ret) { - dev_err(dev, "failed to disable the module\n"); + ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_PDMIEN); + if (ret) return ret; - } /* enable channels */ ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, 0xFF, ((1 << channels) - 1)); - if (ret) { - dev_err(dev, "failed to enable channels %d, reg 0x%X\n", ret, - REG_MICFIL_CTRL1); + if (ret) return ret; - } - ret = fsl_set_clock_params(dev, rate); - if (ret < 0) { - dev_err(dev, "Failed to set clock parameters [%d]\n", ret); + ret = fsl_micfil_reparent_rootclk(micfil, rate); + if (ret) return ret; - } - micfil->dma_params_rx.maxburst = channels * MICFIL_DMA_MAXBURST_RX; - - return 0; -} - -static int fsl_micfil_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir) -{ - struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); - struct device *dev = &micfil->pdev->dev; - - int ret; + ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8); + if (ret) + return ret; - if (!freq) - return 0; + ret = micfil_set_quality(micfil); + if (ret) + return ret; - ret = fsl_micfil_set_mclk_rate(micfil, freq); - if (ret < 0) - dev_err(dev, "failed to set mclk[%lu] to rate %u\n", - clk_get_rate(micfil->mclk), freq); + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, + MICFIL_CTRL2_CLKDIV | MICFIL_CTRL2_CICOSR, + FIELD_PREP(MICFIL_CTRL2_CLKDIV, clk_div) | + FIELD_PREP(MICFIL_CTRL2_CICOSR, 16 - osr)); + + micfil->dma_params_rx.peripheral_config = &micfil->sdmacfg; + micfil->dma_params_rx.peripheral_size = sizeof(micfil->sdmacfg); + micfil->sdmacfg.n_fifos_src = channels; + micfil->sdmacfg.sw_done = true; + micfil->dma_params_rx.maxburst = channels * MICFIL_DMA_MAXBURST_RX; - return ret; + return 0; } static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { .startup = fsl_micfil_startup, .trigger = fsl_micfil_trigger, .hw_params = fsl_micfil_hw_params, - .set_sysclk = fsl_micfil_set_dai_sysclk, }; static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); struct device *dev = cpu_dai->dev; - unsigned int val; - int ret; - int i; + unsigned int val = 0; + int ret, i; - /* set qsel to medium */ - ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, - MICFIL_CTRL2_QSEL_MASK, MICFIL_MEDIUM_QUALITY); + micfil->quality = QUALITY_VLOW0; + + /* set default gain to 2 */ + regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222); + + /* set DC Remover in bypass mode*/ + for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) + val |= MICFIL_DC_BYPASS << MICFIL_DC_CHX_SHIFT(i); + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_DC_CTRL, + MICFIL_DC_CTRL_CONFIG, val); if (ret) { - dev_err(dev, "failed to set quality mode bits, reg 0x%X\n", - REG_MICFIL_CTRL2); + dev_err(dev, "failed to set DC Remover mode bits\n"); return ret; } - - /* set default gain to max_gain */ - regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x77777777); - for (i = 0; i < 8; i++) - micfil->channel_gain[i] = 0xF; + micfil->dc_remover = MICFIL_DC_BYPASS; snd_soc_dai_init_dma_data(cpu_dai, NULL, &micfil->dma_params_rx); /* FIFO Watermark Control - FIFOWMK*/ - val = MICFIL_FIFO_CTRL_FIFOWMK(micfil->soc->fifo_depth) - 1; ret = regmap_update_bits(micfil->regmap, REG_MICFIL_FIFO_CTRL, - MICFIL_FIFO_CTRL_FIFOWMK_MASK, - val); - if (ret) { - dev_err(dev, "failed to set FIFOWMK\n"); + MICFIL_FIFO_CTRL_FIFOWMK, + FIELD_PREP(MICFIL_FIFO_CTRL_FIFOWMK, micfil->soc->fifo_depth - 1)); + if (ret) return ret; - } return 0; } @@ -433,8 +385,8 @@ static struct snd_soc_dai_driver fsl_micfil_dai = { .stream_name = "CPU-Capture", .channels_min = 1, .channels_max = 8, - .rates = FSL_MICFIL_RATES, - .formats = FSL_MICFIL_FORMATS, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .ops = &fsl_micfil_dai_ops, }; @@ -443,7 +395,7 @@ static const struct snd_soc_component_driver fsl_micfil_component = { .name = "fsl-micfil-dai", .controls = fsl_micfil_snd_controls, .num_controls = ARRAY_SIZE(fsl_micfil_snd_controls), - + .legacy_dai_naming = 1, }; /* REGMAP */ @@ -578,11 +530,11 @@ static irqreturn_t micfil_isr(int irq, void *devid) regmap_read(micfil->regmap, REG_MICFIL_CTRL1, &ctrl1_reg); regmap_read(micfil->regmap, REG_MICFIL_FIFO_STAT, &fifo_stat_reg); - dma_enabled = MICFIL_DMA_ENABLED(ctrl1_reg); + dma_enabled = FIELD_GET(MICFIL_CTRL1_DISEL, ctrl1_reg) == MICFIL_CTRL1_DISEL_DMA; /* Channel 0-7 Output Data Flags */ for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) { - if (stat_reg & MICFIL_STAT_CHXF_MASK(i)) + if (stat_reg & MICFIL_STAT_CHXF(i)) dev_dbg(&pdev->dev, "Data available in Data Channel %d\n", i); /* if DMA is not enabled, field must be written with 1 @@ -591,17 +543,17 @@ static irqreturn_t micfil_isr(int irq, void *devid) if (!dma_enabled) regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, - MICFIL_STAT_CHXF_MASK(i), + MICFIL_STAT_CHXF(i), 1); } for (i = 0; i < MICFIL_FIFO_NUM; i++) { - if (fifo_stat_reg & MICFIL_FIFO_STAT_FIFOX_OVER_MASK(i)) + if (fifo_stat_reg & MICFIL_FIFO_STAT_FIFOX_OVER(i)) dev_dbg(&pdev->dev, "FIFO Overflow Exception flag for channel %d\n", i); - if (fifo_stat_reg & MICFIL_FIFO_STAT_FIFOX_UNDER_MASK(i)) + if (fifo_stat_reg & MICFIL_FIFO_STAT_FIFOX_UNDER(i)) dev_dbg(&pdev->dev, "FIFO Underflow Exception flag for channel %d\n", i); @@ -618,16 +570,16 @@ static irqreturn_t micfil_err_isr(int irq, void *devid) regmap_read(micfil->regmap, REG_MICFIL_STAT, &stat_reg); - if (stat_reg & MICFIL_STAT_BSY_FIL_MASK) + if (stat_reg & MICFIL_STAT_BSY_FIL) dev_dbg(&pdev->dev, "isr: Decimation Filter is running\n"); - if (stat_reg & MICFIL_STAT_FIR_RDY_MASK) + if (stat_reg & MICFIL_STAT_FIR_RDY) dev_dbg(&pdev->dev, "isr: FIR Filter Data ready\n"); - if (stat_reg & MICFIL_STAT_LOWFREQF_MASK) { + if (stat_reg & MICFIL_STAT_LOWFREQF) { dev_dbg(&pdev->dev, "isr: ipg_clk_app is too low\n"); regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, - MICFIL_STAT_LOWFREQF_MASK, 1); + MICFIL_STAT_LOWFREQF, 1); } return IRQ_HANDLED; @@ -640,7 +592,6 @@ static int fsl_micfil_probe(struct platform_device *pdev) struct resource *res; void __iomem *regs; int ret, i; - unsigned long irqflag = 0; micfil = devm_kzalloc(&pdev->dev, sizeof(*micfil), GFP_KERNEL); if (!micfil) @@ -668,6 +619,9 @@ static int fsl_micfil_probe(struct platform_device *pdev) return PTR_ERR(micfil->busclk); } + fsl_asoc_get_pll_clocks(&pdev->dev, &micfil->pll8k_clk, + &micfil->pll11k_clk); + /* init regmap */ regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) @@ -699,17 +653,13 @@ static int fsl_micfil_probe(struct platform_device *pdev) /* get IRQs */ for (i = 0; i < MICFIL_IRQ_LINES; i++) { micfil->irq[i] = platform_get_irq(pdev, i); - dev_err(&pdev->dev, "GET IRQ: %d\n", micfil->irq[i]); if (micfil->irq[i] < 0) return micfil->irq[i]; } - if (of_property_read_bool(np, "fsl,shared-interrupt")) - irqflag = IRQF_SHARED; - /* Digital Microphone interface interrupt */ ret = devm_request_irq(&pdev->dev, micfil->irq[0], - micfil_isr, irqflag, + micfil_isr, IRQF_SHARED, micfil->name, micfil); if (ret) { dev_err(&pdev->dev, "failed to claim mic interface irq %u\n", @@ -719,7 +669,7 @@ static int fsl_micfil_probe(struct platform_device *pdev) /* Digital Microphone interface error interrupt */ ret = devm_request_irq(&pdev->dev, micfil->irq[1], - micfil_err_isr, irqflag, + micfil_err_isr, IRQF_SHARED, micfil->name, micfil); if (ret) { dev_err(&pdev->dev, "failed to claim mic interface error irq %u\n", @@ -731,7 +681,6 @@ static int fsl_micfil_probe(struct platform_device *pdev) micfil->dma_params_rx.addr = res->start + REG_MICFIL_DATACH0; micfil->dma_params_rx.maxburst = MICFIL_DMA_MAXBURST_RX; - platform_set_drvdata(pdev, micfil); pm_runtime_enable(&pdev->dev); @@ -747,6 +696,8 @@ static int fsl_micfil_probe(struct platform_device *pdev) return ret; } + fsl_micfil_dai.capture.formats = micfil->soc->formats; + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_micfil_component, &fsl_micfil_dai, 1); if (ret) { diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h index bac825c313..d60285dd07 100644 --- a/sound/soc/fsl/fsl_micfil.h +++ b/sound/soc/fsl/fsl_micfil.h @@ -33,240 +33,103 @@ #define REG_MICFIL_VAD0_ZCD 0xA8 /* MICFIL Control Register 1 -- REG_MICFILL_CTRL1 0x00 */ -#define MICFIL_CTRL1_MDIS_SHIFT 31 -#define MICFIL_CTRL1_MDIS_MASK BIT(MICFIL_CTRL1_MDIS_SHIFT) -#define MICFIL_CTRL1_MDIS BIT(MICFIL_CTRL1_MDIS_SHIFT) -#define MICFIL_CTRL1_DOZEN_SHIFT 30 -#define MICFIL_CTRL1_DOZEN_MASK BIT(MICFIL_CTRL1_DOZEN_SHIFT) -#define MICFIL_CTRL1_DOZEN BIT(MICFIL_CTRL1_DOZEN_SHIFT) -#define MICFIL_CTRL1_PDMIEN_SHIFT 29 -#define MICFIL_CTRL1_PDMIEN_MASK BIT(MICFIL_CTRL1_PDMIEN_SHIFT) -#define MICFIL_CTRL1_PDMIEN BIT(MICFIL_CTRL1_PDMIEN_SHIFT) -#define MICFIL_CTRL1_DBG_SHIFT 28 -#define MICFIL_CTRL1_DBG_MASK BIT(MICFIL_CTRL1_DBG_SHIFT) -#define MICFIL_CTRL1_DBG BIT(MICFIL_CTRL1_DBG_SHIFT) -#define MICFIL_CTRL1_SRES_SHIFT 27 -#define MICFIL_CTRL1_SRES_MASK BIT(MICFIL_CTRL1_SRES_SHIFT) -#define MICFIL_CTRL1_SRES BIT(MICFIL_CTRL1_SRES_SHIFT) -#define MICFIL_CTRL1_DBGE_SHIFT 26 -#define MICFIL_CTRL1_DBGE_MASK BIT(MICFIL_CTRL1_DBGE_SHIFT) -#define MICFIL_CTRL1_DBGE BIT(MICFIL_CTRL1_DBGE_SHIFT) -#define MICFIL_CTRL1_DISEL_SHIFT 24 -#define MICFIL_CTRL1_DISEL_WIDTH 2 -#define MICFIL_CTRL1_DISEL_MASK ((BIT(MICFIL_CTRL1_DISEL_WIDTH) - 1) \ - << MICFIL_CTRL1_DISEL_SHIFT) -#define MICFIL_CTRL1_DISEL(v) (((v) << MICFIL_CTRL1_DISEL_SHIFT) \ - & MICFIL_CTRL1_DISEL_MASK) -#define MICFIL_CTRL1_ERREN_SHIFT 23 -#define MICFIL_CTRL1_ERREN_MASK BIT(MICFIL_CTRL1_ERREN_SHIFT) -#define MICFIL_CTRL1_ERREN BIT(MICFIL_CTRL1_ERREN_SHIFT) -#define MICFIL_CTRL1_CHEN_SHIFT 0 -#define MICFIL_CTRL1_CHEN_WIDTH 8 -#define MICFIL_CTRL1_CHEN_MASK(x) (BIT(x) << MICFIL_CTRL1_CHEN_SHIFT) -#define MICFIL_CTRL1_CHEN(x) (MICFIL_CTRL1_CHEN_MASK(x)) +#define MICFIL_CTRL1_MDIS BIT(31) +#define MICFIL_CTRL1_DOZEN BIT(30) +#define MICFIL_CTRL1_PDMIEN BIT(29) +#define MICFIL_CTRL1_DBG BIT(28) +#define MICFIL_CTRL1_SRES BIT(27) +#define MICFIL_CTRL1_DBGE BIT(26) + +#define MICFIL_CTRL1_DISEL_DISABLE 0 +#define MICFIL_CTRL1_DISEL_DMA 1 +#define MICFIL_CTRL1_DISEL_IRQ 2 +#define MICFIL_CTRL1_DISEL GENMASK(25, 24) +#define MICFIL_CTRL1_ERREN BIT(23) +#define MICFIL_CTRL1_CHEN(ch) BIT(ch) /* MICFIL Control Register 2 -- REG_MICFILL_CTRL2 0x04 */ #define MICFIL_CTRL2_QSEL_SHIFT 25 -#define MICFIL_CTRL2_QSEL_WIDTH 3 -#define MICFIL_CTRL2_QSEL_MASK ((BIT(MICFIL_CTRL2_QSEL_WIDTH) - 1) \ - << MICFIL_CTRL2_QSEL_SHIFT) -#define MICFIL_HIGH_QUALITY BIT(MICFIL_CTRL2_QSEL_SHIFT) -#define MICFIL_MEDIUM_QUALITY (0 << MICFIL_CTRL2_QSEL_SHIFT) -#define MICFIL_LOW_QUALITY (7 << MICFIL_CTRL2_QSEL_SHIFT) -#define MICFIL_VLOW0_QUALITY (6 << MICFIL_CTRL2_QSEL_SHIFT) -#define MICFIL_VLOW1_QUALITY (5 << MICFIL_CTRL2_QSEL_SHIFT) -#define MICFIL_VLOW2_QUALITY (4 << MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_CTRL2_QSEL GENMASK(27, 25) +#define MICFIL_QSEL_MEDIUM_QUALITY 0 +#define MICFIL_QSEL_HIGH_QUALITY 1 +#define MICFIL_QSEL_LOW_QUALITY 7 +#define MICFIL_QSEL_VLOW0_QUALITY 6 +#define MICFIL_QSEL_VLOW1_QUALITY 5 +#define MICFIL_QSEL_VLOW2_QUALITY 4 -#define MICFIL_CTRL2_CICOSR_SHIFT 16 -#define MICFIL_CTRL2_CICOSR_WIDTH 4 -#define MICFIL_CTRL2_CICOSR_MASK ((BIT(MICFIL_CTRL2_CICOSR_WIDTH) - 1) \ - << MICFIL_CTRL2_CICOSR_SHIFT) -#define MICFIL_CTRL2_CICOSR(v) (((v) << MICFIL_CTRL2_CICOSR_SHIFT) \ - & MICFIL_CTRL2_CICOSR_MASK) -#define MICFIL_CTRL2_CLKDIV_SHIFT 0 -#define MICFIL_CTRL2_CLKDIV_WIDTH 8 -#define MICFIL_CTRL2_CLKDIV_MASK ((BIT(MICFIL_CTRL2_CLKDIV_WIDTH) - 1) \ - << MICFIL_CTRL2_CLKDIV_SHIFT) -#define MICFIL_CTRL2_CLKDIV(v) (((v) << MICFIL_CTRL2_CLKDIV_SHIFT) \ - & MICFIL_CTRL2_CLKDIV_MASK) +#define MICFIL_CTRL2_CICOSR GENMASK(19, 16) +#define MICFIL_CTRL2_CLKDIV GENMASK(7, 0) /* MICFIL Status Register -- REG_MICFIL_STAT 0x08 */ -#define MICFIL_STAT_BSY_FIL_SHIFT 31 -#define MICFIL_STAT_BSY_FIL_MASK BIT(MICFIL_STAT_BSY_FIL_SHIFT) -#define MICFIL_STAT_BSY_FIL BIT(MICFIL_STAT_BSY_FIL_SHIFT) -#define MICFIL_STAT_FIR_RDY_SHIFT 30 -#define MICFIL_STAT_FIR_RDY_MASK BIT(MICFIL_STAT_FIR_RDY_SHIFT) -#define MICFIL_STAT_FIR_RDY BIT(MICFIL_STAT_FIR_RDY_SHIFT) -#define MICFIL_STAT_LOWFREQF_SHIFT 29 -#define MICFIL_STAT_LOWFREQF_MASK BIT(MICFIL_STAT_LOWFREQF_SHIFT) -#define MICFIL_STAT_LOWFREQF BIT(MICFIL_STAT_LOWFREQF_SHIFT) -#define MICFIL_STAT_CHXF_SHIFT(v) (v) -#define MICFIL_STAT_CHXF_MASK(v) BIT(MICFIL_STAT_CHXF_SHIFT(v)) -#define MICFIL_STAT_CHXF(v) BIT(MICFIL_STAT_CHXF_SHIFT(v)) +#define MICFIL_STAT_BSY_FIL BIT(31) +#define MICFIL_STAT_FIR_RDY BIT(30) +#define MICFIL_STAT_LOWFREQF BIT(29) +#define MICFIL_STAT_CHXF(ch) BIT(ch) /* MICFIL FIFO Control Register -- REG_MICFIL_FIFO_CTRL 0x10 */ -#define MICFIL_FIFO_CTRL_FIFOWMK_SHIFT 0 -#define MICFIL_FIFO_CTRL_FIFOWMK_WIDTH 3 -#define MICFIL_FIFO_CTRL_FIFOWMK_MASK ((BIT(MICFIL_FIFO_CTRL_FIFOWMK_WIDTH) - 1) \ - << MICFIL_FIFO_CTRL_FIFOWMK_SHIFT) -#define MICFIL_FIFO_CTRL_FIFOWMK(v) (((v) << MICFIL_FIFO_CTRL_FIFOWMK_SHIFT) \ - & MICFIL_FIFO_CTRL_FIFOWMK_MASK) +#define MICFIL_FIFO_CTRL_FIFOWMK GENMASK(2, 0) /* MICFIL FIFO Status Register -- REG_MICFIL_FIFO_STAT 0x14 */ -#define MICFIL_FIFO_STAT_FIFOX_OVER_SHIFT(v) (v) -#define MICFIL_FIFO_STAT_FIFOX_OVER_MASK(v) BIT(MICFIL_FIFO_STAT_FIFOX_OVER_SHIFT(v)) -#define MICFIL_FIFO_STAT_FIFOX_UNDER_SHIFT(v) ((v) + 8) -#define MICFIL_FIFO_STAT_FIFOX_UNDER_MASK(v) BIT(MICFIL_FIFO_STAT_FIFOX_UNDER_SHIFT(v)) +#define MICFIL_FIFO_STAT_FIFOX_OVER(ch) BIT(ch) +#define MICFIL_FIFO_STAT_FIFOX_UNDER(ch) BIT((ch) + 8) + +/* MICFIL DC Remover Control Register -- REG_MICFIL_DC_CTRL */ +#define MICFIL_DC_CTRL_CONFIG GENMASK(15, 0) +#define MICFIL_DC_CHX_SHIFT(ch) ((ch) << 1) +#define MICFIL_DC_CHX(ch) GENMASK((((ch) << 1) + 1), ((ch) << 1)) +#define MICFIL_DC_CUTOFF_21HZ 0 +#define MICFIL_DC_CUTOFF_83HZ 1 +#define MICFIL_DC_CUTOFF_152Hz 2 +#define MICFIL_DC_BYPASS 3 /* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/ -#define MICFIL_VAD0_CTRL1_CHSEL_SHIFT 24 -#define MICFIL_VAD0_CTRL1_CHSEL_WIDTH 3 -#define MICFIL_VAD0_CTRL1_CHSEL_MASK ((BIT(MICFIL_VAD0_CTRL1_CHSEL_WIDTH) - 1) \ - << MICFIL_VAD0_CTRL1_CHSEL_SHIFT) -#define MICFIL_VAD0_CTRL1_CHSEL(v) (((v) << MICFIL_VAD0_CTRL1_CHSEL_SHIFT) \ - & MICFIL_VAD0_CTRL1_CHSEL_MASK) -#define MICFIL_VAD0_CTRL1_CICOSR_SHIFT 16 -#define MICFIL_VAD0_CTRL1_CICOSR_WIDTH 4 -#define MICFIL_VAD0_CTRL1_CICOSR_MASK ((BIT(MICFIL_VAD0_CTRL1_CICOSR_WIDTH) - 1) \ - << MICFIL_VAD0_CTRL1_CICOSR_SHIFT) -#define MICFIL_VAD0_CTRL1_CICOSR(v) (((v) << MICFIL_VAD0_CTRL1_CICOSR_SHIFT) \ - & MICFIL_VAD0_CTRL1_CICOSR_MASK) -#define MICFIL_VAD0_CTRL1_INITT_SHIFT 8 -#define MICFIL_VAD0_CTRL1_INITT_WIDTH 5 -#define MICFIL_VAD0_CTRL1_INITT_MASK ((BIT(MICFIL_VAD0_CTRL1_INITT_WIDTH) - 1) \ - << MICFIL_VAD0_CTRL1_INITT_SHIFT) -#define MICFIL_VAD0_CTRL1_INITT(v) (((v) << MICFIL_VAD0_CTRL1_INITT_SHIFT) \ - & MICFIL_VAD0_CTRL1_INITT_MASK) -#define MICFIL_VAD0_CTRL1_ST10_SHIFT 4 -#define MICFIL_VAD0_CTRL1_ST10_MASK BIT(MICFIL_VAD0_CTRL1_ST10_SHIFT) -#define MICFIL_VAD0_CTRL1_ST10 BIT(MICFIL_VAD0_CTRL1_ST10_SHIFT) -#define MICFIL_VAD0_CTRL1_ERIE_SHIFT 3 -#define MICFIL_VAD0_CTRL1_ERIE_MASK BIT(MICFIL_VAD0_CTRL1_ERIE_SHIFT) -#define MICFIL_VAD0_CTRL1_ERIE BIT(MICFIL_VAD0_CTRL1_ERIE_SHIFT) -#define MICFIL_VAD0_CTRL1_IE_SHIFT 2 -#define MICFIL_VAD0_CTRL1_IE_MASK BIT(MICFIL_VAD0_CTRL1_IE_SHIFT) -#define MICFIL_VAD0_CTRL1_IE BIT(MICFIL_VAD0_CTRL1_IE_SHIFT) -#define MICFIL_VAD0_CTRL1_RST_SHIFT 1 -#define MICFIL_VAD0_CTRL1_RST_MASK BIT(MICFIL_VAD0_CTRL1_RST_SHIFT) -#define MICFIL_VAD0_CTRL1_RST BIT(MICFIL_VAD0_CTRL1_RST_SHIFT) -#define MICFIL_VAD0_CTRL1_EN_SHIFT 0 -#define MICFIL_VAD0_CTRL1_EN_MASK BIT(MICFIL_VAD0_CTRL1_EN_SHIFT) -#define MICFIL_VAD0_CTRL1_EN BIT(MICFIL_VAD0_CTRL1_EN_SHIFT) +#define MICFIL_VAD0_CTRL1_CHSEL GENMASK(26, 24) +#define MICFIL_VAD0_CTRL1_CICOSR GENMASK(19, 16) +#define MICFIL_VAD0_CTRL1_INITT GENMASK(12, 8) +#define MICFIL_VAD0_CTRL1_ST10 BIT(4) +#define MICFIL_VAD0_CTRL1_ERIE BIT(3) +#define MICFIL_VAD0_CTRL1_IE BIT(2) +#define MICFIL_VAD0_CTRL1_RST BIT(1) +#define MICFIL_VAD0_CTRL1_EN BIT(0) /* MICFIL HWVAD0 Control 2 Register -- REG_MICFIL_VAD0_CTRL2*/ -#define MICFIL_VAD0_CTRL2_FRENDIS_SHIFT 31 -#define MICFIL_VAD0_CTRL2_FRENDIS_MASK BIT(MICFIL_VAD0_CTRL2_FRENDIS_SHIFT) -#define MICFIL_VAD0_CTRL2_FRENDIS BIT(MICFIL_VAD0_CTRL2_FRENDIS_SHIFT) -#define MICFIL_VAD0_CTRL2_PREFEN_SHIFT 30 -#define MICFIL_VAD0_CTRL2_PREFEN_MASK BIT(MICFIL_VAD0_CTRL2_PREFEN_SHIFT) -#define MICFIL_VAD0_CTRL2_PREFEN BIT(MICFIL_VAD0_CTRL2_PREFEN_SHIFT) -#define MICFIL_VAD0_CTRL2_FOUTDIS_SHIFT 28 -#define MICFIL_VAD0_CTRL2_FOUTDIS_MASK BIT(MICFIL_VAD0_CTRL2_FOUTDIS_SHIFT) -#define MICFIL_VAD0_CTRL2_FOUTDIS BIT(MICFIL_VAD0_CTRL2_FOUTDIS_SHIFT) -#define MICFIL_VAD0_CTRL2_FRAMET_SHIFT 16 -#define MICFIL_VAD0_CTRL2_FRAMET_WIDTH 6 -#define MICFIL_VAD0_CTRL2_FRAMET_MASK ((BIT(MICFIL_VAD0_CTRL2_FRAMET_WIDTH) - 1) \ - << MICFIL_VAD0_CTRL2_FRAMET_SHIFT) -#define MICFIL_VAD0_CTRL2_FRAMET(v) (((v) << MICFIL_VAD0_CTRL2_FRAMET_SHIFT) \ - & MICFIL_VAD0_CTRL2_FRAMET_MASK) -#define MICFIL_VAD0_CTRL2_INPGAIN_SHIFT 8 -#define MICFIL_VAD0_CTRL2_INPGAIN_WIDTH 4 -#define MICFIL_VAD0_CTRL2_INPGAIN_MASK ((BIT(MICFIL_VAD0_CTRL2_INPGAIN_WIDTH) - 1) \ - << MICFIL_VAD0_CTRL2_INPGAIN_SHIFT) -#define MICFIL_VAD0_CTRL2_INPGAIN(v) (((v) << MICFIL_VAD0_CTRL2_INPGAIN_SHIFT) \ - & MICFIL_VAD0_CTRL2_INPGAIN_MASK) -#define MICFIL_VAD0_CTRL2_HPF_SHIFT 0 -#define MICFIL_VAD0_CTRL2_HPF_WIDTH 2 -#define MICFIL_VAD0_CTRL2_HPF_MASK ((BIT(MICFIL_VAD0_CTRL2_HPF_WIDTH) - 1) \ - << MICFIL_VAD0_CTRL2_HPF_SHIFT) -#define MICFIL_VAD0_CTRL2_HPF(v) (((v) << MICFIL_VAD0_CTRL2_HPF_SHIFT) \ - & MICFIL_VAD0_CTRL2_HPF_MASK) +#define MICFIL_VAD0_CTRL2_FRENDIS BIT(31) +#define MICFIL_VAD0_CTRL2_PREFEN BIT(30) +#define MICFIL_VAD0_CTRL2_FOUTDIS BIT(28) +#define MICFIL_VAD0_CTRL2_FRAMET GENMASK(21, 16) +#define MICFIL_VAD0_CTRL2_INPGAIN GENMASK(11, 8) +#define MICFIL_VAD0_CTRL2_HPF GENMASK(1, 0) /* MICFIL HWVAD0 Signal CONFIG Register -- REG_MICFIL_VAD0_SCONFIG */ -#define MICFIL_VAD0_SCONFIG_SFILEN_SHIFT 31 -#define MICFIL_VAD0_SCONFIG_SFILEN_MASK BIT(MICFIL_VAD0_SCONFIG_SFILEN_SHIFT) -#define MICFIL_VAD0_SCONFIG_SFILEN BIT(MICFIL_VAD0_SCONFIG_SFILEN_SHIFT) -#define MICFIL_VAD0_SCONFIG_SMAXEN_SHIFT 30 -#define MICFIL_VAD0_SCONFIG_SMAXEN_MASK BIT(MICFIL_VAD0_SCONFIG_SMAXEN_SHIFT) -#define MICFIL_VAD0_SCONFIG_SMAXEN BIT(MICFIL_VAD0_SCONFIG_SMAXEN_SHIFT) -#define MICFIL_VAD0_SCONFIG_SGAIN_SHIFT 0 -#define MICFIL_VAD0_SCONFIG_SGAIN_WIDTH 4 -#define MICFIL_VAD0_SCONFIG_SGAIN_MASK ((BIT(MICFIL_VAD0_SCONFIG_SGAIN_WIDTH) - 1) \ - << MICFIL_VAD0_SCONFIG_SGAIN_SHIFT) -#define MICFIL_VAD0_SCONFIG_SGAIN(v) (((v) << MICFIL_VAD0_SCONFIG_SGAIN_SHIFT) \ - & MICFIL_VAD0_SCONFIG_SGAIN_MASK) +#define MICFIL_VAD0_SCONFIG_SFILEN BIT(31) +#define MICFIL_VAD0_SCONFIG_SMAXEN BIT(30) +#define MICFIL_VAD0_SCONFIG_SGAIN GENMASK(3, 0) /* MICFIL HWVAD0 Noise CONFIG Register -- REG_MICFIL_VAD0_NCONFIG */ -#define MICFIL_VAD0_NCONFIG_NFILAUT_SHIFT 31 -#define MICFIL_VAD0_NCONFIG_NFILAUT_MASK BIT(MICFIL_VAD0_NCONFIG_NFILAUT_SHIFT) -#define MICFIL_VAD0_NCONFIG_NFILAUT BIT(MICFIL_VAD0_NCONFIG_NFILAUT_SHIFT) -#define MICFIL_VAD0_NCONFIG_NMINEN_SHIFT 30 -#define MICFIL_VAD0_NCONFIG_NMINEN_MASK BIT(MICFIL_VAD0_NCONFIG_NMINEN_SHIFT) -#define MICFIL_VAD0_NCONFIG_NMINEN BIT(MICFIL_VAD0_NCONFIG_NMINEN_SHIFT) -#define MICFIL_VAD0_NCONFIG_NDECEN_SHIFT 29 -#define MICFIL_VAD0_NCONFIG_NDECEN_MASK BIT(MICFIL_VAD0_NCONFIG_NDECEN_SHIFT) -#define MICFIL_VAD0_NCONFIG_NDECEN BIT(MICFIL_VAD0_NCONFIG_NDECEN_SHIFT) -#define MICFIL_VAD0_NCONFIG_NOREN_SHIFT 28 -#define MICFIL_VAD0_NCONFIG_NOREN BIT(MICFIL_VAD0_NCONFIG_NOREN_SHIFT) -#define MICFIL_VAD0_NCONFIG_NFILADJ_SHIFT 8 -#define MICFIL_VAD0_NCONFIG_NFILADJ_WIDTH 5 -#define MICFIL_VAD0_NCONFIG_NFILADJ_MASK ((BIT(MICFIL_VAD0_NCONFIG_NFILADJ_WIDTH) - 1) \ - << MICFIL_VAD0_NCONFIG_NFILADJ_SHIFT) -#define MICFIL_VAD0_NCONFIG_NFILADJ(v) (((v) << MICFIL_VAD0_NCONFIG_NFILADJ_SHIFT) \ - & MICFIL_VAD0_NCONFIG_NFILADJ_MASK) -#define MICFIL_VAD0_NCONFIG_NGAIN_SHIFT 0 -#define MICFIL_VAD0_NCONFIG_NGAIN_WIDTH 4 -#define MICFIL_VAD0_NCONFIG_NGAIN_MASK ((BIT(MICFIL_VAD0_NCONFIG_NGAIN_WIDTH) - 1) \ - << MICFIL_VAD0_NCONFIG_NGAIN_SHIFT) -#define MICFIL_VAD0_NCONFIG_NGAIN(v) (((v) << MICFIL_VAD0_NCONFIG_NGAIN_SHIFT) \ - & MICFIL_VAD0_NCONFIG_NGAIN_MASK) +#define MICFIL_VAD0_NCONFIG_NFILAUT BIT(31) +#define MICFIL_VAD0_NCONFIG_NMINEN BIT(30) +#define MICFIL_VAD0_NCONFIG_NDECEN BIT(29) +#define MICFIL_VAD0_NCONFIG_NOREN BIT(28) +#define MICFIL_VAD0_NCONFIG_NFILADJ GENMASK(12, 8) +#define MICFIL_VAD0_NCONFIG_NGAIN GENMASK(3, 0) /* MICFIL HWVAD0 Zero-Crossing Detector - REG_MICFIL_VAD0_ZCD */ -#define MICFIL_VAD0_ZCD_ZCDTH_SHIFT 16 -#define MICFIL_VAD0_ZCD_ZCDTH_WIDTH 10 -#define MICFIL_VAD0_ZCD_ZCDTH_MASK ((BIT(MICFIL_VAD0_ZCD_ZCDTH_WIDTH) - 1) \ - << MICFIL_VAD0_ZCD_ZCDTH_SHIFT) -#define MICFIL_VAD0_ZCD_ZCDTH(v) (((v) << MICFIL_VAD0_ZCD_ZCDTH_SHIFT)\ - & MICFIL_VAD0_ZCD_ZCDTH_MASK) -#define MICFIL_VAD0_ZCD_ZCDADJ_SHIFT 8 -#define MICFIL_VAD0_ZCD_ZCDADJ_WIDTH 4 -#define MICFIL_VAD0_ZCD_ZCDADJ_MASK ((BIT(MICFIL_VAD0_ZCD_ZCDADJ_WIDTH) - 1)\ - << MICFIL_VAD0_ZCD_ZCDADJ_SHIFT) -#define MICFIL_VAD0_ZCD_ZCDADJ(v) (((v) << MICFIL_VAD0_ZCD_ZCDADJ_SHIFT)\ - & MICFIL_VAD0_ZCD_ZCDADJ_MASK) -#define MICFIL_VAD0_ZCD_ZCDAND_SHIFT 4 -#define MICFIL_VAD0_ZCD_ZCDAND_MASK BIT(MICFIL_VAD0_ZCD_ZCDAND_SHIFT) -#define MICFIL_VAD0_ZCD_ZCDAND BIT(MICFIL_VAD0_ZCD_ZCDAND_SHIFT) -#define MICFIL_VAD0_ZCD_ZCDAUT_SHIFT 2 -#define MICFIL_VAD0_ZCD_ZCDAUT_MASK BIT(MICFIL_VAD0_ZCD_ZCDAUT_SHIFT) -#define MICFIL_VAD0_ZCD_ZCDAUT BIT(MICFIL_VAD0_ZCD_ZCDAUT_SHIFT) -#define MICFIL_VAD0_ZCD_ZCDEN_SHIFT 0 -#define MICFIL_VAD0_ZCD_ZCDEN_MASK BIT(MICFIL_VAD0_ZCD_ZCDEN_SHIFT) -#define MICFIL_VAD0_ZCD_ZCDEN BIT(MICFIL_VAD0_ZCD_ZCDEN_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDTH GENMASK(25, 16) +#define MICFIL_VAD0_ZCD_ZCDADJ GENMASK(11, 8) +#define MICFIL_VAD0_ZCD_ZCDAND BIT(4) +#define MICFIL_VAD0_ZCD_ZCDAUT BIT(2) +#define MICFIL_VAD0_ZCD_ZCDEN BIT(0) /* MICFIL HWVAD0 Status Register - REG_MICFIL_VAD0_STAT */ -#define MICFIL_VAD0_STAT_INITF_SHIFT 31 -#define MICFIL_VAD0_STAT_INITF_MASK BIT(MICFIL_VAD0_STAT_INITF_SHIFT) -#define MICFIL_VAD0_STAT_INITF BIT(MICFIL_VAD0_STAT_INITF_SHIFT) -#define MICFIL_VAD0_STAT_INSATF_SHIFT 16 -#define MICFIL_VAD0_STAT_INSATF_MASK BIT(MICFIL_VAD0_STAT_INSATF_SHIFT) -#define MICFIL_VAD0_STAT_INSATF BIT(MICFIL_VAD0_STAT_INSATF_SHIFT) -#define MICFIL_VAD0_STAT_EF_SHIFT 15 -#define MICFIL_VAD0_STAT_EF_MASK BIT(MICFIL_VAD0_STAT_EF_SHIFT) -#define MICFIL_VAD0_STAT_EF BIT(MICFIL_VAD0_STAT_EF_SHIFT) -#define MICFIL_VAD0_STAT_IF_SHIFT 0 -#define MICFIL_VAD0_STAT_IF_MASK BIT(MICFIL_VAD0_STAT_IF_SHIFT) -#define MICFIL_VAD0_STAT_IF BIT(MICFIL_VAD0_STAT_IF_SHIFT) +#define MICFIL_VAD0_STAT_INITF BIT(31) +#define MICFIL_VAD0_STAT_INSATF BIT(16) +#define MICFIL_VAD0_STAT_EF BIT(15) +#define MICFIL_VAD0_STAT_IF BIT(0) /* MICFIL Output Control Register */ #define MICFIL_OUTGAIN_CHX_SHIFT(v) (4 * (v)) /* Constants */ -#define MICFIL_DMA_IRQ_DISABLED(v) ((v) & MICFIL_CTRL1_DISEL_MASK) -#define MICFIL_DMA_ENABLED(v) ((0x1 << MICFIL_CTRL1_DISEL_SHIFT) \ - == ((v) & MICFIL_CTRL1_DISEL_MASK)) -#define MICFIL_IRQ_ENABLED(v) ((0x2 << MICFIL_CTRL1_DISEL_SHIFT) \ - == ((v) & MICFIL_CTRL1_DISEL_MASK)) #define MICFIL_OUTPUT_CHANNELS 8 #define MICFIL_FIFO_NUM 8 @@ -278,6 +141,5 @@ #define MICFIL_SLEEP_MIN 90000 /* in us */ #define MICFIL_SLEEP_MAX 100000 /* in us */ #define MICFIL_DMA_MAXBURST_RX 6 -#define MICFIL_CTRL2_OSR_DEFAULT (0 << MICFIL_CTRL2_CICOSR_SHIFT) #endif /* _FSL_MICFIL_H */ diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index ceaecbe3a2..c1e2f67119 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -29,15 +30,41 @@ #define MQS_CLK_DIV_MASK (0xFF << 0) #define MQS_CLK_DIV_SHIFT (0) +/** + * struct fsl_mqs_soc_data - soc specific data + * + * @use_gpr: control register is in General Purpose Register group + * @ctrl_off: control register offset + * @en_mask: enable bit mask + * @en_shift: enable bit shift + * @rst_mask: reset bit mask + * @rst_shift: reset bit shift + * @osr_mask: oversample bit mask + * @osr_shift: oversample bit shift + * @div_mask: clock divider mask + * @div_shift: clock divider bit shift + */ +struct fsl_mqs_soc_data { + bool use_gpr; + int ctrl_off; + int en_mask; + int en_shift; + int rst_mask; + int rst_shift; + int osr_mask; + int osr_shift; + int div_mask; + int div_shift; +}; + /* codec private data */ struct fsl_mqs { struct regmap *regmap; struct clk *mclk; struct clk *ipg; + const struct fsl_mqs_soc_data *soc; - unsigned int reg_iomuxc_gpr2; unsigned int reg_mqs_ctrl; - bool use_gpr; }; #define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) @@ -65,19 +92,11 @@ static int fsl_mqs_hw_params(struct snd_pcm_substream *substream, res = mclk_rate % (32 * lrclk * 2 * 8); if (res == 0 && div > 0 && div <= 256) { - if (mqs_priv->use_gpr) { - regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, - IMX6SX_GPR2_MQS_CLK_DIV_MASK, - (div - 1) << IMX6SX_GPR2_MQS_CLK_DIV_SHIFT); - regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, - IMX6SX_GPR2_MQS_OVERSAMPLE_MASK, 0); - } else { - regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, - MQS_CLK_DIV_MASK, - (div - 1) << MQS_CLK_DIV_SHIFT); - regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, - MQS_OVERSAMPLE_MASK, 0); - } + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, + mqs_priv->soc->div_mask, + (div - 1) << mqs_priv->soc->div_shift); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, + mqs_priv->soc->osr_mask, 0); } else { dev_err(component->dev, "can't get proper divider\n"); } @@ -103,7 +122,7 @@ static int fsl_mqs_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: break; default: return -EINVAL; @@ -118,14 +137,9 @@ static int fsl_mqs_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component); - if (mqs_priv->use_gpr) - regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, - IMX6SX_GPR2_MQS_EN_MASK, - 1 << IMX6SX_GPR2_MQS_EN_SHIFT); - else - regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, - MQS_EN_MASK, - 1 << MQS_EN_SHIFT); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, + mqs_priv->soc->en_mask, + 1 << mqs_priv->soc->en_shift); return 0; } @@ -135,17 +149,12 @@ static void fsl_mqs_shutdown(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component); - if (mqs_priv->use_gpr) - regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, - IMX6SX_GPR2_MQS_EN_MASK, 0); - else - regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, - MQS_EN_MASK, 0); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, + mqs_priv->soc->en_mask, 0); } static const struct snd_soc_component_driver soc_codec_fsl_mqs = { .idle_bias_on = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops fsl_mqs_dai_ops = { @@ -191,12 +200,9 @@ static int fsl_mqs_probe(struct platform_device *pdev) * But in i.MX8QM/i.MX8QXP the control register is moved * to its own domain. */ - if (of_device_is_compatible(np, "fsl,imx8qm-mqs")) - mqs_priv->use_gpr = false; - else - mqs_priv->use_gpr = true; + mqs_priv->soc = of_device_get_match_data(&pdev->dev); - if (mqs_priv->use_gpr) { + if (mqs_priv->soc->use_gpr) { gpr_np = of_parse_phandle(np, "gpr", 0); if (!gpr_np) { dev_err(&pdev->dev, "failed to get gpr node by phandle\n"); @@ -280,12 +286,7 @@ static int fsl_mqs_runtime_resume(struct device *dev) return ret; } - if (mqs_priv->use_gpr) - regmap_write(mqs_priv->regmap, IOMUXC_GPR2, - mqs_priv->reg_iomuxc_gpr2); - else - regmap_write(mqs_priv->regmap, REG_MQS_CTRL, - mqs_priv->reg_mqs_ctrl); + regmap_write(mqs_priv->regmap, mqs_priv->soc->ctrl_off, mqs_priv->reg_mqs_ctrl); return 0; } @@ -293,12 +294,7 @@ static int fsl_mqs_runtime_suspend(struct device *dev) { struct fsl_mqs *mqs_priv = dev_get_drvdata(dev); - if (mqs_priv->use_gpr) - regmap_read(mqs_priv->regmap, IOMUXC_GPR2, - &mqs_priv->reg_iomuxc_gpr2); - else - regmap_read(mqs_priv->regmap, REG_MQS_CTRL, - &mqs_priv->reg_mqs_ctrl); + regmap_read(mqs_priv->regmap, mqs_priv->soc->ctrl_off, &mqs_priv->reg_mqs_ctrl); clk_disable_unprepare(mqs_priv->mclk); clk_disable_unprepare(mqs_priv->ipg); @@ -315,9 +311,49 @@ static const struct dev_pm_ops fsl_mqs_pm_ops = { pm_runtime_force_resume) }; +static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = { + .use_gpr = false, + .ctrl_off = REG_MQS_CTRL, + .en_mask = MQS_EN_MASK, + .en_shift = MQS_EN_SHIFT, + .rst_mask = MQS_SW_RST_MASK, + .rst_shift = MQS_SW_RST_SHIFT, + .osr_mask = MQS_OVERSAMPLE_MASK, + .osr_shift = MQS_OVERSAMPLE_SHIFT, + .div_mask = MQS_CLK_DIV_MASK, + .div_shift = MQS_CLK_DIV_SHIFT, +}; + +static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = { + .use_gpr = true, + .ctrl_off = IOMUXC_GPR2, + .en_mask = IMX6SX_GPR2_MQS_EN_MASK, + .en_shift = IMX6SX_GPR2_MQS_EN_SHIFT, + .rst_mask = IMX6SX_GPR2_MQS_SW_RST_MASK, + .rst_shift = IMX6SX_GPR2_MQS_SW_RST_SHIFT, + .osr_mask = IMX6SX_GPR2_MQS_OVERSAMPLE_MASK, + .osr_shift = IMX6SX_GPR2_MQS_OVERSAMPLE_SHIFT, + .div_mask = IMX6SX_GPR2_MQS_CLK_DIV_MASK, + .div_shift = IMX6SX_GPR2_MQS_CLK_DIV_SHIFT, +}; + +static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = { + .use_gpr = true, + .ctrl_off = 0x20, + .en_mask = BIT(1), + .en_shift = 1, + .rst_mask = BIT(2), + .rst_shift = 2, + .osr_mask = BIT(3), + .osr_shift = 3, + .div_mask = GENMASK(15, 8), + .div_shift = 8, +}; + static const struct of_device_id fsl_mqs_dt_ids[] = { - { .compatible = "fsl,imx8qm-mqs", }, - { .compatible = "fsl,imx6sx-mqs", }, + { .compatible = "fsl,imx8qm-mqs", .data = &fsl_mqs_imx8qm_data }, + { .compatible = "fsl,imx6sx-mqs", .data = &fsl_mqs_imx6sx_data }, + { .compatible = "fsl,imx93-mqs", .data = &fsl_mqs_imx93_data }, {} }; MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids); diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c index 19fd312508..bf94838bdb 100644 --- a/sound/soc/fsl/fsl_rpmsg.c +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -135,7 +135,8 @@ static struct snd_soc_dai_driver fsl_rpmsg_dai = { }; static const struct snd_soc_component_driver fsl_component = { - .name = "fsl-rpmsg", + .name = "fsl-rpmsg", + .legacy_dai_naming = 1, }; static const struct fsl_rpmsg_soc_data imx7ulp_data = { diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index ffc24afb5a..7523bb944b 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,7 @@ #include #include "fsl_sai.h" +#include "fsl_utils.h" #include "imx-pcm.h" #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\ @@ -30,7 +32,8 @@ static const unsigned int fsl_sai_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, - 88200, 96000, 176400, 192000 + 88200, 96000, 176400, 192000, 352800, + 384000, 705600, 768000, 1411200, 2822400, }; static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = { @@ -56,6 +59,31 @@ static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir) return !sai->synchronous[dir] && sai->synchronous[adir]; } +static struct pinctrl_state *fsl_sai_get_pins_state(struct fsl_sai *sai, u32 bclk) +{ + struct pinctrl_state *state = NULL; + + if (sai->is_pdm_mode) { + /* DSD512@44.1kHz, DSD512@48kHz */ + if (bclk >= 22579200) + state = pinctrl_lookup_state(sai->pinctrl, "dsd512"); + + /* Get default DSD state */ + if (IS_ERR_OR_NULL(state)) + state = pinctrl_lookup_state(sai->pinctrl, "dsd"); + } else { + /* 706k32b2c, 768k32b2c, etc */ + if (bclk >= 45158400) + state = pinctrl_lookup_state(sai->pinctrl, "pcm_b2m"); + } + + /* Get default state */ + if (IS_ERR_OR_NULL(state)) + state = pinctrl_lookup_state(sai->pinctrl, "default"); + + return state; +} + static irqreturn_t fsl_sai_isr(int irq, void *devid) { struct fsl_sai *sai = (struct fsl_sai *)devid; @@ -193,14 +221,48 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, return 0; } +static int fsl_sai_set_mclk_rate(struct snd_soc_dai *dai, int clk_id, unsigned int freq) +{ + struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); + int ret; + + fsl_asoc_reparent_pll_clocks(dai->dev, sai->mclk_clk[clk_id], + sai->pll8k_clk, sai->pll11k_clk, freq); + + ret = clk_set_rate(sai->mclk_clk[clk_id], freq); + if (ret < 0) + dev_err(dai->dev, "failed to set clock rate (%u): %d\n", freq, ret); + + return ret; +} + static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { + struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); int ret; if (dir == SND_SOC_CLOCK_IN) return 0; + if (freq > 0 && clk_id != FSL_SAI_CLK_BUS) { + if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) { + dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(sai->mclk_clk[clk_id])) { + dev_err(cpu_dai->dev, "Unassigned clock: %d\n", clk_id); + return -EINVAL; + } + + if (sai->mclk_streams == 0) { + ret = fsl_sai_set_mclk_rate(cpu_dai, clk_id, freq); + if (ret < 0) + return ret; + } + } + ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, true); if (ret) { dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret); @@ -224,6 +286,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, if (!sai->is_lsb_first) val_cr4 |= FSL_SAI_CR4_MF; + sai->is_pdm_mode = false; /* DAI mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -262,6 +325,11 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, val_cr2 |= FSL_SAI_CR2_BCP; sai->is_dsp_mode = true; break; + case SND_SOC_DAIFMT_PDM: + val_cr2 |= FSL_SAI_CR2_BCP; + val_cr4 &= ~FSL_SAI_CR4_MF; + sai->is_pdm_mode = true; + break; case SND_SOC_DAIFMT_RIGHT_J: /* To be done */ default: @@ -292,19 +360,19 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, /* DAI clock provider masks */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; val_cr4 |= FSL_SAI_CR4_FSD_MSTR; sai->is_consumer_mode = false; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: sai->is_consumer_mode = true; break; - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BP_FC: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; sai->is_consumer_mode = false; break; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: val_cr4 |= FSL_SAI_CR4_FSD_MSTR; sai->is_consumer_mode = true; break; @@ -437,6 +505,12 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP, savediv / 2 - 1); + if (sai->soc_data->max_register >= FSL_SAI_MCTL) { + /* SAI is in master mode at this point, so enable MCLK */ + regmap_update_bits(sai->regmap, FSL_SAI_MCTL, + FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN); + } + return 0; } @@ -448,13 +522,18 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, unsigned int ofs = sai->soc_data->reg_offset; bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; unsigned int channels = params_channels(params); + struct snd_dmaengine_dai_dma_data *dma_params; + struct fsl_sai_dl_cfg *dl_cfg = sai->dl_cfg; u32 word_width = params_width(params); + int trce_mask = 0, dl_cfg_idx = 0; + int dl_cfg_cnt = sai->dl_cfg_cnt; + u32 dl_type = FSL_SAI_DL_I2S; u32 val_cr4 = 0, val_cr5 = 0; u32 slots = (channels == 1) ? 2 : channels; u32 slot_width = word_width; int adir = tx ? RX : TX; - u32 pins; - int ret; + u32 pins, bclk; + int ret, i; if (sai->slots) slots = sai->slots; @@ -464,15 +543,42 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, pins = DIV_ROUND_UP(channels, slots); + /* + * PDM mode, channels are independent + * each channels are on one dataline/FIFO. + */ + if (sai->is_pdm_mode) { + pins = channels; + dl_type = FSL_SAI_DL_PDM; + } + + for (i = 0; i < dl_cfg_cnt; i++) { + if (dl_cfg[i].type == dl_type && dl_cfg[i].pins[tx] == pins) { + dl_cfg_idx = i; + break; + } + } + + if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) < pins) { + dev_err(cpu_dai->dev, "channel not supported\n"); + return -EINVAL; + } + + bclk = params_rate(params) * (sai->bclk_ratio ? sai->bclk_ratio : slots * slot_width); + + if (!IS_ERR_OR_NULL(sai->pinctrl)) { + sai->pins_state = fsl_sai_get_pins_state(sai, bclk); + if (!IS_ERR_OR_NULL(sai->pins_state)) { + ret = pinctrl_select_state(sai->pinctrl, sai->pins_state); + if (ret) { + dev_err(cpu_dai->dev, "failed to set proper pins state: %d\n", ret); + return ret; + } + } + } + if (!sai->is_consumer_mode) { - if (sai->bclk_ratio) - ret = fsl_sai_set_bclk(cpu_dai, tx, - sai->bclk_ratio * - params_rate(params)); - else - ret = fsl_sai_set_bclk(cpu_dai, tx, - slots * slot_width * - params_rate(params)); + ret = fsl_sai_set_bclk(cpu_dai, tx, bclk); if (ret) return ret; @@ -486,13 +592,13 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, } } - if (!sai->is_dsp_mode) + if (!sai->is_dsp_mode && !sai->is_pdm_mode) val_cr4 |= FSL_SAI_CR4_SYWD(slot_width); val_cr5 |= FSL_SAI_CR5_WNW(slot_width); val_cr5 |= FSL_SAI_CR5_W0W(slot_width); - if (sai->is_lsb_first) + if (sai->is_lsb_first || sai->is_pdm_mode) val_cr5 |= FSL_SAI_CR5_FBT(0); else val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); @@ -519,13 +625,28 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, FSL_SAI_CR5_FBT_MASK, val_cr5); } - if (sai->soc_data->pins > 1) + if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1) + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), + FSL_SAI_CR4_FCOMB_MASK, 0); + else regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT); + dma_params = tx ? &sai->dma_params_tx : &sai->dma_params_rx; + dma_params->addr = sai->res->start + FSL_SAI_xDR0(tx) + + dl_cfg[dl_cfg_idx].start_off[tx] * 0x4; + + /* Find a proper tcre setting */ + for (i = 0; i < sai->soc_data->pins; i++) { + trce_mask = (1 << (i + 1)) - 1; + if (hweight8(dl_cfg[dl_cfg_idx].mask[tx] & trce_mask) == pins) + break; + } + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), FSL_SAI_CR3_TRCE_MASK, - FSL_SAI_CR3_TRCE((1 << pins) - 1)); + FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask))); + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | FSL_SAI_CR4_CHMOD_MASK, @@ -737,6 +858,23 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static int fsl_sai_dai_resume(struct snd_soc_component *component) +{ + struct fsl_sai *sai = snd_soc_component_get_drvdata(component); + struct device *dev = &sai->pdev->dev; + int ret; + + if (!IS_ERR_OR_NULL(sai->pinctrl) && !IS_ERR_OR_NULL(sai->pins_state)) { + ret = pinctrl_select_state(sai->pinctrl, sai->pins_state); + if (ret) { + dev_err(dev, "failed to set proper pins state: %d\n", ret); + return ret; + } + } + + return 0; +} + static struct snd_soc_dai_driver fsl_sai_dai_template = { .probe = fsl_sai_dai_probe, .playback = { @@ -744,7 +882,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = { .channels_min = 1, .channels_max = 32, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 2822400, .rates = SNDRV_PCM_RATE_KNOT, .formats = FSL_SAI_FORMATS, }, @@ -753,7 +891,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = { .channels_min = 1, .channels_max = 32, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 2822400, .rates = SNDRV_PCM_RATE_KNOT, .formats = FSL_SAI_FORMATS, }, @@ -761,7 +899,9 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = { }; static const struct snd_soc_component_driver fsl_component = { - .name = "fsl-sai", + .name = "fsl-sai", + .resume = fsl_sai_dai_resume, + .legacy_dai_naming = 1, }; static struct reg_default fsl_sai_reg_defaults_ofs0[] = { @@ -998,30 +1138,142 @@ static int fsl_sai_check_version(struct device *dev) return 0; } +/* + * Calculate the offset between first two datalines, don't + * different offset in one case. + */ +static unsigned int fsl_sai_calc_dl_off(unsigned long dl_mask) +{ + int fbidx, nbidx, offset; + + fbidx = find_first_bit(&dl_mask, FSL_SAI_DL_NUM); + nbidx = find_next_bit(&dl_mask, FSL_SAI_DL_NUM, fbidx + 1); + offset = nbidx - fbidx - 1; + + return (offset < 0 || offset >= (FSL_SAI_DL_NUM - 1) ? 0 : offset); +} + +/* + * read the fsl,dataline property from dts file. + * It has 3 value for each configuration, first one means the type: + * I2S(1) or PDM(2), second one is dataline mask for 'rx', third one is + * dataline mask for 'tx'. for example + * + * fsl,dataline = <1 0xff 0xff 2 0xff 0x11>, + * + * It means I2S type rx mask is 0xff, tx mask is 0xff, PDM type + * rx mask is 0xff, tx mask is 0x11 (dataline 1 and 4 enabled). + * + */ +static int fsl_sai_read_dlcfg(struct fsl_sai *sai) +{ + struct platform_device *pdev = sai->pdev; + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + int ret, elems, i, index, num_cfg; + char *propname = "fsl,dataline"; + struct fsl_sai_dl_cfg *cfg; + unsigned long dl_mask; + unsigned int soc_dl; + u32 rx, tx, type; + + elems = of_property_count_u32_elems(np, propname); + + if (elems <= 0) { + elems = 0; + } else if (elems % 3) { + dev_err(dev, "Number of elements must be divisible to 3.\n"); + return -EINVAL; + } + + num_cfg = elems / 3; + /* Add one more for default value */ + cfg = devm_kzalloc(&pdev->dev, (num_cfg + 1) * sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + /* Consider default value "0 0xFF 0xFF" if property is missing */ + soc_dl = BIT(sai->soc_data->pins) - 1; + cfg[0].type = FSL_SAI_DL_DEFAULT; + cfg[0].pins[0] = sai->soc_data->pins; + cfg[0].mask[0] = soc_dl; + cfg[0].start_off[0] = 0; + cfg[0].next_off[0] = 0; + + cfg[0].pins[1] = sai->soc_data->pins; + cfg[0].mask[1] = soc_dl; + cfg[0].start_off[1] = 0; + cfg[0].next_off[1] = 0; + for (i = 1, index = 0; i < num_cfg + 1; i++) { + /* + * type of dataline + * 0 means default mode + * 1 means I2S mode + * 2 means PDM mode + */ + ret = of_property_read_u32_index(np, propname, index++, &type); + if (ret) + return -EINVAL; + + ret = of_property_read_u32_index(np, propname, index++, &rx); + if (ret) + return -EINVAL; + + ret = of_property_read_u32_index(np, propname, index++, &tx); + if (ret) + return -EINVAL; + + if ((rx & ~soc_dl) || (tx & ~soc_dl)) { + dev_err(dev, "dataline cfg[%d] setting error, mask is 0x%x\n", i, soc_dl); + return -EINVAL; + } + + rx = rx & soc_dl; + tx = tx & soc_dl; + + cfg[i].type = type; + cfg[i].pins[0] = hweight8(rx); + cfg[i].mask[0] = rx; + dl_mask = rx; + cfg[i].start_off[0] = find_first_bit(&dl_mask, FSL_SAI_DL_NUM); + cfg[i].next_off[0] = fsl_sai_calc_dl_off(rx); + + cfg[i].pins[1] = hweight8(tx); + cfg[i].mask[1] = tx; + dl_mask = tx; + cfg[i].start_off[1] = find_first_bit(&dl_mask, FSL_SAI_DL_NUM); + cfg[i].next_off[1] = fsl_sai_calc_dl_off(tx); + } + + sai->dl_cfg = cfg; + sai->dl_cfg_cnt = num_cfg + 1; + return 0; +} + static int fsl_sai_runtime_suspend(struct device *dev); static int fsl_sai_runtime_resume(struct device *dev); static int fsl_sai_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; struct fsl_sai *sai; struct regmap *gpr; - struct resource *res; void __iomem *base; char tmp[8]; int irq, ret, i; int index; - sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); + sai = devm_kzalloc(dev, sizeof(*sai), GFP_KERNEL); if (!sai) return -ENOMEM; sai->pdev = pdev; - sai->soc_data = of_device_get_match_data(&pdev->dev); + sai->soc_data = of_device_get_match_data(dev); sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); - base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &sai->res); if (IS_ERR(base)) return PTR_ERR(base); @@ -1032,18 +1284,18 @@ static int fsl_sai_probe(struct platform_device *pdev) ARRAY_SIZE(fsl_sai_reg_defaults_ofs8); } - sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, &fsl_sai_regmap_config); + sai->regmap = devm_regmap_init_mmio(dev, base, &fsl_sai_regmap_config); if (IS_ERR(sai->regmap)) { - dev_err(&pdev->dev, "regmap init failed\n"); + dev_err(dev, "regmap init failed\n"); return PTR_ERR(sai->regmap); } - sai->bus_clk = devm_clk_get(&pdev->dev, "bus"); + sai->bus_clk = devm_clk_get(dev, "bus"); /* Compatible with old DTB cases */ if (IS_ERR(sai->bus_clk) && PTR_ERR(sai->bus_clk) != -EPROBE_DEFER) - sai->bus_clk = devm_clk_get(&pdev->dev, "sai"); + sai->bus_clk = devm_clk_get(dev, "sai"); if (IS_ERR(sai->bus_clk)) { - dev_err(&pdev->dev, "failed to get bus clock: %ld\n", + dev_err(dev, "failed to get bus clock: %ld\n", PTR_ERR(sai->bus_clk)); /* -EPROBE_DEFER */ return PTR_ERR(sai->bus_clk); @@ -1051,9 +1303,9 @@ static int fsl_sai_probe(struct platform_device *pdev) for (i = 1; i < FSL_SAI_MCLK_MAX; i++) { sprintf(tmp, "mclk%d", i); - sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp); + sai->mclk_clk[i] = devm_clk_get(dev, tmp); if (IS_ERR(sai->mclk_clk[i])) { - dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n", + dev_err(dev, "failed to get mclk%d clock: %ld\n", i + 1, PTR_ERR(sai->mclk_clk[i])); sai->mclk_clk[i] = NULL; } @@ -1064,14 +1316,24 @@ static int fsl_sai_probe(struct platform_device *pdev) else sai->mclk_clk[0] = sai->bus_clk; + fsl_asoc_get_pll_clocks(&pdev->dev, &sai->pll8k_clk, + &sai->pll11k_clk); + + /* read dataline mask for rx and tx*/ + ret = fsl_sai_read_dlcfg(sai); + if (ret < 0) { + dev_err(dev, "failed to read dlcfg %d\n", ret); + return ret; + } + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, IRQF_SHARED, + ret = devm_request_irq(dev, irq, fsl_sai_isr, IRQF_SHARED, np->name, sai); if (ret) { - dev_err(&pdev->dev, "failed to claim irq %u\n", irq); + dev_err(dev, "failed to claim irq %u\n", irq); return ret; } @@ -1088,7 +1350,7 @@ static int fsl_sai_probe(struct platform_device *pdev) if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) && of_find_property(np, "fsl,sai-asynchronous", NULL)) { /* error out if both synchronous and asynchronous are present */ - dev_err(&pdev->dev, "invalid binding for synchronous mode\n"); + dev_err(dev, "invalid binding for synchronous mode\n"); return -EINVAL; } @@ -1109,7 +1371,7 @@ static int fsl_sai_probe(struct platform_device *pdev) of_device_is_compatible(np, "fsl,imx6ul-sai")) { gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr"); if (IS_ERR(gpr)) { - dev_err(&pdev->dev, "cannot find iomuxc registers\n"); + dev_err(dev, "cannot find iomuxc registers\n"); return PTR_ERR(gpr); } @@ -1121,38 +1383,38 @@ static int fsl_sai_probe(struct platform_device *pdev) MCLK_DIR(index)); } - sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0; - sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0; + sai->dma_params_rx.addr = sai->res->start + FSL_SAI_RDR0; + sai->dma_params_tx.addr = sai->res->start + FSL_SAI_TDR0; sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; + sai->pinctrl = devm_pinctrl_get(&pdev->dev); + platform_set_drvdata(pdev, sai); - pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - ret = fsl_sai_runtime_resume(&pdev->dev); + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret = fsl_sai_runtime_resume(dev); if (ret) goto err_pm_disable; } - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - pm_runtime_put_noidle(&pdev->dev); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) goto err_pm_get_sync; - } /* Get sai version */ - ret = fsl_sai_check_version(&pdev->dev); + ret = fsl_sai_check_version(dev); if (ret < 0) - dev_warn(&pdev->dev, "Error reading SAI version: %d\n", ret); + dev_warn(dev, "Error reading SAI version: %d\n", ret); /* Select MCLK direction */ if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) && - sai->verid.version >= 0x0301) { + sai->soc_data->max_register >= FSL_SAI_MCTL) { regmap_update_bits(sai->regmap, FSL_SAI_MCTL, FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN); } - ret = pm_runtime_put_sync(&pdev->dev); + ret = pm_runtime_put_sync(dev); if (ret < 0) goto err_pm_get_sync; @@ -1162,15 +1424,18 @@ static int fsl_sai_probe(struct platform_device *pdev) */ if (sai->soc_data->use_imx_pcm) { ret = imx_pcm_dma_init(pdev); - if (ret) + if (ret) { + if (!IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA)) + dev_err(dev, "Error: You must enable the imx-pcm-dma support!\n"); goto err_pm_get_sync; + } } else { - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0); if (ret) goto err_pm_get_sync; } - ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, + ret = devm_snd_soc_register_component(dev, &fsl_component, &sai->cpu_dai_drv, 1); if (ret) goto err_pm_get_sync; @@ -1178,10 +1443,10 @@ static int fsl_sai_probe(struct platform_device *pdev) return ret; err_pm_get_sync: - if (!pm_runtime_status_suspended(&pdev->dev)) - fsl_sai_runtime_suspend(&pdev->dev); + if (!pm_runtime_status_suspended(dev)) + fsl_sai_runtime_suspend(dev); err_pm_disable: - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); return ret; } @@ -1203,6 +1468,7 @@ static const struct fsl_sai_soc_data fsl_sai_vf610_data = { .reg_offset = 0, .mclk0_is_mclk1 = false, .flags = 0, + .max_register = FSL_SAI_RMR, }; static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = { @@ -1213,6 +1479,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = { .reg_offset = 0, .mclk0_is_mclk1 = true, .flags = 0, + .max_register = FSL_SAI_RMR, }; static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = { @@ -1223,6 +1490,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = { .reg_offset = 8, .mclk0_is_mclk1 = false, .flags = PMQOS_CPU_LATENCY, + .max_register = FSL_SAI_RMR, }; static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = { @@ -1233,6 +1501,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = { .reg_offset = 8, .mclk0_is_mclk1 = false, .flags = 0, + .max_register = FSL_SAI_RMR, }; static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = { @@ -1243,6 +1512,40 @@ static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = { .reg_offset = 0, .mclk0_is_mclk1 = false, .flags = 0, + .max_register = FSL_SAI_RMR, +}; + +static const struct fsl_sai_soc_data fsl_sai_imx8mm_data = { + .use_imx_pcm = true, + .use_edma = false, + .fifo_depth = 128, + .reg_offset = 8, + .mclk0_is_mclk1 = false, + .pins = 8, + .flags = 0, + .max_register = FSL_SAI_MCTL, +}; + +static const struct fsl_sai_soc_data fsl_sai_imx8mp_data = { + .use_imx_pcm = true, + .use_edma = false, + .fifo_depth = 128, + .reg_offset = 8, + .mclk0_is_mclk1 = false, + .pins = 8, + .flags = 0, + .max_register = FSL_SAI_MDIV, +}; + +static const struct fsl_sai_soc_data fsl_sai_imx8ulp_data = { + .use_imx_pcm = true, + .use_edma = true, + .fifo_depth = 16, + .reg_offset = 8, + .mclk0_is_mclk1 = false, + .pins = 4, + .flags = PMQOS_CPU_LATENCY, + .max_register = FSL_SAI_RTCAP, }; static const struct of_device_id fsl_sai_ids[] = { @@ -1252,6 +1555,10 @@ static const struct of_device_id fsl_sai_ids[] = { { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp_data }, { .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq_data }, { .compatible = "fsl,imx8qm-sai", .data = &fsl_sai_imx8qm_data }, + { .compatible = "fsl,imx8mm-sai", .data = &fsl_sai_imx8mm_data }, + { .compatible = "fsl,imx8mp-sai", .data = &fsl_sai_imx8mp_data }, + { .compatible = "fsl,imx8ulp-sai", .data = &fsl_sai_imx8ulp_data }, + { .compatible = "fsl,imx8mn-sai", .data = &fsl_sai_imx8mp_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_sai_ids); diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 7310fd02cc..17956b5731 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -11,7 +11,10 @@ #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE |\ - SNDRV_PCM_FMTBIT_S32_LE) + SNDRV_PCM_FMTBIT_S32_LE |\ + SNDRV_PCM_FMTBIT_DSD_U8 |\ + SNDRV_PCM_FMTBIT_DSD_U16_LE |\ + SNDRV_PCM_FMTBIT_DSD_U32_LE) /* SAI Register Map Register */ #define FSL_SAI_VERID 0x00 /* SAI Version ID Register */ @@ -80,8 +83,8 @@ #define FSL_SAI_xCR3(tx, ofs) (tx ? FSL_SAI_TCR3(ofs) : FSL_SAI_RCR3(ofs)) #define FSL_SAI_xCR4(tx, ofs) (tx ? FSL_SAI_TCR4(ofs) : FSL_SAI_RCR4(ofs)) #define FSL_SAI_xCR5(tx, ofs) (tx ? FSL_SAI_TCR5(ofs) : FSL_SAI_RCR5(ofs)) -#define FSL_SAI_xDR(tx, ofs) (tx ? FSL_SAI_TDR(ofs) : FSL_SAI_RDR(ofs)) -#define FSL_SAI_xFR(tx, ofs) (tx ? FSL_SAI_TFR(ofs) : FSL_SAI_RFR(ofs)) +#define FSL_SAI_xDR0(tx) (tx ? FSL_SAI_TDR0 : FSL_SAI_RDR0) +#define FSL_SAI_xFR0(tx) (tx ? FSL_SAI_TFR0 : FSL_SAI_RFR0) #define FSL_SAI_xMR(tx) (tx ? FSL_SAI_TMR : FSL_SAI_RMR) /* SAI Transmit/Receive Control Register */ @@ -215,6 +218,13 @@ #define PMQOS_CPU_LATENCY BIT(0) +/* Max number of dataline */ +#define FSL_SAI_DL_NUM (8) +/* default dataline type is zero */ +#define FSL_SAI_DL_DEFAULT (0) +#define FSL_SAI_DL_I2S BIT(0) +#define FSL_SAI_DL_PDM BIT(1) + struct fsl_sai_soc_data { bool use_imx_pcm; bool use_edma; @@ -223,6 +233,7 @@ struct fsl_sai_soc_data { unsigned int pins; unsigned int reg_offset; unsigned int flags; + unsigned int max_register; }; /** @@ -249,16 +260,30 @@ struct fsl_sai_param { u32 dataline; }; +struct fsl_sai_dl_cfg { + unsigned int type; + unsigned int pins[2]; + unsigned int mask[2]; + unsigned int start_off[2]; + unsigned int next_off[2]; +}; + struct fsl_sai { struct platform_device *pdev; struct regmap *regmap; struct clk *bus_clk; struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; + struct clk *pll8k_clk; + struct clk *pll11k_clk; + struct resource *res; bool is_consumer_mode; bool is_lsb_first; bool is_dsp_mode; + bool is_pdm_mode; bool synchronous[2]; + struct fsl_sai_dl_cfg *dl_cfg; + unsigned int dl_cfg_cnt; unsigned int mclk_id[2]; unsigned int mclk_streams; @@ -273,6 +298,8 @@ struct fsl_sai { struct fsl_sai_verid verid; struct fsl_sai_param param; struct pm_qos_request pm_qos_req; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_state; }; #define TX 1 diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 42d11aca38..7fc1c96929 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -23,6 +23,7 @@ #include #include "fsl_spdif.h" +#include "fsl_utils.h" #include "imx-pcm.h" #define FSL_SPDIF_TXFIFO_WML 0x8 @@ -114,6 +115,8 @@ struct spdif_mixer_control { * @dma_params_rx: DMA parameters for receive channel * @regcache_srpc: regcache for SRPC * @bypass: status of bypass input to output + * @pll8k_clk: PLL clock for the rate of multiply of 8kHz + * @pll11k_clk: PLL clock for the rate of multiply of 11kHz */ struct fsl_spdif_priv { const struct fsl_spdif_soc_data *soc; @@ -137,6 +140,8 @@ struct fsl_spdif_priv { /* regcache for SRPC */ u32 regcache_srpc; bool bypass; + struct clk *pll8k_clk; + struct clk *pll11k_clk; }; static struct fsl_spdif_soc_data fsl_spdif_vf610 = { @@ -480,6 +485,8 @@ static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv, return 0; } +static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, enum spdif_txrate index); + static int spdif_set_sample_rate(struct snd_pcm_substream *substream, int sample_rate) { @@ -528,6 +535,10 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, return -EINVAL; } + ret = fsl_spdif_probe_txclk(spdif_priv, rate); + if (ret) + return ret; + clk = spdif_priv->txclk_src[rate]; if (clk >= STC_TXCLK_SRC_MAX) { dev_err(&pdev->dev, "tx clock source is out of range\n"); @@ -647,6 +658,29 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, } } +static int spdif_reparent_rootclk(struct fsl_spdif_priv *spdif_priv, unsigned int sample_rate) +{ + struct platform_device *pdev = spdif_priv->pdev; + struct clk *clk; + int ret; + + /* Reparent clock if required condition is true */ + if (!fsl_spdif_can_set_clk_rate(spdif_priv, STC_TXCLK_SPDIF_ROOT)) + return 0; + + /* Get root clock */ + clk = spdif_priv->txclk[STC_TXCLK_SPDIF_ROOT]; + + /* Disable clock first, for it was enabled by pm_runtime */ + clk_disable_unprepare(clk); + fsl_asoc_reparent_pll_clocks(&pdev->dev, clk, spdif_priv->pll8k_clk, + spdif_priv->pll11k_clk, sample_rate); + ret = clk_prepare_enable(clk); + if (ret) + return ret; + + return 0; +} static int fsl_spdif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -659,6 +693,13 @@ static int fsl_spdif_hw_params(struct snd_pcm_substream *substream, int ret = 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = spdif_reparent_rootclk(spdif_priv, sample_rate); + if (ret) { + dev_err(&pdev->dev, "%s: reparent root clk failed: %d\n", + __func__, sample_rate); + return ret; + } + ret = spdif_set_sample_rate(substream, sample_rate); if (ret) { dev_err(&pdev->dev, "%s: set sample rate failed: %d\n", @@ -1237,7 +1278,8 @@ static struct snd_soc_dai_driver fsl_spdif_dai = { }; static const struct snd_soc_component_driver fsl_spdif_component = { - .name = "fsl-spdif", + .name = "fsl-spdif", + .legacy_dai_naming = 1, }; /* FSL SPDIF REGMAP */ @@ -1547,11 +1589,8 @@ static int fsl_spdif_probe(struct platform_device *pdev) } spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC; - for (i = 0; i < SPDIF_TXRATE_MAX; i++) { - ret = fsl_spdif_probe_txclk(spdif_priv, i); - if (ret) - return ret; - } + fsl_asoc_get_pll_clocks(&pdev->dev, &spdif_priv->pll8k_clk, + &spdif_priv->pll11k_clk); /* Initial spinlock for control data */ ctrl = &spdif_priv->fsl_spdif_control; diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index ca30a4ede0..c9e0e31d5b 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -92,7 +93,7 @@ */ #define FSLSSI_AC97_DAIFMT \ (SND_SOC_DAIFMT_AC97 | \ - SND_SOC_DAIFMT_CBM_CFS | \ + SND_SOC_DAIFMT_BC_FP | \ SND_SOC_DAIFMT_NB_NF) #define FSLSSI_SIER_DBG_RX_FLAGS \ @@ -214,6 +215,7 @@ struct fsl_ssi_soc_data { * @synchronous: Use synchronous mode - both of TX and RX use STCK and SFCK * @use_dma: DMA is used or FIQ with stream filter * @use_dual_fifo: DMA with support for dual FIFO mode + * @use_dyna_fifo: DMA with support for multi FIFO script * @has_ipg_clk_name: If "ipg" is in the clock name list of device tree * @fifo_depth: Depth of the SSI FIFOs * @slot_width: Width of each DAI slot @@ -243,6 +245,7 @@ struct fsl_ssi_soc_data { * @dma_maxburst: Max number of words to transfer in one go. So far, * this is always the same as fifo_watermark. * @ac97_reg_lock: Mutex lock to serialize AC97 register access operations + * @audio_config: configure for dma multi fifo script */ struct fsl_ssi { struct regmap *regs; @@ -255,6 +258,7 @@ struct fsl_ssi { bool synchronous; bool use_dma; bool use_dual_fifo; + bool use_dyna_fifo; bool has_ipg_clk_name; unsigned int fifo_depth; unsigned int slot_width; @@ -287,6 +291,7 @@ struct fsl_ssi { u32 dma_maxburst; struct mutex ac97_reg_lock; + struct sdma_peripheral_config audio_config[2]; }; /* @@ -353,13 +358,13 @@ static bool fsl_ssi_is_ac97(struct fsl_ssi *ssi) static bool fsl_ssi_is_i2s_clock_provider(struct fsl_ssi *ssi) { return (ssi->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == - SND_SOC_DAIFMT_CBC_CFC; + SND_SOC_DAIFMT_BP_FP; } -static bool fsl_ssi_is_i2s_cbp_cfc(struct fsl_ssi *ssi) +static bool fsl_ssi_is_i2s_bc_fp(struct fsl_ssi *ssi) { return (ssi->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == - SND_SOC_DAIFMT_CBP_CFC; + SND_SOC_DAIFMT_BC_FP; } /** @@ -643,7 +648,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, * task from fifo0, fifo1 would be neglected at the end of each * period. But SSI would still access fifo1 with an invalid data. */ - if (ssi->use_dual_fifo) + if (ssi->use_dual_fifo || ssi->use_dyna_fifo) snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2); @@ -802,6 +807,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, { bool tx2, tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); + struct fsl_ssi_regvals *vals = ssi->regvals; struct regmap *regs = ssi->regs; unsigned int channels = params_channels(hw_params); unsigned int sample_size = params_width(hw_params); @@ -841,7 +847,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, u8 i2s_net = ssi->i2s_net; /* Normal + Network mode to send 16-bit data in 32-bit frames */ - if (fsl_ssi_is_i2s_cbp_cfc(ssi) && sample_size == 16) + if (fsl_ssi_is_i2s_bc_fp(ssi) && sample_size == 16) i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; /* Use Normal mode to send mono data at 1st slot of 2 slots */ @@ -856,6 +862,28 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, tx2 = tx || ssi->synchronous; regmap_update_bits(regs, REG_SSI_SxCCR(tx2), SSI_SxCCR_WL_MASK, wl); + if (ssi->use_dyna_fifo) { + if (channels == 1) { + ssi->audio_config[0].n_fifos_dst = 1; + ssi->audio_config[1].n_fifos_src = 1; + vals[RX].srcr &= ~SSI_SRCR_RFEN1; + vals[TX].stcr &= ~SSI_STCR_TFEN1; + vals[RX].scr &= ~SSI_SCR_TCH_EN; + vals[TX].scr &= ~SSI_SCR_TCH_EN; + } else { + ssi->audio_config[0].n_fifos_dst = 2; + ssi->audio_config[1].n_fifos_src = 2; + vals[RX].srcr |= SSI_SRCR_RFEN1; + vals[TX].stcr |= SSI_STCR_TFEN1; + vals[RX].scr |= SSI_SCR_TCH_EN; + vals[TX].scr |= SSI_SCR_TCH_EN; + } + ssi->dma_params_tx.peripheral_config = &ssi->audio_config[0]; + ssi->dma_params_tx.peripheral_size = sizeof(ssi->audio_config[0]); + ssi->dma_params_rx.peripheral_config = &ssi->audio_config[1]; + ssi->dma_params_rx.peripheral_size = sizeof(ssi->audio_config[1]); + } + return 0; } @@ -892,17 +920,17 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: if (IS_ERR(ssi->baudclk)) { dev_err(ssi->dev, "missing baudclk for master mode\n"); return -EINVAL; } fallthrough; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: ssi->i2s_net |= SSI_SCR_I2S_MODE_SLAVE; break; default: @@ -964,15 +992,15 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt) /* DAI clock provider masks */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: /* Output bit and frame sync clocks */ strcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR; scr |= SSI_SCR_SYS_CLK_EN; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: /* Input bit or frame sync clocks */ break; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: /* Input bit clock but output frame sync clock */ strcr |= SSI_STCR_TFDIR; break; @@ -1154,6 +1182,7 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = { static const struct snd_soc_component_driver fsl_ssi_component = { .name = "fsl-ssi", + .legacy_dai_naming = 1, }; static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { @@ -1353,7 +1382,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, ssi->dma_params_rx.addr = ssi->ssi_phys + REG_SSI_SRX0; /* Use even numbers to avoid channel swap due to SDMA script design */ - if (ssi->use_dual_fifo) { + if (ssi->use_dual_fifo || ssi->use_dyna_fifo) { ssi->dma_params_tx.maxburst &= ~0x1; ssi->dma_params_rx.maxburst &= ~0x1; } @@ -1446,6 +1475,8 @@ static int fsl_ssi_probe_from_dt(struct fsl_ssi *ssi) if (ssi->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) ssi->use_dual_fifo = true; + if (ssi->use_dma && !ret && dmas[2] == IMX_DMATYPE_MULTI_SAI) + ssi->use_dyna_fifo = true; /* * Backward compatible for older bindings by manually triggering the * machine driver's probe(). Use /compatible property, including the diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c index 9bab202569..d0fc430f70 100644 --- a/sound/soc/fsl/fsl_utils.c +++ b/sound/soc/fsl/fsl_utils.c @@ -6,6 +6,8 @@ // // Copyright 2010 Freescale Semiconductor, Inc. +#include +#include #include #include #include @@ -83,6 +85,73 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, } EXPORT_SYMBOL(fsl_asoc_get_dma_channel); +/** + * fsl_asoc_get_pll_clocks - get two PLL clock source + * + * @dev: device pointer + * @pll8k_clk: PLL clock pointer for 8kHz + * @pll11k_clk: PLL clock pointer for 11kHz + * + * This function get two PLL clock source + */ +void fsl_asoc_get_pll_clocks(struct device *dev, struct clk **pll8k_clk, + struct clk **pll11k_clk) +{ + *pll8k_clk = devm_clk_get(dev, "pll8k"); + if (IS_ERR(*pll8k_clk)) + *pll8k_clk = NULL; + + *pll11k_clk = devm_clk_get(dev, "pll11k"); + if (IS_ERR(*pll11k_clk)) + *pll11k_clk = NULL; +} +EXPORT_SYMBOL(fsl_asoc_get_pll_clocks); + +/** + * fsl_asoc_reparent_pll_clocks - set clock parent if necessary + * + * @dev: device pointer + * @clk: root clock pointer + * @pll8k_clk: PLL clock pointer for 8kHz + * @pll11k_clk: PLL clock pointer for 11kHz + * @ratio: target requency for root clock + * + * This function set root clock parent according to the target ratio + */ +void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk, + struct clk *pll8k_clk, + struct clk *pll11k_clk, u64 ratio) +{ + struct clk *p, *pll = NULL, *npll = NULL; + bool reparent = false; + int ret = 0; + + if (!clk || !pll8k_clk || !pll11k_clk) + return; + + p = clk; + while (p && pll8k_clk && pll11k_clk) { + struct clk *pp = clk_get_parent(p); + + if (clk_is_match(pp, pll8k_clk) || + clk_is_match(pp, pll11k_clk)) { + pll = pp; + break; + } + p = pp; + } + + npll = (do_div(ratio, 8000) ? pll11k_clk : pll8k_clk); + reparent = (pll && !clk_is_match(pll, npll)); + + if (reparent) { + ret = clk_set_parent(p, npll); + if (ret < 0) + dev_warn(dev, "failed to set parent:%d\n", ret); + } +} +EXPORT_SYMBOL(fsl_asoc_reparent_pll_clocks); + MODULE_AUTHOR("Timur Tabi "); MODULE_DESCRIPTION("Freescale ASoC utility code"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/fsl_utils.h b/sound/soc/fsl/fsl_utils.h index c5dc2a14b4..4d5f3d93bc 100644 --- a/sound/soc/fsl/fsl_utils.h +++ b/sound/soc/fsl/fsl_utils.h @@ -19,4 +19,11 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, const char *name, struct snd_soc_dai_link *dai, unsigned int *dma_channel_id, unsigned int *dma_id); + +void fsl_asoc_get_pll_clocks(struct device *dev, struct clk **pll8k_clk, + struct clk **pll11k_clk); + +void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk, + struct clk *pll8k_clk, + struct clk *pll11k_clk, u64 ratio); #endif /* _FSL_UTILS_H */ diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index d0556c79fd..c043efe454 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -911,7 +911,8 @@ static struct snd_soc_dai_driver fsl_xcvr_dai = { }; static const struct snd_soc_component_driver fsl_xcvr_comp = { - .name = "fsl-xcvr-dai", + .name = "fsl-xcvr-dai", + .legacy_dai_naming = 1, }; static const struct reg_default fsl_xcvr_reg_defaults[] = { @@ -1228,6 +1229,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev) */ ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0); if (ret) { + pm_runtime_disable(dev); dev_err(dev, "failed to pcm register\n"); return ret; } @@ -1235,6 +1237,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev) ret = devm_snd_soc_register_component(dev, &fsl_xcvr_comp, &fsl_xcvr_dai, 1); if (ret) { + pm_runtime_disable(dev); dev_err(dev, "failed to register component %s\n", fsl_xcvr_comp.name); } @@ -1242,6 +1245,12 @@ static int fsl_xcvr_probe(struct platform_device *pdev) return ret; } +static int fsl_xcvr_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + return 0; +} + static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev) { struct fsl_xcvr *xcvr = dev_get_drvdata(dev); @@ -1370,6 +1379,7 @@ static struct platform_driver fsl_xcvr_driver = { .pm = &fsl_xcvr_pm_ops, .of_match_table = fsl_xcvr_dt_ids, }, + .remove = fsl_xcvr_remove, }; module_platform_driver(fsl_xcvr_driver); diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c index 502fe1b522..1292a845c4 100644 --- a/sound/soc/fsl/imx-audmix.c +++ b/sound/soc/fsl/imx-audmix.c @@ -81,7 +81,7 @@ static int imx_audmix_fe_hw_params(struct snd_pcm_substream *substream, int ret, dir; /* For playback the AUDMIX is consumer, and for record is provider */ - fmt |= tx ? SND_SOC_DAIFMT_CBC_CFC : SND_SOC_DAIFMT_CBP_CFP; + fmt |= tx ? SND_SOC_DAIFMT_BP_FP : SND_SOC_DAIFMT_BC_FC; dir = tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN; /* set DAI configuration */ @@ -122,7 +122,7 @@ static int imx_audmix_be_hw_params(struct snd_pcm_substream *substream, return 0; /* For playback the AUDMIX is consumer */ - fmt |= SND_SOC_DAIFMT_CBP_CFP; + fmt |= SND_SOC_DAIFMT_BC_FC; /* set AUDMIX DAI configuration */ ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt); diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index dfa05d40b2..50b71e5d45 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -62,17 +62,14 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, uintptr_t port = (uintptr_t)file->private_data; u32 pdcr, ptcr; - if (audmux_clk) { - ret = clk_prepare_enable(audmux_clk); - if (ret) - return ret; - } + ret = clk_prepare_enable(audmux_clk); + if (ret) + return ret; ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port)); pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port)); - if (audmux_clk) - clk_disable_unprepare(audmux_clk); + clk_disable_unprepare(audmux_clk); buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) @@ -209,17 +206,14 @@ int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, if (!audmux_base) return -ENOSYS; - if (audmux_clk) { - ret = clk_prepare_enable(audmux_clk); - if (ret) - return ret; - } + ret = clk_prepare_enable(audmux_clk); + if (ret) + return ret; writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port)); writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port)); - if (audmux_clk) - clk_disable_unprepare(audmux_clk); + clk_disable_unprepare(audmux_clk); return 0; } @@ -298,7 +292,7 @@ static int imx_audmux_probe(struct platform_device *pdev) audmux_clk = NULL; } - audmux_type = (enum imx_audmux_type)of_device_get_match_data(&pdev->dev); + audmux_type = (uintptr_t)of_device_get_match_data(&pdev->dev); switch (audmux_type) { case IMX31_AUDMUX: diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index 6f8efd838f..14be29530f 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -17,6 +17,9 @@ #include "fsl_sai.h" +#define IMX_CARD_MCLK_22P5792MHZ 22579200 +#define IMX_CARD_MCLK_24P576MHZ 24576000 + enum codec_type { CODEC_DUMMY = 0, CODEC_AK5558 = 1, @@ -115,7 +118,7 @@ struct imx_card_data { struct snd_soc_card card; int num_dapm_routes; u32 asrc_rate; - u32 asrc_format; + snd_pcm_format_t asrc_format; }; static struct imx_akcodec_fs_mul ak4458_fs_mul[] = { @@ -317,7 +320,7 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, } } - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + ret = snd_soc_dai_set_fmt(cpu_dai, snd_soc_daifmt_clock_provider_flipped(fmt)); if (ret && ret != -ENOTSUPP) { dev_err(dev, "failed to set cpu dai fmt: %d\n", ret); return ret; @@ -353,9 +356,14 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, mclk_freq = akcodec_get_mclk_rate(substream, params, slots, slot_width); else mclk_freq = params_rate(params) * slots * slot_width; - /* Use the maximum freq from DSD512 (512*44100 = 22579200) */ - if (format_is_dsd(params)) - mclk_freq = 22579200; + + if (format_is_dsd(params)) { + /* Use the maximum freq from DSD512 (512*44100 = 22579200) */ + if (!(params_rate(params) % 11025)) + mclk_freq = IMX_CARD_MCLK_22P5792MHZ; + else + mclk_freq = IMX_CARD_MCLK_24P576MHZ; + } ret = snd_soc_dai_set_sysclk(cpu_dai, link_data->cpu_sysclk_id, mclk_freq, SND_SOC_CLOCK_OUT); @@ -466,7 +474,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); snd_mask_none(mask); - snd_mask_set(mask, data->asrc_format); + snd_mask_set(mask, (__force unsigned int)data->asrc_format); return 0; } @@ -485,6 +493,7 @@ static int imx_card_parse_of(struct imx_card_data *data) struct dai_link_data *link_data; struct of_phandle_args args; int ret, num_links; + u32 asrc_fmt = 0; u32 width; ret = snd_soc_of_parse_card_name(card, "model"); @@ -631,7 +640,8 @@ static int imx_card_parse_of(struct imx_card_data *data) goto err; } - ret = of_property_read_u32(args.np, "fsl,asrc-format", &data->asrc_format); + ret = of_property_read_u32(args.np, "fsl,asrc-format", &asrc_fmt); + data->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { /* Fallback to old binding; translate to asrc_format */ ret = of_property_read_u32(args.np, "fsl,asrc-width", &width); diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 168973035e..b80c57362f 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -48,7 +48,7 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) if (gpio_is_valid(data->jack_gpio)) { ret = snd_soc_card_jack_new(rtd->card, "Headphone", SND_JACK_HEADPHONE | SND_JACK_BTN_0, - &headset_jack, NULL, 0); + &headset_jack); if (ret) return ret; diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c index 929f69b758..a780cf5a65 100644 --- a/sound/soc/fsl/imx-hdmi.c +++ b/sound/soc/fsl/imx-hdmi.c @@ -78,8 +78,9 @@ static int imx_hdmi_init(struct snd_soc_pcm_runtime *rtd) data->hdmi_jack_pin.pin = "HDMI Jack"; data->hdmi_jack_pin.mask = SND_JACK_LINEOUT; /* enable jack detection */ - ret = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT, - &data->hdmi_jack, &data->hdmi_jack_pin, 1); + ret = snd_soc_card_jack_new_pins(card, "HDMI Jack", SND_JACK_LINEOUT, + &data->hdmi_jack, + &data->hdmi_jack_pin, 1); if (ret) { dev_err(card->dev, "Can't new HDMI Jack %d\n", ret); return ret; @@ -126,6 +127,7 @@ static int imx_hdmi_probe(struct platform_device *pdev) data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) { ret = -ENOMEM; + put_device(&cpu_pdev->dev); goto fail; } @@ -205,8 +207,7 @@ static int imx_hdmi_probe(struct platform_device *pdev) } fail: - if (cpu_np) - of_node_put(cpu_np); + of_node_put(cpu_np); return ret; } diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h index 5c6cf1ca8c..06b25f4b26 100644 --- a/sound/soc/fsl/imx-pcm.h +++ b/sound/soc/fsl/imx-pcm.h @@ -9,7 +9,7 @@ #ifndef _IMX_PCM_H #define _IMX_PCM_H -#include +#include /* * Do not change this as the FIQ handler depends on this size diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 8daced42d5..580a0d963f 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -120,19 +120,19 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) { ret = -ENOMEM; - goto fail; + goto put_device; } comp = devm_kzalloc(&pdev->dev, 3 * sizeof(*comp), GFP_KERNEL); if (!comp) { ret = -ENOMEM; - goto fail; + goto put_device; } data->codec_clk = clk_get(&codec_dev->dev, NULL); if (IS_ERR(data->codec_clk)) { ret = PTR_ERR(data->codec_clk); - goto fail; + goto put_device; } data->clk_frequency = clk_get_rate(data->codec_clk); @@ -158,10 +158,10 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) data->card.dev = &pdev->dev; ret = snd_soc_of_parse_card_name(&data->card, "model"); if (ret) - goto fail; + goto put_device; ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing"); if (ret) - goto fail; + goto put_device; data->card.num_links = 1; data->card.owner = THIS_MODULE; data->card.dai_link = &data->dai; @@ -174,7 +174,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); - goto fail; + goto put_device; } of_node_put(ssi_np); @@ -182,6 +182,8 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) return 0; +put_device: + put_device(&codec_dev->dev); fail: if (data && !IS_ERR(data->codec_clk)) clk_put(data->codec_clk); diff --git a/sound/soc/fsl/imx-ssi.h b/sound/soc/fsl/imx-ssi.h index 19cd0937e7..2d30d82245 100644 --- a/sound/soc/fsl/imx-ssi.h +++ b/sound/soc/fsl/imx-ssi.h @@ -182,7 +182,7 @@ #define DRV_NAME "imx-ssi" #include -#include +#include #include #include "imx-pcm.h" diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 3149d59ae9..73f3e61f20 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -148,7 +148,8 @@ static struct snd_soc_dai_driver psc_i2s_dai[] = {{ } }; static const struct snd_soc_component_driver psc_i2s_component = { - .name = "mpc5200-i2s", + .name = "mpc5200-i2s", + .legacy_dai_naming = 1, }; /* --------------------------------------------------------------------- diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index 83b4a22bf1..997c3e66c6 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -101,8 +101,7 @@ static int pcm030_fabric_probe(struct platform_device *op) ret = snd_soc_register_card(card); if (ret) { dev_err(&op->dev, "snd_soc_register_card() failed: %d\n", ret); - platform_device_del(pdata->codec_device); - platform_device_put(pdata->codec_device); + platform_device_unregister(pdata->codec_device); } platform_set_drvdata(op, pdata); @@ -113,12 +112,11 @@ static int pcm030_fabric_probe(struct platform_device *op) static int pcm030_fabric_remove(struct platform_device *op) { struct pcm030_audio_data *pdata = platform_get_drvdata(op); - int ret; - ret = snd_soc_unregister_card(pdata->card); + snd_soc_unregister_card(pdata->card); platform_device_unregister(pdata->codec_device); - return ret; + return 0; } static const struct of_device_id pcm030_audio_match[] = { diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 2b598af8fe..b327372f2e 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -158,8 +158,10 @@ static int asoc_simple_parse_dai(struct device_node *ep, * if he unbinded CPU or Codec. */ ret = snd_soc_get_dai_name(&args, &dlc->dai_name); - if (ret < 0) + if (ret < 0) { + of_node_put(node); return ret; + } dlc->of_node = node; diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi index 8eee7b821f..fe547c1877 100644 --- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi +++ b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi @@ -17,6 +17,23 @@ * CONFIG_SND_AUDIO_GRAPH_CARD2 * CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE * CONFIG_SND_TEST_COMPONENT + * + * + * You can indicate more detail each device behavior as debug if you modify + * "compatible" on each test-component. see below + * + * test_cpu { + * - compatible = "test-cpu"; + * + compatible = "test-cpu-verbose"; + * ... + * }; + * + * test_codec { + * - compatible = "test-codec"; + * + compatible = "test-codec-verbose"; + * ... + * }; + * */ / { /* @@ -101,35 +118,74 @@ audio-graph-card2-custom-sample { "TC OUT", "TC DAI11 Playback", "TC DAI9 Capture", "TC IN"; - links = <&cpu0 /* normal: cpu side only */ - &mcpu0 /* multi: cpu side only */ - &fe00 &fe01 &be0 /* dpcm: both FE / BE */ - &fe10 &fe11 &be1 /* dpcm-m: both FE / BE */ - &c2c /* c2c: cpu side only */ - &c2c_m /* c2c: cpu side only */ + links = < + /* + * [Normal]: cpu side only + * cpu0/codec0 + */ + &cpu0 + + /* + * [Multi-CPU/Codec]: cpu side only + * cpu1/cpu2/codec1/codec2 + */ + &mcpu0 + + /* + * [DPCM]: both FE / BE + * cpu3/cpu4/codec3 + */ + &fe00 &fe01 &be0 + + /* + * [DPCM-Multi]: both FE / BE + * cpu5/cpu6/codec4/codec5 + */ + &fe10 &fe11 &be1 + + /* + * [Codec2Codec]: cpu side only + * codec6/codec7 + */ + &c2c + + /* + * [Codec2Codec-Multi]: cpu side only + * codec8/codec9/codec10/codec11 + */ + &c2c_m >; multi { ports@0 { + /* [Multi-CPU] */ mcpu0: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; }; + + /* [Multi-Codec] */ ports@1 { port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; }; + + /* [DPCM-Multi]::BE */ ports@2 { port@0 { mbe_ep: endpoint { remote-endpoint = <&be10_ep>; }; }; port@1 { mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; }; }; port@2 { mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; }; }; }; + + /* [Codec2Codec-Multi]::CPU */ ports@3 { port@0 { mc2c0_ep: endpoint { remote-endpoint = <&c2cmf_ep>; }; }; port@1 { mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; }; }; port@2 { mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; }; }; }; + + /* [Codec2Codec-Multi]::Codec */ ports@4 { port@0 { mc2c1_ep: endpoint { remote-endpoint = <&c2cmb_ep>; }; }; port@1 { mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; }; }; @@ -138,27 +194,36 @@ ports@4 { }; dpcm { - /* FE */ ports@0 { + /* [DPCM]::FE */ fe00: port@0 { fe00_ep: endpoint { remote-endpoint = <&cpu3_ep>; }; }; fe01: port@1 { fe01_ep: endpoint { remote-endpoint = <&cpu4_ep>; }; }; + + /* [DPCM-Multi]::FE */ fe10: port@2 { fe10_ep: endpoint { remote-endpoint = <&cpu5_ep>; }; }; fe11: port@3 { fe11_ep: endpoint { remote-endpoint = <&cpu6_ep>; }; }; }; - /* BE */ + ports@1 { + /* [DPCM]::BE */ be0: port@0 { be00_ep: endpoint { remote-endpoint = <&codec3_ep>; }; }; + + /* [DPCM-Multi]::BE */ be1: port@1 { be10_ep: endpoint { remote-endpoint = <&mbe_ep>; }; }; }; }; codec2codec { + /* [Codec2Codec] */ ports@0 { - rate = <48000>; + /* use default settings */ c2c: port@0 { c2cf_ep: endpoint { remote-endpoint = <&codec6_ep>; }; }; port@1 { c2cb_ep: endpoint { remote-endpoint = <&codec7_ep>; }; }; }; + + /* [Codec2Codec-Multi] */ ports@1 { + /* use original settings */ rate = <48000>; c2c_m: port@0 { c2cmf_ep: endpoint { remote-endpoint = <&mc2c0_ep>; }; }; port@1 { c2cmb_ep: endpoint { remote-endpoint = <&mc2c1_ep>; }; }; @@ -179,11 +244,18 @@ test_cpu { ports { bitclock-master; frame-master; + /* [Normal] */ cpu0: port@0 { cpu0_ep: endpoint { remote-endpoint = <&codec0_ep>; }; }; + + /* [Multi-CPU] */ port@1 { cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; }; port@2 { cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; }; + + /* [DPCM]::FE */ port@3 { cpu3_ep: endpoint { remote-endpoint = <&fe00_ep>; }; }; port@4 { cpu4_ep: endpoint { remote-endpoint = <&fe01_ep>; }; }; + + /* [DPCM-Multi]::FE */ port@5 { cpu5_ep: endpoint { remote-endpoint = <&fe10_ep>; }; }; port@6 { cpu6_ep: endpoint { remote-endpoint = <&fe11_ep>; }; }; }; @@ -206,16 +278,27 @@ ports { */ prefix = "TC"; + /* [Normal] */ port@0 { codec0_ep: endpoint { remote-endpoint = <&cpu0_ep>; }; }; + + /* [Multi-Codec] */ port@1 { codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; }; port@2 { codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; }; + + /* [DPCM]::BE */ port@3 { codec3_ep: endpoint { remote-endpoint = <&be00_ep>; }; }; + + /* [DPCM-Multi]::BE */ port@4 { codec4_ep: endpoint { remote-endpoint = <&mbe1_ep>; }; }; port@5 { codec5_ep: endpoint { remote-endpoint = <&mbe2_ep>; }; }; + + /* [Codec2Codec] */ port@6 { bitclock-master; frame-master; codec6_ep: endpoint { remote-endpoint = <&c2cf_ep>; }; }; port@7 { codec7_ep: endpoint { remote-endpoint = <&c2cb_ep>; }; }; + + /* [Codec2Codec-Multi] */ port@8 { bitclock-master; frame-master; codec8_ep: endpoint { remote-endpoint = <&mc2c00_ep>; }; }; diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index c0f3907a01..8ac6df645e 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -90,12 +90,12 @@ links indicates connection part of CPU side (= A). ports@0 { (X) (A) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; (y) port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; -(y) port@1 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; +(y) port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; }; ports@1 { (X) port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; -(y) port@0 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; -(y) port@1 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; +(y) port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; +(y) port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; }; }; }; @@ -229,7 +229,8 @@ enum graph_type { static enum graph_type __graph_get_type(struct device_node *lnk) { - struct device_node *np; + struct device_node *np, *parent_np; + enum graph_type ret; /* * target { @@ -240,19 +241,33 @@ static enum graph_type __graph_get_type(struct device_node *lnk) * }; */ np = of_get_parent(lnk); - if (of_node_name_eq(np, "ports")) - np = of_get_parent(np); + if (of_node_name_eq(np, "ports")) { + parent_np = of_get_parent(np); + of_node_put(np); + np = parent_np; + } + + if (of_node_name_eq(np, GRAPH_NODENAME_MULTI)) { + ret = GRAPH_MULTI; + goto out_put; + } + + if (of_node_name_eq(np, GRAPH_NODENAME_DPCM)) { + ret = GRAPH_DPCM; + goto out_put; + } - if (of_node_name_eq(np, GRAPH_NODENAME_MULTI)) - return GRAPH_MULTI; + if (of_node_name_eq(np, GRAPH_NODENAME_C2C)) { + ret = GRAPH_C2C; + goto out_put; + } - if (of_node_name_eq(np, GRAPH_NODENAME_DPCM)) - return GRAPH_DPCM; + ret = GRAPH_NORMAL; - if (of_node_name_eq(np, GRAPH_NODENAME_C2C)) - return GRAPH_C2C; +out_put: + of_node_put(np); + return ret; - return GRAPH_NORMAL; } static enum graph_type graph_get_type(struct asoc_simple_priv *priv, @@ -430,8 +445,10 @@ static int asoc_simple_parse_dai(struct device_node *ep, * if he unbinded CPU or Codec. */ ret = snd_soc_get_dai_name(&args, &dlc->dai_name); - if (ret < 0) + if (ret < 0) { + of_node_put(node); return ret; + } dlc->of_node = node; @@ -711,7 +728,7 @@ static void graph_link_init(struct asoc_simple_priv *priv, */ daiclk = snd_soc_daifmt_clock_provider_from_bitmap(bit_frame); if (is_cpu_node) - daiclk = snd_soc_daifmt_clock_provider_fliped(daiclk); + daiclk = snd_soc_daifmt_clock_provider_flipped(daiclk); dai_link->dai_fmt = daifmt | daiclk; dai_link->init = asoc_simple_dai_init; @@ -851,12 +868,10 @@ int audio_graph2_link_c2c(struct asoc_simple_priv *priv, struct link_info *li) { struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); - struct snd_soc_pcm_stream *c2c_conf = dai_props->c2c_conf; struct device_node *port0, *port1, *ports; struct device_node *codec0_port, *codec1_port; struct device_node *ep0, *ep1; - u32 val; + u32 val = 0; int ret = -EINVAL; /* @@ -880,19 +895,33 @@ int audio_graph2_link_c2c(struct asoc_simple_priv *priv, ports = of_get_parent(port0); port1 = of_get_next_child(ports, lnk); - if (!of_get_property(ports, "rate", &val)) { + /* + * Card2 can use original Codec2Codec settings if DT has. + * It will use default settings if no settings on DT. + * see + * asoc_simple_init_for_codec2codec() + * + * Add more settings here if needed + */ + of_property_read_u32(ports, "rate", &val); + if (val) { struct device *dev = simple_priv_to_dev(priv); + struct snd_soc_pcm_stream *c2c_conf; - dev_err(dev, "Codec2Codec needs rate settings\n"); - goto err1; - } + c2c_conf = devm_kzalloc(dev, sizeof(*c2c_conf), GFP_KERNEL); + if (!c2c_conf) + goto err1; + + c2c_conf->formats = SNDRV_PCM_FMTBIT_S32_LE; /* update ME */ + c2c_conf->rates = SNDRV_PCM_RATE_8000_384000; + c2c_conf->rate_min = + c2c_conf->rate_max = val; + c2c_conf->channels_min = + c2c_conf->channels_max = 2; /* update ME */ - c2c_conf->formats = SNDRV_PCM_FMTBIT_S32_LE; /* update ME */ - c2c_conf->rate_min = - c2c_conf->rate_max = val; - c2c_conf->channels_min = - c2c_conf->channels_max = 2; /* update ME */ - dai_link->params = c2c_conf; + dai_link->params = c2c_conf; + dai_link->num_params = 1; + } ep0 = port_to_endpoint(port0); ep1 = port_to_endpoint(port1); @@ -1086,7 +1115,6 @@ static int graph_count_c2c(struct asoc_simple_priv *priv, li->num[li->link].cpus = li->num[li->link].platforms = graph_counter(codec0); li->num[li->link].codecs = graph_counter(codec1); - li->num[li->link].c2c = 1; of_node_put(ports); of_node_put(port1); @@ -1178,8 +1206,6 @@ int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev, struct link_info *li; int ret; - dev_warn(dev, "Audio Graph Card2 is still under Experimental stage\n"); - li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL); if (!li) return -ENOMEM; @@ -1245,6 +1271,9 @@ int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev, if (ret < 0) dev_err_probe(dev, ret, "parse error\n"); + if (ret == 0) + dev_warn(dev, "Audio Graph Card2 is still under Experimental stage\n"); + return ret; } EXPORT_SYMBOL_GPL(audio_graph2_parse_of); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index da0c27828c..4a29e314fa 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -513,7 +513,12 @@ static int asoc_simple_init_dai(struct snd_soc_dai *dai, return 0; } -static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd, +static inline int asoc_simple_component_is_codec(struct snd_soc_component *component) +{ + return component->driver->endianness; +} + +static int asoc_simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd, struct simple_dai_props *dai_props) { struct snd_soc_dai_link *dai_link = rtd->dai_link; @@ -522,9 +527,17 @@ static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hardware hw; int i, ret, stream; + /* Do nothing if it already has Codec2Codec settings */ + if (dai_link->params) + return 0; + + /* Do nothing if it was DPCM :: BE */ + if (dai_link->no_pcm) + return 0; + /* Only Codecs */ for_each_rtd_components(rtd, i, component) { - if (!snd_soc_component_is_codec(component)) + if (!asoc_simple_component_is_codec(component)) return 0; } @@ -575,7 +588,7 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = asoc_simple_init_dai_link_params(rtd, props); + ret = asoc_simple_init_for_codec2codec(rtd, props); if (ret < 0) return ret; @@ -609,7 +622,7 @@ void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus, } EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu); -int asoc_simple_clean_reference(struct snd_soc_card *card) +void asoc_simple_clean_reference(struct snd_soc_card *card) { struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link_component *cpu; @@ -622,7 +635,6 @@ int asoc_simple_clean_reference(struct snd_soc_card *card) for_each_link_codecs(dai_link, j, codec) of_node_put(codec->of_node); } - return 0; } EXPORT_SYMBOL_GPL(asoc_simple_clean_reference); @@ -721,9 +733,8 @@ int asoc_simple_init_jack(struct snd_soc_card *card, sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW); sjack->gpio.debounce_time = 150; - snd_soc_card_jack_new(card, pin_name, mask, - &sjack->jack, - &sjack->pin, 1); + snd_soc_card_jack_new_pins(card, pin_name, mask, &sjack->jack, + &sjack->pin, 1); snd_soc_jack_add_gpios(&sjack->jack, 1, &sjack->gpio); @@ -743,8 +754,7 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, struct asoc_simple_dai *dais; struct snd_soc_dai_link_component *dlcs; struct snd_soc_codec_conf *cconf = NULL; - struct snd_soc_pcm_stream *c2c_conf = NULL; - int i, dai_num = 0, dlc_num = 0, cnf_num = 0, c2c_num = 0; + int i, dai_num = 0, dlc_num = 0, cnf_num = 0; dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL); dai_link = devm_kcalloc(dev, li->link, sizeof(*dai_link), GFP_KERNEL); @@ -763,8 +773,6 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, if (!li->num[i].cpus) cnf_num += li->num[i].codecs; - - c2c_num += li->num[i].c2c; } dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL); @@ -778,12 +786,6 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, return -ENOMEM; } - if (c2c_num) { - c2c_conf = devm_kcalloc(dev, c2c_num, sizeof(*c2c_conf), GFP_KERNEL); - if (!c2c_conf) - return -ENOMEM; - } - dev_dbg(dev, "link %d, dais %d, ccnf %d\n", li->link, dai_num, cnf_num); @@ -797,7 +799,6 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, priv->dais = dais; priv->dlcs = dlcs; priv->codec_conf = cconf; - priv->c2c_conf = c2c_conf; card->dai_link = priv->dai_link; card->num_links = li->link; @@ -815,12 +816,6 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, dlcs += li->num[i].cpus; dais += li->num[i].cpus; - - if (li->num[i].c2c) { - /* Codec2Codec */ - dai_props[i].c2c_conf = c2c_conf; - c2c_conf += li->num[i].c2c; - } } else { /* DPCM Be's CPU = dummy */ dai_props[i].cpus = @@ -878,7 +873,9 @@ int asoc_simple_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - return asoc_simple_clean_reference(card); + asoc_simple_clean_reference(card); + + return 0; } EXPORT_SYMBOL_GPL(asoc_simple_remove); diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c index 5da4725d9e..98c8990596 100644 --- a/sound/soc/generic/test-component.c +++ b/sound/soc/generic/test-component.c @@ -66,7 +66,7 @@ static int test_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; unsigned int clock = fmt & SND_SOC_DAIFMT_CLOCK_MASK; unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK; - unsigned int master = fmt & SND_SOC_DAIFMT_MASTER_MASK; + unsigned int master = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; char *str; dev_info(dai->dev, "name : %s", dai->name); @@ -105,16 +105,16 @@ static int test_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) str = "unknown"; switch (master) { - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BP_FP: str = "clk provider, frame provider"; break; - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BC_FP: str = "clk consumer, frame provider"; break; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BP_FC: str = "clk provider, frame consumer"; break; - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BC_FC: str = "clk consumer, frame consumer"; break; } @@ -192,10 +192,10 @@ static int test_dai_bespoke_trigger(struct snd_pcm_substream *substream, static u64 test_dai_formats = /* * Select below from Sound Card, not auto - * SND_SOC_POSSIBLE_DAIFMT_CBP_CFP - * SND_SOC_POSSIBLE_DAIFMT_CBC_CFP - * SND_SOC_POSSIBLE_DAIFMT_CBP_CFC - * SND_SOC_POSSIBLE_DAIFMT_CBC_CFC + * SND_SOC_POSSIBLE_DAIFMT_BP_FP + * SND_SOC_POSSIBLE_DAIFMT_BC_FP + * SND_SOC_POSSIBLE_DAIFMT_BP_FC + * SND_SOC_POSSIBLE_DAIFMT_BC_FC */ SND_SOC_POSSIBLE_DAIFMT_I2S | SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | @@ -564,11 +564,11 @@ static int test_driver_probe(struct platform_device *pdev) cdriv->pcm_construct = test_component_pcm_construct; cdriv->pointer = test_component_pointer; cdriv->trigger = test_component_trigger; + cdriv->legacy_dai_naming = 1; } else { cdriv->name = "test_codec"; cdriv->idle_bias_on = 1; cdriv->endianness = 1; - cdriv->non_legacy_dai_naming = 1; } cdriv->open = test_component_open; diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c index a297d4af50..27219a9e7d 100644 --- a/sound/soc/hisilicon/hi6210-i2s.c +++ b/sound/soc/hisilicon/hi6210-i2s.c @@ -227,9 +227,9 @@ static int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) * We don't actually set the hardware until the hw_params * call, but we need to validate the user input here. */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_BP_FP: break; default: return -EINVAL; @@ -245,8 +245,8 @@ static int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) } i2s->format = fmt; - i2s->master = (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) == - SND_SOC_DAIFMT_CBS_CFS; + i2s->master = (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == + SND_SOC_DAIFMT_BP_FP; return 0; } @@ -375,21 +375,21 @@ static int hi6210_i2s_hw_params(struct snd_pcm_substream *substream, hi6210_write_reg(i2s, HII2S_MUX_TOP_MODULE_CFG, val); - switch (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: i2s->master = false; val = hi6210_read_reg(i2s, HII2S_I2S_CFG); val |= HII2S_I2S_CFG__S2_MST_SLV; hi6210_write_reg(i2s, HII2S_I2S_CFG, val); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: i2s->master = true; val = hi6210_read_reg(i2s, HII2S_I2S_CFG); val &= ~HII2S_I2S_CFG__S2_MST_SLV; hi6210_write_reg(i2s, HII2S_I2S_CFG, val); break; default: - WARN_ONCE(1, "Invalid i2s->fmt MASTER_MASK. This shouldn't happen\n"); + WARN_ONCE(1, "Invalid i2s->fmt CLOCK_PROVIDER_MASK. This shouldn't happen\n"); return -EINVAL; } @@ -539,6 +539,7 @@ static const struct snd_soc_dai_driver hi6210_i2s_dai_init = { static const struct snd_soc_component_driver hi6210_i2s_i2s_comp = { .name = "hi6210_i2s-i2s", + .legacy_dai_naming = 1, }; static int hi6210_i2s_probe(struct platform_device *pdev) diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c index f1f36f15a5..56bb7bbd39 100644 --- a/sound/soc/img/img-i2s-in.c +++ b/sound/soc/img/img-i2s-in.c @@ -333,8 +333,8 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: break; default: return -EINVAL; @@ -342,11 +342,9 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) chan_control_mask = IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK; - ret = pm_runtime_get_sync(i2s->dev); - if (ret < 0) { - pm_runtime_put_noidle(i2s->dev); + ret = pm_runtime_resume_and_get(i2s->dev); + if (ret < 0) return ret; - } for (i = 0; i < i2s->active_channels; i++) img_i2s_in_ch_disable(i2s, i); @@ -388,7 +386,8 @@ static int img_i2s_in_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_component_driver img_i2s_in_component = { - .name = "img-i2s-in" + .name = "img-i2s-in", + .legacy_dai_naming = 1, }; static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream *st, diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c index 28f48ca150..abeff78293 100644 --- a/sound/soc/img/img-i2s-out.c +++ b/sound/soc/img/img-i2s-out.c @@ -302,10 +302,10 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) if (force_clk_active) control_set |= IMG_I2S_OUT_CTL_CLK_EN_MASK; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: control_set |= IMG_I2S_OUT_CTL_MASTER_MASK; break; default: @@ -346,11 +346,9 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK; - ret = pm_runtime_get_sync(i2s->dev); - if (ret < 0) { - pm_runtime_put_noidle(i2s->dev); + ret = pm_runtime_resume_and_get(i2s->dev); + if (ret < 0) return ret; - } img_i2s_out_disable(i2s); @@ -394,7 +392,8 @@ static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_component_driver img_i2s_out_component = { - .name = "img-i2s-out" + .name = "img-i2s-out", + .legacy_dai_naming = 1, }; static int img_i2s_out_dma_prepare_slave_config(struct snd_pcm_substream *st, @@ -482,11 +481,9 @@ static int img_i2s_out_probe(struct platform_device *pdev) if (ret) goto err_pm_disable; } - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - pm_runtime_put_noidle(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) goto err_suspend; - } reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK; img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c index 800f247283..08506b05e2 100644 --- a/sound/soc/img/img-parallel-out.c +++ b/sound/soc/img/img-parallel-out.c @@ -162,11 +162,9 @@ static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - ret = pm_runtime_get_sync(prl->dev); - if (ret < 0) { - pm_runtime_put_noidle(prl->dev); + ret = pm_runtime_resume_and_get(prl->dev); + if (ret < 0) return ret; - } reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL); reg = (reg & ~IMG_PRL_OUT_CTL_EDGE_MASK) | control_set; @@ -203,7 +201,8 @@ static struct snd_soc_dai_driver img_prl_out_dai = { }; static const struct snd_soc_component_driver img_prl_out_component = { - .name = "img-prl-out" + .name = "img-prl-out", + .legacy_dai_naming = 1, }; static int img_prl_out_probe(struct platform_device *pdev) diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c index 95914d0612..3f1d1a7e87 100644 --- a/sound/soc/img/img-spdif-in.c +++ b/sound/soc/img/img-spdif-in.c @@ -711,7 +711,8 @@ static struct snd_soc_dai_driver img_spdif_in_dai = { }; static const struct snd_soc_component_driver img_spdif_in_component = { - .name = "img-spdif-in" + .name = "img-spdif-in", + .legacy_dai_naming = 1, }; static int img_spdif_in_probe(struct platform_device *pdev) @@ -749,11 +750,9 @@ static int img_spdif_in_probe(struct platform_device *pdev) if (ret) goto err_pm_disable; } - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - pm_runtime_put_noidle(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) goto err_suspend; - } rst = devm_reset_control_get_exclusive(&pdev->dev, "rst"); if (IS_ERR(rst)) { diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c index c3189d9ff7..983761d3fa 100644 --- a/sound/soc/img/img-spdif-out.c +++ b/sound/soc/img/img-spdif-out.c @@ -316,7 +316,8 @@ static struct snd_soc_dai_driver img_spdif_out_dai = { }; static const struct snd_soc_component_driver img_spdif_out_component = { - .name = "img-spdif-out" + .name = "img-spdif-out", + .legacy_dai_naming = 1, }; static int img_spdif_out_probe(struct platform_device *pdev) @@ -362,11 +363,9 @@ static int img_spdif_out_probe(struct platform_device *pdev) if (ret) goto err_pm_disable; } - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - pm_runtime_put_noidle(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) goto err_suspend; - } img_spdif_out_writel(spdif, IMG_SPDIF_OUT_CTL_FS_MASK, IMG_SPDIF_OUT_CTL); diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c index 802c0ee63a..e3b858643b 100644 --- a/sound/soc/img/pistachio-internal-dac.c +++ b/sound/soc/img/pistachio-internal-dac.c @@ -138,7 +138,6 @@ static const struct snd_soc_component_driver pistachio_internal_dac_driver = { .num_dapm_routes = ARRAY_SIZE(pistachio_internal_dac_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int pistachio_internal_dac_probe(struct platform_device *pdev) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index d025ca0c77..ded903f95b 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -211,15 +211,23 @@ config SND_SOC_INTEL_KEEMBAY config SND_SOC_INTEL_AVS tristate "Intel AVS driver" - depends on PCI && ACPI + depends on X86 || COMPILE_TEST + depends on PCI depends on COMMON_CLK - select SND_SOC_ACPI + select SND_SOC_ACPI if ACPI + select SND_SOC_TOPOLOGY + select SND_SOC_HDA select SND_HDA_EXT_CORE select SND_HDA_DSP_LOADER + select SND_INTEL_DSP_CONFIG + select WANT_DEV_COREDUMP help Enable support for Intel(R) cAVS 1.5 platforms with DSP capabilities. This includes Skylake, Kabylake, Amberlake and Apollolake. +# Machine board drivers +source "sound/soc/intel/avs/boards/Kconfig" + # ASoC codec drivers source "sound/soc/intel/boards/Kconfig" diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 335c327329..fd59b35a62 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -831,9 +831,9 @@ static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt) dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format); switch (format) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: return SSP_MODE_PROVIDER; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: return SSP_MODE_CONSUMER; default: dev_err(dai->dev, "Invalid ssp protocol: %d\n", format); @@ -1328,7 +1328,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) { struct sst_data *drv = snd_soc_dai_get_drvdata(dai); struct snd_soc_dapm_widget *w; - struct snd_soc_dapm_path *p = NULL; + struct snd_soc_dapm_path *p; dev_dbg(dai->dev, "enter, dai-name=%s dir=%d\n", dai->name, stream); @@ -1392,7 +1392,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) static int sst_fill_module_list(struct snd_kcontrol *kctl, struct snd_soc_dapm_widget *w, int type) { - struct sst_module *module = NULL; + struct sst_module *module; struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); struct sst_ids *ids = w->priv; int ret = 0; diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index e21e11dac0..160b50f479 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -114,7 +114,7 @@ static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context) static irqreturn_t intel_sst_irq_thread_mrfld(int irq, void *context) { struct intel_sst_drv *drv = (struct intel_sst_drv *) context; - struct ipc_post *__msg, *msg = NULL; + struct ipc_post *__msg, *msg; unsigned long irq_flags; spin_lock_irqsave(&drv->rx_msg_lock, irq_flags); @@ -360,7 +360,6 @@ void sst_context_cleanup(struct intel_sst_drv *ctx) sst_unregister(ctx->dev); sst_set_fw_state_locked(ctx, SST_SHUTDOWN); sysfs_remove_group(&ctx->dev->kobj, &sst_fw_version_attr_group); - flush_scheduled_work(); destroy_workqueue(ctx->post_msg_wq); cpu_latency_qos_remove_request(ctx->qos); kfree(ctx->fw_sg_list.src); diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index 0af618dd80..dc31c2c8f5 100644 --- a/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -136,11 +136,10 @@ static int sst_power_control(struct device *dev, bool state) int usage_count = 0; if (state) { - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); 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; } @@ -193,11 +192,9 @@ static int sst_cdev_open(struct device *dev, struct stream_info *stream; struct intel_sst_drv *ctx = dev_get_drvdata(dev); - retval = pm_runtime_get_sync(ctx->dev); - if (retval < 0) { - pm_runtime_put_sync(ctx->dev); + retval = pm_runtime_resume_and_get(ctx->dev); + if (retval < 0) return retval; - } str_id = sst_get_stream(ctx, str_params); if (str_id > 0) { @@ -645,11 +642,9 @@ 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) { - pm_runtime_put_sync(ctx->dev); + ret_val = pm_runtime_resume_and_get(ctx->dev); + if (ret_val < 0) return ret_val; - } ret_val = sst_send_byte_stream_mrfld(ctx, bytes); sst_pm_runtime_put(ctx); diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 4e8382097e..4e039c7173 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -28,7 +28,7 @@ struct sst_block *sst_create_block(struct intel_sst_drv *ctx, u32 msg_id, u32 drv_id) { - struct sst_block *msg = NULL; + struct sst_block *msg; dev_dbg(ctx->dev, "Enter\n"); msg = kzalloc(sizeof(*msg), GFP_KERNEL); @@ -63,7 +63,7 @@ struct sst_block *sst_create_block(struct intel_sst_drv *ctx, int sst_wake_up_block(struct intel_sst_drv *ctx, int result, u32 drv_id, u32 ipc, void *data, u32 size) { - struct sst_block *block = NULL; + struct sst_block *block; dev_dbg(ctx->dev, "Enter\n"); @@ -91,7 +91,7 @@ int sst_wake_up_block(struct intel_sst_drv *ctx, int result, int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed) { - struct sst_block *block = NULL, *__block; + struct sst_block *block, *__block; dev_dbg(ctx->dev, "Enter\n"); spin_lock_bh(&ctx->block_lock); @@ -341,7 +341,7 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx, } /* FW sent short error response for an IPC */ - if (msg_high.part.result && drv_id && !msg_high.part.large) { + if (msg_high.part.result && !msg_high.part.large) { /* 32-bit FW error code in msg_low */ dev_err(sst_drv_ctx->dev, "FW sent error response 0x%x", msg_low); sst_wake_up_block(sst_drv_ctx, msg_high.part.result, diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile index f842bfc5e9..919212825f 100644 --- a/sound/soc/intel/avs/Makefile +++ b/sound/soc/intel/avs/Makefile @@ -1,6 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o +snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \ + topology.o path.o pcm.o board_selection.o snd-soc-avs-objs += cldma.o +snd-soc-avs-objs += skl.o apl.o + +snd-soc-avs-objs += trace.o +# tell define_trace.h where to find the trace header +CFLAGS_trace.o := -I$(src) obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o + +# Machine support +obj-$(CONFIG_SND_SOC) += boards/ diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h index b48a342fd1..92e37722d2 100644 --- a/sound/soc/intel/avs/avs.h +++ b/sound/soc/intel/avs/avs.h @@ -11,12 +11,18 @@ #include #include +#include #include #include +#include #include "messages.h" #include "registers.h" struct avs_dev; +struct avs_tplg; +struct avs_tplg_library; +struct avs_soc_component; +struct avs_ipc_msg; /* * struct avs_dsp_ops - Platform-specific DSP operations @@ -38,11 +44,21 @@ struct avs_dsp_ops { int (* const load_basefw)(struct avs_dev *, struct firmware *); int (* const load_lib)(struct avs_dev *, struct firmware *, u32); int (* const transfer_mods)(struct avs_dev *, bool, struct avs_module_entry *, u32); + int (* const enable_logs)(struct avs_dev *, enum avs_log_enable, u32, u32, unsigned long, + u32 *); + int (* const log_buffer_offset)(struct avs_dev *, u32); + int (* const log_buffer_status)(struct avs_dev *, union avs_notify_msg *); + int (* const coredump)(struct avs_dev *, union avs_notify_msg *); + bool (* const d0ix_toggle)(struct avs_dev *, struct avs_ipc_msg *, bool); + int (* const set_d0ix)(struct avs_dev *, bool); }; #define avs_dsp_op(adev, op, ...) \ ((adev)->spec->dsp_ops->op(adev, ## __VA_ARGS__)) +extern const struct avs_dsp_ops skl_dsp_ops; +extern const struct avs_dsp_ops apl_dsp_ops; + #define AVS_PLATATTR_CLDMA BIT_ULL(0) #define AVS_PLATATTR_IMR BIT_ULL(1) @@ -70,6 +86,16 @@ struct avs_fw_entry { struct list_head node; }; +struct avs_debug { + struct kfifo trace_fifo; + spinlock_t fifo_lock; /* serialize I/O for trace_fifo */ + spinlock_t trace_lock; /* serialize debug window I/O between each LOG_BUFFER_STATUS */ + wait_queue_head_t trace_waitq; + u32 aging_timer_period; + u32 fifo_full_timer_period; + u32 logged_resources; /* context dependent: core or library */ +}; + /* * struct avs_dev - Intel HD-Audio driver data * @@ -103,6 +129,16 @@ struct avs_dev { char **lib_names; struct completion fw_ready; + struct work_struct probe_work; + + struct nhlt_acpi_table *nhlt; + struct list_head comp_list; + struct mutex comp_list_mutex; + struct list_head path_list; + spinlock_t path_list_lock; + struct mutex path_mutex; + + struct avs_debug dbg; }; /* from hda_bus to avs_dev */ @@ -153,12 +189,18 @@ struct avs_ipc { struct avs_ipc_msg rx; u32 default_timeout_ms; bool ready; + atomic_t recovering; bool rx_completed; spinlock_t rx_lock; struct mutex msg_mutex; struct completion done_completion; struct completion busy_completion; + + struct work_struct recovery_work; + struct delayed_work d0ix_work; + atomic_t d0ix_disable_depth; + bool in_d0ix; }; #define AVS_EIPC EREMOTEIO @@ -195,6 +237,11 @@ int avs_dsp_send_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *reply, int timeout); int avs_dsp_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request, struct avs_ipc_msg *reply); +/* Two variants below are for messages that control DSP power states. */ +int avs_dsp_send_pm_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request, + struct avs_ipc_msg *reply, int timeout, bool wake_d0i0); +int avs_dsp_send_pm_msg(struct avs_dev *adev, struct avs_ipc_msg *request, + struct avs_ipc_msg *reply, bool wake_d0i0); int avs_dsp_send_rom_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request, int timeout); int avs_dsp_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *request); @@ -202,6 +249,11 @@ void avs_dsp_interrupt_control(struct avs_dev *adev, bool enable); int avs_ipc_init(struct avs_ipc *ipc, struct device *dev); void avs_ipc_block(struct avs_ipc *ipc); +int avs_dsp_disable_d0ix(struct avs_dev *adev); +int avs_dsp_enable_d0ix(struct avs_dev *adev); + +int skl_log_buffer_offset(struct avs_dev *adev, u32 core); + /* Firmware resources management */ int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid, struct avs_module_entry *entry); @@ -232,6 +284,7 @@ void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable); void avs_hda_power_gating_enable(struct avs_dev *adev, bool enable); void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable); +int avs_dsp_load_libraries(struct avs_dev *adev, struct avs_tplg_library *libs, u32 num_libs); int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge); int avs_dsp_first_boot_firmware(struct avs_dev *adev); @@ -244,4 +297,53 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id); int avs_hda_transfer_modules(struct avs_dev *adev, bool load, struct avs_module_entry *mods, u32 num_mods); +/* Soc component members */ + +struct avs_soc_component { + struct snd_soc_component base; + struct avs_tplg *tplg; + + struct list_head node; +}; + +#define to_avs_soc_component(comp) \ + container_of(comp, struct avs_soc_component, base) + +extern const struct snd_soc_dai_ops avs_dai_fe_ops; + +int avs_dmic_platform_register(struct avs_dev *adev, const char *name); +int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask, + unsigned long *tdms); +int avs_hda_platform_register(struct avs_dev *adev, const char *name); + +int avs_register_all_boards(struct avs_dev *adev); +void avs_unregister_all_boards(struct avs_dev *adev); + +/* Firmware tracing helpers */ + +unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len, + spinlock_t *lock); + +#define avs_log_buffer_size(adev) \ + ((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores) + +#define avs_log_buffer_addr(adev, core) \ +({ \ + s32 __offset = avs_dsp_op(adev, log_buffer_offset, core); \ + (__offset < 0) ? NULL : \ + (avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \ +}) + +struct apl_log_buffer_layout { + u32 read_ptr; + u32 write_ptr; + u8 buffer[]; +} __packed; + +#define apl_log_payload_size(adev) \ + (avs_log_buffer_size(adev) - sizeof(struct apl_log_buffer_layout)) + +#define apl_log_payload_addr(addr) \ + (addr + sizeof(struct apl_log_buffer_layout)) + #endif /* __SOUND_SOC_INTEL_AVS_H */ diff --git a/sound/soc/intel/avs/cldma.c b/sound/soc/intel/avs/cldma.c index d100c6ba4d..d7a9390b5e 100644 --- a/sound/soc/intel/avs/cldma.c +++ b/sound/soc/intel/avs/cldma.c @@ -176,17 +176,17 @@ int hda_cldma_reset(struct hda_cldma *cl) return ret; } - snd_hdac_stream_updateb(cl, SD_CTL, 1, 1); - ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, (reg & 1), AVS_CL_OP_INTERVAL_US, - AVS_CL_OP_TIMEOUT_US); + snd_hdac_stream_updateb(cl, SD_CTL, SD_CTL_STREAM_RESET, SD_CTL_STREAM_RESET); + ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, (reg & SD_CTL_STREAM_RESET), + AVS_CL_OP_INTERVAL_US, AVS_CL_OP_TIMEOUT_US); if (ret < 0) { dev_err(cl->dev, "cldma set SRST failed: %d\n", ret); return ret; } - snd_hdac_stream_updateb(cl, SD_CTL, 1, 0); - ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, !(reg & 1), AVS_CL_OP_INTERVAL_US, - AVS_CL_OP_TIMEOUT_US); + snd_hdac_stream_updateb(cl, SD_CTL, SD_CTL_STREAM_RESET, 0); + ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, !(reg & SD_CTL_STREAM_RESET), + AVS_CL_OP_INTERVAL_US, AVS_CL_OP_TIMEOUT_US); if (ret < 0) { dev_err(cl->dev, "cldma unset SRST failed: %d\n", ret); return ret; diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index a4d063d12f..c50c20fd68 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -14,9 +14,18 @@ // foundation of this driver // +#include #include +#include +#include +#include #include +#include +#include +#include +#include "../../codecs/hda.h" #include "avs.h" +#include "cldma.h" static void avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask, u32 value) @@ -59,3 +68,624 @@ void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable) value = enable ? AZX_VS_EM2_L1SEN : 0; snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, value); } + +static int avs_hdac_bus_init_streams(struct hdac_bus *bus) +{ + unsigned int cp_streams, pb_streams; + unsigned int gcap; + + gcap = snd_hdac_chip_readw(bus, GCAP); + cp_streams = (gcap >> 8) & 0x0F; + pb_streams = (gcap >> 12) & 0x0F; + bus->num_streams = cp_streams + pb_streams; + + snd_hdac_ext_stream_init_all(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); + snd_hdac_ext_stream_init_all(bus, cp_streams, pb_streams, SNDRV_PCM_STREAM_PLAYBACK); + + return snd_hdac_bus_alloc_stream_pages(bus); +} + +static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset) +{ + struct hdac_ext_link *hlink; + bool ret; + + avs_hdac_clock_gating_enable(bus, false); + ret = snd_hdac_bus_init_chip(bus, full_reset); + + /* Reset stream-to-link mapping */ + list_for_each_entry(hlink, &bus->hlink_list, list) + writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); + + avs_hdac_clock_gating_enable(bus, true); + + /* Set DUM bit to address incorrect position reporting for capture + * streams. In order to do so, CTRL needs to be out of reset state + */ + snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM); + + return ret; +} + +static int probe_codec(struct hdac_bus *bus, int addr) +{ + struct hda_codec *codec; + unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | + (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; + unsigned int res = -1; + int ret; + + 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: 0x%x\n", addr, res); + + codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "hdaudioB%dD%d", bus->idx, addr); + if (IS_ERR(codec)) { + dev_err(bus->dev, "init codec failed: %ld\n", PTR_ERR(codec)); + return PTR_ERR(codec); + } + /* + * Allow avs_core suspend by forcing suspended state on all + * of its codec child devices. Component interested in + * dealing with hda codecs directly takes pm responsibilities + */ + pm_runtime_set_suspended(hda_codec_dev(codec)); + + /* configure effectively creates new ASoC component */ + ret = snd_hda_codec_configure(codec); + if (ret < 0) { + dev_err(bus->dev, "failed to config codec %d\n", ret); + return ret; + } + + return 0; +} + +static void avs_hdac_bus_probe_codecs(struct hdac_bus *bus) +{ + int c; + + /* First try to probe all given codec slots */ + for (c = 0; c < HDA_MAX_CODECS; c++) { + if (!(bus->codec_mask & BIT(c))) + continue; + + if (!probe_codec(bus, c)) + /* success, continue probing */ + continue; + + /* + * 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 &= ~BIT(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); + avs_hdac_bus_init_chip(bus, true); + } +} + +static void avs_hda_probe_work(struct work_struct *work) +{ + struct avs_dev *adev = container_of(work, struct avs_dev, probe_work); + struct hdac_bus *bus = &adev->base.core; + struct hdac_ext_link *hlink; + int ret; + + pm_runtime_set_active(bus->dev); /* clear runtime_error flag */ + + ret = snd_hdac_i915_init(bus); + if (ret < 0) + dev_info(bus->dev, "i915 init unsuccessful: %d\n", ret); + + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); + avs_hdac_bus_init_chip(bus, true); + avs_hdac_bus_probe_codecs(bus); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); + + /* with all codecs probed, links can be powered down */ + list_for_each_entry(hlink, &bus->hlink_list, list) + snd_hdac_ext_bus_link_put(bus, hlink); + + snd_hdac_ext_bus_ppcap_enable(bus, true); + snd_hdac_ext_bus_ppcap_int_enable(bus, true); + + ret = avs_dsp_first_boot_firmware(adev); + if (ret < 0) + return; + + adev->nhlt = intel_nhlt_init(adev->dev); + if (!adev->nhlt) + dev_info(bus->dev, "platform has no NHLT\n"); + + avs_register_all_boards(adev); + + /* configure PM */ + pm_runtime_set_autosuspend_delay(bus->dev, 2000); + pm_runtime_use_autosuspend(bus->dev); + pm_runtime_mark_last_busy(bus->dev); + pm_runtime_put_autosuspend(bus->dev); + pm_runtime_allow(bus->dev); +} + +static void hdac_stream_update_pos(struct hdac_stream *stream, u64 buffer_size) +{ + u64 prev_pos, pos, num_bytes; + + div64_u64_rem(stream->curr_pos, buffer_size, &prev_pos); + pos = snd_hdac_stream_get_pos_posbuf(stream); + + if (pos < prev_pos) + num_bytes = (buffer_size - prev_pos) + pos; + else + num_bytes = pos - prev_pos; + + stream->curr_pos += num_bytes; +} + +/* called from IRQ */ +static void hdac_update_stream(struct hdac_bus *bus, struct hdac_stream *stream) +{ + if (stream->substream) { + snd_pcm_period_elapsed(stream->substream); + } else if (stream->cstream) { + u64 buffer_size = stream->cstream->runtime->buffer_size; + + hdac_stream_update_pos(stream, buffer_size); + snd_compr_fragment_elapsed(stream->cstream); + } +} + +static irqreturn_t hdac_bus_irq_handler(int irq, void *context) +{ + struct hdac_bus *bus = context; + u32 mask, int_enable; + u32 status; + int ret = IRQ_NONE; + + if (!pm_runtime_active(bus->dev)) + return ret; + + spin_lock(&bus->reg_lock); + + status = snd_hdac_chip_readl(bus, INTSTS); + if (status == 0 || status == UINT_MAX) { + spin_unlock(&bus->reg_lock); + return ret; + } + + /* 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); + } + + mask = (0x1 << bus->num_streams) - 1; + + status = snd_hdac_chip_readl(bus, INTSTS); + status &= mask; + if (status) { + /* Disable stream interrupts; Re-enable in bottom half */ + int_enable = snd_hdac_chip_readl(bus, INTCTL); + snd_hdac_chip_writel(bus, INTCTL, (int_enable & (~mask))); + ret = IRQ_WAKE_THREAD; + } else { + ret = IRQ_HANDLED; + } + + spin_unlock(&bus->reg_lock); + return ret; +} + +static irqreturn_t hdac_bus_irq_thread(int irq, void *context) +{ + struct hdac_bus *bus = context; + u32 status; + u32 int_enable; + u32 mask; + unsigned long flags; + + status = snd_hdac_chip_readl(bus, INTSTS); + + snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream); + + /* Re-enable stream interrupts */ + mask = (0x1 << bus->num_streams) - 1; + spin_lock_irqsave(&bus->reg_lock, flags); + int_enable = snd_hdac_chip_readl(bus, INTCTL); + snd_hdac_chip_writel(bus, INTCTL, (int_enable | mask)); + spin_unlock_irqrestore(&bus->reg_lock, flags); + + return IRQ_HANDLED; +} + +static int avs_hdac_acquire_irq(struct avs_dev *adev) +{ + struct hdac_bus *bus = &adev->base.core; + struct pci_dev *pci = to_pci_dev(bus->dev); + int ret; + + /* request one and check that we only got one interrupt */ + ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_LEGACY); + if (ret != 1) { + dev_err(adev->dev, "Failed to allocate IRQ vector: %d\n", ret); + return ret; + } + + ret = pci_request_irq(pci, 0, hdac_bus_irq_handler, hdac_bus_irq_thread, bus, + KBUILD_MODNAME); + if (ret < 0) { + dev_err(adev->dev, "Failed to request stream IRQ handler: %d\n", ret); + goto free_vector; + } + + ret = pci_request_irq(pci, 0, avs_dsp_irq_handler, avs_dsp_irq_thread, adev, + KBUILD_MODNAME); + if (ret < 0) { + dev_err(adev->dev, "Failed to request IPC IRQ handler: %d\n", ret); + goto free_stream_irq; + } + + return 0; + +free_stream_irq: + pci_free_irq(pci, 0, bus); +free_vector: + pci_free_irq_vectors(pci); + return ret; +} + +static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct pci_device_id *id) +{ + struct hda_bus *bus = &adev->base; + struct avs_ipc *ipc; + struct device *dev = &pci->dev; + int ret; + + ret = snd_hdac_ext_bus_init(&bus->core, dev, NULL, &soc_hda_ext_bus_ops); + if (ret < 0) + return ret; + + bus->core.use_posbuf = 1; + bus->core.bdl_pos_adj = 0; + bus->core.sync_write = 1; + bus->pci = pci; + bus->mixer_assigned = -1; + mutex_init(&bus->prepare_mutex); + + ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL); + if (!ipc) + return -ENOMEM; + ret = avs_ipc_init(ipc, dev); + if (ret < 0) + return ret; + + adev->dev = dev; + adev->spec = (const struct avs_spec *)id->driver_data; + adev->ipc = ipc; + adev->hw_cfg.dsp_cores = hweight_long(AVS_MAIN_CORE_MASK); + INIT_WORK(&adev->probe_work, avs_hda_probe_work); + INIT_LIST_HEAD(&adev->comp_list); + INIT_LIST_HEAD(&adev->path_list); + INIT_LIST_HEAD(&adev->fw_list); + init_completion(&adev->fw_ready); + spin_lock_init(&adev->path_list_lock); + mutex_init(&adev->modres_mutex); + mutex_init(&adev->comp_list_mutex); + mutex_init(&adev->path_mutex); + + return 0; +} + +static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) +{ + struct hdac_bus *bus; + struct avs_dev *adev; + struct device *dev = &pci->dev; + int ret; + + ret = snd_intel_dsp_driver_probe(pci); + if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_AVS) + return -ENODEV; + + ret = pcim_enable_device(pci); + if (ret < 0) + return ret; + + adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL); + if (!adev) + return -ENOMEM; + ret = avs_bus_init(adev, pci, id); + if (ret < 0) { + dev_err(dev, "failed to init avs bus: %d\n", ret); + return ret; + } + + ret = pci_request_regions(pci, "AVS HDAudio"); + if (ret < 0) + return ret; + + bus = &adev->base.core; + bus->addr = pci_resource_start(pci, 0); + bus->remap_addr = pci_ioremap_bar(pci, 0); + if (!bus->remap_addr) { + dev_err(bus->dev, "ioremap error\n"); + ret = -ENXIO; + goto err_remap_bar0; + } + + adev->dsp_ba = pci_ioremap_bar(pci, 4); + if (!adev->dsp_ba) { + dev_err(bus->dev, "ioremap error\n"); + ret = -ENXIO; + goto err_remap_bar4; + } + + snd_hdac_bus_parse_capabilities(bus); + if (bus->mlcap) + snd_hdac_ext_bus_get_ml_capabilities(bus); + + if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + dma_set_max_seg_size(dev, UINT_MAX); + + ret = avs_hdac_bus_init_streams(bus); + if (ret < 0) { + dev_err(dev, "failed to init streams: %d\n", ret); + goto err_init_streams; + } + + ret = avs_hdac_acquire_irq(adev); + if (ret < 0) { + dev_err(bus->dev, "failed to acquire irq: %d\n", ret); + goto err_acquire_irq; + } + + pci_set_master(pci); + pci_set_drvdata(pci, bus); + device_disable_async_suspend(dev); + + schedule_work(&adev->probe_work); + + return 0; + +err_acquire_irq: + snd_hdac_bus_free_stream_pages(bus); + snd_hdac_stream_free_all(bus); +err_init_streams: + iounmap(adev->dsp_ba); +err_remap_bar4: + iounmap(bus->remap_addr); +err_remap_bar0: + pci_release_regions(pci); + return ret; +} + +static void avs_pci_remove(struct pci_dev *pci) +{ + struct hdac_device *hdev, *save; + struct hdac_bus *bus = pci_get_drvdata(pci); + struct avs_dev *adev = hdac_to_avs(bus); + + cancel_work_sync(&adev->probe_work); + avs_ipc_block(adev->ipc); + + avs_unregister_all_boards(adev); + + if (adev->nhlt) + intel_nhlt_free(adev->nhlt); + + if (avs_platattr_test(adev, CLDMA)) + hda_cldma_free(&code_loader); + + snd_hdac_stop_streams_and_chip(bus); + avs_dsp_op(adev, int_control, false); + snd_hdac_ext_bus_ppcap_int_enable(bus, false); + + /* it is safe to remove all codecs from the system now */ + list_for_each_entry_safe(hdev, save, &bus->codec_list, list) + snd_hda_codec_unregister(hdac_to_hda_codec(hdev)); + + snd_hdac_bus_free_stream_pages(bus); + snd_hdac_stream_free_all(bus); + /* reverse ml_capabilities */ + snd_hdac_link_free_all(bus); + snd_hdac_ext_bus_exit(bus); + + avs_dsp_core_disable(adev, GENMASK(adev->hw_cfg.dsp_cores - 1, 0)); + snd_hdac_ext_bus_ppcap_enable(bus, false); + + /* snd_hdac_stop_streams_and_chip does that already? */ + snd_hdac_bus_stop_chip(bus); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); + if (bus->audio_component) + snd_hdac_i915_exit(bus); + + avs_module_info_free(adev); + pci_free_irq(pci, 0, adev); + pci_free_irq(pci, 0, bus); + pci_free_irq_vectors(pci); + iounmap(bus->remap_addr); + iounmap(adev->dsp_ba); + pci_release_regions(pci); + + /* Firmware is not needed anymore */ + avs_release_firmwares(adev); + + /* pm_runtime_forbid() can rpm_resume() which we do not want */ + pm_runtime_disable(&pci->dev); + pm_runtime_forbid(&pci->dev); + pm_runtime_enable(&pci->dev); + pm_runtime_get_noresume(&pci->dev); +} + +static int __maybe_unused avs_suspend_common(struct avs_dev *adev) +{ + struct hdac_bus *bus = &adev->base.core; + int ret; + + flush_work(&adev->probe_work); + + snd_hdac_ext_bus_link_power_down_all(bus); + + ret = avs_ipc_set_dx(adev, AVS_MAIN_CORE_MASK, false); + /* + * pm_runtime is blocked on DSP failure but system-wide suspend is not. + * Do not block entire system from suspending if that's the case. + */ + if (ret && ret != -EPERM) { + dev_err(adev->dev, "set dx failed: %d\n", ret); + return AVS_IPC_RET(ret); + } + + avs_ipc_block(adev->ipc); + avs_dsp_op(adev, int_control, false); + snd_hdac_ext_bus_ppcap_int_enable(bus, false); + + ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); + if (ret < 0) { + dev_err(adev->dev, "core_mask %ld disable failed: %d\n", AVS_MAIN_CORE_MASK, ret); + return ret; + } + + snd_hdac_ext_bus_ppcap_enable(bus, false); + /* disable LP SRAM retention */ + avs_hda_power_gating_enable(adev, false); + snd_hdac_bus_stop_chip(bus); + /* disable CG when putting controller to reset */ + avs_hdac_clock_gating_enable(bus, false); + snd_hdac_bus_enter_link_reset(bus); + avs_hdac_clock_gating_enable(bus, true); + + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); + + return 0; +} + +static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge) +{ + struct hdac_bus *bus = &adev->base.core; + struct hdac_ext_link *hlink; + int ret; + + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); + avs_hdac_bus_init_chip(bus, true); + + snd_hdac_ext_bus_ppcap_enable(bus, true); + snd_hdac_ext_bus_ppcap_int_enable(bus, true); + + ret = avs_dsp_boot_firmware(adev, purge); + if (ret < 0) { + dev_err(adev->dev, "firmware boot failed: %d\n", ret); + return ret; + } + + /* turn off the links that were off before suspend */ + list_for_each_entry(hlink, &bus->hlink_list, list) { + if (!hlink->ref_count) + snd_hdac_ext_bus_link_power_down(hlink); + } + + /* check dma status and clean up CORB/RIRB buffers */ + if (!bus->cmd_dma_state) + snd_hdac_bus_stop_cmd_io(bus); + + return 0; +} + +static int __maybe_unused avs_suspend(struct device *dev) +{ + return avs_suspend_common(to_avs_dev(dev)); +} + +static int __maybe_unused avs_resume(struct device *dev) +{ + return avs_resume_common(to_avs_dev(dev), true); +} + +static int __maybe_unused avs_runtime_suspend(struct device *dev) +{ + return avs_suspend_common(to_avs_dev(dev)); +} + +static int __maybe_unused avs_runtime_resume(struct device *dev) +{ + return avs_resume_common(to_avs_dev(dev), true); +} + +static const struct dev_pm_ops avs_dev_pm = { + SET_SYSTEM_SLEEP_PM_OPS(avs_suspend, avs_resume) + SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL) +}; + +static const struct avs_spec skl_desc = { + .name = "skl", + .min_fw_version = { + .major = 9, + .minor = 21, + .hotfix = 0, + .build = 4732, + }, + .dsp_ops = &skl_dsp_ops, + .core_init_mask = 1, + .attributes = AVS_PLATATTR_CLDMA, + .sram_base_offset = SKL_ADSP_SRAM_BASE_OFFSET, + .sram_window_size = SKL_ADSP_SRAM_WINDOW_SIZE, + .rom_status = SKL_ADSP_SRAM_BASE_OFFSET, +}; + +static const struct avs_spec apl_desc = { + .name = "apl", + .min_fw_version = { + .major = 9, + .minor = 22, + .hotfix = 1, + .build = 4323, + }, + .dsp_ops = &apl_dsp_ops, + .core_init_mask = 3, + .attributes = AVS_PLATATTR_IMR, + .sram_base_offset = APL_ADSP_SRAM_BASE_OFFSET, + .sram_window_size = APL_ADSP_SRAM_WINDOW_SIZE, + .rom_status = APL_ADSP_SRAM_BASE_OFFSET, +}; + +static const struct pci_device_id avs_ids[] = { + { PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */ + { PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */ + { PCI_VDEVICE(INTEL, 0x5a98), (unsigned long)&apl_desc }, /* APL */ + { PCI_VDEVICE(INTEL, 0x3198), (unsigned long)&apl_desc }, /* GML */ + { 0 } +}; +MODULE_DEVICE_TABLE(pci, avs_ids); + +static struct pci_driver avs_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = avs_ids, + .probe = avs_pci_probe, + .remove = avs_pci_remove, + .driver = { + .pm = &avs_dev_pm, + }, +}; +module_pci_driver(avs_pci_driver); + +MODULE_AUTHOR("Cezary Rojewski "); +MODULE_AUTHOR("Amadeusz Slawinski "); +MODULE_DESCRIPTION("Intel cAVS sound driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c index 3ff17bd22a..b881100d3e 100644 --- a/sound/soc/intel/avs/dsp.c +++ b/sound/soc/intel/avs/dsp.c @@ -6,23 +6,29 @@ // Amadeusz Slawinski // -#include #include #include "avs.h" #include "registers.h" +#include "trace.h" #define AVS_ADSPCS_INTERVAL_US 500 #define AVS_ADSPCS_TIMEOUT_US 50000 +#define AVS_ADSPCS_DELAY_US 1000 int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power) { u32 value, mask, reg; int ret; + value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS); + trace_avs_dsp_core_op(value, core_mask, "power", power); + mask = AVS_ADSPCS_SPA_MASK(core_mask); value = power ? mask : 0; snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value); + /* Delay the polling to avoid false positives. */ + usleep_range(AVS_ADSPCS_DELAY_US, 2 * AVS_ADSPCS_DELAY_US); mask = AVS_ADSPCS_CPA_MASK(core_mask); value = power ? mask : 0; @@ -43,6 +49,9 @@ int avs_dsp_core_reset(struct avs_dev *adev, u32 core_mask, bool reset) u32 value, mask, reg; int ret; + value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS); + trace_avs_dsp_core_op(value, core_mask, "reset", reset); + mask = AVS_ADSPCS_CRST_MASK(core_mask); value = reset ? mask : 0; @@ -64,6 +73,9 @@ int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall) u32 value, mask, reg; int ret; + value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS); + trace_avs_dsp_core_op(value, core_mask, "stall", stall); + mask = AVS_ADSPCS_CSTALL_MASK(core_mask); value = stall ? mask : 0; @@ -73,11 +85,15 @@ int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall) reg, (reg & mask) == value, AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); - if (ret) + if (ret) { dev_err(adev->dev, "core_mask %d %sstall failed: %d\n", core_mask, stall ? "" : "un", ret); + return ret; + } - return ret; + /* Give HW time to propagate the change. */ + usleep_range(AVS_ADSPCS_DELAY_US, 2 * AVS_ADSPCS_DELAY_US); + return 0; } int avs_dsp_core_enable(struct avs_dev *adev, u32 core_mask) @@ -152,6 +168,15 @@ static int avs_dsp_get_core(struct avs_dev *adev, u32 core_id) adev->core_refs[core_id]++; if (adev->core_refs[core_id] == 1) { + /* + * No cores other than main-core can be running for DSP + * to achieve d0ix. Conscious SET_D0IX IPC failure is permitted, + * simply d0ix power state will no longer be attempted. + */ + ret = avs_dsp_disable_d0ix(adev); + if (ret && ret != -AVS_EIPC) + goto err_disable_d0ix; + ret = avs_dsp_enable(adev, mask); if (ret) goto err_enable_dsp; @@ -160,6 +185,8 @@ static int avs_dsp_get_core(struct avs_dev *adev, u32 core_id) return 0; err_enable_dsp: + avs_dsp_enable_d0ix(adev); +err_disable_d0ix: adev->core_refs[core_id]--; err: dev_err(adev->dev, "get core %d failed: %d\n", core_id, ret); @@ -185,6 +212,9 @@ static int avs_dsp_put_core(struct avs_dev *adev, u32 core_id) ret = avs_dsp_disable(adev, mask); if (ret) goto err; + + /* Match disable_d0ix in avs_dsp_get_core(). */ + avs_dsp_enable_d0ix(adev); } return 0; @@ -298,5 +328,3 @@ int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id) ida_free(&adev->ppl_ida, instance_id); return ret; } - -MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c index 68aaf01edb..020d85c752 100644 --- a/sound/soc/intel/avs/ipc.c +++ b/sound/soc/intel/avs/ipc.c @@ -6,18 +6,185 @@ // Amadeusz Slawinski // +#include #include #include #include "avs.h" #include "messages.h" #include "registers.h" +#include "trace.h" #define AVS_IPC_TIMEOUT_MS 300 +#define AVS_D0IX_DELAY_MS 300 + +static int +avs_dsp_set_d0ix(struct avs_dev *adev, bool enable) +{ + struct avs_ipc *ipc = adev->ipc; + int ret; + + /* Is transition required? */ + if (ipc->in_d0ix == enable) + return 0; + + ret = avs_dsp_op(adev, set_d0ix, enable); + if (ret) { + /* Prevent further d0ix attempts on conscious IPC failure. */ + if (ret == -AVS_EIPC) + atomic_inc(&ipc->d0ix_disable_depth); + + ipc->in_d0ix = false; + return ret; + } + + ipc->in_d0ix = enable; + return 0; +} + +static void avs_dsp_schedule_d0ix(struct avs_dev *adev, struct avs_ipc_msg *tx) +{ + if (atomic_read(&adev->ipc->d0ix_disable_depth)) + return; + + mod_delayed_work(system_power_efficient_wq, &adev->ipc->d0ix_work, + msecs_to_jiffies(AVS_D0IX_DELAY_MS)); +} + +static void avs_dsp_d0ix_work(struct work_struct *work) +{ + struct avs_ipc *ipc = container_of(work, struct avs_ipc, d0ix_work.work); + + avs_dsp_set_d0ix(to_avs_dev(ipc->dev), true); +} + +static int avs_dsp_wake_d0i0(struct avs_dev *adev, struct avs_ipc_msg *tx) +{ + struct avs_ipc *ipc = adev->ipc; + + if (!atomic_read(&ipc->d0ix_disable_depth)) { + cancel_delayed_work_sync(&ipc->d0ix_work); + return avs_dsp_set_d0ix(adev, false); + } + + return 0; +} + +int avs_dsp_disable_d0ix(struct avs_dev *adev) +{ + struct avs_ipc *ipc = adev->ipc; + + /* Prevent PG only on the first disable. */ + if (atomic_add_return(1, &ipc->d0ix_disable_depth) == 1) { + cancel_delayed_work_sync(&ipc->d0ix_work); + return avs_dsp_set_d0ix(adev, false); + } + + return 0; +} + +int avs_dsp_enable_d0ix(struct avs_dev *adev) +{ + struct avs_ipc *ipc = adev->ipc; + + if (atomic_dec_and_test(&ipc->d0ix_disable_depth)) + queue_delayed_work(system_power_efficient_wq, &ipc->d0ix_work, + msecs_to_jiffies(AVS_D0IX_DELAY_MS)); + return 0; +} + +static void avs_dsp_recovery(struct avs_dev *adev) +{ + struct avs_soc_component *acomp; + unsigned int core_mask; + int ret; + + mutex_lock(&adev->comp_list_mutex); + /* disconnect all running streams */ + list_for_each_entry(acomp, &adev->comp_list, node) { + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_card *card; + + card = acomp->base.card; + if (!card) + continue; + + for_each_card_rtds(card, rtd) { + struct snd_pcm *pcm; + int dir; + + pcm = rtd->pcm; + if (!pcm || rtd->dai_link->no_pcm) + continue; + + for_each_pcm_streams(dir) { + struct snd_pcm_substream *substream; + + substream = pcm->streams[dir].substream; + if (!substream || !substream->runtime) + continue; + + snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); + } + } + } + mutex_unlock(&adev->comp_list_mutex); + + /* forcibly shutdown all cores */ + core_mask = GENMASK(adev->hw_cfg.dsp_cores - 1, 0); + avs_dsp_core_disable(adev, core_mask); + + /* attempt dsp reboot */ + ret = avs_dsp_boot_firmware(adev, true); + if (ret < 0) + dev_err(adev->dev, "dsp reboot failed: %d\n", ret); + + pm_runtime_mark_last_busy(adev->dev); + pm_runtime_enable(adev->dev); + pm_request_autosuspend(adev->dev); + + atomic_set(&adev->ipc->recovering, 0); +} + +static void avs_dsp_recovery_work(struct work_struct *work) +{ + struct avs_ipc *ipc = container_of(work, struct avs_ipc, recovery_work); + + avs_dsp_recovery(to_avs_dev(ipc->dev)); +} + +static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg *msg) +{ + struct avs_ipc *ipc = adev->ipc; + + /* Account for the double-exception case. */ + ipc->ready = false; + + if (!atomic_add_unless(&ipc->recovering, 1, 1)) { + dev_err(adev->dev, "dsp recovery is already in progress\n"); + return; + } + + dev_crit(adev->dev, "communication severed, rebooting dsp..\n"); + + cancel_delayed_work_sync(&ipc->d0ix_work); + ipc->in_d0ix = false; + /* Re-enabled on recovery completion. */ + pm_runtime_disable(adev->dev); + + /* Process received notification. */ + avs_dsp_op(adev, coredump, msg); + + schedule_work(&ipc->recovery_work); +} static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header) { struct avs_ipc *ipc = adev->ipc; union avs_reply_msg msg = AVS_MSG(header); + u64 reg; + + reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW)); + trace_avs_ipc_reply_msg(header, reg); ipc->rx.header = header; /* Abort copying payload if request processing was unsuccessful. */ @@ -28,6 +195,7 @@ static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header) ipc->rx.size = msg.ext.large_config.data_off_size; memcpy_fromio(ipc->rx.data, avs_uplink_addr(adev), ipc->rx.size); + trace_avs_msg_payload(ipc->rx.data, ipc->rx.size); } } @@ -37,6 +205,10 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header) union avs_notify_msg msg = AVS_MSG(header); size_t data_size = 0; void *data = NULL; + u64 reg; + + reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW)); + trace_avs_ipc_notify_msg(header, reg); /* Ignore spurious notifications until handshake is established. */ if (!adev->ipc->ready && msg.notify_msg_type != AVS_NOTIFY_FW_READY) { @@ -57,6 +229,10 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header) data_size = sizeof(struct avs_notify_res_data); break; + case AVS_NOTIFY_LOG_BUFFER_STATUS: + case AVS_NOTIFY_EXCEPTION_CAUGHT: + break; + case AVS_NOTIFY_MODULE_EVENT: /* To know the total payload size, header needs to be read first. */ memcpy_fromio(&mod_data, avs_uplink_addr(adev), sizeof(mod_data)); @@ -74,6 +250,7 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header) return; memcpy_fromio(data, avs_uplink_addr(adev), data_size); + trace_avs_msg_payload(data, data_size); } /* Perform notification-specific operations. */ @@ -84,6 +261,14 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header) complete(&adev->fw_ready); break; + case AVS_NOTIFY_LOG_BUFFER_STATUS: + avs_dsp_op(adev, log_buffer_status, &msg); + break; + + case AVS_NOTIFY_EXCEPTION_CAUGHT: + avs_dsp_exception_caught(adev, &msg); + break; + default: break; } @@ -249,9 +434,15 @@ static void avs_ipc_msg_init(struct avs_ipc *ipc, struct avs_ipc_msg *reply) reinit_completion(&ipc->busy_completion); } -static void avs_dsp_send_tx(struct avs_dev *adev, struct avs_ipc_msg *tx) +static void avs_dsp_send_tx(struct avs_dev *adev, struct avs_ipc_msg *tx, bool read_fwregs) { + u64 reg = ULONG_MAX; + tx->header |= SKL_ADSP_HIPCI_BUSY; + if (read_fwregs) + reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW)); + + trace_avs_request(tx, reg); if (tx->size) memcpy_toio(avs_downlink_addr(adev), tx->data, tx->size); @@ -272,15 +463,16 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request spin_lock(&ipc->rx_lock); avs_ipc_msg_init(ipc, reply); - avs_dsp_send_tx(adev, request); + avs_dsp_send_tx(adev, request, true); spin_unlock(&ipc->rx_lock); ret = avs_ipc_wait_busy_completion(ipc, timeout); if (ret) { if (ret == -ETIMEDOUT) { - dev_crit(adev->dev, "communication severed: %d, rebooting dsp..\n", ret); + union avs_notify_msg msg = AVS_NOTIFICATION(EXCEPTION_CAUGHT); - avs_ipc_block(ipc); + /* Same treatment as on exception, just stack_dump=0. */ + avs_dsp_exception_caught(adev, &msg); } goto exit; } @@ -288,6 +480,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request ret = ipc->rx.rsp.status; if (reply) { reply->header = ipc->rx.header; + reply->size = ipc->rx.size; if (reply->data && ipc->rx.size) memcpy(reply->data, ipc->rx.data, reply->size); } @@ -297,10 +490,37 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request return ret; } +static int avs_dsp_send_msg_sequence(struct avs_dev *adev, struct avs_ipc_msg *request, + struct avs_ipc_msg *reply, int timeout, bool wake_d0i0, + bool schedule_d0ix) +{ + int ret; + + trace_avs_d0ix("wake", wake_d0i0, request->header); + if (wake_d0i0) { + ret = avs_dsp_wake_d0i0(adev, request); + if (ret) + return ret; + } + + ret = avs_dsp_do_send_msg(adev, request, reply, timeout); + if (ret) + return ret; + + trace_avs_d0ix("schedule", schedule_d0ix, request->header); + if (schedule_d0ix) + avs_dsp_schedule_d0ix(adev, request); + + return 0; +} + int avs_dsp_send_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request, struct avs_ipc_msg *reply, int timeout) { - return avs_dsp_do_send_msg(adev, request, reply, timeout); + bool wake_d0i0 = avs_dsp_op(adev, d0ix_toggle, request, true); + bool schedule_d0ix = avs_dsp_op(adev, d0ix_toggle, request, false); + + return avs_dsp_send_msg_sequence(adev, request, reply, timeout, wake_d0i0, schedule_d0ix); } int avs_dsp_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request, @@ -309,6 +529,19 @@ int avs_dsp_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request, return avs_dsp_send_msg_timeout(adev, request, reply, adev->ipc->default_timeout_ms); } +int avs_dsp_send_pm_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request, + struct avs_ipc_msg *reply, int timeout, bool wake_d0i0) +{ + return avs_dsp_send_msg_sequence(adev, request, reply, timeout, wake_d0i0, false); +} + +int avs_dsp_send_pm_msg(struct avs_dev *adev, struct avs_ipc_msg *request, + struct avs_ipc_msg *reply, bool wake_d0i0) +{ + return avs_dsp_send_pm_msg_timeout(adev, request, reply, adev->ipc->default_timeout_ms, + wake_d0i0); +} + static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *request, int timeout) { struct avs_ipc *ipc = adev->ipc; @@ -318,7 +551,11 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req spin_lock(&ipc->rx_lock); avs_ipc_msg_init(ipc, NULL); - avs_dsp_send_tx(adev, request); + /* + * with hw still stalled, memory windows may not be + * configured properly so avoid accessing SRAM + */ + avs_dsp_send_tx(adev, request, false); spin_unlock(&ipc->rx_lock); /* ROM messages must be sent before main core is unstalled */ @@ -368,6 +605,8 @@ int avs_ipc_init(struct avs_ipc *ipc, struct device *dev) ipc->dev = dev; ipc->ready = false; ipc->default_timeout_ms = AVS_IPC_TIMEOUT_MS; + INIT_WORK(&ipc->recovery_work, avs_dsp_recovery_work); + INIT_DELAYED_WORK(&ipc->d0ix_work, avs_dsp_d0ix_work); init_completion(&ipc->done_completion); init_completion(&ipc->busy_completion); spin_lock_init(&ipc->rx_lock); @@ -379,4 +618,7 @@ int avs_ipc_init(struct avs_ipc *ipc, struct device *dev) void avs_ipc_block(struct avs_ipc *ipc) { ipc->ready = false; + cancel_work_sync(&ipc->recovery_work); + cancel_delayed_work_sync(&ipc->d0ix_work); + ipc->in_d0ix = false; } diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c index c47f85161d..9e3f8ff33a 100644 --- a/sound/soc/intel/avs/loader.c +++ b/sound/soc/intel/avs/loader.c @@ -15,6 +15,7 @@ #include "cldma.h" #include "messages.h" #include "registers.h" +#include "topology.h" #define AVS_ROM_STS_MASK 0xFF #define AVS_ROM_INIT_DONE 0x1 @@ -26,8 +27,8 @@ #define APL_ROM_INIT_RETRIES 3 #define AVS_FW_INIT_POLLING_US 500 -#define AVS_FW_INIT_TIMEOUT_US 3000000 #define AVS_FW_INIT_TIMEOUT_MS 3000 +#define AVS_FW_INIT_TIMEOUT_US (AVS_FW_INIT_TIMEOUT_MS * 1000) #define AVS_CLDMA_START_DELAY_MS 100 @@ -36,6 +37,8 @@ #define AVS_EXT_MANIFEST_MAGIC 0x31454124 #define SKL_MANIFEST_MAGIC 0x00000006 #define SKL_ADSPFW_OFFSET 0x284 +#define APL_MANIFEST_MAGIC 0x44504324 +#define APL_ADSPFW_OFFSET 0x2000 /* Occasionally, engineering (release candidate) firmware is provided for testing. */ static bool debug_ignore_fw_version; @@ -86,6 +89,8 @@ static int avs_fw_manifest_offset(struct firmware *fw) switch (magic) { case SKL_MANIFEST_MAGIC: return SKL_ADSPFW_OFFSET; + case APL_MANIFEST_MAGIC: + return APL_ADSPFW_OFFSET; default: return -EINVAL; } @@ -466,6 +471,71 @@ int avs_hda_transfer_modules(struct avs_dev *adev, bool load, return 0; } +int avs_dsp_load_libraries(struct avs_dev *adev, struct avs_tplg_library *libs, u32 num_libs) +{ + int start, id, i = 0; + int ret; + + /* Calculate the id to assign for the next lib. */ + for (id = 0; id < adev->fw_cfg.max_libs_count; id++) + if (adev->lib_names[id][0] == '\0') + break; + if (id + num_libs >= adev->fw_cfg.max_libs_count) + return -EINVAL; + + start = id; + while (i < num_libs) { + struct avs_fw_manifest *man; + const struct firmware *fw; + struct firmware stripped_fw; + char *filename; + int j; + + filename = kasprintf(GFP_KERNEL, "%s/%s/%s", AVS_ROOT_DIR, adev->spec->name, + libs[i].name); + if (!filename) + return -ENOMEM; + + /* + * If any call after this one fails, requested firmware is not released with + * avs_release_last_firmware() as failing to load code results in need for reload + * of entire driver module. And then avs_release_firmwares() is in place already. + */ + ret = avs_request_firmware(adev, &fw, filename); + kfree(filename); + if (ret < 0) + return ret; + + stripped_fw = *fw; + ret = avs_fw_manifest_strip_verify(adev, &stripped_fw, NULL); + if (ret) { + dev_err(adev->dev, "invalid library data: %d\n", ret); + return ret; + } + + ret = avs_fw_manifest_offset(&stripped_fw); + if (ret < 0) + return ret; + man = (struct avs_fw_manifest *)(stripped_fw.data + ret); + + /* Don't load anything that's already in DSP memory. */ + for (j = 0; j < id; j++) + if (!strncmp(adev->lib_names[j], man->name, AVS_LIB_NAME_SIZE)) + goto next_lib; + + ret = avs_dsp_op(adev, load_lib, &stripped_fw, id); + if (ret) + return ret; + + strncpy(adev->lib_names[id], man->name, AVS_LIB_NAME_SIZE); + id++; +next_lib: + i++; + } + + return start == id ? 1 : 0; +} + static int avs_dsp_load_basefw(struct avs_dev *adev) { const struct avs_fw_version *min_req; @@ -519,6 +589,7 @@ static int avs_dsp_load_basefw(struct avs_dev *adev) int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge) { + struct avs_soc_component *acomp; int ret, i; /* Forgo full boot if flash from IMR succeeds. */ @@ -538,7 +609,20 @@ int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge) avs_hda_l1sen_enable(adev, false); ret = avs_dsp_load_basefw(adev); + if (ret) + goto reenable_gating; + + mutex_lock(&adev->comp_list_mutex); + list_for_each_entry(acomp, &adev->comp_list, node) { + struct avs_tplg *tplg = acomp->tplg; + + ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs); + if (ret < 0) + break; + } + mutex_unlock(&adev->comp_list_mutex); +reenable_gating: avs_hda_l1sen_enable(adev, true); avs_hda_clock_gating_enable(adev, true); diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c index 004da166a9..d4bcee1aab 100644 --- a/sound/soc/intel/avs/messages.c +++ b/sound/soc/intel/avs/messages.c @@ -59,7 +59,7 @@ int avs_ipc_unload_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids) request.data = mod_ids; request.size = sizeof(*mod_ids) * num_mod_ids; - ret = avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS); + ret = avs_dsp_send_msg(adev, &request, NULL); if (ret) avs_ipc_err(adev, &request, "unload multiple modules", ret); @@ -378,7 +378,6 @@ int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id union avs_module_msg msg = AVS_MODULE_REQUEST(LARGE_CONFIG_GET); struct avs_ipc_msg request; struct avs_ipc_msg reply = {{0}}; - size_t size; void *buf; int ret; @@ -406,15 +405,14 @@ int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id return ret; } - size = reply.rsp.ext.large_config.data_off_size; - buf = krealloc(reply.data, size, GFP_KERNEL); + buf = krealloc(reply.data, reply.size, GFP_KERNEL); if (!buf) { kfree(reply.data); return -ENOMEM; } *reply_data = buf; - *reply_size = size; + *reply_size = reply.size; return 0; } @@ -432,7 +430,7 @@ int avs_ipc_set_dx(struct avs_dev *adev, u32 core_mask, bool powerup) request.data = &dx; request.size = sizeof(dx); - ret = avs_dsp_send_msg(adev, &request, NULL); + ret = avs_dsp_send_pm_msg(adev, &request, NULL, true); if (ret) avs_ipc_err(adev, &request, "set dx", ret); @@ -456,7 +454,7 @@ int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming) request.header = msg.val; - ret = avs_dsp_send_msg(adev, &request, NULL); + ret = avs_dsp_send_pm_msg(adev, &request, NULL, false); if (ret) avs_ipc_err(adev, &request, "set d0ix", ret); @@ -476,6 +474,9 @@ int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg) &payload, &payload_size); if (ret) return ret; + /* Non-zero payload expected for FIRMWARE_CONFIG. */ + if (!payload_size) + return -EREMOTEIO; while (offset < payload_size) { tlv = (struct avs_tlv *)(payload + offset); @@ -561,6 +562,7 @@ int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg) case AVS_FW_CFG_DMA_BUFFER_CONFIG: case AVS_FW_CFG_SCHEDULER_CONFIG: case AVS_FW_CFG_CLOCKS_CONFIG: + case AVS_FW_CFG_RESERVED: break; default: @@ -589,6 +591,9 @@ int avs_ipc_get_hw_config(struct avs_dev *adev, struct avs_hw_cfg *cfg) &payload, &payload_size); if (ret) return ret; + /* Non-zero payload expected for HARDWARE_CONFIG. */ + if (!payload_size) + return -EREMOTEIO; while (offset < payload_size) { tlv = (struct avs_tlv *)(payload + offset); @@ -672,11 +677,45 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info) &payload, &payload_size); if (ret) return ret; + /* Non-zero payload expected for MODULES_INFO. */ + if (!payload_size) + return -EREMOTEIO; *info = (struct avs_mods_info *)payload; return 0; } +int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size) +{ + int ret; + + ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID, + AVS_BASEFW_ENABLE_LOGS, log_info, size); + if (ret) + dev_err(adev->dev, "enable logs failed: %d\n", ret); + + return ret; +} + +int avs_ipc_set_system_time(struct avs_dev *adev) +{ + struct avs_sys_time sys_time; + int ret; + u64 us; + + /* firmware expects UTC time in micro seconds */ + us = ktime_to_us(ktime_get()); + sys_time.val_l = us & UINT_MAX; + sys_time.val_u = us >> 32; + + ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID, + AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time)); + if (ret) + dev_err(adev->dev, "set system time failed: %d\n", ret); + + return ret; +} + int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, u8 instance_id, u32 sink_id, const struct avs_audio_format *src_fmt, diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h index 0395dd7150..c0f90dba9a 100644 --- a/sound/soc/intel/avs/messages.h +++ b/sound/soc/intel/avs/messages.h @@ -186,7 +186,9 @@ union avs_reply_msg { enum avs_notify_msg_type { AVS_NOTIFY_PHRASE_DETECTED = 4, AVS_NOTIFY_RESOURCE_EVENT = 5, + AVS_NOTIFY_LOG_BUFFER_STATUS = 6, AVS_NOTIFY_FW_READY = 8, + AVS_NOTIFY_EXCEPTION_CAUGHT = 10, AVS_NOTIFY_MODULE_EVENT = 12, }; @@ -202,9 +204,17 @@ union avs_notify_msg { u32 msg_direction:1; u32 msg_target:1; }; + struct { + u16 rsvd:12; + u16 core:4; + } log; }; union { u32 val; + struct { + u32 core_id:2; + u32 stack_dump_size:16; + } coredump; } ext; }; } __packed; @@ -324,12 +334,46 @@ int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming); #define AVS_BASEFW_INST_ID 0 enum avs_basefw_runtime_param { + AVS_BASEFW_ENABLE_LOGS = 6, AVS_BASEFW_FIRMWARE_CONFIG = 7, AVS_BASEFW_HARDWARE_CONFIG = 8, AVS_BASEFW_MODULES_INFO = 9, AVS_BASEFW_LIBRARIES_INFO = 16, + AVS_BASEFW_SYSTEM_TIME = 20, +}; + +enum avs_log_enable { + AVS_LOG_DISABLE = 0, + AVS_LOG_ENABLE = 1 }; +enum avs_skl_log_priority { + AVS_SKL_LOG_CRITICAL = 1, + AVS_SKL_LOG_HIGH, + AVS_SKL_LOG_MEDIUM, + AVS_SKL_LOG_LOW, + AVS_SKL_LOG_VERBOSE, +}; + +struct skl_log_state { + u32 enable; + u32 min_priority; +} __packed; + +struct skl_log_state_info { + u32 core_mask; + struct skl_log_state logs_core[]; +} __packed; + +struct apl_log_state_info { + u32 aging_timer_period; + u32 fifo_full_timer_period; + u32 core_mask; + struct skl_log_state logs_core[]; +} __packed; + +int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size); + struct avs_fw_version { u16 major; u16 minor; @@ -497,6 +541,13 @@ static inline bool avs_module_entry_is_loaded(struct avs_module_entry *mentry) int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info); +struct avs_sys_time { + u32 val_l; + u32 val_u; +} __packed; + +int avs_ipc_set_system_time(struct avs_dev *adev); + /* Module configuration */ #define AVS_MIXIN_MOD_UUID \ diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h index 3fd02389ed..95be86148c 100644 --- a/sound/soc/intel/avs/registers.h +++ b/sound/soc/intel/avs/registers.h @@ -14,6 +14,7 @@ #define AZX_PGCTL_LSRMD_MASK BIT(4) #define AZX_CGCTL_MISCBDCGE_MASK BIT(6) #define AZX_VS_EM2_L1SEN BIT(13) +#define AZX_VS_EM2_DUM BIT(23) /* Intel HD Audio General DSP Registers */ #define AVS_ADSP_GEN_BASE 0x0 @@ -47,6 +48,12 @@ #define SKL_ADSP_HIPCIE_DONE BIT(30) #define SKL_ADSP_HIPCT_BUSY BIT(31) +/* Intel HD Audio SRAM windows base addresses */ +#define SKL_ADSP_SRAM_BASE_OFFSET 0x8000 +#define SKL_ADSP_SRAM_WINDOW_SIZE 0x2000 +#define APL_ADSP_SRAM_BASE_OFFSET 0x80000 +#define APL_ADSP_SRAM_WINDOW_SIZE 0x20000 + /* Constants used when accessing SRAM, space shared with firmware */ #define AVS_FW_REG_BASE(adev) ((adev)->spec->sram_base_offset) #define AVS_FW_REG_STATUS(adev) (AVS_FW_REG_BASE(adev) + 0x0) @@ -58,6 +65,7 @@ #define AVS_UPLINK_WINDOW AVS_FW_REGS_WINDOW /* HOST -> DSP communication window */ #define AVS_DOWNLINK_WINDOW 1 +#define AVS_DEBUG_WINDOW 2 /* registry I/O helpers */ #define avs_sram_offset(adev, window_idx) \ diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c index 6473e3ae4c..13611dee97 100644 --- a/sound/soc/intel/avs/utils.c +++ b/sound/soc/intel/avs/utils.c @@ -7,6 +7,7 @@ // #include +#include #include #include "avs.h" #include "messages.h" @@ -299,3 +300,25 @@ void avs_release_firmwares(struct avs_dev *adev) kfree(entry); } } + +unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len, + spinlock_t *lock) +{ + struct __kfifo *__fifo = &fifo->kfifo; + unsigned long flags; + unsigned int l, off; + + spin_lock_irqsave(lock, flags); + len = min(len, kfifo_avail(fifo)); + off = __fifo->in & __fifo->mask; + l = min(len, kfifo_size(fifo) - off); + + memcpy_fromio(__fifo->data + off, src, l); + memcpy_fromio(__fifo->data, src + l, len - l); + /* Make sure data copied from SRAM is visible to all CPUs. */ + smp_mb(); + __fifo->in += len; + spin_unlock_irqrestore(lock, flags); + + return len; +} diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index f3873b5bea..aa12d7e3dd 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -41,7 +41,7 @@ config SND_SOC_INTEL_SOF_CIRRUS_COMMON if SND_SOC_INTEL_CATPT config SND_SOC_INTEL_HASWELL_MACH - tristate "Haswell Lynxpoint" + tristate "Haswell with RT5640 I2S codec" depends on I2C depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST depends on X86_INTEL_LPSS || COMPILE_TEST @@ -85,7 +85,7 @@ config SND_SOC_INTEL_BDW_RT5677_MACH If unsure select "N". config SND_SOC_INTEL_BROADWELL_MACH - tristate "Broadwell Wildcatpoint" + tristate "Broadwell with RT286 I2S codec" depends on I2C depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST depends on X86_INTEL_LPSS || COMPILE_TEST @@ -660,7 +660,6 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH depends on MFD_INTEL_LPSS || COMPILE_TEST depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST depends on SOUNDWIRE - depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC select SND_SOC_MAX98373_I2C select SND_SOC_MAX98373_SDW select SND_SOC_RT700_SDW diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 40c0c3d1c5..eea1e26acf 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-sst-haswell-objs := haswell.o +snd-soc-sst-haswell-objs := hsw_rt5640.o snd-soc-sst-bdw-rt5650-mach-objs := bdw-rt5650.o snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o -snd-soc-sst-broadwell-objs := broadwell.o +snd-soc-sst-broadwell-objs := bdw_rt286.o snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o snd-soc-sst-bxt-rt298-objs := bxt_rt298.o snd-soc-sst-sof-pcm512x-objs := sof_pcm512x.o diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c index bc0eab1c30..67c3f49b92 100644 --- a/sound/soc/intel/boards/bdw-rt5650.c +++ b/sound/soc/intel/boards/bdw-rt5650.c @@ -192,15 +192,15 @@ static int bdw_rt5650_init(struct snd_soc_pcm_runtime *rtd) } /* Create and initialize headphone jack */ - if (snd_soc_card_jack_new(rtd->card, "Headphone Jack", + if (snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE, &headphone_jack, &headphone_jack_pin, 1)) { dev_err(component->dev, "Can't create headphone jack\n"); } /* Create and initialize mic jack */ - if (snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE, - &mic_jack, &mic_jack_pin, 1)) { + if (snd_soc_card_jack_new_pins(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, &mic_jack, &mic_jack_pin, 1)) { dev_err(component->dev, "Can't create mic jack\n"); } @@ -249,6 +249,7 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { /* SSP0 - Codec */ .name = "Codec", .id = 0, + .nonatomic = 1, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 071557fada..3148870276 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -256,7 +256,7 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) } /* Create and initialize headphone jack */ - if (!snd_soc_card_jack_new(rtd->card, "Headphone Jack", + if (!snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE, &headphone_jack, &headphone_jack_pin, 1)) { headphone_jack_gpio.gpiod_dev = component->dev; @@ -268,7 +268,7 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) } /* Create and initialize mic jack */ - if (!snd_soc_card_jack_new(rtd->card, "Mic Jack", + if (!snd_soc_card_jack_new_pins(rtd->card, "Mic Jack", SND_JACK_MICROPHONE, &mic_jack, &mic_jack_pin, 1)) { mic_jack_gpio.gpiod_dev = component->dev; @@ -349,6 +349,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { /* SSP0 - Codec */ .name = "Codec", .id = 0, + .nonatomic = 1, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 9bc7b88e34..7c6c95e99a 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -186,6 +186,17 @@ static const struct snd_soc_dapm_route gemini_map[] = { {"ssp2 Rx", NULL, "Capture"}, }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -231,10 +242,12 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &broxton_headset, NULL, 0); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &broxton_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -720,8 +733,7 @@ static int bxt_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &broxton_hdmi[i], - NULL, 0); + SND_JACK_AVOUT, &broxton_hdmi[i]); if (err) return err; diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 05e8330764..4bd93c3ba3 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -168,7 +168,7 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; int ret = 0; - ret = snd_soc_card_jack_new(rtd->card, "Headset", + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, &broxton_headset, broxton_headset_pins, ARRAY_SIZE(broxton_headset_pins)); @@ -176,7 +176,7 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) if (ret) return ret; - rt298_mic_detect(component, &broxton_headset); + snd_soc_component_set_jack(component, &broxton_headset, NULL); snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); @@ -544,8 +544,7 @@ static int bxt_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &broxton_hdmi[i], - NULL, 0); + SND_JACK_AVOUT, &broxton_hdmi[i]); if (err) return err; diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index 96d3201efb..ae89986686 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -87,11 +87,11 @@ static int byt_cht_cx2072x_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &byt_cht_cx2072x_headset, - byt_cht_cx2072x_headset_pins, - ARRAY_SIZE(byt_cht_cx2072x_headset_pins)); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &byt_cht_cx2072x_headset, + byt_cht_cx2072x_headset_pins, + ARRAY_SIZE(byt_cht_cx2072x_headset_pins)); if (ret) return ret; @@ -126,7 +126,7 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index eb19bf16af..a0c8f1d3f8 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -81,7 +81,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index e18371b5a7..6432b83f61 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -219,10 +219,10 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) return ret; } - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &priv->jack, byt_cht_es8316_jack_pins, - ARRAY_SIZE(byt_cht_es8316_jack_pins)); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &priv->jack, byt_cht_es8316_jack_pins, + ARRAY_SIZE(byt_cht_es8316_jack_pins)); if (ret) { dev_err(card->dev, "jack creation failed %d\n", ret); return ret; @@ -265,7 +265,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC + SND_SOC_DAIFMT_BP_FP ); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c index 115c2bcaab..7fc03f2efd 100644 --- a/sound/soc/intel/boards/bytcht_nocodec.c +++ b/sound/soc/intel/boards/bytcht_nocodec.c @@ -61,7 +61,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index d76a505052..fb9d9e2718 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -773,6 +773,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_OVCD_SF_0P75 | BYT_RT5640_MCLK_EN), }, + { /* HP Pro Tablet 408 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pro Tablet 408"), + }, + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_1500UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { /* HP Stream 7 */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), @@ -1179,12 +1191,14 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); + struct rt5640_set_jack_data *jack_data = &priv->jack_data; struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; const struct snd_soc_dapm_route *custom_map = NULL; int num_routes = 0; int ret; card->dapm.idle_bias_off = true; + jack_data->use_platform_clock = true; /* Start with RC clk for jack-detect (we disable MCLK below) */ if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) @@ -1300,10 +1314,10 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) } if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &priv->jack, rt5640_pins, - ARRAY_SIZE(rt5640_pins)); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &priv->jack, rt5640_pins, + ARRAY_SIZE(rt5640_pins)); if (ret) { dev_err(card->dev, "Jack creation failed %d\n", ret); return ret; @@ -1321,17 +1335,17 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) } if (byt_rt5640_quirk & BYT_RT5640_JD_HP_ELITEP_1000G2) { - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET, - &priv->jack, rt5640_pins, - ARRAY_SIZE(rt5640_pins)); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET, + &priv->jack, rt5640_pins, + ARRAY_SIZE(rt5640_pins)); if (ret) return ret; - ret = snd_soc_card_jack_new(card, "Headset 2", - SND_JACK_HEADSET, - &priv->jack2, rt5640_pins2, - ARRAY_SIZE(rt5640_pins2)); + ret = snd_soc_card_jack_new_pins(card, "Headset 2", + SND_JACK_HEADSET, + &priv->jack2, rt5640_pins2, + ARRAY_SIZE(rt5640_pins2)); if (ret) return ret; @@ -1399,7 +1413,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; @@ -1622,7 +1636,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) * with the codec driver/pdata are non-existent */ - struct acpi_chan_package chan_package; + struct acpi_chan_package chan_package = { 0 }; /* format specified: 2 64-bit integers */ struct acpi_buffer format = {sizeof("NN"), "NN"}; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 39348d2b24..2beb686768 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -652,9 +652,10 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) report = SND_JACK_HEADSET; if (report) { - ret = snd_soc_card_jack_new(runtime->card, "Headset", - report, &priv->jack, bytcr_jack_pins, - ARRAY_SIZE(bytcr_jack_pins)); + ret = snd_soc_card_jack_new_pins(runtime->card, "Headset", + report, &priv->jack, + bytcr_jack_pins, + ARRAY_SIZE(bytcr_jack_pins)); if (ret) { dev_err(runtime->dev, "jack creation failed %d\n", ret); return ret; @@ -705,7 +706,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC + SND_SOC_DAIFMT_BP_FP ); if (ret < 0) { @@ -951,7 +952,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) * with the codec driver/pdata are non-existent */ - struct acpi_chan_package chan_package; + struct acpi_chan_package chan_package = { 0 }; /* format specified: 2 64-bit integers */ struct acpi_buffer format = {sizeof("NN"), "NN"}; diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index 8d8e96e3cd..45a6805787 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -226,9 +226,9 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) jack_type = ARIZONA_JACK_MASK | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3; - ret = snd_soc_card_jack_new(card, "Headset", jack_type, - &priv->jack, byt_wm5102_pins, - ARRAY_SIZE(byt_wm5102_pins)); + ret = snd_soc_card_jack_new_pins(card, "Headset", jack_type, + &priv->jack, byt_wm5102_pins, + ARRAY_SIZE(byt_wm5102_pins)); if (ret) { dev_err(card->dev, "Error creating jack: %d\n", ret); return ret; @@ -265,7 +265,7 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BP_FP); if (ret) { dev_err(rtd->dev, "Error setting format to I2S: %d\n", ret); return ret; @@ -421,8 +421,17 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev) priv->spkvdd_en_gpio = gpiod_get(codec_dev, "wlf,spkvdd-ena", GPIOD_OUT_LOW); put_device(codec_dev); - if (IS_ERR(priv->spkvdd_en_gpio)) - return dev_err_probe(dev, PTR_ERR(priv->spkvdd_en_gpio), "getting spkvdd-GPIO\n"); + if (IS_ERR(priv->spkvdd_en_gpio)) { + ret = PTR_ERR(priv->spkvdd_en_gpio); + /* + * The spkvdd gpio-lookup is registered by: drivers/mfd/arizona-spi.c, + * so -ENOENT means that arizona-spi hasn't probed yet. + */ + if (ret == -ENOENT) + ret = -EPROBE_DEFER; + + return dev_err_probe(dev, ret, "getting spkvdd-GPIO\n"); + } /* override platform name, if required */ byt_wm5102_card.dev = dev; diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index b3d7a0725e..64eb73525e 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -201,9 +201,10 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE; - ret = snd_soc_card_jack_new(runtime->card, "Headset Jack", - jack_type, jack, - hs_jack_pins, ARRAY_SIZE(hs_jack_pins)); + ret = snd_soc_card_jack_new_pins(runtime->card, "Headset Jack", + jack_type, jack, + hs_jack_pins, + ARRAY_SIZE(hs_jack_pins)); if (ret) { dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret); return ret; @@ -263,8 +264,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, return ret; } - fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBC_CFC; + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BP_FP; ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt); if (ret < 0) { @@ -306,8 +306,7 @@ static int cht_max98090_headset_init(struct snd_soc_component *component) SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3; - ret = snd_soc_card_jack_new(card, "Headset Jack", jack_type, - jack, NULL, 0); + ret = snd_soc_card_jack_new(card, "Headset Jack", jack_type, jack); if (ret) { dev_err(card->dev, "Headset Jack creation failed %d\n", ret); return ret; @@ -538,7 +537,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) const char *platform_name; bool sof_parent; - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); + drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); if (!drv) return -ENOMEM; @@ -559,8 +558,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } /* override platform name, if required */ - snd_soc_card_cht.dev = &pdev->dev; - mach = pdev->dev.platform_data; + snd_soc_card_cht.dev = dev; + mach = dev->platform_data; platform_name = mach->mach_params.platform; ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, @@ -576,9 +575,9 @@ static int snd_cht_mc_probe(struct platform_device *pdev) else mclk_name = "pmc_plt_clk_3"; - drv->mclk = devm_clk_get(&pdev->dev, mclk_name); + drv->mclk = devm_clk_get(dev, mclk_name); if (IS_ERR(drv->mclk)) { - dev_err(&pdev->dev, + dev_err(dev, "Failed to get MCLK from %s: %ld\n", mclk_name, PTR_ERR(drv->mclk)); return PTR_ERR(drv->mclk); @@ -594,12 +593,12 @@ static int snd_cht_mc_probe(struct platform_device *pdev) if (drv->quirks & QUIRK_PMC_PLT_CLK_0) { ret_val = clk_prepare_enable(drv->mclk); if (ret_val < 0) { - dev_err(&pdev->dev, "MCLK enable error: %d\n", ret_val); + dev_err(dev, "MCLK enable error: %d\n", ret_val); return ret_val; } } - sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + sof_parent = snd_soc_acpi_sof_parent(dev); /* set card and driver name */ if (sof_parent) { @@ -614,9 +613,9 @@ static int snd_cht_mc_probe(struct platform_device *pdev) if (sof_parent) dev->driver->pm = &snd_soc_pm_ops; - ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); + ret_val = devm_snd_soc_register_card(dev, &snd_soc_card_cht); if (ret_val) { - dev_err(&pdev->dev, + dev_err(dev, "snd_soc_register_card failed %d\n", ret_val); return ret_val; } diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index da6c659de2..4c1d83b317 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -108,8 +108,8 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) */ jack_type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3; - ret = snd_soc_card_jack_new(runtime->card, "Headset", jack_type, jack, - cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins)); + ret = snd_soc_card_jack_new_pins(runtime->card, "Headset", jack_type, + jack, cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins)); if (ret) { dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret); diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index c21561c6a4..96501aed8b 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -302,9 +302,9 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) else jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE; - ret = snd_soc_card_jack_new(runtime->card, "Headset", - jack_type, &ctx->jack, - cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins)); + ret = snd_soc_card_jack_new_pins(runtime->card, "Headset", jack_type, + &ctx->jack, cht_bsw_jack_pins, + ARRAY_SIZE(cht_bsw_jack_pins)); if (ret) { dev_err(runtime->dev, "Headset jack creation failed %d\n", ret); return ret; @@ -362,7 +362,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC + SND_SOC_DAIFMT_BP_FP ); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); @@ -372,7 +372,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC + SND_SOC_DAIFMT_BC_FC ); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); @@ -396,7 +396,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0), SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BC_FC); if (ret < 0) { dev_err(rtd->dev, "can't set format to TDM %d\n", ret); return ret; @@ -603,7 +603,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) * with the codec driver/pdata are non-existent */ - struct acpi_chan_package chan_package; + struct acpi_chan_package chan_package = { 0 }; /* format specified: 2 64-bit integers */ struct acpi_buffer format = {sizeof("NN"), "NN"}; diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 9882aeb24d..ca47f6476b 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -221,12 +221,12 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret; - ret = snd_soc_card_jack_new(runtime->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2, - &ctx->headset, - cht_bsw_headset_pins, - ARRAY_SIZE(cht_bsw_headset_pins)); + ret = snd_soc_card_jack_new_pins(runtime->card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2, + &ctx->headset, + cht_bsw_headset_pins, + ARRAY_SIZE(cht_bsw_headset_pins)); if (ret) return ret; @@ -300,7 +300,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c index 27615acdda..20da83d9ee 100644 --- a/sound/soc/intel/boards/cml_rt1011_rt5682.c +++ b/sound/soc/intel/boards/cml_rt1011_rt5682.c @@ -121,6 +121,17 @@ static const struct snd_soc_dapm_route cml_rt1011_tt_map[] = { {"TR Ext Spk", NULL, "TR SPO" }, }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) { struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); @@ -137,11 +148,13 @@ static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->headset, NULL, 0); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -338,8 +351,7 @@ static int sof_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); ret = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &hdmi_jack[i], - NULL, 0); + SND_JACK_AVOUT, &hdmi_jack[i]); if (ret) return ret; diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index e4bfb0fe5f..cf0f89db3e 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -78,6 +78,17 @@ static const struct snd_soc_dapm_widget geminilake_widgets[] = { SND_SOC_DAPM_SPK("HDMI3", NULL), }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route geminilake_map[] = { /* HP jack connectors - unknown if we have jack detection */ { "Headphone Jack", NULL, "HPOL" }, @@ -173,10 +184,12 @@ static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->geminilake_headset, NULL, 0); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &ctx->geminilake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -571,8 +584,7 @@ static int glk_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &geminilake_hdmi[i], - NULL, 0); + SND_JACK_AVOUT, &geminilake_hdmi[i]); if (err) return err; diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c index 5c31ddc088..83c7dfbccd 100644 --- a/sound/soc/intel/boards/hda_dsp_common.c +++ b/sound/soc/intel/boards/hda_dsp_common.c @@ -62,8 +62,8 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, hpcm->pcm = spcm; hpcm->device = spcm->device; dev_dbg(card->dev, - "%s: mapping HDMI converter %d to PCM %d (%p)\n", - __func__, i, hpcm->device, spcm); + "mapping HDMI converter %d to PCM %d (%p)\n", + i, hpcm->device, spcm); } else { hpcm->pcm = NULL; hpcm->device = SNDRV_PCM_INVALID_DEVICE; diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c index a4bdf634e9..329457e3e3 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c @@ -99,6 +99,17 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_POST_PMD), }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route kabylake_map[] = { { "Headphone Jack", NULL, "HPL" }, { "Headphone Jack", NULL, "HPR" }, @@ -179,10 +190,12 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->kabylake_headset, NULL, 0); + ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &ctx->kabylake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -587,8 +600,7 @@ static int kabylake_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &skylake_hdmi[i], - NULL, 0); + SND_JACK_AVOUT, &skylake_hdmi[i]); if (err) return err; diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 620a9fbcb0..362579f258 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -119,6 +119,17 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_POST_PMD), }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route kabylake_map[] = { /* speaker */ { "Left Spk", NULL, "Left BE_OUT" }, @@ -354,10 +365,12 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->kabylake_headset, NULL, 0); + ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &ctx->kabylake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -965,8 +978,7 @@ static int kabylake_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &kabylake_hdmi[i], - NULL, 0); + SND_JACK_AVOUT, &kabylake_hdmi[i]); if (err) return err; diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c index 1cb56ec363..2c7a547f63 100644 --- a/sound/soc/intel/boards/kbl_rt5660.c +++ b/sound/soc/intel/boards/kbl_rt5660.c @@ -173,9 +173,9 @@ static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd) } /* Create and initialize headphone jack, this jack is not mandatory, don't return if fails */ - ret = snd_soc_card_jack_new(rtd->card, "Lineout Jack", - SND_JACK_LINEOUT, &lineout_jack, - &lineout_jack_pin, 1); + ret = snd_soc_card_jack_new_pins(rtd->card, "Lineout Jack", + SND_JACK_LINEOUT, &lineout_jack, + &lineout_jack_pin, 1); if (ret) dev_warn(component->dev, "Can't create Lineout jack\n"); else { @@ -187,9 +187,9 @@ static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd) } /* Create and initialize mic jack, this jack is not mandatory, don't return if fails */ - ret = snd_soc_card_jack_new(rtd->card, "Mic Jack", - SND_JACK_MICROPHONE, &mic_jack, - &mic_jack_pin, 1); + ret = snd_soc_card_jack_new_pins(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, &mic_jack, + &mic_jack_pin, 1); if (ret) dev_warn(component->dev, "Can't create mic jack\n"); else { @@ -485,8 +485,7 @@ static int kabylake_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &skylake_hdmi[i], - NULL, 0); + SND_JACK_AVOUT, &skylake_hdmi[i]); if (err) return err; diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index f24e0ce5d4..2d4224c5b1 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -206,6 +206,17 @@ static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = { SND_SOC_DAPM_POST_PMD), }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route kabylake_5663_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headphone Jack", NULL, "HPOL" }, @@ -271,10 +282,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset, - NULL, 0); + ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &ctx->kabylake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); return ret; @@ -919,8 +932,7 @@ static int kabylake_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &skylake_hdmi[i], - NULL, 0); + SND_JACK_AVOUT, &skylake_hdmi[i]); if (err) return err; diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index 6874e981c8..2c79fca57b 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -145,6 +145,17 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route kabylake_map[] = { /* Headphones */ { "Headphone Jack", NULL, "Platform Clock" }, @@ -228,10 +239,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset, - NULL, 0); + ret = snd_soc_card_jack_new_pins(&kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &ctx->kabylake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); return ret; @@ -743,8 +756,7 @@ static int kabylake_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP,pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &ctx->kabylake_hdmi[i], - NULL, 0); + SND_JACK_AVOUT, &ctx->kabylake_hdmi[i]); if (err) return err; diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c index 07bfb2e64b..e9cefa4ae5 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -150,17 +150,11 @@ int skl_hda_hdmi_jack_init(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &pcm->hdmi_jack, - NULL, 0); + SND_JACK_AVOUT, &pcm->hdmi_jack); if (err) return err; - err = snd_jack_add_new_kctl(pcm->hdmi_jack.jack, - jack_name, SND_JACK_AVOUT); - if (err) - dev_warn(component->dev, "failed creating Jack kctl\n"); - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, &pcm->hdmi_jack); if (err < 0) diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index f4b4eeca3e..81144efb4b 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -75,7 +75,7 @@ skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); int ret = 0; - dev_dbg(card->dev, "%s: dai link name - %s\n", __func__, link->name); + dev_dbg(card->dev, "dai link name - %s\n", link->name); link->platforms->name = ctx->platform_name; link->nonatomic = 1; @@ -203,7 +203,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) struct skl_hda_private *ctx; int ret; - dev_dbg(&pdev->dev, "%s: entry\n", __func__); + dev_dbg(&pdev->dev, "entry\n"); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 7297eb0561..8dceb0b025 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -97,6 +97,17 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_POST_PMD), }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route skylake_map[] = { /* HP jack connectors - unknown if we have jack detection */ { "Headphone Jack", NULL, "HPOL" }, @@ -163,10 +174,11 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, - NULL, 0); + ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); return ret; @@ -610,8 +622,7 @@ static int skylake_card_late_probe(struct snd_soc_card *card) "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, SND_JACK_AVOUT, - &skylake_hdmi[i], - NULL, 0); + &skylake_hdmi[i]); if (err) return err; diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 68efde1633..62c0d46d00 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -101,6 +101,17 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_POST_PMD), }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_route skylake_map[] = { /* HP jack connectors - unknown if we have jack detection */ {"Headphone Jack", NULL, "HPOL"}, @@ -182,10 +193,11 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) * 4 buttons here map to the google Reference headset * The use of these buttons can be decided by the user space. */ - ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, - NULL, 0); + ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); return ret; @@ -651,8 +663,7 @@ static int skylake_card_late_probe(struct snd_soc_card *card) "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, SND_JACK_AVOUT, - &skylake_hdmi[i], - NULL, 0); + &skylake_hdmi[i]); if (err) return err; diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index eca4a78668..4f3d655e2b 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -125,7 +125,7 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; int ret; - ret = snd_soc_card_jack_new(rtd->card, "Headset", + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, &skylake_headset, skylake_headset_pins, ARRAY_SIZE(skylake_headset_pins)); @@ -133,7 +133,7 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) if (ret) return ret; - rt286_mic_detect(component, &skylake_headset); + snd_soc_component_set_jack(component, &skylake_headset, NULL); snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); @@ -491,8 +491,7 @@ static int skylake_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &skylake_hdmi[i], - NULL, 0); + SND_JACK_AVOUT, &skylake_hdmi[i]); if (err) return err; diff --git a/sound/soc/intel/boards/sof_cirrus_common.c b/sound/soc/intel/boards/sof_cirrus_common.c index e71d74ec1b..f4192df962 100644 --- a/sound/soc/intel/boards/sof_cirrus_common.c +++ b/sound/soc/intel/boards/sof_cirrus_common.c @@ -54,22 +54,29 @@ static struct snd_soc_dai_link_component cs35l41_components[] = { }, }; +/* + * Mapping between ACPI instance id and speaker position. + * + * Four speakers: + * 0: Tweeter left, 1: Woofer left + * 2: Tweeter right, 3: Woofer right + */ static struct snd_soc_codec_conf cs35l41_codec_conf[] = { { .dlc = COMP_CODEC_CONF(CS35L41_DEV0_NAME), - .name_prefix = "WL", + .name_prefix = "TL", }, { .dlc = COMP_CODEC_CONF(CS35L41_DEV1_NAME), - .name_prefix = "WR", + .name_prefix = "WL", }, { .dlc = COMP_CODEC_CONF(CS35L41_DEV2_NAME), - .name_prefix = "TL", + .name_prefix = "TR", }, { .dlc = COMP_CODEC_CONF(CS35L41_DEV3_NAME), - .name_prefix = "TR", + .name_prefix = "WR", }, }; @@ -101,6 +108,21 @@ static int cs35l41_init(struct snd_soc_pcm_runtime *rtd) return ret; } +/* + * Channel map: + * + * TL/WL: ASPRX1 on slot 0, ASPRX2 on slot 1 (default) + * TR/WR: ASPRX1 on slot 1, ASPRX2 on slot 0 + */ +static const struct { + unsigned int rx[2]; +} cs35l41_channel_map[] = { + {.rx = {0, 1}}, /* TL */ + {.rx = {0, 1}}, /* WL */ + {.rx = {1, 0}}, /* TR */ + {.rx = {1, 0}}, /* WR */ +}; + static int cs35l41_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -134,6 +156,16 @@ static int cs35l41_hw_params(struct snd_pcm_substream *substream, ret); return ret; } + + /* setup channel map */ + ret = snd_soc_dai_set_channel_map(codec_dai, 0, NULL, + ARRAY_SIZE(cs35l41_channel_map[i].rx), + (unsigned int *)cs35l41_channel_map[i].rx); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set channel map, ret %d\n", + ret); + return ret; + } } return 0; diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c index ce78c18798..85ffd06589 100644 --- a/sound/soc/intel/boards/sof_cs42l42.c +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -41,8 +41,13 @@ #define SOF_CS42L42_DAILINK_MASK (GENMASK(24, 10)) #define SOF_CS42L42_DAILINK(link1, link2, link3, link4, link5) \ ((((link1) | ((link2) << 3) | ((link3) << 6) | ((link4) << 9) | ((link5) << 12)) << SOF_CS42L42_DAILINK_SHIFT) & SOF_CS42L42_DAILINK_MASK) -#define SOF_MAX98357A_SPEAKER_AMP_PRESENT BIT(25) -#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(26) +#define SOF_BT_OFFLOAD_PRESENT BIT(25) +#define SOF_CS42L42_SSP_BT_SHIFT 26 +#define SOF_CS42L42_SSP_BT_MASK (GENMASK(28, 26)) +#define SOF_CS42L42_SSP_BT(quirk) \ + (((quirk) << SOF_CS42L42_SSP_BT_SHIFT) & SOF_CS42L42_SSP_BT_MASK) +#define SOF_MAX98357A_SPEAKER_AMP_PRESENT BIT(29) +#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(30) enum { LINK_NONE = 0, @@ -50,6 +55,18 @@ enum { LINK_SPK = 2, LINK_DMIC = 3, LINK_HDMI = 4, + LINK_BT = 5, +}; + +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, }; /* Default: SSP2 */ @@ -98,11 +115,13 @@ static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - jack, NULL, 0); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + jack, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -186,8 +205,7 @@ static int sof_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &pcm->hdmi_jack, - NULL, 0); + SND_JACK_AVOUT, &pcm->hdmi_jack); if (err) return err; @@ -278,6 +296,13 @@ static struct snd_soc_dai_link_component dmic_component[] = { } }; +static struct snd_soc_dai_link_component dummy_component[] = { + { + .name = "snd-soc-dummy", + .dai_name = "snd-soc-dummy-dai", + } +}; + static int create_spk_amp_dai_links(struct device *dev, struct snd_soc_dai_link *links, struct snd_soc_dai_link_component *cpus, @@ -467,9 +492,50 @@ static int create_hdmi_dai_links(struct device *dev, return -ENOMEM; } +static int create_bt_offload_dai_links(struct device *dev, + struct snd_soc_dai_link *links, + struct snd_soc_dai_link_component *cpus, + int *id, int ssp_bt) +{ + /* bt offload */ + if (!(sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT)) + return 0; + + links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", + ssp_bt); + if (!links[*id].name) + goto devm_err; + + links[*id].id = *id; + links[*id].codecs = dummy_component; + links[*id].num_codecs = ARRAY_SIZE(dummy_component); + links[*id].platforms = platform_component; + links[*id].num_platforms = ARRAY_SIZE(platform_component); + + links[*id].dpcm_playback = 1; + links[*id].dpcm_capture = 1; + links[*id].no_pcm = 1; + links[*id].cpus = &cpus[*id]; + links[*id].num_cpus = 1; + + links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", + ssp_bt); + if (!links[*id].cpus->dai_name) + goto devm_err; + + (*id)++; + + return 0; + +devm_err: + return -ENOMEM; +} + static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, int ssp_codec, int ssp_amp, + int ssp_bt, int dmic_be_num, int hdmi_num) { @@ -522,6 +588,14 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, goto devm_err; } break; + case LINK_BT: + ret = create_bt_offload_dai_links(dev, links, cpus, &id, ssp_bt); + if (ret < 0) { + dev_err(dev, "fail to create bt offload dai links, ret %d\n", + ret); + goto devm_err; + } + break; case LINK_NONE: /* caught here if it's not used as terminator in macro */ default: @@ -543,7 +617,7 @@ static int sof_audio_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach; struct sof_card_private *ctx; int dmic_be_num, hdmi_num; - int ret, ssp_amp, ssp_codec; + int ret, ssp_bt, ssp_amp, ssp_codec; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -568,6 +642,9 @@ static int sof_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk); + ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >> + SOF_CS42L42_SSP_BT_SHIFT; + ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >> SOF_CS42L42_SSP_AMP_SHIFT; @@ -578,9 +655,11 @@ static int sof_audio_probe(struct platform_device *pdev) if (sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT) sof_audio_card_cs42l42.num_links++; + if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT) + sof_audio_card_cs42l42.num_links++; dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, - dmic_be_num, hdmi_num); + ssp_bt, dmic_be_num, hdmi_num); if (!dai_links) return -ENOMEM; @@ -621,6 +700,17 @@ static const struct platform_device_id board_ids[] = { SOF_CS42L42_SSP_AMP(1)) | SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_NONE), }, + { + .name = "adl_mx98360a_cs4242", + .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_MAX98360A_SPEAKER_AMP_PRESENT | + SOF_CS42L42_SSP_AMP(1) | + SOF_CS42L42_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_PRESENT | + SOF_CS42L42_SSP_BT(2) | + SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_BT)), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c index b7b3b0bf99..34cf849a83 100644 --- a/sound/soc/intel/boards/sof_da7219_max98373.c +++ b/sound/soc/intel/boards/sof_da7219_max98373.c @@ -135,6 +135,17 @@ static const struct snd_soc_dapm_route max98360a_map[] = { {"DMic", NULL, "SoC DMIC"}, }; +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static struct snd_soc_jack headset; static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) @@ -156,11 +167,13 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &headset, NULL, 0); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index 9d617831dd..606cc3242a 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -28,6 +28,24 @@ #define SOF_ES8336_SSP_CODEC_MASK (GENMASK(3, 0)) #define SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK BIT(4) + +/* HDMI capture*/ +#define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(14) +#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 15 +#define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(16, 15)) +#define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \ + (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) + +#define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7 +#define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7)) +#define SOF_HDMI_CAPTURE_1_SSP(quirk) \ + (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK) + +#define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10 +#define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10)) +#define SOF_HDMI_CAPTURE_2_SSP(quirk) \ + (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK) + #define SOF_ES8336_ENABLE_DMIC BIT(5) #define SOF_ES8336_JD_INVERTED BIT(6) #define SOF_ES8336_HEADPHONE_GPIO BIT(7) @@ -57,28 +75,26 @@ static const struct acpi_gpio_params enable_gpio0 = { 0, 0, true }; static const struct acpi_gpio_params enable_gpio1 = { 1, 0, true }; static const struct acpi_gpio_mapping acpi_speakers_enable_gpio0[] = { - { "speakers-enable-gpios", &enable_gpio0, 1 }, + { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, { } }; static const struct acpi_gpio_mapping acpi_speakers_enable_gpio1[] = { - { "speakers-enable-gpios", &enable_gpio1, 1 }, + { "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, }; static const struct acpi_gpio_mapping acpi_enable_both_gpios[] = { - { "speakers-enable-gpios", &enable_gpio0, 1 }, - { "headphone-enable-gpios", &enable_gpio1, 1 }, + { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, + { "headphone-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, { } }; static const struct acpi_gpio_mapping acpi_enable_both_gpios_rev_order[] = { - { "speakers-enable-gpios", &enable_gpio1, 1 }, - { "headphone-enable-gpios", &enable_gpio0, 1 }, + { "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, + { "headphone-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, { } }; -static const struct acpi_gpio_mapping *gpio_mapping = acpi_speakers_enable_gpio0; - static void log_quirks(struct device *dev) { dev_info(dev, "quirk mask %#lx\n", quirk); @@ -245,10 +261,10 @@ static int sof_es8316_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret; - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &priv->jack, sof_es8316_jack_pins, - ARRAY_SIZE(sof_es8316_jack_pins)); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &priv->jack, sof_es8316_jack_pins, + ARRAY_SIZE(sof_es8316_jack_pins)); if (ret) { dev_err(card->dev, "jack creation failed %d\n", ret); return ret; @@ -272,15 +288,6 @@ static int sof_es8336_quirk_cb(const struct dmi_system_id *id) { quirk = (unsigned long)id->driver_data; - if (quirk & SOF_ES8336_HEADPHONE_GPIO) { - if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) - gpio_mapping = acpi_enable_both_gpios; - else - gpio_mapping = acpi_enable_both_gpios_rev_order; - } else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) { - gpio_mapping = acpi_speakers_enable_gpio1; - } - return 1; } @@ -356,6 +363,13 @@ static struct snd_soc_dai_link_component dmic_component[] = { } }; +static struct snd_soc_dai_link_component dummy_component[] = { + { + .name = "snd-soc-dummy", + .dai_name = "snd-soc-dummy-dai", + } +}; + static int sof_es8336_late_probe(struct snd_soc_card *card) { struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); @@ -507,6 +521,37 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, id++; } + /* HDMI-In SSP */ + if (quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) { + int num_of_hdmi_ssp = (quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + + for (i = 1; i <= num_of_hdmi_ssp; i++) { + int port = (i == 1 ? (quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >> + SOF_HDMI_CAPTURE_1_SSP_SHIFT : + (quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >> + SOF_HDMI_CAPTURE_2_SSP_SHIFT); + + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", port); + if (!links[id].cpus->dai_name) + return NULL; + links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); + if (!links[id].name) + return NULL; + links[id].id = id + hdmi_id_offset; + links[id].codecs = dummy_component; + links[id].num_codecs = ARRAY_SIZE(dummy_component); + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + links[id].num_cpus = 1; + id++; + } + } + return links; devm_err: @@ -529,6 +574,7 @@ static int sof_es8336_probe(struct platform_device *pdev) struct acpi_device *adev; struct snd_soc_dai_link *dai_links; struct device *codec_dev; + const struct acpi_gpio_mapping *gpio_mapping; unsigned int cnt = 0; int dmic_be_num = 0; int hdmi_num = 3; @@ -541,29 +587,34 @@ static int sof_es8336_probe(struct platform_device *pdev) card = &sof_es8336_card; card->dev = dev; + if (pdev->id_entry && pdev->id_entry->driver_data) + quirk = (unsigned long)pdev->id_entry->driver_data; + /* check GPIO DMI quirks */ dmi_check_system(sof_es8336_quirk_table); - if (!mach->mach_params.i2s_link_mask) { - dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n"); - } else { - /* - * Set configuration based on platform NHLT. - * In this machine driver, we can only support one SSP for the - * ES8336 link, the else-if below are intentional. - * In some cases multiple SSPs can be reported by NHLT, starting MSB-first - * seems to pick the right connection. - */ - unsigned long ssp = 0; - - if (mach->mach_params.i2s_link_mask & BIT(2)) - ssp = SOF_ES8336_SSP_CODEC(2); - else if (mach->mach_params.i2s_link_mask & BIT(1)) - ssp = SOF_ES8336_SSP_CODEC(1); - else if (mach->mach_params.i2s_link_mask & BIT(0)) - ssp = SOF_ES8336_SSP_CODEC(0); - - quirk |= ssp; + /* Use NHLT configuration only for Non-HDMI capture use case. + * Because more than one SSP will be enabled for HDMI capture hence wrong codec + * SSP will be set. + */ + if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER) { + if (!mach->mach_params.i2s_link_mask) { + dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n"); + } else { + /* + * Set configuration based on platform NHLT. + * In this machine driver, we can only support one SSP for the + * ES8336 link. + * In some cases multiple SSPs can be reported by NHLT, starting MSB-first + * seems to pick the right connection. + */ + unsigned long ssp; + + /* fls returns 1-based results, SSPs indices are 0-based */ + ssp = fls(mach->mach_params.i2s_link_mask) - 1; + + quirk |= ssp; + } } if (mach->mach_params.dmic_num) @@ -579,7 +630,13 @@ static int sof_es8336_probe(struct platform_device *pdev) if (quirk & SOF_ES8336_ENABLE_DMIC) dmic_be_num = 2; - sof_es8336_card.num_links += dmic_be_num + hdmi_num; + /* compute number of dai links */ + sof_es8336_card.num_links = 1 + dmic_be_num + hdmi_num; + + if (quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) + sof_es8336_card.num_links += (quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + dai_links = sof_card_dai_links_create(dev, SOF_ES8336_SSP_CODEC(quirk), dmic_be_num, hdmi_num); @@ -635,6 +692,17 @@ static int sof_es8336_probe(struct platform_device *pdev) } /* get speaker enable GPIO */ + if (quirk & SOF_ES8336_HEADPHONE_GPIO) { + if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) + gpio_mapping = acpi_enable_both_gpios; + else + gpio_mapping = acpi_enable_both_gpios_rev_order; + } else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) { + gpio_mapping = acpi_speakers_enable_gpio1; + } else { + gpio_mapping = acpi_speakers_enable_gpio0; + } + ret = devm_acpi_dev_add_driver_gpios(codec_dev, gpio_mapping); if (ret) dev_warn(codec_dev, "unable to add GPIO mapping table\n"); @@ -690,6 +758,24 @@ static int sof_es8336_remove(struct platform_device *pdev) return 0; } +static const struct platform_device_id board_ids[] = { + { + .name = "sof-essx8336", /* default quirk == 0 */ + }, + { + .name = "adl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, + { } +}; +MODULE_DEVICE_TABLE(platform, board_ids); + static struct platform_driver sof_es8336_driver = { .driver = { .name = "sof-essx8336", @@ -697,10 +783,10 @@ static struct platform_driver sof_es8336_driver = { }, .probe = sof_es8336_probe, .remove = sof_es8336_remove, + .id_table = board_ids, }; module_platform_driver(sof_es8336_driver); MODULE_DESCRIPTION("ASoC Intel(R) SOF + ES8336 Machine driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:sof-essx8336"); MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 33de043b66..8d7e5ba9e5 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -81,6 +81,17 @@ static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); @@ -93,11 +104,13 @@ static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sof_headset, NULL, 0); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sof_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -177,11 +190,6 @@ static int sof_card_late_probe(struct snd_soc_card *card) struct sof_hdmi_pcm *pcm; int err; - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head); - if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { /* Disable Left and Right Spk pin after boot */ snd_soc_dapm_disable_pin(dapm, "Left Spk"); @@ -191,6 +199,11 @@ static int sof_card_late_probe(struct snd_soc_card *card) return err; } + if (list_empty(&ctx->hdmi_pcm_list)) + return -EINVAL; + + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head); + return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component); } diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c index 6815204e58..d4c67d5340 100644 --- a/sound/soc/intel/boards/sof_pcm512x.c +++ b/sound/soc/intel/boards/sof_pcm512x.c @@ -419,7 +419,7 @@ static int sof_audio_probe(struct platform_device *pdev) static int sof_pcm512x_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - struct snd_soc_component *component = NULL; + struct snd_soc_component *component; for_each_card_components(card, component) { if (!strcmp(component->name, pcm512x_component[0].name)) { diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c index a2bcbeee02..b9643ca2e2 100644 --- a/sound/soc/intel/boards/sof_realtek_common.c +++ b/sound/soc/intel/boards/sof_realtek_common.c @@ -459,5 +459,44 @@ void sof_rt1308_dai_link(struct snd_soc_dai_link *link) } EXPORT_SYMBOL_NS(sof_rt1308_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); +/* + * 2-amp Configuration for RT1019 + */ + +static const struct snd_soc_dapm_route rt1019p_dapm_routes[] = { + /* speaker */ + { "Left Spk", NULL, "Speaker" }, + { "Right Spk", NULL, "Speaker" }, +}; + +static struct snd_soc_dai_link_component rt1019p_components[] = { + { + .name = RT1019P_DEV0_NAME, + .dai_name = RT1019P_CODEC_DAI, + }, +}; + +static int rt1019p_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes, + ARRAY_SIZE(rt1019p_dapm_routes)); + if (ret) { + dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); + return ret; + } + return ret; +} + +void sof_rt1019p_dai_link(struct snd_soc_dai_link *link) +{ + link->codecs = rt1019p_components; + link->num_codecs = ARRAY_SIZE(rt1019p_components); + link->init = rt1019p_init; +} +EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); + MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h index e0a5518e8d..7784434210 100644 --- a/sound/soc/intel/boards/sof_realtek_common.h +++ b/sound/soc/intel/boards/sof_realtek_common.h @@ -39,4 +39,9 @@ void sof_rt1015_codec_conf(struct snd_soc_card *card); #define RT1308_DEV0_NAME "i2c-10EC1308:00" void sof_rt1308_dai_link(struct snd_soc_dai_link *link); +#define RT1019P_CODEC_DAI "HiFi" +#define RT1019P_DEV0_NAME "RTL1019:00" + +void sof_rt1019p_dai_link(struct snd_soc_dai_link *link); + #endif /* __SOF_REALTEK_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 7126fcb63d..0459653122 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -60,6 +60,7 @@ #define SOF_RT5682S_HEADPHONE_CODEC_PRESENT BIT(23) #define SOF_MAX98390_SPEAKER_AMP_PRESENT BIT(24) #define SOF_MAX98390_TWEETER_SPEAKER_PRESENT BIT(25) +#define SOF_RT1019_SPEAKER_AMP_PRESENT BIT(26) /* Default: MCLK on, MCLK 19.2M, SSP0 */ @@ -68,11 +69,10 @@ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | static int is_legacy_cpu; -static struct snd_soc_jack sof_hdmi[3]; - struct sof_hdmi_pcm { struct list_head head; struct snd_soc_dai *codec_dai; + struct snd_soc_jack hdmi_jack; int device; }; @@ -247,6 +247,17 @@ static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static struct snd_soc_jack_pin jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); @@ -294,11 +305,13 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sof_headset, NULL, 0); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sof_headset, + jack_pins, + ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -433,7 +446,15 @@ static int sof_card_late_probe(struct snd_soc_card *card) char jack_name[NAME_SIZE]; struct sof_hdmi_pcm *pcm; int err; - int i = 0; + + if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { + /* Disable Left and Right Spk pin after boot */ + snd_soc_dapm_disable_pin(dapm, "Left Spk"); + snd_soc_dapm_disable_pin(dapm, "Right Spk"); + err = snd_soc_dapm_sync(dapm); + if (err < 0) + return err; + } /* HDMI is not supported by SOF on Baytrail/CherryTrail */ if (is_legacy_cpu || !ctx->idisp_codec) @@ -454,25 +475,13 @@ static int sof_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &sof_hdmi[i], - NULL, 0); + SND_JACK_AVOUT, &pcm->hdmi_jack); if (err) return err; err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &sof_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { - /* Disable Left and Right Spk pin after boot */ - snd_soc_dapm_disable_pin(dapm, "Left Spk"); - snd_soc_dapm_disable_pin(dapm, "Right Spk"); - err = snd_soc_dapm_sync(dapm); + &pcm->hdmi_jack); if (err < 0) return err; } @@ -734,6 +743,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, SOF_RT1015_SPEAKER_AMP_100FS) ? 100 : 64); } else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) { sof_rt1015p_dai_link(&links[id]); + } else if (sof_rt5682_quirk & SOF_RT1019_SPEAKER_AMP_PRESENT) { + sof_rt1019p_dai_link(&links[id]); } else if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { links[id].codecs = max_98373_components; @@ -1071,6 +1082,24 @@ static const struct platform_device_id board_ids[] = { SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, + { + .name = "adl_rt1019_rt5682s", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_RT5682S_HEADPHONE_CODEC_PRESENT | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT1019_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1) | + SOF_RT5682_NUM_HDMIDEV(4)), + }, + { + .name = "mtl_mx98357_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1) | + SOF_RT5682_NUM_HDMIDEV(4)), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 1f00679b42..a49bfaab6b 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -246,6 +246,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2 | + SOF_SDW_FOUR_SPK), + }, { .callback = sof_sdw_quirk_cb, .matches = { @@ -315,6 +325,23 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { RT711_JD2 | SOF_SDW_FOUR_SPK), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + /* MeteorLake devices */ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"), + }, + .driver_data = (void *)(RT711_JD1 | SOF_SDW_TGL_HDMI), + }, {} }; @@ -1127,10 +1154,14 @@ static int sof_card_dai_links_create(struct device *dev, for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) codec_info_list[i].amp_num = 0; - if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) - hdmi_num = SOF_TGL_HDMI_COUNT; - else - hdmi_num = SOF_PRE_TGL_HDMI_COUNT; + if (mach_params->codec_mask & IDISP_CODEC_MASK) { + ctx->idisp_codec = true; + + if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) + hdmi_num = SOF_TGL_HDMI_COUNT; + else + hdmi_num = SOF_PRE_TGL_HDMI_COUNT; + } ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); /* @@ -1150,9 +1181,6 @@ static int sof_card_dai_links_create(struct device *dev, return ret; } - if (mach_params->codec_mask & IDISP_CODEC_MASK) - ctx->idisp_codec = true; - /* enable dmic01 & dmic16k */ dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0; comp_num += dmic_num; @@ -1375,7 +1403,9 @@ static int sof_card_dai_links_create(struct device *dev, static int sof_sdw_card_late_probe(struct snd_soc_card *card) { - int i, ret; + struct mc_private *ctx = snd_soc_card_get_drvdata(card); + int ret = 0; + int i; for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { if (!codec_info_list[i].late_probe) @@ -1386,7 +1416,10 @@ static int sof_sdw_card_late_probe(struct snd_soc_card *card) return ret; } - return sof_sdw_hdmi_card_late_probe(card); + if (ctx->idisp_codec) + ret = sof_sdw_hdmi_card_late_probe(card); + + return ret; } /* SoC card */ @@ -1398,6 +1431,33 @@ static struct snd_soc_card card_sof_sdw = { .late_probe = sof_sdw_card_late_probe, }; +static void mc_dailink_exit_loop(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link; + int ret; + int i, j; + + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { + if (!codec_info_list[i].exit) + continue; + /* + * We don't need to call .exit function if there is no matched + * dai link found. + */ + for_each_card_prelinks(card, j, link) { + if (!strcmp(link->codecs[0].dai_name, + codec_info_list[i].dai_name)) { + ret = codec_info_list[i].exit(card, link); + if (ret) + dev_warn(card->dev, + "codec exit failed %d\n", + ret); + break; + } + } + } +} + static int mc_probe(struct platform_device *pdev) { struct snd_soc_card *card = &card_sof_sdw; @@ -1406,7 +1466,7 @@ static int mc_probe(struct platform_device *pdev) int amp_num = 0, i; int ret; - dev_dbg(&pdev->dev, "Entry %s\n", __func__); + dev_dbg(&pdev->dev, "Entry\n"); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -1462,6 +1522,7 @@ static int mc_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); + mc_dailink_exit_loop(card); return ret; } @@ -1473,29 +1534,8 @@ static int mc_probe(struct platform_device *pdev) static int mc_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - struct snd_soc_dai_link *link; - int ret; - int i, j; - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { - if (!codec_info_list[i].exit) - continue; - /* - * We don't need to call .exit function if there is no matched - * dai link found. - */ - for_each_card_prelinks(card, j, link) { - if (!strcmp(link->codecs[0].dai_name, - codec_info_list[i].dai_name)) { - ret = codec_info_list[i].exit(card, link); - if (ret) - dev_warn(&pdev->dev, - "codec exit failed %d\n", - ret); - break; - } - } - } + mc_dailink_exit_loop(card); return 0; } diff --git a/sound/soc/intel/boards/sof_sdw_rt5682.c b/sound/soc/intel/boards/sof_sdw_rt5682.c index ea55479609..3a9be82115 100644 --- a/sound/soc/intel/boards/sof_sdw_rt5682.c +++ b/sound/soc/intel/boards/sof_sdw_rt5682.c @@ -82,13 +82,13 @@ static int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - rt5682_jack_pins, - ARRAY_SIZE(rt5682_jack_pins)); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sdw_headset, + rt5682_jack_pins, + ARRAY_SIZE(rt5682_jack_pins)); if (ret) { dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", ret); diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/intel/boards/sof_sdw_rt700.c index bb9584c8f8..c93b1f5b94 100644 --- a/sound/soc/intel/boards/sof_sdw_rt700.c +++ b/sound/soc/intel/boards/sof_sdw_rt700.c @@ -82,13 +82,13 @@ static int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - rt700_jack_pins, - ARRAY_SIZE(rt700_jack_pins)); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sdw_headset, + rt700_jack_pins, + ARRAY_SIZE(rt700_jack_pins)); if (ret) { dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", ret); diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c index c38b70c9fa..8291967f23 100644 --- a/sound/soc/intel/boards/sof_sdw_rt711.c +++ b/sound/soc/intel/boards/sof_sdw_rt711.c @@ -106,13 +106,13 @@ static int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - rt711_jack_pins, - ARRAY_SIZE(rt711_jack_pins)); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sdw_headset, + rt711_jack_pins, + ARRAY_SIZE(rt711_jack_pins)); if (ret) { dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", ret); @@ -139,6 +139,9 @@ int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_l { struct mc_private *ctx = snd_soc_card_get_drvdata(card); + if (!ctx->headset_codec_dev) + return 0; + device_remove_software_node(ctx->headset_codec_dev); put_device(ctx->headset_codec_dev); diff --git a/sound/soc/intel/boards/sof_sdw_rt711_sdca.c b/sound/soc/intel/boards/sof_sdw_rt711_sdca.c index 4215ddc364..7f16304d02 100644 --- a/sound/soc/intel/boards/sof_sdw_rt711_sdca.c +++ b/sound/soc/intel/boards/sof_sdw_rt711_sdca.c @@ -107,13 +107,13 @@ static int rt711_sdca_rtd_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - rt711_sdca_jack_pins, - ARRAY_SIZE(rt711_sdca_jack_pins)); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sdw_headset, + rt711_sdca_jack_pins, + ARRAY_SIZE(rt711_sdca_jack_pins)); if (ret) { dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", ret); @@ -140,6 +140,9 @@ int sof_sdw_rt711_sdca_exit(struct snd_soc_card *card, struct snd_soc_dai_link * { struct mc_private *ctx = snd_soc_card_get_drvdata(card); + if (!ctx->headset_codec_dev) + return 0; + device_remove_software_node(ctx->headset_codec_dev); put_device(ctx->headset_codec_dev); diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 88530e9de5..4a762e002a 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -78,6 +79,16 @@ struct sof_card_private { bool idisp_codec; }; +static const struct dmi_system_id chromebook_platforms[] = { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {}, +}; + static const struct snd_soc_dapm_widget sof_ssp_amp_dapm_widgets[] = { SND_SOC_DAPM_MIC("SoC DMIC", NULL), }; @@ -94,7 +105,7 @@ static int sof_card_late_probe(struct snd_soc_card *card) char jack_name[NAME_SIZE]; struct sof_hdmi_pcm *pcm; int err; - int i = 0; + int i; if (!(sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT)) return 0; @@ -113,13 +124,13 @@ static int sof_card_late_probe(struct snd_soc_card *card) return hda_dsp_hdmi_build_controls(card, component); } + i = 0; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &pcm->sof_hdmi, - NULL, 0); + SND_JACK_AVOUT, &pcm->sof_hdmi); if (err) return err; @@ -247,6 +258,9 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, sof_rt1308_dai_link(&links[id]); } else if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) { cs35l41_set_dai_link(&links[id]); + + /* feedback from amplifier */ + links[id].dpcm_capture = 1; } links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); @@ -371,7 +385,7 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) struct snd_soc_dai_link *dai_links; struct snd_soc_acpi_mach *mach; struct sof_card_private *ctx; - int dmic_be_num, hdmi_num = 0; + int dmic_be_num = 0, hdmi_num = 0; int ret, ssp_codec; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); @@ -383,7 +397,8 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) mach = pdev->dev.platform_data; - dmic_be_num = mach->mach_params.dmic_num; + if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0) + dmic_be_num = 2; ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK; diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c index 85a34e3731..d48a71d2cf 100644 --- a/sound/soc/intel/catpt/device.c +++ b/sound/soc/intel/catpt/device.c @@ -254,14 +254,11 @@ static int catpt_acpi_probe(struct platform_device *pdev) return -ENODEV; } - spec = device_get_match_data(dev); - if (!spec) - return -ENODEV; - cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL); if (!cdev) return -ENOMEM; + spec = (const struct catpt_spec *)id->driver_data; catpt_dev_init(cdev, dev, spec); /* map DSP bar address */ diff --git a/sound/soc/intel/catpt/messages.h b/sound/soc/intel/catpt/messages.h index 978a20b3f4..c17e948d9f 100644 --- a/sound/soc/intel/catpt/messages.h +++ b/sound/soc/intel/catpt/messages.h @@ -219,11 +219,9 @@ int catpt_ipc_free_stream(struct catpt_dev *cdev, u8 stream_hw_id); enum catpt_ssp_iface { CATPT_SSP_IFACE_0 = 0, CATPT_SSP_IFACE_1 = 1, - CATPT_SSP_IFACE_LAST = CATPT_SSP_IFACE_1, + CATPT_SSP_COUNT, }; -#define CATPT_SSP_COUNT (CATPT_SSP_IFACE_LAST + 1) - enum catpt_mclk_frequency { CATPT_MCLK_OFF = 0, CATPT_MCLK_FREQ_6_MHZ = 1, diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index a26000cd5c..30ca5416c9 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -667,7 +667,9 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm, if (!memcmp(&cdev->devfmt[devfmt.iface], &devfmt, sizeof(devfmt))) return 0; - pm_runtime_get_sync(cdev->dev); + ret = pm_runtime_resume_and_get(cdev->dev); + if (ret < 0 && ret != -EACCES) + return ret; ret = catpt_ipc_set_device_format(cdev, &devfmt); @@ -853,9 +855,12 @@ static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol, snd_soc_kcontrol_component(kcontrol); struct catpt_dev *cdev = dev_get_drvdata(component->dev); u32 dspvol; + int ret; int i; - pm_runtime_get_sync(cdev->dev); + ret = pm_runtime_resume_and_get(cdev->dev); + if (ret < 0 && ret != -EACCES) + return ret; for (i = 0; i < CATPT_CHANNELS_MAX; i++) { dspvol = catpt_mixer_volume(cdev, &cdev->mixer, i); @@ -876,7 +881,9 @@ static int catpt_mixer_volume_put(struct snd_kcontrol *kcontrol, struct catpt_dev *cdev = dev_get_drvdata(component->dev); int ret; - pm_runtime_get_sync(cdev->dev); + ret = pm_runtime_resume_and_get(cdev->dev); + if (ret < 0 && ret != -EACCES) + return ret; ret = catpt_set_dspvol(cdev, cdev->mixer.mixer_hw_id, ucontrol->value.integer.value); @@ -897,6 +904,7 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol, struct catpt_dev *cdev = dev_get_drvdata(component->dev); long *ctlvol = (long *)kcontrol->private_value; u32 dspvol; + int ret; int i; stream = catpt_stream_find(cdev, pin_id); @@ -906,7 +914,9 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol, return 0; } - pm_runtime_get_sync(cdev->dev); + ret = pm_runtime_resume_and_get(cdev->dev); + if (ret < 0 && ret != -EACCES) + return ret; for (i = 0; i < CATPT_CHANNELS_MAX; i++) { dspvol = catpt_stream_volume(cdev, stream, i); @@ -937,7 +947,9 @@ static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol, return 0; } - pm_runtime_get_sync(cdev->dev); + ret = pm_runtime_resume_and_get(cdev->dev); + if (ret < 0 && ret != -EACCES) + return ret; ret = catpt_set_dspvol(cdev, stream->info.stream_hw_id, ucontrol->value.integer.value); @@ -1013,7 +1025,9 @@ static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol, return 0; } - pm_runtime_get_sync(cdev->dev); + ret = pm_runtime_resume_and_get(cdev->dev); + if (ret < 0 && ret != -EACCES) + return ret; ret = catpt_ipc_mute_loopback(cdev, stream->info.stream_hw_id, mute); diff --git a/sound/soc/intel/catpt/sysfs.c b/sound/soc/intel/catpt/sysfs.c index 9579e233a1..1bdbcc04dc 100644 --- a/sound/soc/intel/catpt/sysfs.c +++ b/sound/soc/intel/catpt/sysfs.c @@ -15,7 +15,9 @@ static ssize_t fw_version_show(struct device *dev, struct catpt_fw_version version; int ret; - pm_runtime_get_sync(cdev->dev); + ret = pm_runtime_resume_and_get(cdev->dev); + if (ret < 0 && ret != -EACCES) + return ret; ret = catpt_ipc_get_fw_version(cdev, &version); diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index fef0b2d1de..8ca8f872ec 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -9,6 +9,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \ + soc-acpi-intel-mtl-match.o \ soc-acpi-intel-hda-match.o \ soc-acpi-intel-sdw-mockup-match.o diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index 8bfe7070b8..9990d5502d 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -8,6 +8,11 @@ #include #include +static const struct snd_soc_acpi_codecs essx_83x6 = { + .num_codecs = 3, + .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + static const struct snd_soc_acpi_endpoint single_endpoint = { .num = 0, .aggregated = 0, @@ -137,6 +142,15 @@ static const struct snd_soc_acpi_adr_device rt1316_2_single_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1316_3_single_adr[] = { + { + .adr = 0x000330025D131601ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1316-1" + } +}; + static const struct snd_soc_acpi_adr_device rt714_0_adr[] = { { .adr = 0x000030025D071401ull, @@ -326,6 +340,20 @@ static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link2_rt714_link0[] = { {} }; +static const struct snd_soc_acpi_link_adr adl_sdw_rt711_link0_rt1316_link3[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1316_3_single_adr), + .adr_d = rt1316_3_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_adr_device mx8373_2_adr[] = { { .adr = 0x000223019F837300ull, @@ -412,6 +440,11 @@ static const struct snd_soc_acpi_codecs adl_max98390_amp = { .codecs = {"MX98390"} }; +static const struct snd_soc_acpi_codecs adl_lt6911_hdmi = { + .num_codecs = 1, + .codecs = {"INTC10B0"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { { .comp_ids = &adl_rt5682_rt5682s_hp, @@ -453,7 +486,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { .drv_name = "adl_mx98360a_nau8825", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &adl_max98360a_amp, - .sof_tplg_filename = "sof-adl-mx98360a-nau8825.tplg", + .sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg", + }, + { + .id = "RTL5682", + .drv_name = "adl_rt1019_rt5682s", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_rt1019p_amp, + .sof_tplg_filename = "sof-adl-rt1019-rt5682.tplg", }, { .id = "10508825", @@ -472,12 +512,34 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { .drv_name = "adl_rt5682", .sof_tplg_filename = "sof-adl-rt5682.tplg", }, + { + .id = "10134242", + .drv_name = "adl_mx98360a_cs4242", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_max98360a_amp, + .sof_tplg_filename = "sof-adl-max98360a-cs42l42.tplg", + }, /* place amp-only boards in the end of table */ { .id = "CSC3541", .drv_name = "adl_cs35l41", .sof_tplg_filename = "sof-adl-cs35l41.tplg", }, + { + .comp_ids = &essx_83x6, + .drv_name = "adl_es83x6_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_lt6911_hdmi, + .sof_tplg_filename = "sof-adl-es83x6-ssp1-hdmi-ssp02.tplg", + }, + { + .comp_ids = &essx_83x6, + .drv_name = "sof-essx8336", + .sof_tplg_filename = "sof-adl-es83x6", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER | + SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | + SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines); @@ -532,6 +594,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-adl-rt1316-l2-mono-rt714-l0.tplg", }, + { + .link_mask = 0x9, /* 2 active links required */ + .links = adl_sdw_rt711_link0_rt1316_link3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-adl-rt711-l0-rt1316-l3.tplg", + }, { .link_mask = 0x1, /* link0 required */ .links = adl_rvp, diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c index 0441df97b2..cbcb649604 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c @@ -12,7 +12,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = { { .id = "INT33CA", - .drv_name = "haswell-audio", + .drv_name = "hsw_rt5640", .fw_filename = "intel/IntcSST1.bin", .sof_tplg_filename = "sof-hsw.tplg", }, @@ -23,7 +23,7 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_haswell_machines); struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { { .id = "INT343A", - .drv_name = "broadwell-audio", + .drv_name = "bdw_rt286", .fw_filename = "intel/IntcSST2.bin", .sof_tplg_filename = "sof-bdw-rt286.tplg", }, @@ -41,7 +41,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { }, { .id = "INT33CA", - .drv_name = "haswell-audio", + .drv_name = "hsw_rt5640", .fw_filename = "intel/IntcSST2.bin", .sof_tplg_filename = "sof-bdw-rt5640.tplg", }, diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index a6fb74ba1c..b4893365d0 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -388,15 +388,17 @@ static snd_pcm_uframes_t kmb_pcm_pointer(struct snd_soc_component *component, } static const struct snd_soc_component_driver kmb_component = { - .name = "kmb", - .pcm_construct = kmb_platform_pcm_new, - .open = kmb_pcm_open, - .trigger = kmb_pcm_trigger, - .pointer = kmb_pcm_pointer, + .name = "kmb", + .pcm_construct = kmb_platform_pcm_new, + .open = kmb_pcm_open, + .trigger = kmb_pcm_trigger, + .pointer = kmb_pcm_pointer, + .legacy_dai_naming = 1, }; static const struct snd_soc_component_driver kmb_component_dma = { - .name = "kmb", + .name = "kmb", + .legacy_dai_naming = 1, }; static int kmb_probe(struct snd_soc_dai *cpu_dai) @@ -497,11 +499,11 @@ static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) int ret; switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: kmb_i2s->clock_provider = false; ret = 0; break; - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: writel(CLOCK_PROVIDER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0); ret = clk_prepare_enable(kmb_i2s->clk_i2s); diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 2439a574ac..deb7b82032 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -99,7 +99,6 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, struct nhlt_fmt_cfg *fmt_cfg; struct wav_fmt_ext *wav_fmt; unsigned long rate; - bool present = false; int rate_index = 0; u16 channels, bps; u8 clk_src; @@ -112,9 +111,12 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, if (fmt->fmt_count == 0) return; + fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; for (i = 0; i < fmt->fmt_count; i++) { - fmt_cfg = &fmt->fmt_config[i]; - wav_fmt = &fmt_cfg->fmt_ext; + struct nhlt_fmt_cfg *saved_fmt_cfg = fmt_cfg; + bool present = false; + + wav_fmt = &saved_fmt_cfg->fmt_ext; channels = wav_fmt->fmt.channels; bps = wav_fmt->fmt.bits_per_sample; @@ -132,12 +134,18 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, * derive the rate. */ for (j = i; j < fmt->fmt_count; j++) { - fmt_cfg = &fmt->fmt_config[j]; - wav_fmt = &fmt_cfg->fmt_ext; + struct nhlt_fmt_cfg *tmp_fmt_cfg = fmt_cfg; + + wav_fmt = &tmp_fmt_cfg->fmt_ext; if ((fs == wav_fmt->fmt.samples_per_sec) && - (bps == wav_fmt->fmt.bits_per_sample)) + (bps == wav_fmt->fmt.bits_per_sample)) { channels = max_t(u16, channels, wav_fmt->fmt.channels); + saved_fmt_cfg = tmp_fmt_cfg; + } + /* Move to the next nhlt_fmt_cfg */ + tmp_fmt_cfg = (struct nhlt_fmt_cfg *)(tmp_fmt_cfg->config.caps + + tmp_fmt_cfg->config.size); } rate = channels * bps * fs; @@ -153,8 +161,11 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, /* Fill rate and parent for sclk/sclkfs */ if (!present) { + struct nhlt_fmt_cfg *first_fmt_cfg; + + first_fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; i2s_config_ext = (struct skl_i2s_config_blob_ext *) - fmt->fmt_config[0].config.caps; + first_fmt_cfg->config.caps; /* MCLK Divider Source Select */ if (is_legacy_blob(i2s_config_ext->hdr.sig)) { @@ -168,6 +179,9 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, parent = skl_get_parent_clk(clk_src); + /* Move to the next nhlt_fmt_cfg */ + fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps + + fmt_cfg->config.size); /* * Do not copy the config data if there is no parent * clock available for this clock source select @@ -176,9 +190,9 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, continue; sclk[id].rate_cfg[rate_index].rate = rate; - sclk[id].rate_cfg[rate_index].config = fmt_cfg; + sclk[id].rate_cfg[rate_index].config = saved_fmt_cfg; sclkfs[id].rate_cfg[rate_index].rate = rate; - sclkfs[id].rate_cfg[rate_index].config = fmt_cfg; + sclkfs[id].rate_cfg[rate_index].config = saved_fmt_cfg; sclk[id].parent_name = parent->name; sclkfs[id].parent_name = parent->name; @@ -192,13 +206,13 @@ static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk, { struct skl_i2s_config_blob_ext *i2s_config_ext; struct skl_i2s_config_blob_legacy *i2s_config; - struct nhlt_specific_cfg *fmt_cfg; + struct nhlt_fmt_cfg *fmt_cfg; struct skl_clk_parent_src *parent; u32 clkdiv, div_ratio; u8 clk_src; - fmt_cfg = &fmt->fmt_config[0].config; - i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->caps; + fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; + i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->config.caps; /* MCLK Divider Source Select and divider */ if (is_legacy_blob(i2s_config_ext->hdr.sig)) { @@ -227,7 +241,7 @@ static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk, return; mclk[id].rate_cfg[0].rate = parent->rate/div_ratio; - mclk[id].rate_cfg[0].config = &fmt->fmt_config[0]; + mclk[id].rate_cfg[0].config = fmt_cfg; mclk[id].parent_name = parent->name; } diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 55f310e91b..9d72ebd812 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1380,7 +1380,10 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) const struct skl_dsp_ops *ops; int ret; - pm_runtime_get_sync(component->dev); + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + if (bus->ppcap) { skl->component = component; diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 9bdf020a2b..e06eac592d 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -2950,9 +2950,6 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, block_size = ret; off += array->size; - array = (struct snd_soc_tplg_vendor_array *) - (tplg_w->priv.data + off); - data = (tplg_w->priv.data + off); if (block_type == SKL_TYPE_TUPLE) { @@ -3599,9 +3596,6 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, block_size = ret; off += array->size; - array = (struct snd_soc_tplg_vendor_array *) - (manifest->priv.data + off); - data = (manifest->priv.data + off); if (block_type == SKL_TYPE_TUPLE) { diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig index 29144720cb..e72f826062 100644 --- a/sound/soc/jz4740/Kconfig +++ b/sound/soc/jz4740/Kconfig @@ -2,7 +2,7 @@ config SND_JZ4740_SOC_I2S tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC" depends on MIPS || COMPILE_TEST - depends on OF && HAS_IOMEM + depends on HAS_IOMEM select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740 diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 7ad5d9a924..c4c1e89b47 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -5,10 +5,9 @@ #include #include -#include -#include #include #include +#include #include #include @@ -94,9 +93,7 @@ struct i2s_soc_info { }; struct jz4740_i2s { - struct resource *mem; void __iomem *base; - dma_addr_t phys_base; struct clk *clk_aic; struct clk *clk_i2s; @@ -206,18 +203,18 @@ static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: conf |= JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER; format |= JZ_AIC_I2S_FMT_ENABLE_SYS_CLK; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FP: conf |= JZ_AIC_CONF_SYNC_CLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_BP_FC: conf |= JZ_AIC_CONF_BIT_CLK_MASTER; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: break; default: return -EINVAL; @@ -371,21 +368,6 @@ static int jz4740_i2s_resume(struct snd_soc_component *component) return 0; } -static void jz4740_i2s_init_pcm_config(struct jz4740_i2s *i2s) -{ - struct snd_dmaengine_dai_dma_data *dma_data; - - /* Playback */ - dma_data = &i2s->playback_dma_data; - dma_data->maxburst = 16; - dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO; - - /* Capture */ - dma_data = &i2s->capture_dma_data; - dma_data->maxburst = 16; - dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO; -} - static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) { struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -396,7 +378,6 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) if (ret) return ret; - jz4740_i2s_init_pcm_config(i2s); snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, &i2s->capture_dma_data); @@ -498,9 +479,10 @@ static const struct i2s_soc_info jz4780_i2s_soc_info = { }; static const struct snd_soc_component_driver jz4740_i2s_component = { - .name = "jz4740-i2s", - .suspend = jz4740_i2s_suspend, - .resume = jz4740_i2s_resume, + .name = "jz4740-i2s", + .suspend = jz4740_i2s_suspend, + .resume = jz4740_i2s_resume, + .legacy_dai_naming = 1, }; static const struct of_device_id jz4740_of_matches[] = { @@ -529,7 +511,11 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev) if (IS_ERR(i2s->base)) return PTR_ERR(i2s->base); - i2s->phys_base = mem->start; + i2s->playback_dma_data.maxburst = 16; + i2s->playback_dma_data.addr = mem->start + JZ_REG_AIC_FIFO; + + i2s->capture_dma_data.maxburst = 16; + i2s->capture_dma_data.addr = mem->start + JZ_REG_AIC_FIFO; i2s->clk_aic = devm_clk_get(dev, "aic"); if (IS_ERR(i2s->clk_aic)) diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 0d154350f1..363fa4d476 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -152,6 +152,51 @@ config SND_SOC_MT8183_DA7219_MAX98357A Select Y if you have such device. If unsure select "N". +config SND_SOC_MT8186 + tristate "ASoC support for Mediatek MT8186 chip" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on COMMON_CLK + select SND_SOC_MEDIATEK + select SND_SOC_MT6358 + select MFD_SYSCON if SND_SOC_MT6358 + help + This adds ASoC driver for Mediatek MT8186 boards + that can be used with other codecs. + Select Y if you have such device. + If unsure select "N". + +config SND_SOC_MT8186_MT6366_DA7219_MAX98357 + tristate "ASoC Audio driver for MT8186 with DA7219 MAX98357A codec" + depends on I2C && GPIOLIB + depends on SND_SOC_MT8186 && MTK_PMIC_WRAP + select SND_SOC_MT6358 + select SND_SOC_MAX98357A + select SND_SOC_DA7219 + select SND_SOC_BT_SCO + select SND_SOC_DMIC + select SND_SOC_HDMI_CODEC + help + This adds ASoC driver for Mediatek MT8186 boards + with the MT6366(MT6358) DA7219 MAX98357A codecs. + Select Y if you have such device. + If unsure select "N". + +config SND_SOC_MT8186_MT6366_RT1019_RT5682S + tristate "ASoC Audio driver for MT8186 with RT1019 RT5682S codec" + depends on I2C && GPIOLIB + depends on SND_SOC_MT8186 && MTK_PMIC_WRAP + select SND_SOC_MT6358 + select SND_SOC_RT1015P + select SND_SOC_RT5682S + select SND_SOC_BT_SCO + select SND_SOC_DMIC + select SND_SOC_HDMI_CODEC + help + This adds ASoC driver for Mediatek MT8186 boards + with the MT6366(MT6358) RT1019 RT5682S codecs. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MTK_BTCVSD tristate "ALSA BT SCO CVSD/MSBC Driver" help @@ -179,6 +224,7 @@ config SND_SOC_MT8192_MT6359_RT1015_RT5682 select SND_SOC_RT1015 select SND_SOC_RT1015P select SND_SOC_RT5682_I2C + select SND_SOC_RT5682S select SND_SOC_DMIC help This adds ASoC driver for Mediatek MT8192 boards @@ -198,34 +244,20 @@ config SND_SOC_MT8195 Select Y if you have such device. If unsure select "N". -config SND_SOC_MT8195_MT6359_RT1019_RT5682 - tristate "ASoC Audio driver for MT8195 with MT6359 RT1019 RT5682 codec" - depends on I2C && GPIOLIB - depends on SND_SOC_MT8195 && MTK_PMIC_WRAP - select SND_SOC_MT6359 - select SND_SOC_RT1015P - select SND_SOC_RT5682_I2C - select SND_SOC_RT5682S - select SND_SOC_DMIC - select SND_SOC_HDMI_CODEC - help - This adds ASoC driver for Mediatek MT8195 boards - with the MT6359 RT1019 RT5682 audio codec. - Select Y if you have such device. - If unsure select "N". - -config SND_SOC_MT8195_MT6359_RT1011_RT5682 - tristate "ASoC Audio driver for MT8195 with MT6359 RT1011 RT5682 codec" +config SND_SOC_MT8195_MT6359 + tristate "ASoC Audio driver for MT8195 with MT6359 and I2S codecs" depends on I2C && GPIOLIB depends on SND_SOC_MT8195 && MTK_PMIC_WRAP select SND_SOC_MT6359 select SND_SOC_RT1011 + select SND_SOC_RT1015P select SND_SOC_RT5682_I2C select SND_SOC_RT5682S + select SND_SOC_MAX98390 select SND_SOC_DMIC select SND_SOC_HDMI_CODEC help - This adds ASoC driver for Mediatek MT8195 boards - with the MT6359 RT1011 RT5682 audio codec. + This adds support for ASoC machine driver for Mediatek MT8195 + boards with the MT6359 and other I2S audio codecs. Select Y if you have such device. If unsure select "N". diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 34778ca121..5571c640a2 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/ obj-$(CONFIG_SND_SOC_MT8183) += mt8183/ +obj-$(CONFIG_SND_SOC_MT8186) += mt8186/ obj-$(CONFIG_SND_SOC_MT8192) += mt8192/ obj-$(CONFIG_SND_SOC_MT8195) += mt8195/ diff --git a/sound/soc/mediatek/common/Makefile b/sound/soc/mediatek/common/Makefile index acbe01e9e9..576deb7f8c 100644 --- a/sound/soc/mediatek/common/Makefile +++ b/sound/soc/mediatek/common/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # platform driver -snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o +snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o mtk-dsp-sof-common.o obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o obj-$(CONFIG_SND_SOC_MTK_BTCVSD) += mtk-btcvsd.o diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c index f56de1b918..0cdf2ae362 100644 --- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -129,7 +129,8 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) if (!codec_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_platform_node; } for_each_card_prelinks(card, i, dai_link) { if (dai_link->codecs->name) @@ -140,7 +141,7 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); if (ret) { dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret); - return ret; + goto put_codec_node; } ret = devm_snd_soc_register_card(&pdev->dev, card); @@ -148,6 +149,10 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); +put_codec_node: + of_node_put(codec_node); +put_platform_node: + of_node_put(platform_node); return ret; } diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c index 496f32bcfb..d2f6213a6b 100644 --- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c +++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c @@ -217,7 +217,8 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) if (!codec_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_platform_node; } for_each_card_prelinks(card, i, dai_link) { if (dai_link->codecs->name) @@ -230,6 +231,9 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); + of_node_put(codec_node); +put_platform_node: + of_node_put(platform_node); return ret; } diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index 3149493043..dcaeeeb8aa 100644 --- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c @@ -286,10 +286,8 @@ static int mt8173_afe_dais_set_clks(struct mtk_base_afe *afe, static void mt8173_afe_dais_disable_clks(struct mtk_base_afe *afe, struct clk *m_ck, struct clk *b_ck) { - if (m_ck) - clk_disable_unprepare(m_ck); - if (b_ck) - clk_disable_unprepare(b_ck); + clk_disable_unprepare(m_ck); + clk_disable_unprepare(b_ck); } static int mt8173_afe_i2s_startup(struct snd_pcm_substream *substream, diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index 4cb90da892..c2b0619b61 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -70,10 +70,10 @@ static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; /* enable jack detection */ - ret = snd_soc_card_jack_new(card, "Headphone", SND_JACK_HEADPHONE, - &mt8173_max98090_jack, - mt8173_max98090_jack_pins, - ARRAY_SIZE(mt8173_max98090_jack_pins)); + ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADPHONE, + &mt8173_max98090_jack, + mt8173_max98090_jack_pins, + ARRAY_SIZE(mt8173_max98090_jack_pins)); if (ret) { dev_err(card->dev, "Can't create a new Jack %d\n", ret); return ret; @@ -167,7 +167,8 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) if (!codec_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_platform_node; } for_each_card_prelinks(card, i, dai_link) { if (dai_link->codecs->name) @@ -179,6 +180,8 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, card); of_node_put(codec_node); + +put_platform_node: of_node_put(platform_node); return ret; } diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index b55122b99f..12f40c81b1 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -86,7 +86,7 @@ static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime) SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &mt8173_rt5650_rt5514_jack, NULL, 0); + &mt8173_rt5650_rt5514_jack); if (ret) { dev_err(card->dev, "Can't new Headset Jack %d\n", ret); return ret; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 5716d92990..8794720cea 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -99,7 +99,7 @@ static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime) SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &mt8173_rt5650_rt5676_jack, NULL, 0); + &mt8173_rt5650_rt5676_jack); if (ret) { dev_err(card->dev, "Can't new Headset Jack %d\n", ret); return ret; @@ -256,14 +256,16 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_node; } mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node = of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1); if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_node; } mt8173_rt5650_rt5676_codec_conf[0].dlc.of_node = mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node; @@ -276,13 +278,15 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) if (!mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_node; } card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); +put_node: of_node_put(platform_node); return ret; } diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index fc164f4f95..e05f2b0231 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -132,7 +132,7 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime) SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &mt8173_rt5650_jack, NULL, 0); + &mt8173_rt5650_jack); if (ret) { dev_err(card->dev, "Can't new Headset Jack %d\n", ret); return ret; @@ -149,7 +149,7 @@ static int mt8173_rt5650_hdmi_init(struct snd_soc_pcm_runtime *rtd) int ret; ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, - &mt8173_rt5650_hdmi_jack, NULL, 0); + &mt8173_rt5650_hdmi_jack); if (ret) return ret; @@ -280,7 +280,8 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) if (!mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_platform_node; } mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node = mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node; @@ -293,7 +294,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s codec_capture_dai name fail %d\n", __func__, ret); - return ret; + goto put_platform_node; } mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[1].dai_name = codec_capture_dai; @@ -315,12 +316,14 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) if (!mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codecs->of_node) { dev_err(&pdev->dev, "Property 'audio-codec' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto put_platform_node; } card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); +put_platform_node: of_node_put(platform_node); return ret; } diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index f090dee0c7..b33cc9a73e 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -364,7 +364,7 @@ static int mt8183_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd) int ret; ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, - &priv->hdmi_jack, NULL, 0); + &priv->hdmi_jack); if (ret) return ret; @@ -546,8 +546,7 @@ mt8183_da7219_max98357_headset_init(struct snd_soc_component *component) SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &priv->headset_jack, - NULL, 0); + &priv->headset_jack); if (ret) return ret; diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 889f9e4a96..ab157db783 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -383,7 +383,7 @@ mt8183_mt6358_ts3a227_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd) int ret; ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, - &priv->hdmi_jack, NULL, 0); + &priv->hdmi_jack); if (ret) return ret; @@ -613,8 +613,7 @@ mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component) SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &priv->headset_jack, - NULL, 0); + &priv->headset_jack); if (ret) return ret; diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index ee91569c09..d0f9d66627 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -28,8 +28,13 @@ #define RT1015_DEV0_NAME "rt1015.1-0028" #define RT1015_DEV1_NAME "rt1015.1-0029" -#define RT5682_CODEC_DAI "rt5682-aif1" -#define RT5682_DEV0_NAME "rt5682.1-001a" +#define RT1015_RT5682_CARD_NAME "mt8192_mt6359_rt1015_rt5682" +#define RT1015P_RT5682_CARD_NAME "mt8192_mt6359_rt1015p_rt5682" +#define RT1015P_RT5682S_CARD_NAME "mt8192_mt6359_rt1015p_rt5682s" + +#define RT1015_RT5682_OF_NAME "mediatek,mt8192_mt6359_rt1015_rt5682" +#define RT1015P_RT5682_OF_NAME "mediatek,mt8192_mt6359_rt1015p_rt5682" +#define RT1015P_RT5682S_OF_NAME "mediatek,mt8192_mt6359_rt1015p_rt5682s" struct mt8192_mt6359_priv { struct snd_soc_jack headset_jack; @@ -71,8 +76,8 @@ static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream, return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT); } -static int mt8192_rt5682_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int mt8192_rt5682x_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; @@ -121,8 +126,8 @@ static const struct snd_soc_ops mt8192_rt1015_i2s_ops = { .hw_params = mt8192_rt1015_i2s_hw_params, }; -static const struct snd_soc_ops mt8192_rt5682_i2s_ops = { - .hw_params = mt8192_rt5682_i2s_hw_params, +static const struct snd_soc_ops mt8192_rt5682x_i2s_ops = { + .hw_params = mt8192_rt5682x_i2s_hw_params, }; static int mt8192_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd) @@ -316,7 +321,7 @@ static int mt8192_rt5682_init(struct snd_soc_pcm_runtime *rtd) SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - jack, NULL, 0); + jack); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -338,7 +343,7 @@ static int mt8192_mt6359_hdmi_init(struct snd_soc_pcm_runtime *rtd) int ret; ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, - &priv->hdmi_jack, NULL, 0); + &priv->hdmi_jack); if (ret) { dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret); return ret; @@ -604,17 +609,9 @@ SND_SOC_DAILINK_DEFS(i2s2, DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); -SND_SOC_DAILINK_DEFS(i2s3_rt1015, - DAILINK_COMP_ARRAY(COMP_CPU("I2S3")), - DAILINK_COMP_ARRAY(COMP_CODEC(RT1015_DEV0_NAME, - RT1015_CODEC_DAI), - COMP_CODEC(RT1015_DEV1_NAME, - RT1015_CODEC_DAI)), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -SND_SOC_DAILINK_DEFS(i2s3_rt1015p, +SND_SOC_DAILINK_DEFS(i2s3, DAILINK_COMP_ARRAY(COMP_CPU("I2S3")), - DAILINK_COMP_ARRAY(COMP_CODEC("rt1015p", "HiFi")), + DAILINK_COMP_ARRAY(COMP_EMPTY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); SND_SOC_DAILINK_DEFS(i2s5, @@ -634,14 +631,12 @@ SND_SOC_DAILINK_DEFS(i2s7, SND_SOC_DAILINK_DEFS(i2s8, DAILINK_COMP_ARRAY(COMP_CPU("I2S8")), - DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME, - RT5682_CODEC_DAI)), + DAILINK_COMP_ARRAY(COMP_EMPTY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); SND_SOC_DAILINK_DEFS(i2s9, DAILINK_COMP_ARRAY(COMP_CPU("I2S9")), - DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME, - RT5682_CODEC_DAI)), + DAILINK_COMP_ARRAY(COMP_EMPTY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); SND_SOC_DAILINK_DEFS(connsys_i2s, @@ -929,6 +924,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .dpcm_playback = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s3), }, { .name = "I2S5", @@ -962,7 +958,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .init = mt8192_rt5682_init, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s8), - .ops = &mt8192_rt5682_i2s_ops, + .ops = &mt8192_rt5682x_i2s_ops, }, { .name = "I2S9", @@ -971,7 +967,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s9), - .ops = &mt8192_rt5682_i2s_ops, + .ops = &mt8192_rt5682x_i2s_ops, }, { .name = "CONNSYS_I2S", @@ -1051,7 +1047,7 @@ static struct snd_soc_codec_conf rt1015_amp_conf[] = { }; static struct snd_soc_card mt8192_mt6359_rt1015_rt5682_card = { - .name = "mt8192_mt6359_rt1015_rt5682", + .name = RT1015_RT5682_CARD_NAME, .owner = THIS_MODULE, .dai_link = mt8192_mt6359_dai_links, .num_links = ARRAY_SIZE(mt8192_mt6359_dai_links), @@ -1065,14 +1061,13 @@ static struct snd_soc_card mt8192_mt6359_rt1015_rt5682_card = { .num_configs = ARRAY_SIZE(rt1015_amp_conf), }; -static const struct snd_soc_dapm_widget -mt8192_mt6359_rt1015p_rt5682_widgets[] = { +static const struct snd_soc_dapm_widget mt8192_mt6359_rt1015p_rt5682x_widgets[] = { SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), }; -static const struct snd_soc_dapm_route mt8192_mt6359_rt1015p_rt5682_routes[] = { +static const struct snd_soc_dapm_route mt8192_mt6359_rt1015p_rt5682x_routes[] = { /* speaker */ { "Speakers", NULL, "Speaker" }, /* headset */ @@ -1081,74 +1076,107 @@ static const struct snd_soc_dapm_route mt8192_mt6359_rt1015p_rt5682_routes[] = { { "IN1P", NULL, "Headset Mic" }, }; -static const struct snd_kcontrol_new mt8192_mt6359_rt1015p_rt5682_controls[] = { +static const struct snd_kcontrol_new mt8192_mt6359_rt1015p_rt5682x_controls[] = { SOC_DAPM_PIN_SWITCH("Speakers"), SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), }; -static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682_card = { - .name = "mt8192_mt6359_rt1015p_rt5682", +static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682x_card = { .owner = THIS_MODULE, .dai_link = mt8192_mt6359_dai_links, .num_links = ARRAY_SIZE(mt8192_mt6359_dai_links), - .controls = mt8192_mt6359_rt1015p_rt5682_controls, - .num_controls = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682_controls), - .dapm_widgets = mt8192_mt6359_rt1015p_rt5682_widgets, - .num_dapm_widgets = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682_widgets), - .dapm_routes = mt8192_mt6359_rt1015p_rt5682_routes, - .num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682_routes), + .controls = mt8192_mt6359_rt1015p_rt5682x_controls, + .num_controls = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682x_controls), + .dapm_widgets = mt8192_mt6359_rt1015p_rt5682x_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682x_widgets), + .dapm_routes = mt8192_mt6359_rt1015p_rt5682x_routes, + .num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682x_routes), }; +static int mt8192_mt6359_card_set_be_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link, + struct device_node *node, + char *link_name) +{ + int ret; + + if (node && strcmp(link->name, link_name) == 0) { + ret = snd_soc_of_get_dai_link_codecs(card->dev, node, link); + if (ret < 0) { + dev_err_probe(card->dev, ret, "get dai link codecs fail\n"); + return ret; + } + } + + return 0; +} + static int mt8192_mt6359_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card; - struct device_node *platform_node, *hdmi_codec; + struct device_node *platform_node, *hdmi_codec, *headset_codec, *speaker_codec; int ret, i; struct snd_soc_dai_link *dai_link; struct mt8192_mt6359_priv *priv; - platform_node = of_parse_phandle(pdev->dev.of_node, - "mediatek,platform", 0); - if (!platform_node) { - dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); + card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev); + if (!card) return -EINVAL; + card->dev = &pdev->dev; + + if (of_device_is_compatible(pdev->dev.of_node, RT1015P_RT5682_OF_NAME)) + card->name = RT1015P_RT5682_CARD_NAME; + else if (of_device_is_compatible(pdev->dev.of_node, RT1015P_RT5682S_OF_NAME)) + card->name = RT1015P_RT5682S_CARD_NAME; + else + dev_dbg(&pdev->dev, "No need to set card name\n"); + + hdmi_codec = of_parse_phandle(pdev->dev.of_node, "mediatek,hdmi-codec", 0); + if (!hdmi_codec) + dev_dbg(&pdev->dev, "The machine has no hdmi-codec\n"); + + platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0); + if (!platform_node) { + ret = -EINVAL; + dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n"); + goto err_platform_node; } - card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev); - if (!card) { + speaker_codec = of_get_child_by_name(pdev->dev.of_node, "speaker-codecs"); + if (!speaker_codec) { ret = -EINVAL; - goto put_platform_node; + dev_err_probe(&pdev->dev, ret, "Property 'speaker-codecs' missing or invalid\n"); + goto err_speaker_codec; } - card->dev = &pdev->dev; - hdmi_codec = of_parse_phandle(pdev->dev.of_node, - "mediatek,hdmi-codec", 0); + headset_codec = of_get_child_by_name(pdev->dev.of_node, "headset-codec"); + if (!headset_codec) { + ret = -EINVAL; + dev_err_probe(&pdev->dev, ret, "Property 'headset-codec' missing or invalid\n"); + goto err_headset_codec; + } for_each_card_prelinks(card, i, dai_link) { - if (strcmp(dai_link->name, "I2S3") == 0) { - if (card == &mt8192_mt6359_rt1015_rt5682_card) { - dai_link->ops = &mt8192_rt1015_i2s_ops; - dai_link->cpus = i2s3_rt1015_cpus; - dai_link->num_cpus = - ARRAY_SIZE(i2s3_rt1015_cpus); - dai_link->codecs = i2s3_rt1015_codecs; - dai_link->num_codecs = - ARRAY_SIZE(i2s3_rt1015_codecs); - dai_link->platforms = i2s3_rt1015_platforms; - dai_link->num_platforms = - ARRAY_SIZE(i2s3_rt1015_platforms); - } else if (card == &mt8192_mt6359_rt1015p_rt5682_card) { - dai_link->cpus = i2s3_rt1015p_cpus; - dai_link->num_cpus = - ARRAY_SIZE(i2s3_rt1015p_cpus); - dai_link->codecs = i2s3_rt1015p_codecs; - dai_link->num_codecs = - ARRAY_SIZE(i2s3_rt1015p_codecs); - dai_link->platforms = i2s3_rt1015p_platforms; - dai_link->num_platforms = - ARRAY_SIZE(i2s3_rt1015p_platforms); - } + ret = mt8192_mt6359_card_set_be_link(card, dai_link, speaker_codec, "I2S3"); + if (ret) { + dev_err_probe(&pdev->dev, ret, "%s set speaker_codec fail\n", + dai_link->name); + goto err_probe; + } + + ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S8"); + if (ret) { + dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n", + dai_link->name); + goto err_probe; + } + + ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S9"); + if (ret) { + dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n", + dai_link->name); + goto err_probe; } if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0) { @@ -1156,6 +1184,9 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev) dai_link->ignore = 0; } + if (strcmp(dai_link->codecs[0].dai_name, RT1015_CODEC_DAI) == 0) + dai_link->ops = &mt8192_rt1015_i2s_ops; + if (!dai_link->platforms->name) dai_link->platforms->of_node = platform_node; } @@ -1163,34 +1194,44 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev) priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; - goto put_hdmi_codec; + goto err_probe; } snd_soc_card_set_drvdata(card, priv); ret = mt8192_afe_gpio_init(&pdev->dev); if (ret) { - dev_err(&pdev->dev, "init gpio error %d\n", ret); - goto put_hdmi_codec; + dev_err_probe(&pdev->dev, ret, "%s init gpio error\n", __func__); + goto err_probe; } ret = devm_snd_soc_register_card(&pdev->dev, card); - -put_hdmi_codec: - of_node_put(hdmi_codec); -put_platform_node: + if (ret) + dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n", __func__); + +err_probe: + of_node_put(headset_codec); +err_headset_codec: + of_node_put(speaker_codec); +err_speaker_codec: of_node_put(platform_node); +err_platform_node: + of_node_put(hdmi_codec); return ret; } #ifdef CONFIG_OF static const struct of_device_id mt8192_mt6359_dt_match[] = { { - .compatible = "mediatek,mt8192_mt6359_rt1015_rt5682", + .compatible = RT1015_RT5682_OF_NAME, .data = &mt8192_mt6359_rt1015_rt5682_card, }, { - .compatible = "mediatek,mt8192_mt6359_rt1015p_rt5682", - .data = &mt8192_mt6359_rt1015p_rt5682_card, + .compatible = RT1015P_RT5682_OF_NAME, + .data = &mt8192_mt6359_rt1015p_rt5682x_card, + }, + { + .compatible = RT1015P_RT5682S_OF_NAME, + .data = &mt8192_mt6359_rt1015p_rt5682x_card, }, {} }; diff --git a/sound/soc/mediatek/mt8195/Makefile b/sound/soc/mediatek/mt8195/Makefile index e5f0df5010..aae673ec75 100644 --- a/sound/soc/mediatek/mt8195/Makefile +++ b/sound/soc/mediatek/mt8195/Makefile @@ -12,5 +12,4 @@ snd-soc-mt8195-afe-objs := \ obj-$(CONFIG_SND_SOC_MT8195) += snd-soc-mt8195-afe.o # machine driver -obj-$(CONFIG_SND_SOC_MT8195_MT6359_RT1019_RT5682) += mt8195-mt6359-rt1019-rt5682.o -obj-$(CONFIG_SND_SOC_MT8195_MT6359_RT1011_RT5682) += mt8195-mt6359-rt1011-rt5682.o +obj-$(CONFIG_SND_SOC_MT8195_MT6359) += mt8195-mt6359.o diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c index efd5cc364a..2ee3872c83 100644 --- a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c +++ b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c @@ -284,7 +284,7 @@ static int mt8195_afe_enable_apll_tuner(struct mtk_base_afe *afe, { struct mt8195_afe_tuner_cfg *cfg = mt8195_afe_found_apll_tuner(id); unsigned long flags; - int ret = 0; + int ret; if (!cfg) return -EINVAL; @@ -308,7 +308,7 @@ static int mt8195_afe_enable_apll_tuner(struct mtk_base_afe *afe, spin_unlock_irqrestore(&cfg->ctrl_lock, flags); - return ret; + return 0; } static int mt8195_afe_disable_apll_tuner(struct mtk_base_afe *afe, @@ -316,7 +316,7 @@ static int mt8195_afe_disable_apll_tuner(struct mtk_base_afe *afe, { struct mt8195_afe_tuner_cfg *cfg = mt8195_afe_found_apll_tuner(id); unsigned long flags; - int ret = 0; + int ret; if (!cfg) return -EINVAL; @@ -338,7 +338,7 @@ static int mt8195_afe_disable_apll_tuner(struct mtk_base_afe *afe, if (ret) return ret; - return ret; + return 0; } int mt8195_afe_get_mclk_source_clk_id(int sel) diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c index c02c10da36..c2e2680547 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c @@ -2172,11 +2172,11 @@ static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: etdm_data->slave_mode = true; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: etdm_data->slave_mode = false; break; default: diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c index 151914c873..caceb0deb4 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c @@ -213,8 +213,6 @@ static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream, static int mtk_dai_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - int ret; - dev_dbg(dai->dev, "%s(), id %d, stream %d, widget active p %d, c %d\n", __func__, dai->id, substream->stream, dai->playback_widget->active, dai->capture_widget->active); @@ -222,11 +220,7 @@ static int mtk_dai_pcm_prepare(struct snd_pcm_substream *substream, if (dai->playback_widget->active || dai->capture_widget->active) return 0; - ret = mtk_dai_pcm_configure(substream, dai); - if (ret) - return ret; - - return 0; + return mtk_dai_pcm_configure(substream, dai); } static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) @@ -272,11 +266,11 @@ static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: pcmif_priv->slave_mode = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: pcmif_priv->slave_mode = 0; break; default: diff --git a/sound/soc/meson/aiu-acodec-ctrl.c b/sound/soc/meson/aiu-acodec-ctrl.c index 3776b073a3..d0f0ada5f4 100644 --- a/sound/soc/meson/aiu-acodec-ctrl.c +++ b/sound/soc/meson/aiu-acodec-ctrl.c @@ -192,7 +192,6 @@ static const struct snd_soc_component_driver aiu_acodec_ctrl_component = { .num_dapm_routes = ARRAY_SIZE(aiu_acodec_ctrl_routes), .of_xlate_dai_name = aiu_acodec_of_xlate_dai_name, .endianness = 1, - .non_legacy_dai_naming = 1, #ifdef CONFIG_DEBUG_FS .debugfs_prefix = "acodec", #endif diff --git a/sound/soc/meson/aiu-codec-ctrl.c b/sound/soc/meson/aiu-codec-ctrl.c index 286ac4983d..84c10956c2 100644 --- a/sound/soc/meson/aiu-codec-ctrl.c +++ b/sound/soc/meson/aiu-codec-ctrl.c @@ -139,7 +139,6 @@ static const struct snd_soc_component_driver aiu_hdmi_ctrl_component = { .num_dapm_routes = ARRAY_SIZE(aiu_hdmi_ctrl_routes), .of_xlate_dai_name = aiu_hdmi_of_xlate_dai_name, .endianness = 1, - .non_legacy_dai_naming = 1, #ifdef CONFIG_DEBUG_FS .debugfs_prefix = "hdmi", #endif diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c index 67729de41a..a0dd914c8e 100644 --- a/sound/soc/meson/aiu-encoder-i2s.c +++ b/sound/soc/meson/aiu-encoder-i2s.c @@ -229,7 +229,7 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int skew; /* Only CPU Master / Codec Slave supported ATM */ - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP) return -EINVAL; if (inv == SND_SOC_DAIFMT_NB_IF || diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index 37f4bb3469..61f9d417fd 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -161,6 +161,7 @@ static const struct snd_soc_component_driver axg_frddr_component_drv = { .hw_free = axg_fifo_pcm_hw_free, .pointer = axg_fifo_pcm_pointer, .trigger = axg_fifo_pcm_trigger, + .legacy_dai_naming = 1, }; static const struct axg_fifo_match_data axg_frddr_match_data = { @@ -286,6 +287,7 @@ static const struct snd_soc_component_driver g12a_frddr_component_drv = { .hw_free = axg_fifo_pcm_hw_free, .pointer = axg_fifo_pcm_pointer, .trigger = axg_fifo_pcm_trigger, + .legacy_dai_naming = 1, }; static const struct axg_fifo_match_data g12a_frddr_match_data = { @@ -356,6 +358,7 @@ static const struct snd_soc_component_driver sm1_frddr_component_drv = { .hw_free = axg_fifo_pcm_hw_free, .pointer = axg_fifo_pcm_pointer, .trigger = axg_fifo_pcm_trigger, + .legacy_dai_naming = 1, }; static const struct axg_fifo_match_data sm1_frddr_match_data = { diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c index 672e43a972..88ac58272f 100644 --- a/sound/soc/meson/axg-pdm.c +++ b/sound/soc/meson/axg-pdm.c @@ -457,7 +457,9 @@ static struct snd_soc_dai_driver axg_pdm_dai_drv = { .remove = axg_pdm_dai_remove, }; -static const struct snd_soc_component_driver axg_pdm_component_drv = {}; +static const struct snd_soc_component_driver axg_pdm_component_drv = { + .legacy_dai_naming = 1, +}; static const struct regmap_config axg_pdm_regmap_cfg = { .reg_bits = 32, diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c index 4ba44e0d65..e2cc4c4be7 100644 --- a/sound/soc/meson/axg-spdifin.c +++ b/sound/soc/meson/axg-spdifin.c @@ -390,6 +390,7 @@ static const struct snd_kcontrol_new axg_spdifin_controls[] = { static const struct snd_soc_component_driver axg_spdifin_component_drv = { .controls = axg_spdifin_controls, .num_controls = ARRAY_SIZE(axg_spdifin_controls), + .legacy_dai_naming = 1, }; static const struct regmap_config axg_spdifin_regmap_cfg = { diff --git a/sound/soc/meson/axg-spdifout.c b/sound/soc/meson/axg-spdifout.c index 3960d082e1..e8a12f15f3 100644 --- a/sound/soc/meson/axg-spdifout.c +++ b/sound/soc/meson/axg-spdifout.c @@ -383,6 +383,7 @@ static const struct snd_soc_component_driver axg_spdifout_component_drv = { .dapm_routes = axg_spdifout_dapm_routes, .num_dapm_routes = ARRAY_SIZE(axg_spdifout_dapm_routes), .set_bias_level = axg_spdifout_set_bias_level, + .legacy_dai_naming = 1, }; static const struct regmap_config axg_spdifout_regmap_cfg = { diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index e076ced300..c040c83637 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -119,19 +119,19 @@ static int axg_tdm_iface_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: if (!iface->mclk) { dev_err(dai->dev, "cpu clock master: mclk missing\n"); return -ENODEV; } break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BP_FC: + case SND_SOC_DAIFMT_BC_FP: dev_err(dai->dev, "only CBS_CFS and CBM_CFM are supported\n"); fallthrough; default: @@ -326,8 +326,8 @@ static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; - if ((iface->fmt & SND_SOC_DAIFMT_MASTER_MASK) == - SND_SOC_DAIFMT_CBS_CFS) { + if ((iface->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == + SND_SOC_DAIFMT_BP_FP) { ret = axg_tdm_iface_set_sclk(dai, params); if (ret) return ret; diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index d6adf7edea..e9208e74e9 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c @@ -182,6 +182,7 @@ static const struct snd_soc_component_driver axg_toddr_component_drv = { .hw_free = axg_fifo_pcm_hw_free, .pointer = axg_fifo_pcm_pointer, .trigger = axg_fifo_pcm_trigger, + .legacy_dai_naming = 1, }; static const struct axg_fifo_match_data axg_toddr_match_data = { @@ -242,6 +243,7 @@ static const struct snd_soc_component_driver g12a_toddr_component_drv = { .hw_free = axg_fifo_pcm_hw_free, .pointer = axg_fifo_pcm_pointer, .trigger = axg_fifo_pcm_trigger, + .legacy_dai_naming = 1, }; static const struct axg_fifo_match_data g12a_toddr_match_data = { @@ -312,6 +314,7 @@ static const struct snd_soc_component_driver sm1_toddr_component_drv = { .hw_free = axg_fifo_pcm_hw_free, .pointer = axg_fifo_pcm_pointer, .trigger = axg_fifo_pcm_trigger, + .legacy_dai_naming = 1, }; static const struct axg_fifo_match_data sm1_toddr_match_data = { diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c index 1dfee13968..ddc667956c 100644 --- a/sound/soc/meson/g12a-toacodec.c +++ b/sound/soc/meson/g12a-toacodec.c @@ -242,7 +242,6 @@ static const struct snd_soc_component_driver g12a_toacodec_component_drv = { .dapm_routes = g12a_toacodec_routes, .num_dapm_routes = ARRAY_SIZE(g12a_toacodec_routes), .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_component_driver sm1_toacodec_component_drv = { @@ -254,7 +253,6 @@ static const struct snd_soc_component_driver sm1_toacodec_component_drv = { .dapm_routes = g12a_toacodec_routes, .num_dapm_routes = ARRAY_SIZE(g12a_toacodec_routes), .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config g12a_toacodec_regmap_cfg = { diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c index 6c99052fea..579a04ad4d 100644 --- a/sound/soc/meson/g12a-tohdmitx.c +++ b/sound/soc/meson/g12a-tohdmitx.c @@ -226,7 +226,6 @@ static const struct snd_soc_component_driver g12a_tohdmitx_component_drv = { .dapm_routes = g12a_tohdmitx_routes, .num_dapm_routes = ARRAY_SIZE(g12a_tohdmitx_routes), .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config g12a_tohdmitx_regmap_cfg = { diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c index 2870cfad81..80c5ed1969 100644 --- a/sound/soc/meson/meson-codec-glue.c +++ b/sound/soc/meson/meson-codec-glue.c @@ -13,7 +13,7 @@ static struct snd_soc_dapm_widget * meson_codec_glue_get_input(struct snd_soc_dapm_widget *w) { - struct snd_soc_dapm_path *p = NULL; + struct snd_soc_dapm_path *p; struct snd_soc_dapm_widget *in; snd_soc_dapm_widget_for_each_source_path(w, p) { diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c index a9b8c4e77d..9c6b4dac68 100644 --- a/sound/soc/meson/t9015.c +++ b/sound/soc/meson/t9015.c @@ -234,7 +234,6 @@ static const struct snd_soc_component_driver t9015_codec_driver = { .num_dapm_routes = ARRAY_SIZE(t9015_dapm_routes), .suspend_bias_off = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config t9015_regmap_config = { diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 879c1221a8..ac761d3a01 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -358,8 +358,8 @@ static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) * Saif internally could be slave when working on EXTMASTER mode. * We just hide this to machine driver. */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: if (saif->id == saif->master_id) scr &= ~BM_SAIF_CTRL_SLAVE_MODE; else @@ -663,7 +663,8 @@ static struct snd_soc_dai_driver mxs_saif_dai = { }; static const struct snd_soc_component_driver mxs_saif_component = { - .name = "mxs-saif", + .name = "mxs-saif", + .legacy_dai_naming = 1, }; static irqreturn_t mxs_saif_irq(int irq, void *dev_id) @@ -754,6 +755,7 @@ static int mxs_saif_probe(struct platform_device *pdev) saif->master_id = saif->id; } else { ret = of_alias_get_id(master, "saif"); + of_node_put(master); if (ret < 0) return ret; else diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index cecbec2a09..a045693d5b 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -45,7 +45,7 @@ config SND_PXA2XX_SOC_CORGI tristate "SoC Audio support for Sharp Zaurus SL-C7x0" depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx && I2C select SND_PXA2XX_SOC_I2S - select SND_SOC_WM8731 + select SND_SOC_WM8731_I2C help Say Y if you want to add support for SoC audio on Sharp Zaurus SL-C7x0 models (Corgi, Shepherd, Husky). @@ -71,7 +71,7 @@ config SND_PXA2XX_SOC_POODLE tristate "SoC Audio support for Poodle" depends on SND_PXA2XX_SOC && MACH_POODLE && I2C select SND_PXA2XX_SOC_I2S - select SND_SOC_WM8731 + select SND_SOC_WM8731_I2C help Say Y if you want to add support for SoC audio on Sharp Zaurus SL-5600 model (Poodle). diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 8ee2dea25a..4489d2c8b1 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -21,8 +21,7 @@ #include #include -#include -#include +#include #include "../codecs/wm8731.h" #include "pxa2xx-i2s.h" @@ -41,6 +40,9 @@ static int corgi_jack_func; static int corgi_spk_func; +static struct gpio_desc *gpiod_mute_l, *gpiod_mute_r, + *gpiod_apm_on, *gpiod_mic_bias; + static void corgi_ext_control(struct snd_soc_dapm_context *dapm) { snd_soc_dapm_mutex_lock(dapm); @@ -49,8 +51,8 @@ static void corgi_ext_control(struct snd_soc_dapm_context *dapm) switch (corgi_jack_func) { case CORGI_HP: /* set = unmute headphone */ - gpio_set_value(CORGI_GPIO_MUTE_L, 1); - gpio_set_value(CORGI_GPIO_MUTE_R, 1); + gpiod_set_value(gpiod_mute_l, 1); + gpiod_set_value(gpiod_mute_r, 1); snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); @@ -58,24 +60,24 @@ static void corgi_ext_control(struct snd_soc_dapm_context *dapm) break; case CORGI_MIC: /* reset = mute headphone */ - gpio_set_value(CORGI_GPIO_MUTE_L, 0); - gpio_set_value(CORGI_GPIO_MUTE_R, 0); + gpiod_set_value(gpiod_mute_l, 0); + gpiod_set_value(gpiod_mute_r, 0); snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); break; case CORGI_LINE: - gpio_set_value(CORGI_GPIO_MUTE_L, 0); - gpio_set_value(CORGI_GPIO_MUTE_R, 0); + gpiod_set_value(gpiod_mute_l, 0); + gpiod_set_value(gpiod_mute_r, 0); snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); break; case CORGI_HEADSET: - gpio_set_value(CORGI_GPIO_MUTE_L, 0); - gpio_set_value(CORGI_GPIO_MUTE_R, 1); + gpiod_set_value(gpiod_mute_l, 0); + gpiod_set_value(gpiod_mute_r, 1); snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); @@ -108,8 +110,8 @@ static int corgi_startup(struct snd_pcm_substream *substream) static void corgi_shutdown(struct snd_pcm_substream *substream) { /* set = unmute headphone */ - gpio_set_value(CORGI_GPIO_MUTE_L, 1); - gpio_set_value(CORGI_GPIO_MUTE_R, 1); + gpiod_set_value(gpiod_mute_l, 1); + gpiod_set_value(gpiod_mute_r, 1); } static int corgi_hw_params(struct snd_pcm_substream *substream, @@ -199,14 +201,14 @@ static int corgi_set_spk(struct snd_kcontrol *kcontrol, static int corgi_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - gpio_set_value(CORGI_GPIO_APM_ON, SND_SOC_DAPM_EVENT_ON(event)); + gpiod_set_value(gpiod_apm_on, SND_SOC_DAPM_EVENT_ON(event)); return 0; } static int corgi_mic_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - gpio_set_value(CORGI_GPIO_MIC_BIAS, SND_SOC_DAPM_EVENT_ON(event)); + gpiod_set_value(gpiod_mic_bias, SND_SOC_DAPM_EVENT_ON(event)); return 0; } @@ -293,6 +295,19 @@ static int corgi_probe(struct platform_device *pdev) card->dev = &pdev->dev; + gpiod_mute_l = devm_gpiod_get(&pdev->dev, "mute-l", GPIOD_OUT_HIGH); + if (IS_ERR(gpiod_mute_l)) + return PTR_ERR(gpiod_mute_l); + gpiod_mute_r = devm_gpiod_get(&pdev->dev, "mute-r", GPIOD_OUT_HIGH); + if (IS_ERR(gpiod_mute_r)) + return PTR_ERR(gpiod_mute_r); + gpiod_apm_on = devm_gpiod_get(&pdev->dev, "apm-on", GPIOD_OUT_LOW); + if (IS_ERR(gpiod_apm_on)) + return PTR_ERR(gpiod_apm_on); + gpiod_mic_bias = devm_gpiod_get(&pdev->dev, "mic-bias", GPIOD_OUT_LOW); + if (IS_ERR(gpiod_mic_bias)) + return PTR_ERR(gpiod_mic_bias); + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c index eafa1482af..4e0e9b778d 100644 --- a/sound/soc/pxa/e740_wm9705.c +++ b/sound/soc/pxa/e740_wm9705.c @@ -7,17 +7,19 @@ #include #include -#include +#include #include #include #include -#include -#include +#include #include +static struct gpio_desc *gpiod_output_amp, *gpiod_input_amp; +static struct gpio_desc *gpiod_audio_power; + #define E740_AUDIO_OUT 1 #define E740_AUDIO_IN 2 @@ -25,9 +27,9 @@ static int e740_audio_power; static void e740_sync_audio_power(int status) { - gpio_set_value(GPIO_E740_WM9705_nAVDD2, !status); - gpio_set_value(GPIO_E740_AMP_ON, (status & E740_AUDIO_OUT) ? 1 : 0); - gpio_set_value(GPIO_E740_MIC_ON, (status & E740_AUDIO_IN) ? 1 : 0); + gpiod_set_value(gpiod_audio_power, !status); + gpiod_set_value(gpiod_output_amp, (status & E740_AUDIO_OUT) ? 1 : 0); + gpiod_set_value(gpiod_input_amp, (status & E740_AUDIO_IN) ? 1 : 0); } static int e740_mic_amp_event(struct snd_soc_dapm_widget *w, @@ -116,36 +118,35 @@ static struct snd_soc_card e740 = { .fully_routed = true, }; -static struct gpio e740_audio_gpios[] = { - { GPIO_E740_MIC_ON, GPIOF_OUT_INIT_LOW, "Mic amp" }, - { GPIO_E740_AMP_ON, GPIOF_OUT_INIT_LOW, "Output amp" }, - { GPIO_E740_WM9705_nAVDD2, GPIOF_OUT_INIT_HIGH, "Audio power" }, -}; - static int e740_probe(struct platform_device *pdev) { struct snd_soc_card *card = &e740; int ret; - ret = gpio_request_array(e740_audio_gpios, - ARRAY_SIZE(e740_audio_gpios)); + gpiod_input_amp = devm_gpiod_get(&pdev->dev, "Mic amp", GPIOD_OUT_LOW); + ret = PTR_ERR_OR_ZERO(gpiod_input_amp); + if (ret) + return ret; + gpiod_output_amp = devm_gpiod_get(&pdev->dev, "Output amp", GPIOD_OUT_LOW); + ret = PTR_ERR_OR_ZERO(gpiod_output_amp); + if (ret) + return ret; + gpiod_audio_power = devm_gpiod_get(&pdev->dev, "Audio power", GPIOD_OUT_HIGH); + ret = PTR_ERR_OR_ZERO(gpiod_audio_power); if (ret) return ret; card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { + if (ret) dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); - gpio_free_array(e740_audio_gpios, ARRAY_SIZE(e740_audio_gpios)); - } return ret; } static int e740_remove(struct platform_device *pdev) { - gpio_free_array(e740_audio_gpios, ARRAY_SIZE(e740_audio_gpios)); return 0; } diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c index d75510d7b1..7a1e0d8bfd 100644 --- a/sound/soc/pxa/e750_wm9705.c +++ b/sound/soc/pxa/e750_wm9705.c @@ -7,24 +7,25 @@ #include #include -#include +#include #include #include #include -#include -#include +#include #include +static struct gpio_desc *gpiod_spk_amp, *gpiod_hp_amp; + static int e750_spk_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { if (event & SND_SOC_DAPM_PRE_PMU) - gpio_set_value(GPIO_E750_SPK_AMP_OFF, 0); + gpiod_set_value(gpiod_spk_amp, 1); else if (event & SND_SOC_DAPM_POST_PMD) - gpio_set_value(GPIO_E750_SPK_AMP_OFF, 1); + gpiod_set_value(gpiod_spk_amp, 0); return 0; } @@ -33,9 +34,9 @@ static int e750_hp_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { if (event & SND_SOC_DAPM_PRE_PMU) - gpio_set_value(GPIO_E750_HP_AMP_OFF, 0); + gpiod_set_value(gpiod_hp_amp, 1); else if (event & SND_SOC_DAPM_POST_PMD) - gpio_set_value(GPIO_E750_HP_AMP_OFF, 1); + gpiod_set_value(gpiod_hp_amp, 0); return 0; } @@ -100,35 +101,31 @@ static struct snd_soc_card e750 = { .fully_routed = true, }; -static struct gpio e750_audio_gpios[] = { - { GPIO_E750_HP_AMP_OFF, GPIOF_OUT_INIT_HIGH, "Headphone amp" }, - { GPIO_E750_SPK_AMP_OFF, GPIOF_OUT_INIT_HIGH, "Speaker amp" }, -}; - static int e750_probe(struct platform_device *pdev) { struct snd_soc_card *card = &e750; int ret; - ret = gpio_request_array(e750_audio_gpios, - ARRAY_SIZE(e750_audio_gpios)); + gpiod_hp_amp = devm_gpiod_get(&pdev->dev, "Headphone amp", GPIOD_OUT_LOW); + ret = PTR_ERR_OR_ZERO(gpiod_hp_amp); + if (ret) + return ret; + gpiod_spk_amp = devm_gpiod_get(&pdev->dev, "Speaker amp", GPIOD_OUT_LOW); + ret = PTR_ERR_OR_ZERO(gpiod_spk_amp); if (ret) return ret; card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { + if (ret) dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); - gpio_free_array(e750_audio_gpios, ARRAY_SIZE(e750_audio_gpios)); - } return ret; } static int e750_remove(struct platform_device *pdev) { - gpio_free_array(e750_audio_gpios, ARRAY_SIZE(e750_audio_gpios)); return 0; } diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 56d543da93..a39c494127 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -7,23 +7,24 @@ #include #include -#include +#include #include #include #include #include -#include -#include +#include + +static struct gpio_desc *gpiod_spk_amp, *gpiod_hp_amp; static int e800_spk_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { if (event & SND_SOC_DAPM_PRE_PMU) - gpio_set_value(GPIO_E800_SPK_AMP_ON, 1); + gpiod_set_value(gpiod_spk_amp, 1); else if (event & SND_SOC_DAPM_POST_PMD) - gpio_set_value(GPIO_E800_SPK_AMP_ON, 0); + gpiod_set_value(gpiod_spk_amp, 0); return 0; } @@ -32,9 +33,9 @@ static int e800_hp_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { if (event & SND_SOC_DAPM_PRE_PMU) - gpio_set_value(GPIO_E800_HP_AMP_OFF, 0); + gpiod_set_value(gpiod_hp_amp, 1); else if (event & SND_SOC_DAPM_POST_PMD) - gpio_set_value(GPIO_E800_HP_AMP_OFF, 1); + gpiod_set_value(gpiod_hp_amp, 0); return 0; } @@ -100,35 +101,31 @@ static struct snd_soc_card e800 = { .num_dapm_routes = ARRAY_SIZE(audio_map), }; -static struct gpio e800_audio_gpios[] = { - { GPIO_E800_SPK_AMP_ON, GPIOF_OUT_INIT_HIGH, "Headphone amp" }, - { GPIO_E800_HP_AMP_OFF, GPIOF_OUT_INIT_HIGH, "Speaker amp" }, -}; - static int e800_probe(struct platform_device *pdev) { struct snd_soc_card *card = &e800; int ret; - ret = gpio_request_array(e800_audio_gpios, - ARRAY_SIZE(e800_audio_gpios)); + gpiod_hp_amp = devm_gpiod_get(&pdev->dev, "Headphone amp", GPIOD_OUT_LOW); + ret = PTR_ERR_OR_ZERO(gpiod_hp_amp); + if (ret) + return ret; + gpiod_spk_amp = devm_gpiod_get(&pdev->dev, "Speaker amp", GPIOD_OUT_LOW); + ret = PTR_ERR_OR_ZERO(gpiod_spk_amp); if (ret) return ret; card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { + if (ret) dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); - gpio_free_array(e800_audio_gpios, ARRAY_SIZE(e800_audio_gpios)); - } return ret; } static int e800_remove(struct platform_device *pdev) { - gpio_free_array(e800_audio_gpios, ARRAY_SIZE(e800_audio_gpios)); return 0; } diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index 9076ea7e93..b59ec22e1e 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -23,7 +23,7 @@ #include #include -#include +#include SND_SOC_DAILINK_DEFS(ac97, DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")), diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c index 7334fac758..a323ddb8fc 100644 --- a/sound/soc/pxa/hx4700.c +++ b/sound/soc/pxa/hx4700.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include @@ -18,10 +18,10 @@ #include #include -#include #include #include "pxa2xx-i2s.h" +static struct gpio_desc *gpiod_hp_driver, *gpiod_spk_sd; static struct snd_soc_jack hs_jack; /* Headphones jack detection DAPM pin */ @@ -29,20 +29,18 @@ static struct snd_soc_jack_pin hs_jack_pin[] = { { .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE, + .invert = 1, }, { .pin = "Speaker", /* disable speaker when hp jack is inserted */ .mask = SND_JACK_HEADPHONE, - .invert = 1, }, }; /* Headphones jack detection GPIO */ static struct snd_soc_jack_gpio hs_jack_gpio = { - .gpio = GPIO75_HX4700_EARPHONE_nDET, - .invert = true, - .name = "hp-gpio", + .name = "earphone-det", .report = SND_JACK_HEADPHONE, .debounce_time = 200, }; @@ -81,14 +79,14 @@ static const struct snd_soc_ops hx4700_ops = { static int hx4700_spk_power(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - gpio_set_value(GPIO107_HX4700_SPK_nSD, !!SND_SOC_DAPM_EVENT_ON(event)); + gpiod_set_value(gpiod_spk_sd, !SND_SOC_DAPM_EVENT_ON(event)); return 0; } static int hx4700_hp_power(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - gpio_set_value(GPIO92_HX4700_HP_DRIVER, !!SND_SOC_DAPM_EVENT_ON(event)); + gpiod_set_value(gpiod_hp_driver, !!SND_SOC_DAPM_EVENT_ON(event)); return 0; } @@ -122,9 +120,9 @@ static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd) int err; /* Jack detection API stuff */ - err = snd_soc_card_jack_new(rtd->card, "Headphone Jack", - SND_JACK_HEADPHONE, &hs_jack, hs_jack_pin, - ARRAY_SIZE(hs_jack_pin)); + err = snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack", + SND_JACK_HEADPHONE, &hs_jack, + hs_jack_pin, ARRAY_SIZE(hs_jack_pin)); if (err) return err; @@ -162,11 +160,6 @@ static struct snd_soc_card snd_soc_card_hx4700 = { .fully_routed = true, }; -static struct gpio hx4700_audio_gpios[] = { - { GPIO107_HX4700_SPK_nSD, GPIOF_OUT_INIT_HIGH, "SPK_POWER" }, - { GPIO92_HX4700_HP_DRIVER, GPIOF_OUT_INIT_LOW, "EP_POWER" }, -}; - static int hx4700_audio_probe(struct platform_device *pdev) { int ret; @@ -174,26 +167,26 @@ static int hx4700_audio_probe(struct platform_device *pdev) if (!machine_is_h4700()) return -ENODEV; - ret = gpio_request_array(hx4700_audio_gpios, - ARRAY_SIZE(hx4700_audio_gpios)); + gpiod_hp_driver = devm_gpiod_get(&pdev->dev, "hp-driver", GPIOD_ASIS); + ret = PTR_ERR_OR_ZERO(gpiod_hp_driver); + if (ret) + return ret; + gpiod_spk_sd = devm_gpiod_get(&pdev->dev, "spk-sd", GPIOD_ASIS); + ret = PTR_ERR_OR_ZERO(gpiod_spk_sd); if (ret) return ret; + hs_jack_gpio.gpiod_dev = &pdev->dev; snd_soc_card_hx4700.dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_hx4700); - if (ret) - gpio_free_array(hx4700_audio_gpios, - ARRAY_SIZE(hx4700_audio_gpios)); return ret; } static int hx4700_audio_remove(struct platform_device *pdev) { - gpio_set_value(GPIO92_HX4700_HP_DRIVER, 0); - gpio_set_value(GPIO107_HX4700_SPK_nSD, 0); - - gpio_free_array(hx4700_audio_gpios, ARRAY_SIZE(hx4700_audio_gpios)); + gpiod_set_value(gpiod_hp_driver, 0); + gpiod_set_value(gpiod_spk_sd, 0); return 0; } diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index a5f326c97a..b791a2ba5c 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -14,16 +14,14 @@ #include #include #include -#include +#include #include #include #include #include #include -#include -#include #include #include "../codecs/uda1380.h" #include "pxa2xx-i2s.h" @@ -36,6 +34,9 @@ static int magician_hp_switch; static int magician_spk_switch = 1; static int magician_in_sel = MAGICIAN_MIC; +static struct gpio_desc *gpiod_spk_power, *gpiod_ep_power, *gpiod_mic_power; +static struct gpio_desc *gpiod_in_sel0, *gpiod_in_sel1; + static void magician_ext_control(struct snd_soc_dapm_context *dapm) { @@ -90,13 +91,13 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BC_FC); if (ret < 0) return ret; /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_BP_FP); if (ret < 0) return ret; @@ -128,14 +129,14 @@ static int magician_capture_hw_params(struct snd_pcm_substream *substream, /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_BC_FC); if (ret < 0) return ret; /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_BP_FP); if (ret < 0) return ret; @@ -215,10 +216,10 @@ static int magician_set_input(struct snd_kcontrol *kcontrol, switch (magician_in_sel) { case MAGICIAN_MIC: - gpio_set_value(EGPIO_MAGICIAN_IN_SEL1, 1); + gpiod_set_value(gpiod_in_sel1, 1); break; case MAGICIAN_MIC_EXT: - gpio_set_value(EGPIO_MAGICIAN_IN_SEL1, 0); + gpiod_set_value(gpiod_in_sel1, 0); } return 1; @@ -227,21 +228,21 @@ static int magician_set_input(struct snd_kcontrol *kcontrol, static int magician_spk_power(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, SND_SOC_DAPM_EVENT_ON(event)); + gpiod_set_value(gpiod_spk_power, SND_SOC_DAPM_EVENT_ON(event)); return 0; } static int magician_hp_power(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - gpio_set_value(EGPIO_MAGICIAN_EP_POWER, SND_SOC_DAPM_EVENT_ON(event)); + gpiod_set_value(gpiod_ep_power, SND_SOC_DAPM_EVENT_ON(event)); return 0; } static int magician_mic_bias(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, SND_SOC_DAPM_EVENT_ON(event)); + gpiod_set_value(gpiod_mic_power, SND_SOC_DAPM_EVENT_ON(event)); return 0; } @@ -328,106 +329,38 @@ static struct snd_soc_card snd_soc_card_magician = { .fully_routed = true, }; -static struct platform_device *magician_snd_device; - -/* - * FIXME: move into magician board file once merged into the pxa tree - */ -static struct uda1380_platform_data uda1380_info = { - .gpio_power = EGPIO_MAGICIAN_CODEC_POWER, - .gpio_reset = EGPIO_MAGICIAN_CODEC_RESET, - .dac_clk = UDA1380_DAC_CLK_WSPLL, -}; - -static struct i2c_board_info i2c_board_info[] = { - { - I2C_BOARD_INFO("uda1380", 0x18), - .platform_data = &uda1380_info, - }, -}; - -static int __init magician_init(void) -{ - int ret; - struct i2c_adapter *adapter; - struct i2c_client *client; - - if (!machine_is_magician()) - return -ENODEV; - - adapter = i2c_get_adapter(0); - if (!adapter) - return -ENODEV; - client = i2c_new_client_device(adapter, i2c_board_info); - i2c_put_adapter(adapter); - if (IS_ERR(client)) - return PTR_ERR(client); - - ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER"); - if (ret) - goto err_request_spk; - ret = gpio_request(EGPIO_MAGICIAN_EP_POWER, "EP_POWER"); - if (ret) - goto err_request_ep; - ret = gpio_request(EGPIO_MAGICIAN_MIC_POWER, "MIC_POWER"); - if (ret) - goto err_request_mic; - ret = gpio_request(EGPIO_MAGICIAN_IN_SEL0, "IN_SEL0"); - if (ret) - goto err_request_in_sel0; - ret = gpio_request(EGPIO_MAGICIAN_IN_SEL1, "IN_SEL1"); - if (ret) - goto err_request_in_sel1; - - gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0); - - magician_snd_device = platform_device_alloc("soc-audio", -1); - if (!magician_snd_device) { - ret = -ENOMEM; - goto err_pdev; - } - - platform_set_drvdata(magician_snd_device, &snd_soc_card_magician); - ret = platform_device_add(magician_snd_device); - if (ret) { - platform_device_put(magician_snd_device); - goto err_pdev; - } - - return 0; - -err_pdev: - gpio_free(EGPIO_MAGICIAN_IN_SEL1); -err_request_in_sel1: - gpio_free(EGPIO_MAGICIAN_IN_SEL0); -err_request_in_sel0: - gpio_free(EGPIO_MAGICIAN_MIC_POWER); -err_request_mic: - gpio_free(EGPIO_MAGICIAN_EP_POWER); -err_request_ep: - gpio_free(EGPIO_MAGICIAN_SPK_POWER); -err_request_spk: - return ret; -} - -static void __exit magician_exit(void) +static int magician_audio_probe(struct platform_device *pdev) { - platform_device_unregister(magician_snd_device); - - gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0); - gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0); - gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0); - - gpio_free(EGPIO_MAGICIAN_IN_SEL1); - gpio_free(EGPIO_MAGICIAN_IN_SEL0); - gpio_free(EGPIO_MAGICIAN_MIC_POWER); - gpio_free(EGPIO_MAGICIAN_EP_POWER); - gpio_free(EGPIO_MAGICIAN_SPK_POWER); + struct device *dev = &pdev->dev; + + gpiod_spk_power = devm_gpiod_get(dev, "SPK_POWER", GPIOD_OUT_LOW); + if (IS_ERR(gpiod_spk_power)) + return PTR_ERR(gpiod_spk_power); + gpiod_ep_power = devm_gpiod_get(dev, "EP_POWER", GPIOD_OUT_LOW); + if (IS_ERR(gpiod_ep_power)) + return PTR_ERR(gpiod_ep_power); + gpiod_mic_power = devm_gpiod_get(dev, "MIC_POWER", GPIOD_OUT_LOW); + if (IS_ERR(gpiod_mic_power)) + return PTR_ERR(gpiod_mic_power); + gpiod_in_sel0 = devm_gpiod_get(dev, "IN_SEL0", GPIOD_OUT_HIGH); + if (IS_ERR(gpiod_in_sel0)) + return PTR_ERR(gpiod_in_sel0); + gpiod_in_sel1 = devm_gpiod_get(dev, "IN_SEL1", GPIOD_OUT_LOW); + if (IS_ERR(gpiod_in_sel1)) + return PTR_ERR(gpiod_in_sel1); + + snd_soc_card_magician.dev = &pdev->dev; + return devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_magician); } -module_init(magician_init); -module_exit(magician_exit); +static struct platform_driver magician_audio_driver = { + .driver.name = "magician-audio", + .driver.pm = &snd_soc_pm_ops, + .probe = magician_audio_probe, +}; +module_platform_driver(magician_audio_driver); MODULE_AUTHOR("Philipp Zabel"); MODULE_DESCRIPTION("ALSA SoC Magician"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:magician-audio"); diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index 763db7bbd9..0fa37637ec 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c @@ -33,7 +33,7 @@ #include #include -#include +#include #include #include diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 7e39210a0b..fb5a439044 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -171,11 +171,11 @@ static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai, sspa->sp = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH; sspa->ctrl = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: sspa->sp |= SSPA_SP_MSL; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: break; default: return -EINVAL; @@ -456,10 +456,11 @@ static int mmp_sspa_close(struct snd_soc_component *component, } static const struct snd_soc_component_driver mmp_sspa_component = { - .name = "mmp-sspa", - .mmap = mmp_pcm_mmap, - .open = mmp_sspa_open, - .close = mmp_sspa_close, + .name = "mmp-sspa", + .mmap = mmp_pcm_mmap, + .open = mmp_sspa_open, + .close = mmp_sspa_close, + .legacy_dai_naming = 1, }; static int asoc_mmp_sspa_probe(struct platform_device *pdev) diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index b92ea1a045..a2321c01c1 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include static struct snd_soc_jack hs_jack; @@ -71,9 +71,10 @@ static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd) int err; /* Jack detection API stuff */ - err = snd_soc_card_jack_new(rtd->card, "Headphone Jack", - SND_JACK_HEADPHONE, &hs_jack, hs_jack_pins, - ARRAY_SIZE(hs_jack_pins)); + err = snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack", + SND_JACK_HEADPHONE, &hs_jack, + hs_jack_pins, + ARRAY_SIZE(hs_jack_pins)); if (err) return err; diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 323ba3e230..5fdaa477e8 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -21,8 +21,8 @@ #include #include -#include -#include +#include +#include #include "../codecs/wm8731.h" #include "pxa2xx-i2s.h" @@ -38,21 +38,23 @@ static int poodle_jack_func; static int poodle_spk_func; +static struct poodle_audio_platform_data *poodle_pdata; + static void poodle_ext_control(struct snd_soc_dapm_context *dapm) { /* set up jack connection */ if (poodle_jack_func == POODLE_HP) { /* set = unmute headphone */ - locomo_gpio_write(&poodle_locomo_device.dev, - POODLE_LOCOMO_GPIO_MUTE_L, 1); - locomo_gpio_write(&poodle_locomo_device.dev, - POODLE_LOCOMO_GPIO_MUTE_R, 1); + locomo_gpio_write(poodle_pdata->locomo_dev, + poodle_pdata->gpio_mute_l, 1); + locomo_gpio_write(poodle_pdata->locomo_dev, + poodle_pdata->gpio_mute_r, 1); snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); } else { - locomo_gpio_write(&poodle_locomo_device.dev, - POODLE_LOCOMO_GPIO_MUTE_L, 0); - locomo_gpio_write(&poodle_locomo_device.dev, - POODLE_LOCOMO_GPIO_MUTE_R, 0); + locomo_gpio_write(poodle_pdata->locomo_dev, + poodle_pdata->gpio_mute_l, 0); + locomo_gpio_write(poodle_pdata->locomo_dev, + poodle_pdata->gpio_mute_r, 0); snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); } @@ -80,10 +82,10 @@ static int poodle_startup(struct snd_pcm_substream *substream) static void poodle_shutdown(struct snd_pcm_substream *substream) { /* set = unmute headphone */ - locomo_gpio_write(&poodle_locomo_device.dev, - POODLE_LOCOMO_GPIO_MUTE_L, 1); - locomo_gpio_write(&poodle_locomo_device.dev, - POODLE_LOCOMO_GPIO_MUTE_R, 1); + locomo_gpio_write(poodle_pdata->locomo_dev, + poodle_pdata->gpio_mute_l, 1); + locomo_gpio_write(poodle_pdata->locomo_dev, + poodle_pdata->gpio_mute_r, 1); } static int poodle_hw_params(struct snd_pcm_substream *substream, @@ -174,11 +176,11 @@ static int poodle_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { if (SND_SOC_DAPM_EVENT_ON(event)) - locomo_gpio_write(&poodle_locomo_device.dev, - POODLE_LOCOMO_GPIO_AMP_ON, 0); + locomo_gpio_write(poodle_pdata->locomo_dev, + poodle_pdata->gpio_amp_on, 0); else - locomo_gpio_write(&poodle_locomo_device.dev, - POODLE_LOCOMO_GPIO_AMP_ON, 1); + locomo_gpio_write(poodle_pdata->locomo_dev, + poodle_pdata->gpio_amp_on, 1); return 0; } @@ -254,13 +256,14 @@ static int poodle_probe(struct platform_device *pdev) struct snd_soc_card *card = &poodle; int ret; - locomo_gpio_set_dir(&poodle_locomo_device.dev, - POODLE_LOCOMO_GPIO_AMP_ON, 0); + poodle_pdata = pdev->dev.platform_data; + locomo_gpio_set_dir(poodle_pdata->locomo_dev, + poodle_pdata->gpio_amp_on, 0); /* should we mute HP at startup - burning power ?*/ - locomo_gpio_set_dir(&poodle_locomo_device.dev, - POODLE_LOCOMO_GPIO_MUTE_L, 0); - locomo_gpio_set_dir(&poodle_locomo_device.dev, - POODLE_LOCOMO_GPIO_MUTE_R, 0); + locomo_gpio_set_dir(poodle_pdata->locomo_dev, + poodle_pdata->gpio_mute_l, 0); + locomo_gpio_set_dir(poodle_pdata->locomo_dev, + poodle_pdata->gpio_mute_r, 0); card->dev = &pdev->dev; diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 7f13a35e9c..430dd44632 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -372,10 +372,10 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, { struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBM_CFS: - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_BC_FP: + case SND_SOC_DAIFMT_BP_FP: break; default: return -EINVAL; @@ -432,14 +432,14 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv) sscr1 |= SSCR1_RxTresh(8) | SSCR1_TxTresh(7); - switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (priv->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_SCFR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FP: sscr1 |= SSCR1_SCLKDIR | SSCR1_SCFR; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_BP_FP: break; default: return -EINVAL; @@ -484,9 +484,9 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv) pxa_ssp_write_reg(ssp, SSCR1, sscr1); pxa_ssp_write_reg(ssp, SSPSP, sspsp); - switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBM_CFS: + switch (priv->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_BC_FP: scfr = pxa_ssp_read_reg(ssp, SSCR1) | SSCR1_SCFR; pxa_ssp_write_reg(ssp, SSCR1, scfr); @@ -848,16 +848,17 @@ static struct snd_soc_dai_driver pxa_ssp_dai = { }; static const struct snd_soc_component_driver pxa_ssp_component = { - .name = "pxa-ssp", - .pcm_construct = pxa2xx_soc_pcm_new, - .open = pxa2xx_soc_pcm_open, - .close = pxa2xx_soc_pcm_close, - .hw_params = pxa2xx_soc_pcm_hw_params, - .prepare = pxa2xx_soc_pcm_prepare, - .trigger = pxa2xx_soc_pcm_trigger, - .pointer = pxa2xx_soc_pcm_pointer, - .suspend = pxa_ssp_suspend, - .resume = pxa_ssp_resume, + .name = "pxa-ssp", + .pcm_construct = pxa2xx_soc_pcm_new, + .open = pxa2xx_soc_pcm_open, + .close = pxa2xx_soc_pcm_close, + .hw_params = pxa2xx_soc_pcm_hw_params, + .prepare = pxa2xx_soc_pcm_prepare, + .trigger = pxa2xx_soc_pcm_trigger, + .pointer = pxa2xx_soc_pcm_pointer, + .suspend = pxa_ssp_suspend, + .resume = pxa_ssp_resume, + .legacy_dai_naming = 1, }; #ifdef CONFIG_OF diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 58f8541ba5..809ea34736 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -21,9 +21,11 @@ #include #include -#include -#include -#include +#include + +#define PCDR 0x0040 /* PCM FIFO Data Register */ +#define MODR 0x0140 /* Modem FIFO Data Register */ +#define MCDR 0x0060 /* Mic-in FIFO Data Register */ static void pxa2xx_ac97_warm_reset(struct ac97_controller *adrv) { @@ -59,35 +61,30 @@ static struct ac97_controller_ops pxa2xx_ac97_ops = { }; static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_in = { - .addr = __PREG(PCDR), .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, .chan_name = "pcm_pcm_stereo_in", .maxburst = 32, }; static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_out = { - .addr = __PREG(PCDR), .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, .chan_name = "pcm_pcm_stereo_out", .maxburst = 32, }; static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_out = { - .addr = __PREG(MODR), .addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES, .chan_name = "pcm_aux_mono_out", .maxburst = 16, }; static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_in = { - .addr = __PREG(MODR), .addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES, .chan_name = "pcm_aux_mono_in", .maxburst = 16, }; static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = { - .addr = __PREG(MCDR), .addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES, .chan_name = "pcm_aux_mic_mono", .maxburst = 16, @@ -226,6 +223,7 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) int ret; struct ac97_controller *ctrl; pxa2xx_audio_ops_t *pdata = pdev->dev.platform_data; + struct resource *regs; void **codecs_pdata; if (pdev->id != -1) { @@ -233,6 +231,16 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) return -ENXIO; } + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return -ENXIO; + + pxa2xx_ac97_pcm_stereo_in.addr = regs->start + PCDR; + pxa2xx_ac97_pcm_stereo_out.addr = regs->start + PCDR; + pxa2xx_ac97_pcm_aux_mono_out.addr = regs->start + MODR; + pxa2xx_ac97_pcm_aux_mono_in.addr = regs->start + MODR; + pxa2xx_ac97_pcm_mic_mono_in.addr = regs->start + MCDR; + ret = pxa2xx_ac97_hw_probe(pdev); if (ret) { dev_err(&pdev->dev, "PXA2xx AC97 hw probe error (%d)\n", ret); diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 5bfc1a9665..3e4c704036 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -21,21 +21,20 @@ #include #include -#include -#include +#include #include "pxa2xx-i2s.h" /* * I2S Controller Register and Bit Definitions */ -#define SACR0 __REG(0x40400000) /* Global Control Register */ -#define SACR1 __REG(0x40400004) /* Serial Audio I 2 S/MSB-Justified Control Register */ -#define SASR0 __REG(0x4040000C) /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */ -#define SAIMR __REG(0x40400014) /* Serial Audio Interrupt Mask Register */ -#define SAICR __REG(0x40400018) /* Serial Audio Interrupt Clear Register */ -#define SADIV __REG(0x40400060) /* Audio Clock Divider Register. */ -#define SADR __REG(0x40400080) /* Serial Audio Data Register (TX and RX FIFO access Register). */ +#define SACR0 (0x0000) /* Global Control Register */ +#define SACR1 (0x0004) /* Serial Audio I 2 S/MSB-Justified Control Register */ +#define SASR0 (0x000C) /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */ +#define SAIMR (0x0014) /* Serial Audio Interrupt Mask Register */ +#define SAICR (0x0018) /* Serial Audio Interrupt Clear Register */ +#define SADIV (0x0060) /* Audio Clock Divider Register. */ +#define SADR (0x0080) /* Serial Audio Data Register (TX and RX FIFO access Register). */ #define SACR0_RFTH(x) ((x) << 12) /* Rx FIFO Interrupt or DMA Trigger Threshold */ #define SACR0_TFTH(x) ((x) << 8) /* Tx FIFO Interrupt or DMA Trigger Threshold */ @@ -77,16 +76,15 @@ struct pxa_i2s_port { static struct pxa_i2s_port pxa_i2s; static struct clk *clk_i2s; static int clk_ena = 0; +static void __iomem *i2s_reg_base; static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_out = { - .addr = __PREG(SADR), .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, .chan_name = "tx", .maxburst = 32, }; static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_in = { - .addr = __PREG(SADR), .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, .chan_name = "rx", .maxburst = 32, @@ -102,7 +100,7 @@ static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, return PTR_ERR(clk_i2s); if (!snd_soc_dai_active(cpu_dai)) - SACR0 = 0; + writel(0, i2s_reg_base + SACR0); return 0; } @@ -114,7 +112,7 @@ static int pxa_i2s_wait(void) /* flush the Rx FIFO */ for (i = 0; i < 16; i++) - SADR; + readl(i2s_reg_base + SADR); return 0; } @@ -131,11 +129,11 @@ static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, break; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: pxa_i2s.master = 1; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_BC_FP: pxa_i2s.master = 0; break; default: @@ -174,39 +172,39 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, /* is port used by another stream */ if (!(SACR0 & SACR0_ENB)) { - SACR0 = 0; + writel(0, i2s_reg_base + SACR0); if (pxa_i2s.master) - SACR0 |= SACR0_BCKD; + writel(readl(i2s_reg_base + SACR0) | (SACR0_BCKD), i2s_reg_base + SACR0); - SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1); - SACR1 |= pxa_i2s.fmt; + writel(readl(i2s_reg_base + SACR0) | (SACR0_RFTH(14) | SACR0_TFTH(1)), i2s_reg_base + SACR0); + writel(readl(i2s_reg_base + SACR1) | (pxa_i2s.fmt), i2s_reg_base + SACR1); } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - SAIMR |= SAIMR_TFS; + writel(readl(i2s_reg_base + SAIMR) | (SAIMR_TFS), i2s_reg_base + SAIMR); else - SAIMR |= SAIMR_RFS; + writel(readl(i2s_reg_base + SAIMR) | (SAIMR_RFS), i2s_reg_base + SAIMR); switch (params_rate(params)) { case 8000: - SADIV = 0x48; + writel(0x48, i2s_reg_base + SADIV); break; case 11025: - SADIV = 0x34; + writel(0x34, i2s_reg_base + SADIV); break; case 16000: - SADIV = 0x24; + writel(0x24, i2s_reg_base + SADIV); break; case 22050: - SADIV = 0x1a; + writel(0x1a, i2s_reg_base + SADIV); break; case 44100: - SADIV = 0xd; + writel(0xd, i2s_reg_base + SADIV); break; case 48000: - SADIV = 0xc; + writel(0xc, i2s_reg_base + SADIV); break; case 96000: /* not in manual and possibly slightly inaccurate */ - SADIV = 0x6; + writel(0x6, i2s_reg_base + SADIV); break; } @@ -221,10 +219,10 @@ static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - SACR1 &= ~SACR1_DRPL; + writel(readl(i2s_reg_base + SACR1) & (~SACR1_DRPL), i2s_reg_base + SACR1); else - SACR1 &= ~SACR1_DREC; - SACR0 |= SACR0_ENB; + writel(readl(i2s_reg_base + SACR1) & (~SACR1_DREC), i2s_reg_base + SACR1); + writel(readl(i2s_reg_base + SACR0) | (SACR0_ENB), i2s_reg_base + SACR0); break; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: @@ -243,15 +241,15 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - SACR1 |= SACR1_DRPL; - SAIMR &= ~SAIMR_TFS; + writel(readl(i2s_reg_base + SACR1) | (SACR1_DRPL), i2s_reg_base + SACR1); + writel(readl(i2s_reg_base + SAIMR) & (~SAIMR_TFS), i2s_reg_base + SAIMR); } else { - SACR1 |= SACR1_DREC; - SAIMR &= ~SAIMR_RFS; + writel(readl(i2s_reg_base + SACR1) | (SACR1_DREC), i2s_reg_base + SACR1); + writel(readl(i2s_reg_base + SAIMR) & (~SAIMR_RFS), i2s_reg_base + SAIMR); } - if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) { - SACR0 &= ~SACR0_ENB; + if ((readl(i2s_reg_base + SACR1) & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) { + writel(readl(i2s_reg_base + SACR0) & (~SACR0_ENB), i2s_reg_base + SACR0); pxa_i2s_wait(); if (clk_ena) { clk_disable_unprepare(clk_i2s); @@ -264,13 +262,13 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, static int pxa2xx_soc_pcm_suspend(struct snd_soc_component *component) { /* store registers */ - pxa_i2s.sacr0 = SACR0; - pxa_i2s.sacr1 = SACR1; - pxa_i2s.saimr = SAIMR; - pxa_i2s.sadiv = SADIV; + pxa_i2s.sacr0 = readl(i2s_reg_base + SACR0); + pxa_i2s.sacr1 = readl(i2s_reg_base + SACR1); + pxa_i2s.saimr = readl(i2s_reg_base + SAIMR); + pxa_i2s.sadiv = readl(i2s_reg_base + SADIV); /* deactivate link */ - SACR0 &= ~SACR0_ENB; + writel(readl(i2s_reg_base + SACR0) & (~SACR0_ENB), i2s_reg_base + SACR0); pxa_i2s_wait(); return 0; } @@ -279,12 +277,12 @@ static int pxa2xx_soc_pcm_resume(struct snd_soc_component *component) { pxa_i2s_wait(); - SACR0 = pxa_i2s.sacr0 & ~SACR0_ENB; - SACR1 = pxa_i2s.sacr1; - SAIMR = pxa_i2s.saimr; - SADIV = pxa_i2s.sadiv; + writel(pxa_i2s.sacr0 & ~SACR0_ENB, i2s_reg_base + SACR0); + writel(pxa_i2s.sacr1, i2s_reg_base + SACR1); + writel(pxa_i2s.saimr, i2s_reg_base + SAIMR); + writel(pxa_i2s.sadiv, i2s_reg_base + SADIV); - SACR0 = pxa_i2s.sacr0; + writel(pxa_i2s.sacr0, i2s_reg_base + SACR0); return 0; } @@ -306,12 +304,12 @@ static int pxa2xx_i2s_probe(struct snd_soc_dai *dai) * the SACR0[RST] bit must also be set and cleared to reset all * I2S controller registers. */ - SACR0 = SACR0_RST; - SACR0 = 0; + writel(SACR0_RST, i2s_reg_base + SACR0); + writel(0, i2s_reg_base + SACR0); /* Make sure RPL and REC are disabled */ - SACR1 = SACR1_DRPL | SACR1_DREC; + writel(SACR1_DRPL | SACR1_DREC, i2s_reg_base + SACR1); /* Along with FIFO servicing */ - SAIMR &= ~(SAIMR_RFS | SAIMR_TFS); + writel(readl(i2s_reg_base + SAIMR) & (~(SAIMR_RFS | SAIMR_TFS)), i2s_reg_base + SAIMR); snd_soc_dai_init_dma_data(dai, &pxa2xx_i2s_pcm_stereo_out, &pxa2xx_i2s_pcm_stereo_in); @@ -357,20 +355,37 @@ static struct snd_soc_dai_driver pxa_i2s_dai = { }; static const struct snd_soc_component_driver pxa_i2s_component = { - .name = "pxa-i2s", - .pcm_construct = pxa2xx_soc_pcm_new, - .open = pxa2xx_soc_pcm_open, - .close = pxa2xx_soc_pcm_close, - .hw_params = pxa2xx_soc_pcm_hw_params, - .prepare = pxa2xx_soc_pcm_prepare, - .trigger = pxa2xx_soc_pcm_trigger, - .pointer = pxa2xx_soc_pcm_pointer, - .suspend = pxa2xx_soc_pcm_suspend, - .resume = pxa2xx_soc_pcm_resume, + .name = "pxa-i2s", + .pcm_construct = pxa2xx_soc_pcm_new, + .open = pxa2xx_soc_pcm_open, + .close = pxa2xx_soc_pcm_close, + .hw_params = pxa2xx_soc_pcm_hw_params, + .prepare = pxa2xx_soc_pcm_prepare, + .trigger = pxa2xx_soc_pcm_trigger, + .pointer = pxa2xx_soc_pcm_pointer, + .suspend = pxa2xx_soc_pcm_suspend, + .resume = pxa2xx_soc_pcm_resume, + .legacy_dai_naming = 1, }; static int pxa2xx_i2s_drv_probe(struct platform_device *pdev) { + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!res) { + dev_err(&pdev->dev, "missing MMIO resource\n"); + return -ENXIO; + } + + i2s_reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2s_reg_base)) { + dev_err(&pdev->dev, "ioremap failed\n"); + return PTR_ERR(i2s_reg_base); + } + + pxa2xx_i2s_pcm_stereo_out.addr = res->start + SADR; + pxa2xx_i2s_pcm_stereo_in.addr = res->start + SADR; + return devm_snd_soc_register_component(&pdev->dev, &pxa_i2s_component, &pxa_i2s_dai, 1); } diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 7c1384a869..44303b6eb2 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -14,13 +14,12 @@ #include #include #include -#include +#include #include #include #include #include -#include #include "../codecs/wm8750.h" #include "pxa2xx-i2s.h" @@ -37,7 +36,7 @@ static int spitz_jack_func; static int spitz_spk_func; -static int spitz_mic_gpio; +static struct gpio_desc *gpiod_mic, *gpiod_mute_l, *gpiod_mute_r; static void spitz_ext_control(struct snd_soc_dapm_context *dapm) { @@ -56,8 +55,8 @@ static void spitz_ext_control(struct snd_soc_dapm_context *dapm) snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); - gpio_set_value(SPITZ_GPIO_MUTE_L, 1); - gpio_set_value(SPITZ_GPIO_MUTE_R, 1); + gpiod_set_value(gpiod_mute_l, 1); + gpiod_set_value(gpiod_mute_r, 1); break; case SPITZ_MIC: /* enable mic jack and bias, mute hp */ @@ -65,8 +64,8 @@ static void spitz_ext_control(struct snd_soc_dapm_context *dapm) snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); - gpio_set_value(SPITZ_GPIO_MUTE_L, 0); - gpio_set_value(SPITZ_GPIO_MUTE_R, 0); + gpiod_set_value(gpiod_mute_l, 0); + gpiod_set_value(gpiod_mute_r, 0); break; case SPITZ_LINE: /* enable line jack, disable mic bias and mute hp */ @@ -74,8 +73,8 @@ static void spitz_ext_control(struct snd_soc_dapm_context *dapm) snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack"); - gpio_set_value(SPITZ_GPIO_MUTE_L, 0); - gpio_set_value(SPITZ_GPIO_MUTE_R, 0); + gpiod_set_value(gpiod_mute_l, 0); + gpiod_set_value(gpiod_mute_r, 0); break; case SPITZ_HEADSET: /* enable and unmute headset jack enable mic bias, mute L hp */ @@ -83,8 +82,8 @@ static void spitz_ext_control(struct snd_soc_dapm_context *dapm) snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack"); - gpio_set_value(SPITZ_GPIO_MUTE_L, 0); - gpio_set_value(SPITZ_GPIO_MUTE_R, 1); + gpiod_set_value(gpiod_mute_l, 0); + gpiod_set_value(gpiod_mute_r, 1); break; case SPITZ_HP_OFF: @@ -93,8 +92,8 @@ static void spitz_ext_control(struct snd_soc_dapm_context *dapm) snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); - gpio_set_value(SPITZ_GPIO_MUTE_L, 0); - gpio_set_value(SPITZ_GPIO_MUTE_R, 0); + gpiod_set_value(gpiod_mute_l, 0); + gpiod_set_value(gpiod_mute_r, 0); break; } @@ -199,7 +198,7 @@ static int spitz_set_spk(struct snd_kcontrol *kcontrol, static int spitz_mic_bias(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - gpio_set_value_cansleep(spitz_mic_gpio, SND_SOC_DAPM_EVENT_ON(event)); + gpiod_set_value_cansleep(gpiod_mic, SND_SOC_DAPM_EVENT_ON(event)); return 0; } @@ -287,39 +286,28 @@ static int spitz_probe(struct platform_device *pdev) struct snd_soc_card *card = &snd_soc_spitz; int ret; - if (machine_is_akita()) - spitz_mic_gpio = AKITA_GPIO_MIC_BIAS; - else - spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS; - - ret = gpio_request(spitz_mic_gpio, "MIC GPIO"); - if (ret) - goto err1; - - ret = gpio_direction_output(spitz_mic_gpio, 0); - if (ret) - goto err2; + gpiod_mic = devm_gpiod_get(&pdev->dev, "mic", GPIOD_OUT_LOW); + if (IS_ERR(gpiod_mic)) + return PTR_ERR(gpiod_mic); + gpiod_mute_l = devm_gpiod_get(&pdev->dev, "mute-l", GPIOD_OUT_LOW); + if (IS_ERR(gpiod_mute_l)) + return PTR_ERR(gpiod_mute_l); + gpiod_mute_r = devm_gpiod_get(&pdev->dev, "mute-r", GPIOD_OUT_LOW); + if (IS_ERR(gpiod_mute_r)) + return PTR_ERR(gpiod_mute_r); card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { + if (ret) dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); - goto err2; - } - - return 0; -err2: - gpio_free(spitz_mic_gpio); -err1: return ret; } static int spitz_remove(struct platform_device *pdev) { - gpio_free(spitz_mic_gpio); return 0; } diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 3b40b5fa5d..30f83cab0c 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -16,15 +16,14 @@ #include #include #include -#include +#include #include #include #include #include -#include -#include +#include #define TOSA_HP 0 #define TOSA_MIC_INT 1 @@ -33,6 +32,7 @@ #define TOSA_SPK_ON 0 #define TOSA_SPK_OFF 1 +static struct gpio_desc *tosa_mute; static int tosa_jack_func; static int tosa_spk_func; @@ -128,7 +128,7 @@ static int tosa_set_spk(struct snd_kcontrol *kcontrol, static int tosa_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - gpio_set_value(TOSA_GPIO_L_MUTE, SND_SOC_DAPM_EVENT_ON(event) ? 1 : 0); + gpiod_set_value(tosa_mute, SND_SOC_DAPM_EVENT_ON(event) ? 1 : 0); return 0; } @@ -222,10 +222,11 @@ static int tosa_probe(struct platform_device *pdev) struct snd_soc_card *card = ⤩ int ret; - ret = gpio_request_one(TOSA_GPIO_L_MUTE, GPIOF_OUT_INIT_LOW, - "Headphone Jack"); - if (ret) - return ret; + tosa_mute = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW); + if (IS_ERR(tosa_mute)) + return dev_err_probe(&pdev->dev, PTR_ERR(tosa_mute), + "failed to get L_MUTE GPIO\n"); + gpiod_set_consumer_name(tosa_mute, "Headphone Jack"); card->dev = &pdev->dev; @@ -233,24 +234,16 @@ static int tosa_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); - gpio_free(TOSA_GPIO_L_MUTE); } return ret; } -static int tosa_remove(struct platform_device *pdev) -{ - gpio_free(TOSA_GPIO_L_MUTE); - return 0; -} - static struct platform_driver tosa_driver = { .driver = { .name = "tosa-audio", .pm = &snd_soc_pm_ops, }, .probe = tosa_probe, - .remove = tosa_remove, }; module_platform_driver(tosa_driver); diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c index d5f2961b1a..6cc970bb2a 100644 --- a/sound/soc/pxa/ttc-dkb.c +++ b/sound/soc/pxa/ttc-dkb.c @@ -64,12 +64,14 @@ static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; /* Headset jack detection */ - snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, - &hs_jack, hs_jack_pins, ARRAY_SIZE(hs_jack_pins)); - snd_soc_card_jack_new(rtd->card, "Microphone Jack", SND_JACK_MICROPHONE, - &mic_jack, mic_jack_pins, - ARRAY_SIZE(mic_jack_pins)); + snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack", + SND_JACK_HEADPHONE | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2, + &hs_jack, + hs_jack_pins, ARRAY_SIZE(hs_jack_pins)); + snd_soc_card_jack_new_pins(rtd->card, "Microphone Jack", + SND_JACK_MICROPHONE, &mic_jack, + mic_jack_pins, ARRAY_SIZE(mic_jack_pins)); /* headphone, microphone detection & headset short detection */ pm860x_hs_jack_detect(component, &hs_jack, SND_JACK_HEADPHONE, diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c index edf2b9eec5..020dcce1df 100644 --- a/sound/soc/pxa/z2.c +++ b/sound/soc/pxa/z2.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -21,9 +21,7 @@ #include #include -#include -#include -#include +#include #include "../codecs/wm8750.h" #include "pxa2xx-i2s.h" @@ -90,7 +88,6 @@ static struct snd_soc_jack_pin hs_jack_pins[] = { /* Headset jack detection gpios */ static struct snd_soc_jack_gpio hs_jack_gpios[] = { { - .gpio = GPIO37_ZIPITZ2_HEADSET_DETECT, .name = "hsdet-gpio", .report = SND_JACK_HEADSET, .debounce_time = 200, @@ -132,9 +129,10 @@ static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd) int ret; /* Jack detection API stuff */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET, - &hs_jack, hs_jack_pins, - ARRAY_SIZE(hs_jack_pins)); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET, &hs_jack, + hs_jack_pins, + ARRAY_SIZE(hs_jack_pins)); if (ret) goto err; @@ -196,6 +194,7 @@ static int __init z2_init(void) if (!z2_snd_device) return -ENOMEM; + hs_jack_gpios[0].gpiod_dev = &z2_snd_device->dev; platform_set_drvdata(z2_snd_device, &snd_soc_z2); ret = platform_device_add(z2_snd_device); diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 28d0dfb403..750653404b 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -197,6 +197,8 @@ config SND_SOC_SC7280 select SND_SOC_LPASS_MACRO_COMMON imply SND_SOC_LPASS_RX_MACRO imply SND_SOC_LPASS_TX_MACRO + select SND_SOC_RT5682_I2C + select SND_SOC_RT5682S help Add support for audio on Qualcomm Technologies Inc. SC7280 SoC-based systems. diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index f9d6937532..e54b896111 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -96,7 +96,7 @@ static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s) SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4, - &pdata->jack, NULL, 0); + &pdata->jack); if (rval < 0) { dev_err(card->dev, "Unable to add Headphone Jack\n"); @@ -172,7 +172,7 @@ static int msm8916_qdsp6_dai_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); return apq8016_dai_init(rtd, qdsp6_dai_get_lpass_id(cpu_dai)); } diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index 3efa133d1c..abaf694ee9 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -293,6 +293,7 @@ static struct lpass_variant apq8016_data = { static const struct of_device_id apq8016_lpass_cpu_device_id[] __maybe_unused = { { .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data }, + { .compatible = "qcom,apq8016-lpass-cpu", .data = &apq8016_data }, {} }; MODULE_DEVICE_TABLE(of, apq8016_lpass_cpu_device_id); diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index e6846ad2b5..8a56f38dc7 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -472,6 +472,7 @@ static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component, static const struct snd_soc_component_driver lpass_cpu_comp_driver = { .name = "lpass-cpu", .of_xlate_dai_name = asoc_qcom_of_xlate_dai_name, + .legacy_dai_naming = 1, }; static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) @@ -1090,6 +1091,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0); if (dsp_of_node) { dev_err(dev, "DSP exists and holds audio resources\n"); + of_node_put(dsp_of_node); return -EBUSY; } @@ -1102,6 +1104,11 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) if (!match || !match->data) return -EINVAL; + if (of_device_is_compatible(dev->of_node, "qcom,lpass-cpu-apq8016")) { + dev_warn(dev, "%s compatible is deprecated\n", + match->compatible); + } + drvdata->variant = (struct lpass_variant *)match->data; variant = drvdata->variant; diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 74d62f377d..b41ab7a321 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -898,7 +898,7 @@ static int lpass_platform_cdc_dma_mmap(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; unsigned long size, offset; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); size = vma->vm_end - vma->vm_start; offset = vma->vm_pgoff << PAGE_SHIFT; return io_remap_pfn_range(vma, vma->vm_start, @@ -1160,7 +1160,7 @@ static int lpass_platform_prealloc_cdc_dma_buffer(struct snd_soc_component *comp break; } - buf->area = (unsigned char * __force)memremap(buf->addr, buf->bytes, MEMREMAP_WT); + buf->area = (unsigned char * __force)memremap(buf->addr, buf->bytes, MEMREMAP_WC); return 0; } diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c index 98c0efa1d0..01dac32c50 100644 --- a/sound/soc/qcom/qdsp6/audioreach.c +++ b/sound/soc/qcom/qdsp6/audioreach.c @@ -732,10 +732,10 @@ static int audioreach_i2s_set_media_format(struct q6apm_graph *graph, intf_cfg->cfg.sd_line_idx = module->sd_line_idx; switch (cfg->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: intf_cfg->cfg.ws_src = CONFIG_I2S_WS_SRC_INTERNAL; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: /* CPU is slave */ intf_cfg->cfg.ws_src = CONFIG_I2S_WS_SRC_EXTERNAL; break; diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c index 72c5719f1d..1530e98df1 100644 --- a/sound/soc/qcom/qdsp6/q6adm.c +++ b/sound/soc/qcom/qdsp6/q6adm.c @@ -90,7 +90,7 @@ struct q6adm_session_map_node_v5 { static struct q6copp *q6adm_find_copp(struct q6adm *adm, int port_idx, int copp_idx) { - struct q6copp *c = NULL; + struct q6copp *c; struct q6copp *ret = NULL; unsigned long flags; @@ -180,7 +180,7 @@ static int q6adm_callback(struct apr_device *adev, struct apr_resp_pkt *data) u32 status; u16 copp_id; u16 reserved; - } __packed * open = data->payload; + } __packed *open = data->payload; copp = q6adm_find_copp(adm, port_idx, copp_idx); if (!copp) @@ -217,7 +217,7 @@ static struct q6copp *q6adm_alloc_copp(struct q6adm *adm, int port_idx) idx = find_first_zero_bit(&adm->copp_bitmap[port_idx], MAX_COPPS_PER_PORT); - if (idx > MAX_COPPS_PER_PORT) + if (idx >= MAX_COPPS_PER_PORT) return ERR_PTR(-EBUSY); c = kzalloc(sizeof(*c), GFP_ATOMIC); @@ -299,7 +299,7 @@ static struct q6copp *q6adm_find_matching_copp(struct q6adm *adm, int channel_mode, int bit_width, int app_type) { - struct q6copp *c = NULL; + struct q6copp *c; struct q6copp *ret = NULL; unsigned long flags; diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index 625724852a..919e326b94 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -1328,11 +1328,11 @@ int q6afe_i2s_port_prepare(struct q6afe_port *port, struct q6afe_i2s_cfg *cfg) pcfg->i2s_cfg.bit_width = cfg->bit_width; pcfg->i2s_cfg.data_format = AFE_LINEAR_PCM_DATA; - switch (cfg->fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (cfg->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: pcfg->i2s_cfg.ws_src = AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_BC_FC: /* CPU is slave */ pcfg->i2s_cfg.ws_src = AFE_PORT_CONFIG_I2S_WS_SRC_EXTERNAL; break; diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c index 19c4a90ec1..ee59ef36b8 100644 --- a/sound/soc/qcom/qdsp6/q6apm-dai.c +++ b/sound/soc/qcom/qdsp6/q6apm-dai.c @@ -147,6 +147,12 @@ static int q6apm_dai_prepare(struct snd_soc_component *component, cfg.num_channels = runtime->channels; cfg.bit_width = prtd->bits_per_sample; + if (prtd->state) { + /* clear the previous setup if any */ + q6apm_graph_stop(prtd->graph); + q6apm_unmap_memory_regions(prtd->graph, substream->stream); + } + prtd->pcm_count = snd_pcm_lib_period_bytes(substream); prtd->pos = 0; /* rate and channels are sent to audio driver */ diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index 37225ef256..f5f7c64b23 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -57,7 +57,7 @@ static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd) SND_JACK_HEADPHONE | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pdata->hs_jack, NULL, 0); + &pdata->hs_jack); if (rval < 0) { dev_err(card->dev, "Unable to add Headset Jack\n"); @@ -89,7 +89,7 @@ static int sc7180_hdmi_init(struct snd_soc_pcm_runtime *rtd) rval = snd_soc_card_jack_new( card, "HDMI Jack", SND_JACK_LINEOUT, - &pdata->hdmi_jack, NULL, 0); + &pdata->hdmi_jack); if (rval < 0) { dev_err(card->dev, "Unable to add HDMI Jack\n"); @@ -155,7 +155,7 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream) } snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_BC_FC | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S); diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c index bd0bf9c8cb..da7469a6a2 100644 --- a/sound/soc/qcom/sc7280.c +++ b/sound/soc/qcom/sc7280.c @@ -12,14 +12,23 @@ #include #include #include +#include #include +#include "../codecs/rt5682.h" +#include "../codecs/rt5682s.h" #include "common.h" #include "lpass.h" +#include "qdsp6/q6afe.h" + +#define DEFAULT_MCLK_RATE 19200000 +#define RT5682_PLL_FREQ (48000 * 512) +#define MI2S_BCLK_RATE 1536000 struct sc7280_snd_data { struct snd_soc_card card; struct sdw_stream_runtime *sruntime[LPASS_MAX_PORTS]; + u32 pri_mi2s_clk_count; struct snd_soc_jack hs_jack; struct snd_soc_jack hdmi_jack; bool jack_setup; @@ -50,7 +59,7 @@ static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd) SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5, - &pdata->hs_jack, NULL, 0); + &pdata->hs_jack); if (rval < 0) { dev_err(card->dev, "Unable to add Headset Jack\n"); @@ -69,8 +78,10 @@ static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd) pdata->jack_setup = true; } switch (cpu_dai->id) { + case MI2S_PRIMARY: case LPASS_CDC_DMA_RX0: case LPASS_CDC_DMA_TX3: + case TX_CODEC_DMA_TX_3: for_each_rtd_codec_dais(rtd, i, codec_dai) { rval = snd_soc_component_set_jack(component, &pdata->hs_jack, NULL); if (rval != 0 && rval != -ENOTSUPP) { @@ -96,7 +107,7 @@ static int sc7280_hdmi_init(struct snd_soc_pcm_runtime *rtd) int rval; rval = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT, - &pdata->hdmi_jack, NULL, 0); + &pdata->hdmi_jack); if (rval < 0) { dev_err(card->dev, "Unable to add HDMI Jack\n"); @@ -110,16 +121,60 @@ static int sc7280_hdmi_init(struct snd_soc_pcm_runtime *rtd) return snd_soc_component_set_jack(component, &pdata->hdmi_jack, NULL); } +static int sc7280_rt5682_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_card *card = rtd->card; + struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card); + int ret; + + if (++data->pri_mi2s_clk_count == 1) { + snd_soc_dai_set_sysclk(cpu_dai, + LPASS_MCLK0, + DEFAULT_MCLK_RATE, + SNDRV_PCM_STREAM_PLAYBACK); + } + snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_CBC_CFC | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S); + + ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL2, RT5682S_PLL_S_MCLK, + DEFAULT_MCLK_RATE, RT5682_PLL_FREQ); + if (ret) { + dev_err(rtd->dev, "can't set codec pll: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL2, + RT5682_PLL_FREQ, + SND_SOC_CLOCK_IN); + + if (ret) { + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", + ret); + return ret; + } + + return 0; +} + static int sc7280_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); switch (cpu_dai->id) { + case MI2S_PRIMARY: case LPASS_CDC_DMA_TX3: + case TX_CODEC_DMA_TX_3: return sc7280_headset_init(rtd); case LPASS_CDC_DMA_RX0: case LPASS_CDC_DMA_VA_TX0: case MI2S_SECONDARY: + case RX_CODEC_DMA_RX_0: + case SECONDARY_MI2S_RX: + case VA_CODEC_DMA_TX_0: return 0; case LPASS_DP_RX: return sc7280_hdmi_init(rtd); @@ -147,6 +202,10 @@ static int sc7280_snd_hw_params(struct snd_pcm_substream *substream, switch (cpu_dai->id) { case LPASS_CDC_DMA_TX3: case LPASS_CDC_DMA_RX0: + case RX_CODEC_DMA_RX_0: + case SECONDARY_MI2S_RX: + case TX_CODEC_DMA_TX_3: + case VA_CODEC_DMA_TX_0: for_each_rtd_codec_dais(rtd, i, codec_dai) { sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream); if (sruntime != ERR_PTR(-ENOTSUPP)) @@ -197,6 +256,9 @@ static int sc7280_snd_prepare(struct snd_pcm_substream *substream) switch (cpu_dai->id) { case LPASS_CDC_DMA_RX0: case LPASS_CDC_DMA_TX3: + case RX_CODEC_DMA_RX_0: + case TX_CODEC_DMA_TX_3: + case VA_CODEC_DMA_TX_0: return sc7280_snd_swr_prepare(substream); default: break; @@ -215,6 +277,9 @@ static int sc7280_snd_hw_free(struct snd_pcm_substream *substream) switch (cpu_dai->id) { case LPASS_CDC_DMA_RX0: case LPASS_CDC_DMA_TX3: + case RX_CODEC_DMA_RX_0: + case TX_CODEC_DMA_TX_3: + case VA_CODEC_DMA_TX_0: if (sruntime && data->stream_prepared[cpu_dai->id]) { sdw_disable_stream(sruntime); sdw_deprepare_stream(sruntime); @@ -227,10 +292,70 @@ static int sc7280_snd_hw_free(struct snd_pcm_substream *substream) return 0; } +static void sc7280_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + + switch (cpu_dai->id) { + case MI2S_PRIMARY: + if (--data->pri_mi2s_clk_count == 0) { + snd_soc_dai_set_sysclk(cpu_dai, + LPASS_MCLK0, + 0, + SNDRV_PCM_STREAM_PLAYBACK); + } + break; + case SECONDARY_MI2S_RX: + snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, + 0, SNDRV_PCM_STREAM_PLAYBACK); + break; + default: + break; + } +} + +static int sc7280_snd_startup(struct snd_pcm_substream *substream) +{ + unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; + unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int ret = 0; + + switch (cpu_dai->id) { + case MI2S_PRIMARY: + ret = sc7280_rt5682_init(rtd); + break; + case SECONDARY_MI2S_RX: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; + + snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + + snd_soc_dai_set_fmt(cpu_dai, fmt); + snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); + break; + default: + break; + } + return ret; +} + static const struct snd_soc_ops sc7280_ops = { + .startup = sc7280_snd_startup, .hw_params = sc7280_snd_hw_params, .hw_free = sc7280_snd_hw_free, .prepare = sc7280_snd_prepare, + .shutdown = sc7280_snd_shutdown, +}; + +static const struct snd_soc_dapm_widget sc7280_snd_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), }; static int sc7280_snd_platform_probe(struct platform_device *pdev) @@ -252,6 +377,9 @@ static int sc7280_snd_platform_probe(struct platform_device *pdev) card->driver_name = "SC7280"; card->dev = dev; + card->dapm_widgets = sc7280_snd_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sc7280_snd_widgets); + ret = qcom_snd_parse_of(card); if (ret) return ret; diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 5c1d13eccb..d8d35563af 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -247,7 +247,7 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) SND_JACK_HEADPHONE | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pdata->jack, NULL, 0); + &pdata->jack); if (rval < 0) { dev_err(card->dev, "Unable to add Headphone Jack\n"); @@ -316,8 +316,8 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) static int sdm845_snd_startup(struct snd_pcm_substream *substream) { - unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; - unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; + unsigned int fmt = SND_SOC_DAIFMT_BP_FP; + unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC; struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card); @@ -356,7 +356,7 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT, MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); - snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + snd_soc_dai_set_fmt(cpu_dai, fmt); break; diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 114a29e01c..ce4a571338 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -41,7 +41,7 @@ static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd) SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5, - &data->jack, NULL, 0); + &data->jack); if (rval < 0) { dev_err(card->dev, "Unable to add Headphone Jack\n"); @@ -96,8 +96,8 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static int sm8250_snd_startup(struct snd_pcm_substream *substream) { - unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; - unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; + unsigned int fmt = SND_SOC_DAIFMT_BP_FP; + unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); diff --git a/sound/soc/soc-card.c b/sound/soc/soc-card.c index 41c586b86d..285ab4c9c7 100644 --- a/sound/soc/soc-card.c +++ b/sound/soc/soc-card.c @@ -42,8 +42,42 @@ struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, } EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); +static int jack_new(struct snd_soc_card *card, const char *id, int type, + struct snd_soc_jack *jack, bool initial_kctl) +{ + mutex_init(&jack->mutex); + jack->card = card; + INIT_LIST_HEAD(&jack->pins); + INIT_LIST_HEAD(&jack->jack_zones); + BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier); + + return snd_jack_new(card->snd_card, id, type, &jack->jack, initial_kctl, false); +} + +/** + * snd_soc_card_jack_new - Create a new jack without pins + * @card: ASoC card + * @id: an identifying string for this jack + * @type: a bitmask of enum snd_jack_type values that can be detected by + * this jack + * @jack: structure to use for the jack + * + * Creates a new jack object without pins. If adding pins later, + * snd_soc_card_jack_new_pins() should be used instead with 0 as num_pins + * argument. + * + * Returns zero if successful, or a negative error code on failure. + * On success jack will be initialised. + */ +int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, + struct snd_soc_jack *jack) +{ + return soc_card_ret(card, jack_new(card, id, type, jack, true)); +} +EXPORT_SYMBOL_GPL(snd_soc_card_jack_new); + /** - * snd_soc_card_jack_new - Create a new jack + * snd_soc_card_jack_new_pins - Create a new jack with pins * @card: ASoC card * @id: an identifying string for this jack * @type: a bitmask of enum snd_jack_type values that can be detected by @@ -52,24 +86,20 @@ EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); * @pins: Array of jack pins to be added to the jack or NULL * @num_pins: Number of elements in the @pins array * - * Creates a new jack object. + * Creates a new jack object with pins. If not adding pins, + * snd_soc_card_jack_new() should be used instead. * * Returns zero if successful, or a negative error code on failure. * On success jack will be initialised. */ -int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, - struct snd_soc_jack *jack, - struct snd_soc_jack_pin *pins, unsigned int num_pins) +int snd_soc_card_jack_new_pins(struct snd_soc_card *card, const char *id, + int type, struct snd_soc_jack *jack, + struct snd_soc_jack_pin *pins, + unsigned int num_pins) { int ret; - mutex_init(&jack->mutex); - jack->card = card; - INIT_LIST_HEAD(&jack->pins); - INIT_LIST_HEAD(&jack->jack_zones); - BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier); - - ret = snd_jack_new(card->snd_card, id, type, &jack->jack, false, false); + ret = jack_new(card, id, type, jack, false); if (ret) goto end; @@ -78,7 +108,7 @@ int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, end: return soc_card_ret(card, ret); } -EXPORT_SYMBOL_GPL(snd_soc_card_jack_new); +EXPORT_SYMBOL_GPL(snd_soc_card_jack_new_pins); int snd_soc_card_suspend_pre(struct snd_soc_card *card) { @@ -167,6 +197,12 @@ int snd_soc_card_late_probe(struct snd_soc_card *card) return 0; } +void snd_soc_card_fixup_controls(struct snd_soc_card *card) +{ + if (card->fixup_controls) + card->fixup_controls(card); +} + int snd_soc_card_remove(struct snd_soc_card *card) { int ret = 0; diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index c0664f9499..e12f824424 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -932,6 +932,20 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) return 0; } +static bool snd_soc_component_is_codec_on_rtd(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_component *component) +{ + struct snd_soc_dai *dai; + int i; + + for_each_rtd_codec_dais(rtd, i, dai) { + if (dai->component == component) + return true; + } + + return false; +} + void snd_soc_pcm_component_delay(struct snd_pcm_substream *substream, snd_pcm_sframes_t *cpu_delay, snd_pcm_sframes_t *codec_delay) @@ -953,7 +967,7 @@ void snd_soc_pcm_component_delay(struct snd_pcm_substream *substream, delay = component->driver->delay(component, substream); - if (snd_soc_component_is_codec(component)) + if (snd_soc_component_is_codec_on_rtd(rtd, component)) *codec_delay = max(*codec_delay, delay); else *cpu_delay = max(*cpu_delay, delay); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d3bd1e40c7..a802d6f78d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1210,11 +1210,10 @@ static void snd_soc_runtime_get_dai_fmt(struct snd_soc_pcm_runtime *rtd) * Returns 0 on success, otherwise a negative error code. */ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, - unsigned int dai_fmt) + unsigned int dai_fmt) { struct snd_soc_dai *cpu_dai; struct snd_soc_dai *codec_dai; - unsigned int inv_dai_fmt; unsigned int i; int ret; @@ -1235,31 +1234,11 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, return ret; } - /* - * Flip the polarity for the "CPU" end of a CODEC<->CODEC link - */ - inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK; - switch (dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; - break; - case SND_SOC_DAIFMT_CBM_CFS: - inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; - break; - case SND_SOC_DAIFMT_CBS_CFM: - inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFS; - break; - case SND_SOC_DAIFMT_CBS_CFS: - inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; - break; - } - for_each_rtd_cpu_dais(rtd, i, cpu_dai) { - unsigned int fmt = dai_fmt; - - if (snd_soc_component_is_codec(cpu_dai->component)) - fmt = inv_dai_fmt; + /* Flip the polarity for the "CPU" end of link */ + dai_fmt = snd_soc_daifmt_clock_provider_flipped(dai_fmt); - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { + ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt); if (ret != 0 && ret != -ENOTSUPP) return ret; } @@ -2095,6 +2074,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) goto probe_end; snd_soc_dapm_new_widgets(card); + snd_soc_card_fixup_controls(card); ret = snd_card_register(card->snd_card); if (ret < 0) { @@ -2347,14 +2327,12 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); * @card: Card to unregister * */ -int snd_soc_unregister_card(struct snd_soc_card *card) +void snd_soc_unregister_card(struct snd_soc_card *card) { mutex_lock(&client_mutex); snd_soc_unbind_card(card, true); mutex_unlock(&client_mutex); dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); - - return 0; } EXPORT_SYMBOL_GPL(snd_soc_unregister_card); @@ -2518,7 +2496,7 @@ static int snd_soc_register_dais(struct snd_soc_component *component, for (i = 0; i < count; i++) { dai = snd_soc_register_dai(component, dai_drv + i, count == 1 && - !snd_soc_component_is_codec(component)); + component->driver->legacy_dai_naming); if (dai == NULL) { ret = -ENOMEM; goto err; @@ -2784,6 +2762,11 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, "ASoC: Property '%s' does not exist\n", propname); return -EINVAL; } + if (!num_widgets) { + dev_err(card->dev, "ASoC: Property '%s's length is zero\n", + propname); + return -EINVAL; + } if (num_widgets & 1) { dev_err(card->dev, "ASoC: Property '%s' length is not even\n", propname); @@ -2791,11 +2774,6 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, } num_widgets /= 2; - if (!num_widgets) { - dev_err(card->dev, "ASoC: Property '%s's length is zero\n", - propname); - return -EINVAL; - } widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets), GFP_KERNEL); @@ -3056,7 +3034,7 @@ int snd_soc_of_parse_aux_devs(struct snd_soc_card *card, const char *propname) } EXPORT_SYMBOL_GPL(snd_soc_of_parse_aux_devs); -unsigned int snd_soc_daifmt_clock_provider_fliped(unsigned int dai_fmt) +unsigned int snd_soc_daifmt_clock_provider_flipped(unsigned int dai_fmt) { unsigned int inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; @@ -3077,7 +3055,7 @@ unsigned int snd_soc_daifmt_clock_provider_fliped(unsigned int dai_fmt) return inv_dai_fmt; } -EXPORT_SYMBOL_GPL(snd_soc_daifmt_clock_provider_fliped); +EXPORT_SYMBOL_GPL(snd_soc_daifmt_clock_provider_flipped); unsigned int snd_soc_daifmt_clock_provider_from_bitmap(unsigned int bit_frame) { @@ -3333,6 +3311,61 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, } EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); +static void __snd_soc_of_put_component(struct snd_soc_dai_link_component *component) +{ + if (component->of_node) { + of_node_put(component->of_node); + component->of_node = NULL; + } +} + +static int __snd_soc_of_get_dai_link_component_alloc( + struct device *dev, struct device_node *of_node, + struct snd_soc_dai_link_component **ret_component, + int *ret_num) +{ + struct snd_soc_dai_link_component *component; + int num; + + /* Count the number of CPUs/CODECs */ + num = of_count_phandle_with_args(of_node, "sound-dai", "#sound-dai-cells"); + if (num <= 0) { + if (num == -ENOENT) + dev_err(dev, "No 'sound-dai' property\n"); + else + dev_err(dev, "Bad phandle in 'sound-dai'\n"); + return num; + } + component = devm_kcalloc(dev, num, sizeof(*component), GFP_KERNEL); + if (!component) + return -ENOMEM; + + *ret_component = component; + *ret_num = num; + + return 0; +} + +static int __snd_soc_of_get_dai_link_component_parse( + struct device_node *of_node, + struct snd_soc_dai_link_component *component, int index) +{ + struct of_phandle_args args; + int ret; + + ret = of_parse_phandle_with_args(of_node, "sound-dai", "#sound-dai-cells", + index, &args); + if (ret) + return ret; + + ret = snd_soc_get_dai_name(&args, &component->dai_name); + if (ret < 0) + return ret; + + component->of_node = args.np; + return 0; +} + /* * snd_soc_of_put_dai_link_codecs - Dereference device nodes in the codecs array * @dai_link: DAI link @@ -3344,12 +3377,8 @@ void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link) struct snd_soc_dai_link_component *component; int index; - for_each_link_codecs(dai_link, index, component) { - if (!component->of_node) - break; - of_node_put(component->of_node); - component->of_node = NULL; - } + for_each_link_codecs(dai_link, index, component) + __snd_soc_of_put_component(component); } EXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_codecs); @@ -3371,41 +3400,19 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev, struct device_node *of_node, struct snd_soc_dai_link *dai_link) { - struct of_phandle_args args; struct snd_soc_dai_link_component *component; - char *name; - int index, num_codecs, ret; - - /* Count the number of CODECs */ - name = "sound-dai"; - num_codecs = of_count_phandle_with_args(of_node, name, - "#sound-dai-cells"); - if (num_codecs <= 0) { - if (num_codecs == -ENOENT) - dev_err(dev, "No 'sound-dai' property\n"); - else - dev_err(dev, "Bad phandle in 'sound-dai'\n"); - return num_codecs; - } - component = devm_kcalloc(dev, - num_codecs, sizeof(*component), - GFP_KERNEL); - if (!component) - return -ENOMEM; - dai_link->codecs = component; - dai_link->num_codecs = num_codecs; + int index, ret; + + ret = __snd_soc_of_get_dai_link_component_alloc(dev, of_node, + &dai_link->codecs, &dai_link->num_codecs); + if (ret < 0) + return ret; /* Parse the list */ for_each_link_codecs(dai_link, index, component) { - ret = of_parse_phandle_with_args(of_node, name, - "#sound-dai-cells", - index, &args); + ret = __snd_soc_of_get_dai_link_component_parse(of_node, component, index); if (ret) goto err; - component->of_node = args.np; - ret = snd_soc_get_dai_name(&args, &component->dai_name); - if (ret < 0) - goto err; } return 0; err: @@ -3416,6 +3423,61 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev, } EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs); +/* + * snd_soc_of_put_dai_link_cpus - Dereference device nodes in the codecs array + * @dai_link: DAI link + * + * Dereference device nodes acquired by snd_soc_of_get_dai_link_cpus(). + */ +void snd_soc_of_put_dai_link_cpus(struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_dai_link_component *component; + int index; + + for_each_link_cpus(dai_link, index, component) + __snd_soc_of_put_component(component); +} +EXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_cpus); + +/* + * snd_soc_of_get_dai_link_cpus - Parse a list of CPU DAIs in the devicetree + * @dev: Card device + * @of_node: Device node + * @dai_link: DAI link + * + * Is analogous to snd_soc_of_get_dai_link_codecs but parses a list of CPU DAIs + * instead. + * + * Returns 0 for success + */ +int snd_soc_of_get_dai_link_cpus(struct device *dev, + struct device_node *of_node, + struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_dai_link_component *component; + int index, ret; + + /* Count the number of CPUs */ + ret = __snd_soc_of_get_dai_link_component_alloc(dev, of_node, + &dai_link->cpus, &dai_link->num_cpus); + if (ret < 0) + return ret; + + /* Parse the list */ + for_each_link_cpus(dai_link, index, component) { + ret = __snd_soc_of_get_dai_link_component_parse(of_node, component, index); + if (ret) + goto err; + } + return 0; +err: + snd_soc_of_put_dai_link_cpus(dai_link); + dai_link->cpus = NULL; + dai_link->num_cpus = 0; + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_cpus); + static int __init snd_soc_init(void) { snd_soc_debugfs_init(); diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 6078afe335..d530e8c2b7 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -208,8 +208,7 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { int ret = -ENOTSUPP; - if (dai->driver->ops && - dai->driver->ops->set_fmt) + if (dai->driver->ops && dai->driver->ops->set_fmt) ret = dai->driver->ops->set_fmt(dai, fmt); return soc_dai_ret(dai, ret); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index ca917a849c..b05231414c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -62,6 +62,8 @@ struct snd_soc_dapm_widget * snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget); +static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg); + /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { [snd_soc_dapm_pre] = 1, @@ -368,14 +370,14 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, case snd_soc_dapm_mixer_named_ctl: mc = (struct soc_mixer_control *)kcontrol->private_value; - if (mc->autodisable && snd_soc_volsw_is_stereo(mc)) - dev_warn(widget->dapm->dev, - "ASoC: Unsupported stereo autodisable control '%s'\n", - ctrl_name); - if (mc->autodisable) { struct snd_soc_dapm_widget template; + if (snd_soc_volsw_is_stereo(mc)) + dev_warn(widget->dapm->dev, + "ASoC: Unsupported stereo autodisable control '%s'\n", + ctrl_name); + name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name, "Autodisable"); if (!name) { @@ -442,6 +444,9 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, snd_soc_dapm_add_path(widget->dapm, data->widget, widget, NULL, NULL); + } else if (e->reg != SND_SOC_NOPM) { + data->value = soc_dapm_read(widget->dapm, e->reg) & + (e->mask << e->shift_l); } break; default: @@ -3437,7 +3442,6 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, update.val = val; card->update = &update; } - change |= reg_change; ret = soc_dapm_mixer_update_power(card, kcontrol, connect, rconnect); @@ -3539,7 +3543,6 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, update.val = val; card->update = &update; } - change |= reg_change; ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e); diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 285441d6ae..87858462bb 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -79,29 +79,19 @@ static int dmaengine_pcm_hw_params(struct snd_soc_component *component, { struct dmaengine_pcm *pcm = soc_component_to_pcm(component); struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); - int (*prepare_slave_config)(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct dma_slave_config *slave_config); struct dma_slave_config slave_config; + int ret; - memset(&slave_config, 0, sizeof(slave_config)); - - if (!pcm->config) - prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config; - else - prepare_slave_config = pcm->config->prepare_slave_config; + if (!pcm->config->prepare_slave_config) + return 0; - if (prepare_slave_config) { - int ret = prepare_slave_config(substream, params, &slave_config); - if (ret) - return ret; + memset(&slave_config, 0, sizeof(slave_config)); - ret = dmaengine_slave_config(chan, &slave_config); - if (ret) - return ret; - } + ret = pcm->config->prepare_slave_config(substream, params, &slave_config); + if (ret) + return ret; - return 0; + return dmaengine_slave_config(chan, &slave_config); } static int @@ -121,7 +111,7 @@ dmaengine_pcm_set_runtime_hwparams(struct snd_soc_component *component, return -EINVAL; } - if (pcm->config && pcm->config->pcm_hardware) + if (pcm->config->pcm_hardware) return snd_soc_set_runtime_hwparams(substream, pcm->config->pcm_hardware); @@ -188,7 +178,6 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( { struct dmaengine_pcm *pcm = soc_component_to_pcm(component); struct snd_dmaengine_dai_dma_data *dma_data; - dma_filter_fn fn = NULL; if (rtd->num_cpus > 1) { dev_err(rtd->dev, @@ -201,13 +190,11 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) && pcm->chan[0]) return pcm->chan[0]; - if (pcm->config && pcm->config->compat_request_channel) + if (pcm->config->compat_request_channel) return pcm->config->compat_request_channel(rtd, substream); - if (pcm->config) - fn = pcm->config->compat_filter_fn; - - return snd_dmaengine_pcm_request_channel(fn, dma_data->filter_data); + return snd_dmaengine_pcm_request_channel(pcm->config->compat_filter_fn, + dma_data->filter_data); } static bool dmaengine_pcm_can_report_residue(struct device *dev, @@ -239,12 +226,12 @@ static int dmaengine_pcm_new(struct snd_soc_component *component, size_t max_buffer_size; unsigned int i; - if (config && config->prealloc_buffer_size) + if (config->prealloc_buffer_size) prealloc_buffer_size = config->prealloc_buffer_size; else prealloc_buffer_size = prealloc_buffer_size_kbytes * 1024; - if (config && config->pcm_hardware && config->pcm_hardware->buffer_bytes_max) + if (config->pcm_hardware && config->pcm_hardware->buffer_bytes_max) max_buffer_size = config->pcm_hardware->buffer_bytes_max; else max_buffer_size = SIZE_MAX; @@ -254,7 +241,7 @@ static int dmaengine_pcm_new(struct snd_soc_component *component, if (!substream) continue; - if (!pcm->chan[i] && config && config->chan_names[i]) + if (!pcm->chan[i] && config->chan_names[i]) pcm->chan[i] = dma_request_slave_channel(dev, config->chan_names[i]); @@ -367,10 +354,10 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, struct dma_chan *chan; if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || (!dev->of_node && - !(config && config->dma_dev && config->dma_dev->of_node))) + !(config->dma_dev && config->dma_dev->of_node))) return 0; - if (config && config->dma_dev) { + if (config->dma_dev) { /* * If this warning is seen, it probably means that your Linux * device structure does not match your HW device structure. @@ -387,7 +374,7 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, name = "rx-tx"; else name = dmaengine_pcm_dma_channel_names[i]; - if (config && config->chan_names[i]) + if (config->chan_names[i]) name = config->chan_names[i]; chan = dma_request_chan(dev, name); if (IS_ERR(chan)) { @@ -425,6 +412,10 @@ static void dmaengine_pcm_release_chan(struct dmaengine_pcm *pcm) } } +static const struct snd_dmaengine_pcm_config snd_dmaengine_pcm_default_config = { + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, +}; + /** * snd_dmaengine_pcm_register - Register a dmaengine based PCM device * @dev: The parent device for the PCM device @@ -445,6 +436,8 @@ int snd_dmaengine_pcm_register(struct device *dev, #ifdef CONFIG_DEBUG_FS pcm->component.debugfs_prefix = "dma"; #endif + if (!config) + config = &snd_dmaengine_pcm_default_config; pcm->config = config; pcm->flags = flags; @@ -452,7 +445,7 @@ int snd_dmaengine_pcm_register(struct device *dev, if (ret) goto err_free_dma; - if (config && config->process) + if (config->process) driver = &dmaengine_pcm_component_process; else driver = &dmaengine_pcm_component; diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index d798765d16..fcece5ca38 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -126,7 +126,7 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_get_type); /** * snd_soc_jack_add_pins - Associate DAPM pins with an ASoC jack * - * @jack: ASoC jack + * @jack: ASoC jack created with snd_soc_card_jack_new_pins() * @count: Number of pins * @pins: Array of pins * diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index e693070f51..bd88de0563 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -177,20 +176,28 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - int platform_max; - - if (!mc->platform_max) - mc->platform_max = mc->max; - platform_max = mc->platform_max; - - if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - else + const char *vol_string = NULL; + int max; + + max = uinfo->value.integer.max = mc->max - mc->min; + if (mc->platform_max && mc->platform_max < max) + max = mc->platform_max; + + if (max == 1) { + /* Even two value controls ending in Volume should always be integer */ + vol_string = strstr(kcontrol->id.name, " Volume"); + if (vol_string && !strcmp(vol_string, " Volume")) + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + } else { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + } uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; uinfo->value.integer.min = 0; - uinfo->value.integer.max = platform_max - mc->min; + uinfo->value.integer.max = max; + return 0; } EXPORT_SYMBOL_GPL(snd_soc_info_volsw); @@ -203,7 +210,8 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw); * Callback to provide information about a single mixer control, or a double * mixer control that spans 2 registers of the SX TLV type. SX TLV controls * have a range that represents both positive and negative values either side - * of zero but without a sign bit. + * of zero but without a sign bit. min is the minimum register value, max is + * the number of steps. * * Returns 0 for success. */ @@ -212,12 +220,21 @@ int snd_soc_info_volsw_sx(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + int max; - snd_soc_info_volsw(kcontrol, uinfo); - /* Max represents the number of levels in an SX control not the - * maximum value, so add the minimum value back on - */ - uinfo->value.integer.max += mc->min; + if (mc->platform_max) + max = mc->platform_max; + else + max = mc->max; + + if (max == 1 && !strstr(kcontrol->id.name, " Volume")) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + + uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = max; return 0; } @@ -526,7 +543,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, return -EINVAL; if (mc->platform_max && tmp > mc->platform_max) return -EINVAL; - if (tmp > mc->max - mc->min + 1) + if (tmp > mc->max - mc->min) return -EINVAL; if (invert) @@ -547,7 +564,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, return -EINVAL; if (mc->platform_max && tmp > mc->platform_max) return -EINVAL; - if (tmp > mc->max - mc->min + 1) + if (tmp > mc->max - mc->min) return -EINVAL; if (invert) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 11c9853e9e..4f60c0a833 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1209,8 +1209,7 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, return -EINVAL; } if (fe_substream->pcm->nonatomic && !be_substream->pcm->nonatomic) { - dev_warn(be->dev, "%s: FE is nonatomic but BE is not, forcing BE as nonatomic\n", - __func__); + dev_dbg(be->dev, "FE is nonatomic but BE is not, forcing BE as nonatomic\n"); be_substream->pcm->nonatomic = 1; } @@ -1318,6 +1317,9 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (!be->dai_link->no_pcm) continue; + if (!snd_soc_dpcm_get_substream(be, stream)) + continue; + for_each_rtd_dais(be, i, dai) { w = snd_soc_dai_get_widget(dai, stream); @@ -2090,6 +2092,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd) { struct snd_soc_pcm_runtime *be; + bool pause_stop_transition; struct snd_soc_dpcm *dpcm; unsigned long flags; int ret = 0; @@ -2121,7 +2124,12 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if (be->dpcm[stream].be_start != 1) goto next; - ret = soc_pcm_trigger(be_substream, cmd); + if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_PAUSED) + ret = soc_pcm_trigger(be_substream, + SNDRV_PCM_TRIGGER_PAUSE_RELEASE); + else + ret = soc_pcm_trigger(be_substream, + SNDRV_PCM_TRIGGER_START); if (ret) { be->dpcm[stream].be_start--; goto next; @@ -2148,10 +2156,12 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (!be->dpcm[stream].be_start && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) goto next; + fe->dpcm[stream].fe_pause = false; + be->dpcm[stream].be_pause--; + be->dpcm[stream].be_start++; if (be->dpcm[stream].be_start != 1) goto next; @@ -2175,14 +2185,33 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if (be->dpcm[stream].be_start != 0) goto next; - ret = soc_pcm_trigger(be_substream, cmd); + pause_stop_transition = false; + if (fe->dpcm[stream].fe_pause) { + pause_stop_transition = true; + fe->dpcm[stream].fe_pause = false; + be->dpcm[stream].be_pause--; + } + + if (be->dpcm[stream].be_pause != 0) + ret = soc_pcm_trigger(be_substream, SNDRV_PCM_TRIGGER_PAUSE_PUSH); + else + ret = soc_pcm_trigger(be_substream, SNDRV_PCM_TRIGGER_STOP); + if (ret) { if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_START) be->dpcm[stream].be_start++; + if (pause_stop_transition) { + fe->dpcm[stream].fe_pause = true; + be->dpcm[stream].be_pause++; + } goto next; } - be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; + if (be->dpcm[stream].be_pause != 0) + be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED; + else + be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; + break; case SNDRV_PCM_TRIGGER_SUSPEND: if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) @@ -2204,6 +2233,9 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) goto next; + fe->dpcm[stream].fe_pause = true; + be->dpcm[stream].be_pause++; + be->dpcm[stream].be_start--; if (be->dpcm[stream].be_start != 0) goto next; diff --git a/sound/soc/soc-topology-test.c b/sound/soc/soc-topology-test.c index ae39681615..2cd3540cec 100644 --- a/sound/soc/soc-topology-test.c +++ b/sound/soc/soc-topology-test.c @@ -104,7 +104,6 @@ static const struct snd_soc_component_driver test_component = { .name = "sound-soc-topology-test", .probe = d_probe, .remove = d_remove, - .non_legacy_dai_naming = 1, }; /* ===== TOPOLOGY TEMPLATES ================================================= */ @@ -238,7 +237,6 @@ static int d_probe_null_comp(struct snd_soc_component *component) static const struct snd_soc_component_driver test_component_null_comp = { .name = "sound-soc-topology-test", .probe = d_probe_null_comp, - .non_legacy_dai_naming = 1, }; static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test) @@ -271,9 +269,7 @@ static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, ret); /* cleanup */ - ret = snd_soc_unregister_card(&kunit_comp->card); - KUNIT_EXPECT_EQ(test, 0, ret); - + snd_soc_unregister_card(&kunit_comp->card); snd_soc_unregister_component(test_dev); } @@ -315,8 +311,7 @@ static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, ret); /* cleanup */ - ret = snd_soc_unregister_card(&kunit_comp->card); - KUNIT_EXPECT_EQ(test, 0, ret); + snd_soc_unregister_card(&kunit_comp->card); snd_soc_unregister_component(test_dev); } @@ -346,7 +341,6 @@ static int d_probe_null_fw(struct snd_soc_component *component) static const struct snd_soc_component_driver test_component_null_fw = { .name = "sound-soc-topology-test", .probe = d_probe_null_fw, - .non_legacy_dai_naming = 1, }; static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test) @@ -379,8 +373,7 @@ static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, ret); /* cleanup */ - ret = snd_soc_unregister_card(&kunit_comp->card); - KUNIT_EXPECT_EQ(test, 0, ret); + snd_soc_unregister_card(&kunit_comp->card); snd_soc_unregister_component(test_dev); } @@ -428,8 +421,7 @@ static void snd_soc_tplg_test_load_empty_tplg(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, ret); /* cleanup */ - ret = snd_soc_unregister_card(&kunit_comp->card); - KUNIT_EXPECT_EQ(test, 0, ret); + snd_soc_unregister_card(&kunit_comp->card); snd_soc_unregister_component(test_dev); } @@ -484,8 +476,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_magic(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, ret); /* cleanup */ - ret = snd_soc_unregister_card(&kunit_comp->card); - KUNIT_EXPECT_EQ(test, 0, ret); + snd_soc_unregister_card(&kunit_comp->card); snd_soc_unregister_component(test_dev); } @@ -540,8 +531,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_abi(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, ret); /* cleanup */ - ret = snd_soc_unregister_card(&kunit_comp->card); - KUNIT_EXPECT_EQ(test, 0, ret); + snd_soc_unregister_card(&kunit_comp->card); snd_soc_unregister_component(test_dev); } @@ -596,8 +586,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_size(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, ret); /* cleanup */ - ret = snd_soc_unregister_card(&kunit_comp->card); - KUNIT_EXPECT_EQ(test, 0, ret); + snd_soc_unregister_card(&kunit_comp->card); snd_soc_unregister_component(test_dev); } @@ -655,8 +644,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_payload_size(struct kunit *tes /* cleanup */ snd_soc_unregister_component(test_dev); - ret = snd_soc_unregister_card(&kunit_comp->card); - KUNIT_EXPECT_EQ(test, 0, ret); + snd_soc_unregister_card(&kunit_comp->card); } // TEST CASE @@ -704,8 +692,7 @@ static void snd_soc_tplg_test_load_pcm_tplg(struct kunit *test) snd_soc_unregister_component(test_dev); /* cleanup */ - ret = snd_soc_unregister_card(&kunit_comp->card); - KUNIT_EXPECT_EQ(test, 0, ret); + snd_soc_unregister_card(&kunit_comp->card); } // TEST CASE @@ -757,8 +744,7 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_comp(struct kunit *test) } /* cleanup */ - ret = snd_soc_unregister_card(&kunit_comp->card); - KUNIT_EXPECT_EQ(test, 0, ret); + snd_soc_unregister_card(&kunit_comp->card); } // TEST CASE @@ -806,8 +792,7 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_card(struct kunit *test) if (ret != 0 && ret != -EPROBE_DEFER) KUNIT_FAIL(test, "Failed to register card"); - ret = snd_soc_unregister_card(&kunit_comp->card); - KUNIT_EXPECT_EQ(test, 0, ret); + snd_soc_unregister_card(&kunit_comp->card); } /* cleanup */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 3bb90a8196..b101db8544 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -40,7 +40,7 @@ */ #define SOC_TPLG_PASS_MANIFEST 0 #define SOC_TPLG_PASS_VENDOR 1 -#define SOC_TPLG_PASS_MIXER 2 +#define SOC_TPLG_PASS_CONTROL 2 #define SOC_TPLG_PASS_WIDGET 3 #define SOC_TPLG_PASS_PCM_DAI 4 #define SOC_TPLG_PASS_GRAPH 5 @@ -104,13 +104,13 @@ static int soc_tplg_check_elem_count(struct soc_tplg *tplg, size_t elem_size, return 0; } -static inline int soc_tplg_is_eof(struct soc_tplg *tplg) +static inline bool soc_tplg_is_eof(struct soc_tplg *tplg) { const u8 *end = tplg->hdr_pos; if (end >= tplg->fw->data + tplg->fw->size) - return 1; - return 0; + return true; + return false; } static inline unsigned long soc_tplg_get_hdr_offset(struct soc_tplg *tplg) @@ -237,7 +237,7 @@ static inline void soc_control_err(struct soc_tplg *tplg, struct snd_soc_tplg_ctl_hdr *hdr, const char *name) { dev_err(tplg->dev, - "ASoC: no complete mixer IO handler for %s type (g,p,i) %d:%d:%d at 0x%lx\n", + "ASoC: no complete control IO handler for %s type (g,p,i) %d:%d:%d at 0x%lx\n", name, hdr->ops.get, hdr->ops.put, hdr->ops.info, soc_tplg_get_offset(tplg)); } @@ -360,7 +360,7 @@ static void remove_mixer(struct snd_soc_component *comp, { struct snd_card *card = comp->card->snd_card; - if (pass != SOC_TPLG_PASS_MIXER) + if (pass != SOC_TPLG_PASS_CONTROL) return; if (dobj->ops && dobj->ops->control_unload) @@ -376,7 +376,7 @@ static void remove_enum(struct snd_soc_component *comp, { struct snd_card *card = comp->card->snd_card; - if (pass != SOC_TPLG_PASS_MIXER) + if (pass != SOC_TPLG_PASS_CONTROL) return; if (dobj->ops && dobj->ops->control_unload) @@ -392,7 +392,7 @@ static void remove_bytes(struct snd_soc_component *comp, { struct snd_card *card = comp->card->snd_card; - if (pass != SOC_TPLG_PASS_MIXER) + if (pass != SOC_TPLG_PASS_CONTROL) return; if (dobj->ops && dobj->ops->control_unload) @@ -535,7 +535,7 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, * return an -EINVAL error and prevent the card from * being configured. */ - if (IS_ENABLED(CONFIG_SND_CTL_VALIDATION) && sbe->max > 512) + if (sbe->max > 512) k->access |= SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK; ext_ops = tplg->bytes_ext_ops; @@ -618,7 +618,7 @@ int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w, EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_bind_event); /* optionally pass new dynamic kcontrol to component driver. */ -static int soc_tplg_init_kcontrol(struct soc_tplg *tplg, +static int soc_tplg_control_load(struct soc_tplg *tplg, struct snd_kcontrol_new *k, struct snd_soc_tplg_ctl_hdr *hdr) { if (tplg->ops && tplg->ops->control_load) @@ -676,175 +676,156 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg, return 0; } -static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count, - size_t size) +static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size) { struct snd_soc_tplg_bytes_control *be; struct soc_bytes_ext *sbe; struct snd_kcontrol_new kc; - int i; - int err = 0; + int ret = 0; if (soc_tplg_check_elem_count(tplg, sizeof(struct snd_soc_tplg_bytes_control), - count, size, "mixer bytes")) + 1, size, "mixer bytes")) return -EINVAL; - for (i = 0; i < count; i++) { - be = (struct snd_soc_tplg_bytes_control *)tplg->pos; + be = (struct snd_soc_tplg_bytes_control *)tplg->pos; - /* validate kcontrol */ - if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + /* validate kcontrol */ + if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; - sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL); - if (sbe == NULL) - return -ENOMEM; + sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL); + if (sbe == NULL) + return -ENOMEM; - tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + - le32_to_cpu(be->priv.size)); + tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + + le32_to_cpu(be->priv.size)); - dev_dbg(tplg->dev, - "ASoC: adding bytes kcontrol %s with access 0x%x\n", - be->hdr.name, be->hdr.access); - - memset(&kc, 0, sizeof(kc)); - kc.name = be->hdr.name; - kc.private_value = (long)sbe; - kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc.access = le32_to_cpu(be->hdr.access); - - sbe->max = le32_to_cpu(be->max); - sbe->dobj.type = SND_SOC_DOBJ_BYTES; - sbe->dobj.ops = tplg->ops; - INIT_LIST_HEAD(&sbe->dobj.list); - - /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg); - if (err) { - soc_control_err(tplg, &be->hdr, be->hdr.name); - break; - } + dev_dbg(tplg->dev, + "ASoC: adding bytes kcontrol %s with access 0x%x\n", + be->hdr.name, be->hdr.access); - /* pass control to driver for optional further init */ - err = soc_tplg_init_kcontrol(tplg, &kc, - (struct snd_soc_tplg_ctl_hdr *)be); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", - be->hdr.name); - break; - } + memset(&kc, 0, sizeof(kc)); + kc.name = be->hdr.name; + kc.private_value = (long)sbe; + kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc.access = le32_to_cpu(be->hdr.access); - /* register control here */ - err = soc_tplg_add_kcontrol(tplg, &kc, - &sbe->dobj.control.kcontrol); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to add %s\n", - be->hdr.name); - break; - } + sbe->max = le32_to_cpu(be->max); + sbe->dobj.type = SND_SOC_DOBJ_BYTES; + sbe->dobj.ops = tplg->ops; + INIT_LIST_HEAD(&sbe->dobj.list); - list_add(&sbe->dobj.list, &tplg->comp->dobj_list); + /* map io handlers */ + ret = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg); + if (ret) { + soc_control_err(tplg, &be->hdr, be->hdr.name); + goto err; } - return err; + /* pass control to driver for optional further init */ + ret = soc_tplg_control_load(tplg, &kc, (struct snd_soc_tplg_ctl_hdr *)be); + if (ret < 0) { + dev_err(tplg->dev, "ASoC: failed to init %s\n", be->hdr.name); + goto err; + } + + /* register control here */ + ret = soc_tplg_add_kcontrol(tplg, &kc, &sbe->dobj.control.kcontrol); + if (ret < 0) { + dev_err(tplg->dev, "ASoC: failed to add %s\n", be->hdr.name); + goto err; + } + + list_add(&sbe->dobj.list, &tplg->comp->dobj_list); + +err: + return ret; } -static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, - size_t size) +static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size) { struct snd_soc_tplg_mixer_control *mc; struct soc_mixer_control *sm; struct snd_kcontrol_new kc; - int i; - int err = 0; + int ret = 0; if (soc_tplg_check_elem_count(tplg, sizeof(struct snd_soc_tplg_mixer_control), - count, size, "mixers")) + 1, size, "mixers")) return -EINVAL; - for (i = 0; i < count; i++) { - mc = (struct snd_soc_tplg_mixer_control *)tplg->pos; + mc = (struct snd_soc_tplg_mixer_control *)tplg->pos; - /* validate kcontrol */ - if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + /* validate kcontrol */ + if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; - sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL); - if (sm == NULL) - return -ENOMEM; - tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + - le32_to_cpu(mc->priv.size)); + sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL); + if (sm == NULL) + return -ENOMEM; + tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + + le32_to_cpu(mc->priv.size)); - dev_dbg(tplg->dev, - "ASoC: adding mixer kcontrol %s with access 0x%x\n", - mc->hdr.name, mc->hdr.access); - - memset(&kc, 0, sizeof(kc)); - kc.name = mc->hdr.name; - kc.private_value = (long)sm; - kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc.access = le32_to_cpu(mc->hdr.access); - - /* we only support FL/FR channel mapping atm */ - sm->reg = tplc_chan_get_reg(tplg, mc->channel, - SNDRV_CHMAP_FL); - sm->rreg = tplc_chan_get_reg(tplg, mc->channel, - SNDRV_CHMAP_FR); - sm->shift = tplc_chan_get_shift(tplg, mc->channel, - SNDRV_CHMAP_FL); - sm->rshift = tplc_chan_get_shift(tplg, mc->channel, - SNDRV_CHMAP_FR); - - sm->max = le32_to_cpu(mc->max); - sm->min = le32_to_cpu(mc->min); - sm->invert = le32_to_cpu(mc->invert); - sm->platform_max = le32_to_cpu(mc->platform_max); - sm->dobj.index = tplg->index; - sm->dobj.ops = tplg->ops; - sm->dobj.type = SND_SOC_DOBJ_MIXER; - INIT_LIST_HEAD(&sm->dobj.list); - - /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg); - if (err) { - soc_control_err(tplg, &mc->hdr, mc->hdr.name); - break; - } + dev_dbg(tplg->dev, + "ASoC: adding mixer kcontrol %s with access 0x%x\n", + mc->hdr.name, mc->hdr.access); - /* create any TLV data */ - err = soc_tplg_create_tlv(tplg, &kc, &mc->hdr); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", - mc->hdr.name); - break; - } + memset(&kc, 0, sizeof(kc)); + kc.name = mc->hdr.name; + kc.private_value = (long)sm; + kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc.access = le32_to_cpu(mc->hdr.access); - /* pass control to driver for optional further init */ - err = soc_tplg_init_kcontrol(tplg, &kc, - (struct snd_soc_tplg_ctl_hdr *) mc); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", - mc->hdr.name); - break; - } + /* we only support FL/FR channel mapping atm */ + sm->reg = tplc_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FL); + sm->rreg = tplc_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FR); + sm->shift = tplc_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FL); + sm->rshift = tplc_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FR); - /* register control here */ - err = soc_tplg_add_kcontrol(tplg, &kc, - &sm->dobj.control.kcontrol); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to add %s\n", - mc->hdr.name); - break; - } + sm->max = le32_to_cpu(mc->max); + sm->min = le32_to_cpu(mc->min); + sm->invert = le32_to_cpu(mc->invert); + sm->platform_max = le32_to_cpu(mc->platform_max); + sm->dobj.index = tplg->index; + sm->dobj.ops = tplg->ops; + sm->dobj.type = SND_SOC_DOBJ_MIXER; + INIT_LIST_HEAD(&sm->dobj.list); + + /* map io handlers */ + ret = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg); + if (ret) { + soc_control_err(tplg, &mc->hdr, mc->hdr.name); + goto err; + } - list_add(&sm->dobj.list, &tplg->comp->dobj_list); + /* create any TLV data */ + ret = soc_tplg_create_tlv(tplg, &kc, &mc->hdr); + if (ret < 0) { + dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", mc->hdr.name); + goto err; } - return err; + /* pass control to driver for optional further init */ + ret = soc_tplg_control_load(tplg, &kc, (struct snd_soc_tplg_ctl_hdr *)mc); + if (ret < 0) { + dev_err(tplg->dev, "ASoC: failed to init %s\n", mc->hdr.name); + goto err; + } + + /* register control here */ + ret = soc_tplg_add_kcontrol(tplg, &kc, &sm->dobj.control.kcontrol); + if (ret < 0) { + dev_err(tplg->dev, "ASoC: failed to add %s\n", mc->hdr.name); + goto err; + } + + list_add(&sm->dobj.list, &tplg->comp->dobj_list); + +err: + return ret; } static int soc_tplg_denum_create_texts(struct soc_tplg *tplg, struct soc_enum *se, @@ -911,117 +892,108 @@ static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum * return 0; } -static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, - size_t size) +static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size) { struct snd_soc_tplg_enum_control *ec; struct soc_enum *se; struct snd_kcontrol_new kc; - int i; - int err = 0; + int ret = 0; if (soc_tplg_check_elem_count(tplg, sizeof(struct snd_soc_tplg_enum_control), - count, size, "enums")) + 1, size, "enums")) return -EINVAL; - for (i = 0; i < count; i++) { - ec = (struct snd_soc_tplg_enum_control *)tplg->pos; + ec = (struct snd_soc_tplg_enum_control *)tplg->pos; - /* validate kcontrol */ - if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + /* validate kcontrol */ + if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; - se = devm_kzalloc(tplg->dev, (sizeof(*se)), GFP_KERNEL); - if (se == NULL) - return -ENOMEM; + se = devm_kzalloc(tplg->dev, (sizeof(*se)), GFP_KERNEL); + if (se == NULL) + return -ENOMEM; - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + - le32_to_cpu(ec->priv.size)); + tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + + le32_to_cpu(ec->priv.size)); - dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", - ec->hdr.name, ec->items); + dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", + ec->hdr.name, ec->items); - memset(&kc, 0, sizeof(kc)); - kc.name = ec->hdr.name; - kc.private_value = (long)se; - kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc.access = le32_to_cpu(ec->hdr.access); + memset(&kc, 0, sizeof(kc)); + kc.name = ec->hdr.name; + kc.private_value = (long)se; + kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc.access = le32_to_cpu(ec->hdr.access); - se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); - se->shift_l = tplc_chan_get_shift(tplg, ec->channel, - SNDRV_CHMAP_FL); - se->shift_r = tplc_chan_get_shift(tplg, ec->channel, - SNDRV_CHMAP_FL); + se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); + se->shift_l = tplc_chan_get_shift(tplg, ec->channel, + SNDRV_CHMAP_FL); + se->shift_r = tplc_chan_get_shift(tplg, ec->channel, + SNDRV_CHMAP_FL); - se->mask = le32_to_cpu(ec->mask); - se->dobj.index = tplg->index; - se->dobj.type = SND_SOC_DOBJ_ENUM; - se->dobj.ops = tplg->ops; - INIT_LIST_HEAD(&se->dobj.list); + se->mask = le32_to_cpu(ec->mask); + se->dobj.index = tplg->index; + se->dobj.type = SND_SOC_DOBJ_ENUM; + se->dobj.ops = tplg->ops; + INIT_LIST_HEAD(&se->dobj.list); - switch (le32_to_cpu(ec->hdr.ops.info)) { - case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: - case SND_SOC_TPLG_CTL_ENUM_VALUE: - err = soc_tplg_denum_create_values(tplg, se, ec); - if (err < 0) { - dev_err(tplg->dev, - "ASoC: could not create values for %s\n", - ec->hdr.name); - goto err_denum; - } - fallthrough; - case SND_SOC_TPLG_CTL_ENUM: - case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: - err = soc_tplg_denum_create_texts(tplg, se, ec); - if (err < 0) { - dev_err(tplg->dev, - "ASoC: could not create texts for %s\n", - ec->hdr.name); - goto err_denum; - } - break; - default: - err = -EINVAL; + switch (le32_to_cpu(ec->hdr.ops.info)) { + case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: + case SND_SOC_TPLG_CTL_ENUM_VALUE: + ret = soc_tplg_denum_create_values(tplg, se, ec); + if (ret < 0) { dev_err(tplg->dev, - "ASoC: invalid enum control type %d for %s\n", - ec->hdr.ops.info, ec->hdr.name); - goto err_denum; - } - - /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, tplg); - if (err) { - soc_control_err(tplg, &ec->hdr, ec->hdr.name); - goto err_denum; - } - - /* pass control to driver for optional further init */ - err = soc_tplg_init_kcontrol(tplg, &kc, - (struct snd_soc_tplg_ctl_hdr *) ec); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", + "ASoC: could not create values for %s\n", ec->hdr.name); - goto err_denum; + goto err; } - - /* register control here */ - err = soc_tplg_add_kcontrol(tplg, - &kc, &se->dobj.control.kcontrol); - if (err < 0) { - dev_err(tplg->dev, "ASoC: could not add kcontrol %s\n", + fallthrough; + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: + ret = soc_tplg_denum_create_texts(tplg, se, ec); + if (ret < 0) { + dev_err(tplg->dev, + "ASoC: could not create texts for %s\n", ec->hdr.name); - goto err_denum; + goto err; } + break; + default: + ret = -EINVAL; + dev_err(tplg->dev, + "ASoC: invalid enum control type %d for %s\n", + ec->hdr.ops.info, ec->hdr.name); + goto err; + } - list_add(&se->dobj.list, &tplg->comp->dobj_list); + /* map io handlers */ + ret = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, tplg); + if (ret) { + soc_control_err(tplg, &ec->hdr, ec->hdr.name); + goto err; } - return 0; -err_denum: - return err; + /* pass control to driver for optional further init */ + ret = soc_tplg_control_load(tplg, &kc, (struct snd_soc_tplg_ctl_hdr *)ec); + if (ret < 0) { + dev_err(tplg->dev, "ASoC: failed to init %s\n", ec->hdr.name); + goto err; + } + + /* register control here */ + ret = soc_tplg_add_kcontrol(tplg, &kc, &se->dobj.control.kcontrol); + if (ret < 0) { + dev_err(tplg->dev, "ASoC: could not add kcontrol %s\n", ec->hdr.name); + goto err; + } + + list_add(&se->dobj.list, &tplg->comp->dobj_list); + +err: + return ret; } static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg, @@ -1049,20 +1021,17 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg, case SND_SOC_TPLG_CTL_RANGE: case SND_SOC_TPLG_DAPM_CTL_VOLSW: case SND_SOC_TPLG_DAPM_CTL_PIN: - ret = soc_tplg_dmixer_create(tplg, 1, - le32_to_cpu(hdr->payload_size)); + ret = soc_tplg_dmixer_create(tplg, le32_to_cpu(hdr->payload_size)); break; case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_CTL_ENUM_VALUE: case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: - ret = soc_tplg_denum_create(tplg, 1, - le32_to_cpu(hdr->payload_size)); + ret = soc_tplg_denum_create(tplg, le32_to_cpu(hdr->payload_size)); break; case SND_SOC_TPLG_CTL_BYTES: - ret = soc_tplg_dbytes_create(tplg, 1, - le32_to_cpu(hdr->payload_size)); + ret = soc_tplg_dbytes_create(tplg, le32_to_cpu(hdr->payload_size)); break; default: soc_bind_err(tplg, control_hdr, i); @@ -1224,8 +1193,7 @@ static int soc_tplg_dapm_widget_dmixer_create(struct soc_tplg *tplg, struct snd_ } /* pass control to driver for optional further init */ - err = soc_tplg_init_kcontrol(tplg, kc, - (struct snd_soc_tplg_ctl_hdr *)mc); + err = soc_tplg_control_load(tplg, kc, (struct snd_soc_tplg_ctl_hdr *)mc); if (err < 0) { dev_err(tplg->dev, "ASoC: failed to init %s\n", mc->hdr.name); @@ -1309,8 +1277,7 @@ static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_k } /* pass control to driver for optional further init */ - err = soc_tplg_init_kcontrol(tplg, kc, - (struct snd_soc_tplg_ctl_hdr *)ec); + err = soc_tplg_control_load(tplg, kc, (struct snd_soc_tplg_ctl_hdr *)ec); if (err < 0) { dev_err(tplg->dev, "ASoC: failed to init %s\n", ec->hdr.name); @@ -1362,8 +1329,7 @@ static int soc_tplg_dapm_widget_dbytes_create(struct soc_tplg *tplg, struct snd_ } /* pass control to driver for optional further init */ - err = soc_tplg_init_kcontrol(tplg, kc, - (struct snd_soc_tplg_ctl_hdr *)be); + err = soc_tplg_control_load(tplg, kc, (struct snd_soc_tplg_ctl_hdr *)be); if (err < 0) { dev_err(tplg->dev, "ASoC: failed to init %s\n", be->hdr.name); @@ -2498,7 +2464,7 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, case SND_SOC_TPLG_TYPE_MIXER: case SND_SOC_TPLG_TYPE_ENUM: case SND_SOC_TPLG_TYPE_BYTES: - hdr_pass = SOC_TPLG_PASS_MIXER; + hdr_pass = SOC_TPLG_PASS_CONTROL; elem_load = soc_tplg_kcontrol_elems_load; break; case SND_SOC_TPLG_TYPE_DAPM_GRAPH: @@ -2550,10 +2516,8 @@ static int soc_tplg_process_headers(struct soc_tplg *tplg) { int ret; - tplg->pass = SOC_TPLG_PASS_START; - /* process the header types from start to end */ - while (tplg->pass <= SOC_TPLG_PASS_END) { + for (tplg->pass = SOC_TPLG_PASS_START; tplg->pass <= SOC_TPLG_PASS_END; tplg->pass++) { struct snd_soc_tplg_hdr *hdr; tplg->hdr_pos = tplg->fw->data; @@ -2585,8 +2549,6 @@ static int soc_tplg_process_headers(struct soc_tplg *tplg) hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos; } - /* next data type pass */ - tplg->pass++; } /* signal DAPM we are complete */ @@ -2653,10 +2615,10 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp) { struct snd_card *card = comp->card->snd_card; struct snd_soc_dobj *dobj, *next_dobj; - int pass = SOC_TPLG_PASS_END; + int pass; /* process the header types from end to start */ - while (pass >= SOC_TPLG_PASS_START) { + for (pass = SOC_TPLG_PASS_END; pass >= SOC_TPLG_PASS_START; pass--) { /* remove mixer controls */ down_write(&card->controls_rwsem); @@ -2699,7 +2661,6 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp) } } up_write(&card->controls_rwsem); - pass--; } /* let caller know if FW can be freed when no objects are left */ diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index a4efe7e52a..70c380c0ac 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -52,6 +53,50 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) } EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); +/** + * snd_soc_tdm_params_to_bclk - calculate bclk from params and tdm slot info. + * + * Calculate the bclk from the params sample rate and the tdm slot count and + * tdm slot width. Either or both of tdm_width and tdm_slots can be 0. + * + * If tdm_width == 0 and tdm_slots > 0: the params_width will be used. + * If tdm_width > 0 and tdm_slots == 0: the params_channels will be used + * as the slot count. + * Both tdm_width and tdm_slots are 0: this is equivalent to calling + * snd_soc_params_to_bclk(). + * + * If slot_multiple > 1 the slot count (or params_channels if tdm_slots == 0) + * will be rounded up to a multiple of this value. This is mainly useful for + * I2S mode, which has a left and right phase so the number of slots is always + * a multiple of 2. + * + * @params: Pointer to struct_pcm_hw_params. + * @tdm_width: Width in bits of the tdm slots. + * @tdm_slots: Number of tdm slots per frame. + * @slot_multiple: If >1 roundup slot count to a multiple of this value. + * + * Return: bclk frequency in Hz, else a negative error code if params format + * is invalid. + */ +int snd_soc_tdm_params_to_bclk(struct snd_pcm_hw_params *params, + int tdm_width, int tdm_slots, int slot_multiple) +{ + if (!tdm_slots) + tdm_slots = params_channels(params); + + if (slot_multiple > 1) + tdm_slots = roundup(tdm_slots, slot_multiple); + + if (!tdm_width) { + tdm_width = snd_pcm_format_width(params_format(params)); + if (tdm_width < 0) + return tdm_width; + } + + return snd_soc_calc_bclk(params_rate(params), tdm_width, 1, tdm_slots); +} +EXPORT_SYMBOL_GPL(snd_soc_tdm_params_to_bclk); + static const struct snd_pcm_hardware dummy_dma_hardware = { /* Random values to keep userspace happy when checking constraints */ .info = SNDRV_PCM_INFO_INTERLEAVED | @@ -96,7 +141,6 @@ static const struct snd_soc_component_driver dummy_codec = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #define STUB_RATES SNDRV_PCM_RATE_8000_384000 diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index 59b1dd4a54..2a3ed401ce 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c @@ -77,7 +77,8 @@ irqfd_resampler_ack(struct kvm_irq_ack_notifier *kian) idx = srcu_read_lock(&kvm->irq_srcu); - list_for_each_entry_rcu(irqfd, &resampler->list, resampler_link) + list_for_each_entry_srcu(irqfd, &resampler->list, resampler_link, + srcu_read_lock_held(&kvm->irq_srcu)) eventfd_signal(irqfd->resamplefd, 1); srcu_read_unlock(&kvm->irq_srcu, idx); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 6d971fb1b0..584a5bab3a 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -168,7 +168,7 @@ __weak void kvm_arch_guest_memory_reclaimed(struct kvm *kvm) { } -bool kvm_is_zone_device_pfn(kvm_pfn_t pfn) +bool kvm_is_zone_device_page(struct page *page) { /* * The metadata used by is_zone_device_page() to determine whether or @@ -176,25 +176,42 @@ bool kvm_is_zone_device_pfn(kvm_pfn_t pfn) * the device has been pinned, e.g. by get_user_pages(). WARN if the * page_count() is zero to help detect bad usage of this helper. */ - if (!pfn_valid(pfn) || WARN_ON_ONCE(!page_count(pfn_to_page(pfn)))) + if (WARN_ON_ONCE(!page_count(page))) return false; - return is_zone_device_page(pfn_to_page(pfn)); + return is_zone_device_page(page); } -bool kvm_is_reserved_pfn(kvm_pfn_t pfn) +/* + * Returns a 'struct page' if the pfn is "valid" and backed by a refcounted + * page, NULL otherwise. Note, the list of refcounted PG_reserved page types + * is likely incomplete, it has been compiled purely through people wanting to + * back guest with a certain type of memory and encountering issues. + */ +struct page *kvm_pfn_to_refcounted_page(kvm_pfn_t pfn) { + struct page *page; + + if (!pfn_valid(pfn)) + return NULL; + + page = pfn_to_page(pfn); + if (!PageReserved(page)) + return page; + + /* The ZERO_PAGE(s) is marked PG_reserved, but is refcounted. */ + if (is_zero_pfn(pfn)) + return page; + /* * ZONE_DEVICE pages currently set PG_reserved, but from a refcounting * perspective they are "normal" pages, albeit with slightly different * usage rules. */ - if (pfn_valid(pfn)) - return PageReserved(pfn_to_page(pfn)) && - !is_zero_pfn(pfn) && - !kvm_is_zone_device_pfn(pfn); + if (kvm_is_zone_device_page(page)) + return page; - return true; + return NULL; } /* @@ -239,7 +256,7 @@ static bool kvm_request_needs_ipi(struct kvm_vcpu *vcpu, unsigned req) return mode == IN_GUEST_MODE; } -static void ack_flush(void *_completed) +static void ack_kick(void *_completed) { } @@ -248,7 +265,7 @@ static inline bool kvm_kick_many_cpus(struct cpumask *cpus, bool wait) if (cpumask_empty(cpus)) return false; - smp_call_function_many(cpus, ack_flush, NULL, wait); + smp_call_function_many(cpus, ack_kick, NULL, wait); return true; } @@ -379,14 +396,31 @@ static inline void *mmu_memory_cache_alloc_obj(struct kvm_mmu_memory_cache *mc, return (void *)__get_free_page(gfp_flags); } -int kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int min) +int __kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int capacity, int min) { + gfp_t gfp = mc->gfp_custom ? mc->gfp_custom : GFP_KERNEL_ACCOUNT; void *obj; if (mc->nobjs >= min) return 0; - while (mc->nobjs < ARRAY_SIZE(mc->objects)) { - obj = mmu_memory_cache_alloc_obj(mc, GFP_KERNEL_ACCOUNT); + + if (unlikely(!mc->objects)) { + if (WARN_ON_ONCE(!capacity)) + return -EIO; + + mc->objects = kvmalloc_array(sizeof(void *), capacity, gfp); + if (!mc->objects) + return -ENOMEM; + + mc->capacity = capacity; + } + + /* It is illegal to request a different capacity across topups. */ + if (WARN_ON_ONCE(mc->capacity != capacity)) + return -EIO; + + while (mc->nobjs < mc->capacity) { + obj = mmu_memory_cache_alloc_obj(mc, gfp); if (!obj) return mc->nobjs >= min ? 0 : -ENOMEM; mc->objects[mc->nobjs++] = obj; @@ -394,6 +428,11 @@ int kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int min) return 0; } +int kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int min) +{ + return __kvm_mmu_topup_memory_cache(mc, KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE, min); +} + int kvm_mmu_memory_cache_nr_free_objects(struct kvm_mmu_memory_cache *mc) { return mc->nobjs; @@ -407,6 +446,11 @@ void kvm_mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc) else free_page((unsigned long)mc->objects[--mc->nobjs]); } + + kvfree(mc->objects); + + mc->objects = NULL; + mc->capacity = 0; } void *kvm_mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc) @@ -440,6 +484,10 @@ static void kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) vcpu->ready = false; preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops); vcpu->last_used_slot = NULL; + + /* Fill the stats id string for the vcpu */ + snprintf(vcpu->stats_id, sizeof(vcpu->stats_id), "kvm-%d/vcpu-%d", + task_pid_nr(current), id); } static void kvm_vcpu_destroy(struct kvm_vcpu *vcpu) @@ -654,30 +702,31 @@ static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn, /* * .change_pte() must be surrounded by .invalidate_range_{start,end}(). - * If mmu_notifier_count is zero, then no in-progress invalidations, - * including this one, found a relevant memslot at start(); rechecking - * memslots here is unnecessary. Note, a false positive (count elevated - * by a different invalidation) is sub-optimal but functionally ok. + * If mmu_invalidate_in_progress is zero, then no in-progress + * invalidations, including this one, found a relevant memslot at + * start(); rechecking memslots here is unnecessary. Note, a false + * positive (count elevated by a different invalidation) is sub-optimal + * but functionally ok. */ WARN_ON_ONCE(!READ_ONCE(kvm->mn_active_invalidate_count)); - if (!READ_ONCE(kvm->mmu_notifier_count)) + if (!READ_ONCE(kvm->mmu_invalidate_in_progress)) return; kvm_handle_hva_range(mn, address, address + 1, pte, kvm_set_spte_gfn); } -void kvm_inc_notifier_count(struct kvm *kvm, unsigned long start, - unsigned long end) +void kvm_mmu_invalidate_begin(struct kvm *kvm, unsigned long start, + unsigned long end) { /* * The count increase must become visible at unlock time as no * spte can be established without taking the mmu_lock and * count is also read inside the mmu_lock critical section. */ - kvm->mmu_notifier_count++; - if (likely(kvm->mmu_notifier_count == 1)) { - kvm->mmu_notifier_range_start = start; - kvm->mmu_notifier_range_end = end; + kvm->mmu_invalidate_in_progress++; + if (likely(kvm->mmu_invalidate_in_progress == 1)) { + kvm->mmu_invalidate_range_start = start; + kvm->mmu_invalidate_range_end = end; } else { /* * Fully tracking multiple concurrent ranges has diminishing @@ -688,10 +737,10 @@ void kvm_inc_notifier_count(struct kvm *kvm, unsigned long start, * accumulate and persist until all outstanding invalidates * complete. */ - kvm->mmu_notifier_range_start = - min(kvm->mmu_notifier_range_start, start); - kvm->mmu_notifier_range_end = - max(kvm->mmu_notifier_range_end, end); + kvm->mmu_invalidate_range_start = + min(kvm->mmu_invalidate_range_start, start); + kvm->mmu_invalidate_range_end = + max(kvm->mmu_invalidate_range_end, end); } } @@ -704,7 +753,7 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, .end = range->end, .pte = __pte(0), .handler = kvm_unmap_gfn_range, - .on_lock = kvm_inc_notifier_count, + .on_lock = kvm_mmu_invalidate_begin, .on_unlock = kvm_arch_guest_memory_reclaimed, .flush_on_ret = true, .may_block = mmu_notifier_range_blockable(range), @@ -715,7 +764,7 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, /* * Prevent memslot modification between range_start() and range_end() * so that conditionally locking provides the same result in both - * functions. Without that guarantee, the mmu_notifier_count + * functions. Without that guarantee, the mmu_invalidate_in_progress * adjustments will be imbalanced. * * Pairs with the decrement in range_end(). @@ -724,6 +773,16 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, kvm->mn_active_invalidate_count++; spin_unlock(&kvm->mn_invalidate_lock); + /* + * Invalidate pfn caches _before_ invalidating the secondary MMUs, i.e. + * before acquiring mmu_lock, to avoid holding mmu_lock while acquiring + * each cache's lock. There are relatively few caches in existence at + * any given time, and the caches themselves can check for hva overlap, + * i.e. don't need to rely on memslot overlap checks for performance. + * Because this runs without holding mmu_lock, the pfn caches must use + * mn_active_invalidate_count (see above) instead of + * mmu_invalidate_in_progress. + */ gfn_to_pfn_cache_invalidate_start(kvm, range->start, range->end, hva_range.may_block); @@ -732,22 +791,22 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, return 0; } -void kvm_dec_notifier_count(struct kvm *kvm, unsigned long start, - unsigned long end) +void kvm_mmu_invalidate_end(struct kvm *kvm, unsigned long start, + unsigned long end) { /* * This sequence increase will notify the kvm page fault that * the page that is going to be mapped in the spte could have * been freed. */ - kvm->mmu_notifier_seq++; + kvm->mmu_invalidate_seq++; smp_wmb(); /* * The above sequence increase must be visible before the * below count decrease, which is ensured by the smp_wmb above - * in conjunction with the smp_rmb in mmu_notifier_retry(). + * in conjunction with the smp_rmb in mmu_invalidate_retry(). */ - kvm->mmu_notifier_count--; + kvm->mmu_invalidate_in_progress--; } static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn, @@ -759,7 +818,7 @@ static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn, .end = range->end, .pte = __pte(0), .handler = (void *)kvm_null_fn, - .on_lock = kvm_dec_notifier_count, + .on_lock = kvm_mmu_invalidate_end, .on_unlock = (void *)kvm_null_fn, .flush_on_ret = false, .may_block = mmu_notifier_range_blockable(range), @@ -780,7 +839,7 @@ static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn, if (wake) rcuwait_wake_up(&kvm->mn_memslots_update_rcuwait); - BUG_ON(kvm->mmu_notifier_count < 0); + BUG_ON(kvm->mmu_invalidate_in_progress < 0); } static int kvm_mmu_notifier_clear_flush_young(struct mmu_notifier *mn, @@ -964,21 +1023,21 @@ static void kvm_destroy_vm_debugfs(struct kvm *kvm) } } -static int kvm_create_vm_debugfs(struct kvm *kvm, int fd) +static int kvm_create_vm_debugfs(struct kvm *kvm, const char *fdname) { static DEFINE_MUTEX(kvm_debugfs_lock); struct dentry *dent; char dir_name[ITOA_MAX_LEN * 2]; struct kvm_stat_data *stat_data; const struct _kvm_stats_desc *pdesc; - int i, ret; + int i, ret = -ENOMEM; int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc + kvm_vcpu_stats_header.num_desc; if (!debugfs_initialized()) return 0; - snprintf(dir_name, sizeof(dir_name), "%d-%d", task_pid_nr(current), fd); + snprintf(dir_name, sizeof(dir_name), "%d-%s", task_pid_nr(current), fdname); mutex_lock(&kvm_debugfs_lock); dent = debugfs_lookup(dir_name, kvm_debugfs_dir); if (dent) { @@ -997,13 +1056,13 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, int fd) sizeof(*kvm->debugfs_stat_data), GFP_KERNEL_ACCOUNT); if (!kvm->debugfs_stat_data) - return -ENOMEM; + goto out_err; for (i = 0; i < kvm_vm_stats_header.num_desc; ++i) { pdesc = &kvm_vm_stats_desc[i]; stat_data = kzalloc(sizeof(*stat_data), GFP_KERNEL_ACCOUNT); if (!stat_data) - return -ENOMEM; + goto out_err; stat_data->kvm = kvm; stat_data->desc = pdesc; @@ -1018,7 +1077,7 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, int fd) pdesc = &kvm_vcpu_stats_desc[i]; stat_data = kzalloc(sizeof(*stat_data), GFP_KERNEL_ACCOUNT); if (!stat_data) - return -ENOMEM; + goto out_err; stat_data->kvm = kvm; stat_data->desc = pdesc; @@ -1030,12 +1089,13 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, int fd) } ret = kvm_arch_create_vm_debugfs(kvm); - if (ret) { - kvm_destroy_vm_debugfs(kvm); - return i; - } + if (ret) + goto out_err; return 0; +out_err: + kvm_destroy_vm_debugfs(kvm); + return ret; } /* @@ -1066,7 +1126,7 @@ int __weak kvm_arch_create_vm_debugfs(struct kvm *kvm) return 0; } -static struct kvm *kvm_create_vm(unsigned long type) +static struct kvm *kvm_create_vm(unsigned long type, const char *fdname) { struct kvm *kvm = kvm_arch_alloc_vm(); struct kvm_memslots *slots; @@ -1076,6 +1136,9 @@ static struct kvm *kvm_create_vm(unsigned long type) if (!kvm) return ERR_PTR(-ENOMEM); + /* KVM is pinned via open("/dev/kvm"), the fd passed to this ioctl(). */ + __module_get(kvm_chardev_ops.owner); + KVM_MMU_LOCK_INIT(kvm); mmgrab(current->mm); kvm->mm = current->mm; @@ -1092,6 +1155,7 @@ static struct kvm *kvm_create_vm(unsigned long type) spin_lock_init(&kvm->gpc_lock); INIT_LIST_HEAD(&kvm->devices); + kvm->max_vcpus = KVM_MAX_VCPUS; BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX); @@ -1101,6 +1165,9 @@ static struct kvm *kvm_create_vm(unsigned long type) */ kvm->debugfs_dentry = ERR_PTR(-ENOENT); + snprintf(kvm->stats_id, sizeof(kvm->stats_id), "kvm-%d", + task_pid_nr(current)); + if (init_srcu_struct(&kvm->srcu)) goto out_err_no_srcu; if (init_srcu_struct(&kvm->irq_srcu)) @@ -1149,6 +1216,14 @@ static struct kvm *kvm_create_vm(unsigned long type) if (r) goto out_err_no_mmu_notifier; + r = kvm_coalesced_mmio_init(kvm); + if (r < 0) + goto out_no_coalesced_mmio; + + r = kvm_create_vm_debugfs(kvm, fdname); + if (r) + goto out_err_no_debugfs; + r = kvm_arch_post_init_vm(kvm); if (r) goto out_err; @@ -1160,19 +1235,13 @@ static struct kvm *kvm_create_vm(unsigned long type) preempt_notifier_inc(); kvm_init_pm_notifier(kvm); - /* - * When the fd passed to this ioctl() is opened it pins the module, - * but try_module_get() also prevents getting a reference if the module - * is in MODULE_STATE_GOING (e.g. if someone ran "rmmod --wait"). - */ - if (!try_module_get(kvm_chardev_ops.owner)) { - r = -ENODEV; - goto out_err; - } - return kvm; out_err: + kvm_destroy_vm_debugfs(kvm); +out_err_no_debugfs: + kvm_coalesced_mmio_free(kvm); +out_no_coalesced_mmio: #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER) if (kvm->mmu_notifier.ops) mmu_notifier_unregister(&kvm->mmu_notifier, current->mm); @@ -1191,6 +1260,7 @@ static struct kvm *kvm_create_vm(unsigned long type) out_err_no_srcu: kvm_arch_free_vm(kvm); mmdrop(current->mm); + module_put(kvm_chardev_ops.owner); return ERR_PTR(r); } @@ -1560,7 +1630,7 @@ static int kvm_prepare_memory_region(struct kvm *kvm, r = kvm_arch_prepare_memory_region(kvm, old, new, change); /* Free the bitmap on failure if it was allocated above. */ - if (r && new && new->dirty_bitmap && old && !old->dirty_bitmap) + if (r && new && new->dirty_bitmap && (!old || !old->dirty_bitmap)) kvm_destroy_dirty_bitmap(new); return r; @@ -2448,7 +2518,7 @@ static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault, { unsigned int flags = FOLL_HWPOISON; struct page *page; - int npages = 0; + int npages; might_sleep(); @@ -2491,9 +2561,12 @@ static bool vma_is_valid(struct vm_area_struct *vma, bool write_fault) static int kvm_try_get_pfn(kvm_pfn_t pfn) { - if (kvm_is_reserved_pfn(pfn)) + struct page *page = kvm_pfn_to_refcounted_page(pfn); + + if (!page) return 1; - return get_page_unless_zero(pfn_to_page(pfn)); + + return get_page_unless_zero(page); } static int hva_to_pfn_remapped(struct vm_area_struct *vma, @@ -2579,7 +2652,7 @@ kvm_pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, bool write_fault, bool *writable) { struct vm_area_struct *vma; - kvm_pfn_t pfn = 0; + kvm_pfn_t pfn; int npages, r; /* we can do it either atomically or asynchronously, not both */ @@ -2710,34 +2783,32 @@ int gfn_to_page_many_atomic(struct kvm_memory_slot *slot, gfn_t gfn, } EXPORT_SYMBOL_GPL(gfn_to_page_many_atomic); -static struct page *kvm_pfn_to_page(kvm_pfn_t pfn) -{ - if (is_error_noslot_pfn(pfn)) - return KVM_ERR_PTR_BAD_PAGE; - - if (kvm_is_reserved_pfn(pfn)) { - WARN_ON(1); - return KVM_ERR_PTR_BAD_PAGE; - } - - return pfn_to_page(pfn); -} - +/* + * Do not use this helper unless you are absolutely certain the gfn _must_ be + * backed by 'struct page'. A valid example is if the backing memslot is + * controlled by KVM. Note, if the returned page is valid, it's refcount has + * been elevated by gfn_to_pfn(). + */ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) { + struct page *page; kvm_pfn_t pfn; pfn = gfn_to_pfn(kvm, gfn); - return kvm_pfn_to_page(pfn); + if (is_error_noslot_pfn(pfn)) + return KVM_ERR_PTR_BAD_PAGE; + + page = kvm_pfn_to_refcounted_page(pfn); + if (!page) + return KVM_ERR_PTR_BAD_PAGE; + + return page; } EXPORT_SYMBOL_GPL(gfn_to_page); void kvm_release_pfn(kvm_pfn_t pfn, bool dirty) { - if (pfn == 0) - return; - if (dirty) kvm_release_pfn_dirty(pfn); else @@ -2803,28 +2874,48 @@ void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty) } EXPORT_SYMBOL_GPL(kvm_vcpu_unmap); -struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn) +static bool kvm_is_ad_tracked_page(struct page *page) { - kvm_pfn_t pfn; + /* + * Per page-flags.h, pages tagged PG_reserved "should in general not be + * touched (e.g. set dirty) except by its owner". + */ + return !PageReserved(page); +} - pfn = kvm_vcpu_gfn_to_pfn(vcpu, gfn); +static void kvm_set_page_dirty(struct page *page) +{ + if (kvm_is_ad_tracked_page(page)) + SetPageDirty(page); +} - return kvm_pfn_to_page(pfn); +static void kvm_set_page_accessed(struct page *page) +{ + if (kvm_is_ad_tracked_page(page)) + mark_page_accessed(page); } -EXPORT_SYMBOL_GPL(kvm_vcpu_gfn_to_page); void kvm_release_page_clean(struct page *page) { WARN_ON(is_error_page(page)); - kvm_release_pfn_clean(page_to_pfn(page)); + kvm_set_page_accessed(page); + put_page(page); } EXPORT_SYMBOL_GPL(kvm_release_page_clean); void kvm_release_pfn_clean(kvm_pfn_t pfn) { - if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn)) - put_page(pfn_to_page(pfn)); + struct page *page; + + if (is_error_noslot_pfn(pfn)) + return; + + page = kvm_pfn_to_refcounted_page(pfn); + if (!page) + return; + + kvm_release_page_clean(page); } EXPORT_SYMBOL_GPL(kvm_release_pfn_clean); @@ -2832,28 +2923,48 @@ void kvm_release_page_dirty(struct page *page) { WARN_ON(is_error_page(page)); - kvm_release_pfn_dirty(page_to_pfn(page)); + kvm_set_page_dirty(page); + kvm_release_page_clean(page); } EXPORT_SYMBOL_GPL(kvm_release_page_dirty); void kvm_release_pfn_dirty(kvm_pfn_t pfn) { - kvm_set_pfn_dirty(pfn); - kvm_release_pfn_clean(pfn); + struct page *page; + + if (is_error_noslot_pfn(pfn)) + return; + + page = kvm_pfn_to_refcounted_page(pfn); + if (!page) + return; + + kvm_release_page_dirty(page); } EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty); +/* + * Note, checking for an error/noslot pfn is the caller's responsibility when + * directly marking a page dirty/accessed. Unlike the "release" helpers, the + * "set" helpers are not to be used when the pfn might point at garbage. + */ void kvm_set_pfn_dirty(kvm_pfn_t pfn) { - if (!kvm_is_reserved_pfn(pfn) && !kvm_is_zone_device_pfn(pfn)) - SetPageDirty(pfn_to_page(pfn)); + if (WARN_ON(is_error_noslot_pfn(pfn))) + return; + + if (pfn_valid(pfn)) + kvm_set_page_dirty(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_set_pfn_dirty); void kvm_set_pfn_accessed(kvm_pfn_t pfn) { - if (!kvm_is_reserved_pfn(pfn) && !kvm_is_zone_device_pfn(pfn)) - mark_page_accessed(pfn_to_page(pfn)); + if (WARN_ON(is_error_noslot_pfn(pfn))) + return; + + if (pfn_valid(pfn)) + kvm_set_page_accessed(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed); @@ -3327,9 +3438,11 @@ bool kvm_vcpu_block(struct kvm_vcpu *vcpu) vcpu->stat.generic.blocking = 1; + preempt_disable(); kvm_arch_vcpu_blocking(vcpu); - prepare_to_rcuwait(wait); + preempt_enable(); + for (;;) { set_current_state(TASK_INTERRUPTIBLE); @@ -3339,9 +3452,11 @@ bool kvm_vcpu_block(struct kvm_vcpu *vcpu) waited = true; schedule(); } - finish_rcuwait(wait); + preempt_disable(); + finish_rcuwait(wait); kvm_arch_vcpu_unblocking(vcpu); + preempt_enable(); vcpu->stat.generic.blocking = 0; @@ -3723,9 +3838,18 @@ static int create_vcpu_fd(struct kvm_vcpu *vcpu) return anon_inode_getfd(name, &kvm_vcpu_fops, vcpu, O_RDWR | O_CLOEXEC); } +#ifdef __KVM_HAVE_ARCH_VCPU_DEBUGFS +static int vcpu_get_pid(void *data, u64 *val) +{ + struct kvm_vcpu *vcpu = (struct kvm_vcpu *) data; + *val = pid_nr(rcu_access_pointer(vcpu->pid)); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(vcpu_get_pid_fops, vcpu_get_pid, NULL, "%llu\n"); + static void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu) { -#ifdef __KVM_HAVE_ARCH_VCPU_DEBUGFS struct dentry *debugfs_dentry; char dir_name[ITOA_MAX_LEN * 2]; @@ -3735,10 +3859,12 @@ static void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu) snprintf(dir_name, sizeof(dir_name), "vcpu%d", vcpu->vcpu_id); debugfs_dentry = debugfs_create_dir(dir_name, vcpu->kvm->debugfs_dentry); + debugfs_create_file("pid", 0444, debugfs_dentry, vcpu, + &vcpu_get_pid_fops); kvm_arch_create_vcpu_debugfs(vcpu, debugfs_dentry); -#endif } +#endif /* * Creates some virtual cpus. Good luck creating more than one. @@ -3753,18 +3879,20 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) return -EINVAL; mutex_lock(&kvm->lock); - if (kvm->created_vcpus == KVM_MAX_VCPUS) { + if (kvm->created_vcpus >= kvm->max_vcpus) { mutex_unlock(&kvm->lock); return -EINVAL; } + r = kvm_arch_vcpu_precreate(kvm, id); + if (r) { + mutex_unlock(&kvm->lock); + return r; + } + kvm->created_vcpus++; mutex_unlock(&kvm->lock); - r = kvm_arch_vcpu_precreate(kvm, id); - if (r) - goto vcpu_decrement; - vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL_ACCOUNT); if (!vcpu) { r = -ENOMEM; @@ -3804,10 +3932,6 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) if (r) goto unlock_vcpu_destroy; - /* Fill the stats id string for the vcpu */ - snprintf(vcpu->stats_id, sizeof(vcpu->stats_id), "kvm-%d/vcpu-%d", - task_pid_nr(current), id); - /* Now it's all set up, let userspace reach it */ kvm_get_kvm(kvm); r = create_vcpu_fd(vcpu); @@ -4256,7 +4380,7 @@ void kvm_unregister_device_ops(u32 type) static int kvm_ioctl_create_device(struct kvm *kvm, struct kvm_create_device *cd) { - const struct kvm_device_ops *ops = NULL; + const struct kvm_device_ops *ops; struct kvm_device *dev; bool test = cd->flags & KVM_CREATE_DEVICE_TEST; int type; @@ -4299,8 +4423,11 @@ static int kvm_ioctl_create_device(struct kvm *kvm, kvm_put_kvm_no_destroy(kvm); mutex_lock(&kvm->lock); list_del(&dev->vm_node); + if (ops->release) + ops->release(dev); mutex_unlock(&kvm->lock); - ops->destroy(dev); + if (ops->destroy) + ops->destroy(dev); return ret; } @@ -4771,28 +4898,25 @@ EXPORT_SYMBOL_GPL(file_is_kvm); static int kvm_dev_ioctl_create_vm(unsigned long type) { - int r; + char fdname[ITOA_MAX_LEN + 1]; + int r, fd; struct kvm *kvm; struct file *file; - kvm = kvm_create_vm(type); - if (IS_ERR(kvm)) - return PTR_ERR(kvm); -#ifdef CONFIG_KVM_MMIO - r = kvm_coalesced_mmio_init(kvm); - if (r < 0) - goto put_kvm; -#endif - r = get_unused_fd_flags(O_CLOEXEC); - if (r < 0) - goto put_kvm; + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) + return fd; - snprintf(kvm->stats_id, sizeof(kvm->stats_id), - "kvm-%d", task_pid_nr(current)); + snprintf(fdname, sizeof(fdname), "%d", fd); + + kvm = kvm_create_vm(type, fdname); + if (IS_ERR(kvm)) { + r = PTR_ERR(kvm); + goto put_fd; + } file = anon_inode_getfile("kvm-vm", &kvm_vm_fops, kvm, O_RDWR); if (IS_ERR(file)) { - put_unused_fd(r); r = PTR_ERR(file); goto put_kvm; } @@ -4803,18 +4927,15 @@ static int kvm_dev_ioctl_create_vm(unsigned long type) * cases it will be called by the final fput(file) and will take * care of doing kvm_put_kvm(kvm). */ - if (kvm_create_vm_debugfs(kvm, r) < 0) { - put_unused_fd(r); - fput(file); - return -ENOMEM; - } kvm_uevent_notify_change(KVM_EVENT_CREATE_VM, kvm); - fd_install(r, file); - return r; + fd_install(fd, file); + return fd; put_kvm: kvm_put_kvm(kvm); +put_fd: + put_unused_fd(fd); return r; } diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index dd84676615..68ff41d395 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -95,48 +95,144 @@ bool kvm_gfn_to_pfn_cache_check(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, } EXPORT_SYMBOL_GPL(kvm_gfn_to_pfn_cache_check); -static void __release_gpc(struct kvm *kvm, kvm_pfn_t pfn, void *khva, gpa_t gpa) +static void gpc_unmap_khva(struct kvm *kvm, kvm_pfn_t pfn, void *khva) { - /* Unmap the old page if it was mapped before, and release it */ - if (!is_error_noslot_pfn(pfn)) { - if (khva) { - if (pfn_valid(pfn)) - kunmap(pfn_to_page(pfn)); + /* Unmap the old pfn/page if it was mapped before. */ + if (!is_error_noslot_pfn(pfn) && khva) { + if (pfn_valid(pfn)) + kunmap(pfn_to_page(pfn)); #ifdef CONFIG_HAS_IOMEM - else - memunmap(khva); + else + memunmap(khva); #endif - } - - kvm_release_pfn(pfn, false); } } -static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, unsigned long uhva) +static inline bool mmu_notifier_retry_cache(struct kvm *kvm, unsigned long mmu_seq) { + /* + * mn_active_invalidate_count acts for all intents and purposes + * like mmu_invalidate_in_progress here; but the latter cannot + * be used here because the invalidation of caches in the + * mmu_notifier event occurs _before_ mmu_invalidate_in_progress + * is elevated. + * + * Note, it does not matter that mn_active_invalidate_count + * is not protected by gpc->lock. It is guaranteed to + * be elevated before the mmu_notifier acquires gpc->lock, and + * isn't dropped until after mmu_invalidate_seq is updated. + */ + if (kvm->mn_active_invalidate_count) + return true; + + /* + * Ensure mn_active_invalidate_count is read before + * mmu_invalidate_seq. This pairs with the smp_wmb() in + * mmu_notifier_invalidate_range_end() to guarantee either the + * old (non-zero) value of mn_active_invalidate_count or the + * new (incremented) value of mmu_invalidate_seq is observed. + */ + smp_rmb(); + return kvm->mmu_invalidate_seq != mmu_seq; +} + +static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) +{ + /* Note, the new page offset may be different than the old! */ + void *old_khva = gpc->khva - offset_in_page(gpc->khva); + kvm_pfn_t new_pfn = KVM_PFN_ERR_FAULT; + void *new_khva = NULL; unsigned long mmu_seq; - kvm_pfn_t new_pfn; - int retry; + + lockdep_assert_held(&gpc->refresh_lock); + + lockdep_assert_held_write(&gpc->lock); + + /* + * Invalidate the cache prior to dropping gpc->lock, the gpa=>uhva + * assets have already been updated and so a concurrent check() from a + * different task may not fail the gpa/uhva/generation checks. + */ + gpc->valid = false; do { - mmu_seq = kvm->mmu_notifier_seq; + mmu_seq = kvm->mmu_invalidate_seq; smp_rmb(); + write_unlock_irq(&gpc->lock); + + /* + * If the previous iteration "failed" due to an mmu_notifier + * event, release the pfn and unmap the kernel virtual address + * from the previous attempt. Unmapping might sleep, so this + * needs to be done after dropping the lock. Opportunistically + * check for resched while the lock isn't held. + */ + if (new_pfn != KVM_PFN_ERR_FAULT) { + /* + * Keep the mapping if the previous iteration reused + * the existing mapping and didn't create a new one. + */ + if (new_khva != old_khva) + gpc_unmap_khva(kvm, new_pfn, new_khva); + + kvm_release_pfn_clean(new_pfn); + + cond_resched(); + } + /* We always request a writeable mapping */ - new_pfn = hva_to_pfn(uhva, false, NULL, true, NULL); + new_pfn = hva_to_pfn(gpc->uhva, false, NULL, true, NULL); if (is_error_noslot_pfn(new_pfn)) - break; + goto out_error; + + /* + * Obtain a new kernel mapping if KVM itself will access the + * pfn. Note, kmap() and memremap() can both sleep, so this + * too must be done outside of gpc->lock! + */ + if (gpc->usage & KVM_HOST_USES_PFN) { + if (new_pfn == gpc->pfn) { + new_khva = old_khva; + } else if (pfn_valid(new_pfn)) { + new_khva = kmap(pfn_to_page(new_pfn)); +#ifdef CONFIG_HAS_IOMEM + } else { + new_khva = memremap(pfn_to_hpa(new_pfn), PAGE_SIZE, MEMREMAP_WB); +#endif + } + if (!new_khva) { + kvm_release_pfn_clean(new_pfn); + goto out_error; + } + } + + write_lock_irq(&gpc->lock); + + /* + * Other tasks must wait for _this_ refresh to complete before + * attempting to refresh. + */ + WARN_ON_ONCE(gpc->valid); + } while (mmu_notifier_retry_cache(kvm, mmu_seq)); + + gpc->valid = true; + gpc->pfn = new_pfn; + gpc->khva = new_khva + (gpc->gpa & ~PAGE_MASK); - KVM_MMU_READ_LOCK(kvm); - retry = mmu_notifier_retry_hva(kvm, mmu_seq, uhva); - KVM_MMU_READ_UNLOCK(kvm); - if (!retry) - break; + /* + * Put the reference to the _new_ pfn. The pfn is now tracked by the + * cache and can be safely migrated, swapped, etc... as the cache will + * invalidate any mappings in response to relevant mmu_notifier events. + */ + kvm_release_pfn_clean(new_pfn); - cond_resched(); - } while (1); + return 0; - return new_pfn; +out_error: + write_lock_irq(&gpc->lock); + + return -EFAULT; } int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, @@ -146,9 +242,7 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, unsigned long page_offset = gpa & ~PAGE_MASK; kvm_pfn_t old_pfn, new_pfn; unsigned long old_uhva; - gpa_t old_gpa; void *old_khva; - bool old_valid; int ret = 0; /* @@ -158,13 +252,18 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, if (page_offset + len > PAGE_SIZE) return -EINVAL; + /* + * If another task is refreshing the cache, wait for it to complete. + * There is no guarantee that concurrent refreshes will see the same + * gpa, memslots generation, etc..., so they must be fully serialized. + */ + mutex_lock(&gpc->refresh_lock); + write_lock_irq(&gpc->lock); - old_gpa = gpc->gpa; old_pfn = gpc->pfn; old_khva = gpc->khva - offset_in_page(gpc->khva); old_uhva = gpc->uhva; - old_valid = gpc->valid; /* If the userspace HVA is invalid, refresh that first */ if (gpc->gpa != gpa || gpc->generation != slots->generation || @@ -177,64 +276,17 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpc->uhva = gfn_to_hva_memslot(gpc->memslot, gfn); if (kvm_is_error_hva(gpc->uhva)) { - gpc->pfn = KVM_PFN_ERR_FAULT; ret = -EFAULT; goto out; } - - gpc->uhva += page_offset; } /* * If the userspace HVA changed or the PFN was already invalid, * drop the lock and do the HVA to PFN lookup again. */ - if (!old_valid || old_uhva != gpc->uhva) { - unsigned long uhva = gpc->uhva; - void *new_khva = NULL; - - /* Placeholders for "hva is valid but not yet mapped" */ - gpc->pfn = KVM_PFN_ERR_FAULT; - gpc->khva = NULL; - gpc->valid = true; - - write_unlock_irq(&gpc->lock); - - new_pfn = hva_to_pfn_retry(kvm, uhva); - if (is_error_noslot_pfn(new_pfn)) { - ret = -EFAULT; - goto map_done; - } - - if (gpc->usage & KVM_HOST_USES_PFN) { - if (new_pfn == old_pfn) { - new_khva = old_khva; - old_pfn = KVM_PFN_ERR_FAULT; - old_khva = NULL; - } else if (pfn_valid(new_pfn)) { - new_khva = kmap(pfn_to_page(new_pfn)); -#ifdef CONFIG_HAS_IOMEM - } else { - new_khva = memremap(pfn_to_hpa(new_pfn), PAGE_SIZE, MEMREMAP_WB); -#endif - } - if (new_khva) - new_khva += page_offset; - else - ret = -EFAULT; - } - - map_done: - write_lock_irq(&gpc->lock); - if (ret) { - gpc->valid = false; - gpc->pfn = KVM_PFN_ERR_FAULT; - gpc->khva = NULL; - } else { - /* At this point, gpc->valid may already have been cleared */ - gpc->pfn = new_pfn; - gpc->khva = new_khva; - } + if (!gpc->valid || old_uhva != gpc->uhva) { + ret = hva_to_pfn_retry(kvm, gpc); } else { /* If the HVA→PFN mapping was already valid, don't unmap it. */ old_pfn = KVM_PFN_ERR_FAULT; @@ -242,9 +294,26 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, } out: + /* + * Invalidate the cache and purge the pfn/khva if the refresh failed. + * Some/all of the uhva, gpa, and memslot generation info may still be + * valid, leave it as is. + */ + if (ret) { + gpc->valid = false; + gpc->pfn = KVM_PFN_ERR_FAULT; + gpc->khva = NULL; + } + + /* Snapshot the new pfn before dropping the lock! */ + new_pfn = gpc->pfn; + write_unlock_irq(&gpc->lock); - __release_gpc(kvm, old_pfn, old_khva, old_gpa); + mutex_unlock(&gpc->refresh_lock); + + if (old_pfn != new_pfn) + gpc_unmap_khva(kvm, old_pfn, old_khva); return ret; } @@ -254,14 +323,13 @@ void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) { void *old_khva; kvm_pfn_t old_pfn; - gpa_t old_gpa; + mutex_lock(&gpc->refresh_lock); write_lock_irq(&gpc->lock); gpc->valid = false; old_khva = gpc->khva - offset_in_page(gpc->khva); - old_gpa = gpc->gpa; old_pfn = gpc->pfn; /* @@ -272,8 +340,9 @@ void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) gpc->pfn = KVM_PFN_ERR_FAULT; write_unlock_irq(&gpc->lock); + mutex_unlock(&gpc->refresh_lock); - __release_gpc(kvm, old_pfn, old_khva, old_gpa); + gpc_unmap_khva(kvm, old_pfn, old_khva); } EXPORT_SYMBOL_GPL(kvm_gfn_to_pfn_cache_unmap); @@ -286,6 +355,7 @@ int kvm_gfn_to_pfn_cache_init(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, if (!gpc->active) { rwlock_init(&gpc->lock); + mutex_init(&gpc->refresh_lock); gpc->khva = NULL; gpc->pfn = KVM_PFN_ERR_FAULT; diff --git a/virt/kvm/vfio.c b/virt/kvm/vfio.c index 8fcbc50221..ce1b01d02c 100644 --- a/virt/kvm/vfio.c +++ b/virt/kvm/vfio.c @@ -23,7 +23,7 @@ struct kvm_vfio_group { struct list_head node; - struct vfio_group *vfio_group; + struct file *file; }; struct kvm_vfio { @@ -32,118 +32,61 @@ struct kvm_vfio { bool noncoherent; }; -static struct vfio_group *kvm_vfio_group_get_external_user(struct file *filep) +static void kvm_vfio_file_set_kvm(struct file *file, struct kvm *kvm) { - struct vfio_group *vfio_group; - struct vfio_group *(*fn)(struct file *); + void (*fn)(struct file *file, struct kvm *kvm); - fn = symbol_get(vfio_group_get_external_user); - if (!fn) - return ERR_PTR(-EINVAL); - - vfio_group = fn(filep); - - symbol_put(vfio_group_get_external_user); - - return vfio_group; -} - -static bool kvm_vfio_external_group_match_file(struct vfio_group *group, - struct file *filep) -{ - bool ret, (*fn)(struct vfio_group *, struct file *); - - fn = symbol_get(vfio_external_group_match_file); - if (!fn) - return false; - - ret = fn(group, filep); - - symbol_put(vfio_external_group_match_file); - - return ret; -} - -static void kvm_vfio_group_put_external_user(struct vfio_group *vfio_group) -{ - void (*fn)(struct vfio_group *); - - fn = symbol_get(vfio_group_put_external_user); - if (!fn) - return; - - fn(vfio_group); - - symbol_put(vfio_group_put_external_user); -} - -static void kvm_vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm) -{ - void (*fn)(struct vfio_group *, struct kvm *); - - fn = symbol_get(vfio_group_set_kvm); + fn = symbol_get(vfio_file_set_kvm); if (!fn) return; - fn(group, kvm); + fn(file, kvm); - symbol_put(vfio_group_set_kvm); + symbol_put(vfio_file_set_kvm); } -static bool kvm_vfio_group_is_coherent(struct vfio_group *vfio_group) +static bool kvm_vfio_file_enforced_coherent(struct file *file) { - long (*fn)(struct vfio_group *, unsigned long); - long ret; + bool (*fn)(struct file *file); + bool ret; - fn = symbol_get(vfio_external_check_extension); + fn = symbol_get(vfio_file_enforced_coherent); if (!fn) return false; - ret = fn(vfio_group, VFIO_DMA_CC_IOMMU); + ret = fn(file); - symbol_put(vfio_external_check_extension); + symbol_put(vfio_file_enforced_coherent); - return ret > 0; + return ret; } -#ifdef CONFIG_SPAPR_TCE_IOMMU -static int kvm_vfio_external_user_iommu_id(struct vfio_group *vfio_group) +static struct iommu_group *kvm_vfio_file_iommu_group(struct file *file) { - int (*fn)(struct vfio_group *); - int ret = -EINVAL; + struct iommu_group *(*fn)(struct file *file); + struct iommu_group *ret; - fn = symbol_get(vfio_external_user_iommu_id); + fn = symbol_get(vfio_file_iommu_group); if (!fn) - return ret; + return NULL; - ret = fn(vfio_group); + ret = fn(file); - symbol_put(vfio_external_user_iommu_id); + symbol_put(vfio_file_iommu_group); return ret; } -static struct iommu_group *kvm_vfio_group_get_iommu_group( - struct vfio_group *group) -{ - int group_id = kvm_vfio_external_user_iommu_id(group); - - if (group_id < 0) - return NULL; - - return iommu_group_get_by_id(group_id); -} - +#ifdef CONFIG_SPAPR_TCE_IOMMU static void kvm_spapr_tce_release_vfio_group(struct kvm *kvm, - struct vfio_group *vfio_group) + struct kvm_vfio_group *kvg) { - struct iommu_group *grp = kvm_vfio_group_get_iommu_group(vfio_group); + struct iommu_group *grp = kvm_vfio_file_iommu_group(kvg->file); if (WARN_ON_ONCE(!grp)) return; kvm_spapr_tce_release_iommu_group(kvm, grp); - iommu_group_put(grp); } #endif @@ -163,7 +106,7 @@ static void kvm_vfio_update_coherency(struct kvm_device *dev) mutex_lock(&kv->lock); list_for_each_entry(kvg, &kv->group_list, node) { - if (!kvm_vfio_group_is_coherent(kvg->vfio_group)) { + if (!kvm_vfio_file_enforced_coherent(kvg->file)) { noncoherent = true; break; } @@ -181,149 +124,162 @@ static void kvm_vfio_update_coherency(struct kvm_device *dev) mutex_unlock(&kv->lock); } -static int kvm_vfio_set_group(struct kvm_device *dev, long attr, u64 arg) +static int kvm_vfio_group_add(struct kvm_device *dev, unsigned int fd) { struct kvm_vfio *kv = dev->private; - struct vfio_group *vfio_group; struct kvm_vfio_group *kvg; - int32_t __user *argp = (int32_t __user *)(unsigned long)arg; - struct fd f; - int32_t fd; + struct file *filp; int ret; - switch (attr) { - case KVM_DEV_VFIO_GROUP_ADD: - if (get_user(fd, argp)) - return -EFAULT; - - f = fdget(fd); - if (!f.file) - return -EBADF; - - vfio_group = kvm_vfio_group_get_external_user(f.file); - fdput(f); + filp = fget(fd); + if (!filp) + return -EBADF; - if (IS_ERR(vfio_group)) - return PTR_ERR(vfio_group); - - mutex_lock(&kv->lock); + /* Ensure the FD is a vfio group FD.*/ + if (!kvm_vfio_file_iommu_group(filp)) { + ret = -EINVAL; + goto err_fput; + } - list_for_each_entry(kvg, &kv->group_list, node) { - if (kvg->vfio_group == vfio_group) { - mutex_unlock(&kv->lock); - kvm_vfio_group_put_external_user(vfio_group); - return -EEXIST; - } - } + mutex_lock(&kv->lock); - kvg = kzalloc(sizeof(*kvg), GFP_KERNEL_ACCOUNT); - if (!kvg) { - mutex_unlock(&kv->lock); - kvm_vfio_group_put_external_user(vfio_group); - return -ENOMEM; + list_for_each_entry(kvg, &kv->group_list, node) { + if (kvg->file == filp) { + ret = -EEXIST; + goto err_unlock; } + } - list_add_tail(&kvg->node, &kv->group_list); - kvg->vfio_group = vfio_group; + kvg = kzalloc(sizeof(*kvg), GFP_KERNEL_ACCOUNT); + if (!kvg) { + ret = -ENOMEM; + goto err_unlock; + } - kvm_arch_start_assignment(dev->kvm); + kvg->file = filp; + list_add_tail(&kvg->node, &kv->group_list); - mutex_unlock(&kv->lock); + kvm_arch_start_assignment(dev->kvm); - kvm_vfio_group_set_kvm(vfio_group, dev->kvm); + mutex_unlock(&kv->lock); - kvm_vfio_update_coherency(dev); + kvm_vfio_file_set_kvm(kvg->file, dev->kvm); + kvm_vfio_update_coherency(dev); - return 0; + return 0; +err_unlock: + mutex_unlock(&kv->lock); +err_fput: + fput(filp); + return ret; +} - case KVM_DEV_VFIO_GROUP_DEL: - if (get_user(fd, argp)) - return -EFAULT; +static int kvm_vfio_group_del(struct kvm_device *dev, unsigned int fd) +{ + struct kvm_vfio *kv = dev->private; + struct kvm_vfio_group *kvg; + struct fd f; + int ret; - f = fdget(fd); - if (!f.file) - return -EBADF; + f = fdget(fd); + if (!f.file) + return -EBADF; - ret = -ENOENT; + ret = -ENOENT; - mutex_lock(&kv->lock); + mutex_lock(&kv->lock); - list_for_each_entry(kvg, &kv->group_list, node) { - if (!kvm_vfio_external_group_match_file(kvg->vfio_group, - f.file)) - continue; + list_for_each_entry(kvg, &kv->group_list, node) { + if (kvg->file != f.file) + continue; - list_del(&kvg->node); - kvm_arch_end_assignment(dev->kvm); + list_del(&kvg->node); + kvm_arch_end_assignment(dev->kvm); #ifdef CONFIG_SPAPR_TCE_IOMMU - kvm_spapr_tce_release_vfio_group(dev->kvm, - kvg->vfio_group); + kvm_spapr_tce_release_vfio_group(dev->kvm, kvg); #endif - kvm_vfio_group_set_kvm(kvg->vfio_group, NULL); - kvm_vfio_group_put_external_user(kvg->vfio_group); - kfree(kvg); - ret = 0; - break; - } + kvm_vfio_file_set_kvm(kvg->file, NULL); + fput(kvg->file); + kfree(kvg); + ret = 0; + break; + } - mutex_unlock(&kv->lock); + mutex_unlock(&kv->lock); - fdput(f); + fdput(f); - kvm_vfio_update_coherency(dev); + kvm_vfio_update_coherency(dev); - return ret; + return ret; +} #ifdef CONFIG_SPAPR_TCE_IOMMU - case KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE: { - struct kvm_vfio_spapr_tce param; - struct kvm_vfio *kv = dev->private; - struct vfio_group *vfio_group; - struct kvm_vfio_group *kvg; - struct fd f; - struct iommu_group *grp; +static int kvm_vfio_group_set_spapr_tce(struct kvm_device *dev, + void __user *arg) +{ + struct kvm_vfio_spapr_tce param; + struct kvm_vfio *kv = dev->private; + struct kvm_vfio_group *kvg; + struct fd f; + int ret; - if (copy_from_user(¶m, (void __user *)arg, - sizeof(struct kvm_vfio_spapr_tce))) - return -EFAULT; + if (copy_from_user(¶m, arg, sizeof(struct kvm_vfio_spapr_tce))) + return -EFAULT; - f = fdget(param.groupfd); - if (!f.file) - return -EBADF; + f = fdget(param.groupfd); + if (!f.file) + return -EBADF; - vfio_group = kvm_vfio_group_get_external_user(f.file); - fdput(f); + ret = -ENOENT; - if (IS_ERR(vfio_group)) - return PTR_ERR(vfio_group); + mutex_lock(&kv->lock); - grp = kvm_vfio_group_get_iommu_group(vfio_group); + list_for_each_entry(kvg, &kv->group_list, node) { + struct iommu_group *grp; + + if (kvg->file != f.file) + continue; + + grp = kvm_vfio_file_iommu_group(kvg->file); if (WARN_ON_ONCE(!grp)) { - kvm_vfio_group_put_external_user(vfio_group); - return -EIO; + ret = -EIO; + goto err_fdput; } - ret = -ENOENT; - - mutex_lock(&kv->lock); + ret = kvm_spapr_tce_attach_iommu_group(dev->kvm, param.tablefd, + grp); + break; + } - list_for_each_entry(kvg, &kv->group_list, node) { - if (kvg->vfio_group != vfio_group) - continue; +err_fdput: + mutex_unlock(&kv->lock); + fdput(f); + return ret; +} +#endif - ret = kvm_spapr_tce_attach_iommu_group(dev->kvm, - param.tablefd, grp); - break; - } +static int kvm_vfio_set_group(struct kvm_device *dev, long attr, + void __user *arg) +{ + int32_t __user *argp = arg; + int32_t fd; - mutex_unlock(&kv->lock); + switch (attr) { + case KVM_DEV_VFIO_GROUP_ADD: + if (get_user(fd, argp)) + return -EFAULT; + return kvm_vfio_group_add(dev, fd); - iommu_group_put(grp); - kvm_vfio_group_put_external_user(vfio_group); + case KVM_DEV_VFIO_GROUP_DEL: + if (get_user(fd, argp)) + return -EFAULT; + return kvm_vfio_group_del(dev, fd); - return ret; - } -#endif /* CONFIG_SPAPR_TCE_IOMMU */ +#ifdef CONFIG_SPAPR_TCE_IOMMU + case KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE: + return kvm_vfio_group_set_spapr_tce(dev, arg); +#endif } return -ENXIO; @@ -334,7 +290,8 @@ static int kvm_vfio_set_attr(struct kvm_device *dev, { switch (attr->group) { case KVM_DEV_VFIO_GROUP: - return kvm_vfio_set_group(dev, attr->attr, attr->addr); + return kvm_vfio_set_group(dev, attr->attr, + u64_to_user_ptr(attr->addr)); } return -ENXIO; @@ -367,10 +324,10 @@ static void kvm_vfio_destroy(struct kvm_device *dev) list_for_each_entry_safe(kvg, tmp, &kv->group_list, node) { #ifdef CONFIG_SPAPR_TCE_IOMMU - kvm_spapr_tce_release_vfio_group(dev->kvm, kvg->vfio_group); + kvm_spapr_tce_release_vfio_group(dev->kvm, kvg); #endif - kvm_vfio_group_set_kvm(kvg->vfio_group, NULL); - kvm_vfio_group_put_external_user(kvg->vfio_group); + kvm_vfio_file_set_kvm(kvg->file, NULL); + fput(kvg->file); list_del(&kvg->node); kfree(kvg); kvm_arch_end_assignment(dev->kvm);