From 3aa6be30da899619c44aa654313ba66eb44e7291 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Mon, 3 Jun 2019 11:34:01 -0700 Subject: mfd: cros_ec: Update I2S API Improve I2S API. Rename ec_response_codec_gain into ec_codec_i2s_gain, update caller accordlingly. Signed-off-by: Gwendal Grignou Acked-by: Enric Balletbo i Serra Acked-by: Benson Leung Reviewed-by: Fabien Lahoudere Signed-off-by: Lee Jones --- sound/soc/codecs/cros_ec_codec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 99a3af8a15ff..87830ed5ebf4 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -38,21 +38,21 @@ static const DECLARE_TLV_DB_SCALE(ec_mic_gain_tlv, 0, 100, 0); static int ec_command_get_gain(struct snd_soc_component *component, struct ec_param_codec_i2s *param, - struct ec_response_codec_gain *resp) + struct ec_codec_i2s_gain *resp) { struct cros_ec_codec_data *codec_data = snd_soc_component_get_drvdata(component); struct cros_ec_device *ec_device = codec_data->ec_device; u8 buffer[sizeof(struct cros_ec_command) + max(sizeof(struct ec_param_codec_i2s), - sizeof(struct ec_response_codec_gain))]; + sizeof(struct ec_codec_i2s_gain))]; struct cros_ec_command *msg = (struct cros_ec_command *)&buffer; int ret; msg->version = 0; msg->command = EC_CMD_CODEC_I2S; msg->outsize = sizeof(struct ec_param_codec_i2s); - msg->insize = sizeof(struct ec_response_codec_gain); + msg->insize = sizeof(struct ec_codec_i2s_gain); memcpy(msg->data, param, msg->outsize); @@ -226,7 +226,7 @@ static int get_ec_mic_gain(struct snd_soc_component *component, u8 *left, u8 *right) { struct ec_param_codec_i2s param; - struct ec_response_codec_gain resp; + struct ec_codec_i2s_gain resp; int ret; param.cmd = EC_CODEC_GET_GAIN; -- cgit v1.2.3 From cd238effefa28fac177e51dcf5e9d1a8b59c3c6b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Jun 2019 14:52:48 -0300 Subject: docs: kbuild: convert docs to ReST and rename to *.rst The kbuild documentation clearly shows that the documents there are written at different times: some use markdown, some use their own peculiar logic to split sections. Convert everything to ReST without affecting too much the author's style and avoiding adding uneeded markups. The conversion is actually: - add blank lines and identation in order to identify paragraphs; - fix tables markups; - add some lists markups; - mark literal blocks; - adjust title markups. At its new index.rst, let's add a :orphan: while this is not linked to the main index.rst file, in order to avoid build warnings. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Corbet --- Documentation/admin-guide/README.rst | 2 +- Documentation/kbuild/headers_install.rst | 51 + Documentation/kbuild/headers_install.txt | 50 - Documentation/kbuild/index.rst | 27 + Documentation/kbuild/issues.rst | 11 + Documentation/kbuild/kbuild.rst | 265 ++++ Documentation/kbuild/kbuild.txt | 248 ---- Documentation/kbuild/kconfig-language.rst | 689 +++++++++ Documentation/kbuild/kconfig-language.txt | 669 --------- Documentation/kbuild/kconfig-macro-language.rst | 247 ++++ Documentation/kbuild/kconfig-macro-language.txt | 242 ---- Documentation/kbuild/kconfig.rst | 300 ++++ Documentation/kbuild/kconfig.txt | 272 ---- Documentation/kbuild/makefiles.rst | 1509 ++++++++++++++++++++ Documentation/kbuild/makefiles.txt | 1369 ------------------ Documentation/kbuild/modules.rst | 571 ++++++++ Documentation/kbuild/modules.txt | 541 ------- Documentation/kernel-hacking/hacking.rst | 4 +- Documentation/process/coding-style.rst | 2 +- Documentation/process/submit-checklist.rst | 2 +- .../translations/it_IT/kernel-hacking/hacking.rst | 4 +- .../translations/it_IT/process/coding-style.rst | 2 +- .../it_IT/process/submit-checklist.rst | 2 +- .../translations/zh_CN/process/coding-style.rst | 2 +- .../zh_CN/process/submit-checklist.rst | 2 +- Kconfig | 2 +- arch/arc/plat-eznps/Kconfig | 2 +- arch/c6x/Kconfig | 2 +- arch/microblaze/Kconfig.debug | 2 +- arch/microblaze/Kconfig.platform | 2 +- arch/nds32/Kconfig | 2 +- arch/openrisc/Kconfig | 2 +- arch/powerpc/sysdev/Kconfig | 2 +- arch/riscv/Kconfig | 2 +- drivers/auxdisplay/Kconfig | 2 +- drivers/firmware/Kconfig | 2 +- drivers/mtd/devices/Kconfig | 2 +- drivers/net/ethernet/smsc/Kconfig | 6 +- drivers/net/wireless/intel/iwlegacy/Kconfig | 4 +- drivers/net/wireless/intel/iwlwifi/Kconfig | 2 +- drivers/parport/Kconfig | 2 +- drivers/scsi/Kconfig | 4 +- drivers/staging/sm750fb/Kconfig | 2 +- drivers/usb/misc/Kconfig | 4 +- drivers/video/fbdev/Kconfig | 14 +- net/bridge/netfilter/Kconfig | 2 +- net/ipv4/netfilter/Kconfig | 2 +- net/ipv6/netfilter/Kconfig | 2 +- net/netfilter/Kconfig | 16 +- net/tipc/Kconfig | 2 +- scripts/Kbuild.include | 4 +- scripts/Makefile.host | 2 +- scripts/kconfig/symbol.c | 2 +- .../tests/err_recursive_dep/expected_stderr | 14 +- sound/oss/dmasound/Kconfig | 6 +- 55 files changed, 3738 insertions(+), 3459 deletions(-) create mode 100644 Documentation/kbuild/headers_install.rst delete mode 100644 Documentation/kbuild/headers_install.txt create mode 100644 Documentation/kbuild/index.rst create mode 100644 Documentation/kbuild/issues.rst create mode 100644 Documentation/kbuild/kbuild.rst delete mode 100644 Documentation/kbuild/kbuild.txt create mode 100644 Documentation/kbuild/kconfig-language.rst delete mode 100644 Documentation/kbuild/kconfig-language.txt create mode 100644 Documentation/kbuild/kconfig-macro-language.rst delete mode 100644 Documentation/kbuild/kconfig-macro-language.txt create mode 100644 Documentation/kbuild/kconfig.rst delete mode 100644 Documentation/kbuild/kconfig.txt create mode 100644 Documentation/kbuild/makefiles.rst delete mode 100644 Documentation/kbuild/makefiles.txt create mode 100644 Documentation/kbuild/modules.rst delete mode 100644 Documentation/kbuild/modules.txt (limited to 'sound') diff --git a/Documentation/admin-guide/README.rst b/Documentation/admin-guide/README.rst index a582c780c3bd..cc6151fc0845 100644 --- a/Documentation/admin-guide/README.rst +++ b/Documentation/admin-guide/README.rst @@ -227,7 +227,7 @@ Configuring the kernel "make tinyconfig" Configure the tiniest possible kernel. You can find more information on using the Linux kernel config tools - in Documentation/kbuild/kconfig.txt. + in Documentation/kbuild/kconfig.rst. - NOTES on ``make config``: diff --git a/Documentation/kbuild/headers_install.rst b/Documentation/kbuild/headers_install.rst new file mode 100644 index 000000000000..1ab7294e41ac --- /dev/null +++ b/Documentation/kbuild/headers_install.rst @@ -0,0 +1,51 @@ +============================================= +Exporting kernel headers for use by userspace +============================================= + +The "make headers_install" command exports the kernel's header files in a +form suitable for use by userspace programs. + +The linux kernel's exported header files describe the API for user space +programs attempting to use kernel services. These kernel header files are +used by the system's C library (such as glibc or uClibc) to define available +system calls, as well as constants and structures to be used with these +system calls. The C library's header files include the kernel header files +from the "linux" subdirectory. The system's libc headers are usually +installed at the default location /usr/include and the kernel headers in +subdirectories under that (most notably /usr/include/linux and +/usr/include/asm). + +Kernel headers are backwards compatible, but not forwards compatible. This +means that a program built against a C library using older kernel headers +should run on a newer kernel (although it may not have access to new +features), but a program built against newer kernel headers may not work on an +older kernel. + +The "make headers_install" command can be run in the top level directory of the +kernel source code (or using a standard out-of-tree build). It takes two +optional arguments:: + + make headers_install ARCH=i386 INSTALL_HDR_PATH=/usr + +ARCH indicates which architecture to produce headers for, and defaults to the +current architecture. The linux/asm directory of the exported kernel headers +is platform-specific, to see a complete list of supported architectures use +the command:: + + ls -d include/asm-* | sed 's/.*-//' + +INSTALL_HDR_PATH indicates where to install the headers. It defaults to +"./usr". + +An 'include' directory is automatically created inside INSTALL_HDR_PATH and +headers are installed in 'INSTALL_HDR_PATH/include'. + +The command "make headers_install_all" exports headers for all architectures +simultaneously. (This is mostly of interest to distribution maintainers, +who create an architecture-independent tarball from the resulting include +directory.) You also can use HDR_ARCH_LIST to specify list of architectures. +Remember to provide the appropriate linux/asm directory via "mv" or "ln -s" +before building a C library with headers exported this way. + +The kernel header export infrastructure is maintained by David Woodhouse +. diff --git a/Documentation/kbuild/headers_install.txt b/Documentation/kbuild/headers_install.txt deleted file mode 100644 index f0153adb95e2..000000000000 --- a/Documentation/kbuild/headers_install.txt +++ /dev/null @@ -1,50 +0,0 @@ -Exporting kernel headers for use by userspace -============================================= - -The "make headers_install" command exports the kernel's header files in a -form suitable for use by userspace programs. - -The linux kernel's exported header files describe the API for user space -programs attempting to use kernel services. These kernel header files are -used by the system's C library (such as glibc or uClibc) to define available -system calls, as well as constants and structures to be used with these -system calls. The C library's header files include the kernel header files -from the "linux" subdirectory. The system's libc headers are usually -installed at the default location /usr/include and the kernel headers in -subdirectories under that (most notably /usr/include/linux and -/usr/include/asm). - -Kernel headers are backwards compatible, but not forwards compatible. This -means that a program built against a C library using older kernel headers -should run on a newer kernel (although it may not have access to new -features), but a program built against newer kernel headers may not work on an -older kernel. - -The "make headers_install" command can be run in the top level directory of the -kernel source code (or using a standard out-of-tree build). It takes two -optional arguments: - - make headers_install ARCH=i386 INSTALL_HDR_PATH=/usr - -ARCH indicates which architecture to produce headers for, and defaults to the -current architecture. The linux/asm directory of the exported kernel headers -is platform-specific, to see a complete list of supported architectures use -the command: - - ls -d include/asm-* | sed 's/.*-//' - -INSTALL_HDR_PATH indicates where to install the headers. It defaults to -"./usr". - -An 'include' directory is automatically created inside INSTALL_HDR_PATH and -headers are installed in 'INSTALL_HDR_PATH/include'. - -The command "make headers_install_all" exports headers for all architectures -simultaneously. (This is mostly of interest to distribution maintainers, -who create an architecture-independent tarball from the resulting include -directory.) You also can use HDR_ARCH_LIST to specify list of architectures. -Remember to provide the appropriate linux/asm directory via "mv" or "ln -s" -before building a C library with headers exported this way. - -The kernel header export infrastructure is maintained by David Woodhouse -. diff --git a/Documentation/kbuild/index.rst b/Documentation/kbuild/index.rst new file mode 100644 index 000000000000..42d4cbe4460c --- /dev/null +++ b/Documentation/kbuild/index.rst @@ -0,0 +1,27 @@ +:orphan: + +=================== +Kernel Build System +=================== + +.. toctree:: + :maxdepth: 1 + + kconfig-language + kconfig-macro-language + + kbuild + kconfig + makefiles + modules + + headers_install + + issues + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/kbuild/issues.rst b/Documentation/kbuild/issues.rst new file mode 100644 index 000000000000..9fdded4b681c --- /dev/null +++ b/Documentation/kbuild/issues.rst @@ -0,0 +1,11 @@ +Recursion issue #1 +------------------ + + .. include:: Kconfig.recursion-issue-01 + :literal: + +Recursion issue #2 +------------------ + + .. include:: Kconfig.recursion-issue-02 + :literal: diff --git a/Documentation/kbuild/kbuild.rst b/Documentation/kbuild/kbuild.rst new file mode 100644 index 000000000000..e774e760522d --- /dev/null +++ b/Documentation/kbuild/kbuild.rst @@ -0,0 +1,265 @@ +====== +Kbuild +====== + + +Output files +============ + +modules.order +------------- +This file records the order in which modules appear in Makefiles. This +is used by modprobe to deterministically resolve aliases that match +multiple modules. + +modules.builtin +--------------- +This file lists all modules that are built into the kernel. This is used +by modprobe to not fail when trying to load something builtin. + +modules.builtin.modinfo +-------------------------------------------------- +This file contains modinfo from all modules that are built into the kernel. +Unlike modinfo of a separate module, all fields are prefixed with module name. + + +Environment variables +===================== + +KCPPFLAGS +--------- +Additional options to pass when preprocessing. The preprocessing options +will be used in all cases where kbuild does preprocessing including +building C files and assembler files. + +KAFLAGS +------- +Additional options to the assembler (for built-in and modules). + +AFLAGS_MODULE +------------- +Additional module specific options to use for $(AS). + +AFLAGS_KERNEL +------------- +Additional options for $(AS) when used for assembler +code for code that is compiled as built-in. + +KCFLAGS +------- +Additional options to the C compiler (for built-in and modules). + +CFLAGS_KERNEL +------------- +Additional options for $(CC) when used to compile +code that is compiled as built-in. + +CFLAGS_MODULE +------------- +Additional module specific options to use for $(CC). + +LDFLAGS_MODULE +-------------- +Additional options used for $(LD) when linking modules. + +HOSTCFLAGS +---------- +Additional flags to be passed to $(HOSTCC) when building host programs. + +HOSTCXXFLAGS +------------ +Additional flags to be passed to $(HOSTCXX) when building host programs. + +HOSTLDFLAGS +----------- +Additional flags to be passed when linking host programs. + +HOSTLDLIBS +---------- +Additional libraries to link against when building host programs. + +KBUILD_KCONFIG +-------------- +Set the top-level Kconfig file to the value of this environment +variable. The default name is "Kconfig". + +KBUILD_VERBOSE +-------------- +Set the kbuild verbosity. Can be assigned same values as "V=...". + +See make help for the full list. + +Setting "V=..." takes precedence over KBUILD_VERBOSE. + +KBUILD_EXTMOD +------------- +Set the directory to look for the kernel source when building external +modules. + +Setting "M=..." takes precedence over KBUILD_EXTMOD. + +KBUILD_OUTPUT +------------- +Specify the output directory when building the kernel. + +The output directory can also be specified using "O=...". + +Setting "O=..." takes precedence over KBUILD_OUTPUT. + +KBUILD_DEBARCH +-------------- +For the deb-pkg target, allows overriding the normal heuristics deployed by +deb-pkg. Normally deb-pkg attempts to guess the right architecture based on +the UTS_MACHINE variable, and on some architectures also the kernel config. +The value of KBUILD_DEBARCH is assumed (not checked) to be a valid Debian +architecture. + +ARCH +---- +Set ARCH to the architecture to be built. + +In most cases the name of the architecture is the same as the +directory name found in the arch/ directory. + +But some architectures such as x86 and sparc have aliases. + +- x86: i386 for 32 bit, x86_64 for 64 bit +- sh: sh for 32 bit, sh64 for 64 bit +- sparc: sparc32 for 32 bit, sparc64 for 64 bit + +CROSS_COMPILE +------------- +Specify an optional fixed part of the binutils filename. +CROSS_COMPILE can be a part of the filename or the full path. + +CROSS_COMPILE is also used for ccache in some setups. + +CF +-- +Additional options for sparse. + +CF is often used on the command-line like this:: + + make CF=-Wbitwise C=2 + +INSTALL_PATH +------------ +INSTALL_PATH specifies where to place the updated kernel and system map +images. Default is /boot, but you can set it to other values. + +INSTALLKERNEL +------------- +Install script called when using "make install". +The default name is "installkernel". + +The script will be called with the following arguments: + - $1 - kernel version + - $2 - kernel image file + - $3 - kernel map file + - $4 - default install path (use root directory if blank) + +The implementation of "make install" is architecture specific +and it may differ from the above. + +INSTALLKERNEL is provided to enable the possibility to +specify a custom installer when cross compiling a kernel. + +MODLIB +------ +Specify where to install modules. +The default value is:: + + $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) + +The value can be overridden in which case the default value is ignored. + +INSTALL_MOD_PATH +---------------- +INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory +relocations required by build roots. This is not defined in the +makefile but the argument can be passed to make if needed. + +INSTALL_MOD_STRIP +----------------- +INSTALL_MOD_STRIP, if defined, will cause modules to be +stripped after they are installed. If INSTALL_MOD_STRIP is '1', then +the default option --strip-debug will be used. Otherwise, +INSTALL_MOD_STRIP value will be used as the options to the strip command. + +INSTALL_HDR_PATH +---------------- +INSTALL_HDR_PATH specifies where to install user space headers when +executing "make headers_*". + +The default value is:: + + $(objtree)/usr + +$(objtree) is the directory where output files are saved. +The output directory is often set using "O=..." on the commandline. + +The value can be overridden in which case the default value is ignored. + +KBUILD_SIGN_PIN +--------------- +This variable allows a passphrase or PIN to be passed to the sign-file +utility when signing kernel modules, if the private key requires such. + +KBUILD_MODPOST_WARN +------------------- +KBUILD_MODPOST_WARN can be set to avoid errors in case of undefined +symbols in the final module linking stage. It changes such errors +into warnings. + +KBUILD_MODPOST_NOFINAL +---------------------- +KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. +This is solely useful to speed up test compiles. + +KBUILD_EXTRA_SYMBOLS +-------------------- +For modules that use symbols from other modules. +See more details in modules.txt. + +ALLSOURCE_ARCHS +--------------- +For tags/TAGS/cscope targets, you can specify more than one arch +to be included in the databases, separated by blank space. E.g.:: + + $ make ALLSOURCE_ARCHS="x86 mips arm" tags + +To get all available archs you can also specify all. E.g.:: + + $ make ALLSOURCE_ARCHS=all tags + +KBUILD_ENABLE_EXTRA_GCC_CHECKS +------------------------------ +If enabled over the make command line with "W=1", it turns on additional +gcc -W... options for more extensive build-time checking. + +KBUILD_BUILD_TIMESTAMP +---------------------- +Setting this to a date string overrides the timestamp used in the +UTS_VERSION definition (uname -v in the running kernel). The value has to +be a string that can be passed to date -d. The default value +is the output of the date command at one point during build. + +KBUILD_BUILD_USER, KBUILD_BUILD_HOST +------------------------------------ +These two variables allow to override the user@host string displayed during +boot and in /proc/version. The default value is the output of the commands +whoami and host, respectively. + +KBUILD_LDS +---------- +The linker script with full path. Assigned by the top-level Makefile. + +KBUILD_VMLINUX_OBJS +------------------- +All object files for vmlinux. They are linked to vmlinux in the same +order as listed in KBUILD_VMLINUX_OBJS. + +KBUILD_VMLINUX_LIBS +------------------- +All .a "lib" files for vmlinux. KBUILD_VMLINUX_OBJS and KBUILD_VMLINUX_LIBS +together specify all the object files used to link vmlinux. diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt deleted file mode 100644 index 9c230ea71963..000000000000 --- a/Documentation/kbuild/kbuild.txt +++ /dev/null @@ -1,248 +0,0 @@ -Output files - -modules.order --------------------------------------------------- -This file records the order in which modules appear in Makefiles. This -is used by modprobe to deterministically resolve aliases that match -multiple modules. - -modules.builtin --------------------------------------------------- -This file lists all modules that are built into the kernel. This is used -by modprobe to not fail when trying to load something builtin. - -modules.builtin.modinfo --------------------------------------------------- -This file contains modinfo from all modules that are built into the kernel. -Unlike modinfo of a separate module, all fields are prefixed with module name. - - -Environment variables - -KCPPFLAGS --------------------------------------------------- -Additional options to pass when preprocessing. The preprocessing options -will be used in all cases where kbuild does preprocessing including -building C files and assembler files. - -KAFLAGS --------------------------------------------------- -Additional options to the assembler (for built-in and modules). - -AFLAGS_MODULE --------------------------------------------------- -Additional module specific options to use for $(AS). - -AFLAGS_KERNEL --------------------------------------------------- -Additional options for $(AS) when used for assembler -code for code that is compiled as built-in. - -KCFLAGS --------------------------------------------------- -Additional options to the C compiler (for built-in and modules). - -CFLAGS_KERNEL --------------------------------------------------- -Additional options for $(CC) when used to compile -code that is compiled as built-in. - -CFLAGS_MODULE --------------------------------------------------- -Additional module specific options to use for $(CC). - -LDFLAGS_MODULE --------------------------------------------------- -Additional options used for $(LD) when linking modules. - -HOSTCFLAGS --------------------------------------------------- -Additional flags to be passed to $(HOSTCC) when building host programs. - -HOSTCXXFLAGS --------------------------------------------------- -Additional flags to be passed to $(HOSTCXX) when building host programs. - -HOSTLDFLAGS --------------------------------------------------- -Additional flags to be passed when linking host programs. - -HOSTLDLIBS --------------------------------------------------- -Additional libraries to link against when building host programs. - -KBUILD_KCONFIG --------------------------------------------------- -Set the top-level Kconfig file to the value of this environment -variable. The default name is "Kconfig". - -KBUILD_VERBOSE --------------------------------------------------- -Set the kbuild verbosity. Can be assigned same values as "V=...". -See make help for the full list. -Setting "V=..." takes precedence over KBUILD_VERBOSE. - -KBUILD_EXTMOD --------------------------------------------------- -Set the directory to look for the kernel source when building external -modules. -Setting "M=..." takes precedence over KBUILD_EXTMOD. - -KBUILD_OUTPUT --------------------------------------------------- -Specify the output directory when building the kernel. -The output directory can also be specified using "O=...". -Setting "O=..." takes precedence over KBUILD_OUTPUT. - -KBUILD_DEBARCH --------------------------------------------------- -For the deb-pkg target, allows overriding the normal heuristics deployed by -deb-pkg. Normally deb-pkg attempts to guess the right architecture based on -the UTS_MACHINE variable, and on some architectures also the kernel config. -The value of KBUILD_DEBARCH is assumed (not checked) to be a valid Debian -architecture. - -ARCH --------------------------------------------------- -Set ARCH to the architecture to be built. -In most cases the name of the architecture is the same as the -directory name found in the arch/ directory. -But some architectures such as x86 and sparc have aliases. -x86: i386 for 32 bit, x86_64 for 64 bit -sh: sh for 32 bit, sh64 for 64 bit -sparc: sparc32 for 32 bit, sparc64 for 64 bit - -CROSS_COMPILE --------------------------------------------------- -Specify an optional fixed part of the binutils filename. -CROSS_COMPILE can be a part of the filename or the full path. - -CROSS_COMPILE is also used for ccache in some setups. - -CF --------------------------------------------------- -Additional options for sparse. -CF is often used on the command-line like this: - - make CF=-Wbitwise C=2 - -INSTALL_PATH --------------------------------------------------- -INSTALL_PATH specifies where to place the updated kernel and system map -images. Default is /boot, but you can set it to other values. - -INSTALLKERNEL --------------------------------------------------- -Install script called when using "make install". -The default name is "installkernel". - -The script will be called with the following arguments: - $1 - kernel version - $2 - kernel image file - $3 - kernel map file - $4 - default install path (use root directory if blank) - -The implementation of "make install" is architecture specific -and it may differ from the above. - -INSTALLKERNEL is provided to enable the possibility to -specify a custom installer when cross compiling a kernel. - -MODLIB --------------------------------------------------- -Specify where to install modules. -The default value is: - - $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) - -The value can be overridden in which case the default value is ignored. - -INSTALL_MOD_PATH --------------------------------------------------- -INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory -relocations required by build roots. This is not defined in the -makefile but the argument can be passed to make if needed. - -INSTALL_MOD_STRIP --------------------------------------------------- -INSTALL_MOD_STRIP, if defined, will cause modules to be -stripped after they are installed. If INSTALL_MOD_STRIP is '1', then -the default option --strip-debug will be used. Otherwise, -INSTALL_MOD_STRIP value will be used as the options to the strip command. - -INSTALL_HDR_PATH --------------------------------------------------- -INSTALL_HDR_PATH specifies where to install user space headers when -executing "make headers_*". -The default value is: - - $(objtree)/usr - -$(objtree) is the directory where output files are saved. -The output directory is often set using "O=..." on the commandline. - -The value can be overridden in which case the default value is ignored. - -KBUILD_SIGN_PIN --------------------------------------------------- -This variable allows a passphrase or PIN to be passed to the sign-file -utility when signing kernel modules, if the private key requires such. - -KBUILD_MODPOST_WARN --------------------------------------------------- -KBUILD_MODPOST_WARN can be set to avoid errors in case of undefined -symbols in the final module linking stage. It changes such errors -into warnings. - -KBUILD_MODPOST_NOFINAL --------------------------------------------------- -KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. -This is solely useful to speed up test compiles. - -KBUILD_EXTRA_SYMBOLS --------------------------------------------------- -For modules that use symbols from other modules. -See more details in modules.txt. - -ALLSOURCE_ARCHS --------------------------------------------------- -For tags/TAGS/cscope targets, you can specify more than one arch -to be included in the databases, separated by blank space. E.g.: - - $ make ALLSOURCE_ARCHS="x86 mips arm" tags - -To get all available archs you can also specify all. E.g.: - - $ make ALLSOURCE_ARCHS=all tags - -KBUILD_ENABLE_EXTRA_GCC_CHECKS --------------------------------------------------- -If enabled over the make command line with "W=1", it turns on additional -gcc -W... options for more extensive build-time checking. - -KBUILD_BUILD_TIMESTAMP --------------------------------------------------- -Setting this to a date string overrides the timestamp used in the -UTS_VERSION definition (uname -v in the running kernel). The value has to -be a string that can be passed to date -d. The default value -is the output of the date command at one point during build. - -KBUILD_BUILD_USER, KBUILD_BUILD_HOST --------------------------------------------------- -These two variables allow to override the user@host string displayed during -boot and in /proc/version. The default value is the output of the commands -whoami and host, respectively. - -KBUILD_LDS --------------------------------------------------- -The linker script with full path. Assigned by the top-level Makefile. - -KBUILD_VMLINUX_OBJS --------------------------------------------------- -All object files for vmlinux. They are linked to vmlinux in the same -order as listed in KBUILD_VMLINUX_OBJS. - -KBUILD_VMLINUX_LIBS --------------------------------------------------- -All .a "lib" files for vmlinux. KBUILD_VMLINUX_OBJS and KBUILD_VMLINUX_LIBS -together specify all the object files used to link vmlinux. diff --git a/Documentation/kbuild/kconfig-language.rst b/Documentation/kbuild/kconfig-language.rst new file mode 100644 index 000000000000..2bc8a7803365 --- /dev/null +++ b/Documentation/kbuild/kconfig-language.rst @@ -0,0 +1,689 @@ +================ +Kconfig Language +================ + +Introduction +------------ + +The configuration database is a collection of configuration options +organized in a tree structure:: + + +- Code maturity level options + | +- Prompt for development and/or incomplete code/drivers + +- General setup + | +- Networking support + | +- System V IPC + | +- BSD Process Accounting + | +- Sysctl support + +- Loadable module support + | +- Enable loadable module support + | +- Set version information on all module symbols + | +- Kernel module loader + +- ... + +Every entry has its own dependencies. These dependencies are used +to determine the visibility of an entry. Any child entry is only +visible if its parent entry is also visible. + +Menu entries +------------ + +Most entries define a config option; all other entries help to organize +them. A single configuration option is defined like this:: + + config MODVERSIONS + bool "Set version information on all module symbols" + depends on MODULES + help + Usually, modules have to be recompiled whenever you switch to a new + kernel. ... + +Every line starts with a key word and can be followed by multiple +arguments. "config" starts a new config entry. The following lines +define attributes for this config option. Attributes can be the type of +the config option, input prompt, dependencies, help text and default +values. A config option can be defined multiple times with the same +name, but every definition can have only a single input prompt and the +type must not conflict. + +Menu attributes +--------------- + +A menu entry can have a number of attributes. Not all of them are +applicable everywhere (see syntax). + +- type definition: "bool"/"tristate"/"string"/"hex"/"int" + Every config option must have a type. There are only two basic types: + tristate and string; the other types are based on these two. The type + definition optionally accepts an input prompt, so these two examples + are equivalent:: + + bool "Networking support" + + and:: + + bool + prompt "Networking support" + +- input prompt: "prompt" ["if" ] + Every menu entry can have at most one prompt, which is used to display + to the user. Optionally dependencies only for this prompt can be added + with "if". + +- default value: "default" ["if" ] + A config option can have any number of default values. If multiple + default values are visible, only the first defined one is active. + Default values are not limited to the menu entry where they are + defined. This means the default can be defined somewhere else or be + overridden by an earlier definition. + The default value is only assigned to the config symbol if no other + value was set by the user (via the input prompt above). If an input + prompt is visible the default value is presented to the user and can + be overridden by him. + Optionally, dependencies only for this default value can be added with + "if". + + The default value deliberately defaults to 'n' in order to avoid bloating the + build. With few exceptions, new config options should not change this. The + intent is for "make oldconfig" to add as little as possible to the config from + release to release. + + Note: + Things that merit "default y/m" include: + + a) A new Kconfig option for something that used to always be built + should be "default y". + + b) A new gatekeeping Kconfig option that hides/shows other Kconfig + options (but does not generate any code of its own), should be + "default y" so people will see those other options. + + c) Sub-driver behavior or similar options for a driver that is + "default n". This allows you to provide sane defaults. + + d) Hardware or infrastructure that everybody expects, such as CONFIG_NET + or CONFIG_BLOCK. These are rare exceptions. + +- type definition + default value:: + + "def_bool"/"def_tristate" ["if" ] + + This is a shorthand notation for a type definition plus a value. + Optionally dependencies for this default value can be added with "if". + +- dependencies: "depends on" + This defines a dependency for this menu entry. If multiple + dependencies are defined, they are connected with '&&'. Dependencies + are applied to all other options within this menu entry (which also + accept an "if" expression), so these two examples are equivalent:: + + bool "foo" if BAR + default y if BAR + + and:: + + depends on BAR + bool "foo" + default y + +- reverse dependencies: "select" ["if" ] + While normal dependencies reduce the upper limit of a symbol (see + below), reverse dependencies can be used to force a lower limit of + another symbol. The value of the current menu symbol is used as the + minimal value can be set to. If is selected multiple + times, the limit is set to the largest selection. + Reverse dependencies can only be used with boolean or tristate + symbols. + + Note: + select should be used with care. select will force + a symbol to a value without visiting the dependencies. + By abusing select you are able to select a symbol FOO even + if FOO depends on BAR that is not set. + In general use select only for non-visible symbols + (no prompts anywhere) and for symbols with no dependencies. + That will limit the usefulness but on the other hand avoid + the illegal configurations all over. + +- weak reverse dependencies: "imply" ["if" ] + This is similar to "select" as it enforces a lower limit on another + symbol except that the "implied" symbol's value may still be set to n + from a direct dependency or with a visible prompt. + + Given the following example:: + + config FOO + tristate + imply BAZ + + config BAZ + tristate + depends on BAR + + The following values are possible: + + === === ============= ============== + FOO BAR BAZ's default choice for BAZ + === === ============= ============== + n y n N/m/y + m y m M/y/n + y y y Y/n + y n * N + === === ============= ============== + + This is useful e.g. with multiple drivers that want to indicate their + ability to hook into a secondary subsystem while allowing the user to + configure that subsystem out without also having to unset these drivers. + +- limiting menu display: "visible if" + This attribute is only applicable to menu blocks, if the condition is + false, the menu block is not displayed to the user (the symbols + contained there can still be selected by other symbols, though). It is + similar to a conditional "prompt" attribute for individual menu + entries. Default value of "visible" is true. + +- numerical ranges: "range" ["if" ] + This allows to limit the range of possible input values for int + and hex symbols. The user can only input a value which is larger than + or equal to the first symbol and smaller than or equal to the second + symbol. + +- help text: "help" or "---help---" + This defines a help text. The end of the help text is determined by + the indentation level, this means it ends at the first line which has + a smaller indentation than the first line of the help text. + "---help---" and "help" do not differ in behaviour, "---help---" is + used to help visually separate configuration logic from help within + the file as an aid to developers. + +- misc options: "option" [=] + Various less common options can be defined via this option syntax, + which can modify the behaviour of the menu entry and its config + symbol. These options are currently possible: + + - "defconfig_list" + This declares a list of default entries which can be used when + looking for the default configuration (which is used when the main + .config doesn't exists yet.) + + - "modules" + This declares the symbol to be used as the MODULES symbol, which + enables the third modular state for all config symbols. + At most one symbol may have the "modules" option set. + + - "allnoconfig_y" + This declares the symbol as one that should have the value y when + using "allnoconfig". Used for symbols that hide other symbols. + +Menu dependencies +----------------- + +Dependencies define the visibility of a menu entry and can also reduce +the input range of tristate symbols. The tristate logic used in the +expressions uses one more state than normal boolean logic to express the +module state. Dependency expressions have the following syntax:: + + ::= (1) + '=' (2) + '!=' (3) + '<' (4) + '>' (4) + '<=' (4) + '>=' (4) + '(' ')' (5) + '!' (6) + '&&' (7) + '||' (8) + +Expressions are listed in decreasing order of precedence. + +(1) Convert the symbol into an expression. Boolean and tristate symbols + are simply converted into the respective expression values. All + other symbol types result in 'n'. +(2) If the values of both symbols are equal, it returns 'y', + otherwise 'n'. +(3) If the values of both symbols are equal, it returns 'n', + otherwise 'y'. +(4) If value of is respectively lower, greater, lower-or-equal, + or greater-or-equal than value of , it returns 'y', + otherwise 'n'. +(5) Returns the value of the expression. Used to override precedence. +(6) Returns the result of (2-/expr/). +(7) Returns the result of min(/expr/, /expr/). +(8) Returns the result of max(/expr/, /expr/). + +An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2 +respectively for calculations). A menu entry becomes visible when its +expression evaluates to 'm' or 'y'. + +There are two types of symbols: constant and non-constant symbols. +Non-constant symbols are the most common ones and are defined with the +'config' statement. Non-constant symbols consist entirely of alphanumeric +characters or underscores. +Constant symbols are only part of expressions. Constant symbols are +always surrounded by single or double quotes. Within the quote, any +other character is allowed and the quotes can be escaped using '\'. + +Menu structure +-------------- + +The position of a menu entry in the tree is determined in two ways. First +it can be specified explicitly:: + + menu "Network device support" + depends on NET + + config NETDEVICES + ... + + endmenu + +All entries within the "menu" ... "endmenu" block become a submenu of +"Network device support". All subentries inherit the dependencies from +the menu entry, e.g. this means the dependency "NET" is added to the +dependency list of the config option NETDEVICES. + +The other way to generate the menu structure is done by analyzing the +dependencies. If a menu entry somehow depends on the previous entry, it +can be made a submenu of it. First, the previous (parent) symbol must +be part of the dependency list and then one of these two conditions +must be true: + +- the child entry must become invisible, if the parent is set to 'n' +- the child entry must only be visible, if the parent is visible:: + + config MODULES + bool "Enable loadable module support" + + config MODVERSIONS + bool "Set version information on all module symbols" + depends on MODULES + + comment "module support disabled" + depends on !MODULES + +MODVERSIONS directly depends on MODULES, this means it's only visible if +MODULES is different from 'n'. The comment on the other hand is only +visible when MODULES is set to 'n'. + + +Kconfig syntax +-------------- + +The configuration file describes a series of menu entries, where every +line starts with a keyword (except help texts). The following keywords +end a menu entry: + +- config +- menuconfig +- choice/endchoice +- comment +- menu/endmenu +- if/endif +- source + +The first five also start the definition of a menu entry. + +config:: + "config" + + +This defines a config symbol and accepts any of above +attributes as options. + +menuconfig:: + "menuconfig" + + +This is similar to the simple config entry above, but it also gives a +hint to front ends, that all suboptions should be displayed as a +separate list of options. To make sure all the suboptions will really +show up under the menuconfig entry and not outside of it, every item +from the list must depend on the menuconfig symbol. +In practice, this is achieved by using one of the next two constructs:: + + (1): + menuconfig M + if M + config C1 + config C2 + endif + + (2): + menuconfig M + config C1 + depends on M + config C2 + depends on M + +In the following examples (3) and (4), C1 and C2 still have the M +dependency, but will not appear under menuconfig M anymore, because +of C0, which doesn't depend on M:: + + (3): + menuconfig M + config C0 + if M + config C1 + config C2 + endif + + (4): + menuconfig M + config C0 + config C1 + depends on M + config C2 + depends on M + +choices:: + + "choice" [symbol] + + + "endchoice" + +This defines a choice group and accepts any of the above attributes as +options. A choice can only be of type bool or tristate. If no type is +specified for a choice, its type will be determined by the type of +the first choice element in the group or remain unknown if none of the +choice elements have a type specified, as well. + +While a boolean choice only allows a single config entry to be +selected, a tristate choice also allows any number of config entries +to be set to 'm'. This can be used if multiple drivers for a single +hardware exists and only a single driver can be compiled/loaded into +the kernel, but all drivers can be compiled as modules. + +A choice accepts another option "optional", which allows to set the +choice to 'n' and no entry needs to be selected. +If no [symbol] is associated with a choice, then you can not have multiple +definitions of that choice. If a [symbol] is associated to the choice, +then you may define the same choice (i.e. with the same entries) in another +place. + +comment:: + + "comment" + + +This defines a comment which is displayed to the user during the +configuration process and is also echoed to the output files. The only +possible options are dependencies. + +menu:: + + "menu" + + + "endmenu" + +This defines a menu block, see "Menu structure" above for more +information. The only possible options are dependencies and "visible" +attributes. + +if:: + + "if" + + "endif" + +This defines an if block. The dependency expression is appended +to all enclosed menu entries. + +source:: + + "source" + +This reads the specified configuration file. This file is always parsed. + +mainmenu:: + + "mainmenu" + +This sets the config program's title bar if the config program chooses +to use it. It should be placed at the top of the configuration, before any +other statement. + +'#' Kconfig source file comment: + +An unquoted '#' character anywhere in a source file line indicates +the beginning of a source file comment. The remainder of that line +is a comment. + + +Kconfig hints +------------- +This is a collection of Kconfig tips, most of which aren't obvious at +first glance and most of which have become idioms in several Kconfig +files. + +Adding common features and make the usage configurable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It is a common idiom to implement a feature/functionality that are +relevant for some architectures but not all. +The recommended way to do so is to use a config variable named HAVE_* +that is defined in a common Kconfig file and selected by the relevant +architectures. +An example is the generic IOMAP functionality. + +We would in lib/Kconfig see:: + + # Generic IOMAP is used to ... + config HAVE_GENERIC_IOMAP + + config GENERIC_IOMAP + depends on HAVE_GENERIC_IOMAP && FOO + +And in lib/Makefile we would see:: + + obj-$(CONFIG_GENERIC_IOMAP) += iomap.o + +For each architecture using the generic IOMAP functionality we would see:: + + config X86 + select ... + select HAVE_GENERIC_IOMAP + select ... + +Note: we use the existing config option and avoid creating a new +config variable to select HAVE_GENERIC_IOMAP. + +Note: the use of the internal config variable HAVE_GENERIC_IOMAP, it is +introduced to overcome the limitation of select which will force a +config option to 'y' no matter the dependencies. +The dependencies are moved to the symbol GENERIC_IOMAP and we avoid the +situation where select forces a symbol equals to 'y'. + +Adding features that need compiler support +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are several features that need compiler support. The recommended way +to describe the dependency on the compiler feature is to use "depends on" +followed by a test macro:: + + config STACKPROTECTOR + bool "Stack Protector buffer overflow detection" + depends on $(cc-option,-fstack-protector) + ... + +If you need to expose a compiler capability to makefiles and/or C source files, +`CC_HAS_` is the recommended prefix for the config option:: + + config CC_HAS_STACKPROTECTOR_NONE + def_bool $(cc-option,-fno-stack-protector) + +Build as module only +~~~~~~~~~~~~~~~~~~~~ +To restrict a component build to module-only, qualify its config symbol +with "depends on m". E.g.:: + + config FOO + depends on BAR && m + +limits FOO to module (=m) or disabled (=n). + +Kconfig recursive dependency limitations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you've hit the Kconfig error: "recursive dependency detected" you've run +into a recursive dependency issue with Kconfig, a recursive dependency can be +summarized as a circular dependency. The kconfig tools need to ensure that +Kconfig files comply with specified configuration requirements. In order to do +that kconfig must determine the values that are possible for all Kconfig +symbols, this is currently not possible if there is a circular relation +between two or more Kconfig symbols. For more details refer to the "Simple +Kconfig recursive issue" subsection below. Kconfig does not do recursive +dependency resolution; this has a few implications for Kconfig file writers. +We'll first explain why this issues exists and then provide an example +technical limitation which this brings upon Kconfig developers. Eager +developers wishing to try to address this limitation should read the next +subsections. + +Simple Kconfig recursive issue +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Read: Documentation/kbuild/Kconfig.recursion-issue-01 + +Test with:: + + make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-01 allnoconfig + +Cumulative Kconfig recursive issue +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Read: Documentation/kbuild/Kconfig.recursion-issue-02 + +Test with:: + + make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-02 allnoconfig + +Practical solutions to kconfig recursive issue +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Developers who run into the recursive Kconfig issue have two options +at their disposal. We document them below and also provide a list of +historical issues resolved through these different solutions. + + a) Remove any superfluous "select FOO" or "depends on FOO" + b) Match dependency semantics: + + b1) Swap all "select FOO" to "depends on FOO" or, + + b2) Swap all "depends on FOO" to "select FOO" + +The resolution to a) can be tested with the sample Kconfig file +Documentation/kbuild/Kconfig.recursion-issue-01 through the removal +of the "select CORE" from CORE_BELL_A_ADVANCED as that is implicit already +since CORE_BELL_A depends on CORE. At times it may not be possible to remove +some dependency criteria, for such cases you can work with solution b). + +The two different resolutions for b) can be tested in the sample Kconfig file +Documentation/kbuild/Kconfig.recursion-issue-02. + +Below is a list of examples of prior fixes for these types of recursive issues; +all errors appear to involve one or more select's and one or more "depends on". + +============ =================================== +commit fix +============ =================================== +06b718c01208 select A -> depends on A +c22eacfe82f9 depends on A -> depends on B +6a91e854442c select A -> depends on A +118c565a8f2e select A -> select B +f004e5594705 select A -> depends on A +c7861f37b4c6 depends on A -> (null) +80c69915e5fb select A -> (null) (1) +c2218e26c0d0 select A -> depends on A (1) +d6ae99d04e1c select A -> depends on A +95ca19cf8cbf select A -> depends on A +8f057d7bca54 depends on A -> (null) +8f057d7bca54 depends on A -> select A +a0701f04846e select A -> depends on A +0c8b92f7f259 depends on A -> (null) +e4e9e0540928 select A -> depends on A (2) +7453ea886e87 depends on A > (null) (1) +7b1fff7e4fdf select A -> depends on A +86c747d2a4f0 select A -> depends on A +d9f9ab51e55e select A -> depends on A +0c51a4d8abd6 depends on A -> select A (3) +e98062ed6dc4 select A -> depends on A (3) +91e5d284a7f1 select A -> (null) +============ =================================== + +(1) Partial (or no) quote of error. +(2) That seems to be the gist of that fix. +(3) Same error. + +Future kconfig work +~~~~~~~~~~~~~~~~~~~ + +Work on kconfig is welcomed on both areas of clarifying semantics and on +evaluating the use of a full SAT solver for it. A full SAT solver can be +desirable to enable more complex dependency mappings and / or queries, +for instance on possible use case for a SAT solver could be that of handling +the current known recursive dependency issues. It is not known if this would +address such issues but such evaluation is desirable. If support for a full SAT +solver proves too complex or that it cannot address recursive dependency issues +Kconfig should have at least clear and well defined semantics which also +addresses and documents limitations or requirements such as the ones dealing +with recursive dependencies. + +Further work on both of these areas is welcomed on Kconfig. We elaborate +on both of these in the next two subsections. + +Semantics of Kconfig +~~~~~~~~~~~~~~~~~~~~ + +The use of Kconfig is broad, Linux is now only one of Kconfig's users: +one study has completed a broad analysis of Kconfig use in 12 projects [0]_. +Despite its widespread use, and although this document does a reasonable job +in documenting basic Kconfig syntax a more precise definition of Kconfig +semantics is welcomed. One project deduced Kconfig semantics through +the use of the xconfig configurator [1]_. Work should be done to confirm if +the deduced semantics matches our intended Kconfig design goals. + +Having well defined semantics can be useful for tools for practical +evaluation of depenencies, for instance one such use known case was work to +express in boolean abstraction of the inferred semantics of Kconfig to +translate Kconfig logic into boolean formulas and run a SAT solver on this to +find dead code / features (always inactive), 114 dead features were found in +Linux using this methodology [1]_ (Section 8: Threats to validity). + +Confirming this could prove useful as Kconfig stands as one of the the leading +industrial variability modeling languages [1]_ [2]_. Its study would help +evaluate practical uses of such languages, their use was only theoretical +and real world requirements were not well understood. As it stands though +only reverse engineering techniques have been used to deduce semantics from +variability modeling languages such as Kconfig [3]_. + +.. [0] http://www.eng.uwaterloo.ca/~shshe/kconfig_semantics.pdf +.. [1] http://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf +.. [2] http://gsd.uwaterloo.ca/sites/default/files/ase241-berger_0.pdf +.. [3] http://gsd.uwaterloo.ca/sites/default/files/icse2011.pdf + +Full SAT solver for Kconfig +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Although SAT solvers [4]_ haven't yet been used by Kconfig directly, as noted +in the previous subsection, work has been done however to express in boolean +abstraction the inferred semantics of Kconfig to translate Kconfig logic into +boolean formulas and run a SAT solver on it [5]_. Another known related project +is CADOS [6]_ (former VAMOS [7]_) and the tools, mainly undertaker [8]_, which +has been introduced first with [9]_. The basic concept of undertaker is to +exract variability models from Kconfig, and put them together with a +propositional formula extracted from CPP #ifdefs and build-rules into a SAT +solver in order to find dead code, dead files, and dead symbols. If using a SAT +solver is desirable on Kconfig one approach would be to evaluate repurposing +such efforts somehow on Kconfig. There is enough interest from mentors of +existing projects to not only help advise how to integrate this work upstream +but also help maintain it long term. Interested developers should visit: + +http://kernelnewbies.org/KernelProjects/kconfig-sat + +.. [4] http://www.cs.cornell.edu/~sabhar/chapters/SATSolvers-KR-Handbook.pdf +.. [5] http://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf +.. [6] https://cados.cs.fau.de +.. [7] https://vamos.cs.fau.de +.. [8] https://undertaker.cs.fau.de +.. [9] https://www4.cs.fau.de/Publications/2011/tartler_11_eurosys.pdf diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt deleted file mode 100644 index 864e740811da..000000000000 --- a/Documentation/kbuild/kconfig-language.txt +++ /dev/null @@ -1,669 +0,0 @@ -Introduction ------------- - -The configuration database is a collection of configuration options -organized in a tree structure: - - +- Code maturity level options - | +- Prompt for development and/or incomplete code/drivers - +- General setup - | +- Networking support - | +- System V IPC - | +- BSD Process Accounting - | +- Sysctl support - +- Loadable module support - | +- Enable loadable module support - | +- Set version information on all module symbols - | +- Kernel module loader - +- ... - -Every entry has its own dependencies. These dependencies are used -to determine the visibility of an entry. Any child entry is only -visible if its parent entry is also visible. - -Menu entries ------------- - -Most entries define a config option; all other entries help to organize -them. A single configuration option is defined like this: - -config MODVERSIONS - bool "Set version information on all module symbols" - depends on MODULES - help - Usually, modules have to be recompiled whenever you switch to a new - kernel. ... - -Every line starts with a key word and can be followed by multiple -arguments. "config" starts a new config entry. The following lines -define attributes for this config option. Attributes can be the type of -the config option, input prompt, dependencies, help text and default -values. A config option can be defined multiple times with the same -name, but every definition can have only a single input prompt and the -type must not conflict. - -Menu attributes ---------------- - -A menu entry can have a number of attributes. Not all of them are -applicable everywhere (see syntax). - -- type definition: "bool"/"tristate"/"string"/"hex"/"int" - Every config option must have a type. There are only two basic types: - tristate and string; the other types are based on these two. The type - definition optionally accepts an input prompt, so these two examples - are equivalent: - - bool "Networking support" - and - bool - prompt "Networking support" - -- input prompt: "prompt" ["if" ] - Every menu entry can have at most one prompt, which is used to display - to the user. Optionally dependencies only for this prompt can be added - with "if". - -- default value: "default" ["if" ] - A config option can have any number of default values. If multiple - default values are visible, only the first defined one is active. - Default values are not limited to the menu entry where they are - defined. This means the default can be defined somewhere else or be - overridden by an earlier definition. - The default value is only assigned to the config symbol if no other - value was set by the user (via the input prompt above). If an input - prompt is visible the default value is presented to the user and can - be overridden by him. - Optionally, dependencies only for this default value can be added with - "if". - - The default value deliberately defaults to 'n' in order to avoid bloating the - build. With few exceptions, new config options should not change this. The - intent is for "make oldconfig" to add as little as possible to the config from - release to release. - - Note: - Things that merit "default y/m" include: - - a) A new Kconfig option for something that used to always be built - should be "default y". - - b) A new gatekeeping Kconfig option that hides/shows other Kconfig - options (but does not generate any code of its own), should be - "default y" so people will see those other options. - - c) Sub-driver behavior or similar options for a driver that is - "default n". This allows you to provide sane defaults. - - d) Hardware or infrastructure that everybody expects, such as CONFIG_NET - or CONFIG_BLOCK. These are rare exceptions. - -- type definition + default value: - "def_bool"/"def_tristate" ["if" ] - This is a shorthand notation for a type definition plus a value. - Optionally dependencies for this default value can be added with "if". - -- dependencies: "depends on" - This defines a dependency for this menu entry. If multiple - dependencies are defined, they are connected with '&&'. Dependencies - are applied to all other options within this menu entry (which also - accept an "if" expression), so these two examples are equivalent: - - bool "foo" if BAR - default y if BAR - and - depends on BAR - bool "foo" - default y - -- reverse dependencies: "select" ["if" ] - While normal dependencies reduce the upper limit of a symbol (see - below), reverse dependencies can be used to force a lower limit of - another symbol. The value of the current menu symbol is used as the - minimal value can be set to. If is selected multiple - times, the limit is set to the largest selection. - Reverse dependencies can only be used with boolean or tristate - symbols. - Note: - select should be used with care. select will force - a symbol to a value without visiting the dependencies. - By abusing select you are able to select a symbol FOO even - if FOO depends on BAR that is not set. - In general use select only for non-visible symbols - (no prompts anywhere) and for symbols with no dependencies. - That will limit the usefulness but on the other hand avoid - the illegal configurations all over. - -- weak reverse dependencies: "imply" ["if" ] - This is similar to "select" as it enforces a lower limit on another - symbol except that the "implied" symbol's value may still be set to n - from a direct dependency or with a visible prompt. - - Given the following example: - - config FOO - tristate - imply BAZ - - config BAZ - tristate - depends on BAR - - The following values are possible: - - FOO BAR BAZ's default choice for BAZ - --- --- ------------- -------------- - n y n N/m/y - m y m M/y/n - y y y Y/n - y n * N - - This is useful e.g. with multiple drivers that want to indicate their - ability to hook into a secondary subsystem while allowing the user to - configure that subsystem out without also having to unset these drivers. - -- limiting menu display: "visible if" - This attribute is only applicable to menu blocks, if the condition is - false, the menu block is not displayed to the user (the symbols - contained there can still be selected by other symbols, though). It is - similar to a conditional "prompt" attribute for individual menu - entries. Default value of "visible" is true. - -- numerical ranges: "range" ["if" ] - This allows to limit the range of possible input values for int - and hex symbols. The user can only input a value which is larger than - or equal to the first symbol and smaller than or equal to the second - symbol. - -- help text: "help" or "---help---" - This defines a help text. The end of the help text is determined by - the indentation level, this means it ends at the first line which has - a smaller indentation than the first line of the help text. - "---help---" and "help" do not differ in behaviour, "---help---" is - used to help visually separate configuration logic from help within - the file as an aid to developers. - -- misc options: "option" [=] - Various less common options can be defined via this option syntax, - which can modify the behaviour of the menu entry and its config - symbol. These options are currently possible: - - - "defconfig_list" - This declares a list of default entries which can be used when - looking for the default configuration (which is used when the main - .config doesn't exists yet.) - - - "modules" - This declares the symbol to be used as the MODULES symbol, which - enables the third modular state for all config symbols. - At most one symbol may have the "modules" option set. - - - "allnoconfig_y" - This declares the symbol as one that should have the value y when - using "allnoconfig". Used for symbols that hide other symbols. - -Menu dependencies ------------------ - -Dependencies define the visibility of a menu entry and can also reduce -the input range of tristate symbols. The tristate logic used in the -expressions uses one more state than normal boolean logic to express the -module state. Dependency expressions have the following syntax: - - ::= (1) - '=' (2) - '!=' (3) - '<' (4) - '>' (4) - '<=' (4) - '>=' (4) - '(' ')' (5) - '!' (6) - '&&' (7) - '||' (8) - -Expressions are listed in decreasing order of precedence. - -(1) Convert the symbol into an expression. Boolean and tristate symbols - are simply converted into the respective expression values. All - other symbol types result in 'n'. -(2) If the values of both symbols are equal, it returns 'y', - otherwise 'n'. -(3) If the values of both symbols are equal, it returns 'n', - otherwise 'y'. -(4) If value of is respectively lower, greater, lower-or-equal, - or greater-or-equal than value of , it returns 'y', - otherwise 'n'. -(5) Returns the value of the expression. Used to override precedence. -(6) Returns the result of (2-/expr/). -(7) Returns the result of min(/expr/, /expr/). -(8) Returns the result of max(/expr/, /expr/). - -An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2 -respectively for calculations). A menu entry becomes visible when its -expression evaluates to 'm' or 'y'. - -There are two types of symbols: constant and non-constant symbols. -Non-constant symbols are the most common ones and are defined with the -'config' statement. Non-constant symbols consist entirely of alphanumeric -characters or underscores. -Constant symbols are only part of expressions. Constant symbols are -always surrounded by single or double quotes. Within the quote, any -other character is allowed and the quotes can be escaped using '\'. - -Menu structure --------------- - -The position of a menu entry in the tree is determined in two ways. First -it can be specified explicitly: - -menu "Network device support" - depends on NET - -config NETDEVICES - ... - -endmenu - -All entries within the "menu" ... "endmenu" block become a submenu of -"Network device support". All subentries inherit the dependencies from -the menu entry, e.g. this means the dependency "NET" is added to the -dependency list of the config option NETDEVICES. - -The other way to generate the menu structure is done by analyzing the -dependencies. If a menu entry somehow depends on the previous entry, it -can be made a submenu of it. First, the previous (parent) symbol must -be part of the dependency list and then one of these two conditions -must be true: -- the child entry must become invisible, if the parent is set to 'n' -- the child entry must only be visible, if the parent is visible - -config MODULES - bool "Enable loadable module support" - -config MODVERSIONS - bool "Set version information on all module symbols" - depends on MODULES - -comment "module support disabled" - depends on !MODULES - -MODVERSIONS directly depends on MODULES, this means it's only visible if -MODULES is different from 'n'. The comment on the other hand is only -visible when MODULES is set to 'n'. - - -Kconfig syntax --------------- - -The configuration file describes a series of menu entries, where every -line starts with a keyword (except help texts). The following keywords -end a menu entry: -- config -- menuconfig -- choice/endchoice -- comment -- menu/endmenu -- if/endif -- source -The first five also start the definition of a menu entry. - -config: - - "config" - - -This defines a config symbol and accepts any of above -attributes as options. - -menuconfig: - "menuconfig" - - -This is similar to the simple config entry above, but it also gives a -hint to front ends, that all suboptions should be displayed as a -separate list of options. To make sure all the suboptions will really -show up under the menuconfig entry and not outside of it, every item -from the list must depend on the menuconfig symbol. -In practice, this is achieved by using one of the next two constructs: - -(1): -menuconfig M -if M - config C1 - config C2 -endif - -(2): -menuconfig M -config C1 - depends on M -config C2 - depends on M - -In the following examples (3) and (4), C1 and C2 still have the M -dependency, but will not appear under menuconfig M anymore, because -of C0, which doesn't depend on M: - -(3): -menuconfig M - config C0 -if M - config C1 - config C2 -endif - -(4): -menuconfig M -config C0 -config C1 - depends on M -config C2 - depends on M - -choices: - - "choice" [symbol] - - - "endchoice" - -This defines a choice group and accepts any of the above attributes as -options. A choice can only be of type bool or tristate. If no type is -specified for a choice, its type will be determined by the type of -the first choice element in the group or remain unknown if none of the -choice elements have a type specified, as well. - -While a boolean choice only allows a single config entry to be -selected, a tristate choice also allows any number of config entries -to be set to 'm'. This can be used if multiple drivers for a single -hardware exists and only a single driver can be compiled/loaded into -the kernel, but all drivers can be compiled as modules. - -A choice accepts another option "optional", which allows to set the -choice to 'n' and no entry needs to be selected. -If no [symbol] is associated with a choice, then you can not have multiple -definitions of that choice. If a [symbol] is associated to the choice, -then you may define the same choice (i.e. with the same entries) in another -place. - -comment: - - "comment" - - -This defines a comment which is displayed to the user during the -configuration process and is also echoed to the output files. The only -possible options are dependencies. - -menu: - - "menu" - - - "endmenu" - -This defines a menu block, see "Menu structure" above for more -information. The only possible options are dependencies and "visible" -attributes. - -if: - - "if" - - "endif" - -This defines an if block. The dependency expression is appended -to all enclosed menu entries. - -source: - - "source" - -This reads the specified configuration file. This file is always parsed. - -mainmenu: - - "mainmenu" - -This sets the config program's title bar if the config program chooses -to use it. It should be placed at the top of the configuration, before any -other statement. - -'#' Kconfig source file comment: - -An unquoted '#' character anywhere in a source file line indicates -the beginning of a source file comment. The remainder of that line -is a comment. - - -Kconfig hints -------------- -This is a collection of Kconfig tips, most of which aren't obvious at -first glance and most of which have become idioms in several Kconfig -files. - -Adding common features and make the usage configurable -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -It is a common idiom to implement a feature/functionality that are -relevant for some architectures but not all. -The recommended way to do so is to use a config variable named HAVE_* -that is defined in a common Kconfig file and selected by the relevant -architectures. -An example is the generic IOMAP functionality. - -We would in lib/Kconfig see: - -# Generic IOMAP is used to ... -config HAVE_GENERIC_IOMAP - -config GENERIC_IOMAP - depends on HAVE_GENERIC_IOMAP && FOO - -And in lib/Makefile we would see: -obj-$(CONFIG_GENERIC_IOMAP) += iomap.o - -For each architecture using the generic IOMAP functionality we would see: - -config X86 - select ... - select HAVE_GENERIC_IOMAP - select ... - -Note: we use the existing config option and avoid creating a new -config variable to select HAVE_GENERIC_IOMAP. - -Note: the use of the internal config variable HAVE_GENERIC_IOMAP, it is -introduced to overcome the limitation of select which will force a -config option to 'y' no matter the dependencies. -The dependencies are moved to the symbol GENERIC_IOMAP and we avoid the -situation where select forces a symbol equals to 'y'. - -Adding features that need compiler support -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There are several features that need compiler support. The recommended way -to describe the dependency on the compiler feature is to use "depends on" -followed by a test macro. - -config STACKPROTECTOR - bool "Stack Protector buffer overflow detection" - depends on $(cc-option,-fstack-protector) - ... - -If you need to expose a compiler capability to makefiles and/or C source files, -CC_HAS_ is the recommended prefix for the config option. - -config CC_HAS_STACKPROTECTOR_NONE - def_bool $(cc-option,-fno-stack-protector) - -Build as module only -~~~~~~~~~~~~~~~~~~~~ -To restrict a component build to module-only, qualify its config symbol -with "depends on m". E.g.: - -config FOO - depends on BAR && m - -limits FOO to module (=m) or disabled (=n). - -Kconfig recursive dependency limitations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you've hit the Kconfig error: "recursive dependency detected" you've run -into a recursive dependency issue with Kconfig, a recursive dependency can be -summarized as a circular dependency. The kconfig tools need to ensure that -Kconfig files comply with specified configuration requirements. In order to do -that kconfig must determine the values that are possible for all Kconfig -symbols, this is currently not possible if there is a circular relation -between two or more Kconfig symbols. For more details refer to the "Simple -Kconfig recursive issue" subsection below. Kconfig does not do recursive -dependency resolution; this has a few implications for Kconfig file writers. -We'll first explain why this issues exists and then provide an example -technical limitation which this brings upon Kconfig developers. Eager -developers wishing to try to address this limitation should read the next -subsections. - -Simple Kconfig recursive issue -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Read: Documentation/kbuild/Kconfig.recursion-issue-01 - -Test with: - -make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-01 allnoconfig - -Cumulative Kconfig recursive issue -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Read: Documentation/kbuild/Kconfig.recursion-issue-02 - -Test with: - -make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-02 allnoconfig - -Practical solutions to kconfig recursive issue -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Developers who run into the recursive Kconfig issue have two options -at their disposal. We document them below and also provide a list of -historical issues resolved through these different solutions. - - a) Remove any superfluous "select FOO" or "depends on FOO" - b) Match dependency semantics: - b1) Swap all "select FOO" to "depends on FOO" or, - b2) Swap all "depends on FOO" to "select FOO" - -The resolution to a) can be tested with the sample Kconfig file -Documentation/kbuild/Kconfig.recursion-issue-01 through the removal -of the "select CORE" from CORE_BELL_A_ADVANCED as that is implicit already -since CORE_BELL_A depends on CORE. At times it may not be possible to remove -some dependency criteria, for such cases you can work with solution b). - -The two different resolutions for b) can be tested in the sample Kconfig file -Documentation/kbuild/Kconfig.recursion-issue-02. - -Below is a list of examples of prior fixes for these types of recursive issues; -all errors appear to involve one or more select's and one or more "depends on". - -commit fix -====== === -06b718c01208 select A -> depends on A -c22eacfe82f9 depends on A -> depends on B -6a91e854442c select A -> depends on A -118c565a8f2e select A -> select B -f004e5594705 select A -> depends on A -c7861f37b4c6 depends on A -> (null) -80c69915e5fb select A -> (null) (1) -c2218e26c0d0 select A -> depends on A (1) -d6ae99d04e1c select A -> depends on A -95ca19cf8cbf select A -> depends on A -8f057d7bca54 depends on A -> (null) -8f057d7bca54 depends on A -> select A -a0701f04846e select A -> depends on A -0c8b92f7f259 depends on A -> (null) -e4e9e0540928 select A -> depends on A (2) -7453ea886e87 depends on A > (null) (1) -7b1fff7e4fdf select A -> depends on A -86c747d2a4f0 select A -> depends on A -d9f9ab51e55e select A -> depends on A -0c51a4d8abd6 depends on A -> select A (3) -e98062ed6dc4 select A -> depends on A (3) -91e5d284a7f1 select A -> (null) - -(1) Partial (or no) quote of error. -(2) That seems to be the gist of that fix. -(3) Same error. - -Future kconfig work -~~~~~~~~~~~~~~~~~~~ - -Work on kconfig is welcomed on both areas of clarifying semantics and on -evaluating the use of a full SAT solver for it. A full SAT solver can be -desirable to enable more complex dependency mappings and / or queries, -for instance on possible use case for a SAT solver could be that of handling -the current known recursive dependency issues. It is not known if this would -address such issues but such evaluation is desirable. If support for a full SAT -solver proves too complex or that it cannot address recursive dependency issues -Kconfig should have at least clear and well defined semantics which also -addresses and documents limitations or requirements such as the ones dealing -with recursive dependencies. - -Further work on both of these areas is welcomed on Kconfig. We elaborate -on both of these in the next two subsections. - -Semantics of Kconfig -~~~~~~~~~~~~~~~~~~~~ - -The use of Kconfig is broad, Linux is now only one of Kconfig's users: -one study has completed a broad analysis of Kconfig use in 12 projects [0]. -Despite its widespread use, and although this document does a reasonable job -in documenting basic Kconfig syntax a more precise definition of Kconfig -semantics is welcomed. One project deduced Kconfig semantics through -the use of the xconfig configurator [1]. Work should be done to confirm if -the deduced semantics matches our intended Kconfig design goals. - -Having well defined semantics can be useful for tools for practical -evaluation of depenencies, for instance one such use known case was work to -express in boolean abstraction of the inferred semantics of Kconfig to -translate Kconfig logic into boolean formulas and run a SAT solver on this to -find dead code / features (always inactive), 114 dead features were found in -Linux using this methodology [1] (Section 8: Threats to validity). - -Confirming this could prove useful as Kconfig stands as one of the the leading -industrial variability modeling languages [1] [2]. Its study would help -evaluate practical uses of such languages, their use was only theoretical -and real world requirements were not well understood. As it stands though -only reverse engineering techniques have been used to deduce semantics from -variability modeling languages such as Kconfig [3]. - -[0] http://www.eng.uwaterloo.ca/~shshe/kconfig_semantics.pdf -[1] http://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf -[2] http://gsd.uwaterloo.ca/sites/default/files/ase241-berger_0.pdf -[3] http://gsd.uwaterloo.ca/sites/default/files/icse2011.pdf - -Full SAT solver for Kconfig -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Although SAT solvers [0] haven't yet been used by Kconfig directly, as noted in -the previous subsection, work has been done however to express in boolean -abstraction the inferred semantics of Kconfig to translate Kconfig logic into -boolean formulas and run a SAT solver on it [1]. Another known related project -is CADOS [2] (former VAMOS [3]) and the tools, mainly undertaker [4], which has -been introduced first with [5]. The basic concept of undertaker is to exract -variability models from Kconfig, and put them together with a propositional -formula extracted from CPP #ifdefs and build-rules into a SAT solver in order -to find dead code, dead files, and dead symbols. If using a SAT solver is -desirable on Kconfig one approach would be to evaluate repurposing such efforts -somehow on Kconfig. There is enough interest from mentors of existing projects -to not only help advise how to integrate this work upstream but also help -maintain it long term. Interested developers should visit: - -http://kernelnewbies.org/KernelProjects/kconfig-sat - -[0] http://www.cs.cornell.edu/~sabhar/chapters/SATSolvers-KR-Handbook.pdf -[1] http://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf -[2] https://cados.cs.fau.de -[3] https://vamos.cs.fau.de -[4] https://undertaker.cs.fau.de -[5] https://www4.cs.fau.de/Publications/2011/tartler_11_eurosys.pdf diff --git a/Documentation/kbuild/kconfig-macro-language.rst b/Documentation/kbuild/kconfig-macro-language.rst new file mode 100644 index 000000000000..35b3263b7e40 --- /dev/null +++ b/Documentation/kbuild/kconfig-macro-language.rst @@ -0,0 +1,247 @@ +====================== +Kconfig macro language +====================== + +Concept +------- + +The basic idea was inspired by Make. When we look at Make, we notice sort of +two languages in one. One language describes dependency graphs consisting of +targets and prerequisites. The other is a macro language for performing textual +substitution. + +There is clear distinction between the two language stages. For example, you +can write a makefile like follows:: + + APP := foo + SRC := foo.c + CC := gcc + + $(APP): $(SRC) + $(CC) -o $(APP) $(SRC) + +The macro language replaces the variable references with their expanded form, +and handles as if the source file were input like follows:: + + foo: foo.c + gcc -o foo foo.c + +Then, Make analyzes the dependency graph and determines the targets to be +updated. + +The idea is quite similar in Kconfig - it is possible to describe a Kconfig +file like this:: + + CC := gcc + + config CC_HAS_FOO + def_bool $(shell, $(srctree)/scripts/gcc-check-foo.sh $(CC)) + +The macro language in Kconfig processes the source file into the following +intermediate:: + + config CC_HAS_FOO + def_bool y + +Then, Kconfig moves onto the evaluation stage to resolve inter-symbol +dependency as explained in kconfig-language.txt. + + +Variables +--------- + +Like in Make, a variable in Kconfig works as a macro variable. A macro +variable is expanded "in place" to yield a text string that may then be +expanded further. To get the value of a variable, enclose the variable name in +$( ). The parentheses are required even for single-letter variable names; $X is +a syntax error. The curly brace form as in ${CC} is not supported either. + +There are two types of variables: simply expanded variables and recursively +expanded variables. + +A simply expanded variable is defined using the := assignment operator. Its +righthand side is expanded immediately upon reading the line from the Kconfig +file. + +A recursively expanded variable is defined using the = assignment operator. +Its righthand side is simply stored as the value of the variable without +expanding it in any way. Instead, the expansion is performed when the variable +is used. + +There is another type of assignment operator; += is used to append text to a +variable. The righthand side of += is expanded immediately if the lefthand +side was originally defined as a simple variable. Otherwise, its evaluation is +deferred. + +The variable reference can take parameters, in the following form:: + + $(name,arg1,arg2,arg3) + +You can consider the parameterized reference as a function. (more precisely, +"user-defined function" in contrast to "built-in function" listed below). + +Useful functions must be expanded when they are used since the same function is +expanded differently if different parameters are passed. Hence, a user-defined +function is defined using the = assignment operator. The parameters are +referenced within the body definition with $(1), $(2), etc. + +In fact, recursively expanded variables and user-defined functions are the same +internally. (In other words, "variable" is "function with zero argument".) +When we say "variable" in a broad sense, it includes "user-defined function". + + +Built-in functions +------------------ + +Like Make, Kconfig provides several built-in functions. Every function takes a +particular number of arguments. + +In Make, every built-in function takes at least one argument. Kconfig allows +zero argument for built-in functions, such as $(fileno), $(lineno). You could +consider those as "built-in variable", but it is just a matter of how we call +it after all. Let's say "built-in function" here to refer to natively supported +functionality. + +Kconfig currently supports the following built-in functions. + + - $(shell,command) + + The "shell" function accepts a single argument that is expanded and passed + to a subshell for execution. The standard output of the command is then read + and returned as the value of the function. Every newline in the output is + replaced with a space. Any trailing newlines are deleted. The standard error + is not returned, nor is any program exit status. + + - $(info,text) + + The "info" function takes a single argument and prints it to stdout. + It evaluates to an empty string. + + - $(warning-if,condition,text) + + The "warning-if" function takes two arguments. If the condition part is "y", + the text part is sent to stderr. The text is prefixed with the name of the + current Kconfig file and the current line number. + + - $(error-if,condition,text) + + The "error-if" function is similar to "warning-if", but it terminates the + parsing immediately if the condition part is "y". + + - $(filename) + + The 'filename' takes no argument, and $(filename) is expanded to the file + name being parsed. + + - $(lineno) + + The 'lineno' takes no argument, and $(lineno) is expanded to the line number + being parsed. + + +Make vs Kconfig +--------------- + +Kconfig adopts Make-like macro language, but the function call syntax is +slightly different. + +A function call in Make looks like this:: + + $(func-name arg1,arg2,arg3) + +The function name and the first argument are separated by at least one +whitespace. Then, leading whitespaces are trimmed from the first argument, +while whitespaces in the other arguments are kept. You need to use a kind of +trick to start the first parameter with spaces. For example, if you want +to make "info" function print " hello", you can write like follows:: + + empty := + space := $(empty) $(empty) + $(info $(space)$(space)hello) + +Kconfig uses only commas for delimiters, and keeps all whitespaces in the +function call. Some people prefer putting a space after each comma delimiter:: + + $(func-name, arg1, arg2, arg3) + +In this case, "func-name" will receive " arg1", " arg2", " arg3". The presence +of leading spaces may matter depending on the function. The same applies to +Make - for example, $(subst .c, .o, $(sources)) is a typical mistake; it +replaces ".c" with " .o". + +In Make, a user-defined function is referenced by using a built-in function, +'call', like this:: + + $(call my-func,arg1,arg2,arg3) + +Kconfig invokes user-defined functions and built-in functions in the same way. +The omission of 'call' makes the syntax shorter. + +In Make, some functions treat commas verbatim instead of argument separators. +For example, $(shell echo hello, world) runs the command "echo hello, world". +Likewise, $(info hello, world) prints "hello, world" to stdout. You could say +this is _useful_ inconsistency. + +In Kconfig, for simpler implementation and grammatical consistency, commas that +appear in the $( ) context are always delimiters. It means:: + + $(shell, echo hello, world) + +is an error because it is passing two parameters where the 'shell' function +accepts only one. To pass commas in arguments, you can use the following trick:: + + comma := , + $(shell, echo hello$(comma) world) + + +Caveats +------- + +A variable (or function) cannot be expanded across tokens. So, you cannot use +a variable as a shorthand for an expression that consists of multiple tokens. +The following works:: + + RANGE_MIN := 1 + RANGE_MAX := 3 + + config FOO + int "foo" + range $(RANGE_MIN) $(RANGE_MAX) + +But, the following does not work:: + + RANGES := 1 3 + + config FOO + int "foo" + range $(RANGES) + +A variable cannot be expanded to any keyword in Kconfig. The following does +not work:: + + MY_TYPE := tristate + + config FOO + $(MY_TYPE) "foo" + default y + +Obviously from the design, $(shell command) is expanded in the textual +substitution phase. You cannot pass symbols to the 'shell' function. + +The following does not work as expected:: + + config ENDIAN_FLAG + string + default "-mbig-endian" if CPU_BIG_ENDIAN + default "-mlittle-endian" if CPU_LITTLE_ENDIAN + + config CC_HAS_ENDIAN_FLAG + def_bool $(shell $(srctree)/scripts/gcc-check-flag ENDIAN_FLAG) + +Instead, you can do like follows so that any function call is statically +expanded:: + + config CC_HAS_ENDIAN_FLAG + bool + default $(shell $(srctree)/scripts/gcc-check-flag -mbig-endian) if CPU_BIG_ENDIAN + default $(shell $(srctree)/scripts/gcc-check-flag -mlittle-endian) if CPU_LITTLE_ENDIAN diff --git a/Documentation/kbuild/kconfig-macro-language.txt b/Documentation/kbuild/kconfig-macro-language.txt deleted file mode 100644 index 07da2ea68dce..000000000000 --- a/Documentation/kbuild/kconfig-macro-language.txt +++ /dev/null @@ -1,242 +0,0 @@ -Concept -------- - -The basic idea was inspired by Make. When we look at Make, we notice sort of -two languages in one. One language describes dependency graphs consisting of -targets and prerequisites. The other is a macro language for performing textual -substitution. - -There is clear distinction between the two language stages. For example, you -can write a makefile like follows: - - APP := foo - SRC := foo.c - CC := gcc - - $(APP): $(SRC) - $(CC) -o $(APP) $(SRC) - -The macro language replaces the variable references with their expanded form, -and handles as if the source file were input like follows: - - foo: foo.c - gcc -o foo foo.c - -Then, Make analyzes the dependency graph and determines the targets to be -updated. - -The idea is quite similar in Kconfig - it is possible to describe a Kconfig -file like this: - - CC := gcc - - config CC_HAS_FOO - def_bool $(shell, $(srctree)/scripts/gcc-check-foo.sh $(CC)) - -The macro language in Kconfig processes the source file into the following -intermediate: - - config CC_HAS_FOO - def_bool y - -Then, Kconfig moves onto the evaluation stage to resolve inter-symbol -dependency as explained in kconfig-language.txt. - - -Variables ---------- - -Like in Make, a variable in Kconfig works as a macro variable. A macro -variable is expanded "in place" to yield a text string that may then be -expanded further. To get the value of a variable, enclose the variable name in -$( ). The parentheses are required even for single-letter variable names; $X is -a syntax error. The curly brace form as in ${CC} is not supported either. - -There are two types of variables: simply expanded variables and recursively -expanded variables. - -A simply expanded variable is defined using the := assignment operator. Its -righthand side is expanded immediately upon reading the line from the Kconfig -file. - -A recursively expanded variable is defined using the = assignment operator. -Its righthand side is simply stored as the value of the variable without -expanding it in any way. Instead, the expansion is performed when the variable -is used. - -There is another type of assignment operator; += is used to append text to a -variable. The righthand side of += is expanded immediately if the lefthand -side was originally defined as a simple variable. Otherwise, its evaluation is -deferred. - -The variable reference can take parameters, in the following form: - - $(name,arg1,arg2,arg3) - -You can consider the parameterized reference as a function. (more precisely, -"user-defined function" in contrast to "built-in function" listed below). - -Useful functions must be expanded when they are used since the same function is -expanded differently if different parameters are passed. Hence, a user-defined -function is defined using the = assignment operator. The parameters are -referenced within the body definition with $(1), $(2), etc. - -In fact, recursively expanded variables and user-defined functions are the same -internally. (In other words, "variable" is "function with zero argument".) -When we say "variable" in a broad sense, it includes "user-defined function". - - -Built-in functions ------------------- - -Like Make, Kconfig provides several built-in functions. Every function takes a -particular number of arguments. - -In Make, every built-in function takes at least one argument. Kconfig allows -zero argument for built-in functions, such as $(fileno), $(lineno). You could -consider those as "built-in variable", but it is just a matter of how we call -it after all. Let's say "built-in function" here to refer to natively supported -functionality. - -Kconfig currently supports the following built-in functions. - - - $(shell,command) - - The "shell" function accepts a single argument that is expanded and passed - to a subshell for execution. The standard output of the command is then read - and returned as the value of the function. Every newline in the output is - replaced with a space. Any trailing newlines are deleted. The standard error - is not returned, nor is any program exit status. - - - $(info,text) - - The "info" function takes a single argument and prints it to stdout. - It evaluates to an empty string. - - - $(warning-if,condition,text) - - The "warning-if" function takes two arguments. If the condition part is "y", - the text part is sent to stderr. The text is prefixed with the name of the - current Kconfig file and the current line number. - - - $(error-if,condition,text) - - The "error-if" function is similar to "warning-if", but it terminates the - parsing immediately if the condition part is "y". - - - $(filename) - - The 'filename' takes no argument, and $(filename) is expanded to the file - name being parsed. - - - $(lineno) - - The 'lineno' takes no argument, and $(lineno) is expanded to the line number - being parsed. - - -Make vs Kconfig ---------------- - -Kconfig adopts Make-like macro language, but the function call syntax is -slightly different. - -A function call in Make looks like this: - - $(func-name arg1,arg2,arg3) - -The function name and the first argument are separated by at least one -whitespace. Then, leading whitespaces are trimmed from the first argument, -while whitespaces in the other arguments are kept. You need to use a kind of -trick to start the first parameter with spaces. For example, if you want -to make "info" function print " hello", you can write like follows: - - empty := - space := $(empty) $(empty) - $(info $(space)$(space)hello) - -Kconfig uses only commas for delimiters, and keeps all whitespaces in the -function call. Some people prefer putting a space after each comma delimiter: - - $(func-name, arg1, arg2, arg3) - -In this case, "func-name" will receive " arg1", " arg2", " arg3". The presence -of leading spaces may matter depending on the function. The same applies to -Make - for example, $(subst .c, .o, $(sources)) is a typical mistake; it -replaces ".c" with " .o". - -In Make, a user-defined function is referenced by using a built-in function, -'call', like this: - - $(call my-func,arg1,arg2,arg3) - -Kconfig invokes user-defined functions and built-in functions in the same way. -The omission of 'call' makes the syntax shorter. - -In Make, some functions treat commas verbatim instead of argument separators. -For example, $(shell echo hello, world) runs the command "echo hello, world". -Likewise, $(info hello, world) prints "hello, world" to stdout. You could say -this is _useful_ inconsistency. - -In Kconfig, for simpler implementation and grammatical consistency, commas that -appear in the $( ) context are always delimiters. It means - - $(shell, echo hello, world) - -is an error because it is passing two parameters where the 'shell' function -accepts only one. To pass commas in arguments, you can use the following trick: - - comma := , - $(shell, echo hello$(comma) world) - - -Caveats -------- - -A variable (or function) cannot be expanded across tokens. So, you cannot use -a variable as a shorthand for an expression that consists of multiple tokens. -The following works: - - RANGE_MIN := 1 - RANGE_MAX := 3 - - config FOO - int "foo" - range $(RANGE_MIN) $(RANGE_MAX) - -But, the following does not work: - - RANGES := 1 3 - - config FOO - int "foo" - range $(RANGES) - -A variable cannot be expanded to any keyword in Kconfig. The following does -not work: - - MY_TYPE := tristate - - config FOO - $(MY_TYPE) "foo" - default y - -Obviously from the design, $(shell command) is expanded in the textual -substitution phase. You cannot pass symbols to the 'shell' function. -The following does not work as expected. - - config ENDIAN_FLAG - string - default "-mbig-endian" if CPU_BIG_ENDIAN - default "-mlittle-endian" if CPU_LITTLE_ENDIAN - - config CC_HAS_ENDIAN_FLAG - def_bool $(shell $(srctree)/scripts/gcc-check-flag ENDIAN_FLAG) - -Instead, you can do like follows so that any function call is statically -expanded. - - config CC_HAS_ENDIAN_FLAG - bool - default $(shell $(srctree)/scripts/gcc-check-flag -mbig-endian) if CPU_BIG_ENDIAN - default $(shell $(srctree)/scripts/gcc-check-flag -mlittle-endian) if CPU_LITTLE_ENDIAN diff --git a/Documentation/kbuild/kconfig.rst b/Documentation/kbuild/kconfig.rst new file mode 100644 index 000000000000..88129af7e539 --- /dev/null +++ b/Documentation/kbuild/kconfig.rst @@ -0,0 +1,300 @@ +=================== +Kconfig make config +=================== + +This file contains some assistance for using `make *config`. + +Use "make help" to list all of the possible configuration targets. + +The xconfig ('qconf'), menuconfig ('mconf'), and nconfig ('nconf') +programs also have embedded help text. Be sure to check that for +navigation, search, and other general help text. + +General +------- + +New kernel releases often introduce new config symbols. Often more +important, new kernel releases may rename config symbols. When +this happens, using a previously working .config file and running +"make oldconfig" won't necessarily produce a working new kernel +for you, so you may find that you need to see what NEW kernel +symbols have been introduced. + +To see a list of new config symbols, use:: + + cp user/some/old.config .config + make listnewconfig + +and the config program will list any new symbols, one per line. + +Alternatively, you can use the brute force method:: + + make oldconfig + scripts/diffconfig .config.old .config | less + +---------------------------------------------------------------------- + +Environment variables for `*config` + +KCONFIG_CONFIG +-------------- +This environment variable can be used to specify a default kernel config +file name to override the default name of ".config". + +KCONFIG_OVERWRITECONFIG +----------------------- +If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not +break symlinks when .config is a symlink to somewhere else. + +`CONFIG_` +--------- +If you set `CONFIG_` in the environment, Kconfig will prefix all symbols +with its value when saving the configuration, instead of using the default, +`CONFIG_`. + +---------------------------------------------------------------------- + +Environment variables for '{allyes/allmod/allno/rand}config' + +KCONFIG_ALLCONFIG +----------------- +(partially based on lkml email from/by Rob Landley, re: miniconfig) + +-------------------------------------------------- + +The allyesconfig/allmodconfig/allnoconfig/randconfig variants can also +use the environment variable KCONFIG_ALLCONFIG as a flag or a filename +that contains config symbols that the user requires to be set to a +specific value. If KCONFIG_ALLCONFIG is used without a filename where +KCONFIG_ALLCONFIG == "" or KCONFIG_ALLCONFIG == "1", `make *config` +checks for a file named "all{yes/mod/no/def/random}.config" +(corresponding to the `*config` command that was used) for symbol values +that are to be forced. If this file is not found, it checks for a +file named "all.config" to contain forced values. + +This enables you to create "miniature" config (miniconfig) or custom +config files containing just the config symbols that you are interested +in. Then the kernel config system generates the full .config file, +including symbols of your miniconfig file. + +This 'KCONFIG_ALLCONFIG' file is a config file which contains +(usually a subset of all) preset config symbols. These variable +settings are still subject to normal dependency checks. + +Examples:: + + KCONFIG_ALLCONFIG=custom-notebook.config make allnoconfig + +or:: + + KCONFIG_ALLCONFIG=mini.config make allnoconfig + +or:: + + make KCONFIG_ALLCONFIG=mini.config allnoconfig + +These examples will disable most options (allnoconfig) but enable or +disable the options that are explicitly listed in the specified +mini-config files. + +---------------------------------------------------------------------- + +Environment variables for 'randconfig' + +KCONFIG_SEED +------------ +You can set this to the integer value used to seed the RNG, if you want +to somehow debug the behaviour of the kconfig parser/frontends. +If not set, the current time will be used. + +KCONFIG_PROBABILITY +------------------- +This variable can be used to skew the probabilities. This variable can +be unset or empty, or set to three different formats: + + ======================= ================== ===================== + KCONFIG_PROBABILITY y:n split y:m:n split + ======================= ================== ===================== + unset or empty 50 : 50 33 : 33 : 34 + N N : 100-N N/2 : N/2 : 100-N + [1] N:M N+M : 100-(N+M) N : M : 100-(N+M) + [2] N:M:L N : 100-N M : L : 100-(M+L) + ======================= ================== ===================== + +where N, M and L are integers (in base 10) in the range [0,100], and so +that: + + [1] N+M is in the range [0,100] + + [2] M+L is in the range [0,100] + +Examples:: + + KCONFIG_PROBABILITY=10 + 10% of booleans will be set to 'y', 90% to 'n' + 5% of tristates will be set to 'y', 5% to 'm', 90% to 'n' + KCONFIG_PROBABILITY=15:25 + 40% of booleans will be set to 'y', 60% to 'n' + 15% of tristates will be set to 'y', 25% to 'm', 60% to 'n' + KCONFIG_PROBABILITY=10:15:15 + 10% of booleans will be set to 'y', 90% to 'n' + 15% of tristates will be set to 'y', 15% to 'm', 70% to 'n' + +---------------------------------------------------------------------- + +Environment variables for 'syncconfig' + +KCONFIG_NOSILENTUPDATE +---------------------- +If this variable has a non-blank value, it prevents silent kernel +config updates (requires explicit updates). + +KCONFIG_AUTOCONFIG +------------------ +This environment variable can be set to specify the path & name of the +"auto.conf" file. Its default value is "include/config/auto.conf". + +KCONFIG_TRISTATE +---------------- +This environment variable can be set to specify the path & name of the +"tristate.conf" file. Its default value is "include/config/tristate.conf". + +KCONFIG_AUTOHEADER +------------------ +This environment variable can be set to specify the path & name of the +"autoconf.h" (header) file. +Its default value is "include/generated/autoconf.h". + + +---------------------------------------------------------------------- + +menuconfig +---------- + +SEARCHING for CONFIG symbols + +Searching in menuconfig: + + The Search function searches for kernel configuration symbol + names, so you have to know something close to what you are + looking for. + + Example:: + + /hotplug + This lists all config symbols that contain "hotplug", + e.g., HOTPLUG_CPU, MEMORY_HOTPLUG. + + For search help, enter / followed by TAB-TAB (to highlight + ) and Enter. This will tell you that you can also use + regular expressions (regexes) in the search string, so if you + are not interested in MEMORY_HOTPLUG, you could try:: + + /^hotplug + + When searching, symbols are sorted thus: + + - first, exact matches, sorted alphabetically (an exact match + is when the search matches the complete symbol name); + - then, other matches, sorted alphabetically. + + For example: ^ATH.K matches: + + ATH5K ATH9K ATH5K_AHB ATH5K_DEBUG [...] ATH6KL ATH6KL_DEBUG + [...] ATH9K_AHB ATH9K_BTCOEX_SUPPORT ATH9K_COMMON [...] + + of which only ATH5K and ATH9K match exactly and so are sorted + first (and in alphabetical order), then come all other symbols, + sorted in alphabetical order. + +---------------------------------------------------------------------- + +User interface options for 'menuconfig' + +MENUCONFIG_COLOR +---------------- +It is possible to select different color themes using the variable +MENUCONFIG_COLOR. To select a theme use:: + + make MENUCONFIG_COLOR= menuconfig + +Available themes are:: + + - mono => selects colors suitable for monochrome displays + - blackbg => selects a color scheme with black background + - classic => theme with blue background. The classic look + - bluetitle => a LCD friendly version of classic. (default) + +MENUCONFIG_MODE +--------------- +This mode shows all sub-menus in one large tree. + +Example:: + + make MENUCONFIG_MODE=single_menu menuconfig + +---------------------------------------------------------------------- + +nconfig +------- + +nconfig is an alternate text-based configurator. It lists function +keys across the bottom of the terminal (window) that execute commands. +You can also just use the corresponding numeric key to execute the +commands unless you are in a data entry window. E.g., instead of F6 +for Save, you can just press 6. + +Use F1 for Global help or F3 for the Short help menu. + +Searching in nconfig: + + You can search either in the menu entry "prompt" strings + or in the configuration symbols. + + Use / to begin a search through the menu entries. This does + not support regular expressions. Use or for + Next hit and Previous hit, respectively. Use to + terminate the search mode. + + F8 (SymSearch) searches the configuration symbols for the + given string or regular expression (regex). + +NCONFIG_MODE +------------ +This mode shows all sub-menus in one large tree. + +Example:: + make NCONFIG_MODE=single_menu nconfig + +---------------------------------------------------------------------- + +xconfig +------- + +Searching in xconfig: + + The Search function searches for kernel configuration symbol + names, so you have to know something close to what you are + looking for. + + Example: + Ctrl-F hotplug + or + Menu: File, Search, hotplug + + lists all config symbol entries that contain "hotplug" in + the symbol name. In this Search dialog, you may change the + config setting for any of the entries that are not grayed out. + You can also enter a different search string without having + to return to the main menu. + + +---------------------------------------------------------------------- + +gconfig +------- + +Searching in gconfig: + + There is no search command in gconfig. However, gconfig does + have several different viewing choices, modes, and options. diff --git a/Documentation/kbuild/kconfig.txt b/Documentation/kbuild/kconfig.txt deleted file mode 100644 index 68c82914c0f3..000000000000 --- a/Documentation/kbuild/kconfig.txt +++ /dev/null @@ -1,272 +0,0 @@ -This file contains some assistance for using "make *config". - -Use "make help" to list all of the possible configuration targets. - -The xconfig ('qconf'), menuconfig ('mconf'), and nconfig ('nconf') -programs also have embedded help text. Be sure to check that for -navigation, search, and other general help text. - -====================================================================== -General --------------------------------------------------- - -New kernel releases often introduce new config symbols. Often more -important, new kernel releases may rename config symbols. When -this happens, using a previously working .config file and running -"make oldconfig" won't necessarily produce a working new kernel -for you, so you may find that you need to see what NEW kernel -symbols have been introduced. - -To see a list of new config symbols, use - - cp user/some/old.config .config - make listnewconfig - -and the config program will list any new symbols, one per line. - -Alternatively, you can use the brute force method: - - make oldconfig - scripts/diffconfig .config.old .config | less - -______________________________________________________________________ -Environment variables for '*config' - -KCONFIG_CONFIG --------------------------------------------------- -This environment variable can be used to specify a default kernel config -file name to override the default name of ".config". - -KCONFIG_OVERWRITECONFIG --------------------------------------------------- -If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not -break symlinks when .config is a symlink to somewhere else. - -CONFIG_ --------------------------------------------------- -If you set CONFIG_ in the environment, Kconfig will prefix all symbols -with its value when saving the configuration, instead of using the default, -"CONFIG_". - -______________________________________________________________________ -Environment variables for '{allyes/allmod/allno/rand}config' - -KCONFIG_ALLCONFIG --------------------------------------------------- -(partially based on lkml email from/by Rob Landley, re: miniconfig) --------------------------------------------------- -The allyesconfig/allmodconfig/allnoconfig/randconfig variants can also -use the environment variable KCONFIG_ALLCONFIG as a flag or a filename -that contains config symbols that the user requires to be set to a -specific value. If KCONFIG_ALLCONFIG is used without a filename where -KCONFIG_ALLCONFIG == "" or KCONFIG_ALLCONFIG == "1", "make *config" -checks for a file named "all{yes/mod/no/def/random}.config" -(corresponding to the *config command that was used) for symbol values -that are to be forced. If this file is not found, it checks for a -file named "all.config" to contain forced values. - -This enables you to create "miniature" config (miniconfig) or custom -config files containing just the config symbols that you are interested -in. Then the kernel config system generates the full .config file, -including symbols of your miniconfig file. - -This 'KCONFIG_ALLCONFIG' file is a config file which contains -(usually a subset of all) preset config symbols. These variable -settings are still subject to normal dependency checks. - -Examples: - KCONFIG_ALLCONFIG=custom-notebook.config make allnoconfig -or - KCONFIG_ALLCONFIG=mini.config make allnoconfig -or - make KCONFIG_ALLCONFIG=mini.config allnoconfig - -These examples will disable most options (allnoconfig) but enable or -disable the options that are explicitly listed in the specified -mini-config files. - -______________________________________________________________________ -Environment variables for 'randconfig' - -KCONFIG_SEED --------------------------------------------------- -You can set this to the integer value used to seed the RNG, if you want -to somehow debug the behaviour of the kconfig parser/frontends. -If not set, the current time will be used. - -KCONFIG_PROBABILITY --------------------------------------------------- -This variable can be used to skew the probabilities. This variable can -be unset or empty, or set to three different formats: - KCONFIG_PROBABILITY y:n split y:m:n split - ----------------------------------------------------------------- - unset or empty 50 : 50 33 : 33 : 34 - N N : 100-N N/2 : N/2 : 100-N - [1] N:M N+M : 100-(N+M) N : M : 100-(N+M) - [2] N:M:L N : 100-N M : L : 100-(M+L) - -where N, M and L are integers (in base 10) in the range [0,100], and so -that: - [1] N+M is in the range [0,100] - [2] M+L is in the range [0,100] - -Examples: - KCONFIG_PROBABILITY=10 - 10% of booleans will be set to 'y', 90% to 'n' - 5% of tristates will be set to 'y', 5% to 'm', 90% to 'n' - KCONFIG_PROBABILITY=15:25 - 40% of booleans will be set to 'y', 60% to 'n' - 15% of tristates will be set to 'y', 25% to 'm', 60% to 'n' - KCONFIG_PROBABILITY=10:15:15 - 10% of booleans will be set to 'y', 90% to 'n' - 15% of tristates will be set to 'y', 15% to 'm', 70% to 'n' - -______________________________________________________________________ -Environment variables for 'syncconfig' - -KCONFIG_NOSILENTUPDATE --------------------------------------------------- -If this variable has a non-blank value, it prevents silent kernel -config updates (requires explicit updates). - -KCONFIG_AUTOCONFIG --------------------------------------------------- -This environment variable can be set to specify the path & name of the -"auto.conf" file. Its default value is "include/config/auto.conf". - -KCONFIG_TRISTATE --------------------------------------------------- -This environment variable can be set to specify the path & name of the -"tristate.conf" file. Its default value is "include/config/tristate.conf". - -KCONFIG_AUTOHEADER --------------------------------------------------- -This environment variable can be set to specify the path & name of the -"autoconf.h" (header) file. -Its default value is "include/generated/autoconf.h". - - -====================================================================== -menuconfig --------------------------------------------------- - -SEARCHING for CONFIG symbols - -Searching in menuconfig: - - The Search function searches for kernel configuration symbol - names, so you have to know something close to what you are - looking for. - - Example: - /hotplug - This lists all config symbols that contain "hotplug", - e.g., HOTPLUG_CPU, MEMORY_HOTPLUG. - - For search help, enter / followed by TAB-TAB (to highlight - ) and Enter. This will tell you that you can also use - regular expressions (regexes) in the search string, so if you - are not interested in MEMORY_HOTPLUG, you could try - - /^hotplug - - When searching, symbols are sorted thus: - - first, exact matches, sorted alphabetically (an exact match - is when the search matches the complete symbol name); - - then, other matches, sorted alphabetically. - For example: ^ATH.K matches: - ATH5K ATH9K ATH5K_AHB ATH5K_DEBUG [...] ATH6KL ATH6KL_DEBUG - [...] ATH9K_AHB ATH9K_BTCOEX_SUPPORT ATH9K_COMMON [...] - of which only ATH5K and ATH9K match exactly and so are sorted - first (and in alphabetical order), then come all other symbols, - sorted in alphabetical order. - -______________________________________________________________________ -User interface options for 'menuconfig' - -MENUCONFIG_COLOR --------------------------------------------------- -It is possible to select different color themes using the variable -MENUCONFIG_COLOR. To select a theme use: - - make MENUCONFIG_COLOR= menuconfig - -Available themes are: - mono => selects colors suitable for monochrome displays - blackbg => selects a color scheme with black background - classic => theme with blue background. The classic look - bluetitle => a LCD friendly version of classic. (default) - -MENUCONFIG_MODE --------------------------------------------------- -This mode shows all sub-menus in one large tree. - -Example: - make MENUCONFIG_MODE=single_menu menuconfig - - -====================================================================== -nconfig --------------------------------------------------- - -nconfig is an alternate text-based configurator. It lists function -keys across the bottom of the terminal (window) that execute commands. -You can also just use the corresponding numeric key to execute the -commands unless you are in a data entry window. E.g., instead of F6 -for Save, you can just press 6. - -Use F1 for Global help or F3 for the Short help menu. - -Searching in nconfig: - - You can search either in the menu entry "prompt" strings - or in the configuration symbols. - - Use / to begin a search through the menu entries. This does - not support regular expressions. Use or for - Next hit and Previous hit, respectively. Use to - terminate the search mode. - - F8 (SymSearch) searches the configuration symbols for the - given string or regular expression (regex). - -NCONFIG_MODE --------------------------------------------------- -This mode shows all sub-menus in one large tree. - -Example: - make NCONFIG_MODE=single_menu nconfig - - -====================================================================== -xconfig --------------------------------------------------- - -Searching in xconfig: - - The Search function searches for kernel configuration symbol - names, so you have to know something close to what you are - looking for. - - Example: - Ctrl-F hotplug - or - Menu: File, Search, hotplug - - lists all config symbol entries that contain "hotplug" in - the symbol name. In this Search dialog, you may change the - config setting for any of the entries that are not grayed out. - You can also enter a different search string without having - to return to the main menu. - - -====================================================================== -gconfig --------------------------------------------------- - -Searching in gconfig: - - There is no search command in gconfig. However, gconfig does - have several different viewing choices, modes, and options. - -### diff --git a/Documentation/kbuild/makefiles.rst b/Documentation/kbuild/makefiles.rst new file mode 100644 index 000000000000..9274cdcc9bd2 --- /dev/null +++ b/Documentation/kbuild/makefiles.rst @@ -0,0 +1,1509 @@ +====================== +Linux Kernel Makefiles +====================== + +This document describes the Linux kernel Makefiles. + +.. Table of Contents + + === 1 Overview + === 2 Who does what + === 3 The kbuild files + --- 3.1 Goal definitions + --- 3.2 Built-in object goals - obj-y + --- 3.3 Loadable module goals - obj-m + --- 3.4 Objects which export symbols + --- 3.5 Library file goals - lib-y + --- 3.6 Descending down in directories + --- 3.7 Compilation flags + --- 3.8 Command line dependency + --- 3.9 Dependency tracking + --- 3.10 Special Rules + --- 3.11 $(CC) support functions + --- 3.12 $(LD) support functions + + === 4 Host Program support + --- 4.1 Simple Host Program + --- 4.2 Composite Host Programs + --- 4.3 Using C++ for host programs + --- 4.4 Controlling compiler options for host programs + --- 4.5 When host programs are actually built + --- 4.6 Using hostprogs-$(CONFIG_FOO) + + === 5 Kbuild clean infrastructure + + === 6 Architecture Makefiles + --- 6.1 Set variables to tweak the build to the architecture + --- 6.2 Add prerequisites to archheaders: + --- 6.3 Add prerequisites to archprepare: + --- 6.4 List directories to visit when descending + --- 6.5 Architecture-specific boot images + --- 6.6 Building non-kbuild targets + --- 6.7 Commands useful for building a boot image + --- 6.8 Custom kbuild commands + --- 6.9 Preprocessing linker scripts + --- 6.10 Generic header files + --- 6.11 Post-link pass + + === 7 Kbuild syntax for exported headers + --- 7.1 no-export-headers + --- 7.2 generic-y + --- 7.3 generated-y + --- 7.4 mandatory-y + + === 8 Kbuild Variables + === 9 Makefile language + === 10 Credits + === 11 TODO + +1 Overview +========== + +The Makefiles have five parts:: + + Makefile the top Makefile. + .config the kernel configuration file. + arch/$(ARCH)/Makefile the arch Makefile. + scripts/Makefile.* common rules etc. for all kbuild Makefiles. + kbuild Makefiles there are about 500 of these. + +The top Makefile reads the .config file, which comes from the kernel +configuration process. + +The top Makefile is responsible for building two major products: vmlinux +(the resident kernel image) and modules (any module files). +It builds these goals by recursively descending into the subdirectories of +the kernel source tree. +The list of subdirectories which are visited depends upon the kernel +configuration. The top Makefile textually includes an arch Makefile +with the name arch/$(ARCH)/Makefile. The arch Makefile supplies +architecture-specific information to the top Makefile. + +Each subdirectory has a kbuild Makefile which carries out the commands +passed down from above. The kbuild Makefile uses information from the +.config file to construct various file lists used by kbuild to build +any built-in or modular targets. + +scripts/Makefile.* contains all the definitions/rules etc. that +are used to build the kernel based on the kbuild makefiles. + + +2 Who does what +=============== + +People have four different relationships with the kernel Makefiles. + +*Users* are people who build kernels. These people type commands such as +"make menuconfig" or "make". They usually do not read or edit +any kernel Makefiles (or any other source files). + +*Normal developers* are people who work on features such as device +drivers, file systems, and network protocols. These people need to +maintain the kbuild Makefiles for the subsystem they are +working on. In order to do this effectively, they need some overall +knowledge about the kernel Makefiles, plus detailed knowledge about the +public interface for kbuild. + +*Arch developers* are people who work on an entire architecture, such +as sparc or ia64. Arch developers need to know about the arch Makefile +as well as kbuild Makefiles. + +*Kbuild developers* are people who work on the kernel build system itself. +These people need to know about all aspects of the kernel Makefiles. + +This document is aimed towards normal developers and arch developers. + + +3 The kbuild files +================== + +Most Makefiles within the kernel are kbuild Makefiles that use the +kbuild infrastructure. This chapter introduces the syntax used in the +kbuild makefiles. +The preferred name for the kbuild files are 'Makefile' but 'Kbuild' can +be used and if both a 'Makefile' and a 'Kbuild' file exists, then the 'Kbuild' +file will be used. + +Section 3.1 "Goal definitions" is a quick intro, further chapters provide +more details, with real examples. + +3.1 Goal definitions +-------------------- + + Goal definitions are the main part (heart) of the kbuild Makefile. + These lines define the files to be built, any special compilation + options, and any subdirectories to be entered recursively. + + The most simple kbuild makefile contains one line: + + Example:: + + obj-y += foo.o + + This tells kbuild that there is one object in that directory, named + foo.o. foo.o will be built from foo.c or foo.S. + + If foo.o shall be built as a module, the variable obj-m is used. + Therefore the following pattern is often used: + + Example:: + + obj-$(CONFIG_FOO) += foo.o + + $(CONFIG_FOO) evaluates to either y (for built-in) or m (for module). + If CONFIG_FOO is neither y nor m, then the file will not be compiled + nor linked. + +3.2 Built-in object goals - obj-y +--------------------------------- + + The kbuild Makefile specifies object files for vmlinux + in the $(obj-y) lists. These lists depend on the kernel + configuration. + + Kbuild compiles all the $(obj-y) files. It then calls + "$(AR) rcSTP" to merge these files into one built-in.a file. + This is a thin archive without a symbol table. It will be later + linked into vmlinux by scripts/link-vmlinux.sh + + The order of files in $(obj-y) is significant. Duplicates in + the lists are allowed: the first instance will be linked into + built-in.a and succeeding instances will be ignored. + + Link order is significant, because certain functions + (module_init() / __initcall) will be called during boot in the + order they appear. So keep in mind that changing the link + order may e.g. change the order in which your SCSI + controllers are detected, and thus your disks are renumbered. + + Example:: + + #drivers/isdn/i4l/Makefile + # Makefile for the kernel ISDN subsystem and device drivers. + # Each configuration option enables a list of files. + obj-$(CONFIG_ISDN_I4L) += isdn.o + obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o + +3.3 Loadable module goals - obj-m +--------------------------------- + + $(obj-m) specifies object files which are built as loadable + kernel modules. + + A module may be built from one source file or several source + files. In the case of one source file, the kbuild makefile + simply adds the file to $(obj-m). + + Example:: + + #drivers/isdn/i4l/Makefile + obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o + + Note: In this example $(CONFIG_ISDN_PPP_BSDCOMP) evaluates to 'm' + + If a kernel module is built from several source files, you specify + that you want to build a module in the same way as above; however, + kbuild needs to know which object files you want to build your + module from, so you have to tell it by setting a $(-y) + variable. + + Example:: + + #drivers/isdn/i4l/Makefile + obj-$(CONFIG_ISDN_I4L) += isdn.o + isdn-y := isdn_net_lib.o isdn_v110.o isdn_common.o + + In this example, the module name will be isdn.o. Kbuild will + compile the objects listed in $(isdn-y) and then run + "$(LD) -r" on the list of these files to generate isdn.o. + + Due to kbuild recognizing $(-y) for composite objects, + you can use the value of a `CONFIG_` symbol to optionally include an + object file as part of a composite object. + + Example:: + + #fs/ext2/Makefile + obj-$(CONFIG_EXT2_FS) += ext2.o + ext2-y := balloc.o dir.o file.o ialloc.o inode.o ioctl.o \ + namei.o super.o symlink.o + ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o \ + xattr_trusted.o + + In this example, xattr.o, xattr_user.o and xattr_trusted.o are only + part of the composite object ext2.o if $(CONFIG_EXT2_FS_XATTR) + evaluates to 'y'. + + Note: Of course, when you are building objects into the kernel, + the syntax above will also work. So, if you have CONFIG_EXT2_FS=y, + kbuild will build an ext2.o file for you out of the individual + parts and then link this into built-in.a, as you would expect. + +3.4 Objects which export symbols +-------------------------------- + + No special notation is required in the makefiles for + modules exporting symbols. + +3.5 Library file goals - lib-y +------------------------------ + + Objects listed with obj-* are used for modules, or + combined in a built-in.a for that specific directory. + There is also the possibility to list objects that will + be included in a library, lib.a. + All objects listed with lib-y are combined in a single + library for that directory. + Objects that are listed in obj-y and additionally listed in + lib-y will not be included in the library, since they will + be accessible anyway. + For consistency, objects listed in lib-m will be included in lib.a. + + Note that the same kbuild makefile may list files to be built-in + and to be part of a library. Therefore the same directory + may contain both a built-in.a and a lib.a file. + + Example:: + + #arch/x86/lib/Makefile + lib-y := delay.o + + This will create a library lib.a based on delay.o. For kbuild to + actually recognize that there is a lib.a being built, the directory + shall be listed in libs-y. + + See also "6.4 List directories to visit when descending". + + Use of lib-y is normally restricted to `lib/` and `arch/*/lib`. + +3.6 Descending down in directories +---------------------------------- + + A Makefile is only responsible for building objects in its own + directory. Files in subdirectories should be taken care of by + Makefiles in these subdirs. The build system will automatically + invoke make recursively in subdirectories, provided you let it know of + them. + + To do so, obj-y and obj-m are used. + ext2 lives in a separate directory, and the Makefile present in fs/ + tells kbuild to descend down using the following assignment. + + Example:: + + #fs/Makefile + obj-$(CONFIG_EXT2_FS) += ext2/ + + If CONFIG_EXT2_FS is set to either 'y' (built-in) or 'm' (modular) + the corresponding obj- variable will be set, and kbuild will descend + down in the ext2 directory. + Kbuild only uses this information to decide that it needs to visit + the directory, it is the Makefile in the subdirectory that + specifies what is modular and what is built-in. + + It is good practice to use a `CONFIG_` variable when assigning directory + names. This allows kbuild to totally skip the directory if the + corresponding `CONFIG_` option is neither 'y' nor 'm'. + +3.7 Compilation flags +--------------------- + + ccflags-y, asflags-y and ldflags-y + These three flags apply only to the kbuild makefile in which they + are assigned. They are used for all the normal cc, as and ld + invocations happening during a recursive build. + Note: Flags with the same behaviour were previously named: + EXTRA_CFLAGS, EXTRA_AFLAGS and EXTRA_LDFLAGS. + They are still supported but their usage is deprecated. + + ccflags-y specifies options for compiling with $(CC). + + Example:: + + # drivers/acpi/acpica/Makefile + ccflags-y := -Os -D_LINUX -DBUILDING_ACPICA + ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT + + This variable is necessary because the top Makefile owns the + variable $(KBUILD_CFLAGS) and uses it for compilation flags for the + entire tree. + + asflags-y specifies options for assembling with $(AS). + + Example:: + + #arch/sparc/kernel/Makefile + asflags-y := -ansi + + ldflags-y specifies options for linking with $(LD). + + Example:: + + #arch/cris/boot/compressed/Makefile + ldflags-y += -T $(srctree)/$(src)/decompress_$(arch-y).lds + + subdir-ccflags-y, subdir-asflags-y + The two flags listed above are similar to ccflags-y and asflags-y. + The difference is that the subdir- variants have effect for the kbuild + file where they are present and all subdirectories. + Options specified using subdir-* are added to the commandline before + the options specified using the non-subdir variants. + + Example:: + + subdir-ccflags-y := -Werror + + CFLAGS_$@, AFLAGS_$@ + CFLAGS_$@ and AFLAGS_$@ only apply to commands in current + kbuild makefile. + + $(CFLAGS_$@) specifies per-file options for $(CC). The $@ + part has a literal value which specifies the file that it is for. + + Example:: + + # drivers/scsi/Makefile + CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF + CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \ + -DGDTH_STATISTICS + + These two lines specify compilation flags for aha152x.o and gdth.o. + + $(AFLAGS_$@) is a similar feature for source files in assembly + languages. + + Example:: + + # arch/arm/kernel/Makefile + AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) + AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 + AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt + + +3.9 Dependency tracking +----------------------- + + Kbuild tracks dependencies on the following: + 1) All prerequisite files (both `*.c` and `*.h`) + 2) `CONFIG_` options used in all prerequisite files + 3) Command-line used to compile target + + Thus, if you change an option to $(CC) all affected files will + be re-compiled. + +3.10 Special Rules +------------------ + + Special rules are used when the kbuild infrastructure does + not provide the required support. A typical example is + header files generated during the build process. + Another example are the architecture-specific Makefiles which + need special rules to prepare boot images etc. + + Special rules are written as normal Make rules. + Kbuild is not executing in the directory where the Makefile is + located, so all special rules shall provide a relative + path to prerequisite files and target files. + + Two variables are used when defining special rules: + + $(src) + $(src) is a relative path which points to the directory + where the Makefile is located. Always use $(src) when + referring to files located in the src tree. + + $(obj) + $(obj) is a relative path which points to the directory + where the target is saved. Always use $(obj) when + referring to generated files. + + Example:: + + #drivers/scsi/Makefile + $(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl + $(CPP) -DCHIP=810 - < $< | ... $(src)/script_asm.pl + + This is a special rule, following the normal syntax + required by make. + + The target file depends on two prerequisite files. References + to the target file are prefixed with $(obj), references + to prerequisites are referenced with $(src) (because they are not + generated files). + + $(kecho) + echoing information to user in a rule is often a good practice + but when execution "make -s" one does not expect to see any output + except for warnings/errors. + To support this kbuild defines $(kecho) which will echo out the + text following $(kecho) to stdout except if "make -s" is used. + + Example:: + + #arch/blackfin/boot/Makefile + $(obj)/vmImage: $(obj)/vmlinux.gz + $(call if_changed,uimage) + @$(kecho) 'Kernel: $@ is ready' + + +3.11 $(CC) support functions +---------------------------- + + The kernel may be built with several different versions of + $(CC), each supporting a unique set of features and options. + kbuild provides basic support to check for valid options for $(CC). + $(CC) is usually the gcc compiler, but other alternatives are + available. + + as-option + as-option is used to check if $(CC) -- when used to compile + assembler (`*.S`) files -- supports the given option. An optional + second option may be specified if the first option is not supported. + + Example:: + + #arch/sh/Makefile + cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),) + + In the above example, cflags-y will be assigned the option + -Wa$(comma)-isa=$(isa-y) if it is supported by $(CC). + The second argument is optional, and if supplied will be used + if first argument is not supported. + + cc-ldoption + cc-ldoption is used to check if $(CC) when used to link object files + supports the given option. An optional second option may be + specified if first option are not supported. + + Example:: + + #arch/x86/kernel/Makefile + vsyscall-flags += $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) + + In the above example, vsyscall-flags will be assigned the option + -Wl$(comma)--hash-style=sysv if it is supported by $(CC). + The second argument is optional, and if supplied will be used + if first argument is not supported. + + as-instr + as-instr checks if the assembler reports a specific instruction + and then outputs either option1 or option2 + C escapes are supported in the test instruction + Note: as-instr-option uses KBUILD_AFLAGS for $(AS) options + + cc-option + cc-option is used to check if $(CC) supports a given option, and if + not supported to use an optional second option. + + Example:: + + #arch/x86/Makefile + cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586) + + In the above example, cflags-y will be assigned the option + -march=pentium-mmx if supported by $(CC), otherwise -march=i586. + The second argument to cc-option is optional, and if omitted, + cflags-y will be assigned no value if first option is not supported. + Note: cc-option uses KBUILD_CFLAGS for $(CC) options + + cc-option-yn + cc-option-yn is used to check if gcc supports a given option + and return 'y' if supported, otherwise 'n'. + + Example:: + + #arch/ppc/Makefile + biarch := $(call cc-option-yn, -m32) + aflags-$(biarch) += -a32 + cflags-$(biarch) += -m32 + + In the above example, $(biarch) is set to y if $(CC) supports the -m32 + option. When $(biarch) equals 'y', the expanded variables $(aflags-y) + and $(cflags-y) will be assigned the values -a32 and -m32, + respectively. + Note: cc-option-yn uses KBUILD_CFLAGS for $(CC) options + + cc-disable-warning + cc-disable-warning checks if gcc supports a given warning and returns + the commandline switch to disable it. This special function is needed, + because gcc 4.4 and later accept any unknown -Wno-* option and only + warn about it if there is another warning in the source file. + + Example:: + + KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable) + + In the above example, -Wno-unused-but-set-variable will be added to + KBUILD_CFLAGS only if gcc really accepts it. + + cc-ifversion + cc-ifversion tests the version of $(CC) and equals the fourth parameter + if version expression is true, or the fifth (if given) if the version + expression is false. + + Example:: + + #fs/reiserfs/Makefile + ccflags-y := $(call cc-ifversion, -lt, 0402, -O1) + + In this example, ccflags-y will be assigned the value -O1 if the + $(CC) version is less than 4.2. + cc-ifversion takes all the shell operators: + -eq, -ne, -lt, -le, -gt, and -ge + The third parameter may be a text as in this example, but it may also + be an expanded variable or a macro. + + cc-cross-prefix + cc-cross-prefix is used to check if there exists a $(CC) in path with + one of the listed prefixes. The first prefix where there exist a + prefix$(CC) in the PATH is returned - and if no prefix$(CC) is found + then nothing is returned. + Additional prefixes are separated by a single space in the + call of cc-cross-prefix. + This functionality is useful for architecture Makefiles that try + to set CROSS_COMPILE to well-known values but may have several + values to select between. + It is recommended only to try to set CROSS_COMPILE if it is a cross + build (host arch is different from target arch). And if CROSS_COMPILE + is already set then leave it with the old value. + + Example:: + + #arch/m68k/Makefile + ifneq ($(SUBARCH),$(ARCH)) + ifeq ($(CROSS_COMPILE),) + CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu-) + endif + endif + +3.12 $(LD) support functions +---------------------------- + + ld-option + ld-option is used to check if $(LD) supports the supplied option. + ld-option takes two options as arguments. + The second argument is an optional option that can be used if the + first option is not supported by $(LD). + + Example:: + + #Makefile + LDFLAGS_vmlinux += $(call ld-option, -X) + + +4 Host Program support +====================== + +Kbuild supports building executables on the host for use during the +compilation stage. +Two steps are required in order to use a host executable. + +The first step is to tell kbuild that a host program exists. This is +done utilising the variable hostprogs-y. + +The second step is to add an explicit dependency to the executable. +This can be done in two ways. Either add the dependency in a rule, +or utilise the variable $(always). +Both possibilities are described in the following. + +4.1 Simple Host Program +----------------------- + + In some cases there is a need to compile and run a program on the + computer where the build is running. + The following line tells kbuild that the program bin2hex shall be + built on the build host. + + Example:: + + hostprogs-y := bin2hex + + Kbuild assumes in the above example that bin2hex is made from a single + c-source file named bin2hex.c located in the same directory as + the Makefile. + +4.2 Composite Host Programs +--------------------------- + + Host programs can be made up based on composite objects. + The syntax used to define composite objects for host programs is + similar to the syntax used for kernel objects. + $(-objs) lists all objects used to link the final + executable. + + Example:: + + #scripts/lxdialog/Makefile + hostprogs-y := lxdialog + lxdialog-objs := checklist.o lxdialog.o + + Objects with extension .o are compiled from the corresponding .c + files. In the above example, checklist.c is compiled to checklist.o + and lxdialog.c is compiled to lxdialog.o. + + Finally, the two .o files are linked to the executable, lxdialog. + Note: The syntax -y is not permitted for host-programs. + +4.3 Using C++ for host programs +------------------------------- + + kbuild offers support for host programs written in C++. This was + introduced solely to support kconfig, and is not recommended + for general use. + + Example:: + + #scripts/kconfig/Makefile + hostprogs-y := qconf + qconf-cxxobjs := qconf.o + + In the example above the executable is composed of the C++ file + qconf.cc - identified by $(qconf-cxxobjs). + + If qconf is composed of a mixture of .c and .cc files, then an + additional line can be used to identify this. + + Example:: + + #scripts/kconfig/Makefile + hostprogs-y := qconf + qconf-cxxobjs := qconf.o + qconf-objs := check.o + +4.4 Controlling compiler options for host programs +-------------------------------------------------- + + When compiling host programs, it is possible to set specific flags. + The programs will always be compiled utilising $(HOSTCC) passed + the options specified in $(KBUILD_HOSTCFLAGS). + To set flags that will take effect for all host programs created + in that Makefile, use the variable HOST_EXTRACFLAGS. + + Example:: + + #scripts/lxdialog/Makefile + HOST_EXTRACFLAGS += -I/usr/include/ncurses + + To set specific flags for a single file the following construction + is used: + + Example:: + + #arch/ppc64/boot/Makefile + HOSTCFLAGS_piggyback.o := -DKERNELBASE=$(KERNELBASE) + + It is also possible to specify additional options to the linker. + + Example:: + + #scripts/kconfig/Makefile + HOSTLDLIBS_qconf := -L$(QTDIR)/lib + + When linking qconf, it will be passed the extra option + "-L$(QTDIR)/lib". + +4.5 When host programs are actually built +----------------------------------------- + + Kbuild will only build host-programs when they are referenced + as a prerequisite. + This is possible in two ways: + + (1) List the prerequisite explicitly in a special rule. + + Example:: + + #drivers/pci/Makefile + hostprogs-y := gen-devlist + $(obj)/devlist.h: $(src)/pci.ids $(obj)/gen-devlist + ( cd $(obj); ./gen-devlist ) < $< + + The target $(obj)/devlist.h will not be built before + $(obj)/gen-devlist is updated. Note that references to + the host programs in special rules must be prefixed with $(obj). + + (2) Use $(always) + + When there is no suitable special rule, and the host program + shall be built when a makefile is entered, the $(always) + variable shall be used. + + Example:: + + #scripts/lxdialog/Makefile + hostprogs-y := lxdialog + always := $(hostprogs-y) + + This will tell kbuild to build lxdialog even if not referenced in + any rule. + +4.6 Using hostprogs-$(CONFIG_FOO) +--------------------------------- + + A typical pattern in a Kbuild file looks like this: + + Example:: + + #scripts/Makefile + hostprogs-$(CONFIG_KALLSYMS) += kallsyms + + Kbuild knows about both 'y' for built-in and 'm' for module. + So if a config symbol evaluates to 'm', kbuild will still build + the binary. In other words, Kbuild handles hostprogs-m exactly + like hostprogs-y. But only hostprogs-y is recommended to be used + when no CONFIG symbols are involved. + +5 Kbuild clean infrastructure +============================= + +"make clean" deletes most generated files in the obj tree where the kernel +is compiled. This includes generated files such as host programs. +Kbuild knows targets listed in $(hostprogs-y), $(hostprogs-m), $(always), +$(extra-y) and $(targets). They are all deleted during "make clean". +Files matching the patterns "*.[oas]", "*.ko", plus some additional files +generated by kbuild are deleted all over the kernel src tree when +"make clean" is executed. + +Additional files can be specified in kbuild makefiles by use of $(clean-files). + + Example:: + + #lib/Makefile + clean-files := crc32table.h + +When executing "make clean", the file "crc32table.h" will be deleted. +Kbuild will assume files to be in the same relative directory as the +Makefile, except if prefixed with $(objtree). + +To delete a directory hierarchy use: + + Example:: + + #scripts/package/Makefile + clean-dirs := $(objtree)/debian/ + +This will delete the directory debian in the toplevel directory, including all +subdirectories. + +To exclude certain files from make clean, use the $(no-clean-files) variable. +This is only a special case used in the top level Kbuild file: + + Example:: + + #Kbuild + no-clean-files := $(bounds-file) $(offsets-file) + +Usually kbuild descends down in subdirectories due to "obj-* := dir/", +but in the architecture makefiles where the kbuild infrastructure +is not sufficient this sometimes needs to be explicit. + + Example:: + + #arch/x86/boot/Makefile + subdir- := compressed/ + +The above assignment instructs kbuild to descend down in the +directory compressed/ when "make clean" is executed. + +To support the clean infrastructure in the Makefiles that build the +final bootimage there is an optional target named archclean: + + Example:: + + #arch/x86/Makefile + archclean: + $(Q)$(MAKE) $(clean)=arch/x86/boot + +When "make clean" is executed, make will descend down in arch/x86/boot, +and clean as usual. The Makefile located in arch/x86/boot/ may use +the subdir- trick to descend further down. + +Note 1: arch/$(ARCH)/Makefile cannot use "subdir-", because that file is +included in the top level makefile, and the kbuild infrastructure +is not operational at that point. + +Note 2: All directories listed in core-y, libs-y, drivers-y and net-y will +be visited during "make clean". + +6 Architecture Makefiles +======================== + +The top level Makefile sets up the environment and does the preparation, +before starting to descend down in the individual directories. +The top level makefile contains the generic part, whereas +arch/$(ARCH)/Makefile contains what is required to set up kbuild +for said architecture. +To do so, arch/$(ARCH)/Makefile sets up a number of variables and defines +a few targets. + +When kbuild executes, the following steps are followed (roughly): + +1) Configuration of the kernel => produce .config +2) Store kernel version in include/linux/version.h +3) Updating all other prerequisites to the target prepare: + - Additional prerequisites are specified in arch/$(ARCH)/Makefile +4) Recursively descend down in all directories listed in + init-* core* drivers-* net-* libs-* and build all targets. + - The values of the above variables are expanded in arch/$(ARCH)/Makefile. +5) All object files are then linked and the resulting file vmlinux is + located at the root of the obj tree. + The very first objects linked are listed in head-y, assigned by + arch/$(ARCH)/Makefile. +6) Finally, the architecture-specific part does any required post processing + and builds the final bootimage. + - This includes building boot records + - Preparing initrd images and the like + + +6.1 Set variables to tweak the build to the architecture +-------------------------------------------------------- + + LDFLAGS + Generic $(LD) options + + Flags used for all invocations of the linker. + Often specifying the emulation is sufficient. + + Example:: + + #arch/s390/Makefile + LDFLAGS := -m elf_s390 + + Note: ldflags-y can be used to further customise + the flags used. See chapter 3.7. + + LDFLAGS_vmlinux + Options for $(LD) when linking vmlinux + + LDFLAGS_vmlinux is used to specify additional flags to pass to + the linker when linking the final vmlinux image. + LDFLAGS_vmlinux uses the LDFLAGS_$@ support. + + Example:: + + #arch/x86/Makefile + LDFLAGS_vmlinux := -e stext + + OBJCOPYFLAGS + objcopy flags + + When $(call if_changed,objcopy) is used to translate a .o file, + the flags specified in OBJCOPYFLAGS will be used. + $(call if_changed,objcopy) is often used to generate raw binaries on + vmlinux. + + Example:: + + #arch/s390/Makefile + OBJCOPYFLAGS := -O binary + + #arch/s390/boot/Makefile + $(obj)/image: vmlinux FORCE + $(call if_changed,objcopy) + + In this example, the binary $(obj)/image is a binary version of + vmlinux. The usage of $(call if_changed,xxx) will be described later. + + KBUILD_AFLAGS + $(AS) assembler flags + + Default value - see top level Makefile + Append or modify as required per architecture. + + Example:: + + #arch/sparc64/Makefile + KBUILD_AFLAGS += -m64 -mcpu=ultrasparc + + KBUILD_CFLAGS + $(CC) compiler flags + + Default value - see top level Makefile + Append or modify as required per architecture. + + Often, the KBUILD_CFLAGS variable depends on the configuration. + + Example:: + + #arch/x86/boot/compressed/Makefile + cflags-$(CONFIG_X86_32) := -march=i386 + cflags-$(CONFIG_X86_64) := -mcmodel=small + KBUILD_CFLAGS += $(cflags-y) + + Many arch Makefiles dynamically run the target C compiler to + probe supported options:: + + #arch/x86/Makefile + + ... + cflags-$(CONFIG_MPENTIUMII) += $(call cc-option,\ + -march=pentium2,-march=i686) + ... + # Disable unit-at-a-time mode ... + KBUILD_CFLAGS += $(call cc-option,-fno-unit-at-a-time) + ... + + + The first example utilises the trick that a config option expands + to 'y' when selected. + + KBUILD_AFLAGS_KERNEL + $(AS) options specific for built-in + + $(KBUILD_AFLAGS_KERNEL) contains extra C compiler flags used to compile + resident kernel code. + + KBUILD_AFLAGS_MODULE + Options for $(AS) when building modules + + $(KBUILD_AFLAGS_MODULE) is used to add arch-specific options that + are used for $(AS). + + From commandline AFLAGS_MODULE shall be used (see kbuild.txt). + + KBUILD_CFLAGS_KERNEL + $(CC) options specific for built-in + + $(KBUILD_CFLAGS_KERNEL) contains extra C compiler flags used to compile + resident kernel code. + + KBUILD_CFLAGS_MODULE + Options for $(CC) when building modules + + $(KBUILD_CFLAGS_MODULE) is used to add arch-specific options that + are used for $(CC). + From commandline CFLAGS_MODULE shall be used (see kbuild.txt). + + KBUILD_LDFLAGS_MODULE + Options for $(LD) when linking modules + + $(KBUILD_LDFLAGS_MODULE) is used to add arch-specific options + used when linking modules. This is often a linker script. + + From commandline LDFLAGS_MODULE shall be used (see kbuild.txt). + + KBUILD_ARFLAGS Options for $(AR) when creating archives + + $(KBUILD_ARFLAGS) set by the top level Makefile to "D" (deterministic + mode) if this option is supported by $(AR). + + ARCH_CPPFLAGS, ARCH_AFLAGS, ARCH_CFLAGS Overrides the kbuild defaults + + These variables are appended to the KBUILD_CPPFLAGS, + KBUILD_AFLAGS, and KBUILD_CFLAGS, respectively, after the + top-level Makefile has set any other flags. This provides a + means for an architecture to override the defaults. + + +6.2 Add prerequisites to archheaders +------------------------------------ + + The archheaders: rule is used to generate header files that + may be installed into user space by "make header_install" or + "make headers_install_all". In order to support + "make headers_install_all", this target has to be able to run + on an unconfigured tree, or a tree configured for another + architecture. + + It is run before "make archprepare" when run on the + architecture itself. + + +6.3 Add prerequisites to archprepare +------------------------------------ + + The archprepare: rule is used to list prerequisites that need to be + built before starting to descend down in the subdirectories. + This is usually used for header files containing assembler constants. + + Example:: + + #arch/arm/Makefile + archprepare: maketools + + In this example, the file target maketools will be processed + before descending down in the subdirectories. + See also chapter XXX-TODO that describe how kbuild supports + generating offset header files. + + +6.4 List directories to visit when descending +--------------------------------------------- + + An arch Makefile cooperates with the top Makefile to define variables + which specify how to build the vmlinux file. Note that there is no + corresponding arch-specific section for modules; the module-building + machinery is all architecture-independent. + + + head-y, init-y, core-y, libs-y, drivers-y, net-y + $(head-y) lists objects to be linked first in vmlinux. + + $(libs-y) lists directories where a lib.a archive can be located. + + The rest list directories where a built-in.a object file can be + located. + + $(init-y) objects will be located after $(head-y). + + Then the rest follows in this order: + + $(core-y), $(libs-y), $(drivers-y) and $(net-y). + + The top level Makefile defines values for all generic directories, + and arch/$(ARCH)/Makefile only adds architecture-specific + directories. + + Example:: + + #arch/sparc64/Makefile + core-y += arch/sparc64/kernel/ + libs-y += arch/sparc64/prom/ arch/sparc64/lib/ + drivers-$(CONFIG_OPROFILE) += arch/sparc64/oprofile/ + + +6.5 Architecture-specific boot images +------------------------------------- + + An arch Makefile specifies goals that take the vmlinux file, compress + it, wrap it in bootstrapping code, and copy the resulting files + somewhere. This includes various kinds of installation commands. + The actual goals are not standardized across architectures. + + It is common to locate any additional processing in a boot/ + directory below arch/$(ARCH)/. + + Kbuild does not provide any smart way to support building a + target specified in boot/. Therefore arch/$(ARCH)/Makefile shall + call make manually to build a target in boot/. + + The recommended approach is to include shortcuts in + arch/$(ARCH)/Makefile, and use the full path when calling down + into the arch/$(ARCH)/boot/Makefile. + + Example:: + + #arch/x86/Makefile + boot := arch/x86/boot + bzImage: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + + "$(Q)$(MAKE) $(build)=" is the recommended way to invoke + make in a subdirectory. + + There are no rules for naming architecture-specific targets, + but executing "make help" will list all relevant targets. + To support this, $(archhelp) must be defined. + + Example:: + + #arch/x86/Makefile + define archhelp + echo '* bzImage - Image (arch/$(ARCH)/boot/bzImage)' + endif + + When make is executed without arguments, the first goal encountered + will be built. In the top level Makefile the first goal present + is all:. + An architecture shall always, per default, build a bootable image. + In "make help", the default goal is highlighted with a '*'. + Add a new prerequisite to all: to select a default goal different + from vmlinux. + + Example:: + + #arch/x86/Makefile + all: bzImage + + When "make" is executed without arguments, bzImage will be built. + +6.6 Building non-kbuild targets +------------------------------- + + extra-y + extra-y specifies additional targets created in the current + directory, in addition to any targets specified by `obj-*`. + + Listing all targets in extra-y is required for two purposes: + + 1) Enable kbuild to check changes in command lines + + - When $(call if_changed,xxx) is used + + 2) kbuild knows what files to delete during "make clean" + + Example:: + + #arch/x86/kernel/Makefile + extra-y := head.o init_task.o + + In this example, extra-y is used to list object files that + shall be built, but shall not be linked as part of built-in.a. + + +6.7 Commands useful for building a boot image +--------------------------------------------- + + Kbuild provides a few macros that are useful when building a + boot image. + + if_changed + if_changed is the infrastructure used for the following commands. + + Usage:: + + target: source(s) FORCE + $(call if_changed,ld/objcopy/gzip/...) + + When the rule is evaluated, it is checked to see if any files + need an update, or the command line has changed since the last + invocation. The latter will force a rebuild if any options + to the executable have changed. + Any target that utilises if_changed must be listed in $(targets), + otherwise the command line check will fail, and the target will + always be built. + Assignments to $(targets) are without $(obj)/ prefix. + if_changed may be used in conjunction with custom commands as + defined in 6.8 "Custom kbuild commands". + + Note: It is a typical mistake to forget the FORCE prerequisite. + Another common pitfall is that whitespace is sometimes + significant; for instance, the below will fail (note the extra space + after the comma):: + + target: source(s) FORCE + + **WRONG!** $(call if_changed, ld/objcopy/gzip/...) + + Note: + if_changed should not be used more than once per target. + It stores the executed command in a corresponding .cmd + + file and multiple calls would result in overwrites and + unwanted results when the target is up to date and only the + tests on changed commands trigger execution of commands. + + ld + Link target. Often, LDFLAGS_$@ is used to set specific options to ld. + + Example:: + + #arch/x86/boot/Makefile + LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary + LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext + + targets += setup setup.o bootsect bootsect.o + $(obj)/setup $(obj)/bootsect: %: %.o FORCE + $(call if_changed,ld) + + In this example, there are two possible targets, requiring different + options to the linker. The linker options are specified using the + LDFLAGS_$@ syntax - one for each potential target. + $(targets) are assigned all potential targets, by which kbuild knows + the targets and will: + + 1) check for commandline changes + 2) delete target during make clean + + The ": %: %.o" part of the prerequisite is a shorthand that + frees us from listing the setup.o and bootsect.o files. + + Note: + It is a common mistake to forget the "targets :=" assignment, + resulting in the target file being recompiled for no + obvious reason. + + objcopy + Copy binary. Uses OBJCOPYFLAGS usually specified in + arch/$(ARCH)/Makefile. + OBJCOPYFLAGS_$@ may be used to set additional options. + + gzip + Compress target. Use maximum compression to compress target. + + Example:: + + #arch/x86/boot/compressed/Makefile + $(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE + $(call if_changed,gzip) + + dtc + Create flattened device tree blob object suitable for linking + into vmlinux. Device tree blobs linked into vmlinux are placed + in an init section in the image. Platform code *must* copy the + blob to non-init memory prior to calling unflatten_device_tree(). + + To use this command, simply add `*.dtb` into obj-y or targets, or make + some other target depend on `%.dtb` + + A central rule exists to create `$(obj)/%.dtb` from `$(src)/%.dts`; + architecture Makefiles do no need to explicitly write out that rule. + + Example:: + + targets += $(dtb-y) + DTC_FLAGS ?= -p 1024 + +6.8 Custom kbuild commands +-------------------------- + + When kbuild is executing with KBUILD_VERBOSE=0, then only a shorthand + of a command is normally displayed. + To enable this behaviour for custom commands kbuild requires + two variables to be set:: + + quiet_cmd_ - what shall be echoed + cmd_ - the command to execute + + Example:: + + # + quiet_cmd_image = BUILD $@ + cmd_image = $(obj)/tools/build $(BUILDFLAGS) \ + $(obj)/vmlinux.bin > $@ + + targets += bzImage + $(obj)/bzImage: $(obj)/vmlinux.bin $(obj)/tools/build FORCE + $(call if_changed,image) + @echo 'Kernel: $@ is ready' + + When updating the $(obj)/bzImage target, the line: + + BUILD arch/x86/boot/bzImage + + will be displayed with "make KBUILD_VERBOSE=0". + + +--- 6.9 Preprocessing linker scripts + + When the vmlinux image is built, the linker script + arch/$(ARCH)/kernel/vmlinux.lds is used. + The script is a preprocessed variant of the file vmlinux.lds.S + located in the same directory. + kbuild knows .lds files and includes a rule `*lds.S` -> `*lds`. + + Example:: + + #arch/x86/kernel/Makefile + always := vmlinux.lds + + #Makefile + export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH) + + The assignment to $(always) is used to tell kbuild to build the + target vmlinux.lds. + The assignment to $(CPPFLAGS_vmlinux.lds) tells kbuild to use the + specified options when building the target vmlinux.lds. + + When building the `*.lds` target, kbuild uses the variables:: + + KBUILD_CPPFLAGS : Set in top-level Makefile + cppflags-y : May be set in the kbuild makefile + CPPFLAGS_$(@F) : Target-specific flags. + Note that the full filename is used in this + assignment. + + The kbuild infrastructure for `*lds` files is used in several + architecture-specific files. + +6.10 Generic header files +------------------------- + + The directory include/asm-generic contains the header files + that may be shared between individual architectures. + The recommended approach how to use a generic header file is + to list the file in the Kbuild file. + See "7.2 generic-y" for further info on syntax etc. + +6.11 Post-link pass +------------------- + + If the file arch/xxx/Makefile.postlink exists, this makefile + will be invoked for post-link objects (vmlinux and modules.ko) + for architectures to run post-link passes on. Must also handle + the clean target. + + This pass runs after kallsyms generation. If the architecture + needs to modify symbol locations, rather than manipulate the + kallsyms, it may be easier to add another postlink target for + .tmp_vmlinux? targets to be called from link-vmlinux.sh. + + For example, powerpc uses this to check relocation sanity of + the linked vmlinux file. + +7 Kbuild syntax for exported headers +------------------------------------ + +The kernel includes a set of headers that is exported to userspace. +Many headers can be exported as-is but other headers require a +minimal pre-processing before they are ready for user-space. +The pre-processing does: + +- drop kernel-specific annotations +- drop include of compiler.h +- drop all sections that are kernel internal (guarded by `ifdef __KERNEL__`) + +All headers under include/uapi/, include/generated/uapi/, +arch//include/uapi/ and arch//include/generated/uapi/ +are exported. + +A Kbuild file may be defined under arch//include/uapi/asm/ and +arch//include/asm/ to list asm files coming from asm-generic. +See subsequent chapter for the syntax of the Kbuild file. + +7.1 no-export-headers +--------------------- + + no-export-headers is essentially used by include/uapi/linux/Kbuild to + avoid exporting specific headers (e.g. kvm.h) on architectures that do + not support it. It should be avoided as much as possible. + +7.2 generic-y +------------- + + If an architecture uses a verbatim copy of a header from + include/asm-generic then this is listed in the file + arch/$(ARCH)/include/asm/Kbuild like this: + + Example:: + + #arch/x86/include/asm/Kbuild + generic-y += termios.h + generic-y += rtc.h + + During the prepare phase of the build a wrapper include + file is generated in the directory:: + + arch/$(ARCH)/include/generated/asm + + When a header is exported where the architecture uses + the generic header a similar wrapper is generated as part + of the set of exported headers in the directory:: + + usr/include/asm + + The generated wrapper will in both cases look like the following: + + Example: termios.h:: + + #include + +7.3 generated-y +--------------- + + If an architecture generates other header files alongside generic-y + wrappers, generated-y specifies them. + + This prevents them being treated as stale asm-generic wrappers and + removed. + + Example:: + + #arch/x86/include/asm/Kbuild + generated-y += syscalls_32.h + +7.4 mandatory-y +--------------- + + mandatory-y is essentially used by include/(uapi/)asm-generic/Kbuild + to define the minimum set of ASM headers that all architectures must have. + + This works like optional generic-y. If a mandatory header is missing + in arch/$(ARCH)/include/(uapi/)/asm, Kbuild will automatically generate + a wrapper of the asm-generic one. + + The convention is to list one subdir per line and + preferably in alphabetic order. + +8 Kbuild Variables +================== + +The top Makefile exports the following variables: + + VERSION, PATCHLEVEL, SUBLEVEL, EXTRAVERSION + These variables define the current kernel version. A few arch + Makefiles actually use these values directly; they should use + $(KERNELRELEASE) instead. + + $(VERSION), $(PATCHLEVEL), and $(SUBLEVEL) define the basic + three-part version number, such as "2", "4", and "0". These three + values are always numeric. + + $(EXTRAVERSION) defines an even tinier sublevel for pre-patches + or additional patches. It is usually some non-numeric string + such as "-pre4", and is often blank. + + KERNELRELEASE + $(KERNELRELEASE) is a single string such as "2.4.0-pre4", suitable + for constructing installation directory names or showing in + version strings. Some arch Makefiles use it for this purpose. + + ARCH + This variable defines the target architecture, such as "i386", + "arm", or "sparc". Some kbuild Makefiles test $(ARCH) to + determine which files to compile. + + By default, the top Makefile sets $(ARCH) to be the same as the + host system architecture. For a cross build, a user may + override the value of $(ARCH) on the command line:: + + make ARCH=m68k ... + + + INSTALL_PATH + This variable defines a place for the arch Makefiles to install + the resident kernel image and System.map file. + Use this for architecture-specific install targets. + + INSTALL_MOD_PATH, MODLIB + $(INSTALL_MOD_PATH) specifies a prefix to $(MODLIB) for module + installation. This variable is not defined in the Makefile but + may be passed in by the user if desired. + + $(MODLIB) specifies the directory for module installation. + The top Makefile defines $(MODLIB) to + $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE). The user may + override this value on the command line if desired. + + INSTALL_MOD_STRIP + If this variable is specified, it will cause modules to be stripped + after they are installed. If INSTALL_MOD_STRIP is '1', then the + default option --strip-debug will be used. Otherwise, the + INSTALL_MOD_STRIP value will be used as the option(s) to the strip + command. + + +9 Makefile language +=================== + +The kernel Makefiles are designed to be run with GNU Make. The Makefiles +use only the documented features of GNU Make, but they do use many +GNU extensions. + +GNU Make supports elementary list-processing functions. The kernel +Makefiles use a novel style of list building and manipulation with few +"if" statements. + +GNU Make has two assignment operators, ":=" and "=". ":=" performs +immediate evaluation of the right-hand side and stores an actual string +into the left-hand side. "=" is like a formula definition; it stores the +right-hand side in an unevaluated form and then evaluates this form each +time the left-hand side is used. + +There are some cases where "=" is appropriate. Usually, though, ":=" +is the right choice. + +10 Credits +========== + +- Original version made by Michael Elizabeth Chastain, +- Updates by Kai Germaschewski +- Updates by Sam Ravnborg +- Language QA by Jan Engelhardt + +11 TODO +======= + +- Describe how kbuild supports shipped files with _shipped. +- Generating offset header files. +- Add more variables to section 7? diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt deleted file mode 100644 index d65ad5746f94..000000000000 --- a/Documentation/kbuild/makefiles.txt +++ /dev/null @@ -1,1369 +0,0 @@ -Linux Kernel Makefiles - -This document describes the Linux kernel Makefiles. - -=== Table of Contents - - === 1 Overview - === 2 Who does what - === 3 The kbuild files - --- 3.1 Goal definitions - --- 3.2 Built-in object goals - obj-y - --- 3.3 Loadable module goals - obj-m - --- 3.4 Objects which export symbols - --- 3.5 Library file goals - lib-y - --- 3.6 Descending down in directories - --- 3.7 Compilation flags - --- 3.8 Command line dependency - --- 3.9 Dependency tracking - --- 3.10 Special Rules - --- 3.11 $(CC) support functions - --- 3.12 $(LD) support functions - - === 4 Host Program support - --- 4.1 Simple Host Program - --- 4.2 Composite Host Programs - --- 4.3 Using C++ for host programs - --- 4.4 Controlling compiler options for host programs - --- 4.5 When host programs are actually built - --- 4.6 Using hostprogs-$(CONFIG_FOO) - - === 5 Kbuild clean infrastructure - - === 6 Architecture Makefiles - --- 6.1 Set variables to tweak the build to the architecture - --- 6.2 Add prerequisites to archheaders: - --- 6.3 Add prerequisites to archprepare: - --- 6.4 List directories to visit when descending - --- 6.5 Architecture-specific boot images - --- 6.6 Building non-kbuild targets - --- 6.7 Commands useful for building a boot image - --- 6.8 Custom kbuild commands - --- 6.9 Preprocessing linker scripts - --- 6.10 Generic header files - --- 6.11 Post-link pass - - === 7 Kbuild syntax for exported headers - --- 7.1 no-export-headers - --- 7.2 generic-y - --- 7.3 generated-y - --- 7.4 mandatory-y - - === 8 Kbuild Variables - === 9 Makefile language - === 10 Credits - === 11 TODO - -=== 1 Overview - -The Makefiles have five parts: - - Makefile the top Makefile. - .config the kernel configuration file. - arch/$(ARCH)/Makefile the arch Makefile. - scripts/Makefile.* common rules etc. for all kbuild Makefiles. - kbuild Makefiles there are about 500 of these. - -The top Makefile reads the .config file, which comes from the kernel -configuration process. - -The top Makefile is responsible for building two major products: vmlinux -(the resident kernel image) and modules (any module files). -It builds these goals by recursively descending into the subdirectories of -the kernel source tree. -The list of subdirectories which are visited depends upon the kernel -configuration. The top Makefile textually includes an arch Makefile -with the name arch/$(ARCH)/Makefile. The arch Makefile supplies -architecture-specific information to the top Makefile. - -Each subdirectory has a kbuild Makefile which carries out the commands -passed down from above. The kbuild Makefile uses information from the -.config file to construct various file lists used by kbuild to build -any built-in or modular targets. - -scripts/Makefile.* contains all the definitions/rules etc. that -are used to build the kernel based on the kbuild makefiles. - - -=== 2 Who does what - -People have four different relationships with the kernel Makefiles. - -*Users* are people who build kernels. These people type commands such as -"make menuconfig" or "make". They usually do not read or edit -any kernel Makefiles (or any other source files). - -*Normal developers* are people who work on features such as device -drivers, file systems, and network protocols. These people need to -maintain the kbuild Makefiles for the subsystem they are -working on. In order to do this effectively, they need some overall -knowledge about the kernel Makefiles, plus detailed knowledge about the -public interface for kbuild. - -*Arch developers* are people who work on an entire architecture, such -as sparc or ia64. Arch developers need to know about the arch Makefile -as well as kbuild Makefiles. - -*Kbuild developers* are people who work on the kernel build system itself. -These people need to know about all aspects of the kernel Makefiles. - -This document is aimed towards normal developers and arch developers. - - -=== 3 The kbuild files - -Most Makefiles within the kernel are kbuild Makefiles that use the -kbuild infrastructure. This chapter introduces the syntax used in the -kbuild makefiles. -The preferred name for the kbuild files are 'Makefile' but 'Kbuild' can -be used and if both a 'Makefile' and a 'Kbuild' file exists, then the 'Kbuild' -file will be used. - -Section 3.1 "Goal definitions" is a quick intro, further chapters provide -more details, with real examples. - ---- 3.1 Goal definitions - - Goal definitions are the main part (heart) of the kbuild Makefile. - These lines define the files to be built, any special compilation - options, and any subdirectories to be entered recursively. - - The most simple kbuild makefile contains one line: - - Example: - obj-y += foo.o - - This tells kbuild that there is one object in that directory, named - foo.o. foo.o will be built from foo.c or foo.S. - - If foo.o shall be built as a module, the variable obj-m is used. - Therefore the following pattern is often used: - - Example: - obj-$(CONFIG_FOO) += foo.o - - $(CONFIG_FOO) evaluates to either y (for built-in) or m (for module). - If CONFIG_FOO is neither y nor m, then the file will not be compiled - nor linked. - ---- 3.2 Built-in object goals - obj-y - - The kbuild Makefile specifies object files for vmlinux - in the $(obj-y) lists. These lists depend on the kernel - configuration. - - Kbuild compiles all the $(obj-y) files. It then calls - "$(AR) rcSTP" to merge these files into one built-in.a file. - This is a thin archive without a symbol table. It will be later - linked into vmlinux by scripts/link-vmlinux.sh - - The order of files in $(obj-y) is significant. Duplicates in - the lists are allowed: the first instance will be linked into - built-in.a and succeeding instances will be ignored. - - Link order is significant, because certain functions - (module_init() / __initcall) will be called during boot in the - order they appear. So keep in mind that changing the link - order may e.g. change the order in which your SCSI - controllers are detected, and thus your disks are renumbered. - - Example: - #drivers/isdn/i4l/Makefile - # Makefile for the kernel ISDN subsystem and device drivers. - # Each configuration option enables a list of files. - obj-$(CONFIG_ISDN_I4L) += isdn.o - obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o - ---- 3.3 Loadable module goals - obj-m - - $(obj-m) specifies object files which are built as loadable - kernel modules. - - A module may be built from one source file or several source - files. In the case of one source file, the kbuild makefile - simply adds the file to $(obj-m). - - Example: - #drivers/isdn/i4l/Makefile - obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o - - Note: In this example $(CONFIG_ISDN_PPP_BSDCOMP) evaluates to 'm' - - If a kernel module is built from several source files, you specify - that you want to build a module in the same way as above; however, - kbuild needs to know which object files you want to build your - module from, so you have to tell it by setting a $(-y) - variable. - - Example: - #drivers/isdn/i4l/Makefile - obj-$(CONFIG_ISDN_I4L) += isdn.o - isdn-y := isdn_net_lib.o isdn_v110.o isdn_common.o - - In this example, the module name will be isdn.o. Kbuild will - compile the objects listed in $(isdn-y) and then run - "$(LD) -r" on the list of these files to generate isdn.o. - - Due to kbuild recognizing $(-y) for composite objects, - you can use the value of a CONFIG_ symbol to optionally include an - object file as part of a composite object. - - Example: - #fs/ext2/Makefile - obj-$(CONFIG_EXT2_FS) += ext2.o - ext2-y := balloc.o dir.o file.o ialloc.o inode.o ioctl.o \ - namei.o super.o symlink.o - ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o \ - xattr_trusted.o - - In this example, xattr.o, xattr_user.o and xattr_trusted.o are only - part of the composite object ext2.o if $(CONFIG_EXT2_FS_XATTR) - evaluates to 'y'. - - Note: Of course, when you are building objects into the kernel, - the syntax above will also work. So, if you have CONFIG_EXT2_FS=y, - kbuild will build an ext2.o file for you out of the individual - parts and then link this into built-in.a, as you would expect. - ---- 3.4 Objects which export symbols - - No special notation is required in the makefiles for - modules exporting symbols. - ---- 3.5 Library file goals - lib-y - - Objects listed with obj-* are used for modules, or - combined in a built-in.a for that specific directory. - There is also the possibility to list objects that will - be included in a library, lib.a. - All objects listed with lib-y are combined in a single - library for that directory. - Objects that are listed in obj-y and additionally listed in - lib-y will not be included in the library, since they will - be accessible anyway. - For consistency, objects listed in lib-m will be included in lib.a. - - Note that the same kbuild makefile may list files to be built-in - and to be part of a library. Therefore the same directory - may contain both a built-in.a and a lib.a file. - - Example: - #arch/x86/lib/Makefile - lib-y := delay.o - - This will create a library lib.a based on delay.o. For kbuild to - actually recognize that there is a lib.a being built, the directory - shall be listed in libs-y. - See also "6.4 List directories to visit when descending". - - Use of lib-y is normally restricted to lib/ and arch/*/lib. - ---- 3.6 Descending down in directories - - A Makefile is only responsible for building objects in its own - directory. Files in subdirectories should be taken care of by - Makefiles in these subdirs. The build system will automatically - invoke make recursively in subdirectories, provided you let it know of - them. - - To do so, obj-y and obj-m are used. - ext2 lives in a separate directory, and the Makefile present in fs/ - tells kbuild to descend down using the following assignment. - - Example: - #fs/Makefile - obj-$(CONFIG_EXT2_FS) += ext2/ - - If CONFIG_EXT2_FS is set to either 'y' (built-in) or 'm' (modular) - the corresponding obj- variable will be set, and kbuild will descend - down in the ext2 directory. - Kbuild only uses this information to decide that it needs to visit - the directory, it is the Makefile in the subdirectory that - specifies what is modular and what is built-in. - - It is good practice to use a CONFIG_ variable when assigning directory - names. This allows kbuild to totally skip the directory if the - corresponding CONFIG_ option is neither 'y' nor 'm'. - ---- 3.7 Compilation flags - - ccflags-y, asflags-y and ldflags-y - These three flags apply only to the kbuild makefile in which they - are assigned. They are used for all the normal cc, as and ld - invocations happening during a recursive build. - Note: Flags with the same behaviour were previously named: - EXTRA_CFLAGS, EXTRA_AFLAGS and EXTRA_LDFLAGS. - They are still supported but their usage is deprecated. - - ccflags-y specifies options for compiling with $(CC). - - Example: - # drivers/acpi/acpica/Makefile - ccflags-y := -Os -D_LINUX -DBUILDING_ACPICA - ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT - - This variable is necessary because the top Makefile owns the - variable $(KBUILD_CFLAGS) and uses it for compilation flags for the - entire tree. - - asflags-y specifies options for assembling with $(AS). - - Example: - #arch/sparc/kernel/Makefile - asflags-y := -ansi - - ldflags-y specifies options for linking with $(LD). - - Example: - #arch/cris/boot/compressed/Makefile - ldflags-y += -T $(srctree)/$(src)/decompress_$(arch-y).lds - - subdir-ccflags-y, subdir-asflags-y - The two flags listed above are similar to ccflags-y and asflags-y. - The difference is that the subdir- variants have effect for the kbuild - file where they are present and all subdirectories. - Options specified using subdir-* are added to the commandline before - the options specified using the non-subdir variants. - - Example: - subdir-ccflags-y := -Werror - - CFLAGS_$@, AFLAGS_$@ - - CFLAGS_$@ and AFLAGS_$@ only apply to commands in current - kbuild makefile. - - $(CFLAGS_$@) specifies per-file options for $(CC). The $@ - part has a literal value which specifies the file that it is for. - - Example: - # drivers/scsi/Makefile - CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF - CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \ - -DGDTH_STATISTICS - - These two lines specify compilation flags for aha152x.o and gdth.o. - - $(AFLAGS_$@) is a similar feature for source files in assembly - languages. - - Example: - # arch/arm/kernel/Makefile - AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) - AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 - AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt - - ---- 3.9 Dependency tracking - - Kbuild tracks dependencies on the following: - 1) All prerequisite files (both *.c and *.h) - 2) CONFIG_ options used in all prerequisite files - 3) Command-line used to compile target - - Thus, if you change an option to $(CC) all affected files will - be re-compiled. - ---- 3.10 Special Rules - - Special rules are used when the kbuild infrastructure does - not provide the required support. A typical example is - header files generated during the build process. - Another example are the architecture-specific Makefiles which - need special rules to prepare boot images etc. - - Special rules are written as normal Make rules. - Kbuild is not executing in the directory where the Makefile is - located, so all special rules shall provide a relative - path to prerequisite files and target files. - - Two variables are used when defining special rules: - - $(src) - $(src) is a relative path which points to the directory - where the Makefile is located. Always use $(src) when - referring to files located in the src tree. - - $(obj) - $(obj) is a relative path which points to the directory - where the target is saved. Always use $(obj) when - referring to generated files. - - Example: - #drivers/scsi/Makefile - $(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl - $(CPP) -DCHIP=810 - < $< | ... $(src)/script_asm.pl - - This is a special rule, following the normal syntax - required by make. - The target file depends on two prerequisite files. References - to the target file are prefixed with $(obj), references - to prerequisites are referenced with $(src) (because they are not - generated files). - - $(kecho) - echoing information to user in a rule is often a good practice - but when execution "make -s" one does not expect to see any output - except for warnings/errors. - To support this kbuild defines $(kecho) which will echo out the - text following $(kecho) to stdout except if "make -s" is used. - - Example: - #arch/blackfin/boot/Makefile - $(obj)/vmImage: $(obj)/vmlinux.gz - $(call if_changed,uimage) - @$(kecho) 'Kernel: $@ is ready' - - ---- 3.11 $(CC) support functions - - The kernel may be built with several different versions of - $(CC), each supporting a unique set of features and options. - kbuild provides basic support to check for valid options for $(CC). - $(CC) is usually the gcc compiler, but other alternatives are - available. - - as-option - as-option is used to check if $(CC) -- when used to compile - assembler (*.S) files -- supports the given option. An optional - second option may be specified if the first option is not supported. - - Example: - #arch/sh/Makefile - cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),) - - In the above example, cflags-y will be assigned the option - -Wa$(comma)-isa=$(isa-y) if it is supported by $(CC). - The second argument is optional, and if supplied will be used - if first argument is not supported. - - as-instr - as-instr checks if the assembler reports a specific instruction - and then outputs either option1 or option2 - C escapes are supported in the test instruction - Note: as-instr-option uses KBUILD_AFLAGS for $(AS) options - - cc-option - cc-option is used to check if $(CC) supports a given option, and if - not supported to use an optional second option. - - Example: - #arch/x86/Makefile - cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586) - - In the above example, cflags-y will be assigned the option - -march=pentium-mmx if supported by $(CC), otherwise -march=i586. - The second argument to cc-option is optional, and if omitted, - cflags-y will be assigned no value if first option is not supported. - Note: cc-option uses KBUILD_CFLAGS for $(CC) options - - cc-option-yn - cc-option-yn is used to check if gcc supports a given option - and return 'y' if supported, otherwise 'n'. - - Example: - #arch/ppc/Makefile - biarch := $(call cc-option-yn, -m32) - aflags-$(biarch) += -a32 - cflags-$(biarch) += -m32 - - In the above example, $(biarch) is set to y if $(CC) supports the -m32 - option. When $(biarch) equals 'y', the expanded variables $(aflags-y) - and $(cflags-y) will be assigned the values -a32 and -m32, - respectively. - Note: cc-option-yn uses KBUILD_CFLAGS for $(CC) options - - cc-disable-warning - cc-disable-warning checks if gcc supports a given warning and returns - the commandline switch to disable it. This special function is needed, - because gcc 4.4 and later accept any unknown -Wno-* option and only - warn about it if there is another warning in the source file. - - Example: - KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable) - - In the above example, -Wno-unused-but-set-variable will be added to - KBUILD_CFLAGS only if gcc really accepts it. - - cc-ifversion - cc-ifversion tests the version of $(CC) and equals the fourth parameter - if version expression is true, or the fifth (if given) if the version - expression is false. - - Example: - #fs/reiserfs/Makefile - ccflags-y := $(call cc-ifversion, -lt, 0402, -O1) - - In this example, ccflags-y will be assigned the value -O1 if the - $(CC) version is less than 4.2. - cc-ifversion takes all the shell operators: - -eq, -ne, -lt, -le, -gt, and -ge - The third parameter may be a text as in this example, but it may also - be an expanded variable or a macro. - - cc-cross-prefix - cc-cross-prefix is used to check if there exists a $(CC) in path with - one of the listed prefixes. The first prefix where there exist a - prefix$(CC) in the PATH is returned - and if no prefix$(CC) is found - then nothing is returned. - Additional prefixes are separated by a single space in the - call of cc-cross-prefix. - This functionality is useful for architecture Makefiles that try - to set CROSS_COMPILE to well-known values but may have several - values to select between. - It is recommended only to try to set CROSS_COMPILE if it is a cross - build (host arch is different from target arch). And if CROSS_COMPILE - is already set then leave it with the old value. - - Example: - #arch/m68k/Makefile - ifneq ($(SUBARCH),$(ARCH)) - ifeq ($(CROSS_COMPILE),) - CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu-) - endif - endif - ---- 3.12 $(LD) support functions - - ld-option - ld-option is used to check if $(LD) supports the supplied option. - ld-option takes two options as arguments. - The second argument is an optional option that can be used if the - first option is not supported by $(LD). - - Example: - #Makefile - LDFLAGS_vmlinux += $(call ld-option, -X) - - -=== 4 Host Program support - -Kbuild supports building executables on the host for use during the -compilation stage. -Two steps are required in order to use a host executable. - -The first step is to tell kbuild that a host program exists. This is -done utilising the variable hostprogs-y. - -The second step is to add an explicit dependency to the executable. -This can be done in two ways. Either add the dependency in a rule, -or utilise the variable $(always). -Both possibilities are described in the following. - ---- 4.1 Simple Host Program - - In some cases there is a need to compile and run a program on the - computer where the build is running. - The following line tells kbuild that the program bin2hex shall be - built on the build host. - - Example: - hostprogs-y := bin2hex - - Kbuild assumes in the above example that bin2hex is made from a single - c-source file named bin2hex.c located in the same directory as - the Makefile. - ---- 4.2 Composite Host Programs - - Host programs can be made up based on composite objects. - The syntax used to define composite objects for host programs is - similar to the syntax used for kernel objects. - $(-objs) lists all objects used to link the final - executable. - - Example: - #scripts/lxdialog/Makefile - hostprogs-y := lxdialog - lxdialog-objs := checklist.o lxdialog.o - - Objects with extension .o are compiled from the corresponding .c - files. In the above example, checklist.c is compiled to checklist.o - and lxdialog.c is compiled to lxdialog.o. - Finally, the two .o files are linked to the executable, lxdialog. - Note: The syntax -y is not permitted for host-programs. - ---- 4.3 Using C++ for host programs - - kbuild offers support for host programs written in C++. This was - introduced solely to support kconfig, and is not recommended - for general use. - - Example: - #scripts/kconfig/Makefile - hostprogs-y := qconf - qconf-cxxobjs := qconf.o - - In the example above the executable is composed of the C++ file - qconf.cc - identified by $(qconf-cxxobjs). - - If qconf is composed of a mixture of .c and .cc files, then an - additional line can be used to identify this. - - Example: - #scripts/kconfig/Makefile - hostprogs-y := qconf - qconf-cxxobjs := qconf.o - qconf-objs := check.o - ---- 4.4 Controlling compiler options for host programs - - When compiling host programs, it is possible to set specific flags. - The programs will always be compiled utilising $(HOSTCC) passed - the options specified in $(KBUILD_HOSTCFLAGS). - To set flags that will take effect for all host programs created - in that Makefile, use the variable HOST_EXTRACFLAGS. - - Example: - #scripts/lxdialog/Makefile - HOST_EXTRACFLAGS += -I/usr/include/ncurses - - To set specific flags for a single file the following construction - is used: - - Example: - #arch/ppc64/boot/Makefile - HOSTCFLAGS_piggyback.o := -DKERNELBASE=$(KERNELBASE) - - It is also possible to specify additional options to the linker. - - Example: - #scripts/kconfig/Makefile - HOSTLDLIBS_qconf := -L$(QTDIR)/lib - - When linking qconf, it will be passed the extra option - "-L$(QTDIR)/lib". - ---- 4.5 When host programs are actually built - - Kbuild will only build host-programs when they are referenced - as a prerequisite. - This is possible in two ways: - - (1) List the prerequisite explicitly in a special rule. - - Example: - #drivers/pci/Makefile - hostprogs-y := gen-devlist - $(obj)/devlist.h: $(src)/pci.ids $(obj)/gen-devlist - ( cd $(obj); ./gen-devlist ) < $< - - The target $(obj)/devlist.h will not be built before - $(obj)/gen-devlist is updated. Note that references to - the host programs in special rules must be prefixed with $(obj). - - (2) Use $(always) - When there is no suitable special rule, and the host program - shall be built when a makefile is entered, the $(always) - variable shall be used. - - Example: - #scripts/lxdialog/Makefile - hostprogs-y := lxdialog - always := $(hostprogs-y) - - This will tell kbuild to build lxdialog even if not referenced in - any rule. - ---- 4.6 Using hostprogs-$(CONFIG_FOO) - - A typical pattern in a Kbuild file looks like this: - - Example: - #scripts/Makefile - hostprogs-$(CONFIG_KALLSYMS) += kallsyms - - Kbuild knows about both 'y' for built-in and 'm' for module. - So if a config symbol evaluates to 'm', kbuild will still build - the binary. In other words, Kbuild handles hostprogs-m exactly - like hostprogs-y. But only hostprogs-y is recommended to be used - when no CONFIG symbols are involved. - -=== 5 Kbuild clean infrastructure - -"make clean" deletes most generated files in the obj tree where the kernel -is compiled. This includes generated files such as host programs. -Kbuild knows targets listed in $(hostprogs-y), $(hostprogs-m), $(always), -$(extra-y) and $(targets). They are all deleted during "make clean". -Files matching the patterns "*.[oas]", "*.ko", plus some additional files -generated by kbuild are deleted all over the kernel src tree when -"make clean" is executed. - -Additional files can be specified in kbuild makefiles by use of $(clean-files). - - Example: - #lib/Makefile - clean-files := crc32table.h - -When executing "make clean", the file "crc32table.h" will be deleted. -Kbuild will assume files to be in the same relative directory as the -Makefile, except if prefixed with $(objtree). - -To delete a directory hierarchy use: - - Example: - #scripts/package/Makefile - clean-dirs := $(objtree)/debian/ - -This will delete the directory debian in the toplevel directory, including all -subdirectories. - -To exclude certain files from make clean, use the $(no-clean-files) variable. -This is only a special case used in the top level Kbuild file: - - Example: - #Kbuild - no-clean-files := $(bounds-file) $(offsets-file) - -Usually kbuild descends down in subdirectories due to "obj-* := dir/", -but in the architecture makefiles where the kbuild infrastructure -is not sufficient this sometimes needs to be explicit. - - Example: - #arch/x86/boot/Makefile - subdir- := compressed/ - -The above assignment instructs kbuild to descend down in the -directory compressed/ when "make clean" is executed. - -To support the clean infrastructure in the Makefiles that build the -final bootimage there is an optional target named archclean: - - Example: - #arch/x86/Makefile - archclean: - $(Q)$(MAKE) $(clean)=arch/x86/boot - -When "make clean" is executed, make will descend down in arch/x86/boot, -and clean as usual. The Makefile located in arch/x86/boot/ may use -the subdir- trick to descend further down. - -Note 1: arch/$(ARCH)/Makefile cannot use "subdir-", because that file is -included in the top level makefile, and the kbuild infrastructure -is not operational at that point. - -Note 2: All directories listed in core-y, libs-y, drivers-y and net-y will -be visited during "make clean". - -=== 6 Architecture Makefiles - -The top level Makefile sets up the environment and does the preparation, -before starting to descend down in the individual directories. -The top level makefile contains the generic part, whereas -arch/$(ARCH)/Makefile contains what is required to set up kbuild -for said architecture. -To do so, arch/$(ARCH)/Makefile sets up a number of variables and defines -a few targets. - -When kbuild executes, the following steps are followed (roughly): -1) Configuration of the kernel => produce .config -2) Store kernel version in include/linux/version.h -3) Updating all other prerequisites to the target prepare: - - Additional prerequisites are specified in arch/$(ARCH)/Makefile -4) Recursively descend down in all directories listed in - init-* core* drivers-* net-* libs-* and build all targets. - - The values of the above variables are expanded in arch/$(ARCH)/Makefile. -5) All object files are then linked and the resulting file vmlinux is - located at the root of the obj tree. - The very first objects linked are listed in head-y, assigned by - arch/$(ARCH)/Makefile. -6) Finally, the architecture-specific part does any required post processing - and builds the final bootimage. - - This includes building boot records - - Preparing initrd images and the like - - ---- 6.1 Set variables to tweak the build to the architecture - - LDFLAGS Generic $(LD) options - - Flags used for all invocations of the linker. - Often specifying the emulation is sufficient. - - Example: - #arch/s390/Makefile - LDFLAGS := -m elf_s390 - Note: ldflags-y can be used to further customise - the flags used. See chapter 3.7. - - LDFLAGS_vmlinux Options for $(LD) when linking vmlinux - - LDFLAGS_vmlinux is used to specify additional flags to pass to - the linker when linking the final vmlinux image. - LDFLAGS_vmlinux uses the LDFLAGS_$@ support. - - Example: - #arch/x86/Makefile - LDFLAGS_vmlinux := -e stext - - OBJCOPYFLAGS objcopy flags - - When $(call if_changed,objcopy) is used to translate a .o file, - the flags specified in OBJCOPYFLAGS will be used. - $(call if_changed,objcopy) is often used to generate raw binaries on - vmlinux. - - Example: - #arch/s390/Makefile - OBJCOPYFLAGS := -O binary - - #arch/s390/boot/Makefile - $(obj)/image: vmlinux FORCE - $(call if_changed,objcopy) - - In this example, the binary $(obj)/image is a binary version of - vmlinux. The usage of $(call if_changed,xxx) will be described later. - - KBUILD_AFLAGS $(AS) assembler flags - - Default value - see top level Makefile - Append or modify as required per architecture. - - Example: - #arch/sparc64/Makefile - KBUILD_AFLAGS += -m64 -mcpu=ultrasparc - - KBUILD_CFLAGS $(CC) compiler flags - - Default value - see top level Makefile - Append or modify as required per architecture. - - Often, the KBUILD_CFLAGS variable depends on the configuration. - - Example: - #arch/x86/boot/compressed/Makefile - cflags-$(CONFIG_X86_32) := -march=i386 - cflags-$(CONFIG_X86_64) := -mcmodel=small - KBUILD_CFLAGS += $(cflags-y) - - Many arch Makefiles dynamically run the target C compiler to - probe supported options: - - #arch/x86/Makefile - - ... - cflags-$(CONFIG_MPENTIUMII) += $(call cc-option,\ - -march=pentium2,-march=i686) - ... - # Disable unit-at-a-time mode ... - KBUILD_CFLAGS += $(call cc-option,-fno-unit-at-a-time) - ... - - - The first example utilises the trick that a config option expands - to 'y' when selected. - - KBUILD_AFLAGS_KERNEL $(AS) options specific for built-in - - $(KBUILD_AFLAGS_KERNEL) contains extra C compiler flags used to compile - resident kernel code. - - KBUILD_AFLAGS_MODULE Options for $(AS) when building modules - - $(KBUILD_AFLAGS_MODULE) is used to add arch-specific options that - are used for $(AS). - From commandline AFLAGS_MODULE shall be used (see kbuild.txt). - - KBUILD_CFLAGS_KERNEL $(CC) options specific for built-in - - $(KBUILD_CFLAGS_KERNEL) contains extra C compiler flags used to compile - resident kernel code. - - KBUILD_CFLAGS_MODULE Options for $(CC) when building modules - - $(KBUILD_CFLAGS_MODULE) is used to add arch-specific options that - are used for $(CC). - From commandline CFLAGS_MODULE shall be used (see kbuild.txt). - - KBUILD_LDFLAGS_MODULE Options for $(LD) when linking modules - - $(KBUILD_LDFLAGS_MODULE) is used to add arch-specific options - used when linking modules. This is often a linker script. - From commandline LDFLAGS_MODULE shall be used (see kbuild.txt). - - KBUILD_ARFLAGS Options for $(AR) when creating archives - - $(KBUILD_ARFLAGS) set by the top level Makefile to "D" (deterministic - mode) if this option is supported by $(AR). - - ARCH_CPPFLAGS, ARCH_AFLAGS, ARCH_CFLAGS Overrides the kbuild defaults - - These variables are appended to the KBUILD_CPPFLAGS, - KBUILD_AFLAGS, and KBUILD_CFLAGS, respectively, after the - top-level Makefile has set any other flags. This provides a - means for an architecture to override the defaults. - - ---- 6.2 Add prerequisites to archheaders: - - The archheaders: rule is used to generate header files that - may be installed into user space by "make header_install" or - "make headers_install_all". In order to support - "make headers_install_all", this target has to be able to run - on an unconfigured tree, or a tree configured for another - architecture. - - It is run before "make archprepare" when run on the - architecture itself. - - ---- 6.3 Add prerequisites to archprepare: - - The archprepare: rule is used to list prerequisites that need to be - built before starting to descend down in the subdirectories. - This is usually used for header files containing assembler constants. - - Example: - #arch/arm/Makefile - archprepare: maketools - - In this example, the file target maketools will be processed - before descending down in the subdirectories. - See also chapter XXX-TODO that describe how kbuild supports - generating offset header files. - - ---- 6.4 List directories to visit when descending - - An arch Makefile cooperates with the top Makefile to define variables - which specify how to build the vmlinux file. Note that there is no - corresponding arch-specific section for modules; the module-building - machinery is all architecture-independent. - - - head-y, init-y, core-y, libs-y, drivers-y, net-y - - $(head-y) lists objects to be linked first in vmlinux. - $(libs-y) lists directories where a lib.a archive can be located. - The rest list directories where a built-in.a object file can be - located. - - $(init-y) objects will be located after $(head-y). - Then the rest follows in this order: - $(core-y), $(libs-y), $(drivers-y) and $(net-y). - - The top level Makefile defines values for all generic directories, - and arch/$(ARCH)/Makefile only adds architecture-specific directories. - - Example: - #arch/sparc64/Makefile - core-y += arch/sparc64/kernel/ - libs-y += arch/sparc64/prom/ arch/sparc64/lib/ - drivers-$(CONFIG_OPROFILE) += arch/sparc64/oprofile/ - - ---- 6.5 Architecture-specific boot images - - An arch Makefile specifies goals that take the vmlinux file, compress - it, wrap it in bootstrapping code, and copy the resulting files - somewhere. This includes various kinds of installation commands. - The actual goals are not standardized across architectures. - - It is common to locate any additional processing in a boot/ - directory below arch/$(ARCH)/. - - Kbuild does not provide any smart way to support building a - target specified in boot/. Therefore arch/$(ARCH)/Makefile shall - call make manually to build a target in boot/. - - The recommended approach is to include shortcuts in - arch/$(ARCH)/Makefile, and use the full path when calling down - into the arch/$(ARCH)/boot/Makefile. - - Example: - #arch/x86/Makefile - boot := arch/x86/boot - bzImage: vmlinux - $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ - - "$(Q)$(MAKE) $(build)=" is the recommended way to invoke - make in a subdirectory. - - There are no rules for naming architecture-specific targets, - but executing "make help" will list all relevant targets. - To support this, $(archhelp) must be defined. - - Example: - #arch/x86/Makefile - define archhelp - echo '* bzImage - Image (arch/$(ARCH)/boot/bzImage)' - endif - - When make is executed without arguments, the first goal encountered - will be built. In the top level Makefile the first goal present - is all:. - An architecture shall always, per default, build a bootable image. - In "make help", the default goal is highlighted with a '*'. - Add a new prerequisite to all: to select a default goal different - from vmlinux. - - Example: - #arch/x86/Makefile - all: bzImage - - When "make" is executed without arguments, bzImage will be built. - ---- 6.6 Building non-kbuild targets - - extra-y - - extra-y specifies additional targets created in the current - directory, in addition to any targets specified by obj-*. - - Listing all targets in extra-y is required for two purposes: - 1) Enable kbuild to check changes in command lines - - When $(call if_changed,xxx) is used - 2) kbuild knows what files to delete during "make clean" - - Example: - #arch/x86/kernel/Makefile - extra-y := head.o init_task.o - - In this example, extra-y is used to list object files that - shall be built, but shall not be linked as part of built-in.a. - - ---- 6.7 Commands useful for building a boot image - - Kbuild provides a few macros that are useful when building a - boot image. - - if_changed - - if_changed is the infrastructure used for the following commands. - - Usage: - target: source(s) FORCE - $(call if_changed,ld/objcopy/gzip/...) - - When the rule is evaluated, it is checked to see if any files - need an update, or the command line has changed since the last - invocation. The latter will force a rebuild if any options - to the executable have changed. - Any target that utilises if_changed must be listed in $(targets), - otherwise the command line check will fail, and the target will - always be built. - Assignments to $(targets) are without $(obj)/ prefix. - if_changed may be used in conjunction with custom commands as - defined in 6.8 "Custom kbuild commands". - - Note: It is a typical mistake to forget the FORCE prerequisite. - Another common pitfall is that whitespace is sometimes - significant; for instance, the below will fail (note the extra space - after the comma): - target: source(s) FORCE - #WRONG!# $(call if_changed, ld/objcopy/gzip/...) - - Note: if_changed should not be used more than once per target. - It stores the executed command in a corresponding .cmd - file and multiple calls would result in overwrites and - unwanted results when the target is up to date and only the - tests on changed commands trigger execution of commands. - - ld - Link target. Often, LDFLAGS_$@ is used to set specific options to ld. - - Example: - #arch/x86/boot/Makefile - LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary - LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext - - targets += setup setup.o bootsect bootsect.o - $(obj)/setup $(obj)/bootsect: %: %.o FORCE - $(call if_changed,ld) - - In this example, there are two possible targets, requiring different - options to the linker. The linker options are specified using the - LDFLAGS_$@ syntax - one for each potential target. - $(targets) are assigned all potential targets, by which kbuild knows - the targets and will: - 1) check for commandline changes - 2) delete target during make clean - - The ": %: %.o" part of the prerequisite is a shorthand that - frees us from listing the setup.o and bootsect.o files. - Note: It is a common mistake to forget the "targets :=" assignment, - resulting in the target file being recompiled for no - obvious reason. - - objcopy - Copy binary. Uses OBJCOPYFLAGS usually specified in - arch/$(ARCH)/Makefile. - OBJCOPYFLAGS_$@ may be used to set additional options. - - gzip - Compress target. Use maximum compression to compress target. - - Example: - #arch/x86/boot/compressed/Makefile - $(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE - $(call if_changed,gzip) - - dtc - Create flattened device tree blob object suitable for linking - into vmlinux. Device tree blobs linked into vmlinux are placed - in an init section in the image. Platform code *must* copy the - blob to non-init memory prior to calling unflatten_device_tree(). - - To use this command, simply add *.dtb into obj-y or targets, or make - some other target depend on %.dtb - - A central rule exists to create $(obj)/%.dtb from $(src)/%.dts; - architecture Makefiles do no need to explicitly write out that rule. - - Example: - targets += $(dtb-y) - DTC_FLAGS ?= -p 1024 - ---- 6.8 Custom kbuild commands - - When kbuild is executing with KBUILD_VERBOSE=0, then only a shorthand - of a command is normally displayed. - To enable this behaviour for custom commands kbuild requires - two variables to be set: - quiet_cmd_ - what shall be echoed - cmd_ - the command to execute - - Example: - # - quiet_cmd_image = BUILD $@ - cmd_image = $(obj)/tools/build $(BUILDFLAGS) \ - $(obj)/vmlinux.bin > $@ - - targets += bzImage - $(obj)/bzImage: $(obj)/vmlinux.bin $(obj)/tools/build FORCE - $(call if_changed,image) - @echo 'Kernel: $@ is ready' - - When updating the $(obj)/bzImage target, the line - - BUILD arch/x86/boot/bzImage - - will be displayed with "make KBUILD_VERBOSE=0". - - ---- 6.9 Preprocessing linker scripts - - When the vmlinux image is built, the linker script - arch/$(ARCH)/kernel/vmlinux.lds is used. - The script is a preprocessed variant of the file vmlinux.lds.S - located in the same directory. - kbuild knows .lds files and includes a rule *lds.S -> *lds. - - Example: - #arch/x86/kernel/Makefile - always := vmlinux.lds - - #Makefile - export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH) - - The assignment to $(always) is used to tell kbuild to build the - target vmlinux.lds. - The assignment to $(CPPFLAGS_vmlinux.lds) tells kbuild to use the - specified options when building the target vmlinux.lds. - - When building the *.lds target, kbuild uses the variables: - KBUILD_CPPFLAGS : Set in top-level Makefile - cppflags-y : May be set in the kbuild makefile - CPPFLAGS_$(@F) : Target-specific flags. - Note that the full filename is used in this - assignment. - - The kbuild infrastructure for *lds files is used in several - architecture-specific files. - ---- 6.10 Generic header files - - The directory include/asm-generic contains the header files - that may be shared between individual architectures. - The recommended approach how to use a generic header file is - to list the file in the Kbuild file. - See "7.2 generic-y" for further info on syntax etc. - ---- 6.11 Post-link pass - - If the file arch/xxx/Makefile.postlink exists, this makefile - will be invoked for post-link objects (vmlinux and modules.ko) - for architectures to run post-link passes on. Must also handle - the clean target. - - This pass runs after kallsyms generation. If the architecture - needs to modify symbol locations, rather than manipulate the - kallsyms, it may be easier to add another postlink target for - .tmp_vmlinux? targets to be called from link-vmlinux.sh. - - For example, powerpc uses this to check relocation sanity of - the linked vmlinux file. - -=== 7 Kbuild syntax for exported headers - -The kernel includes a set of headers that is exported to userspace. -Many headers can be exported as-is but other headers require a -minimal pre-processing before they are ready for user-space. -The pre-processing does: -- drop kernel-specific annotations -- drop include of compiler.h -- drop all sections that are kernel internal (guarded by ifdef __KERNEL__) - -All headers under include/uapi/, include/generated/uapi/, -arch//include/uapi/ and arch//include/generated/uapi/ -are exported. - -A Kbuild file may be defined under arch//include/uapi/asm/ and -arch//include/asm/ to list asm files coming from asm-generic. -See subsequent chapter for the syntax of the Kbuild file. - ---- 7.1 no-export-headers - - no-export-headers is essentially used by include/uapi/linux/Kbuild to - avoid exporting specific headers (e.g. kvm.h) on architectures that do - not support it. It should be avoided as much as possible. - ---- 7.2 generic-y - - If an architecture uses a verbatim copy of a header from - include/asm-generic then this is listed in the file - arch/$(ARCH)/include/asm/Kbuild like this: - - Example: - #arch/x86/include/asm/Kbuild - generic-y += termios.h - generic-y += rtc.h - - During the prepare phase of the build a wrapper include - file is generated in the directory: - - arch/$(ARCH)/include/generated/asm - - When a header is exported where the architecture uses - the generic header a similar wrapper is generated as part - of the set of exported headers in the directory: - - usr/include/asm - - The generated wrapper will in both cases look like the following: - - Example: termios.h - #include - ---- 7.3 generated-y - - If an architecture generates other header files alongside generic-y - wrappers, generated-y specifies them. - - This prevents them being treated as stale asm-generic wrappers and - removed. - - Example: - #arch/x86/include/asm/Kbuild - generated-y += syscalls_32.h - ---- 7.4 mandatory-y - - mandatory-y is essentially used by include/(uapi/)asm-generic/Kbuild - to define the minimum set of ASM headers that all architectures must have. - - This works like optional generic-y. If a mandatory header is missing - in arch/$(ARCH)/include/(uapi/)/asm, Kbuild will automatically generate - a wrapper of the asm-generic one. - - The convention is to list one subdir per line and - preferably in alphabetic order. - -=== 8 Kbuild Variables - -The top Makefile exports the following variables: - - VERSION, PATCHLEVEL, SUBLEVEL, EXTRAVERSION - - These variables define the current kernel version. A few arch - Makefiles actually use these values directly; they should use - $(KERNELRELEASE) instead. - - $(VERSION), $(PATCHLEVEL), and $(SUBLEVEL) define the basic - three-part version number, such as "2", "4", and "0". These three - values are always numeric. - - $(EXTRAVERSION) defines an even tinier sublevel for pre-patches - or additional patches. It is usually some non-numeric string - such as "-pre4", and is often blank. - - KERNELRELEASE - - $(KERNELRELEASE) is a single string such as "2.4.0-pre4", suitable - for constructing installation directory names or showing in - version strings. Some arch Makefiles use it for this purpose. - - ARCH - - This variable defines the target architecture, such as "i386", - "arm", or "sparc". Some kbuild Makefiles test $(ARCH) to - determine which files to compile. - - By default, the top Makefile sets $(ARCH) to be the same as the - host system architecture. For a cross build, a user may - override the value of $(ARCH) on the command line: - - make ARCH=m68k ... - - - INSTALL_PATH - - This variable defines a place for the arch Makefiles to install - the resident kernel image and System.map file. - Use this for architecture-specific install targets. - - INSTALL_MOD_PATH, MODLIB - - $(INSTALL_MOD_PATH) specifies a prefix to $(MODLIB) for module - installation. This variable is not defined in the Makefile but - may be passed in by the user if desired. - - $(MODLIB) specifies the directory for module installation. - The top Makefile defines $(MODLIB) to - $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE). The user may - override this value on the command line if desired. - - INSTALL_MOD_STRIP - - If this variable is specified, it will cause modules to be stripped - after they are installed. If INSTALL_MOD_STRIP is '1', then the - default option --strip-debug will be used. Otherwise, the - INSTALL_MOD_STRIP value will be used as the option(s) to the strip - command. - - -=== 9 Makefile language - -The kernel Makefiles are designed to be run with GNU Make. The Makefiles -use only the documented features of GNU Make, but they do use many -GNU extensions. - -GNU Make supports elementary list-processing functions. The kernel -Makefiles use a novel style of list building and manipulation with few -"if" statements. - -GNU Make has two assignment operators, ":=" and "=". ":=" performs -immediate evaluation of the right-hand side and stores an actual string -into the left-hand side. "=" is like a formula definition; it stores the -right-hand side in an unevaluated form and then evaluates this form each -time the left-hand side is used. - -There are some cases where "=" is appropriate. Usually, though, ":=" -is the right choice. - -=== 10 Credits - -Original version made by Michael Elizabeth Chastain, -Updates by Kai Germaschewski -Updates by Sam Ravnborg -Language QA by Jan Engelhardt - -=== 11 TODO - -- Describe how kbuild supports shipped files with _shipped. -- Generating offset header files. -- Add more variables to section 7? - - - diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst new file mode 100644 index 000000000000..24e763482650 --- /dev/null +++ b/Documentation/kbuild/modules.rst @@ -0,0 +1,571 @@ +========================= +Building External Modules +========================= + +This document describes how to build an out-of-tree kernel module. + +.. Table of Contents + + === 1 Introduction + === 2 How to Build External Modules + --- 2.1 Command Syntax + --- 2.2 Options + --- 2.3 Targets + --- 2.4 Building Separate Files + === 3. Creating a Kbuild File for an External Module + --- 3.1 Shared Makefile + --- 3.2 Separate Kbuild file and Makefile + --- 3.3 Binary Blobs + --- 3.4 Building Multiple Modules + === 4. Include Files + --- 4.1 Kernel Includes + --- 4.2 Single Subdirectory + --- 4.3 Several Subdirectories + === 5. Module Installation + --- 5.1 INSTALL_MOD_PATH + --- 5.2 INSTALL_MOD_DIR + === 6. Module Versioning + --- 6.1 Symbols From the Kernel (vmlinux + modules) + --- 6.2 Symbols and External Modules + --- 6.3 Symbols From Another External Module + === 7. Tips & Tricks + --- 7.1 Testing for CONFIG_FOO_BAR + + + +1. Introduction +=============== + +"kbuild" is the build system used by the Linux kernel. Modules must use +kbuild to stay compatible with changes in the build infrastructure and +to pick up the right flags to "gcc." Functionality for building modules +both in-tree and out-of-tree is provided. The method for building +either is similar, and all modules are initially developed and built +out-of-tree. + +Covered in this document is information aimed at developers interested +in building out-of-tree (or "external") modules. The author of an +external module should supply a makefile that hides most of the +complexity, so one only has to type "make" to build the module. This is +easily accomplished, and a complete example will be presented in +section 3. + + +2. How to Build External Modules +================================ + +To build external modules, you must have a prebuilt kernel available +that contains the configuration and header files used in the build. +Also, the kernel must have been built with modules enabled. If you are +using a distribution kernel, there will be a package for the kernel you +are running provided by your distribution. + +An alternative is to use the "make" target "modules_prepare." This will +make sure the kernel contains the information required. The target +exists solely as a simple way to prepare a kernel source tree for +building external modules. + +NOTE: "modules_prepare" will not build Module.symvers even if +CONFIG_MODVERSIONS is set; therefore, a full kernel build needs to be +executed to make module versioning work. + +2.1 Command Syntax +================== + + The command to build an external module is:: + + $ make -C M=$PWD + + The kbuild system knows that an external module is being built + due to the "M=" option given in the command. + + To build against the running kernel use:: + + $ make -C /lib/modules/`uname -r`/build M=$PWD + + Then to install the module(s) just built, add the target + "modules_install" to the command:: + + $ make -C /lib/modules/`uname -r`/build M=$PWD modules_install + +2.2 Options +=========== + + ($KDIR refers to the path of the kernel source directory.) + + make -C $KDIR M=$PWD + + -C $KDIR + The directory where the kernel source is located. + "make" will actually change to the specified directory + when executing and will change back when finished. + + M=$PWD + Informs kbuild that an external module is being built. + The value given to "M" is the absolute path of the + directory where the external module (kbuild file) is + located. + +2.3 Targets +=========== + + When building an external module, only a subset of the "make" + targets are available. + + make -C $KDIR M=$PWD [target] + + The default will build the module(s) located in the current + directory, so a target does not need to be specified. All + output files will also be generated in this directory. No + attempts are made to update the kernel source, and it is a + precondition that a successful "make" has been executed for the + kernel. + + modules + The default target for external modules. It has the + same functionality as if no target was specified. See + description above. + + modules_install + Install the external module(s). The default location is + /lib/modules//extra/, but a prefix may + be added with INSTALL_MOD_PATH (discussed in section 5). + + clean + Remove all generated files in the module directory only. + + help + List the available targets for external modules. + +2.4 Building Separate Files +=========================== + + It is possible to build single files that are part of a module. + This works equally well for the kernel, a module, and even for + external modules. + + Example (The module foo.ko, consist of bar.o and baz.o):: + + make -C $KDIR M=$PWD bar.lst + make -C $KDIR M=$PWD baz.o + make -C $KDIR M=$PWD foo.ko + make -C $KDIR M=$PWD ./ + + +3. Creating a Kbuild File for an External Module +================================================ + +In the last section we saw the command to build a module for the +running kernel. The module is not actually built, however, because a +build file is required. Contained in this file will be the name of +the module(s) being built, along with the list of requisite source +files. The file may be as simple as a single line:: + + obj-m := .o + +The kbuild system will build .o from .c, +and, after linking, will result in the kernel module .ko. +The above line can be put in either a "Kbuild" file or a "Makefile." +When the module is built from multiple sources, an additional line is +needed listing the files:: + + -y := .o .o ... + +NOTE: Further documentation describing the syntax used by kbuild is +located in Documentation/kbuild/makefiles.rst. + +The examples below demonstrate how to create a build file for the +module 8123.ko, which is built from the following files:: + + 8123_if.c + 8123_if.h + 8123_pci.c + 8123_bin.o_shipped <= Binary blob + +--- 3.1 Shared Makefile + + An external module always includes a wrapper makefile that + supports building the module using "make" with no arguments. + This target is not used by kbuild; it is only for convenience. + Additional functionality, such as test targets, can be included + but should be filtered out from kbuild due to possible name + clashes. + + Example 1:: + + --> filename: Makefile + ifneq ($(KERNELRELEASE),) + # kbuild part of makefile + obj-m := 8123.o + 8123-y := 8123_if.o 8123_pci.o 8123_bin.o + + else + # normal makefile + KDIR ?= /lib/modules/`uname -r`/build + + default: + $(MAKE) -C $(KDIR) M=$$PWD + + # Module specific targets + genbin: + echo "X" > 8123_bin.o_shipped + + endif + + The check for KERNELRELEASE is used to separate the two parts + of the makefile. In the example, kbuild will only see the two + assignments, whereas "make" will see everything except these + two assignments. This is due to two passes made on the file: + the first pass is by the "make" instance run on the command + line; the second pass is by the kbuild system, which is + initiated by the parameterized "make" in the default target. + +3.2 Separate Kbuild File and Makefile +------------------------------------- + + In newer versions of the kernel, kbuild will first look for a + file named "Kbuild," and only if that is not found, will it + then look for a makefile. Utilizing a "Kbuild" file allows us + to split up the makefile from example 1 into two files: + + Example 2:: + + --> filename: Kbuild + obj-m := 8123.o + 8123-y := 8123_if.o 8123_pci.o 8123_bin.o + + --> filename: Makefile + KDIR ?= /lib/modules/`uname -r`/build + + default: + $(MAKE) -C $(KDIR) M=$$PWD + + # Module specific targets + genbin: + echo "X" > 8123_bin.o_shipped + + The split in example 2 is questionable due to the simplicity of + each file; however, some external modules use makefiles + consisting of several hundred lines, and here it really pays + off to separate the kbuild part from the rest. + + The next example shows a backward compatible version. + + Example 3:: + + --> filename: Kbuild + obj-m := 8123.o + 8123-y := 8123_if.o 8123_pci.o 8123_bin.o + + --> filename: Makefile + ifneq ($(KERNELRELEASE),) + # kbuild part of makefile + include Kbuild + + else + # normal makefile + KDIR ?= /lib/modules/`uname -r`/build + + default: + $(MAKE) -C $(KDIR) M=$$PWD + + # Module specific targets + genbin: + echo "X" > 8123_bin.o_shipped + + endif + + Here the "Kbuild" file is included from the makefile. This + allows an older version of kbuild, which only knows of + makefiles, to be used when the "make" and kbuild parts are + split into separate files. + +3.3 Binary Blobs +---------------- + + Some external modules need to include an object file as a blob. + kbuild has support for this, but requires the blob file to be + named _shipped. When the kbuild rules kick in, a copy + of _shipped is created with _shipped stripped off, + giving us . This shortened filename can be used in + the assignment to the module. + + Throughout this section, 8123_bin.o_shipped has been used to + build the kernel module 8123.ko; it has been included as + 8123_bin.o:: + + 8123-y := 8123_if.o 8123_pci.o 8123_bin.o + + Although there is no distinction between the ordinary source + files and the binary file, kbuild will pick up different rules + when creating the object file for the module. + +3.4 Building Multiple Modules +============================= + + kbuild supports building multiple modules with a single build + file. For example, if you wanted to build two modules, foo.ko + and bar.ko, the kbuild lines would be:: + + obj-m := foo.o bar.o + foo-y := + bar-y := + + It is that simple! + + +4. Include Files +================ + +Within the kernel, header files are kept in standard locations +according to the following rule: + + * If the header file only describes the internal interface of a + module, then the file is placed in the same directory as the + source files. + * If the header file describes an interface used by other parts + of the kernel that are located in different directories, then + the file is placed in include/linux/. + + NOTE: + There are two notable exceptions to this rule: larger + subsystems have their own directory under include/, such as + include/scsi; and architecture specific headers are located + under arch/$(ARCH)/include/. + +4.1 Kernel Includes +------------------- + + To include a header file located under include/linux/, simply + use:: + + #include + + kbuild will add options to "gcc" so the relevant directories + are searched. + +4.2 Single Subdirectory +----------------------- + + External modules tend to place header files in a separate + include/ directory where their source is located, although this + is not the usual kernel style. To inform kbuild of the + directory, use either ccflags-y or CFLAGS_.o. + + Using the example from section 3, if we moved 8123_if.h to a + subdirectory named include, the resulting kbuild file would + look like:: + + --> filename: Kbuild + obj-m := 8123.o + + ccflags-y := -Iinclude + 8123-y := 8123_if.o 8123_pci.o 8123_bin.o + + Note that in the assignment there is no space between -I and + the path. This is a limitation of kbuild: there must be no + space present. + +4.3 Several Subdirectories +-------------------------- + + kbuild can handle files that are spread over several directories. + Consider the following example:: + + . + |__ src + | |__ complex_main.c + | |__ hal + | |__ hardwareif.c + | |__ include + | |__ hardwareif.h + |__ include + |__ complex.h + + To build the module complex.ko, we then need the following + kbuild file:: + + --> filename: Kbuild + obj-m := complex.o + complex-y := src/complex_main.o + complex-y += src/hal/hardwareif.o + + ccflags-y := -I$(src)/include + ccflags-y += -I$(src)/src/hal/include + + As you can see, kbuild knows how to handle object files located + in other directories. The trick is to specify the directory + relative to the kbuild file's location. That being said, this + is NOT recommended practice. + + For the header files, kbuild must be explicitly told where to + look. When kbuild executes, the current directory is always the + root of the kernel tree (the argument to "-C") and therefore an + absolute path is needed. $(src) provides the absolute path by + pointing to the directory where the currently executing kbuild + file is located. + + +5. Module Installation +====================== + +Modules which are included in the kernel are installed in the +directory: + + /lib/modules/$(KERNELRELEASE)/kernel/ + +And external modules are installed in: + + /lib/modules/$(KERNELRELEASE)/extra/ + +5.1 INSTALL_MOD_PATH +-------------------- + + Above are the default directories but as always some level of + customization is possible. A prefix can be added to the + installation path using the variable INSTALL_MOD_PATH:: + + $ make INSTALL_MOD_PATH=/frodo modules_install + => Install dir: /frodo/lib/modules/$(KERNELRELEASE)/kernel/ + + INSTALL_MOD_PATH may be set as an ordinary shell variable or, + as shown above, can be specified on the command line when + calling "make." This has effect when installing both in-tree + and out-of-tree modules. + +5.2 INSTALL_MOD_DIR +------------------- + + External modules are by default installed to a directory under + /lib/modules/$(KERNELRELEASE)/extra/, but you may wish to + locate modules for a specific functionality in a separate + directory. For this purpose, use INSTALL_MOD_DIR to specify an + alternative name to "extra.":: + + $ make INSTALL_MOD_DIR=gandalf -C $KDIR \ + M=$PWD modules_install + => Install dir: /lib/modules/$(KERNELRELEASE)/gandalf/ + + +6. Module Versioning +==================== + +Module versioning is enabled by the CONFIG_MODVERSIONS tag, and is used +as a simple ABI consistency check. A CRC value of the full prototype +for an exported symbol is created. When a module is loaded/used, the +CRC values contained in the kernel are compared with similar values in +the module; if they are not equal, the kernel refuses to load the +module. + +Module.symvers contains a list of all exported symbols from a kernel +build. + +6.1 Symbols From the Kernel (vmlinux + modules) +----------------------------------------------- + + During a kernel build, a file named Module.symvers will be + generated. Module.symvers contains all exported symbols from + the kernel and compiled modules. For each symbol, the + corresponding CRC value is also stored. + + The syntax of the Module.symvers file is:: + + + + 0x2d036834 scsi_remove_host drivers/scsi/scsi_mod + + For a kernel build without CONFIG_MODVERSIONS enabled, the CRC + would read 0x00000000. + + Module.symvers serves two purposes: + + 1) It lists all exported symbols from vmlinux and all modules. + 2) It lists the CRC if CONFIG_MODVERSIONS is enabled. + +6.2 Symbols and External Modules +-------------------------------- + + When building an external module, the build system needs access + to the symbols from the kernel to check if all external symbols + are defined. This is done in the MODPOST step. modpost obtains + the symbols by reading Module.symvers from the kernel source + tree. If a Module.symvers file is present in the directory + where the external module is being built, this file will be + read too. During the MODPOST step, a new Module.symvers file + will be written containing all exported symbols that were not + defined in the kernel. + +--- 6.3 Symbols From Another External Module + + Sometimes, an external module uses exported symbols from + another external module. kbuild needs to have full knowledge of + all symbols to avoid spitting out warnings about undefined + symbols. Three solutions exist for this situation. + + NOTE: The method with a top-level kbuild file is recommended + but may be impractical in certain situations. + + Use a top-level kbuild file + If you have two modules, foo.ko and bar.ko, where + foo.ko needs symbols from bar.ko, you can use a + common top-level kbuild file so both modules are + compiled in the same build. Consider the following + directory layout:: + + ./foo/ <= contains foo.ko + ./bar/ <= contains bar.ko + + The top-level kbuild file would then look like:: + + #./Kbuild (or ./Makefile): + obj-y := foo/ bar/ + + And executing:: + + $ make -C $KDIR M=$PWD + + will then do the expected and compile both modules with + full knowledge of symbols from either module. + + Use an extra Module.symvers file + When an external module is built, a Module.symvers file + is generated containing all exported symbols which are + not defined in the kernel. To get access to symbols + from bar.ko, copy the Module.symvers file from the + compilation of bar.ko to the directory where foo.ko is + built. During the module build, kbuild will read the + Module.symvers file in the directory of the external + module, and when the build is finished, a new + Module.symvers file is created containing the sum of + all symbols defined and not part of the kernel. + + Use "make" variable KBUILD_EXTRA_SYMBOLS + If it is impractical to copy Module.symvers from + another module, you can assign a space separated list + of files to KBUILD_EXTRA_SYMBOLS in your build file. + These files will be loaded by modpost during the + initialization of its symbol tables. + + +7. Tips & Tricks +================ + +7.1 Testing for CONFIG_FOO_BAR +------------------------------ + + Modules often need to check for certain `CONFIG_` options to + decide if a specific feature is included in the module. In + kbuild this is done by referencing the `CONFIG_` variable + directly:: + + #fs/ext2/Makefile + obj-$(CONFIG_EXT2_FS) += ext2.o + + ext2-y := balloc.o bitmap.o dir.o + ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o + + External modules have traditionally used "grep" to check for + specific `CONFIG_` settings directly in .config. This usage is + broken. As introduced before, external modules should use + kbuild for building and can therefore use the same methods as + in-tree modules when testing for `CONFIG_` definitions. diff --git a/Documentation/kbuild/modules.txt b/Documentation/kbuild/modules.txt deleted file mode 100644 index 80295c613e37..000000000000 --- a/Documentation/kbuild/modules.txt +++ /dev/null @@ -1,541 +0,0 @@ -Building External Modules - -This document describes how to build an out-of-tree kernel module. - -=== Table of Contents - - === 1 Introduction - === 2 How to Build External Modules - --- 2.1 Command Syntax - --- 2.2 Options - --- 2.3 Targets - --- 2.4 Building Separate Files - === 3. Creating a Kbuild File for an External Module - --- 3.1 Shared Makefile - --- 3.2 Separate Kbuild file and Makefile - --- 3.3 Binary Blobs - --- 3.4 Building Multiple Modules - === 4. Include Files - --- 4.1 Kernel Includes - --- 4.2 Single Subdirectory - --- 4.3 Several Subdirectories - === 5. Module Installation - --- 5.1 INSTALL_MOD_PATH - --- 5.2 INSTALL_MOD_DIR - === 6. Module Versioning - --- 6.1 Symbols From the Kernel (vmlinux + modules) - --- 6.2 Symbols and External Modules - --- 6.3 Symbols From Another External Module - === 7. Tips & Tricks - --- 7.1 Testing for CONFIG_FOO_BAR - - - -=== 1. Introduction - -"kbuild" is the build system used by the Linux kernel. Modules must use -kbuild to stay compatible with changes in the build infrastructure and -to pick up the right flags to "gcc." Functionality for building modules -both in-tree and out-of-tree is provided. The method for building -either is similar, and all modules are initially developed and built -out-of-tree. - -Covered in this document is information aimed at developers interested -in building out-of-tree (or "external") modules. The author of an -external module should supply a makefile that hides most of the -complexity, so one only has to type "make" to build the module. This is -easily accomplished, and a complete example will be presented in -section 3. - - -=== 2. How to Build External Modules - -To build external modules, you must have a prebuilt kernel available -that contains the configuration and header files used in the build. -Also, the kernel must have been built with modules enabled. If you are -using a distribution kernel, there will be a package for the kernel you -are running provided by your distribution. - -An alternative is to use the "make" target "modules_prepare." This will -make sure the kernel contains the information required. The target -exists solely as a simple way to prepare a kernel source tree for -building external modules. - -NOTE: "modules_prepare" will not build Module.symvers even if -CONFIG_MODVERSIONS is set; therefore, a full kernel build needs to be -executed to make module versioning work. - ---- 2.1 Command Syntax - - The command to build an external module is: - - $ make -C M=$PWD - - The kbuild system knows that an external module is being built - due to the "M=" option given in the command. - - To build against the running kernel use: - - $ make -C /lib/modules/`uname -r`/build M=$PWD - - Then to install the module(s) just built, add the target - "modules_install" to the command: - - $ make -C /lib/modules/`uname -r`/build M=$PWD modules_install - ---- 2.2 Options - - ($KDIR refers to the path of the kernel source directory.) - - make -C $KDIR M=$PWD - - -C $KDIR - The directory where the kernel source is located. - "make" will actually change to the specified directory - when executing and will change back when finished. - - M=$PWD - Informs kbuild that an external module is being built. - The value given to "M" is the absolute path of the - directory where the external module (kbuild file) is - located. - ---- 2.3 Targets - - When building an external module, only a subset of the "make" - targets are available. - - make -C $KDIR M=$PWD [target] - - The default will build the module(s) located in the current - directory, so a target does not need to be specified. All - output files will also be generated in this directory. No - attempts are made to update the kernel source, and it is a - precondition that a successful "make" has been executed for the - kernel. - - modules - The default target for external modules. It has the - same functionality as if no target was specified. See - description above. - - modules_install - Install the external module(s). The default location is - /lib/modules//extra/, but a prefix may - be added with INSTALL_MOD_PATH (discussed in section 5). - - clean - Remove all generated files in the module directory only. - - help - List the available targets for external modules. - ---- 2.4 Building Separate Files - - It is possible to build single files that are part of a module. - This works equally well for the kernel, a module, and even for - external modules. - - Example (The module foo.ko, consist of bar.o and baz.o): - make -C $KDIR M=$PWD bar.lst - make -C $KDIR M=$PWD baz.o - make -C $KDIR M=$PWD foo.ko - make -C $KDIR M=$PWD ./ - - -=== 3. Creating a Kbuild File for an External Module - -In the last section we saw the command to build a module for the -running kernel. The module is not actually built, however, because a -build file is required. Contained in this file will be the name of -the module(s) being built, along with the list of requisite source -files. The file may be as simple as a single line: - - obj-m := .o - -The kbuild system will build .o from .c, -and, after linking, will result in the kernel module .ko. -The above line can be put in either a "Kbuild" file or a "Makefile." -When the module is built from multiple sources, an additional line is -needed listing the files: - - -y := .o .o ... - -NOTE: Further documentation describing the syntax used by kbuild is -located in Documentation/kbuild/makefiles.txt. - -The examples below demonstrate how to create a build file for the -module 8123.ko, which is built from the following files: - - 8123_if.c - 8123_if.h - 8123_pci.c - 8123_bin.o_shipped <= Binary blob - ---- 3.1 Shared Makefile - - An external module always includes a wrapper makefile that - supports building the module using "make" with no arguments. - This target is not used by kbuild; it is only for convenience. - Additional functionality, such as test targets, can be included - but should be filtered out from kbuild due to possible name - clashes. - - Example 1: - --> filename: Makefile - ifneq ($(KERNELRELEASE),) - # kbuild part of makefile - obj-m := 8123.o - 8123-y := 8123_if.o 8123_pci.o 8123_bin.o - - else - # normal makefile - KDIR ?= /lib/modules/`uname -r`/build - - default: - $(MAKE) -C $(KDIR) M=$$PWD - - # Module specific targets - genbin: - echo "X" > 8123_bin.o_shipped - - endif - - The check for KERNELRELEASE is used to separate the two parts - of the makefile. In the example, kbuild will only see the two - assignments, whereas "make" will see everything except these - two assignments. This is due to two passes made on the file: - the first pass is by the "make" instance run on the command - line; the second pass is by the kbuild system, which is - initiated by the parameterized "make" in the default target. - ---- 3.2 Separate Kbuild File and Makefile - - In newer versions of the kernel, kbuild will first look for a - file named "Kbuild," and only if that is not found, will it - then look for a makefile. Utilizing a "Kbuild" file allows us - to split up the makefile from example 1 into two files: - - Example 2: - --> filename: Kbuild - obj-m := 8123.o - 8123-y := 8123_if.o 8123_pci.o 8123_bin.o - - --> filename: Makefile - KDIR ?= /lib/modules/`uname -r`/build - - default: - $(MAKE) -C $(KDIR) M=$$PWD - - # Module specific targets - genbin: - echo "X" > 8123_bin.o_shipped - - The split in example 2 is questionable due to the simplicity of - each file; however, some external modules use makefiles - consisting of several hundred lines, and here it really pays - off to separate the kbuild part from the rest. - - The next example shows a backward compatible version. - - Example 3: - --> filename: Kbuild - obj-m := 8123.o - 8123-y := 8123_if.o 8123_pci.o 8123_bin.o - - --> filename: Makefile - ifneq ($(KERNELRELEASE),) - # kbuild part of makefile - include Kbuild - - else - # normal makefile - KDIR ?= /lib/modules/`uname -r`/build - - default: - $(MAKE) -C $(KDIR) M=$$PWD - - # Module specific targets - genbin: - echo "X" > 8123_bin.o_shipped - - endif - - Here the "Kbuild" file is included from the makefile. This - allows an older version of kbuild, which only knows of - makefiles, to be used when the "make" and kbuild parts are - split into separate files. - ---- 3.3 Binary Blobs - - Some external modules need to include an object file as a blob. - kbuild has support for this, but requires the blob file to be - named _shipped. When the kbuild rules kick in, a copy - of _shipped is created with _shipped stripped off, - giving us . This shortened filename can be used in - the assignment to the module. - - Throughout this section, 8123_bin.o_shipped has been used to - build the kernel module 8123.ko; it has been included as - 8123_bin.o. - - 8123-y := 8123_if.o 8123_pci.o 8123_bin.o - - Although there is no distinction between the ordinary source - files and the binary file, kbuild will pick up different rules - when creating the object file for the module. - ---- 3.4 Building Multiple Modules - - kbuild supports building multiple modules with a single build - file. For example, if you wanted to build two modules, foo.ko - and bar.ko, the kbuild lines would be: - - obj-m := foo.o bar.o - foo-y := - bar-y := - - It is that simple! - - -=== 4. Include Files - -Within the kernel, header files are kept in standard locations -according to the following rule: - - * If the header file only describes the internal interface of a - module, then the file is placed in the same directory as the - source files. - * If the header file describes an interface used by other parts - of the kernel that are located in different directories, then - the file is placed in include/linux/. - - NOTE: There are two notable exceptions to this rule: larger - subsystems have their own directory under include/, such as - include/scsi; and architecture specific headers are located - under arch/$(ARCH)/include/. - ---- 4.1 Kernel Includes - - To include a header file located under include/linux/, simply - use: - - #include - - kbuild will add options to "gcc" so the relevant directories - are searched. - ---- 4.2 Single Subdirectory - - External modules tend to place header files in a separate - include/ directory where their source is located, although this - is not the usual kernel style. To inform kbuild of the - directory, use either ccflags-y or CFLAGS_.o. - - Using the example from section 3, if we moved 8123_if.h to a - subdirectory named include, the resulting kbuild file would - look like: - - --> filename: Kbuild - obj-m := 8123.o - - ccflags-y := -Iinclude - 8123-y := 8123_if.o 8123_pci.o 8123_bin.o - - Note that in the assignment there is no space between -I and - the path. This is a limitation of kbuild: there must be no - space present. - ---- 4.3 Several Subdirectories - - kbuild can handle files that are spread over several directories. - Consider the following example: - - . - |__ src - | |__ complex_main.c - | |__ hal - | |__ hardwareif.c - | |__ include - | |__ hardwareif.h - |__ include - |__ complex.h - - To build the module complex.ko, we then need the following - kbuild file: - - --> filename: Kbuild - obj-m := complex.o - complex-y := src/complex_main.o - complex-y += src/hal/hardwareif.o - - ccflags-y := -I$(src)/include - ccflags-y += -I$(src)/src/hal/include - - As you can see, kbuild knows how to handle object files located - in other directories. The trick is to specify the directory - relative to the kbuild file's location. That being said, this - is NOT recommended practice. - - For the header files, kbuild must be explicitly told where to - look. When kbuild executes, the current directory is always the - root of the kernel tree (the argument to "-C") and therefore an - absolute path is needed. $(src) provides the absolute path by - pointing to the directory where the currently executing kbuild - file is located. - - -=== 5. Module Installation - -Modules which are included in the kernel are installed in the -directory: - - /lib/modules/$(KERNELRELEASE)/kernel/ - -And external modules are installed in: - - /lib/modules/$(KERNELRELEASE)/extra/ - ---- 5.1 INSTALL_MOD_PATH - - Above are the default directories but as always some level of - customization is possible. A prefix can be added to the - installation path using the variable INSTALL_MOD_PATH: - - $ make INSTALL_MOD_PATH=/frodo modules_install - => Install dir: /frodo/lib/modules/$(KERNELRELEASE)/kernel/ - - INSTALL_MOD_PATH may be set as an ordinary shell variable or, - as shown above, can be specified on the command line when - calling "make." This has effect when installing both in-tree - and out-of-tree modules. - ---- 5.2 INSTALL_MOD_DIR - - External modules are by default installed to a directory under - /lib/modules/$(KERNELRELEASE)/extra/, but you may wish to - locate modules for a specific functionality in a separate - directory. For this purpose, use INSTALL_MOD_DIR to specify an - alternative name to "extra." - - $ make INSTALL_MOD_DIR=gandalf -C $KDIR \ - M=$PWD modules_install - => Install dir: /lib/modules/$(KERNELRELEASE)/gandalf/ - - -=== 6. Module Versioning - -Module versioning is enabled by the CONFIG_MODVERSIONS tag, and is used -as a simple ABI consistency check. A CRC value of the full prototype -for an exported symbol is created. When a module is loaded/used, the -CRC values contained in the kernel are compared with similar values in -the module; if they are not equal, the kernel refuses to load the -module. - -Module.symvers contains a list of all exported symbols from a kernel -build. - ---- 6.1 Symbols From the Kernel (vmlinux + modules) - - During a kernel build, a file named Module.symvers will be - generated. Module.symvers contains all exported symbols from - the kernel and compiled modules. For each symbol, the - corresponding CRC value is also stored. - - The syntax of the Module.symvers file is: - - - 0x2d036834 scsi_remove_host drivers/scsi/scsi_mod - - For a kernel build without CONFIG_MODVERSIONS enabled, the CRC - would read 0x00000000. - - Module.symvers serves two purposes: - 1) It lists all exported symbols from vmlinux and all modules. - 2) It lists the CRC if CONFIG_MODVERSIONS is enabled. - ---- 6.2 Symbols and External Modules - - When building an external module, the build system needs access - to the symbols from the kernel to check if all external symbols - are defined. This is done in the MODPOST step. modpost obtains - the symbols by reading Module.symvers from the kernel source - tree. If a Module.symvers file is present in the directory - where the external module is being built, this file will be - read too. During the MODPOST step, a new Module.symvers file - will be written containing all exported symbols that were not - defined in the kernel. - ---- 6.3 Symbols From Another External Module - - Sometimes, an external module uses exported symbols from - another external module. kbuild needs to have full knowledge of - all symbols to avoid spitting out warnings about undefined - symbols. Three solutions exist for this situation. - - NOTE: The method with a top-level kbuild file is recommended - but may be impractical in certain situations. - - Use a top-level kbuild file - If you have two modules, foo.ko and bar.ko, where - foo.ko needs symbols from bar.ko, you can use a - common top-level kbuild file so both modules are - compiled in the same build. Consider the following - directory layout: - - ./foo/ <= contains foo.ko - ./bar/ <= contains bar.ko - - The top-level kbuild file would then look like: - - #./Kbuild (or ./Makefile): - obj-y := foo/ bar/ - - And executing - - $ make -C $KDIR M=$PWD - - will then do the expected and compile both modules with - full knowledge of symbols from either module. - - Use an extra Module.symvers file - When an external module is built, a Module.symvers file - is generated containing all exported symbols which are - not defined in the kernel. To get access to symbols - from bar.ko, copy the Module.symvers file from the - compilation of bar.ko to the directory where foo.ko is - built. During the module build, kbuild will read the - Module.symvers file in the directory of the external - module, and when the build is finished, a new - Module.symvers file is created containing the sum of - all symbols defined and not part of the kernel. - - Use "make" variable KBUILD_EXTRA_SYMBOLS - If it is impractical to copy Module.symvers from - another module, you can assign a space separated list - of files to KBUILD_EXTRA_SYMBOLS in your build file. - These files will be loaded by modpost during the - initialization of its symbol tables. - - -=== 7. Tips & Tricks - ---- 7.1 Testing for CONFIG_FOO_BAR - - Modules often need to check for certain CONFIG_ options to - decide if a specific feature is included in the module. In - kbuild this is done by referencing the CONFIG_ variable - directly. - - #fs/ext2/Makefile - obj-$(CONFIG_EXT2_FS) += ext2.o - - ext2-y := balloc.o bitmap.o dir.o - ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o - - External modules have traditionally used "grep" to check for - specific CONFIG_ settings directly in .config. This usage is - broken. As introduced before, external modules should use - kbuild for building and can therefore use the same methods as - in-tree modules when testing for CONFIG_ definitions. - diff --git a/Documentation/kernel-hacking/hacking.rst b/Documentation/kernel-hacking/hacking.rst index d824e4feaff3..5891a701a159 100644 --- a/Documentation/kernel-hacking/hacking.rst +++ b/Documentation/kernel-hacking/hacking.rst @@ -718,7 +718,7 @@ make a neat patch, there's administrative work to be done: - Usually you want a configuration option for your kernel hack. Edit ``Kconfig`` in the appropriate directory. The Config language is simple to use by cut and paste, and there's complete documentation in - ``Documentation/kbuild/kconfig-language.txt``. + ``Documentation/kbuild/kconfig-language.rst``. In your description of the option, make sure you address both the expert user and the user who knows nothing about your feature. @@ -728,7 +728,7 @@ make a neat patch, there's administrative work to be done: - Edit the ``Makefile``: the CONFIG variables are exported here so you can usually just add a "obj-$(CONFIG_xxx) += xxx.o" line. The syntax - is documented in ``Documentation/kbuild/makefiles.txt``. + is documented in ``Documentation/kbuild/makefiles.rst``. - Put yourself in ``CREDITS`` if you've done something noteworthy, usually beyond a single file (your name should be at the top of the diff --git a/Documentation/process/coding-style.rst b/Documentation/process/coding-style.rst index fa864a51e6ea..f4a2198187f9 100644 --- a/Documentation/process/coding-style.rst +++ b/Documentation/process/coding-style.rst @@ -686,7 +686,7 @@ filesystems) should advertise this prominently in their prompt string:: ... For full documentation on the configuration files, see the file -Documentation/kbuild/kconfig-language.txt. +Documentation/kbuild/kconfig-language.rst. 11) Data structures diff --git a/Documentation/process/submit-checklist.rst b/Documentation/process/submit-checklist.rst index c88867b173d9..365efc9e4aa8 100644 --- a/Documentation/process/submit-checklist.rst +++ b/Documentation/process/submit-checklist.rst @@ -39,7 +39,7 @@ and elsewhere regarding submitting Linux kernel patches. 6) Any new or modified ``CONFIG`` options do not muck up the config menu and default to off unless they meet the exception criteria documented in - ``Documentation/kbuild/kconfig-language.txt`` Menu attributes: default value. + ``Documentation/kbuild/kconfig-language.rst`` Menu attributes: default value. 7) All new ``Kconfig`` options have help text. diff --git a/Documentation/translations/it_IT/kernel-hacking/hacking.rst b/Documentation/translations/it_IT/kernel-hacking/hacking.rst index 7178e517af0a..24c592852bf1 100644 --- a/Documentation/translations/it_IT/kernel-hacking/hacking.rst +++ b/Documentation/translations/it_IT/kernel-hacking/hacking.rst @@ -755,7 +755,7 @@ anche per avere patch pulite, c'è del lavoro amministrativo da fare: - Solitamente vorrete un'opzione di configurazione per la vostra modifica al kernel. Modificate ``Kconfig`` nella cartella giusta. Il linguaggio Config è facile con copia ed incolla, e c'è una completa documentazione - nel file ``Documentation/kbuild/kconfig-language.txt``. + nel file ``Documentation/kbuild/kconfig-language.rst``. Nella descrizione della vostra opzione, assicuratevi di parlare sia agli utenti esperti sia agli utente che non sanno nulla del vostro lavoro. @@ -767,7 +767,7 @@ anche per avere patch pulite, c'è del lavoro amministrativo da fare: - Modificate il file ``Makefile``: le variabili CONFIG sono esportate qui, quindi potete solitamente aggiungere una riga come la seguete "obj-$(CONFIG_xxx) += xxx.o". La sintassi è documentata nel file - ``Documentation/kbuild/makefiles.txt``. + ``Documentation/kbuild/makefiles.rst``. - Aggiungete voi stessi in ``CREDITS`` se avete fatto qualcosa di notevole, solitamente qualcosa che supera il singolo file (comunque il vostro nome diff --git a/Documentation/translations/it_IT/process/coding-style.rst b/Documentation/translations/it_IT/process/coding-style.rst index a6559d25a23d..8995d2d19f20 100644 --- a/Documentation/translations/it_IT/process/coding-style.rst +++ b/Documentation/translations/it_IT/process/coding-style.rst @@ -696,7 +696,7 @@ nella stringa di titolo:: ... Per la documentazione completa sui file di configurazione, consultate -il documento Documentation/kbuild/kconfig-language.txt +il documento Documentation/kbuild/kconfig-language.rst 11) Strutture dati diff --git a/Documentation/translations/it_IT/process/submit-checklist.rst b/Documentation/translations/it_IT/process/submit-checklist.rst index 70e65a7b3620..ea74cae958d7 100644 --- a/Documentation/translations/it_IT/process/submit-checklist.rst +++ b/Documentation/translations/it_IT/process/submit-checklist.rst @@ -43,7 +43,7 @@ sottomissione delle patch, in particolare 6) Le opzioni ``CONFIG``, nuove o modificate, non scombussolano il menu di configurazione e sono preimpostate come disabilitate a meno che non - soddisfino i criteri descritti in ``Documentation/kbuild/kconfig-language.txt`` + soddisfino i criteri descritti in ``Documentation/kbuild/kconfig-language.rst`` alla punto "Voci di menu: valori predefiniti". 7) Tutte le nuove opzioni ``Kconfig`` hanno un messaggio di aiuto. diff --git a/Documentation/translations/zh_CN/process/coding-style.rst b/Documentation/translations/zh_CN/process/coding-style.rst index 5479c591c2f7..4f6237392e65 100644 --- a/Documentation/translations/zh_CN/process/coding-style.rst +++ b/Documentation/translations/zh_CN/process/coding-style.rst @@ -599,7 +599,7 @@ Documentation/doc-guide/ 和 scripts/kernel-doc 以获得详细信息。 depends on ADFS_FS ... -要查看配置文件的完整文档,请看 Documentation/kbuild/kconfig-language.txt。 +要查看配置文件的完整文档,请看 Documentation/kbuild/kconfig-language.rst。 11) 数据结构 diff --git a/Documentation/translations/zh_CN/process/submit-checklist.rst b/Documentation/translations/zh_CN/process/submit-checklist.rst index 89061aa8fdbe..f4785d2b0491 100644 --- a/Documentation/translations/zh_CN/process/submit-checklist.rst +++ b/Documentation/translations/zh_CN/process/submit-checklist.rst @@ -38,7 +38,7 @@ Linux内核补丁提交清单 违规行为。 6) 任何新的或修改过的 ``CONFIG`` 选项都不会弄脏配置菜单,并默认为关闭,除非 - 它们符合 ``Documentation/kbuild/kconfig-language.txt`` 中记录的异常条件, + 它们符合 ``Documentation/kbuild/kconfig-language.rst`` 中记录的异常条件, 菜单属性:默认值. 7) 所有新的 ``kconfig`` 选项都有帮助文本。 diff --git a/Kconfig b/Kconfig index 990b0c390dfc..e10b3ee084d4 100644 --- a/Kconfig +++ b/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # # For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. +# see Documentation/kbuild/kconfig-language.rst. # mainmenu "Linux/$(ARCH) $(KERNELVERSION) Kernel Configuration" diff --git a/arch/arc/plat-eznps/Kconfig b/arch/arc/plat-eznps/Kconfig index 2eaecfb063a7..a376a50d3fea 100644 --- a/arch/arc/plat-eznps/Kconfig +++ b/arch/arc/plat-eznps/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # # For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. +# see Documentation/kbuild/kconfig-language.rst. # menuconfig ARC_PLAT_EZNPS diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig index eeb0471268a0..c5e6b70e1510 100644 --- a/arch/c6x/Kconfig +++ b/arch/c6x/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # # For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. +# see Documentation/kbuild/kconfig-language.rst. # config C6X diff --git a/arch/microblaze/Kconfig.debug b/arch/microblaze/Kconfig.debug index 3a343188d86c..865527ac332a 100644 --- a/arch/microblaze/Kconfig.debug +++ b/arch/microblaze/Kconfig.debug @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only # For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. +# see Documentation/kbuild/kconfig-language.rst. config TRACE_IRQFLAGS_SUPPORT def_bool y diff --git a/arch/microblaze/Kconfig.platform b/arch/microblaze/Kconfig.platform index 5bf54c1d4f60..7795f90dad86 100644 --- a/arch/microblaze/Kconfig.platform +++ b/arch/microblaze/Kconfig.platform @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only # For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. +# see Documentation/kbuild/kconfig-language.rst. # # Platform selection Kconfig menu for MicroBlaze targets # diff --git a/arch/nds32/Kconfig b/arch/nds32/Kconfig index 3299e287a477..fd0d0639454f 100644 --- a/arch/nds32/Kconfig +++ b/arch/nds32/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only # # For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. +# see Documentation/kbuild/kconfig-language.rst. # config NDS32 diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig index 7cfb20555b10..bf326f0edd2f 100644 --- a/arch/openrisc/Kconfig +++ b/arch/openrisc/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # # For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. +# see Documentation/kbuild/kconfig-language.rst. # config OPENRISC diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index e0dbec780fe9..d23288c4abf6 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. +# see Documentation/kbuild/kconfig-language.rst. # config PPC4xx_PCI_EXPRESS diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 0c4b12205632..be713da93946 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only # # For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. +# see Documentation/kbuild/kconfig-language.rst. # config 64BIT diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index c52c738e554a..dd61fdd400f0 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # # For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. +# see Documentation/kbuild/kconfig-language.rst. # # Auxiliary display drivers configuration. # diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 9026df923542..35078c6f334a 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only # # For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. +# see Documentation/kbuild/kconfig-language.rst. # menu "Firmware Drivers" diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index ef0e476b2525..49abbc52457d 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -48,7 +48,7 @@ config MTD_MS02NV If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), - say M here and read . + say M here and read . The module will be called ms02-nv. config MTD_DATAFLASH diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig index d1b6a78557ec..9e1c3752b200 100644 --- a/drivers/net/ethernet/smsc/Kconfig +++ b/drivers/net/ethernet/smsc/Kconfig @@ -49,7 +49,7 @@ config SMC91X This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called smc91x. If you want to compile it as a - module, say M here and read . + module, say M here and read . config PCMCIA_SMC91C92 tristate "SMC 91Cxx PCMCIA support" @@ -86,7 +86,7 @@ config SMC911X This driver is also available as a module. The module will be called smc911x. If you want to compile it as a module, say M - here and read + here and read config SMSC911X tristate "SMSC LAN911x/LAN921x families embedded ethernet support" @@ -121,6 +121,6 @@ config SMSC9420 This driver is also available as a module. The module will be called smsc9420. If you want to compile it as a module, say M - here and read + here and read endif # NET_VENDOR_SMSC diff --git a/drivers/net/wireless/intel/iwlegacy/Kconfig b/drivers/net/wireless/intel/iwlegacy/Kconfig index aa01c83e0060..e329fd7b09c0 100644 --- a/drivers/net/wireless/intel/iwlegacy/Kconfig +++ b/drivers/net/wireless/intel/iwlegacy/Kconfig @@ -32,7 +32,7 @@ config IWL4965 If you want to compile the driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), - say M here and read . The + say M here and read . The module will be called iwl4965. config IWL3945 @@ -58,7 +58,7 @@ config IWL3945 If you want to compile the driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), - say M here and read . The + say M here and read . The module will be called iwl3945. menu "iwl3945 / iwl4965 Debugging Options" diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig index e5528189163f..235349a33a3c 100644 --- a/drivers/net/wireless/intel/iwlwifi/Kconfig +++ b/drivers/net/wireless/intel/iwlwifi/Kconfig @@ -40,7 +40,7 @@ config IWLWIFI If you want to compile the driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), - say M here and read . The + say M here and read . The module will be called iwlwifi. if IWLWIFI diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index 24189c3399e0..1791830e7a71 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only # # For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. +# see Documentation/kbuild/kconfig-language.rst. # # Parport configuration. # diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 61da513fc0ed..f31b6b780eaf 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -183,7 +183,7 @@ config CHR_DEV_SCH If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), - say M here and read and + say M here and read and . The module will be called ch.o. If unsure, say N. @@ -1474,7 +1474,7 @@ config ZFCP This driver is also available as a module. This module will be called zfcp. If you want to compile it as a module, say M here - and read . + and read . config SCSI_PMCRAID tristate "PMC SIERRA Linux MaxRAID adapter support" diff --git a/drivers/staging/sm750fb/Kconfig b/drivers/staging/sm750fb/Kconfig index fb5a086bf9b1..8c0d8a873d5b 100644 --- a/drivers/staging/sm750fb/Kconfig +++ b/drivers/staging/sm750fb/Kconfig @@ -12,4 +12,4 @@ config FB_SM750 This driver is also available as a module. The module will be called sm750fb. If you want to compile it as a module, say M - here and read . + here and read . diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index c97f270338bf..4a88e1ca25c0 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -16,7 +16,7 @@ config USB_EMI62 This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called audio. If you want to compile it as a - module, say M here and read . + module, say M here and read . config USB_EMI26 tristate "EMI 2|6 USB Audio interface support" @@ -67,7 +67,7 @@ config USB_LEGOTOWER inserted in and removed from the running kernel whenever you want). The module will be called legousbtower. If you want to compile it as a module, say M here and read - . + . config USB_LCD tristate "USB LCD driver support" diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 737b86328c9e..31ba91cb916a 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -289,7 +289,7 @@ config FB_ARMCLCD If you want to compile this as a module (=code which can be inserted into and removed from the running kernel), say M - here and read . The module + here and read . The module will be called amba-clcd. config FB_ACORN @@ -1752,7 +1752,7 @@ config FB_PXA This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). The module will be called pxafb. If you want to compile it as a module, - say M here and read . + say M here and read . If unsure, say N. @@ -1833,7 +1833,7 @@ config FB_W100 This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). The module will be called w100fb. If you want to compile it as a module, - say M here and read . + say M here and read . If unsure, say N. @@ -1862,7 +1862,7 @@ config FB_TMIO This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). The module will be called tmiofb. If you want to compile it as a module, - say M here and read . + say M here and read . If unsure, say N. @@ -1908,7 +1908,7 @@ config FB_S3C2410 This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). The module will be called s3c2410fb. If you want to compile it as a module, - say M here and read . + say M here and read . If unsure, say N. config FB_S3C2410_DEBUG @@ -1945,7 +1945,7 @@ config FB_SM501 This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). The module will be called sm501fb. If you want to compile it as a module, - say M here and read . + say M here and read . If unsure, say N. @@ -2288,7 +2288,7 @@ config FB_SM712 This driver is also available as a module. The module will be called sm712fb. If you want to compile it as a module, say M - here and read . + here and read . source "drivers/video/fbdev/omap/Kconfig" source "drivers/video/fbdev/omap2/Kconfig" diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig index c3ad90c43801..36a98d36d339 100644 --- a/net/bridge/netfilter/Kconfig +++ b/net/bridge/netfilter/Kconfig @@ -114,7 +114,7 @@ config BRIDGE_EBT_LIMIT equivalent of the iptables limit match. If you want to compile it as a module, say M here and read - . If unsure, say `N'. + . If unsure, say `N'. config BRIDGE_EBT_MARK tristate "ebt: mark filter support" diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 3e6494269501..69e76d677f9e 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -308,7 +308,7 @@ config IP_NF_RAW and OUTPUT chains. If you want to compile it as a module, say M here and read - . If unsure, say `N'. + . If unsure, say `N'. # security table for MAC policy config IP_NF_SECURITY diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index f7c6f5be9f76..6120a7800975 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -241,7 +241,7 @@ config IP6_NF_RAW and OUTPUT chains. If you want to compile it as a module, say M here and read - . If unsure, say `N'. + . If unsure, say `N'. # security table for MAC policy config IP6_NF_SECURITY diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 21025c2c605b..dd2af7be3eea 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -1056,7 +1056,7 @@ config NETFILTER_XT_TARGET_TRACE the tables, chains, rules. If you want to compile it as a module, say M here and read - . If unsure, say `N'. + . If unsure, say `N'. config NETFILTER_XT_TARGET_SECMARK tristate '"SECMARK" target support' @@ -1115,7 +1115,7 @@ config NETFILTER_XT_MATCH_ADDRTYPE eg. UNICAST, LOCAL, BROADCAST, ... If you want to compile it as a module, say M here and read - . If unsure, say `N'. + . If unsure, say `N'. config NETFILTER_XT_MATCH_BPF tristate '"bpf" match support' @@ -1160,7 +1160,7 @@ config NETFILTER_XT_MATCH_COMMENT comments in your iptables ruleset. If you want to compile it as a module, say M here and read - . If unsure, say `N'. + . If unsure, say `N'. config NETFILTER_XT_MATCH_CONNBYTES tristate '"connbytes" per-connection counter match support' @@ -1171,7 +1171,7 @@ config NETFILTER_XT_MATCH_CONNBYTES number of bytes and/or packets for each direction within a connection. If you want to compile it as a module, say M here and read - . If unsure, say `N'. + . If unsure, say `N'. config NETFILTER_XT_MATCH_CONNLABEL tristate '"connlabel" match support' @@ -1237,7 +1237,7 @@ config NETFILTER_XT_MATCH_DCCP and DCCP flags. If you want to compile it as a module, say M here and read - . If unsure, say `N'. + . If unsure, say `N'. config NETFILTER_XT_MATCH_DEVGROUP tristate '"devgroup" match support' @@ -1473,7 +1473,7 @@ config NETFILTER_XT_MATCH_QUOTA byte counter. If you want to compile it as a module, say M here and read - . If unsure, say `N'. + . If unsure, say `N'. config NETFILTER_XT_MATCH_RATEEST tristate '"rateest" match support' @@ -1497,7 +1497,7 @@ config NETFILTER_XT_MATCH_REALM in tc world. If you want to compile it as a module, say M here and read - . If unsure, say `N'. + . If unsure, say `N'. config NETFILTER_XT_MATCH_RECENT tristate '"recent" match support' @@ -1519,7 +1519,7 @@ config NETFILTER_XT_MATCH_SCTP and SCTP chunk types. If you want to compile it as a module, say M here and read - . If unsure, say `N'. + . If unsure, say `N'. config NETFILTER_XT_MATCH_SOCKET tristate '"socket" match support' diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig index b93bb7bdb04a..b83e16ade4d2 100644 --- a/net/tipc/Kconfig +++ b/net/tipc/Kconfig @@ -17,7 +17,7 @@ menuconfig TIPC This protocol support is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called tipc. If you want to compile it - as a module, say M here and read . + as a module, say M here and read . If in doubt, say N. diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index f641bb0aa63f..ee58cde8ee3b 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -68,7 +68,7 @@ endef ###### # gcc support functions -# See documentation in Documentation/kbuild/makefiles.txt +# See documentation in Documentation/kbuild/makefiles.rst # cc-cross-prefix # Usage: CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu- m68k-linux-) @@ -210,7 +210,7 @@ objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o))) # if_changed_dep - as if_changed, but uses fixdep to reveal dependencies # including used config symbols # if_changed_rule - as if_changed but execute rule instead -# See Documentation/kbuild/makefiles.txt for more info +# See Documentation/kbuild/makefiles.rst for more info ifneq ($(KBUILD_NOCMDDEP),1) # Check if both arguments are the same including their order. Result is empty diff --git a/scripts/Makefile.host b/scripts/Makefile.host index b6a54bdf0965..a316d368b697 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -6,7 +6,7 @@ # # Both C and C++ are supported, but preferred language is C for such utilities. # -# Sample syntax (see Documentation/kbuild/makefiles.txt for reference) +# Sample syntax (see Documentation/kbuild/makefiles.rst for reference) # hostprogs-y := bin2hex # Will compile bin2hex.c and create an executable named bin2hex # diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 1f9266dadedf..09fd6fa18e1a 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -1114,7 +1114,7 @@ static void sym_check_print_recursive(struct symbol *last_sym) } fprintf(stderr, - "For a resolution refer to Documentation/kbuild/kconfig-language.txt\n" + "For a resolution refer to Documentation/kbuild/kconfig-language.rst\n" "subsection \"Kconfig recursive dependency limitations\"\n" "\n"); diff --git a/scripts/kconfig/tests/err_recursive_dep/expected_stderr b/scripts/kconfig/tests/err_recursive_dep/expected_stderr index 84679b104655..c9f4abf9a791 100644 --- a/scripts/kconfig/tests/err_recursive_dep/expected_stderr +++ b/scripts/kconfig/tests/err_recursive_dep/expected_stderr @@ -1,38 +1,38 @@ Kconfig:11:error: recursive dependency detected! Kconfig:11: symbol B is selected by B -For a resolution refer to Documentation/kbuild/kconfig-language.txt +For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" Kconfig:5:error: recursive dependency detected! Kconfig:5: symbol A depends on A -For a resolution refer to Documentation/kbuild/kconfig-language.txt +For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" Kconfig:17:error: recursive dependency detected! Kconfig:17: symbol C1 depends on C2 Kconfig:21: symbol C2 depends on C1 -For a resolution refer to Documentation/kbuild/kconfig-language.txt +For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" Kconfig:32:error: recursive dependency detected! Kconfig:32: symbol D2 is selected by D1 Kconfig:27: symbol D1 depends on D2 -For a resolution refer to Documentation/kbuild/kconfig-language.txt +For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" Kconfig:37:error: recursive dependency detected! Kconfig:37: symbol E1 depends on E2 Kconfig:42: symbol E2 is implied by E1 -For a resolution refer to Documentation/kbuild/kconfig-language.txt +For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" Kconfig:60:error: recursive dependency detected! Kconfig:60: symbol G depends on G -For a resolution refer to Documentation/kbuild/kconfig-language.txt +For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" Kconfig:51:error: recursive dependency detected! Kconfig:51: symbol F2 depends on F1 Kconfig:49: symbol F1 default value contains F2 -For a resolution refer to Documentation/kbuild/kconfig-language.txt +For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" diff --git a/sound/oss/dmasound/Kconfig b/sound/oss/dmasound/Kconfig index 12e42165b4a5..1a3339859840 100644 --- a/sound/oss/dmasound/Kconfig +++ b/sound/oss/dmasound/Kconfig @@ -11,7 +11,7 @@ config DMASOUND_ATARI This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read - . + . config DMASOUND_PAULA tristate "Amiga DMA sound support" @@ -25,7 +25,7 @@ config DMASOUND_PAULA This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read - . + . config DMASOUND_Q40 tristate "Q40 sound support" @@ -39,7 +39,7 @@ config DMASOUND_Q40 This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read - . + . config DMASOUND tristate -- cgit v1.2.3 From 458f69ef36656dc74679667380422dd8063eabfb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Jun 2019 14:53:00 -0300 Subject: docs: timers: convert docs to ReST and rename to *.rst The conversion here is really trivial: just a bunch of title markups and very few puntual changes is enough to make it to be parsed by Sphinx and generate a nice html. The conversion is actually: - add blank lines and identation in order to identify paragraphs; - fix tables markups; - add some lists markups; - mark literal blocks; - adjust title markups. At its new index.rst, let's add a :orphan: while this is not linked to the main index.rst file, in order to avoid build warnings. Signed-off-by: Mauro Carvalho Chehab Acked-by: Mark Brown Signed-off-by: Jonathan Corbet --- Documentation/timers/NO_HZ.txt | 318 --------------------------------- Documentation/timers/highres.rst | 250 ++++++++++++++++++++++++++ Documentation/timers/highres.txt | 249 -------------------------- Documentation/timers/hpet.rst | 30 ++++ Documentation/timers/hpet.txt | 28 --- Documentation/timers/hrtimers.rst | 178 +++++++++++++++++++ Documentation/timers/hrtimers.txt | 178 ------------------- Documentation/timers/index.rst | 22 +++ Documentation/timers/no_hz.rst | 326 ++++++++++++++++++++++++++++++++++ Documentation/timers/timekeeping.rst | 180 +++++++++++++++++++ Documentation/timers/timekeeping.txt | 179 ------------------- Documentation/timers/timers-howto.rst | 112 ++++++++++++ Documentation/timers/timers-howto.txt | 105 ----------- MAINTAINERS | 2 +- drivers/media/usb/dvb-usb-v2/anysee.c | 2 +- drivers/regulator/core.c | 2 +- include/linux/iopoll.h | 4 +- include/linux/regmap.h | 4 +- scripts/checkpatch.pl | 8 +- sound/soc/sof/ops.h | 2 +- 20 files changed, 1110 insertions(+), 1069 deletions(-) delete mode 100644 Documentation/timers/NO_HZ.txt create mode 100644 Documentation/timers/highres.rst delete mode 100644 Documentation/timers/highres.txt create mode 100644 Documentation/timers/hpet.rst delete mode 100644 Documentation/timers/hpet.txt create mode 100644 Documentation/timers/hrtimers.rst delete mode 100644 Documentation/timers/hrtimers.txt create mode 100644 Documentation/timers/index.rst create mode 100644 Documentation/timers/no_hz.rst create mode 100644 Documentation/timers/timekeeping.rst delete mode 100644 Documentation/timers/timekeeping.txt create mode 100644 Documentation/timers/timers-howto.rst delete mode 100644 Documentation/timers/timers-howto.txt (limited to 'sound') diff --git a/Documentation/timers/NO_HZ.txt b/Documentation/timers/NO_HZ.txt deleted file mode 100644 index 9591092da5e0..000000000000 --- a/Documentation/timers/NO_HZ.txt +++ /dev/null @@ -1,318 +0,0 @@ - NO_HZ: Reducing Scheduling-Clock Ticks - - -This document describes Kconfig options and boot parameters that can -reduce the number of scheduling-clock interrupts, thereby improving energy -efficiency and reducing OS jitter. Reducing OS jitter is important for -some types of computationally intensive high-performance computing (HPC) -applications and for real-time applications. - -There are three main ways of managing scheduling-clock interrupts -(also known as "scheduling-clock ticks" or simply "ticks"): - -1. Never omit scheduling-clock ticks (CONFIG_HZ_PERIODIC=y or - CONFIG_NO_HZ=n for older kernels). You normally will -not- - want to choose this option. - -2. Omit scheduling-clock ticks on idle CPUs (CONFIG_NO_HZ_IDLE=y or - CONFIG_NO_HZ=y for older kernels). This is the most common - approach, and should be the default. - -3. Omit scheduling-clock ticks on CPUs that are either idle or that - have only one runnable task (CONFIG_NO_HZ_FULL=y). Unless you - are running realtime applications or certain types of HPC - workloads, you will normally -not- want this option. - -These three cases are described in the following three sections, followed -by a third section on RCU-specific considerations, a fourth section -discussing testing, and a fifth and final section listing known issues. - - -NEVER OMIT SCHEDULING-CLOCK TICKS - -Very old versions of Linux from the 1990s and the very early 2000s -are incapable of omitting scheduling-clock ticks. It turns out that -there are some situations where this old-school approach is still the -right approach, for example, in heavy workloads with lots of tasks -that use short bursts of CPU, where there are very frequent idle -periods, but where these idle periods are also quite short (tens or -hundreds of microseconds). For these types of workloads, scheduling -clock interrupts will normally be delivered any way because there -will frequently be multiple runnable tasks per CPU. In these cases, -attempting to turn off the scheduling clock interrupt will have no effect -other than increasing the overhead of switching to and from idle and -transitioning between user and kernel execution. - -This mode of operation can be selected using CONFIG_HZ_PERIODIC=y (or -CONFIG_NO_HZ=n for older kernels). - -However, if you are instead running a light workload with long idle -periods, failing to omit scheduling-clock interrupts will result in -excessive power consumption. This is especially bad on battery-powered -devices, where it results in extremely short battery lifetimes. If you -are running light workloads, you should therefore read the following -section. - -In addition, if you are running either a real-time workload or an HPC -workload with short iterations, the scheduling-clock interrupts can -degrade your applications performance. If this describes your workload, -you should read the following two sections. - - -OMIT SCHEDULING-CLOCK TICKS FOR IDLE CPUs - -If a CPU is idle, there is little point in sending it a scheduling-clock -interrupt. After all, the primary purpose of a scheduling-clock interrupt -is to force a busy CPU to shift its attention among multiple duties, -and an idle CPU has no duties to shift its attention among. - -The CONFIG_NO_HZ_IDLE=y Kconfig option causes the kernel to avoid sending -scheduling-clock interrupts to idle CPUs, which is critically important -both to battery-powered devices and to highly virtualized mainframes. -A battery-powered device running a CONFIG_HZ_PERIODIC=y kernel would -drain its battery very quickly, easily 2-3 times as fast as would the -same device running a CONFIG_NO_HZ_IDLE=y kernel. A mainframe running -1,500 OS instances might find that half of its CPU time was consumed by -unnecessary scheduling-clock interrupts. In these situations, there -is strong motivation to avoid sending scheduling-clock interrupts to -idle CPUs. That said, dyntick-idle mode is not free: - -1. It increases the number of instructions executed on the path - to and from the idle loop. - -2. On many architectures, dyntick-idle mode also increases the - number of expensive clock-reprogramming operations. - -Therefore, systems with aggressive real-time response constraints often -run CONFIG_HZ_PERIODIC=y kernels (or CONFIG_NO_HZ=n for older kernels) -in order to avoid degrading from-idle transition latencies. - -An idle CPU that is not receiving scheduling-clock interrupts is said to -be "dyntick-idle", "in dyntick-idle mode", "in nohz mode", or "running -tickless". The remainder of this document will use "dyntick-idle mode". - -There is also a boot parameter "nohz=" that can be used to disable -dyntick-idle mode in CONFIG_NO_HZ_IDLE=y kernels by specifying "nohz=off". -By default, CONFIG_NO_HZ_IDLE=y kernels boot with "nohz=on", enabling -dyntick-idle mode. - - -OMIT SCHEDULING-CLOCK TICKS FOR CPUs WITH ONLY ONE RUNNABLE TASK - -If a CPU has only one runnable task, there is little point in sending it -a scheduling-clock interrupt because there is no other task to switch to. -Note that omitting scheduling-clock ticks for CPUs with only one runnable -task implies also omitting them for idle CPUs. - -The CONFIG_NO_HZ_FULL=y Kconfig option causes the kernel to avoid -sending scheduling-clock interrupts to CPUs with a single runnable task, -and such CPUs are said to be "adaptive-ticks CPUs". This is important -for applications with aggressive real-time response constraints because -it allows them to improve their worst-case response times by the maximum -duration of a scheduling-clock interrupt. It is also important for -computationally intensive short-iteration workloads: If any CPU is -delayed during a given iteration, all the other CPUs will be forced to -wait idle while the delayed CPU finishes. Thus, the delay is multiplied -by one less than the number of CPUs. In these situations, there is -again strong motivation to avoid sending scheduling-clock interrupts. - -By default, no CPU will be an adaptive-ticks CPU. The "nohz_full=" -boot parameter specifies the adaptive-ticks CPUs. For example, -"nohz_full=1,6-8" says that CPUs 1, 6, 7, and 8 are to be adaptive-ticks -CPUs. Note that you are prohibited from marking all of the CPUs as -adaptive-tick CPUs: At least one non-adaptive-tick CPU must remain -online to handle timekeeping tasks in order to ensure that system -calls like gettimeofday() returns accurate values on adaptive-tick CPUs. -(This is not an issue for CONFIG_NO_HZ_IDLE=y because there are no running -user processes to observe slight drifts in clock rate.) Therefore, the -boot CPU is prohibited from entering adaptive-ticks mode. Specifying a -"nohz_full=" mask that includes the boot CPU will result in a boot-time -error message, and the boot CPU will be removed from the mask. Note that -this means that your system must have at least two CPUs in order for -CONFIG_NO_HZ_FULL=y to do anything for you. - -Finally, adaptive-ticks CPUs must have their RCU callbacks offloaded. -This is covered in the "RCU IMPLICATIONS" section below. - -Normally, a CPU remains in adaptive-ticks mode as long as possible. -In particular, transitioning to kernel mode does not automatically change -the mode. Instead, the CPU will exit adaptive-ticks mode only if needed, -for example, if that CPU enqueues an RCU callback. - -Just as with dyntick-idle mode, the benefits of adaptive-tick mode do -not come for free: - -1. CONFIG_NO_HZ_FULL selects CONFIG_NO_HZ_COMMON, so you cannot run - adaptive ticks without also running dyntick idle. This dependency - extends down into the implementation, so that all of the costs - of CONFIG_NO_HZ_IDLE are also incurred by CONFIG_NO_HZ_FULL. - -2. The user/kernel transitions are slightly more expensive due - to the need to inform kernel subsystems (such as RCU) about - the change in mode. - -3. POSIX CPU timers prevent CPUs from entering adaptive-tick mode. - Real-time applications needing to take actions based on CPU time - consumption need to use other means of doing so. - -4. If there are more perf events pending than the hardware can - accommodate, they are normally round-robined so as to collect - all of them over time. Adaptive-tick mode may prevent this - round-robining from happening. This will likely be fixed by - preventing CPUs with large numbers of perf events pending from - entering adaptive-tick mode. - -5. Scheduler statistics for adaptive-tick CPUs may be computed - slightly differently than those for non-adaptive-tick CPUs. - This might in turn perturb load-balancing of real-time tasks. - -6. The LB_BIAS scheduler feature is disabled by adaptive ticks. - -Although improvements are expected over time, adaptive ticks is quite -useful for many types of real-time and compute-intensive applications. -However, the drawbacks listed above mean that adaptive ticks should not -(yet) be enabled by default. - - -RCU IMPLICATIONS - -There are situations in which idle CPUs cannot be permitted to -enter either dyntick-idle mode or adaptive-tick mode, the most -common being when that CPU has RCU callbacks pending. - -The CONFIG_RCU_FAST_NO_HZ=y Kconfig option may be used to cause such CPUs -to enter dyntick-idle mode or adaptive-tick mode anyway. In this case, -a timer will awaken these CPUs every four jiffies in order to ensure -that the RCU callbacks are processed in a timely fashion. - -Another approach is to offload RCU callback processing to "rcuo" kthreads -using the CONFIG_RCU_NOCB_CPU=y Kconfig option. The specific CPUs to -offload may be selected using The "rcu_nocbs=" kernel boot parameter, -which takes a comma-separated list of CPUs and CPU ranges, for example, -"1,3-5" selects CPUs 1, 3, 4, and 5. - -The offloaded CPUs will never queue RCU callbacks, and therefore RCU -never prevents offloaded CPUs from entering either dyntick-idle mode -or adaptive-tick mode. That said, note that it is up to userspace to -pin the "rcuo" kthreads to specific CPUs if desired. Otherwise, the -scheduler will decide where to run them, which might or might not be -where you want them to run. - - -TESTING - -So you enable all the OS-jitter features described in this document, -but do not see any change in your workload's behavior. Is this because -your workload isn't affected that much by OS jitter, or is it because -something else is in the way? This section helps answer this question -by providing a simple OS-jitter test suite, which is available on branch -master of the following git archive: - -git://git.kernel.org/pub/scm/linux/kernel/git/frederic/dynticks-testing.git - -Clone this archive and follow the instructions in the README file. -This test procedure will produce a trace that will allow you to evaluate -whether or not you have succeeded in removing OS jitter from your system. -If this trace shows that you have removed OS jitter as much as is -possible, then you can conclude that your workload is not all that -sensitive to OS jitter. - -Note: this test requires that your system have at least two CPUs. -We do not currently have a good way to remove OS jitter from single-CPU -systems. - - -KNOWN ISSUES - -o Dyntick-idle slows transitions to and from idle slightly. - In practice, this has not been a problem except for the most - aggressive real-time workloads, which have the option of disabling - dyntick-idle mode, an option that most of them take. However, - some workloads will no doubt want to use adaptive ticks to - eliminate scheduling-clock interrupt latencies. Here are some - options for these workloads: - - a. Use PMQOS from userspace to inform the kernel of your - latency requirements (preferred). - - b. On x86 systems, use the "idle=mwait" boot parameter. - - c. On x86 systems, use the "intel_idle.max_cstate=" to limit - ` the maximum C-state depth. - - d. On x86 systems, use the "idle=poll" boot parameter. - However, please note that use of this parameter can cause - your CPU to overheat, which may cause thermal throttling - to degrade your latencies -- and that this degradation can - be even worse than that of dyntick-idle. Furthermore, - this parameter effectively disables Turbo Mode on Intel - CPUs, which can significantly reduce maximum performance. - -o Adaptive-ticks slows user/kernel transitions slightly. - This is not expected to be a problem for computationally intensive - workloads, which have few such transitions. Careful benchmarking - will be required to determine whether or not other workloads - are significantly affected by this effect. - -o Adaptive-ticks does not do anything unless there is only one - runnable task for a given CPU, even though there are a number - of other situations where the scheduling-clock tick is not - needed. To give but one example, consider a CPU that has one - runnable high-priority SCHED_FIFO task and an arbitrary number - of low-priority SCHED_OTHER tasks. In this case, the CPU is - required to run the SCHED_FIFO task until it either blocks or - some other higher-priority task awakens on (or is assigned to) - this CPU, so there is no point in sending a scheduling-clock - interrupt to this CPU. However, the current implementation - nevertheless sends scheduling-clock interrupts to CPUs having a - single runnable SCHED_FIFO task and multiple runnable SCHED_OTHER - tasks, even though these interrupts are unnecessary. - - And even when there are multiple runnable tasks on a given CPU, - there is little point in interrupting that CPU until the current - running task's timeslice expires, which is almost always way - longer than the time of the next scheduling-clock interrupt. - - Better handling of these sorts of situations is future work. - -o A reboot is required to reconfigure both adaptive idle and RCU - callback offloading. Runtime reconfiguration could be provided - if needed, however, due to the complexity of reconfiguring RCU at - runtime, there would need to be an earthshakingly good reason. - Especially given that you have the straightforward option of - simply offloading RCU callbacks from all CPUs and pinning them - where you want them whenever you want them pinned. - -o Additional configuration is required to deal with other sources - of OS jitter, including interrupts and system-utility tasks - and processes. This configuration normally involves binding - interrupts and tasks to particular CPUs. - -o Some sources of OS jitter can currently be eliminated only by - constraining the workload. For example, the only way to eliminate - OS jitter due to global TLB shootdowns is to avoid the unmapping - operations (such as kernel module unload operations) that - result in these shootdowns. For another example, page faults - and TLB misses can be reduced (and in some cases eliminated) by - using huge pages and by constraining the amount of memory used - by the application. Pre-faulting the working set can also be - helpful, especially when combined with the mlock() and mlockall() - system calls. - -o Unless all CPUs are idle, at least one CPU must keep the - scheduling-clock interrupt going in order to support accurate - timekeeping. - -o If there might potentially be some adaptive-ticks CPUs, there - will be at least one CPU keeping the scheduling-clock interrupt - going, even if all CPUs are otherwise idle. - - Better handling of this situation is ongoing work. - -o Some process-handling operations still require the occasional - scheduling-clock tick. These operations include calculating CPU - load, maintaining sched average, computing CFS entity vruntime, - computing avenrun, and carrying out load balancing. They are - currently accommodated by scheduling-clock tick every second - or so. On-going work will eliminate the need even for these - infrequent scheduling-clock ticks. diff --git a/Documentation/timers/highres.rst b/Documentation/timers/highres.rst new file mode 100644 index 000000000000..bde5eb7e5c9e --- /dev/null +++ b/Documentation/timers/highres.rst @@ -0,0 +1,250 @@ +===================================================== +High resolution timers and dynamic ticks design notes +===================================================== + +Further information can be found in the paper of the OLS 2006 talk "hrtimers +and beyond". The paper is part of the OLS 2006 Proceedings Volume 1, which can +be found on the OLS website: +https://www.kernel.org/doc/ols/2006/ols2006v1-pages-333-346.pdf + +The slides to this talk are available from: +http://www.cs.columbia.edu/~nahum/w6998/papers/ols2006-hrtimers-slides.pdf + +The slides contain five figures (pages 2, 15, 18, 20, 22), which illustrate the +changes in the time(r) related Linux subsystems. Figure #1 (p. 2) shows the +design of the Linux time(r) system before hrtimers and other building blocks +got merged into mainline. + +Note: the paper and the slides are talking about "clock event source", while we +switched to the name "clock event devices" in meantime. + +The design contains the following basic building blocks: + +- hrtimer base infrastructure +- timeofday and clock source management +- clock event management +- high resolution timer functionality +- dynamic ticks + + +hrtimer base infrastructure +--------------------------- + +The hrtimer base infrastructure was merged into the 2.6.16 kernel. Details of +the base implementation are covered in Documentation/timers/hrtimers.rst. See +also figure #2 (OLS slides p. 15) + +The main differences to the timer wheel, which holds the armed timer_list type +timers are: + + - time ordered enqueueing into a rb-tree + - independent of ticks (the processing is based on nanoseconds) + + +timeofday and clock source management +------------------------------------- + +John Stultz's Generic Time Of Day (GTOD) framework moves a large portion of +code out of the architecture-specific areas into a generic management +framework, as illustrated in figure #3 (OLS slides p. 18). The architecture +specific portion is reduced to the low level hardware details of the clock +sources, which are registered in the framework and selected on a quality based +decision. The low level code provides hardware setup and readout routines and +initializes data structures, which are used by the generic time keeping code to +convert the clock ticks to nanosecond based time values. All other time keeping +related functionality is moved into the generic code. The GTOD base patch got +merged into the 2.6.18 kernel. + +Further information about the Generic Time Of Day framework is available in the +OLS 2005 Proceedings Volume 1: + + http://www.linuxsymposium.org/2005/linuxsymposium_procv1.pdf + +The paper "We Are Not Getting Any Younger: A New Approach to Time and +Timers" was written by J. Stultz, D.V. Hart, & N. Aravamudan. + +Figure #3 (OLS slides p.18) illustrates the transformation. + + +clock event management +---------------------- + +While clock sources provide read access to the monotonically increasing time +value, clock event devices are used to schedule the next event +interrupt(s). The next event is currently defined to be periodic, with its +period defined at compile time. The setup and selection of the event device +for various event driven functionalities is hardwired into the architecture +dependent code. This results in duplicated code across all architectures and +makes it extremely difficult to change the configuration of the system to use +event interrupt devices other than those already built into the +architecture. Another implication of the current design is that it is necessary +to touch all the architecture-specific implementations in order to provide new +functionality like high resolution timers or dynamic ticks. + +The clock events subsystem tries to address this problem by providing a generic +solution to manage clock event devices and their usage for the various clock +event driven kernel functionalities. The goal of the clock event subsystem is +to minimize the clock event related architecture dependent code to the pure +hardware related handling and to allow easy addition and utilization of new +clock event devices. It also minimizes the duplicated code across the +architectures as it provides generic functionality down to the interrupt +service handler, which is almost inherently hardware dependent. + +Clock event devices are registered either by the architecture dependent boot +code or at module insertion time. Each clock event device fills a data +structure with clock-specific property parameters and callback functions. The +clock event management decides, by using the specified property parameters, the +set of system functions a clock event device will be used to support. This +includes the distinction of per-CPU and per-system global event devices. + +System-level global event devices are used for the Linux periodic tick. Per-CPU +event devices are used to provide local CPU functionality such as process +accounting, profiling, and high resolution timers. + +The management layer assigns one or more of the following functions to a clock +event device: + + - system global periodic tick (jiffies update) + - cpu local update_process_times + - cpu local profiling + - cpu local next event interrupt (non periodic mode) + +The clock event device delegates the selection of those timer interrupt related +functions completely to the management layer. The clock management layer stores +a function pointer in the device description structure, which has to be called +from the hardware level handler. This removes a lot of duplicated code from the +architecture specific timer interrupt handlers and hands the control over the +clock event devices and the assignment of timer interrupt related functionality +to the core code. + +The clock event layer API is rather small. Aside from the clock event device +registration interface it provides functions to schedule the next event +interrupt, clock event device notification service and support for suspend and +resume. + +The framework adds about 700 lines of code which results in a 2KB increase of +the kernel binary size. The conversion of i386 removes about 100 lines of +code. The binary size decrease is in the range of 400 byte. We believe that the +increase of flexibility and the avoidance of duplicated code across +architectures justifies the slight increase of the binary size. + +The conversion of an architecture has no functional impact, but allows to +utilize the high resolution and dynamic tick functionalities without any change +to the clock event device and timer interrupt code. After the conversion the +enabling of high resolution timers and dynamic ticks is simply provided by +adding the kernel/time/Kconfig file to the architecture specific Kconfig and +adding the dynamic tick specific calls to the idle routine (a total of 3 lines +added to the idle function and the Kconfig file) + +Figure #4 (OLS slides p.20) illustrates the transformation. + + +high resolution timer functionality +----------------------------------- + +During system boot it is not possible to use the high resolution timer +functionality, while making it possible would be difficult and would serve no +useful function. The initialization of the clock event device framework, the +clock source framework (GTOD) and hrtimers itself has to be done and +appropriate clock sources and clock event devices have to be registered before +the high resolution functionality can work. Up to the point where hrtimers are +initialized, the system works in the usual low resolution periodic mode. The +clock source and the clock event device layers provide notification functions +which inform hrtimers about availability of new hardware. hrtimers validates +the usability of the registered clock sources and clock event devices before +switching to high resolution mode. This ensures also that a kernel which is +configured for high resolution timers can run on a system which lacks the +necessary hardware support. + +The high resolution timer code does not support SMP machines which have only +global clock event devices. The support of such hardware would involve IPI +calls when an interrupt happens. The overhead would be much larger than the +benefit. This is the reason why we currently disable high resolution and +dynamic ticks on i386 SMP systems which stop the local APIC in C3 power +state. A workaround is available as an idea, but the problem has not been +tackled yet. + +The time ordered insertion of timers provides all the infrastructure to decide +whether the event device has to be reprogrammed when a timer is added. The +decision is made per timer base and synchronized across per-cpu timer bases in +a support function. The design allows the system to utilize separate per-CPU +clock event devices for the per-CPU timer bases, but currently only one +reprogrammable clock event device per-CPU is utilized. + +When the timer interrupt happens, the next event interrupt handler is called +from the clock event distribution code and moves expired timers from the +red-black tree to a separate double linked list and invokes the softirq +handler. An additional mode field in the hrtimer structure allows the system to +execute callback functions directly from the next event interrupt handler. This +is restricted to code which can safely be executed in the hard interrupt +context. This applies, for example, to the common case of a wakeup function as +used by nanosleep. The advantage of executing the handler in the interrupt +context is the avoidance of up to two context switches - from the interrupted +context to the softirq and to the task which is woken up by the expired +timer. + +Once a system has switched to high resolution mode, the periodic tick is +switched off. This disables the per system global periodic clock event device - +e.g. the PIT on i386 SMP systems. + +The periodic tick functionality is provided by an per-cpu hrtimer. The callback +function is executed in the next event interrupt context and updates jiffies +and calls update_process_times and profiling. The implementation of the hrtimer +based periodic tick is designed to be extended with dynamic tick functionality. +This allows to use a single clock event device to schedule high resolution +timer and periodic events (jiffies tick, profiling, process accounting) on UP +systems. This has been proved to work with the PIT on i386 and the Incrementer +on PPC. + +The softirq for running the hrtimer queues and executing the callbacks has been +separated from the tick bound timer softirq to allow accurate delivery of high +resolution timer signals which are used by itimer and POSIX interval +timers. The execution of this softirq can still be delayed by other softirqs, +but the overall latencies have been significantly improved by this separation. + +Figure #5 (OLS slides p.22) illustrates the transformation. + + +dynamic ticks +------------- + +Dynamic ticks are the logical consequence of the hrtimer based periodic tick +replacement (sched_tick). The functionality of the sched_tick hrtimer is +extended by three functions: + +- hrtimer_stop_sched_tick +- hrtimer_restart_sched_tick +- hrtimer_update_jiffies + +hrtimer_stop_sched_tick() is called when a CPU goes into idle state. The code +evaluates the next scheduled timer event (from both hrtimers and the timer +wheel) and in case that the next event is further away than the next tick it +reprograms the sched_tick to this future event, to allow longer idle sleeps +without worthless interruption by the periodic tick. The function is also +called when an interrupt happens during the idle period, which does not cause a +reschedule. The call is necessary as the interrupt handler might have armed a +new timer whose expiry time is before the time which was identified as the +nearest event in the previous call to hrtimer_stop_sched_tick. + +hrtimer_restart_sched_tick() is called when the CPU leaves the idle state before +it calls schedule(). hrtimer_restart_sched_tick() resumes the periodic tick, +which is kept active until the next call to hrtimer_stop_sched_tick(). + +hrtimer_update_jiffies() is called from irq_enter() when an interrupt happens +in the idle period to make sure that jiffies are up to date and the interrupt +handler has not to deal with an eventually stale jiffy value. + +The dynamic tick feature provides statistical values which are exported to +userspace via /proc/stat and can be made available for enhanced power +management control. + +The implementation leaves room for further development like full tickless +systems, where the time slice is controlled by the scheduler, variable +frequency profiling, and a complete removal of jiffies in the future. + + +Aside the current initial submission of i386 support, the patchset has been +extended to x86_64 and ARM already. Initial (work in progress) support is also +available for MIPS and PowerPC. + + Thomas, Ingo diff --git a/Documentation/timers/highres.txt b/Documentation/timers/highres.txt deleted file mode 100644 index 8f9741592123..000000000000 --- a/Documentation/timers/highres.txt +++ /dev/null @@ -1,249 +0,0 @@ -High resolution timers and dynamic ticks design notes ------------------------------------------------------ - -Further information can be found in the paper of the OLS 2006 talk "hrtimers -and beyond". The paper is part of the OLS 2006 Proceedings Volume 1, which can -be found on the OLS website: -https://www.kernel.org/doc/ols/2006/ols2006v1-pages-333-346.pdf - -The slides to this talk are available from: -http://www.cs.columbia.edu/~nahum/w6998/papers/ols2006-hrtimers-slides.pdf - -The slides contain five figures (pages 2, 15, 18, 20, 22), which illustrate the -changes in the time(r) related Linux subsystems. Figure #1 (p. 2) shows the -design of the Linux time(r) system before hrtimers and other building blocks -got merged into mainline. - -Note: the paper and the slides are talking about "clock event source", while we -switched to the name "clock event devices" in meantime. - -The design contains the following basic building blocks: - -- hrtimer base infrastructure -- timeofday and clock source management -- clock event management -- high resolution timer functionality -- dynamic ticks - - -hrtimer base infrastructure ---------------------------- - -The hrtimer base infrastructure was merged into the 2.6.16 kernel. Details of -the base implementation are covered in Documentation/timers/hrtimers.txt. See -also figure #2 (OLS slides p. 15) - -The main differences to the timer wheel, which holds the armed timer_list type -timers are: - - time ordered enqueueing into a rb-tree - - independent of ticks (the processing is based on nanoseconds) - - -timeofday and clock source management -------------------------------------- - -John Stultz's Generic Time Of Day (GTOD) framework moves a large portion of -code out of the architecture-specific areas into a generic management -framework, as illustrated in figure #3 (OLS slides p. 18). The architecture -specific portion is reduced to the low level hardware details of the clock -sources, which are registered in the framework and selected on a quality based -decision. The low level code provides hardware setup and readout routines and -initializes data structures, which are used by the generic time keeping code to -convert the clock ticks to nanosecond based time values. All other time keeping -related functionality is moved into the generic code. The GTOD base patch got -merged into the 2.6.18 kernel. - -Further information about the Generic Time Of Day framework is available in the -OLS 2005 Proceedings Volume 1: -http://www.linuxsymposium.org/2005/linuxsymposium_procv1.pdf - -The paper "We Are Not Getting Any Younger: A New Approach to Time and -Timers" was written by J. Stultz, D.V. Hart, & N. Aravamudan. - -Figure #3 (OLS slides p.18) illustrates the transformation. - - -clock event management ----------------------- - -While clock sources provide read access to the monotonically increasing time -value, clock event devices are used to schedule the next event -interrupt(s). The next event is currently defined to be periodic, with its -period defined at compile time. The setup and selection of the event device -for various event driven functionalities is hardwired into the architecture -dependent code. This results in duplicated code across all architectures and -makes it extremely difficult to change the configuration of the system to use -event interrupt devices other than those already built into the -architecture. Another implication of the current design is that it is necessary -to touch all the architecture-specific implementations in order to provide new -functionality like high resolution timers or dynamic ticks. - -The clock events subsystem tries to address this problem by providing a generic -solution to manage clock event devices and their usage for the various clock -event driven kernel functionalities. The goal of the clock event subsystem is -to minimize the clock event related architecture dependent code to the pure -hardware related handling and to allow easy addition and utilization of new -clock event devices. It also minimizes the duplicated code across the -architectures as it provides generic functionality down to the interrupt -service handler, which is almost inherently hardware dependent. - -Clock event devices are registered either by the architecture dependent boot -code or at module insertion time. Each clock event device fills a data -structure with clock-specific property parameters and callback functions. The -clock event management decides, by using the specified property parameters, the -set of system functions a clock event device will be used to support. This -includes the distinction of per-CPU and per-system global event devices. - -System-level global event devices are used for the Linux periodic tick. Per-CPU -event devices are used to provide local CPU functionality such as process -accounting, profiling, and high resolution timers. - -The management layer assigns one or more of the following functions to a clock -event device: - - system global periodic tick (jiffies update) - - cpu local update_process_times - - cpu local profiling - - cpu local next event interrupt (non periodic mode) - -The clock event device delegates the selection of those timer interrupt related -functions completely to the management layer. The clock management layer stores -a function pointer in the device description structure, which has to be called -from the hardware level handler. This removes a lot of duplicated code from the -architecture specific timer interrupt handlers and hands the control over the -clock event devices and the assignment of timer interrupt related functionality -to the core code. - -The clock event layer API is rather small. Aside from the clock event device -registration interface it provides functions to schedule the next event -interrupt, clock event device notification service and support for suspend and -resume. - -The framework adds about 700 lines of code which results in a 2KB increase of -the kernel binary size. The conversion of i386 removes about 100 lines of -code. The binary size decrease is in the range of 400 byte. We believe that the -increase of flexibility and the avoidance of duplicated code across -architectures justifies the slight increase of the binary size. - -The conversion of an architecture has no functional impact, but allows to -utilize the high resolution and dynamic tick functionalities without any change -to the clock event device and timer interrupt code. After the conversion the -enabling of high resolution timers and dynamic ticks is simply provided by -adding the kernel/time/Kconfig file to the architecture specific Kconfig and -adding the dynamic tick specific calls to the idle routine (a total of 3 lines -added to the idle function and the Kconfig file) - -Figure #4 (OLS slides p.20) illustrates the transformation. - - -high resolution timer functionality ------------------------------------ - -During system boot it is not possible to use the high resolution timer -functionality, while making it possible would be difficult and would serve no -useful function. The initialization of the clock event device framework, the -clock source framework (GTOD) and hrtimers itself has to be done and -appropriate clock sources and clock event devices have to be registered before -the high resolution functionality can work. Up to the point where hrtimers are -initialized, the system works in the usual low resolution periodic mode. The -clock source and the clock event device layers provide notification functions -which inform hrtimers about availability of new hardware. hrtimers validates -the usability of the registered clock sources and clock event devices before -switching to high resolution mode. This ensures also that a kernel which is -configured for high resolution timers can run on a system which lacks the -necessary hardware support. - -The high resolution timer code does not support SMP machines which have only -global clock event devices. The support of such hardware would involve IPI -calls when an interrupt happens. The overhead would be much larger than the -benefit. This is the reason why we currently disable high resolution and -dynamic ticks on i386 SMP systems which stop the local APIC in C3 power -state. A workaround is available as an idea, but the problem has not been -tackled yet. - -The time ordered insertion of timers provides all the infrastructure to decide -whether the event device has to be reprogrammed when a timer is added. The -decision is made per timer base and synchronized across per-cpu timer bases in -a support function. The design allows the system to utilize separate per-CPU -clock event devices for the per-CPU timer bases, but currently only one -reprogrammable clock event device per-CPU is utilized. - -When the timer interrupt happens, the next event interrupt handler is called -from the clock event distribution code and moves expired timers from the -red-black tree to a separate double linked list and invokes the softirq -handler. An additional mode field in the hrtimer structure allows the system to -execute callback functions directly from the next event interrupt handler. This -is restricted to code which can safely be executed in the hard interrupt -context. This applies, for example, to the common case of a wakeup function as -used by nanosleep. The advantage of executing the handler in the interrupt -context is the avoidance of up to two context switches - from the interrupted -context to the softirq and to the task which is woken up by the expired -timer. - -Once a system has switched to high resolution mode, the periodic tick is -switched off. This disables the per system global periodic clock event device - -e.g. the PIT on i386 SMP systems. - -The periodic tick functionality is provided by an per-cpu hrtimer. The callback -function is executed in the next event interrupt context and updates jiffies -and calls update_process_times and profiling. The implementation of the hrtimer -based periodic tick is designed to be extended with dynamic tick functionality. -This allows to use a single clock event device to schedule high resolution -timer and periodic events (jiffies tick, profiling, process accounting) on UP -systems. This has been proved to work with the PIT on i386 and the Incrementer -on PPC. - -The softirq for running the hrtimer queues and executing the callbacks has been -separated from the tick bound timer softirq to allow accurate delivery of high -resolution timer signals which are used by itimer and POSIX interval -timers. The execution of this softirq can still be delayed by other softirqs, -but the overall latencies have been significantly improved by this separation. - -Figure #5 (OLS slides p.22) illustrates the transformation. - - -dynamic ticks -------------- - -Dynamic ticks are the logical consequence of the hrtimer based periodic tick -replacement (sched_tick). The functionality of the sched_tick hrtimer is -extended by three functions: - -- hrtimer_stop_sched_tick -- hrtimer_restart_sched_tick -- hrtimer_update_jiffies - -hrtimer_stop_sched_tick() is called when a CPU goes into idle state. The code -evaluates the next scheduled timer event (from both hrtimers and the timer -wheel) and in case that the next event is further away than the next tick it -reprograms the sched_tick to this future event, to allow longer idle sleeps -without worthless interruption by the periodic tick. The function is also -called when an interrupt happens during the idle period, which does not cause a -reschedule. The call is necessary as the interrupt handler might have armed a -new timer whose expiry time is before the time which was identified as the -nearest event in the previous call to hrtimer_stop_sched_tick. - -hrtimer_restart_sched_tick() is called when the CPU leaves the idle state before -it calls schedule(). hrtimer_restart_sched_tick() resumes the periodic tick, -which is kept active until the next call to hrtimer_stop_sched_tick(). - -hrtimer_update_jiffies() is called from irq_enter() when an interrupt happens -in the idle period to make sure that jiffies are up to date and the interrupt -handler has not to deal with an eventually stale jiffy value. - -The dynamic tick feature provides statistical values which are exported to -userspace via /proc/stat and can be made available for enhanced power -management control. - -The implementation leaves room for further development like full tickless -systems, where the time slice is controlled by the scheduler, variable -frequency profiling, and a complete removal of jiffies in the future. - - -Aside the current initial submission of i386 support, the patchset has been -extended to x86_64 and ARM already. Initial (work in progress) support is also -available for MIPS and PowerPC. - - Thomas, Ingo - - - diff --git a/Documentation/timers/hpet.rst b/Documentation/timers/hpet.rst new file mode 100644 index 000000000000..c9d05d3caaca --- /dev/null +++ b/Documentation/timers/hpet.rst @@ -0,0 +1,30 @@ +=========================================== +High Precision Event Timer Driver for Linux +=========================================== + +The High Precision Event Timer (HPET) hardware follows a specification +by Intel and Microsoft, revision 1. + +Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision") +and up to 32 comparators. Normally three or more comparators are provided, +each of which can generate oneshot interrupts and at least one of which has +additional hardware to support periodic interrupts. The comparators are +also called "timers", which can be misleading since usually timers are +independent of each other ... these share a counter, complicating resets. + +HPET devices can support two interrupt routing modes. In one mode, the +comparators are additional interrupt sources with no particular system +role. Many x86 BIOS writers don't route HPET interrupts at all, which +prevents use of that mode. They support the other "legacy replacement" +mode where the first two comparators block interrupts from 8254 timers +and from the RTC. + +The driver supports detection of HPET driver allocation and initialization +of the HPET before the driver module_init routine is called. This enables +platform code which uses timer 0 or 1 as the main timer to intercept HPET +initialization. An example of this initialization can be found in +arch/x86/kernel/hpet.c. + +The driver provides a userspace API which resembles the API found in the +RTC driver framework. An example user space program is provided in +file:samples/timers/hpet_example.c diff --git a/Documentation/timers/hpet.txt b/Documentation/timers/hpet.txt deleted file mode 100644 index 895345ec513b..000000000000 --- a/Documentation/timers/hpet.txt +++ /dev/null @@ -1,28 +0,0 @@ - High Precision Event Timer Driver for Linux - -The High Precision Event Timer (HPET) hardware follows a specification -by Intel and Microsoft, revision 1. - -Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision") -and up to 32 comparators. Normally three or more comparators are provided, -each of which can generate oneshot interrupts and at least one of which has -additional hardware to support periodic interrupts. The comparators are -also called "timers", which can be misleading since usually timers are -independent of each other ... these share a counter, complicating resets. - -HPET devices can support two interrupt routing modes. In one mode, the -comparators are additional interrupt sources with no particular system -role. Many x86 BIOS writers don't route HPET interrupts at all, which -prevents use of that mode. They support the other "legacy replacement" -mode where the first two comparators block interrupts from 8254 timers -and from the RTC. - -The driver supports detection of HPET driver allocation and initialization -of the HPET before the driver module_init routine is called. This enables -platform code which uses timer 0 or 1 as the main timer to intercept HPET -initialization. An example of this initialization can be found in -arch/x86/kernel/hpet.c. - -The driver provides a userspace API which resembles the API found in the -RTC driver framework. An example user space program is provided in -file:samples/timers/hpet_example.c diff --git a/Documentation/timers/hrtimers.rst b/Documentation/timers/hrtimers.rst new file mode 100644 index 000000000000..c1c20a693e8f --- /dev/null +++ b/Documentation/timers/hrtimers.rst @@ -0,0 +1,178 @@ +====================================================== +hrtimers - subsystem for high-resolution kernel timers +====================================================== + +This patch introduces a new subsystem for high-resolution kernel timers. + +One might ask the question: we already have a timer subsystem +(kernel/timers.c), why do we need two timer subsystems? After a lot of +back and forth trying to integrate high-resolution and high-precision +features into the existing timer framework, and after testing various +such high-resolution timer implementations in practice, we came to the +conclusion that the timer wheel code is fundamentally not suitable for +such an approach. We initially didn't believe this ('there must be a way +to solve this'), and spent a considerable effort trying to integrate +things into the timer wheel, but we failed. In hindsight, there are +several reasons why such integration is hard/impossible: + +- the forced handling of low-resolution and high-resolution timers in + the same way leads to a lot of compromises, macro magic and #ifdef + mess. The timers.c code is very "tightly coded" around jiffies and + 32-bitness assumptions, and has been honed and micro-optimized for a + relatively narrow use case (jiffies in a relatively narrow HZ range) + for many years - and thus even small extensions to it easily break + the wheel concept, leading to even worse compromises. The timer wheel + code is very good and tight code, there's zero problems with it in its + current usage - but it is simply not suitable to be extended for + high-res timers. + +- the unpredictable [O(N)] overhead of cascading leads to delays which + necessitate a more complex handling of high resolution timers, which + in turn decreases robustness. Such a design still leads to rather large + timing inaccuracies. Cascading is a fundamental property of the timer + wheel concept, it cannot be 'designed out' without inevitably + degrading other portions of the timers.c code in an unacceptable way. + +- the implementation of the current posix-timer subsystem on top of + the timer wheel has already introduced a quite complex handling of + the required readjusting of absolute CLOCK_REALTIME timers at + settimeofday or NTP time - further underlying our experience by + example: that the timer wheel data structure is too rigid for high-res + timers. + +- the timer wheel code is most optimal for use cases which can be + identified as "timeouts". Such timeouts are usually set up to cover + error conditions in various I/O paths, such as networking and block + I/O. The vast majority of those timers never expire and are rarely + recascaded because the expected correct event arrives in time so they + can be removed from the timer wheel before any further processing of + them becomes necessary. Thus the users of these timeouts can accept + the granularity and precision tradeoffs of the timer wheel, and + largely expect the timer subsystem to have near-zero overhead. + Accurate timing for them is not a core purpose - in fact most of the + timeout values used are ad-hoc. For them it is at most a necessary + evil to guarantee the processing of actual timeout completions + (because most of the timeouts are deleted before completion), which + should thus be as cheap and unintrusive as possible. + +The primary users of precision timers are user-space applications that +utilize nanosleep, posix-timers and itimer interfaces. Also, in-kernel +users like drivers and subsystems which require precise timed events +(e.g. multimedia) can benefit from the availability of a separate +high-resolution timer subsystem as well. + +While this subsystem does not offer high-resolution clock sources just +yet, the hrtimer subsystem can be easily extended with high-resolution +clock capabilities, and patches for that exist and are maturing quickly. +The increasing demand for realtime and multimedia applications along +with other potential users for precise timers gives another reason to +separate the "timeout" and "precise timer" subsystems. + +Another potential benefit is that such a separation allows even more +special-purpose optimization of the existing timer wheel for the low +resolution and low precision use cases - once the precision-sensitive +APIs are separated from the timer wheel and are migrated over to +hrtimers. E.g. we could decrease the frequency of the timeout subsystem +from 250 Hz to 100 HZ (or even smaller). + +hrtimer subsystem implementation details +---------------------------------------- + +the basic design considerations were: + +- simplicity + +- data structure not bound to jiffies or any other granularity. All the + kernel logic works at 64-bit nanoseconds resolution - no compromises. + +- simplification of existing, timing related kernel code + +another basic requirement was the immediate enqueueing and ordering of +timers at activation time. After looking at several possible solutions +such as radix trees and hashes, we chose the red black tree as the basic +data structure. Rbtrees are available as a library in the kernel and are +used in various performance-critical areas of e.g. memory management and +file systems. The rbtree is solely used for time sorted ordering, while +a separate list is used to give the expiry code fast access to the +queued timers, without having to walk the rbtree. + +(This separate list is also useful for later when we'll introduce +high-resolution clocks, where we need separate pending and expired +queues while keeping the time-order intact.) + +Time-ordered enqueueing is not purely for the purposes of +high-resolution clocks though, it also simplifies the handling of +absolute timers based on a low-resolution CLOCK_REALTIME. The existing +implementation needed to keep an extra list of all armed absolute +CLOCK_REALTIME timers along with complex locking. In case of +settimeofday and NTP, all the timers (!) had to be dequeued, the +time-changing code had to fix them up one by one, and all of them had to +be enqueued again. The time-ordered enqueueing and the storage of the +expiry time in absolute time units removes all this complex and poorly +scaling code from the posix-timer implementation - the clock can simply +be set without having to touch the rbtree. This also makes the handling +of posix-timers simpler in general. + +The locking and per-CPU behavior of hrtimers was mostly taken from the +existing timer wheel code, as it is mature and well suited. Sharing code +was not really a win, due to the different data structures. Also, the +hrtimer functions now have clearer behavior and clearer names - such as +hrtimer_try_to_cancel() and hrtimer_cancel() [which are roughly +equivalent to del_timer() and del_timer_sync()] - so there's no direct +1:1 mapping between them on the algorithmic level, and thus no real +potential for code sharing either. + +Basic data types: every time value, absolute or relative, is in a +special nanosecond-resolution type: ktime_t. The kernel-internal +representation of ktime_t values and operations is implemented via +macros and inline functions, and can be switched between a "hybrid +union" type and a plain "scalar" 64bit nanoseconds representation (at +compile time). The hybrid union type optimizes time conversions on 32bit +CPUs. This build-time-selectable ktime_t storage format was implemented +to avoid the performance impact of 64-bit multiplications and divisions +on 32bit CPUs. Such operations are frequently necessary to convert +between the storage formats provided by kernel and userspace interfaces +and the internal time format. (See include/linux/ktime.h for further +details.) + +hrtimers - rounding of timer values +----------------------------------- + +the hrtimer code will round timer events to lower-resolution clocks +because it has to. Otherwise it will do no artificial rounding at all. + +one question is, what resolution value should be returned to the user by +the clock_getres() interface. This will return whatever real resolution +a given clock has - be it low-res, high-res, or artificially-low-res. + +hrtimers - testing and verification +----------------------------------- + +We used the high-resolution clock subsystem ontop of hrtimers to verify +the hrtimer implementation details in praxis, and we also ran the posix +timer tests in order to ensure specification compliance. We also ran +tests on low-resolution clocks. + +The hrtimer patch converts the following kernel functionality to use +hrtimers: + + - nanosleep + - itimers + - posix-timers + +The conversion of nanosleep and posix-timers enabled the unification of +nanosleep and clock_nanosleep. + +The code was successfully compiled for the following platforms: + + i386, x86_64, ARM, PPC, PPC64, IA64 + +The code was run-tested on the following platforms: + + i386(UP/SMP), x86_64(UP/SMP), ARM, PPC + +hrtimers were also integrated into the -rt tree, along with a +hrtimers-based high-resolution clock implementation, so the hrtimers +code got a healthy amount of testing and use in practice. + + Thomas Gleixner, Ingo Molnar diff --git a/Documentation/timers/hrtimers.txt b/Documentation/timers/hrtimers.txt deleted file mode 100644 index 588d85724f10..000000000000 --- a/Documentation/timers/hrtimers.txt +++ /dev/null @@ -1,178 +0,0 @@ - -hrtimers - subsystem for high-resolution kernel timers ----------------------------------------------------- - -This patch introduces a new subsystem for high-resolution kernel timers. - -One might ask the question: we already have a timer subsystem -(kernel/timers.c), why do we need two timer subsystems? After a lot of -back and forth trying to integrate high-resolution and high-precision -features into the existing timer framework, and after testing various -such high-resolution timer implementations in practice, we came to the -conclusion that the timer wheel code is fundamentally not suitable for -such an approach. We initially didn't believe this ('there must be a way -to solve this'), and spent a considerable effort trying to integrate -things into the timer wheel, but we failed. In hindsight, there are -several reasons why such integration is hard/impossible: - -- the forced handling of low-resolution and high-resolution timers in - the same way leads to a lot of compromises, macro magic and #ifdef - mess. The timers.c code is very "tightly coded" around jiffies and - 32-bitness assumptions, and has been honed and micro-optimized for a - relatively narrow use case (jiffies in a relatively narrow HZ range) - for many years - and thus even small extensions to it easily break - the wheel concept, leading to even worse compromises. The timer wheel - code is very good and tight code, there's zero problems with it in its - current usage - but it is simply not suitable to be extended for - high-res timers. - -- the unpredictable [O(N)] overhead of cascading leads to delays which - necessitate a more complex handling of high resolution timers, which - in turn decreases robustness. Such a design still leads to rather large - timing inaccuracies. Cascading is a fundamental property of the timer - wheel concept, it cannot be 'designed out' without inevitably - degrading other portions of the timers.c code in an unacceptable way. - -- the implementation of the current posix-timer subsystem on top of - the timer wheel has already introduced a quite complex handling of - the required readjusting of absolute CLOCK_REALTIME timers at - settimeofday or NTP time - further underlying our experience by - example: that the timer wheel data structure is too rigid for high-res - timers. - -- the timer wheel code is most optimal for use cases which can be - identified as "timeouts". Such timeouts are usually set up to cover - error conditions in various I/O paths, such as networking and block - I/O. The vast majority of those timers never expire and are rarely - recascaded because the expected correct event arrives in time so they - can be removed from the timer wheel before any further processing of - them becomes necessary. Thus the users of these timeouts can accept - the granularity and precision tradeoffs of the timer wheel, and - largely expect the timer subsystem to have near-zero overhead. - Accurate timing for them is not a core purpose - in fact most of the - timeout values used are ad-hoc. For them it is at most a necessary - evil to guarantee the processing of actual timeout completions - (because most of the timeouts are deleted before completion), which - should thus be as cheap and unintrusive as possible. - -The primary users of precision timers are user-space applications that -utilize nanosleep, posix-timers and itimer interfaces. Also, in-kernel -users like drivers and subsystems which require precise timed events -(e.g. multimedia) can benefit from the availability of a separate -high-resolution timer subsystem as well. - -While this subsystem does not offer high-resolution clock sources just -yet, the hrtimer subsystem can be easily extended with high-resolution -clock capabilities, and patches for that exist and are maturing quickly. -The increasing demand for realtime and multimedia applications along -with other potential users for precise timers gives another reason to -separate the "timeout" and "precise timer" subsystems. - -Another potential benefit is that such a separation allows even more -special-purpose optimization of the existing timer wheel for the low -resolution and low precision use cases - once the precision-sensitive -APIs are separated from the timer wheel and are migrated over to -hrtimers. E.g. we could decrease the frequency of the timeout subsystem -from 250 Hz to 100 HZ (or even smaller). - -hrtimer subsystem implementation details ----------------------------------------- - -the basic design considerations were: - -- simplicity - -- data structure not bound to jiffies or any other granularity. All the - kernel logic works at 64-bit nanoseconds resolution - no compromises. - -- simplification of existing, timing related kernel code - -another basic requirement was the immediate enqueueing and ordering of -timers at activation time. After looking at several possible solutions -such as radix trees and hashes, we chose the red black tree as the basic -data structure. Rbtrees are available as a library in the kernel and are -used in various performance-critical areas of e.g. memory management and -file systems. The rbtree is solely used for time sorted ordering, while -a separate list is used to give the expiry code fast access to the -queued timers, without having to walk the rbtree. - -(This separate list is also useful for later when we'll introduce -high-resolution clocks, where we need separate pending and expired -queues while keeping the time-order intact.) - -Time-ordered enqueueing is not purely for the purposes of -high-resolution clocks though, it also simplifies the handling of -absolute timers based on a low-resolution CLOCK_REALTIME. The existing -implementation needed to keep an extra list of all armed absolute -CLOCK_REALTIME timers along with complex locking. In case of -settimeofday and NTP, all the timers (!) had to be dequeued, the -time-changing code had to fix them up one by one, and all of them had to -be enqueued again. The time-ordered enqueueing and the storage of the -expiry time in absolute time units removes all this complex and poorly -scaling code from the posix-timer implementation - the clock can simply -be set without having to touch the rbtree. This also makes the handling -of posix-timers simpler in general. - -The locking and per-CPU behavior of hrtimers was mostly taken from the -existing timer wheel code, as it is mature and well suited. Sharing code -was not really a win, due to the different data structures. Also, the -hrtimer functions now have clearer behavior and clearer names - such as -hrtimer_try_to_cancel() and hrtimer_cancel() [which are roughly -equivalent to del_timer() and del_timer_sync()] - so there's no direct -1:1 mapping between them on the algorithmic level, and thus no real -potential for code sharing either. - -Basic data types: every time value, absolute or relative, is in a -special nanosecond-resolution type: ktime_t. The kernel-internal -representation of ktime_t values and operations is implemented via -macros and inline functions, and can be switched between a "hybrid -union" type and a plain "scalar" 64bit nanoseconds representation (at -compile time). The hybrid union type optimizes time conversions on 32bit -CPUs. This build-time-selectable ktime_t storage format was implemented -to avoid the performance impact of 64-bit multiplications and divisions -on 32bit CPUs. Such operations are frequently necessary to convert -between the storage formats provided by kernel and userspace interfaces -and the internal time format. (See include/linux/ktime.h for further -details.) - -hrtimers - rounding of timer values ------------------------------------ - -the hrtimer code will round timer events to lower-resolution clocks -because it has to. Otherwise it will do no artificial rounding at all. - -one question is, what resolution value should be returned to the user by -the clock_getres() interface. This will return whatever real resolution -a given clock has - be it low-res, high-res, or artificially-low-res. - -hrtimers - testing and verification ----------------------------------- - -We used the high-resolution clock subsystem ontop of hrtimers to verify -the hrtimer implementation details in praxis, and we also ran the posix -timer tests in order to ensure specification compliance. We also ran -tests on low-resolution clocks. - -The hrtimer patch converts the following kernel functionality to use -hrtimers: - - - nanosleep - - itimers - - posix-timers - -The conversion of nanosleep and posix-timers enabled the unification of -nanosleep and clock_nanosleep. - -The code was successfully compiled for the following platforms: - - i386, x86_64, ARM, PPC, PPC64, IA64 - -The code was run-tested on the following platforms: - - i386(UP/SMP), x86_64(UP/SMP), ARM, PPC - -hrtimers were also integrated into the -rt tree, along with a -hrtimers-based high-resolution clock implementation, so the hrtimers -code got a healthy amount of testing and use in practice. - - Thomas Gleixner, Ingo Molnar diff --git a/Documentation/timers/index.rst b/Documentation/timers/index.rst new file mode 100644 index 000000000000..91f6f8263c48 --- /dev/null +++ b/Documentation/timers/index.rst @@ -0,0 +1,22 @@ +:orphan: + +====== +timers +====== + +.. toctree:: + :maxdepth: 1 + + highres + hpet + hrtimers + no_hz + timekeeping + timers-howto + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/timers/no_hz.rst b/Documentation/timers/no_hz.rst new file mode 100644 index 000000000000..065db217cb04 --- /dev/null +++ b/Documentation/timers/no_hz.rst @@ -0,0 +1,326 @@ +====================================== +NO_HZ: Reducing Scheduling-Clock Ticks +====================================== + + +This document describes Kconfig options and boot parameters that can +reduce the number of scheduling-clock interrupts, thereby improving energy +efficiency and reducing OS jitter. Reducing OS jitter is important for +some types of computationally intensive high-performance computing (HPC) +applications and for real-time applications. + +There are three main ways of managing scheduling-clock interrupts +(also known as "scheduling-clock ticks" or simply "ticks"): + +1. Never omit scheduling-clock ticks (CONFIG_HZ_PERIODIC=y or + CONFIG_NO_HZ=n for older kernels). You normally will -not- + want to choose this option. + +2. Omit scheduling-clock ticks on idle CPUs (CONFIG_NO_HZ_IDLE=y or + CONFIG_NO_HZ=y for older kernels). This is the most common + approach, and should be the default. + +3. Omit scheduling-clock ticks on CPUs that are either idle or that + have only one runnable task (CONFIG_NO_HZ_FULL=y). Unless you + are running realtime applications or certain types of HPC + workloads, you will normally -not- want this option. + +These three cases are described in the following three sections, followed +by a third section on RCU-specific considerations, a fourth section +discussing testing, and a fifth and final section listing known issues. + + +Never Omit Scheduling-Clock Ticks +================================= + +Very old versions of Linux from the 1990s and the very early 2000s +are incapable of omitting scheduling-clock ticks. It turns out that +there are some situations where this old-school approach is still the +right approach, for example, in heavy workloads with lots of tasks +that use short bursts of CPU, where there are very frequent idle +periods, but where these idle periods are also quite short (tens or +hundreds of microseconds). For these types of workloads, scheduling +clock interrupts will normally be delivered any way because there +will frequently be multiple runnable tasks per CPU. In these cases, +attempting to turn off the scheduling clock interrupt will have no effect +other than increasing the overhead of switching to and from idle and +transitioning between user and kernel execution. + +This mode of operation can be selected using CONFIG_HZ_PERIODIC=y (or +CONFIG_NO_HZ=n for older kernels). + +However, if you are instead running a light workload with long idle +periods, failing to omit scheduling-clock interrupts will result in +excessive power consumption. This is especially bad on battery-powered +devices, where it results in extremely short battery lifetimes. If you +are running light workloads, you should therefore read the following +section. + +In addition, if you are running either a real-time workload or an HPC +workload with short iterations, the scheduling-clock interrupts can +degrade your applications performance. If this describes your workload, +you should read the following two sections. + + +Omit Scheduling-Clock Ticks For Idle CPUs +========================================= + +If a CPU is idle, there is little point in sending it a scheduling-clock +interrupt. After all, the primary purpose of a scheduling-clock interrupt +is to force a busy CPU to shift its attention among multiple duties, +and an idle CPU has no duties to shift its attention among. + +The CONFIG_NO_HZ_IDLE=y Kconfig option causes the kernel to avoid sending +scheduling-clock interrupts to idle CPUs, which is critically important +both to battery-powered devices and to highly virtualized mainframes. +A battery-powered device running a CONFIG_HZ_PERIODIC=y kernel would +drain its battery very quickly, easily 2-3 times as fast as would the +same device running a CONFIG_NO_HZ_IDLE=y kernel. A mainframe running +1,500 OS instances might find that half of its CPU time was consumed by +unnecessary scheduling-clock interrupts. In these situations, there +is strong motivation to avoid sending scheduling-clock interrupts to +idle CPUs. That said, dyntick-idle mode is not free: + +1. It increases the number of instructions executed on the path + to and from the idle loop. + +2. On many architectures, dyntick-idle mode also increases the + number of expensive clock-reprogramming operations. + +Therefore, systems with aggressive real-time response constraints often +run CONFIG_HZ_PERIODIC=y kernels (or CONFIG_NO_HZ=n for older kernels) +in order to avoid degrading from-idle transition latencies. + +An idle CPU that is not receiving scheduling-clock interrupts is said to +be "dyntick-idle", "in dyntick-idle mode", "in nohz mode", or "running +tickless". The remainder of this document will use "dyntick-idle mode". + +There is also a boot parameter "nohz=" that can be used to disable +dyntick-idle mode in CONFIG_NO_HZ_IDLE=y kernels by specifying "nohz=off". +By default, CONFIG_NO_HZ_IDLE=y kernels boot with "nohz=on", enabling +dyntick-idle mode. + + +Omit Scheduling-Clock Ticks For CPUs With Only One Runnable Task +================================================================ + +If a CPU has only one runnable task, there is little point in sending it +a scheduling-clock interrupt because there is no other task to switch to. +Note that omitting scheduling-clock ticks for CPUs with only one runnable +task implies also omitting them for idle CPUs. + +The CONFIG_NO_HZ_FULL=y Kconfig option causes the kernel to avoid +sending scheduling-clock interrupts to CPUs with a single runnable task, +and such CPUs are said to be "adaptive-ticks CPUs". This is important +for applications with aggressive real-time response constraints because +it allows them to improve their worst-case response times by the maximum +duration of a scheduling-clock interrupt. It is also important for +computationally intensive short-iteration workloads: If any CPU is +delayed during a given iteration, all the other CPUs will be forced to +wait idle while the delayed CPU finishes. Thus, the delay is multiplied +by one less than the number of CPUs. In these situations, there is +again strong motivation to avoid sending scheduling-clock interrupts. + +By default, no CPU will be an adaptive-ticks CPU. The "nohz_full=" +boot parameter specifies the adaptive-ticks CPUs. For example, +"nohz_full=1,6-8" says that CPUs 1, 6, 7, and 8 are to be adaptive-ticks +CPUs. Note that you are prohibited from marking all of the CPUs as +adaptive-tick CPUs: At least one non-adaptive-tick CPU must remain +online to handle timekeeping tasks in order to ensure that system +calls like gettimeofday() returns accurate values on adaptive-tick CPUs. +(This is not an issue for CONFIG_NO_HZ_IDLE=y because there are no running +user processes to observe slight drifts in clock rate.) Therefore, the +boot CPU is prohibited from entering adaptive-ticks mode. Specifying a +"nohz_full=" mask that includes the boot CPU will result in a boot-time +error message, and the boot CPU will be removed from the mask. Note that +this means that your system must have at least two CPUs in order for +CONFIG_NO_HZ_FULL=y to do anything for you. + +Finally, adaptive-ticks CPUs must have their RCU callbacks offloaded. +This is covered in the "RCU IMPLICATIONS" section below. + +Normally, a CPU remains in adaptive-ticks mode as long as possible. +In particular, transitioning to kernel mode does not automatically change +the mode. Instead, the CPU will exit adaptive-ticks mode only if needed, +for example, if that CPU enqueues an RCU callback. + +Just as with dyntick-idle mode, the benefits of adaptive-tick mode do +not come for free: + +1. CONFIG_NO_HZ_FULL selects CONFIG_NO_HZ_COMMON, so you cannot run + adaptive ticks without also running dyntick idle. This dependency + extends down into the implementation, so that all of the costs + of CONFIG_NO_HZ_IDLE are also incurred by CONFIG_NO_HZ_FULL. + +2. The user/kernel transitions are slightly more expensive due + to the need to inform kernel subsystems (such as RCU) about + the change in mode. + +3. POSIX CPU timers prevent CPUs from entering adaptive-tick mode. + Real-time applications needing to take actions based on CPU time + consumption need to use other means of doing so. + +4. If there are more perf events pending than the hardware can + accommodate, they are normally round-robined so as to collect + all of them over time. Adaptive-tick mode may prevent this + round-robining from happening. This will likely be fixed by + preventing CPUs with large numbers of perf events pending from + entering adaptive-tick mode. + +5. Scheduler statistics for adaptive-tick CPUs may be computed + slightly differently than those for non-adaptive-tick CPUs. + This might in turn perturb load-balancing of real-time tasks. + +6. The LB_BIAS scheduler feature is disabled by adaptive ticks. + +Although improvements are expected over time, adaptive ticks is quite +useful for many types of real-time and compute-intensive applications. +However, the drawbacks listed above mean that adaptive ticks should not +(yet) be enabled by default. + + +RCU Implications +================ + +There are situations in which idle CPUs cannot be permitted to +enter either dyntick-idle mode or adaptive-tick mode, the most +common being when that CPU has RCU callbacks pending. + +The CONFIG_RCU_FAST_NO_HZ=y Kconfig option may be used to cause such CPUs +to enter dyntick-idle mode or adaptive-tick mode anyway. In this case, +a timer will awaken these CPUs every four jiffies in order to ensure +that the RCU callbacks are processed in a timely fashion. + +Another approach is to offload RCU callback processing to "rcuo" kthreads +using the CONFIG_RCU_NOCB_CPU=y Kconfig option. The specific CPUs to +offload may be selected using The "rcu_nocbs=" kernel boot parameter, +which takes a comma-separated list of CPUs and CPU ranges, for example, +"1,3-5" selects CPUs 1, 3, 4, and 5. + +The offloaded CPUs will never queue RCU callbacks, and therefore RCU +never prevents offloaded CPUs from entering either dyntick-idle mode +or adaptive-tick mode. That said, note that it is up to userspace to +pin the "rcuo" kthreads to specific CPUs if desired. Otherwise, the +scheduler will decide where to run them, which might or might not be +where you want them to run. + + +Testing +======= + +So you enable all the OS-jitter features described in this document, +but do not see any change in your workload's behavior. Is this because +your workload isn't affected that much by OS jitter, or is it because +something else is in the way? This section helps answer this question +by providing a simple OS-jitter test suite, which is available on branch +master of the following git archive: + +git://git.kernel.org/pub/scm/linux/kernel/git/frederic/dynticks-testing.git + +Clone this archive and follow the instructions in the README file. +This test procedure will produce a trace that will allow you to evaluate +whether or not you have succeeded in removing OS jitter from your system. +If this trace shows that you have removed OS jitter as much as is +possible, then you can conclude that your workload is not all that +sensitive to OS jitter. + +Note: this test requires that your system have at least two CPUs. +We do not currently have a good way to remove OS jitter from single-CPU +systems. + + +Known Issues +============ + +* Dyntick-idle slows transitions to and from idle slightly. + In practice, this has not been a problem except for the most + aggressive real-time workloads, which have the option of disabling + dyntick-idle mode, an option that most of them take. However, + some workloads will no doubt want to use adaptive ticks to + eliminate scheduling-clock interrupt latencies. Here are some + options for these workloads: + + a. Use PMQOS from userspace to inform the kernel of your + latency requirements (preferred). + + b. On x86 systems, use the "idle=mwait" boot parameter. + + c. On x86 systems, use the "intel_idle.max_cstate=" to limit + ` the maximum C-state depth. + + d. On x86 systems, use the "idle=poll" boot parameter. + However, please note that use of this parameter can cause + your CPU to overheat, which may cause thermal throttling + to degrade your latencies -- and that this degradation can + be even worse than that of dyntick-idle. Furthermore, + this parameter effectively disables Turbo Mode on Intel + CPUs, which can significantly reduce maximum performance. + +* Adaptive-ticks slows user/kernel transitions slightly. + This is not expected to be a problem for computationally intensive + workloads, which have few such transitions. Careful benchmarking + will be required to determine whether or not other workloads + are significantly affected by this effect. + +* Adaptive-ticks does not do anything unless there is only one + runnable task for a given CPU, even though there are a number + of other situations where the scheduling-clock tick is not + needed. To give but one example, consider a CPU that has one + runnable high-priority SCHED_FIFO task and an arbitrary number + of low-priority SCHED_OTHER tasks. In this case, the CPU is + required to run the SCHED_FIFO task until it either blocks or + some other higher-priority task awakens on (or is assigned to) + this CPU, so there is no point in sending a scheduling-clock + interrupt to this CPU. However, the current implementation + nevertheless sends scheduling-clock interrupts to CPUs having a + single runnable SCHED_FIFO task and multiple runnable SCHED_OTHER + tasks, even though these interrupts are unnecessary. + + And even when there are multiple runnable tasks on a given CPU, + there is little point in interrupting that CPU until the current + running task's timeslice expires, which is almost always way + longer than the time of the next scheduling-clock interrupt. + + Better handling of these sorts of situations is future work. + +* A reboot is required to reconfigure both adaptive idle and RCU + callback offloading. Runtime reconfiguration could be provided + if needed, however, due to the complexity of reconfiguring RCU at + runtime, there would need to be an earthshakingly good reason. + Especially given that you have the straightforward option of + simply offloading RCU callbacks from all CPUs and pinning them + where you want them whenever you want them pinned. + +* Additional configuration is required to deal with other sources + of OS jitter, including interrupts and system-utility tasks + and processes. This configuration normally involves binding + interrupts and tasks to particular CPUs. + +* Some sources of OS jitter can currently be eliminated only by + constraining the workload. For example, the only way to eliminate + OS jitter due to global TLB shootdowns is to avoid the unmapping + operations (such as kernel module unload operations) that + result in these shootdowns. For another example, page faults + and TLB misses can be reduced (and in some cases eliminated) by + using huge pages and by constraining the amount of memory used + by the application. Pre-faulting the working set can also be + helpful, especially when combined with the mlock() and mlockall() + system calls. + +* Unless all CPUs are idle, at least one CPU must keep the + scheduling-clock interrupt going in order to support accurate + timekeeping. + +* If there might potentially be some adaptive-ticks CPUs, there + will be at least one CPU keeping the scheduling-clock interrupt + going, even if all CPUs are otherwise idle. + + Better handling of this situation is ongoing work. + +* Some process-handling operations still require the occasional + scheduling-clock tick. These operations include calculating CPU + load, maintaining sched average, computing CFS entity vruntime, + computing avenrun, and carrying out load balancing. They are + currently accommodated by scheduling-clock tick every second + or so. On-going work will eliminate the need even for these + infrequent scheduling-clock ticks. diff --git a/Documentation/timers/timekeeping.rst b/Documentation/timers/timekeeping.rst new file mode 100644 index 000000000000..f83e98852e2c --- /dev/null +++ b/Documentation/timers/timekeeping.rst @@ -0,0 +1,180 @@ +=========================================================== +Clock sources, Clock events, sched_clock() and delay timers +=========================================================== + +This document tries to briefly explain some basic kernel timekeeping +abstractions. It partly pertains to the drivers usually found in +drivers/clocksource in the kernel tree, but the code may be spread out +across the kernel. + +If you grep through the kernel source you will find a number of architecture- +specific implementations of clock sources, clockevents and several likewise +architecture-specific overrides of the sched_clock() function and some +delay timers. + +To provide timekeeping for your platform, the clock source provides +the basic timeline, whereas clock events shoot interrupts on certain points +on this timeline, providing facilities such as high-resolution timers. +sched_clock() is used for scheduling and timestamping, and delay timers +provide an accurate delay source using hardware counters. + + +Clock sources +------------- + +The purpose of the clock source is to provide a timeline for the system that +tells you where you are in time. For example issuing the command 'date' on +a Linux system will eventually read the clock source to determine exactly +what time it is. + +Typically the clock source is a monotonic, atomic counter which will provide +n bits which count from 0 to (2^n)-1 and then wraps around to 0 and start over. +It will ideally NEVER stop ticking as long as the system is running. It +may stop during system suspend. + +The clock source shall have as high resolution as possible, and the frequency +shall be as stable and correct as possible as compared to a real-world wall +clock. It should not move unpredictably back and forth in time or miss a few +cycles here and there. + +It must be immune to the kind of effects that occur in hardware where e.g. +the counter register is read in two phases on the bus lowest 16 bits first +and the higher 16 bits in a second bus cycle with the counter bits +potentially being updated in between leading to the risk of very strange +values from the counter. + +When the wall-clock accuracy of the clock source isn't satisfactory, there +are various quirks and layers in the timekeeping code for e.g. synchronizing +the user-visible time to RTC clocks in the system or against networked time +servers using NTP, but all they do basically is update an offset against +the clock source, which provides the fundamental timeline for the system. +These measures does not affect the clock source per se, they only adapt the +system to the shortcomings of it. + +The clock source struct shall provide means to translate the provided counter +into a nanosecond value as an unsigned long long (unsigned 64 bit) number. +Since this operation may be invoked very often, doing this in a strict +mathematical sense is not desirable: instead the number is taken as close as +possible to a nanosecond value using only the arithmetic operations +multiply and shift, so in clocksource_cyc2ns() you find: + + ns ~= (clocksource * mult) >> shift + +You will find a number of helper functions in the clock source code intended +to aid in providing these mult and shift values, such as +clocksource_khz2mult(), clocksource_hz2mult() that help determine the +mult factor from a fixed shift, and clocksource_register_hz() and +clocksource_register_khz() which will help out assigning both shift and mult +factors using the frequency of the clock source as the only input. + +For real simple clock sources accessed from a single I/O memory location +there is nowadays even clocksource_mmio_init() which will take a memory +location, bit width, a parameter telling whether the counter in the +register counts up or down, and the timer clock rate, and then conjure all +necessary parameters. + +Since a 32-bit counter at say 100 MHz will wrap around to zero after some 43 +seconds, the code handling the clock source will have to compensate for this. +That is the reason why the clock source struct also contains a 'mask' +member telling how many bits of the source are valid. This way the timekeeping +code knows when the counter will wrap around and can insert the necessary +compensation code on both sides of the wrap point so that the system timeline +remains monotonic. + + +Clock events +------------ + +Clock events are the conceptual reverse of clock sources: they take a +desired time specification value and calculate the values to poke into +hardware timer registers. + +Clock events are orthogonal to clock sources. The same hardware +and register range may be used for the clock event, but it is essentially +a different thing. The hardware driving clock events has to be able to +fire interrupts, so as to trigger events on the system timeline. On an SMP +system, it is ideal (and customary) to have one such event driving timer per +CPU core, so that each core can trigger events independently of any other +core. + +You will notice that the clock event device code is based on the same basic +idea about translating counters to nanoseconds using mult and shift +arithmetic, and you find the same family of helper functions again for +assigning these values. The clock event driver does not need a 'mask' +attribute however: the system will not try to plan events beyond the time +horizon of the clock event. + + +sched_clock() +------------- + +In addition to the clock sources and clock events there is a special weak +function in the kernel called sched_clock(). This function shall return the +number of nanoseconds since the system was started. An architecture may or +may not provide an implementation of sched_clock() on its own. If a local +implementation is not provided, the system jiffy counter will be used as +sched_clock(). + +As the name suggests, sched_clock() is used for scheduling the system, +determining the absolute timeslice for a certain process in the CFS scheduler +for example. It is also used for printk timestamps when you have selected to +include time information in printk for things like bootcharts. + +Compared to clock sources, sched_clock() has to be very fast: it is called +much more often, especially by the scheduler. If you have to do trade-offs +between accuracy compared to the clock source, you may sacrifice accuracy +for speed in sched_clock(). It however requires some of the same basic +characteristics as the clock source, i.e. it should be monotonic. + +The sched_clock() function may wrap only on unsigned long long boundaries, +i.e. after 64 bits. Since this is a nanosecond value this will mean it wraps +after circa 585 years. (For most practical systems this means "never".) + +If an architecture does not provide its own implementation of this function, +it will fall back to using jiffies, making its maximum resolution 1/HZ of the +jiffy frequency for the architecture. This will affect scheduling accuracy +and will likely show up in system benchmarks. + +The clock driving sched_clock() may stop or reset to zero during system +suspend/sleep. This does not matter to the function it serves of scheduling +events on the system. However it may result in interesting timestamps in +printk(). + +The sched_clock() function should be callable in any context, IRQ- and +NMI-safe and return a sane value in any context. + +Some architectures may have a limited set of time sources and lack a nice +counter to derive a 64-bit nanosecond value, so for example on the ARM +architecture, special helper functions have been created to provide a +sched_clock() nanosecond base from a 16- or 32-bit counter. Sometimes the +same counter that is also used as clock source is used for this purpose. + +On SMP systems, it is crucial for performance that sched_clock() can be called +independently on each CPU without any synchronization performance hits. +Some hardware (such as the x86 TSC) will cause the sched_clock() function to +drift between the CPUs on the system. The kernel can work around this by +enabling the CONFIG_HAVE_UNSTABLE_SCHED_CLOCK option. This is another aspect +that makes sched_clock() different from the ordinary clock source. + + +Delay timers (some architectures only) +-------------------------------------- + +On systems with variable CPU frequency, the various kernel delay() functions +will sometimes behave strangely. Basically these delays usually use a hard +loop to delay a certain number of jiffy fractions using a "lpj" (loops per +jiffy) value, calibrated on boot. + +Let's hope that your system is running on maximum frequency when this value +is calibrated: as an effect when the frequency is geared down to half the +full frequency, any delay() will be twice as long. Usually this does not +hurt, as you're commonly requesting that amount of delay *or more*. But +basically the semantics are quite unpredictable on such systems. + +Enter timer-based delays. Using these, a timer read may be used instead of +a hard-coded loop for providing the desired delay. + +This is done by declaring a struct delay_timer and assigning the appropriate +function pointers and rate settings for this delay timer. + +This is available on some architectures like OpenRISC or ARM. diff --git a/Documentation/timers/timekeeping.txt b/Documentation/timers/timekeeping.txt deleted file mode 100644 index 2d1732b0a868..000000000000 --- a/Documentation/timers/timekeeping.txt +++ /dev/null @@ -1,179 +0,0 @@ -Clock sources, Clock events, sched_clock() and delay timers ------------------------------------------------------------ - -This document tries to briefly explain some basic kernel timekeeping -abstractions. It partly pertains to the drivers usually found in -drivers/clocksource in the kernel tree, but the code may be spread out -across the kernel. - -If you grep through the kernel source you will find a number of architecture- -specific implementations of clock sources, clockevents and several likewise -architecture-specific overrides of the sched_clock() function and some -delay timers. - -To provide timekeeping for your platform, the clock source provides -the basic timeline, whereas clock events shoot interrupts on certain points -on this timeline, providing facilities such as high-resolution timers. -sched_clock() is used for scheduling and timestamping, and delay timers -provide an accurate delay source using hardware counters. - - -Clock sources -------------- - -The purpose of the clock source is to provide a timeline for the system that -tells you where you are in time. For example issuing the command 'date' on -a Linux system will eventually read the clock source to determine exactly -what time it is. - -Typically the clock source is a monotonic, atomic counter which will provide -n bits which count from 0 to (2^n)-1 and then wraps around to 0 and start over. -It will ideally NEVER stop ticking as long as the system is running. It -may stop during system suspend. - -The clock source shall have as high resolution as possible, and the frequency -shall be as stable and correct as possible as compared to a real-world wall -clock. It should not move unpredictably back and forth in time or miss a few -cycles here and there. - -It must be immune to the kind of effects that occur in hardware where e.g. -the counter register is read in two phases on the bus lowest 16 bits first -and the higher 16 bits in a second bus cycle with the counter bits -potentially being updated in between leading to the risk of very strange -values from the counter. - -When the wall-clock accuracy of the clock source isn't satisfactory, there -are various quirks and layers in the timekeeping code for e.g. synchronizing -the user-visible time to RTC clocks in the system or against networked time -servers using NTP, but all they do basically is update an offset against -the clock source, which provides the fundamental timeline for the system. -These measures does not affect the clock source per se, they only adapt the -system to the shortcomings of it. - -The clock source struct shall provide means to translate the provided counter -into a nanosecond value as an unsigned long long (unsigned 64 bit) number. -Since this operation may be invoked very often, doing this in a strict -mathematical sense is not desirable: instead the number is taken as close as -possible to a nanosecond value using only the arithmetic operations -multiply and shift, so in clocksource_cyc2ns() you find: - - ns ~= (clocksource * mult) >> shift - -You will find a number of helper functions in the clock source code intended -to aid in providing these mult and shift values, such as -clocksource_khz2mult(), clocksource_hz2mult() that help determine the -mult factor from a fixed shift, and clocksource_register_hz() and -clocksource_register_khz() which will help out assigning both shift and mult -factors using the frequency of the clock source as the only input. - -For real simple clock sources accessed from a single I/O memory location -there is nowadays even clocksource_mmio_init() which will take a memory -location, bit width, a parameter telling whether the counter in the -register counts up or down, and the timer clock rate, and then conjure all -necessary parameters. - -Since a 32-bit counter at say 100 MHz will wrap around to zero after some 43 -seconds, the code handling the clock source will have to compensate for this. -That is the reason why the clock source struct also contains a 'mask' -member telling how many bits of the source are valid. This way the timekeeping -code knows when the counter will wrap around and can insert the necessary -compensation code on both sides of the wrap point so that the system timeline -remains monotonic. - - -Clock events ------------- - -Clock events are the conceptual reverse of clock sources: they take a -desired time specification value and calculate the values to poke into -hardware timer registers. - -Clock events are orthogonal to clock sources. The same hardware -and register range may be used for the clock event, but it is essentially -a different thing. The hardware driving clock events has to be able to -fire interrupts, so as to trigger events on the system timeline. On an SMP -system, it is ideal (and customary) to have one such event driving timer per -CPU core, so that each core can trigger events independently of any other -core. - -You will notice that the clock event device code is based on the same basic -idea about translating counters to nanoseconds using mult and shift -arithmetic, and you find the same family of helper functions again for -assigning these values. The clock event driver does not need a 'mask' -attribute however: the system will not try to plan events beyond the time -horizon of the clock event. - - -sched_clock() -------------- - -In addition to the clock sources and clock events there is a special weak -function in the kernel called sched_clock(). This function shall return the -number of nanoseconds since the system was started. An architecture may or -may not provide an implementation of sched_clock() on its own. If a local -implementation is not provided, the system jiffy counter will be used as -sched_clock(). - -As the name suggests, sched_clock() is used for scheduling the system, -determining the absolute timeslice for a certain process in the CFS scheduler -for example. It is also used for printk timestamps when you have selected to -include time information in printk for things like bootcharts. - -Compared to clock sources, sched_clock() has to be very fast: it is called -much more often, especially by the scheduler. If you have to do trade-offs -between accuracy compared to the clock source, you may sacrifice accuracy -for speed in sched_clock(). It however requires some of the same basic -characteristics as the clock source, i.e. it should be monotonic. - -The sched_clock() function may wrap only on unsigned long long boundaries, -i.e. after 64 bits. Since this is a nanosecond value this will mean it wraps -after circa 585 years. (For most practical systems this means "never".) - -If an architecture does not provide its own implementation of this function, -it will fall back to using jiffies, making its maximum resolution 1/HZ of the -jiffy frequency for the architecture. This will affect scheduling accuracy -and will likely show up in system benchmarks. - -The clock driving sched_clock() may stop or reset to zero during system -suspend/sleep. This does not matter to the function it serves of scheduling -events on the system. However it may result in interesting timestamps in -printk(). - -The sched_clock() function should be callable in any context, IRQ- and -NMI-safe and return a sane value in any context. - -Some architectures may have a limited set of time sources and lack a nice -counter to derive a 64-bit nanosecond value, so for example on the ARM -architecture, special helper functions have been created to provide a -sched_clock() nanosecond base from a 16- or 32-bit counter. Sometimes the -same counter that is also used as clock source is used for this purpose. - -On SMP systems, it is crucial for performance that sched_clock() can be called -independently on each CPU without any synchronization performance hits. -Some hardware (such as the x86 TSC) will cause the sched_clock() function to -drift between the CPUs on the system. The kernel can work around this by -enabling the CONFIG_HAVE_UNSTABLE_SCHED_CLOCK option. This is another aspect -that makes sched_clock() different from the ordinary clock source. - - -Delay timers (some architectures only) --------------------------------------- - -On systems with variable CPU frequency, the various kernel delay() functions -will sometimes behave strangely. Basically these delays usually use a hard -loop to delay a certain number of jiffy fractions using a "lpj" (loops per -jiffy) value, calibrated on boot. - -Let's hope that your system is running on maximum frequency when this value -is calibrated: as an effect when the frequency is geared down to half the -full frequency, any delay() will be twice as long. Usually this does not -hurt, as you're commonly requesting that amount of delay *or more*. But -basically the semantics are quite unpredictable on such systems. - -Enter timer-based delays. Using these, a timer read may be used instead of -a hard-coded loop for providing the desired delay. - -This is done by declaring a struct delay_timer and assigning the appropriate -function pointers and rate settings for this delay timer. - -This is available on some architectures like OpenRISC or ARM. diff --git a/Documentation/timers/timers-howto.rst b/Documentation/timers/timers-howto.rst new file mode 100644 index 000000000000..7e3167bec2b1 --- /dev/null +++ b/Documentation/timers/timers-howto.rst @@ -0,0 +1,112 @@ +=================================================================== +delays - Information on the various kernel delay / sleep mechanisms +=================================================================== + +This document seeks to answer the common question: "What is the +RightWay (TM) to insert a delay?" + +This question is most often faced by driver writers who have to +deal with hardware delays and who may not be the most intimately +familiar with the inner workings of the Linux Kernel. + + +Inserting Delays +---------------- + +The first, and most important, question you need to ask is "Is my +code in an atomic context?" This should be followed closely by "Does +it really need to delay in atomic context?" If so... + +ATOMIC CONTEXT: + You must use the `*delay` family of functions. These + functions use the jiffie estimation of clock speed + and will busy wait for enough loop cycles to achieve + the desired delay: + + ndelay(unsigned long nsecs) + udelay(unsigned long usecs) + mdelay(unsigned long msecs) + + udelay is the generally preferred API; ndelay-level + precision may not actually exist on many non-PC devices. + + mdelay is macro wrapper around udelay, to account for + possible overflow when passing large arguments to udelay. + In general, use of mdelay is discouraged and code should + be refactored to allow for the use of msleep. + +NON-ATOMIC CONTEXT: + You should use the `*sleep[_range]` family of functions. + There are a few more options here, while any of them may + work correctly, using the "right" sleep function will + help the scheduler, power management, and just make your + driver better :) + + -- Backed by busy-wait loop: + + udelay(unsigned long usecs) + + -- Backed by hrtimers: + + usleep_range(unsigned long min, unsigned long max) + + -- Backed by jiffies / legacy_timers + + msleep(unsigned long msecs) + msleep_interruptible(unsigned long msecs) + + Unlike the `*delay` family, the underlying mechanism + driving each of these calls varies, thus there are + quirks you should be aware of. + + + SLEEPING FOR "A FEW" USECS ( < ~10us? ): + * Use udelay + + - Why not usleep? + On slower systems, (embedded, OR perhaps a speed- + stepped PC!) the overhead of setting up the hrtimers + for usleep *may* not be worth it. Such an evaluation + will obviously depend on your specific situation, but + it is something to be aware of. + + SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms): + * Use usleep_range + + - Why not msleep for (1ms - 20ms)? + Explained originally here: + http://lkml.org/lkml/2007/8/3/250 + + msleep(1~20) may not do what the caller intends, and + will often sleep longer (~20 ms actual sleep for any + value given in the 1~20ms range). In many cases this + is not the desired behavior. + + - Why is there no "usleep" / What is a good range? + Since usleep_range is built on top of hrtimers, the + wakeup will be very precise (ish), thus a simple + usleep function would likely introduce a large number + of undesired interrupts. + + With the introduction of a range, the scheduler is + free to coalesce your wakeup with any other wakeup + that may have happened for other reasons, or at the + worst case, fire an interrupt for your upper bound. + + The larger a range you supply, the greater a chance + that you will not trigger an interrupt; this should + be balanced with what is an acceptable upper bound on + delay / performance for your specific code path. Exact + tolerances here are very situation specific, thus it + is left to the caller to determine a reasonable range. + + SLEEPING FOR LARGER MSECS ( 10ms+ ) + * Use msleep or possibly msleep_interruptible + + - What's the difference? + msleep sets the current task to TASK_UNINTERRUPTIBLE + whereas msleep_interruptible sets the current task to + TASK_INTERRUPTIBLE before scheduling the sleep. In + short, the difference is whether the sleep can be ended + early by a signal. In general, just use msleep unless + you know you have a need for the interruptible variant. diff --git a/Documentation/timers/timers-howto.txt b/Documentation/timers/timers-howto.txt deleted file mode 100644 index 038f8c77a076..000000000000 --- a/Documentation/timers/timers-howto.txt +++ /dev/null @@ -1,105 +0,0 @@ -delays - Information on the various kernel delay / sleep mechanisms -------------------------------------------------------------------- - -This document seeks to answer the common question: "What is the -RightWay (TM) to insert a delay?" - -This question is most often faced by driver writers who have to -deal with hardware delays and who may not be the most intimately -familiar with the inner workings of the Linux Kernel. - - -Inserting Delays ----------------- - -The first, and most important, question you need to ask is "Is my -code in an atomic context?" This should be followed closely by "Does -it really need to delay in atomic context?" If so... - -ATOMIC CONTEXT: - You must use the *delay family of functions. These - functions use the jiffie estimation of clock speed - and will busy wait for enough loop cycles to achieve - the desired delay: - - ndelay(unsigned long nsecs) - udelay(unsigned long usecs) - mdelay(unsigned long msecs) - - udelay is the generally preferred API; ndelay-level - precision may not actually exist on many non-PC devices. - - mdelay is macro wrapper around udelay, to account for - possible overflow when passing large arguments to udelay. - In general, use of mdelay is discouraged and code should - be refactored to allow for the use of msleep. - -NON-ATOMIC CONTEXT: - You should use the *sleep[_range] family of functions. - There are a few more options here, while any of them may - work correctly, using the "right" sleep function will - help the scheduler, power management, and just make your - driver better :) - - -- Backed by busy-wait loop: - udelay(unsigned long usecs) - -- Backed by hrtimers: - usleep_range(unsigned long min, unsigned long max) - -- Backed by jiffies / legacy_timers - msleep(unsigned long msecs) - msleep_interruptible(unsigned long msecs) - - Unlike the *delay family, the underlying mechanism - driving each of these calls varies, thus there are - quirks you should be aware of. - - - SLEEPING FOR "A FEW" USECS ( < ~10us? ): - * Use udelay - - - Why not usleep? - On slower systems, (embedded, OR perhaps a speed- - stepped PC!) the overhead of setting up the hrtimers - for usleep *may* not be worth it. Such an evaluation - will obviously depend on your specific situation, but - it is something to be aware of. - - SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms): - * Use usleep_range - - - Why not msleep for (1ms - 20ms)? - Explained originally here: - http://lkml.org/lkml/2007/8/3/250 - msleep(1~20) may not do what the caller intends, and - will often sleep longer (~20 ms actual sleep for any - value given in the 1~20ms range). In many cases this - is not the desired behavior. - - - Why is there no "usleep" / What is a good range? - Since usleep_range is built on top of hrtimers, the - wakeup will be very precise (ish), thus a simple - usleep function would likely introduce a large number - of undesired interrupts. - - With the introduction of a range, the scheduler is - free to coalesce your wakeup with any other wakeup - that may have happened for other reasons, or at the - worst case, fire an interrupt for your upper bound. - - The larger a range you supply, the greater a chance - that you will not trigger an interrupt; this should - be balanced with what is an acceptable upper bound on - delay / performance for your specific code path. Exact - tolerances here are very situation specific, thus it - is left to the caller to determine a reasonable range. - - SLEEPING FOR LARGER MSECS ( 10ms+ ) - * Use msleep or possibly msleep_interruptible - - - What's the difference? - msleep sets the current task to TASK_UNINTERRUPTIBLE - whereas msleep_interruptible sets the current task to - TASK_INTERRUPTIBLE before scheduling the sleep. In - short, the difference is whether the sleep can be ended - early by a signal. In general, just use msleep unless - you know you have a need for the interruptible variant. diff --git a/MAINTAINERS b/MAINTAINERS index 5fe44d5d82b4..0db7f12439f7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7192,7 +7192,7 @@ F: drivers/net/ethernet/hp/hp100.* HPET: High Precision Event Timers driver M: Clemens Ladisch S: Maintained -F: Documentation/timers/hpet.txt +F: Documentation/timers/hpet.rst F: drivers/char/hpet.c F: include/linux/hpet.h F: include/uapi/linux/hpet.h diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index 48fb0d41e03b..fb6d99dea31a 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -56,7 +56,7 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32 * (EPIPE, Broken pipe). Function supports currently msleep() as a * parameter but I would not like to use it, since according to - * Documentation/timers/timers-howto.txt it should not be used such + * Documentation/timers/timers-howto.rst it should not be used such * short, under < 20ms, sleeps. Repeating failed message would be * better choice as not to add unwanted delays... * Fixing that correctly is one of those or both; diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c894cf0d8a28..c5d8996d5165 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2304,7 +2304,7 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) * * Delay for the requested amount of time as per the guidelines in: * - * Documentation/timers/timers-howto.txt + * Documentation/timers/timers-howto.rst * * The assumption here is that regulators will never be enabled in * atomic context and therefore sleeping functions can be used. diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h index 3908353deec6..35e15dfd4155 100644 --- a/include/linux/iopoll.h +++ b/include/linux/iopoll.h @@ -21,7 +21,7 @@ * @cond: Break condition (usually involving @val) * @sleep_us: Maximum time to sleep between reads in us (0 * tight-loops). Should be less than ~20ms since usleep_range - * is used (see Documentation/timers/timers-howto.txt). + * is used (see Documentation/timers/timers-howto.rst). * @timeout_us: Timeout in us, 0 means never timeout * * Returns 0 on success and -ETIMEDOUT upon a timeout. In either @@ -60,7 +60,7 @@ * @cond: Break condition (usually involving @val) * @delay_us: Time to udelay between reads in us (0 tight-loops). Should * be less than ~10us since udelay is used (see - * Documentation/timers/timers-howto.txt). + * Documentation/timers/timers-howto.rst). * @timeout_us: Timeout in us, 0 means never timeout * * Returns 0 on success and -ETIMEDOUT upon a timeout. In either diff --git a/include/linux/regmap.h b/include/linux/regmap.h index daeec7dbd65c..ed5e9d0a1285 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -112,7 +112,7 @@ struct reg_sequence { * @cond: Break condition (usually involving @val) * @sleep_us: Maximum time to sleep between reads in us (0 * tight-loops). Should be less than ~20ms since usleep_range - * is used (see Documentation/timers/timers-howto.txt). + * is used (see Documentation/timers/timers-howto.rst). * @timeout_us: Timeout in us, 0 means never timeout * * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_read @@ -154,7 +154,7 @@ struct reg_sequence { * @cond: Break condition (usually involving @val) * @sleep_us: Maximum time to sleep between reads in us (0 * tight-loops). Should be less than ~20ms since usleep_range - * is used (see Documentation/timers/timers-howto.txt). + * is used (see Documentation/timers/timers-howto.rst). * @timeout_us: Timeout in us, 0 means never timeout * * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_field_read diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 342c7c781ba5..a6d436809bf5 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -5712,7 +5712,7 @@ sub process { # ignore udelay's < 10, however if (! ($delay < 10) ) { CHK("USLEEP_RANGE", - "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $herecurr); + "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst\n" . $herecurr); } if ($delay > 2000) { WARN("LONG_UDELAY", @@ -5724,7 +5724,7 @@ sub process { if ($line =~ /\bmsleep\s*\((\d+)\);/) { if ($1 < 20) { WARN("MSLEEP", - "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $herecurr); + "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.rst\n" . $herecurr); } } @@ -6115,11 +6115,11 @@ sub process { my $max = $7; if ($min eq $max) { WARN("USLEEP_RANGE", - "usleep_range should not use min == max args; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n"); + "usleep_range should not use min == max args; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n"); } elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ && $min > $max) { WARN("USLEEP_RANGE", - "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n"); + "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n"); } } diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 80fc3b374c2b..8058a6c73082 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -349,7 +349,7 @@ static inline const struct snd_sof_dsp_ops * @cond: Break condition (usually involving @val) * @sleep_us: Maximum time to sleep between reads in us (0 * tight-loops). Should be less than ~20ms since usleep_range - * is used (see Documentation/timers/timers-howto.txt). + * is used (see Documentation/timers/timers-howto.rst). * @timeout_us: Timeout in us, 0 means never timeout * * Returns 0 on success and -ETIMEDOUT upon a timeout. In either -- cgit v1.2.3 From 418e3ea157efb0eb2c6dd412a8d5f052477c7f5a Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 14 Jun 2019 18:53:59 +0100 Subject: bus_find_device: Unify the match callback with class_find_device There is an arbitrary difference between the prototypes of bus_find_device() and class_find_device() preventing their callers from passing the same pair of data and match() arguments to both of them, which is the const qualifier used in the prototype of class_find_device(). If that qualifier is also used in the bus_find_device() prototype, it will be possible to pass the same match() callback function to both bus_find_device() and class_find_device(), which will allow some optimizations to be made in order to avoid code duplication going forward. Also with that, constify the "data" parameter as it is passed as a const to the match function. For this reason, change the prototype of bus_find_device() to match the prototype of class_find_device() and adjust its callers to use the const qualifier in accordance with the new prototype of it. Cc: Alexander Shishkin Cc: Andrew Lunn Cc: Andreas Noever Cc: Arnd Bergmann Cc: Bjorn Helgaas Cc: Corey Minyard Cc: Christian Borntraeger Cc: David Kershner Cc: "David S. Miller" Cc: David Airlie Cc: Felipe Balbi Cc: Frank Rowand Cc: Grygorii Strashko Cc: Harald Freudenberger Cc: Hartmut Knaack Cc: Heiko Stuebner Cc: Jason Gunthorpe Cc: Jonathan Cameron Cc: "James E.J. Bottomley" Cc: Len Brown Cc: Mark Brown Cc: Michael Ellerman Cc: Michael Jamet Cc: "Martin K. Petersen" Cc: Peter Oberparleiter Cc: Sebastian Ott Cc: Srinivas Kandagatla Cc: Yehezkel Bernat Cc: rafael@kernel.org Acked-by: Corey Minyard Acked-by: David Kershner Acked-by: Mark Brown Acked-by: Rafael J. Wysocki Acked-by: Srinivas Kandagatla Acked-by: Wolfram Sang # for the I2C parts Acked-by: Rob Herring Signed-off-by: Suzuki K Poulose Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/ibmebus.c | 4 ++-- drivers/acpi/acpi_lpss.c | 4 ++-- drivers/acpi/sleep.c | 2 +- drivers/acpi/utils.c | 4 ++-- drivers/base/bus.c | 6 +++--- drivers/base/devcon.c | 2 +- drivers/char/ipmi/ipmi_si_platform.c | 2 +- drivers/firmware/efi/dev-path-parser.c | 4 ++-- drivers/gpu/drm/drm_mipi_dsi.c | 2 +- drivers/hwtracing/coresight/coresight.c | 6 +++--- drivers/hwtracing/coresight/of_coresight.c | 2 +- drivers/hwtracing/intel_th/core.c | 5 ++--- drivers/i2c/i2c-core-acpi.c | 4 ++-- drivers/i2c/i2c-core-of.c | 4 ++-- drivers/iio/inkern.c | 2 +- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 2 +- drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c | 2 +- drivers/net/ethernet/ti/cpsw-phy-sel.c | 4 ++-- drivers/net/ethernet/ti/davinci_emac.c | 2 +- drivers/net/ethernet/toshiba/tc35815.c | 4 ++-- drivers/nvmem/core.c | 2 +- drivers/of/of_mdio.c | 2 +- drivers/of/platform.c | 2 +- drivers/pci/probe.c | 2 +- drivers/pci/search.c | 4 ++-- drivers/s390/cio/css.c | 4 ++-- drivers/s390/cio/device.c | 4 ++-- drivers/s390/cio/scm.c | 4 ++-- drivers/s390/crypto/ap_bus.c | 8 ++++---- drivers/scsi/scsi_proc.c | 2 +- drivers/spi/spi.c | 4 ++-- drivers/thunderbolt/switch.c | 4 ++-- drivers/usb/core/devio.c | 4 ++-- drivers/usb/core/usb.c | 4 ++-- drivers/usb/phy/phy-am335x-control.c | 4 ++-- drivers/usb/phy/phy-isp1301.c | 4 ++-- drivers/visorbus/visorbus_main.c | 4 ++-- include/linux/device.h | 4 ++-- sound/soc/rockchip/rk3399_gru_sound.c | 2 +- 39 files changed, 67 insertions(+), 68 deletions(-) (limited to 'sound') diff --git a/arch/powerpc/platforms/pseries/ibmebus.c b/arch/powerpc/platforms/pseries/ibmebus.c index 84e8ec4011ba..b91eb0929ed1 100644 --- a/arch/powerpc/platforms/pseries/ibmebus.c +++ b/arch/powerpc/platforms/pseries/ibmebus.c @@ -147,13 +147,13 @@ static const struct dma_map_ops ibmebus_dma_ops = { .unmap_page = ibmebus_unmap_page, }; -static int ibmebus_match_path(struct device *dev, void *data) +static int ibmebus_match_path(struct device *dev, const void *data) { struct device_node *dn = to_platform_device(dev)->dev.of_node; return (of_find_node_by_path(data) == dn); } -static int ibmebus_match_node(struct device *dev, void *data) +static int ibmebus_match_node(struct device *dev, const void *data) { return to_platform_device(dev)->dev.of_node == data; } diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index cf768608437e..dc2ca78748a2 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -511,10 +511,10 @@ struct hid_uid { const char *uid; }; -static int match_hid_uid(struct device *dev, void *data) +static int match_hid_uid(struct device *dev, const void *data) { struct acpi_device *adev = ACPI_COMPANION(dev); - struct hid_uid *id = data; + const struct hid_uid *id = data; if (!adev) return 0; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index a34deccd7317..fcf4386ecc78 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -454,7 +454,7 @@ static int acpi_pm_prepare(void) return error; } -static int find_powerf_dev(struct device *dev, void *data) +static int find_powerf_dev(struct device *dev, const void *data) { struct acpi_device *device = to_acpi_device(dev); const char *hid = acpi_device_hid(device); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 1391b63cadfd..e3974a8f8fd4 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -730,10 +730,10 @@ struct acpi_dev_match_info { s64 hrv; }; -static int acpi_dev_match_cb(struct device *dev, void *data) +static int acpi_dev_match_cb(struct device *dev, const void *data) { struct acpi_device *adev = to_acpi_device(dev); - struct acpi_dev_match_info *match = data; + const struct acpi_dev_match_info *match = data; unsigned long long hrv; acpi_status status; diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 0a58e969f8b7..df3cac739813 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -323,8 +323,8 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev); * return to the caller and not iterate over any more devices. */ struct device *bus_find_device(struct bus_type *bus, - struct device *start, void *data, - int (*match)(struct device *dev, void *data)) + struct device *start, const void *data, + int (*match)(struct device *dev, const void *data)) { struct klist_iter i; struct device *dev; @@ -342,7 +342,7 @@ struct device *bus_find_device(struct bus_type *bus, } EXPORT_SYMBOL_GPL(bus_find_device); -static int match_name(struct device *dev, void *data) +static int match_name(struct device *dev, const void *data) { const char *name = data; diff --git a/drivers/base/devcon.c b/drivers/base/devcon.c index 04db9ae235e4..ac026d5fc672 100644 --- a/drivers/base/devcon.c +++ b/drivers/base/devcon.c @@ -107,7 +107,7 @@ static struct bus_type *generic_match_buses[] = { NULL, }; -static int device_fwnode_match(struct device *dev, void *fwnode) +static int device_fwnode_match(struct device *dev, const void *fwnode) { return dev_fwnode(dev) == fwnode; } diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c index f2a91c4d8cab..fd94c4238449 100644 --- a/drivers/char/ipmi/ipmi_si_platform.c +++ b/drivers/char/ipmi/ipmi_si_platform.c @@ -426,7 +426,7 @@ static int ipmi_remove(struct platform_device *pdev) return ipmi_si_remove_by_dev(&pdev->dev); } -static int pdev_match_name(struct device *dev, void *data) +static int pdev_match_name(struct device *dev, const void *data) { struct platform_device *pdev = to_platform_device(dev); const char *name = data; diff --git a/drivers/firmware/efi/dev-path-parser.c b/drivers/firmware/efi/dev-path-parser.c index 85ec99f97841..20123384271c 100644 --- a/drivers/firmware/efi/dev-path-parser.c +++ b/drivers/firmware/efi/dev-path-parser.c @@ -17,9 +17,9 @@ struct acpi_hid_uid { char uid[11]; /* UINT_MAX + null byte */ }; -static int __init match_acpi_dev(struct device *dev, void *data) +static int __init match_acpi_dev(struct device *dev, const void *data) { - struct acpi_hid_uid hid_uid = *(struct acpi_hid_uid *)data; + struct acpi_hid_uid hid_uid = *(const struct acpi_hid_uid *)data; struct acpi_device *adev = to_acpi_device(dev); if (acpi_match_device_ids(adev, hid_uid.hid)) diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 80b75501f5c6..ad19df0686c9 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -93,7 +93,7 @@ static struct bus_type mipi_dsi_bus_type = { .pm = &mipi_dsi_device_pm_ops, }; -static int of_device_match(struct device *dev, void *data) +static int of_device_match(struct device *dev, const void *data) { return dev->of_node == data; } diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 4b130281236a..b67ab6a09587 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -498,9 +498,9 @@ struct coresight_device *coresight_get_sink(struct list_head *path) return csdev; } -static int coresight_enabled_sink(struct device *dev, void *data) +static int coresight_enabled_sink(struct device *dev, const void *data) { - bool *reset = data; + const bool *reset = data; struct coresight_device *csdev = to_coresight_device(dev); if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || @@ -544,7 +544,7 @@ struct coresight_device *coresight_get_enabled_sink(bool deactivate) return dev ? to_coresight_device(dev) : NULL; } -static int coresight_sink_by_id(struct device *dev, void *data) +static int coresight_sink_by_id(struct device *dev, const void *data) { struct coresight_device *csdev = to_coresight_device(dev); unsigned long hash; diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index 7045930fc958..3fc200ec1c03 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -18,7 +18,7 @@ #include -static int of_dev_node_match(struct device *dev, void *data) +static int of_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data; } diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index 033dce563c99..55922896d862 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -789,10 +789,9 @@ static int intel_th_populate(struct intel_th *th) return 0; } -static int match_devt(struct device *dev, void *data) +static int match_devt(struct device *dev, const void *data) { - dev_t devt = (dev_t)(unsigned long)data; - + dev_t devt = (dev_t)(unsigned long)(void *)data; return dev->devt == devt; } diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index d84095591e45..8af35f114821 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -318,7 +318,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev) } EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); -static int i2c_acpi_find_match_adapter(struct device *dev, void *data) +static int i2c_acpi_find_match_adapter(struct device *dev, const void *data) { struct i2c_adapter *adapter = i2c_verify_adapter(dev); @@ -328,7 +328,7 @@ static int i2c_acpi_find_match_adapter(struct device *dev, void *data) return ACPI_HANDLE(dev) == (acpi_handle)data; } -static int i2c_acpi_find_match_device(struct device *dev, void *data) +static int i2c_acpi_find_match_device(struct device *dev, const void *data) { return ACPI_COMPANION(dev) == data; } diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 406e5f695a7e..2eb59a260ad4 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -112,12 +112,12 @@ void of_i2c_register_devices(struct i2c_adapter *adap) of_node_put(bus); } -static int of_dev_node_match(struct device *dev, void *data) +static int of_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data; } -static int of_dev_or_parent_node_match(struct device *dev, void *data) +static int of_dev_or_parent_node_match(struct device *dev, const void *data) { if (dev->of_node == data) return 1; diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 4a5eff3f18bc..c46fb59d92cb 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -93,7 +93,7 @@ static const struct iio_chan_spec #ifdef CONFIG_OF -static int iio_dev_node_match(struct device *dev, void *data) +static int iio_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data && dev->type == &iio_device_type; } diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 4c5d0f160c10..fd90b05849c8 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -4497,7 +4497,7 @@ static const struct acpi_device_id hns_roce_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, hns_roce_acpi_match); -static int hns_roce_node_match(struct device *dev, void *fwnode) +static int hns_roce_node_match(struct device *dev, const void *fwnode) { return dev->fwnode == fwnode; } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c index 09c16d88172e..bb6586d0e5af 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c @@ -754,7 +754,7 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev) return (void *)misc_op; } -static int hns_dsaf_dev_match(struct device *dev, void *fwnode) +static int hns_dsaf_dev_match(struct device *dev, const void *fwnode) { return dev->fwnode == fwnode; } diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c index 48e0924259f5..4e184eecc8e1 100644 --- a/drivers/net/ethernet/ti/cpsw-phy-sel.c +++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c @@ -151,9 +151,9 @@ static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv, } static struct platform_driver cpsw_phy_sel_driver; -static int match(struct device *dev, void *data) +static int match(struct device *dev, const void *data) { - struct device_node *node = (struct device_node *)data; + const struct device_node *node = (const struct device_node *)data; return dev->of_node == node && dev->driver == &cpsw_phy_sel_driver.driver; } diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 4bf65cab79e6..57d131a04db3 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1371,7 +1371,7 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd) return -EOPNOTSUPP; } -static int match_first_device(struct device *dev, void *data) +static int match_first_device(struct device *dev, const void *data) { if (dev->parent && dev->parent->of_node) return of_device_is_compatible(dev->parent->of_node, diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c index c50a9772f4af..8479a440527b 100644 --- a/drivers/net/ethernet/toshiba/tc35815.c +++ b/drivers/net/ethernet/toshiba/tc35815.c @@ -694,10 +694,10 @@ err_out: * should provide a "tc35815-mac" device with a MAC address in its * platform_data. */ -static int tc35815_mac_match(struct device *dev, void *data) +static int tc35815_mac_match(struct device *dev, const void *data) { struct platform_device *plat_dev = to_platform_device(dev); - struct pci_dev *pci_dev = data; + const struct pci_dev *pci_dev = data; unsigned int id = pci_dev->irq; return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id; } diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index c7892c3da91f..ac5d945be88a 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -76,7 +76,7 @@ static struct bus_type nvmem_bus_type = { .name = "nvmem", }; -static int of_nvmem_match(struct device *dev, void *nvmem_np) +static int of_nvmem_match(struct device *dev, const void *nvmem_np) { return dev->of_node == nvmem_np; } diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index de6157357e26..dfe12948c834 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -282,7 +282,7 @@ unregister: EXPORT_SYMBOL(of_mdiobus_register); /* Helper function for of_phy_find_device */ -static int of_phy_match(struct device *dev, void *phy_np) +static int of_phy_match(struct device *dev, const void *phy_np) { return dev->of_node == phy_np; } diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 04ad312fd85b..008d79e33c2d 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -37,7 +37,7 @@ static const struct of_device_id of_skipped_node_table[] = { {} /* Empty terminated list */ }; -static int of_dev_node_match(struct device *dev, void *data) +static int of_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 0e8e2c186f50..f9ef7ad3f75d 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -64,7 +64,7 @@ static struct resource *get_pci_domain_busn_res(int domain_nr) return &r->res; } -static int find_anything(struct device *dev, void *data) +static int find_anything(struct device *dev, const void *data) { return 1; } diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 5c7922612733..7f4e65872b8d 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -236,10 +236,10 @@ struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus, } EXPORT_SYMBOL(pci_get_domain_bus_and_slot); -static int match_pci_dev_by_id(struct device *dev, void *data) +static int match_pci_dev_by_id(struct device *dev, const void *data) { struct pci_dev *pdev = to_pci_dev(dev); - struct pci_device_id *id = data; + const struct pci_device_id *id = data; if (pci_match_one_device(id, pdev)) return 1; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index aea502922646..a2c97830efe0 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -434,10 +434,10 @@ static int css_probe_device(struct subchannel_id schid, struct schib *schib) } static int -check_subchannel(struct device * dev, void * data) +check_subchannel(struct device *dev, const void *data) { struct subchannel *sch; - struct subchannel_id *schid = data; + struct subchannel_id *schid = (void *)data; sch = to_subchannel(dev); return schid_equal(&sch->schid, schid); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 1540229a37bb..d32f373e5bc7 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -642,10 +642,10 @@ static int ccw_device_add(struct ccw_device *cdev) return device_add(dev); } -static int match_dev_id(struct device *dev, void *data) +static int match_dev_id(struct device *dev, const void *data) { struct ccw_device *cdev = to_ccwdev(dev); - struct ccw_dev_id *dev_id = data; + struct ccw_dev_id *dev_id = (void *)data; return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id); } diff --git a/drivers/s390/cio/scm.c b/drivers/s390/cio/scm.c index 6bca1d5455d4..9f26d4310bb3 100644 --- a/drivers/s390/cio/scm.c +++ b/drivers/s390/cio/scm.c @@ -174,10 +174,10 @@ out: kobject_uevent(&scmdev->dev.kobj, KOBJ_CHANGE); } -static int check_address(struct device *dev, void *data) +static int check_address(struct device *dev, const void *data) { struct scm_device *scmdev = to_scm_dev(dev); - struct sale *sale = data; + const struct sale *sale = data; return scmdev->address == sale->sa; } diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index b9fc502c58c2..b7902b643ec8 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1356,16 +1356,16 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func) * Helper function to be used with bus_find_dev * matches for the card device with the given id */ -static int __match_card_device_with_id(struct device *dev, void *data) +static int __match_card_device_with_id(struct device *dev, const void *data) { - return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long) data; + return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long)(void *) data; } /* * Helper function to be used with bus_find_dev * matches for the queue device with a given qid */ -static int __match_queue_device_with_qid(struct device *dev, void *data) +static int __match_queue_device_with_qid(struct device *dev, const void *data) { return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data; } @@ -1374,7 +1374,7 @@ static int __match_queue_device_with_qid(struct device *dev, void *data) * Helper function to be used with bus_find_dev * matches any queue device with given queue id */ -static int __match_queue_device_with_queue_id(struct device *dev, void *data) +static int __match_queue_device_with_queue_id(struct device *dev, const void *data) { return is_queue_dev(dev) && AP_QID_QUEUE(to_ap_queue(dev)->qid) == (int)(long) data; diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 7f0ceb65c3f3..c074631086a4 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -372,7 +372,7 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, return err; } -static int always_match(struct device *dev, void *data) +static int always_match(struct device *dev, const void *data) { return 1; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5e75944ad5d1..3da1121f7572 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3538,7 +3538,7 @@ EXPORT_SYMBOL_GPL(spi_write_then_read); /*-------------------------------------------------------------------------*/ #if IS_ENABLED(CONFIG_OF) -static int __spi_of_device_match(struct device *dev, void *data) +static int __spi_of_device_match(struct device *dev, const void *data) { return dev->of_node == data; } @@ -3639,7 +3639,7 @@ static int spi_acpi_controller_match(struct device *dev, const void *data) return ACPI_COMPANION(dev->parent) == data; } -static int spi_acpi_device_match(struct device *dev, void *data) +static int spi_acpi_device_match(struct device *dev, const void *data) { return ACPI_COMPANION(dev) == data; } diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index c1b016574fb4..c9a7e4a779cd 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -1946,10 +1946,10 @@ struct tb_sw_lookup { u64 route; }; -static int tb_switch_match(struct device *dev, void *data) +static int tb_switch_match(struct device *dev, const void *data) { struct tb_switch *sw = tb_to_switch(dev); - struct tb_sw_lookup *lookup = data; + const struct tb_sw_lookup *lookup = data; if (!sw) return 0; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index fa783531ee88..7bd7de7273a3 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -947,9 +947,9 @@ error: return ret; } -static int match_devt(struct device *dev, void *data) +static int match_devt(struct device *dev, const void *data) { - return dev->devt == (dev_t) (unsigned long) data; + return dev->devt == (dev_t)(unsigned long)(void *)data; } static struct usb_device *usbdev_lookup_by_devt(dev_t devt) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7fcb9f782931..1678e305e037 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -325,9 +325,9 @@ struct find_interface_arg { struct device_driver *drv; }; -static int __find_interface(struct device *dev, void *data) +static int __find_interface(struct device *dev, const void *data) { - struct find_interface_arg *arg = data; + const struct find_interface_arg *arg = data; struct usb_interface *intf; if (!is_usb_interface(dev)) diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c index a3cb25cb74f8..d16dfc320faa 100644 --- a/drivers/usb/phy/phy-am335x-control.c +++ b/drivers/usb/phy/phy-am335x-control.c @@ -118,9 +118,9 @@ static const struct of_device_id omap_control_usb_id_table[] = { MODULE_DEVICE_TABLE(of, omap_control_usb_id_table); static struct platform_driver am335x_control_driver; -static int match(struct device *dev, void *data) +static int match(struct device *dev, const void *data) { - struct device_node *node = (struct device_node *)data; + const struct device_node *node = (const struct device_node *)data; return dev->of_node == node && dev->driver == &am335x_control_driver.driver; } diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c index 93b7d6a30aad..6cf6fbd39237 100644 --- a/drivers/usb/phy/phy-isp1301.c +++ b/drivers/usb/phy/phy-isp1301.c @@ -142,9 +142,9 @@ static struct i2c_driver isp1301_driver = { module_i2c_driver(isp1301_driver); -static int match(struct device *dev, void *data) +static int match(struct device *dev, const void *data) { - struct device_node *node = (struct device_node *)data; + const struct device_node *node = (const struct device_node *)data; return (dev->of_node == node) && (dev->driver == &isp1301_driver.driver); } diff --git a/drivers/visorbus/visorbus_main.c b/drivers/visorbus/visorbus_main.c index 0b2434cc4ecd..152fd29f04f2 100644 --- a/drivers/visorbus/visorbus_main.c +++ b/drivers/visorbus/visorbus_main.c @@ -171,10 +171,10 @@ struct visor_busdev { u32 dev_no; }; -static int match_visorbus_dev_by_id(struct device *dev, void *data) +static int match_visorbus_dev_by_id(struct device *dev, const void *data) { struct visor_device *vdev = to_visor_device(dev); - struct visor_busdev *id = data; + const struct visor_busdev *id = data; if (vdev->chipset_bus_no == id->bus_no && vdev->chipset_dev_no == id->dev_no) diff --git a/include/linux/device.h b/include/linux/device.h index e85264fb6616..cbbdcadc660e 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -166,8 +166,8 @@ void subsys_dev_iter_exit(struct subsys_dev_iter *iter); int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *dev, void *data)); struct device *bus_find_device(struct bus_type *bus, struct device *start, - void *data, - int (*match)(struct device *dev, void *data)); + const void *data, + int (*match)(struct device *dev, const void *data)); struct device *bus_find_device_by_name(struct bus_type *bus, struct device *start, const char *name); diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 3d0cc6e90d7b..c04c9ed185b7 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -405,7 +405,7 @@ static const struct dailink_match_data dailink_match[] = { }, }; -static int of_dev_node_match(struct device *dev, void *data) +static int of_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data; } -- cgit v1.2.3 From 65f50f255349959f15f2761abd17ead8530b2f33 Mon Sep 17 00:00:00 2001 From: Weitao Hou Date: Tue, 16 Jul 2019 16:26:54 -0700 Subject: kernel: fix typos and some coding style in comments fix lenght to length Link: http://lkml.kernel.org/r/20190521050937.4370-1-houweitaoo@gmail.com Signed-off-by: Weitao Hou Acked-by: Kees Cook Cc: Colin Ian King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/devicetree/bindings/usb/s3c2410-usb.txt | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c | 2 +- kernel/sysctl.c | 18 +++++++++--------- sound/soc/qcom/qdsp6/q6asm.c | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/usb/s3c2410-usb.txt b/Documentation/devicetree/bindings/usb/s3c2410-usb.txt index e45b38ce2986..26c85afd0b53 100644 --- a/Documentation/devicetree/bindings/usb/s3c2410-usb.txt +++ b/Documentation/devicetree/bindings/usb/s3c2410-usb.txt @@ -4,7 +4,7 @@ OHCI Required properties: - compatible: should be "samsung,s3c2410-ohci" for USB host controller - - reg: address and lenght of the controller memory mapped region + - reg: address and length of the controller memory mapped region - interrupts: interrupt number for the USB OHCI controller - clocks: Should reference the bus and host clocks - clock-names: Should contain two strings diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 5e4f3a8c5784..e4332d5a5757 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -53,7 +53,7 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) pad = round_up(skb->len, 4) + 4 - skb->len; /* First packet of a A-MSDU burst keeps track of the whole burst - * length, need to update lenght of it and the last packet. + * length, need to update length of it and the last packet. */ skb_walk_frags(skb, iter) { last = iter; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 1c1ad1e14f21..43186ccfa139 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -188,17 +188,17 @@ extern int no_unaligned_warning; * enum sysctl_writes_mode - supported sysctl write modes * * @SYSCTL_WRITES_LEGACY: each write syscall must fully contain the sysctl value - * to be written, and multiple writes on the same sysctl file descriptor - * will rewrite the sysctl value, regardless of file position. No warning - * is issued when the initial position is not 0. + * to be written, and multiple writes on the same sysctl file descriptor + * will rewrite the sysctl value, regardless of file position. No warning + * is issued when the initial position is not 0. * @SYSCTL_WRITES_WARN: same as above but warn when the initial file position is - * not 0. + * not 0. * @SYSCTL_WRITES_STRICT: writes to numeric sysctl entries must always be at - * file position 0 and the value must be fully contained in the buffer - * sent to the write syscall. If dealing with strings respect the file - * position, but restrict this to the max length of the buffer, anything - * passed the max lenght will be ignored. Multiple writes will append - * to the buffer. + * file position 0 and the value must be fully contained in the buffer + * sent to the write syscall. If dealing with strings respect the file + * position, but restrict this to the max length of the buffer, anything + * passed the max length will be ignored. Multiple writes will append + * to the buffer. * * These write modes control how current file position affects the behavior of * updating sysctl values through the proc interface on each write. diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index 4f85cb19a309..e8141a33a55e 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -1194,7 +1194,7 @@ EXPORT_SYMBOL_GPL(q6asm_open_read); * q6asm_write_async() - non blocking write * * @ac: audio client pointer - * @len: lenght in bytes + * @len: length in bytes * @msw_ts: timestamp msw * @lsw_ts: timestamp lsw * @wflags: flags associated with write -- cgit v1.2.3 From 551626ec0ad28dc43cae3094c35be7088cc625ab Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 17 Jul 2019 14:30:23 +0200 Subject: ALSA: hda/hdmi - Don't report spurious jack state changes The HDMI jack handling reports the state change always via snd_jack_report() whenever hdmi_present_sense() is called, even if the state itself doesn't change from the previous time. This is mostly harmless but still a bit confusing to user-space. This patch reduces such spurious jack state changes and reports only when the state really changed. Also, as a minor optimization, avoid overwriting the pin ELD data when the state is identical. Reviewed-by: Kai Vehmanen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index bea7b0961080..c380596b2e84 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1421,7 +1421,7 @@ static void hdmi_pcm_reset_pin(struct hdmi_spec *spec, /* update per_pin ELD from the given new ELD; * setup info frame and notification accordingly */ -static void update_eld(struct hda_codec *codec, +static bool update_eld(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin, struct hdmi_eld *eld) { @@ -1452,18 +1452,22 @@ static void update_eld(struct hda_codec *codec, snd_hdmi_show_eld(codec, &eld->info); eld_changed = (pin_eld->eld_valid != eld->eld_valid); - if (eld->eld_valid && pin_eld->eld_valid) + eld_changed |= (pin_eld->monitor_present != eld->monitor_present); + if (!eld_changed && eld->eld_valid && pin_eld->eld_valid) if (pin_eld->eld_size != eld->eld_size || memcmp(pin_eld->eld_buffer, eld->eld_buffer, eld->eld_size) != 0) eld_changed = true; - pin_eld->monitor_present = eld->monitor_present; - pin_eld->eld_valid = eld->eld_valid; - pin_eld->eld_size = eld->eld_size; - if (eld->eld_valid) - memcpy(pin_eld->eld_buffer, eld->eld_buffer, eld->eld_size); - pin_eld->info = eld->info; + if (eld_changed) { + pin_eld->monitor_present = eld->monitor_present; + pin_eld->eld_valid = eld->eld_valid; + pin_eld->eld_size = eld->eld_size; + if (eld->eld_valid) + memcpy(pin_eld->eld_buffer, eld->eld_buffer, + eld->eld_size); + pin_eld->info = eld->info; + } /* * Re-setup pin and infoframe. This is needed e.g. when @@ -1481,6 +1485,7 @@ static void update_eld(struct hda_codec *codec, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &get_hdmi_pcm(spec, pcm_idx)->eld_ctl->id); + return eld_changed; } /* update ELD and jack state via HD-audio verbs */ @@ -1582,6 +1587,7 @@ static void sync_eld_via_acomp(struct hda_codec *codec, struct hdmi_spec *spec = codec->spec; struct hdmi_eld *eld = &spec->temp_eld; struct snd_jack *jack = NULL; + bool changed; int size; mutex_lock(&per_pin->lock); @@ -1608,15 +1614,13 @@ static void sync_eld_via_acomp(struct hda_codec *codec, * disconnected event. Jack must be fetched before update_eld() */ jack = pin_idx_to_jack(codec, per_pin); - update_eld(codec, per_pin, eld); + changed = update_eld(codec, per_pin, eld); if (jack == NULL) jack = pin_idx_to_jack(codec, per_pin); - if (jack == NULL) - goto unlock; - snd_jack_report(jack, - (eld->monitor_present && eld->eld_valid) ? + if (changed && jack) + snd_jack_report(jack, + (eld->monitor_present && eld->eld_valid) ? SND_JACK_AVOUT : 0); - unlock: mutex_unlock(&per_pin->lock); } -- cgit v1.2.3 From ade49db337a9d44ac5835cfce1ee873549011b27 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Jul 2018 18:05:52 +0200 Subject: ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component binding like i915, but it worked only with the traditional HD-audio unsolicited event for the HDMI hotplug detection and the ELD read-up thereafter. This has been a problem in many ways: first of all, it goes through the hardware event transition (from GPU register write, HD-audio controller trigger, and finally to HD-audio unsolicited event handling), which is often unreliable and may miss some opportunities. Second, each unsol event handling and ELD read-up need the explicit power up / down when the codec is in the runtime suspend. Last but not least, which is the most important, the hotplug wakeup may be missed when the HD-audio controller is in runtime suspend. Especially the last point is a big problem due to the recent change relevant with vga_switcheroo that forcibly enables the runtime PM for AMD HDMI controllers. These issues are solved by introducing the audio component; the hotplug notification is done by a direct function callback, which is more accurate and reliable, and it can be processed without the actual hardware access, i.e. no runtime PM trigger is needed, and the HD-audio gets the event even if it's in runtime suspend. The same for ELD query, as it's read directly from the cached ELD bytes stored in the DRM driver, hence the whole hardware access can be skipped. So here it is: this patch implements the audio component binding with AMD/ATI and Nouveau DRM drivers. The biggest difference from i915 implementation is that this binding is fully optional and it can be enabled asynchronously on the fly. That is, the driver will switch from the HD-audio unsolicited event to the notify callback once when the DRM component gets bound. Similarly, when DRM driver gets unloaded, the HDMI event handling returns to the legacy mode, too. Also, another difference from i915 is that the new code registers the component in the codec driver, while i915 HDMI codec assumes the component binding was already done in the HD-audio controller driver. Hence the new code does need to de-register the component binding at the codec exit, too. Some other details: - The match component ops assumes that both VGA and HD-audio controller PCI entries belong to the same PCI bus, and only accepts such an entry. - The pin2port audio_ops is implemented with assumption of the fixed widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7, ...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6, ...) As of this patch, the corresponding component isn't implemented in DRM side, so this change alone won't give any benefit. By the following changes in DRM sides, the mission will be completed. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 233 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 211 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index c380596b2e84..2096993eaf28 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -119,6 +120,7 @@ struct hdmi_pcm { }; struct hdmi_spec { + struct hda_codec *codec; int num_cvts; struct snd_array cvts; /* struct hdmi_spec_per_cvt */ hda_nid_t cvt_nids[4]; /* only for haswell fix */ @@ -163,9 +165,11 @@ struct hdmi_spec { struct hda_multi_out multiout; struct hda_pcm_stream pcm_playback; - /* i915/powerwell (Haswell+/Valleyview+) specific */ - bool use_acomp_notifier; /* use i915 eld_notify callback for hotplug */ + bool use_jack_detect; /* jack detection enabled */ + bool use_acomp_notifier; /* use eld_notify callback for hotplug */ + bool acomp_registered; /* audio component registered in this driver */ struct drm_audio_component_audio_ops drm_audio_ops; + int (*port2pin)(struct hda_codec *, int); /* reverse port/pin mapping */ struct hdac_chmap chmap; hda_nid_t vendor_nid; @@ -765,6 +769,10 @@ static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid, static void jack_callback(struct hda_codec *codec, struct hda_jack_callback *jack) { + /* stop polling when notification is enabled */ + if (codec_has_acomp(codec)) + return; + /* hda_jack don't support DP MST */ check_presence_and_report(codec, jack->nid, 0); } @@ -823,6 +831,9 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) int tag = res >> AC_UNSOL_RES_TAG_SHIFT; int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; + if (codec_has_acomp(codec)) + return; + if (!snd_hda_jack_tbl_get_from_tag(codec, tag)) { codec_dbg(codec, "Unexpected HDMI event tag 0x%x\n", tag); return; @@ -1636,18 +1647,13 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) snd_hda_power_down_pm(codec); return false; } - } - - if (codec_has_acomp(codec)) { + ret = hdmi_present_sense_via_verbs(per_pin, repoll); + snd_hda_power_down_pm(codec); + } else { sync_eld_via_acomp(codec, per_pin); ret = false; /* don't call snd_hda_jack_report_sync() */ - } else { - ret = hdmi_present_sense_via_verbs(per_pin, repoll); } - if (!codec_has_acomp(codec)) - snd_hda_power_down_pm(codec); - return ret; } @@ -2252,6 +2258,8 @@ static int generic_hdmi_init(struct hda_codec *codec) struct hdmi_spec *spec = codec->spec; int pin_idx; + mutex_lock(&spec->pcm_lock); + spec->use_jack_detect = !codec->jackpoll_interval; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; @@ -2259,11 +2267,15 @@ static int generic_hdmi_init(struct hda_codec *codec) snd_hda_set_dev_select(codec, pin_nid, dev_id); hdmi_init_pin(codec, pin_nid); - if (!codec_has_acomp(codec)) + if (codec_has_acomp(codec)) + continue; + if (spec->use_jack_detect) + snd_hda_jack_detect_enable(codec, pin_nid); + else snd_hda_jack_detect_enable_callback(codec, pin_nid, - codec->jackpoll_interval > 0 ? - jack_callback : NULL); + jack_callback); } + mutex_unlock(&spec->pcm_lock); return 0; } @@ -2296,7 +2308,9 @@ static void generic_hdmi_free(struct hda_codec *codec) struct hdmi_spec *spec = codec->spec; int pin_idx, pcm_idx; - if (codec_has_acomp(codec)) { + if (spec->acomp_registered) { + snd_hdac_acomp_exit(&codec->bus->core); + } else if (codec_has_acomp(codec)) { snd_hdac_acomp_register_notifier(&codec->bus->core, NULL); codec->relaxed_resume = 0; } @@ -2364,6 +2378,7 @@ static int alloc_generic_hdmi(struct hda_codec *codec) if (!spec) return -ENOMEM; + spec->codec = codec; spec->ops = generic_standard_hdmi_ops; spec->dev_num = 1; /* initialize to 1 */ mutex_init(&spec->pcm_lock); @@ -2401,6 +2416,136 @@ static int patch_generic_hdmi(struct hda_codec *codec) return 0; } +/* + * generic audio component binding + */ + +/* turn on / off the unsol event jack detection dynamically */ +static void reprogram_jack_detect(struct hda_codec *codec, hda_nid_t nid, + bool use_acomp) +{ + struct hda_jack_tbl *tbl; + + tbl = snd_hda_jack_tbl_get(codec, nid); + if (tbl) { + /* clear unsol even if component notifier is used, or re-enable + * if notifier is cleared + */ + unsigned int val = use_acomp ? 0 : (AC_USRSP_EN | tbl->tag); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, val); + } else { + /* if no jack entry was defined beforehand, create a new one + * at need (i.e. only when notifier is cleared) + */ + if (!use_acomp) + snd_hda_jack_detect_enable(codec, nid); + } +} + +/* set up / clear component notifier dynamically */ +static void generic_acomp_notifier_set(struct drm_audio_component *acomp, + bool use_acomp) +{ + struct hdmi_spec *spec; + int i; + + spec = container_of(acomp->audio_ops, struct hdmi_spec, drm_audio_ops); + mutex_lock(&spec->pcm_lock); + spec->use_acomp_notifier = use_acomp; + spec->codec->relaxed_resume = use_acomp; + /* reprogram each jack detection logic depending on the notifier */ + if (spec->use_jack_detect) { + for (i = 0; i < spec->num_pins; i++) + reprogram_jack_detect(spec->codec, + get_pin(spec, i)->pin_nid, + use_acomp); + } + mutex_unlock(&spec->pcm_lock); +} + +/* enable / disable the notifier via master bind / unbind */ +static int generic_acomp_master_bind(struct device *dev, + struct drm_audio_component *acomp) +{ + generic_acomp_notifier_set(acomp, true); + return 0; +} + +static void generic_acomp_master_unbind(struct device *dev, + struct drm_audio_component *acomp) +{ + generic_acomp_notifier_set(acomp, false); +} + +/* check whether both HD-audio and DRM PCI devices belong to the same bus */ +static int match_bound_vga(struct device *dev, int subtype, void *data) +{ + struct hdac_bus *bus = data; + struct pci_dev *pci, *master; + + if (!dev_is_pci(dev) || !dev_is_pci(bus->dev)) + return 0; + master = to_pci_dev(bus->dev); + pci = to_pci_dev(dev); + return master->bus == pci->bus; +} + +/* audio component notifier for AMD/Nvidia HDMI codecs */ +static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id) +{ + struct hda_codec *codec = audio_ptr; + struct hdmi_spec *spec = codec->spec; + hda_nid_t pin_nid = spec->port2pin(codec, port); + + if (!pin_nid) + return; + if (get_wcaps_type(get_wcaps(codec, pin_nid)) != AC_WID_PIN) + return; + /* skip notification during system suspend (but not in runtime PM); + * the state will be updated at resume + */ + if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0) + return; + /* ditto during suspend/resume process itself */ + if (snd_hdac_is_in_pm(&codec->core)) + return; + + check_presence_and_report(codec, pin_nid, dev_id); +} + +/* set up the private drm_audio_ops from the template */ +static void setup_drm_audio_ops(struct hda_codec *codec, + const struct drm_audio_component_audio_ops *ops) +{ + struct hdmi_spec *spec = codec->spec; + + spec->drm_audio_ops.audio_ptr = codec; + /* intel_audio_codec_enable() or intel_audio_codec_disable() + * will call pin_eld_notify with using audio_ptr pointer + * We need make sure audio_ptr is really setup + */ + wmb(); + spec->drm_audio_ops.pin2port = ops->pin2port; + spec->drm_audio_ops.pin_eld_notify = ops->pin_eld_notify; + spec->drm_audio_ops.master_bind = ops->master_bind; + spec->drm_audio_ops.master_unbind = ops->master_unbind; +} + +/* initialize the generic HDMI audio component */ +static void generic_acomp_init(struct hda_codec *codec, + const struct drm_audio_component_audio_ops *ops, + int (*port2pin)(struct hda_codec *, int)) +{ + struct hdmi_spec *spec = codec->spec; + + spec->port2pin = port2pin; + setup_drm_audio_ops(codec, ops); + if (!snd_hdac_acomp_init(&codec->bus->core, &spec->drm_audio_ops, + match_bound_vga, 0)) + spec->acomp_registered = true; +} + /* * Intel codec parsers and helpers */ @@ -2569,20 +2714,19 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe) check_presence_and_report(codec, pin_nid, dev_id); } +static const struct drm_audio_component_audio_ops intel_audio_ops = { + .pin2port = intel_pin2port, + .pin_eld_notify = intel_pin_eld_notify, +}; + /* register i915 component pin_eld_notify callback */ static void register_i915_notifier(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; spec->use_acomp_notifier = true; - spec->drm_audio_ops.audio_ptr = codec; - /* intel_audio_codec_enable() or intel_audio_codec_disable() - * will call pin_eld_notify with using audio_ptr pointer - * We need make sure audio_ptr is really setup - */ - wmb(); - spec->drm_audio_ops.pin2port = intel_pin2port; - spec->drm_audio_ops.pin_eld_notify = intel_pin_eld_notify; + spec->port2pin = intel_port2pin; + setup_drm_audio_ops(codec, &intel_audio_ops); snd_hdac_acomp_register_notifier(&codec->bus->core, &spec->drm_audio_ops); /* no need for forcible resume for jack check thanks to notifier */ @@ -2980,6 +3124,7 @@ static int patch_simple_hdmi(struct hda_codec *codec, if (!spec) return -ENOMEM; + spec->codec = codec; codec->spec = spec; hdmi_array_init(spec, 1); @@ -3284,6 +3429,26 @@ static int nvhdmi_chmap_validate(struct hdac_chmap *chmap, return 0; } +/* map from pin NID to port; port is 0-based */ +/* for Nvidia: assume widget NID starting from 4, with step 1 (4, 5, 6, ...) */ +static int nvhdmi_pin2port(void *audio_ptr, int pin_nid) +{ + return pin_nid - 4; +} + +/* reverse-map from port to pin NID: see above */ +static int nvhdmi_port2pin(struct hda_codec *codec, int port) +{ + return port + 4; +} + +static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = { + .pin2port = nvhdmi_pin2port, + .pin_eld_notify = generic_acomp_pin_eld_notify, + .master_bind = generic_acomp_master_bind, + .master_unbind = generic_acomp_master_unbind, +}; + static int patch_nvhdmi(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -3300,6 +3465,8 @@ static int patch_nvhdmi(struct hda_codec *codec) nvhdmi_chmap_cea_alloc_validate_get_type; spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; + generic_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin); + return 0; } @@ -3787,6 +3954,26 @@ static int atihdmi_init(struct hda_codec *codec) return 0; } +/* map from pin NID to port; port is 0-based */ +/* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */ +static int atihdmi_pin2port(void *audio_ptr, int pin_nid) +{ + return pin_nid / 2 - 1; +} + +/* reverse-map from port to pin NID: see above */ +static int atihdmi_port2pin(struct hda_codec *codec, int port) +{ + return port * 2 + 3; +} + +static const struct drm_audio_component_audio_ops atihdmi_audio_ops = { + .pin2port = atihdmi_pin2port, + .pin_eld_notify = generic_acomp_pin_eld_notify, + .master_bind = generic_acomp_master_bind, + .master_unbind = generic_acomp_master_unbind, +}; + static int patch_atihdmi(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -3835,6 +4022,8 @@ static int patch_atihdmi(struct hda_codec *codec) */ codec->link_down_at_suspend = 1; + generic_acomp_init(codec, &atihdmi_audio_ops, atihdmi_port2pin); + return 0; } -- cgit v1.2.3 From caa8422d01e983782548648e125fd617cadcec3f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 20 Jul 2019 12:33:37 +0100 Subject: ALSA: hda: Flush interrupts on disabling I was looking at <4> [241.835158] general protection fault: 0000 [#1] PREEMPT SMP PTI <4> [241.835181] CPU: 1 PID: 214 Comm: kworker/1:3 Tainted: G U 5.2.0-CI-CI_DRM_6509+ #1 <4> [241.835199] Hardware name: Dell Inc. OptiPlex 745 /0GW726, BIOS 2.3.1 05/21/2007 <4> [241.835234] Workqueue: events snd_hdac_bus_process_unsol_events [snd_hda_core] <4> [241.835256] RIP: 0010:input_handle_event+0x16d/0x5e0 <4> [241.835270] Code: 48 8b 93 58 01 00 00 8b 52 08 89 50 04 8b 83 f8 06 00 00 48 8b 93 00 07 00 00 8d 70 01 48 8d 04 c2 83 e1 08 89 b3 f8 06 00 00 <66> 89 28 66 44 89 60 02 44 89 68 04 8b 93 f8 06 00 00 0f 84 fd fe <4> [241.835304] RSP: 0018:ffffc9000019fda0 EFLAGS: 00010046 <4> [241.835317] RAX: 6b6b6b6ec6c6c6c3 RBX: ffff8880290fefc8 RCX: 0000000000000000 <4> [241.835332] RDX: 000000006b6b6b6b RSI: 000000006b6b6b6c RDI: 0000000000000046 <4> [241.835347] RBP: 0000000000000005 R08: 0000000000000000 R09: 0000000000000001 <4> [241.835362] R10: ffffc9000019faa0 R11: 0000000000000000 R12: 0000000000000004 <4> [241.835377] R13: 0000000000000000 R14: ffff8880290ff1d0 R15: 0000000000000293 <4> [241.835392] FS: 0000000000000000(0000) GS:ffff88803de80000(0000) knlGS:0000000000000000 <4> [241.835409] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 <4> [241.835422] CR2: 00007ffe9a99e9b7 CR3: 000000002f588000 CR4: 00000000000006e0 <4> [241.835436] Call Trace: <4> [241.835449] input_event+0x45/0x70 <4> [241.835464] snd_jack_report+0xdc/0x100 <4> [241.835490] snd_hda_jack_report_sync+0x83/0xc0 [snd_hda_codec] <4> [241.835512] snd_hdac_bus_process_unsol_events+0x5a/0x70 [snd_hda_core] <4> [241.835530] process_one_work+0x245/0x610 which has the hallmarks of a worker queued from interrupt after it was supposedly cancelled (note the POISON_FREE), and I could not see where the interrupt would be flushed on shutdown so added the likely suspects. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=111174 Signed-off-by: Chris Wilson Signed-off-by: Takashi Iwai --- sound/hda/hdac_controller.c | 2 ++ sound/pci/hda/hda_intel.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 3b0110545070..196bbc85699e 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -447,6 +447,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); + synchronize_irq(bus->irq); + /* disable SIE for all streams */ snd_hdac_chip_writeb(bus, INTCTL, 0); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cb8b0945547c..fdde80d95966 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1301,9 +1301,9 @@ static int azx_free(struct azx *chip) } if (bus->chip_init) { + azx_stop_chip(chip); azx_clear_irq_pending(chip); azx_stop_all_streams(chip); - azx_stop_chip(chip); } if (bus->irq >= 0) -- cgit v1.2.3 From ef9bec27485fefb6b93168fea73fda0dc9638046 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 26 Jun 2019 00:04:50 -0700 Subject: ASoC: SOF: Intel: hda: Make hdac_device device-managed snd_hdac_ext_bus_device_exit() has been recently modified to no longer free the hdac device. SOF allocates memory for hdac_device and hda_hda_priv with kzalloc. Make them device-managed instead so that they will be freed when the SOF driver is unloaded. Because of the above change, hda_codec is device-managed and it will be freed when the ASoC device is removed. Freeing the codec in snd_hda_codec_dev_release() leads to kernel panic while unloading and reloading the ASoC driver. So, avoid freeing the hda_codec for ASoC driver. This is done in the same patch to avoid bisect failure. Signed-off-by: Libin Yang Signed-off-by: Ranjani Sridharan Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20190626070450.7229-1-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/pci/hda/hda_codec.c | 8 +++++++- sound/soc/sof/intel/hda-codec.c | 6 ++---- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e30e86ca6b72..133200d31170 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -846,7 +846,13 @@ static void snd_hda_codec_dev_release(struct device *dev) snd_hda_sysfs_clear(codec); kfree(codec->modelname); kfree(codec->wcaps); - kfree(codec); + + /* + * In the case of ASoC HD-audio, hda_codec is device managed. + * It will be freed when the ASoC device is removed. + */ + if (codec->core.type == HDA_DEV_LEGACY) + kfree(codec); } #define DEV_NAME_LEN 31 diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index b8b37f082309..0d8437b080bf 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -62,8 +62,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) address, resp); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) - /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */ - hda_priv = kzalloc(sizeof(*hda_priv), GFP_KERNEL); + hda_priv = devm_kzalloc(sdev->dev, sizeof(*hda_priv), GFP_KERNEL); if (!hda_priv) return -ENOMEM; @@ -82,8 +81,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) return 0; #else - /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */ - hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); + hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL); if (!hdev) return -ENOMEM; -- cgit v1.2.3 From f7408a3d5b5fd10571a653d1a81ce9167c62727f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 9 Jul 2019 22:04:25 -0700 Subject: ASoC: wcd9335: Fix misuse of GENMASK macro Arguments are supposed to be ordered high then low. Signed-off-by: Joe Perches Link: https://lore.kernel.org/r/92e31a9f321fe731d428ec3ec9d4654ea8a16d1b.1562734889.git.joe@perches.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd-clsh-v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c index c397d713f01a..cc5a9c9b918b 100644 --- a/sound/soc/codecs/wcd-clsh-v2.c +++ b/sound/soc/codecs/wcd-clsh-v2.c @@ -65,7 +65,7 @@ struct wcd_clsh_ctrl { #define WCD9XXX_FLYBACK_EN_PWDN_WITH_DELAY 0 #define WCD9XXX_RX_BIAS_FLYB_BUFF WCD9335_REG(0x6, 0xC7) #define WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4) -#define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(0, 3) +#define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(3, 0) #define WCD9XXX_HPH_L_EN WCD9335_REG(0x6, 0xD3) #define WCD9XXX_HPH_CONST_SEL_L_MASK GENMASK(7, 3) #define WCD9XXX_HPH_CONST_SEL_BYPASS 0 -- cgit v1.2.3 From eaba5585944e6d692828bca701c9362f60172b8a Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Wed, 10 Jul 2019 13:51:19 +0300 Subject: ASoC: codecs: ad193x: Use regmap_multi_reg_write() when initializing Using regmap_multi_reg_write() when we set the default values for our registers makes the code smaller and easier to read. Suggested-by: Tzung-Bi Shih Signed-off-by: Codrin Ciubotariu Reviewed-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20190710105119.22987-1-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- sound/soc/codecs/ad193x.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 80dab5df9633..fb04c9379b71 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -413,15 +413,10 @@ static struct snd_soc_dai_driver ad193x_no_adc_dai = { .ops = &ad193x_dai_ops, }; -struct ad193x_reg_default { - unsigned int reg; - unsigned int val; -}; - /* codec register values to set after reset */ static void ad193x_reg_default_init(struct ad193x_priv *ad193x) { - const struct ad193x_reg_default reg_init[] = { + const struct reg_sequence reg_init[] = { { 0, 0x99 }, /* PLL_CLK_CTRL0: pll input: mclki/xi 12.288Mhz */ { 1, 0x04 }, /* PLL_CLK_CTRL1: no on-chip Vref */ { 2, 0x40 }, /* DAC_CTRL0: TDM mode */ @@ -437,21 +432,17 @@ static void ad193x_reg_default_init(struct ad193x_priv *ad193x) { 12, 0x00 }, /* DAC_L4_VOL: no attenuation */ { 13, 0x00 }, /* DAC_R4_VOL: no attenuation */ }; - const struct ad193x_reg_default reg_adc_init[] = { + const struct reg_sequence reg_adc_init[] = { { 14, 0x03 }, /* ADC_CTRL0: high-pass filter enable */ { 15, 0x43 }, /* ADC_CTRL1: sata delay=1, adc aux mode */ { 16, 0x00 }, /* ADC_CTRL2: reset */ }; - int i; - for (i = 0; i < ARRAY_SIZE(reg_init); i++) - regmap_write(ad193x->regmap, reg_init[i].reg, reg_init[i].val); + regmap_multi_reg_write(ad193x->regmap, reg_init, ARRAY_SIZE(reg_init)); if (ad193x_has_adc(ad193x)) { - for (i = 0; i < ARRAY_SIZE(reg_adc_init); i++) { - regmap_write(ad193x->regmap, reg_adc_init[i].reg, - reg_adc_init[i].val); - } + regmap_multi_reg_write(ad193x->regmap, reg_adc_init, + ARRAY_SIZE(reg_adc_init)); } } -- cgit v1.2.3 From 4dc057a786dc23fd1ed70e6bcab691c0f26daa1e Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Wed, 10 Jul 2019 17:28:38 -0700 Subject: ASoC: rt5677: remove superfluous set We define this variable with the same value, no need to set it twice Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20190711002838.35363-1-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index c779dc3474f9..deaed5132dc9 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5098,7 +5098,6 @@ static irqreturn_t rt5677_irq(int unused, void *data) goto exit; } - irq_fired = false; for (i = 0; i < RT5677_IRQ_NUM; i++) { if (reg_irq & rt5677_irq_descs[i].status_mask) { irq_fired = true; -- cgit v1.2.3 From 5be6155b50bbf7083b4bfa219e4ce6d1491f42f0 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 11 Jul 2019 18:49:45 +0800 Subject: ASoC: fsl_esai: Wrap some operations to be functions Extract the operation to be functions, to improve the readability. In this patch, fsl_esai_hw_init, fsl_esai_register_restore, fsl_esai_trigger_start and fsl_esai_trigger_stop are extracted. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/804d7e75ae7e06a913479912b578b3538ca7cd3f.1562842206.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 188 +++++++++++++++++++++++++++++------------------ 1 file changed, 117 insertions(+), 71 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 10d2210c91ef..ab460d6d7432 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -35,6 +35,7 @@ * @fifo_depth: depth of tx/rx FIFO * @slot_width: width of each DAI slot * @slots: number of slots + * @channels: channel num for tx or rx * @hck_rate: clock rate of desired HCKx clock * @sck_rate: clock rate of desired SCKx clock * @hck_dir: the direction of HCKx pads @@ -57,6 +58,7 @@ struct fsl_esai { u32 slots; u32 tx_mask; u32 rx_mask; + u32 channels[2]; u32 hck_rate[2]; u32 sck_rate[2]; bool hck_dir[2]; @@ -543,64 +545,132 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, return 0; } +static int fsl_esai_hw_init(struct fsl_esai *esai_priv) +{ + struct platform_device *pdev = esai_priv->pdev; + int ret; + + /* Reset ESAI unit */ + ret = regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR, + ESAI_ECR_ESAIEN_MASK | ESAI_ECR_ERST_MASK, + ESAI_ECR_ESAIEN | ESAI_ECR_ERST); + if (ret) { + dev_err(&pdev->dev, "failed to reset ESAI: %d\n", ret); + return ret; + } + + /* + * We need to enable ESAI so as to access some of its registers. + * Otherwise, we would fail to dump regmap from user space. + */ + ret = regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR, + ESAI_ECR_ESAIEN_MASK | ESAI_ECR_ERST_MASK, + ESAI_ECR_ESAIEN); + if (ret) { + dev_err(&pdev->dev, "failed to enable ESAI: %d\n", ret); + return ret; + } + + regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, + ESAI_PRRC_PDC_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, + ESAI_PCRC_PC_MASK, 0); + + return 0; +} + +static int fsl_esai_register_restore(struct fsl_esai *esai_priv) +{ + int ret; + + /* FIFO reset for safety */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_TFCR, + ESAI_xFCR_xFR, ESAI_xFCR_xFR); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RFCR, + ESAI_xFCR_xFR, ESAI_xFCR_xFR); + + regcache_mark_dirty(esai_priv->regmap); + ret = regcache_sync(esai_priv->regmap); + if (ret) + return ret; + + /* FIFO reset done */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0); + + return 0; +} + +static void fsl_esai_trigger_start(struct fsl_esai *esai_priv, bool tx) +{ + u8 i, channels = esai_priv->channels[tx]; + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); + u32 mask; + + regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), + ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN); + + /* Write initial words reqiured by ESAI as normal procedure */ + for (i = 0; tx && i < channels; i++) + regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0); + + /* + * When set the TE/RE in the end of enablement flow, there + * will be channel swap issue for multi data line case. + * In order to workaround this issue, we switch the bit + * enablement sequence to below sequence + * 1) clear the xSMB & xSMA: which is done in probe and + * stop state. + * 2) set TE/RE + * 3) set xSMB + * 4) set xSMA: xSMA is the last one in this flow, which + * will trigger esai to start. + */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, + tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); + mask = tx ? esai_priv->tx_mask : esai_priv->rx_mask; + + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), + ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), + ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask)); +} + +static void fsl_esai_trigger_stop(struct fsl_esai *esai_priv, bool tx) +{ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), + ESAI_xSMA_xS_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), + ESAI_xSMB_xS_MASK, 0); + + /* Disable and reset FIFO */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), + ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), + ESAI_xFCR_xFR, 0); +} + static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - u8 i, channels = substream->runtime->channels; - u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); - u32 mask; + + esai_priv->channels[tx] = substream->runtime->channels; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), - ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN); - - /* Write initial words reqiured by ESAI as normal procedure */ - for (i = 0; tx && i < channels; i++) - regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0); - - /* - * When set the TE/RE in the end of enablement flow, there - * will be channel swap issue for multi data line case. - * In order to workaround this issue, we switch the bit - * enablement sequence to below sequence - * 1) clear the xSMB & xSMA: which is done in probe and - * stop state. - * 2) set TE/RE - * 3) set xSMB - * 4) set xSMA: xSMA is the last one in this flow, which - * will trigger esai to start. - */ - regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), - tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, - tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); - mask = tx ? esai_priv->tx_mask : esai_priv->rx_mask; - - regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), - ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), - ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask)); - + fsl_esai_trigger_start(esai_priv, tx); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), - tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0); - regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), - ESAI_xSMA_xS_MASK, 0); - regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), - ESAI_xSMB_xS_MASK, 0); - - /* Disable and reset FIFO */ - regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), - ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR); - regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), - ESAI_xFCR_xFR, 0); + fsl_esai_trigger_stop(esai_priv, tx); break; default: return -EINVAL; @@ -866,22 +936,9 @@ static int fsl_esai_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, esai_priv); - /* Reset ESAI unit */ - ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ERST); - if (ret) { - dev_err(&pdev->dev, "failed to reset ESAI: %d\n", ret); - return ret; - } - - /* - * We need to enable ESAI so as to access some of its registers. - * Otherwise, we would fail to dump regmap from user space. - */ - ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ESAIEN); - if (ret) { - dev_err(&pdev->dev, "failed to enable ESAI: %d\n", ret); + ret = fsl_esai_hw_init(esai_priv); + if (ret) return ret; - } esai_priv->tx_mask = 0xFFFFFFFF; esai_priv->rx_mask = 0xFFFFFFFF; @@ -955,20 +1012,10 @@ static int fsl_esai_runtime_resume(struct device *dev) regcache_cache_only(esai->regmap, false); - /* FIFO reset for safety */ - regmap_update_bits(esai->regmap, REG_ESAI_TFCR, - ESAI_xFCR_xFR, ESAI_xFCR_xFR); - regmap_update_bits(esai->regmap, REG_ESAI_RFCR, - ESAI_xFCR_xFR, ESAI_xFCR_xFR); - - ret = regcache_sync(esai->regmap); + ret = fsl_esai_register_restore(esai); if (ret) goto err_regcache_sync; - /* FIFO reset done */ - regmap_update_bits(esai->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0); - regmap_update_bits(esai->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0); - return 0; err_regcache_sync: @@ -991,7 +1038,6 @@ static int fsl_esai_runtime_suspend(struct device *dev) struct fsl_esai *esai = dev_get_drvdata(dev); regcache_cache_only(esai->regmap, true); - regcache_mark_dirty(esai->regmap); if (!IS_ERR(esai->fsysclk)) clk_disable_unprepare(esai->fsysclk); -- cgit v1.2.3 From 1d3dd532883be6167da5df6117efd6d4e8790456 Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Tue, 9 Jul 2019 23:55:43 +0530 Subject: sound: soc: codecs: mt6358: change return type of mt6358_codec_init_reg As mt6358_codec_init_reg function always returns 0 , change return type from int to void. fixes below issue reported by coccicheck sound/soc/codecs/mt6358.c:2260:5-8: Unneeded variable: "ret". Return "0" on line 2289 Signed-off-by: Hariprasad Kelam Acked-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20190709182543.GA6611@hari-Inspiron-1545 Signed-off-by: Mark Brown --- sound/soc/codecs/mt6358.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index 50b3fc5457ea..c17250aab2d0 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -2255,10 +2255,8 @@ static struct snd_soc_dai_driver mt6358_dai_driver[] = { }, }; -static int mt6358_codec_init_reg(struct mt6358_priv *priv) +static void mt6358_codec_init_reg(struct mt6358_priv *priv) { - int ret = 0; - /* Disable HeadphoneL/HeadphoneR short circuit protection */ regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, RG_AUDHPLSCDISABLE_VAUDP15_MASK_SFT, @@ -2285,8 +2283,6 @@ static int mt6358_codec_init_reg(struct mt6358_priv *priv) /* set gpio */ playback_gpio_reset(priv); capture_gpio_reset(priv); - - return ret; } static int mt6358_codec_probe(struct snd_soc_component *cmpnt) -- cgit v1.2.3 From e1fb714bddf452ef0ecf67c420957438977f107d Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Wed, 10 Jul 2019 00:12:37 +0530 Subject: ASoC: bcm: cygnus-pcm: Unneeded variable: "ret". This patch fixes below issues reported by coccicheck sound/soc/bcm/cygnus-pcm.c:642:5-8: Unneeded variable: "ret". Return "0" on line 650 sound/soc/bcm/cygnus-pcm.c:671:5-8: Unneeded variable: "ret". Return "0" on line 696 We cannot change return type of these functions as they are callback functions of snd_pcm_ops Signed-off-by: Hariprasad Kelam Link: https://lore.kernel.org/r/20190709184236.GA7873@hari-Inspiron-1545 Signed-off-by: Mark Brown --- sound/soc/bcm/cygnus-pcm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c index 123ecf5479d7..8966b02844dc 100644 --- a/sound/soc/bcm/cygnus-pcm.c +++ b/sound/soc/bcm/cygnus-pcm.c @@ -639,7 +639,6 @@ static int cygnus_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct cygnus_aio_port *aio; - int ret = 0; aio = cygnus_dai_get_dma_data(substream); dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum); @@ -647,7 +646,7 @@ static int cygnus_pcm_hw_params(struct snd_pcm_substream *substream, snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = params_buffer_bytes(params); - return ret; + return 0; } static int cygnus_pcm_hw_free(struct snd_pcm_substream *substream) @@ -668,7 +667,6 @@ static int cygnus_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct cygnus_aio_port *aio; unsigned long bufsize, periodsize; - int ret = 0; bool is_play; u32 start; struct ringbuf_regs *p_rbuf = NULL; @@ -693,7 +691,7 @@ static int cygnus_pcm_prepare(struct snd_pcm_substream *substream) ringbuf_set_initial(aio->cygaud->audio, p_rbuf, is_play, start, periodsize, bufsize); - return ret; + return 0; } static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_pcm_substream *substream) -- cgit v1.2.3 From af62a3c8a872631e63833e2a99a8f43f81532fae Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Wed, 10 Jul 2019 07:46:27 +0530 Subject: ASoC: wcd9335: add irqflag IRQF_ONESHOT flag Add IRQF_ONESHOT to ensure "Interrupt is not reenabled after the hardirq handler finished". fixes below issue reported by coccicheck sound/soc/codecs/wcd9335.c:4068:8-33: ERROR: Threaded IRQ with no primary handler requested without IRQF_ONESHOT Signed-off-by: Hariprasad Kelam Link: https://lore.kernel.org/r/20190710021627.GA13396@hari-Inspiron-1545 Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 1bbbe421b999..956602788d0e 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -4062,7 +4062,8 @@ static int wcd9335_setup_irqs(struct wcd9335_codec *wcd) ret = devm_request_threaded_irq(wcd->dev, irq, NULL, wcd9335_irqs[i].handler, - IRQF_TRIGGER_RISING, + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, wcd9335_irqs[i].name, wcd); if (ret) { dev_err(wcd->dev, "Failed to request %s\n", -- cgit v1.2.3 From a962a809e5e45715081fa247726a562b8dbd082a Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Tue, 16 Jul 2019 11:24:17 +0800 Subject: ASoC: mediatek: mt8183: make headset codec optional Make headset codec optional because some variant machines may not have an audio jack. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20190716032417.19015-1-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 887c932229d0..4c816c86844b 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -352,8 +352,6 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_max98357_card = { .owner = THIS_MODULE, .dai_link = mt8183_mt6358_ts3a227_max98357_dai_links, .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dai_links), - .aux_dev = &mt8183_mt6358_ts3a227_max98357_headset_dev, - .num_aux_devs = 1, }; static int @@ -404,10 +402,9 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) mt8183_mt6358_ts3a227_max98357_headset_dev.codec_of_node = of_parse_phandle(pdev->dev.of_node, "mediatek,headset-codec", 0); - if (!mt8183_mt6358_ts3a227_max98357_headset_dev.codec_of_node) { - dev_err(&pdev->dev, - "Property 'mediatek,headset-codec' missing/invalid\n"); - return -EINVAL; + if (mt8183_mt6358_ts3a227_max98357_headset_dev.codec_of_node) { + card->aux_dev = &mt8183_mt6358_ts3a227_max98357_headset_dev; + card->num_aux_devs = 1; } default_pins = -- cgit v1.2.3 From 89c9679f699d88986ce552738dc7c5c500c8fc67 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 17 Jul 2019 12:56:33 +0200 Subject: ASoC: fsl_sai: add of_match data New revisions of the SAI IP block have even more differences that need be taken into account by the driver. To avoid sprinking compatible checks all over the driver move the current differences into of_match_data. Signed-off-by: Lucas Stach Tested-by: Angus Ainslie Reviewed-by: Angus Ainslie Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/20190717105635.18514-2-l.stach@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 22 ++++++++++++++-------- sound/soc/fsl/fsl_sai.h | 6 +++++- 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index d58cc3ae90d8..ed0432e7327a 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -788,10 +789,7 @@ static int fsl_sai_probe(struct platform_device *pdev) return -ENOMEM; sai->pdev = pdev; - - if (of_device_is_compatible(np, "fsl,imx6sx-sai") || - of_device_is_compatible(np, "fsl,imx6ul-sai")) - sai->sai_on_imx = true; + sai->soc_data = of_device_get_match_data(&pdev->dev); sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); @@ -900,7 +898,7 @@ static int fsl_sai_probe(struct platform_device *pdev) if (ret) return ret; - if (sai->sai_on_imx) + if (sai->soc_data->use_imx_pcm) return imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE); else return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); @@ -913,10 +911,18 @@ static int fsl_sai_remove(struct platform_device *pdev) return 0; } +static const struct fsl_sai_soc_data fsl_sai_vf610_data = { + .use_imx_pcm = false, +}; + +static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = { + .use_imx_pcm = true, +}; + static const struct of_device_id fsl_sai_ids[] = { - { .compatible = "fsl,vf610-sai", }, - { .compatible = "fsl,imx6sx-sai", }, - { .compatible = "fsl,imx6ul-sai", }, + { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data }, + { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data }, + { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6sx_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 24cb156bf995..83e2bfe05b1b 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -126,6 +126,10 @@ #define FSL_SAI_MAXBURST_TX 6 #define FSL_SAI_MAXBURST_RX 6 +struct fsl_sai_soc_data { + bool use_imx_pcm; +}; + struct fsl_sai { struct platform_device *pdev; struct regmap *regmap; @@ -135,7 +139,6 @@ struct fsl_sai { bool is_slave_mode; bool is_lsb_first; bool is_dsp_mode; - bool sai_on_imx; bool synchronous[2]; unsigned int mclk_id[2]; @@ -143,6 +146,7 @@ struct fsl_sai { unsigned int slots; unsigned int slot_width; + const struct fsl_sai_soc_data *soc_data; struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; }; -- cgit v1.2.3 From bd517707d85f19a7339ea8b882fcbf0fd9976bd6 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 17 Jul 2019 12:56:34 +0200 Subject: ASoC: fsl_sai: derive TX FIFO watermark from FIFO depth The DMA request schould be triggered as soon as the FIFO has space for another burst. As different versions of the SAI block have different FIFO sizes, the watrmark level needs to be derived from version specific data. Signed-off-by: Lucas Stach Tested-by: Angus Ainslie Reviewed-by: Angus Ainslie Link: https://lore.kernel.org/r/20190717105635.18514-3-l.stach@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 4 +++- sound/soc/fsl/fsl_sai.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index ed0432e7327a..1d1a447163e3 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -640,7 +640,7 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) regmap_write(sai->regmap, FSL_SAI_RCSR, 0); regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, - FSL_SAI_MAXBURST_TX * 2); + sai->soc_data->fifo_depth - FSL_SAI_MAXBURST_TX); regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, FSL_SAI_MAXBURST_RX - 1); @@ -913,10 +913,12 @@ static int fsl_sai_remove(struct platform_device *pdev) static const struct fsl_sai_soc_data fsl_sai_vf610_data = { .use_imx_pcm = false, + .fifo_depth = 32, }; static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = { .use_imx_pcm = true, + .fifo_depth = 32, }; static const struct of_device_id fsl_sai_ids[] = { diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 83e2bfe05b1b..7c1ef671da28 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -128,6 +128,7 @@ struct fsl_sai_soc_data { bool use_imx_pcm; + unsigned int fifo_depth; }; struct fsl_sai { -- cgit v1.2.3 From 6d19d8a3cec74a9680947ecb6abdeda38583110e Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 17 Jul 2019 12:51:56 +0200 Subject: ASoC: fsl_sai: mark regmap as fast_io The regmap is only ever used to access MMIO registers, so it's fair to say that register access is fast. Signed-off-by: Lucas Stach Link: https://lore.kernel.org/r/20190717105156.15721-1-l.stach@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 1d1a447163e3..6d3c6c8d50ce 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -763,6 +763,7 @@ static const struct regmap_config fsl_sai_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, + .fast_io = true, .max_register = FSL_SAI_RMR, .reg_defaults = fsl_sai_reg_defaults, -- cgit v1.2.3 From 96cd3b97bf32557ba722c2e96095cb6361b5dc42 Mon Sep 17 00:00:00 2001 From: fengchunguo Date: Mon, 15 Jul 2019 17:55:56 +0800 Subject: ASoC: max98383: fix i2c probe failure Added reset_gpio configuration for i2c probe successfully. If not,i2c address can't be found rightly. Error information: max98373 3-0031: Failed to read: 0x21FF Fixed: [3.761299@3] max98373 3-0031: MAX98373 revisionID: 0x43 [3.828911@3] asoc-aml-card auge_sound: max98373-aif1 <-> TDM-B mapping ok Signed-off-by: fengchunguo Link: https://lore.kernel.org/r/20190715095556.1614-1-chunguo.feng@amlogic.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 34 ++++++++++++++++++++++++++++++---- sound/soc/codecs/max98373.h | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 528695cd6a1c..9a1eb7222357 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "max98373.h" @@ -895,6 +896,17 @@ static void max98373_slot_config(struct i2c_client *i2c, else max98373->i_slot = 1; + max98373->reset_gpio = of_get_named_gpio(dev->of_node, + "maxim,reset-gpio", 0); + if (!gpio_is_valid(max98373->reset_gpio)) { + dev_err(dev, "Looking up %s property in node %s failed %d\n", + "maxim,reset-gpio", dev->of_node->full_name, + max98373->reset_gpio); + } else { + dev_dbg(dev, "maxim,reset-gpio=%d", + max98373->reset_gpio); + } + if (!device_property_read_u32(dev, "maxim,spkfb-slot-no", &value)) max98373->spkfb_slot = value & 0xF; else @@ -923,7 +935,6 @@ static int max98373_i2c_probe(struct i2c_client *i2c, else max98373->interleave_mode = false; - /* regmap initialization */ max98373->regmap = devm_regmap_init_i2c(i2c, &max98373_regmap); @@ -934,6 +945,24 @@ static int max98373_i2c_probe(struct i2c_client *i2c, return ret; } + /* voltage/current slot & gpio configuration */ + max98373_slot_config(i2c, max98373); + + /* Power on device */ + if (gpio_is_valid(max98373->reset_gpio)) { + ret = gpio_request(max98373->reset_gpio, "MAX98373_RESET"); + if (ret) { + dev_err(&i2c->dev, "%s: Failed to request gpio %d\n", + __func__, max98373->reset_gpio); + gpio_free(max98373->reset_gpio); + return -EINVAL; + } + gpio_direction_output(max98373->reset_gpio, 0); + msleep(50); + gpio_direction_output(max98373->reset_gpio, 1); + msleep(20); + } + /* Check Revision ID */ ret = regmap_read(max98373->regmap, MAX98373_R21FF_REV_ID, ®); @@ -944,9 +973,6 @@ static int max98373_i2c_probe(struct i2c_client *i2c, } dev_info(&i2c->dev, "MAX98373 revisionID: 0x%02X\n", reg); - /* voltage/current slot configuration */ - max98373_slot_config(i2c, max98373); - /* codec registeration */ ret = devm_snd_soc_register_component(&i2c->dev, &soc_codec_dev_max98373, max98373_dai, ARRAY_SIZE(max98373_dai)); diff --git a/sound/soc/codecs/max98373.h b/sound/soc/codecs/max98373.h index f6a37aa02f26..533d2053f608 100644 --- a/sound/soc/codecs/max98373.h +++ b/sound/soc/codecs/max98373.h @@ -203,6 +203,7 @@ struct max98373_priv { struct regmap *regmap; + int reset_gpio; unsigned int v_slot; unsigned int i_slot; unsigned int spkfb_slot; -- cgit v1.2.3 From b7e814deae33eb30f8f8c6528e8e69b107978d88 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 19 Jul 2019 16:36:37 +0200 Subject: ASoC: tlv320aic31xx: suppress error message for EPROBE_DEFER Both the supplies and reset GPIO might need a probe deferral for the resource to be available. Don't print a error message in that case, as it is a normal operating condition. Signed-off-by: Lucas Stach Acked-by: Andrew F. Davis Link: https://lore.kernel.org/r/20190719143637.2018-1-l.stach@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 9b37e98da0db..26a4f6cd3288 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1553,7 +1553,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(aic31xx->gpio_reset)) { - dev_err(aic31xx->dev, "not able to acquire gpio\n"); + if (PTR_ERR(aic31xx->gpio_reset) != -EPROBE_DEFER) + dev_err(aic31xx->dev, "not able to acquire gpio\n"); return PTR_ERR(aic31xx->gpio_reset); } @@ -1564,7 +1565,9 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, ARRAY_SIZE(aic31xx->supplies), aic31xx->supplies); if (ret) { - dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret); + if (ret != -EPROBE_DEFER) + dev_err(aic31xx->dev, + "Failed to request supplies: %d\n", ret); return ret; } -- cgit v1.2.3 From 980c10cda954770640d9d7cd7b793efa12cae0d9 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 19 Jul 2019 14:32:35 +0800 Subject: ASoC: rt1308: simplify the EFUSE read function The rt1308_efuse function contains many redundant settings. We remove the redundant settings and the function still works. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20190719063235.18757-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1308.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index d673506c7c39..19d255e01827 100755 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -808,33 +808,11 @@ static void rt1308_efuse(struct rt1308_priv *rt1308) { regmap_write(rt1308->regmap, RT1308_RESET, 0); - regmap_write(rt1308->regmap, RT1308_POWER, 0xff371600); - regmap_write(rt1308->regmap, RT1308_CLK_1, 0x52100000); - regmap_write(rt1308->regmap, RT1308_I2C_I2S_SDW_SET, 0x01014005); - regmap_write(rt1308->regmap, RT1308_CLASS_D_SET_2, 0x227f5501); - regmap_write(rt1308->regmap, RT1308_PADS_1, 0x50150505); - regmap_write(rt1308->regmap, RT1308_VREF, 0x18100000); - regmap_write(rt1308->regmap, RT1308_IV_SENSE, 0x87010000); - regmap_write(rt1308->regmap, RT1308_DUMMY_REG, 0x00000200); - regmap_write(rt1308->regmap, RT1308_SIL_DET, 0x61c30000); - regmap_write(rt1308->regmap, RT1308_CLK_DET, 0x03700000); - regmap_write(rt1308->regmap, RT1308_SINE_TONE_GEN_1, 0x50022f00); regmap_write(rt1308->regmap, RT1308_POWER_STATUS, 0x01800000); - regmap_write(rt1308->regmap, RT1308_DC_CAL_2, 0x00ffff00); - regmap_write(rt1308->regmap, RT1308_CLASS_D_SET_2, 0x607e5501); - - regmap_write(rt1308->regmap, RT1308_CLK_2, 0x0060e000); - regmap_write(rt1308->regmap, RT1308_EFUSE_1, 0x04fe0f00); msleep(100); regmap_write(rt1308->regmap, RT1308_EFUSE_1, 0x44fe0f00); msleep(20); regmap_write(rt1308->regmap, RT1308_PVDD_OFFSET_CTL, 0x10000000); - - regmap_write(rt1308->regmap, RT1308_POWER_STATUS, 0x00800000); - regmap_write(rt1308->regmap, RT1308_POWER, 0x0); - regmap_write(rt1308->regmap, RT1308_CLK_1, 0x52000000); - regmap_write(rt1308->regmap, RT1308_CLASS_D_SET_2, 0x227f5501); - regmap_write(rt1308->regmap, RT1308_SINE_TONE_GEN_1, 0x10022f00); } static int rt1308_i2c_probe(struct i2c_client *i2c, -- cgit v1.2.3 From 730e051c78b05f0ce87df06e0fc1ea002d722fe8 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 19 Jul 2019 14:32:49 +0800 Subject: ASoC: rt1308: add silence detection and manual PDB control We enable the silence detection function in initial settings. PDB control changes to manual mode, hence the driver could fully control the AMP output on/off. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20190719063249.18806-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1308.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index 19d255e01827..cf3d72f99705 100755 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -40,10 +40,10 @@ static const struct reg_sequence init_list[] = { { RT1308_VREF, 0x18100000 }, { RT1308_IV_SENSE, 0x87010000 }, { RT1308_DUMMY_REG, 0x00000200 }, - { RT1308_SIL_DET, 0x61c30000 }, + { RT1308_SIL_DET, 0xe1c30000 }, { RT1308_DC_CAL_2, 0x00ffff00 }, { RT1308_CLK_DET, 0x01000000 }, - { RT1308_POWER_STATUS, 0x00800000 }, + { RT1308_POWER_STATUS, 0x08800000 }, { RT1308_DAC_SET, 0xafaf0700 }, }; @@ -308,12 +308,13 @@ static int rt1308_classd_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: msleep(30); snd_soc_component_update_bits(component, RT1308_POWER_STATUS, - RT1308_POW_PDB_REG_BIT, RT1308_POW_PDB_REG_BIT); + RT1308_POW_PDB_REG_BIT | RT1308_POW_PDB_MN_BIT, + RT1308_POW_PDB_REG_BIT | RT1308_POW_PDB_MN_BIT); msleep(40); break; case SND_SOC_DAPM_PRE_PMD: snd_soc_component_update_bits(component, RT1308_POWER_STATUS, - RT1308_POW_PDB_REG_BIT, 0); + RT1308_POW_PDB_REG_BIT | RT1308_POW_PDB_MN_BIT, 0); usleep_range(150000, 200000); break; -- cgit v1.2.3 From 03b0deb6ba5f47d346fbb0783018c0d415203142 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 22 Jul 2019 10:35:16 +0100 Subject: ASoC: cs47l35: Use define for DSPCLK enable bit Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20190722093516.12906-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l35.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index e3585c1dab3d..d396a8545d51 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -524,7 +524,7 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", MADERA_SYSTEM_CLOCK_1, MADERA_SYSCLK_ENA_SHIFT, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_SUPPLY("OPCLK", MADERA_OUTPUT_SYSTEM_CLOCK, MADERA_OPCLK_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, 6, +SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, MADERA_DSP_CLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0), -- cgit v1.2.3 From 4aefb7387198740318c5e7bf7211701f4e0d849e Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Fri, 19 Jul 2019 20:05:58 +0200 Subject: ASoC: rockchip-max98090: Remove MICBIAS as supply of input pin IN34 Commit ec0d23b295b9 ("ASoC: rockchip-max98090: Fix the Headset Mic route.") moved the MICBIAS widget to supply Headset Mic but forget to remove the MICBIAS widget to supply IN34 which is not really needed, so remove that path so we have: IN34 <==== Headset MIC <==== MICBIAS Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20190719180558.11459-1-enric.balletbo@collabora.com Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_max98090.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index c5fc24675a33..d1c907631c2d 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -45,7 +45,6 @@ static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { static const struct snd_soc_dapm_route rk_audio_map[] = { {"IN34", NULL, "Headset Mic"}, - {"IN34", NULL, "MICBIAS"}, {"Headset Mic", NULL, "MICBIAS"}, {"DMICL", NULL, "Int Mic"}, {"Headphone", NULL, "HPL"}, -- cgit v1.2.3 From b1f373a11d25fc9a5f7679c9b85799fe09b0dc4a Mon Sep 17 00:00:00 2001 From: Oleksandr Suvorov Date: Fri, 19 Jul 2019 10:05:31 +0000 Subject: ASoC: sgtl5000: Improve VAG power and mute control VAG power control is improved to fit the manual [1]. This patch fixes as minimum one bug: if customer muxes Headphone to Line-In right after boot, the VAG power remains off that leads to poor sound quality from line-in. I.e. after boot: - Connect sound source to Line-In jack; - Connect headphone to HP jack; - Run following commands: $ amixer set 'Headphone' 80% $ amixer set 'Headphone Mux' LINE_IN Change VAG power on/off control according to the following algorithm: - turn VAG power ON on the 1st incoming event. - keep it ON if there is any active VAG consumer (ADC/DAC/HP/Line-In). - turn VAG power OFF when there is the latest consumer's pre-down event come. - always delay after VAG power OFF to avoid pop. - delay after VAG power ON if the initiative consumer is Line-In, this prevents pop during line-in muxing. According to the data sheet [1], to avoid any pops/clicks, the outputs should be muted during input/output routing changes. [1] https://www.nxp.com/docs/en/data-sheet/SGTL5000.pdf Cc: stable@vger.kernel.org Fixes: 9b34e6cc3bc2 ("ASoC: Add Freescale SGTL5000 codec support") Signed-off-by: Oleksandr Suvorov Reviewed-by: Marcel Ziswiler Reviewed-by: Fabio Estevam Reviewed-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190719100524.23300-3-oleksandr.suvorov@toradex.com Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 224 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 194 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index a6a4748c97f9..34cc85e49003 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -31,6 +31,13 @@ #define SGTL5000_DAP_REG_OFFSET 0x0100 #define SGTL5000_MAX_REG_OFFSET 0x013A +/* Delay for the VAG ramp up */ +#define SGTL5000_VAG_POWERUP_DELAY 500 /* ms */ +/* Delay for the VAG ramp down */ +#define SGTL5000_VAG_POWERDOWN_DELAY 500 /* ms */ + +#define SGTL5000_OUTPUTS_MUTE (SGTL5000_HP_MUTE | SGTL5000_LINE_OUT_MUTE) + /* default value of sgtl5000 registers */ static const struct reg_default sgtl5000_reg_defaults[] = { { SGTL5000_CHIP_DIG_POWER, 0x0000 }, @@ -123,6 +130,13 @@ enum { I2S_SCLK_STRENGTH_HIGH, }; +enum { + HP_POWER_EVENT, + DAC_POWER_EVENT, + ADC_POWER_EVENT, + LAST_POWER_EVENT = ADC_POWER_EVENT +}; + /* sgtl5000 private structure in codec */ struct sgtl5000_priv { int sysclk; /* sysclk rate */ @@ -137,8 +151,109 @@ struct sgtl5000_priv { u8 micbias_voltage; u8 lrclk_strength; u8 sclk_strength; + u16 mute_state[LAST_POWER_EVENT + 1]; }; +static inline int hp_sel_input(struct snd_soc_component *component) +{ + return (snd_soc_component_read32(component, SGTL5000_CHIP_ANA_CTRL) & + SGTL5000_HP_SEL_MASK) >> SGTL5000_HP_SEL_SHIFT; +} + +static inline u16 mute_output(struct snd_soc_component *component, + u16 mute_mask) +{ + u16 mute_reg = snd_soc_component_read32(component, + SGTL5000_CHIP_ANA_CTRL); + + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_CTRL, + mute_mask, mute_mask); + return mute_reg; +} + +static inline void restore_output(struct snd_soc_component *component, + u16 mute_mask, u16 mute_reg) +{ + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_CTRL, + mute_mask, mute_reg); +} + +static void vag_power_on(struct snd_soc_component *component, u32 source) +{ + if (snd_soc_component_read32(component, SGTL5000_CHIP_ANA_POWER) & + SGTL5000_VAG_POWERUP) + return; + + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER, + SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP); + + /* When VAG powering on to get local loop from Line-In, the sleep + * is required to avoid loud pop. + */ + if (hp_sel_input(component) == SGTL5000_HP_SEL_LINE_IN && + source == HP_POWER_EVENT) + msleep(SGTL5000_VAG_POWERUP_DELAY); +} + +static int vag_power_consumers(struct snd_soc_component *component, + u16 ana_pwr_reg, u32 source) +{ + int consumers = 0; + + /* count dac/adc consumers unconditional */ + if (ana_pwr_reg & SGTL5000_DAC_POWERUP) + consumers++; + if (ana_pwr_reg & SGTL5000_ADC_POWERUP) + consumers++; + + /* + * If the event comes from HP and Line-In is selected, + * current action is 'DAC to be powered down'. + * As HP_POWERUP is not set when HP muxed to line-in, + * we need to keep VAG power ON. + */ + if (source == HP_POWER_EVENT) { + if (hp_sel_input(component) == SGTL5000_HP_SEL_LINE_IN) + consumers++; + } else { + if (ana_pwr_reg & SGTL5000_HP_POWERUP) + consumers++; + } + + return consumers; +} + +static void vag_power_off(struct snd_soc_component *component, u32 source) +{ + u16 ana_pwr = snd_soc_component_read32(component, + SGTL5000_CHIP_ANA_POWER); + + if (!(ana_pwr & SGTL5000_VAG_POWERUP)) + return; + + /* + * This function calls when any of VAG power consumers is disappearing. + * Thus, if there is more than one consumer at the moment, as minimum + * one consumer will definitely stay after the end of the current + * event. + * Don't clear VAG_POWERUP if 2 or more consumers of VAG present: + * - LINE_IN (for HP events) / HP (for DAC/ADC events) + * - DAC + * - ADC + * (the current consumer is disappearing right now) + */ + if (vag_power_consumers(component, ana_pwr, source) >= 2) + return; + + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER, + SGTL5000_VAG_POWERUP, 0); + /* In power down case, we need wait 400-1000 ms + * when VAG fully ramped down. + * As longer we wait, as smaller pop we've got. + */ + msleep(SGTL5000_VAG_POWERDOWN_DELAY); +} + /* * mic_bias power on/off share the same register bits with * output impedance of mic bias, when power on mic bias, we @@ -170,36 +285,46 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, return 0; } -/* - * As manual described, ADC/DAC only works when VAG powerup, - * So enabled VAG before ADC/DAC up. - * In power down case, we need wait 400ms when vag fully ramped down. - */ -static int power_vag_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static int vag_and_mute_control(struct snd_soc_component *component, + int event, int event_source) { - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - const u32 mask = SGTL5000_DAC_POWERUP | SGTL5000_ADC_POWERUP; + static const u16 mute_mask[] = { + /* + * Mask for HP_POWER_EVENT. + * Muxing Headphones have to be wrapped with mute/unmute + * headphones only. + */ + SGTL5000_HP_MUTE, + /* + * Masks for DAC_POWER_EVENT/ADC_POWER_EVENT. + * Muxing DAC or ADC block have to wrapped with mute/unmute + * both headphones and line-out. + */ + SGTL5000_OUTPUTS_MUTE, + SGTL5000_OUTPUTS_MUTE + }; + + struct sgtl5000_priv *sgtl5000 = + snd_soc_component_get_drvdata(component); switch (event) { + case SND_SOC_DAPM_PRE_PMU: + sgtl5000->mute_state[event_source] = + mute_output(component, mute_mask[event_source]); + break; case SND_SOC_DAPM_POST_PMU: - snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER, - SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP); - msleep(400); + vag_power_on(component, event_source); + restore_output(component, mute_mask[event_source], + sgtl5000->mute_state[event_source]); break; - case SND_SOC_DAPM_PRE_PMD: - /* - * Don't clear VAG_POWERUP, when both DAC and ADC are - * operational to prevent inadvertently starving the - * other one of them. - */ - if ((snd_soc_component_read32(component, SGTL5000_CHIP_ANA_POWER) & - mask) != mask) { - snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER, - SGTL5000_VAG_POWERUP, 0); - msleep(400); - } + sgtl5000->mute_state[event_source] = + mute_output(component, mute_mask[event_source]); + vag_power_off(component, event_source); + break; + case SND_SOC_DAPM_POST_PMD: + restore_output(component, mute_mask[event_source], + sgtl5000->mute_state[event_source]); break; default: break; @@ -208,6 +333,41 @@ static int power_vag_event(struct snd_soc_dapm_widget *w, return 0; } +/* + * Mute Headphone when power it up/down. + * Control VAG power on HP power path. + */ +static int headphone_pga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + return vag_and_mute_control(component, event, HP_POWER_EVENT); +} + +/* As manual describes, ADC/DAC powering up/down requires + * to mute outputs to avoid pops. + * Control VAG power on ADC/DAC power path. + */ +static int adc_updown_depop(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + return vag_and_mute_control(component, event, ADC_POWER_EVENT); +} + +static int dac_updown_depop(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + return vag_and_mute_control(component, event, DAC_POWER_EVENT); +} + /* input sources for ADC */ static const char *adc_mux_text[] = { "MIC_IN", "LINE_IN" @@ -280,7 +440,10 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { mic_bias_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_PGA("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0, + headphone_pga_event, + SND_SOC_DAPM_PRE_POST_PMU | + SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0), SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, &adc_mux), @@ -301,11 +464,12 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { 0, SGTL5000_CHIP_DIG_POWER, 1, 0), - SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0), - SND_SOC_DAPM_DAC("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0), - - SND_SOC_DAPM_PRE("VAG_POWER_PRE", power_vag_event), - SND_SOC_DAPM_POST("VAG_POWER_POST", power_vag_event), + SND_SOC_DAPM_ADC_E("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0, + adc_updown_depop, SND_SOC_DAPM_PRE_POST_PMU | + SND_SOC_DAPM_PRE_POST_PMD), + SND_SOC_DAPM_DAC_E("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0, + dac_updown_depop, SND_SOC_DAPM_PRE_POST_PMU | + SND_SOC_DAPM_PRE_POST_PMD), }; /* routes for sgtl5000 */ -- cgit v1.2.3 From cadee10c983145c16d6c75af88f6a943b22ebeb2 Mon Sep 17 00:00:00 2001 From: Oleksandr Suvorov Date: Fri, 19 Jul 2019 10:05:33 +0000 Subject: ASoC: sgtl5000: Fix definition of VAG Ramp Control SGTL5000_SMALL_POP is a bit mask, not a value. Usage of correct definition makes device probing code more clear. Signed-off-by: Oleksandr Suvorov Reviewed-by: Marcel Ziswiler Reviewed-by: Igor Opaniuk Reviewed-by: Fabio Estevam Link: https://lore.kernel.org/r/20190719100524.23300-4-oleksandr.suvorov@toradex.com Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 2 +- sound/soc/codecs/sgtl5000.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 34cc85e49003..3f28e7862b5b 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1460,7 +1460,7 @@ static int sgtl5000_probe(struct snd_soc_component *component) /* enable small pop, introduce 400ms delay in turning off */ snd_soc_component_update_bits(component, SGTL5000_CHIP_REF_CTRL, - SGTL5000_SMALL_POP, 1); + SGTL5000_SMALL_POP, SGTL5000_SMALL_POP); /* disable short cut detector */ snd_soc_component_write(component, SGTL5000_CHIP_SHORT_CTRL, 0); diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h index 18cae08bbd3a..a4bf4bca95bf 100644 --- a/sound/soc/codecs/sgtl5000.h +++ b/sound/soc/codecs/sgtl5000.h @@ -273,7 +273,7 @@ #define SGTL5000_BIAS_CTRL_MASK 0x000e #define SGTL5000_BIAS_CTRL_SHIFT 1 #define SGTL5000_BIAS_CTRL_WIDTH 3 -#define SGTL5000_SMALL_POP 1 +#define SGTL5000_SMALL_POP 0x0001 /* * SGTL5000_CHIP_MIC_CTRL -- cgit v1.2.3 From 694b14554d75f2a1ae111202e71860d58b434a21 Mon Sep 17 00:00:00 2001 From: Oleksandr Suvorov Date: Fri, 19 Jul 2019 10:05:34 +0000 Subject: ASoC: sgtl5000: add ADC mute control This control mute/unmute the ADC input of SGTL5000 using its CHIP_ANA_CTRL register. Signed-off-by: Oleksandr Suvorov Reviewed-by: Marcel Ziswiler Reviewed-by: Igor Opaniuk Reviewed-by: Fabio Estevam Link: https://lore.kernel.org/r/20190719100524.23300-5-oleksandr.suvorov@toradex.com Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 3f28e7862b5b..b65232521ea8 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -720,6 +720,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { SGTL5000_CHIP_ANA_ADC_CTRL, 8, 1, 0, capture_6db_attenuate), SOC_SINGLE("Capture ZC Switch", SGTL5000_CHIP_ANA_CTRL, 1, 1, 0), + SOC_SINGLE("Capture Switch", SGTL5000_CHIP_ANA_CTRL, 0, 1, 1), SOC_DOUBLE_TLV("Headphone Playback Volume", SGTL5000_CHIP_ANA_HP_CTRL, -- cgit v1.2.3 From 631bc8f0134ae9620d86a96b8c5f9445d91a2dca Mon Sep 17 00:00:00 2001 From: Oleksandr Suvorov Date: Fri, 19 Jul 2019 10:05:35 +0000 Subject: ASoC: sgtl5000: Fix of unmute outputs on probe To enable "zero cross detect" for ADC/HP, change HP_ZCD_EN/ADC_ZCD_EN bits only instead of writing the whole CHIP_ANA_CTRL register. Signed-off-by: Oleksandr Suvorov Reviewed-by: Marcel Ziswiler Reviewed-by: Igor Opaniuk Reviewed-by: Fabio Estevam Link: https://lore.kernel.org/r/20190719100524.23300-6-oleksandr.suvorov@toradex.com Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index b65232521ea8..23f4ae2f0723 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1453,6 +1453,7 @@ static int sgtl5000_probe(struct snd_soc_component *component) int ret; u16 reg; struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component); + unsigned int zcd_mask = SGTL5000_HP_ZCD_EN | SGTL5000_ADC_ZCD_EN; /* power up sgtl5000 */ ret = sgtl5000_set_power_regs(component); @@ -1480,9 +1481,8 @@ static int sgtl5000_probe(struct snd_soc_component *component) 0x1f); snd_soc_component_write(component, SGTL5000_CHIP_PAD_STRENGTH, reg); - snd_soc_component_write(component, SGTL5000_CHIP_ANA_CTRL, - SGTL5000_HP_ZCD_EN | - SGTL5000_ADC_ZCD_EN); + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_CTRL, + zcd_mask, zcd_mask); snd_soc_component_update_bits(component, SGTL5000_CHIP_MIC_CTRL, SGTL5000_BIAS_R_MASK, -- cgit v1.2.3 From b6319b061ba279577fd7030a9848fbd6a17151e3 Mon Sep 17 00:00:00 2001 From: Oleksandr Suvorov Date: Fri, 19 Jul 2019 10:05:37 +0000 Subject: ASoC: sgtl5000: Fix charge pump source assignment If VDDA != VDDIO and any of them is greater than 3.1V, charge pump source can be assigned automatically [1]. [1] https://www.nxp.com/docs/en/data-sheet/SGTL5000.pdf Signed-off-by: Oleksandr Suvorov Reviewed-by: Marcel Ziswiler Reviewed-by: Igor Opaniuk Reviewed-by: Fabio Estevam Link: https://lore.kernel.org/r/20190719100524.23300-7-oleksandr.suvorov@toradex.com Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 23f4ae2f0723..aa1f9637d895 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1338,12 +1338,17 @@ static int sgtl5000_set_power_regs(struct snd_soc_component *component) SGTL5000_INT_OSC_EN); /* Enable VDDC charge pump */ ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP; - } else if (vddio >= 3100 && vdda >= 3100) { + } else { ana_pwr &= ~SGTL5000_VDDC_CHRGPMP_POWERUP; - /* VDDC use VDDIO rail */ - lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD; - lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO << - SGTL5000_VDDC_MAN_ASSN_SHIFT; + /* + * if vddio == vdda the source of charge pump should be + * assigned manually to VDDIO + */ + if (vddio == vdda) { + lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD; + lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO << + SGTL5000_VDDC_MAN_ASSN_SHIFT; + } } snd_soc_component_write(component, SGTL5000_CHIP_LINREG_CTRL, lreg_ctrl); -- cgit v1.2.3 From 588f2e2caf6795ca29d50a45ea1e1438274e75e0 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:36:51 +0900 Subject: ALSA: firewire-lib: obsolete ctx_data.tx.first_dbc with CIP_UNALIGHED_DBC flag Recent firmware for Fireworks board module have a quirk to start transmission of CIP with non-zero value for its data block counter. In current implementation of ALSA firewire stack, the quirk is handled by 'struct amdtp_stream.ctx_data.tx.first_dbc' with value 0x02. However, the value comes from reverse engineering. It's better to handle this quirk without the explicit value. In a process to parse CIP header, the quirk of data block counter affects decision of sequence index in sequence-multiplexed data channel; i.e. MIDI conformant data channel. In Fireworks, the index is decided by the number of data blocks from top of the same CIP, thus the value of data block counter is useless. This commit adds CIP_UNALIGHED_DBC flag and obsoletes the explicit value for this quirk. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-am824.c | 8 ++++++-- sound/firewire/amdtp-stream.c | 3 +-- sound/firewire/amdtp-stream.h | 5 +++-- sound/firewire/fireworks/fireworks_stream.c | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index fd5d6b8ac557..99c567ded7a3 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -315,12 +315,16 @@ static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, unsigned int frames) { struct amdtp_am824 *p = s->protocol; - unsigned int f, port; int len; u8 *b; + int f; for (f = 0; f < frames; f++) { - port = (8 - s->ctx_data.tx.first_dbc + s->data_block_counter + f) % 8; + unsigned int port = f; + + if (!(s->flags & CIP_UNALIGHED_DBC)) + port += s->data_block_counter; + port %= 8; b = (u8 *)&buffer[p->midi_position]; len = b[0] - 0x80; diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 4d71d74707cf..fc1e8e5b9429 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -584,8 +584,7 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, s->data_block_counter != UINT_MAX) *dbc = s->data_block_counter; - if (((s->flags & CIP_SKIP_DBC_ZERO_CHECK) && - *dbc == s->ctx_data.tx.first_dbc) || + if ((*dbc == 0x00 && (s->flags & CIP_SKIP_DBC_ZERO_CHECK)) || s->data_block_counter == UINT_MAX) { lost = false; } else if (!(s->flags & CIP_DBC_IS_END_EVENT)) { diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 3942894c11ac..5d611122312b 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -33,6 +33,8 @@ * @CIP_HEADER_WITHOUT_EOH: Only for in-stream. CIP Header doesn't include * valid EOH. * @CIP_NO_HEADERS: a lack of headers in packets + * @CIP_UNALIGHED_DBC: Only for in-stream. The value of dbc is not alighed to + * the value of current SYT_INTERVAL; e.g. initial value is not zero. */ enum cip_flags { CIP_NONBLOCKING = 0x00, @@ -45,6 +47,7 @@ enum cip_flags { CIP_JUMBO_PAYLOAD = 0x40, CIP_HEADER_WITHOUT_EOH = 0x80, CIP_NO_HEADER = 0x100, + CIP_UNALIGHED_DBC = 0x200, }; /** @@ -119,8 +122,6 @@ struct amdtp_stream { // Fixed interval of dbc between previos/current // packets. unsigned int dbc_interval; - // Indicate the value of dbc field in a first packet. - unsigned int first_dbc; } tx; struct { // To calculate CIP data blocks and tstamp. diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index e659a0b89ba5..385fc9686365 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -146,7 +146,7 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw) (efw->firmware_version == 0x5070000 || efw->firmware_version == 0x5070300 || efw->firmware_version == 0x5080000)) - efw->tx_stream.ctx_data.tx.first_dbc = 0x02; + efw->tx_stream.flags |= CIP_UNALIGHED_DBC; /* AudioFire9 always reports wrong dbs. */ if (efw->is_af9) efw->tx_stream.flags |= CIP_WRONG_DBS; -- cgit v1.2.3 From cdefaa44d535a9d555ac4f1925d59ae4d0ef98e8 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:36:52 +0900 Subject: ALSA: firewire-lib: pass data block count as an argument to tracepoints event This is a preparation for future commit that 'struct amdtp_stream.data_block_count' does not represent the value of data block count for current data block. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream-trace.h | 6 +++--- sound/firewire/amdtp-stream.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream-trace.h b/sound/firewire/amdtp-stream-trace.h index 4adbbf789cbe..16c7f6605511 100644 --- a/sound/firewire/amdtp-stream-trace.h +++ b/sound/firewire/amdtp-stream-trace.h @@ -14,8 +14,8 @@ #include TRACE_EVENT(amdtp_packet, - TP_PROTO(const struct amdtp_stream *s, u32 cycles, const __be32 *cip_header, unsigned int payload_length, unsigned int data_blocks, unsigned int index), - TP_ARGS(s, cycles, cip_header, payload_length, data_blocks, index), + TP_PROTO(const struct amdtp_stream *s, u32 cycles, const __be32 *cip_header, unsigned int payload_length, unsigned int data_blocks, unsigned int data_block_counter, unsigned int index), + TP_ARGS(s, cycles, cip_header, payload_length, data_blocks, data_block_counter, index), TP_STRUCT__entry( __field(unsigned int, second) __field(unsigned int, cycle) @@ -47,7 +47,7 @@ TRACE_EVENT(amdtp_packet, } __entry->payload_quadlets = payload_length / sizeof(__be32); __entry->data_blocks = data_blocks; - __entry->data_block_counter = s->data_block_counter, + __entry->data_block_counter = data_block_counter, __entry->packet_index = s->packet_index; __entry->irq = !!in_interrupt(); __entry->index = index; diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index fc1e8e5b9429..fe1512905a43 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -511,7 +511,7 @@ static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle, } trace_amdtp_packet(s, cycle, cip_header, payload_length, data_blocks, - index); + s->data_block_counter, index); if (!(s->flags & CIP_DBC_IS_END_EVENT)) { s->data_block_counter = @@ -653,7 +653,7 @@ static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle, s->data_block_counter = dbc; trace_amdtp_packet(s, cycle, cip_header, *payload_length, *data_blocks, - index); + s->data_block_counter, index); return err; } -- cgit v1.2.3 From ab75481202d2925a017e4cb5407b0bb49c356de8 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:36:53 +0900 Subject: ALSA: firewire-lib: pass data block counter to data block processing layer This is a preparation for future commit that 'struct amdtp_stream.data_block_count' does not represent the value of data block count for current data block. However, data block count is required for calculation of sequence index in sequence-multiplied data channel. Some of data block processing layer require it; e.g. for AM824 data block. This commit passes data block count to the processing layer. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-am824.c | 24 +++++++++++++----------- sound/firewire/amdtp-stream.c | 4 ++-- sound/firewire/amdtp-stream.h | 1 + sound/firewire/digi00x/amdtp-dot.c | 16 +++++++--------- sound/firewire/fireface/amdtp-ff.c | 10 ++++------ sound/firewire/motu/amdtp-motu.c | 8 ++++---- sound/firewire/tascam/amdtp-tascam.c | 10 ++++------ 7 files changed, 35 insertions(+), 38 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index 99c567ded7a3..03a7e0533131 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -284,7 +284,7 @@ static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port) } static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, - unsigned int frames) + unsigned int frames, unsigned int data_block_counter) { struct amdtp_am824 *p = s->protocol; unsigned int f, port; @@ -293,7 +293,7 @@ static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, for (f = 0; f < frames; f++) { b = (u8 *)&buffer[p->midi_position]; - port = (s->data_block_counter + f) % 8; + port = (data_block_counter + f) % 8; if (f < MAX_MIDI_RX_BLOCKS && midi_ratelimit_per_packet(s, port) && p->midi[port] != NULL && @@ -311,8 +311,8 @@ static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, } } -static void read_midi_messages(struct amdtp_stream *s, - __be32 *buffer, unsigned int frames) +static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, + unsigned int frames, unsigned int data_block_counter) { struct amdtp_am824 *p = s->protocol; int len; @@ -323,7 +323,7 @@ static void read_midi_messages(struct amdtp_stream *s, unsigned int port = f; if (!(s->flags & CIP_UNALIGHED_DBC)) - port += s->data_block_counter; + port += data_block_counter; port %= 8; b = (u8 *)&buffer[p->midi_position]; @@ -335,8 +335,9 @@ static void read_midi_messages(struct amdtp_stream *s, } } -static unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffer, - unsigned int data_blocks, unsigned int *syt) +static unsigned int process_rx_data_blocks(struct amdtp_stream *s, + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter, unsigned int *syt) { struct amdtp_am824 *p = s->protocol; struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); @@ -351,13 +352,14 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffe } if (p->midi_ports) - write_midi_messages(s, buffer, data_blocks); + write_midi_messages(s, buffer, data_blocks, data_block_counter); return pcm_frames; } -static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffer, - unsigned int data_blocks, unsigned int *syt) +static unsigned int process_tx_data_blocks(struct amdtp_stream *s, + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter, unsigned int *syt) { struct amdtp_am824 *p = s->protocol; struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); @@ -371,7 +373,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffe } if (p->midi_ports) - read_midi_messages(s, buffer, data_blocks); + read_midi_messages(s, buffer, data_blocks, data_block_counter); return pcm_frames; } diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index fe1512905a43..40de9fc9d751 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -722,7 +722,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, data_blocks = calculate_data_blocks(s, syt); buffer = s->buffer.packets[s->packet_index].buffer; pcm_frames = s->process_data_blocks(s, buffer, data_blocks, - &syt); + s->data_block_counter, &syt); build_it_pkt_header(s, cycle, &template.params, data_blocks, syt, i); @@ -776,7 +776,7 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, if (err >= 0) { buffer = s->buffer.packets[s->packet_index].buffer; pcm_frames = s->process_data_blocks(s, buffer, - data_blocks, &syt); + data_blocks, s->data_block_counter, &syt); if (!(s->flags & CIP_DBC_IS_END_EVENT)) { s->data_block_counter += data_blocks; diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 5d611122312b..762ac3c7e902 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -99,6 +99,7 @@ typedef unsigned int (*amdtp_stream_process_data_blocks_t)( struct amdtp_stream *s, __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter, unsigned int *syt); struct amdtp_stream { struct fw_unit *unit; diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c index 45ff73d16074..5c12973c2652 100644 --- a/sound/firewire/digi00x/amdtp-dot.c +++ b/sound/firewire/digi00x/amdtp-dot.c @@ -234,7 +234,7 @@ static inline void midi_use_bytes(struct amdtp_stream *s, } static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, - unsigned int data_blocks) + unsigned int data_blocks, unsigned int data_block_counter) { struct amdtp_dot *p = s->protocol; unsigned int f, port; @@ -242,7 +242,7 @@ static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, u8 *b; for (f = 0; f < data_blocks; f++) { - port = (s->data_block_counter + f) % 8; + port = (data_block_counter + f) % 8; b = (u8 *)&buffer[0]; len = 0; @@ -330,9 +330,8 @@ void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, - unsigned int data_blocks, - unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter, unsigned int *syt) { struct snd_pcm_substream *pcm; unsigned int pcm_frames; @@ -351,9 +350,8 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, - unsigned int data_blocks, - unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter, unsigned int *syt) { struct snd_pcm_substream *pcm; unsigned int pcm_frames; @@ -367,7 +365,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, pcm_frames = 0; } - write_midi_messages(s, buffer, data_blocks); + write_midi_messages(s, buffer, data_blocks, data_block_counter); return pcm_frames; } diff --git a/sound/firewire/fireface/amdtp-ff.c b/sound/firewire/fireface/amdtp-ff.c index 2938489740b4..71879922ab39 100644 --- a/sound/firewire/fireface/amdtp-ff.c +++ b/sound/firewire/fireface/amdtp-ff.c @@ -103,9 +103,8 @@ int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s, } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, - unsigned int data_blocks, - unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter, unsigned int *syt) { struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; @@ -122,9 +121,8 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, - unsigned int data_blocks, - unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter, unsigned int *syt) { struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index 7973dedd31ef..9693f37a0032 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -299,8 +299,8 @@ static void __maybe_unused copy_message(u64 *frames, __be32 *buffer, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter, unsigned int *syt) { struct amdtp_motu *p = s->protocol; struct snd_pcm_substream *pcm; @@ -361,8 +361,8 @@ static void write_sph(struct amdtp_stream *s, __be32 *buffer, } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter, unsigned int *syt) { struct amdtp_motu *p = (struct amdtp_motu *)s->protocol; struct snd_pcm_substream *pcm; diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c index 95fb10b7a737..3a4d1f855f79 100644 --- a/sound/firewire/tascam/amdtp-tascam.c +++ b/sound/firewire/tascam/amdtp-tascam.c @@ -166,9 +166,8 @@ static void read_status_messages(struct amdtp_stream *s, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, - unsigned int data_blocks, - unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter, unsigned int *syt) { struct snd_pcm_substream *pcm; @@ -182,9 +181,8 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, - unsigned int data_blocks, - unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter, unsigned int *syt) { struct snd_pcm_substream *pcm; -- cgit v1.2.3 From 860d798c370409efbedf66bae2d41b3cbdf14a79 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:36:54 +0900 Subject: ALSA: firewire-lib: operate data block counter in top level of processing for IT context In ALSA IEC 61883-1/6 packet streaming engine, two types of data block counter are supported. This commit applies code refactoring to make it explicitly for IT context. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 40de9fc9d751..c89083ccd729 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -473,12 +473,12 @@ static inline int queue_in_packet(struct amdtp_stream *s, } static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2], - unsigned int syt) + unsigned int data_block_counter, unsigned int syt) { cip_header[0] = cpu_to_be32(READ_ONCE(s->source_node_id_field) | (s->data_block_quadlets << CIP_DBS_SHIFT) | ((s->sph << CIP_SPH_SHIFT) & CIP_SPH_MASK) | - s->data_block_counter); + data_block_counter); cip_header[1] = cpu_to_be32(CIP_EOH | ((s->fmt << CIP_FMT_SHIFT) & CIP_FMT_MASK) | ((s->ctx_data.rx.fdf << CIP_FDF_SHIFT) & CIP_FDF_MASK) | @@ -487,8 +487,9 @@ static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2], static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle, struct fw_iso_packet *params, - unsigned int data_blocks, unsigned int syt, - unsigned int index) + unsigned int data_blocks, + unsigned int data_block_counter, + unsigned int syt, unsigned int index) { unsigned int payload_length; __be32 *cip_header; @@ -496,14 +497,9 @@ static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle, payload_length = data_blocks * sizeof(__be32) * s->data_block_quadlets; params->payload_length = payload_length; - if (s->flags & CIP_DBC_IS_END_EVENT) { - s->data_block_counter = - (s->data_block_counter + data_blocks) & 0xff; - } - if (!(s->flags & CIP_NO_HEADER)) { cip_header = (__be32 *)params->header; - generate_cip_header(s, cip_header, syt); + generate_cip_header(s, cip_header, data_block_counter, syt); params->header_length = 2 * sizeof(__be32); payload_length += params->header_length; } else { @@ -511,12 +507,7 @@ static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle, } trace_amdtp_packet(s, cycle, cip_header, payload_length, data_blocks, - s->data_block_counter, index); - - if (!(s->flags & CIP_DBC_IS_END_EVENT)) { - s->data_block_counter = - (s->data_block_counter + data_blocks) & 0xff; - } + data_block_counter, index); } static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, @@ -709,6 +700,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, u32 cycle; unsigned int syt; unsigned int data_blocks; + unsigned int dbc; __be32 *buffer; unsigned int pcm_frames; struct { @@ -721,11 +713,20 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, syt = calculate_syt(s, cycle); data_blocks = calculate_data_blocks(s, syt); buffer = s->buffer.packets[s->packet_index].buffer; - pcm_frames = s->process_data_blocks(s, buffer, data_blocks, - s->data_block_counter, &syt); + dbc = s->data_block_counter; + pcm_frames = s->process_data_blocks(s, buffer, data_blocks, dbc, + &syt); + + if (s->flags & CIP_DBC_IS_END_EVENT) + dbc = (dbc + data_blocks) & 0xff; build_it_pkt_header(s, cycle, &template.params, data_blocks, - syt, i); + dbc, syt, i); + + if (!(s->flags & CIP_DBC_IS_END_EVENT)) + dbc = (dbc + data_blocks) & 0xff; + + s->data_block_counter = dbc; if (queue_out_packet(s, &template.params) < 0) { cancel_stream(s); -- cgit v1.2.3 From a35463d1f77d9e5244d6f4953d3c7f3a27c7625e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:36:55 +0900 Subject: ALSA: firewire-lib: operate data block counter in top level of processing for IR context In ALSA IEC 61883-1/6 packet streaming engine, two types of data block counter are supported. This commit applies code refactoring to make it explicitly for IR context. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 53 +++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index c89083ccd729..3435bef97a8b 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -512,13 +512,14 @@ static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle, static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, unsigned int payload_length, - unsigned int *data_blocks, unsigned int *dbc, - unsigned int *syt) + unsigned int *data_blocks, + unsigned int *data_block_counter, unsigned int *syt) { u32 cip_header[2]; unsigned int sph; unsigned int fmt; unsigned int fdf; + unsigned int dbc; bool lost; cip_header[0] = be32_to_cpu(buf[0]); @@ -570,16 +571,16 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, } /* Check data block counter continuity */ - *dbc = cip_header[0] & CIP_DBC_MASK; + dbc = cip_header[0] & CIP_DBC_MASK; if (*data_blocks == 0 && (s->flags & CIP_EMPTY_HAS_WRONG_DBC) && - s->data_block_counter != UINT_MAX) - *dbc = s->data_block_counter; + *data_block_counter != UINT_MAX) + dbc = *data_block_counter; - if ((*dbc == 0x00 && (s->flags & CIP_SKIP_DBC_ZERO_CHECK)) || - s->data_block_counter == UINT_MAX) { + if ((dbc == 0x00 && (s->flags & CIP_SKIP_DBC_ZERO_CHECK)) || + *data_block_counter == UINT_MAX) { lost = false; } else if (!(s->flags & CIP_DBC_IS_END_EVENT)) { - lost = *dbc != s->data_block_counter; + lost = dbc != *data_block_counter; } else { unsigned int dbc_interval; @@ -588,13 +589,13 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, else dbc_interval = *data_blocks; - lost = *dbc != ((s->data_block_counter + dbc_interval) & 0xff); + lost = dbc != ((*data_block_counter + dbc_interval) & 0xff); } if (lost) { dev_err(&s->unit->device, "Detect discontinuity of CIP: %02X %02X\n", - s->data_block_counter, *dbc); + *data_block_counter, dbc); return -EIO; } @@ -606,10 +607,10 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle, const __be32 *ctx_header, unsigned int *payload_length, - unsigned int *data_blocks, unsigned int *syt, - unsigned int index) + unsigned int *data_blocks, + unsigned int *data_block_counter, + unsigned int *syt, unsigned int index) { - unsigned int dbc; const __be32 *cip_header; int err; @@ -625,7 +626,7 @@ static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle, if (!(s->flags & CIP_NO_HEADER)) { cip_header = ctx_header + 2; err = check_cip_header(s, cip_header, *payload_length, - data_blocks, &dbc, syt); + data_blocks, data_block_counter, syt); if (err < 0) return err; } else { @@ -635,16 +636,12 @@ static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle, s->data_block_quadlets; *syt = 0; - if (s->data_block_counter != UINT_MAX) - dbc = s->data_block_counter; - else - dbc = 0; + if (*data_block_counter == UINT_MAX) + *data_block_counter = 0; } - s->data_block_counter = dbc; - trace_amdtp_packet(s, cycle, cip_header, *payload_length, *data_blocks, - s->data_block_counter, index); + *data_block_counter, index); return err; } @@ -761,6 +758,7 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, u32 cycle; unsigned int payload_length; unsigned int data_blocks; + unsigned int dbc; unsigned int syt; __be32 *buffer; unsigned int pcm_frames = 0; @@ -769,22 +767,23 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, int err; cycle = compute_cycle_count(ctx_header[1]); + dbc = s->data_block_counter; err = parse_ir_ctx_header(s, cycle, ctx_header, &payload_length, - &data_blocks, &syt, i); + &data_blocks, &dbc, &syt, i); if (err < 0 && err != -EAGAIN) break; if (err >= 0) { buffer = s->buffer.packets[s->packet_index].buffer; pcm_frames = s->process_data_blocks(s, buffer, - data_blocks, s->data_block_counter, &syt); + data_blocks, dbc, &syt); - if (!(s->flags & CIP_DBC_IS_END_EVENT)) { - s->data_block_counter += data_blocks; - s->data_block_counter &= 0xff; - } + if (!(s->flags & CIP_DBC_IS_END_EVENT)) + dbc = (dbc + data_blocks) & 0xff; } + s->data_block_counter = dbc; + if (queue_in_packet(s, ¶ms) < 0) break; -- cgit v1.2.3 From 3baf30532f94030244a31a275b546d042656c535 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:36:56 +0900 Subject: ALSA: firewire-lib: add syt_override member for some protocols Some protocols don't use syt field of CIP header to represent presentation timestamp. For such protocol, ALSA IEC 61883-1/6 packet streaming engine uses a pointer into local variable for the value of syt to call data block processing layer. However, it can decide the value when initializing packet streaming layer. This commit adds 'syt_override' member for packet streaming layer. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 6 ++++++ sound/firewire/amdtp-stream.h | 1 + sound/firewire/motu/amdtp-motu.c | 8 +++++++- sound/firewire/tascam/amdtp-tascam.c | 8 ++++++-- 4 files changed, 20 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 3435bef97a8b..6242240cd8ee 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -104,6 +104,9 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, s->fmt = fmt; s->process_data_blocks = process_data_blocks; + if (dir == AMDTP_OUT_STREAM) + s->ctx_data.rx.syt_override = -1; + return 0; } EXPORT_SYMBOL(amdtp_stream_init); @@ -717,6 +720,9 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, if (s->flags & CIP_DBC_IS_END_EVENT) dbc = (dbc + data_blocks) & 0xff; + if (s->ctx_data.rx.syt_override >= 0) + syt = s->ctx_data.rx.syt_override; + build_it_pkt_header(s, cycle, &template.params, data_blocks, dbc, syt, i); diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 762ac3c7e902..5b9d4212e202 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -133,6 +133,7 @@ struct amdtp_stream { // To generate CIP header. unsigned int fdf; + int syt_override; } rx; } ctx_data; diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index 9693f37a0032..683873699885 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -428,7 +428,13 @@ int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, return err; s->sph = 1; - s->ctx_data.rx.fdf = MOTU_FDF_AM824; + + if (dir == AMDTP_OUT_STREAM) { + // Use fixed value for FDF field. + s->ctx_data.rx.fdf = MOTU_FDF_AM824; + // Not used. + s->ctx_data.rx.syt_override = 0xffff; + } return 0; } diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c index 3a4d1f855f79..8fba6fb8ba8a 100644 --- a/sound/firewire/tascam/amdtp-tascam.c +++ b/sound/firewire/tascam/amdtp-tascam.c @@ -220,8 +220,12 @@ int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit, if (err < 0) return 0; - /* Use fixed value for FDF field. */ - s->ctx_data.rx.fdf = 0x00; + if (dir == AMDTP_OUT_STREAM) { + // Use fixed value for FDF field. + s->ctx_data.rx.fdf = 0x00; + // Not used. + s->ctx_data.rx.syt_override = 0x0000; + } /* This protocol uses fixed number of data channels for PCM samples. */ p = s->protocol; -- cgit v1.2.3 From 600c8018df605a91575aef6811cf927e2d933d30 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:36:57 +0900 Subject: ALSA: firewire-lib: pass no syt information to data block processing layer In a previous commit, the variable passed from packet streaming layer for syt variable is useless. This commit obsoletes it. In my future work, the syt information is passed to data block processing layer by another way. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-am824.c | 8 ++++---- sound/firewire/amdtp-stream.c | 5 ++--- sound/firewire/amdtp-stream.h | 3 +-- sound/firewire/digi00x/amdtp-dot.c | 8 ++++---- sound/firewire/fireface/amdtp-ff.c | 8 ++++---- sound/firewire/motu/amdtp-motu.c | 11 ++++------- sound/firewire/tascam/amdtp-tascam.c | 11 ++++------- 7 files changed, 23 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index 03a7e0533131..21068b23d528 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -336,8 +336,8 @@ static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter, unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter) { struct amdtp_am824 *p = s->protocol; struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); @@ -358,8 +358,8 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter, unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter) { struct amdtp_am824 *p = s->protocol; struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 6242240cd8ee..c8543cdb3c8c 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -714,8 +714,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, data_blocks = calculate_data_blocks(s, syt); buffer = s->buffer.packets[s->packet_index].buffer; dbc = s->data_block_counter; - pcm_frames = s->process_data_blocks(s, buffer, data_blocks, dbc, - &syt); + pcm_frames = s->process_data_blocks(s, buffer, data_blocks, dbc); if (s->flags & CIP_DBC_IS_END_EVENT) dbc = (dbc + data_blocks) & 0xff; @@ -782,7 +781,7 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, if (err >= 0) { buffer = s->buffer.packets[s->packet_index].buffer; pcm_frames = s->process_data_blocks(s, buffer, - data_blocks, dbc, &syt); + data_blocks, dbc); if (!(s->flags & CIP_DBC_IS_END_EVENT)) dbc = (dbc + data_blocks) & 0xff; diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 5b9d4212e202..5996cc60f166 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -99,8 +99,7 @@ typedef unsigned int (*amdtp_stream_process_data_blocks_t)( struct amdtp_stream *s, __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter, - unsigned int *syt); + unsigned int data_block_counter); struct amdtp_stream { struct fw_unit *unit; enum cip_flags flags; diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c index 5c12973c2652..c296d1017ed3 100644 --- a/sound/firewire/digi00x/amdtp-dot.c +++ b/sound/firewire/digi00x/amdtp-dot.c @@ -330,8 +330,8 @@ void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter, unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter) { struct snd_pcm_substream *pcm; unsigned int pcm_frames; @@ -350,8 +350,8 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter, unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter) { struct snd_pcm_substream *pcm; unsigned int pcm_frames; diff --git a/sound/firewire/fireface/amdtp-ff.c b/sound/firewire/fireface/amdtp-ff.c index 71879922ab39..31a60dff94ac 100644 --- a/sound/firewire/fireface/amdtp-ff.c +++ b/sound/firewire/fireface/amdtp-ff.c @@ -103,8 +103,8 @@ int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s, } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter, unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter) { struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; @@ -121,8 +121,8 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter, unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter) { struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index 683873699885..30d5f87119cc 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -299,8 +299,8 @@ static void __maybe_unused copy_message(u64 *frames, __be32 *buffer, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter, unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter) { struct amdtp_motu *p = s->protocol; struct snd_pcm_substream *pcm; @@ -361,15 +361,12 @@ static void write_sph(struct amdtp_stream *s, __be32 *buffer, } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter, unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter) { struct amdtp_motu *p = (struct amdtp_motu *)s->protocol; struct snd_pcm_substream *pcm; - /* Not used. */ - *syt = 0xffff; - /* TODO: how to interact control messages between userspace? */ if (p->midi_ports) diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c index 8fba6fb8ba8a..bc1f2d2120b4 100644 --- a/sound/firewire/tascam/amdtp-tascam.c +++ b/sound/firewire/tascam/amdtp-tascam.c @@ -166,8 +166,8 @@ static void read_status_messages(struct amdtp_stream *s, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter, unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter) { struct snd_pcm_substream *pcm; @@ -181,14 +181,11 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter, unsigned int *syt) + __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_counter) { struct snd_pcm_substream *pcm; - /* This field is not used. */ - *syt = 0x0000; - pcm = READ_ONCE(s->pcm); if (pcm) write_pcm_s32(s, pcm, buffer, data_blocks); -- cgit v1.2.3 From 04130cf8e296bfbd65d2673a5975bd0f200b941d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:36:58 +0900 Subject: ALSA: firewire-lib: add list of packet descriptor In current implementation of ALSA IEC 61883-1/6 packet streaming engine, 16 packets are handled in one interrupt of isochronous context of OHCI 1394. Overall packet processing runs for each. However, this is not better in a point to split the processing into several parts. This commit is an attempt to add intermediate representation for parameters required for the parts. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 15 ++++++++++++--- sound/firewire/amdtp-stream.h | 9 +++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index c8543cdb3c8c..2bea15151d4a 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -936,6 +936,13 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) else s->tag = TAG_CIP; + s->pkt_descs = kcalloc(INTERRUPT_INTERVAL, sizeof(*s->pkt_descs), + GFP_KERNEL); + if (!s->pkt_descs) { + err = -ENOMEM; + goto err_context; + } + s->packet_index = 0; do { struct fw_iso_packet params; @@ -947,7 +954,7 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) err = queue_out_packet(s, ¶ms); } if (err < 0) - goto err_context; + goto err_pkt_descs; } while (s->packet_index > 0); /* NOTE: TAG1 matches CIP. This just affects in stream. */ @@ -958,12 +965,13 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) s->callbacked = false; err = fw_iso_context_start(s->context, -1, 0, tag); if (err < 0) - goto err_context; + goto err_pkt_descs; mutex_unlock(&s->mutex); return 0; - +err_pkt_descs: + kfree(s->pkt_descs); err_context: fw_iso_context_destroy(s->context); s->context = ERR_PTR(-1); @@ -1059,6 +1067,7 @@ void amdtp_stream_stop(struct amdtp_stream *s) fw_iso_context_destroy(s->context); s->context = ERR_PTR(-1); iso_packets_buffer_destroy(&s->buffer, s->unit); + kfree(s->pkt_descs); s->callbacked = false; diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 5996cc60f166..73c492c9a5d5 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -94,6 +94,14 @@ enum amdtp_stream_direction { AMDTP_IN_STREAM }; +struct pkt_desc { + u32 cycle; + u32 syt; + unsigned int data_blocks; + unsigned int data_block_counter; + __be32 *ctx_payload; +}; + struct amdtp_stream; typedef unsigned int (*amdtp_stream_process_data_blocks_t)( struct amdtp_stream *s, @@ -110,6 +118,7 @@ struct amdtp_stream { struct fw_iso_context *context; struct iso_packets_buffer buffer; int packet_index; + struct pkt_desc *pkt_descs; int tag; union { struct { -- cgit v1.2.3 From f4f6ae7b7c1fdbaaaecafd183fabcf5314df2b59 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:36:59 +0900 Subject: ALSA: firewire-lib: use packet descriptor for IT context This commit uses packet descriptor to parse headers of IT context and generate timing information for ideal sequence. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 68 ++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 2bea15151d4a..463c7a340a45 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -676,6 +676,38 @@ static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp) return increment_cycle_count(cycle, QUEUE_LENGTH); } +static void generate_ideal_pkt_descs(struct amdtp_stream *s, + struct pkt_desc *descs, + const __be32 *ctx_header, + unsigned int packets) +{ + unsigned int dbc = s->data_block_counter; + int i; + + for (i = 0; i < packets; ++i) { + struct pkt_desc *desc = descs + i; + unsigned int index = (s->packet_index + i) % QUEUE_LENGTH; + + desc->cycle = compute_cycle_count(*ctx_header); + desc->syt = calculate_syt(s, desc->cycle); + desc->data_blocks = calculate_data_blocks(s, desc->syt); + + if (s->flags & CIP_DBC_IS_END_EVENT) + dbc = (dbc + desc->data_blocks) & 0xff; + + desc->data_block_counter = dbc; + + if (!(s->flags & CIP_DBC_IS_END_EVENT)) + dbc = (dbc + desc->data_blocks) & 0xff; + + desc->ctx_payload = s->buffer.packets[index].buffer; + + ++ctx_header; + } + + s->data_block_counter = dbc; +} + static inline void cancel_stream(struct amdtp_stream *s) { s->packet_index = -1; @@ -696,39 +728,29 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, if (s->packet_index < 0) return; + generate_ideal_pkt_descs(s, s->pkt_descs, ctx_header, packets); + for (i = 0; i < packets; ++i) { - u32 cycle; - unsigned int syt; - unsigned int data_blocks; - unsigned int dbc; - __be32 *buffer; + const struct pkt_desc *desc = s->pkt_descs + i; unsigned int pcm_frames; + unsigned int syt; struct { struct fw_iso_packet params; __be32 header[IT_PKT_HEADER_SIZE_CIP / sizeof(__be32)]; } template = { {0}, {0} }; struct snd_pcm_substream *pcm; - cycle = compute_it_cycle(*ctx_header); - syt = calculate_syt(s, cycle); - data_blocks = calculate_data_blocks(s, syt); - buffer = s->buffer.packets[s->packet_index].buffer; - dbc = s->data_block_counter; - pcm_frames = s->process_data_blocks(s, buffer, data_blocks, dbc); + pcm_frames = s->process_data_blocks(s, desc->ctx_payload, + desc->data_blocks, desc->data_block_counter); - if (s->flags & CIP_DBC_IS_END_EVENT) - dbc = (dbc + data_blocks) & 0xff; - - if (s->ctx_data.rx.syt_override >= 0) + if (s->ctx_data.rx.syt_override < 0) + syt = desc->syt; + else syt = s->ctx_data.rx.syt_override; - build_it_pkt_header(s, cycle, &template.params, data_blocks, - dbc, syt, i); - - if (!(s->flags & CIP_DBC_IS_END_EVENT)) - dbc = (dbc + data_blocks) & 0xff; - - s->data_block_counter = dbc; + build_it_pkt_header(s, desc->cycle, &template.params, + desc->data_blocks, desc->data_block_counter, + syt, i); if (queue_out_packet(s, &template.params) < 0) { cancel_stream(s); @@ -738,8 +760,6 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, pcm = READ_ONCE(s->pcm); if (pcm && pcm_frames > 0) update_pcm_pointers(s, pcm, pcm_frames); - - ++ctx_header; } fw_iso_context_queue_flush(s->context); -- cgit v1.2.3 From 753e717986c24b60962367708479555212730b9f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:37:00 +0900 Subject: ALSA: firewire-lib: use packet descriptor for IR context This commit uses packet descriptor to parse headers of IR context and parse timing information for sequence transferred by target device. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 96 ++++++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 463c7a340a45..68502a8864b9 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -602,6 +602,8 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, return -EIO; } + *data_block_counter = dbc; + *syt = cip_header[1] & CIP_SYT_MASK; return 0; @@ -676,6 +678,48 @@ static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp) return increment_cycle_count(cycle, QUEUE_LENGTH); } +static int generate_device_pkt_descs(struct amdtp_stream *s, + struct pkt_desc *descs, + const __be32 *ctx_header, + unsigned int packets) +{ + unsigned int dbc = s->data_block_counter; + int i; + int err; + + for (i = 0; i < packets; ++i) { + struct pkt_desc *desc = descs + i; + unsigned int index = (s->packet_index + i) % QUEUE_LENGTH; + unsigned int cycle; + unsigned int payload_length; + unsigned int data_blocks; + unsigned int syt; + + cycle = compute_cycle_count(ctx_header[1]); + + err = parse_ir_ctx_header(s, cycle, ctx_header, &payload_length, + &data_blocks, &dbc, &syt, i); + if (err < 0) + return err; + + desc->cycle = cycle; + desc->syt = syt; + desc->data_blocks = data_blocks; + desc->data_block_counter = dbc; + desc->ctx_payload = s->buffer.packets[index].buffer; + + if (!(s->flags & CIP_DBC_IS_END_EVENT)) + dbc = (dbc + desc->data_blocks) & 0xff; + + ctx_header += + s->ctx_data.tx.ctx_header_size / sizeof(*ctx_header); + } + + s->data_block_counter = dbc; + + return 0; +} + static void generate_ideal_pkt_descs(struct amdtp_stream *s, struct pkt_desc *descs, const __be32 *ctx_header, @@ -770,8 +814,10 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, void *private_data) { struct amdtp_stream *s = private_data; - unsigned int i, packets; + unsigned int packets; __be32 *ctx_header = header; + int i; + int err; if (s->packet_index < 0) return; @@ -779,50 +825,34 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, // The number of packets in buffer. packets = header_length / s->ctx_data.tx.ctx_header_size; + err = generate_device_pkt_descs(s, s->pkt_descs, ctx_header, packets); + if (err < 0) { + if (err != -EAGAIN) { + cancel_stream(s); + return; + } + } + for (i = 0; i < packets; i++) { - u32 cycle; - unsigned int payload_length; - unsigned int data_blocks; - unsigned int dbc; - unsigned int syt; - __be32 *buffer; + const struct pkt_desc *desc = s->pkt_descs; unsigned int pcm_frames = 0; struct fw_iso_packet params = {0}; struct snd_pcm_substream *pcm; - int err; - - cycle = compute_cycle_count(ctx_header[1]); - dbc = s->data_block_counter; - err = parse_ir_ctx_header(s, cycle, ctx_header, &payload_length, - &data_blocks, &dbc, &syt, i); - if (err < 0 && err != -EAGAIN) - break; if (err >= 0) { - buffer = s->buffer.packets[s->packet_index].buffer; - pcm_frames = s->process_data_blocks(s, buffer, - data_blocks, dbc); - - if (!(s->flags & CIP_DBC_IS_END_EVENT)) - dbc = (dbc + data_blocks) & 0xff; + pcm_frames = s->process_data_blocks(s, + desc->ctx_payload, desc->data_blocks, + desc->data_block_counter); } - s->data_block_counter = dbc; - - if (queue_in_packet(s, ¶ms) < 0) - break; + if (queue_in_packet(s, ¶ms) < 0) { + cancel_stream(s); + return; + } pcm = READ_ONCE(s->pcm); if (pcm && pcm_frames > 0) update_pcm_pointers(s, pcm, pcm_frames); - - ctx_header += s->ctx_data.tx.ctx_header_size / sizeof(*ctx_header); - } - - /* Queueing error or detecting invalid payload. */ - if (i < packets) { - cancel_stream(s); - return; } fw_iso_context_queue_flush(s->context); -- cgit v1.2.3 From 5e2ece0fdceb02f6c47f53bef309395701a65393 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:37:01 +0900 Subject: ALSA: firewire-lib: code refactoring to process PCM substream This is code refactoring to separate PCM substream processing from packet queueing. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 45 ++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 68502a8864b9..99b89bd70bc5 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -776,16 +776,24 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, for (i = 0; i < packets; ++i) { const struct pkt_desc *desc = s->pkt_descs + i; + struct snd_pcm_substream *pcm; unsigned int pcm_frames; + + pcm_frames = s->process_data_blocks(s, desc->ctx_payload, + desc->data_blocks, desc->data_block_counter); + + pcm = READ_ONCE(s->pcm); + if (pcm && pcm_frames > 0) + update_pcm_pointers(s, pcm, pcm_frames); + } + + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = s->pkt_descs + i; unsigned int syt; struct { struct fw_iso_packet params; __be32 header[IT_PKT_HEADER_SIZE_CIP / sizeof(__be32)]; } template = { {0}, {0} }; - struct snd_pcm_substream *pcm; - - pcm_frames = s->process_data_blocks(s, desc->ctx_payload, - desc->data_blocks, desc->data_block_counter); if (s->ctx_data.rx.syt_override < 0) syt = desc->syt; @@ -800,10 +808,6 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, cancel_stream(s); return; } - - pcm = READ_ONCE(s->pcm); - if (pcm && pcm_frames > 0) - update_pcm_pointers(s, pcm, pcm_frames); } fw_iso_context_queue_flush(s->context); @@ -831,28 +835,29 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, cancel_stream(s); return; } - } - - for (i = 0; i < packets; i++) { - const struct pkt_desc *desc = s->pkt_descs; - unsigned int pcm_frames = 0; - struct fw_iso_packet params = {0}; - struct snd_pcm_substream *pcm; + } else { + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = s->pkt_descs; + struct snd_pcm_substream *pcm; + unsigned int pcm_frames; - if (err >= 0) { pcm_frames = s->process_data_blocks(s, desc->ctx_payload, desc->data_blocks, desc->data_block_counter); + + pcm = READ_ONCE(s->pcm); + if (pcm && pcm_frames > 0) + update_pcm_pointers(s, pcm, pcm_frames); } + } + + for (i = 0; i < packets; ++i) { + struct fw_iso_packet params = {0}; if (queue_in_packet(s, ¶ms) < 0) { cancel_stream(s); return; } - - pcm = READ_ONCE(s->pcm); - if (pcm && pcm_frames > 0) - update_pcm_pointers(s, pcm, pcm_frames); } fw_iso_context_queue_flush(s->context); -- cgit v1.2.3 From 0f5cfcb24d9c931e4571e9995bbfc08cc76d5d4a Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:37:02 +0900 Subject: ALSA: firewire-lib: code refactoring to process context payloads This is code refactoring for common processing for payloads of ishocornous context. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 47 ++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 99b89bd70bc5..573265113a6f 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -760,22 +760,14 @@ static inline void cancel_stream(struct amdtp_stream *s) WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN); } -static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, - size_t header_length, void *header, - void *private_data) +static void process_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets) { - struct amdtp_stream *s = private_data; - const __be32 *ctx_header = header; - unsigned int packets = header_length / sizeof(*ctx_header); int i; - if (s->packet_index < 0) - return; - - generate_ideal_pkt_descs(s, s->pkt_descs, ctx_header, packets); - for (i = 0; i < packets; ++i) { - const struct pkt_desc *desc = s->pkt_descs + i; + const struct pkt_desc *desc = descs + i; struct snd_pcm_substream *pcm; unsigned int pcm_frames; @@ -786,6 +778,23 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, if (pcm && pcm_frames > 0) update_pcm_pointers(s, pcm, pcm_frames); } +} + +static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, + size_t header_length, void *header, + void *private_data) +{ + struct amdtp_stream *s = private_data; + const __be32 *ctx_header = header; + unsigned int packets = header_length / sizeof(*ctx_header); + int i; + + if (s->packet_index < 0) + return; + + generate_ideal_pkt_descs(s, s->pkt_descs, ctx_header, packets); + + process_ctx_payloads(s, s->pkt_descs, packets); for (i = 0; i < packets; ++i) { const struct pkt_desc *desc = s->pkt_descs + i; @@ -836,19 +845,7 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, return; } } else { - for (i = 0; i < packets; ++i) { - const struct pkt_desc *desc = s->pkt_descs; - struct snd_pcm_substream *pcm; - unsigned int pcm_frames; - - pcm_frames = s->process_data_blocks(s, - desc->ctx_payload, desc->data_blocks, - desc->data_block_counter); - - pcm = READ_ONCE(s->pcm); - if (pcm && pcm_frames > 0) - update_pcm_pointers(s, pcm, pcm_frames); - } + process_ctx_payloads(s, s->pkt_descs, packets); } for (i = 0; i < packets; ++i) { -- cgit v1.2.3 From d2c104a3426be9991b35c65f0f260a107c4b2942 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:37:03 +0900 Subject: ALSA: firewire-lib: pass packet descriptor to data block processing layer This commit changes signature of callback function to call data block processing layer with packet descriptor. At present, the layer is called per packet. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-am824.c | 32 ++++++++++++---------- sound/firewire/amdtp-stream.c | 6 ++-- sound/firewire/amdtp-stream.h | 5 ++-- sound/firewire/digi00x/amdtp-dot.c | 27 ++++++++---------- sound/firewire/fireface/amdtp-ff.c | 23 ++++++++-------- sound/firewire/motu/amdtp-motu.c | 53 ++++++++++++++++++++---------------- sound/firewire/tascam/amdtp-tascam.c | 39 ++++++++++++++------------ 7 files changed, 97 insertions(+), 88 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index 21068b23d528..ff089ffa3374 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -336,44 +336,46 @@ static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter) + const struct pkt_desc *desc, + struct snd_pcm_substream *pcm) { struct amdtp_am824 *p = s->protocol; - struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; if (pcm) { - write_pcm_s32(s, pcm, buffer, data_blocks); - pcm_frames = data_blocks * p->frame_multiplier; + write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks); + pcm_frames = desc->data_blocks * p->frame_multiplier; } else { - write_pcm_silence(s, buffer, data_blocks); + write_pcm_silence(s, desc->ctx_payload, desc->data_blocks); pcm_frames = 0; } - if (p->midi_ports) - write_midi_messages(s, buffer, data_blocks, data_block_counter); + if (p->midi_ports) { + write_midi_messages(s, desc->ctx_payload, desc->data_blocks, + desc->data_block_counter); + } return pcm_frames; } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter) + const struct pkt_desc *desc, + struct snd_pcm_substream *pcm) { struct amdtp_am824 *p = s->protocol; - struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; if (pcm) { - read_pcm_s32(s, pcm, buffer, data_blocks); - pcm_frames = data_blocks * p->frame_multiplier; + read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks); + pcm_frames = desc->data_blocks * p->frame_multiplier; } else { pcm_frames = 0; } - if (p->midi_ports) - read_midi_messages(s, buffer, data_blocks, data_block_counter); + if (p->midi_ports) { + read_midi_messages(s, desc->ctx_payload, desc->data_blocks, + desc->data_block_counter); + } return pcm_frames; } diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 573265113a6f..db2feb68105c 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -768,13 +768,11 @@ static void process_ctx_payloads(struct amdtp_stream *s, for (i = 0; i < packets; ++i) { const struct pkt_desc *desc = descs + i; - struct snd_pcm_substream *pcm; + struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; - pcm_frames = s->process_data_blocks(s, desc->ctx_payload, - desc->data_blocks, desc->data_block_counter); + pcm_frames = s->process_data_blocks(s, desc, pcm); - pcm = READ_ONCE(s->pcm); if (pcm && pcm_frames > 0) update_pcm_pointers(s, pcm, pcm_frames); } diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 73c492c9a5d5..0e5b85100a04 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -105,9 +105,8 @@ struct pkt_desc { struct amdtp_stream; typedef unsigned int (*amdtp_stream_process_data_blocks_t)( struct amdtp_stream *s, - __be32 *buffer, - unsigned int data_blocks, - unsigned int data_block_counter); + const struct pkt_desc *desc, + struct snd_pcm_substream *pcm); struct amdtp_stream { struct fw_unit *unit; enum cip_flags flags; diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c index c296d1017ed3..83ac4b37f26d 100644 --- a/sound/firewire/digi00x/amdtp-dot.c +++ b/sound/firewire/digi00x/amdtp-dot.c @@ -330,42 +330,39 @@ void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter) + const struct pkt_desc *desc, + struct snd_pcm_substream *pcm) { - struct snd_pcm_substream *pcm; unsigned int pcm_frames; - pcm = READ_ONCE(s->pcm); if (pcm) { - read_pcm_s32(s, pcm, buffer, data_blocks); - pcm_frames = data_blocks; + read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks); + pcm_frames = desc->data_blocks; } else { pcm_frames = 0; } - read_midi_messages(s, buffer, data_blocks); + read_midi_messages(s, desc->ctx_payload, desc->data_blocks); return pcm_frames; } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter) + const struct pkt_desc *desc, + struct snd_pcm_substream *pcm) { - struct snd_pcm_substream *pcm; unsigned int pcm_frames; - pcm = READ_ONCE(s->pcm); if (pcm) { - write_pcm_s32(s, pcm, buffer, data_blocks); - pcm_frames = data_blocks; + write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks); + pcm_frames = desc->data_blocks; } else { - write_pcm_silence(s, buffer, data_blocks); + write_pcm_silence(s, desc->ctx_payload, desc->data_blocks); pcm_frames = 0; } - write_midi_messages(s, buffer, data_blocks, data_block_counter); + write_midi_messages(s, desc->ctx_payload, desc->data_blocks, + desc->data_block_counter); return pcm_frames; } diff --git a/sound/firewire/fireface/amdtp-ff.c b/sound/firewire/fireface/amdtp-ff.c index 31a60dff94ac..c36232fc4d3e 100644 --- a/sound/firewire/fireface/amdtp-ff.c +++ b/sound/firewire/fireface/amdtp-ff.c @@ -103,17 +103,18 @@ int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s, } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter) + const struct pkt_desc *desc, + struct snd_pcm_substream *pcm) { - struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; if (pcm) { - write_pcm_s32(s, pcm, (__le32 *)buffer, data_blocks); - pcm_frames = data_blocks; + write_pcm_s32(s, pcm, (__le32 *)desc->ctx_payload, + desc->data_blocks); + pcm_frames = desc->data_blocks; } else { - write_pcm_silence(s, (__le32 *)buffer, data_blocks); + write_pcm_silence(s, (__le32 *)desc->ctx_payload, + desc->data_blocks); pcm_frames = 0; } @@ -121,15 +122,15 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter) + const struct pkt_desc *desc, + struct snd_pcm_substream *pcm) { - struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); unsigned int pcm_frames; if (pcm) { - read_pcm_s32(s, pcm, (__le32 *)buffer, data_blocks); - pcm_frames = data_blocks; + read_pcm_s32(s, pcm, (__le32 *)desc->ctx_payload, + desc->data_blocks); + pcm_frames = desc->data_blocks; } else { pcm_frames = 0; } diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index 30d5f87119cc..36ee2c1dd667 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -299,23 +299,27 @@ static void __maybe_unused copy_message(u64 *frames, __be32 *buffer, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter) + const struct pkt_desc *desc, + struct snd_pcm_substream *pcm) { struct amdtp_motu *p = s->protocol; - struct snd_pcm_substream *pcm; + unsigned int pcm_frames; - trace_data_block_sph(s, data_blocks, buffer); - trace_data_block_message(s, data_blocks, buffer); + trace_data_block_sph(s, desc->data_blocks, desc->ctx_payload); + trace_data_block_message(s, desc->data_blocks, desc->ctx_payload); if (p->midi_ports) - read_midi_messages(s, buffer, data_blocks); + read_midi_messages(s, desc->ctx_payload, desc->data_blocks); - pcm = READ_ONCE(s->pcm); - if (data_blocks > 0 && pcm) - read_pcm_s32(s, pcm->runtime, buffer, data_blocks); + if (pcm) { + read_pcm_s32(s, pcm->runtime, desc->ctx_payload, + desc->data_blocks); + pcm_frames = desc->data_blocks; + } else { + pcm_frames = 0; + } - return data_blocks; + return pcm_frames; } static inline void compute_next_elapse_from_start(struct amdtp_motu *p) @@ -361,29 +365,32 @@ static void write_sph(struct amdtp_stream *s, __be32 *buffer, } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter) + const struct pkt_desc *desc, + struct snd_pcm_substream *pcm) { struct amdtp_motu *p = (struct amdtp_motu *)s->protocol; - struct snd_pcm_substream *pcm; + unsigned int pcm_frames; /* TODO: how to interact control messages between userspace? */ if (p->midi_ports) - write_midi_messages(s, buffer, data_blocks); + write_midi_messages(s, desc->ctx_payload, desc->data_blocks); - pcm = READ_ONCE(s->pcm); - if (pcm) - write_pcm_s32(s, pcm->runtime, buffer, data_blocks); - else - write_pcm_silence(s, buffer, data_blocks); + if (pcm) { + write_pcm_s32(s, pcm->runtime, desc->ctx_payload, + desc->data_blocks); + pcm_frames = desc->data_blocks; + } else { + write_pcm_silence(s, desc->ctx_payload, desc->data_blocks); + pcm_frames = 0; + } - write_sph(s, buffer, data_blocks); + write_sph(s, desc->ctx_payload, desc->data_blocks); - trace_data_block_sph(s, data_blocks, buffer); - trace_data_block_message(s, data_blocks, buffer); + trace_data_block_sph(s, desc->data_blocks, desc->ctx_payload); + trace_data_block_message(s, desc->data_blocks, desc->ctx_payload); - return data_blocks; + return pcm_frames; } int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c index bc1f2d2120b4..970b1c4a8ea6 100644 --- a/sound/firewire/tascam/amdtp-tascam.c +++ b/sound/firewire/tascam/amdtp-tascam.c @@ -166,33 +166,38 @@ static void read_status_messages(struct amdtp_stream *s, } static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter) + const struct pkt_desc *desc, + struct snd_pcm_substream *pcm) { - struct snd_pcm_substream *pcm; + unsigned int pcm_frames; - pcm = READ_ONCE(s->pcm); - if (data_blocks > 0 && pcm) - read_pcm_s32(s, pcm, buffer, data_blocks); + if (pcm) { + read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks); + pcm_frames = desc->data_blocks; + } else { + pcm_frames = 0; + } - read_status_messages(s, buffer, data_blocks); + read_status_messages(s, desc->ctx_payload, desc->data_blocks); - return data_blocks; + return pcm_frames; } static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - __be32 *buffer, unsigned int data_blocks, - unsigned int data_block_counter) + const struct pkt_desc *desc, + struct snd_pcm_substream *pcm) { - struct snd_pcm_substream *pcm; + unsigned int pcm_frames; - pcm = READ_ONCE(s->pcm); - if (pcm) - write_pcm_s32(s, pcm, buffer, data_blocks); - else - write_pcm_silence(s, buffer, data_blocks); + if (pcm) { + write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks); + pcm_frames = desc->data_blocks; + } else { + write_pcm_silence(s, desc->ctx_payload, desc->data_blocks); + pcm_frames = 0; + } - return data_blocks; + return pcm_frames; } int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit, -- cgit v1.2.3 From 9fc90644cae9c0abfcce0576ed0a14cca67f69b9 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:37:04 +0900 Subject: ALSA: firewire-lib: code refactoring for AM824 data block processing layer This is code refactoring for AM824 data block processing layer so that it can receive list of packet descriptor. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-am824.c | 51 ++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index ff089ffa3374..5d2952a1a9b2 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -146,19 +146,24 @@ void amdtp_am824_set_midi_position(struct amdtp_stream *s, } EXPORT_SYMBOL_GPL(amdtp_am824_set_midi_position); -static void write_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) +static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames, + unsigned int pcm_frames) { struct amdtp_am824 *p = s->protocol; + unsigned int channels = p->pcm_channels; struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; + unsigned int pcm_buffer_pointer; + int remaining_frames; const u32 *src; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - channels = p->pcm_channels; src = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { @@ -172,19 +177,24 @@ static void write_pcm_s32(struct amdtp_stream *s, } } -static void read_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) +static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames, + unsigned int pcm_frames) { struct amdtp_am824 *p = s->protocol; + unsigned int channels = p->pcm_channels; struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; + unsigned int pcm_buffer_pointer; + int remaining_frames; u32 *dst; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - channels = p->pcm_channels; dst = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { @@ -340,14 +350,14 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, struct snd_pcm_substream *pcm) { struct amdtp_am824 *p = s->protocol; - unsigned int pcm_frames; + unsigned int pcm_frames = 0; if (pcm) { - write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks); + write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, + pcm_frames); pcm_frames = desc->data_blocks * p->frame_multiplier; } else { write_pcm_silence(s, desc->ctx_payload, desc->data_blocks); - pcm_frames = 0; } if (p->midi_ports) { @@ -363,13 +373,12 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, struct snd_pcm_substream *pcm) { struct amdtp_am824 *p = s->protocol; - unsigned int pcm_frames; + unsigned int pcm_frames = 0; if (pcm) { - read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks); + read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, + pcm_frames); pcm_frames = desc->data_blocks * p->frame_multiplier; - } else { - pcm_frames = 0; } if (p->midi_ports) { -- cgit v1.2.3 From bb473966774a79ae9a826f721059496d9b393acc Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:37:05 +0900 Subject: ALSA: firewire-digi00x: code refactoring for DOT data block processing layer This is code refactoring for DOT data block processing layer so that it can receive list of packet descriptor. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/digi00x/amdtp-dot.c | 45 ++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c index 83ac4b37f26d..cef5caf97236 100644 --- a/sound/firewire/digi00x/amdtp-dot.c +++ b/sound/firewire/digi00x/amdtp-dot.c @@ -143,17 +143,23 @@ int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate, } static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) + __be32 *buffer, unsigned int frames, + unsigned int pcm_frames) { struct amdtp_dot *p = s->protocol; + unsigned int channels = p->pcm_channels; struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; + unsigned int pcm_buffer_pointer; + int remaining_frames; const u32 *src; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - channels = p->pcm_channels; src = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; buffer++; for (i = 0; i < frames; ++i) { @@ -169,17 +175,23 @@ static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, } static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) + __be32 *buffer, unsigned int frames, + unsigned int pcm_frames) { struct amdtp_dot *p = s->protocol; + unsigned int channels = p->pcm_channels; struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; + unsigned int pcm_buffer_pointer; + int remaining_frames; u32 *dst; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - channels = p->pcm_channels; dst = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; buffer++; for (i = 0; i < frames; ++i) { @@ -333,13 +345,12 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, const struct pkt_desc *desc, struct snd_pcm_substream *pcm) { - unsigned int pcm_frames; + unsigned int pcm_frames = 0; if (pcm) { - read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks); + read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, + pcm_frames); pcm_frames = desc->data_blocks; - } else { - pcm_frames = 0; } read_midi_messages(s, desc->ctx_payload, desc->data_blocks); @@ -351,14 +362,14 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, const struct pkt_desc *desc, struct snd_pcm_substream *pcm) { - unsigned int pcm_frames; + unsigned int pcm_frames = 0; if (pcm) { - write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks); + write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, + pcm_frames); pcm_frames = desc->data_blocks; } else { write_pcm_silence(s, desc->ctx_payload, desc->data_blocks); - pcm_frames = 0; } write_midi_messages(s, desc->ctx_payload, desc->data_blocks, -- cgit v1.2.3 From 806653b70ee21b374d2844d144609b2e0070a86b Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:37:06 +0900 Subject: ALSA: firewire-tascam: code refactoring for TASCAM data block processing layer This is code refactoring for TASCAM data block processing layer so that it can receive list of packet descriptor. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/tascam/amdtp-tascam.c | 55 +++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c index 970b1c4a8ea6..3c9abf422f24 100644 --- a/sound/firewire/tascam/amdtp-tascam.c +++ b/sound/firewire/tascam/amdtp-tascam.c @@ -32,19 +32,24 @@ int amdtp_tscm_set_parameters(struct amdtp_stream *s, unsigned int rate) return amdtp_stream_set_parameters(s, rate, data_channels); } -static void write_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) +static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames, + unsigned int pcm_frames) { struct amdtp_tscm *p = s->protocol; + unsigned int channels = p->pcm_channels; struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; + unsigned int pcm_buffer_pointer; + int remaining_frames; const u32 *src; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - channels = p->pcm_channels; src = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { @@ -57,19 +62,24 @@ static void write_pcm_s32(struct amdtp_stream *s, } } -static void read_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __be32 *buffer, unsigned int frames) +static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int frames, + unsigned int pcm_frames) { struct amdtp_tscm *p = s->protocol; + unsigned int channels = p->pcm_channels; struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; + unsigned int pcm_buffer_pointer; + int remaining_frames; u32 *dst; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - channels = p->pcm_channels; dst = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; /* The first data channel is for event counter. */ buffer += 1; @@ -169,13 +179,12 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, const struct pkt_desc *desc, struct snd_pcm_substream *pcm) { - unsigned int pcm_frames; + unsigned int pcm_frames = 0; if (pcm) { - read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks); - pcm_frames = desc->data_blocks; - } else { - pcm_frames = 0; + read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, + pcm_frames); + pcm_frames += desc->data_blocks; } read_status_messages(s, desc->ctx_payload, desc->data_blocks); @@ -187,14 +196,14 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, const struct pkt_desc *desc, struct snd_pcm_substream *pcm) { - unsigned int pcm_frames; + unsigned int pcm_frames = 0; if (pcm) { - write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks); - pcm_frames = desc->data_blocks; + write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, + pcm_frames); + pcm_frames += desc->data_blocks; } else { write_pcm_silence(s, desc->ctx_payload, desc->data_blocks); - pcm_frames = 0; } return pcm_frames; -- cgit v1.2.3 From 00d004db6493c62b8bbd7073a9b3b7290cbe0cea Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:37:07 +0900 Subject: ALSA: firewire-motu: code refactoring for MOTU data block processing layer This is code refactoring for MOTU data block processing layer so that it can receive list of packet descriptor. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/motu/amdtp-motu.c | 57 +++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index 36ee2c1dd667..21c6bfdf47c0 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -117,19 +117,25 @@ int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate, return 0; } -static void read_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_runtime *runtime, - __be32 *buffer, unsigned int data_blocks) +static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int data_blocks, + unsigned int pcm_frames) { struct amdtp_motu *p = s->protocol; - unsigned int channels, remaining_frames, i, c; + unsigned int channels = p->pcm_chunks; + struct snd_pcm_runtime *runtime = pcm->runtime; + unsigned int pcm_buffer_pointer; + int remaining_frames; u8 *byte; u32 *dst; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - channels = p->pcm_chunks; dst = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; for (i = 0; i < data_blocks; ++i) { byte = (u8 *)buffer + p->pcm_byte_offset; @@ -147,19 +153,25 @@ static void read_pcm_s32(struct amdtp_stream *s, } } -static void write_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_runtime *runtime, - __be32 *buffer, unsigned int data_blocks) +static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, + __be32 *buffer, unsigned int data_blocks, + unsigned int pcm_frames) { struct amdtp_motu *p = s->protocol; - unsigned int channels, remaining_frames, i, c; + unsigned int channels = p->pcm_chunks; + struct snd_pcm_runtime *runtime = pcm->runtime; + unsigned int pcm_buffer_pointer; + int remaining_frames; u8 *byte; const u32 *src; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - channels = p->pcm_chunks; src = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; for (i = 0; i < data_blocks; ++i) { byte = (u8 *)buffer + p->pcm_byte_offset; @@ -303,7 +315,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, struct snd_pcm_substream *pcm) { struct amdtp_motu *p = s->protocol; - unsigned int pcm_frames; + unsigned int pcm_frames = 0; trace_data_block_sph(s, desc->data_blocks, desc->ctx_payload); trace_data_block_message(s, desc->data_blocks, desc->ctx_payload); @@ -312,11 +324,9 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, read_midi_messages(s, desc->ctx_payload, desc->data_blocks); if (pcm) { - read_pcm_s32(s, pcm->runtime, desc->ctx_payload, - desc->data_blocks); + read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, + pcm_frames); pcm_frames = desc->data_blocks; - } else { - pcm_frames = 0; } return pcm_frames; @@ -368,8 +378,8 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, const struct pkt_desc *desc, struct snd_pcm_substream *pcm) { - struct amdtp_motu *p = (struct amdtp_motu *)s->protocol; - unsigned int pcm_frames; + struct amdtp_motu *p = s->protocol; + unsigned int pcm_frames = 0; /* TODO: how to interact control messages between userspace? */ @@ -377,12 +387,11 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, write_midi_messages(s, desc->ctx_payload, desc->data_blocks); if (pcm) { - write_pcm_s32(s, pcm->runtime, desc->ctx_payload, - desc->data_blocks); + write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, + pcm_frames); pcm_frames = desc->data_blocks; } else { write_pcm_silence(s, desc->ctx_payload, desc->data_blocks); - pcm_frames = 0; } write_sph(s, desc->ctx_payload, desc->data_blocks); -- cgit v1.2.3 From 4731c672c930e490515f1747fb34d56d61ae57ac Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:37:08 +0900 Subject: ALSA: fireface: code refactoring for FF data block processing layer This is code refactoring for FF data block processing layer so that it can receive list of packet descriptor. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/amdtp-ff.c | 49 ++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireface/amdtp-ff.c b/sound/firewire/fireface/amdtp-ff.c index c36232fc4d3e..cb2073cf146b 100644 --- a/sound/firewire/fireface/amdtp-ff.c +++ b/sound/firewire/fireface/amdtp-ff.c @@ -27,19 +27,24 @@ int amdtp_ff_set_parameters(struct amdtp_stream *s, unsigned int rate, return amdtp_stream_set_parameters(s, rate, data_channels); } -static void write_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __le32 *buffer, unsigned int frames) +static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, + __le32 *buffer, unsigned int frames, + unsigned int pcm_frames) { struct amdtp_ff *p = s->protocol; + unsigned int channels = p->pcm_channels; struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; + unsigned int pcm_buffer_pointer; + int remaining_frames; const u32 *src; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - channels = p->pcm_channels; src = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { @@ -52,19 +57,24 @@ static void write_pcm_s32(struct amdtp_stream *s, } } -static void read_pcm_s32(struct amdtp_stream *s, - struct snd_pcm_substream *pcm, - __le32 *buffer, unsigned int frames) +static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, + __le32 *buffer, unsigned int frames, + unsigned int pcm_frames) { struct amdtp_ff *p = s->protocol; + unsigned int channels = p->pcm_channels; struct snd_pcm_runtime *runtime = pcm->runtime; - unsigned int channels, remaining_frames, i, c; + unsigned int pcm_buffer_pointer; + int remaining_frames; u32 *dst; + int i, c; + + pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; + pcm_buffer_pointer %= runtime->buffer_size; - channels = p->pcm_channels; dst = (void *)runtime->dma_area + - frames_to_bytes(runtime, s->pcm_buffer_pointer); - remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer; + frames_to_bytes(runtime, pcm_buffer_pointer); + remaining_frames = runtime->buffer_size - pcm_buffer_pointer; for (i = 0; i < frames; ++i) { for (c = 0; c < channels; ++c) { @@ -106,16 +116,15 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, const struct pkt_desc *desc, struct snd_pcm_substream *pcm) { - unsigned int pcm_frames; + unsigned int pcm_frames = 0; if (pcm) { write_pcm_s32(s, pcm, (__le32 *)desc->ctx_payload, - desc->data_blocks); + desc->data_blocks, pcm_frames); pcm_frames = desc->data_blocks; } else { write_pcm_silence(s, (__le32 *)desc->ctx_payload, desc->data_blocks); - pcm_frames = 0; } return pcm_frames; @@ -125,14 +134,12 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, const struct pkt_desc *desc, struct snd_pcm_substream *pcm) { - unsigned int pcm_frames; + unsigned int pcm_frames = 0; if (pcm) { read_pcm_s32(s, pcm, (__le32 *)desc->ctx_payload, - desc->data_blocks); + desc->data_blocks, pcm_frames); pcm_frames = desc->data_blocks; - } else { - pcm_frames = 0; } return pcm_frames; -- cgit v1.2.3 From 9a738ad1b1a64ef6d8271d8d42d715b75db6eb0d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:37:09 +0900 Subject: ALSA: firewire-lib: process payload of isoc context according to packet descriptors This commit changes each of data block processing layer so that it receives list of packet descriptor. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-am824.c | 71 +++++++++++++++++++-------------- sound/firewire/amdtp-stream.c | 25 +++++------- sound/firewire/amdtp-stream.h | 7 ++-- sound/firewire/digi00x/amdtp-dot.c | 66 +++++++++++++++++++------------ sound/firewire/fireface/amdtp-ff.c | 55 ++++++++++++++++---------- sound/firewire/motu/amdtp-motu.c | 76 +++++++++++++++++++++--------------- sound/firewire/tascam/amdtp-tascam.c | 60 +++++++++++++++++----------- 7 files changed, 212 insertions(+), 148 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index 5d2952a1a9b2..67d735e9a6a4 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -345,45 +345,59 @@ static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, } } -static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - const struct pkt_desc *desc, - struct snd_pcm_substream *pcm) +static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets, + struct snd_pcm_substream *pcm) { struct amdtp_am824 *p = s->protocol; unsigned int pcm_frames = 0; + int i; - if (pcm) { - write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, - pcm_frames); - pcm_frames = desc->data_blocks * p->frame_multiplier; - } else { - write_pcm_silence(s, desc->ctx_payload, desc->data_blocks); - } + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; - if (p->midi_ports) { - write_midi_messages(s, desc->ctx_payload, desc->data_blocks, - desc->data_block_counter); + if (pcm) { + write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks * p->frame_multiplier; + } else { + write_pcm_silence(s, buf, data_blocks); + } + + if (p->midi_ports) { + write_midi_messages(s, buf, data_blocks, + desc->data_block_counter); + } } return pcm_frames; } -static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - const struct pkt_desc *desc, - struct snd_pcm_substream *pcm) +static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets, + struct snd_pcm_substream *pcm) { struct amdtp_am824 *p = s->protocol; unsigned int pcm_frames = 0; + int i; - if (pcm) { - read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, - pcm_frames); - pcm_frames = desc->data_blocks * p->frame_multiplier; - } + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; + + if (pcm) { + read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks * p->frame_multiplier; + } - if (p->midi_ports) { - read_midi_messages(s, desc->ctx_payload, desc->data_blocks, - desc->data_block_counter); + if (p->midi_ports) { + read_midi_messages(s, buf, data_blocks, + desc->data_block_counter); + } } return pcm_frames; @@ -400,15 +414,14 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, enum cip_flags flags) { - amdtp_stream_process_data_blocks_t process_data_blocks; + amdtp_stream_process_ctx_payloads_t process_ctx_payloads; if (dir == AMDTP_IN_STREAM) - process_data_blocks = process_tx_data_blocks; + process_ctx_payloads = process_ir_ctx_payloads; else - process_data_blocks = process_rx_data_blocks; + process_ctx_payloads = process_it_ctx_payloads; return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM, - process_data_blocks, - sizeof(struct amdtp_am824)); + process_ctx_payloads, sizeof(struct amdtp_am824)); } EXPORT_SYMBOL_GPL(amdtp_am824_init); diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index db2feb68105c..369e75e33120 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -74,16 +74,16 @@ static void pcm_period_tasklet(unsigned long data); * @dir: the direction of stream * @flags: the packet transmission method to use * @fmt: the value of fmt field in CIP header - * @process_data_blocks: callback handler to process data blocks + * @process_ctx_payloads: callback handler to process payloads of isoc context * @protocol_size: the size to allocate newly for protocol */ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, enum cip_flags flags, unsigned int fmt, - amdtp_stream_process_data_blocks_t process_data_blocks, + amdtp_stream_process_ctx_payloads_t process_ctx_payloads, unsigned int protocol_size) { - if (process_data_blocks == NULL) + if (process_ctx_payloads == NULL) return -EINVAL; s->protocol = kzalloc(protocol_size, GFP_KERNEL); @@ -102,7 +102,7 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, s->callbacked = false; s->fmt = fmt; - s->process_data_blocks = process_data_blocks; + s->process_ctx_payloads = process_ctx_payloads; if (dir == AMDTP_OUT_STREAM) s->ctx_data.rx.syt_override = -1; @@ -764,18 +764,13 @@ static void process_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *descs, unsigned int packets) { - int i; - - for (i = 0; i < packets; ++i) { - const struct pkt_desc *desc = descs + i; - struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); - unsigned int pcm_frames; - - pcm_frames = s->process_data_blocks(s, desc, pcm); + struct snd_pcm_substream *pcm; + unsigned int pcm_frames; - if (pcm && pcm_frames > 0) - update_pcm_pointers(s, pcm, pcm_frames); - } + pcm = READ_ONCE(s->pcm); + pcm_frames = s->process_ctx_payloads(s, descs, packets, pcm); + if (pcm) + update_pcm_pointers(s, pcm, pcm_frames); } static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 0e5b85100a04..50041fa884d9 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -103,9 +103,10 @@ struct pkt_desc { }; struct amdtp_stream; -typedef unsigned int (*amdtp_stream_process_data_blocks_t)( +typedef unsigned int (*amdtp_stream_process_ctx_payloads_t)( struct amdtp_stream *s, const struct pkt_desc *desc, + unsigned int packets, struct snd_pcm_substream *pcm); struct amdtp_stream { struct fw_unit *unit; @@ -168,13 +169,13 @@ struct amdtp_stream { /* For backends to process data blocks. */ void *protocol; - amdtp_stream_process_data_blocks_t process_data_blocks; + amdtp_stream_process_ctx_payloads_t process_ctx_payloads; }; int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, enum cip_flags flags, unsigned int fmt, - amdtp_stream_process_data_blocks_t process_data_blocks, + amdtp_stream_process_ctx_payloads_t process_ctx_payloads, unsigned int protocol_size); void amdtp_stream_destroy(struct amdtp_stream *s); diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c index cef5caf97236..d613642a2ce3 100644 --- a/sound/firewire/digi00x/amdtp-dot.c +++ b/sound/firewire/digi00x/amdtp-dot.c @@ -341,39 +341,53 @@ void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, WRITE_ONCE(p->midi[port], midi); } -static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - const struct pkt_desc *desc, - struct snd_pcm_substream *pcm) +static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets, + struct snd_pcm_substream *pcm) { unsigned int pcm_frames = 0; + int i; - if (pcm) { - read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, - pcm_frames); - pcm_frames = desc->data_blocks; - } + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; - read_midi_messages(s, desc->ctx_payload, desc->data_blocks); + if (pcm) { + read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks; + } + + read_midi_messages(s, buf, data_blocks); + } return pcm_frames; } -static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - const struct pkt_desc *desc, - struct snd_pcm_substream *pcm) +static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets, + struct snd_pcm_substream *pcm) { unsigned int pcm_frames = 0; + int i; - if (pcm) { - write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, - pcm_frames); - pcm_frames = desc->data_blocks; - } else { - write_pcm_silence(s, desc->ctx_payload, desc->data_blocks); - } + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; - write_midi_messages(s, desc->ctx_payload, desc->data_blocks, - desc->data_block_counter); + if (pcm) { + write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks; + } else { + write_pcm_silence(s, buf, data_blocks); + } + + write_midi_messages(s, buf, data_blocks, + desc->data_block_counter); + } return pcm_frames; } @@ -381,20 +395,20 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, int amdtp_dot_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir) { - amdtp_stream_process_data_blocks_t process_data_blocks; + amdtp_stream_process_ctx_payloads_t process_ctx_payloads; enum cip_flags flags; - /* Use different mode between incoming/outgoing. */ + // Use different mode between incoming/outgoing. if (dir == AMDTP_IN_STREAM) { flags = CIP_NONBLOCKING; - process_data_blocks = process_tx_data_blocks; + process_ctx_payloads = process_ir_ctx_payloads; } else { flags = CIP_BLOCKING; - process_data_blocks = process_rx_data_blocks; + process_ctx_payloads = process_it_ctx_payloads; } return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM, - process_data_blocks, sizeof(struct amdtp_dot)); + process_ctx_payloads, sizeof(struct amdtp_dot)); } void amdtp_dot_reset(struct amdtp_stream *s) diff --git a/sound/firewire/fireface/amdtp-ff.c b/sound/firewire/fireface/amdtp-ff.c index cb2073cf146b..119c0076b17a 100644 --- a/sound/firewire/fireface/amdtp-ff.c +++ b/sound/firewire/fireface/amdtp-ff.c @@ -112,34 +112,47 @@ int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s, return amdtp_stream_add_pcm_hw_constraints(s, runtime); } -static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - const struct pkt_desc *desc, +static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets, struct snd_pcm_substream *pcm) { unsigned int pcm_frames = 0; - - if (pcm) { - write_pcm_s32(s, pcm, (__le32 *)desc->ctx_payload, - desc->data_blocks, pcm_frames); - pcm_frames = desc->data_blocks; - } else { - write_pcm_silence(s, (__le32 *)desc->ctx_payload, - desc->data_blocks); + int i; + + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __le32 *buf = (__le32 *)desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; + + if (pcm) { + write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks; + } else { + write_pcm_silence(s, buf, data_blocks); + } } return pcm_frames; } -static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - const struct pkt_desc *desc, - struct snd_pcm_substream *pcm) +static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets, + struct snd_pcm_substream *pcm) { unsigned int pcm_frames = 0; + int i; - if (pcm) { - read_pcm_s32(s, pcm, (__le32 *)desc->ctx_payload, - desc->data_blocks, pcm_frames); - pcm_frames = desc->data_blocks; + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __le32 *buf = (__le32 *)desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; + + if (pcm) { + read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks; + } } return pcm_frames; @@ -148,13 +161,13 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir) { - amdtp_stream_process_data_blocks_t process_data_blocks; + amdtp_stream_process_ctx_payloads_t process_ctx_payloads; if (dir == AMDTP_IN_STREAM) - process_data_blocks = process_tx_data_blocks; + process_ctx_payloads = process_ir_ctx_payloads; else - process_data_blocks = process_rx_data_blocks; + process_ctx_payloads = process_it_ctx_payloads; return amdtp_stream_init(s, unit, dir, CIP_NO_HEADER, 0, - process_data_blocks, sizeof(struct amdtp_ff)); + process_ctx_payloads, sizeof(struct amdtp_ff)); } diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index 21c6bfdf47c0..05a6e218b0ad 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -310,23 +310,30 @@ static void __maybe_unused copy_message(u64 *frames, __be32 *buffer, } } -static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - const struct pkt_desc *desc, - struct snd_pcm_substream *pcm) +static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets, + struct snd_pcm_substream *pcm) { struct amdtp_motu *p = s->protocol; unsigned int pcm_frames = 0; + int i; + + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; - trace_data_block_sph(s, desc->data_blocks, desc->ctx_payload); - trace_data_block_message(s, desc->data_blocks, desc->ctx_payload); + trace_data_block_sph(s, data_blocks, buf); + trace_data_block_message(s, data_blocks, buf); - if (p->midi_ports) - read_midi_messages(s, desc->ctx_payload, desc->data_blocks); + if (p->midi_ports) + read_midi_messages(s, buf, data_blocks); - if (pcm) { - read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, - pcm_frames); - pcm_frames = desc->data_blocks; + if (pcm) { + read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks; + } } return pcm_frames; @@ -374,30 +381,37 @@ static void write_sph(struct amdtp_stream *s, __be32 *buffer, } } -static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - const struct pkt_desc *desc, - struct snd_pcm_substream *pcm) +static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets, + struct snd_pcm_substream *pcm) { struct amdtp_motu *p = s->protocol; unsigned int pcm_frames = 0; + int i; - /* TODO: how to interact control messages between userspace? */ + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; - if (p->midi_ports) - write_midi_messages(s, desc->ctx_payload, desc->data_blocks); + // TODO: how to interact control messages between userspace? - if (pcm) { - write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, - pcm_frames); - pcm_frames = desc->data_blocks; - } else { - write_pcm_silence(s, desc->ctx_payload, desc->data_blocks); - } + if (p->midi_ports) + write_midi_messages(s, buf, data_blocks); - write_sph(s, desc->ctx_payload, desc->data_blocks); + if (pcm) { + write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks; + } else { + write_pcm_silence(s, buf, data_blocks); + } - trace_data_block_sph(s, desc->data_blocks, desc->ctx_payload); - trace_data_block_message(s, desc->data_blocks, desc->ctx_payload); + write_sph(s, buf, data_blocks); + + trace_data_block_sph(s, data_blocks, buf); + trace_data_block_message(s, data_blocks, buf); + } return pcm_frames; } @@ -406,13 +420,13 @@ int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, const struct snd_motu_protocol *const protocol) { - amdtp_stream_process_data_blocks_t process_data_blocks; + amdtp_stream_process_ctx_payloads_t process_ctx_payloads; int fmt = CIP_FMT_MOTU; int flags = CIP_BLOCKING; int err; if (dir == AMDTP_IN_STREAM) { - process_data_blocks = process_tx_data_blocks; + process_ctx_payloads = process_ir_ctx_payloads; /* * Units of version 3 transmits packets with invalid CIP header @@ -431,11 +445,11 @@ int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, CIP_SKIP_DBC_ZERO_CHECK; } } else { - process_data_blocks = process_rx_data_blocks; + process_ctx_payloads = process_it_ctx_payloads; flags |= CIP_DBC_IS_END_EVENT; } - err = amdtp_stream_init(s, unit, dir, flags, fmt, process_data_blocks, + err = amdtp_stream_init(s, unit, dir, flags, fmt, process_ctx_payloads, sizeof(struct amdtp_motu)); if (err < 0) return err; diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c index 3c9abf422f24..e80bb84c43f6 100644 --- a/sound/firewire/tascam/amdtp-tascam.c +++ b/sound/firewire/tascam/amdtp-tascam.c @@ -175,35 +175,49 @@ static void read_status_messages(struct amdtp_stream *s, } } -static unsigned int process_tx_data_blocks(struct amdtp_stream *s, - const struct pkt_desc *desc, - struct snd_pcm_substream *pcm) +static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets, + struct snd_pcm_substream *pcm) { unsigned int pcm_frames = 0; + int i; - if (pcm) { - read_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, - pcm_frames); - pcm_frames += desc->data_blocks; - } + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; - read_status_messages(s, desc->ctx_payload, desc->data_blocks); + if (pcm) { + read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks; + } + + read_status_messages(s, buf, data_blocks); + } return pcm_frames; } -static unsigned int process_rx_data_blocks(struct amdtp_stream *s, - const struct pkt_desc *desc, - struct snd_pcm_substream *pcm) +static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets, + struct snd_pcm_substream *pcm) { unsigned int pcm_frames = 0; + int i; - if (pcm) { - write_pcm_s32(s, pcm, desc->ctx_payload, desc->data_blocks, - pcm_frames); - pcm_frames += desc->data_blocks; - } else { - write_pcm_silence(s, desc->ctx_payload, desc->data_blocks); + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; + + if (pcm) { + write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); + pcm_frames += data_blocks; + } else { + write_pcm_silence(s, buf, data_blocks); + } } return pcm_frames; @@ -212,22 +226,22 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, unsigned int pcm_channels) { - amdtp_stream_process_data_blocks_t process_data_blocks; + amdtp_stream_process_ctx_payloads_t process_ctx_payloads; struct amdtp_tscm *p; unsigned int fmt; int err; if (dir == AMDTP_IN_STREAM) { fmt = AMDTP_FMT_TSCM_TX; - process_data_blocks = process_tx_data_blocks; + process_ctx_payloads = process_ir_ctx_payloads; } else { fmt = AMDTP_FMT_TSCM_RX; - process_data_blocks = process_rx_data_blocks; + process_ctx_payloads = process_it_ctx_payloads; } err = amdtp_stream_init(s, unit, dir, - CIP_NONBLOCKING | CIP_SKIP_DBC_ZERO_CHECK, fmt, - process_data_blocks, sizeof(struct amdtp_tscm)); + CIP_NONBLOCKING | CIP_SKIP_DBC_ZERO_CHECK, fmt, + process_ctx_payloads, sizeof(struct amdtp_tscm)); if (err < 0) return 0; -- cgit v1.2.3 From d2d5a6b0253d30ef04d513447cdd00df4fa627c3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 22 Jul 2019 12:37:10 +0900 Subject: ALSA: firewire-motu: more code refactoring for MOTU data block processing layer MOTU data block processing layer has some tracepoints events. This commit is code refactoring to split probing the events from processing data blocks. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/motu/amdtp-motu.c | 50 +++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index 05a6e218b0ad..0fd36e469ad0 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -310,6 +310,22 @@ static void __maybe_unused copy_message(u64 *frames, __be32 *buffer, } } +static void probe_tracepoints_events(struct amdtp_stream *s, + const struct pkt_desc *descs, + unsigned int packets) +{ + int i; + + for (i = 0; i < packets; ++i) { + const struct pkt_desc *desc = descs + i; + __be32 *buf = desc->ctx_payload; + unsigned int data_blocks = desc->data_blocks; + + trace_data_block_sph(s, data_blocks, buf); + trace_data_block_message(s, data_blocks, buf); + } +} + static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *descs, unsigned int packets, @@ -319,23 +335,26 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, unsigned int pcm_frames = 0; int i; + // For data block processing. for (i = 0; i < packets; ++i) { const struct pkt_desc *desc = descs + i; __be32 *buf = desc->ctx_payload; unsigned int data_blocks = desc->data_blocks; - trace_data_block_sph(s, data_blocks, buf); - trace_data_block_message(s, data_blocks, buf); - - if (p->midi_ports) - read_midi_messages(s, buf, data_blocks); - if (pcm) { read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); pcm_frames += data_blocks; } + + if (p->midi_ports) + read_midi_messages(s, buf, data_blocks); } + // For tracepoints. + if (trace_data_block_sph_enabled() || + trace_data_block_message_enabled()) + probe_tracepoints_events(s, descs, packets); + return pcm_frames; } @@ -390,16 +409,12 @@ static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, unsigned int pcm_frames = 0; int i; + // For data block processing. for (i = 0; i < packets; ++i) { const struct pkt_desc *desc = descs + i; __be32 *buf = desc->ctx_payload; unsigned int data_blocks = desc->data_blocks; - // TODO: how to interact control messages between userspace? - - if (p->midi_ports) - write_midi_messages(s, buf, data_blocks); - if (pcm) { write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); pcm_frames += data_blocks; @@ -407,12 +422,19 @@ static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, write_pcm_silence(s, buf, data_blocks); } - write_sph(s, buf, data_blocks); + if (p->midi_ports) + write_midi_messages(s, buf, data_blocks); - trace_data_block_sph(s, data_blocks, buf); - trace_data_block_message(s, data_blocks, buf); + // TODO: how to interact control messages between userspace? + + write_sph(s, buf, data_blocks); } + // For tracepoints. + if (trace_data_block_sph_enabled() || + trace_data_block_message_enabled()) + probe_tracepoints_events(s, descs, packets); + return pcm_frames; } -- cgit v1.2.3 From 748fd07e2b9ca4132e3d2aae25395aedc4d1aee8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 22 Jul 2019 14:52:09 +0100 Subject: ASoC: madera: Read device tree configuration Read the configuration of the Madera ASoC driver from device tree. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20190722135209.30302-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/madera.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c index 1b1be19a2f99..5f1e32a5a855 100644 --- a/sound/soc/codecs/madera.c +++ b/sound/soc/codecs/madera.c @@ -300,6 +300,100 @@ int madera_free_overheat(struct madera_priv *priv) } EXPORT_SYMBOL_GPL(madera_free_overheat); +static int madera_get_variable_u32_array(struct device *dev, + const char *propname, + u32 *dest, int n_max, + int multiple) +{ + int n, ret; + + n = device_property_count_u32(dev, propname); + if (n < 0) { + if (n == -EINVAL) + return 0; /* missing, ignore */ + + dev_warn(dev, "%s malformed (%d)\n", propname, n); + + return n; + } else if ((n % multiple) != 0) { + dev_warn(dev, "%s not a multiple of %d entries\n", + propname, multiple); + + return -EINVAL; + } + + if (n > n_max) + n = n_max; + + ret = device_property_read_u32_array(dev, propname, dest, n); + if (ret < 0) + return ret; + + return n; +} + +static void madera_prop_get_inmode(struct madera_priv *priv) +{ + struct madera *madera = priv->madera; + struct madera_codec_pdata *pdata = &madera->pdata.codec; + u32 tmp[MADERA_MAX_INPUT * MADERA_MAX_MUXED_CHANNELS]; + int n, i, in_idx, ch_idx; + + BUILD_BUG_ON(ARRAY_SIZE(pdata->inmode) != MADERA_MAX_INPUT); + BUILD_BUG_ON(ARRAY_SIZE(pdata->inmode[0]) != MADERA_MAX_MUXED_CHANNELS); + + n = madera_get_variable_u32_array(madera->dev, "cirrus,inmode", + tmp, ARRAY_SIZE(tmp), + MADERA_MAX_MUXED_CHANNELS); + if (n < 0) + return; + + in_idx = 0; + ch_idx = 0; + for (i = 0; i < n; ++i) { + pdata->inmode[in_idx][ch_idx] = tmp[i]; + + if (++ch_idx == MADERA_MAX_MUXED_CHANNELS) { + ch_idx = 0; + ++in_idx; + } + } +} + +static void madera_prop_get_pdata(struct madera_priv *priv) +{ + struct madera *madera = priv->madera; + struct madera_codec_pdata *pdata = &madera->pdata.codec; + u32 out_mono[ARRAY_SIZE(pdata->out_mono)]; + int i, n; + + madera_prop_get_inmode(priv); + + n = madera_get_variable_u32_array(madera->dev, "cirrus,out-mono", + out_mono, ARRAY_SIZE(out_mono), 1); + if (n > 0) + for (i = 0; i < n; ++i) + pdata->out_mono[i] = !!out_mono[i]; + + madera_get_variable_u32_array(madera->dev, + "cirrus,max-channels-clocked", + pdata->max_channels_clocked, + ARRAY_SIZE(pdata->max_channels_clocked), + 1); + + madera_get_variable_u32_array(madera->dev, "cirrus,pdm-fmt", + pdata->pdm_fmt, + ARRAY_SIZE(pdata->pdm_fmt), 1); + + madera_get_variable_u32_array(madera->dev, "cirrus,pdm-mute", + pdata->pdm_mute, + ARRAY_SIZE(pdata->pdm_mute), 1); + + madera_get_variable_u32_array(madera->dev, "cirrus,dmic-ref", + pdata->dmic_ref, + ARRAY_SIZE(pdata->dmic_ref), 1); +} + int madera_core_init(struct madera_priv *priv) { int i; @@ -308,6 +402,9 @@ int madera_core_init(struct madera_priv *priv) BUILD_BUG_ON(!madera_mixer_texts[MADERA_NUM_MIXER_INPUTS - 1]); BUILD_BUG_ON(!madera_mixer_values[MADERA_NUM_MIXER_INPUTS - 1]); + if (!dev_get_platdata(priv->madera->dev)) + madera_prop_get_pdata(priv); + mutex_init(&priv->rate_lock); for (i = 0; i < MADERA_MAX_HP_OUTPUT; i++) -- cgit v1.2.3 From f8f85216f8d309daadb37aba8a4b0826783d8747 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 22 Jul 2019 23:15:28 +0200 Subject: ASoC: pcm3168a: Fix a typo in the name of a constant There is a typo in PCM1368A_MAX_SYSCLK, it should be PCM3168A_MAX_SYSCLK (1 and 3 switched in 3168) Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/20190722211528.26600-1-christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index f1104d7d6426..5d59ce254821 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -263,7 +263,7 @@ static unsigned int pcm3168a_scki_ratios[] = { #define PCM3168A_NUM_SCKI_RATIOS_DAC ARRAY_SIZE(pcm3168a_scki_ratios) #define PCM3168A_NUM_SCKI_RATIOS_ADC (ARRAY_SIZE(pcm3168a_scki_ratios) - 2) -#define PCM1368A_MAX_SYSCLK 36864000 +#define PCM3168A_MAX_SYSCLK 36864000 static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a) { @@ -296,7 +296,7 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai, struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(dai->component); int ret; - if (freq > PCM1368A_MAX_SYSCLK) + if (freq > PCM3168A_MAX_SYSCLK) return -EINVAL; ret = clk_set_rate(pcm3168a->scki, freq); -- cgit v1.2.3 From f1b1b9b136827915624136624ff54aba5890a15b Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Mon, 22 Jul 2019 09:13:42 -0500 Subject: ASoC: SOF: pci: mark last_busy value at runtime PM init If last_busy value is not set at runtime PM enable, the device will be suspend immediately after usage counter is 0. Set the last_busy value to make sure delay is working at first boot up. Signed-off-by: Pan Xiuli Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-pci-dev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 65d1bac4c6b8..6fd3df7c57a3 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -223,6 +223,9 @@ static void sof_pci_probe_complete(struct device *dev) */ pm_runtime_allow(dev); + /* mark last_busy for pm_runtime to make sure not suspend immediately */ + pm_runtime_mark_last_busy(dev); + /* follow recommendation in pci-driver.c to decrement usage counter */ pm_runtime_put_noidle(dev); } -- cgit v1.2.3 From 04c8027764bc82a325d3abc6f39a6a4642a937cb Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 22 Jul 2019 09:13:43 -0500 Subject: ASoC: SOF: reset DMA state in prepare When application goes through SUSPEND/STOP->PREPARE->START cycle, we should always reprogram the SOF device to start DMA from a known state so that hw_ptr/appl_ptrs remain valid. This is expected by ALSA core as it resets the buffer state as part of prepare (see snd_pcm_do_prepare()). Fix the issue by forcing reconfiguration of the FW with STREAM_PCM_PARAMS in prepare(). Use combined logic to handle prepare and the existing flow to reprogram hw-params after system suspend. Without the fix, first call to pcm pointer() will return an invalid hw_ptr and application may immediately observe XRUN status, unless "start_threshold" SW parameter is set to maximum value by the application. Signed-off-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 27 +++++++++++++++------------ sound/soc/sof/pm.c | 2 +- sound/soc/sof/sof-priv.h | 2 +- 3 files changed, 17 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 334e9d59b1ba..3b8955e755b2 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -208,12 +208,11 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; + spcm->prepared[substream->stream] = true; + /* save pcm hw_params */ memcpy(&spcm->params[substream->stream], params, sizeof(*params)); - /* clear hw_params_upon_resume flag */ - spcm->hw_params_upon_resume[substream->stream] = 0; - return ret; } @@ -236,6 +235,9 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) if (!spcm) return -EINVAL; + if (!spcm->prepared[substream->stream]) + return 0; + dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); @@ -258,6 +260,8 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) if (ret < 0) dev_err(sdev->dev, "error: platform hw free failed\n"); + spcm->prepared[substream->stream] = false; + return ret; } @@ -278,11 +282,7 @@ static int sof_pcm_prepare(struct snd_pcm_substream *substream) if (!spcm) return -EINVAL; - /* - * check if hw_params needs to be set-up again. - * This is only needed when resuming from system sleep. - */ - if (!spcm->hw_params_upon_resume[substream->stream]) + if (spcm->prepared[substream->stream]) return 0; dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id, @@ -311,6 +311,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_sof_pcm *spcm; struct sof_ipc_stream stream; struct sof_ipc_reply reply; + bool reset_hw_params = false; int ret; /* nothing to do for BE */ @@ -351,6 +352,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; + reset_hw_params = true; break; default: dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd); @@ -363,17 +365,17 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, sizeof(stream), &reply, sizeof(reply)); - if (ret < 0 || cmd != SNDRV_PCM_TRIGGER_SUSPEND) + if (ret < 0 || !reset_hw_params) return ret; /* - * The hw_free op is usually called when the pcm stream is closed. - * Since the stream is not closed during suspend, the DSP needs to be - * notified explicitly to free pcm to prevent errors upon resume. + * In case of stream is stopped, DSP must be reprogrammed upon + * restart, so free PCM here. */ stream.hdr.size = sizeof(stream); stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; stream.comp_id = spcm->stream[substream->stream].comp_id; + spcm->prepared[substream->stream] = false; /* send IPC to the DSP */ return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, @@ -481,6 +483,7 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) spcm->stream[substream->stream].posn.host_posn = 0; spcm->stream[substream->stream].posn.dai_posn = 0; spcm->stream[substream->stream].substream = substream; + spcm->prepared[substream->stream] = false; ret = snd_sof_pcm_platform_open(sdev, substream); if (ret < 0) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 278abfd10490..48c6d78d72e2 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -233,7 +233,7 @@ static int sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev) state = substream->runtime->status->state; if (state == SNDRV_PCM_STATE_SUSPENDED) - spcm->hw_params_upon_resume[dir] = 1; + spcm->prepared[dir] = false; } } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index b8c0b2a22684..fa5cb7d2a660 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -297,7 +297,7 @@ struct snd_sof_pcm { struct snd_sof_pcm_stream stream[2]; struct list_head list; /* list in sdev pcm list */ struct snd_pcm_hw_params params[2]; - int hw_params_upon_resume[2]; /* set up hw_params upon resume */ + bool prepared[2]; /* PCM_PARAMS set successfully */ }; /* ALSA SOF Kcontrol device */ -- cgit v1.2.3 From a49b687192752bd373f33551520cc98389460ad0 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 22 Jul 2019 09:13:44 -0500 Subject: ASoC: SOF: use common code to send PCM_FREE IPC Remove duplicated code by using a common helper function to send the PCM_FREE IPC message to FW. Signed-off-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 3b8955e755b2..8612896673a5 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -216,6 +216,27 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, return ret; } +static int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, + struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm) +{ + struct sof_ipc_stream stream; + struct sof_ipc_reply reply; + int ret; + + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; + stream.comp_id = spcm->stream[substream->stream].comp_id; + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); + if (!ret) + spcm->prepared[substream->stream] = false; + + return ret; +} + static int sof_pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -223,8 +244,6 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; - struct sof_ipc_stream stream; - struct sof_ipc_reply reply; int ret; /* nothing to do for BE */ @@ -241,13 +260,7 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); - stream.hdr.size = sizeof(stream); - stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; - stream.comp_id = spcm->stream[substream->stream].comp_id; - - /* send IPC to the DSP */ - ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, - sizeof(stream), &reply, sizeof(reply)); + ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); snd_pcm_lib_free_pages(substream); @@ -260,8 +273,6 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) if (ret < 0) dev_err(sdev->dev, "error: platform hw free failed\n"); - spcm->prepared[substream->stream] = false; - return ret; } @@ -365,21 +376,10 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, sizeof(stream), &reply, sizeof(reply)); - if (ret < 0 || !reset_hw_params) - return ret; - - /* - * In case of stream is stopped, DSP must be reprogrammed upon - * restart, so free PCM here. - */ - stream.hdr.size = sizeof(stream); - stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; - stream.comp_id = spcm->stream[substream->stream].comp_id; - spcm->prepared[substream->stream] = false; + if (!ret && reset_hw_params) + ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); - /* send IPC to the DSP */ - return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, - sizeof(stream), &reply, sizeof(reply)); + return ret; } static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) -- cgit v1.2.3 From 6dd78b310b8d4ab5d0b851e369b5b3d46c6a32a9 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 22 Jul 2019 09:13:45 -0500 Subject: ASoC: SOF: ipc: use timeout configured at probe Do not hardcode IPC timeout value in ipc.c, but rather use the timeout value configured during device probe. For platforms that do not override the IPC timeout, default value TIMEOUT_DEFAULT_IPC_MS has already been defined in core.c. Signed-off-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 20dfca9c93b7..b2f359d2f7e5 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -17,12 +17,6 @@ #include "sof-priv.h" #include "ops.h" -/* - * IPC message default size and timeout (ms). - * TODO: allow platforms to set size and timeout. - */ -#define IPC_TIMEOUT_MS 300 - static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id); static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd); @@ -211,7 +205,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, /* wait for DSP IPC completion */ ret = wait_event_timeout(msg->waitq, msg->ipc_complete, - msecs_to_jiffies(IPC_TIMEOUT_MS)); + msecs_to_jiffies(sdev->ipc_timeout)); if (ret == 0) { dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n", -- cgit v1.2.3 From c9b54a3360166ca2fec11d55c86b5e685e56bab8 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 22 Jul 2019 09:13:46 -0500 Subject: ASoC: SOF: core: increase default IPC timeouts Increase the default timeout values for boot (100ms to 2sec) and IPC message sending (5ms to 500ms). The values should be overridden with values from platform data. There is no functional need to have such short timeouts as both boot and IPC send errors are considered fatal errors. More relaxed timeouts are convenient when running the driver on top of emulation such as QEMU. Signed-off-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 5beda47cdf9f..81f28f7ff1a0 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -17,8 +17,8 @@ #include "ops.h" /* SOF defaults if not provided by the platform in ms */ -#define TIMEOUT_DEFAULT_IPC_MS 5 -#define TIMEOUT_DEFAULT_BOOT_MS 100 +#define TIMEOUT_DEFAULT_IPC_MS 500 +#define TIMEOUT_DEFAULT_BOOT_MS 2000 /* * Generic object lookup APIs. -- cgit v1.2.3 From ce8234a6357ec8f81b977d8536ff941dbd4162f3 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 22 Jul 2019 09:13:47 -0500 Subject: ASoC: SOF: Introduce snd_sof_dsp_get_bar_index ops FW encapsulates information about section types (e.g DRAM, IRAM) inside module block header. This information can be used in order to correctly load the section to the appropriate place in memory. SOF Linux driver needs to know for each platform how to map the section type with the corresponding memory BAR. So, this patch introduces get_bar_index, a new operation inside snd_sof_dsp_ops. Intel platforms, usually load all the section in a contiguous memory area (usually denoted by sdev->mmio_bar) so things are relatively simple there. Anyhow, on i.MX8 IRAM and DRAM for example are mapped to distinct BARs. By default, if no get_bar function is provided the core implementation will always return sdev->mmio_bar so that there will be no need for a change to existing Intel code. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ops.h | 19 +++++++++++++++++++ sound/soc/sof/sof-priv.h | 3 +++ 2 files changed, 22 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index b1c27615b805..8fda42748f39 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -100,6 +100,25 @@ static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) return 0; } +/* misc */ + +/** + * snd_sof_dsp_get_bar_index - Maps a section type with a BAR index + * + * @sdev: sof device + * @type: section type as described by snd_sof_fw_blk_type + * + * Returns the corresponding BAR index (a positive integer) or -EINVAL + * in case there is no mapping + */ +static inline int snd_sof_dsp_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + if (sof_ops(sdev)->get_bar_index) + return sof_ops(sdev)->get_bar_index(sdev, type); + + return sdev->mmio_bar; +} + /* power management */ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index fa5cb7d2a660..a6ec9115a9fb 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -196,6 +196,9 @@ struct snd_sof_dsp_ops { int (*trace_trigger)(struct snd_sof_dev *sdev, int cmd); /* optional */ + /* misc */ + int (*get_bar_index)(struct snd_sof_dev *sdev, + u32 type); /* optional */ /* DAI ops */ struct snd_soc_dai_driver *drv; int num_drv; -- cgit v1.2.3 From 7198879ef57775df3b1a75c62bb9e313c56876d4 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 22 Jul 2019 09:13:48 -0500 Subject: ASoC: SOF: loader: Use the BAR provided by FW Make sure to use the newly introduced function snd_sof_dsp_get_bar_index that converts the section type to appropriate BAR index. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/loader.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 952a19091c58..e75da8aa7d4a 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -92,7 +92,7 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module) { struct snd_sof_blk_hdr *block; - int count; + int count, bar; u32 offset; size_t remaining; @@ -128,6 +128,13 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, case SOF_FW_BLK_TYPE_IRAM: case SOF_FW_BLK_TYPE_DRAM: offset = block->offset; + bar = snd_sof_dsp_get_bar_index(sdev, block->type); + if (bar < 0) { + dev_err(sdev->dev, + "error: no BAR mapping for block type 0x%x\n", + block->type); + return bar; + } break; default: dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n", @@ -145,7 +152,7 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, block->size); return -EINVAL; } - snd_sof_dsp_block_write(sdev, sdev->mmio_bar, offset, + snd_sof_dsp_block_write(sdev, bar, offset, block + 1, block->size); if (remaining < block->size) { -- cgit v1.2.3 From 441c58cf8e5e0c594b3d1b489e7810ec7248820d Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 22 Jul 2019 09:13:49 -0500 Subject: ASoC: SOF: loader: Don't ignore SRAM block types On i.MX8 data/heap/stack is kept in System RAM so do not ignore SRAM block types received from FW. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/loader.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index e75da8aa7d4a..93cb8fd0844f 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -123,10 +123,11 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, switch (block->type) { case SOF_FW_BLK_TYPE_RSRVD0: - case SOF_FW_BLK_TYPE_SRAM...SOF_FW_BLK_TYPE_RSRVD14: + case SOF_FW_BLK_TYPE_ROM...SOF_FW_BLK_TYPE_RSRVD14: continue; /* not handled atm */ case SOF_FW_BLK_TYPE_IRAM: case SOF_FW_BLK_TYPE_DRAM: + case SOF_FW_BLK_TYPE_SRAM: offset = block->offset; bar = snd_sof_dsp_get_bar_index(sdev, block->type); if (bar < 0) { -- cgit v1.2.3 From 1c38c9223da3af619d35f052ad6f4bbaa0f08ac2 Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Mon, 22 Jul 2019 09:13:50 -0500 Subject: ASoC: SOF: remove unused state variable in suspend function Remove unused and no plan to use variable from suspend function. Signed-off-by: Fred Oh Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 10 +++++----- sound/soc/sof/intel/hda.h | 4 ++-- sound/soc/sof/ops.h | 9 ++++----- sound/soc/sof/pm.c | 4 ++-- sound/soc/sof/sof-priv.h | 5 ++--- 5 files changed, 15 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 91de4785b6a3..4315896b3f07 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -282,7 +282,7 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); } -static int hda_suspend(struct snd_sof_dev *sdev, int state) +static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; @@ -431,19 +431,19 @@ int hda_dsp_runtime_idle(struct snd_sof_dev *sdev) return 0; } -int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state) +int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev) { /* stop hda controller and power dsp off */ - return hda_suspend(sdev, state); + return hda_suspend(sdev, true); } -int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) +int hda_dsp_suspend(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); int ret; /* stop hda controller and power dsp off */ - ret = hda_suspend(sdev, state); + ret = hda_suspend(sdev, false); if (ret < 0) { dev_err(bus->dev, "error: suspending dsp\n"); return ret; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index d9c17146200b..84d5fd021ccb 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -453,9 +453,9 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev); void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev); -int hda_dsp_suspend(struct snd_sof_dev *sdev, int state); +int hda_dsp_suspend(struct snd_sof_dev *sdev); int hda_dsp_resume(struct snd_sof_dev *sdev); -int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state); +int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev); int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_idle(struct snd_sof_dev *sdev); int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 8fda42748f39..793c1aea0c53 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -128,10 +128,10 @@ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) return 0; } -static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev, int state) +static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev) { if (sof_ops(sdev)->suspend) - return sof_ops(sdev)->suspend(sdev, state); + return sof_ops(sdev)->suspend(sdev); return 0; } @@ -144,11 +144,10 @@ static inline int snd_sof_dsp_runtime_resume(struct snd_sof_dev *sdev) return 0; } -static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev, - int state) +static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev) { if (sof_ops(sdev)->runtime_suspend) - return sof_ops(sdev)->runtime_suspend(sdev, state); + return sof_ops(sdev)->runtime_suspend(sdev); return 0; } diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 48c6d78d72e2..e23beaeefe00 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -377,9 +377,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) /* power down all DSP cores */ if (runtime_suspend) - ret = snd_sof_dsp_runtime_suspend(sdev, 0); + ret = snd_sof_dsp_runtime_suspend(sdev); else - ret = snd_sof_dsp_suspend(sdev, 0); + ret = snd_sof_dsp_suspend(sdev); if (ret < 0) dev_err(sdev->dev, "error: failed to power down DSP during suspend %d\n", diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index a6ec9115a9fb..b8c9274ccf42 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -171,10 +171,9 @@ struct snd_sof_dsp_ops { int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ /* DSP PM */ - int (*suspend)(struct snd_sof_dev *sof_dev, int state); /* optional */ + int (*suspend)(struct snd_sof_dev *sof_dev); /* optional */ int (*resume)(struct snd_sof_dev *sof_dev); /* optional */ - int (*runtime_suspend)(struct snd_sof_dev *sof_dev, - int state); /* optional */ + int (*runtime_suspend)(struct snd_sof_dev *sof_dev); /* optional */ int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */ int (*runtime_idle)(struct snd_sof_dev *sof_dev); /* optional */ int (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */ -- cgit v1.2.3 From 184fdfca4ba63d57a668564639a4dcf188fc9822 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Mon, 22 Jul 2019 09:13:51 -0500 Subject: ASoC: SOF: Intel: hda: correct ROM state mask The ROM state is represented by the 24 LSB bits in the ROM status register, so the mask should be 0xffffff instead of 0xf. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 84d5fd021ccb..70909debfeb5 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -175,7 +175,7 @@ #define HDA_DSP_STACK_DUMP_SIZE 32 /* ROM status/error values */ -#define HDA_DSP_ROM_STS_MASK 0xf +#define HDA_DSP_ROM_STS_MASK GENMASK(23, 0) #define HDA_DSP_ROM_INIT 0x1 #define HDA_DSP_ROM_FW_MANIFEST_LOADED 0x3 #define HDA_DSP_ROM_FW_FW_LOADED 0x4 -- cgit v1.2.3 From 6aa232e1ccfcd2b55306b86803dc547c36f8ad15 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 22 Jul 2019 09:13:52 -0500 Subject: ASoC: SOF: Intel: hda: reduce ifdef usage for hda Move the code for hda to one point Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 4315896b3f07..3d711d354fb9 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -359,6 +359,16 @@ static int hda_resume(struct snd_sof_dev *sdev) bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); hda_dsp_ctrl_misc_clock_gating(sdev, true); + + /* 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); #else hda_dsp_ctrl_misc_clock_gating(sdev, false); @@ -391,18 +401,6 @@ static int hda_resume(struct snd_sof_dev *sdev) hda_dsp_ctrl_ppcap_enable(sdev, true); hda_dsp_ctrl_ppcap_int_enable(sdev, true); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* 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); -#endif - return 0; } -- cgit v1.2.3 From fd15f2f5e272145269bcbf834e0e0b560a575891 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 22 Jul 2019 09:13:53 -0500 Subject: ASoC: SOF: Intel: hda: Enable jack detection In commit 7d4f606c50ff ("ALSA: hda - WAKEEN feature enabling for runtime pm"), legacy HD-A driver sets hda controller in reset mode after entering runtime-suspend. And when resuming from suspend mode, it checks hda controller & codec status to detect headphone hotplug event. Now this patch does the same job in SOF runtime pm functions. And we need to check all the non-hdmi codecs for some cases like playback with HDMI or capture with DMIC connected to dsp. In these cases, only controller is active and codecs are suspended, so codecs can't send unsolicited event to controller. The jack polling operation will activate codecs and unsolicited event can work even codecs become suspended later. Tested on whiskylake with hda codecs. Signed-off-by: Rander Wang Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-codec.c | 44 +++++++++++++++++++++++++++++++++++++++-- sound/soc/sof/intel/hda-dsp.c | 21 ++++++++++---------- sound/soc/sof/intel/hda.h | 2 ++ 3 files changed, 54 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 0d8437b080bf..3ca6795a89ba 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -37,16 +38,55 @@ static void hda_codec_load_module(struct hda_codec *codec) static void hda_codec_load_module(struct hda_codec *codec) {} #endif +/* enable controller wake up event for all codecs with jack connectors */ +void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) +{ + struct hda_bus *hbus = sof_to_hbus(sdev); + struct hdac_bus *bus = sof_to_bus(sdev); + struct hda_codec *codec; + unsigned int mask = 0; + + list_for_each_codec(codec, hbus) + if (codec->jacktbl.used) + mask |= BIT(codec->core.addr); + + snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask); +} + +/* check jack status after resuming from suspend mode */ +void hda_codec_jack_check(struct snd_sof_dev *sdev) +{ + struct hda_bus *hbus = sof_to_hbus(sdev); + struct hdac_bus *bus = sof_to_bus(sdev); + struct hda_codec *codec; + + /* disable controller Wake Up event*/ + snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0); + + list_for_each_codec(codec, hbus) + /* + * Wake up all jack-detecting codecs regardless whether an event + * has been recorded in STATESTS + */ + if (codec->jacktbl.used) + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); +} +#else +void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) {} +void hda_codec_jack_check(struct snd_sof_dev *sdev) {} #endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ +EXPORT_SYMBOL(hda_codec_jack_wake_enable); +EXPORT_SYMBOL(hda_codec_jack_check); /* probe individual codec */ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) { - struct hda_bus *hbus = sof_to_hbus(sdev); - struct hdac_device *hdev; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) struct hdac_hda_priv *hda_priv; #endif + struct hda_bus *hbus = sof_to_hbus(sdev); + struct hdac_device *hdev; u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; u32 resp = -1; diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 3d711d354fb9..f9579edbca68 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -295,6 +295,9 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) hda_dsp_ipc_int_disable(sdev); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + if (runtime_suspend) + hda_codec_jack_wake_enable(sdev); + /* power down all hda link */ snd_hdac_ext_bus_link_power_down_all(bus); #endif @@ -329,7 +332,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) return 0; } -static int hda_resume(struct snd_sof_dev *sdev) +static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); @@ -343,7 +346,6 @@ static int hda_resume(struct snd_sof_dev *sdev) */ snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* reset and start hda controller */ ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { @@ -352,13 +354,10 @@ static int hda_resume(struct snd_sof_dev *sdev) return ret; } - hda_dsp_ctrl_misc_clock_gating(sdev, false); - - /* Reset stream-to-link mapping */ - list_for_each_entry(hlink, &bus->hlink_list, list) - bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); - - hda_dsp_ctrl_misc_clock_gating(sdev, true); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* check jack status */ + if (runtime_resume) + hda_codec_jack_check(sdev); /* turn off the links that were off before suspend */ list_for_each_entry(hlink, &bus->hlink_list, list) { @@ -407,13 +406,13 @@ static int hda_resume(struct snd_sof_dev *sdev) int hda_dsp_resume(struct snd_sof_dev *sdev) { /* init hda controller. DSP cores will be powered up during fw boot */ - return hda_resume(sdev); + return hda_resume(sdev, false); } int hda_dsp_runtime_resume(struct snd_sof_dev *sdev) { /* init hda controller. DSP cores will be powered up during fw boot */ - return hda_resume(sdev); + return hda_resume(sdev, true); } int hda_dsp_runtime_idle(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 70909debfeb5..028e865d5e20 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -557,6 +557,8 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, * HDA Codec operations. */ int hda_codec_probe_bus(struct snd_sof_dev *sdev); +void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev); +void hda_codec_jack_check(struct snd_sof_dev *sdev); #endif /* CONFIG_SND_SOC_SOF_HDA */ -- cgit v1.2.3 From 061edb232505797aee53a955225af23fa30d45b8 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Mon, 22 Jul 2019 09:13:54 -0500 Subject: ASoC: SOF: Intel: hda: set position buffer in init chip Set the HDA stream position buffer during init chip. The position buffer needs to be set in both HDA codec and nocodec cases. Using SOF defined function and move it to common code. Signed-off-by: Zhu Yingjiang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-ctrl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index ea63f83a509b..015760284969 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -245,14 +245,13 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* program the position buffer */ if (bus->use_posbuf && bus->posbuf.addr) { - snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr); - snd_hdac_chip_writel(bus, DPUBASE, - upper_32_bits(bus->posbuf.addr)); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE, + (u32)bus->posbuf.addr); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPUBASE, + upper_32_bits(bus->posbuf.addr)); } -#endif bus->chip_init = true; -- cgit v1.2.3 From d06973515f95ac74d68fb3e1f1fb4b055531296c Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Mon, 22 Jul 2019 09:13:55 -0500 Subject: ASoC: SOF: Intel: hda: use SOF defined init chip in resume Unify resume code by using SOF common function hda_dsp_ctrl_init_chip() which can handle both HDA and non-HDA cases. Move code to reset stream-to-link mapping into hda_dsp_ctrl_init_chip(). Signed-off-by: Zhu Yingjiang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-ctrl.c | 9 +++++++++ sound/soc/sof/intel/hda-dsp.c | 26 -------------------------- 2 files changed, 9 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 015760284969..8b856dc35e20 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -164,6 +164,9 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) { struct hdac_bus *bus = sof_to_bus(sdev); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_ext_link *hlink; +#endif struct hdac_stream *stream; int sd_offset, ret = 0; @@ -253,6 +256,12 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) upper_32_bits(bus->posbuf.addr)); } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* Reset stream-to-link mapping */ + list_for_each_entry(hlink, &bus->hlink_list, list) + bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); +#endif + bus->chip_init = true; hda_dsp_ctrl_misc_clock_gating(sdev, true); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index f9579edbca68..f08a5d649346 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -368,32 +368,6 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) /* check dma status and clean up CORB/RIRB buffers */ if (!bus->cmd_dma_state) snd_hdac_bus_stop_cmd_io(bus); -#else - - hda_dsp_ctrl_misc_clock_gating(sdev, false); - - /* reset controller */ - ret = hda_dsp_ctrl_link_reset(sdev, true); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to reset controller during resume\n"); - return ret; - } - - /* take controller out of reset */ - ret = hda_dsp_ctrl_link_reset(sdev, false); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to ready controller during resume\n"); - return ret; - } - - /* enable hda bus irq */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); - - hda_dsp_ctrl_misc_clock_gating(sdev, true); #endif /* enable ppcap interrupt */ -- cgit v1.2.3 From dc7a36f178a94604d29c5dd15c77187905d8e882 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Mon, 22 Jul 2019 09:13:56 -0500 Subject: ASoC: SOF: Intel: hda: remove duplicated clear WAKESTS Remove the first clear WAKESTS, only one clear is needed during init chip. Signed-off-by: Zhu Yingjiang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-16-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-ctrl.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 8b856dc35e20..a7fee403cb90 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -176,11 +176,6 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) hda_dsp_ctrl_misc_clock_gating(sdev, false); if (full_reset) { - /* clear WAKESTS */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, - SOF_HDA_WAKESTS_INT_MASK, - SOF_HDA_WAKESTS_INT_MASK); - /* reset HDA controller */ ret = hda_dsp_ctrl_link_reset(sdev, true); if (ret < 0) { -- cgit v1.2.3 From 672ff5e3596ee27b64edcc73251f4ae1c8ab12ac Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 22 Jul 2019 09:13:57 -0500 Subject: ASoC: SOF: Intel: hda: add a parameter to disable MSI Enabling MSI on HDA can fail, in which case the legacy PCI IRQ mode will be used. To make testing this mode easier add an "enable_msi" module parameter, which is only enabled if debugging is enabled too. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-17-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 28 +++++++++++++++++----------- sound/soc/sof/sof-priv.h | 2 +- 2 files changed, 18 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 7f665392618f..79cce20666b6 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -46,6 +46,12 @@ struct hda_dsp_msg_code { const char *msg; }; +static bool hda_use_msi = IS_ENABLED(CONFIG_PCI); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG) +module_param_named(use_msi, hda_use_msi, bool, 0444); +MODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode"); +#endif + static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = { {HDA_DSP_ROM_FW_MANIFEST_LOADED, "status: manifest loaded"}, {HDA_DSP_ROM_FW_FW_LOADED, "status: fw loaded"}, @@ -529,11 +535,18 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) * register our IRQ * let's try to enable msi firstly * if it fails, use legacy interrupt mode - * TODO: support interrupt mode selection with kernel parameter - * support msi multiple vectors + * TODO: support msi multiple vectors */ - ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI); - if (ret < 0) { + if (hda_use_msi && !pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI)) { + dev_info(sdev->dev, "use msi interrupt mode\n"); + hdev->irq = pci_irq_vector(pci, 0); + /* ipc irq number is the same of hda irq */ + sdev->ipc_irq = hdev->irq; + /* initialised to "false" by kzalloc() */ + sdev->msi_enabled = true; + } + + if (!sdev->msi_enabled) { dev_info(sdev->dev, "use legacy interrupt mode\n"); /* * in IO-APIC mode, hda->irq and ipc_irq are using the same @@ -541,13 +554,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) */ hdev->irq = pci->irq; sdev->ipc_irq = pci->irq; - sdev->msi_enabled = 0; - } else { - dev_info(sdev->dev, "use msi interrupt mode\n"); - hdev->irq = pci_irq_vector(pci, 0); - /* ipc irq number is the same of hda irq */ - sdev->ipc_irq = hdev->irq; - sdev->msi_enabled = 1; } dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index b8c9274ccf42..983eadef4b30 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -435,7 +435,7 @@ struct snd_sof_dev { u32 dtrace_error; u32 dtrace_draining; - u32 msi_enabled; + bool msi_enabled; void *private; /* core does not touch this */ }; -- cgit v1.2.3 From a3ebccb52efdfb3459fa51516238cc464ee310c9 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 22 Jul 2019 09:13:58 -0500 Subject: ASoC: SOF: Intel: hda: reset link DMA state in prepare When application goes through SUSPEND/STOP->PREPARE->START cycle, we should always reprogram the DAI link DMA to ensure it is in sync with the host PCM DMA. Use same state tracking logic to handle both restart and system resume flows. Use link_prepared field of 'struct hdac_ext_stream' to store the state, instead of adding redundant fields to SOF specific structs. Signed-off-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-18-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 8 +++----- sound/soc/sof/intel/hda-dsp.c | 17 ++++++----------- sound/soc/sof/intel/hda.h | 1 - 3 files changed, 9 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index a514f9cf5c9a..a448be60f6dd 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -226,8 +226,6 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); - hda_stream->hw_params_upon_resume = 0; - link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); if (!link) return -EINVAL; @@ -267,8 +265,7 @@ static int hda_link_pcm_prepare(struct snd_pcm_substream *substream, hda_stream = hstream_to_sof_hda_stream(link_dev); - /* setup hw_params again only if resuming from system suspend */ - if (!hda_stream->hw_params_upon_resume) + if (link_dev->link_prepared) return 0; dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream); @@ -317,6 +314,7 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, snd_hdac_ext_link_stream_start(link_dev); break; case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: /* * clear and release link DMA channel. It will be assigned when * hw_params is set up again after resume. @@ -329,10 +327,10 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, snd_hdac_ext_link_clear_stream_id(link, stream_tag); snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); + link_dev->link_prepared = 0; /* fallthrough */ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_STOP: snd_hdac_ext_link_stream_clear(link_dev); break; default: diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index f08a5d649346..e82ecaad1763 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -425,25 +425,19 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev) int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) { - struct hdac_bus *bus = sof_to_bus(sdev); - struct sof_intel_hda_stream *hda_stream; - struct hdac_ext_stream *stream; - struct hdac_stream *s; - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_bus *bus = sof_to_bus(sdev); struct snd_soc_pcm_runtime *rtd; + struct hdac_ext_stream *stream; struct hdac_ext_link *link; + struct hdac_stream *s; const char *name; int stream_tag; -#endif /* set internal flag for BE */ list_for_each_entry(s, &bus->stream_list, list) { stream = stream_to_hdac_ext_stream(s); - hda_stream = container_of(stream, struct sof_intel_hda_stream, - hda_stream); - hda_stream->hw_params_upon_resume = 1; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* * clear and release stream. This should already be taken care * for running streams when the SUSPEND trigger is called. @@ -460,8 +454,9 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) snd_hdac_ext_link_clear_stream_id(link, stream_tag); snd_hdac_ext_stream_release(stream, HDAC_EXT_STREAM_TYPE_LINK); + stream->link_prepared = 0; } -#endif } +#endif return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 028e865d5e20..ceaaa8d467f4 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -418,7 +418,6 @@ struct sof_intel_hda_stream { struct snd_sof_dev *sdev; struct hdac_ext_stream hda_stream; struct sof_intel_stream stream; - int hw_params_upon_resume; /* set up hw_params upon resume */ int host_reserved; /* reserve host DMA channel */ }; -- cgit v1.2.3 From 6298b78742be6593d372ed1b5bfa5397e1393595 Mon Sep 17 00:00:00 2001 From: Janusz Jankowski Date: Mon, 22 Jul 2019 09:14:02 -0500 Subject: ASoC: SOF: Intel: ssp: BCLK delay parameter Some codecs require BCLK to be on for some time, before sending any data. SOF can enable BCLK and then wait for guaranteed time, before starting DMA on SSP start. Signed-off-by: Janusz Jankowski Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-22-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/dai-intel.h | 3 +++ include/uapi/sound/sof/abi.h | 2 +- include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/topology.c | 3 +++ 4 files changed, 8 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 4bb8ee138ba7..a81afd3fbd41 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -76,6 +76,9 @@ struct sof_ipc_dai_ssp_params { uint16_t tdm_per_slot_padding_flag; uint32_t clks_control; uint32_t quirks; + uint32_t bclk_delay; /* guaranteed time (ms) for which BCLK + * will be driven, before sending data + */ } __packed; /* HDA Configuration Request - SOF_IPC_DAI_HDA_CONFIG */ diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 4a9c24434f42..dff70a42445a 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 8 +#define SOF_ABI_MINOR 9 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index dc1b27daaac6..6435240cef13 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -75,6 +75,7 @@ #define SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH 503 #define SOF_TKN_INTEL_SSP_QUIRKS 504 #define SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT 505 +#define SOF_TKN_INTEL_SSP_BCLK_DELAY 506 /* DMIC */ #define SOF_TKN_INTEL_DMIC_DRIVER_VERSION 600 diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 432ae343f960..12b7d900b9c2 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -748,6 +748,9 @@ static const struct sof_topology_token ssp_tokens[] = { get_token_u16, offsetof(struct sof_ipc_dai_ssp_params, tdm_per_slot_padding_flag), 0}, + {SOF_TKN_INTEL_SSP_BCLK_DELAY, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, bclk_delay), 0}, }; -- cgit v1.2.3 From 7ccafa2b3879612ab9ed88bb6664bd4085957186 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 11 Jul 2019 18:49:46 +0800 Subject: ASoC: fsl_esai: recover the channel swap after xrun There is chip errata ERR008000, the reference doc is (https://www.nxp.com/docs/en/errata/IMX6DQCE.pdf), The issue is "While using ESAI transmit or receive and an underrun/overrun happens, channel swap may occur. The only recovery mechanism is to reset the ESAI." This issue exist in imx3/imx5/imx6(partial) series. In this commit add a tasklet to handle reset of ESAI after xrun happens to recover the channel swap. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/326035cb99975361699d9ed748054b08bc06a341.1562842206.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index ab460d6d7432..4ce8ac769244 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -32,6 +32,7 @@ * @extalclk: esai clock source to derive HCK, SCK and FS * @fsysclk: system clock source to derive HCK, SCK and FS * @spbaclk: SPBA clock (optional, depending on SoC design) + * @task: tasklet to handle the reset operation * @fifo_depth: depth of tx/rx FIFO * @slot_width: width of each DAI slot * @slots: number of slots @@ -42,6 +43,7 @@ * @sck_div: if using PSR/PM dividers for SCKx clock * @slave_mode: if fully using DAI slave mode * @synchronous: if using tx/rx synchronous mode + * @reset_at_xrun: flags for enable reset operaton * @name: driver name */ struct fsl_esai { @@ -53,6 +55,7 @@ struct fsl_esai { struct clk *extalclk; struct clk *fsysclk; struct clk *spbaclk; + struct tasklet_struct task; u32 fifo_depth; u32 slot_width; u32 slots; @@ -65,6 +68,7 @@ struct fsl_esai { bool sck_div[2]; bool slave_mode; bool synchronous; + bool reset_at_xrun; char name[32]; }; @@ -73,8 +77,16 @@ static irqreturn_t esai_isr(int irq, void *devid) struct fsl_esai *esai_priv = (struct fsl_esai *)devid; struct platform_device *pdev = esai_priv->pdev; u32 esr; + u32 saisr; regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr); + regmap_read(esai_priv->regmap, REG_ESAI_SAISR, &saisr); + + if ((saisr & (ESAI_SAISR_TUE | ESAI_SAISR_ROE)) && + esai_priv->reset_at_xrun) { + dev_dbg(&pdev->dev, "reset module for xrun\n"); + tasklet_schedule(&esai_priv->task); + } if (esr & ESAI_ESR_TINIT_MASK) dev_dbg(&pdev->dev, "isr: Transmission Initialized\n"); @@ -635,10 +647,17 @@ static void fsl_esai_trigger_start(struct fsl_esai *esai_priv, bool tx) ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask)); regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask)); + + /* Enable Exception interrupt */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + ESAI_xCR_xEIE_MASK, ESAI_xCR_xEIE); } static void fsl_esai_trigger_stop(struct fsl_esai *esai_priv, bool tx) { + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + ESAI_xCR_xEIE_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0); regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), @@ -653,6 +672,51 @@ static void fsl_esai_trigger_stop(struct fsl_esai *esai_priv, bool tx) ESAI_xFCR_xFR, 0); } +static void fsl_esai_hw_reset(unsigned long arg) +{ + struct fsl_esai *esai_priv = (struct fsl_esai *)arg; + bool tx = true, rx = false, enabled[2]; + u32 tfcr, rfcr; + + /* Save the registers */ + regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &tfcr); + regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &rfcr); + enabled[tx] = tfcr & ESAI_xFCR_xFEN; + enabled[rx] = rfcr & ESAI_xFCR_xFEN; + + /* Stop the tx & rx */ + fsl_esai_trigger_stop(esai_priv, tx); + fsl_esai_trigger_stop(esai_priv, rx); + + /* Reset the esai, and ignore return value */ + fsl_esai_hw_init(esai_priv); + + /* Enforce ESAI personal resets for both TX and RX */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, + ESAI_xCR_xPR_MASK, ESAI_xCR_xPR); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, + ESAI_xCR_xPR_MASK, ESAI_xCR_xPR); + + /* Restore registers by regcache_sync, and ignore return value */ + fsl_esai_register_restore(esai_priv); + + /* Remove ESAI personal resets by configuring PCRC and PRRC also */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, + ESAI_xCR_xPR_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, + ESAI_xCR_xPR_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, + ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, + ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO)); + + /* Restart tx / rx, if they already enabled */ + if (enabled[tx]) + fsl_esai_trigger_start(esai_priv, tx); + if (enabled[rx]) + fsl_esai_trigger_start(esai_priv, rx); +} + static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -857,6 +921,10 @@ static int fsl_esai_probe(struct platform_device *pdev) esai_priv->pdev = pdev; snprintf(esai_priv->name, sizeof(esai_priv->name), "%pOFn", np); + if (of_device_is_compatible(np, "fsl,vf610-esai") || + of_device_is_compatible(np, "fsl,imx35-esai")) + esai_priv->reset_at_xrun = true; + /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); @@ -956,6 +1024,9 @@ static int fsl_esai_probe(struct platform_device *pdev) return ret; } + tasklet_init(&esai_priv->task, fsl_esai_hw_reset, + (unsigned long)esai_priv); + pm_runtime_enable(&pdev->dev); regcache_cache_only(esai_priv->regmap, true); @@ -969,7 +1040,10 @@ static int fsl_esai_probe(struct platform_device *pdev) static int fsl_esai_remove(struct platform_device *pdev) { + struct fsl_esai *esai_priv = platform_get_drvdata(pdev); + pm_runtime_disable(&pdev->dev); + tasklet_kill(&esai_priv->task); return 0; } -- cgit v1.2.3 From 934bf82203d679a8f2ff22817e341bc059f5f7fc Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 22 Jul 2019 09:13:59 -0500 Subject: ASoC: SOF: Intel: hda: fix link DMA config For this bug, there are two capture pcm streams active, with one stream and its related stream tag released before suspend. Later when system suspend is done, the stream tag for the remaining active stream is released by SOF driver. After system resume, hda codec driver restores the stream tag for the active pcm stream, but SOF goes to assign a new one, which now doesn't match with the stream tag used by codec driver, and this causes DMA to fail receiving data, leading to unrecoverable XRUN condition in FW. For stream tag is stored in both hda codec and SOF driver, it shouldn't be released only in SOF driver. This patch just keeps the stream information in dma data and checks whether there is a stored DMA data for stream resuming from S3 and restores it. And it also removes DMA data when the stream is released. Tested on Whiskey Lake platform. GitHub issue: https://github.com/thesofproject/sof/issues/1594 Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-19-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 15 +++++++++------ sound/soc/sof/intel/hda-dsp.c | 10 ++++------ 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index a448be60f6dd..2b5e2b8c69c2 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -210,9 +210,13 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, int stream_tag; int ret; - link_dev = hda_link_stream_assign(bus, substream); - if (!link_dev) - return -EBUSY; + /* get stored dma data if resuming from system suspend */ + link_dev = snd_soc_dai_get_dma_data(dai, substream); + if (!link_dev) { + link_dev = hda_link_stream_assign(bus, substream); + if (!link_dev) + return -EBUSY; + } stream_tag = hdac_stream(link_dev)->stream_tag; @@ -316,7 +320,7 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: /* - * clear and release link DMA channel. It will be assigned when + * clear link DMA channel. It will be assigned when * hw_params is set up again after resume. */ ret = hda_link_config_ipc(hda_stream, dai->name, @@ -325,8 +329,6 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, return ret; stream_tag = hdac_stream(link_dev)->stream_tag; snd_hdac_ext_link_clear_stream_id(link, stream_tag); - snd_hdac_ext_stream_release(link_dev, - HDAC_EXT_STREAM_TYPE_LINK); link_dev->link_prepared = 0; /* fallthrough */ @@ -369,6 +371,7 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, stream_tag = hdac_stream(link_dev)->stream_tag; snd_hdac_ext_link_clear_stream_id(link, stream_tag); + snd_soc_dai_set_dma_data(dai, substream, NULL); snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); link_dev->link_prepared = 0; diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index e82ecaad1763..e38008194574 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -439,10 +439,10 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) stream = stream_to_hdac_ext_stream(s); /* - * clear and release stream. This should already be taken care - * for running streams when the SUSPEND trigger is called. - * But paused streams do not get suspended, so this needs to be - * done explicitly during suspend. + * clear stream. This should already be taken care for running + * streams when the SUSPEND trigger is called. But paused + * streams do not get suspended, so this needs to be done + * explicitly during suspend. */ if (stream->link_substream) { rtd = snd_pcm_substream_chip(stream->link_substream); @@ -452,8 +452,6 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) return -EINVAL; stream_tag = hdac_stream(stream)->stream_tag; snd_hdac_ext_link_clear_stream_id(link, stream_tag); - snd_hdac_ext_stream_release(stream, - HDAC_EXT_STREAM_TYPE_LINK); stream->link_prepared = 0; } } -- cgit v1.2.3 From 810dbea3656912d6ad8db691a9a4b2ad97d4b736 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 22 Jul 2019 09:14:00 -0500 Subject: ASoC: SOF: Intel: hda: fix stream id setting snd_hdac_ext_link_clear_stream_id maps stream id to link output, which is for playback, not capture. Tested on Whiskey Lake platform. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190722141402.7194-20-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 15 +++++++++++---- sound/soc/sof/intel/hda-dsp.c | 8 +++++++- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 2b5e2b8c69c2..8796f385be76 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -327,8 +327,12 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, DMA_CHAN_INVALID, substream->stream); if (ret < 0) return ret; - stream_tag = hdac_stream(link_dev)->stream_tag; - snd_hdac_ext_link_clear_stream_id(link, stream_tag); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + } + link_dev->link_prepared = 0; /* fallthrough */ @@ -369,8 +373,11 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, if (!link) return -EINVAL; - stream_tag = hdac_stream(link_dev)->stream_tag; - snd_hdac_ext_link_clear_stream_id(link, stream_tag); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + } + snd_soc_dai_set_dma_data(dai, substream, NULL); snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); link_dev->link_prepared = 0; diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index e38008194574..fb55a3c5afd0 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -450,9 +450,15 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) link = snd_hdac_ext_bus_get_link(bus, name); if (!link) return -EINVAL; + + stream->link_prepared = 0; + + if (hdac_stream(stream)->direction == + SNDRV_PCM_STREAM_CAPTURE) + continue; + stream_tag = hdac_stream(stream)->stream_tag; snd_hdac_ext_link_clear_stream_id(link, stream_tag); - stream->link_prepared = 0; } } #endif -- cgit v1.2.3 From f90aa354be7bffaec2b440eb1831c429ecb1a5e2 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 22 Jul 2019 23:26:39 +0200 Subject: ASoC: rt5665: Fix a typo in the name of a function All function names start with rt5665_, except 'rt5655_set_verf()'. It is likely a typo. Fix it to be consistent. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/20190722212639.26954-1-christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index c050d84a6916..68299ce26d3e 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -2566,7 +2566,7 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w, return 0; } -static int rt5655_set_verf(struct snd_soc_dapm_widget *w, +static int rt5665_set_verf(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); @@ -2686,11 +2686,11 @@ static const struct snd_soc_dapm_widget rt5665_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5665_PWR_VOL, RT5665_PWR_MIC_DET_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("Vref1", RT5665_PWR_ANLG_1, RT5665_PWR_VREF1_BIT, 0, - rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + rt5665_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("Vref2", RT5665_PWR_ANLG_1, RT5665_PWR_VREF2_BIT, 0, - rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + rt5665_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("Vref3", RT5665_PWR_ANLG_1, RT5665_PWR_VREF3_BIT, 0, - rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + rt5665_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), /* ASRC */ SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5665_ASRC_1, -- cgit v1.2.3 From a789adae592e3d28ae87902c0012a8b11c96eb79 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 23 Jul 2019 18:12:47 +0800 Subject: ASoC: rt1308: Convert headers to SPDX Convert include and source files to SPDX. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20190723101247.19741-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1308.c | 17 +++++++---------- sound/soc/codecs/rt1308.h | 6 ++---- 2 files changed, 9 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index cf3d72f99705..6f2ee6809dbb 100755 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -1,13 +1,10 @@ -/* - * rt1308.c -- RT1308 ALSA SoC amplifier component driver - * - * Copyright 2019 Realtek Semiconductor Corp. - * Author: Derek Fang - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// rt1308.c -- RT1308 ALSA SoC amplifier component driver +// +// Copyright 2019 Realtek Semiconductor Corp. +// Author: Derek Fang +// #include #include diff --git a/sound/soc/codecs/rt1308.h b/sound/soc/codecs/rt1308.h index c330aae1d527..ff7c423e879e 100755 --- a/sound/soc/codecs/rt1308.h +++ b/sound/soc/codecs/rt1308.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * RT1308.h -- RT1308 ALSA SoC amplifier component driver + * rt1308.h -- RT1308 ALSA SoC amplifier component driver * * Copyright 2019 Realtek Semiconductor Corp. * Author: Derek Fang * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _RT1308_H_ -- cgit v1.2.3 From 859fd6cbf1fb32b5428c26f837215c085b8a822e Mon Sep 17 00:00:00 2001 From: Timo Wischer Date: Mon, 22 Jul 2019 16:24:01 +0900 Subject: ASoC: rsnd: Support hw_free() callback at DAI level This patch provides the needed infrastructure to support calling hw_free() at the DAI level. This is for example required to free resources allocated in hw_params() callback. The modification of __rsnd_mod_add_hw_params does not have any side effects because rsnd_mod_ops::hw_params callback is not used by anyone until now. Signed-off-by: Timo Wischer Signed-off-by: Jiada Wang Link: https://lore.kernel.org/r/20190722072403.11008-2-jiada_wang@mentor.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 16 +++++++++++++++- sound/soc/sh/rcar/rsnd.h | 12 +++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 56e8dae9a15c..bda5b958d0dc 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1421,6 +1421,20 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream, params_buffer_bytes(hw_params)); } +static int rsnd_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + int ret; + + ret = rsnd_dai_call(hw_free, io, substream); + if (ret) + return ret; + + return snd_pcm_lib_free_pages(substream); +} + static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) { struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); @@ -1436,7 +1450,7 @@ static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) static const struct snd_pcm_ops rsnd_pcm_ops = { .ioctl = snd_pcm_lib_ioctl, .hw_params = rsnd_hw_params, - .hw_free = snd_pcm_lib_free_pages, + .hw_free = rsnd_hw_free, .pointer = rsnd_pointer, }; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 7727add3eb1a..ea6cbaa9743e 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -327,6 +327,9 @@ struct rsnd_mod_ops { int (*cleanup)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); + int (*hw_free)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_pcm_substream *substream); u32 *(*get_status)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, enum rsnd_mod_type type); @@ -351,12 +354,12 @@ struct rsnd_mod { * * B 0: init 1: quit * C 0: start 1: stop + * D 0: hw_params 1: hw_free * * H is always called (see __rsnd_mod_call) * H 0: probe 1: remove * H 0: pcm_new * H 0: fallback - * H 0: hw_params * H 0: pointer * H 0: prepare * H 0: cleanup @@ -365,12 +368,13 @@ struct rsnd_mod { #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 #define __rsnd_mod_shift_stop 8 +#define __rsnd_mod_shift_hw_params 12 +#define __rsnd_mod_shift_hw_free 12 #define __rsnd_mod_shift_probe 28 /* always called */ #define __rsnd_mod_shift_remove 28 /* always called */ #define __rsnd_mod_shift_irq 28 /* always called */ #define __rsnd_mod_shift_pcm_new 28 /* always called */ #define __rsnd_mod_shift_fallback 28 /* always called */ -#define __rsnd_mod_shift_hw_params 28 /* always called */ #define __rsnd_mod_shift_pointer 28 /* always called */ #define __rsnd_mod_shift_prepare 28 /* always called */ #define __rsnd_mod_shift_cleanup 28 /* always called */ @@ -383,10 +387,11 @@ struct rsnd_mod { #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 #define __rsnd_mod_add_stop -1 +#define __rsnd_mod_add_hw_params 1 +#define __rsnd_mod_add_hw_free -1 #define __rsnd_mod_add_irq 0 #define __rsnd_mod_add_pcm_new 0 #define __rsnd_mod_add_fallback 0 -#define __rsnd_mod_add_hw_params 0 #define __rsnd_mod_add_pointer 0 #define __rsnd_mod_call_probe 0 @@ -402,6 +407,7 @@ struct rsnd_mod { #define __rsnd_mod_call_fallback 0 #define __rsnd_mod_call_hw_params 0 #define __rsnd_mod_call_pointer 0 +#define __rsnd_mod_call_hw_free 1 #define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_power_on(mod) clk_enable((mod)->clk) -- cgit v1.2.3 From 06f6e1d41427f394ad3f67ecf06efcd28a46932c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:32:12 +0900 Subject: ASoC: add soc-dai.c Current ALSA SoC has many snd_soc_dai_xxx() function which is using dai->driver->ops->xxx. But, some of them are implemented as snd_soc_dai_xxx(), but others are directly using dai->driver->ops->xxx. Because of it, the code is not easy to read. This patch creats new soc-dai.c and moves snd_soc_dai_xxx() functions into it. One exception is snd_soc_dai_is_dummy() which is based on soc-utils local variable. We need to keep it as-is there. Others which is directly using dai->driver->ops->xxx will be implemented at soc-dai.c by incremental patches. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/871ryij1r6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/Makefile | 2 +- sound/soc/soc-core.c | 243 ------------------------------------------------ sound/soc/soc-dai.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 255 insertions(+), 244 deletions(-) create mode 100644 sound/soc/soc-dai.c (limited to 'sound') diff --git a/sound/soc/Makefile b/sound/soc/Makefile index d90ce8a32887..919c3c027c62 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o +snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o soc-dai.o snd-soc-core-objs += soc-pcm.o soc-io.o soc-devres.o soc-ops.o snd-soc-core-$(CONFIG_SND_SOC_COMPRESS) += soc-compress.o diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fd6eaae6c0ed..6e8c5c8eeaec 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2394,26 +2394,6 @@ int snd_soc_add_dai_controls(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); -/** - * snd_soc_dai_set_sysclk - configure DAI system or master clock. - * @dai: DAI - * @clk_id: DAI specific clock ID - * @freq: new clock frequency in Hz - * @dir: new clock direction - input/output. - * - * Configures the DAI master (MCLK) or system (SYSCLK) clocking. - */ -int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir) -{ - if (dai->driver->ops->set_sysclk) - return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir); - - return snd_soc_component_set_sysclk(dai->component, clk_id, 0, - freq, dir); -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); - /** * snd_soc_component_set_sysclk - configure COMPONENT system or master clock. * @component: COMPONENT @@ -2436,48 +2416,6 @@ int snd_soc_component_set_sysclk(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk); -/** - * snd_soc_dai_set_clkdiv - configure DAI clock dividers. - * @dai: DAI - * @div_id: DAI specific clock divider ID - * @div: new clock divisor. - * - * Configures the clock dividers. This is used to derive the best DAI bit and - * frame clocks from the system or master clock. It's best to set the DAI bit - * and frame clocks as low as possible to save system power. - */ -int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, - int div_id, int div) -{ - if (dai->driver->ops->set_clkdiv) - return dai->driver->ops->set_clkdiv(dai, div_id, div); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); - -/** - * snd_soc_dai_set_pll - configure DAI PLL. - * @dai: DAI - * @pll_id: DAI specific PLL ID - * @source: DAI specific source for the PLL - * @freq_in: PLL input clock frequency in Hz - * @freq_out: requested PLL output clock frequency in Hz - * - * Configures and enables PLL to generate output clock based on input clock. - */ -int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, - unsigned int freq_in, unsigned int freq_out) -{ - if (dai->driver->ops->set_pll) - return dai->driver->ops->set_pll(dai, pll_id, source, - freq_in, freq_out); - - return snd_soc_component_set_pll(dai->component, pll_id, source, - freq_in, freq_out); -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); - /* * snd_soc_component_set_pll - configure component PLL. * @component: COMPONENT @@ -2500,187 +2438,6 @@ int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, } EXPORT_SYMBOL_GPL(snd_soc_component_set_pll); -/** - * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. - * @dai: DAI - * @ratio: Ratio of BCLK to Sample rate. - * - * Configures the DAI for a preset BCLK to sample rate ratio. - */ -int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) -{ - if (dai->driver->ops->set_bclk_ratio) - return dai->driver->ops->set_bclk_ratio(dai, ratio); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); - -/** - * snd_soc_dai_set_fmt - configure DAI hardware audio format. - * @dai: DAI - * @fmt: SND_SOC_DAIFMT_* format value. - * - * Configures the DAI hardware format and clocking. - */ -int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - if (dai->driver->ops->set_fmt == NULL) - return -ENOTSUPP; - return dai->driver->ops->set_fmt(dai, fmt); -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); - -/** - * snd_soc_xlate_tdm_slot - generate tx/rx slot mask. - * @slots: Number of slots in use. - * @tx_mask: bitmask representing active TX slots. - * @rx_mask: bitmask representing active RX slots. - * - * Generates the TDM tx and rx slot default masks for DAI. - */ -static int snd_soc_xlate_tdm_slot_mask(unsigned int slots, - unsigned int *tx_mask, - unsigned int *rx_mask) -{ - if (*tx_mask || *rx_mask) - return 0; - - if (!slots) - return -EINVAL; - - *tx_mask = (1 << slots) - 1; - *rx_mask = (1 << slots) - 1; - - return 0; -} - -/** - * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation - * @dai: The DAI to configure - * @tx_mask: bitmask representing active TX slots. - * @rx_mask: bitmask representing active RX slots. - * @slots: Number of slots in use. - * @slot_width: Width in bits for each slot. - * - * This function configures the specified DAI for TDM operation. @slot contains - * the total number of slots of the TDM stream and @slot_with the width of each - * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the - * active slots of the TDM stream for the specified DAI, i.e. which slots the - * DAI should write to or read from. If a bit is set the corresponding slot is - * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to - * the first slot, bit 1 to the second slot and so on. The first active slot - * maps to the first channel of the DAI, the second active slot to the second - * channel and so on. - * - * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask, - * @rx_mask and @slot_width will be ignored. - * - * Returns 0 on success, a negative error code otherwise. - */ -int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) -{ - if (dai->driver->ops->xlate_tdm_slot_mask) - dai->driver->ops->xlate_tdm_slot_mask(slots, - &tx_mask, &rx_mask); - else - snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); - - dai->tx_mask = tx_mask; - dai->rx_mask = rx_mask; - - if (dai->driver->ops->set_tdm_slot) - return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, - slots, slot_width); - else - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); - -/** - * snd_soc_dai_set_channel_map - configure DAI audio channel map - * @dai: DAI - * @tx_num: how many TX channels - * @tx_slot: pointer to an array which imply the TX slot number channel - * 0~num-1 uses - * @rx_num: how many RX channels - * @rx_slot: pointer to an array which imply the RX slot number channel - * 0~num-1 uses - * - * configure the relationship between channel number and TDM slot number. - */ -int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) -{ - if (dai->driver->ops->set_channel_map) - return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot, - rx_num, rx_slot); - else - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); - -/** - * snd_soc_dai_get_channel_map - Get DAI audio channel map - * @dai: DAI - * @tx_num: how many TX channels - * @tx_slot: pointer to an array which imply the TX slot number channel - * 0~num-1 uses - * @rx_num: how many RX channels - * @rx_slot: pointer to an array which imply the RX slot number channel - * 0~num-1 uses - */ -int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, - unsigned int *tx_num, unsigned int *tx_slot, - unsigned int *rx_num, unsigned int *rx_slot) -{ - if (dai->driver->ops->get_channel_map) - return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot, - rx_num, rx_slot); - else - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map); - -/** - * snd_soc_dai_set_tristate - configure DAI system or master clock. - * @dai: DAI - * @tristate: tristate enable - * - * Tristates the DAI so that others can use it. - */ -int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) -{ - if (dai->driver->ops->set_tristate) - return dai->driver->ops->set_tristate(dai, tristate); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); - -/** - * snd_soc_dai_digital_mute - configure DAI system or master clock. - * @dai: DAI - * @mute: mute enable - * @direction: stream to mute - * - * Mutes the DAI DAC. - */ -int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, - int direction) -{ - if (dai->driver->ops->mute_stream) - return dai->driver->ops->mute_stream(dai, mute, direction); - else if (direction == SNDRV_PCM_STREAM_PLAYBACK && - dai->driver->ops->digital_mute) - return dai->driver->ops->digital_mute(dai, mute); - else - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); - static int snd_soc_bind_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c new file mode 100644 index 000000000000..a1009ead40de --- /dev/null +++ b/sound/soc/soc-dai.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// soc-dai.c +// +// Copyright (C) 2019 Renesas Electronics Corp. +// Kuninori Morimoto +// + +#include +#include + +/** + * snd_soc_dai_set_sysclk - configure DAI system or master clock. + * @dai: DAI + * @clk_id: DAI specific clock ID + * @freq: new clock frequency in Hz + * @dir: new clock direction - input/output. + * + * Configures the DAI master (MCLK) or system (SYSCLK) clocking. + */ +int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + if (dai->driver->ops->set_sysclk) + return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir); + + return snd_soc_component_set_sysclk(dai->component, clk_id, 0, + freq, dir); +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); + +/** + * snd_soc_dai_set_clkdiv - configure DAI clock dividers. + * @dai: DAI + * @div_id: DAI specific clock divider ID + * @div: new clock divisor. + * + * Configures the clock dividers. This is used to derive the best DAI bit and + * frame clocks from the system or master clock. It's best to set the DAI bit + * and frame clocks as low as possible to save system power. + */ +int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, + int div_id, int div) +{ + if (dai->driver->ops->set_clkdiv) + return dai->driver->ops->set_clkdiv(dai, div_id, div); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); + +/** + * snd_soc_dai_set_pll - configure DAI PLL. + * @dai: DAI + * @pll_id: DAI specific PLL ID + * @source: DAI specific source for the PLL + * @freq_in: PLL input clock frequency in Hz + * @freq_out: requested PLL output clock frequency in Hz + * + * Configures and enables PLL to generate output clock based on input clock. + */ +int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + if (dai->driver->ops->set_pll) + return dai->driver->ops->set_pll(dai, pll_id, source, + freq_in, freq_out); + + return snd_soc_component_set_pll(dai->component, pll_id, source, + freq_in, freq_out); +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); + +/** + * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. + * @dai: DAI + * @ratio: Ratio of BCLK to Sample rate. + * + * Configures the DAI for a preset BCLK to sample rate ratio. + */ +int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + if (dai->driver->ops->set_bclk_ratio) + return dai->driver->ops->set_bclk_ratio(dai, ratio); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); + +/** + * snd_soc_dai_set_fmt - configure DAI hardware audio format. + * @dai: DAI + * @fmt: SND_SOC_DAIFMT_* format value. + * + * Configures the DAI hardware format and clocking. + */ +int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + if (dai->driver->ops->set_fmt == NULL) + return -ENOTSUPP; + return dai->driver->ops->set_fmt(dai, fmt); +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); + +/** + * snd_soc_xlate_tdm_slot - generate tx/rx slot mask. + * @slots: Number of slots in use. + * @tx_mask: bitmask representing active TX slots. + * @rx_mask: bitmask representing active RX slots. + * + * Generates the TDM tx and rx slot default masks for DAI. + */ +static int snd_soc_xlate_tdm_slot_mask(unsigned int slots, + unsigned int *tx_mask, + unsigned int *rx_mask) +{ + if (*tx_mask || *rx_mask) + return 0; + + if (!slots) + return -EINVAL; + + *tx_mask = (1 << slots) - 1; + *rx_mask = (1 << slots) - 1; + + return 0; +} + +/** + * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation + * @dai: The DAI to configure + * @tx_mask: bitmask representing active TX slots. + * @rx_mask: bitmask representing active RX slots. + * @slots: Number of slots in use. + * @slot_width: Width in bits for each slot. + * + * This function configures the specified DAI for TDM operation. @slot contains + * the total number of slots of the TDM stream and @slot_with the width of each + * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the + * active slots of the TDM stream for the specified DAI, i.e. which slots the + * DAI should write to or read from. If a bit is set the corresponding slot is + * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to + * the first slot, bit 1 to the second slot and so on. The first active slot + * maps to the first channel of the DAI, the second active slot to the second + * channel and so on. + * + * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask, + * @rx_mask and @slot_width will be ignored. + * + * Returns 0 on success, a negative error code otherwise. + */ +int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + if (dai->driver->ops->xlate_tdm_slot_mask) + dai->driver->ops->xlate_tdm_slot_mask(slots, + &tx_mask, &rx_mask); + else + snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); + + dai->tx_mask = tx_mask; + dai->rx_mask = rx_mask; + + if (dai->driver->ops->set_tdm_slot) + return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, + slots, slot_width); + else + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); + +/** + * snd_soc_dai_set_channel_map - configure DAI audio channel map + * @dai: DAI + * @tx_num: how many TX channels + * @tx_slot: pointer to an array which imply the TX slot number channel + * 0~num-1 uses + * @rx_num: how many RX channels + * @rx_slot: pointer to an array which imply the RX slot number channel + * 0~num-1 uses + * + * configure the relationship between channel number and TDM slot number. + */ +int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + if (dai->driver->ops->set_channel_map) + return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot, + rx_num, rx_slot); + else + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); + +/** + * snd_soc_dai_get_channel_map - Get DAI audio channel map + * @dai: DAI + * @tx_num: how many TX channels + * @tx_slot: pointer to an array which imply the TX slot number channel + * 0~num-1 uses + * @rx_num: how many RX channels + * @rx_slot: pointer to an array which imply the RX slot number channel + * 0~num-1 uses + */ +int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + if (dai->driver->ops->get_channel_map) + return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot, + rx_num, rx_slot); + else + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map); + +/** + * snd_soc_dai_set_tristate - configure DAI system or master clock. + * @dai: DAI + * @tristate: tristate enable + * + * Tristates the DAI so that others can use it. + */ +int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + if (dai->driver->ops->set_tristate) + return dai->driver->ops->set_tristate(dai, tristate); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); + +/** + * snd_soc_dai_digital_mute - configure DAI system or master clock. + * @dai: DAI + * @mute: mute enable + * @direction: stream to mute + * + * Mutes the DAI DAC. + */ +int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, + int direction) +{ + if (dai->driver->ops->mute_stream) + return dai->driver->ops->mute_stream(dai, mute, direction); + else if (direction == SNDRV_PCM_STREAM_PLAYBACK && + dai->driver->ops->digital_mute) + return dai->driver->ops->digital_mute(dai, mute); + else + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); -- cgit v1.2.3 From aa6166c2ac28392d64f2d8b3acfb56c8fe657147 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:33:04 +0900 Subject: ASoC: soc-dai: mv soc_dai_hw_params() to soc-dai Sometimes ALSA SoC naming is very random. Current soc_dai_hw_params() should use snd_soc_dai_xxx() style. And then, 1st parameter should be dai. Otherwise it is confusable. - soc_dai_hw_params(..., dai); + snd_soc_dai_hw_params(dai, ...); Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zhl6hn5b.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 4 ++++ include/sound/soc.h | 4 ---- sound/soc/soc-dai.c | 30 ++++++++++++++++++++++++++++++ sound/soc/soc-dapm.c | 4 ++-- sound/soc/soc-pcm.c | 35 +++-------------------------------- 5 files changed, 39 insertions(+), 38 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index f5d70041108f..3773262a1b77 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -145,6 +145,10 @@ int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, int snd_soc_dai_is_dummy(struct snd_soc_dai *dai); +int snd_soc_dai_hw_params(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); + struct snd_soc_dai_ops { /* * DAI clocking configuration, all optional. diff --git a/include/sound/soc.h b/include/sound/soc.h index 4e8071269639..d770606732cd 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -505,10 +505,6 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms); int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, const struct snd_pcm_hardware *hw); -int soc_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai); - /* Jack reporting */ 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, diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index a1009ead40de..f883d27d136f 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -252,3 +252,33 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, return -ENOTSUPP; } EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); + +int snd_soc_dai_hw_params(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int ret; + + /* perform any topology hw_params fixups before DAI */ + if (rtd->dai_link->be_hw_params_fixup) { + ret = rtd->dai_link->be_hw_params_fixup(rtd, params); + if (ret < 0) { + dev_err(rtd->dev, + "ASoC: hw_params topology fixup failed %d\n", + ret); + return ret; + } + } + + if (dai->driver->ops->hw_params) { + ret = dai->driver->ops->hw_params(substream, params, dai); + if (ret < 0) { + dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n", + dai->name, ret); + return ret; + } + } + + return 0; +} diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index f013b24c050a..8fc6a01f5d8b 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3839,7 +3839,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, } } source->active++; - ret = soc_dai_hw_params(&substream, params, source); + ret = snd_soc_dai_hw_params(source, &substream, params); if (ret < 0) goto out; @@ -3861,7 +3861,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, } } sink->active++; - ret = soc_dai_hw_params(&substream, params, sink); + ret = snd_soc_dai_hw_params(sink, &substream, params); if (ret < 0) goto out; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 4878d22ebd8c..420cc94e0a46 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -877,36 +877,6 @@ static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params, interval->max = channels; } -int soc_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - int ret; - - /* perform any topology hw_params fixups before DAI */ - if (rtd->dai_link->be_hw_params_fixup) { - ret = rtd->dai_link->be_hw_params_fixup(rtd, params); - if (ret < 0) { - dev_err(rtd->dev, - "ASoC: hw_params topology fixup failed %d\n", - ret); - return ret; - } - } - - if (dai->driver->ops->hw_params) { - ret = dai->driver->ops->hw_params(substream, params, dai); - if (ret < 0) { - dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n", - dai->name, ret); - return ret; - } - } - - return 0; -} - static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream, struct snd_soc_component *last) { @@ -989,7 +959,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, soc_pcm_codec_params_fixup(&codec_params, codec_dai->rx_mask); - ret = soc_dai_hw_params(substream, &codec_params, codec_dai); + ret = snd_soc_dai_hw_params(codec_dai, substream, + &codec_params); if(ret < 0) goto codec_err; @@ -1001,7 +972,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, snd_soc_dapm_update_dai(substream, &codec_params, codec_dai); } - ret = soc_dai_hw_params(substream, params, cpu_dai); + ret = snd_soc_dai_hw_params(cpu_dai, substream, params); if (ret < 0) goto interface_err; -- cgit v1.2.3 From 846faaed9df7899e74311db3aec0a41a2f6bc345 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:33:19 +0900 Subject: ASoC: soc-dai: add snd_soc_dai_hw_free() Current ALSA SoC is directly using dai->driver->ops->xxx, thus, it has deep nested bracket, and it makes code unreadable. This patch adds new snd_soc_dai_hw_free() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y30qhn4w.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 ++ sound/soc/soc-dai.c | 7 +++++++ sound/soc/soc-dapm.c | 7 ++----- sound/soc/soc-pcm.c | 12 ++++-------- 4 files changed, 15 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 3773262a1b77..5222b6a758f2 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -148,6 +148,8 @@ int snd_soc_dai_is_dummy(struct snd_soc_dai *dai); int snd_soc_dai_hw_params(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); +void snd_soc_dai_hw_free(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index f883d27d136f..39a685e6acd5 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -282,3 +282,10 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai, return 0; } + +void snd_soc_dai_hw_free(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream) +{ + if (dai->driver->ops->hw_free) + dai->driver->ops->hw_free(substream, dai); +} diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8fc6a01f5d8b..0783b05133ad 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3898,9 +3898,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, snd_soc_dapm_widget_for_each_source_path(w, path) { source = path->source->priv; - if (source->driver->ops->hw_free) - source->driver->ops->hw_free(&substream, - source); + snd_soc_dai_hw_free(source, &substream); source->active--; if (source->driver->ops->shutdown) @@ -3912,8 +3910,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, snd_soc_dapm_widget_for_each_sink_path(w, path) { sink = path->sink->priv; - if (sink->driver->ops->hw_free) - sink->driver->ops->hw_free(&substream, sink); + snd_soc_dai_hw_free(sink, &substream); sink->active--; if (sink->driver->ops->shutdown) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 420cc94e0a46..58fc4e98ab59 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1011,8 +1011,7 @@ out: component_err: soc_pcm_components_hw_free(substream, component); - if (cpu_dai->driver->ops->hw_free) - cpu_dai->driver->ops->hw_free(substream, cpu_dai); + snd_soc_dai_hw_free(cpu_dai, substream); cpu_dai->rate = 0; interface_err: @@ -1023,8 +1022,7 @@ codec_err: if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) continue; - if (codec_dai->driver->ops->hw_free) - codec_dai->driver->ops->hw_free(substream, codec_dai); + snd_soc_dai_hw_free(codec_dai, substream); codec_dai->rate = 0; } @@ -1083,12 +1081,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) continue; - if (codec_dai->driver->ops->hw_free) - codec_dai->driver->ops->hw_free(substream, codec_dai); + snd_soc_dai_hw_free(codec_dai, substream); } - if (cpu_dai->driver->ops->hw_free) - cpu_dai->driver->ops->hw_free(substream, cpu_dai); + snd_soc_dai_hw_free(cpu_dai, substream); mutex_unlock(&rtd->pcm_mutex); return 0; -- cgit v1.2.3 From 5a52a04531486e2ab069b7882432c8b266db36e6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:33:32 +0900 Subject: ASoC: soc-dai: add snd_soc_dai_startup() Current ALSA SoC is directly using dai->driver->ops->xxx, thus, it has deep nested bracket, and it makes code unreadable. This patch adds new snd_soc_dai_startup() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87wogahn4i.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 ++ sound/soc/soc-dai.c | 11 +++++++++++ sound/soc/soc-dapm.c | 28 ++++++++++------------------ sound/soc/soc-pcm.c | 27 +++++++++++---------------- 4 files changed, 34 insertions(+), 34 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 5222b6a758f2..0d16c5bb20bb 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -150,6 +150,8 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai, struct snd_pcm_hw_params *params); void snd_soc_dai_hw_free(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); +int snd_soc_dai_startup(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 39a685e6acd5..6e196636e42f 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -289,3 +289,14 @@ void snd_soc_dai_hw_free(struct snd_soc_dai *dai, if (dai->driver->ops->hw_free) dai->driver->ops->hw_free(substream, dai); } + +int snd_soc_dai_startup(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream) +{ + int ret = 0; + + if (dai->driver->ops->startup) + ret = dai->driver->ops->startup(substream, dai); + + return ret; +} diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0783b05133ad..71bfd049480a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3828,15 +3828,11 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, snd_soc_dapm_widget_for_each_source_path(w, path) { source = path->source->priv; - if (source->driver->ops->startup) { - ret = source->driver->ops->startup(&substream, - source); - if (ret < 0) { - dev_err(source->dev, - "ASoC: startup() failed: %d\n", - ret); - goto out; - } + ret = snd_soc_dai_startup(source, &substream); + if (ret < 0) { + dev_err(source->dev, + "ASoC: startup() failed: %d\n", ret); + goto out; } source->active++; ret = snd_soc_dai_hw_params(source, &substream, params); @@ -3850,15 +3846,11 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, snd_soc_dapm_widget_for_each_sink_path(w, path) { sink = path->sink->priv; - if (sink->driver->ops->startup) { - ret = sink->driver->ops->startup(&substream, - sink); - if (ret < 0) { - dev_err(sink->dev, - "ASoC: startup() failed: %d\n", - ret); - goto out; - } + ret = snd_soc_dai_startup(sink, &substream); + if (ret < 0) { + dev_err(sink->dev, + "ASoC: startup() failed: %d\n", ret); + goto out; } sink->active++; ret = snd_soc_dai_hw_params(sink, &substream, params); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 58fc4e98ab59..9c8713a3eef1 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -535,13 +535,11 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); /* startup the audio subsystem */ - if (cpu_dai->driver->ops->startup) { - ret = cpu_dai->driver->ops->startup(substream, cpu_dai); - if (ret < 0) { - dev_err(cpu_dai->dev, "ASoC: can't open interface" - " %s: %d\n", cpu_dai->name, ret); - goto out; - } + ret = snd_soc_dai_startup(cpu_dai, substream); + if (ret < 0) { + dev_err(cpu_dai->dev, "ASoC: can't open interface %s: %d\n", + cpu_dai->name, ret); + goto out; } ret = soc_pcm_components_open(substream, &component); @@ -549,15 +547,12 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto component_err; for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->ops->startup) { - ret = codec_dai->driver->ops->startup(substream, - codec_dai); - if (ret < 0) { - dev_err(codec_dai->dev, - "ASoC: can't open codec %s: %d\n", - codec_dai->name, ret); - goto codec_dai_err; - } + ret = snd_soc_dai_startup(codec_dai, substream); + if (ret < 0) { + dev_err(codec_dai->dev, + "ASoC: can't open codec %s: %d\n", + codec_dai->name, ret); + goto codec_dai_err; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -- cgit v1.2.3 From 330fcb5135e0588b1ea3b0bbab587d1317c1cf7b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:33:39 +0900 Subject: ASoC: soc-dai: add snd_soc_dai_shutdown() Current ALSA SoC is directly using dai->driver->ops->xxx, thus, it has deep nested bracket, and it makes code unreadable. This patch adds new snd_soc_dai_shutdown() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v9vuhn4b.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 ++ sound/soc/soc-dai.c | 7 +++++++ sound/soc/soc-dapm.c | 7 ++----- sound/soc/soc-pcm.c | 18 ++++++------------ 4 files changed, 17 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 0d16c5bb20bb..32545d457b3d 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -152,6 +152,8 @@ void snd_soc_dai_hw_free(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); int snd_soc_dai_startup(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); +void snd_soc_dai_shutdown(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 6e196636e42f..67ff6cc1fe02 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -300,3 +300,10 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai, return ret; } + +void snd_soc_dai_shutdown(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream) +{ + if (dai->driver->ops->shutdown) + dai->driver->ops->shutdown(substream, dai); +} diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 71bfd049480a..1d04612601ad 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3893,9 +3893,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, snd_soc_dai_hw_free(source, &substream); source->active--; - if (source->driver->ops->shutdown) - source->driver->ops->shutdown(&substream, - source); + snd_soc_dai_shutdown(source, &substream); } substream.stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -3905,8 +3903,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, snd_soc_dai_hw_free(sink, &substream); sink->active--; - if (sink->driver->ops->shutdown) - sink->driver->ops->shutdown(&substream, sink); + snd_soc_dai_shutdown(sink, &substream); } break; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 9c8713a3eef1..ed5ae23c7104 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -641,16 +641,13 @@ machine_err: i = rtd->num_codecs; codec_dai_err: - for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) { - if (codec_dai->driver->ops->shutdown) - codec_dai->driver->ops->shutdown(substream, codec_dai); - } + for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) + snd_soc_dai_shutdown(codec_dai, substream); component_err: soc_pcm_components_close(substream, component); - if (cpu_dai->driver->ops->shutdown) - cpu_dai->driver->ops->shutdown(substream, cpu_dai); + snd_soc_dai_shutdown(cpu_dai, substream); out: mutex_unlock(&rtd->pcm_mutex); @@ -728,13 +725,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream); - if (cpu_dai->driver->ops->shutdown) - cpu_dai->driver->ops->shutdown(substream, cpu_dai); + snd_soc_dai_shutdown(cpu_dai, substream); - for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->ops->shutdown) - codec_dai->driver->ops->shutdown(substream, codec_dai); - } + for_each_rtd_codec_dai(rtd, i, codec_dai) + snd_soc_dai_shutdown(codec_dai, substream); if (rtd->dai_link->ops->shutdown) rtd->dai_link->ops->shutdown(substream); -- cgit v1.2.3 From 4beb8e109d30d339d44308a767dd6f5614492f3e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:33:45 +0900 Subject: ASoC: soc-dai: add snd_soc_dai_prepare() Current ALSA SoC is directly using dai->driver->ops->xxx, thus, it has deep nested bracket, and it makes code unreadable. This patch adds new snd_soc_dai_prepare() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tvbehn46.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 ++ sound/soc/soc-dai.c | 11 +++++++++++ sound/soc/soc-pcm.c | 27 +++++++++++---------------- 3 files changed, 24 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 32545d457b3d..c7dff6a0b5b9 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -154,6 +154,8 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); void snd_soc_dai_shutdown(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); +int snd_soc_dai_prepare(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 67ff6cc1fe02..cb810888c563 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -307,3 +307,14 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai, if (dai->driver->ops->shutdown) dai->driver->ops->shutdown(substream, dai); } + +int snd_soc_dai_prepare(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream) +{ + int ret = 0; + + if (dai->driver->ops->prepare) + ret = dai->driver->ops->prepare(substream, dai); + + return ret; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ed5ae23c7104..d7611af90dce 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -814,27 +814,22 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->ops->prepare) { - ret = codec_dai->driver->ops->prepare(substream, - codec_dai); - if (ret < 0) { - dev_err(codec_dai->dev, - "ASoC: codec DAI prepare error: %d\n", - ret); - goto out; - } - } - } - - if (cpu_dai->driver->ops->prepare) { - ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); + ret = snd_soc_dai_prepare(codec_dai, substream); if (ret < 0) { - dev_err(cpu_dai->dev, - "ASoC: cpu DAI prepare error: %d\n", ret); + dev_err(codec_dai->dev, + "ASoC: codec DAI prepare error: %d\n", + ret); goto out; } } + ret = snd_soc_dai_prepare(cpu_dai, substream); + if (ret < 0) { + dev_err(cpu_dai->dev, + "ASoC: cpu DAI prepare error: %d\n", ret); + goto out; + } + /* cancel any delayed stream shutdown that is pending */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && rtd->pop_wait) { -- cgit v1.2.3 From 95aef35533844f35544851b0cdc1fc154b603307 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:33:51 +0900 Subject: ASoC: soc-dai: add snd_soc_dai_trigger() Current ALSA SoC is directly using dai->driver->ops->xxx, thus, it has deep nested bracket, and it makes code unreadable. This patch adds new snd_soc_dai_trigger() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sgqyhn40.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 ++ sound/soc/soc-dai.c | 12 ++++++++++++ sound/soc/soc-pcm.c | 17 ++++++----------- 3 files changed, 20 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index c7dff6a0b5b9..72b8e76f1cc4 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -156,6 +156,8 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); int snd_soc_dai_prepare(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); +int snd_soc_dai_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, int cmd); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index cb810888c563..18c447e169f6 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -318,3 +318,15 @@ int snd_soc_dai_prepare(struct snd_soc_dai *dai, return ret; } + +int snd_soc_dai_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, + int cmd) +{ + int ret = 0; + + if (dai->driver->ops->trigger) + ret = dai->driver->ops->trigger(substream, cmd, dai); + + return ret; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d7611af90dce..a628b08f966e 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1084,12 +1084,9 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) int i, ret; for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->ops->trigger) { - ret = codec_dai->driver->ops->trigger(substream, - cmd, codec_dai); - if (ret < 0) - return ret; - } + ret = snd_soc_dai_trigger(codec_dai, substream, cmd); + if (ret < 0) + return ret; } for_each_rtdcom(rtd, rtdcom) { @@ -1104,11 +1101,9 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } - if (cpu_dai->driver->ops->trigger) { - ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); - if (ret < 0) - return ret; - } + snd_soc_dai_trigger(cpu_dai, substream, cmd); + if (ret < 0) + return ret; if (rtd->dai_link->ops->trigger) { ret = rtd->dai_link->ops->trigger(substream, cmd); -- cgit v1.2.3 From 5c0769af4caf8fbdad2e9c0051ab0081b8e22b0a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:33:56 +0900 Subject: ASoC: soc-dai: add snd_soc_dai_bespoke_trigger() Current ALSA SoC is directly using dai->driver->ops->xxx, thus, it has deep nested bracket, and it makes code unreadable. This patch adds new snd_soc_dai_bespoke_trigger() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r26ihn3u.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 ++ sound/soc/soc-dai.c | 12 ++++++++++++ sound/soc/soc-pcm.c | 16 ++++++---------- 3 files changed, 20 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 72b8e76f1cc4..6a5566d459ad 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -158,6 +158,8 @@ int snd_soc_dai_prepare(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); int snd_soc_dai_trigger(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, int cmd); +int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, int cmd); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 18c447e169f6..6f466cfcbeef 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -330,3 +330,15 @@ int snd_soc_dai_trigger(struct snd_soc_dai *dai, return ret; } + +int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, + int cmd) +{ + int ret = 0; + + if (dai->driver->ops->bespoke_trigger) + ret = dai->driver->ops->bespoke_trigger(substream, cmd, dai); + + return ret; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index a628b08f966e..a10627f1ceff 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1123,19 +1123,15 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, int i, ret; for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->ops->bespoke_trigger) { - ret = codec_dai->driver->ops->bespoke_trigger(substream, - cmd, codec_dai); - if (ret < 0) - return ret; - } - } - - if (cpu_dai->driver->ops->bespoke_trigger) { - ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai); + ret = snd_soc_dai_bespoke_trigger(codec_dai, substream, cmd); if (ret < 0) return ret; } + + snd_soc_dai_bespoke_trigger(cpu_dai, substream, cmd); + if (ret < 0) + return ret; + return 0; } /* -- cgit v1.2.3 From 1dea80d4b2bd3b53c58f008ca2bcd73182583711 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:34:09 +0900 Subject: ASoC: soc-dai: add snd_soc_dai_delay() Current ALSA SoC is directly using dai->driver->ops->xxx, thus, it has deep nested bracket, and it makes code unreadable. This patch adds new snd_soc_dai_delay() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o91mhn3i.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 ++ sound/soc/soc-dai.c | 11 +++++++++++ sound/soc/soc-pcm.c | 9 +++------ 3 files changed, 16 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 6a5566d459ad..7cfed3034511 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -160,6 +160,8 @@ int snd_soc_dai_trigger(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, int cmd); int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, int cmd); +snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 6f466cfcbeef..5b5b979cd1f3 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -342,3 +342,14 @@ int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, return ret; } + +snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream) +{ + int delay = 0; + + if (dai->driver->ops->delay) + delay = dai->driver->ops->delay(substream, dai); + + return delay; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index a10627f1ceff..f3137723301c 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1169,14 +1169,11 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) /* base delay if assigned in pointer callback */ delay = runtime->delay; - if (cpu_dai->driver->ops->delay) - delay += cpu_dai->driver->ops->delay(substream, cpu_dai); + delay += snd_soc_dai_delay(cpu_dai, substream); for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->ops->delay) - codec_delay = max(codec_delay, - codec_dai->driver->ops->delay(substream, - codec_dai)); + codec_delay = max(codec_delay, + snd_soc_dai_delay(codec_dai, substream)); } delay += codec_delay; -- cgit v1.2.3 From e0f2262292d0c8160cfd9a8c40425107fb65ab29 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:34:29 +0900 Subject: ASoC: soc-dai: add snd_soc_dai_suspend() Current ALSA SoC is directly using dai->driver->xxx, thus, it has deep nested bracket, and it makes code unreadable. This patch adds new snd_soc_dai_suspend() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87muh6hn2x.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 1 + sound/soc/soc-core.c | 8 ++++---- sound/soc/soc-dai.c | 6 ++++++ 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 7cfed3034511..6c5604a7dbc2 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -162,6 +162,7 @@ int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, int cmd); snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); +void snd_soc_dai_suspend(struct snd_soc_dai *dai); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6e8c5c8eeaec..7493afb2371c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -511,8 +511,8 @@ int snd_soc_suspend(struct device *dev) if (rtd->dai_link->ignore_suspend) continue; - if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control) - cpu_dai->driver->suspend(cpu_dai); + if (!cpu_dai->driver->bus_control) + snd_soc_dai_suspend(cpu_dai); } /* close any waiting streams */ @@ -584,8 +584,8 @@ int snd_soc_suspend(struct device *dev) if (rtd->dai_link->ignore_suspend) continue; - if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control) - cpu_dai->driver->suspend(cpu_dai); + if (cpu_dai->driver->bus_control) + snd_soc_dai_suspend(cpu_dai); /* deactivate pins to sleep state */ pinctrl_pm_select_sleep_state(cpu_dai->dev); diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 5b5b979cd1f3..3373598e0682 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -353,3 +353,9 @@ snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, return delay; } + +void snd_soc_dai_suspend(struct snd_soc_dai *dai) +{ + if (dai->driver->suspend) + dai->driver->suspend(dai); +} -- cgit v1.2.3 From 24b09d051164680f0a1d1910efe21ce36ad5c1ca Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:34:43 +0900 Subject: ASoC: soc-dai: add snd_soc_dai_resume() Current ALSA SoC is directly using dai->driver->xxx, thus, it has deep nested bracket, and it makes code unreadable. This patch adds new snd_soc_dai_resume() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lfwqhn2j.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 1 + sound/soc/soc-core.c | 8 ++++---- sound/soc/soc-dai.c | 6 ++++++ 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 6c5604a7dbc2..ed78e34a814e 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -163,6 +163,7 @@ int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); void snd_soc_dai_suspend(struct snd_soc_dai *dai); +void snd_soc_dai_resume(struct snd_soc_dai *dai); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7493afb2371c..5c02f90cea69 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -631,8 +631,8 @@ static void soc_resume_deferred(struct work_struct *work) if (rtd->dai_link->ignore_suspend) continue; - if (cpu_dai->driver->resume && cpu_dai->driver->bus_control) - cpu_dai->driver->resume(cpu_dai); + if (cpu_dai->driver->bus_control) + snd_soc_dai_resume(cpu_dai); } for_each_card_components(card, component) { @@ -678,8 +678,8 @@ static void soc_resume_deferred(struct work_struct *work) if (rtd->dai_link->ignore_suspend) continue; - if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control) - cpu_dai->driver->resume(cpu_dai); + if (!cpu_dai->driver->bus_control) + snd_soc_dai_resume(cpu_dai); } if (card->resume_post) diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 3373598e0682..ddb6f217c0ed 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -359,3 +359,9 @@ void snd_soc_dai_suspend(struct snd_soc_dai *dai) if (dai->driver->suspend) dai->driver->suspend(dai); } + +void snd_soc_dai_resume(struct snd_soc_dai *dai) +{ + if (dai->driver->resume) + dai->driver->resume(dai); +} -- cgit v1.2.3 From cfd9b5fbfe1e8763018aea2600aa0d6ff015ebfc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:34:56 +0900 Subject: ASoC: soc-dai: add snd_soc_dai_probe() Current ALSA SoC is directly using dai->driver->xxx, thus, it has deep nested bracket, and it makes code unreadable. This patch adds new snd_soc_dai_probe() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k1cahn26.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 1 + sound/soc/soc-core.c | 15 +++++++-------- sound/soc/soc-dai.c | 7 +++++++ 3 files changed, 15 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index ed78e34a814e..da8d8b889089 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -164,6 +164,7 @@ snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); void snd_soc_dai_suspend(struct snd_soc_dai *dai); void snd_soc_dai_resume(struct snd_soc_dai *dai); +int snd_soc_dai_probe(struct snd_soc_dai *dai); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 5c02f90cea69..3e73468225f9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1434,18 +1434,17 @@ static int soc_probe_link_components(struct snd_soc_card *card, static int soc_probe_dai(struct snd_soc_dai *dai, int order) { + int ret; + if (dai->probed || dai->driver->probe_order != order) return 0; - if (dai->driver->probe) { - int ret = dai->driver->probe(dai); - - if (ret < 0) { - dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n", - dai->name, ret); - return ret; - } + ret = snd_soc_dai_probe(dai); + if (ret < 0) { + dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n", + dai->name, ret); + return ret; } dai->probed = 1; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index ddb6f217c0ed..55c1fac99613 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -365,3 +365,10 @@ void snd_soc_dai_resume(struct snd_soc_dai *dai) if (dai->driver->resume) dai->driver->resume(dai); } + +int snd_soc_dai_probe(struct snd_soc_dai *dai) +{ + if (dai->driver->probe) + return dai->driver->probe(dai); + return 0; +} -- cgit v1.2.3 From dcdab5820edd6123911dbd767ee1e389008b6a83 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:35:05 +0900 Subject: ASoC: soc-dai: add snd_soc_dai_remove() Current ALSA SoC is directly using dai->driver->xxx, thus, it has deep nested bracket, and it makes code unreadable. This patch adds new snd_soc_dai_remvoe() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87imruhn1x.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 1 + sound/soc/soc-core.c | 13 ++++++------- sound/soc/soc-dai.c | 7 +++++++ 3 files changed, 14 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index da8d8b889089..2a11f177ce01 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -165,6 +165,7 @@ snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, void snd_soc_dai_suspend(struct snd_soc_dai *dai); void snd_soc_dai_resume(struct snd_soc_dai *dai); int snd_soc_dai_probe(struct snd_soc_dai *dai); +int snd_soc_dai_remove(struct snd_soc_dai *dai); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3e73468225f9..727fd342b3fb 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -992,13 +992,12 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) dai->driver->remove_order != order) return; - if (dai->driver->remove) { - err = dai->driver->remove(dai); - if (err < 0) - dev_err(dai->dev, - "ASoC: failed to remove %s: %d\n", - dai->name, err); - } + err = snd_soc_dai_remove(dai); + if (err < 0) + dev_err(dai->dev, + "ASoC: failed to remove %s: %d\n", + dai->name, err); + dai->probed = 0; } diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 55c1fac99613..384765c747da 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -372,3 +372,10 @@ int snd_soc_dai_probe(struct snd_soc_dai *dai) return dai->driver->probe(dai); return 0; } + +int snd_soc_dai_remove(struct snd_soc_dai *dai) +{ + if (dai->driver->remove) + return dai->driver->remove(dai); + return 0; +} -- cgit v1.2.3 From b423c4202135f7794e0a9c55a884f5933d8e7156 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:35:29 +0900 Subject: ASoC: soc-dai: add snd_soc_dai_compress_new() Current ALSA SoC is directly using dai->driver->xxx, thus, it has deep nested bracket, and it makes code unreadable. This patch adds new snd_soc_dai_compress_new() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h87ehn1a.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 ++ sound/soc/soc-core.c | 15 ++++++++------- sound/soc/soc-dai.c | 8 ++++++++ 3 files changed, 18 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 2a11f177ce01..0f8b09520020 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -166,6 +166,8 @@ void snd_soc_dai_suspend(struct snd_soc_dai *dai); void snd_soc_dai_resume(struct snd_soc_dai *dai); int snd_soc_dai_probe(struct snd_soc_dai *dai); int snd_soc_dai_remove(struct snd_soc_dai *dai); +int snd_soc_dai_compress_new(struct snd_soc_dai *dai, + struct snd_soc_pcm_runtime *rtd, int num); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 727fd342b3fb..458b090f026a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1545,15 +1545,16 @@ static int soc_probe_link_dais(struct snd_soc_card *card, num = rtd->dai_link->id; } - if (cpu_dai->driver->compress_new) { - /* create compress_device" */ - ret = cpu_dai->driver->compress_new(rtd, num); - if (ret < 0) { + /* create compress_device if possible */ + ret = snd_soc_dai_compress_new(cpu_dai, rtd, num); + if (ret != -ENOTSUPP) { + if (ret < 0) dev_err(card->dev, "ASoC: can't create compress %s\n", dai_link->stream_name); - return ret; - } - } else if (!dai_link->params) { + return ret; + } + + if (!dai_link->params) { /* create the pcm */ ret = soc_new_pcm(rtd, num); if (ret < 0) { diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 384765c747da..e6f161b9f975 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -379,3 +379,11 @@ int snd_soc_dai_remove(struct snd_soc_dai *dai) return dai->driver->remove(dai); return 0; } + +int snd_soc_dai_compress_new(struct snd_soc_dai *dai, + struct snd_soc_pcm_runtime *rtd, int num) +{ + if (dai->driver->compress_new) + return dai->driver->compress_new(rtd, num); + return -ENOTSUPP; +} -- cgit v1.2.3 From 88fdffa2eef45fc9f6009ee590741c44a57c49c7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:36:27 +0900 Subject: ASoC: soc-core: use existing snd_soc_dai_digital_mute() ALSA SoC already has snd_soc_dai_digital_mute() for digital_mute, let's use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ef2ihmzo.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 458b090f026a..7ecfe641ca46 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -487,10 +487,9 @@ int snd_soc_suspend(struct device *dev) continue; for_each_rtd_codec_dai(rtd, i, dai) { - struct snd_soc_dai_driver *drv = dai->driver; - - if (drv->ops->digital_mute && dai->playback_active) - drv->ops->digital_mute(dai, 1); + if (dai->playback_active) + snd_soc_dai_digital_mute(dai, 1, + SNDRV_PCM_STREAM_PLAYBACK); } } @@ -665,10 +664,9 @@ static void soc_resume_deferred(struct work_struct *work) continue; for_each_rtd_codec_dai(rtd, i, dai) { - struct snd_soc_dai_driver *drv = dai->driver; - - if (drv->ops->digital_mute && dai->playback_active) - drv->ops->digital_mute(dai, 0); + if (dai->playback_active) + snd_soc_dai_digital_mute(dai, 0, + SNDRV_PCM_STREAM_PLAYBACK); } } -- cgit v1.2.3 From 467fece8fbc6774a3a3bd0981e1a342fb5022706 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Jul 2019 10:36:16 +0900 Subject: ASoC: soc-dai: move snd_soc_dai_stream_valid() to soc-dai.c snd_soc_dai_stream_valid() is function to check stream validity. But, some code is using it, some code are checking stream->channels_min directly. Doing samethings by different method is confusable. This patch uses same funcntion for same purpose. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ftmyhmzz.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 1 + sound/soc/soc-compress.c | 9 ++++----- sound/soc/soc-dai.c | 18 ++++++++++++++++++ sound/soc/soc-pcm.c | 39 ++++++++++----------------------------- 4 files changed, 33 insertions(+), 34 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 0f8b09520020..dc48fe081a20 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -168,6 +168,7 @@ int snd_soc_dai_probe(struct snd_soc_dai *dai); int snd_soc_dai_remove(struct snd_soc_dai *dai); int snd_soc_dai_compress_new(struct snd_soc_dai *dai, struct snd_soc_pcm_runtime *rtd, int num); +bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream); struct snd_soc_dai_ops { /* diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index ddef4ff677ce..289211069a1e 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -872,14 +872,13 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) } /* check client and interface hw capabilities */ - if (codec_dai->driver->playback.channels_min) + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && + snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) playback = 1; - if (codec_dai->driver->capture.channels_min) + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && + snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) capture = 1; - capture = capture && cpu_dai->driver->capture.channels_min; - playback = playback && cpu_dai->driver->playback.channels_min; - /* * Compress devices are unidirectional so only one of the directions * should be set, check for that (xor) diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index e6f161b9f975..1c7f63871c1d 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -387,3 +387,21 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai, return dai->driver->compress_new(rtd, num); return -ENOTSUPP; } + +/* + * snd_soc_dai_stream_valid() - check if a DAI supports the given stream + * + * Returns true if the DAI supports the indicated stream type. + */ +bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir) +{ + struct snd_soc_pcm_stream *stream; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + stream = &dai->driver->playback; + else + stream = &dai->driver->capture; + + /* If the codec specifies any channels at all, it supports the stream */ + return stream->channels_min; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index f3137723301c..fabeac164a6c 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -29,24 +29,6 @@ #define DPCM_MAX_BE_USERS 8 -/* - * snd_soc_dai_stream_valid() - check if a DAI supports the given stream - * - * Returns true if the DAI supports the indicated stream type. - */ -static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream) -{ - struct snd_soc_pcm_stream *codec_stream; - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - codec_stream = &dai->driver->playback; - else - codec_stream = &dai->driver->capture; - - /* If the codec specifies any channels at all, it supports the stream */ - return codec_stream->channels_min; -} - /** * snd_soc_runtime_activate() - Increment active count for PCM runtime components * @rtd: ASoC PCM runtime that is activated @@ -2688,8 +2670,8 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) new ? "new" : "old", fe->dai_link->name); /* skip if FE doesn't have playback capability */ - if (!fe->cpu_dai->driver->playback.channels_min || - !fe->codec_dai->driver->playback.channels_min) + if (!snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_PLAYBACK) || + !snd_soc_dai_stream_valid(fe->codec_dai, SNDRV_PCM_STREAM_PLAYBACK)) goto capture; /* skip if FE isn't currently playing */ @@ -2719,8 +2701,8 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) capture: /* skip if FE doesn't have capture capability */ - if (!fe->cpu_dai->driver->capture.channels_min || - !fe->codec_dai->driver->capture.channels_min) + if (!snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_CAPTURE) || + !snd_soc_dai_stream_valid(fe->codec_dai, SNDRV_PCM_STREAM_CAPTURE)) return 0; /* skip if FE isn't currently capturing */ @@ -3030,14 +3012,13 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) capture = rtd->dai_link->dpcm_capture; } else { for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->playback.channels_min) + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && + snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) playback = 1; - if (codec_dai->driver->capture.channels_min) + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && + snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) capture = 1; } - - capture = capture && cpu_dai->driver->capture.channels_min; - playback = playback && cpu_dai->driver->playback.channels_min; } if (rtd->dai_link->playback_only) { @@ -3375,11 +3356,11 @@ static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf, if (!buf) return -ENOMEM; - if (fe->cpu_dai->driver->playback.channels_min) + if (snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK, buf + offset, out_count - offset); - if (fe->cpu_dai->driver->capture.channels_min) + if (snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE, buf + offset, out_count - offset); -- cgit v1.2.3 From a30f1743e4f57b359903fd679476b2903e7e5dac Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Wed, 24 Jul 2019 11:52:54 +0200 Subject: ALSA: line6: sizeof (byte) is always 1, use that fact. sizeof (byte) is always 1, use that fact and make interesting code explicit. Signed-off-by: Pavel Machek Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index ab2ec896f49c..b5a3f754a4f1 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -342,7 +342,7 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, if (address > 0xffff || datalen > 0xff) return -EINVAL; - len = kmalloc(sizeof(*len), GFP_KERNEL); + len = kmalloc(1, GFP_KERNEL); if (!len) return -ENOMEM; @@ -418,7 +418,7 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, if (address > 0xffff || datalen > 0xffff) return -EINVAL; - status = kmalloc(sizeof(*status), GFP_KERNEL); + status = kmalloc(1, GFP_KERNEL); if (!status) return -ENOMEM; -- cgit v1.2.3 From e8758a5ed2783c417be1f5aab5af9fe4be60956f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 24 Jul 2019 07:26:32 +0200 Subject: ASoC: wm8955: Fix a typo in 'wm8995_pll_factors()' function name This should be 'wm8955_pll_factors()' instead. Fix it and use it. Signed-off-by: Christophe JAILLET Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20190724052632.30476-1-christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/codecs/wm8955.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 66a5f1827aa9..9c7e2892c8cb 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -140,7 +140,7 @@ struct pll_factors { * to allow rounding later */ #define FIXED_FLL_SIZE ((1 << 22) * 10) -static int wm8995_pll_factors(struct device *dev, +static int wm8955_pll_factors(struct device *dev, int Fref, int Fout, struct pll_factors *pll) { u64 Kpart; @@ -279,7 +279,7 @@ static int wm8955_configure_clocking(struct snd_soc_component *component) /* Use the last divider configuration we saw for the * sample rate. */ - ret = wm8995_pll_factors(component->dev, wm8955->mclk_rate, + ret = wm8955_pll_factors(component->dev, wm8955->mclk_rate, clock_cfgs[sr].mclk, &pll); if (ret != 0) { dev_err(component->dev, -- cgit v1.2.3 From bcc2a2dc3ba8c3a7aed856f840afa6a47e3cb8e0 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 23 Jul 2019 16:58:48 +0200 Subject: ASoC: Intel: Skylake: Merge skl_sst and skl into skl_dev struct Skylake driver is divided into two modules: - snd_soc_skl - snd_soc_skl_ipc and nothing would be wrong if not for the fact that both cannot exist without one another. IPC module is not some kind of extension, as it is the case for snd_hda_ext_core which is separated from snd_hda_core - legacy hda interface. It's as much core Skylake module as snd_soc_skl is. Statement backed up by existence of circular dependency between this two. To eliminate said problem, struct skl_sst has been created. From that very momment, Skylake has been plagued by header errors (incomplete structs, unknown references etc.) whenever something new is to be added or code is cleaned up. As this design is being corrected, struct skl_sst is no longer needed, so combine it with struct skl. To avoid ambiguity when searching for skl stuff (struct skl *skl) it has also been renamed to skl_dev. No functional changes. Signed-off-by: Piotr Maziarz Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190723145854.8527-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-ipc.h | 1 + sound/soc/intel/skylake/bxt-sst.c | 50 ++--- sound/soc/intel/skylake/cnl-sst-dsp.h | 7 +- sound/soc/intel/skylake/cnl-sst.c | 37 ++-- sound/soc/intel/skylake/skl-debug.c | 8 +- sound/soc/intel/skylake/skl-messages.c | 229 +++++++++++------------ sound/soc/intel/skylake/skl-nhlt.c | 18 +- sound/soc/intel/skylake/skl-pcm.c | 75 ++++---- sound/soc/intel/skylake/skl-ssp-clk.c | 4 +- sound/soc/intel/skylake/skl-sst-dsp.c | 10 +- sound/soc/intel/skylake/skl-sst-dsp.h | 30 +-- sound/soc/intel/skylake/skl-sst-ipc.c | 8 +- sound/soc/intel/skylake/skl-sst-ipc.h | 52 +----- sound/soc/intel/skylake/skl-sst-utils.c | 37 ++-- sound/soc/intel/skylake/skl-sst.c | 51 ++--- sound/soc/intel/skylake/skl-topology.c | 320 +++++++++++++++----------------- sound/soc/intel/skylake/skl-topology.h | 32 ++-- sound/soc/intel/skylake/skl.c | 54 +++--- sound/soc/intel/skylake/skl.h | 94 +++++++--- 19 files changed, 545 insertions(+), 572 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index c6779e2ac830..ef38600e88f7 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h @@ -35,6 +35,7 @@ struct ipc_message { }; struct sst_generic_ipc; +struct sst_dsp; struct sst_plat_ipc_ops { void (*tx_msg)(struct sst_generic_ipc *, struct ipc_message *); diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 46d5159cf905..92a82e6b5fe6 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -14,7 +14,7 @@ #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" -#include "skl-sst-ipc.h" +#include "skl.h" #define BXT_BASEFW_TIMEOUT 3000 #define BXT_INIT_TIMEOUT 300 @@ -49,7 +49,7 @@ static int bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) { struct snd_dma_buffer dmab; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; struct firmware stripped_fw; int ret = 0, i, dma_id, stream_tag; @@ -184,7 +184,7 @@ static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) static int bxt_load_base_firmware(struct sst_dsp *ctx) { struct firmware stripped_fw; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; int ret, i; if (ctx->fw == NULL) { @@ -268,7 +268,7 @@ sst_load_base_firmware_failed: */ static int bxt_d0i3_target_state(struct sst_dsp *ctx) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; struct skl_d0i3_data *d0i3 = &skl->d0i3; if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING) @@ -288,8 +288,8 @@ static void bxt_set_dsp_D0i3(struct work_struct *work) { int ret; struct skl_ipc_d0ix_msg msg; - struct skl_sst *skl = container_of(work, - struct skl_sst, d0i3.work.work); + struct skl_dev *skl = container_of(work, + struct skl_dev, d0i3.work.work); struct sst_dsp *ctx = skl->dsp; struct skl_d0i3_data *d0i3 = &skl->d0i3; int target_state; @@ -331,7 +331,7 @@ static void bxt_set_dsp_D0i3(struct work_struct *work) static int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; struct skl_d0i3_data *d0i3 = &skl->d0i3; /* Schedule D0i3 only if the usecase ref counts are appropriate */ @@ -350,7 +350,7 @@ static int bxt_set_dsp_D0i0(struct sst_dsp *ctx) { int ret; struct skl_ipc_d0ix_msg msg; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; dev_dbg(ctx->dev, "In %s:\n", __func__); @@ -389,7 +389,7 @@ static int bxt_set_dsp_D0i0(struct sst_dsp *ctx) static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; int ret; struct skl_ipc_dxstate_info dx; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); @@ -486,7 +486,7 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) { int ret; struct skl_ipc_dxstate_info dx; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); dx.core_mask = core_mask; @@ -548,9 +548,9 @@ static struct sst_dsp_device skl_dev = { int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_sst **dsp) + struct skl_dev **dsp) { - struct skl_sst *skl; + struct skl_dev *skl; struct sst_dsp *sst; int ret; @@ -591,10 +591,10 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, } EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); -int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx) +int bxt_sst_init_fw(struct device *dev, struct skl_dev *skl) { int ret; - struct sst_dsp *sst = ctx->dsp; + struct sst_dsp *sst = skl->dsp; ret = sst->fw_ops.load_fw(sst); if (ret < 0) { @@ -604,29 +604,29 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx) skl_dsp_init_core_state(sst); - if (ctx->lib_count > 1) { - ret = sst->fw_ops.load_library(sst, ctx->lib_info, - ctx->lib_count); + if (skl->lib_count > 1) { + ret = sst->fw_ops.load_library(sst, skl->lib_info, + skl->lib_count); if (ret < 0) { dev_err(dev, "Load Library failed : %x\n", ret); return ret; } } - ctx->is_first_boot = false; + skl->is_first_boot = false; return 0; } EXPORT_SYMBOL_GPL(bxt_sst_init_fw); -void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) +void bxt_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) { - skl_release_library(ctx->lib_info, ctx->lib_count); - if (ctx->dsp->fw) - release_firmware(ctx->dsp->fw); - skl_freeup_uuid_list(ctx); - skl_ipc_free(&ctx->ipc); - ctx->dsp->ops->free(ctx->dsp); + skl_release_library(skl->lib_info, skl->lib_count); + if (skl->dsp->fw) + release_firmware(skl->dsp->fw); + skl_freeup_uuid_list(skl); + skl_ipc_free(&skl->ipc); + skl->dsp->ops->free(skl->dsp); } EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup); diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.h b/sound/soc/intel/skylake/cnl-sst-dsp.h index 426515faab52..7bd4d2a8fdfa 100644 --- a/sound/soc/intel/skylake/cnl-sst-dsp.h +++ b/sound/soc/intel/skylake/cnl-sst-dsp.h @@ -9,7 +9,6 @@ #define __CNL_SST_DSP_H__ struct sst_dsp; -struct skl_sst; struct sst_dsp_device; struct sst_generic_ipc; @@ -97,8 +96,8 @@ void cnl_ipc_free(struct sst_generic_ipc *ipc); int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_sst **dsp); -int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx); -void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); + struct skl_dev **dsp); +int cnl_sst_init_fw(struct device *dev, struct skl_dev *skl); +void cnl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl); #endif /*__CNL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c index f2c09fa6ea40..2d748a335bcf 100644 --- a/sound/soc/intel/skylake/cnl-sst.c +++ b/sound/soc/intel/skylake/cnl-sst.c @@ -24,8 +24,7 @@ #include "../common/sst-dsp-priv.h" #include "../common/sst-ipc.h" #include "cnl-sst-dsp.h" -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" +#include "skl.h" #define CNL_FW_ROM_INIT 0x1 #define CNL_FW_INIT 0x5 @@ -109,7 +108,7 @@ static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) static int cnl_load_base_firmware(struct sst_dsp *ctx) { struct firmware stripped_fw; - struct skl_sst *cnl = ctx->thread_context; + struct skl_dev *cnl = ctx->thread_context; int ret; if (!ctx->fw) { @@ -167,7 +166,7 @@ cnl_load_base_firmware_failed: static int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) { - struct skl_sst *cnl = ctx->thread_context; + struct skl_dev *cnl = ctx->thread_context; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); struct skl_ipc_dxstate_info dx; int ret; @@ -229,7 +228,7 @@ err: static int cnl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) { - struct skl_sst *cnl = ctx->thread_context; + struct skl_dev *cnl = ctx->thread_context; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); struct skl_ipc_dxstate_info dx; int ret; @@ -293,7 +292,7 @@ static struct sst_ops cnl_ops = { static irqreturn_t cnl_dsp_irq_thread_handler(int irq, void *context) { struct sst_dsp *dsp = context; - struct skl_sst *cnl = sst_dsp_get_thread_context(dsp); + struct skl_dev *cnl = sst_dsp_get_thread_context(dsp); struct sst_generic_ipc *ipc = &cnl->ipc; struct skl_ipc_header header = {0}; u32 hipcida, hipctdr, hipctdd; @@ -386,7 +385,7 @@ static bool cnl_ipc_is_dsp_busy(struct sst_dsp *dsp) return (hipcidr & CNL_ADSP_REG_HIPCIDR_BUSY); } -static int cnl_ipc_init(struct device *dev, struct skl_sst *cnl) +static int cnl_ipc_init(struct device *dev, struct skl_dev *cnl) { struct sst_generic_ipc *ipc; int err; @@ -415,9 +414,9 @@ static int cnl_ipc_init(struct device *dev, struct skl_sst *cnl) int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_sst **dsp) + struct skl_dev **dsp) { - struct skl_sst *cnl; + struct skl_dev *cnl; struct sst_dsp *sst; int ret; @@ -454,12 +453,12 @@ int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, } EXPORT_SYMBOL_GPL(cnl_sst_dsp_init); -int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx) +int cnl_sst_init_fw(struct device *dev, struct skl_dev *skl) { int ret; - struct sst_dsp *sst = ctx->dsp; + struct sst_dsp *sst = skl->dsp; - ret = ctx->dsp->fw_ops.load_fw(sst); + ret = skl->dsp->fw_ops.load_fw(sst); if (ret < 0) { dev_err(dev, "load base fw failed: %d", ret); return ret; @@ -467,21 +466,21 @@ int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx) skl_dsp_init_core_state(sst); - ctx->is_first_boot = false; + skl->is_first_boot = false; return 0; } EXPORT_SYMBOL_GPL(cnl_sst_init_fw); -void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) +void cnl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) { - if (ctx->dsp->fw) - release_firmware(ctx->dsp->fw); + if (skl->dsp->fw) + release_firmware(skl->dsp->fw); - skl_freeup_uuid_list(ctx); - cnl_ipc_free(&ctx->ipc); + skl_freeup_uuid_list(skl); + cnl_ipc_free(&skl->ipc); - ctx->dsp->ops->free(ctx->dsp); + skl->dsp->ops->free(skl->dsp); } EXPORT_SYMBOL_GPL(cnl_sst_dsp_cleanup); diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c index b9b4a72a4334..c43aa4081232 100644 --- a/sound/soc/intel/skylake/skl-debug.c +++ b/sound/soc/intel/skylake/skl-debug.c @@ -20,7 +20,7 @@ #define FW_REG_SIZE 0x60 struct skl_debug { - struct skl *skl; + struct skl_dev *skl; struct device *dev; struct dentry *fs; @@ -172,7 +172,7 @@ static ssize_t fw_softreg_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct skl_debug *d = file->private_data; - struct sst_dsp *sst = d->skl->skl_sst->dsp; + struct sst_dsp *sst = d->skl->dsp; size_t w0_stat_sz = sst->addr.w0_stat_sz; void __iomem *in_base = sst->mailbox.in_base; void __iomem *fw_reg_addr; @@ -213,7 +213,7 @@ static const struct file_operations soft_regs_ctrl_fops = { .llseek = default_llseek, }; -struct skl_debug *skl_debugfs_init(struct skl *skl) +struct skl_debug *skl_debugfs_init(struct skl_dev *skl) { struct skl_debug *d; @@ -252,7 +252,7 @@ err: return NULL; } -void skl_debugfs_exit(struct skl *skl) +void skl_debugfs_exit(struct skl_dev *skl) { struct skl_debug *d = skl->debugfs; diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index febc070839e0..f604d9c6824d 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -47,7 +47,7 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) #define SKL_ASTATE_PARAM_ID 4 -void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data) +void skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data) { struct skl_ipc_large_config_msg msg = {0}; @@ -55,14 +55,14 @@ void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data) msg.param_data_size = (cnt * sizeof(struct skl_astate_param) + sizeof(cnt)); - skl_ipc_set_large_config(&ctx->ipc, &msg, data); + skl_ipc_set_large_config(&skl->ipc, &msg, data); } #define NOTIFICATION_PARAM_ID 3 #define NOTIFICATION_MASK 0xf /* disable notfication for underruns/overruns from firmware module */ -void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable) +void skl_dsp_enable_notification(struct skl_dev *skl, bool enable) { struct notification_mask mask; struct skl_ipc_large_config_msg msg = {0}; @@ -73,7 +73,7 @@ void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable) msg.large_param_id = NOTIFICATION_PARAM_ID; msg.param_data_size = sizeof(mask); - skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)&mask); + skl_ipc_set_large_config(&skl->ipc, &msg, (u32 *)&mask); } static int skl_dsp_setup_spib(struct device *dev, unsigned int size, @@ -277,7 +277,7 @@ const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) return NULL; } -int skl_init_dsp(struct skl *skl) +int skl_init_dsp(struct skl_dev *skl) { void __iomem *mmio_base; struct hdac_bus *bus = skl_to_bus(skl); @@ -307,13 +307,13 @@ int skl_init_dsp(struct skl *skl) loader_ops = ops->loader_ops(); ret = ops->init(bus->dev, mmio_base, irq, skl->fw_name, loader_ops, - &skl->skl_sst); + &skl); if (ret < 0) goto unmap_mmio; - skl->skl_sst->dsp_ops = ops; - cores = &skl->skl_sst->cores; + skl->dsp_ops = ops; + cores = &skl->cores; cores->count = ops->num_cores; cores->state = kcalloc(cores->count, sizeof(*cores->state), GFP_KERNEL); @@ -342,21 +342,20 @@ unmap_mmio: return ret; } -int skl_free_dsp(struct skl *skl) +int skl_free_dsp(struct skl_dev *skl) { struct hdac_bus *bus = skl_to_bus(skl); - struct skl_sst *ctx = skl->skl_sst; /* disable ppcap interrupt */ snd_hdac_ext_bus_ppcap_int_enable(bus, false); - ctx->dsp_ops->cleanup(bus->dev, ctx); + skl->dsp_ops->cleanup(bus->dev, skl); - kfree(ctx->cores.state); - kfree(ctx->cores.usage_count); + kfree(skl->cores.state); + kfree(skl->cores.usage_count); - if (ctx->dsp->addr.lpe) - iounmap(ctx->dsp->addr.lpe); + if (skl->dsp->addr.lpe) + iounmap(skl->dsp->addr.lpe); return 0; } @@ -368,15 +367,14 @@ int skl_free_dsp(struct skl *skl) * mode during system suspend. In the case of normal suspend, cancel * any pending D0i3 work. */ -int skl_suspend_late_dsp(struct skl *skl) +int skl_suspend_late_dsp(struct skl_dev *skl) { - struct skl_sst *ctx = skl->skl_sst; struct delayed_work *dwork; - if (!ctx) + if (!skl) return 0; - dwork = &ctx->d0i3.work; + dwork = &skl->d0i3.work; if (dwork->work.func) { if (skl->supend_active) @@ -388,9 +386,8 @@ int skl_suspend_late_dsp(struct skl *skl) return 0; } -int skl_suspend_dsp(struct skl *skl) +int skl_suspend_dsp(struct skl_dev *skl) { - struct skl_sst *ctx = skl->skl_sst; struct hdac_bus *bus = skl_to_bus(skl); int ret; @@ -398,7 +395,7 @@ int skl_suspend_dsp(struct skl *skl) if (!bus->ppcap) return 0; - ret = skl_dsp_sleep(ctx->dsp); + ret = skl_dsp_sleep(skl->dsp); if (ret < 0) return ret; @@ -409,9 +406,8 @@ int skl_suspend_dsp(struct skl *skl) return 0; } -int skl_resume_dsp(struct skl *skl) +int skl_resume_dsp(struct skl_dev *skl) { - struct skl_sst *ctx = skl->skl_sst; struct hdac_bus *bus = skl_to_bus(skl); int ret; @@ -424,26 +420,26 @@ int skl_resume_dsp(struct skl *skl) snd_hdac_ext_bus_ppcap_int_enable(bus, true); /* check if DSP 1st boot is done */ - if (skl->skl_sst->is_first_boot) + if (skl->is_first_boot) return 0; /* * Disable dynamic clock and power gating during firmware * and library download */ - ctx->enable_miscbdcge(ctx->dev, false); - ctx->clock_power_gating(ctx->dev, false); + skl->enable_miscbdcge(skl->dev, false); + skl->clock_power_gating(skl->dev, false); - ret = skl_dsp_wake(ctx->dsp); - ctx->enable_miscbdcge(ctx->dev, true); - ctx->clock_power_gating(ctx->dev, true); + ret = skl_dsp_wake(skl->dsp); + skl->enable_miscbdcge(skl->dev, true); + skl->clock_power_gating(skl->dev, true); if (ret < 0) return ret; - skl_dsp_enable_notification(skl->skl_sst, false); + skl_dsp_enable_notification(skl, false); if (skl->cfg.astate_cfg != NULL) { - skl_dsp_set_astate_cfg(skl->skl_sst, skl->cfg.astate_cfg->count, + skl_dsp_set_astate_cfg(skl, skl->cfg.astate_cfg->count, skl->cfg.astate_cfg); } return ret; @@ -476,7 +472,7 @@ enum skl_bitdepth skl_get_bit_depth(int params) * which are read from widget information passed through topology binary * This is send when we create a module with INIT_INSTANCE IPC msg */ -static void skl_set_base_module_format(struct skl_sst *ctx, +static void skl_set_base_module_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_base_cfg *base_cfg) { @@ -493,7 +489,7 @@ static void skl_set_base_module_format(struct skl_sst *ctx, base_cfg->audio_fmt.ch_cfg = format->ch_cfg; base_cfg->audio_fmt.sample_type = format->sample_type; - dev_dbg(ctx->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n", + dev_dbg(skl->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n", format->bit_depth, format->valid_bit_depth, format->ch_cfg); @@ -530,7 +526,7 @@ static void skl_copy_copier_caps(struct skl_module_cfg *mconfig, * Calculate the gatewat settings required for copier module, type of * gateway and index of gateway to use */ -static u32 skl_get_node_id(struct skl_sst *ctx, +static u32 skl_get_node_id(struct skl_dev *skl, struct skl_module_cfg *mconfig) { union skl_connector_node_id node_id = {0}; @@ -587,16 +583,15 @@ static u32 skl_get_node_id(struct skl_sst *ctx, return node_id.val; } -static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, +static void skl_setup_cpr_gateway_cfg(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_cpr_cfg *cpr_mconfig) { u32 dma_io_buf; struct skl_module_res *res; int res_idx = mconfig->res_idx; - struct skl *skl = get_skl_ctx(ctx->dev); - cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig); + cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(skl, mconfig); if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) { cpr_mconfig->cpr_feature_mask = 0; @@ -627,7 +622,7 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, break; default: - dev_warn(ctx->dev, "wrong connection type: %d\n", + dev_warn(skl->dev, "wrong connection type: %d\n", mconfig->hw_conn_type); return; } @@ -653,7 +648,7 @@ skip_buf_size_calc: #define DMA_CONTROL_ID 5 #define DMA_I2S_BLOB_SIZE 21 -int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps, +int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, u32 caps_size, u32 node_id) { struct skl_dma_control *dma_ctrl; @@ -686,14 +681,14 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps, memcpy(dma_ctrl->config_data, caps, caps_size); - err = skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)dma_ctrl); + err = skl_ipc_set_large_config(&skl->ipc, &msg, (u32 *)dma_ctrl); kfree(dma_ctrl); return err; } EXPORT_SYMBOL_GPL(skl_dsp_set_dma_control); -static void skl_setup_out_format(struct skl_sst *ctx, +static void skl_setup_out_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_audio_data_format *out_fmt) { @@ -711,7 +706,7 @@ static void skl_setup_out_format(struct skl_sst *ctx, out_fmt->interleaving = format->interleaving_style; out_fmt->sample_type = format->sample_type; - dev_dbg(ctx->dev, "copier out format chan=%d fre=%d bitdepth=%d\n", + dev_dbg(skl->dev, "copier out format chan=%d fre=%d bitdepth=%d\n", out_fmt->number_of_channels, format->s_freq, format->bit_depth); } @@ -720,7 +715,7 @@ static void skl_setup_out_format(struct skl_sst *ctx, * configuration and the target frequency as extra parameter passed as src * config */ -static void skl_set_src_format(struct skl_sst *ctx, +static void skl_set_src_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_src_module_cfg *src_mconfig) { @@ -728,7 +723,7 @@ static void skl_set_src_format(struct skl_sst *ctx, struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx]; struct skl_module_fmt *fmt = &iface->outputs[0].fmt; - skl_set_base_module_format(ctx, mconfig, + skl_set_base_module_format(skl, mconfig, (struct skl_base_cfg *)src_mconfig); src_mconfig->src_cfg = fmt->s_freq; @@ -739,7 +734,7 @@ static void skl_set_src_format(struct skl_sst *ctx, * module configuration and channel configuration * It also take coefficients and now we have defaults applied here */ -static void skl_set_updown_mixer_format(struct skl_sst *ctx, +static void skl_set_updown_mixer_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_up_down_mixer_cfg *mixer_mconfig) { @@ -747,7 +742,7 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx, struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx]; struct skl_module_fmt *fmt = &iface->outputs[0].fmt; - skl_set_base_module_format(ctx, mconfig, + skl_set_base_module_format(skl, mconfig, (struct skl_base_cfg *)mixer_mconfig); mixer_mconfig->out_ch_cfg = fmt->ch_cfg; mixer_mconfig->ch_map = fmt->ch_map; @@ -760,17 +755,17 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx, * format, gateway settings * copier_module_config is sent as input buffer with INIT_INSTANCE IPC msg */ -static void skl_set_copier_format(struct skl_sst *ctx, +static void skl_set_copier_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_cpr_cfg *cpr_mconfig) { struct skl_audio_data_format *out_fmt = &cpr_mconfig->out_fmt; struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)cpr_mconfig; - skl_set_base_module_format(ctx, mconfig, base_cfg); + skl_set_base_module_format(skl, mconfig, base_cfg); - skl_setup_out_format(ctx, mconfig, out_fmt); - skl_setup_cpr_gateway_cfg(ctx, mconfig, cpr_mconfig); + skl_setup_out_format(skl, mconfig, out_fmt); + skl_setup_cpr_gateway_cfg(skl, mconfig, cpr_mconfig); } /* @@ -778,13 +773,13 @@ static void skl_set_copier_format(struct skl_sst *ctx, * configuration and params */ -static void skl_set_algo_format(struct skl_sst *ctx, +static void skl_set_algo_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_algo_cfg *algo_mcfg) { struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)algo_mcfg; - skl_set_base_module_format(ctx, mconfig, base_cfg); + skl_set_base_module_format(skl, mconfig, base_cfg); if (mconfig->formats_config.caps_size == 0) return; @@ -802,7 +797,7 @@ static void skl_set_algo_format(struct skl_sst *ctx, * Mic select module take base module configuration and out-format * configuration */ -static void skl_set_base_outfmt_format(struct skl_sst *ctx, +static void skl_set_base_outfmt_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_base_outfmt_cfg *base_outfmt_mcfg) { @@ -810,11 +805,11 @@ static void skl_set_base_outfmt_format(struct skl_sst *ctx, struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)base_outfmt_mcfg; - skl_set_base_module_format(ctx, mconfig, base_cfg); - skl_setup_out_format(ctx, mconfig, out_fmt); + skl_set_base_module_format(skl, mconfig, base_cfg); + skl_setup_out_format(skl, mconfig, out_fmt); } -static u16 skl_get_module_param_size(struct skl_sst *ctx, +static u16 skl_get_module_param_size(struct skl_dev *skl, struct skl_module_cfg *mconfig) { u16 param_size; @@ -859,14 +854,14 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx, * base module format configuration */ -static int skl_set_module_format(struct skl_sst *ctx, +static int skl_set_module_format(struct skl_dev *skl, struct skl_module_cfg *module_config, u16 *module_config_size, void **param_data) { u16 param_size; - param_size = skl_get_module_param_size(ctx, module_config); + param_size = skl_get_module_param_size(skl, module_config); *param_data = kzalloc(param_size, GFP_KERNEL); if (NULL == *param_data) @@ -876,34 +871,34 @@ static int skl_set_module_format(struct skl_sst *ctx, switch (module_config->m_type) { case SKL_MODULE_TYPE_COPIER: - skl_set_copier_format(ctx, module_config, *param_data); + skl_set_copier_format(skl, module_config, *param_data); break; case SKL_MODULE_TYPE_SRCINT: - skl_set_src_format(ctx, module_config, *param_data); + skl_set_src_format(skl, module_config, *param_data); break; case SKL_MODULE_TYPE_UPDWMIX: - skl_set_updown_mixer_format(ctx, module_config, *param_data); + skl_set_updown_mixer_format(skl, module_config, *param_data); break; case SKL_MODULE_TYPE_ALGO: - skl_set_algo_format(ctx, module_config, *param_data); + skl_set_algo_format(skl, module_config, *param_data); break; case SKL_MODULE_TYPE_BASE_OUTFMT: case SKL_MODULE_TYPE_MIC_SELECT: case SKL_MODULE_TYPE_KPB: - skl_set_base_outfmt_format(ctx, module_config, *param_data); + skl_set_base_outfmt_format(skl, module_config, *param_data); break; default: - skl_set_base_module_format(ctx, module_config, *param_data); + skl_set_base_module_format(skl, module_config, *param_data); break; } - dev_dbg(ctx->dev, "Module type=%d config size: %d bytes\n", + dev_dbg(skl->dev, "Module type=%d config size: %d bytes\n", module_config->id.module_id, param_size); print_hex_dump_debug("Module params:", DUMP_PREFIX_OFFSET, 8, 4, *param_data, param_size, false); @@ -1004,7 +999,7 @@ static void skl_clear_module_state(struct skl_module_pin *mpin, int max, * We first calculate the module format, based on module type and then * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper */ -int skl_init_module(struct skl_sst *ctx, +int skl_init_module(struct skl_dev *skl, struct skl_module_cfg *mconfig) { u16 module_config_size = 0; @@ -1012,19 +1007,19 @@ int skl_init_module(struct skl_sst *ctx, int ret; struct skl_ipc_init_instance_msg msg; - dev_dbg(ctx->dev, "%s: module_id = %d instance=%d\n", __func__, + dev_dbg(skl->dev, "%s: module_id = %d instance=%d\n", __func__, mconfig->id.module_id, mconfig->id.pvt_id); if (mconfig->pipe->state != SKL_PIPE_CREATED) { - dev_err(ctx->dev, "Pipe not created state= %d pipe_id= %d\n", + dev_err(skl->dev, "Pipe not created state= %d pipe_id= %d\n", mconfig->pipe->state, mconfig->pipe->ppl_id); return -EIO; } - ret = skl_set_module_format(ctx, mconfig, + ret = skl_set_module_format(skl, mconfig, &module_config_size, ¶m_data); if (ret < 0) { - dev_err(ctx->dev, "Failed to set module format ret=%d\n", ret); + dev_err(skl->dev, "Failed to set module format ret=%d\n", ret); return ret; } @@ -1035,9 +1030,9 @@ int skl_init_module(struct skl_sst *ctx, msg.core_id = mconfig->core_id; msg.domain = mconfig->domain; - ret = skl_ipc_init_instance(&ctx->ipc, &msg, param_data); + ret = skl_ipc_init_instance(&skl->ipc, &msg, param_data); if (ret < 0) { - dev_err(ctx->dev, "Failed to init instance ret=%d\n", ret); + dev_err(skl->dev, "Failed to init instance ret=%d\n", ret); kfree(param_data); return ret; } @@ -1046,15 +1041,15 @@ int skl_init_module(struct skl_sst *ctx, return ret; } -static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg +static void skl_dump_bind_info(struct skl_dev *skl, struct skl_module_cfg *src_module, struct skl_module_cfg *dst_module) { - dev_dbg(ctx->dev, "%s: src module_id = %d src_instance=%d\n", + dev_dbg(skl->dev, "%s: src module_id = %d src_instance=%d\n", __func__, src_module->id.module_id, src_module->id.pvt_id); - dev_dbg(ctx->dev, "%s: dst_module=%d dst_instance=%d\n", __func__, + dev_dbg(skl->dev, "%s: dst_module=%d dst_instance=%d\n", __func__, dst_module->id.module_id, dst_module->id.pvt_id); - dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n", + dev_dbg(skl->dev, "src_module state = %d dst module state = %d\n", src_module->m_state, dst_module->m_state); } @@ -1063,7 +1058,7 @@ static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg * it is already bind. * Find the pin allocated and unbind then using bind_unbind IPC */ -int skl_unbind_modules(struct skl_sst *ctx, +int skl_unbind_modules(struct skl_dev *skl, struct skl_module_cfg *src_mcfg, struct skl_module_cfg *dst_mcfg) { @@ -1075,7 +1070,7 @@ int skl_unbind_modules(struct skl_sst *ctx, int out_max = src_mcfg->module->max_output_pins; int src_index, dst_index, src_pin_state, dst_pin_state; - skl_dump_bind_info(ctx, src_mcfg, dst_mcfg); + skl_dump_bind_info(skl, src_mcfg, dst_mcfg); /* get src queue index */ src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max); @@ -1104,7 +1099,7 @@ int skl_unbind_modules(struct skl_sst *ctx, msg.dst_instance_id = dst_mcfg->id.pvt_id; msg.bind = false; - ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); + ret = skl_ipc_bind_unbind(&skl->ipc, &msg); if (!ret) { /* free queue only if unbind is success */ skl_free_queue(src_mcfg->m_out_pin, src_index); @@ -1142,7 +1137,7 @@ static void fill_pin_params(struct skl_audio_data_format *pin_fmt, * This function finds the pins and then sends bund_unbind IPC message to * DSP using IPC helper */ -int skl_bind_modules(struct skl_sst *ctx, +int skl_bind_modules(struct skl_dev *skl, struct skl_module_cfg *src_mcfg, struct skl_module_cfg *dst_mcfg) { @@ -1156,7 +1151,7 @@ int skl_bind_modules(struct skl_sst *ctx, struct skl_module *module; struct skl_module_iface *fmt; - skl_dump_bind_info(ctx, src_mcfg, dst_mcfg); + skl_dump_bind_info(skl, src_mcfg, dst_mcfg); if (src_mcfg->m_state < SKL_MODULE_INIT_DONE || dst_mcfg->m_state < SKL_MODULE_INIT_DONE) @@ -1188,7 +1183,7 @@ int skl_bind_modules(struct skl_sst *ctx, format = &fmt->outputs[src_index].fmt; fill_pin_params(&(pin_fmt.dst_fmt), format); - ret = skl_set_module_params(ctx, (void *)&pin_fmt, + ret = skl_set_module_params(skl, (void *)&pin_fmt, sizeof(struct skl_cpr_pin_fmt), CPR_SINK_FMT_PARAM_ID, src_mcfg); @@ -1198,7 +1193,7 @@ int skl_bind_modules(struct skl_sst *ctx, msg.dst_queue = dst_index; - dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n", + dev_dbg(skl->dev, "src queue = %d dst queue =%d\n", msg.src_queue, msg.dst_queue); msg.module_id = src_mcfg->id.module_id; @@ -1207,7 +1202,7 @@ int skl_bind_modules(struct skl_sst *ctx, msg.dst_instance_id = dst_mcfg->id.pvt_id; msg.bind = true; - ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); + ret = skl_ipc_bind_unbind(&skl->ipc, &msg); if (!ret) { src_mcfg->m_state = SKL_MODULE_BIND_DONE; @@ -1223,12 +1218,12 @@ out: return ret; } -static int skl_set_pipe_state(struct skl_sst *ctx, struct skl_pipe *pipe, +static int skl_set_pipe_state(struct skl_dev *skl, struct skl_pipe *pipe, enum skl_ipc_pipeline_state state) { - dev_dbg(ctx->dev, "%s: pipe_state = %d\n", __func__, state); + dev_dbg(skl->dev, "%s: pipe_state = %d\n", __func__, state); - return skl_ipc_set_pipeline_state(&ctx->ipc, pipe->ppl_id, state); + return skl_ipc_set_pipeline_state(&skl->ipc, pipe->ppl_id, state); } /* @@ -1237,17 +1232,17 @@ static int skl_set_pipe_state(struct skl_sst *ctx, struct skl_pipe *pipe, * This function creates pipeline, by sending create pipeline IPC messages * to FW */ -int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe) +int skl_create_pipeline(struct skl_dev *skl, struct skl_pipe *pipe) { int ret; - dev_dbg(ctx->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id); + dev_dbg(skl->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id); - ret = skl_ipc_create_pipeline(&ctx->ipc, pipe->memory_pages, + ret = skl_ipc_create_pipeline(&skl->ipc, pipe->memory_pages, pipe->pipe_priority, pipe->ppl_id, pipe->lp_mode); if (ret < 0) { - dev_err(ctx->dev, "Failed to create pipeline\n"); + dev_err(skl->dev, "Failed to create pipeline\n"); return ret; } @@ -1262,11 +1257,11 @@ int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe) * reset state. Finish the procedure by sending delete pipeline IPC. * DSP will stop the DMA engines and release resources */ -int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) +int skl_delete_pipe(struct skl_dev *skl, struct skl_pipe *pipe) { int ret; - dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); + dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); /* If pipe was not created in FW, do not try to delete it */ if (pipe->state < SKL_PIPE_CREATED) @@ -1274,9 +1269,9 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) /* If pipe is started, do stop the pipe in FW. */ if (pipe->state >= SKL_PIPE_STARTED) { - ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); + ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); if (ret < 0) { - dev_err(ctx->dev, "Failed to stop pipeline\n"); + dev_err(skl->dev, "Failed to stop pipeline\n"); return ret; } @@ -1284,17 +1279,17 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) } /* reset pipe state before deletion */ - ret = skl_set_pipe_state(ctx, pipe, PPL_RESET); + ret = skl_set_pipe_state(skl, pipe, PPL_RESET); if (ret < 0) { - dev_err(ctx->dev, "Failed to reset pipe ret=%d\n", ret); + dev_err(skl->dev, "Failed to reset pipe ret=%d\n", ret); return ret; } pipe->state = SKL_PIPE_RESET; - ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id); + ret = skl_ipc_delete_pipeline(&skl->ipc, pipe->ppl_id); if (ret < 0) { - dev_err(ctx->dev, "Failed to delete pipeline\n"); + dev_err(skl->dev, "Failed to delete pipeline\n"); return ret; } @@ -1308,28 +1303,28 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) * For processing data the pipe need to be run by sending IPC set pipe state * to DSP */ -int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) +int skl_run_pipe(struct skl_dev *skl, struct skl_pipe *pipe) { int ret; - dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); + dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); /* If pipe was not created in FW, do not try to pause or delete */ if (pipe->state < SKL_PIPE_CREATED) return 0; /* Pipe has to be paused before it is started */ - ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); + ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); if (ret < 0) { - dev_err(ctx->dev, "Failed to pause pipe\n"); + dev_err(skl->dev, "Failed to pause pipe\n"); return ret; } pipe->state = SKL_PIPE_PAUSED; - ret = skl_set_pipe_state(ctx, pipe, PPL_RUNNING); + ret = skl_set_pipe_state(skl, pipe, PPL_RUNNING); if (ret < 0) { - dev_err(ctx->dev, "Failed to start pipe\n"); + dev_err(skl->dev, "Failed to start pipe\n"); return ret; } @@ -1342,19 +1337,19 @@ int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) * Stop the pipeline by sending set pipe state IPC * DSP doesnt implement stop so we always send pause message */ -int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) +int skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe) { int ret; - dev_dbg(ctx->dev, "In %s pipe=%d\n", __func__, pipe->ppl_id); + dev_dbg(skl->dev, "In %s pipe=%d\n", __func__, pipe->ppl_id); /* If pipe was not created in FW, do not try to pause or delete */ if (pipe->state < SKL_PIPE_PAUSED) return 0; - ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); + ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); if (ret < 0) { - dev_dbg(ctx->dev, "Failed to stop pipe\n"); + dev_dbg(skl->dev, "Failed to stop pipe\n"); return ret; } @@ -1367,7 +1362,7 @@ int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) * Reset the pipeline by sending set pipe state IPC this will reset the DMA * from the DSP side */ -int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) +int skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe) { int ret; @@ -1375,9 +1370,9 @@ int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) if (pipe->state < SKL_PIPE_PAUSED) return 0; - ret = skl_set_pipe_state(ctx, pipe, PPL_RESET); + ret = skl_set_pipe_state(skl, pipe, PPL_RESET); if (ret < 0) { - dev_dbg(ctx->dev, "Failed to reset pipe ret=%d\n", ret); + dev_dbg(skl->dev, "Failed to reset pipe ret=%d\n", ret); return ret; } @@ -1387,7 +1382,7 @@ int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) } /* Algo parameter set helper function */ -int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, +int skl_set_module_params(struct skl_dev *skl, u32 *params, int size, u32 param_id, struct skl_module_cfg *mcfg) { struct skl_ipc_large_config_msg msg; @@ -1397,10 +1392,10 @@ int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, msg.param_data_size = size; msg.large_param_id = param_id; - return skl_ipc_set_large_config(&ctx->ipc, &msg, params); + return skl_ipc_set_large_config(&skl->ipc, &msg, params); } -int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, +int skl_get_module_params(struct skl_dev *skl, u32 *params, int size, u32 param_id, struct skl_module_cfg *mcfg) { struct skl_ipc_large_config_msg msg; @@ -1410,5 +1405,5 @@ int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, msg.param_data_size = size; msg.large_param_id = param_id; - return skl_ipc_get_large_config(&ctx->ipc, &msg, params); + return skl_ipc_get_large_config(&skl->ipc, &msg, params); } diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 1132109cb992..6fc3a190067e 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -126,7 +126,7 @@ static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt, } struct nhlt_specific_cfg -*skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, +*skl_get_ep_blob(struct skl_dev *skl, u32 instance, u8 link_type, u8 s_fmt, u8 num_ch, u32 s_rate, u8 dirn, u8 dev_type) { @@ -162,7 +162,7 @@ struct nhlt_specific_cfg return NULL; } -int skl_get_dmic_geo(struct skl *skl) +int skl_get_dmic_geo(struct skl_dev *skl) { struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; struct nhlt_endpoint *epnt; @@ -219,7 +219,7 @@ static void skl_nhlt_trim_space(char *trim) s[cnt] = '\0'; } -int skl_nhlt_update_topology_bin(struct skl *skl) +int skl_nhlt_update_topology_bin(struct skl_dev *skl) { struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; struct hdac_bus *bus = skl_to_bus(skl); @@ -243,7 +243,7 @@ static ssize_t skl_nhlt_platform_id_show(struct device *dev, { struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; char platform_id[32]; @@ -257,7 +257,7 @@ static ssize_t skl_nhlt_platform_id_show(struct device *dev, static DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL); -int skl_nhlt_create_sysfs(struct skl *skl) +int skl_nhlt_create_sysfs(struct skl_dev *skl) { struct device *dev = &skl->pci->dev; @@ -267,7 +267,7 @@ int skl_nhlt_create_sysfs(struct skl *skl) return 0; } -void skl_nhlt_remove_sysfs(struct skl *skl) +void skl_nhlt_remove_sysfs(struct skl_dev *skl) { struct device *dev = &skl->pci->dev; @@ -279,7 +279,7 @@ void skl_nhlt_remove_sysfs(struct skl *skl) * stores all possible rates supported in a rate table for the corresponding * sclk/sclkfs. */ -static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, +static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, struct nhlt_fmt *fmt, u8 id) { struct skl_i2s_config_blob_ext *i2s_config_ext; @@ -377,7 +377,7 @@ static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, } } -static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk, +static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk, struct nhlt_fmt *fmt, u8 id) { struct skl_i2s_config_blob_ext *i2s_config_ext; @@ -421,7 +421,7 @@ static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk, mclk[id].parent_name = parent->name; } -void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks) +void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks) { struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; struct nhlt_endpoint *epnt; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 760bbcf9a469..2ae5d09d7228 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -116,7 +116,7 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream, { struct hdac_bus *bus = dev_get_drvdata(dai->dev); struct snd_soc_dapm_widget *w; - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) w = dai->playback_widget; @@ -132,7 +132,7 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream, int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) { struct hdac_bus *bus = dev_get_drvdata(dev); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); unsigned int format_val; struct hdac_stream *hstream; struct hdac_ext_stream *stream; @@ -224,7 +224,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream; struct snd_pcm_runtime *runtime = substream->runtime; struct skl_dma_params *dma_params; - struct skl *skl = get_skl_ctx(dai->dev); + struct skl_dev *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -271,7 +271,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, static int skl_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct skl *skl = get_skl_ctx(dai->dev); + struct skl_dev *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig; int ret; @@ -288,7 +288,7 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream, mconfig->pipe->state == SKL_PIPE_CREATED || mconfig->pipe->state == SKL_PIPE_PAUSED)) { - ret = skl_reset_pipe(skl->skl_sst, mconfig->pipe); + ret = skl_reset_pipe(skl, mconfig->pipe); if (ret < 0) return ret; @@ -350,7 +350,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct hdac_bus *bus = dev_get_drvdata(dai->dev); struct skl_dma_params *dma_params = NULL; - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -370,9 +370,9 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, * CGCTL.MISCBDCGE if disabled by driver */ if (!strncmp(dai->name, "Reference Pin", 13) && - skl->skl_sst->miscbdcg_disabled) { - skl->skl_sst->enable_miscbdcge(dai->dev, true); - skl->skl_sst->miscbdcg_disabled = false; + skl->miscbdcg_disabled) { + skl->enable_miscbdcge(dai->dev, true); + skl->miscbdcg_disabled = false; } mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); @@ -387,7 +387,7 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream, { struct hdac_bus *bus = dev_get_drvdata(dai->dev); struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - struct skl *skl = get_skl_ctx(dai->dev); + struct skl_dev *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig; int ret; @@ -396,7 +396,7 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream, mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); if (mconfig) { - ret = skl_reset_pipe(skl->skl_sst, mconfig->pipe); + ret = skl_reset_pipe(skl, mconfig->pipe); if (ret < 0) dev_err(dai->dev, "%s:Reset failed ret =%d", __func__, ret); @@ -471,8 +471,7 @@ static int skl_decoupled_trigger(struct snd_pcm_substream *substream, static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct skl *skl = get_skl_ctx(dai->dev); - struct skl_sst *ctx = skl->skl_sst; + struct skl_dev *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig; struct hdac_bus *bus = get_bus_ctx(substream); struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); @@ -515,7 +514,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, ret = skl_decoupled_trigger(substream, cmd); if (ret < 0) return ret; - return skl_run_pipe(ctx, mconfig->pipe); + return skl_run_pipe(skl, mconfig->pipe); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -526,7 +525,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, * there are no underrun/overrun in the case if there is a delay * between the two operations. */ - ret = skl_stop_pipe(ctx, mconfig->pipe); + ret = skl_stop_pipe(skl, mconfig->pipe); if (ret < 0) return ret; @@ -602,14 +601,14 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct skl *skl = get_skl_ctx(dai->dev); + struct skl_dev *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig = NULL; /* In case of XRUN recovery, reset the FW pipe to clean state */ mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); if (mconfig && !mconfig->pipe->passthru && (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) - skl_reset_pipe(skl->skl_sst, mconfig->pipe); + skl_reset_pipe(skl, mconfig->pipe); return 0; } @@ -1301,7 +1300,7 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) struct hdac_bus *bus = dev_get_drvdata(dai->dev); struct snd_pcm *pcm = rtd->pcm; unsigned int size; - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); if (dai->driver->playback.channels_min || dai->driver->capture.channels_min) { @@ -1318,9 +1317,9 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) +static int skl_get_module_info(struct skl_dev *skl, + struct skl_module_cfg *mconfig) { - struct skl_sst *ctx = skl->skl_sst; struct skl_module_inst_id *pin_id; guid_t *uuid_mod, *uuid_tplg; struct skl_module *skl_module; @@ -1329,12 +1328,12 @@ static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) uuid_mod = (guid_t *)mconfig->guid; - if (list_empty(&ctx->uuid_list)) { - dev_err(ctx->dev, "Module list is empty\n"); + if (list_empty(&skl->uuid_list)) { + dev_err(skl->dev, "Module list is empty\n"); return -EIO; } - list_for_each_entry(module, &ctx->uuid_list, list) { + list_for_each_entry(module, &skl->uuid_list, list) { if (guid_equal(uuid_mod, &module->uuid)) { mconfig->id.module_id = module->id; if (mconfig->module) @@ -1361,7 +1360,7 @@ static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) if (skl->nr_modules && ret) return ret; - list_for_each_entry(module, &ctx->uuid_list, list) { + list_for_each_entry(module, &skl->uuid_list, list) { for (i = 0; i < MAX_IN_QUEUE; i++) { pin_id = &mconfig->m_in_pin[i].id; if (guid_equal(&pin_id->mod_uuid, &module->uuid)) @@ -1378,7 +1377,7 @@ static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) return 0; } -static int skl_populate_modules(struct skl *skl) +static int skl_populate_modules(struct skl_dev *skl) { struct skl_pipeline *p; struct skl_pipe_module *m; @@ -1393,7 +1392,7 @@ static int skl_populate_modules(struct skl *skl) ret = skl_get_module_info(skl, mconfig); if (ret < 0) { - dev_err(skl->skl_sst->dev, + dev_err(skl->dev, "query module info failed\n"); return ret; } @@ -1408,7 +1407,7 @@ static int skl_populate_modules(struct skl *skl) static int skl_platform_soc_probe(struct snd_soc_component *component) { struct hdac_bus *bus = dev_get_drvdata(component->dev); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); const struct skl_dsp_ops *ops; int ret; @@ -1434,22 +1433,22 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) * Disable dynamic clock and power gating during firmware * and library download */ - skl->skl_sst->enable_miscbdcge(component->dev, false); - skl->skl_sst->clock_power_gating(component->dev, false); + skl->enable_miscbdcge(component->dev, false); + skl->clock_power_gating(component->dev, false); - ret = ops->init_fw(component->dev, skl->skl_sst); - skl->skl_sst->enable_miscbdcge(component->dev, true); - skl->skl_sst->clock_power_gating(component->dev, true); + ret = ops->init_fw(component->dev, skl); + skl->enable_miscbdcge(component->dev, true); + skl->clock_power_gating(component->dev, true); if (ret < 0) { dev_err(component->dev, "Failed to boot first fw: %d\n", ret); return ret; } skl_populate_modules(skl); - skl->skl_sst->update_d0i3c = skl_update_d0i3c; - skl_dsp_enable_notification(skl->skl_sst, false); + skl->update_d0i3c = skl_update_d0i3c; + skl_dsp_enable_notification(skl, false); if (skl->cfg.astate_cfg != NULL) { - skl_dsp_set_astate_cfg(skl->skl_sst, + skl_dsp_set_astate_cfg(skl, skl->cfg.astate_cfg->count, skl->cfg.astate_cfg); } @@ -1463,7 +1462,7 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) static void skl_pcm_remove(struct snd_soc_component *component) { struct hdac_bus *bus = dev_get_drvdata(component->dev); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); skl_tplg_exit(component, bus); @@ -1486,7 +1485,7 @@ int skl_platform_register(struct device *dev) struct snd_soc_dai_driver *dais; int num_dais = ARRAY_SIZE(skl_platform_dai); struct hdac_bus *bus = dev_get_drvdata(dev); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); skl->dais = kmemdup(skl_platform_dai, sizeof(skl_platform_dai), GFP_KERNEL); @@ -1520,7 +1519,7 @@ err: int skl_platform_unregister(struct device *dev) { struct hdac_bus *bus = dev_get_drvdata(dev); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct skl_module_deferred_bind *modules, *tmp; if (!list_empty(&skl->bind_list)) { diff --git a/sound/soc/intel/skylake/skl-ssp-clk.c b/sound/soc/intel/skylake/skl-ssp-clk.c index 5bb6e40d4d3e..1608d21bcba1 100644 --- a/sound/soc/intel/skylake/skl-ssp-clk.c +++ b/sound/soc/intel/skylake/skl-ssp-clk.c @@ -101,7 +101,7 @@ static void skl_fill_clk_ipc(struct skl_clk_rate_cfg_table *rcfg, u8 clk_type) } /* Sends dma control IPC to turn the clock ON/OFF */ -static int skl_send_clk_dma_control(struct skl *skl, +static int skl_send_clk_dma_control(struct skl_dev *skl, struct skl_clk_rate_cfg_table *rcfg, u32 vbus_id, u8 clk_type, bool enable) @@ -152,7 +152,7 @@ static int skl_send_clk_dma_control(struct skl *skl, memcpy(i2s_config + sp_cfg->size, data, size); node_id = ((SKL_DMA_I2S_LINK_INPUT_CLASS << 8) | (vbus_id << 4)); - ret = skl_dsp_set_dma_control(skl->skl_sst, (u32 *)i2s_config, + ret = skl_dsp_set_dma_control(skl, (u32 *)i2s_config, i2s_config_size, node_id); kfree(i2s_config); diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index 36590c5b4673..225706d148d8 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -12,7 +12,7 @@ #include "../common/sst-dsp.h" #include "../common/sst-ipc.h" #include "../common/sst-dsp-priv.h" -#include "skl-sst-ipc.h" +#include "skl.h" /* various timeout values */ #define SKL_DSP_PU_TO 50 @@ -33,7 +33,7 @@ void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state) */ void skl_dsp_init_core_state(struct sst_dsp *ctx) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; int i; skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; @@ -48,7 +48,7 @@ void skl_dsp_init_core_state(struct sst_dsp *ctx) /* Get the mask for all enabled cores */ unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; unsigned int core_mask, en_cores_mask; u32 val; @@ -335,7 +335,7 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) */ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; int ret = 0; if (core_id >= skl->cores.count) { @@ -364,7 +364,7 @@ EXPORT_SYMBOL_GPL(skl_dsp_get_core); int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; int ret = 0; if (core_id >= skl->cores.count) { diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index a80219562036..ed968f1042c7 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -15,9 +15,9 @@ #include "skl-sst-cldma.h" struct sst_dsp; -struct skl_sst; struct sst_dsp_device; struct skl_lib_info; +struct skl_dev; /* Intel HD Audio General DSP Registers */ #define SKL_ADSP_GEN_BASE 0x0 @@ -222,32 +222,32 @@ int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id); int skl_dsp_boot(struct sst_dsp *ctx); int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_sst **dsp); + struct skl_dev **dsp); int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_sst **dsp); -int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx); -int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx); -void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); -void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); + struct skl_dev **dsp); +int skl_sst_init_fw(struct device *dev, struct skl_dev *skl); +int bxt_sst_init_fw(struct device *dev, struct skl_dev *skl); +void skl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl); +void bxt_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl); int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, unsigned int offset, int index); -int skl_get_pvt_id(struct skl_sst *ctx, guid_t *uuid_mod, int instance_id); -int skl_put_pvt_id(struct skl_sst *ctx, guid_t *uuid_mod, int *pvt_id); -int skl_get_pvt_instance_id_map(struct skl_sst *ctx, +int skl_get_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int instance_id); +int skl_put_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int *pvt_id); +int skl_get_pvt_instance_id_map(struct skl_dev *skl, int module_id, int instance_id); -void skl_freeup_uuid_list(struct skl_sst *ctx); +void skl_freeup_uuid_list(struct skl_dev *skl); int skl_dsp_strip_extended_manifest(struct firmware *fw); -void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable); +void skl_dsp_enable_notification(struct skl_dev *skl, bool enable); -void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data); +void skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data); int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, - struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp, + struct skl_dsp_loader_ops dsp_ops, struct skl_dev **dsp, struct sst_dsp_device *skl_dev); -int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo, +int skl_prepare_lib_load(struct skl_dev *skl, struct skl_lib_info *linfo, struct firmware *stripped_fw, unsigned int hdr_offset, int index); void skl_release_library(struct skl_lib_info *linfo, int lib_count); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 2cc8f7d2d319..ee1493acc9a8 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -345,7 +345,7 @@ out: int skl_ipc_process_notification(struct sst_generic_ipc *ipc, struct skl_ipc_header header) { - struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); + struct skl_dev *skl = container_of(ipc, struct skl_dev, ipc); if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { switch (IPC_GLB_NOTIFY_TYPE(header.primary)) { @@ -436,7 +436,7 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc, struct ipc_message *msg; u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; u64 *ipc_header = (u64 *)(&header); - struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); + struct skl_dev *skl = container_of(ipc, struct skl_dev, ipc); unsigned long flags; spin_lock_irqsave(&ipc->dsp->spinlock, flags); @@ -488,7 +488,7 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc, irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) { struct sst_dsp *dsp = context; - struct skl_sst *skl = sst_dsp_get_thread_context(dsp); + struct skl_dev *skl = sst_dsp_get_thread_context(dsp); struct sst_generic_ipc *ipc = &skl->ipc; struct skl_ipc_header header = {0}; u32 hipcie, hipct, hipcte; @@ -595,7 +595,7 @@ bool skl_ipc_int_status(struct sst_dsp *ctx) SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC; } -int skl_ipc_init(struct device *dev, struct skl_sst *skl) +int skl_ipc_init(struct device *dev, struct skl_dev *skl) { struct sst_generic_ipc *ipc; int err; diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 9c31a48e99dd..93af08cf41d2 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -10,9 +10,9 @@ #include #include "../common/sst-ipc.h" +#include "skl-sst-dsp.h" struct sst_dsp; -struct skl_sst; struct sst_generic_ipc; enum skl_ipc_pipeline_state { @@ -67,54 +67,6 @@ struct skl_lib_info { const struct firmware *fw; }; -struct skl_sst { - struct device *dev; - struct sst_dsp *dsp; - - /* boot */ - wait_queue_head_t boot_wait; - bool boot_complete; - - /* module load */ - wait_queue_head_t mod_load_wait; - bool mod_load_complete; - bool mod_load_status; - - /* IPC messaging */ - struct sst_generic_ipc ipc; - - /* callback for miscbdge */ - void (*enable_miscbdcge)(struct device *dev, bool enable); - /* Is CGCTL.MISCBDCGE disabled */ - bool miscbdcg_disabled; - - /* Populate module information */ - struct list_head uuid_list; - - /* Is firmware loaded */ - bool fw_loaded; - - /* first boot ? */ - bool is_first_boot; - - /* multi-core */ - struct skl_dsp_cores cores; - - /* library info */ - struct skl_lib_info lib_info[SKL_MAX_LIB]; - int lib_count; - - /* Callback to update D0i3C register */ - void (*update_d0i3c)(struct device *dev, bool enable); - - struct skl_d0i3_data d0i3; - - const struct skl_dsp_ops *dsp_ops; - - /* Callback to update dynamic clock and power gating registers */ - void (*clock_power_gating)(struct device *dev, bool enable); -}; - struct skl_ipc_init_instance_msg { u32 module_id; u32 instance_id; @@ -204,7 +156,7 @@ void skl_ipc_int_disable(struct sst_dsp *dsp); bool skl_ipc_int_status(struct sst_dsp *dsp); void skl_ipc_free(struct sst_generic_ipc *ipc); -int skl_ipc_init(struct device *dev, struct skl_sst *skl); +int skl_ipc_init(struct device *dev, struct skl_dev *skl); void skl_clear_module_cnt(struct sst_dsp *ctx); void skl_ipc_process_reply(struct sst_generic_ipc *ipc, diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index 928c677b506c..d43cbf4a71ef 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c @@ -8,10 +8,9 @@ #include #include #include -#include "skl-sst-dsp.h" #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" -#include "skl-sst-ipc.h" +#include "skl.h" #define DEFAULT_HASH_SHA256_LEN 32 @@ -99,12 +98,12 @@ static int skl_get_pvtid_map(struct uuid_module *module, int instance_id) return -EINVAL; } -int skl_get_pvt_instance_id_map(struct skl_sst *ctx, +int skl_get_pvt_instance_id_map(struct skl_dev *skl, int module_id, int instance_id) { struct uuid_module *module; - list_for_each_entry(module, &ctx->uuid_list, list) { + list_for_each_entry(module, &skl->uuid_list, list) { if (module->id == module_id) return skl_get_pvtid_map(module, instance_id); } @@ -163,19 +162,19 @@ static inline int skl_pvtid_128(struct uuid_module *module) /** * skl_get_pvt_id: generate a private id for use as module id * - * @ctx: driver context + * @skl: driver context * @uuid_mod: module's uuid * @instance_id: module's instance id * * This generates a 128 bit private unique id for a module TYPE so that * module instance is unique */ -int skl_get_pvt_id(struct skl_sst *ctx, guid_t *uuid_mod, int instance_id) +int skl_get_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int instance_id) { struct uuid_module *module; int pvt_id; - list_for_each_entry(module, &ctx->uuid_list, list) { + list_for_each_entry(module, &skl->uuid_list, list) { if (guid_equal(uuid_mod, &module->uuid)) { pvt_id = skl_pvtid_128(module); @@ -194,18 +193,18 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id); /** * skl_put_pvt_id: free up the private id allocated * - * @ctx: driver context + * @skl: driver context * @uuid_mod: module's uuid * @pvt_id: module pvt id * * This frees a 128 bit private unique id previously generated */ -int skl_put_pvt_id(struct skl_sst *ctx, guid_t *uuid_mod, int *pvt_id) +int skl_put_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int *pvt_id) { int i; struct uuid_module *module; - list_for_each_entry(module, &ctx->uuid_list, list) { + list_for_each_entry(module, &skl->uuid_list, list) { if (guid_equal(uuid_mod, &module->uuid)) { if (*pvt_id != 0) @@ -234,7 +233,7 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, struct adsp_module_entry *mod_entry; int i, num_entry, size; const char *buf; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; struct uuid_module *module; struct firmware stripped_fw; unsigned int safe_file; @@ -317,11 +316,11 @@ free_uuid_list: return ret; } -void skl_freeup_uuid_list(struct skl_sst *ctx) +void skl_freeup_uuid_list(struct skl_dev *skl) { struct uuid_module *uuid, *_uuid; - list_for_each_entry_safe(uuid, _uuid, &ctx->uuid_list, list) { + list_for_each_entry_safe(uuid, _uuid, &skl->uuid_list, list) { list_del(&uuid->list); kfree(uuid); } @@ -355,16 +354,12 @@ int skl_dsp_strip_extended_manifest(struct firmware *fw) } int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, - struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp, + struct skl_dsp_loader_ops dsp_ops, struct skl_dev **dsp, struct sst_dsp_device *skl_dev) { - struct skl_sst *skl; + struct skl_dev *skl = *dsp; struct sst_dsp *sst; - skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); - if (skl == NULL) - return -ENOMEM; - skl->dev = dev; skl_dev->thread_context = skl; INIT_LIST_HEAD(&skl->uuid_list); @@ -381,13 +376,11 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, INIT_LIST_HEAD(&sst->module_list); skl->is_first_boot = true; - if (dsp) - *dsp = skl; return 0; } -int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo, +int skl_prepare_lib_load(struct skl_dev *skl, struct skl_lib_info *linfo, struct firmware *stripped_fw, unsigned int hdr_offset, int index) { diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 70c3a604c381..8af7546def1f 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -16,7 +16,7 @@ #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" #include "../common/sst-ipc.h" -#include "skl-sst-ipc.h" +#include "skl.h" #define SKL_BASEFW_TIMEOUT 300 #define SKL_INIT_TIMEOUT 1000 @@ -66,7 +66,7 @@ static int skl_transfer_firmware(struct sst_dsp *ctx, static int skl_load_base_firmware(struct sst_dsp *ctx) { int ret = 0, i; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; struct firmware stripped_fw; u32 reg; @@ -161,7 +161,7 @@ static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) { int ret; struct skl_ipc_dxstate_info dx; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); /* If core0 is being turned on, we need to load the FW */ @@ -215,7 +215,7 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) { int ret; struct skl_ipc_dxstate_info dx; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); dx.core_mask = core_mask; @@ -332,7 +332,7 @@ static int skl_transfer_module(struct sst_dsp *ctx, const void *data, u32 size, u16 mod_id, u8 table_id, bool is_module) { int ret, bytes_left, curr_pos; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; skl->mod_load_complete = false; bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, data, size, false); @@ -384,7 +384,7 @@ out: static int skl_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; struct firmware stripped_fw; int ret, i; @@ -443,7 +443,7 @@ static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid) static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) { int usage_cnt; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; int ret = 0; usage_cnt = skl_put_module(ctx, mod_id); @@ -518,9 +518,10 @@ static struct sst_dsp_device skl_dev = { }; int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp) + const char *fw_name, struct skl_dsp_loader_ops dsp_ops, + struct skl_dev **dsp) { - struct skl_sst *skl; + struct skl_dev *skl; struct sst_dsp *sst; int ret; @@ -554,10 +555,10 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, } EXPORT_SYMBOL_GPL(skl_sst_dsp_init); -int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx) +int skl_sst_init_fw(struct device *dev, struct skl_dev *skl) { int ret; - struct sst_dsp *sst = ctx->dsp; + struct sst_dsp *sst = skl->dsp; ret = sst->fw_ops.load_fw(sst); if (ret < 0) { @@ -567,32 +568,32 @@ int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx) skl_dsp_init_core_state(sst); - if (ctx->lib_count > 1) { - ret = sst->fw_ops.load_library(sst, ctx->lib_info, - ctx->lib_count); + if (skl->lib_count > 1) { + ret = sst->fw_ops.load_library(sst, skl->lib_info, + skl->lib_count); if (ret < 0) { dev_err(dev, "Load Library failed : %x\n", ret); return ret; } } - ctx->is_first_boot = false; + skl->is_first_boot = false; return 0; } EXPORT_SYMBOL_GPL(skl_sst_init_fw); -void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) +void skl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) { - if (ctx->dsp->fw) - release_firmware(ctx->dsp->fw); - skl_clear_module_table(ctx->dsp); - skl_freeup_uuid_list(ctx); - skl_ipc_free(&ctx->ipc); - ctx->dsp->ops->free(ctx->dsp); - if (ctx->boot_complete) { - ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); - skl_cldma_int_disable(ctx->dsp); + if (skl->dsp->fw) + release_firmware(skl->dsp->fw); + skl_clear_module_table(skl->dsp); + skl_freeup_uuid_list(skl); + skl_ipc_free(&skl->ipc); + skl->dsp->ops->free(skl->dsp); + if (skl->boot_complete) { + skl->dsp->cl_dev.ops.cl_cleanup_controller(skl->dsp); + skl_cldma_int_disable(skl->dsp); } } EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 6241e35213af..abf860109607 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -45,9 +45,9 @@ static const int mic_quatro_list[][SKL_CH_QUATRO] = { #define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \ ((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq)) -void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps) +void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps) { - struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; + struct skl_d0i3_data *d0i3 = &skl->d0i3; switch (caps) { case SKL_D0I3_NONE: @@ -64,9 +64,9 @@ void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps) } } -void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps) +void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps) { - struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; + struct skl_d0i3_data *d0i3 = &skl->d0i3; switch (caps) { case SKL_D0I3_NONE: @@ -113,18 +113,16 @@ static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w, * Each pipelines needs memory to be allocated. Check if we have free memory * from available pool. */ -static bool skl_is_pipe_mem_avail(struct skl *skl, +static bool skl_is_pipe_mem_avail(struct skl_dev *skl, struct skl_module_cfg *mconfig) { - struct skl_sst *ctx = skl->skl_sst; - if (skl->resource.mem + mconfig->pipe->memory_pages > skl->resource.max_mem) { - dev_err(ctx->dev, + dev_err(skl->dev, "%s: module_id %d instance %d\n", __func__, mconfig->id.module_id, mconfig->id.instance_id); - dev_err(ctx->dev, + dev_err(skl->dev, "exceeds ppl memory available %d mem %d\n", skl->resource.max_mem, skl->resource.mem); return false; @@ -138,7 +136,7 @@ static bool skl_is_pipe_mem_avail(struct skl *skl, * Note: DSP does actual memory management we only keep track for complete * pool */ -static void skl_tplg_alloc_pipe_mem(struct skl *skl, +static void skl_tplg_alloc_pipe_mem(struct skl_dev *skl, struct skl_module_cfg *mconfig) { skl->resource.mem += mconfig->pipe->memory_pages; @@ -152,18 +150,17 @@ static void skl_tplg_alloc_pipe_mem(struct skl *skl, * pipe. */ -static bool skl_is_pipe_mcps_avail(struct skl *skl, +static bool skl_is_pipe_mcps_avail(struct skl_dev *skl, struct skl_module_cfg *mconfig) { - struct skl_sst *ctx = skl->skl_sst; u8 res_idx = mconfig->res_idx; struct skl_module_res *res = &mconfig->module->resources[res_idx]; if (skl->resource.mcps + res->cps > skl->resource.max_mcps) { - dev_err(ctx->dev, + dev_err(skl->dev, "%s: module_id %d instance %d\n", __func__, mconfig->id.module_id, mconfig->id.instance_id); - dev_err(ctx->dev, + dev_err(skl->dev, "exceeds ppl mcps available %d > mem %d\n", skl->resource.max_mcps, skl->resource.mcps); return false; @@ -172,7 +169,7 @@ static bool skl_is_pipe_mcps_avail(struct skl *skl, } } -static void skl_tplg_alloc_pipe_mcps(struct skl *skl, +static void skl_tplg_alloc_pipe_mcps(struct skl_dev *skl, struct skl_module_cfg *mconfig) { u8 res_idx = mconfig->res_idx; @@ -185,7 +182,7 @@ static void skl_tplg_alloc_pipe_mcps(struct skl *skl, * Free the mcps when tearing down */ static void -skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig) +skl_tplg_free_pipe_mcps(struct skl_dev *skl, struct skl_module_cfg *mconfig) { u8 res_idx = mconfig->res_idx; struct skl_module_res *res = &mconfig->module->resources[res_idx]; @@ -197,30 +194,29 @@ skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig) * Free the memory when tearing down */ static void -skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig) +skl_tplg_free_pipe_mem(struct skl_dev *skl, struct skl_module_cfg *mconfig) { skl->resource.mem -= mconfig->pipe->memory_pages; } -static void skl_dump_mconfig(struct skl_sst *ctx, - struct skl_module_cfg *mcfg) +static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg) { struct skl_module_iface *iface = &mcfg->module->formats[0]; - dev_dbg(ctx->dev, "Dumping config\n"); - dev_dbg(ctx->dev, "Input Format:\n"); - dev_dbg(ctx->dev, "channels = %d\n", iface->inputs[0].fmt.channels); - dev_dbg(ctx->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq); - dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg); - dev_dbg(ctx->dev, "valid bit depth = %d\n", + dev_dbg(skl->dev, "Dumping config\n"); + dev_dbg(skl->dev, "Input Format:\n"); + dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels); + dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq); + dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg); + dev_dbg(skl->dev, "valid bit depth = %d\n", iface->inputs[0].fmt.valid_bit_depth); - dev_dbg(ctx->dev, "Output Format:\n"); - dev_dbg(ctx->dev, "channels = %d\n", iface->outputs[0].fmt.channels); - dev_dbg(ctx->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq); - dev_dbg(ctx->dev, "valid bit depth = %d\n", + dev_dbg(skl->dev, "Output Format:\n"); + dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels); + dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq); + dev_dbg(skl->dev, "valid bit depth = %d\n", iface->outputs[0].fmt.valid_bit_depth); - dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg); + dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg); } static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) @@ -322,7 +318,7 @@ static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, * params, so once we have calculate params, we need buffer calculation as * well. */ -static void skl_tplg_update_buffer_size(struct skl_sst *ctx, +static void skl_tplg_update_buffer_size(struct skl_dev *skl, struct skl_module_cfg *mcfg) { int multiplier = 1; @@ -374,13 +370,12 @@ static u8 skl_tplg_be_dev_type(int dev_type) } static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, - struct skl_sst *ctx) + struct skl_dev *skl) { struct skl_module_cfg *m_cfg = w->priv; int link_type, dir; u32 ch, s_freq, s_fmt; struct nhlt_specific_cfg *cfg; - struct skl *skl = get_skl_ctx(ctx->dev); u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type); int fmt_idx = m_cfg->fmt_idx; struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx]; @@ -389,7 +384,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, if (m_cfg->formats_config.caps_size > 0) return 0; - dev_dbg(ctx->dev, "Applying default cfg blob\n"); + dev_dbg(skl->dev, "Applying default cfg blob\n"); switch (m_cfg->dev_type) { case SKL_DEVICE_DMIC: link_type = NHLT_LINK_DMIC; @@ -425,9 +420,9 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, m_cfg->formats_config.caps_size = cfg->size; m_cfg->formats_config.caps = (u32 *) &cfg->caps; } else { - dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n", + dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n", m_cfg->vbus_id, link_type, dir); - dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n", + dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d\n", ch, s_freq, s_fmt); return -EIO; } @@ -436,7 +431,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, } static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, - struct skl_sst *ctx) + struct skl_dev *skl) { struct skl_module_cfg *m_cfg = w->priv; struct skl_pipe_params *params = m_cfg->pipe->p_params; @@ -446,10 +441,10 @@ static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, if (!m_cfg->params_fixup) return; - dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n", + dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n", w->name); - skl_dump_mconfig(ctx, m_cfg); + skl_dump_mconfig(skl, m_cfg); if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) is_fe = true; @@ -457,12 +452,12 @@ static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, is_fe = false; skl_tplg_update_params_fixup(m_cfg, params, is_fe); - skl_tplg_update_buffer_size(ctx, m_cfg); + skl_tplg_update_buffer_size(skl, m_cfg); - dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n", + dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n", w->name); - skl_dump_mconfig(ctx, m_cfg); + skl_dump_mconfig(skl, m_cfg); } /* @@ -471,7 +466,7 @@ static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, * set module params will be done after module is initialised. */ static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, - struct skl_sst *ctx) + struct skl_dev *skl) { int i, ret; struct skl_module_cfg *mconfig = w->priv; @@ -483,7 +478,7 @@ static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, if (mconfig->formats_config.caps_size > 0 && mconfig->formats_config.set_params == SKL_PARAM_SET) { sp_cfg = &mconfig->formats_config; - ret = skl_set_module_params(ctx, sp_cfg->caps, + ret = skl_set_module_params(skl, sp_cfg->caps, sp_cfg->caps_size, sp_cfg->param_id, mconfig); if (ret < 0) @@ -497,7 +492,7 @@ static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, bc = (struct skl_algo_data *)sb->dobj.private; if (bc->set_params == SKL_PARAM_SET) { - ret = skl_set_module_params(ctx, + ret = skl_set_module_params(skl, (u32 *)bc->params, bc->size, bc->param_id, mconfig); if (ret < 0) @@ -542,15 +537,15 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) return 0; } -static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe, +static int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe, struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg) { switch (mcfg->dev_type) { case SKL_DEVICE_HDAHOST: - return skl_pcm_host_dma_prepare(ctx->dev, pipe->p_params); + return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params); case SKL_DEVICE_HDALINK: - return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params); + return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params); } return 0; @@ -562,12 +557,11 @@ static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe, * skl_init_module() routine, so invoke that for all modules in a pipeline */ static int -skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) +skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) { struct skl_pipe_module *w_module; struct snd_soc_dapm_widget *w; struct skl_module_cfg *mconfig; - struct skl_sst *ctx = skl->skl_sst; u8 cfg_idx; int ret = 0; @@ -578,7 +572,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) /* check if module ids are populated */ if (mconfig->id.module_id < 0) { - dev_err(skl->skl_sst->dev, + dev_err(skl->dev, "module %pUL id not populated\n", (guid_t *)mconfig->guid); return -EIO; @@ -592,8 +586,8 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) if (!skl_is_pipe_mcps_avail(skl, mconfig)) return -ENOMEM; - if (mconfig->module->loadable && ctx->dsp->fw_ops.load_mod) { - ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, + if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) { + ret = skl->dsp->fw_ops.load_mod(skl->dsp, mconfig->id.module_id, mconfig->guid); if (ret < 0) return ret; @@ -602,50 +596,50 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) } /* prepare the DMA if the module is gateway cpr */ - ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig); + ret = skl_tplg_module_prepare(skl, pipe, w, mconfig); if (ret < 0) return ret; /* update blob if blob is null for be with default value */ - skl_tplg_update_be_blob(w, ctx); + skl_tplg_update_be_blob(w, skl); /* * apply fix/conversion to module params based on * FE/BE params */ - skl_tplg_update_module_params(w, ctx); + skl_tplg_update_module_params(w, skl); uuid_mod = (guid_t *)mconfig->guid; - mconfig->id.pvt_id = skl_get_pvt_id(ctx, uuid_mod, + mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod, mconfig->id.instance_id); if (mconfig->id.pvt_id < 0) return ret; skl_tplg_set_module_init_data(w); - ret = skl_dsp_get_core(ctx->dsp, mconfig->core_id); + ret = skl_dsp_get_core(skl->dsp, mconfig->core_id); if (ret < 0) { - dev_err(ctx->dev, "Failed to wake up core %d ret=%d\n", + dev_err(skl->dev, "Failed to wake up core %d ret=%d\n", mconfig->core_id, ret); return ret; } - ret = skl_init_module(ctx, mconfig); + ret = skl_init_module(skl, mconfig); if (ret < 0) { - skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id); + skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); goto err; } skl_tplg_alloc_pipe_mcps(skl, mconfig); - ret = skl_tplg_set_module_params(w, ctx); + ret = skl_tplg_set_module_params(w, skl); if (ret < 0) goto err; } return 0; err: - skl_dsp_put_core(ctx->dsp, mconfig->core_id); + skl_dsp_put_core(skl->dsp, mconfig->core_id); return ret; } -static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, +static int skl_tplg_unload_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) { int ret = 0; @@ -657,19 +651,19 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, mconfig = w_module->w->priv; uuid_mod = (guid_t *)mconfig->guid; - if (mconfig->module->loadable && ctx->dsp->fw_ops.unload_mod && + if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod && mconfig->m_state > SKL_MODULE_UNINIT) { - ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp, + ret = skl->dsp->fw_ops.unload_mod(skl->dsp, mconfig->id.module_id); if (ret < 0) return -EIO; } - skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id); + skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); - ret = skl_dsp_put_core(ctx->dsp, mconfig->core_id); + ret = skl_dsp_put_core(skl->dsp, mconfig->core_id); if (ret < 0) { /* don't return; continue with other modules */ - dev_err(ctx->dev, "Failed to sleep core %d ret=%d\n", + dev_err(skl->dev, "Failed to sleep core %d ret=%d\n", mconfig->core_id, ret); } } @@ -686,9 +680,8 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, * 0th configuratation by default for such pipes. */ static int -skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig) +skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig) { - struct skl_sst *ctx = skl->skl_sst; struct skl_pipe *pipe = mconfig->pipe; struct skl_pipe_params *params = pipe->p_params; struct skl_path_config *pconfig = &pipe->configs[0]; @@ -702,7 +695,7 @@ skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig) } if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) { - dev_dbg(ctx->dev, "No conn_type detected, take 0th config\n"); + dev_dbg(skl->dev, "No conn_type detected, take 0th config\n"); pipe->cur_config_idx = 0; pipe->memory_pages = pconfig->mem_pages; @@ -726,13 +719,13 @@ skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig) fmt->channels, fmt->freq, fmt->bps)) { pipe->cur_config_idx = i; pipe->memory_pages = pconfig->mem_pages; - dev_dbg(ctx->dev, "Using pipe config: %d\n", i); + dev_dbg(skl->dev, "Using pipe config: %d\n", i); return 0; } } - dev_err(ctx->dev, "Invalid pipe config: %d %d %d for pipe: %d\n", + dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n", params->ch, params->s_freq, params->s_fmt, pipe->ppl_id); return -EINVAL; } @@ -746,14 +739,13 @@ skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig) * - finally bind all modules together */ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { int ret; struct skl_module_cfg *mconfig = w->priv; struct skl_pipe_module *w_module; struct skl_pipe *s_pipe = mconfig->pipe; struct skl_module_cfg *src_module = NULL, *dst_module, *module; - struct skl_sst *ctx = skl->skl_sst; struct skl_module_deferred_bind *modules; ret = skl_tplg_get_pipe_config(skl, mconfig); @@ -771,7 +763,7 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, * Create a list of modules for pipe. * This list contains modules from source to sink */ - ret = skl_create_pipeline(ctx, mconfig->pipe); + ret = skl_create_pipeline(skl, mconfig->pipe); if (ret < 0) return ret; @@ -792,7 +784,7 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, continue; } - ret = skl_bind_modules(ctx, src_module, dst_module); + ret = skl_bind_modules(skl, src_module, dst_module); if (ret < 0) return ret; @@ -810,7 +802,7 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, list_for_each_entry(modules, &skl->bind_list, node) { module = w_module->w->priv; if (modules->dst == module) - skl_bind_modules(ctx, modules->src, + skl_bind_modules(skl, modules->src, modules->dst); } } @@ -818,7 +810,7 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, return 0; } -static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params, +static int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params, int size, struct skl_module_cfg *mcfg) { int i, pvt_id; @@ -829,7 +821,7 @@ static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params, struct skl_mod_inst_map *inst = kpb_params->u.map; for (i = 0; i < kpb_params->num_modules; i++) { - pvt_id = skl_get_pvt_instance_id_map(ctx, inst->mod_id, + pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id, inst->inst_id); if (pvt_id < 0) return -EINVAL; @@ -849,7 +841,7 @@ static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params, * send params after binding */ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, - struct skl_module_cfg *mcfg, struct skl_sst *ctx) + struct skl_module_cfg *mcfg, struct skl_dev *skl) { int i, ret; struct skl_module_cfg *mconfig = w->priv; @@ -876,7 +868,7 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, if (mconfig->formats_config.caps_size > 0 && mconfig->formats_config.set_params == SKL_PARAM_BIND) { sp_cfg = &mconfig->formats_config; - ret = skl_set_module_params(ctx, sp_cfg->caps, + ret = skl_set_module_params(skl, sp_cfg->caps, sp_cfg->caps_size, sp_cfg->param_id, mconfig); if (ret < 0) @@ -894,10 +886,10 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, if (!params) return -ENOMEM; - skl_fill_sink_instance_id(ctx, params, bc->max, + skl_fill_sink_instance_id(skl, params, bc->max, mconfig); - ret = skl_set_module_params(ctx, params, + ret = skl_set_module_params(skl, params, bc->max, bc->param_id, mconfig); kfree(params); @@ -910,11 +902,11 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, return 0; } -static int skl_get_module_id(struct skl_sst *ctx, guid_t *uuid) +static int skl_get_module_id(struct skl_dev *skl, guid_t *uuid) { struct uuid_module *module; - list_for_each_entry(module, &ctx->uuid_list, list) { + list_for_each_entry(module, &skl->uuid_list, list) { if (guid_equal(uuid, &module->uuid)) return module->id; } @@ -922,7 +914,7 @@ static int skl_get_module_id(struct skl_sst *ctx, guid_t *uuid) return -EINVAL; } -static int skl_tplg_find_moduleid_from_uuid(struct skl *skl, +static int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl, const struct snd_kcontrol_new *k) { struct soc_bytes_ext *sb = (void *) k->private_value; @@ -942,7 +934,7 @@ static int skl_tplg_find_moduleid_from_uuid(struct skl *skl, params->num_modules = uuid_params->num_modules; for (i = 0; i < uuid_params->num_modules; i++) { - module_id = skl_get_module_id(skl->skl_sst, + module_id = skl_get_module_id(skl, &uuid_params->u.map_uuid[i].mod_uuid); if (module_id < 0) { devm_kfree(bus->dev, params); @@ -966,7 +958,7 @@ static int skl_tplg_find_moduleid_from_uuid(struct skl *skl, * Retrieve the module id from UUID mentioned in the * post bind params */ -void skl_tplg_add_moduleid_in_bind_params(struct skl *skl, +void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl, struct snd_soc_dapm_widget *w) { struct skl_module_cfg *mconfig = w->priv; @@ -985,12 +977,12 @@ void skl_tplg_add_moduleid_in_bind_params(struct skl *skl, SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) && (skl_tplg_find_moduleid_from_uuid(skl, &w->kcontrol_news[i]) < 0)) - dev_err(skl->skl_sst->dev, + dev_err(skl->dev, "%s: invalid kpb post bind params\n", __func__); } -static int skl_tplg_module_add_deferred_bind(struct skl *skl, +static int skl_tplg_module_add_deferred_bind(struct skl_dev *skl, struct skl_module_cfg *src, struct skl_module_cfg *dst) { struct skl_module_deferred_bind *m_list, *modules; @@ -1028,26 +1020,27 @@ static int skl_tplg_module_add_deferred_bind(struct skl *skl, } static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, - struct skl *skl, + struct skl_dev *skl, struct snd_soc_dapm_widget *src_w, struct skl_module_cfg *src_mconfig) { struct snd_soc_dapm_path *p; struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; struct skl_module_cfg *sink_mconfig; - struct skl_sst *ctx = skl->skl_sst; int ret; snd_soc_dapm_widget_for_each_sink_path(w, p) { if (!p->connect) continue; - dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name); - dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); + dev_dbg(skl->dev, + "%s: src widget=%s\n", __func__, w->name); + dev_dbg(skl->dev, + "%s: sink widget=%s\n", __func__, p->sink->name); next_sink = p->sink; - if (!is_skl_dsp_widget_type(p->sink, ctx->dev)) + if (!is_skl_dsp_widget_type(p->sink, skl->dev)) return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); /* @@ -1056,7 +1049,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, * they are ones used for SKL so check that first */ if ((p->sink->priv != NULL) && - is_skl_dsp_widget_type(p->sink, ctx->dev)) { + is_skl_dsp_widget_type(p->sink, skl->dev)) { sink = p->sink; sink_mconfig = sink->priv; @@ -1088,19 +1081,21 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, continue; /* Bind source to sink, mixin is always source */ - ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); + ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); if (ret) return ret; /* set module params after bind */ - skl_tplg_set_module_bind_params(src_w, src_mconfig, ctx); - skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); + skl_tplg_set_module_bind_params(src_w, + src_mconfig, skl); + skl_tplg_set_module_bind_params(sink, + sink_mconfig, skl); /* Start sinks pipe first */ if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - ret = skl_run_pipe(ctx, + ret = skl_run_pipe(skl, sink_mconfig->pipe); if (ret) return ret; @@ -1125,10 +1120,9 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, * - Then run current pipe */ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { struct skl_module_cfg *src_mconfig; - struct skl_sst *ctx = skl->skl_sst; int ret = 0; src_mconfig = w->priv; @@ -1144,25 +1138,24 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, /* Start source pipe last after starting all sinks */ if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - return skl_run_pipe(ctx, src_mconfig->pipe); + return skl_run_pipe(skl, src_mconfig->pipe); return 0; } static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( - struct snd_soc_dapm_widget *w, struct skl *skl) + struct snd_soc_dapm_widget *w, struct skl_dev *skl) { struct snd_soc_dapm_path *p; struct snd_soc_dapm_widget *src_w = NULL; - struct skl_sst *ctx = skl->skl_sst; snd_soc_dapm_widget_for_each_source_path(w, p) { src_w = p->source; if (!p->connect) continue; - dev_dbg(ctx->dev, "sink widget=%s\n", w->name); - dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); + dev_dbg(skl->dev, "sink widget=%s\n", w->name); + dev_dbg(skl->dev, "src widget=%s\n", p->source->name); /* * here we will check widgets in sink pipelines, so that can @@ -1170,7 +1163,7 @@ static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( * ones used for SKL so check that first */ if ((p->source->priv != NULL) && - is_skl_dsp_widget_type(p->source, ctx->dev)) { + is_skl_dsp_widget_type(p->source, skl->dev)) { return p->source; } } @@ -1191,12 +1184,11 @@ static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( * - start this pipeline */ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { int ret = 0; struct snd_soc_dapm_widget *source, *sink; struct skl_module_cfg *src_mconfig, *sink_mconfig; - struct skl_sst *ctx = skl->skl_sst; int src_pipe_started = 0; sink = w; @@ -1222,16 +1214,16 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, } if (src_pipe_started) { - ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); + ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); if (ret) return ret; /* set module params after bind */ - skl_tplg_set_module_bind_params(source, src_mconfig, ctx); - skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); + skl_tplg_set_module_bind_params(source, src_mconfig, skl); + skl_tplg_set_module_bind_params(sink, sink_mconfig, skl); if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - ret = skl_run_pipe(ctx, sink_mconfig->pipe); + ret = skl_run_pipe(skl, sink_mconfig->pipe); } return ret; @@ -1244,16 +1236,15 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, * - unbind with source pipelines if still connected */ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { struct skl_module_cfg *src_mconfig, *sink_mconfig; int ret = 0, i; - struct skl_sst *ctx = skl->skl_sst; sink_mconfig = w->priv; /* Stop the pipe */ - ret = skl_stop_pipe(ctx, sink_mconfig->pipe); + ret = skl_stop_pipe(skl, sink_mconfig->pipe); if (ret) return ret; @@ -1263,7 +1254,7 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, if (!src_mconfig) continue; - ret = skl_unbind_modules(ctx, + ret = skl_unbind_modules(skl, src_mconfig, sink_mconfig); } } @@ -1280,12 +1271,11 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, * deleted, pipeline delete is enough here */ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { struct skl_module_cfg *mconfig = w->priv; struct skl_pipe_module *w_module; struct skl_module_cfg *src_module = NULL, *dst_module; - struct skl_sst *ctx = skl->skl_sst; struct skl_pipe *s_pipe = mconfig->pipe; struct skl_module_deferred_bind *modules, *tmp; @@ -1307,7 +1297,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, * modules from deferred bind list. */ if (modules->dst == src_module) { - skl_unbind_modules(ctx, modules->src, + skl_unbind_modules(skl, modules->src, modules->dst); } @@ -1334,18 +1324,18 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, continue; } - skl_unbind_modules(ctx, src_module, dst_module); + skl_unbind_modules(skl, src_module, dst_module); src_module = dst_module; } - skl_delete_pipe(ctx, mconfig->pipe); + skl_delete_pipe(skl, mconfig->pipe); list_for_each_entry(w_module, &s_pipe->w_list, node) { src_module = w_module->w->priv; src_module->m_state = SKL_MODULE_UNINIT; } - return skl_tplg_unload_pipe_modules(ctx, s_pipe); + return skl_tplg_unload_pipe_modules(skl, s_pipe); } /* @@ -1355,16 +1345,15 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, * - In source pipe is connected, unbind with source pipelines */ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { struct skl_module_cfg *src_mconfig, *sink_mconfig; int ret = 0, i; - struct skl_sst *ctx = skl->skl_sst; src_mconfig = w->priv; /* Stop the pipe since this is a mixin module */ - ret = skl_stop_pipe(ctx, src_mconfig->pipe); + ret = skl_stop_pipe(skl, src_mconfig->pipe); if (ret) return ret; @@ -1377,7 +1366,7 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, * This is a connecter and if path is found that means * unbind between source and sink has not happened yet */ - ret = skl_unbind_modules(ctx, src_mconfig, + ret = skl_unbind_modules(skl, src_mconfig, sink_mconfig); } } @@ -1395,7 +1384,7 @@ static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { struct snd_soc_dapm_context *dapm = w->dapm; - struct skl *skl = get_skl_ctx(dapm->dev); + struct skl_dev *skl = get_skl_ctx(dapm->dev); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1425,7 +1414,7 @@ static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, { struct snd_soc_dapm_context *dapm = w->dapm; - struct skl *skl = get_skl_ctx(dapm->dev); + struct skl_dev *skl = get_skl_ctx(dapm->dev); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1446,10 +1435,10 @@ static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); struct skl_module_cfg *mconfig = w->priv; - struct skl *skl = get_skl_ctx(w->dapm->dev); + struct skl_dev *skl = get_skl_ctx(w->dapm->dev); if (w->power) - skl_get_module_params(skl->skl_sst, (u32 *)bc->params, + skl_get_module_params(skl, (u32 *)bc->params, bc->size, bc->param_id, mconfig); /* decrement size for TLV header */ @@ -1481,7 +1470,7 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *sb = (struct soc_bytes_ext *)kcontrol->private_value; struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; - struct skl *skl = get_skl_ctx(w->dapm->dev); + struct skl_dev *skl = get_skl_ctx(w->dapm->dev); if (ac->params) { /* @@ -1498,7 +1487,7 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, return -EFAULT; if (w->power) - return skl_set_module_params(skl->skl_sst, + return skl_set_module_params(skl, (u32 *)ac->params, ac->size, ac->param_id, mconfig); } @@ -1659,7 +1648,7 @@ int skl_tplg_update_pipe_params(struct device *dev, struct skl_pipe_params *params) { struct skl_module_res *res = &mconfig->module->resources[0]; - struct skl *skl = get_skl_ctx(dev); + struct skl_dev *skl = get_skl_ctx(dev); struct skl_module_fmt *format = NULL; u8 cfg_idx = mconfig->pipe->cur_config_idx; @@ -1856,7 +1845,7 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, struct skl_pipe_params *params) { struct nhlt_specific_cfg *cfg; - struct skl *skl = get_skl_ctx(dai->dev); + struct skl_dev *skl = get_skl_ctx(dai->dev); int link_type = skl_tplg_be_link_type(mconfig->dev_type); u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type); @@ -2070,7 +2059,7 @@ static int skl_tplg_fill_pipe_tkn(struct device *dev, * Return an existing pipe if the pipe already exists. */ static int skl_tplg_add_pipe(struct device *dev, - struct skl_module_cfg *mconfig, struct skl *skl, + struct skl_module_cfg *mconfig, struct skl_dev *skl, struct snd_soc_tplg_vendor_value_elem *tkn_elem) { struct skl_pipeline *ppl; @@ -2381,7 +2370,7 @@ static int skl_tplg_fill_res_tkn(struct device *dev, */ static int skl_tplg_get_token(struct device *dev, struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl *skl, struct skl_module_cfg *mconfig) + struct skl_dev *skl, struct skl_module_cfg *mconfig) { int tkn_count = 0; int ret; @@ -2631,7 +2620,7 @@ static int skl_tplg_get_token(struct device *dev, * module private data */ static int skl_tplg_get_tokens(struct device *dev, - char *pvt_data, struct skl *skl, + char *pvt_data, struct skl_dev *skl, struct skl_module_cfg *mconfig, int block_size) { struct snd_soc_tplg_vendor_array *array; @@ -2727,8 +2716,8 @@ static int skl_tplg_get_desc_blocks(struct device *dev, * Otherwise we create a new instance and add into driver list */ static int skl_tplg_add_pipe_v4(struct device *dev, - struct skl_module_cfg *mconfig, struct skl *skl, - struct skl_dfw_v4_pipe *dfw_pipe) + struct skl_module_cfg *mconfig, struct skl_dev *skl, + struct skl_dfw_v4_pipe *dfw_pipe) { struct skl_pipeline *ppl; struct skl_pipe *pipe; @@ -2804,7 +2793,7 @@ static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt, } static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w, - struct skl *skl, struct device *dev, + struct skl_dev *skl, struct device *dev, struct skl_module_cfg *mconfig) { struct skl_dfw_v4_module *dfw = @@ -2886,7 +2875,7 @@ static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w, * for the type and size of the suceeding data block. */ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, - struct skl *skl, struct device *dev, + struct skl_dev *skl, struct device *dev, struct skl_module_cfg *mconfig) { struct snd_soc_tplg_vendor_array *array; @@ -2981,9 +2970,8 @@ static void skl_clear_pin_config(struct snd_soc_component *component, } } -void skl_cleanup_resources(struct skl *skl) +void skl_cleanup_resources(struct skl_dev *skl) { - struct skl_sst *ctx = skl->skl_sst; struct snd_soc_component *soc_component = skl->component; struct snd_soc_dapm_widget *w; struct snd_soc_card *card; @@ -2999,11 +2987,11 @@ void skl_cleanup_resources(struct skl *skl) skl->resource.mcps = 0; list_for_each_entry(w, &card->widgets, list) { - if (is_skl_dsp_widget_type(w, ctx->dev) && w->priv != NULL) + if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL) skl_clear_pin_config(soc_component, w); } - skl_clear_module_cnt(ctx->dsp); + skl_clear_module_cnt(skl->dsp); } /* @@ -3019,7 +3007,7 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index, { int ret; struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct skl_module_cfg *mconfig; if (!tplg_w->priv.size) @@ -3163,21 +3151,21 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt, static int skl_tplg_fill_str_mfest_tkn(struct device *dev, struct snd_soc_tplg_vendor_string_elem *str_elem, - struct skl *skl) + struct skl_dev *skl) { int tkn_count = 0; static int ref_count; switch (str_elem->token) { case SKL_TKN_STR_LIB_NAME: - if (ref_count > skl->skl_sst->lib_count - 1) { + if (ref_count > skl->lib_count - 1) { ref_count = 0; return -EINVAL; } - strncpy(skl->skl_sst->lib_info[ref_count].name, + strncpy(skl->lib_info[ref_count].name, str_elem->string, - ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name)); + ARRAY_SIZE(skl->lib_info[ref_count].name)); ref_count++; break; @@ -3192,7 +3180,7 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev, static int skl_tplg_get_str_tkn(struct device *dev, struct snd_soc_tplg_vendor_array *array, - struct skl *skl) + struct skl_dev *skl) { int tkn_count = 0, ret; struct snd_soc_tplg_vendor_string_elem *str_elem; @@ -3299,7 +3287,7 @@ static int skl_tplg_fill_mod_info(struct device *dev, static int skl_tplg_get_int_tkn(struct device *dev, struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl *skl) + struct skl_dev *skl) { int tkn_count = 0, ret; static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx; @@ -3319,7 +3307,7 @@ static int skl_tplg_get_int_tkn(struct device *dev, switch (tkn_elem->token) { case SKL_TKN_U32_LIB_COUNT: - skl->skl_sst->lib_count = tkn_elem->value; + skl->lib_count = tkn_elem->value; break; case SKL_TKN_U8_NUM_MOD: @@ -3466,7 +3454,7 @@ static int skl_tplg_get_int_tkn(struct device *dev, } static int skl_tplg_get_manifest_uuid(struct device *dev, - struct skl *skl, + struct skl_dev *skl, struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) { static int ref_count; @@ -3489,7 +3477,7 @@ static int skl_tplg_get_manifest_uuid(struct device *dev, * type. */ static int skl_tplg_get_manifest_tkn(struct device *dev, - char *pvt_data, struct skl *skl, + char *pvt_data, struct skl_dev *skl, int block_size) { int tkn_count = 0, ret; @@ -3550,7 +3538,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, * preceded by descriptors for type and size of data block. */ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, - struct device *dev, struct skl *skl) + struct device *dev, struct skl_dev *skl) { struct snd_soc_tplg_vendor_array *array; int num_blocks, block_size = 0, block_type, off = 0; @@ -3612,7 +3600,7 @@ static int skl_manifest_load(struct snd_soc_component *cmpnt, int index, struct snd_soc_tplg_manifest *manifest) { struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); /* proceed only if we have private data defined */ if (manifest->priv.size == 0) @@ -3620,9 +3608,9 @@ static int skl_manifest_load(struct snd_soc_component *cmpnt, int index, skl_tplg_get_manifest_data(manifest, bus->dev, skl); - if (skl->skl_sst->lib_count > SKL_MAX_LIB) { + if (skl->lib_count > SKL_MAX_LIB) { dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", - skl->skl_sst->lib_count); + skl->lib_count); return -EINVAL; } @@ -3671,7 +3659,7 @@ static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component) return 0; } -static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe) +static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe) { struct skl_pipe_module *w_module; struct snd_soc_dapm_widget *w; @@ -3705,7 +3693,7 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus) { int ret; const struct firmware *fw; - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct skl_pipeline *ppl; ret = request_firmware(&fw, skl->tplg_name, bus->dev); @@ -3748,7 +3736,7 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus) void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus) { - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct skl_pipeline *ppl, *tmp; if (!list_empty(&skl->ppl_list)) diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 665e35cee50d..0a4d89cdaa4c 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -447,7 +447,7 @@ enum skl_channel { SKL_CH_QUATRO = 4, }; -static inline struct skl *get_skl_ctx(struct device *dev) +static inline struct skl_dev *get_skl_ctx(struct device *dev) { struct hdac_bus *bus = dev_get_drvdata(dev); @@ -456,7 +456,7 @@ static inline struct skl *get_skl_ctx(struct device *dev) int skl_tplg_be_update_params(struct snd_soc_dai *dai, struct skl_pipe_params *params); -int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps, +int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, u32 caps_size, u32 node_id); void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai, struct skl_pipe_params *params, int stream); @@ -469,32 +469,32 @@ struct skl_module_cfg *skl_tplg_fe_get_cpr_module( int skl_tplg_update_pipe_params(struct device *dev, struct skl_module_cfg *mconfig, struct skl_pipe_params *params); -void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps); -void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps); +void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps); +void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps); -int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe); +int skl_create_pipeline(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); +int skl_run_pipe(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_pause_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); +int skl_pause_pipe(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); +int skl_delete_pipe(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); +int skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); +int skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config); +int skl_init_module(struct skl_dev *skl, struct skl_module_cfg *module_config); -int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg +int skl_bind_modules(struct skl_dev *skl, struct skl_module_cfg *src_module, struct skl_module_cfg *dst_module); -int skl_unbind_modules(struct skl_sst *ctx, struct skl_module_cfg +int skl_unbind_modules(struct skl_dev *skl, struct skl_module_cfg *src_module, struct skl_module_cfg *dst_module); -int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, +int skl_set_module_params(struct skl_dev *skl, u32 *params, int size, u32 param_id, struct skl_module_cfg *mcfg); -int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, +int skl_get_module_params(struct skl_dev *skl, u32 *params, int size, u32 param_id, struct skl_module_cfg *mcfg); struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, @@ -508,6 +508,6 @@ int skl_pcm_link_dma_prepare(struct device *dev, int skl_dai_load(struct snd_soc_component *cmp, int index, struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai); -void skl_tplg_add_moduleid_in_bind_params(struct skl *skl, +void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl, struct snd_soc_dapm_widget *w); #endif diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 3362e71b4563..6be25e617c21 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -50,7 +50,7 @@ static void skl_update_pci_byte(struct pci_dev *pci, unsigned int reg, pci_write_config_byte(pci, reg, data); } -static void skl_init_pci(struct skl *skl) +static void skl_init_pci(struct skl_dev *skl) { struct hdac_bus *bus = skl_to_bus(skl); @@ -252,7 +252,7 @@ static irqreturn_t skl_threaded_handler(int irq, void *dev_id) static int skl_acquire_irq(struct hdac_bus *bus, int do_disconnect) { - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); int ret; ret = request_threaded_irq(skl->pci->irq, skl_interrupt, @@ -276,7 +276,7 @@ static int skl_suspend_late(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); return skl_suspend_late_dsp(skl); } @@ -284,7 +284,7 @@ static int skl_suspend_late(struct device *dev) #ifdef CONFIG_PM static int _skl_suspend(struct hdac_bus *bus) { - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct pci_dev *pci = to_pci_dev(bus->dev); int ret; @@ -307,7 +307,7 @@ static int _skl_suspend(struct hdac_bus *bus) static int _skl_resume(struct hdac_bus *bus) { - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); skl_init_pci(skl); skl_dum_set(bus); @@ -325,7 +325,7 @@ static int skl_suspend(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); int ret; /* @@ -345,7 +345,7 @@ static int skl_suspend(struct device *dev) ret = _skl_suspend(bus); if (ret < 0) return ret; - skl->skl_sst->fw_loaded = false; + skl->fw_loaded = false; } return 0; @@ -355,7 +355,7 @@ static int skl_resume(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct hdac_ext_link *hlink = NULL; int ret; @@ -430,7 +430,7 @@ static const struct dev_pm_ops skl_pm = { */ static int skl_free(struct hdac_bus *bus) { - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); skl->init_done = 0; /* to be sure */ @@ -475,7 +475,7 @@ static struct skl_ssp_clk skl_ssp_clks[] = { {.name = "ssp5_sclkfs"}, }; -static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl *skl, +static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl_dev *skl, struct snd_soc_acpi_mach *machines) { struct hdac_bus *bus = skl_to_bus(skl); @@ -494,7 +494,7 @@ static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl *skl, return mach; } -static int skl_find_machine(struct skl *skl, void *driver_data) +static int skl_find_machine(struct skl_dev *skl, void *driver_data) { struct hdac_bus *bus = skl_to_bus(skl); struct snd_soc_acpi_mach *mach = driver_data; @@ -522,7 +522,7 @@ static int skl_find_machine(struct skl *skl, void *driver_data) return 0; } -static int skl_machine_device_register(struct skl *skl) +static int skl_machine_device_register(struct skl_dev *skl) { struct snd_soc_acpi_mach *mach = skl->mach; struct hdac_bus *bus = skl_to_bus(skl); @@ -558,13 +558,13 @@ static int skl_machine_device_register(struct skl *skl) return 0; } -static void skl_machine_device_unregister(struct skl *skl) +static void skl_machine_device_unregister(struct skl_dev *skl) { if (skl->i2s_dev) platform_device_unregister(skl->i2s_dev); } -static int skl_dmic_device_register(struct skl *skl) +static int skl_dmic_device_register(struct skl_dev *skl) { struct hdac_bus *bus = skl_to_bus(skl); struct platform_device *pdev; @@ -588,7 +588,7 @@ static int skl_dmic_device_register(struct skl *skl) return 0; } -static void skl_dmic_device_unregister(struct skl *skl) +static void skl_dmic_device_unregister(struct skl_dev *skl) { if (skl->dmic_dev) platform_device_unregister(skl->dmic_dev); @@ -626,7 +626,7 @@ static void init_skl_xtal_rate(int pci_id) } } -static int skl_clock_device_register(struct skl *skl) +static int skl_clock_device_register(struct skl_dev *skl) { struct platform_device_info pdevinfo = {NULL}; struct skl_clk_pdata *clk_pdata; @@ -656,7 +656,7 @@ static int skl_clock_device_register(struct skl *skl) return PTR_ERR_OR_ZERO(skl->clk_dev); } -static void skl_clock_device_unregister(struct skl *skl) +static void skl_clock_device_unregister(struct skl_dev *skl) { if (skl->clk_dev) platform_device_unregister(skl->clk_dev); @@ -692,7 +692,7 @@ static int probe_codec(struct hdac_bus *bus, int addr) unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; unsigned int res = -1; - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) struct hdac_hda_priv *hda_codec; int err; @@ -792,7 +792,7 @@ static int skl_i915_init(struct hdac_bus *bus) static void skl_probe_work(struct work_struct *work) { - struct skl *skl = container_of(work, struct skl, probe_work); + struct skl_dev *skl = container_of(work, struct skl_dev, probe_work); struct hdac_bus *bus = skl_to_bus(skl); struct hdac_ext_link *hlink = NULL; int err; @@ -855,10 +855,10 @@ out_err: */ static int skl_create(struct pci_dev *pci, const struct hdac_io_ops *io_ops, - struct skl **rskl) + struct skl_dev **rskl) { struct hdac_ext_bus_ops *ext_ops = NULL; - struct skl *skl; + struct skl_dev *skl; struct hdac_bus *bus; struct hda_bus *hbus; int err; @@ -902,7 +902,7 @@ static int skl_create(struct pci_dev *pci, static int skl_first_init(struct hdac_bus *bus) { - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct pci_dev *pci = skl->pci; int err; unsigned short gcap; @@ -978,7 +978,7 @@ static int skl_first_init(struct hdac_bus *bus) static int skl_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - struct skl *skl; + struct skl_dev *skl; struct hdac_bus *bus = NULL; int err; @@ -1071,8 +1071,8 @@ static int skl_probe(struct pci_dev *pci, dev_dbg(bus->dev, "error failed to register dsp\n"); goto out_nhlt_free; } - skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; - skl->skl_sst->clock_power_gating = skl_clock_power_gating; + skl->enable_miscbdcge = skl_enable_miscbdcge; + skl->clock_power_gating = skl_clock_power_gating; if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); @@ -1107,7 +1107,7 @@ static void skl_shutdown(struct pci_dev *pci) struct hdac_bus *bus = pci_get_drvdata(pci); struct hdac_stream *s; struct hdac_ext_stream *stream; - struct skl *skl; + struct skl_dev *skl; if (!bus) return; @@ -1129,7 +1129,7 @@ static void skl_shutdown(struct pci_dev *pci) static void skl_remove(struct pci_dev *pci) { struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); cancel_work_sync(&skl->probe_work); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 6070666a6392..d3d84f4125d9 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -18,6 +18,7 @@ #include #include "skl-nhlt.h" #include "skl-ssp-clk.h" +#include "skl-sst-ipc.h" #define SKL_SUSPEND_DELAY 2000 @@ -63,7 +64,7 @@ struct skl_fw_config { struct skl_astate_config *astate_cfg; }; -struct skl { +struct skl_dev { struct hda_bus hbus; struct pci_dev *pci; @@ -75,7 +76,6 @@ struct skl { struct snd_soc_dai_driver *dais; struct nhlt_acpi_table *nhlt; /* nhlt ptr */ - struct skl_sst *skl_sst; /* sst skl ctx */ struct skl_dsp_resource resource; struct list_head ppl_list; @@ -96,13 +96,59 @@ struct skl { bool use_tplg_pcm; struct skl_fw_config cfg; struct snd_soc_acpi_mach *mach; + + struct device *dev; + struct sst_dsp *dsp; + + /* boot */ + wait_queue_head_t boot_wait; + bool boot_complete; + + /* module load */ + wait_queue_head_t mod_load_wait; + bool mod_load_complete; + bool mod_load_status; + + /* IPC messaging */ + struct sst_generic_ipc ipc; + + /* callback for miscbdge */ + void (*enable_miscbdcge)(struct device *dev, bool enable); + /* Is CGCTL.MISCBDCGE disabled */ + bool miscbdcg_disabled; + + /* Populate module information */ + struct list_head uuid_list; + + /* Is firmware loaded */ + bool fw_loaded; + + /* first boot ? */ + bool is_first_boot; + + /* multi-core */ + struct skl_dsp_cores cores; + + /* library info */ + struct skl_lib_info lib_info[SKL_MAX_LIB]; + int lib_count; + + /* Callback to update D0i3C register */ + void (*update_d0i3c)(struct device *dev, bool enable); + + struct skl_d0i3_data d0i3; + + const struct skl_dsp_ops *dsp_ops; + + /* Callback to update dynamic clock and power gating registers */ + void (*clock_power_gating)(struct device *dev, bool enable); }; #define skl_to_bus(s) (&(s)->hbus.core) -#define bus_to_skl(bus) container_of(bus, struct skl, hbus.core) +#define bus_to_skl(bus) container_of(bus, struct skl_dev, hbus.core) #define skl_to_hbus(s) (&(s)->hbus) -#define hbus_to_skl(hbus) container_of((hbus), struct skl, (hbus)) +#define hbus_to_skl(hbus) container_of((hbus), struct skl_dev, (hbus)) /* to pass dai dma data */ struct skl_dma_params { @@ -121,9 +167,9 @@ struct skl_dsp_ops { int (*init)(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops loader_ops, - struct skl_sst **skl_sst); - int (*init_fw)(struct device *dev, struct skl_sst *ctx); - void (*cleanup)(struct device *dev, struct skl_sst *ctx); + struct skl_dev **skl_sst); + int (*init_fw)(struct device *dev, struct skl_dev *skl); + void (*cleanup)(struct device *dev, struct skl_dev *skl); }; int skl_platform_unregister(struct device *dev); @@ -131,42 +177,42 @@ int skl_platform_register(struct device *dev); struct nhlt_acpi_table *skl_nhlt_init(struct device *dev); void skl_nhlt_free(struct nhlt_acpi_table *addr); -struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, +struct nhlt_specific_cfg *skl_get_ep_blob(struct skl_dev *skl, u32 instance, u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn, u8 dev_type); -int skl_get_dmic_geo(struct skl *skl); -int skl_nhlt_update_topology_bin(struct skl *skl); -int skl_init_dsp(struct skl *skl); -int skl_free_dsp(struct skl *skl); -int skl_suspend_late_dsp(struct skl *skl); -int skl_suspend_dsp(struct skl *skl); -int skl_resume_dsp(struct skl *skl); -void skl_cleanup_resources(struct skl *skl); +int skl_get_dmic_geo(struct skl_dev *skl); +int skl_nhlt_update_topology_bin(struct skl_dev *skl); +int skl_init_dsp(struct skl_dev *skl); +int skl_free_dsp(struct skl_dev *skl); +int skl_suspend_late_dsp(struct skl_dev *skl); +int skl_suspend_dsp(struct skl_dev *skl); +int skl_resume_dsp(struct skl_dev *skl); +void skl_cleanup_resources(struct skl_dev *skl); const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); void skl_update_d0i3c(struct device *dev, bool enable); -int skl_nhlt_create_sysfs(struct skl *skl); -void skl_nhlt_remove_sysfs(struct skl *skl); -void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks); +int skl_nhlt_create_sysfs(struct skl_dev *skl); +void skl_nhlt_remove_sysfs(struct skl_dev *skl); +void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks); struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id); -int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps, +int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, u32 caps_size, u32 node_id); struct skl_module_cfg; #ifdef CONFIG_DEBUG_FS -struct skl_debug *skl_debugfs_init(struct skl *skl); -void skl_debugfs_exit(struct skl *skl); +struct skl_debug *skl_debugfs_init(struct skl_dev *skl); +void skl_debugfs_exit(struct skl_dev *skl); void skl_debug_init_module(struct skl_debug *d, struct snd_soc_dapm_widget *w, struct skl_module_cfg *mconfig); #else -static inline struct skl_debug *skl_debugfs_init(struct skl *skl) +static inline struct skl_debug *skl_debugfs_init(struct skl_dev *skl) { return NULL; } -static inline void skl_debugfs_exit(struct skl *skl) +static inline void skl_debugfs_exit(struct skl_dev *skl) {} static inline void skl_debug_init_module(struct skl_debug *d, -- cgit v1.2.3 From 88abcc90cb04cbabcc3e384e8d3431a49f56a2b3 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Tue, 23 Jul 2019 16:58:49 +0200 Subject: ASoC: Intel: Skylake: Combine snd_soc_skl_ipc and snd_soc_skl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As both modules are core part of Skylake driver and none can live without the other, combine snd_soc_skl_ipc and snd_soc_skl. It's highly probable IPC module was to be treated as an interface for platform specific code implementations e.g.: possibility of existence of BXT specific code without SKL one. However, most funtionalities are being inherited from one DSP firmware to another, and thus this assumption fails. skl-sst, bxt-sst and cnl-sst are not individuals pointing respectively to SKL (cAVS 1.5), BXT (cAVS 1.5+) & CNL (cAVS 1.8) standalone implementations. Code found within these is shared among all platforms whenever necessary to avoid code duplication and reduce development burden. Merge also helps in cleaning up internal code in future changes. Signed-off-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190723145854.8527-3-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/Makefile | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 86f6e1d801af..48544ff1a3e6 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 -snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o \ -skl-topology.o +snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o skl-topology.o \ + skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o skl-sst-cldma.o \ + skl-sst.o bxt-sst.o cnl-sst.o skl-sst-utils.o ifdef CONFIG_DEBUG_FS snd-soc-skl-objs += skl-debug.o @@ -8,13 +9,6 @@ endif obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o -# Skylake IPC Support -snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o \ - skl-sst-cldma.o skl-sst.o bxt-sst.o cnl-sst.o \ - skl-sst-utils.o - -obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o - #Skylake Clock device support snd-soc-skl-ssp-clk-objs := skl-ssp-clk.o -- cgit v1.2.3 From f2a167ca681d21aa46f127032cc005879c328823 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 23 Jul 2019 16:58:50 +0200 Subject: ASoC: Intel: Skylake: Remove MCPS available check The entire logic for MCPS calculation and DSP scheduling is found within DSP firmware. Currently driver implements simplistic, inaccurate logic itself which may prevent pipeline creation despite firmware being completely fine its parameters. Remove that logic and leave the MCPS calculation to DSP alone. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190723145854.8527-4-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 67 +--------------------------------- sound/soc/intel/skylake/skl.h | 2 - 2 files changed, 1 insertion(+), 68 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index abf860109607..2af311150543 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -142,54 +142,6 @@ static void skl_tplg_alloc_pipe_mem(struct skl_dev *skl, skl->resource.mem += mconfig->pipe->memory_pages; } -/* - * Pipeline needs needs DSP CPU resources for computation, this is - * quantified in MCPS (Million Clocks Per Second) required for module/pipe - * - * Each pipelines needs mcps to be allocated. Check if we have mcps for this - * pipe. - */ - -static bool skl_is_pipe_mcps_avail(struct skl_dev *skl, - struct skl_module_cfg *mconfig) -{ - u8 res_idx = mconfig->res_idx; - struct skl_module_res *res = &mconfig->module->resources[res_idx]; - - if (skl->resource.mcps + res->cps > skl->resource.max_mcps) { - dev_err(skl->dev, - "%s: module_id %d instance %d\n", __func__, - mconfig->id.module_id, mconfig->id.instance_id); - dev_err(skl->dev, - "exceeds ppl mcps available %d > mem %d\n", - skl->resource.max_mcps, skl->resource.mcps); - return false; - } else { - return true; - } -} - -static void skl_tplg_alloc_pipe_mcps(struct skl_dev *skl, - struct skl_module_cfg *mconfig) -{ - u8 res_idx = mconfig->res_idx; - struct skl_module_res *res = &mconfig->module->resources[res_idx]; - - skl->resource.mcps += res->cps; -} - -/* - * Free the mcps when tearing down - */ -static void -skl_tplg_free_pipe_mcps(struct skl_dev *skl, struct skl_module_cfg *mconfig) -{ - u8 res_idx = mconfig->res_idx; - struct skl_module_res *res = &mconfig->module->resources[res_idx]; - - skl->resource.mcps -= res->cps; -} - /* * Free the memory when tearing down */ @@ -582,10 +534,6 @@ skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; - /* check resource available */ - if (!skl_is_pipe_mcps_avail(skl, mconfig)) - return -ENOMEM; - if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) { ret = skl->dsp->fw_ops.load_mod(skl->dsp, mconfig->id.module_id, mconfig->guid); @@ -627,7 +575,7 @@ skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); goto err; } - skl_tplg_alloc_pipe_mcps(skl, mconfig); + ret = skl_tplg_set_module_params(w, skl); if (ret < 0) goto err; @@ -752,10 +700,6 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, if (ret < 0) return ret; - /* check resource available */ - if (!skl_is_pipe_mcps_avail(skl, mconfig)) - return -EBUSY; - if (!skl_is_pipe_mem_avail(skl, mconfig)) return -ENOMEM; @@ -768,7 +712,6 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, return ret; skl_tplg_alloc_pipe_mem(skl, mconfig); - skl_tplg_alloc_pipe_mcps(skl, mconfig); /* Init all pipe modules from source to sink */ ret = skl_tplg_init_pipe_modules(skl, s_pipe); @@ -1264,7 +1207,6 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, /* * in the Post-PMD event of mixer we need to do following: - * - Free the mcps used * - Free the mem used * - Unbind the modules within the pipeline * - Delete the pipeline (modules are not required to be explicitly @@ -1282,7 +1224,6 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, if (s_pipe->state == SKL_PIPE_INVALID) return -EINVAL; - skl_tplg_free_pipe_mcps(skl, mconfig); skl_tplg_free_pipe_mem(skl, mconfig); list_for_each_entry(w_module, &s_pipe->w_list, node) { @@ -1317,8 +1258,6 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, list_for_each_entry(w_module, &s_pipe->w_list, node) { dst_module = w_module->w->priv; - if (mconfig->m_state >= SKL_MODULE_INIT_DONE) - skl_tplg_free_pipe_mcps(skl, dst_module); if (src_module == NULL) { src_module = dst_module; continue; @@ -1340,7 +1279,6 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, /* * in the Post-PMD event of PGA we need to do following: - * - Free the mcps used * - Stop the pipeline * - In source pipe is connected, unbind with source pipelines */ @@ -2984,7 +2922,6 @@ void skl_cleanup_resources(struct skl_dev *skl) return; skl->resource.mem = 0; - skl->resource.mcps = 0; list_for_each_entry(w, &card->widgets, list) { if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL) @@ -3683,7 +3620,6 @@ static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe) } /* This will be read from topology manifest, currently defined here */ -#define SKL_MAX_MCPS 30000000 #define SKL_FW_MAX_MEM 1000000 /* @@ -3720,7 +3656,6 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus) return -EINVAL; } - skl->resource.max_mcps = SKL_MAX_MCPS; skl->resource.max_mem = SKL_FW_MAX_MEM; skl->tplg = fw; diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index d3d84f4125d9..21c33c1af934 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -42,9 +42,7 @@ #define AZX_REG_VS_EM2_L1SEN BIT(13) struct skl_dsp_resource { - u32 max_mcps; u32 max_mem; - u32 mcps; u32 mem; }; -- cgit v1.2.3 From e5c29dc5221c328b6e54c5b2aba1feca4003c051 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 23 Jul 2019 16:58:51 +0200 Subject: ASoC: Intel: Skylake: Remove memory available check Current memory availability check is a stub, while actual memory management takes place in firmware. Leave this task to firmware entirely and remove redundant code. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190723145854.8527-5-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 59 ---------------------------------- sound/soc/intel/skylake/skl.h | 6 ---- 2 files changed, 65 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 2af311150543..53a024c0464d 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -109,49 +109,6 @@ static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w, } } -/* - * Each pipelines needs memory to be allocated. Check if we have free memory - * from available pool. - */ -static bool skl_is_pipe_mem_avail(struct skl_dev *skl, - struct skl_module_cfg *mconfig) -{ - if (skl->resource.mem + mconfig->pipe->memory_pages > - skl->resource.max_mem) { - dev_err(skl->dev, - "%s: module_id %d instance %d\n", __func__, - mconfig->id.module_id, - mconfig->id.instance_id); - dev_err(skl->dev, - "exceeds ppl memory available %d mem %d\n", - skl->resource.max_mem, skl->resource.mem); - return false; - } else { - return true; - } -} - -/* - * Add the mem to the mem pool. This is freed when pipe is deleted. - * Note: DSP does actual memory management we only keep track for complete - * pool - */ -static void skl_tplg_alloc_pipe_mem(struct skl_dev *skl, - struct skl_module_cfg *mconfig) -{ - skl->resource.mem += mconfig->pipe->memory_pages; -} - -/* - * Free the memory when tearing down - */ -static void -skl_tplg_free_pipe_mem(struct skl_dev *skl, struct skl_module_cfg *mconfig) -{ - skl->resource.mem -= mconfig->pipe->memory_pages; -} - - static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg) { struct skl_module_iface *iface = &mcfg->module->formats[0]; @@ -681,7 +638,6 @@ skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig) /* * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we * need create the pipeline. So we do following: - * - check the resources * - Create the pipeline * - Initialize the modules in pipeline * - finally bind all modules together @@ -700,9 +656,6 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, if (ret < 0) return ret; - if (!skl_is_pipe_mem_avail(skl, mconfig)) - return -ENOMEM; - /* * Create a list of modules for pipe. * This list contains modules from source to sink @@ -711,8 +664,6 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, if (ret < 0) return ret; - skl_tplg_alloc_pipe_mem(skl, mconfig); - /* Init all pipe modules from source to sink */ ret = skl_tplg_init_pipe_modules(skl, s_pipe); if (ret < 0) @@ -1207,7 +1158,6 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, /* * in the Post-PMD event of mixer we need to do following: - * - Free the mem used * - Unbind the modules within the pipeline * - Delete the pipeline (modules are not required to be explicitly * deleted, pipeline delete is enough here @@ -1224,8 +1174,6 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, if (s_pipe->state == SKL_PIPE_INVALID) return -EINVAL; - skl_tplg_free_pipe_mem(skl, mconfig); - list_for_each_entry(w_module, &s_pipe->w_list, node) { if (list_empty(&skl->bind_list)) break; @@ -2921,8 +2869,6 @@ void skl_cleanup_resources(struct skl_dev *skl) if (!card || !card->instantiated) return; - skl->resource.mem = 0; - list_for_each_entry(w, &card->widgets, list) { if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL) skl_clear_pin_config(soc_component, w); @@ -3619,9 +3565,6 @@ static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe) pipe->passthru = false; } -/* This will be read from topology manifest, currently defined here */ -#define SKL_FW_MAX_MEM 1000000 - /* * SKL topology init routine */ @@ -3656,8 +3599,6 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus) return -EINVAL; } - skl->resource.max_mem = SKL_FW_MAX_MEM; - skl->tplg = fw; ret = skl_tplg_create_pipe_widget_list(component); if (ret < 0) diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 21c33c1af934..600a61f79b0a 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -41,11 +41,6 @@ #define AZX_VS_EM2_DUM BIT(23) #define AZX_REG_VS_EM2_L1SEN BIT(13) -struct skl_dsp_resource { - u32 max_mem; - u32 mem; -}; - struct skl_debug; struct skl_astate_param { @@ -75,7 +70,6 @@ struct skl_dev { struct nhlt_acpi_table *nhlt; /* nhlt ptr */ - struct skl_dsp_resource resource; struct list_head ppl_list; struct list_head bind_list; -- cgit v1.2.3 From d4e23b7c87e3439f6d0ec0c65ad7f919d6f4c124 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Tue, 23 Jul 2019 16:58:52 +0200 Subject: ASoC: Intel: Skylake: Do not disable FW notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per FW team recommendation we should not disable notifications. By default, all notifications are enabled in DSP firmware. These notifications provide a vital information whenever an error occurs. Currently, driver disables them during boot sequences. By doing so, Skylake may silently ignore severe stream errors. Correct that by removing permissive code. Signed-off-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190723145854.8527-6-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 20 -------------------- sound/soc/intel/skylake/skl-pcm.c | 1 - sound/soc/intel/skylake/skl-sst-dsp.h | 1 - sound/soc/intel/skylake/skl-topology.h | 5 ----- 4 files changed, 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index f604d9c6824d..07762543fb13 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -58,24 +58,6 @@ void skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data) skl_ipc_set_large_config(&skl->ipc, &msg, data); } -#define NOTIFICATION_PARAM_ID 3 -#define NOTIFICATION_MASK 0xf - -/* disable notfication for underruns/overruns from firmware module */ -void skl_dsp_enable_notification(struct skl_dev *skl, bool enable) -{ - struct notification_mask mask; - struct skl_ipc_large_config_msg msg = {0}; - - mask.notify = NOTIFICATION_MASK; - mask.enable = enable; - - msg.large_param_id = NOTIFICATION_PARAM_ID; - msg.param_data_size = sizeof(mask); - - skl_ipc_set_large_config(&skl->ipc, &msg, (u32 *)&mask); -} - static int skl_dsp_setup_spib(struct device *dev, unsigned int size, int stream_tag, int enable) { @@ -436,8 +418,6 @@ int skl_resume_dsp(struct skl_dev *skl) if (ret < 0) return ret; - skl_dsp_enable_notification(skl, false); - if (skl->cfg.astate_cfg != NULL) { skl_dsp_set_astate_cfg(skl, skl->cfg.astate_cfg->count, skl->cfg.astate_cfg); diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 2ae5d09d7228..7f287424af9b 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1445,7 +1445,6 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) } skl_populate_modules(skl); skl->update_d0i3c = skl_update_d0i3c; - skl_dsp_enable_notification(skl, false); if (skl->cfg.astate_cfg != NULL) { skl_dsp_set_astate_cfg(skl, diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index ed968f1042c7..cdfec0fca577 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -240,7 +240,6 @@ int skl_get_pvt_instance_id_map(struct skl_dev *skl, void skl_freeup_uuid_list(struct skl_dev *skl); int skl_dsp_strip_extended_manifest(struct firmware *fw); -void skl_dsp_enable_notification(struct skl_dev *skl, bool enable); void skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data); diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 0a4d89cdaa4c..e2a2fc5c5545 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -140,11 +140,6 @@ struct skl_src_module_cfg { enum skl_s_freq src_cfg; } __packed; -struct notification_mask { - u32 notify; - u32 enable; -} __packed; - struct skl_up_down_mixer_cfg { struct skl_base_cfg base_cfg; enum skl_ch_cfg out_ch_cfg; -- cgit v1.2.3 From 84b71067ea840fadee32588aa3967d0d8c4e0b9a Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 23 Jul 2019 16:58:53 +0200 Subject: ASoC: Intel: Skylake: Make MCPS and CPS params obsolete As per FW Interface Modules Configuration, init instance IPC request requires base initial module configuration. This configuration structure is made of: - cpc (chunks per cycle) - ibs (input buffer size) - obs (output buffer size) - is_pages (memory pages required) - audio_fmt (self explanatory) Skylake topology accepts following tokens: MCPS, CPS and CPC. All of these are directly connected. Moreover, assigning one of these allows to calculate the remaining two. In simplest scenario and assuming 1ms scheduling, following is true: CPS = CPC times 1000 MCPS = CPS times 1000 000 Note: these calculations vary depending on scenario and scheduling requirements. Given the current implementation, userspace is allowed to provide different values for all three causing informational chaos. On top of that, struct skl_base_cfg which represents base module configuration, incorrectly takes CPS param instead of CPC. This ambiguity may lead to user unintentionally providing improper values to DSP firmware and thus impacting module scheduling in unexpected fashion. Fix by making MCPS and CPS topology params obsolete and relying solely on CPC value. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190723145854.8527-7-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-debug.c | 6 ++++-- sound/soc/intel/skylake/skl-messages.c | 2 +- sound/soc/intel/skylake/skl-topology.c | 15 ++++++--------- sound/soc/intel/skylake/skl-topology.h | 4 +--- 4 files changed, 12 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c index c43aa4081232..fb232428109f 100644 --- a/sound/soc/intel/skylake/skl-debug.c +++ b/sound/soc/intel/skylake/skl-debug.c @@ -66,6 +66,8 @@ static ssize_t module_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct skl_module_cfg *mconfig = file->private_data; + struct skl_module *module = mconfig->module; + struct skl_module_res *res = &module->resources[mconfig->res_idx]; char *buf; ssize_t ret; @@ -79,8 +81,8 @@ static ssize_t module_read(struct file *file, char __user *user_buf, mconfig->id.pvt_id); ret += snprintf(buf + ret, MOD_BUF - ret, - "Resources:\n\tMCPS %#x\n\tIBS %#x\n\tOBS %#x\t\n", - mconfig->mcps, mconfig->ibs, mconfig->obs); + "Resources:\n\tCPC %#x\n\tIBS %#x\n\tOBS %#x\t\n", + res->cpc, res->ibs, res->obs); ret += snprintf(buf + ret, MOD_BUF - ret, "Module data:\n\tCore %d\n\tIn queue %d\n\t" diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 07762543fb13..e8cc710f092b 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -477,7 +477,7 @@ static void skl_set_base_module_format(struct skl_dev *skl, base_cfg->audio_fmt.interleaving = format->interleaving_style; - base_cfg->cps = res->cps; + base_cfg->cpc = res->cpc; base_cfg->ibs = res->ibs; base_cfg->obs = res->obs; base_cfg->is_pages = res->is_pages; diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 53a024c0464d..118866cd5075 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -2205,10 +2205,6 @@ static int skl_tplg_fill_res_tkn(struct device *dev, return -EINVAL; switch (tkn_elem->token) { - case SKL_TKN_MM_U32_CPS: - res->cps = tkn_elem->value; - break; - case SKL_TKN_MM_U32_DMA_SIZE: res->dma_buffer_size = tkn_elem->value; break; @@ -2229,10 +2225,6 @@ static int skl_tplg_fill_res_tkn(struct device *dev, res->ibs = tkn_elem->value; break; - case SKL_TKN_U32_MAX_MCPS: - res->cps = tkn_elem->value; - break; - case SKL_TKN_MM_U32_RES_PIN_ID: case SKL_TKN_MM_U32_PIN_BUF: ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res, @@ -2241,6 +2233,11 @@ static int skl_tplg_fill_res_tkn(struct device *dev, return ret; break; + case SKL_TKN_MM_U32_CPS: + case SKL_TKN_U32_MAX_MCPS: + /* ignore unused tokens */ + break; + default: dev_err(dev, "Not a res type token: %d", tkn_elem->token); return -EINVAL; @@ -2693,7 +2690,7 @@ static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w, return ret; mconfig->id.module_id = -1; mconfig->id.instance_id = dfw->instance_id; - mconfig->module->resources[0].cps = dfw->max_mcps; + mconfig->module->resources[0].cpc = dfw->max_mcps / 1000; mconfig->module->resources[0].ibs = dfw->ibs; mconfig->module->resources[0].obs = dfw->obs; mconfig->core_id = dfw->core_id; diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index e2a2fc5c5545..99a0277191ca 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -101,7 +101,7 @@ struct skl_audio_data_format { } __packed; struct skl_base_cfg { - u32 cps; + u32 cpc; u32 ibs; u32 obs; u32 is_pages; @@ -343,7 +343,6 @@ struct skl_module_pin_resources { struct skl_module_res { u8 id; u32 is_pages; - u32 cps; u32 ibs; u32 obs; u32 dma_buffer_size; @@ -384,7 +383,6 @@ struct skl_module_cfg { u8 out_queue_mask; u8 in_queue; u8 out_queue; - u32 mcps; u32 ibs; u32 obs; u8 is_loadable; -- cgit v1.2.3 From bdc873feec900005d52f9afd3a63290531c0c1f4 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 23 Jul 2019 16:58:54 +0200 Subject: ASoC: Intel: Skylake: Cleanup skl_module_cfg declaration With removal of MCPS, CPS and CPC ambiguity, ibs and obs params for struct skl_module_cfg have been left unused. Update struct declaration by removing these two. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190723145854.8527-8-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 99a0277191ca..e967800dbb62 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -383,8 +383,6 @@ struct skl_module_cfg { u8 out_queue_mask; u8 in_queue; u8 out_queue; - u32 ibs; - u32 obs; u8 is_loadable; u8 core_id; u8 dev_type; -- cgit v1.2.3 From f2c8b57014038ae064a0f918f939af510f0aed02 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 25 Jul 2019 11:33:21 +0300 Subject: ASoC: pcm3168a: Allow all channels in case of parallel DIN/DOUT setup If multi DIN/DOUT mode is selected (tdm_slots == 2) then configure the channel constraint to allow all channels. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190725083321.6776-1-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 5d59ce254821..e84a1509fe65 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -599,6 +599,10 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, sample_min, 32); + /* Allow all channels in multi DIN/DOUT mode */ + if (pcm3168a->tdm_slots == 2) + channel_max = channel_maxs[tx]; + snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2, channel_max); -- cgit v1.2.3 From 816fe206138a7e3895c3a74fbd326a51df003f70 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 25 Jul 2019 11:34:11 +0300 Subject: ASoC: ti: davinci-mcasp: Add support for RIGHT_J format The formater unit's rotation needs to be programmed differently for right aligned bus format to have the data moved to the correct place. Take the opportunity and simplify the formater unit setup code. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190725083411.7211-1-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index ac59b509ead5..09ba3d3c70a0 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -465,6 +465,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, /* FS need to be inverted */ inv_fs = true; break; + case SND_SOC_DAIFMT_RIGHT_J: case SND_SOC_DAIFMT_LEFT_J: /* configure a full-word SYNC pulse (LRCLK) */ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); @@ -758,34 +759,28 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, int sample_width) { u32 fmt; - u32 tx_rotate = (sample_width / 4) & 0x7; + u32 tx_rotate, rx_rotate, slot_width; u32 mask = (1ULL << sample_width) - 1; - u32 slot_width = sample_width; - - /* - * For captured data we should not rotate, inversion and masking is - * enoguh to get the data to the right position: - * Format data from bus after reverse (XRBUF) - * S16_LE: |LSB|MSB|xxx|xxx| |xxx|xxx|MSB|LSB| - * S24_3LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| - * S24_LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| - * S32_LE: |LSB|DAT|DAT|MSB| |MSB|DAT|DAT|LSB| - */ - u32 rx_rotate = 0; + if (mcasp->slot_width) + slot_width = mcasp->slot_width; + else + slot_width = sample_width; /* - * Setting the tdm slot width either with set_clkdiv() or - * set_tdm_slot() allows us to for example send 32 bits per - * channel to the codec, while only 16 of them carry audio - * payload. + * TX rotation: + * right aligned formats: rotate w/ slot_width + * left aligned formats: rotate w/ sample_width + * + * RX rotation: + * right aligned formats: no rotation needed + * left aligned formats: rotate w/ (slot_width - sample_width) */ - if (mcasp->slot_width) { - /* - * When we have more bclk then it is needed for the - * data, we need to use the rotation to move the - * received samples to have correct alignment. - */ - slot_width = mcasp->slot_width; + if ((mcasp->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) == + SND_SOC_DAIFMT_RIGHT_J) { + tx_rotate = (slot_width / 4) & 0x7; + rx_rotate = 0; + } else { + tx_rotate = (sample_width / 4) & 0x7; rx_rotate = (slot_width - sample_width) / 4; } -- cgit v1.2.3 From b7989e271e9f7fd4edb4166cd2a79b980c4b6136 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 25 Jul 2019 11:34:32 +0300 Subject: ASoC: ti: davinci-mcasp: Improve serializer handling in multi AXR setups When multiple serializers are used we need to track the number of serializers used by the other stream direction to avoid killing data lines when the first stream used more serializers than the second would need. We are still protected against the case when the second stream uses more serializers which had affected the running stream as well. To take advantage of the improved serializer logic we need to modify the channel constraints rule as well to allow the use of multiple serializers for the second stream as additional ones will not affect the FS/BCLK on the bus. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190725083432.7419-1-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 92 +++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 39 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 09ba3d3c70a0..c3a2c53fdb3a 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -109,6 +109,7 @@ struct davinci_mcasp { /* Used for comstraint setting on the second stream */ u32 channels; + u8 active_serializers[2]; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; @@ -813,6 +814,7 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, u8 rx_ser = 0; u8 slots = mcasp->tdm_slots; u8 max_active_serializers = (channels + slots - 1) / slots; + u8 max_rx_serializers, max_tx_serializers; int active_serializers, numevt; u32 reg; /* Default configuration */ @@ -822,22 +824,28 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, if (stream == SNDRV_PCM_STREAM_PLAYBACK) { mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); + max_tx_serializers = max_active_serializers; + max_rx_serializers = + mcasp->active_serializers[SNDRV_PCM_STREAM_CAPTURE]; } else { mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS); + max_tx_serializers = + mcasp->active_serializers[SNDRV_PCM_STREAM_PLAYBACK]; + max_rx_serializers = max_active_serializers; } for (i = 0; i < mcasp->num_serializer; i++) { mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), mcasp->serial_dir[i]); if (mcasp->serial_dir[i] == TX_MODE && - tx_ser < max_active_serializers) { + tx_ser < max_tx_serializers) { mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), mcasp->dismod, DISMOD_MASK); set_bit(PIN_BIT_AXR(i), &mcasp->pdir); tx_ser++; } else if (mcasp->serial_dir[i] == RX_MODE && - rx_ser < max_active_serializers) { + rx_ser < max_rx_serializers) { clear_bit(PIN_BIT_AXR(i), &mcasp->pdir); rx_ser++; } else { @@ -884,7 +892,8 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, } else { dma_data->maxburst = 0; } - return 0; + + goto out; } if (period_words % active_serializers) { @@ -914,6 +923,9 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, numevt = 0; dma_data->maxburst = numevt; +out: + mcasp->active_serializers[stream] = active_serializers; + return 0; } @@ -1153,6 +1165,37 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, int period_size = params_period_size(params); int ret; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_U8: + case SNDRV_PCM_FORMAT_S8: + word_length = 8; + break; + + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_S16_LE: + word_length = 16; + break; + + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_S24_3LE: + word_length = 24; + break; + + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_S24_LE: + word_length = 24; + break; + + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_S32_LE: + word_length = 32; + break; + + default: + printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); + return -EINVAL; + } + ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt); if (ret) return ret; @@ -1187,37 +1230,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_U8: - case SNDRV_PCM_FORMAT_S8: - word_length = 8; - break; - - case SNDRV_PCM_FORMAT_U16_LE: - case SNDRV_PCM_FORMAT_S16_LE: - word_length = 16; - break; - - case SNDRV_PCM_FORMAT_U24_3LE: - case SNDRV_PCM_FORMAT_S24_3LE: - word_length = 24; - break; - - case SNDRV_PCM_FORMAT_U24_LE: - case SNDRV_PCM_FORMAT_S24_LE: - word_length = 24; - break; - - case SNDRV_PCM_FORMAT_U32_LE: - case SNDRV_PCM_FORMAT_S32_LE: - word_length = 32; - break; - - default: - printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); - return -EINVAL; - } - davinci_config_channel_size(mcasp, word_length); if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) @@ -1404,12 +1416,13 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, max_channels *= tdm_slots; /* * If the already active stream has less channels than the calculated - * limnit based on the seirializers * tdm_slots, we need to use that as - * a constraint for the second stream. - * Otherwise (first stream or less allowed channels) we use the - * calculated constraint. + * limit based on the seirializers * tdm_slots, and only one serializer + * is in use we need to use that as a constraint for the second stream. + * Otherwise (first stream or less allowed channels or more than one + * serializer in use) we use the calculated constraint. */ - if (mcasp->channels && mcasp->channels < max_channels) + if (mcasp->channels && mcasp->channels < max_channels && + ruledata->serializers == 1) max_channels = mcasp->channels; /* * But we can always allow channels upto the amount of @@ -1470,6 +1483,7 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); mcasp->substreams[substream->stream] = NULL; + mcasp->active_serializers[substream->stream] = 0; if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) return; -- cgit v1.2.3 From 5e291a908869dd4fe70832a89678c6b0c1b8c481 Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Thu, 25 Jul 2019 10:09:24 +0800 Subject: ALSA: echoaudio: Replace kmalloc + memcpy with kmemdup Instead of using kmalloc + memcpy, use kmemdup to simplify the code. Signed-off-by: Chuhong Yuan Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/echoaudio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index b612a536a5a1..ca9125726be2 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -2189,11 +2189,10 @@ static int snd_echo_resume(struct device *dev) u32 pipe_alloc_mask; int err; - commpage_bak = kmalloc(sizeof(*commpage), GFP_KERNEL); + commpage = chip->comm_page; + commpage_bak = kmemdup(commpage, sizeof(*commpage), GFP_KERNEL); if (commpage_bak == NULL) return -ENOMEM; - commpage = chip->comm_page; - memcpy(commpage_bak, commpage, sizeof(*commpage)); err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); if (err < 0) { -- cgit v1.2.3 From 5af9e972ac72b1c9f13cd35ccfb4687741c53f3e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 25 Jul 2019 15:37:43 +0200 Subject: ASoC: SOF: Makefile - fix the top-level kernel module names (add snd- prefix) Use the proper module name. The objs assignments are already there. Signed-off-by: Jaroslav Kysela Cc: Liam Girdwood Cc: Pierre-Louis Bossart Cc: Takashi Iwai Cc: Mark Brown 0 Link: https://lore.kernel.org/r/20190725133743.22145-1-perex@perex.cz Signed-off-by: Mark Brown --- sound/soc/sof/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 8f14c9d2950b..585fb6917489 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -11,8 +11,8 @@ obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o -obj-$(CONFIG_SND_SOC_SOF_ACPI) += sof-acpi-dev.o -obj-$(CONFIG_SND_SOC_SOF_PCI) += sof-pci-dev.o +obj-$(CONFIG_SND_SOC_SOF_ACPI) += snd-sof-acpi.o +obj-$(CONFIG_SND_SOC_SOF_PCI) += snd-sof-pci.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ -- cgit v1.2.3 From 01ec57a4371e573bfcfa898307af098a8c6f9dcf Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 25 Jul 2019 17:39:29 +0100 Subject: ASoC: wm_adsp: Allow bus error handler to be called directly There is no need for end drivers to add helper functions to allow the bus error handler to be called, simply update the prototype so it can be called directly. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20190725163931.24964-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l90.c | 9 +-------- sound/soc/codecs/wm_adsp.c | 6 ++++-- sound/soc/codecs/wm_adsp.h | 4 ++-- 3 files changed, 7 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index c4ecb0e6911a..67cac60a859d 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -2402,13 +2402,6 @@ static irqreturn_t cs47l90_adsp2_irq(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t cs47l90_dsp_bus_error(int irq, void *data) -{ - struct wm_adsp *dsp = (struct wm_adsp *)data; - - return wm_adsp2_bus_error(dsp); -} - static int cs47l90_component_probe(struct snd_soc_component *component) { struct cs47l90 *cs47l90 = snd_soc_component_get_drvdata(component); @@ -2558,7 +2551,7 @@ static int cs47l90_probe(struct platform_device *pdev) if (ret == 0) { ret = madera_init_bus_error_irq(&cs47l90->core, i, - cs47l90_dsp_bus_error); + wm_adsp2_bus_error); if (ret != 0) wm_adsp2_remove(&cs47l90->core.adsp[i]); } diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index f5fbadc5e7e2..ae28d9907c30 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -4242,8 +4242,9 @@ static void wm_adsp_fatal_error(struct wm_adsp *dsp) } } -irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp) +irqreturn_t wm_adsp2_bus_error(int irq, void *data) { + struct wm_adsp *dsp = (struct wm_adsp *)data; unsigned int val; struct regmap *regmap = dsp->regmap; int ret = 0; @@ -4307,8 +4308,9 @@ error: } EXPORT_SYMBOL_GPL(wm_adsp2_bus_error); -irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp) +irqreturn_t wm_halo_bus_error(int irq, void *data) { + struct wm_adsp *dsp = (struct wm_adsp *)data; struct regmap *regmap = dsp->regmap; unsigned int fault[6]; struct reg_sequence clear[] = { diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 3b03d1eb986f..aa634ef6c9f5 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -171,8 +171,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, int wm_adsp_early_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp); -irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp); +irqreturn_t wm_adsp2_bus_error(int irq, void *data); +irqreturn_t wm_halo_bus_error(int irq, void *data); irqreturn_t wm_halo_wdt_expire(int irq, void *data); int wm_adsp_event(struct snd_soc_dapm_widget *w, -- cgit v1.2.3 From 9cba2d6a144741ad99bfa379337bb984a8ed94bd Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 25 Jul 2019 17:39:30 +0100 Subject: ASoC: cs47l15: Add codec driver for Cirrus Logic CS47L15 Adds the codec driver for the CS47L15 SmartCodec. This is a multi-functional codec based on the Cirrus Logic Madera platform. Signed-off-by: Richard Fitzgerald Signed-off-by: Jaswinder Jassal Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20190725163931.24964-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs47l15.c | 1490 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/madera.c | 4 + 4 files changed, 1502 insertions(+) create mode 100644 sound/soc/codecs/cs47l15.c (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9f89a5346299..dc23476d2eea 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -70,6 +70,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS43130 if I2C select SND_SOC_CS4341 if SND_SOC_I2C_AND_SPI select SND_SOC_CS4349 if I2C + select SND_SOC_CS47L15 if MFD_CS47L15 select SND_SOC_CS47L24 if MFD_CS47L24 select SND_SOC_CS47L35 if MFD_CS47L35 select SND_SOC_CS47L85 if MFD_CS47L85 @@ -581,6 +582,9 @@ config SND_SOC_CS4349 tristate "Cirrus Logic CS4349 CODEC" depends on I2C +config SND_SOC_CS47L15 + tristate + config SND_SOC_CS47L24 tristate @@ -722,9 +726,11 @@ config SND_SOC_LOCHNAGAR_SC config SND_SOC_MADERA tristate + default y if SND_SOC_CS47L15=y default y if SND_SOC_CS47L35=y default y if SND_SOC_CS47L85=y default y if SND_SOC_CS47L90=y + default m if SND_SOC_CS47L15=m default m if SND_SOC_CS47L35=m default m if SND_SOC_CS47L85=m default m if SND_SOC_CS47L90=m diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5b4bb8cf4325..174346b1418a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -64,6 +64,7 @@ snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o snd-soc-cs43130-objs := cs43130.o snd-soc-cs4341-objs := cs4341.o snd-soc-cs4349-objs := cs4349.o +snd-soc-cs47l15-objs := cs47l15.o snd-soc-cs47l24-objs := cs47l24.o snd-soc-cs47l35-objs := cs47l35.o snd-soc-cs47l85-objs := cs47l85.o @@ -346,6 +347,7 @@ obj-$(CONFIG_SND_SOC_CS43130) += snd-soc-cs43130.o obj-$(CONFIG_SND_SOC_CS4341) += snd-soc-cs4341.o obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o +obj-$(CONFIG_SND_SOC_CS47L15) += snd-soc-cs47l15.o obj-$(CONFIG_SND_SOC_CS47L35) += snd-soc-cs47l35.o obj-$(CONFIG_SND_SOC_CS47L85) += snd-soc-cs47l85.o obj-$(CONFIG_SND_SOC_CS47L90) += snd-soc-cs47l90.o diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c new file mode 100644 index 000000000000..ece1276f38eb --- /dev/null +++ b/sound/soc/codecs/cs47l15.c @@ -0,0 +1,1490 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// ALSA SoC Audio driver for CS47L15 codec +// +// Copyright (C) 2016-2019 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "madera.h" +#include "wm_adsp.h" + +#define CS47L15_NUM_ADSP 1 +#define CS47L15_MONO_OUTPUTS 1 + +/* Mid-mode registers */ +#define CS47L15_ADC_INT_BIAS_MASK 0x3800 +#define CS47L15_ADC_INT_BIAS_SHIFT 11 +#define CS47L15_PGA_BIAS_SEL_MASK 0x03 +#define CS47L15_PGA_BIAS_SEL_SHIFT 0 + +#define DRV_NAME "cs47l15-codec" + +struct cs47l15 { + struct madera_priv core; + struct madera_fll fll[2]; + + bool in1_lp_mode; +}; + +static const struct wm_adsp_region cs47l15_dsp1_regions[] = { + { .type = WMFW_ADSP2_PM, .base = 0x080000 }, + { .type = WMFW_ADSP2_ZM, .base = 0x0e0000 }, + { .type = WMFW_ADSP2_XM, .base = 0x0a0000 }, + { .type = WMFW_ADSP2_YM, .base = 0x0c0000 }, +}; + +static const char * const cs47l15_outdemux_texts[] = { + "HPOUT", + "EPOUT", +}; + +static SOC_ENUM_SINGLE_DECL(cs47l15_outdemux_enum, SND_SOC_NOPM, 0, + cs47l15_outdemux_texts); + +static const struct snd_kcontrol_new cs47l15_outdemux = + SOC_DAPM_ENUM_EXT("HPOUT1 Demux", cs47l15_outdemux_enum, + madera_out1_demux_get, madera_out1_demux_put); + +static int cs47l15_adsp_power_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + struct madera_priv *priv = &cs47l15->core; + struct madera *madera = priv->madera; + unsigned int freq; + int ret; + + ret = regmap_read(madera->regmap, MADERA_DSP_CLOCK_2, &freq); + if (ret != 0) { + dev_err(madera->dev, + "Failed to read MADERA_DSP_CLOCK_2: %d\n", ret); + return ret; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = madera_set_adsp_clk(&cs47l15->core, w->shift, freq); + if (ret) + return ret; + break; + default: + break; + } + + return wm_adsp_early_event(w, kcontrol, event); +} + +#define CS47L15_NG_SRC(name, base) \ + SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \ + SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \ + SOC_SINGLE(name " NG SPKOUTL Switch", base, 6, 1, 0), \ + SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \ + SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0) + +static int cs47l15_in1_adc_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = !!cs47l15->in1_lp_mode; + + return 0; +} + +static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + + switch (ucontrol->value.integer.value[0]) { + case 0: + /* Set IN1 to normal mode */ + snd_soc_component_update_bits(component, MADERA_DMIC1L_CONTROL, + MADERA_IN1_OSR_MASK, + 5 << MADERA_IN1_OSR_SHIFT); + snd_soc_component_update_bits(component, CS47L15_ADC_INT_BIAS, + CS47L15_ADC_INT_BIAS_MASK, + 4 << CS47L15_ADC_INT_BIAS_SHIFT); + snd_soc_component_update_bits(component, CS47L15_PGA_BIAS_SEL, + CS47L15_PGA_BIAS_SEL_MASK, 0); + cs47l15->in1_lp_mode = false; + break; + default: + /* Set IN1 to LP mode */ + snd_soc_component_update_bits(component, MADERA_DMIC1L_CONTROL, + MADERA_IN1_OSR_MASK, + 4 << MADERA_IN1_OSR_SHIFT); + snd_soc_component_update_bits(component, CS47L15_ADC_INT_BIAS, + CS47L15_ADC_INT_BIAS_MASK, + 1 << CS47L15_ADC_INT_BIAS_SHIFT); + snd_soc_component_update_bits(component, CS47L15_PGA_BIAS_SEL, + CS47L15_PGA_BIAS_SEL_MASK, + 3 << CS47L15_PGA_BIAS_SEL_SHIFT); + cs47l15->in1_lp_mode = true; + break; + } + + return 0; +} + +static const struct snd_kcontrol_new cs47l15_snd_controls[] = { +SOC_ENUM("IN1 OSR", madera_in_dmic_osr[0]), +SOC_ENUM("IN2 OSR", madera_in_dmic_osr[1]), + +SOC_SINGLE_RANGE_TLV("IN1L Volume", MADERA_IN1L_CONTROL, + MADERA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, madera_ana_tlv), +SOC_SINGLE_RANGE_TLV("IN1R Volume", MADERA_IN1R_CONTROL, + MADERA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, madera_ana_tlv), + +SOC_ENUM("IN HPF Cutoff Frequency", madera_in_hpf_cut_enum), + +SOC_SINGLE("IN1L HPF Switch", MADERA_IN1L_CONTROL, MADERA_IN1L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN1R HPF Switch", MADERA_IN1R_CONTROL, MADERA_IN1R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2L HPF Switch", MADERA_IN2L_CONTROL, MADERA_IN2L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2R HPF Switch", MADERA_IN2R_CONTROL, MADERA_IN2R_HPF_SHIFT, 1, 0), + +SOC_SINGLE_TLV("IN1L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_1L, + MADERA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN1R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_1R, + MADERA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN2L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_2L, + MADERA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN2R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_2R, + MADERA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), + +SOC_ENUM("Input Ramp Up", madera_in_vi_ramp), +SOC_ENUM("Input Ramp Down", madera_in_vd_ramp), + +MADERA_MIXER_CONTROLS("EQ1", MADERA_EQ1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("EQ2", MADERA_EQ2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("EQ3", MADERA_EQ3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("EQ4", MADERA_EQ4MIX_INPUT_1_SOURCE), + +MADERA_EQ_CONTROL("EQ1 Coefficients", MADERA_EQ1_2), +SOC_SINGLE_TLV("EQ1 B1 Volume", MADERA_EQ1_1, MADERA_EQ1_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B2 Volume", MADERA_EQ1_1, MADERA_EQ1_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B3 Volume", MADERA_EQ1_1, MADERA_EQ1_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B4 Volume", MADERA_EQ1_2, MADERA_EQ1_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B5 Volume", MADERA_EQ1_2, MADERA_EQ1_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_EQ_CONTROL("EQ2 Coefficients", MADERA_EQ2_2), +SOC_SINGLE_TLV("EQ2 B1 Volume", MADERA_EQ2_1, MADERA_EQ2_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B2 Volume", MADERA_EQ2_1, MADERA_EQ2_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B3 Volume", MADERA_EQ2_1, MADERA_EQ2_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B4 Volume", MADERA_EQ2_2, MADERA_EQ2_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B5 Volume", MADERA_EQ2_2, MADERA_EQ2_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_EQ_CONTROL("EQ3 Coefficients", MADERA_EQ3_2), +SOC_SINGLE_TLV("EQ3 B1 Volume", MADERA_EQ3_1, MADERA_EQ3_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B2 Volume", MADERA_EQ3_1, MADERA_EQ3_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B3 Volume", MADERA_EQ3_1, MADERA_EQ3_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B4 Volume", MADERA_EQ3_2, MADERA_EQ3_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B5 Volume", MADERA_EQ3_2, MADERA_EQ3_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_EQ_CONTROL("EQ4 Coefficients", MADERA_EQ4_2), +SOC_SINGLE_TLV("EQ4 B1 Volume", MADERA_EQ4_1, MADERA_EQ4_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B2 Volume", MADERA_EQ4_1, MADERA_EQ4_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B3 Volume", MADERA_EQ4_1, MADERA_EQ4_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B4 Volume", MADERA_EQ4_2, MADERA_EQ4_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B5 Volume", MADERA_EQ4_2, MADERA_EQ4_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_MIXER_CONTROLS("DRC1L", MADERA_DRC1LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DRC1R", MADERA_DRC1RMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DRC2L", MADERA_DRC2LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DRC2R", MADERA_DRC2RMIX_INPUT_1_SOURCE), + +SND_SOC_BYTES_MASK("DRC1", MADERA_DRC1_CTRL1, 5, + MADERA_DRC1R_ENA | MADERA_DRC1L_ENA), +SND_SOC_BYTES_MASK("DRC2", MADERA_DRC2_CTRL1, 5, + MADERA_DRC2R_ENA | MADERA_DRC2L_ENA), + +MADERA_MIXER_CONTROLS("LHPF1", MADERA_HPLP1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("LHPF2", MADERA_HPLP2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("LHPF3", MADERA_HPLP3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("LHPF4", MADERA_HPLP4MIX_INPUT_1_SOURCE), + +MADERA_LHPF_CONTROL("LHPF1 Coefficients", MADERA_HPLPF1_2), +MADERA_LHPF_CONTROL("LHPF2 Coefficients", MADERA_HPLPF2_2), +MADERA_LHPF_CONTROL("LHPF3 Coefficients", MADERA_HPLPF3_2), +MADERA_LHPF_CONTROL("LHPF4 Coefficients", MADERA_HPLPF4_2), + +SOC_ENUM("LHPF1 Mode", madera_lhpf1_mode), +SOC_ENUM("LHPF2 Mode", madera_lhpf2_mode), +SOC_ENUM("LHPF3 Mode", madera_lhpf3_mode), +SOC_ENUM("LHPF4 Mode", madera_lhpf4_mode), + +MADERA_RATE_ENUM("ISRC1 FSL", madera_isrc_fsl[0]), +MADERA_RATE_ENUM("ISRC2 FSL", madera_isrc_fsl[1]), +MADERA_RATE_ENUM("ISRC1 FSH", madera_isrc_fsh[0]), +MADERA_RATE_ENUM("ISRC2 FSH", madera_isrc_fsh[1]), + +WM_ADSP2_PRELOAD_SWITCH("DSP1", 1), + +MADERA_MIXER_CONTROLS("DSP1L", MADERA_DSP1LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DSP1R", MADERA_DSP1RMIX_INPUT_1_SOURCE), + +SOC_SINGLE_TLV("Noise Generator Volume", MADERA_COMFORT_NOISE_GENERATOR, + MADERA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, madera_noise_tlv), + +MADERA_MIXER_CONTROLS("HPOUT1L", MADERA_OUT1LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("HPOUT1R", MADERA_OUT1RMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SPKOUTL", MADERA_OUT4LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SPKDAT1L", MADERA_OUT5LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SPKDAT1R", MADERA_OUT5RMIX_INPUT_1_SOURCE), + +SOC_SINGLE("HPOUT1 SC Protect Switch", MADERA_HP1_SHORT_CIRCUIT_CTRL, + MADERA_HP1_SC_ENA_SHIFT, 1, 0), + +SOC_SINGLE("SPKDAT1 High Performance Switch", MADERA_OUTPUT_PATH_CONFIG_5L, + MADERA_OUT5_OSR_SHIFT, 1, 0), + +SOC_DOUBLE_R("HPOUT1 Digital Switch", MADERA_DAC_DIGITAL_VOLUME_1L, + MADERA_DAC_DIGITAL_VOLUME_1R, MADERA_OUT1L_MUTE_SHIFT, 1, 1), +SOC_SINGLE("Speaker Digital Switch", MADERA_DAC_DIGITAL_VOLUME_4L, + MADERA_OUT4L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("SPKDAT1 Digital Switch", MADERA_DAC_DIGITAL_VOLUME_5L, + MADERA_DAC_DIGITAL_VOLUME_5R, MADERA_OUT5L_MUTE_SHIFT, 1, 1), + +SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_1L, + MADERA_DAC_DIGITAL_VOLUME_1R, MADERA_OUT1L_VOL_SHIFT, + 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("Speaker Digital Volume", MADERA_DAC_DIGITAL_VOLUME_4L, + MADERA_OUT4L_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_5L, + MADERA_DAC_DIGITAL_VOLUME_5R, MADERA_OUT5L_VOL_SHIFT, + 0xbf, 0, madera_digital_tlv), + +SOC_DOUBLE("SPKDAT1 Switch", MADERA_PDM_SPK1_CTRL_1, MADERA_SPK1L_MUTE_SHIFT, + MADERA_SPK1R_MUTE_SHIFT, 1, 1), + +SOC_ENUM("Output Ramp Up", madera_out_vi_ramp), +SOC_ENUM("Output Ramp Down", madera_out_vd_ramp), + +SOC_SINGLE("Noise Gate Switch", MADERA_NOISE_GATE_CONTROL, + MADERA_NGATE_ENA_SHIFT, 1, 0), +SOC_SINGLE_TLV("Noise Gate Threshold Volume", MADERA_NOISE_GATE_CONTROL, + MADERA_NGATE_THR_SHIFT, 7, 1, madera_ng_tlv), +SOC_ENUM("Noise Gate Hold", madera_ng_hold), + +SOC_SINGLE_BOOL_EXT("IN1 LP Mode Switch", 0, + cs47l15_in1_adc_get, cs47l15_in1_adc_put), + +CS47L15_NG_SRC("HPOUT1L", MADERA_NOISE_GATE_SELECT_1L), +CS47L15_NG_SRC("HPOUT1R", MADERA_NOISE_GATE_SELECT_1R), +CS47L15_NG_SRC("SPKOUTL", MADERA_NOISE_GATE_SELECT_4L), +CS47L15_NG_SRC("SPKDAT1L", MADERA_NOISE_GATE_SELECT_5L), +CS47L15_NG_SRC("SPKDAT1R", MADERA_NOISE_GATE_SELECT_5R), + +MADERA_MIXER_CONTROLS("AIF1TX1", MADERA_AIF1TX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX2", MADERA_AIF1TX2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX3", MADERA_AIF1TX3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX4", MADERA_AIF1TX4MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX5", MADERA_AIF1TX5MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX6", MADERA_AIF1TX6MIX_INPUT_1_SOURCE), + +MADERA_MIXER_CONTROLS("AIF2TX1", MADERA_AIF2TX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX2", MADERA_AIF2TX2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX3", MADERA_AIF2TX3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX4", MADERA_AIF2TX4MIX_INPUT_1_SOURCE), + +MADERA_MIXER_CONTROLS("AIF3TX1", MADERA_AIF3TX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF3TX2", MADERA_AIF3TX2MIX_INPUT_1_SOURCE), + +MADERA_GAINMUX_CONTROLS("SPDIF1TX1", MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE), +MADERA_GAINMUX_CONTROLS("SPDIF1TX2", MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE), + +WM_ADSP_FW_CONTROL("DSP1", 0), +}; + +MADERA_MIXER_ENUMS(EQ1, MADERA_EQ1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(EQ2, MADERA_EQ2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(EQ3, MADERA_EQ3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(EQ4, MADERA_EQ4MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(DRC1L, MADERA_DRC1LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DRC1R, MADERA_DRC1RMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DRC2L, MADERA_DRC2LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DRC2R, MADERA_DRC2RMIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(LHPF1, MADERA_HPLP1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(LHPF2, MADERA_HPLP2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(LHPF3, MADERA_HPLP3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(LHPF4, MADERA_HPLP4MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(DSP1L, MADERA_DSP1LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DSP1R, MADERA_DSP1RMIX_INPUT_1_SOURCE); +MADERA_DSP_AUX_ENUMS(DSP1, MADERA_DSP1AUX1MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(PWM1, MADERA_PWM1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(PWM2, MADERA_PWM2MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(OUT1L, MADERA_OUT1LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(OUT1R, MADERA_OUT1RMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SPKOUTL, MADERA_OUT4LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SPKDAT1L, MADERA_OUT5LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SPKDAT1R, MADERA_OUT5RMIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(AIF1TX1, MADERA_AIF1TX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX2, MADERA_AIF1TX2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX3, MADERA_AIF1TX3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX4, MADERA_AIF1TX4MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX5, MADERA_AIF1TX5MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX6, MADERA_AIF1TX6MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(AIF2TX1, MADERA_AIF2TX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX2, MADERA_AIF2TX2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX3, MADERA_AIF2TX3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX4, MADERA_AIF2TX4MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(AIF3TX1, MADERA_AIF3TX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF3TX2, MADERA_AIF3TX2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(SPD1TX1, MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(SPD1TX2, MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC1INT1, MADERA_ISRC1INT1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1INT2, MADERA_ISRC1INT2MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1INT3, MADERA_ISRC1INT3MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1INT4, MADERA_ISRC1INT4MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC1DEC1, MADERA_ISRC1DEC1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1DEC2, MADERA_ISRC1DEC2MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1DEC3, MADERA_ISRC1DEC3MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1DEC4, MADERA_ISRC1DEC4MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC2INT1, MADERA_ISRC2INT1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2INT2, MADERA_ISRC2INT2MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2INT3, MADERA_ISRC2INT3MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2INT4, MADERA_ISRC2INT4MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC2DEC1, MADERA_ISRC2DEC1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2DEC2, MADERA_ISRC2DEC2MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2DEC3, MADERA_ISRC2DEC3MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2DEC4, MADERA_ISRC2DEC4MIX_INPUT_1_SOURCE); + +static const char * const cs47l15_aec_loopback_texts[] = { + "HPOUT1L", "HPOUT1R", "SPKOUTL", "SPKDAT1L", "SPKDAT1R", +}; + +static const unsigned int cs47l15_aec_loopback_values[] = { + 0, 1, 6, 8, 9, +}; + +static const struct soc_enum cs47l15_aec1_loopback = + SOC_VALUE_ENUM_SINGLE(MADERA_DAC_AEC_CONTROL_1, + MADERA_AEC1_LOOPBACK_SRC_SHIFT, 0xf, + ARRAY_SIZE(cs47l15_aec_loopback_texts), + cs47l15_aec_loopback_texts, + cs47l15_aec_loopback_values); + +static const struct soc_enum cs47l15_aec2_loopback = + SOC_VALUE_ENUM_SINGLE(MADERA_DAC_AEC_CONTROL_2, + MADERA_AEC2_LOOPBACK_SRC_SHIFT, 0xf, + ARRAY_SIZE(cs47l15_aec_loopback_texts), + cs47l15_aec_loopback_texts, + cs47l15_aec_loopback_values); + +static const struct snd_kcontrol_new cs47l15_aec_loopback_mux[] = { + SOC_DAPM_ENUM("AEC1 Loopback", cs47l15_aec1_loopback), + SOC_DAPM_ENUM("AEC2 Loopback", cs47l15_aec2_loopback), +}; + +static const struct snd_soc_dapm_widget cs47l15_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("SYSCLK", MADERA_SYSTEM_CLOCK_1, MADERA_SYSCLK_ENA_SHIFT, + 0, madera_sysclk_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_SUPPLY("OPCLK", MADERA_OUTPUT_SYSTEM_CLOCK, + MADERA_OPCLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, + MADERA_DSP_CLK_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD1", 20, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS), +SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDD", 0, 0), + +SND_SOC_DAPM_SUPPLY("MICBIAS1", MADERA_MIC_BIAS_CTRL_1, + MADERA_MICB1_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("MICBIAS1A", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1A_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS1B", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1B_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS1C", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1C_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("FXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_FX, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("ISRC1CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_ISRC1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("ISRC2CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_ISRC2, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("OUTCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_OUT, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("SPDCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_SPD, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_DSP1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF1TXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_AIF1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF2TXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_AIF2, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF3TXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_AIF3, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("PWMCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_PWM, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + +SND_SOC_DAPM_SIGGEN("TONE"), +SND_SOC_DAPM_SIGGEN("NOISE"), + +SND_SOC_DAPM_INPUT("IN1ALN"), +SND_SOC_DAPM_INPUT("IN1ALP"), +SND_SOC_DAPM_INPUT("IN1BLN"), +SND_SOC_DAPM_INPUT("IN1BLP"), +SND_SOC_DAPM_INPUT("IN1ARN"), +SND_SOC_DAPM_INPUT("IN1ARP"), +SND_SOC_DAPM_INPUT("IN1BRN"), +SND_SOC_DAPM_INPUT("IN1BRP"), +SND_SOC_DAPM_INPUT("IN2N"), +SND_SOC_DAPM_INPUT("IN2P"), +SND_SOC_DAPM_INPUT("SPKRXDAT"), + +SND_SOC_DAPM_MUX("IN1L Analog Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[0]), +SND_SOC_DAPM_MUX("IN1R Analog Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[1]), + +SND_SOC_DAPM_MUX("IN1L Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[0]), +SND_SOC_DAPM_MUX("IN1R Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[0]), + +SND_SOC_DAPM_MUX("IN2L Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[1]), +SND_SOC_DAPM_MUX("IN2R Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[1]), + +SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), +SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"), + +SND_SOC_DAPM_OUTPUT("DSP Trigger Out"), + +SND_SOC_DAPM_DEMUX("HPOUT1 Demux", SND_SOC_NOPM, 0, 0, &cs47l15_outdemux), + +SND_SOC_DAPM_PGA("PWM1 Driver", MADERA_PWM_DRIVE_1, MADERA_PWM1_ENA_SHIFT, + 0, NULL, 0), +SND_SOC_DAPM_PGA("PWM2 Driver", MADERA_PWM_DRIVE_1, MADERA_PWM2_ENA_SHIFT, + 0, NULL, 0), + +SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX6_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX4_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, + MADERA_AIF3_TX_ENABLES, MADERA_AIF3TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, + MADERA_AIF3_TX_ENABLES, MADERA_AIF3TX2_ENA_SHIFT, 0), + +SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, + MADERA_OUT1L_ENA_SHIFT, 0, NULL, 0, madera_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, + MADERA_OUT1R_ENA_SHIFT, 0, NULL, 0, madera_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM, + MADERA_OUT4L_ENA_SHIFT, 0, NULL, 0, madera_spk_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT5L", MADERA_OUTPUT_ENABLES_1, + MADERA_OUT5L_ENA_SHIFT, 0, NULL, 0, madera_out_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT5R", MADERA_OUTPUT_ENABLES_1, + MADERA_OUT5R_ENA_SHIFT, 0, NULL, 0, madera_out_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + +SND_SOC_DAPM_PGA("SPD1TX1", MADERA_SPD1_TX_CONTROL, + MADERA_SPD1_VAL1_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("SPD1TX2", MADERA_SPD1_TX_CONTROL, + MADERA_SPD1_VAL2_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_OUT_DRV("SPD1", MADERA_SPD1_TX_CONTROL, + MADERA_SPD1_ENA_SHIFT, 0, NULL, 0), + +/* + * mux_in widgets : arranged in the order of sources + * specified in MADERA_MIXER_INPUT_ROUTES + */ + +SND_SOC_DAPM_PGA("Noise Generator", MADERA_COMFORT_NOISE_GENERATOR, + MADERA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("Tone Generator 1", MADERA_TONE_GENERATOR_1, + MADERA_TONE1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("Tone Generator 2", MADERA_TONE_GENERATOR_1, + MADERA_TONE2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SIGGEN("HAPTICS"), + +SND_SOC_DAPM_MUX("AEC1 Loopback", MADERA_DAC_AEC_CONTROL_1, + MADERA_AEC1_LOOPBACK_ENA_SHIFT, 0, + &cs47l15_aec_loopback_mux[0]), +SND_SOC_DAPM_MUX("AEC2 Loopback", MADERA_DAC_AEC_CONTROL_2, + MADERA_AEC2_LOOPBACK_ENA_SHIFT, 0, + &cs47l15_aec_loopback_mux[1]), + +SND_SOC_DAPM_PGA_E("IN1L", MADERA_INPUT_ENABLES, MADERA_IN1L_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN1R", MADERA_INPUT_ENABLES, MADERA_IN1R_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN2L", MADERA_INPUT_ENABLES, MADERA_IN2L_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN2R", MADERA_INPUT_ENABLES, MADERA_IN2R_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + +SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX6_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX4_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, + MADERA_AIF3_RX_ENABLES, MADERA_AIF3RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, + MADERA_AIF3_RX_ENABLES, MADERA_AIF3RX2_ENA_SHIFT, 0), + +SND_SOC_DAPM_PGA("EQ1", MADERA_EQ1_1, MADERA_EQ1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ2", MADERA_EQ2_1, MADERA_EQ2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ3", MADERA_EQ3_1, MADERA_EQ3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ4", MADERA_EQ4_1, MADERA_EQ4_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("DRC1L", MADERA_DRC1_CTRL1, MADERA_DRC1L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC1R", MADERA_DRC1_CTRL1, MADERA_DRC1R_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC2L", MADERA_DRC2_CTRL1, MADERA_DRC2L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC2R", MADERA_DRC2_CTRL1, MADERA_DRC2R_ENA_SHIFT, 0, + NULL, 0), + +SND_SOC_DAPM_PGA("LHPF1", MADERA_HPLPF1_1, MADERA_LHPF1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("LHPF2", MADERA_HPLPF2_1, MADERA_LHPF2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("LHPF3", MADERA_HPLPF3_1, MADERA_LHPF3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("LHPF4", MADERA_HPLPF4_1, MADERA_LHPF4_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC1DEC1", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC2", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC3", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC4", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_DEC4_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC1INT1", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT2", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT3", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT4", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_INT4_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2DEC1", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC2", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC3", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC4", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_DEC4_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2INT1", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT2", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT3", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT4", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_INT4_ENA_SHIFT, 0, NULL, 0), + +WM_ADSP2("DSP1", 0, cs47l15_adsp_power_ev), + +/* end of ordered widget list */ + +MADERA_MIXER_WIDGETS(EQ1, "EQ1"), +MADERA_MIXER_WIDGETS(EQ2, "EQ2"), +MADERA_MIXER_WIDGETS(EQ3, "EQ3"), +MADERA_MIXER_WIDGETS(EQ4, "EQ4"), + +MADERA_MIXER_WIDGETS(DRC1L, "DRC1L"), +MADERA_MIXER_WIDGETS(DRC1R, "DRC1R"), +MADERA_MIXER_WIDGETS(DRC2L, "DRC2L"), +MADERA_MIXER_WIDGETS(DRC2R, "DRC2R"), + +SND_SOC_DAPM_SWITCH("DRC1 Activity Output", SND_SOC_NOPM, 0, 0, + &madera_drc_activity_output_mux[0]), +SND_SOC_DAPM_SWITCH("DRC2 Activity Output", SND_SOC_NOPM, 0, 0, + &madera_drc_activity_output_mux[1]), + +MADERA_MIXER_WIDGETS(LHPF1, "LHPF1"), +MADERA_MIXER_WIDGETS(LHPF2, "LHPF2"), +MADERA_MIXER_WIDGETS(LHPF3, "LHPF3"), +MADERA_MIXER_WIDGETS(LHPF4, "LHPF4"), + +MADERA_MIXER_WIDGETS(PWM1, "PWM1"), +MADERA_MIXER_WIDGETS(PWM2, "PWM2"), + +MADERA_MIXER_WIDGETS(OUT1L, "HPOUT1L"), +MADERA_MIXER_WIDGETS(OUT1R, "HPOUT1R"), +MADERA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"), +MADERA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"), +MADERA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"), + +MADERA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"), +MADERA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"), +MADERA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"), +MADERA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"), +MADERA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"), +MADERA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"), + +MADERA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"), +MADERA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), +MADERA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"), +MADERA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"), + +MADERA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), +MADERA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), + +MADERA_MUX_WIDGETS(SPD1TX1, "SPDIF1TX1"), +MADERA_MUX_WIDGETS(SPD1TX2, "SPDIF1TX2"), + +MADERA_DSP_WIDGETS(DSP1, "DSP1"), + +SND_SOC_DAPM_SWITCH("DSP1 Trigger Output", SND_SOC_NOPM, 0, 0, + &madera_dsp_trigger_output_mux[0]), + +MADERA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"), +MADERA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"), +MADERA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"), +MADERA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"), + +MADERA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"), +MADERA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"), +MADERA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"), +MADERA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"), + +MADERA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"), +MADERA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"), +MADERA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"), +MADERA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"), + +MADERA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), +MADERA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), +MADERA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"), +MADERA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"), + +SND_SOC_DAPM_OUTPUT("HPOUTL"), +SND_SOC_DAPM_OUTPUT("HPOUTR"), +SND_SOC_DAPM_OUTPUT("EPOUTP"), +SND_SOC_DAPM_OUTPUT("EPOUTN"), +SND_SOC_DAPM_OUTPUT("SPKOUTN"), +SND_SOC_DAPM_OUTPUT("SPKOUTP"), +SND_SOC_DAPM_OUTPUT("SPKDAT1L"), +SND_SOC_DAPM_OUTPUT("SPKDAT1R"), +SND_SOC_DAPM_OUTPUT("SPDIF1"), + +SND_SOC_DAPM_OUTPUT("MICSUPP"), +}; + +#define MADERA_MIXER_INPUT_ROUTES(name) \ + { name, "Noise Generator", "Noise Generator" }, \ + { name, "Tone Generator 1", "Tone Generator 1" }, \ + { name, "Tone Generator 2", "Tone Generator 2" }, \ + { name, "Haptics", "HAPTICS" }, \ + { name, "AEC1", "AEC1 Loopback" }, \ + { name, "AEC2", "AEC2 Loopback" }, \ + { name, "IN1L", "IN1L" }, \ + { name, "IN1R", "IN1R" }, \ + { name, "IN2L", "IN2L" }, \ + { name, "IN2R", "IN2R" }, \ + { name, "AIF1RX1", "AIF1RX1" }, \ + { name, "AIF1RX2", "AIF1RX2" }, \ + { name, "AIF1RX3", "AIF1RX3" }, \ + { name, "AIF1RX4", "AIF1RX4" }, \ + { name, "AIF1RX5", "AIF1RX5" }, \ + { name, "AIF1RX6", "AIF1RX6" }, \ + { name, "AIF2RX1", "AIF2RX1" }, \ + { name, "AIF2RX2", "AIF2RX2" }, \ + { name, "AIF2RX3", "AIF2RX3" }, \ + { name, "AIF2RX4", "AIF2RX4" }, \ + { name, "AIF3RX1", "AIF3RX1" }, \ + { name, "AIF3RX2", "AIF3RX2" }, \ + { name, "EQ1", "EQ1" }, \ + { name, "EQ2", "EQ2" }, \ + { name, "EQ3", "EQ3" }, \ + { name, "EQ4", "EQ4" }, \ + { name, "DRC1L", "DRC1L" }, \ + { name, "DRC1R", "DRC1R" }, \ + { name, "DRC2L", "DRC2L" }, \ + { name, "DRC2R", "DRC2R" }, \ + { name, "LHPF1", "LHPF1" }, \ + { name, "LHPF2", "LHPF2" }, \ + { name, "LHPF3", "LHPF3" }, \ + { name, "LHPF4", "LHPF4" }, \ + { name, "ISRC1DEC1", "ISRC1DEC1" }, \ + { name, "ISRC1DEC2", "ISRC1DEC2" }, \ + { name, "ISRC1DEC3", "ISRC1DEC3" }, \ + { name, "ISRC1DEC4", "ISRC1DEC4" }, \ + { name, "ISRC1INT1", "ISRC1INT1" }, \ + { name, "ISRC1INT2", "ISRC1INT2" }, \ + { name, "ISRC1INT3", "ISRC1INT3" }, \ + { name, "ISRC1INT4", "ISRC1INT4" }, \ + { name, "ISRC2DEC1", "ISRC2DEC1" }, \ + { name, "ISRC2DEC2", "ISRC2DEC2" }, \ + { name, "ISRC2DEC3", "ISRC2DEC3" }, \ + { name, "ISRC2DEC4", "ISRC2DEC4" }, \ + { name, "ISRC2INT1", "ISRC2INT1" }, \ + { name, "ISRC2INT2", "ISRC2INT2" }, \ + { name, "ISRC2INT3", "ISRC2INT3" }, \ + { name, "ISRC2INT4", "ISRC2INT4" }, \ + { name, "DSP1.1", "DSP1" }, \ + { name, "DSP1.2", "DSP1" }, \ + { name, "DSP1.3", "DSP1" }, \ + { name, "DSP1.4", "DSP1" }, \ + { name, "DSP1.5", "DSP1" }, \ + { name, "DSP1.6", "DSP1" } + +static const struct snd_soc_dapm_route cs47l15_dapm_routes[] = { + /* Internal clock domains */ + { "EQ1", NULL, "FXCLK" }, + { "EQ2", NULL, "FXCLK" }, + { "EQ3", NULL, "FXCLK" }, + { "EQ4", NULL, "FXCLK" }, + { "DRC1L", NULL, "FXCLK" }, + { "DRC1R", NULL, "FXCLK" }, + { "DRC2L", NULL, "FXCLK" }, + { "DRC2R", NULL, "FXCLK" }, + { "LHPF1", NULL, "FXCLK" }, + { "LHPF2", NULL, "FXCLK" }, + { "LHPF3", NULL, "FXCLK" }, + { "LHPF4", NULL, "FXCLK" }, + { "PWM1 Mixer", NULL, "PWMCLK" }, + { "PWM2 Mixer", NULL, "PWMCLK" }, + { "OUT1L", NULL, "OUTCLK" }, + { "OUT1R", NULL, "OUTCLK" }, + { "OUT4L", NULL, "OUTCLK" }, + { "OUT5L", NULL, "OUTCLK" }, + { "OUT5R", NULL, "OUTCLK" }, + { "AIF1TX1", NULL, "AIF1TXCLK" }, + { "AIF1TX2", NULL, "AIF1TXCLK" }, + { "AIF1TX3", NULL, "AIF1TXCLK" }, + { "AIF1TX4", NULL, "AIF1TXCLK" }, + { "AIF1TX5", NULL, "AIF1TXCLK" }, + { "AIF1TX6", NULL, "AIF1TXCLK" }, + { "AIF2TX1", NULL, "AIF2TXCLK" }, + { "AIF2TX2", NULL, "AIF2TXCLK" }, + { "AIF2TX3", NULL, "AIF2TXCLK" }, + { "AIF2TX4", NULL, "AIF2TXCLK" }, + { "AIF3TX1", NULL, "AIF3TXCLK" }, + { "AIF3TX2", NULL, "AIF3TXCLK" }, + { "SPD1TX1", NULL, "SPDCLK" }, + { "SPD1TX2", NULL, "SPDCLK" }, + { "DSP1", NULL, "DSP1CLK" }, + { "ISRC1DEC1", NULL, "ISRC1CLK" }, + { "ISRC1DEC2", NULL, "ISRC1CLK" }, + { "ISRC1DEC3", NULL, "ISRC1CLK" }, + { "ISRC1DEC4", NULL, "ISRC1CLK" }, + { "ISRC1INT1", NULL, "ISRC1CLK" }, + { "ISRC1INT2", NULL, "ISRC1CLK" }, + { "ISRC1INT3", NULL, "ISRC1CLK" }, + { "ISRC1INT4", NULL, "ISRC1CLK" }, + { "ISRC2DEC1", NULL, "ISRC2CLK" }, + { "ISRC2DEC2", NULL, "ISRC2CLK" }, + { "ISRC2DEC3", NULL, "ISRC2CLK" }, + { "ISRC2DEC4", NULL, "ISRC2CLK" }, + { "ISRC2INT1", NULL, "ISRC2CLK" }, + { "ISRC2INT2", NULL, "ISRC2CLK" }, + { "ISRC2INT3", NULL, "ISRC2CLK" }, + { "ISRC2INT4", NULL, "ISRC2CLK" }, + + { "OUT1L", NULL, "CPVDD1" }, + { "OUT1R", NULL, "CPVDD1" }, + { "OUT4L", NULL, "SPKVDD" }, + + { "OUT1L", NULL, "SYSCLK" }, + { "OUT1R", NULL, "SYSCLK" }, + { "OUT4L", NULL, "SYSCLK" }, + { "OUT5L", NULL, "SYSCLK" }, + { "OUT5R", NULL, "SYSCLK" }, + + { "SPD1", NULL, "SYSCLK" }, + { "SPD1", NULL, "SPD1TX1" }, + { "SPD1", NULL, "SPD1TX2" }, + + { "IN1L", NULL, "SYSCLK" }, + { "IN1R", NULL, "SYSCLK" }, + { "IN2L", NULL, "SYSCLK" }, + { "IN2R", NULL, "SYSCLK" }, + + { "MICBIAS1", NULL, "MICVDD" }, + + { "MICBIAS1A", NULL, "MICBIAS1" }, + { "MICBIAS1B", NULL, "MICBIAS1" }, + { "MICBIAS1C", NULL, "MICBIAS1" }, + + { "Noise Generator", NULL, "SYSCLK" }, + { "Tone Generator 1", NULL, "SYSCLK" }, + { "Tone Generator 2", NULL, "SYSCLK" }, + + { "Noise Generator", NULL, "NOISE" }, + { "Tone Generator 1", NULL, "TONE" }, + { "Tone Generator 2", NULL, "TONE" }, + + { "AIF1 Capture", NULL, "AIF1TX1" }, + { "AIF1 Capture", NULL, "AIF1TX2" }, + { "AIF1 Capture", NULL, "AIF1TX3" }, + { "AIF1 Capture", NULL, "AIF1TX4" }, + { "AIF1 Capture", NULL, "AIF1TX5" }, + { "AIF1 Capture", NULL, "AIF1TX6" }, + + { "AIF1RX1", NULL, "AIF1 Playback" }, + { "AIF1RX2", NULL, "AIF1 Playback" }, + { "AIF1RX3", NULL, "AIF1 Playback" }, + { "AIF1RX4", NULL, "AIF1 Playback" }, + { "AIF1RX5", NULL, "AIF1 Playback" }, + { "AIF1RX6", NULL, "AIF1 Playback" }, + + { "AIF2 Capture", NULL, "AIF2TX1" }, + { "AIF2 Capture", NULL, "AIF2TX2" }, + { "AIF2 Capture", NULL, "AIF2TX3" }, + { "AIF2 Capture", NULL, "AIF2TX4" }, + + { "AIF2RX1", NULL, "AIF2 Playback" }, + { "AIF2RX2", NULL, "AIF2 Playback" }, + { "AIF2RX3", NULL, "AIF2 Playback" }, + { "AIF2RX4", NULL, "AIF2 Playback" }, + + { "AIF3 Capture", NULL, "AIF3TX1" }, + { "AIF3 Capture", NULL, "AIF3TX2" }, + + { "AIF3RX1", NULL, "AIF3 Playback" }, + { "AIF3RX2", NULL, "AIF3 Playback" }, + + { "AIF1 Playback", NULL, "SYSCLK" }, + { "AIF2 Playback", NULL, "SYSCLK" }, + { "AIF3 Playback", NULL, "SYSCLK" }, + + { "AIF1 Capture", NULL, "SYSCLK" }, + { "AIF2 Capture", NULL, "SYSCLK" }, + { "AIF3 Capture", NULL, "SYSCLK" }, + + { "Audio Trace DSP", NULL, "DSP1" }, + + { "IN1L Analog Mux", "A", "IN1ALN" }, + { "IN1L Analog Mux", "A", "IN1ALP" }, + { "IN1L Analog Mux", "B", "IN1BLN" }, + { "IN1L Analog Mux", "B", "IN1BLP" }, + { "IN1R Analog Mux", "A", "IN1ARN" }, + { "IN1R Analog Mux", "A", "IN1ARP" }, + { "IN1R Analog Mux", "B", "IN1BRN" }, + { "IN1R Analog Mux", "B", "IN1BRP" }, + + { "IN1L Mode", "Analog", "IN1L Analog Mux" }, + { "IN1R Mode", "Analog", "IN1R Analog Mux" }, + + { "IN1L Mode", "Digital", "IN1ALN" }, + { "IN1L Mode", "Digital", "IN1ALP" }, + { "IN1R Mode", "Digital", "IN1ALN" }, + { "IN1R Mode", "Digital", "IN1ALP" }, + + { "IN1L", NULL, "IN1L Mode" }, + { "IN1R", NULL, "IN1R Mode" }, + + { "IN2L Mode", "Analog", "IN2N" }, + { "IN2L Mode", "Analog", "IN2P" }, + + { "IN2L Mode", "Digital", "SPKRXDAT" }, + { "IN2R Mode", "Digital", "SPKRXDAT" }, + + { "IN2L", NULL, "IN2L Mode" }, + { "IN2R", NULL, "IN2R Mode" }, + + MADERA_MIXER_ROUTES("OUT1L", "HPOUT1L"), + MADERA_MIXER_ROUTES("OUT1R", "HPOUT1R"), + MADERA_MIXER_ROUTES("OUT4L", "SPKOUTL"), + MADERA_MIXER_ROUTES("OUT5L", "SPKDAT1L"), + MADERA_MIXER_ROUTES("OUT5R", "SPKDAT1R"), + + MADERA_MIXER_ROUTES("PWM1 Driver", "PWM1"), + MADERA_MIXER_ROUTES("PWM2 Driver", "PWM2"), + + MADERA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"), + MADERA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"), + MADERA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"), + MADERA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"), + MADERA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"), + MADERA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"), + + MADERA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"), + MADERA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), + MADERA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"), + MADERA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"), + + MADERA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"), + MADERA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"), + + MADERA_MUX_ROUTES("SPD1TX1", "SPDIF1TX1"), + MADERA_MUX_ROUTES("SPD1TX2", "SPDIF1TX2"), + + MADERA_MIXER_ROUTES("EQ1", "EQ1"), + MADERA_MIXER_ROUTES("EQ2", "EQ2"), + MADERA_MIXER_ROUTES("EQ3", "EQ3"), + MADERA_MIXER_ROUTES("EQ4", "EQ4"), + + MADERA_MIXER_ROUTES("DRC1L", "DRC1L"), + MADERA_MIXER_ROUTES("DRC1R", "DRC1R"), + MADERA_MIXER_ROUTES("DRC2L", "DRC2L"), + MADERA_MIXER_ROUTES("DRC2R", "DRC2R"), + + MADERA_MIXER_ROUTES("LHPF1", "LHPF1"), + MADERA_MIXER_ROUTES("LHPF2", "LHPF2"), + MADERA_MIXER_ROUTES("LHPF3", "LHPF3"), + MADERA_MIXER_ROUTES("LHPF4", "LHPF4"), + + MADERA_DSP_ROUTES("DSP1"), + + { "DSP Trigger Out", NULL, "DSP1 Trigger Output" }, + + { "DSP1 Trigger Output", "Switch", "DSP1" }, + + MADERA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"), + MADERA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"), + MADERA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"), + MADERA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"), + + MADERA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"), + MADERA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"), + MADERA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"), + MADERA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"), + + MADERA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"), + MADERA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"), + MADERA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"), + MADERA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"), + + MADERA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"), + MADERA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"), + MADERA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"), + MADERA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"), + + { "AEC1 Loopback", "HPOUT1L", "OUT1L" }, + { "AEC1 Loopback", "HPOUT1R", "OUT1R" }, + { "AEC2 Loopback", "HPOUT1L", "OUT1L" }, + { "AEC2 Loopback", "HPOUT1R", "OUT1R" }, + { "HPOUT1 Demux", NULL, "OUT1L" }, + { "HPOUT1 Demux", NULL, "OUT1R" }, + { "HPOUTL", "HPOUT", "HPOUT1 Demux" }, + { "HPOUTR", "HPOUT", "HPOUT1 Demux" }, + { "EPOUTP", "EPOUT", "HPOUT1 Demux" }, + { "EPOUTN", "EPOUT", "HPOUT1 Demux" }, + + { "AEC1 Loopback", "SPKOUTL", "OUT4L" }, + { "AEC2 Loopback", "SPKOUTL", "OUT4L" }, + { "SPKOUTN", NULL, "OUT4L" }, + { "SPKOUTP", NULL, "OUT4L" }, + + { "AEC1 Loopback", "SPKDAT1L", "OUT5L" }, + { "AEC1 Loopback", "SPKDAT1R", "OUT5R" }, + { "AEC2 Loopback", "SPKDAT1L", "OUT5L" }, + { "AEC2 Loopback", "SPKDAT1R", "OUT5R" }, + { "SPKDAT1L", NULL, "OUT5L" }, + { "SPKDAT1R", NULL, "OUT5R" }, + + { "SPDIF1", NULL, "SPD1" }, + + { "MICSUPP", NULL, "SYSCLK" }, + + { "DRC1 Signal Activity", NULL, "DRC1 Activity Output" }, + { "DRC2 Signal Activity", NULL, "DRC2 Activity Output" }, + { "DRC1 Activity Output", "Switch", "DRC1L" }, + { "DRC1 Activity Output", "Switch", "DRC1R" }, + { "DRC2 Activity Output", "Switch", "DRC2L" }, + { "DRC2 Activity Output", "Switch", "DRC2R" }, +}; + +static int cs47l15_set_fll(struct snd_soc_component *component, int fll_id, + int source, unsigned int fref, unsigned int fout) +{ + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + + switch (fll_id) { + case MADERA_FLL1_REFCLK: + return madera_set_fll_refclk(&cs47l15->fll[0], source, fref, + fout); + case MADERA_FLLAO_REFCLK: + return madera_set_fll_ao_refclk(&cs47l15->fll[1], source, fref, + fout); + case MADERA_FLL1_SYNCCLK: + return madera_set_fll_syncclk(&cs47l15->fll[0], source, fref, + fout); + default: + return -EINVAL; + } +} + +static struct snd_soc_dai_driver cs47l15_dai[] = { + { + .name = "cs47l15-aif1", + .id = 1, + .base = MADERA_AIF1_BCLK_CTRL, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 6, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 6, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l15-aif2", + .id = 2, + .base = MADERA_AIF2_BCLK_CTRL, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 4, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l15-aif3", + .id = 3, + .base = MADERA_AIF3_BCLK_CTRL, + .playback = { + .stream_name = "AIF3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "AIF3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l15-cpu-trace", + .capture = { + .stream_name = "Audio Trace CPU", + .channels_min = 1, + .channels_max = 6, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .compress_new = snd_soc_new_compress, + }, + { + .name = "cs47l15-dsp-trace", + .capture = { + .stream_name = "Audio Trace DSP", + .channels_min = 1, + .channels_max = 6, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + }, +}; + +static int cs47l15_open(struct snd_compr_stream *stream) +{ + struct snd_soc_pcm_runtime *rtd = stream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + struct madera_priv *priv = &cs47l15->core; + struct madera *madera = priv->madera; + int n_adsp; + + if (strcmp(rtd->codec_dai->name, "cs47l15-dsp-trace") == 0) { + n_adsp = 0; + } else { + dev_err(madera->dev, + "No suitable compressed stream for DAI '%s'\n", + rtd->codec_dai->name); + return -EINVAL; + } + + return wm_adsp_compr_open(&priv->adsp[n_adsp], stream); +} + +static irqreturn_t cs47l15_adsp2_irq(int irq, void *data) +{ + struct cs47l15 *cs47l15 = data; + struct madera_priv *priv = &cs47l15->core; + struct madera *madera = priv->madera; + int ret; + + ret = wm_adsp_compr_handle_irq(&priv->adsp[0]); + if (ret == -ENODEV) { + dev_err(madera->dev, "Spurious compressed data IRQ\n"); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static int cs47l15_component_probe(struct snd_soc_component *component) +{ + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + struct madera *madera = cs47l15->core.madera; + int ret; + + snd_soc_component_init_regmap(component, madera->regmap); + + mutex_lock(&madera->dapm_ptr_lock); + madera->dapm = snd_soc_component_get_dapm(component); + mutex_unlock(&madera->dapm_ptr_lock); + + ret = madera_init_inputs(component); + if (ret) + return ret; + + ret = madera_init_outputs(component, CS47L15_MONO_OUTPUTS); + if (ret) + return ret; + + snd_soc_component_disable_pin(component, "HAPTICS"); + + ret = snd_soc_add_component_controls(component, + madera_adsp_rate_controls, + CS47L15_NUM_ADSP); + if (ret) + return ret; + + wm_adsp2_component_probe(&cs47l15->core.adsp[0], component); + + return 0; +} + +static void cs47l15_component_remove(struct snd_soc_component *component) +{ + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + struct madera *madera = cs47l15->core.madera; + + mutex_lock(&madera->dapm_ptr_lock); + madera->dapm = NULL; + mutex_unlock(&madera->dapm_ptr_lock); + + wm_adsp2_component_remove(&cs47l15->core.adsp[0], component); +} + +#define CS47L15_DIG_VU 0x0200 + +static unsigned int cs47l15_digital_vu[] = { + MADERA_DAC_DIGITAL_VOLUME_1L, + MADERA_DAC_DIGITAL_VOLUME_1R, + MADERA_DAC_DIGITAL_VOLUME_4L, + MADERA_DAC_DIGITAL_VOLUME_5L, + MADERA_DAC_DIGITAL_VOLUME_5R, +}; + +static const struct snd_compr_ops cs47l15_compr_ops = { + .open = &cs47l15_open, + .free = &wm_adsp_compr_free, + .set_params = &wm_adsp_compr_set_params, + .get_caps = &wm_adsp_compr_get_caps, + .trigger = &wm_adsp_compr_trigger, + .pointer = &wm_adsp_compr_pointer, + .copy = &wm_adsp_compr_copy, +}; + +static const struct snd_soc_component_driver soc_component_dev_cs47l15 = { + .probe = &cs47l15_component_probe, + .remove = &cs47l15_component_remove, + .set_sysclk = &madera_set_sysclk, + .set_pll = &cs47l15_set_fll, + .name = DRV_NAME, + .compr_ops = &cs47l15_compr_ops, + .controls = cs47l15_snd_controls, + .num_controls = ARRAY_SIZE(cs47l15_snd_controls), + .dapm_widgets = cs47l15_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs47l15_dapm_widgets), + .dapm_routes = cs47l15_dapm_routes, + .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) +{ + struct madera *madera = dev_get_drvdata(pdev->dev.parent); + struct cs47l15 *cs47l15; + int i, ret; + + BUILD_BUG_ON(ARRAY_SIZE(cs47l15_dai) > MADERA_MAX_DAI); + + /* quick exit if Madera irqchip driver hasn't completed probe */ + if (!madera->irq_dev) { + dev_dbg(&pdev->dev, "irqchip driver not ready\n"); + return -EPROBE_DEFER; + } + + cs47l15 = devm_kzalloc(&pdev->dev, sizeof(struct cs47l15), + GFP_KERNEL); + if (!cs47l15) + return -ENOMEM; + + platform_set_drvdata(pdev, cs47l15); + + cs47l15->core.madera = madera; + cs47l15->core.dev = &pdev->dev; + cs47l15->core.num_inputs = 4; + + ret = madera_core_init(&cs47l15->core); + if (ret) + return ret; + + ret = madera_init_overheat(&cs47l15->core); + if (ret) + goto error_core; + + ret = madera_request_irq(madera, MADERA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", cs47l15_adsp2_irq, + cs47l15); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); + goto error_overheat; + } + + ret = madera_set_irq_wake(madera, MADERA_IRQ_DSP_IRQ1, 1); + if (ret) + dev_warn(&pdev->dev, "Failed to set DSP IRQ wake: %d\n", ret); + + cs47l15->core.adsp[0].part = "cs47l15"; + cs47l15->core.adsp[0].num = 1; + cs47l15->core.adsp[0].type = WMFW_ADSP2; + cs47l15->core.adsp[0].rev = 2; + cs47l15->core.adsp[0].dev = madera->dev; + cs47l15->core.adsp[0].regmap = madera->regmap_32bit; + + cs47l15->core.adsp[0].base = MADERA_DSP1_CONFIG_1; + cs47l15->core.adsp[0].mem = cs47l15_dsp1_regions; + cs47l15->core.adsp[0].num_mems = ARRAY_SIZE(cs47l15_dsp1_regions); + + cs47l15->core.adsp[0].lock_regions = + WM_ADSP2_REGION_1 | WM_ADSP2_REGION_2 | WM_ADSP2_REGION_3; + + ret = wm_adsp2_init(&cs47l15->core.adsp[0]); + if (ret != 0) + goto error_dsp_irq; + + ret = madera_init_bus_error_irq(&cs47l15->core, 0, wm_adsp2_bus_error); + if (ret) + goto error_adsp; + + madera_init_fll(madera, 1, MADERA_FLL1_CONTROL_1 - 1, + &cs47l15->fll[0]); + madera_init_fll(madera, 4, MADERA_FLLAO_CONTROL_1 - 1, + &cs47l15->fll[1]); + + for (i = 0; i < ARRAY_SIZE(cs47l15_dai); i++) + madera_init_dai(&cs47l15->core, i); + + /* Latch volume update bits */ + for (i = 0; i < ARRAY_SIZE(cs47l15_digital_vu); i++) + regmap_update_bits(madera->regmap, cs47l15_digital_vu[i], + CS47L15_DIG_VU, CS47L15_DIG_VU); + + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + + ret = devm_snd_soc_register_component(&pdev->dev, + &soc_component_dev_cs47l15, + cs47l15_dai, + ARRAY_SIZE(cs47l15_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register component: %d\n", ret); + goto error_pm_runtime; + } + + return ret; + +error_pm_runtime: + pm_runtime_disable(&pdev->dev); + madera_free_bus_error_irq(&cs47l15->core, 0); +error_adsp: + wm_adsp2_remove(&cs47l15->core.adsp[0]); +error_dsp_irq: + madera_set_irq_wake(madera, MADERA_IRQ_DSP_IRQ1, 0); + madera_free_irq(madera, MADERA_IRQ_DSP_IRQ1, cs47l15); +error_overheat: + madera_free_overheat(&cs47l15->core); +error_core: + madera_core_free(&cs47l15->core); + + return ret; +} + +static int cs47l15_remove(struct platform_device *pdev) +{ + struct cs47l15 *cs47l15 = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + + madera_free_bus_error_irq(&cs47l15->core, 0); + + wm_adsp2_remove(&cs47l15->core.adsp[0]); + + madera_set_irq_wake(cs47l15->core.madera, MADERA_IRQ_DSP_IRQ1, 0); + madera_free_irq(cs47l15->core.madera, MADERA_IRQ_DSP_IRQ1, cs47l15); + madera_free_overheat(&cs47l15->core); + madera_core_free(&cs47l15->core); + + return 0; +} + +static struct platform_driver cs47l15_codec_driver = { + .driver = { + .name = "cs47l15-codec", + }, + .probe = &cs47l15_probe, + .remove = &cs47l15_remove, +}; + +module_platform_driver(cs47l15_codec_driver); + +MODULE_SOFTDEP("pre: madera irq-madera arizona-micsupp"); +MODULE_DESCRIPTION("ASoC CS47L15 driver"); +MODULE_AUTHOR("Richard Fitzgerald "); +MODULE_AUTHOR("Jaswinder Jassal "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cs47l15-codec"); diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c index 5f1e32a5a855..1c00e2a115bc 100644 --- a/sound/soc/codecs/madera.c +++ b/sound/soc/codecs/madera.c @@ -1041,6 +1041,10 @@ static void madera_configure_input_mode(struct madera *madera) int max_analogue_inputs, max_dmic_sup, i; switch (madera->type) { + case CS47L15: + max_analogue_inputs = 1; + max_dmic_sup = 2; + break; case CS47L35: max_analogue_inputs = 2; max_dmic_sup = 2; -- cgit v1.2.3 From 6535e831b4c867467d838f2c7866b4dce1d74679 Mon Sep 17 00:00:00 2001 From: Stuart Henderson Date: Thu, 25 Jul 2019 17:39:31 +0100 Subject: ASoC: cs47l92: Add codec driver for Cirrus Logic CS47L92 Adds the codec driver for the CS47L92 SmartCodec. This is a multi-functional codec based on the Cirrus Logic Madera platform. Signed-off-by: Stuart Henderson Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20190725163931.24964-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs47l92.c | 2039 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/madera.c | 430 +++++++++- sound/soc/codecs/madera.h | 10 + 5 files changed, 2478 insertions(+), 9 deletions(-) create mode 100644 sound/soc/codecs/cs47l92.c (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index dc23476d2eea..da4c1ae89742 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -75,6 +75,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS47L35 if MFD_CS47L35 select SND_SOC_CS47L85 if MFD_CS47L85 select SND_SOC_CS47L90 if MFD_CS47L90 + select SND_SOC_CS47L92 if MFD_CS47L92 select SND_SOC_CS53L30 if I2C select SND_SOC_CX20442 if TTY select SND_SOC_CX2072X if I2C @@ -597,6 +598,9 @@ config SND_SOC_CS47L85 config SND_SOC_CS47L90 tristate +config SND_SOC_CS47L92 + tristate + # Cirrus Logic Quad-Channel ADC config SND_SOC_CS53L30 tristate "Cirrus Logic CS53L30 CODEC" @@ -730,10 +734,12 @@ config SND_SOC_MADERA default y if SND_SOC_CS47L35=y default y if SND_SOC_CS47L85=y default y if SND_SOC_CS47L90=y + default y if SND_SOC_CS47L92=y default m if SND_SOC_CS47L15=m default m if SND_SOC_CS47L35=m default m if SND_SOC_CS47L85=m default m if SND_SOC_CS47L90=m + default m if SND_SOC_CS47L92=m config SND_SOC_MAX98088 tristate "Maxim MAX98088/9 Low-Power, Stereo Audio Codec" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 174346b1418a..9230016b0f9f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -69,6 +69,7 @@ snd-soc-cs47l24-objs := cs47l24.o snd-soc-cs47l35-objs := cs47l35.o snd-soc-cs47l85-objs := cs47l85.o snd-soc-cs47l90-objs := cs47l90.o +snd-soc-cs47l92-objs := cs47l92.o snd-soc-cs53l30-objs := cs53l30.o snd-soc-cx20442-objs := cx20442.o snd-soc-cx2072x-objs := cx2072x.o @@ -351,6 +352,7 @@ obj-$(CONFIG_SND_SOC_CS47L15) += snd-soc-cs47l15.o obj-$(CONFIG_SND_SOC_CS47L35) += snd-soc-cs47l35.o obj-$(CONFIG_SND_SOC_CS47L85) += snd-soc-cs47l85.o obj-$(CONFIG_SND_SOC_CS47L90) += snd-soc-cs47l90.o +obj-$(CONFIG_SND_SOC_CS47L92) += snd-soc-cs47l92.o obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_CX2072X) += snd-soc-cx2072x.o diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c new file mode 100644 index 000000000000..d50f75f3b3e4 --- /dev/null +++ b/sound/soc/codecs/cs47l92.c @@ -0,0 +1,2039 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// ALSA SoC Audio driver for CS47L92 codec +// +// Copyright (C) 2016-2019 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "madera.h" +#include "wm_adsp.h" + +#define CS47L92_NUM_ADSP 1 +#define CS47L92_MONO_OUTPUTS 3 + +#define DRV_NAME "cs47l92-codec" + +struct cs47l92 { + struct madera_priv core; + struct madera_fll fll[2]; +}; + +static const struct wm_adsp_region cs47l92_dsp1_regions[] = { + { .type = WMFW_ADSP2_PM, .base = 0x080000 }, + { .type = WMFW_ADSP2_ZM, .base = 0x0e0000 }, + { .type = WMFW_ADSP2_XM, .base = 0x0a0000 }, + { .type = WMFW_ADSP2_YM, .base = 0x0c0000 }, +}; + +static const char * const cs47l92_outdemux_texts[] = { + "HPOUT3", + "HPOUT4", +}; + +static int cs47l92_put_demux(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); + struct madera_priv *priv = &cs47l92->core; + struct madera *madera = priv->madera; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int ep_sel, mux, change, cur; + bool out_mono; + int ret; + + if (ucontrol->value.enumerated.item[0] > e->items - 1) + return -EINVAL; + + mux = ucontrol->value.enumerated.item[0]; + + snd_soc_dapm_mutex_lock(dapm); + + ep_sel = mux << e->shift_l; + + change = snd_soc_component_test_bits(component, MADERA_OUTPUT_ENABLES_1, + MADERA_EP_SEL_MASK, + ep_sel); + if (!change) + goto end; + + ret = regmap_read(madera->regmap, MADERA_OUTPUT_ENABLES_1, &cur); + if (ret != 0) + dev_warn(madera->dev, "Failed to read outputs: %d\n", ret); + + /* EP_SEL should not be modified while HPOUT3 or 4 is enabled */ + ret = regmap_update_bits(madera->regmap, MADERA_OUTPUT_ENABLES_1, + MADERA_OUT3L_ENA | MADERA_OUT3R_ENA, 0); + if (ret) + dev_warn(madera->dev, "Failed to disable outputs: %d\n", ret); + + usleep_range(2000, 3000); /* wait for wseq to complete */ + + ret = regmap_update_bits(madera->regmap, MADERA_OUTPUT_ENABLES_1, + MADERA_EP_SEL, ep_sel); + if (ret) { + dev_err(madera->dev, "Failed to set OUT3 demux: %d\n", ret); + } else { + out_mono = madera->pdata.codec.out_mono[2 + mux]; + + ret = madera_set_output_mode(component, 3, out_mono); + if (ret < 0) + dev_warn(madera->dev, + "Failed to set output mode: %d\n", ret); + } + + ret = regmap_update_bits(madera->regmap, MADERA_OUTPUT_ENABLES_1, + MADERA_OUT3L_ENA | MADERA_OUT3R_ENA, cur); + if (ret) { + dev_warn(madera->dev, "Failed to restore outputs: %d\n", ret); + } else { + /* wait for wseq */ + if (cur & (MADERA_OUT3L_ENA | MADERA_OUT3R_ENA)) + msleep(34); /* enable delay */ + else + usleep_range(2000, 3000); /* disable delay */ + } + +end: + snd_soc_dapm_mutex_unlock(dapm); + + return snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); +} + +static SOC_ENUM_SINGLE_DECL(cs47l92_outdemux_enum, + MADERA_OUTPUT_ENABLES_1, + MADERA_EP_SEL_SHIFT, + cs47l92_outdemux_texts); + +static const struct snd_kcontrol_new cs47l92_outdemux = + SOC_DAPM_ENUM_EXT("OUT3 Demux", cs47l92_outdemux_enum, + snd_soc_dapm_get_enum_double, cs47l92_put_demux); + +static int cs47l92_adsp_power_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); + struct madera_priv *priv = &cs47l92->core; + struct madera *madera = priv->madera; + unsigned int freq; + int ret; + + ret = regmap_read(madera->regmap, MADERA_DSP_CLOCK_2, &freq); + if (ret != 0) { + dev_err(madera->dev, + "Failed to read MADERA_DSP_CLOCK_2: %d\n", ret); + return ret; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = madera_set_adsp_clk(&cs47l92->core, w->shift, freq); + if (ret) + return ret; + break; + default: + break; + } + + return wm_adsp_early_event(w, kcontrol, event); +} + +#define CS47L92_NG_SRC(name, base) \ + SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \ + SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \ + SOC_SINGLE(name " NG HPOUT2L Switch", base, 2, 1, 0), \ + SOC_SINGLE(name " NG HPOUT2R Switch", base, 3, 1, 0), \ + SOC_SINGLE(name " NG HPOUT3L Switch", base, 4, 1, 0), \ + SOC_SINGLE(name " NG HPOUT3R Switch", base, 5, 1, 0), \ + SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \ + SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0) + +static const struct snd_kcontrol_new cs47l92_snd_controls[] = { +SOC_ENUM("IN1 OSR", madera_in_dmic_osr[0]), +SOC_ENUM("IN2 OSR", madera_in_dmic_osr[1]), +SOC_ENUM("IN3 OSR", madera_in_dmic_osr[2]), +SOC_ENUM("IN4 OSR", madera_in_dmic_osr[3]), + +SOC_SINGLE_RANGE_TLV("IN1L Volume", MADERA_IN1L_CONTROL, + MADERA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, madera_ana_tlv), +SOC_SINGLE_RANGE_TLV("IN1R Volume", MADERA_IN1R_CONTROL, + MADERA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, madera_ana_tlv), +SOC_SINGLE_RANGE_TLV("IN2L Volume", MADERA_IN2L_CONTROL, + MADERA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, madera_ana_tlv), +SOC_SINGLE_RANGE_TLV("IN2R Volume", MADERA_IN2R_CONTROL, + MADERA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, madera_ana_tlv), + +SOC_ENUM("IN HPF Cutoff Frequency", madera_in_hpf_cut_enum), + +SOC_SINGLE_EXT("IN1L LP Switch", MADERA_ADC_DIGITAL_VOLUME_1L, + MADERA_IN1L_LP_MODE_SHIFT, 1, 0, + snd_soc_get_volsw, madera_lp_mode_put), +SOC_SINGLE_EXT("IN1R LP Switch", MADERA_ADC_DIGITAL_VOLUME_1R, + MADERA_IN1L_LP_MODE_SHIFT, 1, 0, + snd_soc_get_volsw, madera_lp_mode_put), +SOC_SINGLE_EXT("IN2L LP Switch", MADERA_ADC_DIGITAL_VOLUME_2L, + MADERA_IN1L_LP_MODE_SHIFT, 1, 0, + snd_soc_get_volsw, madera_lp_mode_put), +SOC_SINGLE_EXT("IN2R LP Switch", MADERA_ADC_DIGITAL_VOLUME_2R, + MADERA_IN1L_LP_MODE_SHIFT, 1, 0, + snd_soc_get_volsw, madera_lp_mode_put), + +SOC_SINGLE("IN1L HPF Switch", MADERA_IN1L_CONTROL, + MADERA_IN1L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN1R HPF Switch", MADERA_IN1R_CONTROL, + MADERA_IN1R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2L HPF Switch", MADERA_IN2L_CONTROL, + MADERA_IN2L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2R HPF Switch", MADERA_IN2R_CONTROL, + MADERA_IN2R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN3L HPF Switch", MADERA_IN3L_CONTROL, + MADERA_IN3L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN3R HPF Switch", MADERA_IN3R_CONTROL, + MADERA_IN3R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN4L HPF Switch", MADERA_IN4L_CONTROL, + MADERA_IN4L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN4R HPF Switch", MADERA_IN4R_CONTROL, + MADERA_IN4R_HPF_SHIFT, 1, 0), + +SOC_SINGLE_TLV("IN1L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_1L, + MADERA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN1R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_1R, + MADERA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN2L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_2L, + MADERA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN2R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_2R, + MADERA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN3L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_3L, + MADERA_IN3L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN3R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_3R, + MADERA_IN3R_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN4L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_4L, + MADERA_IN4L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN4R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_4R, + MADERA_IN4R_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), + +SOC_ENUM("Input Ramp Up", madera_in_vi_ramp), +SOC_ENUM("Input Ramp Down", madera_in_vd_ramp), + +MADERA_MIXER_CONTROLS("EQ1", MADERA_EQ1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("EQ2", MADERA_EQ2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("EQ3", MADERA_EQ3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("EQ4", MADERA_EQ4MIX_INPUT_1_SOURCE), + +MADERA_EQ_CONTROL("EQ1 Coefficients", MADERA_EQ1_2), +SOC_SINGLE_TLV("EQ1 B1 Volume", MADERA_EQ1_1, MADERA_EQ1_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B2 Volume", MADERA_EQ1_1, MADERA_EQ1_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B3 Volume", MADERA_EQ1_1, MADERA_EQ1_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B4 Volume", MADERA_EQ1_2, MADERA_EQ1_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B5 Volume", MADERA_EQ1_2, MADERA_EQ1_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_EQ_CONTROL("EQ2 Coefficients", MADERA_EQ2_2), +SOC_SINGLE_TLV("EQ2 B1 Volume", MADERA_EQ2_1, MADERA_EQ2_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B2 Volume", MADERA_EQ2_1, MADERA_EQ2_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B3 Volume", MADERA_EQ2_1, MADERA_EQ2_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B4 Volume", MADERA_EQ2_2, MADERA_EQ2_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B5 Volume", MADERA_EQ2_2, MADERA_EQ2_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_EQ_CONTROL("EQ3 Coefficients", MADERA_EQ3_2), +SOC_SINGLE_TLV("EQ3 B1 Volume", MADERA_EQ3_1, MADERA_EQ3_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B2 Volume", MADERA_EQ3_1, MADERA_EQ3_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B3 Volume", MADERA_EQ3_1, MADERA_EQ3_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B4 Volume", MADERA_EQ3_2, MADERA_EQ3_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B5 Volume", MADERA_EQ3_2, MADERA_EQ3_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_EQ_CONTROL("EQ4 Coefficients", MADERA_EQ4_2), +SOC_SINGLE_TLV("EQ4 B1 Volume", MADERA_EQ4_1, MADERA_EQ4_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B2 Volume", MADERA_EQ4_1, MADERA_EQ4_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B3 Volume", MADERA_EQ4_1, MADERA_EQ4_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B4 Volume", MADERA_EQ4_2, MADERA_EQ4_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B5 Volume", MADERA_EQ4_2, MADERA_EQ4_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +SOC_SINGLE("DAC High Performance Mode Switch", MADERA_OUTPUT_RATE_1, + MADERA_CP_DAC_MODE_SHIFT, 1, 0), + +MADERA_MIXER_CONTROLS("DRC1L", MADERA_DRC1LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DRC1R", MADERA_DRC1RMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DRC2L", MADERA_DRC2LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DRC2R", MADERA_DRC2RMIX_INPUT_1_SOURCE), + +SND_SOC_BYTES_MASK("DRC1", MADERA_DRC1_CTRL1, 5, + MADERA_DRC1R_ENA | MADERA_DRC1L_ENA), +SND_SOC_BYTES_MASK("DRC2", MADERA_DRC2_CTRL1, 5, + MADERA_DRC2R_ENA | MADERA_DRC2L_ENA), + +MADERA_MIXER_CONTROLS("LHPF1", MADERA_HPLP1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("LHPF2", MADERA_HPLP2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("LHPF3", MADERA_HPLP3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("LHPF4", MADERA_HPLP4MIX_INPUT_1_SOURCE), + +MADERA_LHPF_CONTROL("LHPF1 Coefficients", MADERA_HPLPF1_2), +MADERA_LHPF_CONTROL("LHPF2 Coefficients", MADERA_HPLPF2_2), +MADERA_LHPF_CONTROL("LHPF3 Coefficients", MADERA_HPLPF3_2), +MADERA_LHPF_CONTROL("LHPF4 Coefficients", MADERA_HPLPF4_2), + +SOC_ENUM("LHPF1 Mode", madera_lhpf1_mode), +SOC_ENUM("LHPF2 Mode", madera_lhpf2_mode), +SOC_ENUM("LHPF3 Mode", madera_lhpf3_mode), +SOC_ENUM("LHPF4 Mode", madera_lhpf4_mode), + +MADERA_RATE_ENUM("ISRC1 FSL", madera_isrc_fsl[0]), +MADERA_RATE_ENUM("ISRC2 FSL", madera_isrc_fsl[1]), +MADERA_RATE_ENUM("ISRC1 FSH", madera_isrc_fsh[0]), +MADERA_RATE_ENUM("ISRC2 FSH", madera_isrc_fsh[1]), +MADERA_RATE_ENUM("ASRC1 Rate 1", madera_asrc1_bidir_rate[0]), +MADERA_RATE_ENUM("ASRC1 Rate 2", madera_asrc1_bidir_rate[1]), + +WM_ADSP2_PRELOAD_SWITCH("DSP1", 1), + +MADERA_MIXER_CONTROLS("DSP1L", MADERA_DSP1LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DSP1R", MADERA_DSP1RMIX_INPUT_1_SOURCE), + +SOC_SINGLE_TLV("Noise Generator Volume", MADERA_COMFORT_NOISE_GENERATOR, + MADERA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, madera_noise_tlv), + +MADERA_MIXER_CONTROLS("HPOUT1L", MADERA_OUT1LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("HPOUT1R", MADERA_OUT1RMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("HPOUT2L", MADERA_OUT2LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("HPOUT2R", MADERA_OUT2RMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("HPOUT3L", MADERA_OUT3LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("HPOUT3R", MADERA_OUT3RMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SPKDAT1L", MADERA_OUT5LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SPKDAT1R", MADERA_OUT5RMIX_INPUT_1_SOURCE), + +SOC_SINGLE("HPOUT1 SC Protect Switch", MADERA_HP1_SHORT_CIRCUIT_CTRL, + MADERA_HP1_SC_ENA_SHIFT, 1, 0), +SOC_SINGLE("HPOUT2 SC Protect Switch", MADERA_HP2_SHORT_CIRCUIT_CTRL, + MADERA_HP2_SC_ENA_SHIFT, 1, 0), +SOC_SINGLE("HPOUT3 SC Protect Switch", MADERA_HP3_SHORT_CIRCUIT_CTRL, + MADERA_HP3_SC_ENA_SHIFT, 1, 0), + +SOC_SINGLE("SPKDAT1 High Performance Switch", MADERA_OUTPUT_PATH_CONFIG_5L, + MADERA_OUT5_OSR_SHIFT, 1, 0), + +SOC_DOUBLE_R("HPOUT1 Digital Switch", MADERA_DAC_DIGITAL_VOLUME_1L, + MADERA_DAC_DIGITAL_VOLUME_1R, MADERA_OUT1L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("HPOUT2 Digital Switch", MADERA_DAC_DIGITAL_VOLUME_2L, + MADERA_DAC_DIGITAL_VOLUME_2R, MADERA_OUT2L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("HPOUT3 Digital Switch", MADERA_DAC_DIGITAL_VOLUME_3L, + MADERA_DAC_DIGITAL_VOLUME_3R, MADERA_OUT3L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("SPKDAT1 Digital Switch", MADERA_DAC_DIGITAL_VOLUME_5L, + MADERA_DAC_DIGITAL_VOLUME_5R, MADERA_OUT5L_MUTE_SHIFT, 1, 1), + +SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_1L, + MADERA_DAC_DIGITAL_VOLUME_1R, MADERA_OUT1L_VOL_SHIFT, + 0xbf, 0, madera_digital_tlv), +SOC_DOUBLE_R_TLV("HPOUT2 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_2L, + MADERA_DAC_DIGITAL_VOLUME_2R, MADERA_OUT2L_VOL_SHIFT, + 0xbf, 0, madera_digital_tlv), +SOC_DOUBLE_R_TLV("HPOUT3 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_3L, + MADERA_DAC_DIGITAL_VOLUME_3R, MADERA_OUT3L_VOL_SHIFT, + 0xbf, 0, madera_digital_tlv), +SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_5L, + MADERA_DAC_DIGITAL_VOLUME_5R, MADERA_OUT5L_VOL_SHIFT, + 0xbf, 0, madera_digital_tlv), + +SOC_DOUBLE("SPKDAT1 Switch", MADERA_PDM_SPK1_CTRL_1, MADERA_SPK1L_MUTE_SHIFT, + MADERA_SPK1R_MUTE_SHIFT, 1, 1), + +SOC_ENUM("Output Ramp Up", madera_out_vi_ramp), +SOC_ENUM("Output Ramp Down", madera_out_vd_ramp), + +SOC_SINGLE("Noise Gate Switch", MADERA_NOISE_GATE_CONTROL, + MADERA_NGATE_ENA_SHIFT, 1, 0), +SOC_SINGLE_TLV("Noise Gate Threshold Volume", MADERA_NOISE_GATE_CONTROL, + MADERA_NGATE_THR_SHIFT, 7, 1, madera_ng_tlv), +SOC_ENUM("Noise Gate Hold", madera_ng_hold), + +SOC_ENUM_EXT("DFC1RX Width", madera_dfc_width[0], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC1RX Type", madera_dfc_type[0], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC1TX Width", madera_dfc_width[1], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC1TX Type", madera_dfc_type[1], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC2RX Width", madera_dfc_width[2], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC2RX Type", madera_dfc_type[2], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC2TX Width", madera_dfc_width[3], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC2TX Type", madera_dfc_type[3], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC3RX Width", madera_dfc_width[4], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC3RX Type", madera_dfc_type[4], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC3TX Width", madera_dfc_width[5], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC3TX Type", madera_dfc_type[5], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC4RX Width", madera_dfc_width[6], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC4RX Type", madera_dfc_type[6], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC4TX Width", madera_dfc_width[7], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC4TX Type", madera_dfc_type[7], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC5RX Width", madera_dfc_width[8], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC5RX Type", madera_dfc_type[8], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC5TX Width", madera_dfc_width[9], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC5TX Type", madera_dfc_type[9], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC6RX Width", madera_dfc_width[10], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC6RX Type", madera_dfc_type[10], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC6TX Width", madera_dfc_width[11], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC6TX Type", madera_dfc_type[11], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC7RX Width", madera_dfc_width[12], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC7RX Type", madera_dfc_type[12], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC7TX Width", madera_dfc_width[13], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC7TX Type", madera_dfc_type[13], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC8RX Width", madera_dfc_width[14], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC8RX Type", madera_dfc_type[14], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC8TX Width", madera_dfc_width[15], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC8TX Type", madera_dfc_type[15], + snd_soc_get_enum_double, madera_dfc_put), + +CS47L92_NG_SRC("HPOUT1L", MADERA_NOISE_GATE_SELECT_1L), +CS47L92_NG_SRC("HPOUT1R", MADERA_NOISE_GATE_SELECT_1R), +CS47L92_NG_SRC("HPOUT2L", MADERA_NOISE_GATE_SELECT_2L), +CS47L92_NG_SRC("HPOUT2R", MADERA_NOISE_GATE_SELECT_2R), +CS47L92_NG_SRC("HPOUT3L", MADERA_NOISE_GATE_SELECT_3L), +CS47L92_NG_SRC("HPOUT3R", MADERA_NOISE_GATE_SELECT_3R), +CS47L92_NG_SRC("SPKDAT1L", MADERA_NOISE_GATE_SELECT_5L), +CS47L92_NG_SRC("SPKDAT1R", MADERA_NOISE_GATE_SELECT_5R), + +MADERA_MIXER_CONTROLS("AIF1TX1", MADERA_AIF1TX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX2", MADERA_AIF1TX2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX3", MADERA_AIF1TX3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX4", MADERA_AIF1TX4MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX5", MADERA_AIF1TX5MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX6", MADERA_AIF1TX6MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX7", MADERA_AIF1TX7MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX8", MADERA_AIF1TX8MIX_INPUT_1_SOURCE), + +MADERA_MIXER_CONTROLS("AIF2TX1", MADERA_AIF2TX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX2", MADERA_AIF2TX2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX3", MADERA_AIF2TX3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX4", MADERA_AIF2TX4MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX5", MADERA_AIF2TX5MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX6", MADERA_AIF2TX6MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX7", MADERA_AIF2TX7MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX8", MADERA_AIF2TX8MIX_INPUT_1_SOURCE), + +MADERA_MIXER_CONTROLS("AIF3TX1", MADERA_AIF3TX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF3TX2", MADERA_AIF3TX2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF3TX3", MADERA_AIF3TX3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF3TX4", MADERA_AIF3TX4MIX_INPUT_1_SOURCE), + +MADERA_MIXER_CONTROLS("SLIMTX1", MADERA_SLIMTX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX2", MADERA_SLIMTX2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX3", MADERA_SLIMTX3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX4", MADERA_SLIMTX4MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX5", MADERA_SLIMTX5MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX6", MADERA_SLIMTX6MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX7", MADERA_SLIMTX7MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX8", MADERA_SLIMTX8MIX_INPUT_1_SOURCE), + +MADERA_GAINMUX_CONTROLS("SPDIFTX1", MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE), +MADERA_GAINMUX_CONTROLS("SPDIFTX2", MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE), + +WM_ADSP_FW_CONTROL("DSP1", 0), +}; + +MADERA_MIXER_ENUMS(EQ1, MADERA_EQ1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(EQ2, MADERA_EQ2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(EQ3, MADERA_EQ3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(EQ4, MADERA_EQ4MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(DRC1L, MADERA_DRC1LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DRC1R, MADERA_DRC1RMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DRC2L, MADERA_DRC2LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DRC2R, MADERA_DRC2RMIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(LHPF1, MADERA_HPLP1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(LHPF2, MADERA_HPLP2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(LHPF3, MADERA_HPLP3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(LHPF4, MADERA_HPLP4MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(DSP1L, MADERA_DSP1LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DSP1R, MADERA_DSP1RMIX_INPUT_1_SOURCE); +MADERA_DSP_AUX_ENUMS(DSP1, MADERA_DSP1AUX1MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(PWM1, MADERA_PWM1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(PWM2, MADERA_PWM2MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(OUT1L, MADERA_OUT1LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(OUT1R, MADERA_OUT1RMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(OUT2L, MADERA_OUT2LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(OUT2R, MADERA_OUT2RMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(OUT3L, MADERA_OUT3LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(OUT3R, MADERA_OUT3RMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SPKDAT1L, MADERA_OUT5LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SPKDAT1R, MADERA_OUT5RMIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(AIF1TX1, MADERA_AIF1TX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX2, MADERA_AIF1TX2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX3, MADERA_AIF1TX3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX4, MADERA_AIF1TX4MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX5, MADERA_AIF1TX5MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX6, MADERA_AIF1TX6MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX7, MADERA_AIF1TX7MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX8, MADERA_AIF1TX8MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(AIF2TX1, MADERA_AIF2TX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX2, MADERA_AIF2TX2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX3, MADERA_AIF2TX3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX4, MADERA_AIF2TX4MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX5, MADERA_AIF2TX5MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX6, MADERA_AIF2TX6MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX7, MADERA_AIF2TX7MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX8, MADERA_AIF2TX8MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(AIF3TX1, MADERA_AIF3TX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF3TX2, MADERA_AIF3TX2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF3TX3, MADERA_AIF3TX3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF3TX4, MADERA_AIF3TX4MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(SLIMTX1, MADERA_SLIMTX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX2, MADERA_SLIMTX2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX3, MADERA_SLIMTX3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX4, MADERA_SLIMTX4MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX5, MADERA_SLIMTX5MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX6, MADERA_SLIMTX6MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX7, MADERA_SLIMTX7MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX8, MADERA_SLIMTX8MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(SPD1TX1, MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(SPD1TX2, MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ASRC1IN1L, MADERA_ASRC1_1LMIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ASRC1IN1R, MADERA_ASRC1_1RMIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ASRC1IN2L, MADERA_ASRC1_2LMIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ASRC1IN2R, MADERA_ASRC1_2RMIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC1INT1, MADERA_ISRC1INT1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1INT2, MADERA_ISRC1INT2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC1DEC1, MADERA_ISRC1DEC1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1DEC2, MADERA_ISRC1DEC2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC2INT1, MADERA_ISRC2INT1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2INT2, MADERA_ISRC2INT2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC2DEC1, MADERA_ISRC2DEC1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2DEC2, MADERA_ISRC2DEC2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(DFC1, MADERA_DFC1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC2, MADERA_DFC2MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC3, MADERA_DFC3MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC4, MADERA_DFC4MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC5, MADERA_DFC5MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC6, MADERA_DFC6MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC7, MADERA_DFC7MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC8, MADERA_DFC8MIX_INPUT_1_SOURCE); + +static const char * const cs47l92_aec_loopback_texts[] = { + "HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R", + "SPKDAT1L", "SPKDAT1R", +}; + +static const unsigned int cs47l92_aec_loopback_values[] = { + 0, 1, 2, 3, 4, 5, 8, 9 +}; + +static const struct soc_enum cs47l92_aec_loopback = + SOC_VALUE_ENUM_SINGLE(MADERA_DAC_AEC_CONTROL_1, + MADERA_AEC1_LOOPBACK_SRC_SHIFT, 0xf, + ARRAY_SIZE(cs47l92_aec_loopback_texts), + cs47l92_aec_loopback_texts, + cs47l92_aec_loopback_values); + +static const struct snd_kcontrol_new cs47l92_aec_loopback_mux = + SOC_DAPM_ENUM("AEC1 Loopback", cs47l92_aec_loopback); + +static const struct snd_soc_dapm_widget cs47l92_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("SYSCLK", MADERA_SYSTEM_CLOCK_1, MADERA_SYSCLK_ENA_SHIFT, + 0, madera_sysclk_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_SUPPLY("ASYNCCLK", MADERA_ASYNC_CLOCK_1, + MADERA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("OPCLK", MADERA_OUTPUT_SYSTEM_CLOCK, + MADERA_OPCLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", MADERA_OUTPUT_ASYNC_CLOCK, + MADERA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, + MADERA_DSP_CLK_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD1", 20, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD2", 20, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS), + +SND_SOC_DAPM_SUPPLY("MICBIAS1", MADERA_MIC_BIAS_CTRL_1, + MADERA_MICB1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS2", MADERA_MIC_BIAS_CTRL_2, + MADERA_MICB1_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("MICBIAS1A", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1A_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS1B", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1B_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS1C", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1C_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS1D", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1D_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("MICBIAS2A", MADERA_MIC_BIAS_CTRL_6, + MADERA_MICB2A_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS2B", MADERA_MIC_BIAS_CTRL_6, + MADERA_MICB2B_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("FXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_FX, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("ASRC1CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_ASRC1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("ISRC1CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_ISRC1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("ISRC2CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_ISRC2, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("OUTCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_OUT, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("SPDCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_SPD, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_DSP1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF1TXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_AIF1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF2TXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_AIF2, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF3TXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_AIF3, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("SLIMBUSCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_SLIMBUS, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("PWMCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_PWM, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("DFCCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_DFC, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + +SND_SOC_DAPM_SIGGEN("TONE"), +SND_SOC_DAPM_SIGGEN("NOISE"), + +SND_SOC_DAPM_INPUT("IN1ALN"), +SND_SOC_DAPM_INPUT("IN1ALP"), +SND_SOC_DAPM_INPUT("IN1BLN"), +SND_SOC_DAPM_INPUT("IN1BLP"), +SND_SOC_DAPM_INPUT("IN1ARN"), +SND_SOC_DAPM_INPUT("IN1ARP"), +SND_SOC_DAPM_INPUT("IN1BR"), +SND_SOC_DAPM_INPUT("IN2ALN"), +SND_SOC_DAPM_INPUT("IN2ALP"), +SND_SOC_DAPM_INPUT("IN2BL"), +SND_SOC_DAPM_INPUT("IN2ARN"), +SND_SOC_DAPM_INPUT("IN2ARP"), +SND_SOC_DAPM_INPUT("IN2BR"), + +SND_SOC_DAPM_MUX("IN1L Analog Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[0]), +SND_SOC_DAPM_MUX("IN1R Analog Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[1]), +SND_SOC_DAPM_MUX("IN2L Analog Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[2]), +SND_SOC_DAPM_MUX("IN2R Analog Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[3]), + +SND_SOC_DAPM_MUX("IN1L Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[0]), +SND_SOC_DAPM_MUX("IN1R Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[0]), + +SND_SOC_DAPM_MUX("IN2L Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[1]), +SND_SOC_DAPM_MUX("IN2R Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[1]), + +SND_SOC_DAPM_DEMUX("OUT3 Demux", SND_SOC_NOPM, 0, 0, &cs47l92_outdemux), + +SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), +SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"), + +SND_SOC_DAPM_PGA("PWM1 Driver", MADERA_PWM_DRIVE_1, MADERA_PWM1_ENA_SHIFT, + 0, NULL, 0), +SND_SOC_DAPM_PGA("PWM2 Driver", MADERA_PWM_DRIVE_1, MADERA_PWM2_ENA_SHIFT, + 0, NULL, 0), + +SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX7", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX8", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, + MADERA_AIF3_TX_ENABLES, MADERA_AIF3TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, + MADERA_AIF3_TX_ENABLES, MADERA_AIF3TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF3TX3", NULL, 0, + MADERA_AIF3_TX_ENABLES, MADERA_AIF3TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF3TX4", NULL, 0, + MADERA_AIF3_TX_ENABLES, MADERA_AIF3TX4_ENA_SHIFT, 0), + +SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, + MADERA_OUT1L_ENA_SHIFT, 0, NULL, 0, madera_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, + MADERA_OUT1R_ENA_SHIFT, 0, NULL, 0, madera_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT2L", SND_SOC_NOPM, + MADERA_OUT2L_ENA_SHIFT, 0, NULL, 0, madera_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT2R", SND_SOC_NOPM, + MADERA_OUT2R_ENA_SHIFT, 0, NULL, 0, madera_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT3L", MADERA_OUTPUT_ENABLES_1, + MADERA_OUT3L_ENA_SHIFT, 0, NULL, 0, madera_out_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT3R", MADERA_OUTPUT_ENABLES_1, + MADERA_OUT3R_ENA_SHIFT, 0, NULL, 0, madera_out_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT5L", MADERA_OUTPUT_ENABLES_1, + MADERA_OUT5L_ENA_SHIFT, 0, NULL, 0, madera_out_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT5R", MADERA_OUTPUT_ENABLES_1, + MADERA_OUT5R_ENA_SHIFT, 0, NULL, 0, madera_out_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + +SND_SOC_DAPM_PGA("SPD1TX1", MADERA_SPD1_TX_CONTROL, + MADERA_SPD1_VAL1_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("SPD1TX2", MADERA_SPD1_TX_CONTROL, + MADERA_SPD1_VAL2_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_OUT_DRV("SPD1", MADERA_SPD1_TX_CONTROL, + MADERA_SPD1_ENA_SHIFT, 0, NULL, 0), + +/* + * mux_in widgets : arranged in the order of sources + * specified in MADERA_MIXER_INPUT_ROUTES + */ + +SND_SOC_DAPM_PGA("Noise Generator", MADERA_COMFORT_NOISE_GENERATOR, + MADERA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("Tone Generator 1", MADERA_TONE_GENERATOR_1, + MADERA_TONE1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("Tone Generator 2", MADERA_TONE_GENERATOR_1, + MADERA_TONE2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SIGGEN("HAPTICS"), + +SND_SOC_DAPM_MUX("AEC1 Loopback", MADERA_DAC_AEC_CONTROL_1, + MADERA_AEC1_LOOPBACK_ENA_SHIFT, 0, + &cs47l92_aec_loopback_mux), + +SND_SOC_DAPM_PGA_E("IN1L", MADERA_INPUT_ENABLES, MADERA_IN1L_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN1R", MADERA_INPUT_ENABLES, MADERA_IN1R_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN2L", MADERA_INPUT_ENABLES, MADERA_IN2L_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN2R", MADERA_INPUT_ENABLES, MADERA_IN2R_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN3L", MADERA_INPUT_ENABLES, MADERA_IN3L_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN3R", MADERA_INPUT_ENABLES, MADERA_IN3R_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN4L", MADERA_INPUT_ENABLES, MADERA_IN4L_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN4R", MADERA_INPUT_ENABLES, MADERA_IN4R_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + +SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX7", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX8", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, + MADERA_AIF3_RX_ENABLES, MADERA_AIF3RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, + MADERA_AIF3_RX_ENABLES, MADERA_AIF3RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF3RX3", NULL, 0, + MADERA_AIF3_RX_ENABLES, MADERA_AIF3RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF3RX4", NULL, 0, + MADERA_AIF3_RX_ENABLES, MADERA_AIF3RX4_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_PGA("EQ1", MADERA_EQ1_1, MADERA_EQ1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ2", MADERA_EQ2_1, MADERA_EQ2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ3", MADERA_EQ3_1, MADERA_EQ3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ4", MADERA_EQ4_1, MADERA_EQ4_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("DRC1L", MADERA_DRC1_CTRL1, MADERA_DRC1L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC1R", MADERA_DRC1_CTRL1, MADERA_DRC1R_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC2L", MADERA_DRC2_CTRL1, MADERA_DRC2L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC2R", MADERA_DRC2_CTRL1, MADERA_DRC2R_ENA_SHIFT, 0, + NULL, 0), + +SND_SOC_DAPM_PGA("LHPF1", MADERA_HPLPF1_1, MADERA_LHPF1_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF2", MADERA_HPLPF2_1, MADERA_LHPF2_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF3", MADERA_HPLPF3_1, MADERA_LHPF3_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF4", MADERA_HPLPF4_1, MADERA_LHPF4_ENA_SHIFT, 0, + NULL, 0), + +SND_SOC_DAPM_PGA("ASRC1IN1L", MADERA_ASRC1_ENABLE, + MADERA_ASRC1_IN1L_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ASRC1IN1R", MADERA_ASRC1_ENABLE, + MADERA_ASRC1_IN1R_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ASRC1IN2L", MADERA_ASRC1_ENABLE, + MADERA_ASRC1_IN2L_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ASRC1IN2R", MADERA_ASRC1_ENABLE, + MADERA_ASRC1_IN2R_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC1DEC1", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC2", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC1INT1", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT2", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2DEC1", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC2", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2INT1", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT2", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0), + +WM_ADSP2("DSP1", 0, cs47l92_adsp_power_ev), + +/* end of ordered widget list */ + +SND_SOC_DAPM_PGA("DFC1", MADERA_DFC1_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC2", MADERA_DFC2_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC3", MADERA_DFC3_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC4", MADERA_DFC4_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC5", MADERA_DFC5_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC6", MADERA_DFC6_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC7", MADERA_DFC7_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC8", MADERA_DFC8_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), + +MADERA_MIXER_WIDGETS(EQ1, "EQ1"), +MADERA_MIXER_WIDGETS(EQ2, "EQ2"), +MADERA_MIXER_WIDGETS(EQ3, "EQ3"), +MADERA_MIXER_WIDGETS(EQ4, "EQ4"), + +MADERA_MIXER_WIDGETS(DRC1L, "DRC1L"), +MADERA_MIXER_WIDGETS(DRC1R, "DRC1R"), +MADERA_MIXER_WIDGETS(DRC2L, "DRC2L"), +MADERA_MIXER_WIDGETS(DRC2R, "DRC2R"), + +SND_SOC_DAPM_SWITCH("DRC1 Activity Output", SND_SOC_NOPM, 0, 0, + &madera_drc_activity_output_mux[0]), +SND_SOC_DAPM_SWITCH("DRC2 Activity Output", SND_SOC_NOPM, 0, 0, + &madera_drc_activity_output_mux[1]), + +MADERA_MIXER_WIDGETS(LHPF1, "LHPF1"), +MADERA_MIXER_WIDGETS(LHPF2, "LHPF2"), +MADERA_MIXER_WIDGETS(LHPF3, "LHPF3"), +MADERA_MIXER_WIDGETS(LHPF4, "LHPF4"), + +MADERA_MIXER_WIDGETS(PWM1, "PWM1"), +MADERA_MIXER_WIDGETS(PWM2, "PWM2"), + +MADERA_MIXER_WIDGETS(OUT1L, "HPOUT1L"), +MADERA_MIXER_WIDGETS(OUT1R, "HPOUT1R"), +MADERA_MIXER_WIDGETS(OUT2L, "HPOUT2L"), +MADERA_MIXER_WIDGETS(OUT2R, "HPOUT2R"), +MADERA_MIXER_WIDGETS(OUT3L, "HPOUT3L"), +MADERA_MIXER_WIDGETS(OUT3R, "HPOUT3R"), +MADERA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"), +MADERA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"), + +MADERA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"), +MADERA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"), +MADERA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"), +MADERA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"), +MADERA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"), +MADERA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"), +MADERA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"), +MADERA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"), + +MADERA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"), +MADERA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), +MADERA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"), +MADERA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"), +MADERA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"), +MADERA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"), +MADERA_MIXER_WIDGETS(AIF2TX7, "AIF2TX7"), +MADERA_MIXER_WIDGETS(AIF2TX8, "AIF2TX8"), + +MADERA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), +MADERA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), +MADERA_MIXER_WIDGETS(AIF3TX3, "AIF3TX3"), +MADERA_MIXER_WIDGETS(AIF3TX4, "AIF3TX4"), + +MADERA_MIXER_WIDGETS(SLIMTX1, "SLIMTX1"), +MADERA_MIXER_WIDGETS(SLIMTX2, "SLIMTX2"), +MADERA_MIXER_WIDGETS(SLIMTX3, "SLIMTX3"), +MADERA_MIXER_WIDGETS(SLIMTX4, "SLIMTX4"), +MADERA_MIXER_WIDGETS(SLIMTX5, "SLIMTX5"), +MADERA_MIXER_WIDGETS(SLIMTX6, "SLIMTX6"), +MADERA_MIXER_WIDGETS(SLIMTX7, "SLIMTX7"), +MADERA_MIXER_WIDGETS(SLIMTX8, "SLIMTX8"), + +MADERA_MUX_WIDGETS(SPD1TX1, "SPDIFTX1"), +MADERA_MUX_WIDGETS(SPD1TX2, "SPDIFTX2"), + +MADERA_MUX_WIDGETS(ASRC1IN1L, "ASRC1IN1L"), +MADERA_MUX_WIDGETS(ASRC1IN1R, "ASRC1IN1R"), +MADERA_MUX_WIDGETS(ASRC1IN2L, "ASRC1IN2L"), +MADERA_MUX_WIDGETS(ASRC1IN2R, "ASRC1IN2R"), + +MADERA_DSP_WIDGETS(DSP1, "DSP1"), + +MADERA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"), +MADERA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"), + +MADERA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"), +MADERA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"), + +MADERA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"), +MADERA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"), + +MADERA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), +MADERA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), + +MADERA_MUX_WIDGETS(DFC1, "DFC1"), +MADERA_MUX_WIDGETS(DFC2, "DFC2"), +MADERA_MUX_WIDGETS(DFC3, "DFC3"), +MADERA_MUX_WIDGETS(DFC4, "DFC4"), +MADERA_MUX_WIDGETS(DFC5, "DFC5"), +MADERA_MUX_WIDGETS(DFC6, "DFC6"), +MADERA_MUX_WIDGETS(DFC7, "DFC7"), +MADERA_MUX_WIDGETS(DFC8, "DFC8"), + +SND_SOC_DAPM_OUTPUT("HPOUT1L"), +SND_SOC_DAPM_OUTPUT("HPOUT1R"), +SND_SOC_DAPM_OUTPUT("HPOUT2L"), +SND_SOC_DAPM_OUTPUT("HPOUT2R"), +SND_SOC_DAPM_OUTPUT("HPOUT3L"), +SND_SOC_DAPM_OUTPUT("HPOUT3R"), +SND_SOC_DAPM_OUTPUT("HPOUT4L"), +SND_SOC_DAPM_OUTPUT("HPOUT4R"), +SND_SOC_DAPM_OUTPUT("SPKDAT1L"), +SND_SOC_DAPM_OUTPUT("SPKDAT1R"), +SND_SOC_DAPM_OUTPUT("SPDIF1"), + +SND_SOC_DAPM_OUTPUT("MICSUPP"), +}; + +#define MADERA_MIXER_INPUT_ROUTES(name) \ + { name, "Noise Generator", "Noise Generator" }, \ + { name, "Tone Generator 1", "Tone Generator 1" }, \ + { name, "Tone Generator 2", "Tone Generator 2" }, \ + { name, "Haptics", "HAPTICS" }, \ + { name, "AEC1", "AEC1 Loopback" }, \ + { name, "IN1L", "IN1L" }, \ + { name, "IN1R", "IN1R" }, \ + { name, "IN2L", "IN2L" }, \ + { name, "IN2R", "IN2R" }, \ + { name, "IN3L", "IN3L" }, \ + { name, "IN3R", "IN3R" }, \ + { name, "IN4L", "IN4L" }, \ + { name, "IN4R", "IN4R" }, \ + { name, "AIF1RX1", "AIF1RX1" }, \ + { name, "AIF1RX2", "AIF1RX2" }, \ + { name, "AIF1RX3", "AIF1RX3" }, \ + { name, "AIF1RX4", "AIF1RX4" }, \ + { name, "AIF1RX5", "AIF1RX5" }, \ + { name, "AIF1RX6", "AIF1RX6" }, \ + { name, "AIF1RX7", "AIF1RX7" }, \ + { name, "AIF1RX8", "AIF1RX8" }, \ + { name, "AIF2RX1", "AIF2RX1" }, \ + { name, "AIF2RX2", "AIF2RX2" }, \ + { name, "AIF2RX3", "AIF2RX3" }, \ + { name, "AIF2RX4", "AIF2RX4" }, \ + { name, "AIF2RX5", "AIF2RX5" }, \ + { name, "AIF2RX6", "AIF2RX6" }, \ + { name, "AIF2RX7", "AIF2RX7" }, \ + { name, "AIF2RX8", "AIF2RX8" }, \ + { name, "AIF3RX1", "AIF3RX1" }, \ + { name, "AIF3RX2", "AIF3RX2" }, \ + { name, "AIF3RX3", "AIF3RX3" }, \ + { name, "AIF3RX4", "AIF3RX4" }, \ + { name, "SLIMRX1", "SLIMRX1" }, \ + { name, "SLIMRX2", "SLIMRX2" }, \ + { name, "SLIMRX3", "SLIMRX3" }, \ + { name, "SLIMRX4", "SLIMRX4" }, \ + { name, "SLIMRX5", "SLIMRX5" }, \ + { name, "SLIMRX6", "SLIMRX6" }, \ + { name, "SLIMRX7", "SLIMRX7" }, \ + { name, "SLIMRX8", "SLIMRX8" }, \ + { name, "EQ1", "EQ1" }, \ + { name, "EQ2", "EQ2" }, \ + { name, "EQ3", "EQ3" }, \ + { name, "EQ4", "EQ4" }, \ + { name, "DRC1L", "DRC1L" }, \ + { name, "DRC1R", "DRC1R" }, \ + { name, "DRC2L", "DRC2L" }, \ + { name, "DRC2R", "DRC2R" }, \ + { name, "LHPF1", "LHPF1" }, \ + { name, "LHPF2", "LHPF2" }, \ + { name, "LHPF3", "LHPF3" }, \ + { name, "LHPF4", "LHPF4" }, \ + { name, "ASRC1IN1L", "ASRC1IN1L" }, \ + { name, "ASRC1IN1R", "ASRC1IN1R" }, \ + { name, "ASRC1IN2L", "ASRC1IN2L" }, \ + { name, "ASRC1IN2R", "ASRC1IN2R" }, \ + { name, "ISRC1DEC1", "ISRC1DEC1" }, \ + { name, "ISRC1DEC2", "ISRC1DEC2" }, \ + { name, "ISRC1INT1", "ISRC1INT1" }, \ + { name, "ISRC1INT2", "ISRC1INT2" }, \ + { name, "ISRC2DEC1", "ISRC2DEC1" }, \ + { name, "ISRC2DEC2", "ISRC2DEC2" }, \ + { name, "ISRC2INT1", "ISRC2INT1" }, \ + { name, "ISRC2INT2", "ISRC2INT2" }, \ + { name, "DSP1.1", "DSP1" }, \ + { name, "DSP1.2", "DSP1" }, \ + { name, "DSP1.3", "DSP1" }, \ + { name, "DSP1.4", "DSP1" }, \ + { name, "DSP1.5", "DSP1" }, \ + { name, "DSP1.6", "DSP1" }, \ + { name, "DFC1", "DFC1" }, \ + { name, "DFC2", "DFC2" }, \ + { name, "DFC3", "DFC3" }, \ + { name, "DFC4", "DFC4" }, \ + { name, "DFC5", "DFC5" }, \ + { name, "DFC6", "DFC6" }, \ + { name, "DFC7", "DFC7" }, \ + { name, "DFC8", "DFC8" } + +static const struct snd_soc_dapm_route cs47l92_dapm_routes[] = { + /* Internal clock domains */ + { "EQ1", NULL, "FXCLK" }, + { "EQ2", NULL, "FXCLK" }, + { "EQ3", NULL, "FXCLK" }, + { "EQ4", NULL, "FXCLK" }, + { "DRC1L", NULL, "FXCLK" }, + { "DRC1R", NULL, "FXCLK" }, + { "DRC2L", NULL, "FXCLK" }, + { "DRC2R", NULL, "FXCLK" }, + { "LHPF1", NULL, "FXCLK" }, + { "LHPF2", NULL, "FXCLK" }, + { "LHPF3", NULL, "FXCLK" }, + { "LHPF4", NULL, "FXCLK" }, + { "PWM1 Mixer", NULL, "PWMCLK" }, + { "PWM2 Mixer", NULL, "PWMCLK" }, + { "OUT1L", NULL, "OUTCLK" }, + { "OUT1R", NULL, "OUTCLK" }, + { "OUT2L", NULL, "OUTCLK" }, + { "OUT2R", NULL, "OUTCLK" }, + { "OUT3L", NULL, "OUTCLK" }, + { "OUT3R", NULL, "OUTCLK" }, + { "OUT5L", NULL, "OUTCLK" }, + { "OUT5R", NULL, "OUTCLK" }, + { "AIF1TX1", NULL, "AIF1TXCLK" }, + { "AIF1TX2", NULL, "AIF1TXCLK" }, + { "AIF1TX3", NULL, "AIF1TXCLK" }, + { "AIF1TX4", NULL, "AIF1TXCLK" }, + { "AIF1TX5", NULL, "AIF1TXCLK" }, + { "AIF1TX6", NULL, "AIF1TXCLK" }, + { "AIF1TX7", NULL, "AIF1TXCLK" }, + { "AIF1TX8", NULL, "AIF1TXCLK" }, + { "AIF2TX1", NULL, "AIF2TXCLK" }, + { "AIF2TX2", NULL, "AIF2TXCLK" }, + { "AIF2TX3", NULL, "AIF2TXCLK" }, + { "AIF2TX4", NULL, "AIF2TXCLK" }, + { "AIF2TX5", NULL, "AIF2TXCLK" }, + { "AIF2TX6", NULL, "AIF2TXCLK" }, + { "AIF2TX7", NULL, "AIF2TXCLK" }, + { "AIF2TX8", NULL, "AIF2TXCLK" }, + { "AIF3TX1", NULL, "AIF3TXCLK" }, + { "AIF3TX2", NULL, "AIF3TXCLK" }, + { "AIF3TX3", NULL, "AIF3TXCLK" }, + { "AIF3TX4", NULL, "AIF3TXCLK" }, + { "SLIMTX1", NULL, "SLIMBUSCLK" }, + { "SLIMTX2", NULL, "SLIMBUSCLK" }, + { "SLIMTX3", NULL, "SLIMBUSCLK" }, + { "SLIMTX4", NULL, "SLIMBUSCLK" }, + { "SLIMTX5", NULL, "SLIMBUSCLK" }, + { "SLIMTX6", NULL, "SLIMBUSCLK" }, + { "SLIMTX7", NULL, "SLIMBUSCLK" }, + { "SLIMTX8", NULL, "SLIMBUSCLK" }, + { "SPD1TX1", NULL, "SPDCLK" }, + { "SPD1TX2", NULL, "SPDCLK" }, + { "DSP1", NULL, "DSP1CLK" }, + { "ISRC1DEC1", NULL, "ISRC1CLK" }, + { "ISRC1DEC2", NULL, "ISRC1CLK" }, + { "ISRC1INT1", NULL, "ISRC1CLK" }, + { "ISRC1INT2", NULL, "ISRC1CLK" }, + { "ISRC2DEC1", NULL, "ISRC2CLK" }, + { "ISRC2DEC2", NULL, "ISRC2CLK" }, + { "ISRC2INT1", NULL, "ISRC2CLK" }, + { "ISRC2INT2", NULL, "ISRC2CLK" }, + { "ASRC1IN1L", NULL, "ASRC1CLK" }, + { "ASRC1IN1R", NULL, "ASRC1CLK" }, + { "ASRC1IN2L", NULL, "ASRC1CLK" }, + { "ASRC1IN2R", NULL, "ASRC1CLK" }, + { "DFC1", NULL, "DFCCLK" }, + { "DFC2", NULL, "DFCCLK" }, + { "DFC3", NULL, "DFCCLK" }, + { "DFC4", NULL, "DFCCLK" }, + { "DFC5", NULL, "DFCCLK" }, + { "DFC6", NULL, "DFCCLK" }, + { "DFC7", NULL, "DFCCLK" }, + { "DFC8", NULL, "DFCCLK" }, + + { "OUT1L", NULL, "CPVDD1" }, + { "OUT1L", NULL, "CPVDD2" }, + { "OUT1R", NULL, "CPVDD1" }, + { "OUT1R", NULL, "CPVDD2" }, + { "OUT2L", NULL, "CPVDD1" }, + { "OUT2L", NULL, "CPVDD2" }, + { "OUT2R", NULL, "CPVDD1" }, + { "OUT2R", NULL, "CPVDD2" }, + { "OUT3L", NULL, "CPVDD1" }, + { "OUT3L", NULL, "CPVDD2" }, + { "OUT3R", NULL, "CPVDD1" }, + { "OUT3R", NULL, "CPVDD2" }, + + { "OUT1L", NULL, "SYSCLK" }, + { "OUT1R", NULL, "SYSCLK" }, + { "OUT2L", NULL, "SYSCLK" }, + { "OUT2R", NULL, "SYSCLK" }, + { "OUT3L", NULL, "SYSCLK" }, + { "OUT3R", NULL, "SYSCLK" }, + { "OUT5L", NULL, "SYSCLK" }, + { "OUT5R", NULL, "SYSCLK" }, + + { "SPD1", NULL, "SYSCLK" }, + { "SPD1", NULL, "SPD1TX1" }, + { "SPD1", NULL, "SPD1TX2" }, + + { "IN1L", NULL, "SYSCLK" }, + { "IN1R", NULL, "SYSCLK" }, + { "IN2L", NULL, "SYSCLK" }, + { "IN2R", NULL, "SYSCLK" }, + { "IN3L", NULL, "SYSCLK" }, + { "IN3R", NULL, "SYSCLK" }, + { "IN4L", NULL, "SYSCLK" }, + { "IN4R", NULL, "SYSCLK" }, + + { "ASRC1IN1L", NULL, "SYSCLK" }, + { "ASRC1IN1R", NULL, "SYSCLK" }, + { "ASRC1IN2L", NULL, "SYSCLK" }, + { "ASRC1IN2R", NULL, "SYSCLK" }, + + { "ASRC1IN1L", NULL, "ASYNCCLK" }, + { "ASRC1IN1R", NULL, "ASYNCCLK" }, + { "ASRC1IN2L", NULL, "ASYNCCLK" }, + { "ASRC1IN2R", NULL, "ASYNCCLK" }, + + { "MICBIAS1", NULL, "MICVDD" }, + { "MICBIAS2", NULL, "MICVDD" }, + + { "MICBIAS1A", NULL, "MICBIAS1" }, + { "MICBIAS1B", NULL, "MICBIAS1" }, + { "MICBIAS1C", NULL, "MICBIAS1" }, + { "MICBIAS1D", NULL, "MICBIAS1" }, + + { "MICBIAS2A", NULL, "MICBIAS2" }, + { "MICBIAS2B", NULL, "MICBIAS2" }, + + { "Noise Generator", NULL, "SYSCLK" }, + { "Tone Generator 1", NULL, "SYSCLK" }, + { "Tone Generator 2", NULL, "SYSCLK" }, + + { "Noise Generator", NULL, "NOISE" }, + { "Tone Generator 1", NULL, "TONE" }, + { "Tone Generator 2", NULL, "TONE" }, + + { "AIF1 Capture", NULL, "AIF1TX1" }, + { "AIF1 Capture", NULL, "AIF1TX2" }, + { "AIF1 Capture", NULL, "AIF1TX3" }, + { "AIF1 Capture", NULL, "AIF1TX4" }, + { "AIF1 Capture", NULL, "AIF1TX5" }, + { "AIF1 Capture", NULL, "AIF1TX6" }, + { "AIF1 Capture", NULL, "AIF1TX7" }, + { "AIF1 Capture", NULL, "AIF1TX8" }, + + { "AIF1RX1", NULL, "AIF1 Playback" }, + { "AIF1RX2", NULL, "AIF1 Playback" }, + { "AIF1RX3", NULL, "AIF1 Playback" }, + { "AIF1RX4", NULL, "AIF1 Playback" }, + { "AIF1RX5", NULL, "AIF1 Playback" }, + { "AIF1RX6", NULL, "AIF1 Playback" }, + { "AIF1RX7", NULL, "AIF1 Playback" }, + { "AIF1RX8", NULL, "AIF1 Playback" }, + + { "AIF2 Capture", NULL, "AIF2TX1" }, + { "AIF2 Capture", NULL, "AIF2TX2" }, + { "AIF2 Capture", NULL, "AIF2TX3" }, + { "AIF2 Capture", NULL, "AIF2TX4" }, + { "AIF2 Capture", NULL, "AIF2TX5" }, + { "AIF2 Capture", NULL, "AIF2TX6" }, + { "AIF2 Capture", NULL, "AIF2TX7" }, + { "AIF2 Capture", NULL, "AIF2TX8" }, + + { "AIF2RX1", NULL, "AIF2 Playback" }, + { "AIF2RX2", NULL, "AIF2 Playback" }, + { "AIF2RX3", NULL, "AIF2 Playback" }, + { "AIF2RX4", NULL, "AIF2 Playback" }, + { "AIF2RX5", NULL, "AIF2 Playback" }, + { "AIF2RX6", NULL, "AIF2 Playback" }, + { "AIF2RX7", NULL, "AIF2 Playback" }, + { "AIF2RX8", NULL, "AIF2 Playback" }, + + { "AIF3 Capture", NULL, "AIF3TX1" }, + { "AIF3 Capture", NULL, "AIF3TX2" }, + { "AIF3 Capture", NULL, "AIF3TX3" }, + { "AIF3 Capture", NULL, "AIF3TX4" }, + + { "AIF3RX1", NULL, "AIF3 Playback" }, + { "AIF3RX2", NULL, "AIF3 Playback" }, + { "AIF3RX3", NULL, "AIF3 Playback" }, + { "AIF3RX4", NULL, "AIF3 Playback" }, + + { "Slim1 Capture", NULL, "SLIMTX1" }, + { "Slim1 Capture", NULL, "SLIMTX2" }, + { "Slim1 Capture", NULL, "SLIMTX3" }, + { "Slim1 Capture", NULL, "SLIMTX4" }, + + { "SLIMRX1", NULL, "Slim1 Playback" }, + { "SLIMRX2", NULL, "Slim1 Playback" }, + { "SLIMRX3", NULL, "Slim1 Playback" }, + { "SLIMRX4", NULL, "Slim1 Playback" }, + + { "Slim2 Capture", NULL, "SLIMTX5" }, + { "Slim2 Capture", NULL, "SLIMTX6" }, + + { "SLIMRX5", NULL, "Slim2 Playback" }, + { "SLIMRX6", NULL, "Slim2 Playback" }, + + { "Slim3 Capture", NULL, "SLIMTX7" }, + { "Slim3 Capture", NULL, "SLIMTX8" }, + + { "SLIMRX7", NULL, "Slim3 Playback" }, + { "SLIMRX8", NULL, "Slim3 Playback" }, + + { "AIF1 Playback", NULL, "SYSCLK" }, + { "AIF2 Playback", NULL, "SYSCLK" }, + { "AIF3 Playback", NULL, "SYSCLK" }, + { "Slim1 Playback", NULL, "SYSCLK" }, + { "Slim2 Playback", NULL, "SYSCLK" }, + { "Slim3 Playback", NULL, "SYSCLK" }, + + { "AIF1 Capture", NULL, "SYSCLK" }, + { "AIF2 Capture", NULL, "SYSCLK" }, + { "AIF3 Capture", NULL, "SYSCLK" }, + { "Slim1 Capture", NULL, "SYSCLK" }, + { "Slim2 Capture", NULL, "SYSCLK" }, + { "Slim3 Capture", NULL, "SYSCLK" }, + + { "Audio Trace DSP", NULL, "DSP1" }, + + { "IN1L Analog Mux", "A", "IN1ALN" }, + { "IN1L Analog Mux", "A", "IN1ALP" }, + { "IN1L Analog Mux", "B", "IN1BLN" }, + { "IN1L Analog Mux", "B", "IN1BLP" }, + { "IN1R Analog Mux", "A", "IN1ARN" }, + { "IN1R Analog Mux", "A", "IN1ARP" }, + { "IN1R Analog Mux", "B", "IN1BR" }, + { "IN1R Analog Mux", "B", "IN1ALN" }, + + { "IN1L Mode", "Analog", "IN1L Analog Mux" }, + { "IN1R Mode", "Analog", "IN1R Analog Mux" }, + + { "IN1L Mode", "Digital", "IN1ALN" }, + { "IN1L Mode", "Digital", "IN1ALP" }, + { "IN1R Mode", "Digital", "IN1ALN" }, + { "IN1R Mode", "Digital", "IN1ALP" }, + + { "IN1L", NULL, "IN1L Mode" }, + { "IN1R", NULL, "IN1R Mode" }, + + { "IN2L Analog Mux", "A", "IN2ALN" }, + { "IN2L Analog Mux", "A", "IN2ALP" }, + { "IN2L Analog Mux", "B", "IN2ALN" }, + { "IN2L Analog Mux", "B", "IN2BL" }, + { "IN2R Analog Mux", "A", "IN2ARN" }, + { "IN2R Analog Mux", "A", "IN2ARP" }, + { "IN2R Analog Mux", "B", "IN2ARN" }, + { "IN2R Analog Mux", "B", "IN2BR" }, + + { "IN2L Mode", "Analog", "IN2L Analog Mux" }, + { "IN2R Mode", "Analog", "IN2R Analog Mux" }, + + { "IN2L Mode", "Digital", "IN2ALN" }, + { "IN2L Mode", "Digital", "IN2ALP" }, + { "IN2R Mode", "Digital", "IN2ALN" }, + { "IN2R Mode", "Digital", "IN2ALP" }, + + { "IN2L", NULL, "IN2L Mode" }, + { "IN2R", NULL, "IN2R Mode" }, + + { "IN3L", NULL, "IN1ARN" }, + { "IN3L", NULL, "IN1ARP" }, + { "IN3R", NULL, "IN1ARN" }, + { "IN3R", NULL, "IN1ARP" }, + + { "IN4L", NULL, "IN2ARN" }, + { "IN4L", NULL, "IN2ARP" }, + { "IN4R", NULL, "IN2ARN" }, + { "IN4R", NULL, "IN2ARP" }, + + MADERA_MIXER_ROUTES("OUT1L", "HPOUT1L"), + MADERA_MIXER_ROUTES("OUT1R", "HPOUT1R"), + MADERA_MIXER_ROUTES("OUT2L", "HPOUT2L"), + MADERA_MIXER_ROUTES("OUT2R", "HPOUT2R"), + MADERA_MIXER_ROUTES("OUT3L", "HPOUT3L"), + MADERA_MIXER_ROUTES("OUT3R", "HPOUT3R"), + + MADERA_MIXER_ROUTES("OUT5L", "SPKDAT1L"), + MADERA_MIXER_ROUTES("OUT5R", "SPKDAT1R"), + + MADERA_MIXER_ROUTES("PWM1 Driver", "PWM1"), + MADERA_MIXER_ROUTES("PWM2 Driver", "PWM2"), + + MADERA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"), + MADERA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"), + MADERA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"), + MADERA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"), + MADERA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"), + MADERA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"), + MADERA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"), + MADERA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"), + + MADERA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"), + MADERA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), + MADERA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"), + MADERA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"), + MADERA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"), + MADERA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"), + MADERA_MIXER_ROUTES("AIF2TX7", "AIF2TX7"), + MADERA_MIXER_ROUTES("AIF2TX8", "AIF2TX8"), + + MADERA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"), + MADERA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"), + MADERA_MIXER_ROUTES("AIF3TX3", "AIF3TX3"), + MADERA_MIXER_ROUTES("AIF3TX4", "AIF3TX4"), + + MADERA_MIXER_ROUTES("SLIMTX1", "SLIMTX1"), + MADERA_MIXER_ROUTES("SLIMTX2", "SLIMTX2"), + MADERA_MIXER_ROUTES("SLIMTX3", "SLIMTX3"), + MADERA_MIXER_ROUTES("SLIMTX4", "SLIMTX4"), + MADERA_MIXER_ROUTES("SLIMTX5", "SLIMTX5"), + MADERA_MIXER_ROUTES("SLIMTX6", "SLIMTX6"), + MADERA_MIXER_ROUTES("SLIMTX7", "SLIMTX7"), + MADERA_MIXER_ROUTES("SLIMTX8", "SLIMTX8"), + + MADERA_MUX_ROUTES("SPD1TX1", "SPDIFTX1"), + MADERA_MUX_ROUTES("SPD1TX2", "SPDIFTX2"), + + MADERA_MIXER_ROUTES("EQ1", "EQ1"), + MADERA_MIXER_ROUTES("EQ2", "EQ2"), + MADERA_MIXER_ROUTES("EQ3", "EQ3"), + MADERA_MIXER_ROUTES("EQ4", "EQ4"), + + MADERA_MIXER_ROUTES("DRC1L", "DRC1L"), + MADERA_MIXER_ROUTES("DRC1R", "DRC1R"), + MADERA_MIXER_ROUTES("DRC2L", "DRC2L"), + MADERA_MIXER_ROUTES("DRC2R", "DRC2R"), + + MADERA_MIXER_ROUTES("LHPF1", "LHPF1"), + MADERA_MIXER_ROUTES("LHPF2", "LHPF2"), + MADERA_MIXER_ROUTES("LHPF3", "LHPF3"), + MADERA_MIXER_ROUTES("LHPF4", "LHPF4"), + + MADERA_MUX_ROUTES("ASRC1IN1L", "ASRC1IN1L"), + MADERA_MUX_ROUTES("ASRC1IN1R", "ASRC1IN1R"), + MADERA_MUX_ROUTES("ASRC1IN2L", "ASRC1IN2L"), + MADERA_MUX_ROUTES("ASRC1IN2R", "ASRC1IN2R"), + + MADERA_DSP_ROUTES("DSP1"), + + MADERA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"), + MADERA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"), + + MADERA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"), + MADERA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"), + + MADERA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"), + MADERA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"), + + MADERA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"), + MADERA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"), + + { "AEC1 Loopback", "HPOUT1L", "OUT1L" }, + { "AEC1 Loopback", "HPOUT1R", "OUT1R" }, + { "HPOUT1L", NULL, "OUT1L" }, + { "HPOUT1R", NULL, "OUT1R" }, + + { "AEC1 Loopback", "HPOUT2L", "OUT2L" }, + { "AEC1 Loopback", "HPOUT2R", "OUT2R" }, + { "HPOUT2L", NULL, "OUT2L" }, + { "HPOUT2R", NULL, "OUT2R" }, + + { "AEC1 Loopback", "HPOUT3L", "OUT3L" }, + { "AEC1 Loopback", "HPOUT3R", "OUT3R" }, + { "OUT3 Demux", NULL, "OUT3L" }, + { "OUT3 Demux", NULL, "OUT3R" }, + + { "HPOUT3L", "HPOUT3", "OUT3 Demux" }, + { "HPOUT3R", "HPOUT3", "OUT3 Demux" }, + { "HPOUT4L", "HPOUT4", "OUT3 Demux" }, + { "HPOUT4R", "HPOUT4", "OUT3 Demux" }, + + { "AEC1 Loopback", "SPKDAT1L", "OUT5L" }, + { "AEC1 Loopback", "SPKDAT1R", "OUT5R" }, + { "SPKDAT1L", NULL, "OUT5L" }, + { "SPKDAT1R", NULL, "OUT5R" }, + + { "SPDIF1", NULL, "SPD1" }, + + { "MICSUPP", NULL, "SYSCLK" }, + + { "DRC1 Signal Activity", NULL, "DRC1 Activity Output" }, + { "DRC2 Signal Activity", NULL, "DRC2 Activity Output" }, + { "DRC1 Activity Output", "Switch", "DRC1L" }, + { "DRC1 Activity Output", "Switch", "DRC1R" }, + { "DRC2 Activity Output", "Switch", "DRC2L" }, + { "DRC2 Activity Output", "Switch", "DRC2R" }, + + MADERA_MUX_ROUTES("DFC1", "DFC1"), + MADERA_MUX_ROUTES("DFC2", "DFC2"), + MADERA_MUX_ROUTES("DFC3", "DFC3"), + MADERA_MUX_ROUTES("DFC4", "DFC4"), + MADERA_MUX_ROUTES("DFC5", "DFC5"), + MADERA_MUX_ROUTES("DFC6", "DFC6"), + MADERA_MUX_ROUTES("DFC7", "DFC7"), + MADERA_MUX_ROUTES("DFC8", "DFC8"), +}; + +static int cs47l92_set_fll(struct snd_soc_component *component, int fll_id, + int source, unsigned int fref, unsigned int fout) +{ + struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); + + switch (fll_id) { + case MADERA_FLL1_REFCLK: + return madera_fllhj_set_refclk(&cs47l92->fll[0], source, fref, + fout); + case MADERA_FLL2_REFCLK: + return madera_fllhj_set_refclk(&cs47l92->fll[1], source, fref, + fout); + default: + return -EINVAL; + } +} + +static struct snd_soc_dai_driver cs47l92_dai[] = { + { + .name = "cs47l92-aif1", + .id = 1, + .base = MADERA_AIF1_BCLK_CTRL, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 8, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 8, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l92-aif2", + .id = 2, + .base = MADERA_AIF2_BCLK_CTRL, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 8, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 8, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l92-aif3", + .id = 3, + .base = MADERA_AIF3_BCLK_CTRL, + .playback = { + .stream_name = "AIF3 Playback", + .channels_min = 1, + .channels_max = 4, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "AIF3 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l92-slim1", + .id = 5, + .playback = { + .stream_name = "Slim1 Playback", + .channels_min = 1, + .channels_max = 4, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "Slim1 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_simple_dai_ops, + }, + { + .name = "cs47l92-slim2", + .id = 6, + .playback = { + .stream_name = "Slim2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "Slim2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_simple_dai_ops, + }, + { + .name = "cs47l92-slim3", + .id = 7, + .playback = { + .stream_name = "Slim3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "Slim3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_simple_dai_ops, + }, + { + .name = "cs47l92-cpu-trace", + .capture = { + .stream_name = "Audio Trace CPU", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .compress_new = snd_soc_new_compress, + }, + { + .name = "cs47l92-dsp-trace", + .capture = { + .stream_name = "Audio Trace DSP", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + }, +}; + +static int cs47l92_open(struct snd_compr_stream *stream) +{ + struct snd_soc_pcm_runtime *rtd = stream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); + struct madera_priv *priv = &cs47l92->core; + struct madera *madera = priv->madera; + int n_adsp; + + if (strcmp(rtd->codec_dai->name, "cs47l92-dsp-trace") == 0) { + n_adsp = 0; + } else { + dev_err(madera->dev, + "No suitable compressed stream for DAI '%s'\n", + rtd->codec_dai->name); + return -EINVAL; + } + + return wm_adsp_compr_open(&priv->adsp[n_adsp], stream); +} + +static irqreturn_t cs47l92_adsp2_irq(int irq, void *data) +{ + struct cs47l92 *cs47l92 = data; + struct madera_priv *priv = &cs47l92->core; + struct madera *madera = priv->madera; + int ret; + + ret = wm_adsp_compr_handle_irq(&priv->adsp[0]); + if (ret == -ENODEV) { + dev_err(madera->dev, "Spurious compressed data IRQ\n"); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static int cs47l92_component_probe(struct snd_soc_component *component) +{ + struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); + struct madera *madera = cs47l92->core.madera; + int ret; + + snd_soc_component_init_regmap(component, madera->regmap); + + mutex_lock(&madera->dapm_ptr_lock); + madera->dapm = snd_soc_component_get_dapm(component); + mutex_unlock(&madera->dapm_ptr_lock); + + ret = madera_init_inputs(component); + if (ret) + return ret; + + ret = madera_init_outputs(component, CS47L92_MONO_OUTPUTS); + if (ret) + return ret; + + snd_soc_component_disable_pin(component, "HAPTICS"); + + ret = snd_soc_add_component_controls(component, + madera_adsp_rate_controls, + CS47L92_NUM_ADSP); + if (ret) + return ret; + + return wm_adsp2_component_probe(&cs47l92->core.adsp[0], component); +} + +static void cs47l92_component_remove(struct snd_soc_component *component) +{ + struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); + struct madera *madera = cs47l92->core.madera; + + mutex_lock(&madera->dapm_ptr_lock); + madera->dapm = NULL; + mutex_unlock(&madera->dapm_ptr_lock); + + wm_adsp2_component_remove(&cs47l92->core.adsp[0], component); +} + +#define CS47L92_DIG_VU 0x0200 + +static unsigned int cs47l92_digital_vu[] = { + MADERA_DAC_DIGITAL_VOLUME_1L, + MADERA_DAC_DIGITAL_VOLUME_1R, + MADERA_DAC_DIGITAL_VOLUME_2L, + MADERA_DAC_DIGITAL_VOLUME_2R, + MADERA_DAC_DIGITAL_VOLUME_3L, + MADERA_DAC_DIGITAL_VOLUME_3R, + MADERA_DAC_DIGITAL_VOLUME_5L, + MADERA_DAC_DIGITAL_VOLUME_5R, +}; + +static const struct snd_compr_ops cs47l92_compr_ops = { + .open = &cs47l92_open, + .free = &wm_adsp_compr_free, + .set_params = &wm_adsp_compr_set_params, + .get_caps = &wm_adsp_compr_get_caps, + .trigger = &wm_adsp_compr_trigger, + .pointer = &wm_adsp_compr_pointer, + .copy = &wm_adsp_compr_copy, +}; + +static const struct snd_soc_component_driver soc_component_dev_cs47l92 = { + .probe = &cs47l92_component_probe, + .remove = &cs47l92_component_remove, + .set_sysclk = &madera_set_sysclk, + .set_pll = &cs47l92_set_fll, + .name = DRV_NAME, + .compr_ops = &cs47l92_compr_ops, + .controls = cs47l92_snd_controls, + .num_controls = ARRAY_SIZE(cs47l92_snd_controls), + .dapm_widgets = cs47l92_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs47l92_dapm_widgets), + .dapm_routes = cs47l92_dapm_routes, + .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) +{ + struct madera *madera = dev_get_drvdata(pdev->dev.parent); + struct cs47l92 *cs47l92; + int i, ret; + + BUILD_BUG_ON(ARRAY_SIZE(cs47l92_dai) > MADERA_MAX_DAI); + + /* quick exit if Madera irqchip driver hasn't completed probe */ + if (!madera->irq_dev) { + dev_dbg(&pdev->dev, "irqchip driver not ready\n"); + return -EPROBE_DEFER; + } + + cs47l92 = devm_kzalloc(&pdev->dev, sizeof(struct cs47l92), GFP_KERNEL); + if (!cs47l92) + return -ENOMEM; + + platform_set_drvdata(pdev, cs47l92); + + cs47l92->core.madera = madera; + cs47l92->core.dev = &pdev->dev; + cs47l92->core.num_inputs = 8; + + ret = madera_core_init(&cs47l92->core); + if (ret) + return ret; + + ret = madera_request_irq(madera, MADERA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", cs47l92_adsp2_irq, + cs47l92); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); + goto error_core; + } + + ret = madera_set_irq_wake(madera, MADERA_IRQ_DSP_IRQ1, 1); + if (ret) + dev_warn(&pdev->dev, "Failed to set DSP IRQ wake: %d\n", ret); + + cs47l92->core.adsp[0].part = "cs47l92"; + cs47l92->core.adsp[0].num = 1; + cs47l92->core.adsp[0].type = WMFW_ADSP2; + cs47l92->core.adsp[0].rev = 2; + cs47l92->core.adsp[0].dev = madera->dev; + cs47l92->core.adsp[0].regmap = madera->regmap_32bit; + + cs47l92->core.adsp[0].base = MADERA_DSP1_CONFIG_1; + cs47l92->core.adsp[0].mem = cs47l92_dsp1_regions; + cs47l92->core.adsp[0].num_mems = ARRAY_SIZE(cs47l92_dsp1_regions); + + cs47l92->core.adsp[0].lock_regions = WM_ADSP2_REGION_1_9; + + ret = wm_adsp2_init(&cs47l92->core.adsp[0]); + if (ret != 0) + goto error_dsp_irq; + + ret = madera_init_bus_error_irq(&cs47l92->core, 0, wm_adsp2_bus_error); + if (ret != 0) { + wm_adsp2_remove(&cs47l92->core.adsp[0]); + goto error_adsp; + } + + madera_init_fll(madera, 1, MADERA_FLL1_CONTROL_1 - 1, + &cs47l92->fll[0]); + madera_init_fll(madera, 2, MADERA_FLL2_CONTROL_1 - 1, + &cs47l92->fll[1]); + + for (i = 0; i < ARRAY_SIZE(cs47l92_dai); i++) + madera_init_dai(&cs47l92->core, i); + + /* Latch volume update bits */ + for (i = 0; i < ARRAY_SIZE(cs47l92_digital_vu); i++) + regmap_update_bits(madera->regmap, cs47l92_digital_vu[i], + CS47L92_DIG_VU, CS47L92_DIG_VU); + + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + + ret = devm_snd_soc_register_component(&pdev->dev, + &soc_component_dev_cs47l92, + cs47l92_dai, + ARRAY_SIZE(cs47l92_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register component: %d\n", ret); + goto error_pm_runtime; + } + + return ret; + +error_pm_runtime: + pm_runtime_disable(&pdev->dev); + madera_free_bus_error_irq(&cs47l92->core, 0); +error_adsp: + wm_adsp2_remove(&cs47l92->core.adsp[0]); +error_dsp_irq: + madera_set_irq_wake(madera, MADERA_IRQ_DSP_IRQ1, 0); + madera_free_irq(madera, MADERA_IRQ_DSP_IRQ1, cs47l92); +error_core: + madera_core_free(&cs47l92->core); + + return ret; +} + +static int cs47l92_remove(struct platform_device *pdev) +{ + struct cs47l92 *cs47l92 = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + + madera_free_bus_error_irq(&cs47l92->core, 0); + wm_adsp2_remove(&cs47l92->core.adsp[0]); + + madera_set_irq_wake(cs47l92->core.madera, MADERA_IRQ_DSP_IRQ1, 0); + madera_free_irq(cs47l92->core.madera, MADERA_IRQ_DSP_IRQ1, cs47l92); + + madera_core_free(&cs47l92->core); + + return 0; +} + +static struct platform_driver cs47l92_codec_driver = { + .driver = { + .name = "cs47l92-codec", + }, + .probe = &cs47l92_probe, + .remove = &cs47l92_remove, +}; + +module_platform_driver(cs47l92_codec_driver); + +MODULE_SOFTDEP("pre: madera irq-madera arizona-micsupp"); +MODULE_DESCRIPTION("ASoC CS47L92 driver"); +MODULE_AUTHOR("Stuart Henderson "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cs47l92-codec"); diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c index 1c00e2a115bc..52639811cc52 100644 --- a/sound/soc/codecs/madera.c +++ b/sound/soc/codecs/madera.c @@ -87,6 +87,16 @@ #define MADERA_FLLAO_MIN_N 4 #define MADERA_FLLAO_MAX_N 1023 #define MADERA_FLLAO_MAX_FBDIV 254 +#define MADERA_FLLHJ_INT_MAX_N 1023 +#define MADERA_FLLHJ_INT_MIN_N 1 +#define MADERA_FLLHJ_FRAC_MAX_N 255 +#define MADERA_FLLHJ_FRAC_MIN_N 4 +#define MADERA_FLLHJ_LOW_THRESH 192000 +#define MADERA_FLLHJ_MID_THRESH 1152000 +#define MADERA_FLLHJ_MAX_THRESH 13000000 +#define MADERA_FLLHJ_LOW_GAINS 0x23f0 +#define MADERA_FLLHJ_MID_GAINS 0x22f2 +#define MADERA_FLLHJ_HIGH_GAINS 0x21f0 #define MADERA_FLL_SYNCHRONISER_OFFS 0x10 #define CS47L35_FLL_SYNCHRONISER_OFFS 0xE @@ -96,6 +106,7 @@ #define MADERA_FLL_CONTROL_4_OFFS 0x4 #define MADERA_FLL_CONTROL_5_OFFS 0x5 #define MADERA_FLL_CONTROL_6_OFFS 0x6 +#define MADERA_FLL_GAIN_OFFS 0x8 #define MADERA_FLL_CONTROL_7_OFFS 0x9 #define MADERA_FLL_EFS_2_OFFS 0xA #define MADERA_FLL_SYNCHRONISER_1_OFFS 0x1 @@ -107,6 +118,9 @@ #define MADERA_FLL_SYNCHRONISER_7_OFFS 0x7 #define MADERA_FLL_SPREAD_SPECTRUM_OFFS 0x9 #define MADERA_FLL_GPIO_CLOCK_OFFS 0xA +#define MADERA_FLL_CONTROL_10_OFFS 0xA +#define MADERA_FLL_CONTROL_11_OFFS 0xB +#define MADERA_FLL1_DIGITAL_TEST_1_OFFS 0xD #define MADERA_FLLAO_CONTROL_1_OFFS 0x1 #define MADERA_FLLAO_CONTROL_2_OFFS 0x2 @@ -1871,6 +1885,18 @@ const struct soc_enum madera_asrc1_rate[] = { }; EXPORT_SYMBOL_GPL(madera_asrc1_rate); +const struct soc_enum madera_asrc1_bidir_rate[] = { + SOC_VALUE_ENUM_SINGLE(MADERA_ASRC1_RATE1, + MADERA_ASRC1_RATE1_SHIFT, 0xf, + MADERA_RATE_ENUM_SIZE, + madera_rate_text, madera_rate_val), + SOC_VALUE_ENUM_SINGLE(MADERA_ASRC1_RATE2, + MADERA_ASRC1_RATE2_SHIFT, 0xf, + MADERA_RATE_ENUM_SIZE, + madera_rate_text, madera_rate_val), +}; +EXPORT_SYMBOL_GPL(madera_asrc1_bidir_rate); + const struct soc_enum madera_asrc2_rate[] = { SOC_VALUE_ENUM_SINGLE(MADERA_ASRC2_RATE1, MADERA_ASRC2_RATE1_SHIFT, 0xf, @@ -2250,6 +2276,9 @@ int madera_out_ev(struct snd_soc_dapm_widget *w, switch (madera->type) { case CS47L90: case CS47L91: + case CS42L92: + case CS47L92: + case CS47L93: out_up_delay = 6; break; default: @@ -2365,9 +2394,17 @@ int madera_hp_ev(struct snd_soc_dapm_widget *w, madera->hp_ena &= ~mask; madera->hp_ena |= val; - /* if OUT1 is routed to EPOUT, ignore HP clamp and impedance */ - regmap_read(madera->regmap, MADERA_OUTPUT_ENABLES_1, &ep_sel); - ep_sel &= MADERA_EP_SEL_MASK; + switch (madera->type) { + case CS42L92: + case CS47L92: + case CS47L93: + break; + default: + /* if OUT1 is routed to EPOUT, ignore HP clamp and impedance */ + regmap_read(madera->regmap, MADERA_OUTPUT_ENABLES_1, &ep_sel); + ep_sel &= MADERA_EP_SEL_MASK; + break; + } /* Force off if HPDET has disabled the clamp for this output */ if (!ep_sel && @@ -2543,6 +2580,58 @@ static int madera_get_dspclk_setting(struct madera *madera, } } +static int madera_set_outclk(struct snd_soc_component *component, + unsigned int source, unsigned int freq) +{ + int div, div_inc, rate; + + switch (source) { + case MADERA_OUTCLK_SYSCLK: + dev_dbg(component->dev, "Configured OUTCLK to SYSCLK\n"); + snd_soc_component_update_bits(component, MADERA_OUTPUT_RATE_1, + MADERA_OUT_CLK_SRC_MASK, source); + return 0; + case MADERA_OUTCLK_ASYNCCLK: + dev_dbg(component->dev, "Configured OUTCLK to ASYNCCLK\n"); + snd_soc_component_update_bits(component, MADERA_OUTPUT_RATE_1, + MADERA_OUT_CLK_SRC_MASK, source); + return 0; + case MADERA_OUTCLK_MCLK1: + case MADERA_OUTCLK_MCLK2: + case MADERA_OUTCLK_MCLK3: + break; + default: + return -EINVAL; + } + + if (freq % 4000) + rate = 5644800; + else + rate = 6144000; + + div = 1; + div_inc = 0; + while (div <= 8) { + if (freq / div == rate && !(freq % div)) { + dev_dbg(component->dev, "Configured %dHz OUTCLK\n", rate); + snd_soc_component_update_bits(component, + MADERA_OUTPUT_RATE_1, + MADERA_OUT_EXT_CLK_DIV_MASK | + MADERA_OUT_CLK_SRC_MASK, + (div_inc << MADERA_OUT_EXT_CLK_DIV_SHIFT) | + source); + return 0; + } + div_inc++; + div *= 2; + } + + dev_err(component->dev, + "Unable to generate %dHz OUTCLK from %dHz MCLK\n", + rate, freq); + return -EINVAL; +} + int madera_set_sysclk(struct snd_soc_component *component, int clk_id, int source, unsigned int freq, int dir) { @@ -2579,6 +2668,8 @@ int madera_set_sysclk(struct snd_soc_component *component, int clk_id, case MADERA_CLK_OPCLK: case MADERA_CLK_ASYNC_OPCLK: return madera_set_opclk(component, clk_id, freq); + case MADERA_CLK_OUTCLK: + return madera_set_outclk(component, source, freq); default: return -EINVAL; } @@ -2792,6 +2883,10 @@ static const unsigned int madera_sr_vals[] = { #define MADERA_192K_44K1_RATE_MASK 0x003E00 #define MADERA_192K_RATE_MASK (MADERA_192K_48K_RATE_MASK | \ MADERA_192K_44K1_RATE_MASK) +#define MADERA_384K_48K_RATE_MASK 0x0F007E +#define MADERA_384K_44K1_RATE_MASK 0x007E00 +#define MADERA_384K_RATE_MASK (MADERA_384K_48K_RATE_MASK | \ + MADERA_384K_44K1_RATE_MASK) static const struct snd_pcm_hw_constraint_list madera_constraint = { .count = ARRAY_SIZE(madera_sr_vals), @@ -2804,6 +2899,7 @@ static int madera_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct madera_priv *priv = snd_soc_component_get_drvdata(component); struct madera_dai_priv *dai_priv = &priv->dai[dai->id - 1]; + struct madera *madera = priv->madera; unsigned int base_rate; if (!substream->runtime) @@ -2823,12 +2919,26 @@ static int madera_startup(struct snd_pcm_substream *substream, return 0; } - if (base_rate == 0) - dai_priv->constraint.mask = MADERA_192K_RATE_MASK; - else if (base_rate % 4000) - dai_priv->constraint.mask = MADERA_192K_44K1_RATE_MASK; - else - dai_priv->constraint.mask = MADERA_192K_48K_RATE_MASK; + switch (madera->type) { + case CS42L92: + case CS47L92: + case CS47L93: + if (base_rate == 0) + dai_priv->constraint.mask = MADERA_384K_RATE_MASK; + else if (base_rate % 4000) + dai_priv->constraint.mask = MADERA_384K_44K1_RATE_MASK; + else + dai_priv->constraint.mask = MADERA_384K_48K_RATE_MASK; + break; + default: + if (base_rate == 0) + dai_priv->constraint.mask = MADERA_192K_RATE_MASK; + else if (base_rate % 4000) + dai_priv->constraint.mask = MADERA_192K_44K1_RATE_MASK; + else + dai_priv->constraint.mask = MADERA_192K_48K_RATE_MASK; + break; + } return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, @@ -4149,6 +4259,308 @@ int madera_set_fll_ao_refclk(struct madera_fll *fll, int source, } EXPORT_SYMBOL_GPL(madera_set_fll_ao_refclk); +static int madera_fllhj_disable(struct madera_fll *fll) +{ + struct madera *madera = fll->madera; + bool change; + + madera_fll_dbg(fll, "Disabling FLL\n"); + + /* Disable lockdet, but don't set ctrl_upd update but. This allows the + * lock status bit to clear as normal, but should the FLL be enabled + * again due to a control clock being required, the lock won't re-assert + * as the FLL config registers are automatically applied when the FLL + * enables. + */ + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_11_OFFS, + MADERA_FLL1_LOCKDET_MASK, 0); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_1_OFFS, + MADERA_FLL1_HOLD_MASK, MADERA_FLL1_HOLD_MASK); + regmap_update_bits_check(madera->regmap, + fll->base + MADERA_FLL_CONTROL_1_OFFS, + MADERA_FLL1_ENA_MASK, 0, &change); + + madera_wait_for_fll(fll, false); + + /* ctrl_up gates the writes to all the fll's registers, setting it to 0 + * here ensures that after a runtime suspend/resume cycle when one + * enables the fll then ctrl_up is the last bit that is configured + * by the fll enable code rather than the cache sync operation which + * would have updated it much earlier before writing out all fll + * registers + */ + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_2_OFFS, + MADERA_FLL1_CTRL_UPD_MASK, 0); + + if (change) + pm_runtime_put_autosuspend(madera->dev); + + return 0; +} + +static int madera_fllhj_apply(struct madera_fll *fll, int fin) +{ + struct madera *madera = fll->madera; + int refdiv, fref, fout, lockdet_thr, fbdiv, hp, fast_clk, fllgcd; + bool frac = false; + unsigned int fll_n, min_n, max_n, ratio, theta, lambda; + unsigned int gains, val, num; + + madera_fll_dbg(fll, "fin=%d, fout=%d\n", fin, fll->fout); + + for (refdiv = 0; refdiv < 4; refdiv++) + if ((fin / (1 << refdiv)) <= MADERA_FLLHJ_MAX_THRESH) + break; + + fref = fin / (1 << refdiv); + + /* Use simple heuristic approach to find a configuration that + * should work for most input clocks. + */ + fast_clk = 0; + fout = fll->fout; + frac = fout % fref; + + if (fref < MADERA_FLLHJ_LOW_THRESH) { + lockdet_thr = 2; + gains = MADERA_FLLHJ_LOW_GAINS; + if (frac) + fbdiv = 256; + else + fbdiv = 4; + } else if (fref < MADERA_FLLHJ_MID_THRESH) { + lockdet_thr = 8; + gains = MADERA_FLLHJ_MID_GAINS; + fbdiv = 1; + } else { + lockdet_thr = 8; + gains = MADERA_FLLHJ_HIGH_GAINS; + fbdiv = 1; + /* For high speed input clocks, enable 300MHz fast oscillator + * when we're in fractional divider mode. + */ + if (frac) { + fast_clk = 0x3; + fout = fll->fout * 6; + } + } + /* Use high performance mode for fractional configurations. */ + if (frac) { + hp = 0x3; + min_n = MADERA_FLLHJ_FRAC_MIN_N; + max_n = MADERA_FLLHJ_FRAC_MAX_N; + } else { + hp = 0x0; + min_n = MADERA_FLLHJ_INT_MIN_N; + max_n = MADERA_FLLHJ_INT_MAX_N; + } + + ratio = fout / fref; + + madera_fll_dbg(fll, "refdiv=%d, fref=%d, frac:%d\n", + refdiv, fref, frac); + + while (ratio / fbdiv < min_n) { + fbdiv /= 2; + if (fbdiv < 1) { + madera_fll_err(fll, "FBDIV (%d) must be >= 1\n", fbdiv); + return -EINVAL; + } + } + while (frac && (ratio / fbdiv > max_n)) { + fbdiv *= 2; + if (fbdiv >= 1024) { + madera_fll_err(fll, "FBDIV (%u) >= 1024\n", fbdiv); + return -EINVAL; + } + } + + madera_fll_dbg(fll, "lockdet=%d, hp=0x%x, fbdiv:%d\n", + lockdet_thr, hp, fbdiv); + + /* Calculate N.K values */ + fllgcd = gcd(fout, fbdiv * fref); + num = fout / fllgcd; + lambda = (fref * fbdiv) / fllgcd; + fll_n = num / lambda; + theta = num % lambda; + + madera_fll_dbg(fll, "fll_n=%d, gcd=%d, theta=%d, lambda=%d\n", + fll_n, fllgcd, theta, lambda); + + /* Some sanity checks before any registers are written. */ + if (fll_n < min_n || fll_n > max_n) { + madera_fll_err(fll, "N not in valid %s mode range %d-%d: %d\n", + frac ? "fractional" : "integer", min_n, max_n, + fll_n); + return -EINVAL; + } + if (fbdiv < 1 || (frac && fbdiv >= 1024) || (!frac && fbdiv >= 256)) { + madera_fll_err(fll, "Invalid fbdiv for %s mode (%u)\n", + frac ? "fractional" : "integer", fbdiv); + return -EINVAL; + } + + /* clear the ctrl_upd bit to guarantee we write to it later. */ + regmap_write(madera->regmap, + fll->base + MADERA_FLL_CONTROL_2_OFFS, + fll_n << MADERA_FLL1_N_SHIFT); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_3_OFFS, + MADERA_FLL1_THETA_MASK, + theta << MADERA_FLL1_THETA_SHIFT); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_4_OFFS, + MADERA_FLL1_LAMBDA_MASK, + lambda << MADERA_FLL1_LAMBDA_SHIFT); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_5_OFFS, + MADERA_FLL1_FB_DIV_MASK, + fbdiv << MADERA_FLL1_FB_DIV_SHIFT); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_6_OFFS, + MADERA_FLL1_REFCLK_DIV_MASK, + refdiv << MADERA_FLL1_REFCLK_DIV_SHIFT); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_GAIN_OFFS, + 0xffff, + gains); + val = hp << MADERA_FLL1_HP_SHIFT; + val |= 1 << MADERA_FLL1_PHASEDET_ENA_SHIFT; + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_10_OFFS, + MADERA_FLL1_HP_MASK | MADERA_FLL1_PHASEDET_ENA_MASK, + val); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_11_OFFS, + MADERA_FLL1_LOCKDET_THR_MASK, + lockdet_thr << MADERA_FLL1_LOCKDET_THR_SHIFT); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL1_DIGITAL_TEST_1_OFFS, + MADERA_FLL1_SYNC_EFS_ENA_MASK | + MADERA_FLL1_CLK_VCO_FAST_SRC_MASK, + fast_clk); + + return 0; +} + +static int madera_fllhj_enable(struct madera_fll *fll) +{ + struct madera *madera = fll->madera; + int already_enabled = madera_is_enabled_fll(fll, fll->base); + int ret; + + if (already_enabled < 0) + return already_enabled; + + if (!already_enabled) + pm_runtime_get_sync(madera->dev); + + madera_fll_dbg(fll, "Enabling FLL, initially %s\n", + already_enabled ? "enabled" : "disabled"); + + /* FLLn_HOLD must be set before configuring any registers */ + regmap_update_bits(fll->madera->regmap, + fll->base + MADERA_FLL_CONTROL_1_OFFS, + MADERA_FLL1_HOLD_MASK, + MADERA_FLL1_HOLD_MASK); + + /* Apply refclk */ + ret = madera_fllhj_apply(fll, fll->ref_freq); + if (ret) { + madera_fll_err(fll, "Failed to set FLL: %d\n", ret); + goto out; + } + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_1_OFFS, + CS47L92_FLL1_REFCLK_SRC_MASK, + fll->ref_src << CS47L92_FLL1_REFCLK_SRC_SHIFT); + + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_1_OFFS, + MADERA_FLL1_ENA_MASK, + MADERA_FLL1_ENA_MASK); + +out: + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_11_OFFS, + MADERA_FLL1_LOCKDET_MASK, + MADERA_FLL1_LOCKDET_MASK); + + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_2_OFFS, + MADERA_FLL1_CTRL_UPD_MASK, + MADERA_FLL1_CTRL_UPD_MASK); + + /* Release the hold so that flln locks to external frequency */ + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_1_OFFS, + MADERA_FLL1_HOLD_MASK, + 0); + + if (!already_enabled) + madera_wait_for_fll(fll, true); + + return 0; +} + +static int madera_fllhj_validate(struct madera_fll *fll, + unsigned int ref_in, + unsigned int fout) +{ + if (fout && !ref_in) { + madera_fll_err(fll, "fllout set without valid input clk\n"); + return -EINVAL; + } + + if (fll->fout && fout != fll->fout) { + madera_fll_err(fll, "Can't change output on active FLL\n"); + return -EINVAL; + } + + if (ref_in / MADERA_FLL_MAX_REFDIV > MADERA_FLLHJ_MAX_THRESH) { + madera_fll_err(fll, "Can't scale %dMHz to <=13MHz\n", ref_in); + return -EINVAL; + } + + return 0; +} + +int madera_fllhj_set_refclk(struct madera_fll *fll, int source, + unsigned int fin, unsigned int fout) +{ + int ret = 0; + + /* To remain consistent with previous FLLs, we expect fout to be + * provided in the form of the required sysclk rate, which is + * 2x the calculated fll out. + */ + if (fout) + fout /= 2; + + if (fll->ref_src == source && fll->ref_freq == fin && + fll->fout == fout) + return 0; + + if (fin && fout && madera_fllhj_validate(fll, fin, fout)) + return -EINVAL; + + fll->ref_src = source; + fll->ref_freq = fin; + fll->fout = fout; + + if (fout) + ret = madera_fllhj_enable(fll); + else + madera_fllhj_disable(fll); + + return ret; +} +EXPORT_SYMBOL_GPL(madera_fllhj_set_refclk); + /** * madera_set_output_mode - Set the mode of the specified output * diff --git a/sound/soc/codecs/madera.h b/sound/soc/codecs/madera.h index 0af66f280770..1f3e8e230cf2 100644 --- a/sound/soc/codecs/madera.h +++ b/sound/soc/codecs/madera.h @@ -47,6 +47,7 @@ #define MADERA_CLK_SYSCLK_3 6 #define MADERA_CLK_ASYNCCLK_2 7 #define MADERA_CLK_DSPCLK 8 +#define MADERA_CLK_OUTCLK 9 #define MADERA_CLK_SRC_MCLK1 0x0 #define MADERA_CLK_SRC_MCLK2 0x1 @@ -61,6 +62,12 @@ #define MADERA_CLK_SRC_AIF4BCLK 0xB #define MADERA_CLK_SRC_FLLAO 0xF +#define MADERA_OUTCLK_SYSCLK 0 +#define MADERA_OUTCLK_ASYNCCLK 1 +#define MADERA_OUTCLK_MCLK1 4 +#define MADERA_OUTCLK_MCLK2 5 +#define MADERA_OUTCLK_MCLK3 6 + #define MADERA_MIXER_VOL_MASK 0x00FE #define MADERA_MIXER_VOL_SHIFT 1 #define MADERA_MIXER_VOL_WIDTH 7 @@ -326,6 +333,7 @@ extern const struct soc_enum madera_sample_rate[]; extern const struct soc_enum madera_isrc_fsl[]; extern const struct soc_enum madera_isrc_fsh[]; extern const struct soc_enum madera_asrc1_rate[]; +extern const struct soc_enum madera_asrc1_bidir_rate[]; extern const struct soc_enum madera_asrc2_rate[]; extern const struct soc_enum madera_dfc_width[]; extern const struct soc_enum madera_dfc_type[]; @@ -403,6 +411,8 @@ int madera_set_fll_syncclk(struct madera_fll *fll, int source, unsigned int fref, unsigned int fout); int madera_set_fll_ao_refclk(struct madera_fll *fll, int source, unsigned int fin, unsigned int fout); +int madera_fllhj_set_refclk(struct madera_fll *fll, int source, + unsigned int fin, unsigned int fout); int madera_core_init(struct madera_priv *priv); int madera_core_free(struct madera_priv *priv); -- cgit v1.2.3 From 68c907f10cd816cad2287167a1a1d77914a6d466 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 25 Jul 2019 18:59:44 +0200 Subject: ASoC: codec2codec: run callbacks in order When handling dai_link events on codec to codec links, run all .startup() callbacks on sinks and sources before running any .hw_params(). Same goes for hw_free() and shutdown(). This is closer to the behavior of regular dai links Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190725165949.29699-2-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1d04612601ad..034b31fd2ecb 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3835,11 +3835,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, goto out; } source->active++; - ret = snd_soc_dai_hw_params(source, &substream, params); - if (ret < 0) - goto out; - - dapm_update_dai_unlocked(&substream, params, source); } substream.stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -3853,6 +3848,23 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, goto out; } sink->active++; + } + + substream.stream = SNDRV_PCM_STREAM_CAPTURE; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; + + ret = snd_soc_dai_hw_params(source, &substream, params); + if (ret < 0) + goto out; + + dapm_update_dai_unlocked(&substream, params, source); + } + + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + ret = snd_soc_dai_hw_params(sink, &substream, params); if (ret < 0) goto out; @@ -3889,9 +3901,18 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, substream.stream = SNDRV_PCM_STREAM_CAPTURE; snd_soc_dapm_widget_for_each_source_path(w, path) { source = path->source->priv; - snd_soc_dai_hw_free(source, &substream); + } + + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + snd_soc_dai_hw_free(sink, &substream); + } + substream.stream = SNDRV_PCM_STREAM_CAPTURE; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; source->active--; snd_soc_dai_shutdown(source, &substream); } @@ -3899,9 +3920,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, substream.stream = SNDRV_PCM_STREAM_PLAYBACK; snd_soc_dapm_widget_for_each_sink_path(w, path) { sink = path->sink->priv; - - snd_soc_dai_hw_free(sink, &substream); - sink->active--; snd_soc_dai_shutdown(sink, &substream); } -- cgit v1.2.3 From 054d65004c6a008dfefbdae4fc1b46a3ad4e94c1 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 25 Jul 2019 18:59:45 +0200 Subject: ASoC: codec2codec: name link using stream direction At the moment, codec to codec dai link widgets are named after the cpu dai and the 1st codec valid on the link. This might be confusing if there is multiple valid codecs on the link for one stream direction. Instead, use the dai link name and the stream direction to name the the dai link widget Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190725165949.29699-3-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 034b31fd2ecb..7db4abd9a0a5 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4056,8 +4056,7 @@ outfree_w_param: static struct snd_soc_dapm_widget * snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink) + char *id) { struct snd_soc_dapm_widget template; struct snd_soc_dapm_widget *w; @@ -4067,7 +4066,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, int ret; link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s", - source->name, sink->name); + rtd->dai_link->name, id); if (!link_name) return ERR_PTR(-ENOMEM); @@ -4247,15 +4246,13 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, } for_each_rtd_codec_dai(rtd, i, codec_dai) { - /* connect BE DAI playback if widgets are valid */ codec = codec_dai->playback_widget; if (playback_cpu && codec) { if (!playback) { playback = snd_soc_dapm_new_dai(card, rtd, - playback_cpu, - codec); + "playback"); if (IS_ERR(playback)) { dev_err(rtd->dev, "ASoC: Failed to create DAI %s: %ld\n", @@ -4284,8 +4281,7 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, if (codec && capture_cpu) { if (!capture) { capture = snd_soc_dapm_new_dai(card, rtd, - codec, - capture_cpu); + "capture"); if (IS_ERR(capture)) { dev_err(rtd->dev, "ASoC: Failed to create DAI %s: %ld\n", -- cgit v1.2.3 From 3dcfb397dad2ad55bf50de3c5d5a57090d35a18a Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 25 Jul 2019 18:59:46 +0200 Subject: ASoC: codec2codec: deal with params when necessary When there is an event on codec to codec dai_link, we only need to deal with params if the event is SND_SOC_DAPM_PRE_PMU, when .hw_params() is called. For the other events, it is useless. Also, dealing with the codec to codec params just before calling .hw_params() callbacks give change to either party on the link to alter params content in .startup(), which might be useful in some cases Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190725165949.29699-4-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 159 +++++++++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 67 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7db4abd9a0a5..6dcaf9ff6eb5 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3764,25 +3764,59 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); -static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static int +snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, + struct snd_pcm_substream *substream) { struct snd_soc_dapm_path *path; struct snd_soc_dai *source, *sink; - struct snd_soc_pcm_runtime *rtd = w->priv; - const struct snd_soc_pcm_stream *config; - struct snd_pcm_substream substream; + struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_hw_params *params = NULL; - struct snd_pcm_runtime *runtime = NULL; + const struct snd_soc_pcm_stream *config = NULL; unsigned int fmt; - int ret = 0; + int ret; - config = rtd->dai_link->params + rtd->params_select; + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; - if (WARN_ON(!config) || - WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || - list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) - return -EINVAL; + substream->stream = SNDRV_PCM_STREAM_CAPTURE; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; + + ret = snd_soc_dai_startup(source, substream); + if (ret < 0) { + dev_err(source->dev, + "ASoC: startup() failed: %d\n", ret); + goto out; + } + source->active++; + } + + substream->stream = SNDRV_PCM_STREAM_PLAYBACK; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + ret = snd_soc_dai_startup(sink, substream); + if (ret < 0) { + dev_err(sink->dev, + "ASoC: startup() failed: %d\n", ret); + goto out; + } + sink->active++; + } + + /* + * Note: getting the config after .startup() gives a chance to + * either party on the link to alter the configuration if + * necessary + */ + config = rtd->dai_link->params + rtd->params_select; + if (WARN_ON(!config)) { + dev_err(w->dapm->dev, "ASoC: link config missing\n"); + ret = -EINVAL; + goto out; + } /* Be a little careful as we don't want to overflow the mask array */ if (config->formats) { @@ -3790,27 +3824,62 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, } else { dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n", config->formats); - fmt = 0; - } - /* Currently very limited parameter selection */ - params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - ret = -ENOMEM; + ret = -EINVAL; goto out; } - snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt); + snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt); hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min = config->rate_min; hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max = config->rate_max; - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min = config->channels_min; hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max = config->channels_max; + substream->stream = SNDRV_PCM_STREAM_CAPTURE; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; + + ret = snd_soc_dai_hw_params(source, substream, params); + if (ret < 0) + goto out; + + dapm_update_dai_unlocked(substream, params, source); + } + + substream->stream = SNDRV_PCM_STREAM_PLAYBACK; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + ret = snd_soc_dai_hw_params(sink, substream, params); + if (ret < 0) + goto out; + + dapm_update_dai_unlocked(substream, params, sink); + } + +out: + kfree(params); + return 0; +} + +static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_dapm_path *path; + struct snd_soc_dai *source, *sink; + struct snd_soc_pcm_runtime *rtd = w->priv; + struct snd_pcm_substream substream; + struct snd_pcm_runtime *runtime = NULL; + int ret = 0; + + if (WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || + list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) + return -EINVAL; + memset(&substream, 0, sizeof(substream)); /* Allocate a dummy snd_pcm_runtime for startup() and other ops() */ @@ -3824,53 +3893,10 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - substream.stream = SNDRV_PCM_STREAM_CAPTURE; - snd_soc_dapm_widget_for_each_source_path(w, path) { - source = path->source->priv; - - ret = snd_soc_dai_startup(source, &substream); - if (ret < 0) { - dev_err(source->dev, - "ASoC: startup() failed: %d\n", ret); - goto out; - } - source->active++; - } - - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - snd_soc_dapm_widget_for_each_sink_path(w, path) { - sink = path->sink->priv; - - ret = snd_soc_dai_startup(sink, &substream); - if (ret < 0) { - dev_err(sink->dev, - "ASoC: startup() failed: %d\n", ret); - goto out; - } - sink->active++; - } - - substream.stream = SNDRV_PCM_STREAM_CAPTURE; - snd_soc_dapm_widget_for_each_source_path(w, path) { - source = path->source->priv; - - ret = snd_soc_dai_hw_params(source, &substream, params); - if (ret < 0) - goto out; - - dapm_update_dai_unlocked(&substream, params, source); - } - - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - snd_soc_dapm_widget_for_each_sink_path(w, path) { - sink = path->sink->priv; - - ret = snd_soc_dai_hw_params(sink, &substream, params); - if (ret < 0) - goto out; + ret = snd_soc_dai_link_event_pre_pmu(w, &substream); + if (ret < 0) + goto out; - dapm_update_dai_unlocked(&substream, params, sink); - } break; case SND_SOC_DAPM_POST_PMU: @@ -3932,7 +3958,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, out: kfree(runtime); - kfree(params); return ret; } -- cgit v1.2.3 From 2448c813b12cf1fb08da1d20bdb2ae583cda2d6f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 26 Jul 2019 09:42:44 +0300 Subject: ASoC: ti: davinci-mcasp: Support for correct symmetric sample bits Implement custom snd_pcm_hw_rule to filter the available formats for the second stream to make it symmetric and allow only formats which require the same amount of bits on the bus as the running stream. A simple constraint is not working correctly because for example: the first stream is started with S24_LE If we place 24 as constraint for the SAMPLE_BITS then the second stream can not use S24_LE as it is physically 32bits. If we would place 32 as constraint (physical width) then S32_LE would have been allowed, but S24_3LE is not. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190726064244.3762-3-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 50 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 87ae19329e71..7aa3c32e4a49 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -109,6 +109,7 @@ struct davinci_mcasp { /* Used for comstraint setting on the second stream */ u32 channels; + int max_format_width; u8 active_serializers[2]; #ifdef CONFIG_GPIOLIB @@ -766,6 +767,8 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, if (mcasp->slot_width) slot_width = mcasp->slot_width; + else if (mcasp->max_format_width) + slot_width = mcasp->max_format_width; else slot_width = sample_width; /* @@ -1233,8 +1236,11 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, davinci_config_channel_size(mcasp, word_length); - if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) + if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { mcasp->channels = channels; + if (!mcasp->max_format_width) + mcasp->max_format_width = word_length; + } return 0; } @@ -1286,6 +1292,28 @@ static int davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params *params, return snd_mask_refine(fmt, &nfmt); } +static int davinci_mcasp_hw_rule_format_width(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct davinci_mcasp_ruledata *rd = rule->private; + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + struct snd_mask nfmt; + int i, format_width; + + snd_mask_none(&nfmt); + format_width = rd->mcasp->max_format_width; + + for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { + if (snd_mask_test(fmt, i)) { + if (snd_pcm_format_width(i) == format_width) { + snd_mask_set(&nfmt, i); + } + } + } + + return snd_mask_refine(fmt, &nfmt); +} + static const unsigned int davinci_mcasp_dai_rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, @@ -1463,7 +1491,20 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &mcasp->chconstr[substream->stream]); - if (mcasp->slot_width) { + if (mcasp->max_format_width) { + /* + * Only allow formats which require same amount of bits on the + * bus as the currently running stream + */ + ret = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_FORMAT, + davinci_mcasp_hw_rule_format_width, + ruledata, + SNDRV_PCM_HW_PARAM_FORMAT, -1); + if (ret) + return ret; + } + else if (mcasp->slot_width) { /* Only allow formats require <= slot_width bits on the bus */ ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, @@ -1514,8 +1555,10 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) return; - if (!cpu_dai->active) + if (!cpu_dai->active) { mcasp->channels = 0; + mcasp->max_format_width = 0; + } } static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { @@ -1571,7 +1614,6 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }, .ops = &davinci_mcasp_dai_ops, - .symmetric_samplebits = 1, .symmetric_rates = 1, }, { -- cgit v1.2.3 From dd65f7e19c6961ba6a69f7c925021b7a270cb950 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 26 Jul 2019 11:42:34 +0200 Subject: ALSA: hda - Show the fatal CORB/RIRB error more clearly The last fallback of CORB/RIRB communication error recovery is to turn on the single command mode, and this last resort usually means that something is really screwed up. Instead of a normal dev_err(), show the error more clearly with dev_WARN() with the caller stack trace. Also, show the bus-reset fallback also as an error, too. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index c8d1b4316245..4b4cb0fd5102 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -864,10 +864,13 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr, */ if (hbus->allow_bus_reset && !hbus->response_reset && !hbus->in_reset) { hbus->response_reset = 1; + dev_err(chip->card->dev, + "No response from codec, resetting bus: last cmd=0x%08x\n", + bus->last_cmd[addr]); return -EAGAIN; /* give a chance to retry */ } - dev_err(chip->card->dev, + dev_WARN(chip->card->dev, "azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n", bus->last_cmd[addr]); chip->single_cmd = 1; -- cgit v1.2.3 From 2127c01b7f63b06a21559f56a8c81a3c6535bd1a Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Fri, 26 Jul 2019 10:14:42 +0800 Subject: ALSA: i2c: ak4xxx-adda: Fix a possible null pointer dereference in build_adc_controls() In build_adc_controls(), there is an if statement on line 773 to check whether ak->adc_info is NULL: if (! ak->adc_info || ! ak->adc_info[mixer_ch].switch_name) When ak->adc_info is NULL, it is used on line 792: knew.name = ak->adc_info[mixer_ch].selector_name; Thus, a possible null-pointer dereference may occur. To fix this bug, referring to lines 773 and 774, ak->adc_info and ak->adc_info[mixer_ch].selector_name are checked before being used. This bug is found by a static analysis tool STCheck written by us. Signed-off-by: Jia-Ju Bai Signed-off-by: Takashi Iwai --- sound/i2c/other/ak4xxx-adda.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 5f59316f982a..7d15093844b9 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -775,11 +775,12 @@ static int build_adc_controls(struct snd_akm4xxx *ak) return err; memset(&knew, 0, sizeof(knew)); - knew.name = ak->adc_info[mixer_ch].selector_name; - if (!knew.name) { + if (!ak->adc_info || + !ak->adc_info[mixer_ch].selector_name) { knew.name = "Capture Channel"; knew.index = mixer_ch + ak->idx_offset * 2; - } + } else + knew.name = ak->adc_info[mixer_ch].selector_name; knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; knew.info = ak4xxx_capture_source_info; -- cgit v1.2.3 From c8415833ec242b9ddf73bf9e1057e12f9b0fcd16 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 26 Jul 2019 13:33:27 +0100 Subject: ASoC: codec2codec: fix missing return of error return code Currently in function snd_soc_dai_link_event_pre_pmu the error return code in variable err is being set but this is not actually being returned, the function just returns zero even when there are failures. Fix this by returning the error return code. Addresses-Coverity: ("Unused value") Fixes: 3dcfb397dad2 ("ASoC: codec2codec: deal with params when necessary") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190726123327.10467-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index be9bb05b0165..2d183e2d23de 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3776,7 +3776,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, struct snd_pcm_hw_params *params = NULL; const struct snd_soc_pcm_stream *config = NULL; unsigned int fmt; - int ret; + int ret = 0; params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) @@ -3865,7 +3865,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, out: kfree(params); - return 0; + return ret; } static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, -- cgit v1.2.3 From 096769ea95380ef3048765aef676e8947bc368d4 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Fri, 26 Jul 2019 11:09:29 +0200 Subject: ASoC: Intel: Skylake: Remove static table index when parsing topology MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently when we remove and reload driver we use previous ref_count value to start iterating over skl->modules which leads to out of table access. To fix this just inline the function and calculate indexes everytime we parse UUID token. Signed-off-by: Amadeusz Sławiński Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190726090929.27946-2-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 118866cd5075..c1c37ce759bd 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -3333,25 +3333,6 @@ static int skl_tplg_get_int_tkn(struct device *dev, return tkn_count; } -static int skl_tplg_get_manifest_uuid(struct device *dev, - struct skl_dev *skl, - struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) -{ - static int ref_count; - struct skl_module *mod; - - if (uuid_tkn->token == SKL_TKN_UUID) { - mod = skl->modules[ref_count]; - guid_copy(&mod->uuid, (guid_t *)&uuid_tkn->uuid); - ref_count++; - } else { - dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token); - return -EINVAL; - } - - return 0; -} - /* * Fill the manifest structure by parsing the tokens based on the * type. @@ -3362,6 +3343,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, { int tkn_count = 0, ret; int off = 0, tuple_size = 0; + u8 uuid_index = 0; struct snd_soc_tplg_vendor_array *array; struct snd_soc_tplg_vendor_value_elem *tkn_elem; @@ -3384,9 +3366,17 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, continue; case SND_SOC_TPLG_TUPLE_TYPE_UUID: - ret = skl_tplg_get_manifest_uuid(dev, skl, array->uuid); - if (ret < 0) - return ret; + if (array->uuid->token != SKL_TKN_UUID) { + dev_err(dev, "Not an UUID token: %d\n", + array->uuid->token); + return -EINVAL; + } + if (uuid_index >= skl->nr_modules) { + dev_err(dev, "Too many UUID tokens\n"); + return -EINVAL; + } + guid_copy(&skl->modules[uuid_index++]->uuid, + (guid_t *)&array->uuid->uuid); tuple_size += sizeof(*array->uuid); continue; -- cgit v1.2.3 From 9e4d5c1be21f0c00e747e92186784f3298309b3e Mon Sep 17 00:00:00 2001 From: "Geoffrey D. Bennett" Date: Mon, 29 Jul 2019 00:42:45 +0930 Subject: ALSA: usb-audio: Scarlett Gen 2 mixer interface Add mixer quirk for the Focusrite Scarlett 6i6, 18i8, and 18i20 Gen 2 audio interfaces. Although the interfaces are USB compliant, additional input/output level controls and hardware routing/mixing functionality are available using proprietary USB requests. Signed-off-by: Geoffrey D. Bennett Signed-off-by: Takashi Iwai --- sound/usb/Makefile | 1 + sound/usb/mixer.c | 4 + sound/usb/mixer.h | 4 + sound/usb/mixer_quirks.c | 7 + sound/usb/mixer_scarlett_gen2.c | 2075 +++++++++++++++++++++++++++++++++++++++ sound/usb/mixer_scarlett_gen2.h | 7 + 6 files changed, 2098 insertions(+) create mode 100644 sound/usb/mixer_scarlett_gen2.c create mode 100644 sound/usb/mixer_scarlett_gen2.h (limited to 'sound') diff --git a/sound/usb/Makefile b/sound/usb/Makefile index e1ce257ab705..f4b7384caa9d 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -11,6 +11,7 @@ snd-usb-audio-objs := card.o \ mixer.o \ mixer_quirks.o \ mixer_scarlett.o \ + mixer_scarlett_gen2.o \ mixer_us16x08.o \ pcm.o \ power.o \ diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 7498b5191b68..7b51ab4c35b0 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -3509,6 +3509,8 @@ void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer) usb_kill_urb(mixer->urb); if (mixer->rc_urb) usb_kill_urb(mixer->rc_urb); + if (mixer->private_free) + mixer->private_free(mixer); mixer->disconnected = true; } @@ -3536,6 +3538,8 @@ static int snd_usb_mixer_activate(struct usb_mixer_interface *mixer) int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer) { snd_usb_mixer_inactivate(mixer); + if (mixer->private_suspend) + mixer->private_suspend(mixer); return 0; } diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 394cd9107507..37e1b234c802 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -28,6 +28,10 @@ struct usb_mixer_interface { struct media_mixer_ctl *media_mixer_ctl; bool disconnected; + + void *private_data; + void (*private_free)(struct usb_mixer_interface *mixer); + void (*private_suspend)(struct usb_mixer_interface *mixer); }; #define MAX_CHANNELS 16 /* max logical channels */ diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 199fa157a411..70805c15b0b5 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -32,6 +32,7 @@ #include "mixer.h" #include "mixer_quirks.h" #include "mixer_scarlett.h" +#include "mixer_scarlett_gen2.h" #include "mixer_us16x08.h" #include "helper.h" @@ -2258,6 +2259,12 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) err = snd_scarlett_controls_create(mixer); break; + case USB_ID(0x1235, 0x8203): /* Focusrite Scarlett 6i6 2nd Gen */ + case USB_ID(0x1235, 0x8204): /* Focusrite Scarlett 18i8 2nd Gen */ + case USB_ID(0x1235, 0x8201): /* Focusrite Scarlett 18i20 2nd Gen */ + err = snd_scarlett_gen2_controls_create(mixer); + break; + case USB_ID(0x041e, 0x323b): /* Creative Sound Blaster E1 */ err = snd_soundblaster_e1_switch_create(mixer); break; diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c new file mode 100644 index 000000000000..7d460b1f1735 --- /dev/null +++ b/sound/usb/mixer_scarlett_gen2.c @@ -0,0 +1,2075 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Focusrite Scarlett 6i6/18i8/18i20 Gen 2 Driver for ALSA + * + * Copyright (c) 2018-2019 by Geoffrey D. Bennett + * + * Based on the Scarlett (Gen 1) Driver for ALSA: + * + * Copyright (c) 2013 by Tobias Hoffmann + * Copyright (c) 2013 by Robin Gareus + * Copyright (c) 2002 by Takashi Iwai + * Copyright (c) 2014 by Chris J Arges + * + * Many codes borrowed from audio.c by + * Alan Cox (alan at lxorguk.ukuu.org.uk) + * Thomas Sailer (sailer at ife.ee.ethz.ch) + * + * Code cleanup: + * David Henningsson + */ + +/* Mixer Interface for the Focusrite Scarlett 6i6/18i8/18i20 Gen 2 audio + * interface. Based on the Gen 1 driver and rewritten. + */ + +/* The protocol was reverse engineered by looking at the communication + * between Focusrite Control 2.3.4 and the Focusrite(R) Scarlett 18i20 + * (firmware 1083) using usbmon in July-August 2018. + * + * Scarlett 18i8 support added in April 2019. + * + * Scarlett 6i6 support added in June 2019 (thanks to Martin Wittmann + * for providing usbmon output and testing). + * + * This ALSA mixer gives access to: + * - input, output, mixer-matrix muxes + * - 18x10 mixer-matrix gain stages + * - gain/volume controls + * - level meters + * - line/inst level and pad controls + * + * + * /--------------\ 18chn 20chn /--------------\ + * | Hardware in +--+------\ /-------------+--+ ALSA PCM out | + * \--------------/ | | | | \--------------/ + * | | | /-----\ | + * | | | | | | + * | v v v | | + * | +---------------+ | | + * | \ Matrix Mux / | | + * | +-----+-----+ | | + * | | | | + * | |18chn | | + * | | | | + * | | 10chn| | + * | v | | + * | +------------+ | | + * | | Mixer | | | + * | | Matrix | | | + * | | | | | + * | | 18x10 Gain | | | + * | | stages | | | + * | +-----+------+ | | + * | | | | + * |18chn |10chn | |20chn + * | | | | + * | +----------/ | + * | | | + * v v v + * =========================== + * +---------------+ +--—------------+ + * \ Output Mux / \ Capture Mux / + * +---+---+---+ +-----+-----+ + * | | | + * 10chn| | |18chn + * | | | + * /--------------\ | | | /--------------\ + * | S/PDIF, ADAT |<--/ |10chn \-->| ALSA PCM in | + * | Hardware out | | \--------------/ + * \--------------/ | + * v + * +-------------+ Software gain per channel. + * | Master Gain |<-- 18i20 only: Switch per channel + * +------+------+ to select HW or SW gain control. + * | + * |10chn + * /--------------\ | + * | Analogue |<------/ + * | Hardware out | + * \--------------/ + * + * + */ + +#include +#include +#include + +#include +#include + +#include "usbaudio.h" +#include "mixer.h" +#include "helper.h" + +#include "mixer_scarlett_gen2.h" + +/* device_setup value to enable */ +#define SCARLETT2_ENABLE 0x01 + +/* some gui mixers can't handle negative ctl values */ +#define SCARLETT2_VOLUME_BIAS 127 + +/* mixer range from -80dB to +6dB in 0.5dB steps */ +#define SCARLETT2_MIXER_MIN_DB -80 +#define SCARLETT2_MIXER_BIAS (-SCARLETT2_MIXER_MIN_DB * 2) +#define SCARLETT2_MIXER_MAX_DB 6 +#define SCARLETT2_MIXER_MAX_VALUE \ + ((SCARLETT2_MIXER_MAX_DB - SCARLETT2_MIXER_MIN_DB) * 2) + +/* map from (dB + 80) * 2 to mixer value + * for dB in 0 .. 172: int(8192 * pow(10, ((dB - 160) / 2 / 20))) + */ +static const u16 scarlett2_mixer_values[173] = { + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 12, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 23, 24, 25, 27, 29, 30, 32, 34, 36, 38, 41, 43, 46, 48, 51, + 54, 57, 61, 65, 68, 73, 77, 81, 86, 91, 97, 103, 109, 115, + 122, 129, 137, 145, 154, 163, 173, 183, 194, 205, 217, 230, + 244, 259, 274, 290, 307, 326, 345, 365, 387, 410, 434, 460, + 487, 516, 547, 579, 614, 650, 689, 730, 773, 819, 867, 919, + 973, 1031, 1092, 1157, 1225, 1298, 1375, 1456, 1543, 1634, + 1731, 1833, 1942, 2057, 2179, 2308, 2445, 2590, 2744, 2906, + 3078, 3261, 3454, 3659, 3876, 4105, 4349, 4606, 4879, 5168, + 5475, 5799, 6143, 6507, 6892, 7301, 7733, 8192, 8677, 9191, + 9736, 10313, 10924, 11571, 12257, 12983, 13752, 14567, 15430, + 16345 +}; + +/* Maximum number of analogue outputs */ +#define SCARLETT2_ANALOGUE_MAX 10 + +/* Maximum number of level and pad switches */ +#define SCARLETT2_LEVEL_SWITCH_MAX 2 +#define SCARLETT2_PAD_SWITCH_MAX 4 + +/* Maximum number of inputs to the mixer */ +#define SCARLETT2_INPUT_MIX_MAX 18 + +/* Maximum number of outputs from the mixer */ +#define SCARLETT2_OUTPUT_MIX_MAX 10 + +/* Maximum size of the data in the USB mux assignment message: + * 18 inputs, 20 outputs, 18 matrix inputs, 8 spare + */ +#define SCARLETT2_MUX_MAX 64 + +/* Number of meters: + * 18 inputs, 20 outputs, 18 matrix inputs + */ +#define SCARLETT2_NUM_METERS 56 + +/* Hardware port types: + * - None (no input to mux) + * - Analogue I/O + * - S/PDIF I/O + * - ADAT I/O + * - Mixer I/O + * - PCM I/O + */ +enum { + SCARLETT2_PORT_TYPE_NONE = 0, + SCARLETT2_PORT_TYPE_ANALOGUE = 1, + SCARLETT2_PORT_TYPE_SPDIF = 2, + SCARLETT2_PORT_TYPE_ADAT = 3, + SCARLETT2_PORT_TYPE_MIX = 4, + SCARLETT2_PORT_TYPE_PCM = 5, + SCARLETT2_PORT_TYPE_COUNT = 6, +}; + +/* Count of total I/O and number available at each sample rate */ +enum { + SCARLETT2_PORT_IN = 0, + SCARLETT2_PORT_OUT = 1, + SCARLETT2_PORT_OUT_44 = 2, + SCARLETT2_PORT_OUT_88 = 3, + SCARLETT2_PORT_OUT_176 = 4, + SCARLETT2_PORT_DIRECTIONS = 5, +}; + +/* Hardware buttons on the 18i20 */ +#define SCARLETT2_BUTTON_MAX 2 + +static const char *const scarlett2_button_names[SCARLETT2_BUTTON_MAX] = { + "Mute", "Dim" +}; + +/* Description of each hardware port type: + * - id: hardware ID for this port type + * - num: number of sources/destinations of this port type + * - src_descr: printf format string for mux input selections + * - src_num_offset: added to channel number for the fprintf + * - dst_descr: printf format string for mixer controls + */ +struct scarlett2_ports { + u16 id; + int num[SCARLETT2_PORT_DIRECTIONS]; + const char * const src_descr; + int src_num_offset; + const char * const dst_descr; +}; + +struct scarlett2_device_info { + u8 line_out_hw_vol; /* line out hw volume is sw controlled */ + u8 button_count; /* number of buttons */ + u8 level_input_count; /* inputs with level selectable */ + u8 pad_input_count; /* inputs with pad selectable */ + const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX]; + struct scarlett2_ports ports[SCARLETT2_PORT_TYPE_COUNT]; +}; + +struct scarlett2_mixer_data { + struct usb_mixer_interface *mixer; + struct mutex usb_mutex; /* prevent sending concurrent USB requests */ + struct mutex data_mutex; /* lock access to this data */ + struct delayed_work work; + const struct scarlett2_device_info *info; + int num_mux_srcs; + u16 scarlett2_seq; + u8 vol_updated; + u8 master_vol; + u8 vol[SCARLETT2_ANALOGUE_MAX]; + u8 vol_sw_hw_switch[SCARLETT2_ANALOGUE_MAX]; + u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX]; + u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX]; + u8 buttons[SCARLETT2_BUTTON_MAX]; + struct snd_kcontrol *master_vol_ctl; + struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX]; + struct snd_kcontrol *button_ctls[SCARLETT2_BUTTON_MAX]; + u8 mux[SCARLETT2_MUX_MAX]; + u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX]; +}; + +/*** Model-specific data ***/ + +static const struct scarlett2_device_info s6i6_gen2_info = { + /* The first two analogue inputs can be switched between line + * and instrument levels. + */ + .level_input_count = 2, + + /* The first two analogue inputs have an optional pad. */ + .pad_input_count = 2, + + .line_out_descrs = { + "Monitor L", + "Monitor R", + "Headphones L", + "Headphones R", + }, + + .ports = { + { + .id = 0x000, + .num = { 1, 0, 8, 8, 8 }, + .src_descr = "Off", + .src_num_offset = 0, + }, + { + .id = 0x080, + .num = { 4, 4, 4, 4, 4 }, + .src_descr = "Analogue %d", + .src_num_offset = 1, + .dst_descr = "Analogue Output %02d Playback" + }, + { + .id = 0x180, + .num = { 2, 2, 2, 2, 2 }, + .src_descr = "S/PDIF %d", + .src_num_offset = 1, + .dst_descr = "S/PDIF Output %d Playback" + }, + { + .id = 0x300, + .num = { 10, 18, 18, 18, 18 }, + .src_descr = "Mix %c", + .src_num_offset = 65, + .dst_descr = "Mixer Input %02d Capture" + }, + { + .id = 0x600, + .num = { 6, 6, 6, 6, 6 }, + .src_descr = "PCM %d", + .src_num_offset = 1, + .dst_descr = "PCM %02d Capture" + }, + }, +}; + +static const struct scarlett2_device_info s18i8_gen2_info = { + /* The first two analogue inputs can be switched between line + * and instrument levels. + */ + .level_input_count = 2, + + /* The first four analogue inputs have an optional pad. */ + .pad_input_count = 4, + + .line_out_descrs = { + "Monitor L", + "Monitor R", + "Headphones 1 L", + "Headphones 1 R", + "Headphones 2 L", + "Headphones 2 R", + }, + + .ports = { + { + .id = 0x000, + .num = { 1, 0, 8, 8, 4 }, + .src_descr = "Off", + .src_num_offset = 0, + }, + { + .id = 0x080, + .num = { 8, 6, 6, 6, 6 }, + .src_descr = "Analogue %d", + .src_num_offset = 1, + .dst_descr = "Analogue Output %02d Playback" + }, + { + /* S/PDIF outputs aren't available at 192KHz + * but are included in the USB mux I/O + * assignment message anyway + */ + .id = 0x180, + .num = { 2, 2, 2, 2, 2 }, + .src_descr = "S/PDIF %d", + .src_num_offset = 1, + .dst_descr = "S/PDIF Output %d Playback" + }, + { + .id = 0x200, + .num = { 8, 0, 0, 0, 0 }, + .src_descr = "ADAT %d", + .src_num_offset = 1, + }, + { + .id = 0x300, + .num = { 10, 18, 18, 18, 18 }, + .src_descr = "Mix %c", + .src_num_offset = 65, + .dst_descr = "Mixer Input %02d Capture" + }, + { + .id = 0x600, + .num = { 20, 18, 18, 14, 10 }, + .src_descr = "PCM %d", + .src_num_offset = 1, + .dst_descr = "PCM %02d Capture" + }, + }, +}; + +static const struct scarlett2_device_info s18i20_gen2_info = { + /* The analogue line outputs on the 18i20 can be switched + * between software and hardware volume control + */ + .line_out_hw_vol = 1, + + /* Mute and dim buttons */ + .button_count = 2, + + .line_out_descrs = { + "Monitor L", + "Monitor R", + NULL, + NULL, + NULL, + NULL, + "Headphones 1 L", + "Headphones 1 R", + "Headphones 2 L", + "Headphones 2 R", + }, + + .ports = { + { + .id = 0x000, + .num = { 1, 0, 8, 8, 6 }, + .src_descr = "Off", + .src_num_offset = 0, + }, + { + .id = 0x080, + .num = { 8, 10, 10, 10, 10 }, + .src_descr = "Analogue %d", + .src_num_offset = 1, + .dst_descr = "Analogue Output %02d Playback" + }, + { + /* S/PDIF outputs aren't available at 192KHz + * but are included in the USB mux I/O + * assignment message anyway + */ + .id = 0x180, + .num = { 2, 2, 2, 2, 2 }, + .src_descr = "S/PDIF %d", + .src_num_offset = 1, + .dst_descr = "S/PDIF Output %d Playback" + }, + { + .id = 0x200, + .num = { 8, 8, 8, 4, 0 }, + .src_descr = "ADAT %d", + .src_num_offset = 1, + .dst_descr = "ADAT Output %d Playback" + }, + { + .id = 0x300, + .num = { 10, 18, 18, 18, 18 }, + .src_descr = "Mix %c", + .src_num_offset = 65, + .dst_descr = "Mixer Input %02d Capture" + }, + { + .id = 0x600, + .num = { 20, 18, 18, 14, 10 }, + .src_descr = "PCM %d", + .src_num_offset = 1, + .dst_descr = "PCM %02d Capture" + }, + }, +}; + +/* get the starting port index number for a given port type/direction */ +static int scarlett2_get_port_start_num(const struct scarlett2_ports *ports, + int direction, int port_type) +{ + int i, num = 0; + + for (i = 0; i < port_type; i++) + num += ports[i].num[direction]; + + return num; +} + +/*** USB Interactions ***/ + +/* Vendor-Specific Interface, Endpoint, MaxPacketSize, Interval */ +#define SCARLETT2_USB_VENDOR_SPECIFIC_INTERFACE 5 +#define SCARLETT2_USB_INTERRUPT_ENDPOINT 4 +#define SCARLETT2_USB_INTERRUPT_MAX_DATA 64 +#define SCARLETT2_USB_INTERRUPT_INTERVAL 3 + +/* Interrupt flags for volume and mute/dim button changes */ +#define SCARLETT2_USB_INTERRUPT_VOL_CHANGE 0x400000 +#define SCARLETT2_USB_INTERRUPT_BUTTON_CHANGE 0x200000 + +/* Commands for sending/receiving requests/responses */ +#define SCARLETT2_USB_VENDOR_SPECIFIC_CMD_REQ 2 +#define SCARLETT2_USB_VENDOR_SPECIFIC_CMD_RESP 3 + +#define SCARLETT2_USB_INIT_SEQ 0x00000000 +#define SCARLETT2_USB_GET_METER_LEVELS 0x00001001 +#define SCARLETT2_USB_SET_MIX 0x00002002 +#define SCARLETT2_USB_SET_MUX 0x00003002 +#define SCARLETT2_USB_GET_DATA 0x00800000 +#define SCARLETT2_USB_SET_DATA 0x00800001 +#define SCARLETT2_USB_DATA_CMD 0x00800002 +#define SCARLETT2_USB_CONFIG_SAVE 6 + +#define SCARLETT2_USB_VOLUME_STATUS_OFFSET 0x31 +#define SCARLETT2_USB_METER_LEVELS_GET_MAGIC 1 + +/* volume status is read together (matches scarlett2_config_items[]) */ +struct scarlett2_usb_volume_status { + /* mute & dim buttons */ + u8 buttons[SCARLETT2_BUTTON_MAX]; + + u8 pad1; + + /* software volume setting */ + s16 sw_vol[SCARLETT2_ANALOGUE_MAX]; + + /* actual volume of output inc. dim (-18dB) */ + s16 hw_vol[SCARLETT2_ANALOGUE_MAX]; + + u8 pad2[SCARLETT2_ANALOGUE_MAX]; + + /* sw (0) or hw (1) controlled */ + u8 sw_hw_switch[SCARLETT2_ANALOGUE_MAX]; + + u8 pad3[6]; + + /* front panel volume knob */ + s16 master_vol; +} __packed; + +/* Configuration parameters that can be read and written */ +enum { + SCARLETT2_CONFIG_BUTTONS = 0, + SCARLETT2_CONFIG_LINE_OUT_VOLUME = 1, + SCARLETT2_CONFIG_SW_HW_SWITCH = 2, + SCARLETT2_CONFIG_LEVEL_SWITCH = 3, + SCARLETT2_CONFIG_PAD_SWITCH = 4, + SCARLETT2_CONFIG_COUNT = 5 +}; + +/* Location, size, and activation command number for the configuration + * parameters + */ +struct scarlett2_config { + u8 offset; + u8 size; + u8 activate; +}; + +static const struct scarlett2_config + scarlett2_config_items[SCARLETT2_CONFIG_COUNT] = { + /* Mute/Dim Buttons */ + { + .offset = 0x31, + .size = 1, + .activate = 2 + }, + + /* Line Out Volume */ + { + .offset = 0x34, + .size = 2, + .activate = 1 + }, + + /* SW/HW Volume Switch */ + { + .offset = 0x66, + .size = 1, + .activate = 3 + }, + + /* Level Switch */ + { + .offset = 0x7c, + .size = 1, + .activate = 7 + }, + + /* Pad Switch */ + { + .offset = 0x84, + .size = 1, + .activate = 8 + } +}; + +/* proprietary request/response format */ +struct scarlett2_usb_packet { + u32 cmd; + u16 size; + u16 seq; + u32 error; + u32 pad; + u8 data[]; +}; + +#define SCARLETT2_USB_PACKET_LEN (sizeof(struct scarlett2_usb_packet)) + +static void scarlett2_fill_request_header(struct scarlett2_mixer_data *private, + struct scarlett2_usb_packet *req, + u32 cmd, u16 req_size) +{ + /* sequence must go up by 1 for each request */ + u16 seq = private->scarlett2_seq++; + + req->cmd = cpu_to_le32(cmd); + req->size = cpu_to_le16(req_size); + req->seq = cpu_to_le16(seq); + req->error = 0; + req->pad = 0; +} + +/* Send a proprietary format request to the Scarlett interface */ +static int scarlett2_usb( + struct usb_mixer_interface *mixer, u32 cmd, + void *req_data, u16 req_size, void *resp_data, u16 resp_size) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + u16 req_buf_size = sizeof(struct scarlett2_usb_packet) + req_size; + u16 resp_buf_size = sizeof(struct scarlett2_usb_packet) + resp_size; + struct scarlett2_usb_packet *req = NULL, *resp = NULL; + int err = 0; + + req = kmalloc(req_buf_size, GFP_KERNEL); + if (!req) { + err = -ENOMEM; + goto error; + } + + resp = kmalloc(resp_buf_size, GFP_KERNEL); + if (!resp) { + err = -ENOMEM; + goto error; + } + + mutex_lock(&private->usb_mutex); + + /* build request message and send it */ + + scarlett2_fill_request_header(private, req, cmd, req_size); + + if (req_size) + memcpy(req->data, req_data, req_size); + + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), + SCARLETT2_USB_VENDOR_SPECIFIC_CMD_REQ, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + 0, + SCARLETT2_USB_VENDOR_SPECIFIC_INTERFACE, + req, + req_buf_size); + + if (err != req_buf_size) { + usb_audio_err( + mixer->chip, + "Scarlett Gen 2 USB request result cmd %x was %d\n", + cmd, err); + err = -EINVAL; + goto unlock; + } + + /* send a second message to get the response */ + + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), + SCARLETT2_USB_VENDOR_SPECIFIC_CMD_RESP, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + 0, + SCARLETT2_USB_VENDOR_SPECIFIC_INTERFACE, + resp, + resp_buf_size); + + /* validate the response */ + + if (err != resp_buf_size) { + usb_audio_err( + mixer->chip, + "Scarlett Gen 2 USB response result cmd %x was %d\n", + cmd, err); + err = -EINVAL; + goto unlock; + } + + if (resp->cmd != req->cmd || + resp->seq != req->seq || + resp_size != le16_to_cpu(resp->size) || + resp->error || + resp->pad) { + usb_audio_err( + mixer->chip, + "Scarlett Gen 2 USB invalid response; " + "cmd tx/rx %d/%d seq %d/%d size %d/%d " + "error %d pad %d\n", + le16_to_cpu(req->cmd), le16_to_cpu(resp->cmd), + le16_to_cpu(req->seq), le16_to_cpu(resp->seq), + resp_size, le16_to_cpu(resp->size), + le16_to_cpu(resp->error), + le16_to_cpu(resp->pad)); + err = -EINVAL; + goto unlock; + } + + if (resp_size > 0) + memcpy(resp_data, resp->data, resp_size); + +unlock: + mutex_unlock(&private->usb_mutex); +error: + kfree(req); + kfree(resp); + return err; +} + +/* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */ +static void scarlett2_config_save(struct usb_mixer_interface *mixer) +{ + u32 req = cpu_to_le32(SCARLETT2_USB_CONFIG_SAVE); + + scarlett2_usb(mixer, SCARLETT2_USB_DATA_CMD, + &req, sizeof(u32), + NULL, 0); +} + +/* Delayed work to save config */ +static void scarlett2_config_save_work(struct work_struct *work) +{ + struct scarlett2_mixer_data *private = + container_of(work, struct scarlett2_mixer_data, work.work); + + scarlett2_config_save(private->mixer); +} + +/* Send a USB message to set a configuration parameter (volume level, + * sw/hw volume switch, line/inst level switch, or pad switch) + */ +static int scarlett2_usb_set_config( + struct usb_mixer_interface *mixer, + int config_item_num, int index, int value) +{ + const struct scarlett2_config config_item = + scarlett2_config_items[config_item_num]; + struct { + u32 offset; + u32 bytes; + s32 value; + } __packed req; + u32 req2; + int err; + struct scarlett2_mixer_data *private = mixer->private_data; + + /* Cancel any pending NVRAM save */ + cancel_delayed_work_sync(&private->work); + + /* Send the configuration parameter data */ + req.offset = cpu_to_le32(config_item.offset + index * config_item.size); + req.bytes = cpu_to_le32(config_item.size); + req.value = cpu_to_le32(value); + err = scarlett2_usb(mixer, SCARLETT2_USB_SET_DATA, + &req, sizeof(u32) * 2 + config_item.size, + NULL, 0); + if (err < 0) + return err; + + /* Activate the change */ + req2 = cpu_to_le32(config_item.activate); + err = scarlett2_usb(mixer, SCARLETT2_USB_DATA_CMD, + &req2, sizeof(req2), NULL, 0); + if (err < 0) + return err; + + /* Schedule the change to be written to NVRAM */ + schedule_delayed_work(&private->work, msecs_to_jiffies(2000)); + + return 0; +} + +/* Send a USB message to get data; result placed in *buf */ +static int scarlett2_usb_get( + struct usb_mixer_interface *mixer, + int offset, void *buf, int size) +{ + struct { + u32 offset; + u32 size; + } __packed req; + + req.offset = cpu_to_le32(offset); + req.size = cpu_to_le32(size); + return scarlett2_usb(mixer, SCARLETT2_USB_GET_DATA, + &req, sizeof(req), buf, size); +} + +/* Send a USB message to get configuration parameters; result placed in *buf */ +static int scarlett2_usb_get_config( + struct usb_mixer_interface *mixer, + int config_item_num, int count, void *buf) +{ + const struct scarlett2_config config_item = + scarlett2_config_items[config_item_num]; + int size = config_item.size * count; + + return scarlett2_usb_get(mixer, config_item.offset, buf, size); +} + +/* Send a USB message to get volume status; result placed in *buf */ +static int scarlett2_usb_get_volume_status( + struct usb_mixer_interface *mixer, + struct scarlett2_usb_volume_status *buf) +{ + return scarlett2_usb_get(mixer, SCARLETT2_USB_VOLUME_STATUS_OFFSET, + buf, sizeof(*buf)); +} + +/* Send a USB message to set the volumes for all inputs of one mix + * (values obtained from private->mix[]) + */ +static int scarlett2_usb_set_mix(struct usb_mixer_interface *mixer, + int mix_num) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + struct { + u16 mix_num; + u16 data[SCARLETT2_INPUT_MIX_MAX]; + } __packed req; + + int i, j; + int num_mixer_in = + info->ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT]; + + req.mix_num = cpu_to_le16(mix_num); + + for (i = 0, j = mix_num * num_mixer_in; i < num_mixer_in; i++, j++) + req.data[i] = cpu_to_le16( + scarlett2_mixer_values[private->mix[j]] + ); + + return scarlett2_usb(mixer, SCARLETT2_USB_SET_MIX, + &req, (num_mixer_in + 1) * sizeof(u16), + NULL, 0); +} + +/* Convert a port number index (per info->ports) to a hardware ID */ +static u32 scarlett2_mux_src_num_to_id(const struct scarlett2_ports *ports, + int num) +{ + int port_type; + + for (port_type = 0; + port_type < SCARLETT2_PORT_TYPE_COUNT; + port_type++) { + if (num < ports[port_type].num[SCARLETT2_PORT_IN]) + return ports[port_type].id | num; + num -= ports[port_type].num[SCARLETT2_PORT_IN]; + } + + /* Oops */ + return 0; +} + +/* Send USB messages to set mux inputs */ +static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const struct scarlett2_ports *ports = info->ports; + int rate, port_dir_rate; + + static const int assignment_order[SCARLETT2_PORT_TYPE_COUNT] = { + SCARLETT2_PORT_TYPE_PCM, + SCARLETT2_PORT_TYPE_ANALOGUE, + SCARLETT2_PORT_TYPE_SPDIF, + SCARLETT2_PORT_TYPE_ADAT, + SCARLETT2_PORT_TYPE_MIX, + SCARLETT2_PORT_TYPE_NONE, + }; + + struct { + u16 pad; + u16 num; + u32 data[SCARLETT2_MUX_MAX]; + } __packed req; + + req.pad = 0; + + /* mux settings for each rate */ + for (rate = 0, port_dir_rate = SCARLETT2_PORT_OUT_44; + port_dir_rate <= SCARLETT2_PORT_OUT_176; + rate++, port_dir_rate++) { + int order_num, i, err; + + req.num = cpu_to_le16(rate); + + for (order_num = 0, i = 0; + order_num < SCARLETT2_PORT_TYPE_COUNT; + order_num++) { + int port_type = assignment_order[order_num]; + int j = scarlett2_get_port_start_num(ports, + SCARLETT2_PORT_OUT, + port_type); + int port_id = ports[port_type].id; + int channel; + + for (channel = 0; + channel < ports[port_type].num[port_dir_rate]; + channel++, i++, j++) + /* lower 12 bits for the destination and + * next 12 bits for the source + */ + req.data[i] = !port_id + ? 0 + : cpu_to_le32( + port_id | + channel | + scarlett2_mux_src_num_to_id( + ports, private->mux[j] + ) << 12 + ); + + /* skip private->mux[j] entries not output */ + j += ports[port_type].num[SCARLETT2_PORT_OUT] - + ports[port_type].num[port_dir_rate]; + } + + err = scarlett2_usb(mixer, SCARLETT2_USB_SET_MUX, + &req, (i + 1) * sizeof(u32), + NULL, 0); + if (err < 0) + return err; + } + + return 0; +} + +/* Send USB message to get meter levels */ +static int scarlett2_usb_get_meter_levels(struct usb_mixer_interface *mixer, + u16 *levels) +{ + struct { + u16 pad; + u16 num_meters; + u32 magic; + } __packed req; + u32 resp[SCARLETT2_NUM_METERS]; + int i, err; + + req.pad = 0; + req.num_meters = cpu_to_le16(SCARLETT2_NUM_METERS); + req.magic = cpu_to_le32(SCARLETT2_USB_METER_LEVELS_GET_MAGIC); + err = scarlett2_usb(mixer, SCARLETT2_USB_GET_METER_LEVELS, + &req, sizeof(req), resp, sizeof(resp)); + if (err < 0) + return err; + + /* copy, convert to u16 */ + for (i = 0; i < SCARLETT2_NUM_METERS; i++) + levels[i] = resp[i]; + + return 0; +} + +/*** Control Functions ***/ + +/* helper function to create a new control */ +static int scarlett2_add_new_ctl(struct usb_mixer_interface *mixer, + const struct snd_kcontrol_new *ncontrol, + int index, int channels, const char *name, + struct snd_kcontrol **kctl_return) +{ + struct snd_kcontrol *kctl; + struct usb_mixer_elem_info *elem; + int err; + + elem = kzalloc(sizeof(*elem), GFP_KERNEL); + if (!elem) + return -ENOMEM; + + elem->head.mixer = mixer; + elem->control = index; + elem->head.id = index; + elem->channels = channels; + + kctl = snd_ctl_new1(ncontrol, elem); + if (!kctl) { + kfree(elem); + return -ENOMEM; + } + kctl->private_free = snd_usb_mixer_elem_free; + + strlcpy(kctl->id.name, name, sizeof(kctl->id.name)); + + err = snd_usb_mixer_add_control(&elem->head, kctl); + if (err < 0) + return err; + + if (kctl_return) + *kctl_return = kctl; + + return 0; +} + +/*** Analogue Line Out Volume Controls ***/ + +/* Update hardware volume controls after receiving notification that + * they have changed + */ +static int scarlett2_update_volumes(struct usb_mixer_interface *mixer) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + const struct scarlett2_ports *ports = private->info->ports; + struct scarlett2_usb_volume_status volume_status; + int num_line_out = + ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT]; + int err, i; + + private->vol_updated = 0; + + err = scarlett2_usb_get_volume_status(mixer, &volume_status); + if (err < 0) + return err; + + private->master_vol = clamp( + volume_status.master_vol + SCARLETT2_VOLUME_BIAS, + 0, SCARLETT2_VOLUME_BIAS); + + for (i = 0; i < num_line_out; i++) { + if (private->vol_sw_hw_switch[i]) + private->vol[i] = private->master_vol; + } + + for (i = 0; i < private->info->button_count; i++) + private->buttons[i] = !!volume_status.buttons[i]; + + return 0; +} + +static int scarlett2_volume_ctl_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = elem->channels; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = SCARLETT2_VOLUME_BIAS; + uinfo->value.integer.step = 1; + return 0; +} + +static int scarlett2_master_volume_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_mixer_data *private = mixer->private_data; + + if (private->vol_updated) { + mutex_lock(&private->data_mutex); + scarlett2_update_volumes(mixer); + mutex_unlock(&private->data_mutex); + } + + ucontrol->value.integer.value[0] = private->master_vol; + return 0; +} + +static int scarlett2_volume_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_mixer_data *private = mixer->private_data; + int index = elem->control; + + if (private->vol_updated) { + mutex_lock(&private->data_mutex); + scarlett2_update_volumes(mixer); + mutex_unlock(&private->data_mutex); + } + + ucontrol->value.integer.value[0] = private->vol[index]; + return 0; +} + +static int scarlett2_volume_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_mixer_data *private = mixer->private_data; + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->vol[index]; + val = ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->vol[index] = val; + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME, + index, val - SCARLETT2_VOLUME_BIAS); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const DECLARE_TLV_DB_MINMAX( + db_scale_scarlett2_gain, -SCARLETT2_VOLUME_BIAS * 100, 0 +); + +static const struct snd_kcontrol_new scarlett2_master_volume_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "", + .info = scarlett2_volume_ctl_info, + .get = scarlett2_master_volume_ctl_get, + .private_value = 0, /* max value */ + .tlv = { .p = db_scale_scarlett2_gain } +}; + +static const struct snd_kcontrol_new scarlett2_line_out_volume_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "", + .info = scarlett2_volume_ctl_info, + .get = scarlett2_volume_ctl_get, + .put = scarlett2_volume_ctl_put, + .private_value = 0, /* max value */ + .tlv = { .p = db_scale_scarlett2_gain } +}; + +/*** HW/SW Volume Switch Controls ***/ + +static int scarlett2_sw_hw_enum_ctl_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const values[2] = { + "SW", "HW" + }; + + return snd_ctl_enum_info(uinfo, 1, 2, values); +} + +static int scarlett2_sw_hw_enum_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_mixer_data *private = elem->head.mixer->private_data; + + ucontrol->value.enumerated.item[0] = + private->vol_sw_hw_switch[elem->control]; + return 0; +} + +static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_mixer_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->vol_sw_hw_switch[index]; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->vol_sw_hw_switch[index] = val; + + /* Change access mode to RO (hardware controlled volume) + * or RW (software controlled volume) + */ + if (val) + private->vol_ctls[index]->vd[0].access &= + ~SNDRV_CTL_ELEM_ACCESS_WRITE; + else + private->vol_ctls[index]->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_WRITE; + + /* Reset volume to master volume */ + private->vol[index] = private->master_vol; + + /* Set SW volume to current HW volume */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME, + index, private->master_vol - SCARLETT2_VOLUME_BIAS); + if (err < 0) + goto unlock; + + /* Notify of RO/RW change */ + snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_INFO, + &private->vol_ctls[index]->id); + + /* Send SW/HW switch change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SW_HW_SWITCH, + index, val); + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_sw_hw_enum_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_sw_hw_enum_ctl_info, + .get = scarlett2_sw_hw_enum_ctl_get, + .put = scarlett2_sw_hw_enum_ctl_put, +}; + +/*** Line Level/Instrument Level Switch Controls ***/ + +static int scarlett2_level_enum_ctl_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const values[2] = { + "Line", "Inst" + }; + + return snd_ctl_enum_info(uinfo, 1, 2, values); +} + +static int scarlett2_level_enum_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_mixer_data *private = elem->head.mixer->private_data; + + ucontrol->value.enumerated.item[0] = + private->level_switch[elem->control]; + return 0; +} + +static int scarlett2_level_enum_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_mixer_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->level_switch[index]; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->level_switch[index] = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_LEVEL_SWITCH, + index, val); + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_level_enum_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_level_enum_ctl_info, + .get = scarlett2_level_enum_ctl_get, + .put = scarlett2_level_enum_ctl_put, +}; + +/*** Pad Switch Controls ***/ + +static int scarlett2_pad_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_mixer_data *private = elem->head.mixer->private_data; + + ucontrol->value.enumerated.item[0] = + private->pad_switch[elem->control]; + return 0; +} + +static int scarlett2_pad_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_mixer_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->pad_switch[index]; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->pad_switch[index] = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_PAD_SWITCH, + index, val); + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_pad_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_pad_ctl_get, + .put = scarlett2_pad_ctl_put, +}; + +/*** Mute/Dim Controls ***/ + +static int scarlett2_button_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_mixer_data *private = mixer->private_data; + + if (private->vol_updated) { + mutex_lock(&private->data_mutex); + scarlett2_update_volumes(mixer); + mutex_unlock(&private->data_mutex); + } + + ucontrol->value.enumerated.item[0] = private->buttons[elem->control]; + return 0; +} + +static int scarlett2_button_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_mixer_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->buttons[index]; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->buttons[index] = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_BUTTONS, + index, val); + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_button_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_button_ctl_get, + .put = scarlett2_button_ctl_put +}; + +/*** Create the analogue output controls ***/ + +static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const struct scarlett2_ports *ports = info->ports; + int num_line_out = + ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT]; + int err, i; + char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + + /* Add R/O HW volume control */ + if (info->line_out_hw_vol) { + snprintf(s, sizeof(s), "Master HW Playback Volume"); + err = scarlett2_add_new_ctl(mixer, + &scarlett2_master_volume_ctl, + 0, 1, s, &private->master_vol_ctl); + if (err < 0) + return err; + } + + /* Add volume controls */ + for (i = 0; i < num_line_out; i++) { + + /* Fader */ + if (info->line_out_descrs[i]) + snprintf(s, sizeof(s), + "Line %02d (%s) Playback Volume", + i + 1, info->line_out_descrs[i]); + else + snprintf(s, sizeof(s), + "Line %02d Playback Volume", + i + 1); + err = scarlett2_add_new_ctl(mixer, + &scarlett2_line_out_volume_ctl, + i, 1, s, &private->vol_ctls[i]); + if (err < 0) + return err; + + /* Make the fader read-only if the SW/HW switch is set to HW */ + if (private->vol_sw_hw_switch[i]) + private->vol_ctls[i]->vd[0].access &= + ~SNDRV_CTL_ELEM_ACCESS_WRITE; + + /* SW/HW Switch */ + if (info->line_out_hw_vol) { + snprintf(s, sizeof(s), + "Line Out %02d Volume Control Playback Enum", + i + 1); + err = scarlett2_add_new_ctl(mixer, + &scarlett2_sw_hw_enum_ctl, + i, 1, s, NULL); + if (err < 0) + return err; + } + } + + /* Add HW button controls */ + for (i = 0; i < private->info->button_count; i++) { + err = scarlett2_add_new_ctl(mixer, &scarlett2_button_ctl, + i, 1, scarlett2_button_names[i], + &private->button_ctls[i]); + if (err < 0) + return err; + } + + return 0; +} + +/*** Create the analogue input controls ***/ + +static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int err, i; + char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + + /* Add input level (line/inst) controls */ + for (i = 0; i < info->level_input_count; i++) { + snprintf(s, sizeof(s), "Line In %d Level Capture Enum", i + 1); + err = scarlett2_add_new_ctl(mixer, &scarlett2_level_enum_ctl, + i, 1, s, NULL); + if (err < 0) + return err; + } + + /* Add input pad controls */ + for (i = 0; i < info->pad_input_count; i++) { + snprintf(s, sizeof(s), "Line In %d Pad Capture Switch", i + 1); + err = scarlett2_add_new_ctl(mixer, &scarlett2_pad_ctl, + i, 1, s, NULL); + if (err < 0) + return err; + } + + return 0; +} + +/*** Mixer Volume Controls ***/ + +static int scarlett2_mixer_ctl_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = elem->channels; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = SCARLETT2_MIXER_MAX_VALUE; + uinfo->value.integer.step = 1; + return 0; +} + +static int scarlett2_mixer_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_mixer_data *private = elem->head.mixer->private_data; + + ucontrol->value.integer.value[0] = private->mix[elem->control]; + return 0; +} + +static int scarlett2_mixer_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_mixer_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const struct scarlett2_ports *ports = info->ports; + int oval, val, num_mixer_in, mix_num, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->mix[elem->control]; + val = ucontrol->value.integer.value[0]; + num_mixer_in = ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT]; + mix_num = elem->control / num_mixer_in; + + if (oval == val) + goto unlock; + + private->mix[elem->control] = val; + err = scarlett2_usb_set_mix(mixer, mix_num); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const DECLARE_TLV_DB_MINMAX( + db_scale_scarlett2_mixer, + SCARLETT2_MIXER_MIN_DB * 100, + SCARLETT2_MIXER_MAX_DB * 100 +); + +static const struct snd_kcontrol_new scarlett2_mixer_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "", + .info = scarlett2_mixer_ctl_info, + .get = scarlett2_mixer_ctl_get, + .put = scarlett2_mixer_ctl_put, + .private_value = SCARLETT2_MIXER_MAX_DB, /* max value */ + .tlv = { .p = db_scale_scarlett2_mixer } +}; + +static int scarlett2_add_mixer_ctls(struct usb_mixer_interface *mixer) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + const struct scarlett2_ports *ports = private->info->ports; + int err, i, j; + int index; + char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + + int num_inputs = ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT]; + int num_outputs = ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_IN]; + + for (i = 0, index = 0; i < num_outputs; i++) { + for (j = 0; j < num_inputs; j++, index++) { + snprintf(s, sizeof(s), + "Mix %c Input %02d Playback Volume", + 'A' + i, j + 1); + err = scarlett2_add_new_ctl(mixer, &scarlett2_mixer_ctl, + index, 1, s, NULL); + if (err < 0) + return err; + } + } + + return 0; +} + +/*** Mux Source Selection Controls ***/ + +static int scarlett2_mux_src_enum_ctl_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_mixer_data *private = elem->head.mixer->private_data; + const struct scarlett2_ports *ports = private->info->ports; + unsigned int item = uinfo->value.enumerated.item; + int items = private->num_mux_srcs; + int port_type; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = elem->channels; + uinfo->value.enumerated.items = items; + + if (item >= items) + item = uinfo->value.enumerated.item = items - 1; + + for (port_type = 0; + port_type < SCARLETT2_PORT_TYPE_COUNT; + port_type++) { + if (item < ports[port_type].num[SCARLETT2_PORT_IN]) { + sprintf(uinfo->value.enumerated.name, + ports[port_type].src_descr, + item + ports[port_type].src_num_offset); + return 0; + } + item -= ports[port_type].num[SCARLETT2_PORT_IN]; + } + + return -EINVAL; +} + +static int scarlett2_mux_src_enum_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_mixer_data *private = elem->head.mixer->private_data; + + ucontrol->value.enumerated.item[0] = private->mux[elem->control]; + return 0; +} + +static int scarlett2_mux_src_enum_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_mixer_data *private = mixer->private_data; + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->mux[index]; + val = clamp(ucontrol->value.integer.value[0], + 0L, private->num_mux_srcs - 1L); + + if (oval == val) + goto unlock; + + private->mux[index] = val; + err = scarlett2_usb_set_mux(mixer); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_mux_src_enum_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_mux_src_enum_ctl_info, + .get = scarlett2_mux_src_enum_ctl_get, + .put = scarlett2_mux_src_enum_ctl_put, +}; + +static int scarlett2_add_mux_enums(struct usb_mixer_interface *mixer) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + const struct scarlett2_ports *ports = private->info->ports; + int port_type, channel, i; + + for (i = 0, port_type = 0; + port_type < SCARLETT2_PORT_TYPE_COUNT; + port_type++) { + for (channel = 0; + channel < ports[port_type].num[SCARLETT2_PORT_OUT]; + channel++, i++) { + int err; + char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + const char *const descr = ports[port_type].dst_descr; + + snprintf(s, sizeof(s) - 5, descr, channel + 1); + strcat(s, " Enum"); + + err = scarlett2_add_new_ctl(mixer, + &scarlett2_mux_src_enum_ctl, + i, 1, s, NULL); + if (err < 0) + return err; + } + } + + return 0; +} + +/*** Meter Controls ***/ + +static int scarlett2_meter_ctl_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = elem->channels; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 4095; + uinfo->value.integer.step = 1; + return 0; +} + +static int scarlett2_meter_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + u16 meter_levels[SCARLETT2_NUM_METERS]; + int i, err; + + err = scarlett2_usb_get_meter_levels(elem->head.mixer, meter_levels); + if (err < 0) + return err; + + for (i = 0; i < elem->channels; i++) + ucontrol->value.integer.value[i] = meter_levels[i]; + + return 0; +} + +static const struct snd_kcontrol_new scarlett2_meter_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .name = "", + .info = scarlett2_meter_ctl_info, + .get = scarlett2_meter_ctl_get +}; + +static int scarlett2_add_meter_ctl(struct usb_mixer_interface *mixer) +{ + return scarlett2_add_new_ctl(mixer, &scarlett2_meter_ctl, + 0, SCARLETT2_NUM_METERS, + "Level Meter", NULL); +} + +/*** Cleanup/Suspend Callbacks ***/ + +static void scarlett2_private_free(struct usb_mixer_interface *mixer) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + + cancel_delayed_work_sync(&private->work); + kfree(private); + mixer->private_data = NULL; +} + +static void scarlett2_private_suspend(struct usb_mixer_interface *mixer) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + + if (cancel_delayed_work_sync(&private->work)) + scarlett2_config_save(private->mixer); +} + +/*** Initialisation ***/ + +static int scarlett2_count_mux_srcs(const struct scarlett2_ports *ports) +{ + int port_type, count = 0; + + for (port_type = 0; + port_type < SCARLETT2_PORT_TYPE_COUNT; + port_type++) + count += ports[port_type].num[SCARLETT2_PORT_IN]; + + return count; +} + +/* Default routing connects PCM outputs and inputs to Analogue, + * S/PDIF, then ADAT + */ +static void scarlett2_init_routing(u8 *mux, + const struct scarlett2_ports *ports) +{ + int i, input_num, input_count, port_type; + int output_num, output_count, port_type_connect_num; + + static const int connect_order[] = { + SCARLETT2_PORT_TYPE_ANALOGUE, + SCARLETT2_PORT_TYPE_SPDIF, + SCARLETT2_PORT_TYPE_ADAT, + -1 + }; + + /* Assign PCM inputs (routing outputs) */ + output_num = scarlett2_get_port_start_num(ports, + SCARLETT2_PORT_OUT, + SCARLETT2_PORT_TYPE_PCM); + output_count = ports[SCARLETT2_PORT_TYPE_PCM].num[SCARLETT2_PORT_OUT]; + + for (port_type = connect_order[port_type_connect_num = 0]; + port_type >= 0; + port_type = connect_order[++port_type_connect_num]) { + input_num = scarlett2_get_port_start_num( + ports, SCARLETT2_PORT_IN, port_type); + input_count = ports[port_type].num[SCARLETT2_PORT_IN]; + for (i = 0; + i < input_count && output_count; + i++, output_count--) + mux[output_num++] = input_num++; + } + + /* Assign PCM outputs (routing inputs) */ + input_num = scarlett2_get_port_start_num(ports, + SCARLETT2_PORT_IN, + SCARLETT2_PORT_TYPE_PCM); + input_count = ports[SCARLETT2_PORT_TYPE_PCM].num[SCARLETT2_PORT_IN]; + + for (port_type = connect_order[port_type_connect_num = 0]; + port_type >= 0; + port_type = connect_order[++port_type_connect_num]) { + output_num = scarlett2_get_port_start_num( + ports, SCARLETT2_PORT_OUT, port_type); + output_count = ports[port_type].num[SCARLETT2_PORT_OUT]; + for (i = 0; + i < output_count && input_count; + i++, input_count--) + mux[output_num++] = input_num++; + } +} + +/* Initialise private data, routing, sequence number */ +static int scarlett2_init_private(struct usb_mixer_interface *mixer, + const struct scarlett2_device_info *info) +{ + struct scarlett2_mixer_data *private = + kzalloc(sizeof(struct scarlett2_mixer_data), GFP_KERNEL); + + if (!private) + return -ENOMEM; + + mutex_init(&private->usb_mutex); + mutex_init(&private->data_mutex); + INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work); + private->info = info; + private->num_mux_srcs = scarlett2_count_mux_srcs(info->ports); + private->scarlett2_seq = 0; + private->mixer = mixer; + mixer->private_data = private; + mixer->private_free = scarlett2_private_free; + mixer->private_suspend = scarlett2_private_suspend; + + /* Setup default routing */ + scarlett2_init_routing(private->mux, info->ports); + + /* Initialise the sequence number used for the proprietary commands */ + return scarlett2_usb(mixer, SCARLETT2_USB_INIT_SEQ, NULL, 0, NULL, 0); +} + +/* Read line-in config and line-out volume settings on start */ +static int scarlett2_read_configs(struct usb_mixer_interface *mixer) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const struct scarlett2_ports *ports = info->ports; + int num_line_out = + ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT]; + u8 level_switches[SCARLETT2_LEVEL_SWITCH_MAX]; + u8 pad_switches[SCARLETT2_PAD_SWITCH_MAX]; + struct scarlett2_usb_volume_status volume_status; + int err, i; + + if (info->level_input_count) { + err = scarlett2_usb_get_config( + mixer, + SCARLETT2_CONFIG_LEVEL_SWITCH, + info->level_input_count, + level_switches); + if (err < 0) + return err; + for (i = 0; i < info->level_input_count; i++) + private->level_switch[i] = level_switches[i]; + } + + if (info->pad_input_count) { + err = scarlett2_usb_get_config( + mixer, + SCARLETT2_CONFIG_PAD_SWITCH, + info->pad_input_count, + pad_switches); + if (err < 0) + return err; + for (i = 0; i < info->pad_input_count; i++) + private->pad_switch[i] = pad_switches[i]; + } + + err = scarlett2_usb_get_volume_status(mixer, &volume_status); + if (err < 0) + return err; + + private->master_vol = clamp( + volume_status.master_vol + SCARLETT2_VOLUME_BIAS, + 0, SCARLETT2_VOLUME_BIAS); + + for (i = 0; i < num_line_out; i++) { + int volume; + + private->vol_sw_hw_switch[i] = + info->line_out_hw_vol + && volume_status.sw_hw_switch[i]; + + volume = private->vol_sw_hw_switch[i] + ? volume_status.master_vol + : volume_status.sw_vol[i]; + volume = clamp(volume + SCARLETT2_VOLUME_BIAS, + 0, SCARLETT2_VOLUME_BIAS); + private->vol[i] = volume; + } + + for (i = 0; i < info->button_count; i++) + private->buttons[i] = !!volume_status.buttons[i]; + + return 0; +} + +/* Notify on volume change */ +static void scarlett2_mixer_interrupt_vol_change( + struct usb_mixer_interface *mixer) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + const struct scarlett2_ports *ports = private->info->ports; + int num_line_out = + ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT]; + int i; + + private->vol_updated = 1; + + snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->master_vol_ctl->id); + + for (i = 0; i < num_line_out; i++) { + if (!private->vol_sw_hw_switch[i]) + continue; + snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->vol_ctls[i]->id); + } +} + +/* Notify on button change */ +static void scarlett2_mixer_interrupt_button_change( + struct usb_mixer_interface *mixer) +{ + struct scarlett2_mixer_data *private = mixer->private_data; + int i; + + private->vol_updated = 1; + + for (i = 0; i < private->info->button_count; i++) + snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->button_ctls[i]->id); +} + +/* Interrupt callback */ +static void scarlett2_mixer_interrupt(struct urb *urb) +{ + struct usb_mixer_interface *mixer = urb->context; + int len = urb->actual_length; + int ustatus = urb->status; + u32 data; + + if (ustatus != 0) + goto requeue; + + if (len == 8) { + data = le32_to_cpu(*(u32 *)urb->transfer_buffer); + if (data & SCARLETT2_USB_INTERRUPT_VOL_CHANGE) + scarlett2_mixer_interrupt_vol_change(mixer); + if (data & SCARLETT2_USB_INTERRUPT_BUTTON_CHANGE) + scarlett2_mixer_interrupt_button_change(mixer); + } else { + usb_audio_err(mixer->chip, + "scarlett mixer interrupt length %d\n", len); + } + +requeue: + if (ustatus != -ENOENT && + ustatus != -ECONNRESET && + ustatus != -ESHUTDOWN) { + urb->dev = mixer->chip->dev; + usb_submit_urb(urb, GFP_ATOMIC); + } +} + +static int scarlett2_mixer_status_create(struct usb_mixer_interface *mixer) +{ + struct usb_device *dev = mixer->chip->dev; + unsigned int pipe = usb_rcvintpipe(dev, + SCARLETT2_USB_INTERRUPT_ENDPOINT); + void *transfer_buffer; + + if (mixer->urb) { + usb_audio_err(mixer->chip, + "%s: mixer urb already in use!\n", __func__); + return 0; + } + + if (snd_usb_pipe_sanity_check(dev, pipe)) + return -EINVAL; + + mixer->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!mixer->urb) + return -ENOMEM; + + transfer_buffer = kmalloc(SCARLETT2_USB_INTERRUPT_MAX_DATA, GFP_KERNEL); + if (!transfer_buffer) + return -ENOMEM; + + usb_fill_int_urb(mixer->urb, dev, pipe, + transfer_buffer, SCARLETT2_USB_INTERRUPT_MAX_DATA, + scarlett2_mixer_interrupt, mixer, + SCARLETT2_USB_INTERRUPT_INTERVAL); + + return usb_submit_urb(mixer->urb, GFP_KERNEL); +} + +/* Entry point */ +int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer) +{ + const struct scarlett2_device_info *info; + int err; + + /* only use UAC_VERSION_2 */ + if (!mixer->protocol) + return 0; + + switch (mixer->chip->usb_id) { + case USB_ID(0x1235, 0x8203): + info = &s6i6_gen2_info; + break; + case USB_ID(0x1235, 0x8204): + info = &s18i8_gen2_info; + break; + case USB_ID(0x1235, 0x8201): + info = &s18i20_gen2_info; + break; + default: /* device not (yet) supported */ + return -EINVAL; + } + + if (!(mixer->chip->setup & SCARLETT2_ENABLE)) { + usb_audio_err(mixer->chip, + "Focusrite Scarlett Gen 2 Mixer Driver disabled; " + "use options snd_usb_audio device_setup=1 " + "to enable and report any issues to g@b4.vu"); + return 0; + } + + /* Initialise private data, routing, sequence number */ + err = scarlett2_init_private(mixer, info); + if (err < 0) + return err; + + /* Read volume levels and controls from the interface */ + err = scarlett2_read_configs(mixer); + if (err < 0) + return err; + + /* Create the analogue output controls */ + err = scarlett2_add_line_out_ctls(mixer); + if (err < 0) + return err; + + /* Create the analogue input controls */ + err = scarlett2_add_line_in_ctls(mixer); + if (err < 0) + return err; + + /* Create the input, output, and mixer mux input selections */ + err = scarlett2_add_mux_enums(mixer); + if (err < 0) + return err; + + /* Create the matrix mixer controls */ + err = scarlett2_add_mixer_ctls(mixer); + if (err < 0) + return err; + + /* Create the level meter controls */ + err = scarlett2_add_meter_ctl(mixer); + if (err < 0) + return err; + + /* Set up the interrupt polling if there are hardware buttons */ + if (info->button_count) { + err = scarlett2_mixer_status_create(mixer); + if (err < 0) + return err; + } + + return 0; +} diff --git a/sound/usb/mixer_scarlett_gen2.h b/sound/usb/mixer_scarlett_gen2.h new file mode 100644 index 000000000000..52e1dad77afd --- /dev/null +++ b/sound/usb/mixer_scarlett_gen2.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __USB_MIXER_SCARLETT_GEN2_H +#define __USB_MIXER_SCARLETT_GEN2_H + +int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer); + +#endif /* __USB_MIXER_SCARLETT_GEN2_H */ -- cgit v1.2.3 From f474808acb3c4b30552d9c59b181244e0300d218 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jul 2019 09:14:22 +0200 Subject: ALSA: aoa: onyx: always initialize register read value A lot of places in the driver use onyx_read_register() without checking the return value, and it's been working OK for ~10 years or so, so probably never fails ... Rather than trying to check the return value everywhere, which would be relatively intrusive, at least make sure we don't use an uninitialized value. Fixes: f3d9478b2ce4 ("[ALSA] snd-aoa: add snd-aoa") Reported-by: Stephen Rothwell Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai --- sound/aoa/codecs/onyx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index db917546965d..9827bee109c1 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c @@ -71,8 +71,10 @@ static int onyx_read_register(struct onyx *onyx, u8 reg, u8 *value) return 0; } v = i2c_smbus_read_byte_data(onyx->i2c, reg); - if (v < 0) + if (v < 0) { + *value = 0; return -1; + } *value = (u8)v; onyx->cache[ONYX_REG_CONTROL-FIRSTREGISTER] = *value; return 0; -- cgit v1.2.3 From 8e774e023565c682c67617da5141c7395c8a5fac Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jul 2019 15:54:54 -0500 Subject: sound: dmasound_atari: Mark expected switch fall-through Mark switch cases where we are expecting to fall through. This patch fixes the following warning (Building: m68k): sound/oss/dmasound/dmasound_atari.c: warning: this statement may fall through [-Wimplicit-fallthrough=]: => 1449:24 Notice that, in this particular case, the code comment is modified in accordance with what GCC is expecting to find. Reported-by: Geert Uytterhoeven Tested-by: Geert Uytterhoeven Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: Takashi Iwai --- sound/oss/dmasound/dmasound_atari.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c index 83653683fd68..823ccfa089b2 100644 --- a/sound/oss/dmasound/dmasound_atari.c +++ b/sound/oss/dmasound/dmasound_atari.c @@ -1432,25 +1432,25 @@ static int FalconMixerIoctl(u_int cmd, u_long arg) { int data; switch (cmd) { - case SOUND_MIXER_READ_RECMASK: + case SOUND_MIXER_READ_RECMASK: return IOCTL_OUT(arg, SOUND_MASK_MIC); - case SOUND_MIXER_READ_DEVMASK: + case SOUND_MIXER_READ_DEVMASK: return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER); - case SOUND_MIXER_READ_STEREODEVS: + case SOUND_MIXER_READ_STEREODEVS: return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC); - case SOUND_MIXER_READ_VOLUME: + case SOUND_MIXER_READ_VOLUME: return IOCTL_OUT(arg, VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) | VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8); - case SOUND_MIXER_READ_CAPS: + case SOUND_MIXER_READ_CAPS: return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT); - case SOUND_MIXER_WRITE_MIC: + case SOUND_MIXER_WRITE_MIC: IOCTL_IN(arg, data); tt_dmasnd.input_gain = RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 | RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff); - /* fall thru, return set value */ - case SOUND_MIXER_READ_MIC: + /* fall through - return set value */ + case SOUND_MIXER_READ_MIC: return IOCTL_OUT(arg, RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) | RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8); -- cgit v1.2.3 From 83554cb94515467cfff10f70ec858d60bbbab8ca Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jul 2019 20:49:44 -0500 Subject: ALSA: sparc: Mark expected switch fall-throughs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark switch cases where we are expecting to fall through. This patch fixes the following warnings (Building: sparc64): sound/sparc/dbri.c: In function ‘reverse_bytes’: sound/sparc/dbri.c:582:5: warning: this statement may fall through [-Wimplicit-fallthrough=] b = ((b & 0xffff0000) >> 16) | ((b & 0x0000ffff) << 16); ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sound/sparc/dbri.c:583:2: note: here case 16: ^~~~ sound/sparc/dbri.c:584:5: warning: this statement may fall through [-Wimplicit-fallthrough=] b = ((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8); ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sound/sparc/dbri.c:585:2: note: here case 8: ^~~~ sound/sparc/dbri.c:586:5: warning: this statement may fall through [-Wimplicit-fallthrough=] b = ((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4); ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sound/sparc/dbri.c:587:2: note: here case 4: ^~~~ sound/sparc/dbri.c:588:5: warning: this statement may fall through [-Wimplicit-fallthrough=] b = ((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2); ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sound/sparc/dbri.c:589:2: note: here case 2: ^~~~ Signed-off-by: Gustavo A. R. Silva Signed-off-by: Takashi Iwai --- sound/sparc/dbri.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 010113156239..6e065d44060e 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -580,12 +580,16 @@ static __u32 reverse_bytes(__u32 b, int len) switch (len) { case 32: b = ((b & 0xffff0000) >> 16) | ((b & 0x0000ffff) << 16); + /* fall through */ case 16: b = ((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8); + /* fall through */ case 8: b = ((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4); + /* fall through */ case 4: b = ((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2); + /* fall through */ case 2: b = ((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1); case 1: -- cgit v1.2.3 From 2c4956bc1e9062e5e3c5ea7612294f24e6d4fbdd Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 29 Jul 2019 10:01:39 +0200 Subject: ASoC: meson: g12a-tohdmitx: override codec2codec params So far, forwarding the hw_params of the input to output relied on the .hw_params() callback of the cpu side of the codec2codec link to be called first. This is a bit weak. Instead, override the stream params of the codec2codec to link to set it up correctly. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190729080139.32068-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/g12a-tohdmitx.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c index 707ccb192e4c..9943c807ec5d 100644 --- a/sound/soc/meson/g12a-tohdmitx.c +++ b/sound/soc/meson/g12a-tohdmitx.c @@ -28,7 +28,7 @@ #define CTRL0_SPDIF_CLK_SEL BIT(0) struct g12a_tohdmitx_input { - struct snd_pcm_hw_params params; + struct snd_soc_pcm_stream params; unsigned int fmt; }; @@ -225,26 +225,17 @@ static int g12a_tohdmitx_input_hw_params(struct snd_pcm_substream *substream, { struct g12a_tohdmitx_input *data = dai->playback_dma_data; - /* Save the stream params for the downstream link */ - memcpy(&data->params, params, sizeof(*params)); + data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params)); + data->params.rate_min = params_rate(params); + data->params.rate_max = params_rate(params); + data->params.formats = 1 << params_format(params); + data->params.channels_min = params_channels(params); + data->params.channels_max = params_channels(params); + data->params.sig_bits = dai->driver->playback.sig_bits; return 0; } -static int g12a_tohdmitx_output_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct g12a_tohdmitx_input *in_data = - g12a_tohdmitx_get_input_data(dai->capture_widget); - - if (!in_data) - return -ENODEV; - - memcpy(params, &in_data->params, sizeof(*params)); - - return 0; -} static int g12a_tohdmitx_input_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) @@ -266,6 +257,14 @@ static int g12a_tohdmitx_output_startup(struct snd_pcm_substream *substream, if (!in_data) return -ENODEV; + if (WARN_ON(!rtd->dai_link->params)) { + dev_warn(dai->dev, "codec2codec link expected\n"); + return -EINVAL; + } + + /* Replace link params with the input params */ + rtd->dai_link->params = &in_data->params; + if (!in_data->fmt) return 0; @@ -278,7 +277,6 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = { }; static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { - .hw_params = g12a_tohdmitx_output_hw_params, .startup = g12a_tohdmitx_output_startup, }; -- cgit v1.2.3 From 21cc4ea85879c1b424fb01caa6e481c14286f7f0 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:05 +0800 Subject: ASoC: tegra20_das: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-2-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_das.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c index 10f9c3b19c88..1070b2710d5e 100644 --- a/sound/soc/tegra/tegra20_das.c +++ b/sound/soc/tegra/tegra20_das.c @@ -120,7 +120,6 @@ static const struct regmap_config tegra20_das_regmap_config = { static int tegra20_das_probe(struct platform_device *pdev) { - struct resource *res; void __iomem *regs; int ret = 0; @@ -134,8 +133,7 @@ static int tegra20_das_probe(struct platform_device *pdev) } das->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) { ret = PTR_ERR(regs); goto err; -- cgit v1.2.3 From 7d22808641cdea50baeae636acf5d592a7aa1239 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:06 +0800 Subject: ASoC: tegra: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-3-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_i2s.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index ac6983c6bd72..e6d548fa980b 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -368,7 +368,6 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) struct tegra30_i2s *i2s; const struct of_device_id *match; u32 cif_ids[2]; - struct resource *mem; void __iomem *regs; int ret; @@ -406,8 +405,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) goto err; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, mem); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) { ret = PTR_ERR(regs); goto err_clk_put; -- cgit v1.2.3 From f052172a5bb474fef2d0c3911655c9e107a3c024 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:07 +0800 Subject: ASoC: rockchip: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-4-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/rk3328_codec.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index 24f8f86d58e9..287c962ba00d 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -432,7 +432,6 @@ static int rk3328_platform_probe(struct platform_device *pdev) { struct device_node *rk3328_np = pdev->dev.of_node; struct rk3328_codec_priv *rk3328; - struct resource *res; struct regmap *grf; void __iomem *base; int ret = 0; @@ -482,8 +481,7 @@ static int rk3328_platform_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); -- cgit v1.2.3 From 4b3540074361fc7b97f2da54365c55ceca6333d2 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:08 +0800 Subject: ASoC: ep93xx-i2s: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-5-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/cirrus/ep93xx-i2s.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 0b4355e95f84..7d9cf67129d4 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -430,15 +430,13 @@ static const struct snd_soc_component_driver ep93xx_i2s_component = { static int ep93xx_i2s_probe(struct platform_device *pdev) { struct ep93xx_i2s_info *info; - struct resource *res; int err; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->regs = devm_ioremap_resource(&pdev->dev, res); + info->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(info->regs)) return PTR_ERR(info->regs); -- cgit v1.2.3 From fceef72b68d63593d8543a8d608ccc8427e13d56 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:09 +0800 Subject: ASoC: mt8173: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-6-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-afe-pcm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index 0382896c162e..90bd2c92cae7 100644 --- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c @@ -1056,7 +1056,6 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) int irq_id; struct mtk_base_afe *afe; struct mt8173_afe_private *afe_priv; - struct resource *res; ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33)); if (ret) @@ -1086,8 +1085,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - afe->base_addr = devm_ioremap_resource(&pdev->dev, res); + afe->base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(afe->base_addr)) return PTR_ERR(afe->base_addr); -- cgit v1.2.3 From 61e799e3658952397da80f6c2e3581e7b65209a8 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:10 +0800 Subject: ASoC: mt6797: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-7-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt6797/mt6797-afe-pcm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c index 08a6532da322..e52c032d53aa 100644 --- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c +++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c @@ -749,7 +749,6 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev) { struct mtk_base_afe *afe; struct mt6797_afe_private *afe_priv; - struct resource *res; struct device *dev; int i, irq_id, ret; @@ -774,9 +773,7 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev) } /* regmap init */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - afe->base_addr = devm_ioremap_resource(&pdev->dev, res); + afe->base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(afe->base_addr)) return PTR_ERR(afe->base_addr); -- cgit v1.2.3 From d003e3081c1d069b94d1b5f4c3bc8234d4603282 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:11 +0800 Subject: ASoC: imx-audmux: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-8-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-audmux.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index b2351cd33b0f..7595f24a006e 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -298,12 +298,10 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev, static int imx_audmux_probe(struct platform_device *pdev) { - struct resource *res; const struct of_device_id *of_id = of_match_device(imx_audmux_dt_ids, &pdev->dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - audmux_base = devm_ioremap_resource(&pdev->dev, res); + audmux_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(audmux_base)) return PTR_ERR(audmux_base); -- cgit v1.2.3 From 959bb6b54d708652fe06097feecc3acd4d6b8c89 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:12 +0800 Subject: ASoC: fsl_audmix: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-9-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_audmix.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index 3897a54a11fe..c7e4e9757dce 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -458,7 +458,6 @@ static int fsl_audmix_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct fsl_audmix *priv; - struct resource *res; const char *mdrv; const struct of_device_id *of_id; void __iomem *regs; @@ -475,8 +474,7 @@ static int fsl_audmix_probe(struct platform_device *pdev) return -ENOMEM; /* Get the addresses */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); -- cgit v1.2.3 From d400b1b30cbff1c0962bbb3f895e839ccd120cb7 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:13 +0800 Subject: ASoC: bcm2835-i2s: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-10-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/bcm/bcm2835-i2s.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 5ef80f3d446a..e6a12e271b07 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -828,7 +828,6 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) { struct bcm2835_i2s_dev *dev; int ret; - struct resource *mem; void __iomem *base; const __be32 *addr; dma_addr_t dma_base; @@ -848,8 +847,7 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) } /* Request ioarea */ - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); -- cgit v1.2.3 From c9dbe688983b1d77a9a46cf6b7ac88348a1ca395 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:14 +0800 Subject: ASoC: sirf: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-11-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/sirf/sirf-usp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c index 8bab119c753a..2af0c6f14ee6 100644 --- a/sound/soc/sirf/sirf-usp.c +++ b/sound/soc/sirf/sirf-usp.c @@ -359,7 +359,6 @@ static int sirf_usp_pcm_probe(struct platform_device *pdev) int ret; struct sirf_usp *usp; void __iomem *base; - struct resource *mem_res; usp = devm_kzalloc(&pdev->dev, sizeof(struct sirf_usp), GFP_KERNEL); @@ -368,8 +367,7 @@ static int sirf_usp_pcm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, usp); - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem_res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); usp->regmap = devm_regmap_init_mmio(&pdev->dev, base, -- cgit v1.2.3 From 1327bfe2887c0e29bcdc0c5c3e445da107ccb4e2 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:15 +0800 Subject: ASoC: mxs-saif: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-12-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/mxs/mxs-saif.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 269b6d6df250..a2c79426513b 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -732,7 +732,6 @@ static int mxs_saif_mclk_init(struct platform_device *pdev) static int mxs_saif_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct resource *iores; struct mxs_saif *saif; int irq, ret = 0; struct device_node *master; @@ -786,9 +785,7 @@ static int mxs_saif_probe(struct platform_device *pdev) return ret; } - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - saif->base = devm_ioremap_resource(&pdev->dev, iores); + saif->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(saif->base)) return PTR_ERR(saif->base); -- cgit v1.2.3 From 0fb46f541bb3e6e5bbb155c08b9e75f92c21acb9 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:16 +0800 Subject: ASoC: spear: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-13-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/spear/spdif_in.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c index 78a6a360b4a6..4b68d6ee75da 100644 --- a/sound/soc/spear/spdif_in.c +++ b/sound/soc/spear/spdif_in.c @@ -202,12 +202,11 @@ static int spdif_in_probe(struct platform_device *pdev) { struct spdif_in_dev *host; struct spear_spdif_platform_data *pdata; - struct resource *res, *res_fifo; + struct resource *res_fifo; void __iomem *io_base; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - io_base = devm_ioremap_resource(&pdev->dev, res); + io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(io_base)) return PTR_ERR(io_base); -- cgit v1.2.3 From 89dd38bf130e661d92c6ab7e3b003907f1d3f367 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:17 +0800 Subject: ASoC: kirkwood-i2s: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-14-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/kirkwood/kirkwood-i2s.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 3446a113f482..5076ec4cc7a6 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -523,7 +523,6 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data; struct snd_soc_dai_driver *soc_dai = kirkwood_i2s_dai; struct kirkwood_dma_data *priv; - struct resource *mem; struct device_node *np = pdev->dev.of_node; int err; @@ -533,8 +532,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, priv); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->io = devm_ioremap_resource(&pdev->dev, mem); + priv->io = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->io)) return PTR_ERR(priv->io); -- cgit v1.2.3 From ebdd7be5415c7795c77609ad908222038e441835 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:18 +0800 Subject: ASoC: xtfpga-i2s: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-15-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/xtensa/xtfpga-i2s.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index 9ce2c75186b9..9da395d14a8d 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -531,7 +531,6 @@ static int xtfpga_i2s_runtime_resume(struct device *dev) static int xtfpga_i2s_probe(struct platform_device *pdev) { struct xtfpga_i2s *i2s; - struct resource *mem; int err, irq; i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); @@ -543,8 +542,7 @@ static int xtfpga_i2s_probe(struct platform_device *pdev) i2s->dev = &pdev->dev; dev_dbg(&pdev->dev, "dev: %p, i2s: %p\n", &pdev->dev, i2s); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2s->regs = devm_ioremap_resource(&pdev->dev, mem); + i2s->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2s->regs)) { err = PTR_ERR(i2s->regs); goto err; -- cgit v1.2.3 From 22581e7c51f50fbbadba70499bb5e2d09f830cbb Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jul 2019 17:15:34 -0500 Subject: ASoC: ti: Mark expected switch fall-throughs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark switch cases where we are expecting to fall through. This patch fixes the following warning (Building: arm): sound/soc/ti/n810.c: In function ‘n810_ext_control’: sound/soc/ti/n810.c:48:10: warning: this statement may fall through [-Wimplicit-fallthrough=] line1l = 1; ~~~~~~~^~~ sound/soc/ti/n810.c:49:2: note: here case N810_JACK_HP: ^~~~ sound/soc/ti/rx51.c: In function ‘rx51_ext_control’: sound/soc/ti/rx51.c:57:6: warning: this statement may fall through [-Wimplicit-fallthrough=] hs = 1; ~~~^~~ sound/soc/ti/rx51.c:58:2: note: here case RX51_JACK_HP: ^~~~ Signed-off-by: Gustavo A. R. Silva Acked-by: Jarkko Nikula Link: https://lore.kernel.org/r/20190729221534.GA18696@embeddedor Signed-off-by: Mark Brown --- sound/soc/ti/n810.c | 1 + sound/soc/ti/rx51.c | 1 + 2 files changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/ti/n810.c b/sound/soc/ti/n810.c index 2c3f2a4c1700..3ad2b6daf31e 100644 --- a/sound/soc/ti/n810.c +++ b/sound/soc/ti/n810.c @@ -46,6 +46,7 @@ static void n810_ext_control(struct snd_soc_dapm_context *dapm) switch (n810_jack_func) { case N810_JACK_HS: line1l = 1; + /* fall through */ case N810_JACK_HP: hp = 1; break; diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c index bc6046534fa5..ccd0e8a07dd1 100644 --- a/sound/soc/ti/rx51.c +++ b/sound/soc/ti/rx51.c @@ -55,6 +55,7 @@ static void rx51_ext_control(struct snd_soc_dapm_context *dapm) break; case RX51_JACK_HS: hs = 1; + /* fall through */ case RX51_JACK_HP: hp = 1; break; -- cgit v1.2.3 From 0c03e37af47efcb8600f95f399783c082fcf2f93 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 24 Jul 2019 08:00:23 +0200 Subject: ASoC: cs4271: Fix a typo in the CS4171_NR_RATIOS This should be CS4271_NR_RATIOS. Fix it and use it. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/20190724060023.31302-1-christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/codecs/cs4271.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 1d03a1348162..04b86a51e055 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -334,7 +334,7 @@ static struct cs4271_clk_cfg cs4271_clk_tab[] = { {0, CS4271_MODE1_MODE_4X, 256, CS4271_MODE1_DIV_2}, }; -#define CS4171_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab) +#define CS4271_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab) static int cs4271_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, @@ -383,13 +383,13 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream, val = CS4271_MODE1_MODE_4X; ratio = cs4271->mclk / cs4271->rate; - for (i = 0; i < CS4171_NR_RATIOS; i++) + for (i = 0; i < CS4271_NR_RATIOS; i++) if ((cs4271_clk_tab[i].master == cs4271->master) && (cs4271_clk_tab[i].speed_mode == val) && (cs4271_clk_tab[i].ratio == ratio)) break; - if (i == CS4171_NR_RATIOS) { + if (i == CS4271_NR_RATIOS) { dev_err(component->dev, "Invalid sample rate\n"); return -EINVAL; } -- cgit v1.2.3 From 2e73d98f2ecf61008926bb8a425c3281a89959c0 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:31 +0800 Subject: ASoC: meson: axg-pdm: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-28-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-pdm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c index 9d5684493ffc..bfd37d49a73e 100644 --- a/sound/soc/meson/axg-pdm.c +++ b/sound/soc/meson/axg-pdm.c @@ -585,7 +585,6 @@ static int axg_pdm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct axg_pdm *priv; - struct resource *res; void __iomem *regs; int ret; @@ -600,8 +599,7 @@ static int axg_pdm_probe(struct platform_device *pdev) return -ENODEV; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); -- cgit v1.2.3 From d61feec0f60c250c786a9e0069ce909979491c7b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:32 +0800 Subject: ASoC: meson: axg-spdifin: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-29-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-spdifin.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c index 01b2035fa841..d0d09f945b48 100644 --- a/sound/soc/meson/axg-spdifin.c +++ b/sound/soc/meson/axg-spdifin.c @@ -453,7 +453,6 @@ static int axg_spdifin_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct axg_spdifin *priv; struct snd_soc_dai_driver *dai_drv; - struct resource *res; void __iomem *regs; int ret; @@ -468,8 +467,7 @@ static int axg_spdifin_probe(struct platform_device *pdev) return -ENODEV; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); -- cgit v1.2.3 From c43fd289dd58951f3cfddb3bb66a6ed7747c5986 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:33 +0800 Subject: ASoC: meson: axg-spdifout: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-30-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-spdifout.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-spdifout.c b/sound/soc/meson/axg-spdifout.c index 9dea528053ad..7ce6aa97ddf7 100644 --- a/sound/soc/meson/axg-spdifout.c +++ b/sound/soc/meson/axg-spdifout.c @@ -401,7 +401,6 @@ static int axg_spdifout_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct axg_spdifout *priv; - struct resource *res; void __iomem *regs; int ret; @@ -410,8 +409,7 @@ static int axg_spdifout_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, priv); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); -- cgit v1.2.3 From 9b2089313156ad16bd257217cc67e10597a82923 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:34 +0800 Subject: ASoC: meson: axg-fifo: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-31-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-fifo.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index 01c1c7db2510..80a3dde35b5c 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -314,7 +314,6 @@ int axg_fifo_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; const struct axg_fifo_match_data *data; struct axg_fifo *fifo; - struct resource *res; void __iomem *regs; data = of_device_get_match_data(dev); @@ -328,8 +327,7 @@ int axg_fifo_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, fifo); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); -- cgit v1.2.3 From cf80aa2c1359f5d014981e251049bcc21a2217bc Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:35 +0800 Subject: ASoC: xlnx: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-32-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_i2s.c | 4 +--- sound/soc/xilinx/xlnx_spdif.c | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c index 8b353166ad44..cc641e582c82 100644 --- a/sound/soc/xilinx/xlnx_i2s.c +++ b/sound/soc/xilinx/xlnx_i2s.c @@ -95,7 +95,6 @@ MODULE_DEVICE_TABLE(of, xlnx_i2s_of_match); static int xlnx_i2s_probe(struct platform_device *pdev) { - struct resource *res; void __iomem *base; struct snd_soc_dai_driver *dai_drv; int ret; @@ -107,8 +106,7 @@ static int xlnx_i2s_probe(struct platform_device *pdev) if (!dai_drv) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/xilinx/xlnx_spdif.c b/sound/soc/xilinx/xlnx_spdif.c index 3b9000fd8c49..e2ca087adee6 100644 --- a/sound/soc/xilinx/xlnx_spdif.c +++ b/sound/soc/xilinx/xlnx_spdif.c @@ -260,8 +260,7 @@ static int xlnx_spdif_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ctx->base = devm_ioremap_resource(dev, res); + ctx->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ctx->base)) { ret = PTR_ERR(ctx->base); goto clk_err; -- cgit v1.2.3 From e12fd61fd7c1bbbb758ede9fdf58ac2bd5de6b33 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:36 +0800 Subject: ASoC: sun8i-codec-analog: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-33-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec-analog.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index e92aeedd6feb..be872eefa61e 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -819,12 +819,10 @@ MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match); static int sun8i_codec_analog_probe(struct platform_device *pdev) { - struct resource *res; struct regmap *regmap; void __iomem *base; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) { dev_err(&pdev->dev, "Failed to map the registers\n"); return PTR_ERR(base); -- cgit v1.2.3 From 54dd39e4aca8edb231e13349ac3a3a44ef28d3d4 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:37 +0800 Subject: ASoC: sunxi: sun50i-codec-analog: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-34-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun50i-codec-analog.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c index 6d1de565350e..f5b7069bcca2 100644 --- a/sound/soc/sunxi/sun50i-codec-analog.c +++ b/sound/soc/sunxi/sun50i-codec-analog.c @@ -459,12 +459,10 @@ MODULE_DEVICE_TABLE(of, sun50i_codec_analog_of_match); static int sun50i_codec_analog_probe(struct platform_device *pdev) { - struct resource *res; struct regmap *regmap; void __iomem *base; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) { dev_err(&pdev->dev, "Failed to map the registers\n"); return PTR_ERR(base); -- cgit v1.2.3 From 790b36578e23264ff05be2ba8466ebcf7d3db38a Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:38 +0800 Subject: ASoC: sun8i-codec: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-35-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 0e0e8ebaa571..55798bc8eae2 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -533,7 +533,6 @@ static const struct regmap_config sun8i_codec_regmap_config = { static int sun8i_codec_probe(struct platform_device *pdev) { - struct resource *res_base; struct sun8i_codec *scodec; void __iomem *base; int ret; @@ -556,8 +555,7 @@ static int sun8i_codec_probe(struct platform_device *pdev) return PTR_ERR(scodec->clk_bus); } - res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res_base); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) { dev_err(&pdev->dev, "Failed to map the registers\n"); return PTR_ERR(base); -- cgit v1.2.3 From 1c63223cda84fb10643938e4e4eb02110f8ae9a2 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:19 +0800 Subject: ASoC: stm32: sai: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-16-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 63f68e663676..1ac5103cea78 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -152,7 +152,6 @@ static int stm32_sai_probe(struct platform_device *pdev) { struct stm32_sai_data *sai; struct reset_control *rst; - struct resource *res; const struct of_device_id *of_id; u32 val; int ret; @@ -161,8 +160,7 @@ static int stm32_sai_probe(struct platform_device *pdev) if (!sai) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - sai->base = devm_ioremap_resource(&pdev->dev, res); + sai->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(sai->base)) return PTR_ERR(sai->base); -- cgit v1.2.3 From f62d6426718837663484bbf0ed94e56573cbc365 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:20 +0800 Subject: ASoC: codecs: msm8916-wcd: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-17-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-digital.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 1db7e43ec203..9fa5d44fdc79 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -1143,7 +1143,6 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev) struct msm8916_wcd_digital_priv *priv; struct device *dev = &pdev->dev; void __iomem *base; - struct resource *mem_res; struct regmap *digital_map; int ret; @@ -1151,8 +1150,7 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem_res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); -- cgit v1.2.3 From 94db63761576a98279e19f51173dec85f803bad4 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:21 +0800 Subject: ASoC: codecs: jz4725b: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-18-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/jz4725b.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c index 766354c73076..2567a5d15b55 100644 --- a/sound/soc/codecs/jz4725b.c +++ b/sound/soc/codecs/jz4725b.c @@ -545,15 +545,13 @@ static int jz4725b_codec_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct jz_icdc *icdc; - struct resource *mem; int ret; icdc = devm_kzalloc(dev, sizeof(*icdc), GFP_KERNEL); if (!icdc) return -ENOMEM; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - icdc->base = devm_ioremap_resource(dev, mem); + icdc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(icdc->base)) return PTR_ERR(icdc->base); -- cgit v1.2.3 From 72d09322e709c5c2d7112d6a19ec9f3846d3609d Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:22 +0800 Subject: ASoC: mmp-sspa: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-19-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-sspa.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 72f4364b2d20..e3e5425b5c62 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -399,7 +399,6 @@ static const struct snd_soc_component_driver mmp_sspa_component = { static int asoc_mmp_sspa_probe(struct platform_device *pdev) { struct sspa_priv *priv; - struct resource *res; priv = devm_kzalloc(&pdev->dev, sizeof(struct sspa_priv), GFP_KERNEL); @@ -417,8 +416,7 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev) if (priv->dma_params == NULL) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->sspa->mmio_base = devm_ioremap_resource(&pdev->dev, res); + priv->sspa->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->sspa->mmio_base)) return PTR_ERR(priv->sspa->mmio_base); -- cgit v1.2.3 From a8dc106410a2c3c87917447fb8c132b66062443e Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:23 +0800 Subject: ASoC: jz4740: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-20-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/jz4740.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 974e17fa1911..460aa1fd1efe 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -318,7 +318,6 @@ static int jz4740_codec_probe(struct platform_device *pdev) { int ret; struct jz4740_codec *jz4740_codec; - struct resource *mem; void __iomem *base; jz4740_codec = devm_kzalloc(&pdev->dev, sizeof(*jz4740_codec), @@ -326,8 +325,7 @@ static int jz4740_codec_probe(struct platform_device *pdev) if (!jz4740_codec) return -ENOMEM; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); -- cgit v1.2.3 From 2d1ffc7d0f58f6a39a34854e952f5020fc655af0 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:24 +0800 Subject: ASoC: inno_rk3036: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-21-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/inno_rk3036.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c index 7feedbb7bbed..14d8fe1c28a4 100644 --- a/sound/soc/codecs/inno_rk3036.c +++ b/sound/soc/codecs/inno_rk3036.c @@ -405,7 +405,6 @@ static int rk3036_codec_platform_probe(struct platform_device *pdev) { struct rk3036_codec_priv *priv; struct device_node *of_node = pdev->dev.of_node; - struct resource *res; void __iomem *base; struct regmap *grf; int ret; @@ -414,8 +413,7 @@ static int rk3036_codec_platform_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); -- cgit v1.2.3 From 4e5bc35988af2483138feb3c5c3bf5fb0cae4228 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:25 +0800 Subject: ASoC: uniphier: evea: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-22-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/uniphier/evea.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/uniphier/evea.c b/sound/soc/uniphier/evea.c index f9c10165fbc1..d27e9ca07856 100644 --- a/sound/soc/uniphier/evea.c +++ b/sound/soc/uniphier/evea.c @@ -451,7 +451,6 @@ static const struct regmap_config evea_regmap_config = { static int evea_probe(struct platform_device *pdev) { struct evea_priv *evea; - struct resource *res; void __iomem *preg; int ret; @@ -475,8 +474,7 @@ static int evea_probe(struct platform_device *pdev) if (IS_ERR(evea->rst_exiv)) return PTR_ERR(evea->rst_exiv); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - preg = devm_ioremap_resource(&pdev->dev, res); + preg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(preg)) return PTR_ERR(preg); -- cgit v1.2.3 From b885c9fa363fa4604d78ea00adfed64db656fb78 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:26 +0800 Subject: ASoC: uniphier: aio-dma: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-23-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/uniphier/aio-dma.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c index fa001d3c1a88..862346d66774 100644 --- a/sound/soc/uniphier/aio-dma.c +++ b/sound/soc/uniphier/aio-dma.c @@ -276,12 +276,10 @@ int uniphier_aiodma_soc_register_platform(struct platform_device *pdev) { struct uniphier_aio_chip *chip = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; - struct resource *res; void __iomem *preg; int irq, ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - preg = devm_ioremap_resource(dev, res); + preg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(preg)) return PTR_ERR(preg); -- cgit v1.2.3 From b1abe8780041d568ae07013a3592519fca855a1c Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:27 +0800 Subject: ASoC: psc-ac97: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-24-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/au1x/psc-ac97.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 21e5f6aed7f3..08bc04e2da2a 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -363,7 +363,7 @@ static const struct snd_soc_component_driver au1xpsc_ac97_component = { static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) { int ret; - struct resource *iores, *dmares; + struct resource *dmares; unsigned long sel; struct au1xpsc_audio_data *wd; @@ -374,8 +374,7 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) mutex_init(&wd->lock); - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - wd->mmio = devm_ioremap_resource(&pdev->dev, iores); + wd->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(wd->mmio)) return PTR_ERR(wd->mmio); -- cgit v1.2.3 From 12a63c0fa03691328b948690601dc7dde8fc527b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:28 +0800 Subject: ASoC: au1x: psc-i2s: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-25-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/au1x/psc-i2s.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 076303f96b8c..767ce950d0da 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -291,7 +291,7 @@ static const struct snd_soc_component_driver au1xpsc_i2s_component = { static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) { - struct resource *iores, *dmares; + struct resource *dmares; unsigned long sel; struct au1xpsc_audio_data *wd; @@ -300,8 +300,7 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) if (!wd) return -ENOMEM; - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - wd->mmio = devm_ioremap_resource(&pdev->dev, iores); + wd->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(wd->mmio)) return PTR_ERR(wd->mmio); -- cgit v1.2.3 From a95c901248642d62dc7462a2d2190c8ac183c84f Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:29 +0800 Subject: ASoC: meson: g12a-tohdmitx: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-26-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/meson/g12a-tohdmitx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c index 9943c807ec5d..9cfbd343a00c 100644 --- a/sound/soc/meson/g12a-tohdmitx.c +++ b/sound/soc/meson/g12a-tohdmitx.c @@ -376,12 +376,10 @@ MODULE_DEVICE_TABLE(of, g12a_tohdmitx_of_match); static int g12a_tohdmitx_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct resource *res; void __iomem *regs; struct regmap *map; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); -- cgit v1.2.3 From 10392fcad7dfc8ea38959b18327ff18b81b1c161 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 27 Jul 2019 23:07:30 +0800 Subject: ASoC: meson: axg-tdm-formatter: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190727150738.54764-27-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-tdm-formatter.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c index 2e498201139f..21c735afab35 100644 --- a/sound/soc/meson/axg-tdm-formatter.c +++ b/sound/soc/meson/axg-tdm-formatter.c @@ -253,7 +253,6 @@ int axg_tdm_formatter_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; const struct axg_tdm_formatter_driver *drv; struct axg_tdm_formatter *formatter; - struct resource *res; void __iomem *regs; int ret; @@ -269,8 +268,7 @@ int axg_tdm_formatter_probe(struct platform_device *pdev) platform_set_drvdata(pdev, formatter); formatter->drv = drv; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); -- cgit v1.2.3 From caa918ef14065b812737f3ee4ac349dcfff196e6 Mon Sep 17 00:00:00 2001 From: Andra Danciu Date: Wed, 31 Jul 2019 14:19:30 +0300 Subject: ASoC: codecs: Add uda1334 codec driver The UDA1334BTS supports the I2S-bus data format with word lengths of up to 24 bits serial data format and has basic features such as de-emphasis (at 44.1 kHz sampling rate) and mute. Datasheet can be found at: https://www.nxp.com/docs/en/data-sheet/UDA1334BTS.pdf Cc: Daniel Baluta Signed-off-by: Andra Danciu Link: https://lore.kernel.org/r/20190731111930.20230-3-andradanciu1997@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 9 ++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/uda1334.c | 295 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 306 insertions(+) create mode 100644 sound/soc/codecs/uda1334.c (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index da4c1ae89742..89238343e34d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -199,6 +199,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TS3A227E if I2C select SND_SOC_TWL4030 if TWL4030_CORE select SND_SOC_TWL6040 if TWL6040_CORE + select SND_SOC_UDA1334 if GPIOLIB select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C select SND_SOC_WCD9335 if SLIMBUS @@ -1207,6 +1208,14 @@ config SND_SOC_TWL4030 config SND_SOC_TWL6040 tristate +config SND_SOC_UDA1334 + tristate "NXP UDA1334 DAC" + depends on GPIOLIB + help + The UDA1334 is an NXP audio codec, supports the I2S-bus data format + and has basic features such as de-emphasis (at 44.1 kHz sampling + rate) and mute. + config SND_SOC_UDA134X tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9230016b0f9f..c498373dcc5f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -212,6 +212,7 @@ snd-soc-tscs454-objs := tscs454.o snd-soc-ts3a227e-objs := ts3a227e.o snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o +snd-soc-uda1334-objs := uda1334.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o @@ -494,6 +495,7 @@ obj-$(CONFIG_SND_SOC_TSCS454) += snd-soc-tscs454.o obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o +obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o diff --git a/sound/soc/codecs/uda1334.c b/sound/soc/codecs/uda1334.c new file mode 100644 index 000000000000..21ab8c5487ba --- /dev/null +++ b/sound/soc/codecs/uda1334.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// uda1334.c -- UDA1334 ALSA SoC Audio driver +// +// Based on WM8523 ALSA SoC Audio driver written by Mark Brown + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UDA1334_NUM_RATES 6 + +/* codec private data */ +struct uda1334_priv { + struct gpio_desc *mute; + struct gpio_desc *deemph; + unsigned int sysclk; + unsigned int rate_constraint_list[UDA1334_NUM_RATES]; + struct snd_pcm_hw_constraint_list rate_constraint; +}; + +static const struct snd_soc_dapm_widget uda1334_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_OUTPUT("LINEVOUTL"), +SND_SOC_DAPM_OUTPUT("LINEVOUTR"), +}; + +static const struct snd_soc_dapm_route uda1334_dapm_routes[] = { + { "LINEVOUTL", NULL, "DAC" }, + { "LINEVOUTR", NULL, "DAC" }, +}; + +static int uda1334_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component); + int deemph = ucontrol->value.integer.value[0]; + + if (deemph > 1) + return -EINVAL; + + gpiod_set_value_cansleep(uda1334->deemph, deemph); + + return 0; +}; + +static int uda1334_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component); + int ret; + + ret = gpiod_get_value_cansleep(uda1334->deemph); + if (ret < 0) + return -EINVAL; + + ucontrol->value.integer.value[0] = ret; + + return 0; +}; + +static const struct snd_kcontrol_new uda1334_snd_controls[] = { + SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0, + uda1334_get_deemph, uda1334_put_deemph), +}; + +static const struct { + int value; + int ratio; +} lrclk_ratios[UDA1334_NUM_RATES] = { + { 1, 128 }, + { 2, 192 }, + { 3, 256 }, + { 4, 384 }, + { 5, 512 }, + { 6, 768 }, +}; + +static int uda1334_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component); + + /* + * The set of sample rates that can be supported depends on the + * MCLK supplied to the CODEC - enforce this. + */ + if (!uda1334->sysclk) { + dev_err(component->dev, + "No MCLK configured, call set_sysclk() on init\n"); + return -EINVAL; + } + + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &uda1334->rate_constraint); + + gpiod_set_value_cansleep(uda1334->mute, 1); + + return 0; +} + +static void uda1334_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component); + + gpiod_set_value_cansleep(uda1334->mute, 0); +} + +static int uda1334_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component); + unsigned int val; + int i, j = 0; + + uda1334->sysclk = freq; + + uda1334->rate_constraint.count = 0; + for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { + val = freq / lrclk_ratios[i].ratio; + /* + * Check that it's a standard rate since core can't + * cope with others and having the odd rates confuses + * constraint matching. + */ + + switch (val) { + case 8000: + case 32000: + case 44100: + case 48000: + case 64000: + case 88200: + case 96000: + dev_dbg(component->dev, "Supported sample rate: %dHz\n", + val); + uda1334->rate_constraint_list[j++] = val; + uda1334->rate_constraint.count++; + break; + default: + dev_dbg(component->dev, "Skipping sample rate: %dHz\n", + val); + } + } + + /* Need at least one supported rate... */ + if (uda1334->rate_constraint.count == 0) + return -EINVAL; + + return 0; +} + +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); + + if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS)) { + dev_err(codec_dai->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + return 0; +} + +static int uda1334_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(dai->component); + + if (uda1334->mute) + gpiod_set_value_cansleep(uda1334->mute, mute); + + return 0; +} + +#define UDA1334_RATES SNDRV_PCM_RATE_8000_96000 + +#define UDA1334_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +static const struct snd_soc_dai_ops uda1334_dai_ops = { + .startup = uda1334_startup, + .shutdown = uda1334_shutdown, + .set_sysclk = uda1334_set_dai_sysclk, + .set_fmt = uda1334_set_fmt, + .mute_stream = uda1334_mute_stream, +}; + +static struct snd_soc_dai_driver uda1334_dai = { + .name = "uda1334-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = UDA1334_RATES, + .formats = UDA1334_FORMATS, + }, + .ops = &uda1334_dai_ops, +}; + +static int uda1334_probe(struct snd_soc_component *component) +{ + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component); + + uda1334->rate_constraint.list = &uda1334->rate_constraint_list[0]; + uda1334->rate_constraint.count = + ARRAY_SIZE(uda1334->rate_constraint_list); + + return 0; +} + +static const struct snd_soc_component_driver soc_component_dev_uda1334 = { + .probe = uda1334_probe, + .controls = uda1334_snd_controls, + .num_controls = ARRAY_SIZE(uda1334_snd_controls), + .dapm_widgets = uda1334_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(uda1334_dapm_widgets), + .dapm_routes = uda1334_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(uda1334_dapm_routes), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct of_device_id uda1334_of_match[] = { + { .compatible = "nxp,uda1334" }, + { /* sentinel*/ } +}; +MODULE_DEVICE_TABLE(of, uda1334_of_match); + +static int uda1334_codec_probe(struct platform_device *pdev) +{ + struct uda1334_priv *uda1334; + int ret; + + uda1334 = devm_kzalloc(&pdev->dev, sizeof(struct uda1334_priv), + GFP_KERNEL); + if (!uda1334) + return -ENOMEM; + + platform_set_drvdata(pdev, uda1334); + + uda1334->mute = devm_gpiod_get(&pdev->dev, "nxp,mute", GPIOD_OUT_LOW); + if (IS_ERR(uda1334->mute)) { + ret = PTR_ERR(uda1334->mute); + dev_err(&pdev->dev, "Failed to get mute line: %d\n", ret); + return ret; + } + + uda1334->deemph = devm_gpiod_get(&pdev->dev, "nxp,deemph", GPIOD_OUT_LOW); + if (IS_ERR(uda1334->deemph)) { + ret = PTR_ERR(uda1334->deemph); + dev_err(&pdev->dev, "Failed to get deemph line: %d\n", ret); + return ret; + } + + ret = devm_snd_soc_register_component(&pdev->dev, + &soc_component_dev_uda1334, + &uda1334_dai, 1); + if (ret < 0) + dev_err(&pdev->dev, "Failed to register component: %d\n", ret); + + return ret; +} + +static struct platform_driver uda1334_codec_driver = { + .probe = uda1334_codec_probe, + .driver = { + .name = "uda1334-codec", + .of_match_table = uda1334_of_match, + }, +}; +module_platform_driver(uda1334_codec_driver); + +MODULE_DESCRIPTION("ASoC UDA1334 driver"); +MODULE_AUTHOR("Andra Danciu "); +MODULE_ALIAS("platform:uda1334-codec"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 63643b5902c4bf096b504b0563f5426ba5baef15 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 29 Jul 2019 10:51:47 -0500 Subject: ASoC: Intel: Skylake: move NHLT header to common directory Prepare move from NHLT code to common directory, starting with header. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/intel-nhlt.h | 119 +++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-nhlt.c | 1 + sound/soc/intel/skylake/skl-nhlt.h | 119 --------------------------------- sound/soc/intel/skylake/skl-ssp-clk.c | 1 + sound/soc/intel/skylake/skl-topology.c | 1 + sound/soc/intel/skylake/skl.h | 1 - 6 files changed, 122 insertions(+), 120 deletions(-) create mode 100644 include/sound/intel-nhlt.h delete mode 100644 sound/soc/intel/skylake/skl-nhlt.h (limited to 'sound') diff --git a/include/sound/intel-nhlt.h b/include/sound/intel-nhlt.h new file mode 100644 index 000000000000..f85fbf9c7ce4 --- /dev/null +++ b/include/sound/intel-nhlt.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * skl-nhlt.h - Intel HDA Platform NHLT header + * + * Copyright (C) 2015 Intel Corp + * Author: Sanjiv Kumar + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#ifndef __SKL_NHLT_H__ +#define __SKL_NHLT_H__ + +#include + +struct wav_fmt { + u16 fmt_tag; + u16 channels; + u32 samples_per_sec; + u32 avg_bytes_per_sec; + u16 block_align; + u16 bits_per_sample; + u16 cb_size; +} __packed; + +struct wav_fmt_ext { + struct wav_fmt fmt; + union samples { + u16 valid_bits_per_sample; + u16 samples_per_block; + u16 reserved; + } sample; + u32 channel_mask; + u8 sub_fmt[16]; +} __packed; + +enum nhlt_link_type { + NHLT_LINK_HDA = 0, + NHLT_LINK_DSP = 1, + NHLT_LINK_DMIC = 2, + NHLT_LINK_SSP = 3, + NHLT_LINK_INVALID +}; + +enum nhlt_device_type { + NHLT_DEVICE_BT = 0, + NHLT_DEVICE_DMIC = 1, + NHLT_DEVICE_I2S = 4, + NHLT_DEVICE_INVALID +}; + +struct nhlt_specific_cfg { + u32 size; + u8 caps[0]; +} __packed; + +struct nhlt_fmt_cfg { + struct wav_fmt_ext fmt_ext; + struct nhlt_specific_cfg config; +} __packed; + +struct nhlt_fmt { + u8 fmt_count; + struct nhlt_fmt_cfg fmt_config[0]; +} __packed; + +struct nhlt_endpoint { + u32 length; + u8 linktype; + u8 instance_id; + u16 vendor_id; + u16 device_id; + u16 revision_id; + u32 subsystem_id; + u8 device_type; + u8 direction; + u8 virtual_bus_id; + struct nhlt_specific_cfg config; +} __packed; + +struct nhlt_acpi_table { + struct acpi_table_header header; + u8 endpoint_count; + struct nhlt_endpoint desc[0]; +} __packed; + +struct nhlt_resource_desc { + u32 extra; + u16 flags; + u64 addr_spc_gra; + u64 min_addr; + u64 max_addr; + u64 addr_trans_offset; + u64 length; +} __packed; + +#define MIC_ARRAY_2CH 2 +#define MIC_ARRAY_4CH 4 + +struct nhlt_tdm_config { + u8 virtual_slot; + u8 config_type; +} __packed; + +struct nhlt_dmic_array_config { + struct nhlt_tdm_config tdm_config; + u8 array_type; +} __packed; + +enum { + NHLT_MIC_ARRAY_2CH_SMALL = 0xa, + NHLT_MIC_ARRAY_2CH_BIG = 0xb, + NHLT_MIC_ARRAY_4CH_1ST_GEOM = 0xc, + NHLT_MIC_ARRAY_4CH_L_SHAPED = 0xd, + NHLT_MIC_ARRAY_4CH_2ND_GEOM = 0xe, + NHLT_MIC_ARRAY_VENDOR_DEFINED = 0xf, +}; + +#endif diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 1132109cb992..aabc5d71650e 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -9,6 +9,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include +#include #include "skl.h" #include "skl-i2s.h" diff --git a/sound/soc/intel/skylake/skl-nhlt.h b/sound/soc/intel/skylake/skl-nhlt.h deleted file mode 100644 index f85fbf9c7ce4..000000000000 --- a/sound/soc/intel/skylake/skl-nhlt.h +++ /dev/null @@ -1,119 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * skl-nhlt.h - Intel HDA Platform NHLT header - * - * Copyright (C) 2015 Intel Corp - * Author: Sanjiv Kumar - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#ifndef __SKL_NHLT_H__ -#define __SKL_NHLT_H__ - -#include - -struct wav_fmt { - u16 fmt_tag; - u16 channels; - u32 samples_per_sec; - u32 avg_bytes_per_sec; - u16 block_align; - u16 bits_per_sample; - u16 cb_size; -} __packed; - -struct wav_fmt_ext { - struct wav_fmt fmt; - union samples { - u16 valid_bits_per_sample; - u16 samples_per_block; - u16 reserved; - } sample; - u32 channel_mask; - u8 sub_fmt[16]; -} __packed; - -enum nhlt_link_type { - NHLT_LINK_HDA = 0, - NHLT_LINK_DSP = 1, - NHLT_LINK_DMIC = 2, - NHLT_LINK_SSP = 3, - NHLT_LINK_INVALID -}; - -enum nhlt_device_type { - NHLT_DEVICE_BT = 0, - NHLT_DEVICE_DMIC = 1, - NHLT_DEVICE_I2S = 4, - NHLT_DEVICE_INVALID -}; - -struct nhlt_specific_cfg { - u32 size; - u8 caps[0]; -} __packed; - -struct nhlt_fmt_cfg { - struct wav_fmt_ext fmt_ext; - struct nhlt_specific_cfg config; -} __packed; - -struct nhlt_fmt { - u8 fmt_count; - struct nhlt_fmt_cfg fmt_config[0]; -} __packed; - -struct nhlt_endpoint { - u32 length; - u8 linktype; - u8 instance_id; - u16 vendor_id; - u16 device_id; - u16 revision_id; - u32 subsystem_id; - u8 device_type; - u8 direction; - u8 virtual_bus_id; - struct nhlt_specific_cfg config; -} __packed; - -struct nhlt_acpi_table { - struct acpi_table_header header; - u8 endpoint_count; - struct nhlt_endpoint desc[0]; -} __packed; - -struct nhlt_resource_desc { - u32 extra; - u16 flags; - u64 addr_spc_gra; - u64 min_addr; - u64 max_addr; - u64 addr_trans_offset; - u64 length; -} __packed; - -#define MIC_ARRAY_2CH 2 -#define MIC_ARRAY_4CH 4 - -struct nhlt_tdm_config { - u8 virtual_slot; - u8 config_type; -} __packed; - -struct nhlt_dmic_array_config { - struct nhlt_tdm_config tdm_config; - u8 array_type; -} __packed; - -enum { - NHLT_MIC_ARRAY_2CH_SMALL = 0xa, - NHLT_MIC_ARRAY_2CH_BIG = 0xb, - NHLT_MIC_ARRAY_4CH_1ST_GEOM = 0xc, - NHLT_MIC_ARRAY_4CH_L_SHAPED = 0xd, - NHLT_MIC_ARRAY_4CH_2ND_GEOM = 0xe, - NHLT_MIC_ARRAY_VENDOR_DEFINED = 0xf, -}; - -#endif diff --git a/sound/soc/intel/skylake/skl-ssp-clk.c b/sound/soc/intel/skylake/skl-ssp-clk.c index 5bb6e40d4d3e..5bfcd46452f9 100644 --- a/sound/soc/intel/skylake/skl-ssp-clk.c +++ b/sound/soc/intel/skylake/skl-ssp-clk.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "skl.h" #include "skl-ssp-clk.h" #include "skl-topology.h" diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 6241e35213af..f8a501cf5fbd 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 6070666a6392..928e8115a1a7 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -16,7 +16,6 @@ #include #include #include -#include "skl-nhlt.h" #include "skl-ssp-clk.h" #define SKL_SUSPEND_DELAY 2000 -- cgit v1.2.3 From 303681f4356d322232dd5f6d9eb4bc62666064c5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 29 Jul 2019 10:51:48 -0500 Subject: ALSA: hda: move parts of NHLT code to new module Move parts of the code outside of the Skylake driver to help detect the presence of DMICs (which are not supported by the HDaudio legacy driver). No functionality change (except for the removal of useless OR operations), only indentation and checkpatch fixes, making sure that the code compiles without ACPI and fixing an ACPI leak Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/intel-nhlt.h | 41 ++++++++++++++---- sound/hda/Kconfig | 5 +++ sound/hda/Makefile | 3 ++ sound/hda/intel-nhlt.c | 103 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 sound/hda/intel-nhlt.c (limited to 'sound') diff --git a/include/sound/intel-nhlt.h b/include/sound/intel-nhlt.h index f85fbf9c7ce4..857922f03931 100644 --- a/include/sound/intel-nhlt.h +++ b/include/sound/intel-nhlt.h @@ -1,18 +1,17 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * skl-nhlt.h - Intel HDA Platform NHLT header + * intel-nhlt.h - Intel HDA Platform NHLT header * - * Copyright (C) 2015 Intel Corp - * Author: Sanjiv Kumar - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Copyright (c) 2015-2019 Intel Corporation */ -#ifndef __SKL_NHLT_H__ -#define __SKL_NHLT_H__ + +#ifndef __INTEL_NHLT_H__ +#define __INTEL_NHLT_H__ #include +#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT) + struct wav_fmt { u16 fmt_tag; u16 channels; @@ -116,4 +115,30 @@ enum { NHLT_MIC_ARRAY_VENDOR_DEFINED = 0xf, }; +struct nhlt_acpi_table *intel_nhlt_init(struct device *dev); + +void intel_nhlt_free(struct nhlt_acpi_table *addr); + +int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt); + +#else + +struct nhlt_acpi_table; + +static inline struct nhlt_acpi_table *intel_nhlt_init(struct device *dev) +{ + return NULL; +} + +static inline void intel_nhlt_free(struct nhlt_acpi_table *addr) +{ +} + +static inline int intel_nhlt_get_dmic_geo(struct device *dev, + struct nhlt_acpi_table *nhlt) +{ + return 0; +} +#endif + #endif diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index f6feced15f17..9ccbcb5a06bd 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -29,3 +29,8 @@ config SND_HDA_PREALLOC_SIZE Note that the pre-allocation size can be changed dynamically via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. + +config SND_INTEL_NHLT + tristate + # this config should be selected only for Intel ACPI platforms. + # A fallback is provided so that the code compiles in all cases. \ No newline at end of file diff --git a/sound/hda/Makefile b/sound/hda/Makefile index 2160202e2dc1..8560f6ef1b19 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -13,3 +13,6 @@ obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o #extended hda obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/ + +snd-intel-nhlt-objs := intel-nhlt.o +obj-$(CONFIG_SND_INTEL_NHLT) += snd-intel-nhlt.o diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c new file mode 100644 index 000000000000..7a62e03ba407 --- /dev/null +++ b/sound/hda/intel-nhlt.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2015-2019 Intel Corporation + +#include +#include + +#define NHLT_ACPI_HEADER_SIG "NHLT" + +/* Unique identification for getting NHLT blobs */ +static guid_t osc_guid = + GUID_INIT(0xA69F886E, 0x6CEB, 0x4594, + 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53); + +struct nhlt_acpi_table *intel_nhlt_init(struct device *dev) +{ + acpi_handle handle; + union acpi_object *obj; + struct nhlt_resource_desc *nhlt_ptr; + struct nhlt_acpi_table *nhlt_table = NULL; + + handle = ACPI_HANDLE(dev); + if (!handle) { + dev_err(dev, "Didn't find ACPI_HANDLE\n"); + return NULL; + } + + obj = acpi_evaluate_dsm(handle, &osc_guid, 1, 1, NULL); + + if (!obj) + return NULL; + + if (obj->type != ACPI_TYPE_BUFFER) { + dev_dbg(dev, "No NHLT table found\n"); + ACPI_FREE(obj); + return NULL; + } + + nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; + if (nhlt_ptr->length) + nhlt_table = (struct nhlt_acpi_table *) + memremap(nhlt_ptr->min_addr, nhlt_ptr->length, + MEMREMAP_WB); + ACPI_FREE(obj); + if (nhlt_table && + (strncmp(nhlt_table->header.signature, + NHLT_ACPI_HEADER_SIG, + strlen(NHLT_ACPI_HEADER_SIG)) != 0)) { + memunmap(nhlt_table); + dev_err(dev, "NHLT ACPI header signature incorrect\n"); + return NULL; + } + return nhlt_table; +} +EXPORT_SYMBOL_GPL(intel_nhlt_init); + +void intel_nhlt_free(struct nhlt_acpi_table *nhlt) +{ + memunmap((void *)nhlt); +} +EXPORT_SYMBOL_GPL(intel_nhlt_free); + +int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) +{ + struct nhlt_endpoint *epnt; + struct nhlt_dmic_array_config *cfg; + unsigned int dmic_geo = 0; + u8 j; + + if (!nhlt) + return 0; + + epnt = (struct nhlt_endpoint *)nhlt->desc; + + for (j = 0; j < nhlt->endpoint_count; j++) { + if (epnt->linktype == NHLT_LINK_DMIC) { + cfg = (struct nhlt_dmic_array_config *) + (epnt->config.caps); + switch (cfg->array_type) { + case NHLT_MIC_ARRAY_2CH_SMALL: + case NHLT_MIC_ARRAY_2CH_BIG: + dmic_geo = MIC_ARRAY_2CH; + break; + + case NHLT_MIC_ARRAY_4CH_1ST_GEOM: + case NHLT_MIC_ARRAY_4CH_L_SHAPED: + case NHLT_MIC_ARRAY_4CH_2ND_GEOM: + dmic_geo = MIC_ARRAY_4CH; + break; + + default: + dev_warn(dev, "undefined DMIC array_type 0x%0x\n", + cfg->array_type); + } + } + epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); + } + + return dmic_geo; +} +EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel NHLT driver"); -- cgit v1.2.3 From 7a33ea70e1868ee578fe2e9a85dd300efa1a35d5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 29 Jul 2019 10:51:49 -0500 Subject: ALSA: hda: intel-nhlt: handle NHLT VENDOR_DEFINED DMIC geometry The NHLT spec defines a VENDOR_DEFINED geometry, which requires reading additional information to figure out the number of microphones. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/intel-nhlt.h | 10 ++++++++-- sound/hda/intel-nhlt.c | 6 +++++- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/include/sound/intel-nhlt.h b/include/sound/intel-nhlt.h index 857922f03931..f657fd8fc0ad 100644 --- a/include/sound/intel-nhlt.h +++ b/include/sound/intel-nhlt.h @@ -96,16 +96,22 @@ struct nhlt_resource_desc { #define MIC_ARRAY_2CH 2 #define MIC_ARRAY_4CH 4 -struct nhlt_tdm_config { +struct nhlt_device_specific_config { u8 virtual_slot; u8 config_type; } __packed; struct nhlt_dmic_array_config { - struct nhlt_tdm_config tdm_config; + struct nhlt_device_specific_config device_config; u8 array_type; } __packed; +struct nhlt_vendor_dmic_array_config { + struct nhlt_dmic_array_config dmic_config; + u8 nb_mics; + /* TODO add vendor mic config */ +} __packed; + enum { NHLT_MIC_ARRAY_2CH_SMALL = 0xa, NHLT_MIC_ARRAY_2CH_BIG = 0xb, diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index 7a62e03ba407..daede96f28ee 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -63,6 +63,7 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) { struct nhlt_endpoint *epnt; struct nhlt_dmic_array_config *cfg; + struct nhlt_vendor_dmic_array_config *cfg_vendor; unsigned int dmic_geo = 0; u8 j; @@ -86,7 +87,10 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) case NHLT_MIC_ARRAY_4CH_2ND_GEOM: dmic_geo = MIC_ARRAY_4CH; break; - + case NHLT_MIC_ARRAY_VENDOR_DEFINED: + cfg_vendor = (struct nhlt_vendor_dmic_array_config *)cfg; + dmic_geo = cfg_vendor->nb_mics; + break; default: dev_warn(dev, "undefined DMIC array_type 0x%0x\n", cfg->array_type); -- cgit v1.2.3 From 1169cbf6b98e11397715d457e42070e066325fc0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 29 Jul 2019 10:51:50 -0500 Subject: ASoC: Intel: Skylake: use common NHLT module No functionality change, only use common functions now. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- sound/soc/intel/Kconfig | 1 + sound/soc/intel/skylake/skl-nhlt.c | 90 -------------------------------------- sound/soc/intel/skylake/skl.c | 12 +++-- sound/soc/intel/skylake/skl.h | 3 -- 4 files changed, 9 insertions(+), 97 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 96a00a9d4cf8..a3ec17fd63cd 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -215,6 +215,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON select SND_SOC_INTEL_SST select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC select SND_SOC_ACPI_INTEL_MATCH + select SND_INTEL_NHLT help If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ GeminiLake or CannonLake platform with the DSP enabled in the BIOS diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index aabc5d71650e..6f57ceb9efb7 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -13,54 +13,6 @@ #include "skl.h" #include "skl-i2s.h" -#define NHLT_ACPI_HEADER_SIG "NHLT" - -/* Unique identification for getting NHLT blobs */ -static guid_t osc_guid = - GUID_INIT(0xA69F886E, 0x6CEB, 0x4594, - 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53); - - -struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) -{ - acpi_handle handle; - union acpi_object *obj; - struct nhlt_resource_desc *nhlt_ptr = NULL; - struct nhlt_acpi_table *nhlt_table = NULL; - - handle = ACPI_HANDLE(dev); - if (!handle) { - dev_err(dev, "Didn't find ACPI_HANDLE\n"); - return NULL; - } - - obj = acpi_evaluate_dsm(handle, &osc_guid, 1, 1, NULL); - if (obj && obj->type == ACPI_TYPE_BUFFER) { - nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; - if (nhlt_ptr->length) - nhlt_table = (struct nhlt_acpi_table *) - memremap(nhlt_ptr->min_addr, nhlt_ptr->length, - MEMREMAP_WB); - ACPI_FREE(obj); - if (nhlt_table && (strncmp(nhlt_table->header.signature, - NHLT_ACPI_HEADER_SIG, - strlen(NHLT_ACPI_HEADER_SIG)) != 0)) { - memunmap(nhlt_table); - dev_err(dev, "NHLT ACPI header signature incorrect\n"); - return NULL; - } - return nhlt_table; - } - - dev_err(dev, "device specific method to extract NHLT blob failed\n"); - return NULL; -} - -void skl_nhlt_free(struct nhlt_acpi_table *nhlt) -{ - memunmap((void *) nhlt); -} - static struct nhlt_specific_cfg *skl_get_specific_cfg( struct device *dev, struct nhlt_fmt *fmt, u8 no_ch, u32 rate, u16 bps, u8 linktype) @@ -163,48 +115,6 @@ struct nhlt_specific_cfg return NULL; } -int skl_get_dmic_geo(struct skl *skl) -{ - struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; - struct nhlt_endpoint *epnt; - struct nhlt_dmic_array_config *cfg; - struct device *dev = &skl->pci->dev; - unsigned int dmic_geo = 0; - u8 j; - - if (!nhlt) - return 0; - - epnt = (struct nhlt_endpoint *)nhlt->desc; - - for (j = 0; j < nhlt->endpoint_count; j++) { - if (epnt->linktype == NHLT_LINK_DMIC) { - cfg = (struct nhlt_dmic_array_config *) - (epnt->config.caps); - switch (cfg->array_type) { - case NHLT_MIC_ARRAY_2CH_SMALL: - case NHLT_MIC_ARRAY_2CH_BIG: - dmic_geo |= MIC_ARRAY_2CH; - break; - - case NHLT_MIC_ARRAY_4CH_1ST_GEOM: - case NHLT_MIC_ARRAY_4CH_L_SHAPED: - case NHLT_MIC_ARRAY_4CH_2ND_GEOM: - dmic_geo |= MIC_ARRAY_4CH; - break; - - default: - dev_warn(dev, "undefined DMIC array_type 0x%0x\n", - cfg->array_type); - - } - } - epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); - } - - return dmic_geo; -} - static void skl_nhlt_trim_space(char *trim) { char *s = trim; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 3362e71b4563..2b5159890a57 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -26,9 +26,11 @@ #include #include #include +#include #include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" + #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) #include "../../../soc/codecs/hdac_hda.h" #endif @@ -516,7 +518,9 @@ static int skl_find_machine(struct skl *skl, void *driver_data) if (pdata) { skl->use_tplg_pcm = pdata->use_tplg_pcm; - mach->mach_params.dmic_num = skl_get_dmic_geo(skl); + mach->mach_params.dmic_num = + intel_nhlt_get_dmic_geo(&skl->pci->dev, + skl->nhlt); } return 0; @@ -1029,7 +1033,7 @@ static int skl_probe(struct pci_dev *pci, device_disable_async_suspend(bus->dev); - skl->nhlt = skl_nhlt_init(bus->dev); + skl->nhlt = intel_nhlt_init(bus->dev); if (skl->nhlt == NULL) { #if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) @@ -1095,7 +1099,7 @@ out_dsp_free: out_clk_free: skl_clock_device_unregister(skl); out_nhlt_free: - skl_nhlt_free(skl->nhlt); + intel_nhlt_free(skl->nhlt); out_free: skl_free(bus); @@ -1144,7 +1148,7 @@ static void skl_remove(struct pci_dev *pci) skl_dmic_device_unregister(skl); skl_clock_device_unregister(skl); skl_nhlt_remove_sysfs(skl); - skl_nhlt_free(skl->nhlt); + intel_nhlt_free(skl->nhlt); skl_free(bus); dev_set_drvdata(&pci->dev, NULL); } diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 928e8115a1a7..f4dd6c767993 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -128,13 +128,10 @@ struct skl_dsp_ops { int skl_platform_unregister(struct device *dev); int skl_platform_register(struct device *dev); -struct nhlt_acpi_table *skl_nhlt_init(struct device *dev); -void skl_nhlt_free(struct nhlt_acpi_table *addr); struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn, u8 dev_type); -int skl_get_dmic_geo(struct skl *skl); int skl_nhlt_update_topology_bin(struct skl *skl); int skl_init_dsp(struct skl *skl); int skl_free_dsp(struct skl *skl); -- cgit v1.2.3 From 8c57588313805d4e12a3d470dee3405c2236655f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 29 Jul 2019 10:51:51 -0500 Subject: ALSA: hda/intel: stop probe if DMICS are detected on Skylake+ platforms The legacy HD-Audio driver cannot handle Skylake+ platforms with digital microphones. For those platforms, the SOF or SST drivers need to be used. This patch provides an automatic way of detecting the presence of DMICs using NHTL information reported by the BIOS. A kernel kconfig option or a kernel module parameter provide an opt-in means of stopping the probe. The kernel would then look for an alternate driver registered for the same PCI ID to probe. With this capability, distros no longer have to blacklist snd-hda-intel, but still need to make sure the SOF/SST drivers are functional by providing the relevant firmware and topology files in /lib/firmware/intel The coexistence between SOF and SST drivers and their dynamic detection is not addressed by this patch, different mechanisms need to be used, e.g. DMI-based quirks. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 10 ++++++++++ sound/pci/hda/hda_intel.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 35d934309cb2..b5966014b5f7 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -12,6 +12,7 @@ config SND_HDA_INTEL tristate "HD Audio PCI" depends on SND_PCI select SND_HDA + select SND_INTEL_NHLT if ACPI help Say Y here to include support for Intel "High Definition Audio" (Azalia) and its compatible devices. @@ -22,6 +23,15 @@ config SND_HDA_INTEL To compile this driver as a module, choose M here: the module will be called snd-hda-intel. +config SND_HDA_INTEL_DETECT_DMIC + bool "DMIC detection and probe abort" + depends on SND_HDA_INTEL + help + Say Y to detect digital microphones on SKL+ devices. DMICs + cannot be handled by the HDaudio legacy driver and are + currently only supported by the SOF driver. + If unsure say N. + config SND_HDA_TEGRA tristate "NVIDIA Tegra HD Audio" depends on ARCH_TEGRA diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cb8b0945547c..ae9c13248a1d 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -124,6 +125,7 @@ static char *patch[SNDRV_CARDS]; static bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = CONFIG_SND_HDA_INPUT_BEEP_MODE}; #endif +static bool dmic_detect = IS_ENABLED(CONFIG_SND_HDA_INTEL_DETECT_DMIC); module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); @@ -158,6 +160,8 @@ module_param_array(beep_mode, bool, NULL, 0444); MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode " "(0=off, 1=on) (default=1)."); #endif +module_param(dmic_detect, bool, 0444); +MODULE_PARM_DESC(dmic_detect, "DMIC detect on SKL+ platforms"); #ifdef CONFIG_PM static int param_set_xint(const char *val, const struct kernel_param *kp); @@ -2025,6 +2029,25 @@ static const struct hda_controller_ops pci_hda_ops = { .position_check = azx_position_check, }; +static int azx_check_dmic(struct pci_dev *pci, struct azx *chip) +{ + struct nhlt_acpi_table *nhlt; + int ret = 0; + + if (chip->driver_type == AZX_DRIVER_SKL && + pci->class != 0x040300) { + nhlt = intel_nhlt_init(&pci->dev); + if (nhlt) { + if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) { + ret = -ENODEV; + dev_info(&pci->dev, "Digital mics found on Skylake+ platform, aborting probe\n"); + } + intel_nhlt_free(nhlt); + } + } + return ret; +} + static int azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -2055,6 +2078,17 @@ static int azx_probe(struct pci_dev *pci, card->private_data = chip; hda = container_of(chip, struct hda_intel, chip); + /* + * stop probe if digital microphones detected on Skylake+ platform + * with the DSP enabled. This is an opt-in behavior defined at build + * time or at run-time with a module parameter + */ + if (dmic_detect) { + err = azx_check_dmic(pci, chip); + if (err < 0) + goto out_free; + } + pci_set_drvdata(pci, card); err = register_vga_switcheroo(chip); -- cgit v1.2.3 From a342031cdd0818cb0fbcb44798211c7a02c7ca27 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 25 Jul 2019 18:59:47 +0200 Subject: ASoC: create pcm for codec2codec links as well At the moment, codec to codec links uses an ephemeral variable for the struct snd_pcm_substream. Also the struct snd_soc_pcm_runtime does not have real struct snd_pcm. This might a problem if the functions used by a codec on codec to codec link expect these structures to exist, and keep on existing during the life of the codec. For example, it is the case of the hdmi-codec, which uses snd_pcm_add_chmap_ctls(). For the controls to works, the pcm and substream must to exist. This change is first step, it create pcm (and substreams) for codec to codec links, in the same way as dpcm backend links. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190725165949.29699-5-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 42 ++++++++++++------------------------------ sound/soc/soc-pcm.c | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 06697b2d96b1..da11e44b01aa 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -447,16 +447,6 @@ static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card) flush_delayed_work(&rtd->delayed_work); } -static void codec2codec_close_delayed_work(struct work_struct *work) -{ - /* - * Currently nothing to do for c2c links - * Since c2c links are internal nodes in the DAPM graph and - * don't interface with the outside world or application layer - * we don't have to do any special handling on close. - */ -} - #ifdef CONFIG_PM_SLEEP /* powers down audio subsystem for suspend */ int snd_soc_suspend(struct device *dev) @@ -1555,27 +1545,19 @@ static int soc_probe_link_dais(struct snd_soc_card *card, return ret; } - if (!dai_link->params) { - /* create the pcm */ - ret = soc_new_pcm(rtd, num); - if (ret < 0) { - dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", - dai_link->stream_name, ret); - return ret; - } - ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); - if (ret < 0) - return ret; - ret = soc_link_dai_pcm_new(rtd->codec_dais, - rtd->num_codecs, rtd); - if (ret < 0) - return ret; - } else { - INIT_DELAYED_WORK(&rtd->delayed_work, - codec2codec_close_delayed_work); + /* create the pcm */ + ret = soc_new_pcm(rtd, num); + if (ret < 0) { + dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", + dai_link->stream_name, ret); + return ret; } - - return 0; + ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); + if (ret < 0) + return ret; + ret = soc_link_dai_pcm_new(rtd->codec_dais, + rtd->num_codecs, rtd); + return ret; } static int soc_bind_aux_dev(struct snd_soc_card *card, int num) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index fabeac164a6c..30264bc592f6 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -678,6 +678,16 @@ static void close_delayed_work(struct work_struct *work) mutex_unlock(&rtd->pcm_mutex); } +static void codec2codec_close_delayed_work(struct work_struct *work) +{ + /* + * Currently nothing to do for c2c links + * Since c2c links are internal nodes in the DAPM graph and + * don't interface with the outside world or application layer + * we don't have to do any special handling on close. + */ +} + /* * Called by ALSA when a PCM substream is closed. Private data can be * freed here. The cpu DAI, codec DAI, machine and components are also @@ -3011,6 +3021,12 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) playback = rtd->dai_link->dpcm_playback; capture = rtd->dai_link->dpcm_capture; } else { + /* Adapt stream for codec2codec links */ + struct snd_soc_pcm_stream *cpu_capture = rtd->dai_link->params ? + &cpu_dai->driver->playback : &cpu_dai->driver->capture; + struct snd_soc_pcm_stream *cpu_playback = rtd->dai_link->params ? + &cpu_dai->driver->capture : &cpu_dai->driver->playback; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) @@ -3019,6 +3035,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) capture = 1; } + + capture = capture && cpu_capture->channels_min; + playback = playback && cpu_playback->channels_min; } if (rtd->dai_link->playback_only) { @@ -3032,7 +3051,13 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) } /* create the PCM */ - if (rtd->dai_link->no_pcm) { + if (rtd->dai_link->params) { + snprintf(new_name, sizeof(new_name), "codec2codec(%s)", + rtd->dai_link->stream_name); + + ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, + playback, capture, &pcm); + } else if (rtd->dai_link->no_pcm) { snprintf(new_name, sizeof(new_name), "(%s)", rtd->dai_link->stream_name); @@ -3059,13 +3084,17 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name); /* DAPM dai link stream work */ - INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); + if (rtd->dai_link->params) + INIT_DELAYED_WORK(&rtd->delayed_work, + codec2codec_close_delayed_work); + else + INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); pcm->nonatomic = rtd->dai_link->nonatomic; rtd->pcm = pcm; pcm->private_data = rtd; - if (rtd->dai_link->no_pcm) { + if (rtd->dai_link->no_pcm || rtd->dai_link->params) { if (playback) pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; if (capture) -- cgit v1.2.3 From a72706ed8208ac3f72d1c3ebbc6509e368b0dcb0 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 25 Jul 2019 18:59:48 +0200 Subject: ASoC: codec2codec: remove ephemeral variables Now that codec to codec links struct snd_soc_pcm_runtime have lasting pcm and substreams, let's use them. Alsa allocate and keep the struct snd_pcm_runtime as long as the link is powered. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190725165949.29699-6-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 72 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2d183e2d23de..1c953a1b46ce 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3775,6 +3775,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_hw_params *params = NULL; const struct snd_soc_pcm_stream *config = NULL; + struct snd_pcm_runtime *runtime = NULL; unsigned int fmt; int ret = 0; @@ -3782,6 +3783,14 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, if (!params) return -ENOMEM; + runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); + if (!runtime) { + ret = -ENOMEM; + goto out; + } + + substream->runtime = runtime; + substream->stream = SNDRV_PCM_STREAM_CAPTURE; snd_soc_dapm_widget_for_each_source_path(w, path) { source = path->source->priv; @@ -3808,6 +3817,8 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, sink->active++; } + substream->hw_opened = 1; + /* * Note: getting the config after .startup() gives a chance to * either party on the link to alter the configuration if @@ -3864,6 +3875,9 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, } out: + if (ret < 0) + kfree(runtime); + kfree(params); return ret; } @@ -3873,29 +3887,16 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, { struct snd_soc_dapm_path *path; struct snd_soc_dai *source, *sink; - struct snd_soc_pcm_runtime *rtd = w->priv; - struct snd_pcm_substream substream; - struct snd_pcm_runtime *runtime = NULL; - int ret = 0; + struct snd_pcm_substream *substream = w->priv; + int ret = 0, saved_stream = substream->stream; if (WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) return -EINVAL; - memset(&substream, 0, sizeof(substream)); - - /* Allocate a dummy snd_pcm_runtime for startup() and other ops() */ - runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); - if (!runtime) { - ret = -ENOMEM; - goto out; - } - substream.runtime = runtime; - substream.private_data = rtd; - switch (event) { case SND_SOC_DAPM_PRE_PMU: - ret = snd_soc_dai_link_event_pre_pmu(w, &substream); + ret = snd_soc_dai_link_event_pre_pmu(w, substream); if (ret < 0) goto out; @@ -3926,40 +3927,45 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret = 0; } - substream.stream = SNDRV_PCM_STREAM_CAPTURE; + substream->stream = SNDRV_PCM_STREAM_CAPTURE; snd_soc_dapm_widget_for_each_source_path(w, path) { source = path->source->priv; - snd_soc_dai_hw_free(source, &substream); + snd_soc_dai_hw_free(source, substream); } - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + substream->stream = SNDRV_PCM_STREAM_PLAYBACK; snd_soc_dapm_widget_for_each_sink_path(w, path) { sink = path->sink->priv; - snd_soc_dai_hw_free(sink, &substream); + snd_soc_dai_hw_free(sink, substream); } - substream.stream = SNDRV_PCM_STREAM_CAPTURE; + substream->stream = SNDRV_PCM_STREAM_CAPTURE; snd_soc_dapm_widget_for_each_source_path(w, path) { source = path->source->priv; source->active--; - snd_soc_dai_shutdown(source, &substream); + snd_soc_dai_shutdown(source, substream); } - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + substream->stream = SNDRV_PCM_STREAM_PLAYBACK; snd_soc_dapm_widget_for_each_sink_path(w, path) { sink = path->sink->priv; sink->active--; - snd_soc_dai_shutdown(sink, &substream); + snd_soc_dai_shutdown(sink, substream); } break; + case SND_SOC_DAPM_POST_PMD: + kfree(substream->runtime); + break; + default: WARN(1, "Unknown event %d\n", event); ret = -EINVAL; } out: - kfree(runtime); + /* Restore the substream direction */ + substream->stream = saved_stream; return ret; } @@ -4082,9 +4088,11 @@ outfree_w_param: } static struct snd_soc_dapm_widget * -snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, +snd_soc_dapm_new_dai(struct snd_soc_card *card, + struct snd_pcm_substream *substream, char *id) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dapm_widget template; struct snd_soc_dapm_widget *w; const char **w_param_text; @@ -4103,7 +4111,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, template.name = link_name; template.event = snd_soc_dai_link_event; template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD; + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD; template.kcontrol_news = NULL; /* allocate memory for control, only in case of multiple configs */ @@ -4138,7 +4146,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, goto outfree_kcontrol_news; } - w->priv = rtd; + w->priv = substream; return w; @@ -4260,6 +4268,8 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, struct snd_soc_dai *codec_dai; struct snd_soc_dapm_widget *playback = NULL, *capture = NULL; struct snd_soc_dapm_widget *codec, *playback_cpu, *capture_cpu; + struct snd_pcm_substream *substream; + struct snd_pcm_str *streams = rtd->pcm->streams; int i; if (rtd->dai_link->params) { @@ -4278,7 +4288,8 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, if (playback_cpu && codec) { if (!playback) { - playback = snd_soc_dapm_new_dai(card, rtd, + substream = streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + playback = snd_soc_dapm_new_dai(card, substream, "playback"); if (IS_ERR(playback)) { dev_err(rtd->dev, @@ -4307,7 +4318,8 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, if (codec && capture_cpu) { if (!capture) { - capture = snd_soc_dapm_new_dai(card, rtd, + substream = streams[SNDRV_PCM_STREAM_CAPTURE].substream; + capture = snd_soc_dapm_new_dai(card, substream, "capture"); if (IS_ERR(capture)) { dev_err(rtd->dev, -- cgit v1.2.3 From 9de98628c895d15427138073986eab1e3ce39cb4 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 25 Jul 2019 18:59:49 +0200 Subject: ASoC: codec2codec: fill some of the runtime stream parameters Set the information provided struct snd_soc_pcm_stream in the struct snd_pcm_runtime of the codec to codec link. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190725165949.29699-7-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1c953a1b46ce..e16838e1bda2 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3874,6 +3874,11 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, dapm_update_dai_unlocked(substream, params, sink); } + runtime->format = params_format(params); + runtime->subformat = params_subformat(params); + runtime->channels = params_channels(params); + runtime->rate = params_rate(params); + out: if (ret < 0) kfree(runtime); -- cgit v1.2.3 From d8701fae95c0e6cb587b293cb8e01acc96dd1095 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 31 Jul 2019 15:17:14 +0200 Subject: ASoC: Intel: SoC: skylake: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Also, if a debugfs call fails, userspace is notified with an error in the log, so no need to log the error again. Cc: Pierre-Louis Bossart Cc: Liam Girdwood Cc: Jie Yang Cc: Mark Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: alsa-devel@alsa-project.org Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20190731131716.9764-1-gregkh@linuxfoundation.org Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-debug.c | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c index fb232428109f..212370bf704c 100644 --- a/sound/soc/intel/skylake/skl-debug.c +++ b/sound/soc/intel/skylake/skl-debug.c @@ -164,10 +164,8 @@ void skl_debug_init_module(struct skl_debug *d, struct snd_soc_dapm_widget *w, struct skl_module_cfg *mconfig) { - if (!debugfs_create_file(w->name, 0444, - d->modules, mconfig, - &mcfg_fops)) - dev_err(d->dev, "%s: module debugfs init failed\n", w->name); + debugfs_create_file(w->name, 0444, d->modules, mconfig, + &mcfg_fops); } static ssize_t fw_softreg_read(struct file *file, char __user *user_buf, @@ -224,34 +222,18 @@ struct skl_debug *skl_debugfs_init(struct skl_dev *skl) return NULL; /* create the debugfs dir with platform component's debugfs as parent */ - d->fs = debugfs_create_dir("dsp", - skl->component->debugfs_root); - if (IS_ERR(d->fs) || !d->fs) { - dev_err(&skl->pci->dev, "debugfs root creation failed\n"); - return NULL; - } + d->fs = debugfs_create_dir("dsp", skl->component->debugfs_root); d->skl = skl; d->dev = &skl->pci->dev; /* now create the module dir */ d->modules = debugfs_create_dir("modules", d->fs); - if (IS_ERR(d->modules) || !d->modules) { - dev_err(&skl->pci->dev, "modules debugfs create failed\n"); - goto err; - } - if (!debugfs_create_file("fw_soft_regs_rd", 0444, d->fs, d, - &soft_regs_ctrl_fops)) { - dev_err(d->dev, "fw soft regs control debugfs init failed\n"); - goto err; - } + debugfs_create_file("fw_soft_regs_rd", 0444, d->fs, d, + &soft_regs_ctrl_fops); return d; - -err: - debugfs_remove_recursive(d->fs); - return NULL; } void skl_debugfs_exit(struct skl_dev *skl) -- cgit v1.2.3 From fee531d6fc49b9a616525e30955c4cf3b403f632 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 31 Jul 2019 15:17:15 +0200 Subject: ASoC: core: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Also, there is no need to store the individual debugfs file name, just remove the whole directory all at once, saving a local variable. Note, the soc-pcm "state" file has now moved to a subdirectory, as it is only a good idea to save the dentries for debugfs directories, not individual files, as the individual file debugfs functions are changing to not return a dentry. Cc: Liam Girdwood Cc: Mark Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: alsa-devel@alsa-project.org Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20190731131716.9764-2-gregkh@linuxfoundation.org Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - sound/soc/soc-core.c | 43 ++++++------------------------------------- sound/soc/soc-dapm.c | 30 ++++-------------------------- sound/soc/soc-pcm.c | 14 ++++---------- 4 files changed, 14 insertions(+), 74 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index d770606732cd..f0797792dd8d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1220,7 +1220,6 @@ struct snd_soc_card { #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_card_root; - struct dentry *debugfs_pop_time; #endif u32 pop_time; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index da11e44b01aa..ed66d2c68d10 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -165,13 +165,6 @@ static void soc_init_component_debugfs(struct snd_soc_component *component) component->card->debugfs_card_root); } - if (IS_ERR(component->debugfs_root)) { - dev_warn(component->dev, - "ASoC: Failed to create component debugfs directory: %ld\n", - PTR_ERR(component->debugfs_root)); - return; - } - snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component), component->debugfs_root); } @@ -215,32 +208,15 @@ DEFINE_SHOW_ATTRIBUTE(component_list); static void soc_init_card_debugfs(struct snd_soc_card *card) { - if (!snd_soc_debugfs_root) - return; - card->debugfs_card_root = debugfs_create_dir(card->name, snd_soc_debugfs_root); - if (IS_ERR(card->debugfs_card_root)) { - dev_warn(card->dev, - "ASoC: Failed to create card debugfs directory: %ld\n", - PTR_ERR(card->debugfs_card_root)); - card->debugfs_card_root = NULL; - return; - } - card->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644, - card->debugfs_card_root, - &card->pop_time); - if (IS_ERR(card->debugfs_pop_time)) - dev_warn(card->dev, - "ASoC: Failed to create pop time debugfs file: %ld\n", - PTR_ERR(card->debugfs_pop_time)); + debugfs_create_u32("dapm_pop_time", 0644, card->debugfs_card_root, + &card->pop_time); } static void soc_cleanup_card_debugfs(struct snd_soc_card *card) { - if (!card->debugfs_card_root) - return; debugfs_remove_recursive(card->debugfs_card_root); card->debugfs_card_root = NULL; } @@ -248,19 +224,12 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card) static void snd_soc_debugfs_init(void) { snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL); - if (IS_ERR_OR_NULL(snd_soc_debugfs_root)) { - pr_warn("ASoC: Failed to create debugfs directory\n"); - snd_soc_debugfs_root = NULL; - return; - } - if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL, - &dai_list_fops)) - pr_warn("ASoC: Failed to create DAI list debugfs file\n"); + debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL, + &dai_list_fops); - if (!debugfs_create_file("components", 0444, snd_soc_debugfs_root, NULL, - &component_list_fops)) - pr_warn("ASoC: Failed to create component list debugfs file\n"); + debugfs_create_file("components", 0444, snd_soc_debugfs_root, NULL, + &component_list_fops); } static void snd_soc_debugfs_exit(void) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e16838e1bda2..d93c1038fab0 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2154,50 +2154,28 @@ static const struct file_operations dapm_bias_fops = { void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, struct dentry *parent) { - struct dentry *d; - if (!parent || IS_ERR(parent)) return; dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); - if (IS_ERR(dapm->debugfs_dapm)) { - dev_warn(dapm->dev, - "ASoC: Failed to create DAPM debugfs directory %ld\n", - PTR_ERR(dapm->debugfs_dapm)); - return; - } - - d = debugfs_create_file("bias_level", 0444, - dapm->debugfs_dapm, dapm, - &dapm_bias_fops); - if (IS_ERR(d)) - dev_warn(dapm->dev, - "ASoC: Failed to create bias level debugfs file: %ld\n", - PTR_ERR(d)); + debugfs_create_file("bias_level", 0444, dapm->debugfs_dapm, dapm, + &dapm_bias_fops); } static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w) { struct snd_soc_dapm_context *dapm = w->dapm; - struct dentry *d; if (!dapm->debugfs_dapm || !w->name) return; - d = debugfs_create_file(w->name, 0444, - dapm->debugfs_dapm, w, - &dapm_widget_power_fops); - if (IS_ERR(d)) - dev_warn(w->dapm->dev, - "ASoC: Failed to create %s debugfs file: %ld\n", - w->name, PTR_ERR(d)); + debugfs_create_file(w->name, 0444, dapm->debugfs_dapm, w, + &dapm_widget_power_fops); } static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) { - if (!dapm->debugfs_dapm) - return; debugfs_remove_recursive(dapm->debugfs_dapm); dapm->debugfs_dapm = NULL; } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 30264bc592f6..ce7297c37537 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1205,9 +1205,9 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, stream ? "<-" : "->", be->dai_link->name); #ifdef CONFIG_DEBUG_FS - if (fe->debugfs_dpcm_root) - dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644, - fe->debugfs_dpcm_root, &dpcm->state); + dpcm->debugfs_state = debugfs_create_dir(be->dai_link->name, + fe->debugfs_dpcm_root); + debugfs_create_u32("state", 0644, dpcm->debugfs_state, &dpcm->state); #endif return 1; } @@ -1262,7 +1262,7 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) dpcm_be_reparent(fe, dpcm->be, stream); #ifdef CONFIG_DEBUG_FS - debugfs_remove(dpcm->debugfs_state); + debugfs_remove_recursive(dpcm->debugfs_state); #endif spin_lock_irqsave(&fe->card->dpcm_lock, flags); list_del(&dpcm->list_be); @@ -3415,12 +3415,6 @@ void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name, rtd->card->debugfs_card_root); - if (!rtd->debugfs_dpcm_root) { - dev_dbg(rtd->dev, - "ASoC: Failed to create dpcm debugfs directory %s\n", - rtd->dai_link->name); - return; - } debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root, rtd, &dpcm_state_fops); -- cgit v1.2.3 From 3ff3a4f657b3fab2d56247983c2ebed180ef2fbb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 31 Jul 2019 15:17:16 +0200 Subject: ASoC: SOF: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Also, if a debugfs call fails, userspace is notified with an error in the log, so no need to log the error again. Because we no longer need to check the return value, there's no need to save the dentry returned by debugfs. Just use the dentry in the file pointer if we really need to figure out the "name" of the file being opened. Cc: Liam Girdwood Cc: Mark Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: Ranjani Sridharan Cc: Pierre-Louis Bossart Cc: alsa-devel@alsa-project.org Signed-off-by: Greg Kroah-Hartman Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20190731131716.9764-3-gregkh@linuxfoundation.org Signed-off-by: Mark Brown --- sound/soc/sof/debug.c | 49 ++++++++++++++++++------------------------------ sound/soc/sof/sof-priv.h | 1 - sound/soc/sof/trace.c | 9 ++------- 3 files changed, 20 insertions(+), 39 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 2388477a965e..40940b2fe9d5 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -128,6 +128,7 @@ static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, unsigned long ipc_duration_ms = 0; bool flood_duration_test = false; unsigned long ipc_count = 0; + struct dentry *dentry; int err; #endif size_t size; @@ -149,11 +150,12 @@ static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, * ipc_duration_ms test floods the DSP for the time specified * in the debugfs entry. */ - if (strcmp(dfse->dfsentry->d_name.name, "ipc_flood_count") && - strcmp(dfse->dfsentry->d_name.name, "ipc_flood_duration_ms")) + dentry = file->f_path.dentry; + if (strcmp(dentry->d_name.name, "ipc_flood_count") && + strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) return -EINVAL; - if (!strcmp(dfse->dfsentry->d_name.name, "ipc_flood_duration_ms")) + if (!strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) flood_duration_test = true; /* test completion criterion */ @@ -219,6 +221,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, { struct snd_sof_dfsentry *dfse = file->private_data; struct snd_sof_dev *sdev = dfse->sdev; + struct dentry *dentry; loff_t pos = *ppos; size_t size_ret; int skip = 0; @@ -226,8 +229,9 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, u8 *buf; #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) - if ((!strcmp(dfse->dfsentry->d_name.name, "ipc_flood_count") || - !strcmp(dfse->dfsentry->d_name.name, "ipc_flood_duration_ms")) && + dentry = file->f_path.dentry; + if ((!strcmp(dentry->d_name.name, "ipc_flood_count") || + !strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) && dfse->cache_buf) { if (*ppos) return 0; @@ -290,8 +294,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, if (!pm_runtime_active(sdev->dev) && dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) { dev_err(sdev->dev, - "error: debugfs entry %s cannot be read in DSP D3\n", - dfse->dfsentry->d_name.name); + "error: debugfs entry cannot be read in DSP D3\n"); kfree(buf); return -EINVAL; } @@ -356,17 +359,11 @@ int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, } #endif - dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, - dfse, &sof_dfs_fops); - if (!dfse->dfsentry) { - /* can't rely on debugfs, only log error and keep going */ - dev_err(sdev->dev, "error: cannot create debugfs entry %s\n", - name); - } else { - /* add to dfsentry list */ - list_add(&dfse->list, &sdev->dfsentry_list); + debugfs_create_file(name, 0444, sdev->debugfs_root, dfse, + &sof_dfs_fops); - } + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); return 0; } @@ -402,16 +399,10 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, return -ENOMEM; #endif - dfse->dfsentry = debugfs_create_file(name, mode, sdev->debugfs_root, - dfse, &sof_dfs_fops); - if (!dfse->dfsentry) { - /* can't rely on debugfs, only log error and keep going */ - dev_err(sdev->dev, "error: cannot create debugfs entry %s\n", - name); - } else { - /* add to dfsentry list */ - list_add(&dfse->list, &sdev->dfsentry_list); - } + debugfs_create_file(name, mode, sdev->debugfs_root, dfse, + &sof_dfs_fops); + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); return 0; } @@ -426,10 +417,6 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) /* use "sof" as top level debugFS dir */ sdev->debugfs_root = debugfs_create_dir("sof", NULL); - if (IS_ERR_OR_NULL(sdev->debugfs_root)) { - dev_err(sdev->dev, "error: failed to create debugfs directory\n"); - return 0; - } /* init dfsentry list */ INIT_LIST_HEAD(&sdev->dfsentry_list); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 983eadef4b30..1cec3f23f9cd 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -230,7 +230,6 @@ enum sof_debugfs_access_type { /* FS entry for debug files that can expose DSP memories, registers */ struct snd_sof_dfsentry { - struct dentry *dfsentry; size_t size; enum sof_dfsentry_type type; /* diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index befed975161c..4c3cff031fd6 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -148,13 +148,8 @@ static int trace_debugfs_create(struct snd_sof_dev *sdev) dfse->size = sdev->dmatb.bytes; dfse->sdev = sdev; - dfse->dfsentry = debugfs_create_file("trace", 0444, sdev->debugfs_root, - dfse, &sof_dfs_trace_fops); - if (!dfse->dfsentry) { - /* can't rely on debugfs, only log error and keep going */ - dev_err(sdev->dev, - "error: cannot create debugfs entry for trace\n"); - } + debugfs_create_file("trace", 0444, sdev->debugfs_root, dfse, + &sof_dfs_trace_fops); return 0; } -- cgit v1.2.3 From f24e41d3d04f326613d8a7ebecf72c3019826f71 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 31 Jul 2019 23:32:34 +0100 Subject: ASoC: zx-tdm: remove redundant assignment to ts_width on error return path The value assigned to ts_width is never read on the error return path so the assignment is redundant and can be removed. Remove it. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190731223234.16153-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/zte/zx-tdm.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/zte/zx-tdm.c b/sound/soc/zte/zx-tdm.c index 5e877fe9ba7b..0e5a05b25a77 100644 --- a/sound/soc/zte/zx-tdm.c +++ b/sound/soc/zte/zx-tdm.c @@ -211,7 +211,6 @@ static int zx_tdm_hw_params(struct snd_pcm_substream *substream, ts_width = 1; break; default: - ts_width = 0; dev_err(socdai->dev, "Unknown data format\n"); return -EINVAL; } -- cgit v1.2.3 From 3bb4aefd2aed628452b8ce544b76abda0ce531f0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 1 Aug 2019 17:28:24 +0100 Subject: ALSA: isa/wavefront: remove redundant assignment to pointer bptr The pointer bptr is being assigned a value that is never read and it is being updated in the next statement with a new value. The initialization is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Takashi Iwai --- sound/isa/wavefront/wavefront_synth.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index aec1c46e6697..c5b1d5900eed 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -788,7 +788,6 @@ wavefront_send_patch (snd_wavefront_t *dev, wavefront_patch_info *header) dev->patch_status[header->number] |= WF_SLOT_FILLED; - bptr = buf; bptr = munge_int32 (header->number, buf, 2); munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES); -- cgit v1.2.3 From b6fcab14ff027c4d54505d9cdff41535c3daf077 Mon Sep 17 00:00:00 2001 From: Tony W Wang-oc Date: Fri, 2 Aug 2019 03:04:08 +0000 Subject: ALSA: hda: Add support of Zhaoxin controller Add the new PCI ID 0x1d17 0x3288 Zhaoxin controller support Signed-off-by: Tony W Wang-oc Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 635d971b003b..151f206e1c02 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -270,6 +270,7 @@ enum { AZX_DRIVER_CTX, AZX_DRIVER_CTHDA, AZX_DRIVER_CMEDIA, + AZX_DRIVER_ZHAOXIN, AZX_DRIVER_GENERIC, AZX_NUM_DRIVERS, /* keep this as last entry */ }; @@ -384,6 +385,7 @@ static char *driver_short_names[] = { [AZX_DRIVER_CTX] = "HDA Creative", [AZX_DRIVER_CTHDA] = "HDA Creative", [AZX_DRIVER_CMEDIA] = "HDA C-Media", + [AZX_DRIVER_ZHAOXIN] = "HDA Zhaoxin", [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; @@ -2624,6 +2626,8 @@ static const struct pci_device_id azx_ids[] = { .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI }, + /* Zhaoxin */ + { PCI_DEVICE(0x1d17, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN }, { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); -- cgit v1.2.3 From cf9441adb1a35506d7606866c382b9d8614169b5 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 30 Jul 2019 11:15:49 -0700 Subject: ASoC: Remove dev_err() usage after platform_get_irq() We don't need dev_err() messages when platform_get_irq() fails now that platform_get_irq() prints an error message itself when something goes wrong. Let's remove these prints with a simple semantic patch. // @@ expression ret; struct platform_device *E; @@ ret = ( platform_get_irq(E, ...) | platform_get_irq_byname(E, ...) ); if ( \( ret < 0 \| ret <= 0 \) ) { ( -if (ret != -EPROBE_DEFER) -{ ... -dev_err(...); -... } | ... -dev_err(...); ) ... } // While we're here, remove braces on if statements that only have one statement (manually). Cc: Liam Girdwood Cc: Mark Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: alsa-devel@alsa-project.org Cc: Greg Kroah-Hartman Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20190730181557.90391-50-swboyd@chromium.org Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-classd.c | 7 ++----- sound/soc/atmel/atmel-pdmic.c | 7 ++----- sound/soc/bcm/cygnus-ssp.c | 7 ++----- sound/soc/codecs/msm8916-wcd-analog.c | 12 +++--------- sound/soc/codecs/twl6040.c | 4 +--- sound/soc/fsl/fsl_asrc.c | 4 +--- sound/soc/fsl/fsl_esai.c | 4 +--- sound/soc/fsl/fsl_sai.c | 4 +--- sound/soc/fsl/fsl_spdif.c | 4 +--- sound/soc/fsl/fsl_ssi.c | 4 +--- sound/soc/fsl/imx-ssi.c | 4 +--- sound/soc/kirkwood/kirkwood-i2s.c | 4 +--- sound/soc/mediatek/common/mtk-btcvsd.c | 4 +--- sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 4 +--- sound/soc/mediatek/mt8173/mt8173-afe-pcm.c | 4 +--- sound/soc/mxs/mxs-saif.c | 8 ++------ sound/soc/qcom/lpass-platform.c | 5 +---- sound/soc/sof/intel/bdw.c | 5 +---- sound/soc/sof/intel/byt.c | 5 +---- sound/soc/sprd/sprd-mcdt.c | 4 +--- sound/soc/sti/sti_uniperif.c | 4 +--- sound/soc/stm/stm32_i2s.c | 5 +---- sound/soc/stm/stm32_sai.c | 4 +--- sound/soc/stm/stm32_spdifrx.c | 4 +--- sound/soc/sunxi/sun4i-i2s.c | 4 +--- sound/soc/uniphier/aio-dma.c | 4 +--- sound/soc/xilinx/xlnx_formatter_pcm.c | 2 -- sound/soc/xtensa/xtfpga-i2s.c | 1 - 28 files changed, 32 insertions(+), 100 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 0f2c574f27f1..e98601eccfa3 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -571,11 +571,8 @@ static int atmel_classd_probe(struct platform_device *pdev) dd->pdata = pdata; dd->irq = platform_get_irq(pdev, 0); - if (dd->irq < 0) { - ret = dd->irq; - dev_err(dev, "failed to could not get irq: %d\n", ret); - return ret; - } + if (dd->irq < 0) + return dd->irq; dd->pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(dd->pclk)) { diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c index e09c28349e0d..04ec6f0af179 100644 --- a/sound/soc/atmel/atmel-pdmic.c +++ b/sound/soc/atmel/atmel-pdmic.c @@ -612,11 +612,8 @@ static int atmel_pdmic_probe(struct platform_device *pdev) dd->dev = dev; dd->irq = platform_get_irq(pdev, 0); - if (dd->irq < 0) { - ret = dd->irq; - dev_err(dev, "failed to get irq: %d\n", ret); - return ret; - } + if (dd->irq < 0) + return dd->irq; dd->pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(dd->pclk)) { diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index b7c358b48d8d..2f9357d7da96 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -1342,11 +1342,8 @@ static int cygnus_ssp_probe(struct platform_device *pdev) } cygaud->irq_num = platform_get_irq(pdev, 0); - if (cygaud->irq_num <= 0) { - dev_err(dev, "platform_get_irq failed\n"); - err = cygaud->irq_num; - return err; - } + if (cygaud->irq_num <= 0) + return cygaud->irq_num; err = audio_clk_init(pdev, cygaud); if (err) { diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 368b6c09474b..667e9f73aba3 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -1185,10 +1185,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) } irq = platform_get_irq_byname(pdev, "mbhc_switch_int"); - if (irq < 0) { - dev_err(dev, "failed to get mbhc switch irq\n"); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_mbhc_switch_irq_handler, @@ -1200,10 +1198,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) if (priv->mbhc_btn_enabled) { irq = platform_get_irq_byname(pdev, "mbhc_but_press_det"); - if (irq < 0) { - dev_err(dev, "failed to get button press irq\n"); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_press_irq_handler, @@ -1214,10 +1210,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) dev_err(dev, "cannot request mbhc button press irq\n"); irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det"); - if (irq < 0) { - dev_err(dev, "failed to get button release irq\n"); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_release_irq_handler, diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 472c2fff34a8..f34637afee51 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1108,10 +1108,8 @@ static int twl6040_probe(struct snd_soc_component *component) priv->component = component; priv->plug_irq = platform_get_irq(pdev, 0); - if (priv->plug_irq < 0) { - dev_err(component->dev, "invalid irq: %d\n", priv->plug_irq); + if (priv->plug_irq < 0) return priv->plug_irq; - } INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work); diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index cbbf6257f08a..cfa40ef6b1ca 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -885,10 +885,8 @@ static int fsl_asrc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0, dev_name(&pdev->dev), asrc_priv); diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 4ce8ac769244..5832144beb9f 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -962,10 +962,8 @@ static int fsl_esai_probe(struct platform_device *pdev) PTR_ERR(esai_priv->spbaclk)); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, esai_isr, 0, esai_priv->name, esai_priv); diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 6d3c6c8d50ce..8f4d9fa95599 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -831,10 +831,8 @@ static int fsl_sai_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai); if (ret) { diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 4842e6df9a2d..7858a5499ac5 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1248,10 +1248,8 @@ static int fsl_spdif_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, dev_name(&pdev->dev), spdif_priv); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index fa862af25c1a..b0a6fead1a6a 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1510,10 +1510,8 @@ static int fsl_ssi_probe(struct platform_device *pdev) } ssi->irq = platform_get_irq(pdev, 0); - if (ssi->irq < 0) { - dev_err(dev, "no irq for node %s\n", pdev->name); + if (ssi->irq < 0) return ssi->irq; - } /* Set software limitations for synchronous mode except AC97 */ if (ssi->synchronous && !fsl_ssi_is_ac97(ssi)) { diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index 9038b61317be..42031ba7da31 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -520,10 +520,8 @@ static int imx_ssi_probe(struct platform_device *pdev) } ssi->irq = platform_get_irq(pdev, 0); - if (ssi->irq < 0) { - dev_err(&pdev->dev, "Failed to get IRQ: %d\n", ssi->irq); + if (ssi->irq < 0) return ssi->irq; - } ssi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ssi->clk)) { diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 5076ec4cc7a6..61226fefe1c4 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -537,10 +537,8 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) return PTR_ERR(priv->io); priv->irq = platform_get_irq(pdev, 0); - if (priv->irq < 0) { - dev_err(&pdev->dev, "platform_get_irq failed: %d\n", priv->irq); + if (priv->irq < 0) return priv->irq; - } if (np) { priv->burst = 128; /* might be 32 or 128 */ diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index c7a81c4be068..d00608c73c6e 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -1335,10 +1335,8 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) /* irq */ irq_id = platform_get_irq(pdev, 0); - if (irq_id <= 0) { - dev_err(dev, "%pOFn no irq found\n", dev->of_node); + if (irq_id <= 0) return irq_id < 0 ? irq_id : -ENXIO; - } ret = devm_request_irq(dev, irq_id, mtk_btcvsd_snd_irq_handler, IRQF_TRIGGER_LOW, "BTCVSD_ISR_Handle", diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index 7064a9fd6f74..9af76ae315a5 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -1342,10 +1342,8 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) return -ENOMEM; irq_id = platform_get_irq_byname(pdev, "asys"); - if (irq_id < 0) { - dev_err(dev, "unable to get ASYS IRQ\n"); + if (irq_id < 0) return irq_id; - } ret = devm_request_irq(dev, irq_id, mt2701_asys_isr, IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index 90bd2c92cae7..0ee29255e731 100644 --- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c @@ -1074,10 +1074,8 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) afe->dev = &pdev->dev; irq_id = platform_get_irq(pdev, 0); - if (irq_id <= 0) { - dev_err(afe->dev, "np %pOFn no irq\n", afe->dev->of_node); + if (irq_id <= 0) return irq_id < 0 ? irq_id : -ENXIO; - } ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler, 0, "Afe_ISR_Handle", (void *)afe); if (ret) { diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index a2c79426513b..1e38ce858326 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -790,12 +790,8 @@ static int mxs_saif_probe(struct platform_device *pdev) return PTR_ERR(saif->base); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - dev_err(&pdev->dev, "failed to get irq resource: %d\n", - ret); - return ret; - } + if (irq < 0) + return irq; saif->dev = &pdev->dev; ret = devm_request_irq(&pdev->dev, irq, mxs_saif_irq, 0, diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index cf7a299f4547..4c745baa39f7 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -564,11 +564,8 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev) int ret; drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif"); - if (drvdata->lpaif_irq < 0) { - dev_err(&pdev->dev, "error getting irq handle: %d\n", - drvdata->lpaif_irq); + if (drvdata->lpaif_irq < 0) return -ENODEV; - } /* ensure audio hardware is disabled */ ret = regmap_write(drvdata->lpaif_map, diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 70d524ef9bc0..4bb9636da990 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -613,11 +613,8 @@ static int bdw_probe(struct snd_sof_dev *sdev) /* register our IRQ */ sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc); - if (sdev->ipc_irq < 0) { - dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", - desc->irqindex_host_ipc); + if (sdev->ipc_irq < 0) return sdev->ipc_irq; - } dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 107d711efc3f..000d576f6a8d 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -728,11 +728,8 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) irq: /* register our IRQ */ sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc); - if (sdev->ipc_irq < 0) { - dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", - desc->irqindex_host_ipc); + if (sdev->ipc_irq < 0) return sdev->ipc_irq; - } dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, diff --git a/sound/soc/sprd/sprd-mcdt.c b/sound/soc/sprd/sprd-mcdt.c index 7448015a4935..f439e5503a3c 100644 --- a/sound/soc/sprd/sprd-mcdt.c +++ b/sound/soc/sprd/sprd-mcdt.c @@ -959,10 +959,8 @@ static int sprd_mcdt_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mcdt); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get MCDT interrupt\n"); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, sprd_mcdt_irq_handler, 0, "sprd-mcdt", mcdt); diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 645bcbe91601..ee4a0151e63e 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -426,10 +426,8 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, UNIPERIF_FIFO_DATA_OFFSET(uni); uni->irq = platform_get_irq(priv->pdev, 0); - if (uni->irq < 0) { - dev_err(dev, "Failed to get IRQ resource\n"); + if (uni->irq < 0) return -ENXIO; - } uni->type = dev_data->type; diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index ba6452dab69b..3e7226a53e53 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -855,11 +855,8 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, /* Get irqs */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - if (irq != -EPROBE_DEFER) - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, IRQF_ONESHOT, dev_name(&pdev->dev), i2s); diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 1ac5103cea78..ef4273361d0d 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -193,10 +193,8 @@ static int stm32_sai_probe(struct platform_device *pdev) /* init irqs */ sai->irq = platform_get_irq(pdev, 0); - if (sai->irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (sai->irq < 0) return sai->irq; - } /* reset */ rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index ee71b898897b..cd4b235fce57 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -909,10 +909,8 @@ static int stm32_spdifrx_parse_of(struct platform_device *pdev, } spdifrx->irq = platform_get_irq(pdev, 0); - if (spdifrx->irq < 0) { - dev_err(&pdev->dev, "No irq for node %s\n", pdev->name); + if (spdifrx->irq < 0) return spdifrx->irq; - } return 0; } diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 9b2232908b65..d97d694c48df 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1087,10 +1087,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev) return PTR_ERR(regs); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Can't retrieve our interrupt\n"); + if (irq < 0) return irq; - } i2s->variant = of_device_get_match_data(&pdev->dev); if (!i2s->variant) { diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c index 862346d66774..e8446cc4e8f8 100644 --- a/sound/soc/uniphier/aio-dma.c +++ b/sound/soc/uniphier/aio-dma.c @@ -289,10 +289,8 @@ int uniphier_aiodma_soc_register_platform(struct platform_device *pdev) return PTR_ERR(chip->regmap); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "Could not get irq.\n"); + if (irq < 0) return irq; - } ret = devm_request_irq(dev, irq, aiodma_irq, IRQF_SHARED, dev_name(dev), pdev); diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index dc8721f4f56b..48970efe7838 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -613,7 +613,6 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev) aud_drv_data->mm2s_irq = platform_get_irq_byname(pdev, "irq_mm2s"); if (aud_drv_data->mm2s_irq < 0) { - dev_err(dev, "xlnx audio mm2s irq resource failed\n"); ret = aud_drv_data->mm2s_irq; goto clk_err; } @@ -640,7 +639,6 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev) aud_drv_data->s2mm_irq = platform_get_irq_byname(pdev, "irq_s2mm"); if (aud_drv_data->s2mm_irq < 0) { - dev_err(dev, "xlnx audio s2mm irq resource failed\n"); ret = aud_drv_data->s2mm_irq; goto clk_err; } diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index 9da395d14a8d..efd374f114a0 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -570,7 +570,6 @@ static int xtfpga_i2s_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "No IRQ resource\n"); err = irq; goto err; } -- cgit v1.2.3 From 18bd7b5ef3a313a9af1314508bca1ed982c05f75 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:49:23 +0900 Subject: ASoC: soc-pcm: remove soc_rtdcom_ack() No ALSA SoC driver has .ack at component->driver->ops. We can revive it if some-driver want to use it, but let's remove it so far to avoid maintaining complex code Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87muh15roz.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ce7297c37537..bf04b69d6878 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2873,26 +2873,6 @@ static void soc_pcm_private_free(struct snd_pcm *pcm) } } -static int soc_rtdcom_ack(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->ack) - continue; - - /* FIXME. it returns 1st ask now */ - return component->driver->ops->ack(substream); - } - - return -EINVAL; -} - static int soc_rtdcom_copy_user(struct snd_pcm_substream *substream, int channel, unsigned long pos, void __user *buf, unsigned long bytes) @@ -3129,8 +3109,6 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (!ops) continue; - if (ops->ack) - rtd->ops.ack = soc_rtdcom_ack; if (ops->copy_user) rtd->ops.copy_user = soc_rtdcom_copy_user; if (ops->copy_kernel) -- cgit v1.2.3 From 4efbb20971af527990f3c51056d142e3f7dc6b4a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:49:29 +0900 Subject: ASoC: soc-pcm: remove soc_rtdcom_copy_kernel() No ALSA SoC driver has .copy_kernel at component->driver->ops. We can revive it if some-driver want to use it, but let's remove it so far to avoid maintaining complex code Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lfwl5rot.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index bf04b69d6878..e85548244b55 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2896,28 +2896,6 @@ static int soc_rtdcom_copy_user(struct snd_pcm_substream *substream, int channel return -EINVAL; } -static int soc_rtdcom_copy_kernel(struct snd_pcm_substream *substream, int channel, - unsigned long pos, void *buf, unsigned long bytes) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->copy_kernel) - continue; - - /* FIXME. it returns 1st copy now */ - return component->driver->ops->copy_kernel(substream, channel, - pos, buf, bytes); - } - - return -EINVAL; -} - static int soc_rtdcom_fill_silence(struct snd_pcm_substream *substream, int channel, unsigned long pos, unsigned long bytes) { @@ -3111,8 +3089,6 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (ops->copy_user) rtd->ops.copy_user = soc_rtdcom_copy_user; - if (ops->copy_kernel) - rtd->ops.copy_kernel = soc_rtdcom_copy_kernel; if (ops->fill_silence) rtd->ops.fill_silence = soc_rtdcom_fill_silence; if (ops->page) -- cgit v1.2.3 From 57cb28856ed8db11faa7cc1c751eb6ad00e7c3f0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:49:43 +0900 Subject: ASoC: soc-pcm: remove soc_fill_silence() No ALSA SoC driver has .fill_silence at component->driver->ops. We can revive it if some-driver want to use it, but let's remove it so far to avoid maintaining complex code Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k1c55rof.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e85548244b55..1e6c4e226933 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2896,28 +2896,6 @@ static int soc_rtdcom_copy_user(struct snd_pcm_substream *substream, int channel return -EINVAL; } -static int soc_rtdcom_fill_silence(struct snd_pcm_substream *substream, int channel, - unsigned long pos, unsigned long bytes) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->fill_silence) - continue; - - /* FIXME. it returns 1st silence now */ - return component->driver->ops->fill_silence(substream, channel, - pos, bytes); - } - - return -EINVAL; -} - static struct page *soc_rtdcom_page(struct snd_pcm_substream *substream, unsigned long offset) { @@ -3089,8 +3067,6 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (ops->copy_user) rtd->ops.copy_user = soc_rtdcom_copy_user; - if (ops->fill_silence) - rtd->ops.fill_silence = soc_rtdcom_fill_silence; if (ops->page) rtd->ops.page = soc_rtdcom_page; if (ops->mmap) -- cgit v1.2.3 From 4ff1fef10f353b928bcc9d56d31fda53f2c43191 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:49:48 +0900 Subject: ASoC: add soc-component.c ALSA SoC has many snd_soc_component_xxx(), but these are randomly located in many files. Because of it, code is difficult to read. This patch creates new soc-component.c, and moves existing snd_soc_component_xxx() into it. But not yet fully. We need more cleanup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87imrp5roa.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 328 ++++++++++++++++++++++++++++++++++++++++++ include/sound/soc.h | 306 +-------------------------------------- sound/soc/Makefile | 2 +- sound/soc/soc-component.c | 269 ++++++++++++++++++++++++++++++++++ sound/soc/soc-core.c | 44 ------ sound/soc/soc-jack.c | 18 --- sound/soc/soc-utils.c | 199 ------------------------- 7 files changed, 599 insertions(+), 567 deletions(-) create mode 100644 include/sound/soc-component.h create mode 100644 sound/soc/soc-component.c (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h new file mode 100644 index 000000000000..a97d499e5d7a --- /dev/null +++ b/include/sound/soc-component.h @@ -0,0 +1,328 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * soc-component.h + * + * Copyright (c) 2019 Kuninori Morimoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __SOC_COMPONENT_H +#define __SOC_COMPONENT_H + +#include + +/* + * Component probe and remove ordering levels for components with runtime + * dependencies. + */ +#define SND_SOC_COMP_ORDER_FIRST -2 +#define SND_SOC_COMP_ORDER_EARLY -1 +#define SND_SOC_COMP_ORDER_NORMAL 0 +#define SND_SOC_COMP_ORDER_LATE 1 +#define SND_SOC_COMP_ORDER_LAST 2 + +#define for_each_comp_order(order) \ + for (order = SND_SOC_COMP_ORDER_FIRST; \ + order <= SND_SOC_COMP_ORDER_LAST; \ + order++) + +/* component interface */ +struct snd_soc_component_driver { + const char *name; + + /* Default control and setup, added after probe() is run */ + const struct snd_kcontrol_new *controls; + unsigned int num_controls; + const struct snd_soc_dapm_widget *dapm_widgets; + unsigned int num_dapm_widgets; + const struct snd_soc_dapm_route *dapm_routes; + unsigned int num_dapm_routes; + + int (*probe)(struct snd_soc_component *component); + void (*remove)(struct snd_soc_component *component); + int (*suspend)(struct snd_soc_component *component); + int (*resume)(struct snd_soc_component *component); + + unsigned int (*read)(struct snd_soc_component *component, + unsigned int reg); + int (*write)(struct snd_soc_component *component, + unsigned int reg, unsigned int val); + + /* pcm creation and destruction */ + int (*pcm_new)(struct snd_soc_pcm_runtime *rtd); + void (*pcm_free)(struct snd_pcm *pcm); + + /* component wide operations */ + int (*set_sysclk)(struct snd_soc_component *component, + int clk_id, int source, unsigned int freq, int dir); + int (*set_pll)(struct snd_soc_component *component, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out); + int (*set_jack)(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data); + + /* DT */ + int (*of_xlate_dai_name)(struct snd_soc_component *component, + struct of_phandle_args *args, + const char **dai_name); + int (*of_xlate_dai_id)(struct snd_soc_component *comment, + struct device_node *endpoint); + void (*seq_notifier)(struct snd_soc_component *component, + enum snd_soc_dapm_type type, int subseq); + int (*stream_event)(struct snd_soc_component *component, int event); + int (*set_bias_level)(struct snd_soc_component *component, + enum snd_soc_bias_level level); + + const struct snd_pcm_ops *ops; + const struct snd_compr_ops *compr_ops; + + /* probe ordering - for components with runtime dependencies */ + int probe_order; + int remove_order; + + /* + * signal if the module handling the component should not be removed + * if a pcm is open. Setting this would prevent the module + * refcount being incremented in probe() but allow it be incremented + * when a pcm is opened and decremented when it is closed. + */ + unsigned int module_get_upon_open:1; + + /* bits */ + unsigned int idle_bias_on:1; + unsigned int suspend_bias_off:1; + unsigned int use_pmdown_time:1; /* care pmdown_time at stop */ + unsigned int endianness:1; + unsigned int non_legacy_dai_naming:1; + + /* this component uses topology and ignore machine driver FEs */ + const char *ignore_machine; + const char *topology_name_prefix; + int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); + bool use_dai_pcm_id; /* use DAI link PCM ID as PCM device number */ + int be_pcm_base; /* base device ID for all BE PCMs */ +}; + +struct snd_soc_component { + const char *name; + int id; + const char *name_prefix; + struct device *dev; + struct snd_soc_card *card; + + unsigned int active; + + unsigned int suspended:1; /* is in suspend PM state */ + + struct list_head list; + struct list_head card_aux_list; /* for auxiliary bound components */ + struct list_head card_list; + + const struct snd_soc_component_driver *driver; + + struct list_head dai_list; + int num_dai; + + struct regmap *regmap; + int val_bytes; + + struct mutex io_mutex; + + /* attached dynamic objects */ + struct list_head dobj_list; + + /* + * DO NOT use any of the fields below in drivers, they are temporary and + * are going to be removed again soon. If you use them in driver code + * the driver will be marked as BROKEN when these fields are removed. + */ + + /* Don't use these, use snd_soc_component_get_dapm() */ + struct snd_soc_dapm_context dapm; + + /* machine specific init */ + int (*init)(struct snd_soc_component *component); + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; + const char *debugfs_prefix; +#endif +}; + +#define for_each_component_dais(component, dai)\ + list_for_each_entry(dai, &(component)->dai_list, list) +#define for_each_component_dais_safe(component, dai, _dai)\ + list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list) + +/** + * snd_soc_dapm_to_component() - Casts a DAPM context to the component it is + * embedded in + * @dapm: The DAPM context to cast to the component + * + * This function must only be used on DAPM contexts that are known to be part of + * a component (e.g. in a component driver). Otherwise the behavior is + * undefined. + */ +static inline struct snd_soc_component *snd_soc_dapm_to_component( + struct snd_soc_dapm_context *dapm) +{ + return container_of(dapm, struct snd_soc_component, dapm); +} + +/** + * snd_soc_component_get_dapm() - Returns the DAPM context associated with a + * component + * @component: The component for which to get the DAPM context + */ +static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm( + struct snd_soc_component *component) +{ + return &component->dapm; +} + +/** + * snd_soc_component_init_bias_level() - Initialize COMPONENT DAPM bias level + * @component: The COMPONENT for which to initialize the DAPM bias level + * @level: The DAPM level to initialize to + * + * Initializes the COMPONENT DAPM bias level. See snd_soc_dapm_init_bias_level() + */ +static inline void +snd_soc_component_init_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + snd_soc_dapm_init_bias_level( + snd_soc_component_get_dapm(component), level); +} + +/** + * snd_soc_component_get_bias_level() - Get current COMPONENT DAPM bias level + * @component: The COMPONENT for which to get the DAPM bias level + * + * Returns: The current DAPM bias level of the COMPONENT. + */ +static inline enum snd_soc_bias_level +snd_soc_component_get_bias_level(struct snd_soc_component *component) +{ + return snd_soc_dapm_get_bias_level( + snd_soc_component_get_dapm(component)); +} + +/** + * snd_soc_component_force_bias_level() - Set the COMPONENT DAPM bias level + * @component: The COMPONENT for which to set the level + * @level: The level to set to + * + * Forces the COMPONENT bias level to a specific state. See + * snd_soc_dapm_force_bias_level(). + */ +static inline int +snd_soc_component_force_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + return snd_soc_dapm_force_bias_level( + snd_soc_component_get_dapm(component), + level); +} + +/** + * snd_soc_dapm_kcontrol_component() - Returns the component associated to a + * kcontrol + * @kcontrol: The kcontrol + * + * This function must only be used on DAPM contexts that are known to be part of + * a COMPONENT (e.g. in a COMPONENT driver). Otherwise the behavior is undefined + */ +static inline struct snd_soc_component *snd_soc_dapm_kcontrol_component( + struct snd_kcontrol *kcontrol) +{ + return snd_soc_dapm_to_component(snd_soc_dapm_kcontrol_dapm(kcontrol)); +} + +/** + * snd_soc_component_cache_sync() - Sync the register cache with the hardware + * @component: COMPONENT to sync + * + * Note: This function will call regcache_sync() + */ +static inline int snd_soc_component_cache_sync( + struct snd_soc_component *component) +{ + return regcache_sync(component->regmap); +} + +/* component IO */ +int snd_soc_component_read(struct snd_soc_component *component, + unsigned int reg, unsigned int *val); +unsigned int snd_soc_component_read32(struct snd_soc_component *component, + unsigned int reg); +int snd_soc_component_write(struct snd_soc_component *component, + unsigned int reg, unsigned int val); +int snd_soc_component_update_bits(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, + unsigned int val); +int snd_soc_component_update_bits_async(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, + unsigned int val); +void snd_soc_component_async_complete(struct snd_soc_component *component); +int snd_soc_component_test_bits(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, + unsigned int value); + +/* component wide operations */ +int snd_soc_component_set_sysclk(struct snd_soc_component *component, + int clk_id, int source, + unsigned int freq, int dir); +int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, + int source, unsigned int freq_in, + unsigned int freq_out); +int snd_soc_component_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data); + +#ifdef CONFIG_REGMAP +void snd_soc_component_init_regmap(struct snd_soc_component *component, + struct regmap *regmap); +void snd_soc_component_exit_regmap(struct snd_soc_component *component); +#endif + +static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c, + void *data) +{ + dev_set_drvdata(c->dev, data); +} + +static inline void *snd_soc_component_get_drvdata(struct snd_soc_component *c) +{ + return dev_get_drvdata(c->dev); +} + +static inline bool snd_soc_component_is_active( + struct snd_soc_component *component) +{ + return component->active != 0; +} + +/* component pin */ +int snd_soc_component_enable_pin(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_disable_pin(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_nc_pin(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_get_pin_status(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_force_enable_pin(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_force_enable_pin_unlocked( + struct snd_soc_component *component, + const char *pin); + +#endif /* __SOC_COMPONENT_H */ diff --git a/include/sound/soc.h b/include/sound/soc.h index f0797792dd8d..6ac6481b4882 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -362,21 +362,6 @@ #define SOC_ENUM_SINGLE_VIRT_DECL(name, xtexts) \ const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts) -/* - * Component probe and remove ordering levels for components with runtime - * dependencies. - */ -#define SND_SOC_COMP_ORDER_FIRST -2 -#define SND_SOC_COMP_ORDER_EARLY -1 -#define SND_SOC_COMP_ORDER_NORMAL 0 -#define SND_SOC_COMP_ORDER_LATE 1 -#define SND_SOC_COMP_ORDER_LAST 2 - -#define for_each_comp_order(order) \ - for (order = SND_SOC_COMP_ORDER_FIRST; \ - order <= SND_SOC_COMP_ORDER_LAST; \ - order++) - /* * Bias levels * @@ -747,132 +732,6 @@ struct snd_soc_compr_ops { int (*trigger)(struct snd_compr_stream *); }; -/* component interface */ -struct snd_soc_component_driver { - const char *name; - - /* Default control and setup, added after probe() is run */ - const struct snd_kcontrol_new *controls; - unsigned int num_controls; - const struct snd_soc_dapm_widget *dapm_widgets; - unsigned int num_dapm_widgets; - const struct snd_soc_dapm_route *dapm_routes; - unsigned int num_dapm_routes; - - int (*probe)(struct snd_soc_component *); - void (*remove)(struct snd_soc_component *); - int (*suspend)(struct snd_soc_component *); - int (*resume)(struct snd_soc_component *); - - unsigned int (*read)(struct snd_soc_component *, unsigned int); - int (*write)(struct snd_soc_component *, unsigned int, unsigned int); - - /* pcm creation and destruction */ - int (*pcm_new)(struct snd_soc_pcm_runtime *); - void (*pcm_free)(struct snd_pcm *); - - /* component wide operations */ - int (*set_sysclk)(struct snd_soc_component *component, - int clk_id, int source, unsigned int freq, int dir); - int (*set_pll)(struct snd_soc_component *component, int pll_id, - int source, unsigned int freq_in, unsigned int freq_out); - int (*set_jack)(struct snd_soc_component *component, - struct snd_soc_jack *jack, void *data); - - /* DT */ - int (*of_xlate_dai_name)(struct snd_soc_component *component, - struct of_phandle_args *args, - const char **dai_name); - int (*of_xlate_dai_id)(struct snd_soc_component *comment, - struct device_node *endpoint); - void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type, - int subseq); - int (*stream_event)(struct snd_soc_component *, int event); - int (*set_bias_level)(struct snd_soc_component *component, - enum snd_soc_bias_level level); - - const struct snd_pcm_ops *ops; - const struct snd_compr_ops *compr_ops; - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; - - /* - * signal if the module handling the component should not be removed - * if a pcm is open. Setting this would prevent the module - * refcount being incremented in probe() but allow it be incremented - * when a pcm is opened and decremented when it is closed. - */ - unsigned int module_get_upon_open:1; - - /* bits */ - unsigned int idle_bias_on:1; - unsigned int suspend_bias_off:1; - unsigned int use_pmdown_time:1; /* care pmdown_time at stop */ - unsigned int endianness:1; - unsigned int non_legacy_dai_naming:1; - - /* this component uses topology and ignore machine driver FEs */ - const char *ignore_machine; - const char *topology_name_prefix; - int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params); - bool use_dai_pcm_id; /* use the DAI link PCM ID as PCM device number */ - int be_pcm_base; /* base device ID for all BE PCMs */ -}; - -struct snd_soc_component { - const char *name; - int id; - const char *name_prefix; - struct device *dev; - struct snd_soc_card *card; - - unsigned int active; - - unsigned int suspended:1; /* is in suspend PM state */ - - struct list_head list; - struct list_head card_aux_list; /* for auxiliary bound components */ - struct list_head card_list; - - const struct snd_soc_component_driver *driver; - - struct list_head dai_list; - int num_dai; - - struct regmap *regmap; - int val_bytes; - - struct mutex io_mutex; - - /* attached dynamic objects */ - struct list_head dobj_list; - - /* - * DO NOT use any of the fields below in drivers, they are temporary and - * are going to be removed again soon. If you use them in driver code the - * driver will be marked as BROKEN when these fields are removed. - */ - - /* Don't use these, use snd_soc_component_get_dapm() */ - struct snd_soc_dapm_context dapm; - - /* machine specific init */ - int (*init)(struct snd_soc_component *component); - -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_root; - const char *debugfs_prefix; -#endif -}; - -#define for_each_component_dais(component, dai)\ - list_for_each_entry(dai, &(component)->dai_list, list) -#define for_each_component_dais_safe(component, dai, _dai)\ - list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list) - struct snd_soc_rtdcom_list { struct snd_soc_component *component; struct list_head list; /* rtd::component_list */ @@ -1337,134 +1196,6 @@ struct soc_enum { struct snd_soc_dobj dobj; }; -/** - * snd_soc_dapm_to_component() - Casts a DAPM context to the component it is - * embedded in - * @dapm: The DAPM context to cast to the component - * - * This function must only be used on DAPM contexts that are known to be part of - * a component (e.g. in a component driver). Otherwise the behavior is - * undefined. - */ -static inline struct snd_soc_component *snd_soc_dapm_to_component( - struct snd_soc_dapm_context *dapm) -{ - return container_of(dapm, struct snd_soc_component, dapm); -} - -/** - * snd_soc_component_get_dapm() - Returns the DAPM context associated with a - * component - * @component: The component for which to get the DAPM context - */ -static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm( - struct snd_soc_component *component) -{ - return &component->dapm; -} - -/** - * snd_soc_component_init_bias_level() - Initialize COMPONENT DAPM bias level - * @component: The COMPONENT for which to initialize the DAPM bias level - * @level: The DAPM level to initialize to - * - * Initializes the COMPONENT DAPM bias level. See snd_soc_dapm_init_bias_level(). - */ -static inline void -snd_soc_component_init_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) -{ - snd_soc_dapm_init_bias_level( - snd_soc_component_get_dapm(component), level); -} - -/** - * snd_soc_component_get_bias_level() - Get current COMPONENT DAPM bias level - * @component: The COMPONENT for which to get the DAPM bias level - * - * Returns: The current DAPM bias level of the COMPONENT. - */ -static inline enum snd_soc_bias_level -snd_soc_component_get_bias_level(struct snd_soc_component *component) -{ - return snd_soc_dapm_get_bias_level( - snd_soc_component_get_dapm(component)); -} - -/** - * snd_soc_component_force_bias_level() - Set the COMPONENT DAPM bias level - * @component: The COMPONENT for which to set the level - * @level: The level to set to - * - * Forces the COMPONENT bias level to a specific state. See - * snd_soc_dapm_force_bias_level(). - */ -static inline int -snd_soc_component_force_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) -{ - return snd_soc_dapm_force_bias_level( - snd_soc_component_get_dapm(component), - level); -} - -/** - * snd_soc_dapm_kcontrol_component() - Returns the component associated to a kcontrol - * @kcontrol: The kcontrol - * - * This function must only be used on DAPM contexts that are known to be part of - * a COMPONENT (e.g. in a COMPONENT driver). Otherwise the behavior is undefined. - */ -static inline struct snd_soc_component *snd_soc_dapm_kcontrol_component( - struct snd_kcontrol *kcontrol) -{ - return snd_soc_dapm_to_component(snd_soc_dapm_kcontrol_dapm(kcontrol)); -} - -/** - * snd_soc_component_cache_sync() - Sync the register cache with the hardware - * @component: COMPONENT to sync - * - * Note: This function will call regcache_sync() - */ -static inline int snd_soc_component_cache_sync( - struct snd_soc_component *component) -{ - return regcache_sync(component->regmap); -} - -/* component IO */ -int snd_soc_component_read(struct snd_soc_component *component, - unsigned int reg, unsigned int *val); -unsigned int snd_soc_component_read32(struct snd_soc_component *component, - unsigned int reg); -int snd_soc_component_write(struct snd_soc_component *component, - unsigned int reg, unsigned int val); -int snd_soc_component_update_bits(struct snd_soc_component *component, - unsigned int reg, unsigned int mask, unsigned int val); -int snd_soc_component_update_bits_async(struct snd_soc_component *component, - unsigned int reg, unsigned int mask, unsigned int val); -void snd_soc_component_async_complete(struct snd_soc_component *component); -int snd_soc_component_test_bits(struct snd_soc_component *component, - unsigned int reg, unsigned int mask, unsigned int value); - -/* component wide operations */ -int snd_soc_component_set_sysclk(struct snd_soc_component *component, - int clk_id, int source, unsigned int freq, int dir); -int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, - int source, unsigned int freq_in, - unsigned int freq_out); -int snd_soc_component_set_jack(struct snd_soc_component *component, - struct snd_soc_jack *jack, void *data); - -#ifdef CONFIG_REGMAP - -void snd_soc_component_init_regmap(struct snd_soc_component *component, - struct regmap *regmap); -void snd_soc_component_exit_regmap(struct snd_soc_component *component); - -#endif - /* device driver data */ static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card, @@ -1478,17 +1209,6 @@ static inline void *snd_soc_card_get_drvdata(struct snd_soc_card *card) return card->drvdata; } -static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c, - void *data) -{ - dev_set_drvdata(c->dev, data); -} - -static inline void *snd_soc_component_get_drvdata(struct snd_soc_component *c) -{ - return dev_get_drvdata(c->dev); -} - static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) { INIT_LIST_HEAD(&card->widgets); @@ -1535,12 +1255,6 @@ static inline unsigned int snd_soc_enum_item_to_val(struct soc_enum *e, return e->values[item]; } -static inline bool snd_soc_component_is_active( - struct snd_soc_component *component) -{ - return component->active != 0; -} - /** * snd_soc_kcontrol_component() - Returns the component that registered the * control @@ -1676,24 +1390,6 @@ static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm) mutex_unlock(&dapm->card->dapm_mutex); } -int snd_soc_component_enable_pin(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_disable_pin(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_nc_pin(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_get_pin_status(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_force_enable_pin(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_force_enable_pin_unlocked( - struct snd_soc_component *component, - const char *pin); +#include #endif diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 919c3c027c62..250a0dea9294 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o soc-dai.o +snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o soc-dai.o soc-component.o snd-soc-core-objs += soc-pcm.o soc-io.o soc-devres.o soc-ops.o snd-soc-core-$(CONFIG_SND_SOC_COMPRESS) += soc-compress.o diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c new file mode 100644 index 000000000000..e19f78bfb919 --- /dev/null +++ b/sound/soc/soc-component.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// soc-component.c +// +// Copyright (C) 2019 Renesas Electronics Corp. +// Kuninori Morimoto +// +#include + +/** + * snd_soc_component_set_sysclk - configure COMPONENT system or master clock. + * @component: COMPONENT + * @clk_id: DAI specific clock ID + * @source: Source for the clock + * @freq: new clock frequency in Hz + * @dir: new clock direction - input/output. + * + * Configures the CODEC master (MCLK) or system (SYSCLK) clocking. + */ +int snd_soc_component_set_sysclk(struct snd_soc_component *component, + int clk_id, int source, unsigned int freq, + int dir) +{ + if (component->driver->set_sysclk) + return component->driver->set_sysclk(component, clk_id, source, + freq, dir); + + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk); + +/* + * snd_soc_component_set_pll - configure component PLL. + * @component: COMPONENT + * @pll_id: DAI specific PLL ID + * @source: DAI specific source for the PLL + * @freq_in: PLL input clock frequency in Hz + * @freq_out: requested PLL output clock frequency in Hz + * + * Configures and enables PLL to generate output clock based on input clock. + */ +int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, + int source, unsigned int freq_in, + unsigned int freq_out) +{ + if (component->driver->set_pll) + return component->driver->set_pll(component, pll_id, source, + freq_in, freq_out); + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_component_set_pll); + +int snd_soc_component_enable_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_enable_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_enable_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin); + +int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_enable_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_enable_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked); + +int snd_soc_component_disable_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_disable_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_disable_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin); + +int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_disable_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_disable_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked); + +int snd_soc_component_nc_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_nc_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_nc_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin); + +int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_nc_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_nc_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked); + +int snd_soc_component_get_pin_status(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_get_pin_status(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_get_pin_status(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status); + +int snd_soc_component_force_enable_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_force_enable_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_force_enable_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin); + +int snd_soc_component_force_enable_pin_unlocked( + struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked); + +/** + * snd_soc_component_set_jack - configure component jack. + * @component: COMPONENTs + * @jack: structure to use for the jack + * @data: can be used if codec driver need extra data for configuring jack + * + * Configures and enables jack detection function. + */ +int snd_soc_component_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + if (component->driver->set_jack) + return component->driver->set_jack(component, jack, data); + + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_component_set_jack); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ed66d2c68d10..dc3e45547da2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2345,50 +2345,6 @@ int snd_soc_add_dai_controls(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); -/** - * snd_soc_component_set_sysclk - configure COMPONENT system or master clock. - * @component: COMPONENT - * @clk_id: DAI specific clock ID - * @source: Source for the clock - * @freq: new clock frequency in Hz - * @dir: new clock direction - input/output. - * - * Configures the CODEC master (MCLK) or system (SYSCLK) clocking. - */ -int snd_soc_component_set_sysclk(struct snd_soc_component *component, - int clk_id, int source, unsigned int freq, - int dir) -{ - if (component->driver->set_sysclk) - return component->driver->set_sysclk(component, clk_id, source, - freq, dir); - - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk); - -/* - * snd_soc_component_set_pll - configure component PLL. - * @component: COMPONENT - * @pll_id: DAI specific PLL ID - * @source: DAI specific source for the PLL - * @freq_in: PLL input clock frequency in Hz - * @freq_out: requested PLL output clock frequency in Hz - * - * Configures and enables PLL to generate output clock based on input clock. - */ -int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, - int source, unsigned int freq_in, - unsigned int freq_out) -{ - if (component->driver->set_pll) - return component->driver->set_pll(component, pll_id, source, - freq_in, freq_out); - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_component_set_pll); - static int snd_soc_bind_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index c7b990abdbaa..a71d2340eb05 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -23,24 +23,6 @@ struct jack_gpio_tbl { struct snd_soc_jack_gpio *gpios; }; -/** - * snd_soc_component_set_jack - configure component jack. - * @component: COMPONENTs - * @jack: structure to use for the jack - * @data: can be used if codec driver need extra data for configuring jack - * - * Configures and enables jack detection function. - */ -int snd_soc_component_set_jack(struct snd_soc_component *component, - struct snd_soc_jack *jack, void *data) -{ - if (component->driver->set_jack) - return component->driver->set_jack(component, jack, data); - - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_component_set_jack); - /** * snd_soc_card_jack_new - Create a new jack * @card: ASoC card diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index e3b9dd634c6d..54dcece52b0c 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -52,205 +52,6 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) } EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); -int snd_soc_component_enable_pin(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_enable_pin(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_enable_pin(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin); - -int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_enable_pin_unlocked(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_enable_pin_unlocked(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked); - -int snd_soc_component_disable_pin(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_disable_pin(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_disable_pin(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin); - -int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_disable_pin_unlocked(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_disable_pin_unlocked(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked); - -int snd_soc_component_nc_pin(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_nc_pin(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_nc_pin(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin); - -int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_nc_pin_unlocked(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_nc_pin_unlocked(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked); - -int snd_soc_component_get_pin_status(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_get_pin_status(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_get_pin_status(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status); - -int snd_soc_component_force_enable_pin(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_force_enable_pin(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_force_enable_pin(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin); - -int snd_soc_component_force_enable_pin_unlocked( - struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked); - static const struct snd_pcm_hardware dummy_dma_hardware = { /* Random values to keep userspace happy when checking constraints */ .info = SNDRV_PCM_INFO_INTERLEAVED | -- cgit v1.2.3 From 4a81e8f30d0b422b7f10562952124d719f73b071 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:49:54 +0900 Subject: ASoC: soc-component: add snd_soc_component_get/put() ALSA SoC is calling try_module_get()/module_put() based on component->driver->module_get_upon_open. To keep simple and readable code, we should create its function. This patch adds new snd_soc_component_get/put(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h8795ro4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 13 +++++++++++++ sound/soc/soc-component.c | 18 ++++++++++++++++++ sound/soc/soc-core.c | 9 ++++----- sound/soc/soc-pcm.c | 10 ++++------ 4 files changed, 39 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index a97d499e5d7a..a76cadf49a16 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -287,6 +287,19 @@ void snd_soc_component_init_regmap(struct snd_soc_component *component, void snd_soc_component_exit_regmap(struct snd_soc_component *component); #endif +#define snd_soc_component_module_get_when_probe(component)\ + snd_soc_component_module_get(component, 0) +#define snd_soc_component_module_get_when_open(component) \ + snd_soc_component_module_get(component, 1) +int snd_soc_component_module_get(struct snd_soc_component *component, + int upon_open); +#define snd_soc_component_module_put_when_remove(component) \ + snd_soc_component_module_put(component, 0) +#define snd_soc_component_module_put_when_close(component) \ + snd_soc_component_module_put(component, 1) +void snd_soc_component_module_put(struct snd_soc_component *component, + int upon_open); + static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c, void *data) { diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index e19f78bfb919..ac2d7bd5d844 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -5,6 +5,7 @@ // Copyright (C) 2019 Renesas Electronics Corp. // Kuninori Morimoto // +#include #include /** @@ -267,3 +268,20 @@ int snd_soc_component_set_jack(struct snd_soc_component *component, return -ENOTSUPP; } EXPORT_SYMBOL_GPL(snd_soc_component_set_jack); + +int snd_soc_component_module_get(struct snd_soc_component *component, + int upon_open) +{ + if (component->driver->module_get_upon_open == !!upon_open && + !try_module_get(component->dev->driver->owner)) + return -ENODEV; + + return 0; +} + +void snd_soc_component_module_put(struct snd_soc_component *component, + int upon_open) +{ + if (component->driver->module_get_upon_open == !!upon_open) + module_put(component->dev->driver->owner); +} diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index dc3e45547da2..9ba19efcc56c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -926,8 +926,7 @@ static void soc_cleanup_component(struct snd_soc_component *component) snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); component->card = NULL; - if (!component->driver->module_get_upon_open) - module_put(component->dev->driver->owner); + snd_soc_component_module_put_when_close(component); } static void soc_remove_component(struct snd_soc_component *component) @@ -1255,9 +1254,9 @@ static int soc_probe_component(struct snd_soc_card *card, return 0; } - if (!component->driver->module_get_upon_open && - !try_module_get(component->dev->driver->owner)) - return -ENODEV; + ret = snd_soc_component_module_get_when_probe(component); + if (ret < 0) + return ret; component->card = card; dapm->card = card; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 1e6c4e226933..5fef18507286 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -440,12 +439,12 @@ static int soc_pcm_components_open(struct snd_pcm_substream *substream, component = rtdcom->component; *last = component; - if (component->driver->module_get_upon_open && - !try_module_get(component->dev->driver->owner)) { + ret = snd_soc_component_module_get_when_open(component); + if (ret < 0) { dev_err(component->dev, "ASoC: can't get module %s\n", component->name); - return -ENODEV; + return ret; } if (!component->driver->ops || @@ -481,8 +480,7 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream, component->driver->ops->close) component->driver->ops->close(substream); - if (component->driver->module_get_upon_open) - module_put(component->dev->driver->owner); + snd_soc_component_module_put_when_close(component); } return 0; -- cgit v1.2.3 From ae2f4849286eed48a3aa79a7b73bb5bcd0c9213b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:50:01 +0900 Subject: ASoC: soc-component: add snd_soc_component_open() Current ALSA SoC is directly using component->driver->ops->xxx, thus, it is deep nested, and makes code difficult to read, and is not good for encapsulation. This patch adds new snd_soc_component_open() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ftmt5rnx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 4 ++++ sound/soc/soc-component.c | 10 ++++++++++ sound/soc/soc-pcm.c | 6 +----- 3 files changed, 15 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index a76cadf49a16..156b1a5b6ddd 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -338,4 +338,8 @@ int snd_soc_component_force_enable_pin_unlocked( struct snd_soc_component *component, const char *pin); +/* component driver ops */ +int snd_soc_component_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index ac2d7bd5d844..ada46f9729b2 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -285,3 +285,13 @@ void snd_soc_component_module_put(struct snd_soc_component *component, if (component->driver->module_get_upon_open == !!upon_open) module_put(component->dev->driver->owner); } + +int snd_soc_component_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + if (component->driver->ops && + component->driver->ops->open) + return component->driver->ops->open(substream); + + return 0; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 5fef18507286..caf7028cee62 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -447,11 +447,7 @@ static int soc_pcm_components_open(struct snd_pcm_substream *substream, return ret; } - if (!component->driver->ops || - !component->driver->ops->open) - continue; - - ret = component->driver->ops->open(substream); + ret = snd_soc_component_open(component, substream); if (ret < 0) { dev_err(component->dev, "ASoC: can't open component %s: %d\n", -- cgit v1.2.3 From 3672beb8cad6beb7b8c017514aef0f4f507debcf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:50:07 +0900 Subject: ASoC: soc-component: add snd_soc_component_close() Current ALSA SoC is directly using component->driver->ops->xxx, thus, it is deep nested, and makes code difficult to read, and is not good for encapsulation. This patch adds new snd_soc_component_close() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ef2d5rnr.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 10 ++++++++++ sound/soc/soc-pcm.c | 8 +++----- 3 files changed, 15 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 156b1a5b6ddd..8dacac953884 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -341,5 +341,7 @@ int snd_soc_component_force_enable_pin_unlocked( /* component driver ops */ int snd_soc_component_open(struct snd_soc_component *component, struct snd_pcm_substream *substream); +int snd_soc_component_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index ada46f9729b2..cee66183470d 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -295,3 +295,13 @@ int snd_soc_component_open(struct snd_soc_component *component, return 0; } + +int snd_soc_component_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + if (component->driver->ops && + component->driver->ops->close) + return component->driver->ops->close(substream); + + return 0; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index caf7028cee62..4848642ef159 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -465,6 +465,7 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; + int ret = 0; for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -472,14 +473,11 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream, if (component == last) break; - if (component->driver->ops && - component->driver->ops->close) - component->driver->ops->close(substream); - + ret |= snd_soc_component_close(component, substream); snd_soc_component_module_put_when_close(component); } - return 0; + return ret; } /* -- cgit v1.2.3 From 6d53723380ed73a2ced648d6e92774b39e5af1bd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:50:13 +0900 Subject: ASoC: soc-component: add snd_soc_component_prepare() Current ALSA SoC is directly using component->driver->ops->xxx, thus, it is deep nested, and makes code difficult to read, and is not good for encapsulation. This patch adds new snd_soc_component_prepare() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87d0hx5rnm.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 10 ++++++++++ sound/soc/soc-pcm.c | 6 +----- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 8dacac953884..ff8233014444 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -343,5 +343,7 @@ int snd_soc_component_open(struct snd_soc_component *component, struct snd_pcm_substream *substream); int snd_soc_component_close(struct snd_soc_component *component, struct snd_pcm_substream *substream); +int snd_soc_component_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index cee66183470d..733d7139d875 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -305,3 +305,13 @@ int snd_soc_component_close(struct snd_soc_component *component, return 0; } + +int snd_soc_component_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + if (component->driver->ops && + component->driver->ops->prepare) + return component->driver->ops->prepare(substream); + + return 0; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 4848642ef159..c7fee67bc0dc 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -785,11 +785,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; - if (!component->driver->ops || - !component->driver->ops->prepare) - continue; - - ret = component->driver->ops->prepare(substream); + ret = snd_soc_component_prepare(component, substream); if (ret < 0) { dev_err(component->dev, "ASoC: platform prepare error: %d\n", ret); -- cgit v1.2.3 From 245c539a1206d74e8508a07550fb7c99d0817b8c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:50:19 +0900 Subject: ASoC: soc-component: add snd_soc_component_hw_params() Current ALSA SoC is directly using component->driver->ops->xxx, thus, it is deep nested, and makes code difficult to read, and is not good for encapsulation. This patch adds new snd_soc_component_hw_params() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87blxh5rnf.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 3 +++ sound/soc/soc-component.c | 11 +++++++++++ sound/soc/soc-pcm.c | 6 +----- 3 files changed, 15 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index ff8233014444..778a6e7d352d 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -345,5 +345,8 @@ int snd_soc_component_close(struct snd_soc_component *component, struct snd_pcm_substream *substream); int snd_soc_component_prepare(struct snd_soc_component *component, struct snd_pcm_substream *substream); +int snd_soc_component_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 733d7139d875..7b6456370da5 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -315,3 +315,14 @@ int snd_soc_component_prepare(struct snd_soc_component *component, return 0; } + +int snd_soc_component_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + if (component->driver->ops && + component->driver->ops->hw_params) + return component->driver->ops->hw_params(substream, params); + + return 0; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index c7fee67bc0dc..8be1d22dc87a 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -951,11 +951,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; - if (!component->driver->ops || - !component->driver->ops->hw_params) - continue; - - ret = component->driver->ops->hw_params(substream, params); + ret = snd_soc_component_hw_params(component, substream, params); if (ret < 0) { dev_err(component->dev, "ASoC: %s hw params failed: %d\n", -- cgit v1.2.3 From eae7136aa2083699c69de5890fd6c32c501952b5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:50:24 +0900 Subject: ASoC: soc-component: add snd_soc_component_hw_free() Current ALSA SoC is directly using component->driver->ops->xxx, thus, it is deep nested, and makes code difficult to read, and is not good for encapsulation. This patch adds new snd_soc_component_hw_free() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a7d15rna.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 10 ++++++++++ sound/soc/soc-pcm.c | 9 +++------ 3 files changed, 15 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 778a6e7d352d..fbcd911ac25e 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -348,5 +348,7 @@ int snd_soc_component_prepare(struct snd_soc_component *component, int snd_soc_component_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); +int snd_soc_component_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 7b6456370da5..e2bc34efe547 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -326,3 +326,13 @@ int snd_soc_component_hw_params(struct snd_soc_component *component, return 0; } + +int snd_soc_component_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + if (component->driver->ops && + component->driver->ops->hw_free) + return component->driver->ops->hw_free(substream); + + return 0; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 8be1d22dc87a..8c5289904f20 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -847,6 +847,7 @@ static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; + int ret = 0; for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -854,14 +855,10 @@ static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream, if (component == last) break; - if (!component->driver->ops || - !component->driver->ops->hw_free) - continue; - - component->driver->ops->hw_free(substream); + ret |= snd_soc_component_hw_free(component, substream); } - return 0; + return ret; } /* -- cgit v1.2.3 From 5693d50c830272cb3c4a04d2ce4db502debd1259 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:50:29 +0900 Subject: ASoC: soc-component: add snd_soc_component_trigger() Current ALSA SoC is directly using component->driver->ops->xxx, thus, it is deep nested, and makes code difficult to read, and is not good for encapsulation. This patch adds new snd_soc_component_trigger() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878ssl5rn5.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 3 +++ sound/soc/soc-component.c | 11 +++++++++++ sound/soc/soc-pcm.c | 6 +----- 3 files changed, 15 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index fbcd911ac25e..302e27a89d47 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -350,5 +350,8 @@ int snd_soc_component_hw_params(struct snd_soc_component *component, struct snd_pcm_hw_params *params); int snd_soc_component_hw_free(struct snd_soc_component *component, struct snd_pcm_substream *substream); +int snd_soc_component_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + int cmd); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index e2bc34efe547..cf0d20a877e6 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -336,3 +336,14 @@ int snd_soc_component_hw_free(struct snd_soc_component *component, return 0; } + +int snd_soc_component_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + int cmd) +{ + if (component->driver->ops && + component->driver->ops->trigger) + return component->driver->ops->trigger(substream, cmd); + + return 0; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 8c5289904f20..cd49c2d688c3 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1065,11 +1065,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; - if (!component->driver->ops || - !component->driver->ops->trigger) - continue; - - ret = component->driver->ops->trigger(substream, cmd); + ret = snd_soc_component_trigger(component, substream, cmd); if (ret < 0) return ret; } -- cgit v1.2.3 From 66c51573b89d0a5c1089139a2f0dd029a755c37d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:50:34 +0900 Subject: ASoC: soc-component: add snd_soc_component_suspend() Current ALSA SoC is directly using component->driver->xxx, thus, it is deep nested, and makes code difficult to read, and is not good for encapsulation. This patch adds new snd_soc_component_suspend() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/877e855rn0.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 1 + sound/soc/soc-component.c | 7 +++++++ sound/soc/soc-core.c | 4 +--- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 302e27a89d47..cdb014f41fd1 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -353,5 +353,6 @@ int snd_soc_component_hw_free(struct snd_soc_component *component, int snd_soc_component_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd); +void snd_soc_component_suspend(struct snd_soc_component *component); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index cf0d20a877e6..f0e63cd991c8 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -347,3 +347,10 @@ int snd_soc_component_trigger(struct snd_soc_component *component, return 0; } + +void snd_soc_component_suspend(struct snd_soc_component *component) +{ + if (component->driver->suspend) + component->driver->suspend(component); + component->suspended = 1; +} diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9ba19efcc56c..855b19abc1d2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -520,9 +520,7 @@ int snd_soc_suspend(struct device *dev) /* fall through */ case SND_SOC_BIAS_OFF: - if (component->driver->suspend) - component->driver->suspend(component); - component->suspended = 1; + snd_soc_component_suspend(component); if (component->regmap) regcache_mark_dirty(component->regmap); /* deactivate pins to sleep state */ -- cgit v1.2.3 From 9a840cbac77a90e8406296aaa132ebf2c84ed9e3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:51:08 +0900 Subject: ASoC: soc-component: add snd_soc_component_resume() Current ALSA SoC is directly using component->driver->xxx, thus, it is deep nested, and makes code difficult to read, and is not good for encapsulation. This patch adds new snd_soc_component_resume() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/875znp5rm2.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 1 + sound/soc/soc-component.c | 7 +++++++ sound/soc/soc-core.c | 4 +--- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index cdb014f41fd1..1e3b70855ba7 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -354,5 +354,6 @@ int snd_soc_component_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd); void snd_soc_component_suspend(struct snd_soc_component *component); +void snd_soc_component_resume(struct snd_soc_component *component); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index f0e63cd991c8..cbae7672b72d 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -354,3 +354,10 @@ void snd_soc_component_suspend(struct snd_soc_component *component) component->driver->suspend(component); component->suspended = 1; } + +void snd_soc_component_resume(struct snd_soc_component *component) +{ + if (component->driver->resume) + component->driver->resume(component); + component->suspended = 0; +} diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 855b19abc1d2..6cdfe7b2fe06 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -593,9 +593,7 @@ static void soc_resume_deferred(struct work_struct *work) for_each_card_components(card, component) { if (component->suspended) { - if (component->driver->resume) - component->driver->resume(component); - component->suspended = 0; + snd_soc_component_resume(component); } } -- cgit v1.2.3 From e40fadbcef583808c11d2e86b8ac1c652731468e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:51:13 +0900 Subject: ASoC: soc-component: add snd_soc_component_is_suspended() Current ALSA SoC is directly using component->xxx, But, it is not good for encapsulation. This patch adds new snd_soc_component_is_suspended() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874l395rlx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 1 + sound/soc/soc-component.c | 5 +++++ sound/soc/soc-core.c | 5 ++--- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 1e3b70855ba7..9600dc4ca6b4 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -355,5 +355,6 @@ int snd_soc_component_trigger(struct snd_soc_component *component, int cmd); void snd_soc_component_suspend(struct snd_soc_component *component); void snd_soc_component_resume(struct snd_soc_component *component); +int snd_soc_component_is_suspended(struct snd_soc_component *component); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index cbae7672b72d..0a9ca84d7ac6 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -361,3 +361,8 @@ void snd_soc_component_resume(struct snd_soc_component *component) component->driver->resume(component); component->suspended = 0; } + +int snd_soc_component_is_suspended(struct snd_soc_component *component) +{ + return component->suspended; +} diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6cdfe7b2fe06..ea93edd328a2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -503,7 +503,7 @@ int snd_soc_suspend(struct device *dev) * If there are paths active then the COMPONENT will be held * with bias _ON and should not be suspended. */ - if (!component->suspended) { + if (!snd_soc_component_is_suspended(component)) { switch (snd_soc_dapm_get_bias_level(dapm)) { case SND_SOC_BIAS_STANDBY: /* @@ -592,9 +592,8 @@ static void soc_resume_deferred(struct work_struct *work) } for_each_card_components(card, component) { - if (component->suspended) { + if (snd_soc_component_is_suspended(component)) snd_soc_component_resume(component); - } } for_each_card_rtds(card, rtd) { -- cgit v1.2.3 From 08e837dd9e39bd3e25b1fa1a13f6ba44040e3f0d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:51:17 +0900 Subject: ASoC: soc-component: add snd_soc_component_probe() Current ALSA SoC is directly using component->driver->xxx, thus, it is deep nested, and makes code difficult to read, and is not good for encapsulation. This patch adds new snd_soc_component_probe() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8736it5rlt.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 1 + sound/soc/soc-component.c | 8 ++++++++ sound/soc/soc-core.c | 12 +++++------- 3 files changed, 14 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 9600dc4ca6b4..34e774efcf69 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -356,5 +356,6 @@ int snd_soc_component_trigger(struct snd_soc_component *component, void snd_soc_component_suspend(struct snd_soc_component *component); void snd_soc_component_resume(struct snd_soc_component *component); int snd_soc_component_is_suspended(struct snd_soc_component *component); +int snd_soc_component_probe(struct snd_soc_component *component); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 0a9ca84d7ac6..b2bfc0375193 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -366,3 +366,11 @@ int snd_soc_component_is_suspended(struct snd_soc_component *component) { return component->suspended; } + +int snd_soc_component_probe(struct snd_soc_component *component) +{ + if (component->driver->probe) + return component->driver->probe(component); + + return 0; +} diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ea93edd328a2..6a422ddae130 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1282,13 +1282,11 @@ static int soc_probe_component(struct snd_soc_card *card, } } - if (component->driver->probe) { - ret = component->driver->probe(component); - if (ret < 0) { - dev_err(component->dev, - "ASoC: failed to probe component %d\n", ret); - goto err_probe; - } + ret = snd_soc_component_probe(component); + if (ret < 0) { + dev_err(component->dev, + "ASoC: failed to probe component %d\n", ret); + goto err_probe; } WARN(dapm->idle_bias_off && dapm->bias_level != SND_SOC_BIAS_OFF, -- cgit v1.2.3 From 03b34dd7d87ce3493cb1837c9e59c3b3aac4724f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:51:22 +0900 Subject: ASoC: soc-component: add snd_soc_component_remove() Current ALSA SoC is directly using component->driver->xxx, thus, it is deep nested, and makes code difficult to read, and is not good for encapsulation. This patch adds new snd_soc_component_remove() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/871ryd5rlo.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 1 + sound/soc/soc-component.c | 6 ++++++ sound/soc/soc-core.c | 3 +-- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 34e774efcf69..b8480d947901 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -357,5 +357,6 @@ void snd_soc_component_suspend(struct snd_soc_component *component); void snd_soc_component_resume(struct snd_soc_component *component); int snd_soc_component_is_suspended(struct snd_soc_component *component); int snd_soc_component_probe(struct snd_soc_component *component); +void snd_soc_component_remove(struct snd_soc_component *component); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index b2bfc0375193..eba77ea2b62d 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -374,3 +374,9 @@ int snd_soc_component_probe(struct snd_soc_component *component) return 0; } + +void snd_soc_component_remove(struct snd_soc_component *component) +{ + if (component->driver->remove) + component->driver->remove(component); +} diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6a422ddae130..6a6403ddf62d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -929,8 +929,7 @@ static void soc_remove_component(struct snd_soc_component *component) if (!component->card) return; - if (component->driver->remove) - component->driver->remove(component); + snd_soc_component_remove(component); soc_cleanup_component(component); } -- cgit v1.2.3 From 2c7b1704819435d188c7697c6815f788bf9e6200 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:51:26 +0900 Subject: ASoC: soc-component: add snd_soc_component_of_xlate_dai_id() Current ALSA SoC is directly using component->driver->xxx, thus, it is deep nested, and makes code difficult to read, and is not good for encapsulation. This patch adds new snd_soc_component_of_xlate_dai_id() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zhl14d14.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 9 +++++++++ sound/soc/soc-core.c | 5 ++--- 3 files changed, 13 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index b8480d947901..3f4acd337c4a 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -358,5 +358,7 @@ void snd_soc_component_resume(struct snd_soc_component *component); int snd_soc_component_is_suspended(struct snd_soc_component *component); int snd_soc_component_probe(struct snd_soc_component *component); void snd_soc_component_remove(struct snd_soc_component *component); +int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, + struct device_node *ep); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index eba77ea2b62d..faf49992f661 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -380,3 +380,12 @@ void snd_soc_component_remove(struct snd_soc_component *component) if (component->driver->remove) component->driver->remove(component); } + +int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, + struct device_node *ep) +{ + if (component->driver->of_xlate_dai_id) + return component->driver->of_xlate_dai_id(component, ep); + + return -ENOTSUPP; +} diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6a6403ddf62d..f63d09dd55f4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3334,9 +3334,8 @@ int snd_soc_get_dai_id(struct device_node *ep) ret = -ENOTSUPP; mutex_lock(&client_mutex); component = soc_find_component(&dlc); - if (component && - component->driver->of_xlate_dai_id) - ret = component->driver->of_xlate_dai_id(component, ep); + if (component) + ret = snd_soc_component_of_xlate_dai_id(component, ep); mutex_unlock(&client_mutex); of_node_put(dlc.of_node); -- cgit v1.2.3 From a2a341752558cc67d6fe5c8ada7c16f9c3690f89 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:51:31 +0900 Subject: ASoC: soc-component: add snd_soc_component_of_xlate_dai_name() Current ALSA SoC is directly using component->driver->xxx, thus, it is deep nested, and makes code difficult to read, and is not good for encapsulation. This patch adds new snd_soc_component_of_xlate_dai_name() and use it Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y30l4d0z.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 3 +++ sound/soc/soc-component.c | 10 ++++++++++ sound/soc/soc-core.c | 7 ++----- 3 files changed, 15 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 3f4acd337c4a..3ed2c39e45c2 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -360,5 +360,8 @@ int snd_soc_component_probe(struct snd_soc_component *component); void snd_soc_component_remove(struct snd_soc_component *component); int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, struct device_node *ep); +int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, + struct of_phandle_args *args, + const char **dai_name); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index faf49992f661..de1bc5196f67 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -389,3 +389,13 @@ int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, return -ENOTSUPP; } + +int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, + struct of_phandle_args *args, + const char **dai_name) +{ + if (component->driver->of_xlate_dai_name) + return component->driver->of_xlate_dai_name(component, + args, dai_name); + return -ENOTSUPP; +} diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f63d09dd55f4..2f068c239f34 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3358,11 +3358,8 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, if (component_of_node != args->np) continue; - if (pos->driver->of_xlate_dai_name) { - ret = pos->driver->of_xlate_dai_name(pos, - args, - dai_name); - } else { + ret = snd_soc_component_of_xlate_dai_name(pos, args, dai_name); + if (ret == -ENOTSUPP) { struct snd_soc_dai *dai; int id = -1; -- cgit v1.2.3 From 9d415fbf773f162a5c274e671741c6fa94b74287 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:51:35 +0900 Subject: ASoC: soc-component: move snd_soc_component_seq_notifier() Current soc-dapm / soc-core are using a long way round to call .seq_notifier. if (driver->seq_notifier) dapm->seq_notifier = ...; ... if (dapm->seq_notifier) ret = dapm->seq_notifier(...); We can directly call it via driver->seq_notifier. One note here is that both Card and Component have dapm, but, Card's dapm doesn't have dapm->component. We need to check it. This patch moves snd_soc_component_seq_notifier() to soc-component.c, and updates parameters. dapm->seq_notifier is no longer needed Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87wog54d0v.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 3 +++ include/sound/soc-dapm.h | 2 -- sound/soc/soc-component.c | 7 +++++++ sound/soc/soc-core.c | 10 ---------- sound/soc/soc-dapm.c | 15 ++++++++------- 5 files changed, 18 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 3ed2c39e45c2..7ac903c1e33f 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -281,6 +281,9 @@ int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, int snd_soc_component_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack, void *data); +void snd_soc_component_seq_notifier(struct snd_soc_component *component, + enum snd_soc_dapm_type type, int subseq); + #ifdef CONFIG_REGMAP void snd_soc_component_init_regmap(struct snd_soc_component *component, struct regmap *regmap); diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 6c6694160130..a03db6f8faa8 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -661,8 +661,6 @@ struct snd_soc_dapm_context { unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */ /* Go to BIAS_OFF in suspend if the DAPM context is idle */ unsigned int suspend_bias_off:1; - void (*seq_notifier)(struct snd_soc_dapm_context *, - enum snd_soc_dapm_type, int); struct device *dev; /* from parent - for debug */ struct snd_soc_component *component; /* parent component */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index de1bc5196f67..ca0b28b1d918 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -52,6 +52,13 @@ int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, } EXPORT_SYMBOL_GPL(snd_soc_component_set_pll); +void snd_soc_component_seq_notifier(struct snd_soc_component *component, + enum snd_soc_dapm_type type, int subseq) +{ + if (component->driver->seq_notifier) + component->driver->seq_notifier(component, type, subseq); +} + int snd_soc_component_enable_pin(struct snd_soc_component *component, const char *pin) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2f068c239f34..c618fecc3d45 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2646,14 +2646,6 @@ int snd_soc_register_dai(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(snd_soc_register_dai); -static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm, - enum snd_soc_dapm_type type, int subseq) -{ - struct snd_soc_component *component = dapm->component; - - component->driver->seq_notifier(component, type, subseq); -} - static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm, int event) { @@ -2690,8 +2682,6 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, dapm->bias_level = SND_SOC_BIAS_OFF; dapm->idle_bias_off = !driver->idle_bias_on; dapm->suspend_bias_off = driver->suspend_bias_off; - if (driver->seq_notifier) - dapm->seq_notifier = snd_soc_component_seq_notifier; if (driver->stream_event) dapm->stream_event = snd_soc_component_stream_event; if (driver->set_bias_level) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d93c1038fab0..0b60f688b433 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1611,12 +1611,12 @@ static void dapm_seq_run(struct snd_soc_card *card, if (!list_empty(&pending)) dapm_seq_run_coalesced(card, &pending); - if (cur_dapm && cur_dapm->seq_notifier) { + if (cur_dapm && cur_dapm->component) { for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) if (sort[i] == cur_sort) - cur_dapm->seq_notifier(cur_dapm, - i, - cur_subseq); + snd_soc_component_seq_notifier( + cur_dapm->component, + i, cur_subseq); } if (cur_dapm && w->dapm != cur_dapm) @@ -1674,11 +1674,12 @@ static void dapm_seq_run(struct snd_soc_card *card, if (!list_empty(&pending)) dapm_seq_run_coalesced(card, &pending); - if (cur_dapm && cur_dapm->seq_notifier) { + if (cur_dapm && cur_dapm->component) { for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) if (sort[i] == cur_sort) - cur_dapm->seq_notifier(cur_dapm, - i, cur_subseq); + snd_soc_component_seq_notifier( + cur_dapm->component, + i, cur_subseq); } list_for_each_entry(d, &card->dapm_list, list) { -- cgit v1.2.3 From 8e2a990d76aced95c6f01c2d67d8835c86f0ca67 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:51:39 +0900 Subject: ASoC: soc-component: move snd_soc_component_stream_event() Current soc-dapm / soc-core are using a long way round to call .stream_event. if (driver->stream_event) dapm->stream_event = ...; ... if (dapm->stream_event) ret = dapm->stream_event(...); We can directly call it via driver->stream_event. One note here is that both Card and Component have dapm, but, Card's dapm doesn't have dapm->component. We need to check it. This patch moves snd_soc_component_stream_event() to soc-component.c and updates parameters. dapm->stream_event is no longer needed Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v9vp4d0r.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ include/sound/soc-dapm.h | 1 - sound/soc/soc-component.c | 9 +++++++++ sound/soc/soc-core.c | 10 ---------- sound/soc/soc-dapm.c | 9 +++++++-- 5 files changed, 18 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 7ac903c1e33f..1f84f04e2670 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -283,6 +283,8 @@ int snd_soc_component_set_jack(struct snd_soc_component *component, void snd_soc_component_seq_notifier(struct snd_soc_component *component, enum snd_soc_dapm_type type, int subseq); +int snd_soc_component_stream_event(struct snd_soc_component *component, + int event); #ifdef CONFIG_REGMAP void snd_soc_component_init_regmap(struct snd_soc_component *component, diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index a03db6f8faa8..c2f14a335891 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -670,7 +670,6 @@ struct snd_soc_dapm_context { enum snd_soc_bias_level target_bias_level; struct list_head list; - int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); int (*set_bias_level)(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index ca0b28b1d918..f33dda8023ec 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -59,6 +59,15 @@ void snd_soc_component_seq_notifier(struct snd_soc_component *component, component->driver->seq_notifier(component, type, subseq); } +int snd_soc_component_stream_event(struct snd_soc_component *component, + int event) +{ + if (component->driver->stream_event) + return component->driver->stream_event(component, event); + + return 0; +} + int snd_soc_component_enable_pin(struct snd_soc_component *component, const char *pin) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c618fecc3d45..8cfbe5fb5921 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2646,14 +2646,6 @@ int snd_soc_register_dai(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(snd_soc_register_dai); -static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm, - int event) -{ - struct snd_soc_component *component = dapm->component; - - return component->driver->stream_event(component, event); -} - static int snd_soc_component_set_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { @@ -2682,8 +2674,6 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, dapm->bias_level = SND_SOC_BIAS_OFF; dapm->idle_bias_off = !driver->idle_bias_on; dapm->suspend_bias_off = driver->suspend_bias_off; - if (driver->stream_event) - dapm->stream_event = snd_soc_component_stream_event; if (driver->set_bias_level) dapm->set_bias_level = snd_soc_component_set_bias_level; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0b60f688b433..9288b2b43f98 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1913,6 +1913,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) LIST_HEAD(down_list); ASYNC_DOMAIN_EXCLUSIVE(async_domain); enum snd_soc_bias_level bias; + int ret; lockdep_assert_held(&card->dapm_mutex); @@ -2029,8 +2030,12 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) /* do we need to notify any clients that DAPM event is complete */ list_for_each_entry(d, &card->dapm_list, list) { - if (d->stream_event) - d->stream_event(d, event); + if (!d->component) + continue; + + ret = snd_soc_component_stream_event(d->component, event); + if (ret < 0) + return ret; } pop_dbg(card->dev, card->pop_time, -- cgit v1.2.3 From 7951b14611851bdae18e9bca18015b1d84731d0d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:51:43 +0900 Subject: ASoC: soc-component: move snd_soc_component_set_bias_level() Current soc-dapm / soc-core are using a long way round to call .set_bias_level. if (driver->set_bias_level) dapm->set_bias_level = ...; ... if (dapm->set_bias_level) ret = dapm->set_bias_level(...); We can directly call it via driver->set_bias_level. One note here is that both Card and Component have dapm, but, Card's dapm doesn't have dapm->component. We need to check it. This patch moves snd_soc_component_set_bias_level() to soc-component.c and updates parameters. dapm->set_bias_level is no longer needed Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tvb94d0n.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ include/sound/soc-dapm.h | 3 --- sound/soc/soc-component.c | 9 +++++++++ sound/soc/soc-core.c | 10 ---------- sound/soc/soc-dapm.c | 4 ++-- 5 files changed, 13 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 1f84f04e2670..2aaf12bbbed0 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -285,6 +285,8 @@ void snd_soc_component_seq_notifier(struct snd_soc_component *component, enum snd_soc_dapm_type type, int subseq); int snd_soc_component_stream_event(struct snd_soc_component *component, int event); +int snd_soc_component_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level); #ifdef CONFIG_REGMAP void snd_soc_component_init_regmap(struct snd_soc_component *component, diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index c2f14a335891..2aa73d6dd7be 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -670,9 +670,6 @@ struct snd_soc_dapm_context { enum snd_soc_bias_level target_bias_level; struct list_head list; - int (*set_bias_level)(struct snd_soc_dapm_context *dapm, - enum snd_soc_bias_level level); - struct snd_soc_dapm_wcache path_sink_cache; struct snd_soc_dapm_wcache path_source_cache; diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index f33dda8023ec..cb63df6e46eb 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -68,6 +68,15 @@ int snd_soc_component_stream_event(struct snd_soc_component *component, return 0; } +int snd_soc_component_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + if (component->driver->set_bias_level) + return component->driver->set_bias_level(component, level); + + return 0; +} + int snd_soc_component_enable_pin(struct snd_soc_component *component, const char *pin) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8cfbe5fb5921..0f75dac4bb26 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2646,14 +2646,6 @@ int snd_soc_register_dai(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(snd_soc_register_dai); -static int snd_soc_component_set_bias_level(struct snd_soc_dapm_context *dapm, - enum snd_soc_bias_level level) -{ - struct snd_soc_component *component = dapm->component; - - return component->driver->set_bias_level(component, level); -} - static int snd_soc_component_initialize(struct snd_soc_component *component, const struct snd_soc_component_driver *driver, struct device *dev) { @@ -2674,8 +2666,6 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, dapm->bias_level = SND_SOC_BIAS_OFF; dapm->idle_bias_off = !driver->idle_bias_on; dapm->suspend_bias_off = driver->suspend_bias_off; - if (driver->set_bias_level) - dapm->set_bias_level = snd_soc_component_set_bias_level; INIT_LIST_HEAD(&component->dai_list); mutex_init(&component->io_mutex); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 9288b2b43f98..d09bdca63c62 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -684,8 +684,8 @@ int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, { int ret = 0; - if (dapm->set_bias_level) - ret = dapm->set_bias_level(dapm, level); + if (dapm->component) + ret = snd_soc_component_set_bias_level(dapm->component, level); if (ret == 0) dapm->bias_level = level; -- cgit v1.2.3 From 0035e2565b93e0902a06320ba1716bc1ddd753b3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:51:47 +0900 Subject: ASoC: soc-component: add snd_soc_pcm_component_pointer() Current ALSA SoC is directly using component->driver->ops->xxx, thus, the code nested deeply, and it makes code difficult to read, and is not good for encapsulation. We want to implement component related function at soc-component.c, but, some of them need to care whole snd_soc_pcm_runtime (= rtd) connected component. Let's call component related function which need to care with for_each_rtdcom() loop as snd_soc_pcm_component_xxx(). This patch adds new snd_soc_pcm_component_pointer() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sgqt4d0j.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 18 ++++++++++++++++++ sound/soc/soc-pcm.c | 13 +------------ 3 files changed, 21 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 2aaf12bbbed0..38b4be1d99f5 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -371,4 +371,6 @@ int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, struct of_phandle_args *args, const char **dai_name); +int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); + #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index cb63df6e46eb..e2053c8bf1f0 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -424,3 +424,21 @@ int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, args, dai_name); return -ENOTSUPP; } + +int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component; + struct snd_soc_rtdcom_list *rtdcom; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* FIXME: use 1st pointer */ + if (component->driver->ops && + component->driver->ops->pointer) + return component->driver->ops->pointer(substream); + } + + return 0; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index cd49c2d688c3..020e1d275076 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1111,8 +1111,6 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; struct snd_pcm_runtime *runtime = substream->runtime; @@ -1124,17 +1122,8 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) /* clearing the previous total delay */ runtime->delay = 0; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; + offset = snd_soc_pcm_component_pointer(substream); - if (!component->driver->ops || - !component->driver->ops->pointer) - continue; - - /* FIXME: use 1st pointer */ - offset = component->driver->ops->pointer(substream); - break; - } /* base delay if assigned in pointer callback */ delay = runtime->delay; -- cgit v1.2.3 From 96a47908d8769479f5217bf3f432ccdc06a29747 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:51:51 +0900 Subject: ASoC: soc-component: add snd_soc_pcm_component_ioctrl() Current ALSA SoC is directly using component->driver->ops->xxx, thus, the code nested deeply, and it makes code difficult to read, and is not good for encapsulation. We want to implement component related function at soc-component.c, but, some of them need to care whole snd_soc_pcm_runtime (= rtd) connected component. Let's call component related function which need to care with for_each_rtdcom() loop as snd_soc_pcm_component_xxx(). This patch adds new snd_soc_pcm_component_ioctrl() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r26d4d0f.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 20 ++++++++++++++++++++ sound/soc/soc-pcm.c | 25 ++----------------------- 3 files changed, 24 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 38b4be1d99f5..5db4e5d028d0 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -372,5 +372,7 @@ int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, const char **dai_name); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); +int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index e2053c8bf1f0..a6c0857a9e90 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -442,3 +442,23 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) return 0; } + +int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component; + struct snd_soc_rtdcom_list *rtdcom; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* FIXME: use 1st ioctl */ + if (component->driver->ops && + component->driver->ops->ioctl) + return component->driver->ops->ioctl(substream, + cmd, arg); + } + + return snd_pcm_lib_ioctl(substream, cmd, arg); +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 020e1d275076..12377b8d41c2 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2453,27 +2453,6 @@ out: return ret; } -static int soc_pcm_ioctl(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->ioctl) - continue; - - /* FIXME: use 1st ioctl */ - return component->driver->ops->ioctl(substream, cmd, arg); - } - - return snd_pcm_lib_ioctl(substream, cmd, arg); -} - static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_pcm_substream *substream = @@ -3013,7 +2992,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.hw_free = dpcm_fe_dai_hw_free; rtd->ops.close = dpcm_fe_dai_close; rtd->ops.pointer = soc_pcm_pointer; - rtd->ops.ioctl = soc_pcm_ioctl; + rtd->ops.ioctl = snd_soc_pcm_component_ioctl; } else { rtd->ops.open = soc_pcm_open; rtd->ops.hw_params = soc_pcm_hw_params; @@ -3022,7 +3001,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.hw_free = soc_pcm_hw_free; rtd->ops.close = soc_pcm_close; rtd->ops.pointer = soc_pcm_pointer; - rtd->ops.ioctl = soc_pcm_ioctl; + rtd->ops.ioctl = snd_soc_pcm_component_ioctl; } for_each_rtdcom(rtd, rtdcom) { -- cgit v1.2.3 From 82d81f5cced36e480b581ae51c595e2deb9f2d56 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:51:56 +0900 Subject: ASoC: soc-component: add snd_soc_pcm_component_copy_user() Current ALSA SoC is directly using component->driver->ops->xxx, thus, the code nested deeply, and it makes code difficult to read, and is not good for encapsulation. We want to implement component related function at soc-component.c, but, some of them need to care whole snd_soc_pcm_runtime (= rtd) connected component. Let's call component related function which need to care with for_each_rtdcom() loop as snd_soc_pcm_component_xxx(). This patch adds new snd_soc_pcm_component_copy_user() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pnlx4d0a.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 3 +++ sound/soc/soc-component.c | 21 +++++++++++++++++++++ sound/soc/soc-pcm.c | 25 +------------------------ 3 files changed, 25 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 5db4e5d028d0..6b95d2467053 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -374,5 +374,8 @@ int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); +int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *buf, unsigned long bytes); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index a6c0857a9e90..20897dce1bec 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -462,3 +462,24 @@ int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, return snd_pcm_lib_ioctl(substream, cmd, arg); } + +int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *buf, unsigned long bytes) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* FIXME. it returns 1st copy now */ + if (component->driver->ops && + component->driver->ops->copy_user) + return component->driver->ops->copy_user( + substream, channel, pos, buf, bytes); + } + + return -EINVAL; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 12377b8d41c2..b0e6ce89b012 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2818,29 +2818,6 @@ static void soc_pcm_private_free(struct snd_pcm *pcm) } } -static int soc_rtdcom_copy_user(struct snd_pcm_substream *substream, int channel, - unsigned long pos, void __user *buf, - unsigned long bytes) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->copy_user) - continue; - - /* FIXME. it returns 1st copy now */ - return component->driver->ops->copy_user(substream, channel, - pos, buf, bytes); - } - - return -EINVAL; -} - static struct page *soc_rtdcom_page(struct snd_pcm_substream *substream, unsigned long offset) { @@ -3011,7 +2988,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) continue; if (ops->copy_user) - rtd->ops.copy_user = soc_rtdcom_copy_user; + rtd->ops.copy_user = snd_soc_pcm_component_copy_user; if (ops->page) rtd->ops.page = soc_rtdcom_page; if (ops->mmap) -- cgit v1.2.3 From 9c712e4f57229081e837d593fc1e4183b068a41c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:52:00 +0900 Subject: ASoC: soc-component: add snd_soc_pcm_component_page() Current ALSA SoC is directly using component->driver->ops->xxx, thus, the code nested deeply, and it makes code difficult to read, and is not good for encapsulation. We want to implement component related function at soc-component.c, but, some of them need to care whole snd_soc_pcm_runtime (= rtd) connected component. Let's call component related function which need to care with for_each_rtdcom() loop as snd_soc_pcm_component_xxx(). This patch adds new snd_soc_pcm_component_page() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o91h4d06.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 23 +++++++++++++++++++++++ sound/soc/soc-pcm.c | 26 +------------------------- 3 files changed, 26 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 6b95d2467053..4cab257962a6 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -377,5 +377,7 @@ int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, int channel, unsigned long pos, void __user *buf, unsigned long bytes); +struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, + unsigned long offset); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 20897dce1bec..d503bc9b0850 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -483,3 +483,26 @@ int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, return -EINVAL; } + +struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + struct page *page; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* FIXME. it returns 1st page now */ + if (component->driver->ops && + component->driver->ops->page) { + page = component->driver->ops->page(substream, offset); + if (page) + return page; + } + } + + return NULL; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index b0e6ce89b012..fe34f2e5d75e 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2818,30 +2818,6 @@ static void soc_pcm_private_free(struct snd_pcm *pcm) } } -static struct page *soc_rtdcom_page(struct snd_pcm_substream *substream, - unsigned long offset) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - struct page *page; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->page) - continue; - - /* FIXME. it returns 1st page now */ - page = component->driver->ops->page(substream, offset); - if (page) - return page; - } - - return NULL; -} - static int soc_rtdcom_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { @@ -2990,7 +2966,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (ops->copy_user) rtd->ops.copy_user = snd_soc_pcm_component_copy_user; if (ops->page) - rtd->ops.page = soc_rtdcom_page; + rtd->ops.page = snd_soc_pcm_component_page; if (ops->mmap) rtd->ops.mmap = soc_rtdcom_mmap; } -- cgit v1.2.3 From 205875e1a12ef9c61e939db9ded90fe3f6352e75 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:52:04 +0900 Subject: ASoC: soc-component: add snd_soc_pcm_component_mmap() Current ALSA SoC is directly using component->driver->ops->xxx, thus, the code nested deeply, and it makes code difficult to read, and is not good for encapsulation. We want to implement component related function at soc-component.c, but, some of them need to care whole snd_soc_pcm_runtime (= rtd) connected component. Let's call component related function which need to care with for_each_rtdcom() loop as snd_soc_pcm_component_xxx(). This patch adds new snd_soc_pcm_component_mmap() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87muh14d02.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 19 +++++++++++++++++++ sound/soc/soc-pcm.c | 23 +---------------------- 3 files changed, 22 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 4cab257962a6..dd1ea5d71998 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -379,5 +379,7 @@ int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, void __user *buf, unsigned long bytes); struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, unsigned long offset); +int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index d503bc9b0850..2aff1b087522 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -506,3 +506,22 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, return NULL; } + +int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* FIXME. it returns 1st mmap now */ + if (component->driver->ops && + component->driver->ops->mmap) + return component->driver->ops->mmap(substream, vma); + } + + return -EINVAL; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index fe34f2e5d75e..7bbee0d71942 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2818,27 +2818,6 @@ static void soc_pcm_private_free(struct snd_pcm *pcm) } } -static int soc_rtdcom_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->mmap) - continue; - - /* FIXME. it returns 1st mmap now */ - return component->driver->ops->mmap(substream, vma); - } - - return -EINVAL; -} - /* create a new pcm */ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) { @@ -2968,7 +2947,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (ops->page) rtd->ops.page = snd_soc_pcm_component_page; if (ops->mmap) - rtd->ops.mmap = soc_rtdcom_mmap; + rtd->ops.mmap = snd_soc_pcm_component_mmap; } if (playback) -- cgit v1.2.3 From 7484291e9b7564af65b2581dcdebeeaf98bc86d0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:52:08 +0900 Subject: ASoC: soc-component: add snd_soc_pcm_component_pcm_new() Current ALSA SoC is directly using component->driver->xxx, thus, the code nested deeply, and it makes code difficult to read, and is not good for encapsulation. We want to implement component related function at soc-component.c, but, some of them need to care whole snd_soc_pcm_runtime (= rtd) connected component. Let's call component related function which need to care with for_each_rtdcom() loop as snd_soc_pcm_component_xxx(). This patch adds new snd_soc_pcm_component_pcm() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lfwl4czy.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 1 + sound/soc/soc-component.c | 20 ++++++++++++++++++++ sound/soc/soc-pcm.c | 18 ++++-------------- 3 files changed, 25 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index dd1ea5d71998..d3048ad06582 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -381,5 +381,6 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, unsigned long offset); int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); +int snd_soc_pcm_component_new(struct snd_pcm *pcm); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 2aff1b087522..ff13d901bbab 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -525,3 +525,23 @@ int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, return -EINVAL; } + +int snd_soc_pcm_component_new(struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + int ret; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (component->driver->pcm_new) { + ret = component->driver->pcm_new(rtd); + if (ret < 0) + return ret; + } + } + + return 0; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 7bbee0d71942..955c49fd3bda 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2823,7 +2823,6 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) { struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_pcm *pcm; char new_name[64]; @@ -2956,19 +2955,10 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (capture) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->pcm_new) - continue; - - ret = component->driver->pcm_new(rtd); - if (ret < 0) { - dev_err(component->dev, - "ASoC: pcm constructor failed: %d\n", - ret); - return ret; - } + ret = snd_soc_pcm_component_new(pcm); + if (ret < 0) { + dev_err(rtd->dev, "ASoC: pcm constructor failed: %d\n", ret); + return ret; } pcm->private_free = soc_pcm_private_free; -- cgit v1.2.3 From 79776da0989733a5bac0a1e635e3a284c3f5c745 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jul 2019 13:52:12 +0900 Subject: ASoC: soc-component: add snd_soc_pcm_component_pcm_free() Current ALSA SoC is directly using component->driver->xxx, thus, the code nested deeply, and it makes code difficult to read, and is not good for encapsulation. We want to implement component related function at soc-component.c, but, some of them need to care whole snd_soc_pcm_runtime (= rtd) connected component. Let's call component related function which need to care with for_each_rtdcom() loop as snd_soc_pcm_component_xxx(). This patch adds new snd_soc_pcm_component_pcm_free() and use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k1c54czu.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 1 + sound/soc/soc-component.c | 14 ++++++++++++++ sound/soc/soc-pcm.c | 9 +-------- 3 files changed, 16 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index d3048ad06582..5d80b2eef525 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -382,5 +382,6 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); int snd_soc_pcm_component_new(struct snd_pcm *pcm); +void snd_soc_pcm_component_free(struct snd_pcm *pcm); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index ff13d901bbab..79ffc2820ba9 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -545,3 +545,17 @@ int snd_soc_pcm_component_new(struct snd_pcm *pcm) return 0; } + +void snd_soc_pcm_component_free(struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (component->driver->pcm_free) + component->driver->pcm_free(pcm); + } +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 955c49fd3bda..77c986fe08d0 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2805,17 +2805,10 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) static void soc_pcm_private_free(struct snd_pcm *pcm) { struct snd_soc_pcm_runtime *rtd = pcm->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; /* need to sync the delayed work before releasing resources */ flush_delayed_work(&rtd->delayed_work); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (component->driver->pcm_free) - component->driver->pcm_free(pcm); - } + snd_soc_pcm_component_free(pcm); } /* create a new pcm */ -- cgit v1.2.3 From 3ec3d7a3ff10692d4f8a2baa0ff18fe10a9b6ad4 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:20 +0900 Subject: ALSA: firewire-lib: add AMDTP domain structure to handle several isoc contexts This commit adds 'struct amdtp_domain' structure. This structure has list of instance of AMDTP stream to handle a couple of isochronous contexts. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 22 ++++++++++++++++++++++ sound/firewire/amdtp-stream.h | 7 +++++++ 2 files changed, 29 insertions(+) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 369e75e33120..02077696fa77 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1136,3 +1136,25 @@ void amdtp_stream_pcm_abort(struct amdtp_stream *s) snd_pcm_stop_xrun(pcm); } EXPORT_SYMBOL(amdtp_stream_pcm_abort); + +/** + * amdtp_domain_init - initialize an AMDTP domain structure + * @d: the AMDTP domain to initialize. + */ +int amdtp_domain_init(struct amdtp_domain *d) +{ + INIT_LIST_HEAD(&d->streams); + + return 0; +} +EXPORT_SYMBOL_GPL(amdtp_domain_init); + +/** + * amdtp_domain_destroy - destroy an AMDTP domain structure + * @d: the AMDTP domain to destroy. + */ +void amdtp_domain_destroy(struct amdtp_domain *d) +{ + WARN_ON(!list_empty(&d->streams)); +} +EXPORT_SYMBOL_GPL(amdtp_domain_destroy); diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 50041fa884d9..2378db4b4195 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -267,4 +267,11 @@ static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s, msecs_to_jiffies(timeout)) > 0; } +struct amdtp_domain { + struct list_head streams; +}; + +int amdtp_domain_init(struct amdtp_domain *d); +void amdtp_domain_destroy(struct amdtp_domain *d); + #endif -- cgit v1.2.3 From 6261f90bdb0b605ffb158717ec7a03b1753aded5 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:21 +0900 Subject: ALSA: firewire-lib: add a kernel API to stop a couple of AMDTP streams in AMDTP domain This commit adds a kernel API to stop a couple of isochronous contexts for AMDTP streams. The API is not protected with any lock primitive. Callers should use this with enough lock against concurrent access. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 16 ++++++++++++++++ sound/firewire/amdtp-stream.h | 5 +++++ 2 files changed, 21 insertions(+) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 02077696fa77..31fc90f76443 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1158,3 +1158,19 @@ void amdtp_domain_destroy(struct amdtp_domain *d) WARN_ON(!list_empty(&d->streams)); } EXPORT_SYMBOL_GPL(amdtp_domain_destroy); + +/** + * amdtp_domain_stop - stop sending packets for isoc context in the same domain. + * @d: the AMDTP domain to which the isoc contexts belong. + */ +void amdtp_domain_stop(struct amdtp_domain *d) +{ + struct amdtp_stream *s, *next; + + list_for_each_entry_safe(s, next, &d->streams, list) { + list_del(&s->list); + + amdtp_stream_stop(s); + } +} +EXPORT_SYMBOL_GPL(amdtp_domain_stop); diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 2378db4b4195..ab2a69180240 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -170,6 +170,9 @@ struct amdtp_stream { /* For backends to process data blocks. */ void *protocol; amdtp_stream_process_ctx_payloads_t process_ctx_payloads; + + // For domain. + struct list_head list; }; int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, @@ -274,4 +277,6 @@ struct amdtp_domain { int amdtp_domain_init(struct amdtp_domain *d); void amdtp_domain_destroy(struct amdtp_domain *d); +void amdtp_domain_stop(struct amdtp_domain *d); + #endif -- cgit v1.2.3 From 157a53eef6a016e6938d9fd266b85221fcd4eaa3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:22 +0900 Subject: ALSA: firewire-lib: add a kernel API to add AMDTP stream into AMDTP domain This commit adds a kernel API to insert AMDTP stream to list in AMDTP domain. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 26 ++++++++++++++++++++++++++ sound/firewire/amdtp-stream.h | 5 +++++ 2 files changed, 31 insertions(+) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 31fc90f76443..fa7989ee4769 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1159,6 +1159,32 @@ void amdtp_domain_destroy(struct amdtp_domain *d) } EXPORT_SYMBOL_GPL(amdtp_domain_destroy); +/** + * amdtp_domain_add_stream - register isoc context into the domain. + * @d: the AMDTP domain. + * @s: the AMDTP stream. + * @channel: the isochronous channel on the bus. + * @speed: firewire speed code. + */ +int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, + int channel, int speed) +{ + struct amdtp_stream *tmp; + + list_for_each_entry(tmp, &d->streams, list) { + if (s == tmp) + return -EBUSY; + } + + list_add(&s->list, &d->streams); + + s->channel = channel; + s->speed = speed; + + return 0; +} +EXPORT_SYMBOL_GPL(amdtp_domain_add_stream); + /** * amdtp_domain_stop - stop sending packets for isoc context in the same domain. * @d: the AMDTP domain to which the isoc contexts belong. diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index ab2a69180240..4b102fd7529d 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -172,6 +172,8 @@ struct amdtp_stream { amdtp_stream_process_ctx_payloads_t process_ctx_payloads; // For domain. + int channel; + int speed; struct list_head list; }; @@ -277,6 +279,9 @@ struct amdtp_domain { int amdtp_domain_init(struct amdtp_domain *d); void amdtp_domain_destroy(struct amdtp_domain *d); +int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, + int channel, int speed); + void amdtp_domain_stop(struct amdtp_domain *d); #endif -- cgit v1.2.3 From 9b4702b06c0e25abc612e6f02f3e25a51c684a01 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:23 +0900 Subject: ALSA: firewire-lib: add a kernel API to start AMDTP streams in AMDTP domain This commit adds a kernel API to start a couple of isochronous contexts for some AMDTP streams. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 24 ++++++++++++++++++++++++ sound/firewire/amdtp-stream.h | 1 + 2 files changed, 25 insertions(+) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index fa7989ee4769..158d210caea7 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1185,6 +1185,30 @@ int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, } EXPORT_SYMBOL_GPL(amdtp_domain_add_stream); +/** + * amdtp_domain_start - start sending packets for isoc context in the domain. + * @d: the AMDTP domain. + */ +int amdtp_domain_start(struct amdtp_domain *d) +{ + struct amdtp_stream *s; + int err = 0; + + list_for_each_entry(s, &d->streams, list) { + err = amdtp_stream_start(s, s->channel, s->speed); + if (err < 0) + break; + } + + if (err < 0) { + list_for_each_entry(s, &d->streams, list) + amdtp_stream_stop(s); + } + + return err; +} +EXPORT_SYMBOL_GPL(amdtp_domain_start); + /** * amdtp_domain_stop - stop sending packets for isoc context in the same domain. * @d: the AMDTP domain to which the isoc contexts belong. diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 4b102fd7529d..15d471660a43 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -282,6 +282,7 @@ void amdtp_domain_destroy(struct amdtp_domain *d); int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, int channel, int speed); +int amdtp_domain_start(struct amdtp_domain *d); void amdtp_domain_stop(struct amdtp_domain *d); #endif -- cgit v1.2.3 From 94491c175d6bf4b838043a3fb5adabd731d8fbab Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:24 +0900 Subject: ALSA: fireworks: code refactoring for initialization/destruction of AMDTP streams This commit is a preparation to support AMDTP domain. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireworks/fireworks_stream.c | 77 ++++++++++++++--------------- 1 file changed, 36 insertions(+), 41 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 385fc9686365..0f62c50055e9 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -8,8 +8,7 @@ #define CALLBACK_TIMEOUT 100 -static int -init_stream(struct snd_efw *efw, struct amdtp_stream *stream) +static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream) { struct cmp_connection *conn; enum cmp_direction c_dir; @@ -28,14 +27,37 @@ init_stream(struct snd_efw *efw, struct amdtp_stream *stream) err = cmp_connection_init(conn, efw->unit, c_dir, 0); if (err < 0) - goto end; + return err; err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING); if (err < 0) { amdtp_stream_destroy(stream); cmp_connection_destroy(conn); + return err; } -end: + + if (stream == &efw->tx_stream) { + // Fireworks transmits NODATA packets with TAG0. + efw->tx_stream.flags |= CIP_EMPTY_WITH_TAG0; + // Fireworks has its own meaning for dbc. + efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT; + // Fireworks reset dbc at bus reset. + efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK; + // But Recent firmwares starts packets with non-zero dbc. + // Driver version 5.7.6 installs firmware version 5.7.3. + if (efw->is_fireworks3 && + (efw->firmware_version == 0x5070000 || + efw->firmware_version == 0x5070300 || + efw->firmware_version == 0x5080000)) + efw->tx_stream.flags |= CIP_UNALIGHED_DBC; + // AudioFire9 always reports wrong dbs. + if (efw->is_af9) + efw->tx_stream.flags |= CIP_WRONG_DBS; + // Firmware version 5.5 reports fixed interval for dbc. + if (efw->firmware_version == 0x5050000) + efw->tx_stream.ctx_data.tx.dbc_interval = 8; + } + return err; } @@ -83,22 +105,16 @@ static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream, return 0; } -/* - * This function should be called before starting the stream or after stopping - * the streams. - */ -static void -destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream) +// This function should be called before starting the stream or after stopping +// the streams. +static void destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream) { - struct cmp_connection *conn; + amdtp_stream_destroy(stream); if (stream == &efw->tx_stream) - conn = &efw->out_conn; + cmp_connection_destroy(&efw->out_conn); else - conn = &efw->in_conn; - - amdtp_stream_destroy(stream); - cmp_connection_destroy(conn); + cmp_connection_destroy(&efw->in_conn); } static int @@ -131,42 +147,21 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw) err = init_stream(efw, &efw->tx_stream); if (err < 0) - goto end; - /* Fireworks transmits NODATA packets with TAG0. */ - efw->tx_stream.flags |= CIP_EMPTY_WITH_TAG0; - /* Fireworks has its own meaning for dbc. */ - efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT; - /* Fireworks reset dbc at bus reset. */ - efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK; - /* - * But Recent firmwares starts packets with non-zero dbc. - * Driver version 5.7.6 installs firmware version 5.7.3. - */ - if (efw->is_fireworks3 && - (efw->firmware_version == 0x5070000 || - efw->firmware_version == 0x5070300 || - efw->firmware_version == 0x5080000)) - efw->tx_stream.flags |= CIP_UNALIGHED_DBC; - /* AudioFire9 always reports wrong dbs. */ - if (efw->is_af9) - efw->tx_stream.flags |= CIP_WRONG_DBS; - /* Firmware version 5.5 reports fixed interval for dbc. */ - if (efw->firmware_version == 0x5050000) - efw->tx_stream.ctx_data.tx.dbc_interval = 8; + return err; err = init_stream(efw, &efw->rx_stream); if (err < 0) { destroy_stream(efw, &efw->tx_stream); - goto end; + return err; } - /* set IEC61883 compliant mode (actually not fully compliant...) */ + // set IEC61883 compliant mode (actually not fully compliant...). err = snd_efw_command_set_tx_mode(efw, SND_EFW_TRANSPORT_MODE_IEC61883); if (err < 0) { destroy_stream(efw, &efw->tx_stream); destroy_stream(efw, &efw->rx_stream); } -end: + return err; } -- cgit v1.2.3 From 7eb7b18e9fc7c8dc3d3c186ec6b0cfa9147299f8 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:25 +0900 Subject: ALSA: fireworks: code refactoring for bus reset handler This commit is a preparation to support AMDTP domain. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireworks/fireworks_stream.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 0f62c50055e9..af340491dc43 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -299,14 +299,11 @@ void snd_efw_stream_stop_duplex(struct snd_efw *efw) void snd_efw_stream_update_duplex(struct snd_efw *efw) { - if (cmp_connection_update(&efw->out_conn) < 0 || - cmp_connection_update(&efw->in_conn) < 0) { - stop_stream(efw, &efw->rx_stream); - stop_stream(efw, &efw->tx_stream); - } else { - amdtp_stream_update(&efw->rx_stream); - amdtp_stream_update(&efw->tx_stream); - } + stop_stream(efw, &efw->rx_stream); + stop_stream(efw, &efw->tx_stream); + + amdtp_stream_pcm_abort(&efw->rx_stream); + amdtp_stream_pcm_abort(&efw->tx_stream); } void snd_efw_stream_destroy_duplex(struct snd_efw *efw) -- cgit v1.2.3 From d79360ebe9c8668caf0e3932216f236fffbfa1b6 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:26 +0900 Subject: ALSA: firewire-digi00x: code refactoring for initialization/destruction of AMDTP stream This commit is a preparation to support AMDTP domain. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/digi00x/digi00x-stream.c | 65 +++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index 3e77dbd3ee22..cff193f00a97 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -218,43 +218,62 @@ static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream, fw_parent_device(dg00x->unit)->max_speed); } -int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x) +static int init_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s) { + struct fw_iso_resources *resources; + enum amdtp_stream_direction dir; int err; - /* For out-stream. */ - err = fw_iso_resources_init(&dg00x->rx_resources, dg00x->unit); + if (s == &dg00x->tx_stream) { + resources = &dg00x->tx_resources; + dir = AMDTP_IN_STREAM; + } else { + resources = &dg00x->rx_resources; + dir = AMDTP_OUT_STREAM; + } + + err = fw_iso_resources_init(resources, dg00x->unit); if (err < 0) - goto error; - err = amdtp_dot_init(&dg00x->rx_stream, dg00x->unit, AMDTP_OUT_STREAM); + return err; + + err = amdtp_dot_init(s, dg00x->unit, dir); if (err < 0) - goto error; + fw_iso_resources_destroy(resources); + + return err; +} - /* For in-stream. */ - err = fw_iso_resources_init(&dg00x->tx_resources, dg00x->unit); +static void destroy_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s) +{ + amdtp_stream_destroy(s); + + if (s == &dg00x->tx_stream) + fw_iso_resources_destroy(&dg00x->tx_resources); + else + fw_iso_resources_destroy(&dg00x->rx_resources); +} + +int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x) +{ + int err; + + err = init_stream(dg00x, &dg00x->rx_stream); if (err < 0) - goto error; - err = amdtp_dot_init(&dg00x->tx_stream, dg00x->unit, AMDTP_IN_STREAM); + return err; + + err = init_stream(dg00x, &dg00x->tx_stream); if (err < 0) - goto error; + destroy_stream(dg00x, &dg00x->rx_stream); - return 0; -error: - snd_dg00x_stream_destroy_duplex(dg00x); return err; } -/* - * This function should be called before starting streams or after stopping - * streams. - */ +// This function should be called before starting streams or after stopping +// streams. void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x) { - amdtp_stream_destroy(&dg00x->rx_stream); - fw_iso_resources_destroy(&dg00x->rx_resources); - - amdtp_stream_destroy(&dg00x->tx_stream); - fw_iso_resources_destroy(&dg00x->tx_resources); + destroy_stream(dg00x, &dg00x->rx_stream); + destroy_stream(dg00x, &dg00x->tx_stream); } int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate) -- cgit v1.2.3 From 5f9625a5ba5dcf1815f123fced65f289b558aca4 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:27 +0900 Subject: ALSA: firewire-tascam: code refactoring for initialization/destruction of AMDTP stream This commit is a preparation to support AMDTP domain. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/tascam/tascam-stream.c | 71 ++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index e852e46ebe6f..d5e77036e0ee 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -287,38 +287,60 @@ static int keep_resources(struct snd_tscm *tscm, unsigned int rate, fw_parent_device(tscm->unit)->max_speed); } -int snd_tscm_stream_init_duplex(struct snd_tscm *tscm) +static int init_stream(struct snd_tscm *tscm, struct amdtp_stream *s) { + struct fw_iso_resources *resources; + enum amdtp_stream_direction dir; unsigned int pcm_channels; int err; - /* For out-stream. */ - err = fw_iso_resources_init(&tscm->rx_resources, tscm->unit); - if (err < 0) - return err; - pcm_channels = tscm->spec->pcm_playback_analog_channels; + if (s == &tscm->tx_stream) { + resources = &tscm->tx_resources; + dir = AMDTP_IN_STREAM; + pcm_channels = tscm->spec->pcm_capture_analog_channels; + } else { + resources = &tscm->rx_resources; + dir = AMDTP_OUT_STREAM; + pcm_channels = tscm->spec->pcm_playback_analog_channels; + } + if (tscm->spec->has_adat) pcm_channels += 8; if (tscm->spec->has_spdif) pcm_channels += 2; - err = amdtp_tscm_init(&tscm->rx_stream, tscm->unit, AMDTP_OUT_STREAM, - pcm_channels); + + err = fw_iso_resources_init(resources, tscm->unit); if (err < 0) return err; - /* For in-stream. */ - err = fw_iso_resources_init(&tscm->tx_resources, tscm->unit); + err = amdtp_tscm_init(s, tscm->unit, dir, pcm_channels); + if (err < 0) + fw_iso_resources_free(resources); + + return err; +} + +static void destroy_stream(struct snd_tscm *tscm, struct amdtp_stream *s) +{ + amdtp_stream_destroy(s); + + if (s == &tscm->tx_stream) + fw_iso_resources_destroy(&tscm->tx_resources); + else + fw_iso_resources_destroy(&tscm->rx_resources); +} + +int snd_tscm_stream_init_duplex(struct snd_tscm *tscm) +{ + int err; + + err = init_stream(tscm, &tscm->tx_stream); if (err < 0) return err; - pcm_channels = tscm->spec->pcm_capture_analog_channels; - if (tscm->spec->has_adat) - pcm_channels += 8; - if (tscm->spec->has_spdif) - pcm_channels += 2; - err = amdtp_tscm_init(&tscm->tx_stream, tscm->unit, AMDTP_IN_STREAM, - pcm_channels); + + err = init_stream(tscm, &tscm->rx_stream); if (err < 0) - amdtp_stream_destroy(&tscm->rx_stream); + destroy_stream(tscm, &tscm->tx_stream); return err; } @@ -333,17 +355,12 @@ void snd_tscm_stream_update_duplex(struct snd_tscm *tscm) amdtp_stream_stop(&tscm->rx_stream); } -/* - * This function should be called before starting streams or after stopping - * streams. - */ +// This function should be called before starting streams or after stopping +// streams. void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm) { - amdtp_stream_destroy(&tscm->rx_stream); - amdtp_stream_destroy(&tscm->tx_stream); - - fw_iso_resources_destroy(&tscm->rx_resources); - fw_iso_resources_destroy(&tscm->tx_resources); + destroy_stream(tscm, &tscm->rx_stream); + destroy_stream(tscm, &tscm->tx_stream); } int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate) -- cgit v1.2.3 From 39e522a5a45fe805a2925aaddc30a4b2c6ded642 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:28 +0900 Subject: ALSA: firewire-motu: code refactoring for initialization/destruction of AMDTP stream This commit is a preparation to support AMDTP domain. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu-stream.c | 48 ++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index 2bbb335e8de1..cc9f34426a47 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -300,62 +300,52 @@ void snd_motu_stream_stop_duplex(struct snd_motu *motu) } } -static int init_stream(struct snd_motu *motu, enum amdtp_stream_direction dir) +static int init_stream(struct snd_motu *motu, struct amdtp_stream *s) { - int err; - struct amdtp_stream *stream; struct fw_iso_resources *resources; + enum amdtp_stream_direction dir; + int err; - if (dir == AMDTP_IN_STREAM) { - stream = &motu->tx_stream; + if (s == &motu->tx_stream) { resources = &motu->tx_resources; + dir = AMDTP_IN_STREAM; } else { - stream = &motu->rx_stream; resources = &motu->rx_resources; + dir = AMDTP_OUT_STREAM; } err = fw_iso_resources_init(resources, motu->unit); if (err < 0) return err; - err = amdtp_motu_init(stream, motu->unit, dir, motu->spec->protocol); - if (err < 0) { - amdtp_stream_destroy(stream); + err = amdtp_motu_init(s, motu->unit, dir, motu->spec->protocol); + if (err < 0) fw_iso_resources_destroy(resources); - } return err; } -static void destroy_stream(struct snd_motu *motu, - enum amdtp_stream_direction dir) +static void destroy_stream(struct snd_motu *motu, struct amdtp_stream *s) { - struct amdtp_stream *stream; - struct fw_iso_resources *resources; + amdtp_stream_destroy(s); - if (dir == AMDTP_IN_STREAM) { - stream = &motu->tx_stream; - resources = &motu->tx_resources; - } else { - stream = &motu->rx_stream; - resources = &motu->rx_resources; - } - - amdtp_stream_destroy(stream); - fw_iso_resources_destroy(resources); + if (s == &motu->tx_stream) + fw_iso_resources_destroy(&motu->tx_resources); + else + fw_iso_resources_destroy(&motu->rx_resources); } int snd_motu_stream_init_duplex(struct snd_motu *motu) { int err; - err = init_stream(motu, AMDTP_IN_STREAM); + err = init_stream(motu, &motu->tx_stream); if (err < 0) return err; - err = init_stream(motu, AMDTP_OUT_STREAM); + err = init_stream(motu, &motu->rx_stream); if (err < 0) - destroy_stream(motu, AMDTP_IN_STREAM); + destroy_stream(motu, &motu->tx_stream); return err; } @@ -366,8 +356,8 @@ int snd_motu_stream_init_duplex(struct snd_motu *motu) */ void snd_motu_stream_destroy_duplex(struct snd_motu *motu) { - destroy_stream(motu, AMDTP_IN_STREAM); - destroy_stream(motu, AMDTP_OUT_STREAM); + destroy_stream(motu, &motu->rx_stream); + destroy_stream(motu, &motu->tx_stream); motu->substreams_counter = 0; } -- cgit v1.2.3 From 42355abb9c33503f7b5889d71e1432fabdf2fd7f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:29 +0900 Subject: ALSA: fireface: code refactoring for initialization/destruction of AMDTP stream This commit is a preparation to support AMDTP domain. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-stream.c | 39 ++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index 4208b8004d1a..e4710204f481 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -39,54 +39,53 @@ static inline void finish_session(struct snd_ff *ff) ff->spec->protocol->switch_fetching_mode(ff, false); } -static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir) +static int init_stream(struct snd_ff *ff, struct amdtp_stream *s) { - int err; struct fw_iso_resources *resources; - struct amdtp_stream *stream; + enum amdtp_stream_direction dir; + int err; - if (dir == AMDTP_IN_STREAM) { + if (s == &ff->tx_stream) { resources = &ff->tx_resources; - stream = &ff->tx_stream; + dir = AMDTP_IN_STREAM; } else { resources = &ff->rx_resources; - stream = &ff->rx_stream; + dir = AMDTP_OUT_STREAM; } err = fw_iso_resources_init(resources, ff->unit); if (err < 0) return err; - err = amdtp_ff_init(stream, ff->unit, dir); + err = amdtp_ff_init(s, ff->unit, dir); if (err < 0) fw_iso_resources_destroy(resources); return err; } -static void destroy_stream(struct snd_ff *ff, enum amdtp_stream_direction dir) +static void destroy_stream(struct snd_ff *ff, struct amdtp_stream *s) { - if (dir == AMDTP_IN_STREAM) { - amdtp_stream_destroy(&ff->tx_stream); + amdtp_stream_destroy(s); + + if (s == &ff->tx_stream) fw_iso_resources_destroy(&ff->tx_resources); - } else { - amdtp_stream_destroy(&ff->rx_stream); + else fw_iso_resources_destroy(&ff->rx_resources); - } } int snd_ff_stream_init_duplex(struct snd_ff *ff) { int err; - err = init_stream(ff, AMDTP_OUT_STREAM); + err = init_stream(ff, &ff->rx_stream); if (err < 0) - goto end; + return err; - err = init_stream(ff, AMDTP_IN_STREAM); + err = init_stream(ff, &ff->tx_stream); if (err < 0) - destroy_stream(ff, AMDTP_OUT_STREAM); -end: + destroy_stream(ff, &ff->rx_stream); + return err; } @@ -96,8 +95,8 @@ end: */ void snd_ff_stream_destroy_duplex(struct snd_ff *ff) { - destroy_stream(ff, AMDTP_IN_STREAM); - destroy_stream(ff, AMDTP_OUT_STREAM); + destroy_stream(ff, &ff->rx_stream); + destroy_stream(ff, &ff->tx_stream); } int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate) -- cgit v1.2.3 From b0db4d512941455894e7a13f71594b7d4638b94b Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:30 +0900 Subject: ALSA: bebob: support AMDTP domain This commit adds AMDTP domain support for ALSA bebob driver. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.h | 2 ++ sound/firewire/bebob/bebob_stream.c | 62 ++++++++++++++++--------------------- 2 files changed, 29 insertions(+), 35 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index 9e0b689fe34a..356d6ba60959 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -115,6 +115,8 @@ struct snd_bebob { /* For BeBoB version quirk. */ unsigned int version; + + struct amdtp_domain domain; }; static inline int diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 334dc7c96e1d..73fee991bd75 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -445,10 +445,9 @@ start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) goto end; } - /* start amdtp stream */ - err = amdtp_stream_start(stream, - conn->resources.channel, - conn->speed); + // start amdtp stream. + err = amdtp_domain_add_stream(&bebob->domain, stream, + conn->resources.channel, conn->speed); end: return err; } @@ -523,7 +522,13 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob) return err; } - return 0; + err = amdtp_domain_init(&bebob->domain); + if (err < 0) { + destroy_stream(bebob, &bebob->tx_stream); + destroy_stream(bebob, &bebob->rx_stream); + } + + return err; } static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream, @@ -566,9 +571,7 @@ int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate) if (rate == 0) rate = curr_rate; if (curr_rate != rate) { - amdtp_stream_stop(&bebob->tx_stream); - amdtp_stream_stop(&bebob->rx_stream); - + amdtp_domain_stop(&bebob->domain); break_both_connections(bebob); cmp_connection_release(&bebob->out_conn); @@ -620,9 +623,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) // packet queueing error or detecting discontinuity if (amdtp_streaming_error(&bebob->rx_stream) || amdtp_streaming_error(&bebob->tx_stream)) { - amdtp_stream_stop(&bebob->rx_stream); - amdtp_stream_stop(&bebob->tx_stream); - + amdtp_domain_stop(&bebob->domain); break_both_connections(bebob); } @@ -640,11 +641,16 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) return err; err = start_stream(bebob, &bebob->rx_stream); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to run AMDTP master stream:%d\n", err); + if (err < 0) + goto error; + + err = start_stream(bebob, &bebob->tx_stream); + if (err < 0) + goto error; + + err = amdtp_domain_start(&bebob->domain); + if (err < 0) goto error; - } // NOTE: // The firmware customized by M-Audio uses these commands to @@ -660,21 +666,8 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) } if (!amdtp_stream_wait_callback(&bebob->rx_stream, - CALLBACK_TIMEOUT)) { - err = -ETIMEDOUT; - goto error; - } - } - - if (!amdtp_stream_running(&bebob->tx_stream)) { - err = start_stream(bebob, &bebob->tx_stream); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to run AMDTP slave stream:%d\n", err); - goto error; - } - - if (!amdtp_stream_wait_callback(&bebob->tx_stream, + CALLBACK_TIMEOUT) || + !amdtp_stream_wait_callback(&bebob->tx_stream, CALLBACK_TIMEOUT)) { err = -ETIMEDOUT; goto error; @@ -683,8 +676,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) return 0; error: - amdtp_stream_stop(&bebob->tx_stream); - amdtp_stream_stop(&bebob->rx_stream); + amdtp_domain_stop(&bebob->domain); break_both_connections(bebob); return err; } @@ -692,9 +684,7 @@ error: void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob) { if (bebob->substreams_counter == 0) { - amdtp_stream_stop(&bebob->rx_stream); - amdtp_stream_stop(&bebob->tx_stream); - + amdtp_domain_stop(&bebob->domain); break_both_connections(bebob); cmp_connection_release(&bebob->out_conn); @@ -708,6 +698,8 @@ void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob) */ void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob) { + amdtp_domain_destroy(&bebob->domain); + destroy_stream(bebob, &bebob->tx_stream); destroy_stream(bebob, &bebob->rx_stream); } -- cgit v1.2.3 From db40eeb2469fef4efe26789ea2596372ee43ae2f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:31 +0900 Subject: ALSA: fireworks: support AMDTP domain This commit adds AMDTP domain support for ALSA fireworks driver. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireworks/fireworks.h | 2 + sound/firewire/fireworks/fireworks_stream.c | 92 +++++++++++++++-------------- 2 files changed, 51 insertions(+), 43 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 31efd4b53b4f..4cda297f8438 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -107,6 +107,8 @@ struct snd_efw { u8 *resp_buf; u8 *pull_ptr; u8 *push_ptr; + + struct amdtp_domain domain; }; int snd_efw_transaction_cmd(struct fw_unit *unit, diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index af340491dc43..f2de304d2f26 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -61,17 +61,6 @@ static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream) return err; } -static void -stop_stream(struct snd_efw *efw, struct amdtp_stream *stream) -{ - amdtp_stream_stop(stream); - - if (stream == &efw->tx_stream) - cmp_connection_break(&efw->out_conn); - else - cmp_connection_break(&efw->in_conn); -} - static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream, unsigned int rate) { @@ -89,19 +78,13 @@ static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream, return err; // Start amdtp stream. - err = amdtp_stream_start(stream, conn->resources.channel, conn->speed); + err = amdtp_domain_add_stream(&efw->domain, stream, + conn->resources.channel, conn->speed); if (err < 0) { cmp_connection_break(conn); return err; } - // Wait first callback. - if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) { - amdtp_stream_stop(stream); - cmp_connection_break(conn); - return -ETIMEDOUT; - } - return 0; } @@ -155,6 +138,13 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw) return err; } + err = amdtp_domain_init(&efw->domain); + if (err < 0) { + destroy_stream(efw, &efw->tx_stream); + destroy_stream(efw, &efw->rx_stream); + return err; + } + // set IEC61883 compliant mode (actually not fully compliant...). err = snd_efw_command_set_tx_mode(efw, SND_EFW_TRANSPORT_MODE_IEC61883); if (err < 0) { @@ -209,8 +199,10 @@ int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate) if (rate == 0) rate = curr_rate; if (rate != curr_rate) { - stop_stream(efw, &efw->tx_stream); - stop_stream(efw, &efw->rx_stream); + amdtp_domain_stop(&efw->domain); + + cmp_connection_break(&efw->out_conn); + cmp_connection_break(&efw->in_conn); cmp_connection_release(&efw->out_conn); cmp_connection_release(&efw->in_conn); @@ -250,47 +242,57 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw) if (efw->substreams_counter == 0) return -EIO; - err = snd_efw_command_get_sampling_rate(efw, &rate); - if (err < 0) - return err; - if (amdtp_streaming_error(&efw->rx_stream) || amdtp_streaming_error(&efw->tx_stream)) { - stop_stream(efw, &efw->rx_stream); - stop_stream(efw, &efw->tx_stream); + amdtp_domain_stop(&efw->domain); + cmp_connection_break(&efw->out_conn); + cmp_connection_break(&efw->in_conn); } - /* master should be always running */ + err = snd_efw_command_get_sampling_rate(efw, &rate); + if (err < 0) + return err; + if (!amdtp_stream_running(&efw->rx_stream)) { err = start_stream(efw, &efw->rx_stream, rate); - if (err < 0) { - dev_err(&efw->unit->device, - "fail to start AMDTP master stream:%d\n", err); + if (err < 0) goto error; - } - } - if (!amdtp_stream_running(&efw->tx_stream)) { err = start_stream(efw, &efw->tx_stream, rate); - if (err < 0) { - dev_err(&efw->unit->device, - "fail to start AMDTP slave stream:%d\n", err); + if (err < 0) + goto error; + + err = amdtp_domain_start(&efw->domain); + if (err < 0) + goto error; + + // Wait first callback. + if (!amdtp_stream_wait_callback(&efw->rx_stream, + CALLBACK_TIMEOUT) || + !amdtp_stream_wait_callback(&efw->tx_stream, + CALLBACK_TIMEOUT)) { + err = -ETIMEDOUT; goto error; } } return 0; error: - stop_stream(efw, &efw->rx_stream); - stop_stream(efw, &efw->tx_stream); + amdtp_domain_stop(&efw->domain); + + cmp_connection_break(&efw->out_conn); + cmp_connection_break(&efw->in_conn); + return err; } void snd_efw_stream_stop_duplex(struct snd_efw *efw) { if (efw->substreams_counter == 0) { - stop_stream(efw, &efw->tx_stream); - stop_stream(efw, &efw->rx_stream); + amdtp_domain_stop(&efw->domain); + + cmp_connection_break(&efw->out_conn); + cmp_connection_break(&efw->in_conn); cmp_connection_release(&efw->out_conn); cmp_connection_release(&efw->in_conn); @@ -299,8 +301,10 @@ void snd_efw_stream_stop_duplex(struct snd_efw *efw) void snd_efw_stream_update_duplex(struct snd_efw *efw) { - stop_stream(efw, &efw->rx_stream); - stop_stream(efw, &efw->tx_stream); + amdtp_domain_stop(&efw->domain); + + cmp_connection_break(&efw->out_conn); + cmp_connection_break(&efw->in_conn); amdtp_stream_pcm_abort(&efw->rx_stream); amdtp_stream_pcm_abort(&efw->tx_stream); @@ -308,6 +312,8 @@ void snd_efw_stream_update_duplex(struct snd_efw *efw) void snd_efw_stream_destroy_duplex(struct snd_efw *efw) { + amdtp_domain_destroy(&efw->domain); + destroy_stream(efw, &efw->rx_stream); destroy_stream(efw, &efw->tx_stream); } -- cgit v1.2.3 From ac5d77864cfcb0f034221c2b3dac828ae24c722e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:32 +0900 Subject: ALSA: oxfw: support AMDTP domain This commit adds AMDTP domain support for ALSA oxfw driver. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-stream.c | 72 +++++++++++++++++++++++---------------- sound/firewire/oxfw/oxfw.h | 2 ++ 2 files changed, 45 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 74c972d25c66..0318dc4dcc55 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -114,19 +114,13 @@ static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) if (err < 0) return err; - err = amdtp_stream_start(stream, conn->resources.channel, conn->speed); + err = amdtp_domain_add_stream(&oxfw->domain, stream, + conn->resources.channel, conn->speed); if (err < 0) { cmp_connection_break(conn); return err; } - // Wait first packet. - if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) { - amdtp_stream_stop(stream); - cmp_connection_break(conn); - return -ETIMEDOUT; - } - return 0; } @@ -280,12 +274,12 @@ int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, pcm_channels = formation.pcm; } if (formation.rate != rate || formation.pcm != pcm_channels) { - amdtp_stream_stop(&oxfw->rx_stream); + amdtp_domain_stop(&oxfw->domain); + cmp_connection_break(&oxfw->in_conn); cmp_connection_release(&oxfw->in_conn); if (oxfw->has_output) { - amdtp_stream_stop(&oxfw->tx_stream); cmp_connection_break(&oxfw->out_conn); cmp_connection_release(&oxfw->out_conn); } @@ -325,55 +319,66 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw) if (amdtp_streaming_error(&oxfw->rx_stream) || amdtp_streaming_error(&oxfw->tx_stream)) { - amdtp_stream_stop(&oxfw->rx_stream); - cmp_connection_break(&oxfw->in_conn); + amdtp_domain_stop(&oxfw->domain); - if (oxfw->has_output) { - amdtp_stream_stop(&oxfw->tx_stream); + cmp_connection_break(&oxfw->in_conn); + if (oxfw->has_output) cmp_connection_break(&oxfw->out_conn); - } } if (!amdtp_stream_running(&oxfw->rx_stream)) { err = start_stream(oxfw, &oxfw->rx_stream); if (err < 0) { dev_err(&oxfw->unit->device, - "fail to start rx stream: %d\n", err); + "fail to prepare rx stream: %d\n", err); goto error; } - } - if (oxfw->has_output) { - if (!amdtp_stream_running(&oxfw->tx_stream)) { + if (oxfw->has_output && + !amdtp_stream_running(&oxfw->tx_stream)) { err = start_stream(oxfw, &oxfw->tx_stream); if (err < 0) { dev_err(&oxfw->unit->device, - "fail to start tx stream: %d\n", err); + "fail to prepare tx stream: %d\n", err); goto error; } } + + err = amdtp_domain_start(&oxfw->domain); + if (err < 0) + goto error; + + // Wait first packet. + if (!amdtp_stream_wait_callback(&oxfw->rx_stream, + CALLBACK_TIMEOUT) || + !amdtp_stream_wait_callback(&oxfw->tx_stream, + CALLBACK_TIMEOUT)) { + err = -ETIMEDOUT; + goto error; + } + } return 0; error: - amdtp_stream_stop(&oxfw->rx_stream); + amdtp_domain_stop(&oxfw->domain); + cmp_connection_break(&oxfw->in_conn); - if (oxfw->has_output) { - amdtp_stream_stop(&oxfw->tx_stream); + if (oxfw->has_output) cmp_connection_break(&oxfw->out_conn); - } + return err; } void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw) { if (oxfw->substreams_count == 0) { - amdtp_stream_stop(&oxfw->rx_stream); + amdtp_domain_stop(&oxfw->domain); + cmp_connection_break(&oxfw->in_conn); cmp_connection_release(&oxfw->in_conn); if (oxfw->has_output) { - amdtp_stream_stop(&oxfw->tx_stream); cmp_connection_break(&oxfw->out_conn); cmp_connection_release(&oxfw->out_conn); } @@ -409,13 +414,22 @@ int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw) } } - return 0; + err = amdtp_domain_init(&oxfw->domain); + if (err < 0) { + destroy_stream(oxfw, &oxfw->rx_stream); + if (oxfw->has_output) + destroy_stream(oxfw, &oxfw->tx_stream); + } + + return err; } // This function should be called before starting the stream or after stopping // the streams. void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw) { + amdtp_domain_destroy(&oxfw->domain); + destroy_stream(oxfw, &oxfw->rx_stream); if (oxfw->has_output) @@ -424,13 +438,13 @@ void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw) void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw) { - amdtp_stream_stop(&oxfw->rx_stream); + amdtp_domain_stop(&oxfw->domain); + cmp_connection_break(&oxfw->in_conn); amdtp_stream_pcm_abort(&oxfw->rx_stream); if (oxfw->has_output) { - amdtp_stream_stop(&oxfw->tx_stream); cmp_connection_break(&oxfw->out_conn); amdtp_stream_pcm_abort(&oxfw->tx_stream); diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index cb69ab87bb14..c9627b8c5d6e 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -63,6 +63,8 @@ struct snd_oxfw { const struct ieee1394_device_id *entry; void *spec; + + struct amdtp_domain domain; }; /* -- cgit v1.2.3 From e9f21129b8d84debf53e06f73d340d5af136270f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:33 +0900 Subject: ALSA: dice: support AMDTP domain This commit adds AMDTP domain support for ALSA dice driver. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-stream.c | 32 +++++++++++++++++++++++++------- sound/firewire/dice/dice.h | 2 ++ 2 files changed, 27 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index a9f0c77734c3..af8c5a2c28f3 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -154,14 +154,10 @@ static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, for (i = 0; i < params->count; i++) { reg = cpu_to_be32((u32)-1); if (dir == AMDTP_IN_STREAM) { - amdtp_stream_stop(&dice->tx_stream[i]); - snd_dice_transaction_write_tx(dice, params->size * i + TX_ISOCHRONOUS, ®, sizeof(reg)); } else { - amdtp_stream_stop(&dice->rx_stream[i]); - snd_dice_transaction_write_rx(dice, params->size * i + RX_ISOCHRONOUS, ®, sizeof(reg)); @@ -297,10 +293,11 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate) if (dice->substreams_counter == 0 || curr_rate != rate) { struct reg_params tx_params, rx_params; + amdtp_domain_stop(&dice->domain); + err = get_register_params(dice, &tx_params, &rx_params); if (err < 0) return err; - finish_session(dice, &tx_params, &rx_params); release_resources(dice); @@ -377,7 +374,8 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, return err; } - err = amdtp_stream_start(stream, resources->channel, max_speed); + err = amdtp_domain_add_stream(&dice->domain, stream, + resources->channel, max_speed); if (err < 0) return err; } @@ -410,6 +408,7 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice) for (i = 0; i < MAX_STREAMS; ++i) { if (amdtp_streaming_error(&dice->tx_stream[i]) || amdtp_streaming_error(&dice->rx_stream[i])) { + amdtp_domain_stop(&dice->domain); finish_session(dice, &tx_params, &rx_params); break; } @@ -456,6 +455,10 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice) goto error; } + err = amdtp_domain_start(&dice->domain); + if (err < 0) + goto error; + for (i = 0; i < MAX_STREAMS; i++) { if ((i < tx_params.count && !amdtp_stream_wait_callback(&dice->tx_stream[i], @@ -471,6 +474,7 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice) return 0; error: + amdtp_domain_stop(&dice->domain); finish_session(dice, &tx_params, &rx_params); return err; } @@ -485,8 +489,10 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice) struct reg_params tx_params, rx_params; if (dice->substreams_counter == 0) { - if (get_register_params(dice, &tx_params, &rx_params) >= 0) + if (get_register_params(dice, &tx_params, &rx_params) >= 0) { + amdtp_domain_stop(&dice->domain); finish_session(dice, &tx_params, &rx_params); + } release_resources(dice); } @@ -567,6 +573,14 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice) break; } } + + err = amdtp_domain_init(&dice->domain); + if (err < 0) { + for (i = 0; i < MAX_STREAMS; ++i) { + destroy_stream(dice, AMDTP_OUT_STREAM, i); + destroy_stream(dice, AMDTP_IN_STREAM, i); + } + } end: return err; } @@ -579,6 +593,8 @@ void snd_dice_stream_destroy_duplex(struct snd_dice *dice) destroy_stream(dice, AMDTP_IN_STREAM, i); destroy_stream(dice, AMDTP_OUT_STREAM, i); } + + amdtp_domain_destroy(&dice->domain); } void snd_dice_stream_update_duplex(struct snd_dice *dice) @@ -596,6 +612,8 @@ void snd_dice_stream_update_duplex(struct snd_dice *dice) dice->global_enabled = false; if (get_register_params(dice, &tx_params, &rx_params) == 0) { + amdtp_domain_stop(&dice->domain); + stop_streams(dice, AMDTP_IN_STREAM, &tx_params); stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); } diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index c6304e5e9fc4..fa6d74303f54 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -112,6 +112,8 @@ struct snd_dice { bool global_enabled; struct completion clock_accepted; unsigned int substreams_counter; + + struct amdtp_domain domain; }; enum snd_dice_addr_type { -- cgit v1.2.3 From 9a08067ec318cbeaf0caa2d104cf677e723e02a3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:34 +0900 Subject: ALSA: firewire-digi00x: support AMDTP domain This commit adds AMDTP domain support for ALSA firewire-digi00x driver. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/digi00x/digi00x-stream.c | 55 +++++++++++++++++++-------------- sound/firewire/digi00x/digi00x.h | 2 ++ 2 files changed, 33 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index cff193f00a97..d6a92460060f 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -126,9 +126,6 @@ static void finish_session(struct snd_dg00x *dg00x) { __be32 data; - amdtp_stream_stop(&dg00x->tx_stream); - amdtp_stream_stop(&dg00x->rx_stream); - data = cpu_to_be32(0x00000003); snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST, DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET, @@ -265,13 +262,23 @@ int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x) if (err < 0) destroy_stream(dg00x, &dg00x->rx_stream); + err = amdtp_domain_init(&dg00x->domain); + if (err < 0) { + destroy_stream(dg00x, &dg00x->rx_stream); + destroy_stream(dg00x, &dg00x->tx_stream); + } + return err; } -// This function should be called before starting streams or after stopping -// streams. +/* + * This function should be called before starting streams or after stopping + * streams. + */ void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x) { + amdtp_domain_destroy(&dg00x->domain); + destroy_stream(dg00x, &dg00x->rx_stream); destroy_stream(dg00x, &dg00x->tx_stream); } @@ -288,6 +295,8 @@ int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate) rate = curr_rate; if (dg00x->substreams_counter == 0 || curr_rate != rate) { + amdtp_domain_stop(&dg00x->domain); + finish_session(dg00x); fw_iso_resources_free(&dg00x->tx_resources); @@ -320,8 +329,10 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x) return 0; if (amdtp_streaming_error(&dg00x->tx_stream) || - amdtp_streaming_error(&dg00x->rx_stream)) + amdtp_streaming_error(&dg00x->rx_stream)) { + amdtp_domain_stop(&dg00x->domain); finish_session(dg00x); + } if (generation != fw_parent_device(dg00x->unit)->card->generation) { err = fw_iso_resources_update(&dg00x->tx_resources); @@ -338,36 +349,30 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x) * which source of clock is used. */ if (!amdtp_stream_running(&dg00x->rx_stream)) { + int spd = fw_parent_device(dg00x->unit)->max_speed; + err = begin_session(dg00x); if (err < 0) goto error; - err = amdtp_stream_start(&dg00x->rx_stream, - dg00x->rx_resources.channel, - fw_parent_device(dg00x->unit)->max_speed); + err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->rx_stream, + dg00x->rx_resources.channel, spd); if (err < 0) goto error; - if (!amdtp_stream_wait_callback(&dg00x->rx_stream, - CALLBACK_TIMEOUT)) { - err = -ETIMEDOUT; + err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->tx_stream, + dg00x->tx_resources.channel, spd); + if (err < 0) goto error; - } - } - /* - * The value of SYT field in transmitted packets is always 0x0000. Thus, - * duplex streams with timestamp synchronization cannot be built. - */ - if (!amdtp_stream_running(&dg00x->tx_stream)) { - err = amdtp_stream_start(&dg00x->tx_stream, - dg00x->tx_resources.channel, - fw_parent_device(dg00x->unit)->max_speed); + err = amdtp_domain_start(&dg00x->domain); if (err < 0) goto error; - if (!amdtp_stream_wait_callback(&dg00x->tx_stream, - CALLBACK_TIMEOUT)) { + if (!amdtp_stream_wait_callback(&dg00x->rx_stream, + CALLBACK_TIMEOUT) || + !amdtp_stream_wait_callback(&dg00x->tx_stream, + CALLBACK_TIMEOUT)) { err = -ETIMEDOUT; goto error; } @@ -375,6 +380,7 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x) return 0; error: + amdtp_domain_stop(&dg00x->domain); finish_session(dg00x); return err; @@ -383,6 +389,7 @@ error: void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x) { if (dg00x->substreams_counter == 0) { + amdtp_domain_stop(&dg00x->domain); finish_session(dg00x); fw_iso_resources_free(&dg00x->tx_resources); diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h index 0994d191ccda..8041c65f2736 100644 --- a/sound/firewire/digi00x/digi00x.h +++ b/sound/firewire/digi00x/digi00x.h @@ -59,6 +59,8 @@ struct snd_dg00x { /* Console models have additional MIDI ports for control surface. */ bool is_console; + + struct amdtp_domain domain; }; #define DG00X_ADDR_BASE 0xffffe0000000ull -- cgit v1.2.3 From c281d46a51e31703183aa66ed9315446a0a10953 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:35 +0900 Subject: ALSA: firewire-tascam: support AMDTP domain This commit adds AMDTP domain support for ALSA firewire-tascam driver. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/tascam/tascam-stream.c | 54 +++++++++++++++++++++-------------- sound/firewire/tascam/tascam.h | 2 ++ 2 files changed, 34 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index d5e77036e0ee..9e2dc2fe3271 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -180,9 +180,6 @@ static void finish_session(struct snd_tscm *tscm) { __be32 reg; - amdtp_stream_stop(&tscm->rx_stream); - amdtp_stream_stop(&tscm->tx_stream); - reg = 0; snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING, @@ -339,8 +336,16 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm) return err; err = init_stream(tscm, &tscm->rx_stream); - if (err < 0) + if (err < 0) { + destroy_stream(tscm, &tscm->tx_stream); + return err; + } + + err = amdtp_domain_init(&tscm->domain); + if (err < 0) { destroy_stream(tscm, &tscm->tx_stream); + destroy_stream(tscm, &tscm->rx_stream); + } return err; } @@ -348,17 +353,18 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm) // At bus reset, streaming is stopped and some registers are clear. void snd_tscm_stream_update_duplex(struct snd_tscm *tscm) { - amdtp_stream_pcm_abort(&tscm->tx_stream); - amdtp_stream_stop(&tscm->tx_stream); + amdtp_domain_stop(&tscm->domain); + amdtp_stream_pcm_abort(&tscm->tx_stream); amdtp_stream_pcm_abort(&tscm->rx_stream); - amdtp_stream_stop(&tscm->rx_stream); } // This function should be called before starting streams or after stopping // streams. void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm) { + amdtp_domain_destroy(&tscm->domain); + destroy_stream(tscm, &tscm->rx_stream); destroy_stream(tscm, &tscm->tx_stream); } @@ -373,6 +379,8 @@ int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate) return err; if (tscm->substreams_counter == 0 || rate != curr_rate) { + amdtp_domain_stop(&tscm->domain); + finish_session(tscm); fw_iso_resources_free(&tscm->tx_resources); @@ -405,8 +413,10 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) return 0; if (amdtp_streaming_error(&tscm->rx_stream) || - amdtp_streaming_error(&tscm->tx_stream)) + amdtp_streaming_error(&tscm->tx_stream)) { + amdtp_domain_stop(&tscm->domain); finish_session(tscm); + } if (generation != fw_parent_device(tscm->unit)->card->generation) { err = fw_iso_resources_update(&tscm->tx_resources); @@ -419,6 +429,8 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) } if (!amdtp_stream_running(&tscm->rx_stream)) { + int spd = fw_parent_device(tscm->unit)->max_speed; + err = set_stream_formats(tscm, rate); if (err < 0) goto error; @@ -427,27 +439,23 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) if (err < 0) goto error; - err = amdtp_stream_start(&tscm->rx_stream, - tscm->rx_resources.channel, - fw_parent_device(tscm->unit)->max_speed); + err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream, + tscm->rx_resources.channel, spd); if (err < 0) goto error; - if (!amdtp_stream_wait_callback(&tscm->rx_stream, - CALLBACK_TIMEOUT)) { - err = -ETIMEDOUT; + err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream, + tscm->tx_resources.channel, spd); + if (err < 0) goto error; - } - } - if (!amdtp_stream_running(&tscm->tx_stream)) { - err = amdtp_stream_start(&tscm->tx_stream, - tscm->tx_resources.channel, - fw_parent_device(tscm->unit)->max_speed); + err = amdtp_domain_start(&tscm->domain); if (err < 0) - goto error; + return err; - if (!amdtp_stream_wait_callback(&tscm->tx_stream, + if (!amdtp_stream_wait_callback(&tscm->rx_stream, + CALLBACK_TIMEOUT) || + !amdtp_stream_wait_callback(&tscm->tx_stream, CALLBACK_TIMEOUT)) { err = -ETIMEDOUT; goto error; @@ -456,6 +464,7 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) return 0; error: + amdtp_domain_stop(&tscm->domain); finish_session(tscm); return err; @@ -464,6 +473,7 @@ error: void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm) { if (tscm->substreams_counter == 0) { + amdtp_domain_stop(&tscm->domain); finish_session(tscm); fw_iso_resources_free(&tscm->tx_resources); diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h index 734e5bb9c3da..64a2e4d2bbfe 100644 --- a/sound/firewire/tascam/tascam.h +++ b/sound/firewire/tascam/tascam.h @@ -97,6 +97,8 @@ struct snd_tscm { struct snd_firewire_tascam_change queue[SND_TSCM_QUEUE_COUNT]; unsigned int pull_pos; unsigned int push_pos; + + struct amdtp_domain domain; }; #define TSCM_ADDR_BASE 0xffff00000000ull -- cgit v1.2.3 From ccc6c1b0e604144d4d068eb676b444397cecf1b3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:36 +0900 Subject: ALSA: firewire-motu: support AMDTP domain This commit adds AMDTP domain support for ALSA firewire-motu driver. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu-stream.c | 83 +++++++++++++++++++-------------------- sound/firewire/motu/motu.h | 2 + 2 files changed, 42 insertions(+), 43 deletions(-) (limited to 'sound') diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index cc9f34426a47..813e38e6a86e 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -92,9 +92,6 @@ static void finish_session(struct snd_motu *motu) if (err < 0) return; - amdtp_stream_stop(&motu->tx_stream); - amdtp_stream_stop(&motu->rx_stream); - err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, ®, sizeof(reg)); if (err < 0) @@ -109,27 +106,6 @@ static void finish_session(struct snd_motu *motu) sizeof(reg)); } -static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream) -{ - struct fw_iso_resources *resources; - int err; - - if (stream == &motu->rx_stream) - resources = &motu->rx_resources; - else - resources = &motu->tx_resources; - - err = amdtp_stream_start(stream, resources->channel, - fw_parent_device(motu->unit)->max_speed); - if (err < 0) - return err; - - if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) - return -ETIMEDOUT; - - return 0; -} - int snd_motu_stream_cache_packet_formats(struct snd_motu *motu) { int err; @@ -169,6 +145,7 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate) rate = curr_rate; if (motu->substreams_counter == 0 || curr_rate != rate) { + amdtp_domain_stop(&motu->domain); finish_session(motu); fw_iso_resources_free(&motu->tx_resources); @@ -234,8 +211,10 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu) return 0; if (amdtp_streaming_error(&motu->rx_stream) || - amdtp_streaming_error(&motu->tx_stream)) + amdtp_streaming_error(&motu->tx_stream)) { + amdtp_domain_stop(&motu->domain); finish_session(motu); + } if (generation != fw_parent_device(motu->unit)->card->generation) { err = fw_iso_resources_update(&motu->rx_resources); @@ -248,6 +227,8 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu) } if (!amdtp_stream_running(&motu->rx_stream)) { + int spd = fw_parent_device(motu->unit)->max_speed; + err = ensure_packet_formats(motu); if (err < 0) return err; @@ -259,26 +240,32 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu) goto stop_streams; } - err = start_isoc_ctx(motu, &motu->rx_stream); - if (err < 0) { - dev_err(&motu->unit->device, - "fail to start IT context: %d\n", err); + err = amdtp_domain_add_stream(&motu->domain, &motu->tx_stream, + motu->tx_resources.channel, spd); + if (err < 0) goto stop_streams; - } - err = motu->spec->protocol->switch_fetching_mode(motu, true); - if (err < 0) { - dev_err(&motu->unit->device, - "fail to enable frame fetching: %d\n", err); + err = amdtp_domain_add_stream(&motu->domain, &motu->rx_stream, + motu->rx_resources.channel, spd); + if (err < 0) + goto stop_streams; + + err = amdtp_domain_start(&motu->domain); + if (err < 0) + goto stop_streams; + + if (!amdtp_stream_wait_callback(&motu->tx_stream, + CALLBACK_TIMEOUT) || + !amdtp_stream_wait_callback(&motu->rx_stream, + CALLBACK_TIMEOUT)) { + err = -ETIMEDOUT; goto stop_streams; } - } - if (!amdtp_stream_running(&motu->tx_stream)) { - err = start_isoc_ctx(motu, &motu->tx_stream); + err = motu->spec->protocol->switch_fetching_mode(motu, true); if (err < 0) { dev_err(&motu->unit->device, - "fail to start IR context: %d", err); + "fail to enable frame fetching: %d\n", err); goto stop_streams; } } @@ -286,6 +273,7 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu) return 0; stop_streams: + amdtp_domain_stop(&motu->domain); finish_session(motu); return err; } @@ -293,6 +281,7 @@ stop_streams: void snd_motu_stream_stop_duplex(struct snd_motu *motu) { if (motu->substreams_counter == 0) { + amdtp_domain_stop(&motu->domain); finish_session(motu); fw_iso_resources_free(&motu->tx_resources); @@ -344,18 +333,26 @@ int snd_motu_stream_init_duplex(struct snd_motu *motu) return err; err = init_stream(motu, &motu->rx_stream); - if (err < 0) + if (err < 0) { destroy_stream(motu, &motu->tx_stream); + return err; + } + + err = amdtp_domain_init(&motu->domain); + if (err < 0) { + destroy_stream(motu, &motu->tx_stream); + destroy_stream(motu, &motu->rx_stream); + } return err; } -/* - * This function should be called before starting streams or after stopping - * streams. - */ +// This function should be called before starting streams or after stopping +// streams. void snd_motu_stream_destroy_duplex(struct snd_motu *motu) { + amdtp_domain_destroy(&motu->domain); + destroy_stream(motu, &motu->rx_stream); destroy_stream(motu, &motu->tx_stream); diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index 09d1451d7de4..350ee2c16f4a 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h @@ -69,6 +69,8 @@ struct snd_motu { int dev_lock_count; bool dev_lock_changed; wait_queue_head_t hwdep_wait; + + struct amdtp_domain domain; }; enum snd_motu_spec_flags { -- cgit v1.2.3 From c9a9ce899cd1798f054f264043bddc021b47cb1e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:37 +0900 Subject: ALSA: fireface: support AMDTP domain This commit adds AMDTP domain support for ALSA fireface driver. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-stream.c | 57 +++++++++++++++++++++---------------- sound/firewire/fireface/ff.h | 2 ++ 2 files changed, 35 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index e4710204f481..e8e6f9fd6433 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -32,9 +32,6 @@ int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc, static inline void finish_session(struct snd_ff *ff) { - amdtp_stream_stop(&ff->tx_stream); - amdtp_stream_stop(&ff->rx_stream); - ff->spec->protocol->finish_session(ff); ff->spec->protocol->switch_fetching_mode(ff, false); } @@ -83,8 +80,16 @@ int snd_ff_stream_init_duplex(struct snd_ff *ff) return err; err = init_stream(ff, &ff->tx_stream); - if (err < 0) + if (err < 0) { destroy_stream(ff, &ff->rx_stream); + return err; + } + + err = amdtp_domain_init(&ff->domain); + if (err < 0) { + destroy_stream(ff, &ff->rx_stream); + destroy_stream(ff, &ff->tx_stream); + } return err; } @@ -95,6 +100,8 @@ int snd_ff_stream_init_duplex(struct snd_ff *ff) */ void snd_ff_stream_destroy_duplex(struct snd_ff *ff) { + amdtp_domain_destroy(&ff->domain); + destroy_stream(ff, &ff->rx_stream); destroy_stream(ff, &ff->tx_stream); } @@ -113,6 +120,7 @@ int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate) enum snd_ff_stream_mode mode; int i; + amdtp_domain_stop(&ff->domain); finish_session(ff); fw_iso_resources_free(&ff->tx_resources); @@ -155,51 +163,52 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) return 0; if (amdtp_streaming_error(&ff->tx_stream) || - amdtp_streaming_error(&ff->rx_stream)) + amdtp_streaming_error(&ff->rx_stream)) { + amdtp_domain_stop(&ff->domain); finish_session(ff); + } /* * Regardless of current source of clock signal, drivers transfer some * packets. Then, the device transfers packets. */ if (!amdtp_stream_running(&ff->rx_stream)) { + int spd = fw_parent_device(ff->unit)->max_speed; + err = ff->spec->protocol->begin_session(ff, rate); if (err < 0) goto error; - err = amdtp_stream_start(&ff->rx_stream, - ff->rx_resources.channel, - fw_parent_device(ff->unit)->max_speed); + err = amdtp_domain_add_stream(&ff->domain, &ff->rx_stream, + ff->rx_resources.channel, spd); if (err < 0) goto error; - if (!amdtp_stream_wait_callback(&ff->rx_stream, - CALLBACK_TIMEOUT_MS)) { - err = -ETIMEDOUT; - goto error; - } - - err = ff->spec->protocol->switch_fetching_mode(ff, true); + err = amdtp_domain_add_stream(&ff->domain, &ff->tx_stream, + ff->tx_resources.channel, spd); if (err < 0) goto error; - } - if (!amdtp_stream_running(&ff->tx_stream)) { - err = amdtp_stream_start(&ff->tx_stream, - ff->tx_resources.channel, - fw_parent_device(ff->unit)->max_speed); + err = amdtp_domain_start(&ff->domain); if (err < 0) goto error; - if (!amdtp_stream_wait_callback(&ff->tx_stream, + if (!amdtp_stream_wait_callback(&ff->rx_stream, + CALLBACK_TIMEOUT_MS) || + !amdtp_stream_wait_callback(&ff->tx_stream, CALLBACK_TIMEOUT_MS)) { err = -ETIMEDOUT; goto error; } + + err = ff->spec->protocol->switch_fetching_mode(ff, true); + if (err < 0) + goto error; } return 0; error: + amdtp_domain_stop(&ff->domain); finish_session(ff); return err; @@ -208,6 +217,7 @@ error: void snd_ff_stream_stop_duplex(struct snd_ff *ff) { if (ff->substreams_counter == 0) { + amdtp_domain_stop(&ff->domain); finish_session(ff); fw_iso_resources_free(&ff->tx_resources); @@ -217,12 +227,11 @@ void snd_ff_stream_stop_duplex(struct snd_ff *ff) void snd_ff_stream_update_duplex(struct snd_ff *ff) { + amdtp_domain_stop(&ff->domain); + // The device discontinue to transfer packets. amdtp_stream_pcm_abort(&ff->tx_stream); - amdtp_stream_stop(&ff->tx_stream); - amdtp_stream_pcm_abort(&ff->rx_stream); - amdtp_stream_stop(&ff->rx_stream); } void snd_ff_stream_lock_changed(struct snd_ff *ff) diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 36dd0c75b9f7..b4c22ca6079e 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -91,6 +91,8 @@ struct snd_ff { int dev_lock_count; bool dev_lock_changed; wait_queue_head_t hwdep_wait; + + struct amdtp_domain domain; }; enum snd_ff_clock_src { -- cgit v1.2.3 From 74f94e41825549638a5b24410c1f62d5ea57134e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 4 Aug 2019 15:21:38 +0900 Subject: ALSA: firewire-lib: localize kernel APIs to start/stop each AMDTP stream As a result to support AMDTP domain, no drivers call kernel APIs to start/stop each AMDTP stream. This commit localize these APIs. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 6 ++---- sound/firewire/amdtp-stream.h | 2 -- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 158d210caea7..1a92855c7647 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -894,7 +894,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context, * amdtp_stream_set_parameters() and it must be started before any PCM or MIDI * device can be started. */ -int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) +static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) { static const struct { unsigned int data_block; @@ -1027,7 +1027,6 @@ err_unlock: return err; } -EXPORT_SYMBOL(amdtp_stream_start); /** * amdtp_stream_pcm_pointer - get the PCM buffer position @@ -1098,7 +1097,7 @@ EXPORT_SYMBOL(amdtp_stream_update); * All PCM and MIDI devices of the stream must be stopped before the stream * itself can be stopped. */ -void amdtp_stream_stop(struct amdtp_stream *s) +static void amdtp_stream_stop(struct amdtp_stream *s) { mutex_lock(&s->mutex); @@ -1118,7 +1117,6 @@ void amdtp_stream_stop(struct amdtp_stream *s) mutex_unlock(&s->mutex); } -EXPORT_SYMBOL(amdtp_stream_stop); /** * amdtp_stream_pcm_abort - abort the running PCM device diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 15d471660a43..bbbca964b9b4 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -188,9 +188,7 @@ int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int data_block_quadlets); unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s); -int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed); void amdtp_stream_update(struct amdtp_stream *s); -void amdtp_stream_stop(struct amdtp_stream *s); int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime); -- cgit v1.2.3 From c1ae5e7f057beb1daa72831ab22ec06e71669af7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 27 Jul 2019 10:55:49 +0200 Subject: ALSA: usb-audio: Unify audioformat release code There are many open code for releasing audioformat object. Provide a unified helper and call it from the all places. Only a cleanup, no functional changes. Signed-off-by: Takashi Iwai --- sound/usb/stream.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/usb/stream.c b/sound/usb/stream.c index e852c7fd6109..963d425004f8 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -28,6 +28,14 @@ #include "power.h" #include "media.h" +static void audioformat_free(struct audioformat *fp) +{ + list_del(&fp->list); /* unlink for avoiding double-free */ + kfree(fp->rate_table); + kfree(fp->chmap); + kfree(fp); +} + /* * free a substream */ @@ -37,11 +45,8 @@ static void free_substream(struct snd_usb_substream *subs) if (!subs->num_formats) return; /* not initialized */ - list_for_each_entry_safe(fp, n, &subs->fmt_list, list) { - kfree(fp->rate_table); - kfree(fp->chmap); - kfree(fp); - } + list_for_each_entry_safe(fp, n, &subs->fmt_list, list) + audioformat_free(fp); kfree(subs->rate_list.list); kfree(subs->str_pd); snd_media_stream_delete(subs); @@ -832,8 +837,7 @@ found_clock: /* ok, let's parse further... */ if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream) < 0) { - kfree(fp->rate_table); - kfree(fp); + audioformat_free(fp); return NULL; } @@ -1043,9 +1047,7 @@ found_clock: pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) { - kfree(fp->chmap); - kfree(fp->rate_table); - kfree(fp); + audioformat_free(fp); return NULL; } pd->pd_id = (stream == SNDRV_PCM_STREAM_PLAYBACK) ? @@ -1064,9 +1066,7 @@ found_clock: /* ok, let's parse further... */ if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) { kfree(pd); - kfree(fp->chmap); - kfree(fp->rate_table); - kfree(fp); + audioformat_free(fp); return NULL; } } @@ -1185,11 +1185,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) err = snd_usb_add_audio_stream(chip, stream, fp); if (err < 0) { - list_del(&fp->list); /* unlink for avoiding double-free */ + audioformat_free(fp); kfree(pd); - kfree(fp->rate_table); - kfree(fp->chmap); - kfree(fp); return err; } /* try to set the interface... */ -- cgit v1.2.3 From f7f530181461aaf6afa0b3f0be4d239dea410896 Mon Sep 17 00:00:00 2001 From: Alexander Tsoy Date: Fri, 11 Aug 2017 02:36:14 +0300 Subject: ALSA: usb-audio: fix PCM device order Some cards have alternate setting with non-PCM format as the first altsetting in the interface descriptors. This confuses userspace, since alsa-lib uses device 0 by default. So lets parse interfaces in two steps: 1. Parse altsettings with PCM formats. 2. Parse altsettings with non-PCM formats. This fixes at least following cards: - Audinst HUD-mx2 - Audinst HUD-mini [ Adapted to 5.3 kernel by tiwai ] Signed-off-by: Alexander Tsoy Signed-off-by: Takashi Iwai --- sound/usb/stream.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 963d425004f8..fc3e9fcfbc38 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -1077,7 +1077,9 @@ found_clock: return fp; } -int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) +static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + int iface_no, + bool *has_non_pcm, bool non_pcm) { struct usb_device *dev; struct usb_interface *iface; @@ -1178,6 +1180,16 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) else if (IS_ERR(fp)) return PTR_ERR(fp); + if (fp->fmt_type != UAC_FORMAT_TYPE_I) + *has_non_pcm = true; + if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) { + audioformat_free(fp); + kfree(pd); + fp = NULL; + pd = NULL; + continue; + } + dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); if (protocol == UAC_VERSION_3) err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); @@ -1197,3 +1209,23 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) return 0; } +int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) +{ + int err; + bool has_non_pcm = false; + + /* parse PCM formats */ + err = __snd_usb_parse_audio_interface(chip, iface_no, &has_non_pcm, false); + if (err < 0) + return err; + + if (has_non_pcm) { + /* parse non-PCM formats */ + err = __snd_usb_parse_audio_interface(chip, iface_no, &has_non_pcm, true); + if (err < 0) + return err; + } + + return 0; +} + -- cgit v1.2.3 From 1b34121d9f26d272b0b2334209af6b6fc82d4bf1 Mon Sep 17 00:00:00 2001 From: Ard van Breemen Date: Fri, 2 Aug 2019 13:52:14 +0200 Subject: ALSA: usb-audio: Skip bSynchAddress endpoint check if it is invalid The Linux kernel assumes that get_endpoint(alts,0) and get_endpoint(alts,1) are eachothers feedback endpoints. To reassure that validity it will test bsynchaddress to comply with that assumption. But if the bsyncaddress is 0 (invalid), it will flag that as a wrong assumption and return an error. Fix: Skip the test if bSynchAddress is 0. Note: those with a valid bSynchAddress should have a code quirck added. Signed-off-by: Ard van Breemen Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 75b96929f76c..51a8faf25ed8 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -456,6 +456,7 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, } ep = get_endpoint(alts, 1)->bEndpointAddress; if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && + get_endpoint(alts, 0)->bSynchAddress != 0 && ((is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) { dev_err(&dev->dev, -- cgit v1.2.3 From 118b2806a07605d6e3c880e35a5c472bfda7582f Mon Sep 17 00:00:00 2001 From: Ard van Breemen Date: Fri, 2 Aug 2019 13:52:15 +0200 Subject: ALSA: usb-audio: Add Pioneer DDJ-SX3 PCM quirck The Pioneer DDJ-SX3 is a plain 12 32bit channel out and 10 channel in PCM/midi controller. The PCM part is "vendor specific". It needs the "ignore invalid bsynchaddress" patch as it uses 0 for that. Signed-off-by: Ard van Breemen Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'sound') diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index e918ce346027..70c338f3ae24 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3534,5 +3534,62 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } } }, +{ + /* + * PIONEER DJ DDJ-SX3 + * PCM is 12 channels out, 10 channels in @ 44.1 fixed + * interface 0, vendor class alt setting 1 for endpoints 5 and 0x86 + * The feedback for the output is the input. + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0023), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 12, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x05, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC, + .rates = SNDRV_PCM_RATE_44100, + .rate_min = 44100, + .rate_max = 44100, + .nr_rates = 1, + .rate_table = (unsigned int[]) { 44100 } + } + }, + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 10, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x86, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC| + USB_ENDPOINT_USAGE_IMPLICIT_FB, + .rates = SNDRV_PCM_RATE_44100, + .rate_min = 44100, + .rate_max = 44100, + .nr_rates = 1, + .rate_table = (unsigned int[]) { 44100 } + } + }, + { + .ifnum = -1 + } + } + } +}, #undef USB_DEVICE_VENDOR_SPEC -- cgit v1.2.3 From 06e8f5c842f2dbb232897ba967ea7b422745c271 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 6 Aug 2019 12:45:38 +0900 Subject: ASoC: rsnd: don't call clk_get_rate() under atomic context ADG is using clk_get_rate() under atomic context, thus, we might have scheduling issue. To avoid this issue, we need to get/keep clk rate under non atomic context. We need to handle ADG as special device at Renesas Sound driver. From SW point of view, we want to impletent it as rsnd_mod_ops :: prepare, but it makes code just complicate. To avoid complicated code/patch, this patch adds new clk_rate[] array, and keep clk IN rate when rsnd_adg_clk_enable() was called. Reported-by: Leon Kong Signed-off-by: Kuninori Morimoto Tested-by: Leon Kong Link: https://lore.kernel.org/r/87v9vb0xkp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index fce4e050a9b7..b9aacf3d3b29 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -30,6 +30,7 @@ struct rsnd_adg { struct clk *clkout[CLKOUTMAX]; struct clk_onecell_data onecell; struct rsnd_mod mod; + int clk_rate[CLKMAX]; u32 flags; u32 ckr; u32 rbga; @@ -114,9 +115,9 @@ static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv, unsigned int val, en; unsigned int min, diff; unsigned int sel_rate[] = { - clk_get_rate(adg->clk[CLKA]), /* 0000: CLKA */ - clk_get_rate(adg->clk[CLKB]), /* 0001: CLKB */ - clk_get_rate(adg->clk[CLKC]), /* 0010: CLKC */ + adg->clk_rate[CLKA], /* 0000: CLKA */ + adg->clk_rate[CLKB], /* 0001: CLKB */ + adg->clk_rate[CLKC], /* 0010: CLKC */ adg->rbga_rate_for_441khz, /* 0011: RBGA */ adg->rbgb_rate_for_48khz, /* 0100: RBGB */ }; @@ -302,7 +303,7 @@ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate) * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI. */ for_each_rsnd_clk(clk, adg, i) { - if (rate == clk_get_rate(clk)) + if (rate == adg->clk_rate[i]) return sel_table[i]; } @@ -369,10 +370,18 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) for_each_rsnd_clk(clk, adg, i) { ret = 0; - if (enable) + if (enable) { ret = clk_prepare_enable(clk); - else + + /* + * We shouldn't use clk_get_rate() under + * atomic context. Let's keep it when + * rsnd_adg_clk_enable() was called + */ + adg->clk_rate[i] = clk_get_rate(adg->clk[i]); + } else { clk_disable_unprepare(clk); + } if (ret < 0) dev_warn(dev, "can't use clk %d\n", i); -- cgit v1.2.3 From cc352735d49c9c25fd711795bee35d3d001ddffa Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 6 Aug 2019 15:19:58 -0700 Subject: ASoC: SOF: Intel: hda: Initialize HDA controller after i915 init On some platforms, sound card registration fails when a HDMI monitor is not connected. This is caused by a recent commit that switched the order in which the HDA controller and the i915 are initialized. Initializing the i915 before initializing the HDA controller fixes the problem. Fixes: be1b577d01787c ("ASoC: SOF: Intel: hda: fix the hda init chip" Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20190806221958.19180-1-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 136f98bf5d7e..82f61c4e74bd 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -321,10 +321,23 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (bus->ppcap) dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n"); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* init i915 and HDMI codecs */ + ret = hda_codec_i915_init(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: init i915 and HDMI codec failed\n"); + return ret; + } +#endif + + /* Init HDA controller after i915 init */ ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + hda_codec_i915_exit(sdev); +#endif return ret; } @@ -332,13 +345,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); - /* init i915 and HDMI codecs */ - ret = hda_codec_i915_init(sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: no HDMI audio devices found\n"); - return ret; - } - /* codec detection */ if (!bus->codec_mask) { dev_info(bus->dev, "no hda codecs found!\n"); -- cgit v1.2.3 From 3403b808a0eb6d25883b72a6c4d2a4a452f8a233 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 6 Aug 2019 17:14:35 +0800 Subject: ASoC: rt1011: Add R0 temperature and TDM1 ADC2DAT Swap control - The user level application could set the R0 temperature after booting system. The degree Celsius of R0 temperature store in the non-volatile space when doing R0 calibration. - TDM1 ADC2DAT Swap controls use to control TDM slot2/3 data Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20190806091435.14329-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 9 ++++++++- sound/soc/codecs/rt1011.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index 0a6ff13d76e1..b25b4c1127ca 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1029,6 +1029,8 @@ static const char * const rt1011_tdm_adc_swap_select[] = { static SOC_ENUM_SINGLE_DECL(rt1011_tdm_adc1_1_enum, RT1011_TDM1_SET_3, 6, rt1011_tdm_adc_swap_select); +static SOC_ENUM_SINGLE_DECL(rt1011_tdm_adc2_1_enum, RT1011_TDM1_SET_3, 4, + rt1011_tdm_adc_swap_select); static void rt1011_reset(struct regmap *regmap) { @@ -1333,7 +1335,8 @@ static const struct snd_kcontrol_new rt1011_snd_controls[] = { /* TDM1 Data Out Selection */ SOC_ENUM("TDM1 DOUT Source", rt1011_tdm1_adc1_dat_enum), SOC_ENUM("TDM1 DOUT Location", rt1011_tdm1_adc1_loc_enum), - SOC_ENUM("TDM1 ADCDAT Swap Select", rt1011_tdm_adc1_1_enum), + SOC_ENUM("TDM1 ADC1DAT Swap Select", rt1011_tdm_adc1_1_enum), + SOC_ENUM("TDM1 ADC2DAT Swap Select", rt1011_tdm_adc2_1_enum), /* Data Out Mode */ SOC_ENUM("I2S ADC DOUT Mode", rt1011_adc_dout_mode_enum), @@ -1355,6 +1358,10 @@ static const struct snd_kcontrol_new rt1011_snd_controls[] = { SOC_SINGLE_EXT("R0 Calibration", SND_SOC_NOPM, 0, 1, 0, rt1011_r0_cali_get, rt1011_r0_cali_put), RT1011_R0_LOAD("R0 Load Mode"), + + /* R0 temperature */ + SOC_SINGLE("R0 Temperature", RT1011_STP_INITIAL_RESISTANCE_TEMP, + 2, 255, 0), }; static int rt1011_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, diff --git a/sound/soc/codecs/rt1011.h b/sound/soc/codecs/rt1011.h index 98a38800c4df..5d431d7f1d16 100644 --- a/sound/soc/codecs/rt1011.h +++ b/sound/soc/codecs/rt1011.h @@ -227,6 +227,7 @@ #define RT1011_STP_CALIB_RS_TEMP 0x152a #define RT1011_INIT_RECIPROCAL_REG_24_16 0x1538 #define RT1011_INIT_RECIPROCAL_REG_15_0 0x1539 +#define RT1011_STP_INITIAL_RESISTANCE_TEMP 0x153c #define RT1011_STP_ALPHA_RECIPROCAL_MSB 0x153e #define RT1011_SPK_RESISTANCE_1 0x1544 #define RT1011_SPK_RESISTANCE_2 0x1546 -- cgit v1.2.3 From 0922c7a51c775b71a297598623debe9cb6ce3a08 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 6 Aug 2019 17:14:59 +0800 Subject: ASoC: rt1011: Add a flag for the R0 calibration test The factory test needs to know whether the calibration completed. This flag helps to confirm the calibration completed or not. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20190806091459.14382-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 14 +++++++++++++- sound/soc/codecs/rt1011.h | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index b25b4c1127ca..638abcaf52b3 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1225,7 +1225,10 @@ static int rt1011_bq_drc_info(struct snd_kcontrol *kcontrol, static int rt1011_r0_cali_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - ucontrol->value.integer.value[0] = 0; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1011_priv *rt1011 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rt1011->cali_done; return 0; } @@ -1239,6 +1242,7 @@ static int rt1011_r0_cali_put(struct snd_kcontrol *kcontrol, if (!component->card->instantiated) return 0; + rt1011->cali_done = 0; if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF && ucontrol->value.integer.value[0]) rt1011_calibrate(rt1011, 1); @@ -2135,6 +2139,7 @@ static int rt1011_calibrate(struct rt1011_priv *rt1011, unsigned char cali_flag) r0_factor = ((format / r0[0] * 100) / 128) - (r0_integer * 100); rt1011->r0_reg = r0[0]; + rt1011->cali_done = 1; dev_info(dev, "r0 resistance about %d.%02d ohm, reg=0x%X\n", r0_integer, r0_factor, r0[0]); } @@ -2185,6 +2190,13 @@ static void rt1011_calibration_work(struct work_struct *work) rt1011_calibrate(rt1011, 1); + /* + * This flag should reset after booting. + * The factory test will do calibration again and use this flag to check + * whether the calibration completed + */ + rt1011->cali_done = 0; + /* initial */ rt1011_reg_init(component); } diff --git a/sound/soc/codecs/rt1011.h b/sound/soc/codecs/rt1011.h index 5d431d7f1d16..2d65983f3d0f 100644 --- a/sound/soc/codecs/rt1011.h +++ b/sound/soc/codecs/rt1011.h @@ -666,7 +666,7 @@ struct rt1011_priv { int pll_out; int bq_drc_set; - unsigned int r0_reg; + unsigned int r0_reg, cali_done; int recv_spk_mode; }; -- cgit v1.2.3 From bb67dd1878de5766c24fe7a4002d1a12c14da518 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 6 Aug 2019 12:06:03 -0500 Subject: ASoC: SOF: Intel: hda: fix MSI handling The addition of a kernel module parameter to optionally disable MSI had the side effect of permanently disabling it. The return value of pci_alloc_irq_vectors() is the number of allocated vectors or a negative number on error, so testing with the ! operator is not quite right. It was one optimization too far. Restore previous behavior to use MSI by default, unless the user selects not to do so or the allocation of irq_vectors fails. Fixes: 672ff5e3596ee ('ASoC: SOF: Intel: hda: add a parameter to disable MSI') Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190806170603.10815-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 79cce20666b6..53813de7844e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -537,7 +537,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) * if it fails, use legacy interrupt mode * TODO: support msi multiple vectors */ - if (hda_use_msi && !pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI)) { + if (hda_use_msi && pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI) > 0) { dev_info(sdev->dev, "use msi interrupt mode\n"); hdev->irq = pci_irq_vector(pci, 0); /* ipc irq number is the same of hda irq */ -- cgit v1.2.3 From ad64bfbd09d7b7997a1b1510983350836bcd6ed9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:30:13 +0900 Subject: ASoC: soc-core: set component->debugfs_root NULL To be more safety code, let's set NULL to component->debugfs_root when it was cleanuped. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87muglahq0.wl-kuninori.morimoto.gx@renesas.com Reviewed-by: Ranjani Sridharan Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0f75dac4bb26..2f37c4e0974b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -171,7 +171,10 @@ static void soc_init_component_debugfs(struct snd_soc_component *component) static void soc_cleanup_component_debugfs(struct snd_soc_component *component) { + if (!component->debugfs_root) + return; debugfs_remove_recursive(component->debugfs_root); + component->debugfs_root = NULL; } static int dai_list_show(struct seq_file *m, void *v) -- cgit v1.2.3 From 6634e3d6ea8cd92fce10d1d2da0c8e42ab84da32 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:30:31 +0900 Subject: ASoC: soc-core: add comment for for_each_xxx soc-core has many for_each_xxx, but it is a little bit difficult to know which list is relead to which for_each_xxx. This patch adds missing comment for it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lfw5ahpj.wl-kuninori.morimoto.gx@renesas.com Reviewed-by: Ranjani Sridharan Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2f37c4e0974b..5e6a48a0f79e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -380,6 +380,7 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) static void soc_add_pcm_runtime(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd) { + /* see for_each_card_rtds */ list_add_tail(&rtd->list, &card->rtd_list); rtd->num = card->num_rtd; card->num_rtd++; @@ -1149,6 +1150,7 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, if (dai_link->dobj.type && card->add_dai_link) card->add_dai_link(card, dai_link); + /* see for_each_card_links */ list_add_tail(&dai_link->list, &card->dai_link_list); return 0; -- cgit v1.2.3 From 5b99a0aad08a3428cc3262ecee29a71c88c981c2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:30:36 +0900 Subject: ASoC: soc-core: check return value of snd_soc_add_dai_link() snd_soc_add_dai_link() might return error, we need to check it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k1bpahpd.wl-kuninori.morimoto.gx@renesas.com Reviewed-by: Ranjani Sridharan Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 5e6a48a0f79e..7345679d4903 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1964,8 +1964,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* add predefined DAI links to the list */ - for_each_card_prelinks(card, i, dai_link) - snd_soc_add_dai_link(card, dai_link); + for_each_card_prelinks(card, i, dai_link) { + ret = snd_soc_add_dai_link(card, dai_link); + if (ret < 0) + goto probe_end; + } /* card bind complete so register a sound card */ ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, -- cgit v1.2.3 From 42849064500b24892e2abfe8679507dfffd585f1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:30:41 +0900 Subject: ASoC: soc-core: don't use for_each_card_links_safe() at snd_soc_find_dai_link() It doesn't removes list during loop at snd_soc_find_dai_link(). We don't need to use _safe loop. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87imr9ahp9.wl-kuninori.morimoto.gx@renesas.com Reviewed-by: Ranjani Sridharan Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7345679d4903..e176b972e4e6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -817,11 +817,11 @@ struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, int id, const char *name, const char *stream_name) { - struct snd_soc_dai_link *link, *_link; + struct snd_soc_dai_link *link; lockdep_assert_held(&client_mutex); - for_each_card_links_safe(card, link, _link) { + for_each_card_links(card, link) { if (link->id != id) continue; -- cgit v1.2.3 From 32d2c172fe88705058310635a732259c0a98e89b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:30:47 +0900 Subject: ASoC: soc-core: reuse rtdcom at snd_soc_rtdcom_add() snd_soc_rtdcom_add() is using both "rtdcom" and "new_rtdcom" as variable name, but these are not used at same time. Let's reuse rtdcom. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h86tahp2.wl-kuninori.morimoto.gx@renesas.com Reviewed-by: Ranjani Sridharan Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e176b972e4e6..d12054ab8741 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -274,7 +274,6 @@ static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, struct snd_soc_component *component) { struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_rtdcom_list *new_rtdcom; for_each_rtdcom(rtd, rtdcom) { /* already connected */ @@ -282,14 +281,14 @@ static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, return 0; } - new_rtdcom = kmalloc(sizeof(*new_rtdcom), GFP_KERNEL); - if (!new_rtdcom) + rtdcom = kmalloc(sizeof(*rtdcom), GFP_KERNEL); + if (!rtdcom) return -ENOMEM; - new_rtdcom->component = component; - INIT_LIST_HEAD(&new_rtdcom->list); + rtdcom->component = component; + INIT_LIST_HEAD(&rtdcom->list); - list_add_tail(&new_rtdcom->list, &rtd->component_list); + list_add_tail(&rtdcom->list, &rtd->component_list); return 0; } -- cgit v1.2.3 From b8ba3b572c70c8559ef76c1e0ca02e7b05126e8c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:30:53 +0900 Subject: ASoC: soc-core: tidyup for snd_soc_dapm_new_controls() snd_soc_dapm_new_controls() registers controls by using for(... i < num; ...). It means if widget was NULL, num should be zero. Thus, we don't need to check about widget pointer. This patch also cares missing return value. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ftmdahow.wl-kuninori.morimoto.gx@renesas.com Reviewed-by: Ranjani Sridharan Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d12054ab8741..bb1e9e2c4ff4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1264,16 +1264,14 @@ static int soc_probe_component(struct snd_soc_card *card, soc_init_component_debugfs(component); - if (component->driver->dapm_widgets) { - ret = snd_soc_dapm_new_controls(dapm, + ret = snd_soc_dapm_new_controls(dapm, component->driver->dapm_widgets, component->driver->num_dapm_widgets); - if (ret != 0) { - dev_err(component->dev, - "Failed to create new controls %d\n", ret); - goto err_probe; - } + if (ret != 0) { + dev_err(component->dev, + "Failed to create new controls %d\n", ret); + goto err_probe; } for_each_component_dais(component, dai) { @@ -1990,13 +1988,15 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); #endif - if (card->dapm_widgets) - snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, - card->num_dapm_widgets); + ret = snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, + card->num_dapm_widgets); + if (ret < 0) + goto probe_end; - if (card->of_dapm_widgets) - snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets, - card->num_of_dapm_widgets); + ret = snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets, + card->num_of_dapm_widgets); + if (ret < 0) + goto probe_end; /* initialise the sound card only once */ if (card->probe) { -- cgit v1.2.3 From abf31feea26c0f412a191c83f408311a0de7435c Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 23 Jul 2019 16:43:40 +0200 Subject: ASoC: Intel: Update request-reply IPC model struct ipc_message contains fields: header, tx_data and tx_size which represent TX i.e. request while RX is represented by rx_data and rx_size with reply's header equivalent missing. Reply header may contain some vital information including, but not limited to, received payload size. Some IPCs have entire payload found within RX header instead. Content and value of said header is context dependent and may vary between firmware versions and target platform. Current model does not allow such IPCs to function at all. Rather than appending yet another parameter to an already long list of such for sst_ipc_tx_message_XXXs, declare message container in form of struct sst_ipc_message and add them to parent's ipc_message declaration. Align haswell, baytrail and skylake with updated request-reply model and modify their reply processing functions to save RX header within message container. Despite the range of changes, status quo is achieved. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190723144341.21339-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/baytrail/sst-baytrail-ipc.c | 65 ++++++----- sound/soc/intel/common/sst-ipc.c | 69 ++++++------ sound/soc/intel/common/sst-ipc.h | 27 ++--- sound/soc/intel/haswell/sst-haswell-ipc.c | 164 +++++++++++++++------------- sound/soc/intel/skylake/cnl-sst.c | 6 +- sound/soc/intel/skylake/skl-sst-ipc.c | 110 +++++++++++-------- 6 files changed, 239 insertions(+), 202 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 8bd1eddcc091..74274bd38f7a 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -211,7 +211,7 @@ static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt, static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg) { struct sst_byt_stream *stream; - u64 header = msg->header; + u64 header = msg->tx.header; u8 stream_id = sst_byt_header_str_id(header); u8 stream_msg = sst_byt_header_msg_id(header); @@ -240,9 +240,10 @@ static int sst_byt_process_reply(struct sst_byt *byt, u64 header) if (msg == NULL) return 1; + msg->rx.header = header; if (header & IPC_HEADER_LARGE(true)) { - msg->rx_size = sst_byt_header_data(header); - sst_dsp_inbox_read(byt->dsp, msg->rx_data, msg->rx_size); + msg->rx.size = sst_byt_header_data(header); + sst_dsp_inbox_read(byt->dsp, msg->rx.data, msg->rx.size); } /* update any stream states */ @@ -407,17 +408,18 @@ int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream, int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream) { - struct sst_byt_alloc_params *str_req = &stream->request; - struct sst_byt_alloc_response *reply = &stream->reply; - u64 header; + struct sst_ipc_message request, reply = {0}; int ret; - header = sst_byt_header(IPC_IA_ALLOC_STREAM, - sizeof(*str_req) + sizeof(u32), + request.header = sst_byt_header(IPC_IA_ALLOC_STREAM, + sizeof(stream->request) + sizeof(u32), true, stream->str_id); - ret = sst_ipc_tx_message_wait(&byt->ipc, header, str_req, - sizeof(*str_req), - reply, sizeof(*reply)); + request.data = &stream->request; + request.size = sizeof(stream->request); + reply.data = &stream->reply; + reply.size = sizeof(stream->reply); + + ret = sst_ipc_tx_message_wait(&byt->ipc, request, &reply); if (ret < 0) { dev_err(byt->dev, "ipc: error stream commit failed\n"); return ret; @@ -430,7 +432,7 @@ int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream) int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) { - u64 header; + struct sst_ipc_message request = {0}; int ret = 0; struct sst_dsp *sst = byt->dsp; unsigned long flags; @@ -438,8 +440,9 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) if (!stream->commited) goto out; - header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id); - ret = sst_ipc_tx_message_wait(&byt->ipc, header, NULL, 0, NULL, 0); + request.header = sst_byt_header(IPC_IA_FREE_STREAM, + 0, false, stream->str_id); + ret = sst_ipc_tx_message_wait(&byt->ipc, request, NULL); if (ret < 0) { dev_err(byt->dev, "ipc: free stream %d failed\n", stream->str_id); @@ -459,15 +462,13 @@ out: static int sst_byt_stream_operations(struct sst_byt *byt, int type, int stream_id, int wait) { - u64 header; + struct sst_ipc_message request = {0}; - header = sst_byt_header(type, 0, false, stream_id); + request.header = sst_byt_header(type, 0, false, stream_id); if (wait) - return sst_ipc_tx_message_wait(&byt->ipc, header, NULL, - 0, NULL, 0); + return sst_ipc_tx_message_wait(&byt->ipc, request, NULL); else - return sst_ipc_tx_message_nowait(&byt->ipc, header, - NULL, 0); + return sst_ipc_tx_message_nowait(&byt->ipc, request); } /* stream ALSA trigger operations */ @@ -475,19 +476,17 @@ int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream, u32 start_offset) { struct sst_byt_start_stream_params start_stream; - void *tx_msg; - size_t size; - u64 header; + struct sst_ipc_message request; int ret; start_stream.byte_offset = start_offset; - header = sst_byt_header(IPC_IA_START_STREAM, + request.header = sst_byt_header(IPC_IA_START_STREAM, sizeof(start_stream) + sizeof(u32), true, stream->str_id); - tx_msg = &start_stream; - size = sizeof(start_stream); + request.data = &start_stream; + request.size = sizeof(start_stream); - ret = sst_ipc_tx_message_nowait(&byt->ipc, header, tx_msg, size); + ret = sst_ipc_tx_message_nowait(&byt->ipc, request); if (ret < 0) dev_err(byt->dev, "ipc: error failed to start stream %d\n", stream->str_id); @@ -623,10 +622,10 @@ EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready); static void byt_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) { - if (msg->header & IPC_HEADER_LARGE(true)) - sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); + if (msg->tx.header & IPC_HEADER_LARGE(true)) + sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); - sst_dsp_shim_write64_unlocked(ipc->dsp, SST_IPCX, msg->header); + sst_dsp_shim_write64_unlocked(ipc->dsp, SST_IPCX, msg->tx.header); } static void byt_shim_dbg(struct sst_generic_ipc *ipc, const char *text) @@ -648,9 +647,9 @@ static void byt_tx_data_copy(struct ipc_message *msg, char *tx_data, size_t tx_size) { /* msg content = lower 32-bit of the header + data */ - *(u32 *)msg->tx_data = (u32)(msg->header & (u32)-1); - memcpy(msg->tx_data + sizeof(u32), tx_data, tx_size); - msg->tx_size += sizeof(u32); + *(u32 *)msg->tx.data = (u32)(msg->tx.header & (u32)-1); + memcpy(msg->tx.data + sizeof(u32), tx_data, tx_size); + msg->tx.size += sizeof(u32); } static u64 byt_reply_msg_match(u64 header, u64 *mask) diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index ef5b66af1cd2..1186a03a88d6 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -43,7 +43,7 @@ static struct ipc_message *msg_get_empty(struct sst_generic_ipc *ipc) } static int tx_wait_done(struct sst_generic_ipc *ipc, - struct ipc_message *msg, void *rx_data) + struct ipc_message *msg, struct sst_ipc_message *reply) { unsigned long flags; int ret; @@ -62,8 +62,11 @@ static int tx_wait_done(struct sst_generic_ipc *ipc, } else { /* copy the data returned from DSP */ - if (rx_data) - memcpy(rx_data, msg->rx_data, msg->rx_size); + if (reply) { + reply->header = msg->rx.header; + if (reply->data) + memcpy(reply->data, msg->rx.data, msg->rx.size); + } ret = msg->errno; } @@ -72,9 +75,9 @@ static int tx_wait_done(struct sst_generic_ipc *ipc, return ret; } -static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes, void *rx_data, - size_t rx_bytes, int wait) +static int ipc_tx_message(struct sst_generic_ipc *ipc, + struct sst_ipc_message request, + struct sst_ipc_message *reply, int wait) { struct ipc_message *msg; unsigned long flags; @@ -87,23 +90,24 @@ static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header, return -EBUSY; } - msg->header = header; - msg->tx_size = tx_bytes; - msg->rx_size = rx_bytes; + msg->tx.header = request.header; + msg->tx.size = request.size; + msg->rx.header = 0; + msg->rx.size = reply ? reply->size : 0; msg->wait = wait; msg->errno = 0; msg->pending = false; msg->complete = false; - if ((tx_bytes) && (ipc->ops.tx_data_copy != NULL)) - ipc->ops.tx_data_copy(msg, tx_data, tx_bytes); + if ((request.size) && (ipc->ops.tx_data_copy != NULL)) + ipc->ops.tx_data_copy(msg, request.data, request.size); list_add_tail(&msg->list, &ipc->tx_list); schedule_work(&ipc->kwork); spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); if (wait) - return tx_wait_done(ipc, msg, rx_data); + return tx_wait_done(ipc, msg, reply); else return 0; } @@ -118,13 +122,13 @@ static int msg_empty_list_init(struct sst_generic_ipc *ipc) return -ENOMEM; for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - ipc->msg[i].tx_data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL); - if (ipc->msg[i].tx_data == NULL) + ipc->msg[i].tx.data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL); + if (ipc->msg[i].tx.data == NULL) goto free_mem; - ipc->msg[i].rx_data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL); - if (ipc->msg[i].rx_data == NULL) { - kfree(ipc->msg[i].tx_data); + ipc->msg[i].rx.data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL); + if (ipc->msg[i].rx.data == NULL) { + kfree(ipc->msg[i].tx.data); goto free_mem; } @@ -136,8 +140,8 @@ static int msg_empty_list_init(struct sst_generic_ipc *ipc) free_mem: while (i > 0) { - kfree(ipc->msg[i-1].tx_data); - kfree(ipc->msg[i-1].rx_data); + kfree(ipc->msg[i-1].tx.data); + kfree(ipc->msg[i-1].rx.data); --i; } kfree(ipc->msg); @@ -173,8 +177,8 @@ static void ipc_tx_msgs(struct work_struct *work) spin_unlock_irq(&ipc->dsp->spinlock); } -int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) +int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, + struct sst_ipc_message request, struct sst_ipc_message *reply) { int ret; @@ -187,8 +191,7 @@ int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, if (ipc->ops.check_dsp_lp_on(ipc->dsp, true)) return -EIO; - ret = ipc_tx_message(ipc, header, tx_data, tx_bytes, - rx_data, rx_bytes, 1); + ret = ipc_tx_message(ipc, request, reply, 1); if (ipc->ops.check_dsp_lp_on) if (ipc->ops.check_dsp_lp_on(ipc->dsp, false)) @@ -198,19 +201,17 @@ int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, } EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait); -int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes) +int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, + struct sst_ipc_message request) { - return ipc_tx_message(ipc, header, tx_data, tx_bytes, - NULL, 0, 0); + return ipc_tx_message(ipc, request, NULL, 0); } EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait); -int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) +int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, + struct sst_ipc_message request, struct sst_ipc_message *reply) { - return ipc_tx_message(ipc, header, tx_data, tx_bytes, - rx_data, rx_bytes, 1); + return ipc_tx_message(ipc, request, reply, 1); } EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm); @@ -230,7 +231,7 @@ struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, } list_for_each_entry(msg, &ipc->rx_list, list) { - if ((msg->header & mask) == header) + if ((msg->tx.header & mask) == header) return msg; } @@ -304,8 +305,8 @@ void sst_ipc_fini(struct sst_generic_ipc *ipc) if (ipc->msg) { for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - kfree(ipc->msg[i].tx_data); - kfree(ipc->msg[i].rx_data); + kfree(ipc->msg[i].tx.data); + kfree(ipc->msg[i].rx.data); } kfree(ipc->msg); } diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index ef38600e88f7..08c4831b2664 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h @@ -17,15 +17,16 @@ #define IPC_MAX_MAILBOX_BYTES 256 -struct ipc_message { - struct list_head list; +struct sst_ipc_message { u64 header; + void *data; + size_t size; +}; - /* direction wrt host CPU */ - char *tx_data; - size_t tx_size; - char *rx_data; - size_t rx_size; +struct ipc_message { + struct list_head list; + struct sst_ipc_message tx; + struct sst_ipc_message rx; wait_queue_head_t waitq; bool pending; @@ -66,14 +67,14 @@ struct sst_generic_ipc { struct sst_plat_ipc_ops ops; }; -int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes); +int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, + struct sst_ipc_message request, struct sst_ipc_message *reply); -int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes); +int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, + struct sst_ipc_message request); -int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes); +int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, + struct sst_ipc_message request, struct sst_ipc_message *reply); struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, u64 header); diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index a83b92d6bea8..5c73b11375e3 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -511,7 +511,7 @@ static void hsw_notification_work(struct work_struct *work) static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg) { struct sst_hsw_stream *stream; - u32 header = msg->header & ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); + u32 header = msg->tx.header & ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); u32 stream_id = msg_get_stream_id(header); u32 stream_msg = msg_get_stream_type(header); @@ -552,6 +552,7 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) return -EIO; } + msg->rx.header = header; /* first process the header */ switch (reply) { case IPC_GLB_REPLY_PENDING: @@ -562,13 +563,13 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) case IPC_GLB_REPLY_SUCCESS: if (msg->pending) { trace_ipc_pending_reply("completed", header); - sst_dsp_inbox_read(hsw->dsp, msg->rx_data, - msg->rx_size); + sst_dsp_inbox_read(hsw->dsp, msg->rx.data, + msg->rx.size); hsw->ipc.pending = false; } else { /* copy data from the DSP */ - sst_dsp_outbox_read(hsw->dsp, msg->rx_data, - msg->rx_size); + sst_dsp_outbox_read(hsw->dsp, msg->rx.data, + msg->rx.size); } break; /* these will be rare - but useful for debug */ @@ -810,11 +811,13 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) int sst_hsw_fw_get_version(struct sst_hsw *hsw, struct sst_hsw_ipc_fw_version *version) { + struct sst_ipc_message request = {0}, reply = {0}; int ret; - ret = sst_ipc_tx_message_wait(&hsw->ipc, - IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION), - NULL, 0, version, sizeof(*version)); + request.header = IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION); + reply.data = version; + reply.size = sizeof(*version); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, &reply); if (ret < 0) dev_err(hsw->dev, "error: get version failed\n"); @@ -840,7 +843,7 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume) { struct sst_hsw_ipc_volume_req *req; - u32 header; + struct sst_ipc_message request; int ret; trace_ipc_request("set stream volume", stream->reply.stream_hw_id); @@ -848,11 +851,11 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, if (channel >= 2 && channel != SST_HSW_CHANNELS_ALL) return -EINVAL; - header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | + request.header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); - header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); - header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT); - header |= (stage_id << IPC_STG_ID_SHIFT); + request.header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); + request.header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT); + request.header |= (stage_id << IPC_STG_ID_SHIFT); req = &stream->vol_req; req->target_volume = volume; @@ -877,8 +880,9 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, req->channel = channel; } - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, req, - sizeof(*req), NULL, 0); + request.data = req; + request.size = sizeof(*req); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) { dev_err(hsw->dev, "error: set stream volume failed\n"); return ret; @@ -905,7 +909,7 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, u32 volume) { struct sst_hsw_ipc_volume_req req; - u32 header; + struct sst_ipc_message request; int ret; trace_ipc_request("set mixer volume", volume); @@ -933,18 +937,19 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, req.channel = channel; } - header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | + request.header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); - header |= (hsw->mixer_info.mixer_hw_id << IPC_STR_ID_SHIFT); - header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT); - header |= (stage_id << IPC_STG_ID_SHIFT); + request.header |= (hsw->mixer_info.mixer_hw_id << IPC_STR_ID_SHIFT); + request.header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT); + request.header |= (stage_id << IPC_STG_ID_SHIFT); req.curve_duration = hsw->curve_duration; req.curve_type = hsw->curve_type; req.target_volume = volume; - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &req, - sizeof(req), NULL, 0); + request.data = &req; + request.size = sizeof(req); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) { dev_err(hsw->dev, "error: set mixer volume failed\n"); return ret; @@ -983,7 +988,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) { - u32 header; + struct sst_ipc_message request; int ret = 0; struct sst_dsp *sst = hsw->dsp; unsigned long flags; @@ -1000,10 +1005,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) trace_ipc_request("stream free", stream->host_id); stream->free_req.stream_id = stream->reply.stream_hw_id; - header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM); + request.header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM); + request.data = &stream->free_req; + request.size = sizeof(stream->free_req); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &stream->free_req, - sizeof(stream->free_req), NULL, 0); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) { dev_err(hsw->dev, "error: free stream %d failed\n", stream->free_req.stream_id); @@ -1175,9 +1181,7 @@ int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) { - struct sst_hsw_ipc_stream_alloc_req *str_req = &stream->request; - struct sst_hsw_ipc_stream_alloc_reply *reply = &stream->reply; - u32 header; + struct sst_ipc_message request, reply = {0}; int ret; if (!stream) { @@ -1192,10 +1196,13 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) trace_ipc_request("stream alloc", stream->host_id); - header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM); + request.header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM); + request.data = &stream->request; + request.size = sizeof(stream->request); + reply.data = &stream->reply; + reply.size = sizeof(stream->reply); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, str_req, - sizeof(*str_req), reply, sizeof(*reply)); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, &reply); if (ret < 0) { dev_err(hsw->dev, "error: stream commit failed\n"); return ret; @@ -1235,23 +1242,22 @@ void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw, ABI to be opaque to client PCM drivers to cope with any future ABI changes */ int sst_hsw_mixer_get_info(struct sst_hsw *hsw) { - struct sst_hsw_ipc_stream_info_reply *reply; - u32 header; + struct sst_ipc_message request = {0}, reply = {0}; int ret; - reply = &hsw->mixer_info; - header = IPC_GLB_TYPE(IPC_GLB_GET_MIXER_STREAM_INFO); + request.header = IPC_GLB_TYPE(IPC_GLB_GET_MIXER_STREAM_INFO); + reply.data = &hsw->mixer_info; + reply.size = sizeof(hsw->mixer_info); trace_ipc_request("get global mixer info", 0); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, NULL, 0, - reply, sizeof(*reply)); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, &reply); if (ret < 0) { dev_err(hsw->dev, "error: get stream info failed\n"); return ret; } - trace_hsw_mixer_info_reply(reply); + trace_hsw_mixer_info_reply(&hsw->mixer_info); return 0; } @@ -1260,16 +1266,15 @@ int sst_hsw_mixer_get_info(struct sst_hsw *hsw) static int sst_hsw_stream_operations(struct sst_hsw *hsw, int type, int stream_id, int wait) { - u32 header; + struct sst_ipc_message request = {0}; - header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(type); - header |= (stream_id << IPC_STR_ID_SHIFT); + request.header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE); + request.header |= IPC_STR_TYPE(type) | (stream_id << IPC_STR_ID_SHIFT); if (wait) - return sst_ipc_tx_message_wait(&hsw->ipc, header, - NULL, 0, NULL, 0); + return sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); else - return sst_ipc_tx_message_nowait(&hsw->ipc, header, NULL, 0); + return sst_ipc_tx_message_nowait(&hsw->ipc, request); } /* Stream ALSA trigger operations */ @@ -1377,8 +1382,8 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw, enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk, enum sst_hsw_device_mode mode, u32 clock_divider) { + struct sst_ipc_message request; struct sst_hsw_ipc_device_config_req config; - u32 header; int ret; trace_ipc_request("set device config", dev); @@ -1394,10 +1399,11 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw, trace_hsw_device_config_req(&config); - header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS); + request.header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS); + request.data = &config; + request.size = sizeof(config); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &config, - sizeof(config), NULL, 0); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) dev_err(hsw->dev, "error: set device formats failed\n"); @@ -1409,16 +1415,20 @@ EXPORT_SYMBOL_GPL(sst_hsw_device_set_config); int sst_hsw_dx_set_state(struct sst_hsw *hsw, enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx) { - u32 header, state_; + struct sst_ipc_message request, reply = {0}; + u32 state_; int ret, item; - header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE); state_ = state; + request.header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE); + request.data = &state_; + request.size = sizeof(state_); + reply.data = dx; + reply.size = sizeof(*dx); trace_ipc_request("PM enter Dx state", state); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &state_, - sizeof(state_), dx, sizeof(*dx)); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, &reply); if (ret < 0) { dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); return ret; @@ -1878,7 +1888,7 @@ int sst_hsw_module_enable(struct sst_hsw *hsw, u32 module_id, u32 instance_id) { int ret; - u32 header = 0; + struct sst_ipc_message request; struct sst_hsw_ipc_module_config config; struct sst_module *module; struct sst_module_runtime *runtime; @@ -1907,10 +1917,10 @@ int sst_hsw_module_enable(struct sst_hsw *hsw, return -ENXIO; } - header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | + request.header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | IPC_MODULE_OPERATION(IPC_MODULE_ENABLE) | IPC_MODULE_ID(module_id); - dev_dbg(dev, "module enable header: %x\n", header); + dev_dbg(dev, "module enable header: %x\n", (u32)request.header); config.map.module_entries_count = 1; config.map.module_entries[0].module_id = module->id; @@ -1932,8 +1942,9 @@ int sst_hsw_module_enable(struct sst_hsw *hsw, config.scratch_mem.size, config.scratch_mem.offset, config.map.module_entries[0].entry_point); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, - &config, sizeof(config), NULL, 0); + request.data = &config; + request.size = sizeof(config); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) dev_err(dev, "ipc: module enable failed - %d\n", ret); else @@ -1946,7 +1957,7 @@ int sst_hsw_module_disable(struct sst_hsw *hsw, u32 module_id, u32 instance_id) { int ret; - u32 header; + struct sst_ipc_message request = {0}; struct sst_module *module; struct device *dev = hsw->dev; struct sst_dsp *dsp = hsw->dsp; @@ -1967,11 +1978,11 @@ int sst_hsw_module_disable(struct sst_hsw *hsw, return -ENXIO; } - header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | + request.header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | IPC_MODULE_OPERATION(IPC_MODULE_DISABLE) | IPC_MODULE_ID(module_id); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) dev_err(dev, "module disable failed - %d\n", ret); else @@ -1985,15 +1996,16 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, u32 param_size, char *param) { int ret; - u32 header = 0; - u32 payload_size = 0, transfer_parameter_size = 0; + struct sst_ipc_message request = {0}; + u32 payload_size = 0; struct sst_hsw_transfer_parameter *parameter; struct device *dev = hsw->dev; - header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | + request.header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | IPC_MODULE_OPERATION(IPC_MODULE_SET_PARAMETER) | IPC_MODULE_ID(module_id); - dev_dbg(dev, "sst_hsw_module_set_param header=%x\n", header); + dev_dbg(dev, "sst_hsw_module_set_param header=%x\n", + (u32)request.header); payload_size = param_size + sizeof(struct sst_hsw_transfer_parameter) - @@ -2003,14 +2015,14 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, if (payload_size <= SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE) { /* short parameter, mailbox can contain data */ - dev_dbg(dev, "transfer parameter size : %d\n", - transfer_parameter_size); + dev_dbg(dev, "transfer parameter size : %lu\n", + request.size); - transfer_parameter_size = ALIGN(payload_size, 4); - dev_dbg(dev, "transfer parameter aligned size : %d\n", - transfer_parameter_size); + request.size = ALIGN(payload_size, 4); + dev_dbg(dev, "transfer parameter aligned size : %lu\n", + request.size); - parameter = kzalloc(transfer_parameter_size, GFP_KERNEL); + parameter = kzalloc(request.size, GFP_KERNEL); if (parameter == NULL) return -ENOMEM; @@ -2022,9 +2034,9 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, parameter->parameter_id = parameter_id; parameter->data_size = param_size; + request.data = parameter; - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, - parameter, transfer_parameter_size , NULL, 0); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) dev_err(dev, "ipc: module set parameter failed - %d\n", ret); @@ -2041,8 +2053,8 @@ static struct sst_dsp_device hsw_dev = { static void hsw_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) { /* send the message */ - sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); - sst_dsp_ipc_msg_tx(ipc->dsp, msg->header); + sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); + sst_dsp_ipc_msg_tx(ipc->dsp, msg->tx.header); } static void hsw_shim_dbg(struct sst_generic_ipc *ipc, const char *text) @@ -2063,7 +2075,7 @@ static void hsw_shim_dbg(struct sst_generic_ipc *ipc, const char *text) static void hsw_tx_data_copy(struct ipc_message *msg, char *tx_data, size_t tx_size) { - memcpy(msg->tx_data, tx_data, tx_size); + memcpy(msg->tx.data, tx_data, tx_size); } static u64 hsw_reply_msg_match(u64 header, u64 *mask) diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c index 2d748a335bcf..4f64f097e9ae 100644 --- a/sound/soc/intel/skylake/cnl-sst.c +++ b/sound/soc/intel/skylake/cnl-sst.c @@ -366,10 +366,10 @@ static struct sst_dsp_device cnl_dev = { static void cnl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) { - struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header); + struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header); - if (msg->tx_size) - sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); + if (msg->tx.size) + sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDD, header->extension); sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDR, diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index ee1493acc9a8..a2b69a02aab2 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -281,7 +281,7 @@ void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, size_t tx_size) { if (tx_size) - memcpy(msg->tx_data, tx_data, tx_size); + memcpy(msg->tx.data, tx_data, tx_size); } static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp) @@ -295,10 +295,10 @@ static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp) /* Lock to be held by caller */ static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) { - struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header); + struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header); - if (msg->tx_size) - sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); + if (msg->tx.size) + sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCIE, header->extension); sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCI, @@ -447,11 +447,12 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc, return; } + msg->rx.header = *ipc_header; /* first process the header */ if (reply == IPC_GLB_REPLY_SUCCESS) { dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary); /* copy the rx data from the mailbox */ - sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size); + sst_dsp_inbox_read(ipc->dsp, msg->rx.data, msg->rx.size); switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { case IPC_GLB_LOAD_MULTIPLE_MODS: case IPC_GLB_LOAD_LIBRARY: @@ -635,7 +636,7 @@ int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); @@ -646,9 +647,10 @@ int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); header.extension = IPC_PPL_LP_MODE(lp_mode); + request.header = *(u64 *)(&header); dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret); return ret; @@ -661,16 +663,17 @@ EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline); int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL); header.primary |= IPC_INSTANCE_ID(instance_id); + request.header = *(u64 *)(&header); dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret); return ret; @@ -684,7 +687,7 @@ int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, u8 instance_id, enum skl_ipc_pipeline_state state) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); @@ -692,9 +695,10 @@ int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE); header.primary |= IPC_INSTANCE_ID(instance_id); header.primary |= IPC_PPL_STATE(state); + request.header = *(u64 *)(&header); dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret); return ret; @@ -707,7 +711,7 @@ int skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); @@ -716,8 +720,10 @@ skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id) header.primary |= IPC_INSTANCE_ID(instance_id); header.extension = IPC_DMA_ID(dma_id); + request.header = *(u64 *)(&header); + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret); return ret; @@ -730,16 +736,17 @@ EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline); int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL); header.primary |= IPC_INSTANCE_ID(instance_id); + request.header = *(u64 *)(&header); dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: restore pipeline failed, err: %d\n", ret); return ret; @@ -753,7 +760,7 @@ int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request; int ret; header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); @@ -762,10 +769,13 @@ int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, header.primary |= IPC_MOD_INSTANCE_ID(instance_id); header.primary |= IPC_MOD_ID(module_id); + request.header = *(u64 *)(&header); + request.data = dx; + request.size = sizeof(*dx); + dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, header.primary, header.extension); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, - dx, sizeof(*dx), NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret); return ret; @@ -779,7 +789,7 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc, struct skl_ipc_init_instance_msg *msg, void *param_data) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request; int ret; u32 *buffer = (u32 *)param_data; /* param_block_size must be in dwords */ @@ -799,10 +809,13 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc, header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size); header.extension |= IPC_DOMAIN(msg->domain); + request.header = *(u64 *)(&header); + request.data = param_data; + request.size = msg->param_data_size; + dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, header.primary, header.extension); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, param_data, - msg->param_data_size, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: init instance failed\n"); @@ -817,7 +830,7 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, struct skl_ipc_bind_unbind_msg *msg) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND; int ret; @@ -831,10 +844,11 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id); header.extension |= IPC_DST_QUEUE(msg->dst_queue); header.extension |= IPC_SRC_QUEUE(msg->src_queue); + request.header = *(u64 *)(&header); dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary, header.extension); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: bind/unbind failed\n"); return ret; @@ -854,7 +868,7 @@ int skl_ipc_load_modules(struct sst_generic_ipc *ipc, u8 module_cnt, void *data) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); @@ -862,8 +876,11 @@ int skl_ipc_load_modules(struct sst_generic_ipc *ipc, header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS); header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); - ret = sst_ipc_tx_message_nowait(ipc, *ipc_header, data, - (sizeof(u16) * module_cnt)); + request.header = *(u64 *)(&header); + request.data = data; + request.size = sizeof(u16) * module_cnt; + + ret = sst_ipc_tx_message_nowait(ipc, request); if (ret < 0) dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret); @@ -875,7 +892,7 @@ int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt, void *data) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); @@ -883,8 +900,11 @@ int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt, header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS); header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data, - (sizeof(u16) * module_cnt), NULL, 0); + request.header = *(u64 *)(&header); + request.data = data; + request.size = sizeof(u16) * module_cnt; + + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret); @@ -896,7 +916,7 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, struct skl_ipc_large_config_msg *msg, u32 *param) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request; int ret = 0; size_t sz_remaining, tx_size, data_offset; @@ -923,9 +943,11 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, header.primary, header.extension); dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n", (unsigned)data_offset, (unsigned)tx_size); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, - ((char *)param) + data_offset, - tx_size, NULL, 0); + + request.header = *(u64 *)(&header); + request.data = ((char *)param) + data_offset; + request.size = tx_size; + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: set large config fail, err: %d\n", ret); @@ -950,7 +972,7 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, struct skl_ipc_large_config_msg *msg, u32 *param) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}, reply = {0}; int ret = 0; size_t sz_remaining, rx_size, data_offset; @@ -974,9 +996,10 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, if (rx_size == sz_remaining) header.extension |= IPC_FINAL_BLOCK(1); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, - ((char *)param) + data_offset, - msg->param_data_size); + request.header = *(u64 *)(&header); + reply.data = ((char *)param) + data_offset; + reply.size = msg->param_data_size; + ret = sst_ipc_tx_message_wait(ipc, request, &reply); if (ret < 0) { dev_err(ipc->dev, "ipc: get large config fail, err: %d\n", ret); @@ -1001,7 +1024,7 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, u8 dma_id, u8 table_id, bool wait) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret = 0; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); @@ -1009,12 +1032,12 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_LIBRARY); header.primary |= IPC_MOD_INSTANCE_ID(table_id); header.primary |= IPC_MOD_ID(dma_id); + request.header = *(u64 *)(&header); if (wait) - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, - NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); else - ret = sst_ipc_tx_message_nowait(ipc, *ipc_header, NULL, 0); + ret = sst_ipc_tx_message_nowait(ipc, request); if (ret < 0) dev_err(ipc->dev, "ipc: load lib failed\n"); @@ -1026,7 +1049,7 @@ EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library); int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret; header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); @@ -1037,6 +1060,7 @@ int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) header.extension = IPC_D0IX_WAKE(msg->wake); header.extension |= IPC_D0IX_STREAMING(msg->streaming); + request.header = *(u64 *)(&header); dev_dbg(ipc->dev, "In %s primary=%x ext=%x\n", __func__, header.primary, header.extension); @@ -1044,7 +1068,7 @@ int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) /* * Use the nopm IPC here as we dont want it checking for D0iX */ - ret = sst_ipc_tx_message_nopm(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_nopm(ipc, request, NULL); if (ret < 0) dev_err(ipc->dev, "ipc: set d0ix failed, err %d\n", ret); -- cgit v1.2.3 From 5f0ac20ed6db1d6da2eea8b862cf3d54fdfb5830 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 6 Aug 2019 18:12:10 +0300 Subject: ASoC: fsl_sai: Add registers definition for multiple datalines SAI IP supports up to 8 data lines. The configuration of supported number of data lines is decided at SoC integration time. This patch adds definitions for all related data TX/RX registers: * TDR0..7, Transmit data register * TFR0..7, Transmit FIFO register * RDR0..7, Receive data register * RFR0..7, Receive FIFO register Signed-off-by: Daniel Baluta Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/20190806151214.6783-2-daniel.baluta@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 76 ++++++++++++++++++++++++++++++++++++++++++------- sound/soc/fsl/fsl_sai.h | 36 ++++++++++++++++++++--- 2 files changed, 98 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 8f4d9fa95599..e4221f2a5ee3 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -685,7 +685,14 @@ static struct reg_default fsl_sai_reg_defaults[] = { {FSL_SAI_TCR3, 0}, {FSL_SAI_TCR4, 0}, {FSL_SAI_TCR5, 0}, - {FSL_SAI_TDR, 0}, + {FSL_SAI_TDR0, 0}, + {FSL_SAI_TDR1, 0}, + {FSL_SAI_TDR2, 0}, + {FSL_SAI_TDR3, 0}, + {FSL_SAI_TDR4, 0}, + {FSL_SAI_TDR5, 0}, + {FSL_SAI_TDR6, 0}, + {FSL_SAI_TDR7, 0}, {FSL_SAI_TMR, 0}, {FSL_SAI_RCR1, 0}, {FSL_SAI_RCR2, 0}, @@ -704,7 +711,14 @@ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) case FSL_SAI_TCR3: case FSL_SAI_TCR4: case FSL_SAI_TCR5: - case FSL_SAI_TFR: + case FSL_SAI_TFR0: + case FSL_SAI_TFR1: + case FSL_SAI_TFR2: + case FSL_SAI_TFR3: + case FSL_SAI_TFR4: + case FSL_SAI_TFR5: + case FSL_SAI_TFR6: + case FSL_SAI_TFR7: case FSL_SAI_TMR: case FSL_SAI_RCSR: case FSL_SAI_RCR1: @@ -712,8 +726,22 @@ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) case FSL_SAI_RCR3: case FSL_SAI_RCR4: case FSL_SAI_RCR5: - case FSL_SAI_RDR: - case FSL_SAI_RFR: + case FSL_SAI_RDR0: + case FSL_SAI_RDR1: + case FSL_SAI_RDR2: + case FSL_SAI_RDR3: + case FSL_SAI_RDR4: + case FSL_SAI_RDR5: + case FSL_SAI_RDR6: + case FSL_SAI_RDR7: + case FSL_SAI_RFR0: + case FSL_SAI_RFR1: + case FSL_SAI_RFR2: + case FSL_SAI_RFR3: + case FSL_SAI_RFR4: + case FSL_SAI_RFR5: + case FSL_SAI_RFR6: + case FSL_SAI_RFR7: case FSL_SAI_RMR: return true; default: @@ -726,9 +754,30 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) switch (reg) { case FSL_SAI_TCSR: case FSL_SAI_RCSR: - case FSL_SAI_TFR: - case FSL_SAI_RFR: - case FSL_SAI_RDR: + case FSL_SAI_TFR0: + case FSL_SAI_TFR1: + case FSL_SAI_TFR2: + case FSL_SAI_TFR3: + case FSL_SAI_TFR4: + case FSL_SAI_TFR5: + case FSL_SAI_TFR6: + case FSL_SAI_TFR7: + case FSL_SAI_RFR0: + case FSL_SAI_RFR1: + case FSL_SAI_RFR2: + case FSL_SAI_RFR3: + case FSL_SAI_RFR4: + case FSL_SAI_RFR5: + case FSL_SAI_RFR6: + case FSL_SAI_RFR7: + case FSL_SAI_RDR0: + case FSL_SAI_RDR1: + case FSL_SAI_RDR2: + case FSL_SAI_RDR3: + case FSL_SAI_RDR4: + case FSL_SAI_RDR5: + case FSL_SAI_RDR6: + case FSL_SAI_RDR7: return true; default: return false; @@ -744,7 +793,14 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) case FSL_SAI_TCR3: case FSL_SAI_TCR4: case FSL_SAI_TCR5: - case FSL_SAI_TDR: + case FSL_SAI_TDR0: + case FSL_SAI_TDR1: + case FSL_SAI_TDR2: + case FSL_SAI_TDR3: + case FSL_SAI_TDR4: + case FSL_SAI_TDR5: + case FSL_SAI_TDR6: + case FSL_SAI_TDR7: case FSL_SAI_TMR: case FSL_SAI_RCSR: case FSL_SAI_RCR1: @@ -883,8 +939,8 @@ static int fsl_sai_probe(struct platform_device *pdev) MCLK_DIR(index)); } - sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; - sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; + sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0; + sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0; sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 7c1ef671da28..4bb478041d67 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -20,8 +20,22 @@ #define FSL_SAI_TCR3 0x0c /* SAI Transmit Configuration 3 */ #define FSL_SAI_TCR4 0x10 /* SAI Transmit Configuration 4 */ #define FSL_SAI_TCR5 0x14 /* SAI Transmit Configuration 5 */ -#define FSL_SAI_TDR 0x20 /* SAI Transmit Data */ -#define FSL_SAI_TFR 0x40 /* SAI Transmit FIFO */ +#define FSL_SAI_TDR0 0x20 /* SAI Transmit Data 0 */ +#define FSL_SAI_TDR1 0x24 /* SAI Transmit Data 1 */ +#define FSL_SAI_TDR2 0x28 /* SAI Transmit Data 2 */ +#define FSL_SAI_TDR3 0x2C /* SAI Transmit Data 3 */ +#define FSL_SAI_TDR4 0x30 /* SAI Transmit Data 4 */ +#define FSL_SAI_TDR5 0x34 /* SAI Transmit Data 5 */ +#define FSL_SAI_TDR6 0x38 /* SAI Transmit Data 6 */ +#define FSL_SAI_TDR7 0x3C /* SAI Transmit Data 7 */ +#define FSL_SAI_TFR0 0x40 /* SAI Transmit FIFO 0 */ +#define FSL_SAI_TFR1 0x44 /* SAI Transmit FIFO 1 */ +#define FSL_SAI_TFR2 0x48 /* SAI Transmit FIFO 2 */ +#define FSL_SAI_TFR3 0x4C /* SAI Transmit FIFO 3 */ +#define FSL_SAI_TFR4 0x50 /* SAI Transmit FIFO 4 */ +#define FSL_SAI_TFR5 0x54 /* SAI Transmit FIFO 5 */ +#define FSL_SAI_TFR6 0x58 /* SAI Transmit FIFO 6 */ +#define FSL_SAI_TFR7 0x5C /* SAI Transmit FIFO 7 */ #define FSL_SAI_TMR 0x60 /* SAI Transmit Mask */ #define FSL_SAI_RCSR 0x80 /* SAI Receive Control */ #define FSL_SAI_RCR1 0x84 /* SAI Receive Configuration 1 */ @@ -29,8 +43,22 @@ #define FSL_SAI_RCR3 0x8c /* SAI Receive Configuration 3 */ #define FSL_SAI_RCR4 0x90 /* SAI Receive Configuration 4 */ #define FSL_SAI_RCR5 0x94 /* SAI Receive Configuration 5 */ -#define FSL_SAI_RDR 0xa0 /* SAI Receive Data */ -#define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */ +#define FSL_SAI_RDR0 0xa0 /* SAI Receive Data 0 */ +#define FSL_SAI_RDR1 0xa4 /* SAI Receive Data 1 */ +#define FSL_SAI_RDR2 0xa8 /* SAI Receive Data 2 */ +#define FSL_SAI_RDR3 0xac /* SAI Receive Data 3 */ +#define FSL_SAI_RDR4 0xb0 /* SAI Receive Data 4 */ +#define FSL_SAI_RDR5 0xb4 /* SAI Receive Data 5 */ +#define FSL_SAI_RDR6 0xb8 /* SAI Receive Data 6 */ +#define FSL_SAI_RDR7 0xbc /* SAI Receive Data 7 */ +#define FSL_SAI_RFR0 0xc0 /* SAI Receive FIFO 0 */ +#define FSL_SAI_RFR1 0xc4 /* SAI Receive FIFO 1 */ +#define FSL_SAI_RFR2 0xc8 /* SAI Receive FIFO 2 */ +#define FSL_SAI_RFR3 0xcc /* SAI Receive FIFO 3 */ +#define FSL_SAI_RFR4 0xd0 /* SAI Receive FIFO 4 */ +#define FSL_SAI_RFR5 0xd4 /* SAI Receive FIFO 5 */ +#define FSL_SAI_RFR6 0xd8 /* SAI Receive FIFO 6 */ +#define FSL_SAI_RFR7 0xdc /* SAI Receive FIFO 7 */ #define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */ #define FSL_SAI_xCSR(tx) (tx ? FSL_SAI_TCSR : FSL_SAI_RCSR) -- cgit v1.2.3 From b84f50b0fcb497a62068926fca793d2d213c7dbd Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 6 Aug 2019 18:12:11 +0300 Subject: ASoC: fsl_sai: Update Tx/Rx channel enable mask Tx channel enable (TCE) / Rx channel enable (RCE) bits enable corresponding data channel for Tx/Rx operation. Because SAI supports up the 8 channels TCE/RCE occupy up the 8 bits inside TCR3/RCR3 registers we need to extend the mask to reflect this. Signed-off-by: Daniel Baluta Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/20190806151214.6783-3-daniel.baluta@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 6 ++++-- sound/soc/fsl/fsl_sai.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index e4221f2a5ee3..f2698c94c9fe 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -599,7 +599,8 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int ret; - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), + FSL_SAI_CR3_TRCE_MASK, FSL_SAI_CR3_TRCE); ret = snd_pcm_hw_constraint_list(substream->runtime, 0, @@ -614,7 +615,8 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream, struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0); + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), + FSL_SAI_CR3_TRCE_MASK, 0); } static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 4bb478041d67..20c5b9b1e8bc 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -110,6 +110,7 @@ /* SAI Transmit and Receive Configuration 3 Register */ #define FSL_SAI_CR3_TRCE BIT(16) +#define FSL_SAI_CR3_TRCE_MASK GENMASK(23, 16) #define FSL_SAI_CR3_WDFL(x) (x) #define FSL_SAI_CR3_WDFL_MASK 0x1f -- cgit v1.2.3 From 4f7a0728b5305e2d865f543fbcffd617e03c7674 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 6 Aug 2019 18:12:12 +0300 Subject: ASoC: fsl_sai: Add support for SAI new version New IP version introduces Version ID and Parameter registers and optionally added Timestamp feature. VERID and PARAM registers are placed at the top of registers address space and some registers are shifted according to the following table: Tx/Rx data registers and Tx/Rx FIFO registers keep their addresses, all other registers are shifted by 8. SAI Memory map is described in chapter 13.10.4.1.1 I2S Memory map of the Reference Manual [1]. In order to make as less changes as possible we attach an offset to each register offset to each changed register definition. The offset is read from each board private data. [1]https://cache.nxp.com/secured/assets/documents/en/reference-manual/IMX8MDQLQRM.pdf?__gda__=1563728701_38bea7f0f726472cc675cb141b91bec7&fileExt=.pdf Signed-off-by: Mihai Serban [initial coding in the NXP internal tree] Signed-off-by: Shengjiu Wang [bugfixing and cleanups] Signed-off-by: Daniel Baluta [adapted to linux-next] Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/20190806151214.6783-4-daniel.baluta@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 228 ++++++++++++++++++++++++++++-------------------- sound/soc/fsl/fsl_sai.h | 41 ++++----- 2 files changed, 156 insertions(+), 113 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index f2698c94c9fe..0c5452927c04 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -40,6 +40,7 @@ static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = { static irqreturn_t fsl_sai_isr(int irq, void *devid) { struct fsl_sai *sai = (struct fsl_sai *)devid; + unsigned int ofs = sai->soc_data->reg_offset; struct device *dev = &sai->pdev->dev; u32 flags, xcsr, mask; bool irq_none = true; @@ -52,7 +53,7 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT; /* Tx IRQ */ - regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr); + regmap_read(sai->regmap, FSL_SAI_TCSR(ofs), &xcsr); flags = xcsr & mask; if (flags) @@ -82,11 +83,11 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) xcsr &= ~FSL_SAI_CSR_xF_MASK; if (flags) - regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), flags | xcsr); irq_rx: /* Rx IRQ */ - regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr); + regmap_read(sai->regmap, FSL_SAI_RCSR(ofs), &xcsr); flags = xcsr & mask; if (flags) @@ -116,7 +117,7 @@ irq_rx: xcsr &= ~FSL_SAI_CSR_xF_MASK; if (flags) - regmap_write(sai->regmap, FSL_SAI_RCSR, flags | xcsr); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), flags | xcsr); out: if (irq_none) @@ -140,6 +141,7 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int fsl_dir) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int ofs = sai->soc_data->reg_offset; bool tx = fsl_dir == FSL_FMT_TRANSMITTER; u32 val_cr2 = 0; @@ -160,7 +162,7 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, return -EINVAL; } - regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), FSL_SAI_CR2_MSEL_MASK, val_cr2); return 0; @@ -193,6 +195,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, unsigned int fmt, int fsl_dir) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int ofs = sai->soc_data->reg_offset; bool tx = fsl_dir == FSL_FMT_TRANSMITTER; u32 val_cr2 = 0, val_cr4 = 0; @@ -287,9 +290,9 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, return -EINVAL; } - regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val_cr2); - regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_MF | FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val_cr4); @@ -316,6 +319,7 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); + unsigned int ofs = sai->soc_data->reg_offset; unsigned long clk_rate; u32 savediv = 0, ratio, savesub = freq; u32 id; @@ -378,17 +382,17 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) */ if ((sai->synchronous[TX] && !sai->synchronous[RX]) || (!tx && !sai->synchronous[RX])) { - regmap_update_bits(sai->regmap, FSL_SAI_RCR2, + regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), FSL_SAI_CR2_MSEL_MASK, FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); - regmap_update_bits(sai->regmap, FSL_SAI_RCR2, + regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), FSL_SAI_CR2_DIV_MASK, savediv - 1); } else if ((sai->synchronous[RX] && !sai->synchronous[TX]) || (tx && !sai->synchronous[TX])) { - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, + regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), FSL_SAI_CR2_MSEL_MASK, FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, + regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), FSL_SAI_CR2_DIV_MASK, savediv - 1); } @@ -403,6 +407,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int ofs = sai->soc_data->reg_offset; bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; unsigned int channels = params_channels(params); u32 word_width = params_width(params); @@ -455,19 +460,19 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, if (!sai->is_slave_mode) { if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) { - regmap_update_bits(sai->regmap, FSL_SAI_TCR4, + regmap_update_bits(sai->regmap, FSL_SAI_TCR4(ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, val_cr4); - regmap_update_bits(sai->regmap, FSL_SAI_TCR5, + regmap_update_bits(sai->regmap, FSL_SAI_TCR5(ofs), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | FSL_SAI_CR5_FBT_MASK, val_cr5); regmap_write(sai->regmap, FSL_SAI_TMR, ~0UL - ((1 << channels) - 1)); } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) { - regmap_update_bits(sai->regmap, FSL_SAI_RCR4, + regmap_update_bits(sai->regmap, FSL_SAI_RCR4(ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, val_cr4); - regmap_update_bits(sai->regmap, FSL_SAI_RCR5, + regmap_update_bits(sai->regmap, FSL_SAI_RCR5(ofs), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | FSL_SAI_CR5_FBT_MASK, val_cr5); regmap_write(sai->regmap, FSL_SAI_RMR, @@ -475,10 +480,10 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, } } - regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, val_cr4); - regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | FSL_SAI_CR5_FBT_MASK, val_cr5); regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1)); @@ -506,6 +511,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int ofs = sai->soc_data->reg_offset; + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u32 xcsr, count = 100; @@ -514,9 +521,9 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. */ - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, - sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); - regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, + regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), FSL_SAI_CR2_SYNC, + sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); + regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), FSL_SAI_CR2_SYNC, sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); /* @@ -527,43 +534,44 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, + regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR, + regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_FRDE, 0); - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_xIE_MASK, 0); /* Check if the opposite FRDE is also disabled */ - regmap_read(sai->regmap, FSL_SAI_xCSR(!tx), &xcsr); + regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, ofs), &xcsr); if (!(xcsr & FSL_SAI_CSR_FRDE)) { /* Disable both directions and reset their FIFOs */ - regmap_update_bits(sai->regmap, FSL_SAI_TCSR, + regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_TERE, 0); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, + regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_TERE, 0); /* TERE will remain set till the end of current frame */ do { udelay(10); - regmap_read(sai->regmap, FSL_SAI_xCSR(tx), &xcsr); + regmap_read(sai->regmap, + FSL_SAI_xCSR(tx, ofs), &xcsr); } while (--count && xcsr & FSL_SAI_CSR_TERE); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR, + regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, + regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); /* @@ -575,13 +583,13 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, */ if (!sai->is_slave_mode) { /* Software Reset for both Tx and Rx */ - regmap_write(sai->regmap, - FSL_SAI_TCSR, FSL_SAI_CSR_SR); - regmap_write(sai->regmap, - FSL_SAI_RCSR, FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), + FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), + FSL_SAI_CSR_SR); /* Clear SR bit to finish the reset */ - regmap_write(sai->regmap, FSL_SAI_TCSR, 0); - regmap_write(sai->regmap, FSL_SAI_RCSR, 0); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0); } } break; @@ -596,10 +604,11 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int ofs = sai->soc_data->reg_offset; bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int ret; - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), FSL_SAI_CR3_TRCE_MASK, FSL_SAI_CR3_TRCE); @@ -613,9 +622,10 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int ofs = sai->soc_data->reg_offset; bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), FSL_SAI_CR3_TRCE_MASK, 0); } @@ -633,18 +643,20 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); + unsigned int ofs = sai->soc_data->reg_offset; /* Software Reset for both Tx and Rx */ - regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); - regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR); /* Clear SR bit to finish the reset */ - regmap_write(sai->regmap, FSL_SAI_TCSR, 0); - regmap_write(sai->regmap, FSL_SAI_RCSR, 0); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0); - regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, + regmap_update_bits(sai->regmap, FSL_SAI_TCR1(ofs), + FSL_SAI_CR1_RFW_MASK, sai->soc_data->fifo_depth - FSL_SAI_MAXBURST_TX); - regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, - FSL_SAI_MAXBURST_RX - 1); + regmap_update_bits(sai->regmap, FSL_SAI_RCR1(ofs), + FSL_SAI_CR1_RFW_MASK, FSL_SAI_MAXBURST_RX - 1); snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx, &sai->dma_params_rx); @@ -681,12 +693,12 @@ static const struct snd_soc_component_driver fsl_component = { .name = "fsl-sai", }; -static struct reg_default fsl_sai_reg_defaults[] = { - {FSL_SAI_TCR1, 0}, - {FSL_SAI_TCR2, 0}, - {FSL_SAI_TCR3, 0}, - {FSL_SAI_TCR4, 0}, - {FSL_SAI_TCR5, 0}, +static struct reg_default fsl_sai_reg_defaults_ofs0[] = { + {FSL_SAI_TCR1(0), 0}, + {FSL_SAI_TCR2(0), 0}, + {FSL_SAI_TCR3(0), 0}, + {FSL_SAI_TCR4(0), 0}, + {FSL_SAI_TCR5(0), 0}, {FSL_SAI_TDR0, 0}, {FSL_SAI_TDR1, 0}, {FSL_SAI_TDR2, 0}, @@ -695,24 +707,50 @@ static struct reg_default fsl_sai_reg_defaults[] = { {FSL_SAI_TDR5, 0}, {FSL_SAI_TDR6, 0}, {FSL_SAI_TDR7, 0}, - {FSL_SAI_TMR, 0}, - {FSL_SAI_RCR1, 0}, - {FSL_SAI_RCR2, 0}, - {FSL_SAI_RCR3, 0}, - {FSL_SAI_RCR4, 0}, - {FSL_SAI_RCR5, 0}, - {FSL_SAI_RMR, 0}, + {FSL_SAI_TMR, 0}, + {FSL_SAI_RCR1(0), 0}, + {FSL_SAI_RCR2(0), 0}, + {FSL_SAI_RCR3(0), 0}, + {FSL_SAI_RCR4(0), 0}, + {FSL_SAI_RCR5(0), 0}, + {FSL_SAI_RMR, 0}, +}; + +static struct reg_default fsl_sai_reg_defaults_ofs8[] = { + {FSL_SAI_TCR1(8), 0}, + {FSL_SAI_TCR2(8), 0}, + {FSL_SAI_TCR3(8), 0}, + {FSL_SAI_TCR4(8), 0}, + {FSL_SAI_TCR5(8), 0}, + {FSL_SAI_TDR0, 0}, + {FSL_SAI_TDR1, 0}, + {FSL_SAI_TDR2, 0}, + {FSL_SAI_TDR3, 0}, + {FSL_SAI_TDR4, 0}, + {FSL_SAI_TDR5, 0}, + {FSL_SAI_TDR6, 0}, + {FSL_SAI_TDR7, 0}, + {FSL_SAI_TMR, 0}, + {FSL_SAI_RCR1(8), 0}, + {FSL_SAI_RCR2(8), 0}, + {FSL_SAI_RCR3(8), 0}, + {FSL_SAI_RCR4(8), 0}, + {FSL_SAI_RCR5(8), 0}, + {FSL_SAI_RMR, 0}, }; static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) { + struct fsl_sai *sai = dev_get_drvdata(dev); + unsigned int ofs = sai->soc_data->reg_offset; + + if (reg >= FSL_SAI_TCSR(ofs) && reg <= FSL_SAI_TCR5(ofs)) + return true; + + if (reg >= FSL_SAI_RCSR(ofs) && reg <= FSL_SAI_RCR5(ofs)) + return true; + switch (reg) { - case FSL_SAI_TCSR: - case FSL_SAI_TCR1: - case FSL_SAI_TCR2: - case FSL_SAI_TCR3: - case FSL_SAI_TCR4: - case FSL_SAI_TCR5: case FSL_SAI_TFR0: case FSL_SAI_TFR1: case FSL_SAI_TFR2: @@ -722,12 +760,6 @@ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) case FSL_SAI_TFR6: case FSL_SAI_TFR7: case FSL_SAI_TMR: - case FSL_SAI_RCSR: - case FSL_SAI_RCR1: - case FSL_SAI_RCR2: - case FSL_SAI_RCR3: - case FSL_SAI_RCR4: - case FSL_SAI_RCR5: case FSL_SAI_RDR0: case FSL_SAI_RDR1: case FSL_SAI_RDR2: @@ -753,9 +785,13 @@ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) { + struct fsl_sai *sai = dev_get_drvdata(dev); + unsigned int ofs = sai->soc_data->reg_offset; + + if (reg == FSL_SAI_TCSR(ofs) || reg == FSL_SAI_RCSR(ofs)) + return true; + switch (reg) { - case FSL_SAI_TCSR: - case FSL_SAI_RCSR: case FSL_SAI_TFR0: case FSL_SAI_TFR1: case FSL_SAI_TFR2: @@ -788,13 +824,16 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) { + struct fsl_sai *sai = dev_get_drvdata(dev); + unsigned int ofs = sai->soc_data->reg_offset; + + if (reg >= FSL_SAI_TCSR(ofs) && reg <= FSL_SAI_TCR5(ofs)) + return true; + + if (reg >= FSL_SAI_RCSR(ofs) && reg <= FSL_SAI_RCR5(ofs)) + return true; + switch (reg) { - case FSL_SAI_TCSR: - case FSL_SAI_TCR1: - case FSL_SAI_TCR2: - case FSL_SAI_TCR3: - case FSL_SAI_TCR4: - case FSL_SAI_TCR5: case FSL_SAI_TDR0: case FSL_SAI_TDR1: case FSL_SAI_TDR2: @@ -804,12 +843,6 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) case FSL_SAI_TDR6: case FSL_SAI_TDR7: case FSL_SAI_TMR: - case FSL_SAI_RCSR: - case FSL_SAI_RCR1: - case FSL_SAI_RCR2: - case FSL_SAI_RCR3: - case FSL_SAI_RCR4: - case FSL_SAI_RCR5: case FSL_SAI_RMR: return true; default: @@ -817,15 +850,15 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) } } -static const struct regmap_config fsl_sai_regmap_config = { +static struct regmap_config fsl_sai_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, .fast_io = true, .max_register = FSL_SAI_RMR, - .reg_defaults = fsl_sai_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults), + .reg_defaults = fsl_sai_reg_defaults_ofs0, + .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults_ofs0), .readable_reg = fsl_sai_readable_reg, .volatile_reg = fsl_sai_volatile_reg, .writeable_reg = fsl_sai_writeable_reg, @@ -857,6 +890,12 @@ static int fsl_sai_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); + if (sai->soc_data->reg_offset == 8) { + fsl_sai_regmap_config.reg_defaults = fsl_sai_reg_defaults_ofs8; + fsl_sai_regmap_config.num_reg_defaults = + ARRAY_SIZE(fsl_sai_reg_defaults_ofs8); + } + sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base, &fsl_sai_regmap_config); @@ -971,11 +1010,13 @@ static int fsl_sai_remove(struct platform_device *pdev) static const struct fsl_sai_soc_data fsl_sai_vf610_data = { .use_imx_pcm = false, .fifo_depth = 32, + .reg_offset = 0, }; static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = { .use_imx_pcm = true, .fifo_depth = 32, + .reg_offset = 0, }; static const struct of_device_id fsl_sai_ids[] = { @@ -1008,6 +1049,7 @@ static int fsl_sai_runtime_suspend(struct device *dev) static int fsl_sai_runtime_resume(struct device *dev) { struct fsl_sai *sai = dev_get_drvdata(dev); + unsigned int ofs = sai->soc_data->reg_offset; int ret; ret = clk_prepare_enable(sai->bus_clk); @@ -1029,11 +1071,11 @@ static int fsl_sai_runtime_resume(struct device *dev) } regcache_cache_only(sai->regmap, false); - regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); - regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR); usleep_range(1000, 2000); - regmap_write(sai->regmap, FSL_SAI_TCSR, 0); - regmap_write(sai->regmap, FSL_SAI_RCSR, 0); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0); ret = regcache_sync(sai->regmap); if (ret) diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 20c5b9b1e8bc..b89b0ca26053 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -14,12 +14,12 @@ SNDRV_PCM_FMTBIT_S32_LE) /* SAI Register Map Register */ -#define FSL_SAI_TCSR 0x00 /* SAI Transmit Control */ -#define FSL_SAI_TCR1 0x04 /* SAI Transmit Configuration 1 */ -#define FSL_SAI_TCR2 0x08 /* SAI Transmit Configuration 2 */ -#define FSL_SAI_TCR3 0x0c /* SAI Transmit Configuration 3 */ -#define FSL_SAI_TCR4 0x10 /* SAI Transmit Configuration 4 */ -#define FSL_SAI_TCR5 0x14 /* SAI Transmit Configuration 5 */ +#define FSL_SAI_TCSR(ofs) (0x00 + ofs) /* SAI Transmit Control */ +#define FSL_SAI_TCR1(ofs) (0x04 + ofs) /* SAI Transmit Configuration 1 */ +#define FSL_SAI_TCR2(ofs) (0x08 + ofs) /* SAI Transmit Configuration 2 */ +#define FSL_SAI_TCR3(ofs) (0x0c + ofs) /* SAI Transmit Configuration 3 */ +#define FSL_SAI_TCR4(ofs) (0x10 + ofs) /* SAI Transmit Configuration 4 */ +#define FSL_SAI_TCR5(ofs) (0x14 + ofs) /* SAI Transmit Configuration 5 */ #define FSL_SAI_TDR0 0x20 /* SAI Transmit Data 0 */ #define FSL_SAI_TDR1 0x24 /* SAI Transmit Data 1 */ #define FSL_SAI_TDR2 0x28 /* SAI Transmit Data 2 */ @@ -37,12 +37,12 @@ #define FSL_SAI_TFR6 0x58 /* SAI Transmit FIFO 6 */ #define FSL_SAI_TFR7 0x5C /* SAI Transmit FIFO 7 */ #define FSL_SAI_TMR 0x60 /* SAI Transmit Mask */ -#define FSL_SAI_RCSR 0x80 /* SAI Receive Control */ -#define FSL_SAI_RCR1 0x84 /* SAI Receive Configuration 1 */ -#define FSL_SAI_RCR2 0x88 /* SAI Receive Configuration 2 */ -#define FSL_SAI_RCR3 0x8c /* SAI Receive Configuration 3 */ -#define FSL_SAI_RCR4 0x90 /* SAI Receive Configuration 4 */ -#define FSL_SAI_RCR5 0x94 /* SAI Receive Configuration 5 */ +#define FSL_SAI_RCSR(ofs) (0x80 + ofs) /* SAI Receive Control */ +#define FSL_SAI_RCR1(ofs) (0x84 + ofs)/* SAI Receive Configuration 1 */ +#define FSL_SAI_RCR2(ofs) (0x88 + ofs) /* SAI Receive Configuration 2 */ +#define FSL_SAI_RCR3(ofs) (0x8c + ofs) /* SAI Receive Configuration 3 */ +#define FSL_SAI_RCR4(ofs) (0x90 + ofs) /* SAI Receive Configuration 4 */ +#define FSL_SAI_RCR5(ofs) (0x94 + ofs) /* SAI Receive Configuration 5 */ #define FSL_SAI_RDR0 0xa0 /* SAI Receive Data 0 */ #define FSL_SAI_RDR1 0xa4 /* SAI Receive Data 1 */ #define FSL_SAI_RDR2 0xa8 /* SAI Receive Data 2 */ @@ -61,14 +61,14 @@ #define FSL_SAI_RFR7 0xdc /* SAI Receive FIFO 7 */ #define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */ -#define FSL_SAI_xCSR(tx) (tx ? FSL_SAI_TCSR : FSL_SAI_RCSR) -#define FSL_SAI_xCR1(tx) (tx ? FSL_SAI_TCR1 : FSL_SAI_RCR1) -#define FSL_SAI_xCR2(tx) (tx ? FSL_SAI_TCR2 : FSL_SAI_RCR2) -#define FSL_SAI_xCR3(tx) (tx ? FSL_SAI_TCR3 : FSL_SAI_RCR3) -#define FSL_SAI_xCR4(tx) (tx ? FSL_SAI_TCR4 : FSL_SAI_RCR4) -#define FSL_SAI_xCR5(tx) (tx ? FSL_SAI_TCR5 : FSL_SAI_RCR5) -#define FSL_SAI_xDR(tx) (tx ? FSL_SAI_TDR : FSL_SAI_RDR) -#define FSL_SAI_xFR(tx) (tx ? FSL_SAI_TFR : FSL_SAI_RFR) +#define FSL_SAI_xCSR(tx, ofs) (tx ? FSL_SAI_TCSR(ofs) : FSL_SAI_RCSR(ofs)) +#define FSL_SAI_xCR1(tx, ofs) (tx ? FSL_SAI_TCR1(ofs) : FSL_SAI_RCR1(ofs)) +#define FSL_SAI_xCR2(tx, ofs) (tx ? FSL_SAI_TCR2(ofs) : FSL_SAI_RCR2(ofs)) +#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_xMR(tx) (tx ? FSL_SAI_TMR : FSL_SAI_RMR) /* SAI Transmit/Receive Control Register */ @@ -158,6 +158,7 @@ struct fsl_sai_soc_data { bool use_imx_pcm; unsigned int fifo_depth; + unsigned int reg_offset; }; struct fsl_sai { -- cgit v1.2.3 From a860fac420971c5a90d4f78959b44ead793aee4f Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 6 Aug 2019 18:12:13 +0300 Subject: ASoC: fsl_sai: Add support for imx7ulp/imx8mq SAI module on imx7ulp/imx8m features 2 new registers (VERID and PARAM) at the beginning of register address space. On imx7ulp FIFOs can held up to 16 x 32 bit samples. On imx8mq FIFOs can held up to 128 x 32 bit samples. Signed-off-by: Daniel Baluta Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/20190806151214.6783-5-daniel.baluta@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 0c5452927c04..4a346fcb5630 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1019,10 +1019,24 @@ static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = { .reg_offset = 0, }; +static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = { + .use_imx_pcm = true, + .fifo_depth = 16, + .reg_offset = 8, +}; + +static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = { + .use_imx_pcm = true, + .fifo_depth = 128, + .reg_offset = 8, +}; + static const struct of_device_id fsl_sai_ids[] = { { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data }, { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data }, { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6sx_data }, + { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp_data }, + { .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_sai_ids); -- cgit v1.2.3 From 619a1f195f93276dc8c6e33fe057e007adc9c288 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Aug 2019 20:02:31 +0200 Subject: ALSA: hda: Remove page allocation redirection The HD-audio core allocates and releases pages via driver's specific dma_alloc_pages and dma_free_pages ops defined in bus->io_ops. This was because some platforms require the uncached pages and the handling of page flags had to be done locally in the driver code. Since the recent change in ALSA core memory allocator, we can simply pass SNDRV_DMA_TYPE_DEV_UC for the uncached pages, and the only difference became about this type to be passed to the core allocator. That is, it's good time for cleaning up the mess. This patch changes the allocation code in HD-audio core to call the core allocator directly so that we get rid of dma_alloc_pages and dma_free_pages io_ops. If a driver needs the uncached pages, it has to set bus->dma_type right after the bus initialization. This is merely a code refactoring and shouldn't bring any behavior changes. Reviewed-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 6 +----- sound/hda/ext/hdac_ext_bus.c | 13 ------------- sound/hda/hdac_bus.c | 1 + sound/hda/hdac_controller.c | 18 +++++++++--------- sound/hda/hdac_stream.c | 8 ++++---- sound/pci/hda/hda_intel.c | 24 ++++-------------------- sound/pci/hda/hda_tegra.c | 16 ---------------- sound/soc/intel/skylake/skl-messages.c | 15 ++------------- sound/soc/sof/intel/hda-bus.c | 14 -------------- 9 files changed, 21 insertions(+), 94 deletions(-) (limited to 'sound') diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 612a17e375d0..20549def0a27 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -264,11 +264,6 @@ struct hdac_io_ops { u16 (*reg_readw)(u16 __iomem *addr); void (*reg_writeb)(u8 value, u8 __iomem *addr); u8 (*reg_readb)(u8 __iomem *addr); - /* Allocation ops */ - int (*dma_alloc_pages)(struct hdac_bus *bus, int type, size_t size, - struct snd_dma_buffer *buf); - void (*dma_free_pages)(struct hdac_bus *bus, - struct snd_dma_buffer *buf); }; #define HDA_UNSOL_QUEUE_SIZE 64 @@ -344,6 +339,7 @@ struct hdac_bus { /* CORB/RIRB and position buffers */ struct snd_dma_buffer rb; struct snd_dma_buffer posbuf; + int dma_type; /* SNDRV_DMA_TYPE_XXX for CORB/RIRB */ /* hdac_stream linked list */ struct list_head stream_list; diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index 4f9f1d2a2ec5..7825b74068f4 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -47,17 +47,6 @@ static u8 hdac_ext_readb(u8 __iomem *addr) return readb(addr); } -static int hdac_ext_dma_alloc_pages(struct hdac_bus *bus, int type, - size_t size, struct snd_dma_buffer *buf) -{ - return snd_dma_alloc_pages(type, bus->dev, size, buf); -} - -static void hdac_ext_dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) -{ - snd_dma_free_pages(buf); -} - static const struct hdac_io_ops hdac_ext_default_io = { .reg_writel = hdac_ext_writel, .reg_readl = hdac_ext_readl, @@ -65,8 +54,6 @@ static const struct hdac_io_ops hdac_ext_default_io = { .reg_readw = hdac_ext_readw, .reg_writeb = hdac_ext_writeb, .reg_readb = hdac_ext_readb, - .dma_alloc_pages = hdac_ext_dma_alloc_pages, - .dma_free_pages = hdac_ext_dma_free_pages, }; /** diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index 14e57ffd5bc1..00ea12e67dc8 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -34,6 +34,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, else bus->ops = &default_ops; bus->io_ops = io_ops; + bus->dma_type = SNDRV_DMA_TYPE_DEV; INIT_LIST_HEAD(&bus->stream_list); INIT_LIST_HEAD(&bus->codec_list); INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 3b0110545070..7e7be8e4dcf9 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -575,12 +575,13 @@ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus) { struct hdac_stream *s; int num_streams = 0; + int dma_type = bus->dma_type ? bus->dma_type : SNDRV_DMA_TYPE_DEV; int err; list_for_each_entry(s, &bus->stream_list, list) { /* allocate memory for the BDL for each stream */ - err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, - BDL_SIZE, &s->bdl); + err = snd_dma_alloc_pages(dma_type, bus->dev, + BDL_SIZE, &s->bdl); num_streams++; if (err < 0) return -ENOMEM; @@ -589,16 +590,15 @@ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus) if (WARN_ON(!num_streams)) return -EINVAL; /* allocate memory for the position buffer */ - err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, - num_streams * 8, &bus->posbuf); + err = snd_dma_alloc_pages(dma_type, bus->dev, + num_streams * 8, &bus->posbuf); if (err < 0) return -ENOMEM; list_for_each_entry(s, &bus->stream_list, list) s->posbuf = (__le32 *)(bus->posbuf.area + s->index * 8); /* single page (at least 4096 bytes) must suffice for both ringbuffes */ - return bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, - PAGE_SIZE, &bus->rb); + return snd_dma_alloc_pages(dma_type, bus->dev, PAGE_SIZE, &bus->rb); } EXPORT_SYMBOL_GPL(snd_hdac_bus_alloc_stream_pages); @@ -612,12 +612,12 @@ void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus) list_for_each_entry(s, &bus->stream_list, list) { if (s->bdl.area) - bus->io_ops->dma_free_pages(bus, &s->bdl); + snd_dma_free_pages(&s->bdl); } if (bus->rb.area) - bus->io_ops->dma_free_pages(bus, &bus->rb); + snd_dma_free_pages(&bus->rb); if (bus->posbuf.area) - bus->io_ops->dma_free_pages(bus, &bus->posbuf); + snd_dma_free_pages(&bus->posbuf); } EXPORT_SYMBOL_GPL(snd_hdac_bus_free_stream_pages); diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index 55d53b89ac21..fc68d4ce0a37 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -680,8 +680,8 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, azx_dev->locked = true; spin_unlock_irq(&bus->reg_lock); - err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV_SG, - byte_size, bufp); + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, bus->dev, + byte_size, bufp); if (err < 0) goto err_alloc; @@ -707,7 +707,7 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, return azx_dev->stream_tag; error: - bus->io_ops->dma_free_pages(bus, bufp); + snd_dma_free_pages(bufp); err_alloc: spin_lock_irq(&bus->reg_lock); azx_dev->locked = false; @@ -754,7 +754,7 @@ void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev, azx_dev->period_bytes = 0; azx_dev->format_val = 0; - bus->io_ops->dma_free_pages(bus, dmab); + snd_dma_free_pages(dmab); dmab->area = NULL; spin_lock_irq(&bus->reg_lock); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cb8b0945547c..3bb4c26f2799 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1694,6 +1694,10 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, return err; } + /* use the non-cached pages in non-snoop mode */ + if (!azx_snoop(chip)) + azx_bus(chip)->dma_type = SNDRV_DMA_TYPE_DEV_UC; + /* Workaround for a communication error on CFL (bko#199007) and CNL */ if (IS_CFL(pci) || IS_CNL(pci)) azx_bus(chip)->polling_mode = 1; @@ -1979,24 +1983,6 @@ static int disable_msi_reset_irq(struct azx *chip) return 0; } -/* DMA page allocation helpers. */ -static int dma_alloc_pages(struct hdac_bus *bus, - int type, - size_t size, - struct snd_dma_buffer *buf) -{ - struct azx *chip = bus_to_azx(bus); - - if (!azx_snoop(chip) && type == SNDRV_DMA_TYPE_DEV) - type = SNDRV_DMA_TYPE_DEV_UC; - return snd_dma_alloc_pages(type, bus->dev, size, buf); -} - -static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) -{ - snd_dma_free_pages(buf); -} - static void pcm_mmap_prepare(struct snd_pcm_substream *substream, struct vm_area_struct *area) { @@ -2015,8 +2001,6 @@ static const struct hdac_io_ops pci_hda_io_ops = { .reg_readw = pci_azx_readw, .reg_writeb = pci_azx_writeb, .reg_readb = pci_azx_readb, - .dma_alloc_pages = dma_alloc_pages, - .dma_free_pages = dma_free_pages, }; static const struct hda_controller_ops pci_hda_ops = { diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 7dbe9f39fc79..ba414cc639f1 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -75,20 +75,6 @@ MODULE_PARM_DESC(power_save, #define power_save 0 #endif -/* - * DMA page allocation ops. - */ -static int dma_alloc_pages(struct hdac_bus *bus, int type, size_t size, - struct snd_dma_buffer *buf) -{ - return snd_dma_alloc_pages(type, bus->dev, size, buf); -} - -static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) -{ - snd_dma_free_pages(buf); -} - /* * Register access ops. Tegra HDA register access is DWORD only. */ @@ -153,8 +139,6 @@ static const struct hdac_io_ops hda_tegra_io_ops = { .reg_readw = hda_tegra_readw, .reg_writeb = hda_tegra_writeb, .reg_readb = hda_tegra_readb, - .dma_alloc_pages = dma_alloc_pages, - .dma_free_pages = dma_free_pages, }; static const struct hda_controller_ops hda_tegra_ops; /* nothing special */ diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index febc070839e0..c6f9e05c929e 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -25,23 +25,12 @@ static int skl_alloc_dma_buf(struct device *dev, struct snd_dma_buffer *dmab, size_t size) { - struct hdac_bus *bus = dev_get_drvdata(dev); - - if (!bus) - return -ENODEV; - - return bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, size, dmab); + return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, dmab); } static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) { - struct hdac_bus *bus = dev_get_drvdata(dev); - - if (!bus) - return -ENODEV; - - bus->io_ops->dma_free_pages(bus, dmab); - + snd_dma_free_pages(dmab); return 0; } diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index a7e6d8227df6..0bc93fa06b5b 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -51,18 +51,6 @@ static u8 sof_hda_readb(u8 __iomem *addr) return readb(addr); } -static int sof_hda_dma_alloc_pages(struct hdac_bus *bus, int type, - size_t size, struct snd_dma_buffer *buf) -{ - return snd_dma_alloc_pages(type, bus->dev, size, buf); -} - -static void sof_hda_dma_free_pages(struct hdac_bus *bus, - struct snd_dma_buffer *buf) -{ - snd_dma_free_pages(buf); -} - static const struct hdac_io_ops io_ops = { .reg_writel = sof_hda_writel, .reg_readl = sof_hda_readl, @@ -70,8 +58,6 @@ static const struct hdac_io_ops io_ops = { .reg_readw = sof_hda_readw, .reg_writeb = sof_hda_writeb, .reg_readb = sof_hda_readb, - .dma_alloc_pages = sof_hda_dma_alloc_pages, - .dma_free_pages = sof_hda_dma_free_pages, }; /* -- cgit v1.2.3 From 19abfefd4c7604993d1c31e098a3f48bdafe334d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Aug 2019 20:32:08 +0200 Subject: ALSA: hda: Direct MMIO accesses HD-audio drivers access to the mmio registers indirectly via the corresponding bus->io_ops callbacks. This is because some platform (notably Tegra SoC) requires the word-aligned access. But it's rather a rare case, and other platforms suffer from the penalties by indirect calls unnecessarily. This patch is an attempt to optimize and cleanup for this situation. Now the special aligned access is used only when a new kconfig CONFIG_SND_HDA_ALIGNED_MMIO is set. And the HD-audio core itself provides the aligned MMIO access helpers instead of the driver side. If Kconfig isn't set (as default), the standard helpers like readl() or writel() are used directly. A couple of places in ASoC Intel drivers have the access via io_ops reg_writel(), and they are replaced with the direct writel() calls. And now with this patch, the whole bus->io_ops becomes empty, so it's dropped completely. The bus initialization functions are changed accordingly as well to drop the whole bus->io_ops. Reviewed-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 63 +++++++++++++++++++------------------- include/sound/hdaudio_ext.h | 1 - sound/hda/Kconfig | 3 ++ sound/hda/ext/hdac_ext_bus.c | 47 +---------------------------- sound/hda/hdac_bus.c | 35 +++++++++++++++++++--- sound/pci/hda/Kconfig | 1 + sound/pci/hda/hda_controller.c | 6 ++-- sound/pci/hda/hda_controller.h | 3 +- sound/pci/hda/hda_intel.c | 47 +---------------------------- sound/pci/hda/hda_tegra.c | 68 +----------------------------------------- sound/soc/intel/skylake/skl.c | 7 ++--- sound/soc/sof/intel/hda-bus.c | 40 ------------------------- sound/soc/sof/intel/hda-dsp.c | 2 +- 13 files changed, 75 insertions(+), 248 deletions(-) (limited to 'sound') diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 20549def0a27..4af4af55e854 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -253,19 +253,6 @@ struct hdac_ext_bus_ops { int (*hdev_detach)(struct hdac_device *hdev); }; -/* - * Lowlevel I/O operators - */ -struct hdac_io_ops { - /* mapped register accesses */ - void (*reg_writel)(u32 value, u32 __iomem *addr); - u32 (*reg_readl)(u32 __iomem *addr); - void (*reg_writew)(u16 value, u16 __iomem *addr); - u16 (*reg_readw)(u16 __iomem *addr); - void (*reg_writeb)(u8 value, u8 __iomem *addr); - u8 (*reg_readb)(u8 __iomem *addr); -}; - #define HDA_UNSOL_QUEUE_SIZE 64 #define HDA_MAX_CODECS 8 /* limit by controller side */ @@ -299,7 +286,6 @@ struct hdac_rb { struct hdac_bus { struct device *dev; const struct hdac_bus_ops *ops; - const struct hdac_io_ops *io_ops; const struct hdac_ext_bus_ops *ext_ops; /* h/w resources */ @@ -380,8 +366,7 @@ struct hdac_bus { }; int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, - const struct hdac_bus_ops *ops, - const struct hdac_io_ops *io_ops); + const struct hdac_bus_ops *ops); void snd_hdac_bus_exit(struct hdac_bus *bus); int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr, unsigned int cmd, unsigned int *res); @@ -425,21 +410,38 @@ int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus); void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus); +#ifdef CONFIG_SND_HDA_ALIGNED_MMIO +unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask); +void snd_hdac_aligned_write(unsigned int val, void __iomem *addr, + unsigned int mask); +#define snd_hdac_reg_writeb(v, addr) snd_hdac_aligned_write(v, addr, 0xff) +#define snd_hdac_reg_writew(v, addr) snd_hdac_aligned_write(v, addr, 0xffff) +#define snd_hdac_reg_readb(addr) snd_hdac_aligned_read(addr, 0xff) +#define snd_hdac_reg_readw(addr) snd_hdac_aligned_read(addr, 0xffff) +#else /* CONFIG_SND_HDA_ALIGNED_MMIO */ +#define snd_hdac_reg_writeb(val, addr) writeb(val, addr) +#define snd_hdac_reg_writew(val, addr) writew(val, addr) +#define snd_hdac_reg_readb(addr) readb(addr) +#define snd_hdac_reg_readw(addr) readw(addr) +#endif /* CONFIG_SND_HDA_ALIGNED_MMIO */ +#define snd_hdac_reg_writel(val, addr) writel(val, addr) +#define snd_hdac_reg_readl(addr) readl(addr) + /* * macros for easy use */ #define _snd_hdac_chip_writeb(chip, reg, value) \ - ((chip)->io_ops->reg_writeb(value, (chip)->remap_addr + (reg))) + snd_hdac_reg_writeb(value, (chip)->remap_addr + (reg)) #define _snd_hdac_chip_readb(chip, reg) \ - ((chip)->io_ops->reg_readb((chip)->remap_addr + (reg))) + snd_hdac_reg_readb((chip)->remap_addr + (reg)) #define _snd_hdac_chip_writew(chip, reg, value) \ - ((chip)->io_ops->reg_writew(value, (chip)->remap_addr + (reg))) + snd_hdac_reg_writew(value, (chip)->remap_addr + (reg)) #define _snd_hdac_chip_readw(chip, reg) \ - ((chip)->io_ops->reg_readw((chip)->remap_addr + (reg))) + snd_hdac_reg_readw((chip)->remap_addr + (reg)) #define _snd_hdac_chip_writel(chip, reg, value) \ - ((chip)->io_ops->reg_writel(value, (chip)->remap_addr + (reg))) + snd_hdac_reg_writel(value, (chip)->remap_addr + (reg)) #define _snd_hdac_chip_readl(chip, reg) \ - ((chip)->io_ops->reg_readl((chip)->remap_addr + (reg))) + snd_hdac_reg_readl((chip)->remap_addr + (reg)) /* read/write a register, pass without AZX_REG_ prefix */ #define snd_hdac_chip_writel(chip, reg, value) \ @@ -544,24 +546,19 @@ int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, /* * macros for easy use */ -#define _snd_hdac_stream_write(type, dev, reg, value) \ - ((dev)->bus->io_ops->reg_write ## type(value, (dev)->sd_addr + (reg))) -#define _snd_hdac_stream_read(type, dev, reg) \ - ((dev)->bus->io_ops->reg_read ## type((dev)->sd_addr + (reg))) - /* read/write a register, pass without AZX_REG_ prefix */ #define snd_hdac_stream_writel(dev, reg, value) \ - _snd_hdac_stream_write(l, dev, AZX_REG_ ## reg, value) + snd_hdac_reg_writel(value, (dev)->sd_addr + AZX_REG_ ## reg) #define snd_hdac_stream_writew(dev, reg, value) \ - _snd_hdac_stream_write(w, dev, AZX_REG_ ## reg, value) + snd_hdac_reg_writew(value, (dev)->sd_addr + AZX_REG_ ## reg) #define snd_hdac_stream_writeb(dev, reg, value) \ - _snd_hdac_stream_write(b, dev, AZX_REG_ ## reg, value) + snd_hdac_reg_writeb(value, (dev)->sd_addr + AZX_REG_ ## reg) #define snd_hdac_stream_readl(dev, reg) \ - _snd_hdac_stream_read(l, dev, AZX_REG_ ## reg) + snd_hdac_reg_readl((dev)->sd_addr + AZX_REG_ ## reg) #define snd_hdac_stream_readw(dev, reg) \ - _snd_hdac_stream_read(w, dev, AZX_REG_ ## reg) + snd_hdac_reg_readw((dev)->sd_addr + AZX_REG_ ## reg) #define snd_hdac_stream_readb(dev, reg) \ - _snd_hdac_stream_read(b, dev, AZX_REG_ ## reg) + snd_hdac_reg_readb((dev)->sd_addr + AZX_REG_ ## reg) /* update a register, pass without AZX_REG_ prefix */ #define snd_hdac_stream_updatel(dev, reg, mask, val) \ diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index f34aced69ca8..ef88b20c7b0a 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -6,7 +6,6 @@ int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev, const struct hdac_bus_ops *ops, - const struct hdac_io_ops *io_ops, const struct hdac_ext_bus_ops *ext_ops); void snd_hdac_ext_bus_exit(struct hdac_bus *bus); diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index f6feced15f17..1d475cf3f754 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -6,6 +6,9 @@ config SND_HDA_CORE config SND_HDA_DSP_LOADER bool +config SND_HDA_ALIGNED_MMIO + bool + config SND_HDA_COMPONENT bool diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index 7825b74068f4..242306d820ec 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -17,67 +17,22 @@ MODULE_DESCRIPTION("HDA extended core"); MODULE_LICENSE("GPL v2"); -static void hdac_ext_writel(u32 value, u32 __iomem *addr) -{ - writel(value, addr); -} - -static u32 hdac_ext_readl(u32 __iomem *addr) -{ - return readl(addr); -} - -static void hdac_ext_writew(u16 value, u16 __iomem *addr) -{ - writew(value, addr); -} - -static u16 hdac_ext_readw(u16 __iomem *addr) -{ - return readw(addr); -} - -static void hdac_ext_writeb(u8 value, u8 __iomem *addr) -{ - writeb(value, addr); -} - -static u8 hdac_ext_readb(u8 __iomem *addr) -{ - return readb(addr); -} - -static const struct hdac_io_ops hdac_ext_default_io = { - .reg_writel = hdac_ext_writel, - .reg_readl = hdac_ext_readl, - .reg_writew = hdac_ext_writew, - .reg_readw = hdac_ext_readw, - .reg_writeb = hdac_ext_writeb, - .reg_readb = hdac_ext_readb, -}; - /** * snd_hdac_ext_bus_init - initialize a HD-audio extended bus * @ebus: the pointer to extended bus object * @dev: device pointer * @ops: bus verb operators - * @io_ops: lowlevel I/O operators, can be NULL. If NULL core will use * default ops * * Returns 0 if successful, or a negative error code. */ int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev, const struct hdac_bus_ops *ops, - const struct hdac_io_ops *io_ops, const struct hdac_ext_bus_ops *ext_ops) { int ret; - /* check if io ops are provided, if not load the defaults */ - if (io_ops == NULL) - io_ops = &hdac_ext_default_io; - - ret = snd_hdac_bus_init(bus, dev, ops, io_ops); + ret = snd_hdac_bus_init(bus, dev, ops); if (ret < 0) return ret; diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index 00ea12e67dc8..dc2523ef7d98 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -19,13 +19,11 @@ static const struct hdac_bus_ops default_ops = { * snd_hdac_bus_init - initialize a HD-audio bas bus * @bus: the pointer to bus object * @ops: bus verb operators - * @io_ops: lowlevel I/O operators * * Returns 0 if successful, or a negative error code. */ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, - const struct hdac_bus_ops *ops, - const struct hdac_io_ops *io_ops) + const struct hdac_bus_ops *ops) { memset(bus, 0, sizeof(*bus)); bus->dev = dev; @@ -33,7 +31,6 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, bus->ops = ops; else bus->ops = &default_ops; - bus->io_ops = io_ops; bus->dma_type = SNDRV_DMA_TYPE_DEV; INIT_LIST_HEAD(&bus->stream_list); INIT_LIST_HEAD(&bus->codec_list); @@ -218,3 +215,33 @@ void snd_hdac_bus_remove_device(struct hdac_bus *bus, flush_work(&bus->unsol_work); } EXPORT_SYMBOL_GPL(snd_hdac_bus_remove_device); + +#ifdef CONFIG_SND_HDA_ALIGNED_MMIO +/* Helpers for aligned read/write of mmio space, for Tegra */ +unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask) +{ + void __iomem *aligned_addr = + (void __iomem *)((unsigned long)(addr) & ~0x3); + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; + unsigned int v; + + v = readl(aligned_addr); + return (v >> shift) & mask; +} +EXPORT_SYMBOL_GPL(snd_hdac_aligned_read); + +void snd_hdac_aligned_write(unsigned int val, void __iomem *addr, + unsigned int mask) +{ + void __iomem *aligned_addr = + (void __iomem *)((unsigned long)(addr) & ~0x3); + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; + unsigned int v; + + v = readl(aligned_addr); + v &= ~(mask << shift); + v |= val << shift; + writel(v, aligned_addr); +} +EXPORT_SYMBOL_GPL(snd_hdac_aligned_write); +#endif /* CONFIG_SND_HDA_ALIGNED_MMIO */ diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 35d934309cb2..82198ea8f7f8 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -26,6 +26,7 @@ config SND_HDA_TEGRA tristate "NVIDIA Tegra HD Audio" depends on ARCH_TEGRA select SND_HDA + select SND_HDA_ALIGNED_MMIO help Say Y here to support the HDA controller present in NVIDIA Tegra SoCs diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index c8d1b4316245..ee5504e2441f 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1202,14 +1202,12 @@ void snd_hda_bus_reset(struct hda_bus *bus) } /* HD-audio bus initialization */ -int azx_bus_init(struct azx *chip, const char *model, - const struct hdac_io_ops *io_ops) +int azx_bus_init(struct azx *chip, const char *model) { struct hda_bus *bus = &chip->bus; int err; - err = snd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops, - io_ops); + err = snd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops); if (err < 0) return err; diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index baa15374fbcb..146a71e0d594 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -206,8 +206,7 @@ void azx_stop_chip(struct azx *chip); irqreturn_t azx_interrupt(int irq, void *dev_id); /* Codec interface */ -int azx_bus_init(struct azx *chip, const char *model, - const struct hdac_io_ops *io_ops); +int azx_bus_init(struct azx *chip, const char *model); int azx_probe_codecs(struct azx *chip, unsigned int max_slots); int azx_codec_configure(struct azx *chip); int azx_init_streams(struct azx *chip); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3bb4c26f2799..963a92943a6d 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1627,7 +1627,6 @@ static int default_bdl_pos_adj(struct azx *chip) /* * constructor */ -static const struct hdac_io_ops pci_hda_io_ops; static const struct hda_controller_ops pci_hda_ops; static int azx_create(struct snd_card *card, struct pci_dev *pci, @@ -1687,7 +1686,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, else chip->bdl_pos_adj = bdl_pos_adj[dev]; - err = azx_bus_init(chip, model[dev], &pci_hda_io_ops); + err = azx_bus_init(chip, model[dev]); if (err < 0) { kfree(hda); pci_disable_device(pci); @@ -1932,41 +1931,6 @@ static void azx_firmware_cb(const struct firmware *fw, void *context) } #endif -/* - * HDA controller ops. - */ - -/* PCI register access. */ -static void pci_azx_writel(u32 value, u32 __iomem *addr) -{ - writel(value, addr); -} - -static u32 pci_azx_readl(u32 __iomem *addr) -{ - return readl(addr); -} - -static void pci_azx_writew(u16 value, u16 __iomem *addr) -{ - writew(value, addr); -} - -static u16 pci_azx_readw(u16 __iomem *addr) -{ - return readw(addr); -} - -static void pci_azx_writeb(u8 value, u8 __iomem *addr) -{ - writeb(value, addr); -} - -static u8 pci_azx_readb(u8 __iomem *addr) -{ - return readb(addr); -} - static int disable_msi_reset_irq(struct azx *chip) { struct hdac_bus *bus = azx_bus(chip); @@ -1994,15 +1958,6 @@ static void pcm_mmap_prepare(struct snd_pcm_substream *substream, #endif } -static const struct hdac_io_ops pci_hda_io_ops = { - .reg_writel = pci_azx_writel, - .reg_readl = pci_azx_readl, - .reg_writew = pci_azx_writew, - .reg_readw = pci_azx_readw, - .reg_writeb = pci_azx_writeb, - .reg_readb = pci_azx_readb, -}; - static const struct hda_controller_ops pci_hda_ops = { .disable_msi_reset_irq = disable_msi_reset_irq, .pcm_mmap_prepare = pcm_mmap_prepare, diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index ba414cc639f1..8350954b7986 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -75,72 +75,6 @@ MODULE_PARM_DESC(power_save, #define power_save 0 #endif -/* - * Register access ops. Tegra HDA register access is DWORD only. - */ -static void hda_tegra_writel(u32 value, u32 __iomem *addr) -{ - writel(value, addr); -} - -static u32 hda_tegra_readl(u32 __iomem *addr) -{ - return readl(addr); -} - -static void hda_tegra_writew(u16 value, u16 __iomem *addr) -{ - unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; - void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3); - u32 v; - - v = readl(dword_addr); - v &= ~(0xffff << shift); - v |= value << shift; - writel(v, dword_addr); -} - -static u16 hda_tegra_readw(u16 __iomem *addr) -{ - unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; - void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3); - u32 v; - - v = readl(dword_addr); - return (v >> shift) & 0xffff; -} - -static void hda_tegra_writeb(u8 value, u8 __iomem *addr) -{ - unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; - void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3); - u32 v; - - v = readl(dword_addr); - v &= ~(0xff << shift); - v |= value << shift; - writel(v, dword_addr); -} - -static u8 hda_tegra_readb(u8 __iomem *addr) -{ - unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; - void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3); - u32 v; - - v = readl(dword_addr); - return (v >> shift) & 0xff; -} - -static const struct hdac_io_ops hda_tegra_io_ops = { - .reg_writel = hda_tegra_writel, - .reg_readl = hda_tegra_readl, - .reg_writew = hda_tegra_writew, - .reg_readw = hda_tegra_readw, - .reg_writeb = hda_tegra_writeb, - .reg_readb = hda_tegra_readb, -}; - static const struct hda_controller_ops hda_tegra_ops; /* nothing special */ static void hda_tegra_init(struct hda_tegra *hda) @@ -459,7 +393,7 @@ static int hda_tegra_create(struct snd_card *card, INIT_WORK(&hda->probe_work, hda_tegra_probe_work); - err = azx_bus_init(chip, NULL, &hda_tegra_io_ops); + err = azx_bus_init(chip, NULL); if (err < 0) return err; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 3362e71b4563..c6d8076dc2fd 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -132,7 +132,7 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset) /* Reset stream-to-link mapping */ list_for_each_entry(hlink, &bus->hlink_list, list) - bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); + writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); skl_enable_miscbdcge(bus->dev, true); @@ -854,7 +854,6 @@ out_err: * constructor */ static int skl_create(struct pci_dev *pci, - const struct hdac_io_ops *io_ops, struct skl **rskl) { struct hdac_ext_bus_ops *ext_ops = NULL; @@ -884,7 +883,7 @@ static int skl_create(struct pci_dev *pci, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) ext_ops = snd_soc_hdac_hda_get_ops(); #endif - snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, ext_ops); + snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, ext_ops); bus->use_posbuf = 1; skl->pci = pci; INIT_WORK(&skl->probe_work, skl_probe_work); @@ -1013,7 +1012,7 @@ static int skl_probe(struct pci_dev *pci, } /* we use ext core ops, so provide NULL for ops here */ - err = skl_create(pci, NULL, &skl); + err = skl_create(pci, &skl); if (err < 0) return err; diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 0bc93fa06b5b..438121c70f99 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -21,45 +21,6 @@ static const struct hdac_bus_ops bus_ops = { #endif -static void sof_hda_writel(u32 value, u32 __iomem *addr) -{ - writel(value, addr); -} - -static u32 sof_hda_readl(u32 __iomem *addr) -{ - return readl(addr); -} - -static void sof_hda_writew(u16 value, u16 __iomem *addr) -{ - writew(value, addr); -} - -static u16 sof_hda_readw(u16 __iomem *addr) -{ - return readw(addr); -} - -static void sof_hda_writeb(u8 value, u8 __iomem *addr) -{ - writeb(value, addr); -} - -static u8 sof_hda_readb(u8 __iomem *addr) -{ - return readb(addr); -} - -static const struct hdac_io_ops io_ops = { - .reg_writel = sof_hda_writel, - .reg_readl = sof_hda_readl, - .reg_writew = sof_hda_writew, - .reg_readw = sof_hda_readw, - .reg_writeb = sof_hda_writeb, - .reg_readb = sof_hda_readb, -}; - /* * This can be used for both with/without hda link support. */ @@ -69,7 +30,6 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, memset(bus, 0, sizeof(*bus)); bus->dev = dev; - bus->io_ops = &io_ops; INIT_LIST_HEAD(&bus->stream_list); bus->irq = -1; diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 91de4785b6a3..8d4ce5b4febd 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -356,7 +356,7 @@ static int hda_resume(struct snd_sof_dev *sdev) /* Reset stream-to-link mapping */ list_for_each_entry(hlink, &bus->hlink_list, list) - bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); + writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); hda_dsp_ctrl_misc_clock_gating(sdev, true); #else -- cgit v1.2.3 From d4ff1b3917a529bdc75592af6b1504ad6c4029f7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Aug 2019 20:50:50 +0200 Subject: ASoC: SOF: Intel: Initialize hdaudio bus properly The SOF HD-audio bus has its house-made initialization code. It's supposedly for making the code independent from HD-audio bus drivers. However, this is error-prone, and above all, the SOF driver has already dependency on HD-audio bus driver when CONFIG_SND_SOF_HDA is set. That is, if this Kconfig is set, there is no reason to avoid the call to the proper bus init function. Also, the ext_ops that is set at bus initialization can be better handled inside sof_hda_bus_init(). We don't need to refer this outside the bus initialization. So this patch addresses these issues: - sof_hda_bus_init() calls nothing but snd_hdac_ext_bus_init() when CONFIG_SND_SOF_HDA is set. Otherwise some fields are initialized locally like before for avoiding the dependency. - ext_ops is referred inside sof_hda_bus_init(). The ext_ops argument of snd_hda_bus_init() is dropped. Acked-by: Mark Brown Reviewed-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- sound/soc/sof/intel/hda-bus.c | 31 +++++++++---------------------- sound/soc/sof/intel/hda.c | 6 +----- sound/soc/sof/intel/hda.h | 3 +-- 3 files changed, 11 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 438121c70f99..0caec3a070d3 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -12,28 +12,26 @@ #include "../sof-priv.h" #include "hda.h" -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - -static const struct hdac_bus_ops bus_ops = { - .command = snd_hdac_bus_send_cmd, - .get_response = snd_hdac_bus_get_response, -}; - +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +#define sof_hda_ext_ops snd_soc_hdac_hda_get_ops() +#else +#define sof_hda_ext_ops NULL #endif /* * This can be used for both with/without hda link support. */ -void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, - const struct hdac_ext_bus_ops *ext_ops) +void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev) { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + snd_hdac_ext_bus_init(bus, dev, NULL, sof_hda_ext_ops); +#else /* CONFIG_SND_SOC_SOF_HDA */ memset(bus, 0, sizeof(*bus)); bus->dev = dev; INIT_LIST_HEAD(&bus->stream_list); bus->irq = -1; - bus->ext_ops = ext_ops; /* * There is only one HDA bus atm. keep the index as 0. @@ -42,16 +40,5 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, bus->idx = 0; spin_lock_init(&bus->reg_lock); - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - INIT_LIST_HEAD(&bus->codec_list); - INIT_LIST_HEAD(&bus->hlink_list); - - mutex_init(&bus->cmd_mutex); - mutex_init(&bus->lock); - bus->ops = &bus_ops; - INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); - bus->cmd_dma_state = true; -#endif - +#endif /* CONFIG_SND_SOC_SOF_HDA */ } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 7f665392618f..7ca27000c34d 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -236,7 +236,6 @@ static int hda_init(struct snd_sof_dev *sdev) { struct hda_bus *hbus; struct hdac_bus *bus; - struct hdac_ext_bus_ops *ext_ops = NULL; struct pci_dev *pci = to_pci_dev(sdev->dev); int ret; @@ -244,10 +243,7 @@ static int hda_init(struct snd_sof_dev *sdev) bus = sof_to_bus(sdev); /* HDA bus init */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) - ext_ops = snd_soc_hdac_hda_get_ops(); -#endif - sof_hda_bus_init(bus, &pci->dev, ext_ops); + sof_hda_bus_init(bus, &pci->dev); /* Workaround for a communication error on CFL (bko#199007) and CNL */ if (IS_CFL(pci) || IS_CNL(pci)) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index d9c17146200b..75b096050fa2 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -549,8 +549,7 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev); /* * HDA bus operations. */ -void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, - const struct hdac_ext_bus_ops *ext_ops); +void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* -- cgit v1.2.3 From 804cbf4bb063204ca6c2471baa694548aab02ce3 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 7 Aug 2019 09:50:30 -0500 Subject: ASoC: hdac_hda: fix page fault issue by removing race There is a race between hda codec device removing and the jack-detecting work, which will lead to a page fault issue as the latter work is accessing codec device which could be already removed. Here add the cancellation of jack-detecting work before codecs are actually removed to avoid the race and fix the issue. Bug: https://github.com/thesofproject/linux/issues/1067 Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190807145030.26117-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hda.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 7d4940256914..91242b6f8ea7 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -495,6 +495,10 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) static int hdac_hda_dev_remove(struct hdac_device *hdev) { + struct hdac_hda_priv *hda_pvt; + + hda_pvt = dev_get_drvdata(&hdev->dev); + cancel_delayed_work_sync(&hda_pvt->codec.jackpoll_work); return 0; } -- cgit v1.2.3 From e6d7020c2946bef2efab7c70339eee6a6b3cb6a6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:30:58 +0900 Subject: ASoC: soc-core: tidyup for snd_soc_add_component_controls() snd_soc_add_component_controls() registers controls by using for(... i < num; ...). If controls was NULL, num should be zero. Thus, we don't need to check about controls pointer. This patch also cares missing return value. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ef1xahor.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bb1e9e2c4ff4..e481f9999bfb 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1304,10 +1304,12 @@ static int soc_probe_component(struct snd_soc_card *card, } } - if (component->driver->controls) - snd_soc_add_component_controls(component, - component->driver->controls, - component->driver->num_controls); + ret = snd_soc_add_component_controls(component, + component->driver->controls, + component->driver->num_controls); + if (ret < 0) + goto err_probe; + if (component->driver->dapm_routes) snd_soc_dapm_add_routes(dapm, component->driver->dapm_routes, -- cgit v1.2.3 From daa480bde6b3a9b728965e52efffc329ccee3f77 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:31:03 +0900 Subject: ASoC: soc-core: tidyup for snd_soc_dapm_add_routes() snd_soc_dapm_add_routes() registers routes by using for(... i < num; ...). If routes was NULL, num should be zero. Thus, we don't need to check about route pointer. This patch also cares missing return value. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87d0hhahon.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e481f9999bfb..de95b68ce9ee 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1310,10 +1310,11 @@ static int soc_probe_component(struct snd_soc_card *card, if (ret < 0) goto err_probe; - if (component->driver->dapm_routes) - snd_soc_dapm_add_routes(dapm, - component->driver->dapm_routes, - component->driver->num_dapm_routes); + ret = snd_soc_dapm_add_routes(dapm, + component->driver->dapm_routes, + component->driver->num_dapm_routes); + if (ret < 0) + goto err_probe; list_add(&dapm->list, &card->dapm_list); /* see for_each_card_components */ @@ -2061,13 +2062,15 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) snd_soc_add_card_controls(card, card->controls, card->num_controls); - if (card->dapm_routes) - snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, - card->num_dapm_routes); + ret = snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, + card->num_dapm_routes); + if (ret < 0) + goto probe_end; - if (card->of_dapm_routes) - snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes, - card->num_of_dapm_routes); + ret = snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes, + card->num_of_dapm_routes); + if (ret < 0) + goto probe_end; /* try to set some sane longname if DMI is available */ snd_soc_set_dmi_name(card, NULL); -- cgit v1.2.3 From 9b98c7c2a0599084c7ed629b5f88f474d2578307 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:31:08 +0900 Subject: ASoC: soc-core: tidyup for snd_soc_add_card_controls() snd_soc_add_card_controls() registers controls by using for(... i < num; ...). If controls was NULL, num should be zero. Thus, we don't need to check about controls pointer. This patch also cares missing return value. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87blx1ahoi.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index de95b68ce9ee..4b9ae867613c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2058,9 +2058,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) snd_soc_dapm_link_dai_widgets(card); snd_soc_dapm_connect_dai_link_widgets(card); - if (card->controls) - snd_soc_add_card_controls(card, card->controls, - card->num_controls); + ret = snd_soc_add_card_controls(card, card->controls, + card->num_controls); + if (ret < 0) + goto probe_end; ret = snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, card->num_dapm_routes); -- cgit v1.2.3 From d8ca7a0a8583fc491b625450580c4092879af3dd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:31:14 +0900 Subject: ASoC: soc-core: call snd_soc_dapm_debugfs_init() at soc_init_card_debugfs() We have 2 soc_init_card_debugfs() implementations for with/without DEBUG_FS. But, snd_soc_instantiate_card() calls snd_soc_dapm_debugfs_init() under ifdef DEBUG_FS after soc_init_card_debugfs(). This is very strange. We can call snd_soc_dapm_debugfs_init() under soc_init_card_debugfs(). #ifdef CONFIG_DEBUG_FS => static void soc_init_card_debugfs(...) { ... } ... #else => static inline void soc_init_card_debugfs(...) { ... } #endif static int snd_soc_instantiate_card(struct snd_soc_card *card) { ... => soc_init_card_debugfs(card); * #ifdef CONFIG_DEBUG_FS * snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); * #endif } Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a7clahob.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4b9ae867613c..cf3d967d731e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -216,6 +216,8 @@ static void soc_init_card_debugfs(struct snd_soc_card *card) debugfs_create_u32("dapm_pop_time", 0644, card->debugfs_card_root, &card->pop_time); + + snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); } static void soc_cleanup_card_debugfs(struct snd_soc_card *card) @@ -1982,10 +1984,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) soc_init_card_debugfs(card); -#ifdef CONFIG_DEBUG_FS - snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); -#endif - #ifdef CONFIG_PM_SLEEP /* deferred resume work */ INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); -- cgit v1.2.3 From b245d273cbcd64eeaa93305f99c4ea8a6baf9c89 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:31:19 +0900 Subject: ASoC: soc-core: remove unneeded list_empty() check for snd_soc_try_rebind_card() list_for_each_entry_safe() will do nothing if it was empty list. This patch removes unneeded list_empty() check for list_for_each_entry_safe(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878ss5aho6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cf3d967d731e..6b0042835233 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2808,12 +2808,9 @@ static void snd_soc_try_rebind_card(void) { struct snd_soc_card *card, *c; - if (!list_empty(&unbind_card_list)) { - list_for_each_entry_safe(card, c, &unbind_card_list, list) { - if (!snd_soc_bind_card(card)) - list_del(&card->list); - } - } + list_for_each_entry_safe(card, c, &unbind_card_list, list) + if (!snd_soc_bind_card(card)) + list_del(&card->list); } int snd_soc_add_component(struct device *dev, -- cgit v1.2.3 From b3da42519c3e6ad977af844d61c31d0e5f874f1c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:31:24 +0900 Subject: ASoC: soc-core: tidyup for card->deferred_resume_work card->deferred_resume_work is used if CONFIG_PM_SLEEP was defined. but 1) It is defined even though CONFIG_PM_SLEEP was not defined 2) random ifdef code is difficult to read. This patch tidyup these issues. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/877e7paho1.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++-- sound/soc/soc-core.c | 14 ++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 6ac6481b4882..85ad971e9432 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1058,8 +1058,6 @@ struct snd_soc_card { int num_of_dapm_routes; bool fully_routed; - struct work_struct deferred_resume_work; - /* lists of probed devices belonging to this card */ struct list_head component_dev_list; struct list_head list; @@ -1079,6 +1077,9 @@ struct snd_soc_card { #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_card_root; +#endif +#ifdef CONFIG_PM_SLEEP + struct work_struct deferred_resume_work; #endif u32 pop_time; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6b0042835233..25b26caea4e0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -701,9 +701,18 @@ int snd_soc_resume(struct device *dev) return 0; } EXPORT_SYMBOL_GPL(snd_soc_resume); + +static void soc_resume_init(struct snd_soc_card *card) +{ + /* deferred resume work */ + INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); +} #else #define snd_soc_suspend NULL #define snd_soc_resume NULL +static inline void soc_resume_init(struct snd_soc_card *card) +{ +} #endif static const struct snd_soc_dai_ops null_dai_ops = { @@ -1984,10 +1993,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) soc_init_card_debugfs(card); -#ifdef CONFIG_PM_SLEEP - /* deferred resume work */ - INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); -#endif + soc_resume_init(card); ret = snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, card->num_dapm_widgets); -- cgit v1.2.3 From ee5b3f11416d1ba69e919b2fe86aae0b46f9a83e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:31:31 +0900 Subject: ASoC: soc-core: define soc_dpcm_debugfs_add() for non CONFIG_DEBUG_FS soc_dpcm_debugfs_add() is implemented at soc-pcm.c under CONFIG_DEBUG_FS. Thus, soc-core.c which is only user of it need to use CONFIG_DEBUG_FS, too. This patch defines soc_dpcm_debugfs_add() for non CONFIG_DEBUG_FS case. Then, we can remove #ifdef CONFIG_DEBUG_FS from soc-core.c Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/875zn9ahnv.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dpcm.h | 9 ++++++++- sound/soc/soc-core.c | 2 -- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index 4be3a2b7c106..e55aeb00ce2d 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -142,9 +142,16 @@ void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream, /* internal use only */ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute); -void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd); int soc_dpcm_runtime_update(struct snd_soc_card *); +#ifdef CONFIG_DEBUG_FS +void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd); +#else +static inline void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) +{ +} +#endif + int dpcm_path_get(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dapm_widget_list **list_); int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 25b26caea4e0..2a75fba31aa4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1487,11 +1487,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, if (ret) return ret; -#ifdef CONFIG_DEBUG_FS /* add DPCM sysfs entries */ if (dai_link->dynamic) soc_dpcm_debugfs_add(rtd); -#endif num = rtd->num; -- cgit v1.2.3 From 596becd3f82a7b7e091b0f5c380bc9a0e6758126 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Aug 2019 10:31:36 +0900 Subject: ASoC: soc-core: dai_link check under soc_dpcm_debugfs_add() soc_dpcm_debugfs_add(rtd) is checking rtd->dai_link pointer, but, rtd->dai_link->dynamic have been already checked before calling it. static int soc_probe_link_dais(...) { dai_link = rtd->dai_link; ... => if (dai_link->dynamic) => soc_dpcm_debugfs_add(rtd); ... } void soc_dpcm_debugfs_add(rtd) { => if (!rtd->dai_link) return; ... } These pointer checks are strange/pointless. This patch checks dai_link->dynamic under soc_dpcm_debugfs_add(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874l2tahnq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 3 +-- sound/soc/soc-pcm.c | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2a75fba31aa4..1fbd525763d5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1488,8 +1488,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, return ret; /* add DPCM sysfs entries */ - if (dai_link->dynamic) - soc_dpcm_debugfs_add(rtd); + soc_dpcm_debugfs_add(rtd); num = rtd->num; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 77c986fe08d0..da657c8179cc 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -3200,6 +3200,9 @@ void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) if (!rtd->dai_link) return; + if (!rtd->dai_link->dynamic) + return; + if (!rtd->card->debugfs_card_root) return; -- cgit v1.2.3 From 0e36f36b04e7677c6b74349c9d4baea1ed5668f2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 7 Aug 2019 21:51:31 -0500 Subject: ASoC: soc-core: fix module_put() warning in soc_cleanup_component The recent changes introduce warnings in the SOF load/unload module tests. The code does not seem balanced with a confusion between _close() and _remove() macros. Using _remove() fixes the issue and removes the warning. Suggested-by: Ranjani Sridharan Fixes: 4a81e8f30d0b4 ('ASoC: soc-component: add snd_soc_component_get/put()') Signed-off-by: Pierre-Louis Bossart Acked-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20190808025131.32482-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1fbd525763d5..bf45e60eb34f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -935,7 +935,7 @@ static void soc_cleanup_component(struct snd_soc_component *component) snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); component->card = NULL; - snd_soc_component_module_put_when_close(component); + snd_soc_component_module_put_when_remove(component); } static void soc_remove_component(struct snd_soc_component *component) -- cgit v1.2.3 From 8e082d8f42fabf9a4a0708d8012f4995765478fc Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 8 Aug 2019 11:25:52 +0800 Subject: ASoC: tscs454: remove unused variable 'PLL_48K_RATE' The global variable 'PLL_48K_RATE' is never used so just remove it. Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190808032552.45360-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/tscs454.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c index 93d84e5ae2d5..c3587af9985c 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -22,7 +22,6 @@ #include "tscs454.h" -static const unsigned int PLL_48K_RATE = (48000 * 256); static const unsigned int PLL_44_1K_RATE = (44100 * 256); #define COEFF_SIZE 3 -- cgit v1.2.3 From 0e4cc44f5066b22938f384cd57db99d66311de90 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Thu, 8 Aug 2019 14:27:34 -0500 Subject: ASoC: intel: skl_hda_dsp_common: create HDMI jack kctl This patch call snd_jack_add_new_kctl() to create the HDMI jack kctls. Userspace needs these kctls to detect the hdmi monitor hotplug. In /usr/share/alsa/ucm, the config file needs to assign a jack kctl to "JackControl" to let PA get the jack hotplug status. Signed-off-by: Libin Yang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190808192734.18286-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_hda_dsp_common.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c index 55fd82e05e2c..58409b6e476e 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -147,6 +147,11 @@ int skl_hda_hdmi_jack_init(struct snd_soc_card *card) 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) -- cgit v1.2.3 From 63e45324c284d240562a5b435afc4b23ae7d923c Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 8 Aug 2019 20:15:48 +0200 Subject: ASoC: Intel: Skylake: Limit large_config_get to single frame Reply for the very first LARGE_CONFIG_GET request contains total size of payload to be retrieved by host. From then on, each subsequent reply carries buffer offset instead. As looping is not covered by any real-life example, remove it and cleanup the function for followup overhaul. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190808181549.12521-2-cezary.rojewski@intel.com Reviewed-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-ipc.c | 37 +++++++---------------------------- 1 file changed, 7 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index a2b69a02aab2..196c80dadb1f 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -973,8 +973,7 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, { struct skl_ipc_header header = {0}; struct sst_ipc_message request = {0}, reply = {0}; - int ret = 0; - size_t sz_remaining, rx_size, data_offset; + int ret; header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); @@ -987,34 +986,12 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, header.extension |= IPC_FINAL_BLOCK(1); header.extension |= IPC_INITIAL_BLOCK(1); - sz_remaining = msg->param_data_size; - data_offset = 0; - - while (sz_remaining != 0) { - rx_size = sz_remaining > SKL_ADSP_W1_SZ - ? SKL_ADSP_W1_SZ : sz_remaining; - if (rx_size == sz_remaining) - header.extension |= IPC_FINAL_BLOCK(1); - - request.header = *(u64 *)(&header); - reply.data = ((char *)param) + data_offset; - reply.size = msg->param_data_size; - ret = sst_ipc_tx_message_wait(ipc, request, &reply); - if (ret < 0) { - dev_err(ipc->dev, - "ipc: get large config fail, err: %d\n", ret); - return ret; - } - sz_remaining -= rx_size; - data_offset = msg->param_data_size - sz_remaining; - - /* clear the fields */ - header.extension &= IPC_INITIAL_BLOCK_CLEAR; - header.extension &= IPC_DATA_OFFSET_SZ_CLEAR; - /* fill the fields */ - header.extension |= IPC_INITIAL_BLOCK(1); - header.extension |= IPC_DATA_OFFSET_SZ(data_offset); - } + request.header = *(u64 *)(&header); + reply.data = param; + reply.size = msg->param_data_size; + ret = sst_ipc_tx_message_wait(ipc, request, &reply); + if (ret < 0) + dev_err(ipc->dev, "ipc: get large config fail, err: %d\n", ret); return ret; } -- cgit v1.2.3 From 36004c42c761a6d95b867a4fbb9a955034e53351 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 8 Aug 2019 20:15:49 +0200 Subject: ASoC: Intel: Skylake: large_config_get overhaul LARGE_CONFIG_GET is mainly used to retrieve requested module parameters but it may also carry TX payload with them. Update its implementation to account for both TX and RX data. First reply.header carries total payload size within data_off_sizefield. Make use of reply.header to realloc returned buffer with correct size. Failure of IPC request is permissive - error-payload may be returned, an informative data why GET for given param failed - and thus function should not collapse before entire processing is finished. Caller is responsible for checking returned payload and bytes parameters. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190808181549.12521-3-cezary.rojewski@intel.com Reviewed-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 3 ++- sound/soc/intel/skylake/skl-sst-ipc.c | 25 ++++++++++++++++++++----- sound/soc/intel/skylake/skl-sst-ipc.h | 3 ++- 3 files changed, 24 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index e8cc710f092b..84f0e6f58eb5 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -1379,11 +1379,12 @@ int skl_get_module_params(struct skl_dev *skl, u32 *params, int size, u32 param_id, struct skl_module_cfg *mcfg) { struct skl_ipc_large_config_msg msg; + size_t bytes = size; msg.module_id = mcfg->id.module_id; msg.instance_id = mcfg->id.pvt_id; msg.param_data_size = size; msg.large_param_id = param_id; - return skl_ipc_get_large_config(&skl->ipc, &msg, params); + return skl_ipc_get_large_config(&skl->ipc, &msg, ¶ms, &bytes); } diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 196c80dadb1f..667cdddc289f 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -969,12 +969,18 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, EXPORT_SYMBOL_GPL(skl_ipc_set_large_config); int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, - struct skl_ipc_large_config_msg *msg, u32 *param) + struct skl_ipc_large_config_msg *msg, + u32 **payload, size_t *bytes) { struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}, reply = {0}; + struct sst_ipc_message request, reply = {0}; + unsigned int *buf; int ret; + reply.data = kzalloc(SKL_ADSP_W1_SZ, GFP_KERNEL); + if (!reply.data) + return -ENOMEM; + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_GET); @@ -986,13 +992,22 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, header.extension |= IPC_FINAL_BLOCK(1); header.extension |= IPC_INITIAL_BLOCK(1); - request.header = *(u64 *)(&header); - reply.data = param; - reply.size = msg->param_data_size; + request.header = *(u64 *)&header; + request.data = *payload; + request.size = *bytes; + reply.size = SKL_ADSP_W1_SZ; + ret = sst_ipc_tx_message_wait(ipc, request, &reply); if (ret < 0) dev_err(ipc->dev, "ipc: get large config fail, err: %d\n", ret); + reply.size = (reply.header >> 32) & IPC_DATA_OFFSET_SZ_MASK; + buf = krealloc(reply.data, reply.size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + *payload = buf; + *bytes = reply.size; + return ret; } EXPORT_SYMBOL_GPL(skl_ipc_get_large_config); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 93af08cf41d2..08ac31778325 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -139,7 +139,8 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, struct skl_ipc_large_config_msg *msg, u32 *param); int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, - struct skl_ipc_large_config_msg *msg, u32 *param); + struct skl_ipc_large_config_msg *msg, + u32 **payload, size_t *bytes); int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, u8 dma_id, u8 table_id, bool wait); -- cgit v1.2.3 From f6326fa4855b0f8173af822fcc139afdbf4d4b71 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 8 Aug 2019 23:15:54 +0100 Subject: ASoC: sof: Fix warning when IPC flood test is not enabled dentry is only used when the flood test is done so move the declaration of the variable inside the ifdef for the flood test. Signed-off-by: Mark Brown --- sound/soc/sof/debug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 40940b2fe9d5..54cd431faab7 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -221,7 +221,6 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, { struct snd_sof_dfsentry *dfse = file->private_data; struct snd_sof_dev *sdev = dfse->sdev; - struct dentry *dentry; loff_t pos = *ppos; size_t size_ret; int skip = 0; @@ -229,6 +228,8 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, u8 *buf; #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) + struct dentry *dentry; + dentry = file->f_path.dentry; if ((!strcmp(dentry->d_name.name, "ipc_flood_count") || !strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) && -- cgit v1.2.3 From fe4010667741df8c8d6bef1780ec34ebf43cf007 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 9 Aug 2019 12:54:58 +1000 Subject: ALSA: hda: readl/writel need linux/io.h Fixes: 19abfefd4c76 ("ALSA: hda: Direct MMIO accesses") Signed-off-by: Stephen Rothwell Signed-off-by: Takashi Iwai --- sound/hda/hdac_bus.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index dc2523ef7d98..cd25e2b3f7f2 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include -- cgit v1.2.3 From cc911c2251f07470f8e085ec8ff670e6bdd56add Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 9 Aug 2019 17:01:13 +0800 Subject: ALSA: ac97: remove unused variable 'snd_ac97_controls_master_mono' sound/pci/ac97/ac97_codec.c:599:38: warning: snd_ac97_controls_master_mono defined but not used [-Wunused-const-variable=] It is never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 96b4601aae73..66f6c3bf08e3 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -596,11 +596,6 @@ static int snd_ac97_put_volsw(struct snd_kcontrol *kcontrol, return err; } -static const struct snd_kcontrol_new snd_ac97_controls_master_mono[2] = { -AC97_SINGLE("Master Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1), -AC97_SINGLE("Master Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1) -}; - static const struct snd_kcontrol_new snd_ac97_controls_tone[2] = { AC97_SINGLE("Tone Control - Bass", AC97_MASTER_TONE, 8, 15, 1), AC97_SINGLE("Tone Control - Treble", AC97_MASTER_TONE, 0, 15, 1) -- cgit v1.2.3 From a62bd63893027bfa32fccbba0e0ac067824c362c Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 9 Aug 2019 19:01:00 +0800 Subject: ASoC: SOF: Intel: Add missing include file hdac_hda.h Building with SND_SOC_SOF_HDA_AUDIO_CODEC fails: sound/soc/sof/intel/hda-bus.c: In function sof_hda_bus_init: sound/soc/sof/intel/hda-bus.c:16:25: error: implicit declaration of function snd_soc_hdac_hda_get_ops; did you mean snd_soc_jack_add_gpiods? [-Werror=implicit-function-declaration] #define sof_hda_ext_ops snd_soc_hdac_hda_get_ops() Reported-by: Hulk Robot Suggested-by: Takashi Iwai Fixes: d4ff1b3917a5 ('ASoC: SOF: Intel: Initialize hdaudio bus properly") Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190809110100.71236-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-bus.c | 1 + sound/soc/sof/intel/hda.c | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 0caec3a070d3..1d2babdda9dd 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -13,6 +13,7 @@ #include "hda.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +#include "../../codecs/hdac_hda.h" #define sof_hda_ext_ops snd_soc_hdac_hda_get_ops() #else #define sof_hda_ext_ops NULL diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index d04844d6b104..28eb780494aa 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -23,9 +23,6 @@ #include #include "../ops.h" #include "hda.h" -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) -#include "../../codecs/hdac_hda.h" -#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) #include -- cgit v1.2.3 From bc8d9f737fc01cce913f1cc215b7e66f01697e52 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 9 Aug 2019 16:02:34 +0800 Subject: ASoC: mt6351: remove unused variable 'mt_lineout_control' sound/soc/codecs/mt6351.c:1070:38: warning: mt_lineout_control defined but not used [-Wunused-const-variable=] It is never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190809080234.23332-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6351.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c index 4b3ce01c5a93..5c0536eb1044 100644 --- a/sound/soc/codecs/mt6351.c +++ b/sound/soc/codecs/mt6351.c @@ -1066,11 +1066,6 @@ static int mt_mic_bias_2_event(struct snd_soc_dapm_widget *w, return 0; } -/* DAPM Kcontrols */ -static const struct snd_kcontrol_new mt_lineout_control = - SOC_DAPM_SINGLE("Switch", MT6351_AUDDEC_ANA_CON3, - RG_AUDLOLPWRUP_VAUDP32_BIT, 1, 0); - /* DAPM Widgets */ static const struct snd_soc_dapm_widget mt6351_dapm_widgets[] = { /* Digital Clock */ -- cgit v1.2.3 From 0fd70e22a0ffebd13028bf2c7da6b747070475bf Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 9 Aug 2019 16:24:40 +0800 Subject: ASoC: ml26124: remove unused variable 'ngth' In file included from ./include/sound/tlv.h:10:0, from sound/soc/codecs/ml26124.c:19: sound/soc/codecs/ml26124.c:59:35: warning: ngth defined but not used [-Wunused-const-variable=] static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0); ^ ./include/uapi/sound/tlv.h:64:15: note: in definition of macro SNDRV_CTL_TLVD_DECLARE_DB_SCALE unsigned int name[] = { \ ^~~~ sound/soc/codecs/ml26124.c:59:14: note: in expansion of macro DECLARE_TLV_DB_SCALE static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0); ^~~~~~~~~~~~~~~~~~~~ It is never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190809082440.67412-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/ml26124.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 3abd27893ce6..55823bc95d06 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -56,7 +56,6 @@ static const DECLARE_TLV_DB_SCALE(alclvl, -2250, 150, 0); static const DECLARE_TLV_DB_SCALE(mingain, -1200, 600, 0); static const DECLARE_TLV_DB_SCALE(maxgain, -675, 600, 0); static const DECLARE_TLV_DB_SCALE(boost_vol, -1200, 75, 0); -static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0); static const char * const ml26124_companding[] = {"16bit PCM", "u-law", "A-law"}; -- cgit v1.2.3 From 0b76f512c206dd7c3f7761b24826887af80204c6 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 7 Aug 2019 10:01:58 -0500 Subject: ASoC: SOF: Remove call to snd_sof_dsp_mailbox_init This is reserved for some historical reason, we didn't enable memory windows for byt/bdw at the beginning, to make it compatible, we get those mailbox offsets from fw_ready struct firstly, and then update them if they existed in the following memory windows, to make sure the mailbox still can be used if no memory windows are created. With this change all platforms have the same implementation for xxx_fw_ready function so that we can refactor it in a common file. Suggested-by: Keyon Jie Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190807150203.26359-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/bdw.c | 5 ----- sound/soc/sof/intel/byt.c | 5 ----- 2 files changed, 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 4bb9636da990..94be024a99eb 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -455,11 +455,6 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, sizeof(*fw_ready)); - snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, - fw_ready->dspbox_size, - fw_ready->hostbox_offset, - fw_ready->hostbox_size); - /* make sure ABI version is compatible */ ret = snd_sof_ipc_valid(sdev); if (ret < 0) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 000d576f6a8d..cb8f02ee09f2 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -237,11 +237,6 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, sizeof(*fw_ready)); - snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, - fw_ready->dspbox_size, - fw_ready->hostbox_offset, - fw_ready->hostbox_size); - /* make sure ABI version is compatible */ ret = snd_sof_ipc_valid(sdev); if (ret < 0) -- cgit v1.2.3 From ddf14b640b05839cfe44d686d5a5cc7c55076094 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 7 Aug 2019 10:02:02 -0500 Subject: ASoC: SOF: Intel: bdw: Use generic function for fw ready / mem windows creation bdw_get_windows / bdw_fw_ready is identical with the generic implementation introduced in a previous patch. So remove bdw_get_windows / bdw_fw_ready and use the generic sof_get_windows version. Do not forget to implement get_mailbox_offset/get_window_offset so that we export the correct mailbox/memory window offset to the outside world. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190807150203.26359-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/bdw.c | 156 ++++------------------------------------------ 1 file changed, 13 insertions(+), 143 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 94be024a99eb..e282179263e8 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -327,148 +327,6 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) return IRQ_HANDLED; } -/* - * IPC Firmware ready. - */ -static void bdw_get_windows(struct snd_sof_dev *sdev) -{ - struct sof_ipc_window_elem *elem; - u32 outbox_offset = 0; - u32 stream_offset = 0; - u32 inbox_offset = 0; - u32 outbox_size = 0; - u32 stream_size = 0; - u32 inbox_size = 0; - int i; - - if (!sdev->info_window) { - dev_err(sdev->dev, "error: have no window info\n"); - return; - } - - for (i = 0; i < sdev->info_window->num_windows; i++) { - elem = &sdev->info_window->window[i]; - - switch (elem->type) { - case SOF_IPC_REGION_UPBOX: - inbox_offset = elem->offset + MBOX_OFFSET; - inbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - inbox_offset, - elem->size, "inbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DOWNBOX: - outbox_offset = elem->offset + MBOX_OFFSET; - outbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - outbox_offset, - elem->size, "outbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "etrace", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "debug", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_STREAM: - stream_offset = elem->offset + MBOX_OFFSET; - stream_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - stream_offset, - elem->size, "stream", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "regs", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_EXCEPTION: - sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "exception", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - default: - dev_err(sdev->dev, "error: get illegal window info\n"); - return; - } - } - - if (outbox_size == 0 || inbox_size == 0) { - dev_err(sdev->dev, "error: get illegal mailbox window\n"); - return; - } - - snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, - outbox_offset, outbox_size); - sdev->stream_box.offset = stream_offset; - sdev->stream_box.size = stream_size; - - dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", - inbox_offset, inbox_size); - dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", - outbox_offset, outbox_size); - dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", - stream_offset, stream_size); -} - -/* check for ABI compatibility and create memory windows on first boot */ -static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) -{ - struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - u32 offset; - int ret; - - /* mailbox must be on 4k boundary */ - offset = MBOX_OFFSET; - - dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset %d\n", - msg_id, offset); - - /* no need to re-check version/ABI for subsequent boots */ - if (!sdev->first_boot) - return 0; - - /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); - - /* make sure ABI version is compatible */ - ret = snd_sof_ipc_valid(sdev); - if (ret < 0) - return ret; - - /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + - sizeof(struct sof_ipc_fw_ready)); - - bdw_get_windows(sdev); - - return 0; -} - /* * IPC Mailbox IO */ @@ -522,6 +380,16 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) msg->reply_error = ret; } +static int bdw_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MBOX_OFFSET; +} + +static int bdw_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MBOX_OFFSET; +} + static void bdw_host_done(struct snd_sof_dev *sdev) { /* clear BUSY bit and set DONE bit - accept new messages */ @@ -672,7 +540,9 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { /* ipc */ .send_msg = bdw_send_msg, - .fw_ready = bdw_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = bdw_get_mailbox_offset, + .get_window_offset = bdw_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, -- cgit v1.2.3 From 6eebd3907527764618ee250e1106b9e809c46143 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 7 Aug 2019 10:02:03 -0500 Subject: ASoC: SOF: Intel: hda: Use generic function for fw ready / mem windows creation We can use generic sof_fw_ready function and reduce code duplication. Careful here that we need to provide the implementation for get_mailbox_offset and get_window_offset. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190807150203.26359-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 4 +- sound/soc/sof/intel/cnl.c | 4 +- sound/soc/sof/intel/hda-ipc.c | 150 ++---------------------------------------- sound/soc/sof/intel/hda.h | 4 +- 4 files changed, 13 insertions(+), 149 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index fd2e26d79796..8dc7a5558da4 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -46,7 +46,9 @@ const struct snd_sof_dsp_ops sof_apl_ops = { /* ipc */ .send_msg = hda_dsp_ipc_send_msg, - .fw_ready = hda_dsp_ipc_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, + .get_window_offset = hda_dsp_ipc_get_window_offset, .ipc_msg_data = hda_ipc_msg_data, .ipc_pcm_params = hda_ipc_pcm_params, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index ffd8d4394537..6d7d9c93252c 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -204,7 +204,9 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { /* ipc */ .send_msg = cnl_ipc_send_msg, - .fw_ready = hda_dsp_ipc_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, + .get_window_offset = hda_dsp_ipc_get_window_offset, .ipc_msg_data = hda_ipc_msg_data, .ipc_pcm_params = hda_ipc_pcm_params, diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 2ecba91f5219..6aae6f18b3dc 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -266,156 +266,14 @@ out: return ret; } -/* IPC Firmware ready */ - -static void ipc_get_windows(struct snd_sof_dev *sdev) +int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { - struct sof_ipc_window_elem *elem; - u32 outbox_offset = 0; - u32 stream_offset = 0; - u32 inbox_offset = 0; - u32 outbox_size = 0; - u32 stream_size = 0; - u32 inbox_size = 0; - int i; - - if (!sdev->info_window) { - dev_err(sdev->dev, "error: have no window info\n"); - return; - } - - for (i = 0; i < sdev->info_window->num_windows; i++) { - elem = &sdev->info_window->window[i]; - - switch (elem->type) { - case SOF_IPC_REGION_UPBOX: - inbox_offset = - elem->offset + SRAM_WINDOW_OFFSET(elem->id); - inbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - inbox_offset, - elem->size, "inbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DOWNBOX: - outbox_offset = - elem->offset + SRAM_WINDOW_OFFSET(elem->id); - outbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - outbox_offset, - elem->size, "outbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "etrace", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "debug", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_STREAM: - stream_offset = - elem->offset + SRAM_WINDOW_OFFSET(elem->id); - stream_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "stream", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "regs", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_EXCEPTION: - sdev->dsp_oops_offset = elem->offset + - SRAM_WINDOW_OFFSET(elem->id); - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "exception", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - default: - dev_err(sdev->dev, "error: get illegal window info\n"); - return; - } - } - - if (outbox_size == 0 || inbox_size == 0) { - dev_err(sdev->dev, "error: get illegal mailbox window\n"); - return; - } - - snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, - outbox_offset, outbox_size); - sdev->stream_box.offset = stream_offset; - sdev->stream_box.size = stream_size; - - dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", - inbox_offset, inbox_size); - dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", - outbox_offset, outbox_size); - dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", - stream_offset, stream_size); + return HDA_DSP_MBOX_UPLINK_OFFSET; } -/* check for ABI compatibility and create memory windows on first boot */ -int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) { - struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - u32 offset; - int ret; - - /* mailbox must be on 4k boundary */ - offset = HDA_DSP_MBOX_UPLINK_OFFSET; - - dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", - msg_id, offset); - - /* no need to re-check version/ABI for subsequent boots */ - if (!sdev->first_boot) - return 0; - - /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); - - /* make sure ABI version is compatible */ - ret = snd_sof_ipc_valid(sdev); - if (ret < 0) - return ret; - - /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, - HDA_DSP_MBOX_UPLINK_OFFSET + - sizeof(struct sof_ipc_fw_ready)); - - ipc_get_windows(sdev); - - return 0; + return SRAM_WINDOW_OFFSET(id); } void hda_ipc_msg_data(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 65904c3511df..6db3dcbab3bd 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -519,7 +519,9 @@ int hda_ipc_pcm_params(struct snd_sof_dev *sdev, int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev); -int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id); +int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev); +int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id); + irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context); irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context); int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); -- cgit v1.2.3 From bb9c93f58cb66049cb5a5570cc476d9a8a97f491 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 7 Aug 2019 10:01:59 -0500 Subject: ASoC: SOF: Introduce snd_sof_dsp_get_mailbox_offset This will allow us to export mailbox offset in order to read the fw_ready message from. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190807150203.26359-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ops.h | 9 +++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 11 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 793c1aea0c53..c820606f19a1 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -119,6 +119,15 @@ static inline int snd_sof_dsp_get_bar_index(struct snd_sof_dev *sdev, u32 type) return sdev->mmio_bar; } +static inline int snd_sof_dsp_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->get_mailbox_offset) + return sof_ops(sdev)->get_mailbox_offset(sdev); + + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; +} + /* power management */ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 1cec3f23f9cd..3aefb8ec3ef9 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -198,6 +198,8 @@ struct snd_sof_dsp_ops { /* misc */ int (*get_bar_index)(struct snd_sof_dev *sdev, u32 type); /* optional */ + int (*get_mailbox_offset)(struct snd_sof_dev *sdev);/* mandatory for common loader code */ + /* DAI ops */ struct snd_soc_dai_driver *drv; int num_drv; -- cgit v1.2.3 From e17422cda9d60339d71e117d3fdfd444e83669a4 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 7 Aug 2019 10:02:00 -0500 Subject: ASoC: SOF: Introduce snd_sof_dsp_get_window_offset This will allow us to export the offset for a memory window. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190807150203.26359-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ops.h | 9 +++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 11 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index c820606f19a1..824d36fe59fd 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -128,6 +128,15 @@ static inline int snd_sof_dsp_get_mailbox_offset(struct snd_sof_dev *sdev) return -ENOTSUPP; } +static inline int snd_sof_dsp_get_window_offset(struct snd_sof_dev *sdev, + u32 id) +{ + if (sof_ops(sdev)->get_window_offset) + return sof_ops(sdev)->get_window_offset(sdev, id); + + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; +} /* power management */ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 3aefb8ec3ef9..de11f28bae3a 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -199,6 +199,8 @@ struct snd_sof_dsp_ops { int (*get_bar_index)(struct snd_sof_dev *sdev, u32 type); /* optional */ int (*get_mailbox_offset)(struct snd_sof_dev *sdev);/* mandatory for common loader code */ + int (*get_window_offset)(struct snd_sof_dev *sdev, + u32 id);/* mandatory for common loader code */ /* DAI ops */ struct snd_soc_dai_driver *drv; -- cgit v1.2.3 From 83ee7ab1627b7597bbb9acc26b37e9f96fff40c9 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 7 Aug 2019 10:02:01 -0500 Subject: ASoC: SOF: Intel: byt: Refactor fw ready / mem windows creation There is a lot of duplicate code when processing IPC firmware ready notification and creating memory windows. First step in reducing the code duplication is to introduce generic functions: * sof_get_windows * sof_fw_ready that will replace, in the first step, the specific implementation related to baytrail related platforms: * byt_get_windows * byt_fw_ready So we are basically moving code from intel/byt.c to loader.c keeping in mind that mbox_offset is a per platform constant so we need to use newly introduced snd_sof_dsp_get_mailbox_offset / snd_sof_dsp_get_window_offset in order to get the correct mbox offset / window offset value. Also, bar is a per platform constant so we use snd_sof_dsp_get_bar_index instead of the hardcoded BYT_DSP_BAR. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190807150203.26359-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/byt.c | 164 ++++++-------------------------------------- sound/soc/sof/loader.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 2 + 3 files changed, 189 insertions(+), 145 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index cb8f02ee09f2..5e7a6aaa627a 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -109,148 +109,6 @@ static void byt_host_done(struct snd_sof_dev *sdev); static void byt_dsp_done(struct snd_sof_dev *sdev); static void byt_get_reply(struct snd_sof_dev *sdev); -/* - * IPC Firmware ready. - */ -static void byt_get_windows(struct snd_sof_dev *sdev) -{ - struct sof_ipc_window_elem *elem; - u32 outbox_offset = 0; - u32 stream_offset = 0; - u32 inbox_offset = 0; - u32 outbox_size = 0; - u32 stream_size = 0; - u32 inbox_size = 0; - int i; - - if (!sdev->info_window) { - dev_err(sdev->dev, "error: have no window info\n"); - return; - } - - for (i = 0; i < sdev->info_window->num_windows; i++) { - elem = &sdev->info_window->window[i]; - - switch (elem->type) { - case SOF_IPC_REGION_UPBOX: - inbox_offset = elem->offset + MBOX_OFFSET; - inbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - inbox_offset, - elem->size, "inbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DOWNBOX: - outbox_offset = elem->offset + MBOX_OFFSET; - outbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - outbox_offset, - elem->size, "outbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "etrace", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "debug", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_STREAM: - stream_offset = elem->offset + MBOX_OFFSET; - stream_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - stream_offset, - elem->size, "stream", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "regs", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_EXCEPTION: - sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "exception", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - default: - dev_err(sdev->dev, "error: get illegal window info\n"); - return; - } - } - - if (outbox_size == 0 || inbox_size == 0) { - dev_err(sdev->dev, "error: get illegal mailbox window\n"); - return; - } - - snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, - outbox_offset, outbox_size); - sdev->stream_box.offset = stream_offset; - sdev->stream_box.size = stream_size; - - dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", - inbox_offset, inbox_size); - dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", - outbox_offset, outbox_size); - dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", - stream_offset, stream_size); -} - -/* check for ABI compatibility and create memory windows on first boot */ -static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) -{ - struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - u32 offset; - int ret; - - /* mailbox must be on 4k boundary */ - offset = MBOX_OFFSET; - - dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", - msg_id, offset); - - /* no need to re-check version/ABI for subsequent boots */ - if (!sdev->first_boot) - return 0; - - /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); - - /* make sure ABI version is compatible */ - ret = snd_sof_ipc_valid(sdev); - if (ret < 0) - return ret; - - /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + - sizeof(struct sof_ipc_fw_ready)); - - byt_get_windows(sdev); - - return 0; -} - /* * Debug */ @@ -418,6 +276,16 @@ static void byt_get_reply(struct snd_sof_dev *sdev) msg->reply_error = ret; } +static int byt_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MBOX_OFFSET; +} + +static int byt_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MBOX_OFFSET; +} + static void byt_host_done(struct snd_sof_dev *sdev) { /* clear BUSY bit and set DONE bit - accept new messages */ @@ -612,7 +480,9 @@ const struct snd_sof_dsp_ops sof_tng_ops = { /* ipc */ .send_msg = byt_send_msg, - .fw_ready = byt_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = byt_get_mailbox_offset, + .get_window_offset = byt_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, @@ -771,7 +641,9 @@ const struct snd_sof_dsp_ops sof_byt_ops = { /* ipc */ .send_msg = byt_send_msg, - .fw_ready = byt_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = byt_get_mailbox_offset, + .get_window_offset = byt_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, @@ -828,7 +700,9 @@ const struct snd_sof_dsp_ops sof_cht_ops = { /* ipc */ .send_msg = byt_send_msg, - .fw_ready = byt_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = byt_get_mailbox_offset, + .get_window_offset = byt_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 93cb8fd0844f..d7f32745fefe 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -87,6 +87,174 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) } EXPORT_SYMBOL(snd_sof_fw_parse_ext_data); +/* + * IPC Firmware ready. + */ +static void sof_get_windows(struct snd_sof_dev *sdev) +{ + struct sof_ipc_window_elem *elem; + u32 outbox_offset = 0; + u32 stream_offset = 0; + u32 inbox_offset = 0; + u32 outbox_size = 0; + u32 stream_size = 0; + u32 inbox_size = 0; + int window_offset; + int bar; + int i; + + if (!sdev->info_window) { + dev_err(sdev->dev, "error: have no window info\n"); + return; + } + + bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM); + if (bar < 0) { + dev_err(sdev->dev, "error: have no bar mapping\n"); + return; + } + + for (i = 0; i < sdev->info_window->num_windows; i++) { + elem = &sdev->info_window->window[i]; + + window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id); + if (window_offset < 0) { + dev_warn(sdev->dev, "warn: no offset for window %d\n", + elem->id); + continue; + } + + switch (elem->type) { + case SOF_IPC_REGION_UPBOX: + inbox_offset = window_offset + elem->offset; + inbox_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + inbox_offset, + elem->size, "inbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_DOWNBOX: + outbox_offset = window_offset + elem->offset; + outbox_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + outbox_offset, + elem->size, "outbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_TRACE: + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + window_offset + + elem->offset, + elem->size, "etrace", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_DEBUG: + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + window_offset + + elem->offset, + elem->size, "debug", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_STREAM: + stream_offset = window_offset + elem->offset; + stream_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + stream_offset, + elem->size, "stream", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_REGS: + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + window_offset + + elem->offset, + elem->size, "regs", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_EXCEPTION: + sdev->dsp_oops_offset = window_offset + elem->offset; + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + window_offset + + elem->offset, + elem->size, "exception", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + default: + dev_err(sdev->dev, "error: get illegal window info\n"); + return; + } + } + + if (outbox_size == 0 || inbox_size == 0) { + dev_err(sdev->dev, "error: get illegal mailbox window\n"); + return; + } + + snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, + outbox_offset, outbox_size); + sdev->stream_box.offset = stream_offset; + sdev->stream_box.size = stream_size; + + dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", + inbox_offset, inbox_size); + dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", + outbox_offset, outbox_size); + dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", + stream_offset, stream_size); +} + +/* check for ABI compatibility and create memory windows on first boot */ +int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; + int offset; + int bar; + int ret; + + /* mailbox must be on 4k boundary */ + offset = snd_sof_dsp_get_mailbox_offset(sdev); + if (offset < 0) { + dev_err(sdev->dev, "error: have no mailbox offset\n"); + return offset; + } + + bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM); + if (bar < 0) { + dev_err(sdev->dev, "error: have no bar mapping\n"); + return -EINVAL; + } + + dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", + msg_id, offset); + + /* no need to re-check version/ABI for subsequent boots */ + if (!sdev->first_boot) + return 0; + + /* copy data from the DSP FW ready offset */ + sof_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready)); + + /* make sure ABI version is compatible */ + ret = snd_sof_ipc_valid(sdev); + if (ret < 0) + return ret; + + /* now check for extended data */ + snd_sof_fw_parse_ext_data(sdev, bar, offset + + sizeof(struct sof_ipc_fw_ready)); + + sof_get_windows(sdev); + + return 0; +} +EXPORT_SYMBOL(sof_fw_ready); + /* generic module parser for mmaped DSPs */ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index de11f28bae3a..730f3259dd02 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -642,6 +642,8 @@ void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t size); +int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id); + void intel_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, void *p, size_t sz); -- cgit v1.2.3 From 40073a9d53eac3f3ebf569aa9afd61301eff9190 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 9 Aug 2019 19:01:00 +0800 Subject: ASoC: SOF: Intel: Add missing include file hdac_hda.h Building with SND_SOC_SOF_HDA_AUDIO_CODEC fails: sound/soc/sof/intel/hda-bus.c: In function sof_hda_bus_init: sound/soc/sof/intel/hda-bus.c:16:25: error: implicit declaration of function snd_soc_hdac_hda_get_ops; did you mean snd_soc_jack_add_gpiods? [-Werror=implicit-function-declaration] #define sof_hda_ext_ops snd_soc_hdac_hda_get_ops() Reported-by: Hulk Robot Suggested-by: Takashi Iwai Fixes: d4ff1b3917a5 ("ASoC: SOF: Intel: Initialize hdaudio bus properly") Signed-off-by: YueHaibing Signed-off-by: Takashi Iwai --- sound/soc/sof/intel/hda-bus.c | 1 + sound/soc/sof/intel/hda.c | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 0caec3a070d3..1d2babdda9dd 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -13,6 +13,7 @@ #include "hda.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +#include "../../codecs/hdac_hda.h" #define sof_hda_ext_ops snd_soc_hdac_hda_get_ops() #else #define sof_hda_ext_ops NULL diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 7ca27000c34d..dd6c8ad62b3e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -23,9 +23,6 @@ #include #include "../ops.h" #include "hda.h" -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) -#include "../../codecs/hdac_hda.h" -#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) #include -- cgit v1.2.3 From f43ec25aa5480515a39a405084ca8cb5e2c408aa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 9 Aug 2019 16:13:16 +0200 Subject: ALSA: hda - Inform too slow responses For the sake of debugging, show each response that took too long time and its corresponding last verb. Since such an error happens in series once when started, use the ratelimited variant for suppressing the flood. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 156930d0c9d3..ec0608d44263 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -789,6 +789,7 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr, unsigned long timeout; unsigned long loopcounter; int do_poll = 0; + bool warned = false; again: timeout = jiffies + msecs_to_jiffies(1000); @@ -808,9 +809,17 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr, spin_unlock_irq(&bus->reg_lock); if (time_after(jiffies, timeout)) break; - if (hbus->needs_damn_long_delay || loopcounter > 3000) +#define LOOP_COUNT_MAX 3000 + if (hbus->needs_damn_long_delay || + loopcounter > LOOP_COUNT_MAX) { + if (loopcounter > LOOP_COUNT_MAX && !warned) { + dev_dbg_ratelimited(chip->card->dev, + "too slow response, last cmd=%#08x\n", + bus->last_cmd[addr]); + warned = true; + } msleep(2); /* temporary workaround */ - else { + } else { udelay(10); cond_resched(); } -- cgit v1.2.3 From a2ef03fe617a8365fb7794531b11ba587509a9b9 Mon Sep 17 00:00:00 2001 From: Tomas Espeleta Date: Fri, 9 Aug 2019 16:37:54 +0200 Subject: ALSA: hda - Add a quirk model for fixing Huawei Matebook X right speaker [ This is rather a revival of the patch Tomas sent in months ago, but applying only with the quirk model option -- tiwai ] Hard coded coefficients to make Huawuei Matebook X right speaker work. The Matebook X has a ALC298, please refer to bug 197801 on how these numbers were reverse engineered from the Windows driver The reversed engineered sequence represents a repeating pattern of verbs, and the only values that are changing periodically are written on indexes 0x23 and 0x25: 0x500, 0x23 0x400, VALUE1 0x500, 0x25 0x400, VALUE2 * skipped reading sequences (0x500 - 0xc00 sequences are ignored) * static values from reverse engineering are used NOTE: since a significant risk is still considered, this is provided as an experimental fix that isn't applied as default for now. For enabling the fix, you'll have to choose huawei-mbx-stereo via model option of snd-hda-intel module. If we get feedback from users that this works stably, we may apply it per default. [ Some coding style fixes and replacement with AC_VERB_* by tiwai ] BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=197801 Signed-off-by: Tomas Espeleta Signed-off-by: Takashi Iwai --- Documentation/sound/hd-audio/models.rst | 3 ++ sound/pci/hda/patch_realtek.c | 74 +++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) (limited to 'sound') diff --git a/Documentation/sound/hd-audio/models.rst b/Documentation/sound/hd-audio/models.rst index 7d7c191102a7..11298f0ce44d 100644 --- a/Documentation/sound/hd-audio/models.rst +++ b/Documentation/sound/hd-audio/models.rst @@ -260,6 +260,9 @@ alc295-hp-x360 HP Spectre X360 fixups alc-sense-combo Headset button support for Chrome platform +huawei-mbx-stereo + Enable initialization verbs for Huawei MBX stereo speakers; + might be risky, try this at your own risk ALC66x/67x/892 ============== diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index de224cbea7a0..cb7baa65b298 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3762,6 +3762,72 @@ static void alc269_x101_hp_automute_hook(struct hda_codec *codec, vref); } +/* + * Magic sequence to make Huawei Matebook X right speaker working (bko#197801) + */ +struct hda_alc298_mbxinit { + unsigned char value_0x23; + unsigned char value_0x25; +}; + +static void alc298_huawei_mbx_stereo_seq(struct hda_codec *codec, + const struct hda_alc298_mbxinit *initval, + bool first) +{ + snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x0); + alc_write_coef_idx(codec, 0x26, 0xb000); + + if (first) + snd_hda_codec_write(codec, 0x21, 0, AC_VERB_GET_PIN_SENSE, 0x0); + + snd_hda_codec_write(codec, 0x6, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x80); + alc_write_coef_idx(codec, 0x26, 0xf000); + alc_write_coef_idx(codec, 0x23, initval->value_0x23); + + if (initval->value_0x23 != 0x1e) + alc_write_coef_idx(codec, 0x25, initval->value_0x25); + + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x26); + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb010); +} + +static void alc298_fixup_huawei_mbx_stereo(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + /* Initialization magic */ + static const struct hda_alc298_mbxinit dac_init[] = { + {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00}, + {0x10, 0x00}, {0x1a, 0x40}, {0x1b, 0x82}, {0x1c, 0x00}, + {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00}, + {0x20, 0xc2}, {0x21, 0xc8}, {0x22, 0x26}, {0x23, 0x24}, + {0x27, 0xff}, {0x28, 0xff}, {0x29, 0xff}, {0x2a, 0x8f}, + {0x2b, 0x02}, {0x2c, 0x48}, {0x2d, 0x34}, {0x2e, 0x00}, + {0x2f, 0x00}, + {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, + {0x34, 0x00}, {0x35, 0x01}, {0x36, 0x93}, {0x37, 0x0c}, + {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0xf8}, {0x38, 0x80}, + {} + }; + const struct hda_alc298_mbxinit *seq; + + if (action != HDA_FIXUP_ACT_INIT) + return; + + /* Start */ + snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x00); + snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x80); + alc_write_coef_idx(codec, 0x26, 0xf000); + alc_write_coef_idx(codec, 0x22, 0x31); + alc_write_coef_idx(codec, 0x23, 0x0b); + alc_write_coef_idx(codec, 0x25, 0x00); + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x26); + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb010); + + for (seq = dac_init; seq->value_0x23; seq++) + alc298_huawei_mbx_stereo_seq(codec, seq, seq == dac_init); +} + static void alc269_fixup_x101_headset_mic(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -5787,6 +5853,7 @@ enum { ALC255_FIXUP_DUMMY_LINEOUT_VERB, ALC255_FIXUP_DELL_HEADSET_MIC, ALC256_FIXUP_HUAWEI_MACH_WX9_PINS, + ALC298_FIXUP_HUAWEI_MBX_STEREO, ALC295_FIXUP_HP_X360, ALC221_FIXUP_HP_HEADSET_MIC, ALC285_FIXUP_LENOVO_HEADPHONE_NOISE, @@ -6095,6 +6162,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC255_FIXUP_MIC_MUTE_LED }, + [ALC298_FIXUP_HUAWEI_MBX_STEREO] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc298_fixup_huawei_mbx_stereo, + .chained = true, + .chain_id = ALC255_FIXUP_MIC_MUTE_LED + }, [ALC269_FIXUP_ASUS_X101_FUNC] = { .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_x101_headset_mic, @@ -7272,6 +7345,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC225_FIXUP_HEADSET_JACK, .name = "alc-headset-jack"}, {.id = ALC295_FIXUP_CHROME_BOOK, .name = "alc-chrome-book"}, {.id = ALC299_FIXUP_PREDATOR_SPK, .name = "predator-spk"}, + {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"}, {} }; #define ALC225_STANDARD_PINS \ -- cgit v1.2.3 From 332ccf00bf85adbf48015084be0e60f5cc57a055 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 9 Aug 2019 17:15:31 +0200 Subject: ASoC: hdac_hdmi: Offload dapm update at jack detection hdac_hdmi_present_sense() calls the audio component to get ELD update, then it reports the jack status change and updates DAPM graph accordingly. This works when it's called from the normal code paths. However, it may lead to a dead lock when it's called from the audio component notifier. Namely, the DAPM update involves with the runtime PM, and it eventually calls again the audio component get_power() ops. Since i915 driver already takes a mutex around the audio component ops calls, we'll eventually get the mutex doubly. As a workaround, in this patch, only the jack state is updated in the code path from hdac_hdmi_eld_notify_cb(), and the DAPM update is deferred to a work so that it's processed in another context. Reported-by: Imre Deak Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20190809151531.24359-1-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 57 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 47eee18b66a3..11ec031ad749 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -88,8 +88,10 @@ struct hdac_hdmi_port { hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; const char *jack_pin; + bool is_connect; struct snd_soc_dapm_context *dapm; const char *output_pin; + struct work_struct dapm_work; }; struct hdac_hdmi_pcm { @@ -163,11 +165,7 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, { struct hdac_device *hdev = port->pin->hdev; - if (is_connect) - snd_soc_dapm_enable_pin(port->dapm, port->jack_pin); - else - snd_soc_dapm_disable_pin(port->dapm, port->jack_pin); - + port->is_connect = is_connect; if (is_connect) { /* * Report Jack connect event when a device is connected @@ -193,10 +191,32 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, if (pcm->jack_event > 0) pcm->jack_event--; } +} +static void hdac_hdmi_port_dapm_update(struct hdac_hdmi_port *port) +{ + if (port->is_connect) + snd_soc_dapm_enable_pin(port->dapm, port->jack_pin); + else + snd_soc_dapm_disable_pin(port->dapm, port->jack_pin); snd_soc_dapm_sync(port->dapm); } +static void hdac_hdmi_jack_dapm_work(struct work_struct *work) +{ + struct hdac_hdmi_port *port; + + port = container_of(work, struct hdac_hdmi_port, dapm_work); + hdac_hdmi_port_dapm_update(port); +} + +static void hdac_hdmi_jack_report_sync(struct hdac_hdmi_pcm *pcm, + struct hdac_hdmi_port *port, bool is_connect) +{ + hdac_hdmi_jack_report(pcm, port, is_connect); + hdac_hdmi_port_dapm_update(port); +} + /* MST supported verbs */ /* * Get the no devices that can be connected to a port on the Pin widget. @@ -873,7 +893,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, list_for_each_entry_safe(p, p_next, &pcm->port_list, head) { if (p == port && p->id == port->id && p->pin == port->pin) { - hdac_hdmi_jack_report(pcm, port, false); + hdac_hdmi_jack_report_sync(pcm, port, false); list_del(&p->head); } } @@ -887,7 +907,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, if (!strcmp(cvt_name, pcm->cvt->name)) { list_add_tail(&port->head, &pcm->port_list); if (port->eld.monitor_present && port->eld.eld_valid) { - hdac_hdmi_jack_report(pcm, port, true); + hdac_hdmi_jack_report_sync(pcm, port, true); mutex_unlock(&hdmi->pin_mutex); return ret; } @@ -1250,16 +1270,20 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, * report jack here. It will be done in usermode mux * control select. */ - if (pcm) + if (pcm) { hdac_hdmi_jack_report(pcm, port, false); + schedule_work(&port->dapm_work); + } mutex_unlock(&hdmi->pin_mutex); return; } if (port->eld.monitor_present && port->eld.eld_valid) { - if (pcm) + if (pcm) { hdac_hdmi_jack_report(pcm, port, true); + schedule_work(&port->dapm_work); + } print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, port->eld.eld_buffer, port->eld.eld_size, false); @@ -1288,6 +1312,7 @@ static int hdac_hdmi_add_ports(struct hdac_device *hdev, for (i = 0; i < max_ports; i++) { ports[i].id = i; ports[i].pin = pin; + INIT_WORK(&ports[i].dapm_work, hdac_hdmi_jack_dapm_work); } pin->ports = ports; pin->num_ports = max_ports; @@ -2052,8 +2077,20 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) return ret; } +static void clear_dapm_works(struct hdac_device *hdev) +{ + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); + struct hdac_hdmi_pin *pin; + int i; + + list_for_each_entry(pin, &hdmi->pin_list, head) + for (i = 0; i < pin->num_ports; i++) + cancel_work_sync(&pin->ports[i].dapm_work); +} + static int hdac_hdmi_dev_remove(struct hdac_device *hdev) { + clear_dapm_works(hdev); snd_hdac_display_power(hdev->bus, hdev->addr, false); return 0; @@ -2072,6 +2109,8 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) if (!bus) return 0; + clear_dapm_works(hdev); + /* * Power down afg. * codec_read is preferred over codec_write to set the power state. -- cgit v1.2.3 From 3dc29b8b2062075602c7aff1514a120b4ed0187f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:52:33 +0900 Subject: ASoC: soc-core: support snd_soc_dai_link_component for aux_dev To find aux_dev, ASoC is using .name, codec_name, codec_of_node. Here, .name is used to fallback in case of no codec. But, we already have this kind of component finding method by snd_soc_dai_link_component and soc_find_component(). We shouldn't have duplicated implementation to do same things. This patch adds snd_soc_dai_link_component support to finding aux_dev. Now, no driver is using only .name. All drivers are using codec_name and/or codec_of_node. This means no driver is finding component from .name so far. (Actually almost all drivers are using .name as just "device name", not for finding component...) This patch 1) add snd_soc_dai_link_component support for aux_dev. legacy style will be removed if all drivers are switched to new style. 2) try to find component via snd_soc_dai_link_component. Then, it doesn't try to find via .name, because no driver is using it so far. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y3046wcf.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 7 +++++++ sound/soc/soc-core.c | 36 ++++++++++-------------------------- 2 files changed, 17 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 85ad971e9432..fd6ecea48fc0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -941,6 +941,7 @@ struct snd_soc_dai_link { #define COMP_CPU(_dai) { .dai_name = _dai, } #define COMP_CODEC(_name, _dai) { .name = _name, .dai_name = _dai, } #define COMP_PLATFORM(_name) { .name = _name } +#define COMP_AUX(_name) { .name = _name } #define COMP_DUMMY() { .name = "snd-soc-dummy", .dai_name = "snd-soc-dummy-dai", } extern struct snd_soc_dai_link_component null_dailink_component[0]; @@ -971,6 +972,12 @@ struct snd_soc_aux_dev { const char *codec_name; struct device_node *codec_of_node; + /* + * name, codec_name, codec_of_node will be replaced + * into dlc. don't use both in the same time + */ + struct snd_soc_dai_link_component dlc; + /* codec/machine specific init - e.g. add machine controls */ int (*init)(struct snd_soc_component *component); }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bf45e60eb34f..56b99e340dda 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1537,38 +1537,22 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; struct snd_soc_component *component; - struct snd_soc_dai_link_component dlc; - if (aux_dev->codec_of_node || aux_dev->codec_name) { - /* codecs, usually analog devices */ - dlc.name = aux_dev->codec_name; - dlc.of_node = aux_dev->codec_of_node; - component = soc_find_component(&dlc); - if (!component) { - if (dlc.of_node) - dlc.name = of_node_full_name(dlc.of_node); - goto err_defer; - } - } else if (aux_dev->name) { - /* generic components */ - dlc.name = aux_dev->name; - dlc.of_node = NULL; - component = soc_find_component(&dlc); - if (!component) - goto err_defer; - } else { - dev_err(card->dev, "ASoC: Invalid auxiliary device\n"); - return -EINVAL; - } + /* remove me */ + if (aux_dev->codec_name) + aux_dev->dlc.name = aux_dev->codec_name; + if (aux_dev->codec_of_node) + aux_dev->dlc.of_node = aux_dev->codec_of_node; + + /* codecs, usually analog devices */ + component = soc_find_component(&aux_dev->dlc); + if (!component) + return -EPROBE_DEFER; component->init = aux_dev->init; list_add(&component->card_aux_list, &card->aux_comp_list); return 0; - -err_defer: - dev_err(card->dev, "ASoC: %s not registered\n", dlc.name); - return -EPROBE_DEFER; } static int soc_probe_aux_devices(struct snd_soc_card *card) -- cgit v1.2.3 From 14fdfc058d812f683d9aa51083d1a920aa6a1eb9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:52:47 +0900 Subject: ASoC: simple-card: use snd_soc_dai_link_component for aux_dev We can use snd_soc_dai_link_component to specify aux_dev. Let's use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87wofo6wc1.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index ef849151ba56..0eac3bcb9736 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -424,7 +424,7 @@ static int simple_parse_aux_devs(struct device_node *node, aux_node = of_parse_phandle(node, PREFIX "aux-devs", i); if (!aux_node) return -EINVAL; - card->aux_dev[i].codec_of_node = aux_node; + card->aux_dev[i].dlc.of_node = aux_node; } card->num_aux_devs = n; -- cgit v1.2.3 From aa1afd92f374a895ab74cb96dacd25a3485a08c4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:53:33 +0900 Subject: ASoC: intel: cht_bsw_max98090_ti: use snd_soc_dai_link_component for aux_dev We can use snd_soc_dai_link_component to specify aux_dev. Let's use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v9v86war.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 33eb72545be6..1db9a95e6a79 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -324,9 +324,8 @@ static const struct snd_soc_ops cht_be_ssp2_ops = { }; static struct snd_soc_aux_dev cht_max98090_headset_dev = { - .name = "Headset Chip", + .dlc = COMP_AUX("i2c-104C227E:00"), .init = cht_max98090_headset_init, - .codec_name = "i2c-104C227E:00", }; SND_SOC_DAILINK_DEF(dummy, -- cgit v1.2.3 From 5c9e38cb57ce07d780dc05d34ae140271c2da159 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:53:45 +0900 Subject: ASoC: mediatek: mt8183-da7219-max98357: use snd_soc_dai_link_component for aux_dev We can use snd_soc_dai_link_component to specify aux_dev. Let's use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tvas6waf.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index 59076e21cb47..2a6097174614 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -370,7 +370,7 @@ static int mt8183_da7219_max98357_headset_init(struct snd_soc_component *component); static struct snd_soc_aux_dev mt8183_da7219_max98357_headset_dev = { - .name = "Headset Chip", + .dlc = COMP_EMPTY(), .init = mt8183_da7219_max98357_headset_init, }; @@ -436,10 +436,10 @@ static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev) dai_link->platforms->of_node = platform_node; } - mt8183_da7219_max98357_headset_dev.codec_of_node = + mt8183_da7219_max98357_headset_dev.dlc.of_node = of_parse_phandle(pdev->dev.of_node, "mediatek,headset-codec", 0); - if (!mt8183_da7219_max98357_headset_dev.codec_of_node) { + if (!mt8183_da7219_max98357_headset_dev.dlc.of_node) { dev_err(&pdev->dev, "Property 'mediatek,headset-codec' missing/invalid\n"); return -EINVAL; -- cgit v1.2.3 From a73b522d4b570ee41754990e81f6f4e849af1af9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:53:59 +0900 Subject: ASoC: meson: axg-card: use snd_soc_dai_link_component for aux_dev We can use snd_soc_dai_link_component to specify aux_dev. Let's use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r25w6wa1.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-card.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 14a8321744da..6283e5025548 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -124,7 +124,7 @@ static void axg_card_clean_references(struct axg_card *priv) if (card->aux_dev) { for (i = 0; i < card->num_aux_devs; i++) - of_node_put(card->aux_dev[i].codec_of_node); + of_node_put(card->aux_dev[i].dlc.of_node); } kfree(card->dai_link); @@ -158,9 +158,9 @@ static int axg_card_add_aux_devices(struct snd_soc_card *card) card->num_aux_devs = num; for (i = 0; i < card->num_aux_devs; i++, aux++) { - aux->codec_of_node = + aux->dlc.of_node = of_parse_phandle(node, "audio-aux-devs", i); - if (!aux->codec_of_node) + if (!aux->dlc.of_node) return -EINVAL; } -- cgit v1.2.3 From 70a6b7bfba9bfd781b8c137f059487017dd385d8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:54:05 +0900 Subject: ASoC: rockchip: rockchip_max98090: use snd_soc_dai_link_component for aux_dev We can use snd_soc_dai_link_component to specify aux_dev. Let's use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pnlg6w9v.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_max98090.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index 1af1147c3da3..7b0c21fa6dca 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -160,7 +160,7 @@ static struct snd_soc_dai_link rk_dailink = { static int rk_98090_headset_init(struct snd_soc_component *component); static struct snd_soc_aux_dev rk_98090_headset_dev = { - .name = "Headset Chip", + .dlc = COMP_EMPTY(), .init = rk_98090_headset_init, }; @@ -226,9 +226,9 @@ static int snd_rk_mc_probe(struct platform_device *pdev) rk_dailink.platforms->of_node = rk_dailink.cpus->of_node; - rk_98090_headset_dev.codec_of_node = of_parse_phandle(np, + rk_98090_headset_dev.dlc.of_node = of_parse_phandle(np, "rockchip,headset-codec", 0); - if (!rk_98090_headset_dev.codec_of_node) { + if (!rk_98090_headset_dev.dlc.of_node) { dev_err(&pdev->dev, "Property 'rockchip,headset-codec' missing/invalid\n"); return -EINVAL; -- cgit v1.2.3 From d20bb789d7283bcbacd3b12c60668c473bc1dac0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:54:10 +0900 Subject: ASoC: samsung: neo1973_wm8753: use snd_soc_dai_link_component for aux_dev We can use snd_soc_dai_link_component to specify aux_dev. Let's use it. Signed-off-by: Kuninori Morimoto Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/87o9106w9p.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/neo1973_wm8753.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 396776ffd670..38f536bafa09 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -297,8 +297,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { static struct snd_soc_aux_dev neo1973_aux_devs[] = { { - .name = "dfbmcs320", - .codec_name = "dfbmcs320.0", + .dlc = COMP_AUX("dfbmcs320.0"), }, }; -- cgit v1.2.3 From 2d946aaa80c79452c700381b4c1f06f11dfd2bdd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:54:15 +0900 Subject: ASoC: samsung: speyside: use snd_soc_dai_link_component for aux_dev We can use snd_soc_dai_link_component to specify aux_dev. Let's use it. Signed-off-by: Kuninori Morimoto Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/87mugk6w9l.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/speyside.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 51e4c976c8be..9e58cbed942a 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -240,8 +240,7 @@ static int speyside_wm9081_init(struct snd_soc_component *component) static struct snd_soc_aux_dev speyside_aux_dev[] = { { - .name = "wm9081", - .codec_name = "wm9081.1-006c", + .dlc = COMP_AUX("wm9081.1-006c"), .init = speyside_wm9081_init, }, }; -- cgit v1.2.3 From 124749194ad2e08fbea9c34fa5e2728310bf4486 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:54:20 +0900 Subject: ASoC: samsung: tm2_wm5110: use snd_soc_dai_link_component for aux_dev We can use snd_soc_dai_link_component to specify aux_dev. Let's use it. Signed-off-by: Kuninori Morimoto Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/87lfw46w9g.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/tm2_wm5110.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index c091033d17ad..bb9910d4cbe2 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -307,7 +307,6 @@ static struct snd_soc_aux_dev tm2_speaker_amp_dev; static int tm2_late_probe(struct snd_soc_card *card) { struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); - struct snd_soc_dai_link_component dlc = { 0 }; unsigned int ch_map[] = { 0, 1 }; struct snd_soc_dai *amp_pdm_dai; struct snd_soc_pcm_runtime *rtd; @@ -334,8 +333,7 @@ static int tm2_late_probe(struct snd_soc_card *card) return ret; } - dlc.of_node = tm2_speaker_amp_dev.codec_of_node; - amp_pdm_dai = snd_soc_find_dai(&dlc); + amp_pdm_dai = snd_soc_find_dai(&tm2_speaker_amp_dev.dlc); if (!amp_pdm_dai) return -ENODEV; @@ -532,9 +530,9 @@ static int tm2_probe(struct platform_device *pdev) return ret; } - card->aux_dev[0].codec_of_node = of_parse_phandle(dev->of_node, + card->aux_dev[0].dlc.of_node = of_parse_phandle(dev->of_node, "audio-amplifier", 0); - if (!card->aux_dev[0].codec_of_node) { + if (!card->aux_dev[0].dlc.of_node) { dev_err(dev, "audio-amplifier property invalid or missing\n"); return -EINVAL; } @@ -623,7 +621,7 @@ dai_node_put: of_node_put(cpu_dai_node[i]); } - of_node_put(card->aux_dev[0].codec_of_node); + of_node_put(card->aux_dev[0].dlc.of_node); return ret; } -- cgit v1.2.3 From 3d0d2d64b7eb4f2a451fa184829b749851c14f55 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:54:25 +0900 Subject: ASoC: sunxi: sun4i-codec: use snd_soc_dai_link_component for aux_dev We can use snd_soc_dai_link_component to specify aux_dev. Let's use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k1bo6w9b.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 619073e7d972..ee448d5e07a6 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1424,7 +1424,7 @@ static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = { }; static struct snd_soc_aux_dev aux_dev = { - .name = "Codec Analog Controls", + .dlc = COMP_EMPTY(), }; static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) @@ -1436,10 +1436,10 @@ static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) if (!card) return ERR_PTR(-ENOMEM); - aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + aux_dev.dlc.of_node = of_parse_phandle(dev->of_node, "allwinner,codec-analog-controls", 0); - if (!aux_dev.codec_of_node) { + if (!aux_dev.dlc.of_node) { dev_err(dev, "Can't find analog controls for codec.\n"); return ERR_PTR(-EINVAL); }; @@ -1474,10 +1474,10 @@ static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev) if (!card) return ERR_PTR(-ENOMEM); - aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + aux_dev.dlc.of_node = of_parse_phandle(dev->of_node, "allwinner,codec-analog-controls", 0); - if (!aux_dev.codec_of_node) { + if (!aux_dev.dlc.of_node) { dev_err(dev, "Can't find analog controls for codec.\n"); return ERR_PTR(-EINVAL); }; @@ -1512,10 +1512,10 @@ static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev) if (!card) return ERR_PTR(-ENOMEM); - aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + aux_dev.dlc.of_node = of_parse_phandle(dev->of_node, "allwinner,codec-analog-controls", 0); - if (!aux_dev.codec_of_node) { + if (!aux_dev.dlc.of_node) { dev_err(dev, "Can't find analog controls for codec.\n"); return ERR_PTR(-EINVAL); }; -- cgit v1.2.3 From 77b21d2822fdbfad19170516256c4c7f236054a9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:54:30 +0900 Subject: ASoC: ti: rx51: use snd_soc_dai_link_component for aux_dev We can use snd_soc_dai_link_component to specify aux_dev. Let's use it. Signed-off-by: Kuninori Morimoto Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/r/87imr86w96.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ti/rx51.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c index ccd0e8a07dd1..588f680a9c24 100644 --- a/sound/soc/ti/rx51.c +++ b/sound/soc/ti/rx51.c @@ -319,12 +319,10 @@ static struct snd_soc_dai_link rx51_dai[] = { static struct snd_soc_aux_dev rx51_aux_dev[] = { { - .name = "TLV320AIC34b", - .codec_name = "tlv320aic3x-codec.2-0019", + .dlc = COMP_AUX("tlv320aic3x-codec.2-0019"), }, { - .name = "TPA61320A2", - .codec_name = "tpa6130a2.2-0060", + .dlc = COMP_AUX("tpa6130a2.2-0060"), }, }; @@ -397,8 +395,8 @@ static int rx51_soc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Auxiliary Codec node is not provided\n"); return -EINVAL; } - rx51_aux_dev[0].codec_name = NULL; - rx51_aux_dev[0].codec_of_node = dai_node; + rx51_aux_dev[0].dlc.name = NULL; + rx51_aux_dev[0].dlc.of_node = dai_node; rx51_codec_conf[0].dev_name = NULL; rx51_codec_conf[0].of_node = dai_node; @@ -407,8 +405,8 @@ static int rx51_soc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Headphone amplifier node is not provided\n"); return -EINVAL; } - rx51_aux_dev[1].codec_name = NULL; - rx51_aux_dev[1].codec_of_node = dai_node; + rx51_aux_dev[1].dlc.name = NULL; + rx51_aux_dev[1].dlc.of_node = dai_node; rx51_codec_conf[1].dev_name = NULL; rx51_codec_conf[1].of_node = dai_node; } -- cgit v1.2.3 From a48b561d873d1d9fda55782d275eff94ec647863 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:54:39 +0900 Subject: ASoC: soc-core: remove legacy style of aux_dev Now all drivers are using snd_soc_dai_link_component for aux_dev. Let's remove legacy style Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h86s6w8x.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 9 --------- sound/soc/soc-core.c | 6 ------ 2 files changed, 15 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index fd6ecea48fc0..2fc56e5963f3 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -963,19 +963,10 @@ struct snd_soc_codec_conf { }; struct snd_soc_aux_dev { - const char *name; /* Codec name */ - /* * specify multi-codec either by device name, or by * DT/OF node, but not both. */ - const char *codec_name; - struct device_node *codec_of_node; - - /* - * name, codec_name, codec_of_node will be replaced - * into dlc. don't use both in the same time - */ struct snd_soc_dai_link_component dlc; /* codec/machine specific init - e.g. add machine controls */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 56b99e340dda..4af382d52675 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1538,12 +1538,6 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num) struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; struct snd_soc_component *component; - /* remove me */ - if (aux_dev->codec_name) - aux_dev->dlc.name = aux_dev->codec_name; - if (aux_dev->codec_of_node) - aux_dev->dlc.of_node = aux_dev->codec_of_node; - /* codecs, usually analog devices */ component = soc_find_component(&aux_dev->dlc); if (!component) -- cgit v1.2.3 From dbf0649f4340c8bb7d36b8d6255dba03ed6981e7 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 8 Aug 2019 22:32:15 +0800 Subject: ASoC: max98926: remove two unused variables sound/soc/codecs/max98926.c:28:26: warning: max98926_dai_txt defined but not used [-Wunused-const-variable=] sound/soc/codecs/max98926.c:23:27: warning: max98926_boost_current_txt defined but not used [-Wunused-const-variable=] They are never used, so can be removd. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190808143215.65904-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98926.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 818c0301fb29..c4dfa8ab1d49 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -20,15 +20,6 @@ static const char * const max98926_boost_voltage_txt[] = { "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V" }; -static const char * const max98926_boost_current_txt[] = { - "0.6", "0.8", "1.0", "1.2", "1.4", "1.6", "1.8", "2.0", - "2.2", "2.4", "2.6", "2.8", "3.2", "3.6", "4.0", "4.4" -}; - -static const char *const max98926_dai_txt[] = { - "Left", "Right", "LeftRight", "LeftRightDiv2", -}; - static const char *const max98926_pdm_ch_text[] = { "Current", "Voltage", }; -- cgit v1.2.3 From c86102a333f77dcd0f7ef20ba836c6f13f1a077a Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 8 Aug 2019 22:35:07 +0800 Subject: ASoC: max9850: remove unused variable 'max9850_reg' sound/soc/codecs/max9850.c:31:33: warning: max9850_reg defined but not used [-Wunused-const-variable=] It is not used since commit 068416620c0d ("ASoC: max9850: Convert to direct regmap API usage") Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190808143507.66788-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/max9850.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index f50ee8f5fe93..6f43748f9239 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -27,19 +27,6 @@ struct max9850_priv { unsigned int sysclk; }; -/* max9850 register cache */ -static const struct reg_default max9850_reg[] = { - { 2, 0x0c }, - { 3, 0x00 }, - { 4, 0x00 }, - { 5, 0x00 }, - { 6, 0x00 }, - { 7, 0x00 }, - { 8, 0x00 }, - { 9, 0x00 }, - { 10, 0x00 }, -}; - /* these registers are not used at the moment but provided for the sake of * completeness */ static bool max9850_volatile_register(struct device *dev, unsigned int reg) -- cgit v1.2.3 From b812cd5864548bd9718879896fdd2822d3cb3d76 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:53:52 +0900 Subject: ASoC: mediatek: mt8183-mt6358-ts3a227-max98357: use snd_soc_dai_link_component for aux_dev We can use snd_soc_dai_link_component to specify aux_dev. Let's use it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sgqc6wa8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 4c816c86844b..53f54078f78c 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -343,7 +343,7 @@ static int mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *cpnt); static struct snd_soc_aux_dev mt8183_mt6358_ts3a227_max98357_headset_dev = { - .name = "Headset Chip", + .dlc = COMP_EMPTY(), .init = mt8183_mt6358_ts3a227_max98357_headset_init, }; @@ -399,10 +399,10 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) dai_link->platforms->of_node = platform_node; } - mt8183_mt6358_ts3a227_max98357_headset_dev.codec_of_node = + mt8183_mt6358_ts3a227_max98357_headset_dev.dlc.of_node = of_parse_phandle(pdev->dev.of_node, "mediatek,headset-codec", 0); - if (mt8183_mt6358_ts3a227_max98357_headset_dev.codec_of_node) { + if (mt8183_mt6358_ts3a227_max98357_headset_dev.dlc.of_node) { card->aux_dev = &mt8183_mt6358_ts3a227_max98357_headset_dev; card->num_aux_devs = 1; } -- cgit v1.2.3 From c2b71c71037bea7765aa6ff37824520d19108769 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Aug 2019 14:54:44 +0900 Subject: ASoC: soc-core: add for_each_xxx macro for aux_dev To be more readable code, this patch adds new for_each_xxx() macro for aux_dev. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ftmc6w8s.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 10 ++++++++++ sound/soc/meson/axg-card.c | 7 ++++--- sound/soc/soc-core.c | 15 ++++++++------- 3 files changed, 22 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 2fc56e5963f3..b1fe5ebea257 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1087,6 +1087,10 @@ struct snd_soc_card { for ((i) = 0; \ ((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \ (i)++) +#define for_each_card_pre_auxs(card, i, aux) \ + for ((i) = 0; \ + ((i) < (card)->num_aux_devs) && ((aux) = &(card)->aux_dev[i]); \ + (i)++) #define for_each_card_links(card, link) \ list_for_each_entry(link, &(card)->dai_link_list, list) @@ -1098,6 +1102,12 @@ struct snd_soc_card { #define for_each_card_rtds_safe(card, rtd, _rtd) \ list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list) +#define for_each_card_auxs(card, component) \ + list_for_each_entry(component, &card->aux_comp_list, card_aux_list) +#define for_each_card_auxs_safe(card, component, _comp) \ + list_for_each_entry_safe(component, _comp, \ + &card->aux_comp_list, card_aux_list) + #define for_each_card_components(card, component) \ list_for_each_entry(component, &(card)->component_dev_list, card_list) diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 6283e5025548..1f698adde506 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -111,6 +111,7 @@ static void axg_card_clean_references(struct axg_card *priv) struct snd_soc_card *card = &priv->card; struct snd_soc_dai_link *link; struct snd_soc_dai_link_component *codec; + struct snd_soc_aux_dev *aux; int i, j; if (card->dai_link) { @@ -123,8 +124,8 @@ static void axg_card_clean_references(struct axg_card *priv) } if (card->aux_dev) { - for (i = 0; i < card->num_aux_devs; i++) - of_node_put(card->aux_dev[i].dlc.of_node); + for_each_card_pre_auxs(card, i, aux) + of_node_put(aux->dlc.of_node); } kfree(card->dai_link); @@ -157,7 +158,7 @@ static int axg_card_add_aux_devices(struct snd_soc_card *card) card->aux_dev = aux; card->num_aux_devs = num; - for (i = 0; i < card->num_aux_devs; i++, aux++) { + for_each_card_pre_auxs(card, i, aux) { aux->dlc.of_node = of_parse_phandle(node, "audio-aux-devs", i); if (!aux->dlc.of_node) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4af382d52675..e9f44505cc3e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1533,9 +1533,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, return ret; } -static int soc_bind_aux_dev(struct snd_soc_card *card, int num) +static int soc_bind_aux_dev(struct snd_soc_card *card, + struct snd_soc_aux_dev *aux_dev) { - struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; struct snd_soc_component *component; /* codecs, usually analog devices */ @@ -1544,6 +1544,7 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num) return -EPROBE_DEFER; component->init = aux_dev->init; + /* see for_each_card_auxs */ list_add(&component->card_aux_list, &card->aux_comp_list); return 0; @@ -1556,7 +1557,7 @@ static int soc_probe_aux_devices(struct snd_soc_card *card) int ret; for_each_comp_order(order) { - list_for_each_entry(comp, &card->aux_comp_list, card_aux_list) { + for_each_card_auxs(card, comp) { if (comp->driver->probe_order == order) { ret = soc_probe_component(card, comp); if (ret < 0) { @@ -1578,8 +1579,7 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) int order; for_each_comp_order(order) { - list_for_each_entry_safe(comp, _comp, - &card->aux_comp_list, card_aux_list) { + for_each_card_auxs_safe(card, comp, _comp) { if (comp->driver->remove_order == order) { soc_remove_component(comp); @@ -1913,6 +1913,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link *dai_link; + struct snd_soc_aux_dev *aux; int ret, i, order; mutex_lock(&client_mutex); @@ -1943,8 +1944,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* bind aux_devs too */ - for (i = 0; i < card->num_aux_devs; i++) { - ret = soc_bind_aux_dev(card, i); + for_each_card_pre_auxs(card, i, aux) { + ret = soc_bind_aux_dev(card, aux); if (ret != 0) goto probe_end; } -- cgit v1.2.3 From 8afd1a99d713ccc7cf1bd509b205c3bb60cf0b90 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 9 Aug 2019 18:22:34 -0500 Subject: ASoC: Intel: sof-rt5682: add dmic dapm widget to support dmic PCM We need add DAPM MIC endpoint widget "SoC DMIC" and route, to enable DMIC PCM DAPM support. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190809232236.21182-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 64db00353e18..7285474f7d65 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -309,6 +309,7 @@ static const struct snd_soc_dapm_widget sof_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Spk", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), }; static const struct snd_soc_dapm_route sof_map[] = { @@ -319,6 +320,9 @@ static const struct snd_soc_dapm_route sof_map[] = { /* other jacks */ { "IN1P", NULL, "Headset Mic" }, + /* digital mics */ + {"DMic", NULL, "SoC DMIC"}, + }; static const struct snd_soc_dapm_route speaker_map[] = { -- cgit v1.2.3 From 8b209cdb696f49f7f5d6c1922bed435e54631ddd Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Aug 2019 22:27:36 +0200 Subject: ASoC: remove w90x900/nuc900 platform drivers The ARM w90x900 platform is getting removed, so this driver is obsolete. Signed-off-by: Arnd Bergmann Acked-by: Mark Brown Link: https://lore.kernel.org/r/20190809202749.742267-9-arnd@arndb.de Signed-off-by: Mark Brown --- sound/soc/Kconfig | 1 - sound/soc/Makefile | 1 - sound/soc/nuc900/Kconfig | 29 --- sound/soc/nuc900/Makefile | 12 -- sound/soc/nuc900/nuc900-ac97.c | 391 ---------------------------------------- sound/soc/nuc900/nuc900-audio.c | 73 -------- sound/soc/nuc900/nuc900-audio.h | 108 ----------- sound/soc/nuc900/nuc900-pcm.c | 321 --------------------------------- 8 files changed, 936 deletions(-) delete mode 100644 sound/soc/nuc900/Kconfig delete mode 100644 sound/soc/nuc900/Makefile delete mode 100644 sound/soc/nuc900/nuc900-ac97.c delete mode 100644 sound/soc/nuc900/nuc900-audio.c delete mode 100644 sound/soc/nuc900/nuc900-audio.h delete mode 100644 sound/soc/nuc900/nuc900-pcm.c (limited to 'sound') diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index dc86e4073001..bdc305cece6e 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -51,7 +51,6 @@ source "sound/soc/dwc/Kconfig" source "sound/soc/fsl/Kconfig" source "sound/soc/hisilicon/Kconfig" source "sound/soc/jz4740/Kconfig" -source "sound/soc/nuc900/Kconfig" source "sound/soc/kirkwood/Kconfig" source "sound/soc/img/Kconfig" source "sound/soc/intel/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 250a0dea9294..861a21b79484 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -39,7 +39,6 @@ obj-$(CONFIG_SND_SOC) += intel/ obj-$(CONFIG_SND_SOC) += mediatek/ obj-$(CONFIG_SND_SOC) += meson/ obj-$(CONFIG_SND_SOC) += mxs/ -obj-$(CONFIG_SND_SOC) += nuc900/ obj-$(CONFIG_SND_SOC) += kirkwood/ obj-$(CONFIG_SND_SOC) += pxa/ obj-$(CONFIG_SND_SOC) += qcom/ diff --git a/sound/soc/nuc900/Kconfig b/sound/soc/nuc900/Kconfig deleted file mode 100644 index e1b22fbcb159..000000000000 --- a/sound/soc/nuc900/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -## -## NUC900 series AC97 API -## -config SND_SOC_NUC900 - tristate "SoC Audio for NUC900 series" - depends on ARCH_W90X900 - select SND_SOC_NUC900_AC97 - help - This option enables support for AC97 mode on the NUC900 SoC. - -config SND_SOC_NUC900_AC97 - tristate - select AC97_BUS - select SND_AC97_CODEC - select SND_SOC_AC97_BUS - - -## -## Boards -## -config SND_SOC_NUC900EVB - tristate "NUC900 AC97 support for demo board" - depends on SND_SOC_NUC900 - select SND_SOC_NUC900_AC97 - select SND_SOC_AC97_CODEC - help - Select this option to enable audio (AC97) on the - NUC900 demoboard. diff --git a/sound/soc/nuc900/Makefile b/sound/soc/nuc900/Makefile deleted file mode 100644 index c7ba2b9549d2..000000000000 --- a/sound/soc/nuc900/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# NUC900 series audio -snd-soc-nuc900-pcm-objs := nuc900-pcm.o -snd-soc-nuc900-ac97-objs := nuc900-ac97.o - -obj-$(CONFIG_SND_SOC_NUC900) += snd-soc-nuc900-pcm.o -obj-$(CONFIG_SND_SOC_NUC900_AC97) += snd-soc-nuc900-ac97.o - -# Boards -snd-soc-nuc900-audio-objs := nuc900-audio.o - -obj-$(CONFIG_SND_SOC_NUC900EVB) += snd-soc-nuc900-audio.o diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c deleted file mode 100644 index 5f2e5c069377..000000000000 --- a/sound/soc/nuc900/nuc900-ac97.c +++ /dev/null @@ -1,391 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2009-2010 Nuvoton technology corporation. - * - * Wan ZongShun - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "nuc900-audio.h" - -static DEFINE_MUTEX(ac97_mutex); -struct nuc900_audio *nuc900_ac97_data; -EXPORT_SYMBOL_GPL(nuc900_ac97_data); - -static int nuc900_checkready(void) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - - if (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS0) & CODEC_READY)) - return -EPERM; - - return 0; -} - -/* AC97 controller reads codec register */ -static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97, - unsigned short reg) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - unsigned long timeout = 0x10000, val; - - mutex_lock(&ac97_mutex); - - val = nuc900_checkready(); - if (val) { - dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); - goto out; - } - - /* set the R_WB bit and write register index */ - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, R_WB | reg); - - /* set the valid frame bit and valid slots */ - val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); - val |= (VALID_FRAME | SLOT1_VALID); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val); - - udelay(100); - - /* polling the AC_R_FINISH */ - while (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_R_FINISH) - && --timeout) - mdelay(1); - - if (!timeout) { - dev_err(nuc900_audio->dev, "AC97 read register time out !\n"); - val = -EPERM; - goto out; - } - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0) ; - val &= ~SLOT1_VALID; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val); - - if (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS1) >> 2 != reg) { - dev_err(nuc900_audio->dev, - "R_INDEX of REG_ACTL_ACIS1 not match!\n"); - } - - udelay(100); - val = (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS2) & 0xFFFF); - -out: - mutex_unlock(&ac97_mutex); - return val; -} - -/* AC97 controller writes to codec register */ -static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg, - unsigned short val) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - unsigned long tmp, timeout = 0x10000; - - mutex_lock(&ac97_mutex); - - tmp = nuc900_checkready(); - if (tmp) - dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); - - /* clear the R_WB bit and write register index */ - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, reg); - - /* write register value */ - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS2, val); - - /* set the valid frame bit and valid slots */ - tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); - tmp |= SLOT1_VALID | SLOT2_VALID | VALID_FRAME; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); - - udelay(100); - - /* polling the AC_W_FINISH */ - while ((AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_W_FINISH) - && --timeout) - mdelay(1); - - if (!timeout) - dev_err(nuc900_audio->dev, "AC97 write register time out !\n"); - - tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); - tmp &= ~(SLOT1_VALID | SLOT2_VALID); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); - - mutex_unlock(&ac97_mutex); - -} - -static void nuc900_ac97_warm_reset(struct snd_ac97 *ac97) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - unsigned long val; - - mutex_lock(&ac97_mutex); - - /* warm reset AC 97 */ - val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); - val |= AC_W_RES; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val); - - udelay(100); - - val = nuc900_checkready(); - if (val) - dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); - - mutex_unlock(&ac97_mutex); -} - -static void nuc900_ac97_cold_reset(struct snd_ac97 *ac97) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - unsigned long val; - - mutex_lock(&ac97_mutex); - - /* reset Audio Controller */ - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - val |= ACTL_RESET_BIT; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - val &= (~ACTL_RESET_BIT); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - - /* reset AC-link interface */ - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - val |= AC_RESET; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - val &= ~AC_RESET; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - - /* cold reset AC 97 */ - val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); - val |= AC_C_RES; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); - val &= (~AC_C_RES); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val); - - udelay(100); - - mutex_unlock(&ac97_mutex); - -} - -/* AC97 controller operations */ -static struct snd_ac97_bus_ops nuc900_ac97_ops = { - .read = nuc900_ac97_read, - .write = nuc900_ac97_write, - .reset = nuc900_ac97_cold_reset, - .warm_reset = nuc900_ac97_warm_reset, -}; - -static int nuc900_ac97_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - int ret; - unsigned long val, tmp; - - ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); - tmp |= (SLOT3_VALID | SLOT4_VALID | VALID_FRAME); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); - - tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR); - tmp |= (P_DMA_END_IRQ | P_DMA_MIDDLE_IRQ); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, tmp); - val |= AC_PLAY; - } else { - tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR); - tmp |= (R_DMA_END_IRQ | R_DMA_MIDDLE_IRQ); - - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, tmp); - val |= AC_RECORD; - } - - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); - tmp &= ~(SLOT3_VALID | SLOT4_VALID); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); - - AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, RESET_PRSR); - val &= ~AC_PLAY; - } else { - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, RESET_PRSR); - val &= ~AC_RECORD; - } - - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int nuc900_ac97_probe(struct snd_soc_dai *dai) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - unsigned long val; - - mutex_lock(&ac97_mutex); - - /* enable unit clock */ - clk_enable(nuc900_audio->clk); - - /* enable audio controller and AC-link interface */ - val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); - val |= (IIS_AC_PIN_SEL | ACLINK_EN); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); - - mutex_unlock(&ac97_mutex); - - return 0; -} - -static int nuc900_ac97_remove(struct snd_soc_dai *dai) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - - clk_disable(nuc900_audio->clk); - return 0; -} - -static const struct snd_soc_dai_ops nuc900_ac97_dai_ops = { - .trigger = nuc900_ac97_trigger, -}; - -static struct snd_soc_dai_driver nuc900_ac97_dai = { - .probe = nuc900_ac97_probe, - .remove = nuc900_ac97_remove, - .bus_control = true, - .playback = { - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .channels_min = 1, - .channels_max = 2, - }, - .capture = { - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .channels_min = 1, - .channels_max = 2, - }, - .ops = &nuc900_ac97_dai_ops, -}; - -static const struct snd_soc_component_driver nuc900_ac97_component = { - .name = "nuc900-ac97", -}; - -static int nuc900_ac97_drvprobe(struct platform_device *pdev) -{ - struct nuc900_audio *nuc900_audio; - int ret; - - if (nuc900_ac97_data) - return -EBUSY; - - nuc900_audio = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_audio), - GFP_KERNEL); - if (!nuc900_audio) - return -ENOMEM; - - spin_lock_init(&nuc900_audio->lock); - - nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - nuc900_audio->mmio = devm_ioremap_resource(&pdev->dev, - nuc900_audio->res); - if (IS_ERR(nuc900_audio->mmio)) - return PTR_ERR(nuc900_audio->mmio); - - nuc900_audio->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(nuc900_audio->clk)) { - ret = PTR_ERR(nuc900_audio->clk); - goto out; - } - - ret = platform_get_irq(pdev, 0); - if (ret < 0) - goto out; - nuc900_audio->irq_num = ret; - - nuc900_ac97_data = nuc900_audio; - - ret = snd_soc_set_ac97_ops(&nuc900_ac97_ops); - if (ret) - goto out; - - ret = devm_snd_soc_register_component(&pdev->dev, &nuc900_ac97_component, - &nuc900_ac97_dai, 1); - if (ret) - goto out; - - /* enbale ac97 multifunction pin */ - mfp_set_groupg(nuc900_audio->dev, NULL); - - return 0; - -out: - snd_soc_set_ac97_ops(NULL); - return ret; -} - -static int nuc900_ac97_drvremove(struct platform_device *pdev) -{ - nuc900_ac97_data = NULL; - snd_soc_set_ac97_ops(NULL); - - return 0; -} - -static struct platform_driver nuc900_ac97_driver = { - .driver = { - .name = "nuc900-ac97", - }, - .probe = nuc900_ac97_drvprobe, - .remove = nuc900_ac97_drvremove, -}; - -module_platform_driver(nuc900_ac97_driver); - -MODULE_AUTHOR("Wan ZongShun "); -MODULE_DESCRIPTION("NUC900 AC97 SoC driver!"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:nuc900-ac97"); diff --git a/sound/soc/nuc900/nuc900-audio.c b/sound/soc/nuc900/nuc900-audio.c deleted file mode 100644 index 19146690d514..000000000000 --- a/sound/soc/nuc900/nuc900-audio.c +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2010 Nuvoton technology corporation. - * - * Wan ZongShun - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "nuc900-audio.h" - -SND_SOC_DAILINK_DEFS(ac97, - DAILINK_COMP_ARRAY(COMP_CPU("nuc900-ac97")), - DAILINK_COMP_ARRAY(COMP_CODEC("ac97-codec", "ac97-hifi")), - DAILINK_COMP_ARRAY(COMP_PLATFORM("nuc900-pcm-audio"))); - -static struct snd_soc_dai_link nuc900evb_ac97_dai = { - .name = "AC97", - .stream_name = "AC97 HiFi", - SND_SOC_DAILINK_REG(ac97), -}; - -static struct snd_soc_card nuc900evb_audio_machine = { - .name = "NUC900EVB_AC97", - .owner = THIS_MODULE, - .dai_link = &nuc900evb_ac97_dai, - .num_links = 1, -}; - -static struct platform_device *nuc900evb_asoc_dev; - -static int __init nuc900evb_audio_init(void) -{ - int ret; - - ret = -ENOMEM; - nuc900evb_asoc_dev = platform_device_alloc("soc-audio", -1); - if (!nuc900evb_asoc_dev) - goto out; - - /* nuc900 board audio device */ - platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_audio_machine); - - ret = platform_device_add(nuc900evb_asoc_dev); - - if (ret) { - platform_device_put(nuc900evb_asoc_dev); - nuc900evb_asoc_dev = NULL; - } - -out: - return ret; -} - -static void __exit nuc900evb_audio_exit(void) -{ - platform_device_unregister(nuc900evb_asoc_dev); -} - -module_init(nuc900evb_audio_init); -module_exit(nuc900evb_audio_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("NUC900 Series ASoC audio support"); -MODULE_AUTHOR("Wan ZongShun"); diff --git a/sound/soc/nuc900/nuc900-audio.h b/sound/soc/nuc900/nuc900-audio.h deleted file mode 100644 index 90ffa7bbce01..000000000000 --- a/sound/soc/nuc900/nuc900-audio.h +++ /dev/null @@ -1,108 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2010 Nuvoton technology corporation. - * - * Wan ZongShun - */ - -#ifndef _NUC900_AUDIO_H -#define _NUC900_AUDIO_H - -#include - -/* Audio Control Registers */ -#define ACTL_CON 0x00 -#define ACTL_RESET 0x04 -#define ACTL_RDSTB 0x08 -#define ACTL_RDST_LENGTH 0x0C -#define ACTL_RDSTC 0x10 -#define ACTL_RSR 0x14 -#define ACTL_PDSTB 0x18 -#define ACTL_PDST_LENGTH 0x1C -#define ACTL_PDSTC 0x20 -#define ACTL_PSR 0x24 -#define ACTL_IISCON 0x28 -#define ACTL_ACCON 0x2C -#define ACTL_ACOS0 0x30 -#define ACTL_ACOS1 0x34 -#define ACTL_ACOS2 0x38 -#define ACTL_ACIS0 0x3C -#define ACTL_ACIS1 0x40 -#define ACTL_ACIS2 0x44 -#define ACTL_COUNTER 0x48 - -/* bit definition of REG_ACTL_CON register */ -#define R_DMA_IRQ 0x1000 -#define T_DMA_IRQ 0x0800 -#define IIS_AC_PIN_SEL 0x0100 -#define FIFO_TH 0x0080 -#define ADC_EN 0x0010 -#define M80_EN 0x0008 -#define ACLINK_EN 0x0004 -#define IIS_EN 0x0002 - -/* bit definition of REG_ACTL_RESET register */ -#define W5691_PLAY 0x20000 -#define ACTL_RESET_BIT 0x10000 -#define RECORD_RIGHT_CHNNEL 0x08000 -#define RECORD_LEFT_CHNNEL 0x04000 -#define PLAY_RIGHT_CHNNEL 0x02000 -#define PLAY_LEFT_CHNNEL 0x01000 -#define DAC_PLAY 0x00800 -#define ADC_RECORD 0x00400 -#define M80_PLAY 0x00200 -#define AC_RECORD 0x00100 -#define AC_PLAY 0x00080 -#define IIS_RECORD 0x00040 -#define IIS_PLAY 0x00020 -#define DAC_RESET 0x00010 -#define ADC_RESET 0x00008 -#define M80_RESET 0x00004 -#define AC_RESET 0x00002 -#define IIS_RESET 0x00001 - -/* bit definition of REG_ACTL_ACCON register */ -#define AC_BCLK_PU_EN 0x20 -#define AC_R_FINISH 0x10 -#define AC_W_FINISH 0x08 -#define AC_W_RES 0x04 -#define AC_C_RES 0x02 - -/* bit definition of ACTL_RSR register */ -#define R_FIFO_EMPTY 0x04 -#define R_DMA_END_IRQ 0x02 -#define R_DMA_MIDDLE_IRQ 0x01 - -/* bit definition of ACTL_PSR register */ -#define P_FIFO_EMPTY 0x04 -#define P_DMA_END_IRQ 0x02 -#define P_DMA_MIDDLE_IRQ 0x01 - -/* bit definition of ACTL_ACOS0 register */ -#define SLOT1_VALID 0x01 -#define SLOT2_VALID 0x02 -#define SLOT3_VALID 0x04 -#define SLOT4_VALID 0x08 -#define VALID_FRAME 0x10 - -/* bit definition of ACTL_ACOS1 register */ -#define R_WB 0x80 - -#define CODEC_READY 0x10 -#define RESET_PRSR 0x00 -#define AUDIO_WRITE(addr, val) __raw_writel(val, addr) -#define AUDIO_READ(addr) __raw_readl(addr) - -struct nuc900_audio { - void __iomem *mmio; - spinlock_t lock; - unsigned long irq_num; - struct resource *res; - struct clk *clk; - struct device *dev; - -}; - -extern struct nuc900_audio *nuc900_ac97_data; - -#endif /*end _NUC900_AUDIO_H */ diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c deleted file mode 100644 index 4442a26e9502..000000000000 --- a/sound/soc/nuc900/nuc900-pcm.c +++ /dev/null @@ -1,321 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2010 Nuvoton technology corporation. - * - * Wan ZongShun - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "nuc900-audio.h" - -static const struct snd_pcm_hardware nuc900_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME, - .buffer_bytes_max = 4*1024, - .period_bytes_min = 1*1024, - .period_bytes_max = 4*1024, - .periods_min = 1, - .periods_max = 1024, -}; - -static int nuc900_dma_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); -} - -static void nuc900_update_dma_register(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - void __iomem *mmio_addr, *mmio_len; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - mmio_addr = nuc900_audio->mmio + ACTL_PDSTB; - mmio_len = nuc900_audio->mmio + ACTL_PDST_LENGTH; - } else { - mmio_addr = nuc900_audio->mmio + ACTL_RDSTB; - mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH; - } - - AUDIO_WRITE(mmio_addr, runtime->dma_addr); - AUDIO_WRITE(mmio_len, runtime->dma_bytes); -} - -static void nuc900_dma_start(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - unsigned long val; - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); - val |= (T_DMA_IRQ | R_DMA_IRQ); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); -} - -static void nuc900_dma_stop(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - unsigned long val; - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); - val &= ~(T_DMA_IRQ | R_DMA_IRQ); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); -} - -static irqreturn_t nuc900_dma_interrupt(int irq, void *dev_id) -{ - struct snd_pcm_substream *substream = dev_id; - struct nuc900_audio *nuc900_audio = substream->runtime->private_data; - unsigned long val; - - spin_lock(&nuc900_audio->lock); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); - - if (val & R_DMA_IRQ) { - AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | R_DMA_IRQ); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR); - - if (val & R_DMA_MIDDLE_IRQ) { - val |= R_DMA_MIDDLE_IRQ; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val); - } - - if (val & R_DMA_END_IRQ) { - val |= R_DMA_END_IRQ; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val); - } - } else if (val & T_DMA_IRQ) { - AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | T_DMA_IRQ); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR); - - if (val & P_DMA_MIDDLE_IRQ) { - val |= P_DMA_MIDDLE_IRQ; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val); - } - - if (val & P_DMA_END_IRQ) { - val |= P_DMA_END_IRQ; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val); - } - } else { - dev_err(nuc900_audio->dev, "Wrong DMA interrupt status!\n"); - spin_unlock(&nuc900_audio->lock); - return IRQ_HANDLED; - } - - spin_unlock(&nuc900_audio->lock); - - snd_pcm_period_elapsed(substream); - - return IRQ_HANDLED; -} - -static int nuc900_dma_hw_free(struct snd_pcm_substream *substream) -{ - snd_pcm_lib_free_pages(substream); - return 0; -} - -static int nuc900_dma_prepare(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - unsigned long flags, val; - int ret = 0; - - spin_lock_irqsave(&nuc900_audio->lock, flags); - - nuc900_update_dma_register(substream); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - - switch (runtime->channels) { - case 1: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - val &= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL); - val |= PLAY_RIGHT_CHNNEL; - } else { - val &= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL); - val |= RECORD_RIGHT_CHNNEL; - } - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - break; - case 2: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val |= (PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL); - else - val |= (RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - break; - default: - ret = -EINVAL; - } - spin_unlock_irqrestore(&nuc900_audio->lock, flags); - return ret; -} - -static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd) -{ - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - nuc900_dma_start(substream); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - nuc900_dma_stop(substream); - break; - - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static int nuc900_dma_getposition(struct snd_pcm_substream *substream, - dma_addr_t *src, dma_addr_t *dst) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - - if (src != NULL) - *src = AUDIO_READ(nuc900_audio->mmio + ACTL_PDSTC); - - if (dst != NULL) - *dst = AUDIO_READ(nuc900_audio->mmio + ACTL_RDSTC); - - return 0; -} - -static snd_pcm_uframes_t nuc900_dma_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - dma_addr_t src, dst; - unsigned long res; - - nuc900_dma_getposition(substream, &src, &dst); - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - res = dst - runtime->dma_addr; - else - res = src - runtime->dma_addr; - - return bytes_to_frames(substream->runtime, res); -} - -static int nuc900_dma_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio; - - snd_soc_set_runtime_hwparams(substream, &nuc900_pcm_hardware); - - nuc900_audio = nuc900_ac97_data; - - if (request_irq(nuc900_audio->irq_num, nuc900_dma_interrupt, - 0, "nuc900-dma", substream)) - return -EBUSY; - - runtime->private_data = nuc900_audio; - - return 0; -} - -static int nuc900_dma_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - - free_irq(nuc900_audio->irq_num, substream); - - return 0; -} - -static int nuc900_dma_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - return dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area, - runtime->dma_addr, runtime->dma_bytes); -} - -static const struct snd_pcm_ops nuc900_dma_ops = { - .open = nuc900_dma_open, - .close = nuc900_dma_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = nuc900_dma_hw_params, - .hw_free = nuc900_dma_hw_free, - .prepare = nuc900_dma_prepare, - .trigger = nuc900_dma_trigger, - .pointer = nuc900_dma_pointer, - .mmap = nuc900_dma_mmap, -}; - -static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_card *card = rtd->card->snd_card; - struct snd_pcm *pcm = rtd->pcm; - int ret; - - ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - card->dev, 4 * 1024, (4 * 1024) - 1); - - return 0; -} - -static const struct snd_soc_component_driver nuc900_soc_component = { - .ops = &nuc900_dma_ops, - .pcm_new = nuc900_dma_new, -}; - -static int nuc900_soc_platform_probe(struct platform_device *pdev) -{ - return devm_snd_soc_register_component(&pdev->dev, &nuc900_soc_component, - NULL, 0); -} - -static struct platform_driver nuc900_pcm_driver = { - .driver = { - .name = "nuc900-pcm-audio", - }, - - .probe = nuc900_soc_platform_probe, -}; - -module_platform_driver(nuc900_pcm_driver); - -MODULE_AUTHOR("Wan ZongShun, "); -MODULE_DESCRIPTION("nuc900 Audio DMA module"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From ae032156ec4142b7a1d644eba652806785de1777 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Fri, 9 Aug 2019 14:59:51 -0700 Subject: ASoC: rt5677: Revert remove superfluous set Commit 4dc057a786dc23 ("ASoC: rt5677: remove superfluous set") was an attempted code cleanup but was incorrectly tested before sent and actually breaks the interrupt since it never resets the value on each loop now. The breakage is most testable when hotwording code is added and also uses the interrupt. Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20190809215952.155660-1-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index deaed5132dc9..c779dc3474f9 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5098,6 +5098,7 @@ static irqreturn_t rt5677_irq(int unused, void *data) goto exit; } + irq_fired = false; for (i = 0; i < RT5677_IRQ_NUM; i++) { if (reg_irq & rt5677_irq_descs[i].status_mask) { irq_fired = true; -- cgit v1.2.3 From 9c2806c4941641a6c75736f8c4303c89d2013cc4 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 9 Aug 2019 18:27:46 +0800 Subject: ASoC: fsl_esai: Add compatible string for imx6ull Add compatible string for imx6ull, from imx6ull platform, the issue of channel swap after xrun is fixed in hardware. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/1565346467-5769-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 5832144beb9f..a78e4ab478df 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -1049,6 +1049,7 @@ static int fsl_esai_remove(struct platform_device *pdev) static const struct of_device_id fsl_esai_dt_ids[] = { { .compatible = "fsl,imx35-esai", }, { .compatible = "fsl,vf610-esai", }, + { .compatible = "fsl,imx6ull-esai", }, {} }; MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids); -- cgit v1.2.3 From cac974a51ebb955f3be260a9633836e1413c8672 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Fri, 9 Aug 2019 18:17:14 -0500 Subject: ASoC: SOF: topology: use set_get_data in process load Currently when loading sof process components there's a check if binary control data is associated with it. If found the data is extracted to be part of component loading and initialization. If binary data exceeds the ipc max size, loading fails with error as large message support is only implemented in set_get_data method. So make the process loading use set_get_data to enable large parameters in component initialization. Also refactor the process component loading function as it digs out 3 times almost identical information of related controls. This is redundant, looks ugly and makes it difficult to understand the mechanism. So make a function out of fetching the control data and use it in process loading. Signed-off-by: Ranjani Sridharan Signed-off-by: Jaska Uimonen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190809231714.20874-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 201 ++++++++++++++++++++++++++++++----------------- 1 file changed, 127 insertions(+), 74 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 12b7d900b9c2..9cffea142395 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -42,6 +42,13 @@ /* size of tplg abi in byte */ #define SOF_TPLG_ABI_SIZE 3 +struct sof_widget_data { + int ctrl_type; + int ipc_cmd; + struct sof_abi_hdr *pdata; + struct snd_sof_control *control; +}; + /* send pcm params ipc */ static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) { @@ -1742,51 +1749,32 @@ err: return ret; } -static int sof_process_load(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw, - struct sof_ipc_comp_reply *r, - int type) +static size_t sof_get_control_data(struct snd_sof_dev *sdev, + struct snd_soc_dapm_widget *widget, + struct sof_widget_data *wdata) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *private = &tw->priv; - struct snd_soc_dapm_widget *widget = swidget->widget; const struct snd_kcontrol_new *kc; - struct soc_bytes_ext *sbe; struct soc_mixer_control *sm; + struct soc_bytes_ext *sbe; struct soc_enum *se; - struct snd_sof_control *scontrol = NULL; - struct sof_abi_hdr *pdata = NULL; - struct sof_ipc_comp_process *process; - size_t ipc_size, ipc_data_size = 0; - int ret, i, offset = 0; - - if (type == SOF_COMP_NONE) { - dev_err(sdev->dev, "error: invalid process comp type %d\n", - type); - return -EINVAL; - } + size_t size = 0; + int i; - /* - * get possible component controls - get size of all pdata, - * then memcpy with headers - */ for (i = 0; i < widget->num_kcontrols; i++) { - kc = &widget->kcontrol_news[i]; switch (widget->dobj.widget.kcontrol_type) { case SND_SOC_TPLG_TYPE_MIXER: sm = (struct soc_mixer_control *)kc->private_value; - scontrol = sm->dobj.private; + wdata[i].control = sm->dobj.private; break; case SND_SOC_TPLG_TYPE_BYTES: sbe = (struct soc_bytes_ext *)kc->private_value; - scontrol = sbe->dobj.private; + wdata[i].control = sbe->dobj.private; break; case SND_SOC_TPLG_TYPE_ENUM: se = (struct soc_enum *)kc->private_value; - scontrol = se->dobj.private; + wdata[i].control = se->dobj.private; break; default: dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n", @@ -1795,31 +1783,98 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, return -EINVAL; } - if (!scontrol) { + if (!wdata[i].control) { dev_err(sdev->dev, "error: no scontrol for widget %s\n", widget->name); return -EINVAL; } - /* don't include if no private data */ - pdata = scontrol->control_data->data; - if (!pdata) - continue; + wdata[i].pdata = wdata[i].control->control_data->data; + if (!wdata[i].pdata) + return -EINVAL; /* make sure data is valid - data can be updated at runtime */ - if (pdata->magic != SOF_ABI_MAGIC) - continue; + if (wdata[i].pdata->magic != SOF_ABI_MAGIC) + return -EINVAL; + + size += wdata[i].pdata->size; + + /* get data type */ + switch (wdata[i].control->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_ENUM: + case SOF_CTRL_CMD_SWITCH: + wdata[i].ipc_cmd = SOF_IPC_COMP_SET_VALUE; + wdata[i].ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; + break; + case SOF_CTRL_CMD_BINARY: + wdata[i].ipc_cmd = SOF_IPC_COMP_SET_DATA; + wdata[i].ctrl_type = SOF_CTRL_TYPE_DATA_SET; + break; + default: + break; + } + } + + return size; +} + +static int sof_process_load(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r, + int type) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_dapm_widget *widget = swidget->widget; + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_process *process = NULL; + struct sof_widget_data *wdata = NULL; + size_t ipc_data_size = 0; + size_t ipc_size; + int offset = 0; + int ret = 0; + int i; + + if (type == SOF_COMP_NONE) { + dev_err(sdev->dev, "error: invalid process comp type %d\n", + type); + return -EINVAL; + } + + /* allocate struct for widget control data sizes and types */ + if (widget->num_kcontrols) { + wdata = kcalloc(widget->num_kcontrols, + sizeof(*wdata), + GFP_KERNEL); + + if (!wdata) + return -ENOMEM; - ipc_data_size += pdata->size; + /* get possible component controls and get size of all pdata */ + ipc_data_size = sof_get_control_data(sdev, widget, wdata); + + if (ipc_data_size <= 0) { + ret = ipc_data_size; + goto out; + } } ipc_size = sizeof(struct sof_ipc_comp_process) + le32_to_cpu(private->size) + ipc_data_size; + /* we are exceeding max ipc size, config needs to be sent separately */ + if (ipc_size > SOF_IPC_MSG_MAX_SIZE) { + ipc_size -= ipc_data_size; + ipc_data_size = 0; + } + process = kzalloc(ipc_size, GFP_KERNEL); - if (!process) - return -ENOMEM; + if (!process) { + ret = -ENOMEM; + goto out; + } /* configure iir IPC message */ process->comp.hdr.size = ipc_size; @@ -1845,40 +1900,13 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, * get possible component controls - get size of all pdata, * then memcpy with headers */ - for (i = 0; i < widget->num_kcontrols; i++) { - kc = &widget->kcontrol_news[i]; - - switch (widget->dobj.widget.kcontrol_type) { - case SND_SOC_TPLG_TYPE_MIXER: - sm = (struct soc_mixer_control *)kc->private_value; - scontrol = sm->dobj.private; - break; - case SND_SOC_TPLG_TYPE_BYTES: - sbe = (struct soc_bytes_ext *)kc->private_value; - scontrol = sbe->dobj.private; - break; - case SND_SOC_TPLG_TYPE_ENUM: - se = (struct soc_enum *)kc->private_value; - scontrol = se->dobj.private; - break; - default: - dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n", - widget->dobj.widget.kcontrol_type, - widget->name); - return -EINVAL; + if (ipc_data_size) { + for (i = 0; i < widget->num_kcontrols; i++) { + memcpy(&process->data + offset, + wdata[i].pdata->data, + wdata[i].pdata->size); + offset += wdata[i].pdata->size; } - - /* don't include if no private data */ - pdata = scontrol->control_data->data; - if (!pdata) - continue; - - /* make sure data is valid - data can be updated at runtime */ - if (pdata->magic != SOF_ABI_MAGIC) - continue; - - memcpy(&process->data + offset, pdata->data, pdata->size); - offset += pdata->size; } process->size = ipc_data_size; @@ -1886,10 +1914,35 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, ret = sof_ipc_tx_message(sdev->ipc, process->comp.hdr.cmd, process, ipc_size, r, sizeof(*r)); - if (ret >= 0) - return ret; + + if (ret < 0) { + dev_err(sdev->dev, "error: create process failed\n"); + goto err; + } + + /* we sent the data in single message so return */ + if (ipc_data_size) + goto out; + + /* send control data with large message supported method */ + for (i = 0; i < widget->num_kcontrols; i++) { + wdata[i].control->readback_offset = 0; + ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, wdata[i].control, + wdata[i].ipc_cmd, + wdata[i].ctrl_type, + wdata[i].control->cmd, + true); + if (ret != 0) { + dev_err(sdev->dev, "error: send control failed\n"); + break; + } + } + err: - kfree(process); + if (ret < 0) + kfree(process); +out: + kfree(wdata); return ret; } -- cgit v1.2.3 From 872f3ac583cb00c14a4dc86b1511cf98618dd671 Mon Sep 17 00:00:00 2001 From: Szymon Mielczarek Date: Fri, 9 Aug 2019 10:40:34 +0200 Subject: ASoC: dapm: Invalidate only paths reachable for a given stream By resetting the cached number of endpoints for all card's widgets we may overwrite previously cached values for other streams. The situation may happen especially when running streams simultaneously. Signed-off-by: Szymon Mielczarek Link: https://lore.kernel.org/r/20190809084034.26220-1-szymonx.mielczarek@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 50 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d09bdca63c62..10819b3e0b98 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1128,6 +1128,34 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, return 0; } +/* + * Recursively reset the cached number of inputs or outputs for the specified + * widget and all widgets that can be reached via incoming or outcoming paths + * from the widget. + */ +static void invalidate_paths_ep(struct snd_soc_dapm_widget *widget, + enum snd_soc_dapm_direction dir) +{ + enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir); + struct snd_soc_dapm_path *path; + + widget->endpoints[dir] = -1; + + snd_soc_dapm_widget_for_each_path(widget, rdir, path) { + if (path->weak || path->is_supply) + continue; + + if (path->walking) + return; + + if (path->connect) { + path->walking = 1; + invalidate_paths_ep(path->node[dir], dir); + path->walking = 0; + } + } +} + /* * Common implementation for is_connected_output_ep() and * is_connected_input_ep(). The function is inlined since the combined size of @@ -1257,21 +1285,17 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - /* - * For is_connected_{output,input}_ep fully discover the graph we need - * to reset the cached number of inputs and outputs. - */ - list_for_each_entry(w, &card->widgets, list) { - w->endpoints[SND_SOC_DAPM_DIR_IN] = -1; - w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1; - } - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - paths = is_connected_output_ep(dai->playback_widget, &widgets, + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + w = dai->playback_widget; + invalidate_paths_ep(w, SND_SOC_DAPM_DIR_OUT); + paths = is_connected_output_ep(w, &widgets, custom_stop_condition); - else - paths = is_connected_input_ep(dai->capture_widget, &widgets, + } else { + w = dai->capture_widget; + invalidate_paths_ep(w, SND_SOC_DAPM_DIR_IN); + paths = is_connected_input_ep(w, &widgets, custom_stop_condition); + } /* Drop starting point */ list_del(widgets.next); -- cgit v1.2.3 From 1a3fb5d3f420d5f022768fcff091e5a9862f5877 Mon Sep 17 00:00:00 2001 From: Sathya Prakash M R Date: Fri, 9 Aug 2019 18:22:33 -0500 Subject: ASoC: Intel: boards: Match Product Family instead of product The generic machine driver of sof_rt5682 supports more platforms of same product family. hence match the product family instead of product name. Signed-off-by: Sathya Prakash M R Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190809232236.21182-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index daeaa396d928..c1181bc0119e 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -91,8 +91,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { { .callback = sof_rt5682_quirk_cb, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_PRODUCT_NAME, "Hatch"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Hatch"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | SOF_RT5682_MCLK_24MHZ | -- cgit v1.2.3 From 0181d2853126db0717de6bd5b3287f1c87faf7c3 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 9 Aug 2019 18:22:35 -0500 Subject: ASoC: Intel: skl-hda-dsp-generic: add dependency to dmic driver The hda generic machine actually has dependency on the dmic driver, select SND_SOC_DMIC at the machine selected to fix it. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190809232236.21182-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 50bf149818b5..4a529cea0190 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -387,6 +387,7 @@ if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" select SND_SOC_HDAC_HDMI + select SND_SOC_DMIC # SND_SOC_HDAC_HDA is already selected help This adds support for ASoC machine driver for Intel platforms -- cgit v1.2.3 From 79631210fc413546d0ed73632ff904ded5192cc9 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 9 Aug 2019 18:22:36 -0500 Subject: ASoC: Intel: skl-hda-dsp-generic: add dmic dapm widget and route Adding DAPM MIC endpoint widget "SoC DMIC" and route, to enable DMIC DAPM support with hda generic machine. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190809232236.21182-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_hda_dsp_generic.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 9ed68eb4f058..1778acdc367c 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -23,6 +23,7 @@ static const struct snd_soc_dapm_widget skl_hda_widgets[] = { SND_SOC_DAPM_MIC("Alt Analog In", NULL), SND_SOC_DAPM_SPK("Digital Out", NULL), SND_SOC_DAPM_MIC("Digital In", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), }; static const struct snd_soc_dapm_route skl_hda_map[] = { @@ -41,6 +42,9 @@ static const struct snd_soc_dapm_route skl_hda_map[] = { { "Codec Input Pin2", NULL, "Digital In" }, { "Codec Input Pin3", NULL, "Alt Analog In" }, + /* digital mics */ + {"DMic", NULL, "SoC DMIC"}, + /* CODEC BE connections */ { "Analog Codec Playback", NULL, "Analog CPU Playback" }, { "Analog CPU Playback", NULL, "codec0_out" }, -- cgit v1.2.3 From abe51c351827e0086dad079dfe02918fecdf4830 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 12 Aug 2019 12:52:25 +0300 Subject: ASoC: pcm3168a: Retain the independence of DAC and ADC side of the codec The DAC and ADC path of the codec is independent, have dedicated LRCK (FS) and BCK for DAC/ADC. They can be configured to use different format, TDM slots and slot_width if needed. Move these parameters under dedicated io_params structure and manage them independently based on the dai. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190812095226.18870-2-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 125 +++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 71 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index e84a1509fe65..75fa8e9ee894 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -44,18 +44,25 @@ static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = { "VCCDA2" }; +#define PCM3168A_DAI_DAC 0 +#define PCM3168A_DAI_ADC 1 + +/* ADC/DAC side parameters */ +struct pcm3168a_io_params { + bool master_mode; + unsigned int fmt; + int tdm_slots; + u32 tdm_mask; + int slot_width; +}; + struct pcm3168a_priv { struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES]; struct regmap *regmap; struct clk *scki; - bool adc_master_mode; - bool dac_master_mode; unsigned long sysclk; - unsigned int adc_fmt; - unsigned int dac_fmt; - int tdm_slots; - u32 tdm_mask[2]; - int slot_width; + + struct pcm3168a_io_params io_params[2]; }; static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" }; @@ -308,8 +315,7 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai, return 0; } -static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, - unsigned int format, bool dac) +static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format) { struct snd_soc_component *component = dai->component; struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); @@ -356,43 +362,31 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, return -EINVAL; } - if (dac) { + if (dai->id == PCM3168A_DAI_DAC) { reg = PCM3168A_DAC_PWR_MST_FMT; mask = PCM3168A_DAC_FMT_MASK; shift = PCM3168A_DAC_FMT_SHIFT; - pcm3168a->dac_master_mode = master_mode; - pcm3168a->dac_fmt = fmt; } else { reg = PCM3168A_ADC_MST_FMT; mask = PCM3168A_ADC_FMTAD_MASK; shift = PCM3168A_ADC_FMTAD_SHIFT; - pcm3168a->adc_master_mode = master_mode; - pcm3168a->adc_fmt = fmt; } + pcm3168a->io_params[dai->id].master_mode = master_mode; + pcm3168a->io_params[dai->id].fmt = fmt; + regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift); return 0; } -static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai, - unsigned int format) -{ - return pcm3168a_set_dai_fmt(dai, format, true); -} - -static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai, - unsigned int format) -{ - return pcm3168a_set_dai_fmt(dai, format, false); -} - static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct snd_soc_component *component = dai->component; struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); + struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id]; if (tx_mask >= (1<= (1<dev, @@ -408,22 +402,25 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, return -EINVAL; } - if (pcm3168a->tdm_slots && pcm3168a->tdm_slots != slots) { + if (io_params->tdm_slots && io_params->tdm_slots != slots) { dev_err(component->dev, "Not matching slots %d vs %d\n", - pcm3168a->tdm_slots, slots); + io_params->tdm_slots, slots); return -EINVAL; } - if (pcm3168a->slot_width && pcm3168a->slot_width != slot_width) { + if (io_params->slot_width && io_params->slot_width != slot_width) { dev_err(component->dev, "Not matching slot_width %d vs %d\n", - pcm3168a->slot_width, slot_width); + io_params->slot_width, slot_width); return -EINVAL; } - pcm3168a->tdm_slots = slots; - pcm3168a->slot_width = slot_width; - pcm3168a->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; - pcm3168a->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; + io_params->tdm_slots = slots; + io_params->slot_width = slot_width; + /* Ignore the not relevant mask for the DAI/direction */ + if (dai->id == PCM3168A_DAI_DAC) + io_params->tdm_mask = tx_mask; + else + io_params->tdm_mask = rx_mask; return 0; } @@ -434,7 +431,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); - bool tx, master_mode; + struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id]; + bool master_mode; u32 val, mask, shift, reg; unsigned int rate, fmt, ratio, max_ratio; unsigned int tdm_slots; @@ -444,23 +442,21 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, ratio = pcm3168a->sysclk / rate; - tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - if (tx) { + if (dai->id == PCM3168A_DAI_DAC) { max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC; reg = PCM3168A_DAC_PWR_MST_FMT; mask = PCM3168A_DAC_MSDA_MASK; shift = PCM3168A_DAC_MSDA_SHIFT; - master_mode = pcm3168a->dac_master_mode; - fmt = pcm3168a->dac_fmt; } else { max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC; reg = PCM3168A_ADC_MST_FMT; mask = PCM3168A_ADC_MSAD_MASK; shift = PCM3168A_ADC_MSAD_SHIFT; - master_mode = pcm3168a->adc_master_mode; - fmt = pcm3168a->adc_fmt; } + master_mode = io_params->master_mode; + fmt = io_params->fmt; + for (i = 0; i < max_ratio; i++) { if (pcm3168a_scki_ratios[i] == ratio) break; @@ -471,8 +467,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if (pcm3168a->slot_width) - slot_width = pcm3168a->slot_width; + if (io_params->slot_width) + slot_width = io_params->slot_width; else slot_width = params_width(params); @@ -497,8 +493,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if (pcm3168a->tdm_slots) - tdm_slots = pcm3168a->tdm_slots; + if (io_params->tdm_slots) + tdm_slots = io_params->tdm_slots; else tdm_slots = params_channels(params); @@ -534,7 +530,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(pcm3168a->regmap, reg, mask, val); - if (tx) { + if (dai->id == PCM3168A_DAI_DAC) { mask = PCM3168A_DAC_FMT_MASK; shift = PCM3168A_DAC_FMT_SHIFT; } else { @@ -552,20 +548,13 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); - bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - unsigned int fmt; unsigned int sample_min; unsigned int channel_max; unsigned int channel_maxs[] = { - 6, /* rx */ - 8 /* tx */ + 8, /* DAC */ + 6 /* ADC */ }; - if (tx) - fmt = pcm3168a->dac_fmt; - else - fmt = pcm3168a->adc_fmt; - /* * Available Data Bits * @@ -578,7 +567,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, * I2S * LEFT_J */ - switch (fmt) { + switch (pcm3168a->io_params[dai->id].fmt) { case PCM3168A_FMT_RIGHT_J: sample_min = 16; channel_max = 2; @@ -588,7 +577,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, case PCM3168A_FMT_DSP_A: case PCM3168A_FMT_DSP_B: sample_min = 24; - channel_max = channel_maxs[tx]; + channel_max = channel_maxs[dai->id]; break; default: sample_min = 24; @@ -600,8 +589,8 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, sample_min, 32); /* Allow all channels in multi DIN/DOUT mode */ - if (pcm3168a->tdm_slots == 2) - channel_max = channel_maxs[tx]; + if (pcm3168a->io_params[dai->id].tdm_slots == 2) + channel_max = channel_maxs[dai->id]; snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_CHANNELS, @@ -609,26 +598,19 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = { +static const struct snd_soc_dai_ops pcm3168a_dai_ops = { .startup = pcm3168a_startup, - .set_fmt = pcm3168a_set_dai_fmt_dac, + .set_fmt = pcm3168a_set_dai_fmt, .set_sysclk = pcm3168a_set_dai_sysclk, .hw_params = pcm3168a_hw_params, .digital_mute = pcm3168a_digital_mute, .set_tdm_slot = pcm3168a_set_tdm_slot, }; -static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = { - .startup = pcm3168a_startup, - .set_fmt = pcm3168a_set_dai_fmt_adc, - .set_sysclk = pcm3168a_set_dai_sysclk, - .hw_params = pcm3168a_hw_params, - .set_tdm_slot = pcm3168a_set_tdm_slot, -}; - static struct snd_soc_dai_driver pcm3168a_dais[] = { { .name = "pcm3168a-dac", + .id = PCM3168A_DAI_DAC, .playback = { .stream_name = "Playback", .channels_min = 1, @@ -636,10 +618,11 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = PCM3168A_FORMATS }, - .ops = &pcm3168a_dac_dai_ops + .ops = &pcm3168a_dai_ops }, { .name = "pcm3168a-adc", + .id = PCM3168A_DAI_ADC, .capture = { .stream_name = "Capture", .channels_min = 1, @@ -647,7 +630,7 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = { .rates = SNDRV_PCM_RATE_8000_96000, .formats = PCM3168A_FORMATS }, - .ops = &pcm3168a_adc_dai_ops + .ops = &pcm3168a_dai_ops }, }; -- cgit v1.2.3 From 6fa4e0cae684d268d309d1b1f929d52e3df5649c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 12 Aug 2019 12:52:26 +0300 Subject: ASoC: pcm3168a: Allow reconfiguration of tdm_slots and slot_width When using right_j format and the codec is slave it can support 16bit format, but only if slot_width == 16, in the same DAI mode the 24 bit audio can work with 24 or 32 slot_width. Because of this, the codec and CPU needs to be reconfigured when the sample format changes. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190812095226.18870-3-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 75fa8e9ee894..50ed86d45c26 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -402,18 +402,6 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, return -EINVAL; } - if (io_params->tdm_slots && io_params->tdm_slots != slots) { - dev_err(component->dev, "Not matching slots %d vs %d\n", - io_params->tdm_slots, slots); - return -EINVAL; - } - - if (io_params->slot_width && io_params->slot_width != slot_width) { - dev_err(component->dev, "Not matching slot_width %d vs %d\n", - io_params->slot_width, slot_width); - return -EINVAL; - } - io_params->tdm_slots = slots; io_params->slot_width = slot_width; /* Ignore the not relevant mask for the DAI/direction */ -- cgit v1.2.3 From 7da20788d3ff59506aebd946d8a424f01f2c1c66 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 12 Aug 2019 18:01:47 +0200 Subject: ALSA: hda: Set fifo_size for both playback and capture streams Currently we set hdac_stream.fifo_size field only for the playback stream by some odd reason I forgot, while this field isn't referred in any places. Actually this fifo_size field would have been required in the position report correction for VIA chipset, but due to the lack of the fifo_size set for capture streams, snd-hda-intel driver fetches the register by itself. This patch straightens and simplifies the code by setting the fifo_size field for both playback and capture streams, and use it in the HD-audio controller driver. Signed-off-by: Takashi Iwai --- sound/hda/hdac_stream.c | 6 +----- sound/pci/hda/hda_intel.c | 8 +------- 2 files changed, 2 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index fc68d4ce0a37..d8fe7ff0cd58 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -229,11 +229,7 @@ int snd_hdac_stream_setup(struct hdac_stream *azx_dev) /* set the interrupt enable bits in the descriptor control register */ snd_hdac_stream_updatel(azx_dev, SD_CTL, 0, SD_INT_MASK); - if (azx_dev->direction == SNDRV_PCM_STREAM_PLAYBACK) - azx_dev->fifo_size = - snd_hdac_stream_readw(azx_dev, SD_FIFOSIZE) + 1; - else - azx_dev->fifo_size = 0; + azx_dev->fifo_size = snd_hdac_stream_readw(azx_dev, SD_FIFOSIZE) + 1; /* when LPIB delay correction gives a small negative value, * we ignore it; currently set the threshold statically to diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3a209e07d5d8..dc8a83cb7393 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -84,8 +84,6 @@ enum { #define INTEL_SCH_HDA_DEVC 0x78 #define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) -/* Define IN stream 0 FIFO size offset in VIA controller */ -#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 /* Define VIA HD Audio Device ID*/ #define VIA_HDAC_DEVICE_ID 0x3288 @@ -811,11 +809,7 @@ static unsigned int azx_via_get_position(struct azx *chip, mod_dma_pos = le32_to_cpu(*azx_dev->core.posbuf); mod_dma_pos %= azx_dev->core.period_bytes; - /* azx_dev->fifo_size can't get FIFO size of in stream. - * Get from base address + offset. - */ - fifo_size = readw(azx_bus(chip)->remap_addr + - VIA_IN_STREAM0_FIFO_SIZE_OFFSET); + fifo_size = azx_stream(azx_dev)->fifo_size - 1; if (azx_dev->insufficient) { /* Link position never gather than FIFO size */ -- cgit v1.2.3 From 68b953aeb50d9206de27d6c216e301f01dfac34d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Aug 2019 11:06:23 -0500 Subject: ASoC: SOF: Intel: hda: fixup HDaudio topology name with DMIC number The SOF project maintains 6 topologies for HDaudio (iDisp or HDaudio+iDisp, no DMIC, 2 DMICs, 4 DMICs). The user is currently required to manually rename the topology file used in /lib/firmware/intel/sof-tplg. We can do better to avoid such renames and use logic to select the relevant file. The NHLT information can be used to figure out which topology file should be used. Alternatively, when NHLT is not present in ACPI tables or is possibly incorrect, a module parameter can provide that information, e.g. on Up^2 board with the test DMIC kit. Tested on Up^2 board and Acer Swift-SF314-55 Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190812160623.20821-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 1 + sound/soc/sof/intel/hda.c | 75 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index dd14ce92fe10..545071afbe18 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -254,6 +254,7 @@ config SND_SOC_SOF_HDA tristate select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC + select SND_INTEL_NHLT help This option is not user-selectable but automagically handled by 'select' statements at a higher level diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 28eb780494aa..c97c004afa43 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include "../ops.h" @@ -49,6 +50,12 @@ module_param_named(use_msi, hda_use_msi, bool, 0444); MODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode"); #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +static int hda_dmic_num = -1; +module_param_named(dmic_num, hda_dmic_num, int, 0444); +MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number"); +#endif + static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = { {HDA_DSP_ROM_FW_MANIFEST_LOADED, "status: manifest loaded"}, {HDA_DSP_ROM_FW_FW_LOADED, "status: fw loaded"}, @@ -283,8 +290,26 @@ static int hda_init(struct snd_sof_dev *sdev) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +static int check_nhlt_dmic(struct snd_sof_dev *sdev) +{ + struct nhlt_acpi_table *nhlt; + int dmic_num; + + nhlt = intel_nhlt_init(sdev->dev); + if (nhlt) { + dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt); + intel_nhlt_free(nhlt); + if (dmic_num == 2 || dmic_num == 4) + return dmic_num; + } + + return 0; +} + static const char *fixup_tplg_name(struct snd_sof_dev *sdev, - const char *sof_tplg_filename) + const char *sof_tplg_filename, + const char *idisp_str, + const char *dmic_str) { const char *tplg_filename = NULL; char *filename; @@ -298,7 +323,8 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, split_ext = strsep(&filename, "."); if (split_ext) { tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, - "%s-idisp.tplg", split_ext); + "%s%s%s.tplg", + split_ext, idisp_str, dmic_str); if (!tplg_filename) return NULL; } @@ -317,6 +343,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct snd_sof_pdata *pdata = sdev->pdata; struct snd_soc_acpi_mach *mach; const char *tplg_filename; + const char *idisp_str; + const char *dmic_str; + int dmic_num; int codec_num = 0; int i; #endif @@ -381,17 +410,39 @@ static int hda_init_caps(struct snd_sof_dev *sdev) dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); - /* fixup topology file for HDMI only platforms */ - if (codec_num == 1) { - /* use local variable for readability */ - tplg_filename = pdata->tplg_filename; - tplg_filename = fixup_tplg_name(sdev, tplg_filename); - if (!tplg_filename) { - hda_codec_i915_exit(sdev); - return ret; - } - pdata->tplg_filename = tplg_filename; + if (codec_num == 1) + idisp_str = "-idisp"; + else + idisp_str = ""; + + /* first check NHLT for DMICs */ + dmic_num = check_nhlt_dmic(sdev); + + /* allow for module parameter override */ + if (hda_dmic_num != -1) + dmic_num = hda_dmic_num; + + switch (dmic_num) { + case 2: + dmic_str = "-2ch"; + break; + case 4: + dmic_str = "-4ch"; + break; + default: + dmic_num = 0; + dmic_str = ""; + break; + } + + tplg_filename = pdata->tplg_filename; + tplg_filename = fixup_tplg_name(sdev, tplg_filename, + idisp_str, dmic_str); + if (!tplg_filename) { + hda_codec_i915_exit(sdev); + return ret; } + pdata->tplg_filename = tplg_filename; } } -- cgit v1.2.3 From 7188f656cdf762d4ea8ce16b6aaf4c6b06e119ec Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Tue, 13 Aug 2019 15:44:30 +0800 Subject: ASoC: rockchip: rockchip_max98090: Set period size to 240 From stress testing of arecord, we found that period size greater than ~900 will bring pl330 to DYING state and can not recover within 100 iterations. The result is that arecord will stuck and get I/O error, and issue can not be recovered until reboot. This issue does not happen when period size is small. Set constraint of period size to 240 to prevent such issue. With the constraint, there will be no issue after 2000 iterations. We can revert this patch once the root cause is found in rockchip's pl330 implementation. Signed-off-by: Cheng-Yi Chiang Link: https://lore.kernel.org/r/20190813074430.191791-1-cychiang@chromium.org Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_max98090.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index 782e534d4c0d..d54f672d38d8 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -138,8 +138,19 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream, return ret; } +static int rk_aif1_startup(struct snd_pcm_substream *substream) +{ + /* + * Set period size to 240 because pl330 has issue + * dealing with larger period in stress testing. + */ + return snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 240, 240); +} + static const struct snd_soc_ops rk_aif1_ops = { .hw_params = rk_aif1_hw_params, + .startup = rk_aif1_startup, }; SND_SOC_DAILINK_DEFS(hifi, -- cgit v1.2.3 From ae3a5901dde2ab136ec0cebda2fccc48e810d2ec Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Tue, 13 Aug 2019 12:42:35 +0900 Subject: ASoC: ti: Fix typos in ti/Kconfig This patch fixes some spelling typo in Kconfig. Signed-off-by: Masanari Iida Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190813034235.30673-1-standby24x7@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig index 2197f3e1eaed..87a9b9dd4e98 100644 --- a/sound/soc/ti/Kconfig +++ b/sound/soc/ti/Kconfig @@ -12,7 +12,7 @@ config SND_SOC_TI_SDMA_PCM comment "Texas Instruments DAI support for:" config SND_SOC_DAVINCI_ASP - tristate "daVinci Audio Serial Port (ASP) or McBSP suport" + tristate "daVinci Audio Serial Port (ASP) or McBSP support" depends on ARCH_DAVINCI || COMPILE_TEST select SND_SOC_TI_EDMA_PCM help @@ -33,7 +33,7 @@ config SND_SOC_DAVINCI_MCASP - Keystone devices config SND_SOC_DAVINCI_VCIF - tristate "daVinci Voice Interface (VCIF) suport" + tristate "daVinci Voice Interface (VCIF) support" depends on ARCH_DAVINCI || COMPILE_TEST select SND_SOC_TI_EDMA_PCM help -- cgit v1.2.3 From 8da2d74c10fd71cc04e2585fe8bb3ced325f8e25 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Aug 2019 09:03:05 -0500 Subject: ASoC: Intel: hsw: remove i386 build warning w/ size_t argument Recent changes in the common IPC code introduced a build warning with size_t fields, use the correct %zu format. include/linux/dynamic_debug.h:82:16: warning: format '%lu' expects argument of type 'long unsigned int', but argument 4 has type 'size_t' [-Wformat=] Fixes: abf31feea26c0 ('ASoC: Intel: Update request-reply IPC model') Reported-by: kbuild test robot Cc: Cezary Rojewski Signed-off-by: Pierre-Louis Bossart Acked-By: Cezary Rojewski Link: https://lore.kernel.org/r/20190812140305.17570-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/haswell/sst-haswell-ipc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index 5c73b11375e3..0ff89ea96ccf 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -2015,11 +2015,11 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, if (payload_size <= SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE) { /* short parameter, mailbox can contain data */ - dev_dbg(dev, "transfer parameter size : %lu\n", + dev_dbg(dev, "transfer parameter size : %zu\n", request.size); request.size = ALIGN(payload_size, 4); - dev_dbg(dev, "transfer parameter aligned size : %lu\n", + dev_dbg(dev, "transfer parameter aligned size : %zu\n", request.size); parameter = kzalloc(request.size, GFP_KERNEL); -- cgit v1.2.3 From 9c6c417d95d83999c16965186f6e755ad8a8b658 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Aug 2019 14:05:02 -0500 Subject: ASoC: SOF: fix HDA direct MMIO access The recent change to remove the bus->io_ops callbacks used an older version of the SOF code base, and when merged into Mark's for-next it invalidated changes, resulting in broken compilation identified by kbuild and reproduced during the weekly SOF rebase. Restore SOF code overridden by git merge and apply Takashi's intended change in the 'right' location. Fixes: c2f16a94a8049 ("Merge branch 'topic/hda-bus-ops-cleanup'") Reported-by: kbuild test robot Cc: Takashi Iwai Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190812190502.30729-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-ctrl.c | 2 +- sound/soc/sof/intel/hda-dsp.c | 39 --------------------------------------- 2 files changed, 1 insertion(+), 40 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index a7fee403cb90..bc41028a7a01 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -254,7 +254,7 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* Reset stream-to-link mapping */ list_for_each_entry(hlink, &bus->hlink_list, list) - bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); + writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); #endif bus->chip_init = true; diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 097727cda5cb..fb55a3c5afd0 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -354,45 +354,6 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) return ret; } - hda_dsp_ctrl_misc_clock_gating(sdev, false); - - /* Reset stream-to-link mapping */ - list_for_each_entry(hlink, &bus->hlink_list, list) - writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); - - hda_dsp_ctrl_misc_clock_gating(sdev, true); -#else - - hda_dsp_ctrl_misc_clock_gating(sdev, false); - - /* reset controller */ - ret = hda_dsp_ctrl_link_reset(sdev, true); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to reset controller during resume\n"); - return ret; - } - - /* take controller out of reset */ - ret = hda_dsp_ctrl_link_reset(sdev, false); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to ready controller during resume\n"); - return ret; - } - - /* enable hda bus irq */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); - - hda_dsp_ctrl_misc_clock_gating(sdev, true); -#endif - - /* enable ppcap interrupt */ - hda_dsp_ctrl_ppcap_enable(sdev, true); - hda_dsp_ctrl_ppcap_int_enable(sdev, true); - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* check jack status */ if (runtime_resume) -- cgit v1.2.3 From 31fa571c01d869c659d6bc0a7960a55ce314923c Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 13 Aug 2019 22:43:23 +0800 Subject: ALSA: hda/sigmatel - remove unused variable 'stac9200_core_init' sound/pci/hda/patch_sigmatel.c:981:30: warning: stac9200_core_init defined but not used [-Wunused-const-variable=] It is never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 0d9b62768241..894f3f509e76 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -975,15 +975,6 @@ static int stac_create_spdif_mux_ctls(struct hda_codec *codec) return 0; } -/* - */ - -static const struct hda_verb stac9200_core_init[] = { - /* set dac0mux for dac converter */ - { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {} -}; - static const struct hda_verb stac9200_eapd_init[] = { /* set dac0mux for dac converter */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, -- cgit v1.2.3 From d7da429339f503854b777ed941456841a72b48b6 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 13 Aug 2019 15:01:51 +0100 Subject: ALSA: sb: remove redundant assignment to variable result Variable result is initialized to a value that is never read and it is re-assigned later. The initialization is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Takashi Iwai --- sound/isa/sb/sb_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index 162338f1b68a..ff031d670400 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -80,7 +80,7 @@ int snd_sbdsp_reset(struct snd_sb *chip) static int snd_sbdsp_version(struct snd_sb * chip) { - unsigned int result = -ENODEV; + unsigned int result; snd_sbdsp_command(chip, SB_DSP_GET_VERSION); result = (short) snd_sbdsp_get_byte(chip) << 8; -- cgit v1.2.3 From f2dbe87c5ac1f88e6007ba1f1374f4bd8a197fb6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 13 Aug 2019 17:11:28 +0200 Subject: ALSA: hda - Drop unsol event handler for Intel HDMI codecs We don't need to deal with the unsol events for Intel chips that are tied with the graphics via audio component notifier. Although the presence of the audio component is checked at the beginning of hdmi_unsol_event(), better to short cut by dropping unsol_event ops. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=204565 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 2096993eaf28..933c7bf47ef6 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2760,6 +2760,8 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec, /* precondition and allocation for Intel codecs */ static int alloc_intel_hdmi(struct hda_codec *codec) { + int err; + /* requires i915 binding */ if (!codec->bus->core.audio_component) { codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n"); @@ -2768,7 +2770,12 @@ static int alloc_intel_hdmi(struct hda_codec *codec) return -ENODEV; } - return alloc_generic_hdmi(codec); + err = alloc_generic_hdmi(codec); + if (err < 0) + return err; + /* no need to handle unsol events */ + codec->patch_ops.unsol_event = NULL; + return 0; } /* parse and post-process for Intel codecs */ -- cgit v1.2.3 From ee5f85d9290fe25d460bd320b7fe073075d72d33 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 13 Aug 2019 17:25:39 +0200 Subject: ALSA: hda: Add codec on bus address table lately The call of snd_hdac_bus_add_device() is needed only for registering the codec onto the bus caddr_tbl[] that is referred essentially only in the unsol event handler. That is, the reason of this call and the release by the counter-part function snd_hdac_bus_remove_device() is just to assure that the unsol event gets notified to the codec. But the current implementation of the unsol notification wouldn't work properly when the codec is still in a premature init state. So this patch tries to work around it by delaying the caddr_tbl[] registration at the point of snd_hdac_device_register(). Also, the order of snd_hdac_bus_remove_device() and device_del() calls are shuffled to make sure that the unsol event is masked before deleting the device. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=204565 Signed-off-by: Takashi Iwai --- sound/hda/hdac_device.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index b26cc93e7e10..033bcef8751a 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -61,10 +61,6 @@ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus, pm_runtime_get_noresume(&codec->dev); atomic_set(&codec->in_pm, 0); - err = snd_hdac_bus_add_device(bus, codec); - if (err < 0) - goto error; - /* fill parameters */ codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, AC_PAR_VENDOR_ID); @@ -143,15 +139,22 @@ int snd_hdac_device_register(struct hdac_device *codec) err = device_add(&codec->dev); if (err < 0) return err; + err = snd_hdac_bus_add_device(codec->bus, codec); + if (err < 0) + goto error; mutex_lock(&codec->widget_lock); err = hda_widget_sysfs_init(codec); mutex_unlock(&codec->widget_lock); - if (err < 0) { - device_del(&codec->dev); - return err; - } + if (err < 0) + goto error_remove; return 0; + + error_remove: + snd_hdac_bus_remove_device(codec->bus, codec); + error: + device_del(&codec->dev); + return err; } EXPORT_SYMBOL_GPL(snd_hdac_device_register); @@ -165,8 +168,8 @@ void snd_hdac_device_unregister(struct hdac_device *codec) mutex_lock(&codec->widget_lock); hda_widget_sysfs_exit(codec); mutex_unlock(&codec->widget_lock); - device_del(&codec->dev); snd_hdac_bus_remove_device(codec->bus, codec); + device_del(&codec->dev); } } EXPORT_SYMBOL_GPL(snd_hdac_device_unregister); -- cgit v1.2.3 From 53eff75e5f4dd4b9bc489955fdc60fde48d85e93 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 14 Aug 2019 18:27:08 +0200 Subject: ALSA: hda: Drop export of snd_hdac_bus_add/remove_device() snd_hdac_bus_add_device() and snd_hdac_remove_device() are called only internally in hda-core. Let's drop the exports of them and move the declarations into local.h. Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 3 --- sound/hda/hdac_bus.c | 3 +-- sound/hda/local.h | 4 ++++ 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 4af4af55e854..edb176a265c7 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -374,9 +374,6 @@ int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr, unsigned int cmd, unsigned int *res); void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex); -int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec); -void snd_hdac_bus_remove_device(struct hdac_bus *bus, - struct hdac_device *codec); void snd_hdac_bus_process_unsol_events(struct work_struct *work); static inline void snd_hdac_codec_link_up(struct hdac_device *codec) diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index cd25e2b3f7f2..18ed3185df82 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -9,6 +9,7 @@ #include #include #include +#include "local.h" #include "trace.h" static const struct hdac_bus_ops default_ops = { @@ -196,7 +197,6 @@ int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec) bus->num_codecs++; return 0; } -EXPORT_SYMBOL_GPL(snd_hdac_bus_add_device); /** * snd_hdac_bus_remove_device - Remove a codec from bus @@ -215,7 +215,6 @@ void snd_hdac_bus_remove_device(struct hdac_bus *bus, bus->num_codecs--; flush_work(&bus->unsol_work); } -EXPORT_SYMBOL_GPL(snd_hdac_bus_remove_device); #ifdef CONFIG_SND_HDA_ALIGNED_MMIO /* Helpers for aligned read/write of mmio space, for Tegra */ diff --git a/sound/hda/local.h b/sound/hda/local.h index 877631e39373..3a4e303169a6 100644 --- a/sound/hda/local.h +++ b/sound/hda/local.h @@ -33,4 +33,8 @@ int hda_widget_sysfs_reinit(struct hdac_device *codec, hda_nid_t start_nid, int num_nodes); void hda_widget_sysfs_exit(struct hdac_device *codec); +int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec); +void snd_hdac_bus_remove_device(struct hdac_bus *bus, + struct hdac_device *codec); + #endif /* __HDAC_LOCAL_H */ -- cgit v1.2.3 From ddf7cb83b0f45feb94ad89a987f600c766c463ca Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 14 Aug 2019 19:59:44 +0200 Subject: ALSA: hda: Unexport a few more stuff Drop EXPORT_SYMBOL*() from a few more stuff in HD-audio core that aren't used outside. Particular the unsol event handler can be staticized now because the recent change removed all external callers. Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 6 ------ sound/hda/hdac_bus.c | 5 +++-- sound/hda/hdac_device.c | 6 ++---- sound/hda/hdac_regmap.c | 1 + sound/hda/local.h | 3 +++ 5 files changed, 9 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index edb176a265c7..b260c5fd2337 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -122,10 +122,6 @@ int snd_hdac_codec_modalias(struct hdac_device *hdac, char *buf, size_t size); int snd_hdac_refresh_widgets(struct hdac_device *codec); -unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, - unsigned int verb, unsigned int parm); -int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd, - unsigned int flags, unsigned int *res); int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid, unsigned int verb, unsigned int parm, unsigned int *res); int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm, @@ -374,8 +370,6 @@ int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr, unsigned int cmd, unsigned int *res); void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex); -void snd_hdac_bus_process_unsol_events(struct work_struct *work); - static inline void snd_hdac_codec_link_up(struct hdac_device *codec) { set_bit(codec->addr, &codec->bus->codec_powered); diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index 18ed3185df82..8f19876244eb 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -12,6 +12,8 @@ #include "local.h" #include "trace.h" +static void snd_hdac_bus_process_unsol_events(struct work_struct *work); + static const struct hdac_bus_ops default_ops = { .command = snd_hdac_bus_send_cmd, .get_response = snd_hdac_bus_get_response, @@ -149,7 +151,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_queue_event); /* * process queued unsolicited events */ -void snd_hdac_bus_process_unsol_events(struct work_struct *work) +static void snd_hdac_bus_process_unsol_events(struct work_struct *work) { struct hdac_bus *bus = container_of(work, struct hdac_bus, unsol_work); struct hdac_device *codec; @@ -172,7 +174,6 @@ void snd_hdac_bus_process_unsol_events(struct work_struct *work) drv->unsol_event(codec, res); } } -EXPORT_SYMBOL_GPL(snd_hdac_bus_process_unsol_events); /** * snd_hdac_bus_add_device - Add a codec to bus diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index 033bcef8751a..bf83d7062ef6 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -221,8 +221,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_codec_modalias); * * Return an encoded command verb or -1 for error. */ -unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, - unsigned int verb, unsigned int parm) +static unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, + unsigned int verb, unsigned int parm) { u32 val, addr; @@ -240,7 +240,6 @@ unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, val |= parm; return val; } -EXPORT_SYMBOL_GPL(snd_hdac_make_cmd); /** * snd_hdac_exec_verb - execute an encoded verb @@ -261,7 +260,6 @@ int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd, return codec->exec_verb(codec, cmd, flags, res); return snd_hdac_bus_exec_verb(codec->bus, codec->addr, cmd, res); } -EXPORT_SYMBOL_GPL(snd_hdac_exec_verb); /** diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c index f399a1552e73..286361ecd640 100644 --- a/sound/hda/hdac_regmap.c +++ b/sound/hda/hdac_regmap.c @@ -21,6 +21,7 @@ #include #include #include +#include "local.h" static int codec_pm_lock(struct hdac_device *codec) { diff --git a/sound/hda/local.h b/sound/hda/local.h index 3a4e303169a6..5b935219352f 100644 --- a/sound/hda/local.h +++ b/sound/hda/local.h @@ -37,4 +37,7 @@ int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec); void snd_hdac_bus_remove_device(struct hdac_bus *bus, struct hdac_device *codec); +int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd, + unsigned int flags, unsigned int *res); + #endif /* __HDAC_LOCAL_H */ -- cgit v1.2.3 From 630742c296341a8cfe00dfd941392025ba8dd4e8 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:23:00 +0800 Subject: ASoC: es8328: Fix copy-paste error in es8328_right_line_controls It seems 'es8328_rline_enum' should be used in es8328_right_line_controls Fixes: 567e4f98922c ("ASoC: add es8328 codec driver") Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815092300.68712-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 822a25a8f53c..69b81e704127 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -228,7 +228,7 @@ static const struct soc_enum es8328_rline_enum = ARRAY_SIZE(es8328_line_texts), es8328_line_texts); static const struct snd_kcontrol_new es8328_right_line_controls = - SOC_DAPM_ENUM("Route", es8328_lline_enum); + SOC_DAPM_ENUM("Route", es8328_rline_enum); /* Left Mixer */ static const struct snd_kcontrol_new es8328_left_mixer_controls[] = { -- cgit v1.2.3 From 9b4275c415acca6264a3d7f1182589959c93d530 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:01:57 +0800 Subject: ASoC: cs4349: Use PM ops 'cs4349_runtime_pm' sound/soc/codecs/cs4349.c:358:32: warning: cs4349_runtime_pm defined but not used [-Wunused-const-variable=] cs4349_runtime_pm ops already defined, it seems we should enable it. Reported-by: Hulk Robot Fixes: e40da86 ("ASoC: cs4349: Add support for Cirrus Logic CS4349") Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815090157.70036-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 09716fab1e26..3381209a882d 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -378,6 +378,7 @@ static struct i2c_driver cs4349_i2c_driver = { .driver = { .name = "cs4349", .of_match_table = cs4349_of_match, + .pm = &cs4349_runtime_pm, }, .id_table = cs4349_i2c_id, .probe = cs4349_i2c_probe, -- cgit v1.2.3 From 554b75bde64bcad9662530726d1483f7ef012069 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:19:20 +0800 Subject: ASoC: wm8737: Fix copy-paste error in wm8737_snd_controls sound/soc/codecs/wm8737.c:112:29: warning: high_3d defined but not used [-Wunused-const-variable=] 'high_3d' should be used for 3D High Cut-off. Reported-by: Hulk Robot Fixes: 2a9ae13a2641 ("ASoC: Add initial WM8737 driver") Signed-off-by: YueHaibing Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20190815091920.64480-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8737.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 0c246fb5e5ac..7a3f9fbe8d53 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -167,7 +167,7 @@ SOC_DOUBLE("Polarity Invert Switch", WM8737_ADC_CONTROL, 5, 6, 1, 0), SOC_SINGLE("3D Switch", WM8737_3D_ENHANCE, 0, 1, 0), SOC_SINGLE("3D Depth", WM8737_3D_ENHANCE, 1, 15, 0), SOC_ENUM("3D Low Cut-off", low_3d), -SOC_ENUM("3D High Cut-off", low_3d), +SOC_ENUM("3D High Cut-off", high_3d), SOC_SINGLE_TLV("3D ADC Volume", WM8737_3D_ENHANCE, 7, 1, 1, adc_tlv), SOC_SINGLE("Noise Gate Switch", WM8737_NOISE_GATE, 0, 1, 0), -- cgit v1.2.3 From 0faf1237c60a3791d7ff32035d3097d3e022e68f Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 13 Aug 2019 22:25:01 +0800 Subject: ASoC: soc-core: Fix -Wunused-const-variable warning If CONFIG_DMI is not set, gcc warns: sound/soc/soc-core.c:81:27: warning: dmi_blacklist defined but not used [-Wunused-const-variable=] Add #ifdef guard around it. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190813142501.13080-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e9f44505cc3e..abe2f47cee6e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -73,6 +73,7 @@ static int pmdown_time = 5000; module_param(pmdown_time, int, 0); MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); +#ifdef CONFIG_DMI /* * If a DMI filed contain strings in this blacklist (e.g. * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken @@ -87,6 +88,7 @@ static const char * const dmi_blacklist[] = { "Board Product Name", NULL, /* terminator */ }; +#endif static ssize_t pmdown_time_show(struct device *dev, struct device_attribute *attr, char *buf) -- cgit v1.2.3 From a9e792d006edbd33724f2eb858887d3b591d82c5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 13 Aug 2019 22:38:11 +0800 Subject: ASoC: mt2701: remove unused variables sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:799:38: warning: mt2701_afe_o23_mix defined but not used [-Wunused-const-variable=] sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:803:38: warning: mt2701_afe_o24_mix defined but not used [-Wunused-const-variable=] sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:835:38: warning: mt2701_afe_multi_ch_out_i2s4 defined but not used [-Wunused-const-variable=] They are never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190813143811.31456-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index 9af76ae315a5..d7f5defa50c2 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -796,14 +796,6 @@ static const struct snd_kcontrol_new mt2701_afe_o22_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN22, 19, 1, 0), }; -static const struct snd_kcontrol_new mt2701_afe_o23_mix[] = { - SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN23, 20, 1, 0), -}; - -static const struct snd_kcontrol_new mt2701_afe_o24_mix[] = { - SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN24, 21, 1, 0), -}; - static const struct snd_kcontrol_new mt2701_afe_o31_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I35 Switch", AFE_CONN41, 9, 1, 0), }; @@ -832,11 +824,6 @@ static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s3[] = { PWR2_TOP_CON, 18, 1, 0), }; -static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s4[] = { - SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S4 Out Switch", - PWR2_TOP_CON, 19, 1, 0), -}; - static const struct snd_soc_dapm_widget mt2701_afe_pcm_widgets[] = { /* inter-connections */ SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0), -- cgit v1.2.3 From 57c3ed42f52cdc51f416c93b19708ef6ceb4a00b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 13 Aug 2019 22:39:52 +0800 Subject: ASoC: mediatek: mt8183-da7219-max98357: remove unused variable sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c:120:1: warning: mt8183_da7219_max98357_dapm_widgets defined but not used [-Wunused-const-variable=] sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c:124:40: warning: mt8183_da7219_max98357_dapm_routes defined but not used [-Wunused-const-variable=] They are never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190813143952.29232-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index 2a6097174614..43f99e59a078 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -116,15 +116,6 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static const struct snd_soc_dapm_widget -mt8183_da7219_max98357_dapm_widgets[] = { - SND_SOC_DAPM_OUTPUT("IT6505_8CH"), -}; - -static const struct snd_soc_dapm_route mt8183_da7219_max98357_dapm_routes[] = { - {"IT6505_8CH", NULL, "TDM"}, -}; - /* FE */ SND_SOC_DAILINK_DEFS(playback1, DAILINK_COMP_ARRAY(COMP_CPU("DL1")), -- cgit v1.2.3 From d59170b42610c7cbc6e96431ca8357a8bdbf592b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 13 Aug 2019 22:41:22 +0800 Subject: ASoC: mediatek: mt8183-mt6358-ts3a227-max98357: remove unused variables sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c:50:1: warning: mt8183_mt6358_ts3a227_max98357_dapm_widgets defined but not used [-Wunused-const-variable=] sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c:55:1: warning: mt8183_mt6358_ts3a227_max98357_dapm_routes defined but not used [-Wunused-const-variable=] They are never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190813144122.67676-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 53f54078f78c..272766c1b859 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -46,16 +46,6 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static const struct snd_soc_dapm_widget -mt8183_mt6358_ts3a227_max98357_dapm_widgets[] = { - SND_SOC_DAPM_OUTPUT("IT6505_8CH"), -}; - -static const struct snd_soc_dapm_route -mt8183_mt6358_ts3a227_max98357_dapm_routes[] = { - {"IT6505_8CH", NULL, "TDM"}, -}; - static int mt8183_mt6358_ts3a227_max98357_bt_sco_startup( struct snd_pcm_substream *substream) -- cgit v1.2.3 From ccb1fa21ef58a2ac15519bb878470762e967e8b3 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Mon, 5 Aug 2019 12:56:37 +0800 Subject: ASoC: mediatek: mt6358: add delay after dmic clock on Most dmics produce a high level when they receive clock. The difference between power-on and memory record time is about 10ms, but the dmic needs 50ms to output normal data. This commit add 100ms delay after SoC output clock so that we can cut off the pop noise at the beginning. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1564980997-11359-1-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6358.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index c17250aab2d0..bb737fd678cc 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -1730,6 +1730,10 @@ static int mt6358_dmic_enable(struct mt6358_priv *priv) /* UL turn on */ regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, 0x0003); + + /* Prevent pop noise form dmic hw */ + msleep(100); + return 0; } -- cgit v1.2.3 From ff30779bd50eb823e2e75cfc7cc8a3373bfa3fd9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 21 Jun 2019 14:31:16 +0300 Subject: ASoC: Intel: Skylake: Print constant literals from format specifier Instead of using two additional "%s" specifiers, put the constant string literals directly to the format specifier. Cc: Liam Girdwood Cc: Mark Brown Cc: Vinod Koul Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190621113116.47525-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 8af7546def1f..61a8e4756a2b 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -413,8 +413,7 @@ static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid) int ret = 0; char mod_name[64]; /* guid str = 32 chars + 4 hyphens */ - snprintf(mod_name, sizeof(mod_name), "%s%pUL%s", - "intel/dsp_fw_", guid, ".bin"); + snprintf(mod_name, sizeof(mod_name), "intel/dsp_fw_%pUL.bin", guid); module_entry = skl_module_get_from_id(ctx, mod_id); if (module_entry == NULL) { -- cgit v1.2.3 From c25b456dc579298ac0ed7304f7d06a66288e96df Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 16:54:54 +0800 Subject: ASoC: cs42l73: remove unused variables 'vsp_output_mux' and 'xsp_output_mux' sound/soc/codecs/cs42l73.c:276:38: warning: vsp_output_mux defined but not used [-Wunused-const-variable=] sound/soc/codecs/cs42l73.c:279:38: warning: xsp_output_mux defined but not used [-Wunused-const-variable=] They are never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815085454.30384-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index a81739367109..36089f8bcf0a 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -273,12 +273,6 @@ static SOC_ENUM_SINGLE_DECL(xsp_output_mux_enum, CS42L73_MIXERCTL, 4, cs42l73_spo_mixer_text); -static const struct snd_kcontrol_new vsp_output_mux = - SOC_DAPM_ENUM("Route", vsp_output_mux_enum); - -static const struct snd_kcontrol_new xsp_output_mux = - SOC_DAPM_ENUM("Route", xsp_output_mux_enum); - static const struct snd_kcontrol_new hp_amp_ctl = SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 0, 1, 1); -- cgit v1.2.3 From bed7f1469f08fd123cdec7a351ef0d875feadcf6 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:01:57 +0800 Subject: ASoC: cs4349: Use PM ops 'cs4349_runtime_pm' sound/soc/codecs/cs4349.c:358:32: warning: cs4349_runtime_pm defined but not used [-Wunused-const-variable=] cs4349_runtime_pm ops already defined, it seems we should enable it. Reported-by: Hulk Robot Fixes: e40da86 ("ASoC: cs4349: Add support for Cirrus Logic CS4349") Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815090157.70036-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 09716fab1e26..3381209a882d 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -378,6 +378,7 @@ static struct i2c_driver cs4349_i2c_driver = { .driver = { .name = "cs4349", .of_match_table = cs4349_of_match, + .pm = &cs4349_runtime_pm, }, .id_table = cs4349_i2c_id, .probe = cs4349_i2c_probe, -- cgit v1.2.3 From 9d22142c9b1ec8612b880121dd0bc27311cbb2b5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:04:04 +0800 Subject: ASoC: max98371: remove unused variable 'max98371_noload_gain_tlv' sound/soc/codecs/max98371.c:157:35: warning: max98371_noload_gain_tlv defined but not used [-Wunused-const-variable=] It is never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815090404.72752-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98371.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c index ce801489a86d..dfee05f985bd 100644 --- a/sound/soc/codecs/max98371.c +++ b/sound/soc/codecs/max98371.c @@ -154,10 +154,6 @@ static const DECLARE_TLV_DB_RANGE(max98371_gain_tlv, 8, 10, TLV_DB_SCALE_ITEM(400, 100, 0) ); -static const DECLARE_TLV_DB_RANGE(max98371_noload_gain_tlv, - 0, 11, TLV_DB_SCALE_ITEM(950, 100, 0), -); - static const DECLARE_TLV_DB_SCALE(digital_tlv, -6300, 50, 1); static const struct snd_kcontrol_new max98371_snd_controls[] = { -- cgit v1.2.3 From 5b366753c1c12feead0ae53b45482f569ed5399c Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:06:02 +0800 Subject: ASoC: rt1011: remove unused variable 'dac_vol_tlv' and 'adc_vol_tlv' sound/soc/codecs/rt1011.c:981:35: warning: dac_vol_tlv defined but not used [-Wunused-const-variable=] sound/soc/codecs/rt1011.c:982:35: warning: adc_vol_tlv defined but not used [-Wunused-const-variable=] They are never used, so can be removed. Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815090602.9000-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index 638abcaf52b3..fa34565a3938 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -978,9 +978,6 @@ static bool rt1011_readable_register(struct device *dev, unsigned int reg) } } -static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9435, 37, 0); -static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1739, 37, 0); - static const char * const rt1011_din_source_select[] = { "Left", "Right", -- cgit v1.2.3 From ab0ac2707784a966927c229752849c343bd1dbbf Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:15:34 +0800 Subject: ASoC: tlv320aic23: remove unused variable 'tlv320aic23_rec_src' sound/soc/codecs/tlv320aic23.c:70:29: warning: tlv320aic23_rec_src defined but not used [-Wunused-const-variable=] It is never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815091534.57780-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic23.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 080a840c987a..f8e2f4b74db3 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -67,8 +67,6 @@ static SOC_ENUM_SINGLE_DECL(rec_src_enum, static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls = SOC_DAPM_ENUM("Input Select", rec_src_enum); -static SOC_ENUM_SINGLE_DECL(tlv320aic23_rec_src, - TLV320AIC23_ANLG, 2, rec_src_text); static SOC_ENUM_SINGLE_DECL(tlv320aic23_deemph, TLV320AIC23_DIGT, 1, deemph_text); -- cgit v1.2.3 From 6d6376b143d59ab1b8635807c78d224d03580418 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:17:38 +0800 Subject: ASoC: tlv320aic31xx: remove unused variable 'cm_m_enum' sound/soc/codecs/tlv320aic31xx.c:261:29: warning: cm_m_enum defined but not used [-Wunused-const-variable=] It is never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815091738.21680-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 26a4f6cd3288..df627a08def9 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -258,7 +258,6 @@ static SOC_ENUM_SINGLE_DECL(mic1rp_p_enum, AIC31XX_MICPGAPI, 4, static SOC_ENUM_SINGLE_DECL(mic1lm_p_enum, AIC31XX_MICPGAPI, 2, mic_select_text); -static SOC_ENUM_SINGLE_DECL(cm_m_enum, AIC31XX_MICPGAMI, 6, mic_select_text); static SOC_ENUM_SINGLE_DECL(mic1lm_m_enum, AIC31XX_MICPGAMI, 4, mic_select_text); -- cgit v1.2.3 From 97d39be9ce5befc2e36f15d0df33832e0f633565 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:20:56 +0800 Subject: ASoC: es8328: remove unused variable 'pga_tlv' sound/soc/codecs/es8328.c:102:35: warning: pga_tlv defined but not used [-Wunused-const-variable=] They are never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815092056.28724-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 822a25a8f53c..4a3d303fedfb 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -99,7 +99,6 @@ static SOC_ENUM_SINGLE_DECL(adcpol, static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0); static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0); -static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0); -- cgit v1.2.3 From d63887bc4f50fede7013bda7c733d58ecc43efc1 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:23:00 +0800 Subject: ASoC: es8328: Fix copy-paste error in es8328_right_line_controls It seems 'es8328_rline_enum' should be used in es8328_right_line_controls Fixes: 567e4f98922c ("ASoC: add es8328 codec driver") Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815092300.68712-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 4a3d303fedfb..fdf64c29f563 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -227,7 +227,7 @@ static const struct soc_enum es8328_rline_enum = ARRAY_SIZE(es8328_line_texts), es8328_line_texts); static const struct snd_kcontrol_new es8328_right_line_controls = - SOC_DAPM_ENUM("Route", es8328_lline_enum); + SOC_DAPM_ENUM("Route", es8328_rline_enum); /* Left Mixer */ static const struct snd_kcontrol_new es8328_left_mixer_controls[] = { -- cgit v1.2.3 From e33d565795930d0341bb946aec457a814ccd53e6 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:24:36 +0800 Subject: ASoC: cs42l56: remove unused variable 'adc_swap_enum' sound/soc/codecs/cs42l56.c:206:30: warning: adc_swap_enum defined but not used [-Wunused-const-variable=] It is never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815092436.34632-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l56.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index b4d7627525f9..ac569ab3d30f 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -199,14 +199,6 @@ static const struct soc_enum beep_bass_enum = SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1, ARRAY_SIZE(beep_bass_text), beep_bass_text); -static const char * const adc_swap_text[] = { - "None", "A+B/2", "A-B/2", "Swap" -}; - -static const struct soc_enum adc_swap_enum = - SOC_ENUM_SINGLE(CS42L56_MISC_ADC_CTL, 3, - ARRAY_SIZE(adc_swap_text), adc_swap_text); - static const char * const pgaa_mux_text[] = { "AIN1A", "AIN2A", "AIN3A"}; -- cgit v1.2.3 From 12f0bfadf69bb154052722e7e4e5cd1639044c76 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:25:47 +0800 Subject: ASoC: 88pm860x: remove unused variables 'pcm_switch_controls' and 'aif1_mux' sound/soc/codecs/88pm860x-codec.c:533:38: warning: pcm_switch_controls defined but not used [-Wunused-const-variable=] sound/soc/codecs/88pm860x-codec.c:560:38: warning: aif1_mux defined but not used [-Wunused-const-variable=] They are never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815092547.29564-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/88pm860x-codec.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index e982722b448e..00b2c43d28a1 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -529,10 +529,6 @@ static const struct snd_kcontrol_new pm860x_snd_controls[] = { * DAPM Controls */ -/* PCM Switch / PCM Interface */ -static const struct snd_kcontrol_new pcm_switch_controls = - SOC_DAPM_SINGLE("Switch", PM860X_ADC_EN_2, 0, 1, 0); - /* AUX1 Switch */ static const struct snd_kcontrol_new aux1_switch_controls = SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 4, 1, 0); @@ -549,17 +545,6 @@ static const struct snd_kcontrol_new lepa_switch_controls = static const struct snd_kcontrol_new repa_switch_controls = SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 1, 1, 0); -/* PCM Mux / Mux7 */ -static const char *aif1_text[] = { - "PCM L", "PCM R", -}; - -static SOC_ENUM_SINGLE_DECL(aif1_enum, - PM860X_PCM_IFACE_3, 6, aif1_text); - -static const struct snd_kcontrol_new aif1_mux = - SOC_DAPM_ENUM("PCM Mux", aif1_enum); - /* I2S Mux / Mux9 */ static const char *i2s_din_text[] = { "DIN", "DIN1", -- cgit v1.2.3 From 72b745e3ad65deac94ea4eb83262c52ba3ffdb5b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 13 Aug 2019 13:45:32 +0300 Subject: ASoC: core: Move pcm_mutex up to card level from snd_soc_pcm_runtime The pcm_mutex is used to prevent concurrent execution of snd_pcm_ops callbacks. This works fine most of the cases but it can not handle setups when the same DAI is used by different rtd, for example: pcm3168a have two DAIs: one for Playback and one for Capture. If the codec is connected to a single CPU DAI we need to have two dai_link to support both playback and capture. In this case the snd_pcm_ops callbacks can be executed in parallel causing unexpected races in DAI drivers. By moving the pcm_mutex up to card level this can be solved while - hopefully - not breaking other setups. Signed-off-by: Peter Ujfalusi Tested-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190813104532.16669-1-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- include/sound/soc.h | 6 ++++-- sound/soc/soc-compress.c | 48 ++++++++++++++++++++++++------------------------ sound/soc/soc-core.c | 2 +- sound/soc/soc-pcm.c | 36 ++++++++++++++++++------------------ 4 files changed, 47 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index b1fe5ebea257..5c841c2ee814 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -988,6 +988,10 @@ struct snd_soc_card { struct mutex mutex; struct mutex dapm_mutex; + /* Mutex for PCM operations */ + struct mutex pcm_mutex; + enum snd_soc_pcm_subclass pcm_subclass; + spinlock_t dpcm_lock; bool instantiated; @@ -1116,8 +1120,6 @@ struct snd_soc_pcm_runtime { struct device *dev; struct snd_soc_card *card; struct snd_soc_dai_link *dai_link; - struct mutex pcm_mutex; - enum snd_soc_pcm_subclass pcm_subclass; struct snd_pcm_ops ops; unsigned int params_select; /* currently selected param for dai link */ diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 289211069a1e..9e54d8ae6d2c 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -80,7 +80,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) { ret = cpu_dai->driver->cops->startup(cstream, cpu_dai); @@ -108,7 +108,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) snd_soc_runtime_activate(rtd, cstream->direction); - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return 0; @@ -118,7 +118,7 @@ machine_err: if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) cpu_dai->driver->cops->shutdown(cstream, cpu_dai); out: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -224,7 +224,7 @@ static void close_delayed_work(struct work_struct *work) container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); struct snd_soc_dai *codec_dai = rtd->codec_dai; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); dev_dbg(rtd->dev, "Compress ASoC: pop wq checking: %s status: %s waiting: %s\n", @@ -239,7 +239,7 @@ static void close_delayed_work(struct work_struct *work) SND_SOC_DAPM_STREAM_STOP); } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); } static int soc_compr_free(struct snd_compr_stream *cstream) @@ -249,7 +249,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) struct snd_soc_dai *codec_dai = rtd->codec_dai; int stream; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -292,7 +292,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) SND_SOC_DAPM_STREAM_STOP); } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return 0; } @@ -375,7 +375,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); ret = soc_compr_components_trigger(cstream, cmd); if (ret < 0) @@ -394,7 +394,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) } out: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -480,7 +480,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); /* * First we call set_params for the CPU DAI, then the component @@ -514,14 +514,14 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, /* cancel any delayed stream shutdown that is pending */ rtd->pop_wait = 0; - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); cancel_delayed_work_sync(&rtd->delayed_work); return 0; err: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -593,7 +593,7 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) { ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai); @@ -613,7 +613,7 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, } err: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -625,7 +625,7 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, struct snd_soc_rtdcom_list *rtdcom; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -638,7 +638,7 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, break; } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -650,7 +650,7 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, struct snd_soc_rtdcom_list *rtdcom; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -664,7 +664,7 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, break; } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -676,7 +676,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) { ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai); @@ -697,7 +697,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) } err: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -710,7 +710,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, int ret = 0; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer) cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai); @@ -726,7 +726,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, break; } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -738,7 +738,7 @@ static int soc_compr_copy(struct snd_compr_stream *cstream, struct snd_soc_rtdcom_list *rtdcom; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -751,7 +751,7 @@ static int soc_compr_copy(struct snd_compr_stream *cstream, break; } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index abe2f47cee6e..b3f820fb53e6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1360,7 +1360,6 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, rtd->dev->groups = soc_dev_attr_groups; dev_set_name(rtd->dev, "%s", name); dev_set_drvdata(rtd->dev, rtd); - mutex_init(&rtd->pcm_mutex); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients); @@ -2383,6 +2382,7 @@ int snd_soc_register_card(struct snd_soc_card *card) card->instantiated = 0; mutex_init(&card->mutex); mutex_init(&card->dapm_mutex); + mutex_init(&card->pcm_mutex); spin_lock_init(&card->dpcm_lock); return snd_soc_bind_card(card); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index da657c8179cc..e163dde5eab1 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -36,7 +36,7 @@ * Increments the active count for all the DAIs and components attached to a PCM * runtime. Should typically be called when a stream is opened. * - * Must be called with the rtd->pcm_mutex being held + * Must be called with the rtd->card->pcm_mutex being held */ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) { @@ -44,7 +44,7 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) struct snd_soc_dai *codec_dai; int i; - lockdep_assert_held(&rtd->pcm_mutex); + lockdep_assert_held(&rtd->card->pcm_mutex); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active++; @@ -72,7 +72,7 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) * Decrements the active count for all the DAIs and components attached to a PCM * runtime. Should typically be called when a stream is closed. * - * Must be called with the rtd->pcm_mutex being held + * Must be called with the rtd->card->pcm_mutex being held */ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) { @@ -80,7 +80,7 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) struct snd_soc_dai *codec_dai; int i; - lockdep_assert_held(&rtd->pcm_mutex); + lockdep_assert_held(&rtd->card->pcm_mutex); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active--; @@ -506,7 +506,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) pm_runtime_get_sync(component->dev); } - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); /* startup the audio subsystem */ ret = snd_soc_dai_startup(cpu_dai, substream); @@ -604,7 +604,7 @@ dynamic: snd_soc_runtime_activate(rtd, substream->stream); - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return 0; config_err: @@ -623,7 +623,7 @@ component_err: snd_soc_dai_shutdown(cpu_dai, substream); out: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -653,7 +653,7 @@ static void close_delayed_work(struct work_struct *work) container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); struct snd_soc_dai *codec_dai = rtd->codec_dais[0]; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n", codec_dai->driver->playback.stream_name, @@ -667,7 +667,7 @@ static void close_delayed_work(struct work_struct *work) SND_SOC_DAPM_STREAM_STOP); } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); } static void codec2codec_close_delayed_work(struct work_struct *work) @@ -694,7 +694,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai; int i; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); snd_soc_runtime_deactivate(rtd, substream->stream); @@ -738,7 +738,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) SND_SOC_DAPM_STREAM_STOP); } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -771,7 +771,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai; int i, ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (rtd->dai_link->ops->prepare) { ret = rtd->dai_link->ops->prepare(substream); @@ -826,7 +826,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream); out: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -876,7 +876,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai; int i, ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (rtd->dai_link->ops->hw_params) { ret = rtd->dai_link->ops->hw_params(substream, params); if (ret < 0) { @@ -962,7 +962,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (ret) goto component_err; out: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; component_err: @@ -986,7 +986,7 @@ codec_err: if (rtd->dai_link->ops->hw_free) rtd->dai_link->ops->hw_free(substream); - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -1001,7 +1001,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int i; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); /* clear the corresponding DAIs parameters when going to be inactive */ if (cpu_dai->active == 1) { @@ -1043,7 +1043,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) snd_soc_dai_hw_free(cpu_dai, substream); - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return 0; } -- cgit v1.2.3 From c643c189f0fec116e75f9661e734545af0e3225e Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Thu, 15 Aug 2019 14:51:49 +0800 Subject: ASoC: Intel: boards: Add Cometlake machine driver support reuse and add Cometlake support with: SSP0 for DA7219 headphone codec SSP1 for MAX98357a speaker amp codec Signed-off-by: Mac Chiang Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/1565851909-13825-1-git-send-email-mac.chiang@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 27 ++++++++++++++------ sound/soc/intel/boards/bxt_da7219_max98357a.c | 31 ++++++++++++++++++++++- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 12 +++++++++ sound/soc/intel/common/soc-intel-quirks.h | 5 ++++ 4 files changed, 66 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 4a529cea0190..5c27f7ab4a5f 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -256,16 +256,20 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH endif ## SND_SOC_INTEL_SKL +config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC + tristate + select SND_SOC_DA7219 + select SND_SOC_MAX98357A + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + if SND_SOC_INTEL_APL config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "Broxton with DA7219 and MAX98357A in I2S Mode" depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_DA7219 - select SND_SOC_MAX98357A - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC select SND_HDA_DSP_LOADER help This adds support for ASoC machine driver for Broxton-P platforms @@ -326,10 +330,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH tristate "KBL with DA7219 and MAX98357A in I2S Mode" depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_DA7219 - select SND_SOC_MAX98357A - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC help This adds support for ASoC Onboard Codec I2S machine driver. This will create an alsa sound card for DA7219 + MAX98357A I2S audio codec. @@ -413,4 +414,14 @@ config SND_SOC_INTEL_SOF_RT5682_MACH If unsure select "N". endif ## SND_SOC_SOF_HDA_COMMON || SND_SOC_SOF_BAYTRAIL +if (SND_SOC_SOF_COMETLAKE_LP && SND_SOC_SOF_HDA_LINK) + +config SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH + tristate "CML_LP with DA7219 and MAX98357A in I2S Mode" + depends on I2C && ACPI + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC + +endif ## SND_SOC_SOF_COMETLAKE_LP && SND_SOC_SOF_HDA_LINK + endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index c0d865a940dc..ac1dea5f9d11 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -179,10 +179,17 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) int ret; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_component *component = rtd->codec_dai->component; + int clk_freq; /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 19200000, + if (soc_intel_is_cml()) + clk_freq = 24000000; + else + clk_freq = 19200000; + + ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, SND_SOC_CLOCK_IN); + if (ret) { dev_err(rtd->dev, "can't set codec sysclk configuration\n"); return ret; @@ -683,6 +690,25 @@ static int broxton_audio_probe(struct platform_device *pdev) broxton_dais[i].cpus->dai_name = "SSP2 Pin"; } } + } else if (soc_intel_is_cml()) { + unsigned int i; + + broxton_audio_card.name = "cmlda7219max"; + + for (i = 0; i < ARRAY_SIZE(broxton_dais); i++) { + /* MAXIM_CODEC is connected to SSP1. */ + if (!strcmp(broxton_dais[i].codecs->dai_name, + BXT_MAXIM_CODEC_DAI)) { + broxton_dais[i].name = "SSP1-Codec"; + broxton_dais[i].cpus->dai_name = "SSP1 Pin"; + } + /* DIALOG_CODEC is connected to SSP0 */ + else if (!strcmp(broxton_dais[i].codecs->dai_name, + BXT_DIALOG_CODEC_DAI)) { + broxton_dais[i].name = "SSP0-Codec"; + broxton_dais[i].cpus->dai_name = "SSP0 Pin"; + } + } } /* override plaform name, if required */ @@ -700,6 +726,7 @@ static int broxton_audio_probe(struct platform_device *pdev) static const struct platform_device_id bxt_board_ids[] = { { .name = "bxt_da7219_max98357a" }, { .name = "glk_da7219_max98357a" }, + { .name = "cml_da7219_max98357a" }, { } }; @@ -720,6 +747,8 @@ MODULE_AUTHOR("Rohit Ainapure "); MODULE_AUTHOR("Harsha Priya "); MODULE_AUTHOR("Conrad Cooke "); MODULE_AUTHOR("Naveen Manohar "); +MODULE_AUTHOR("Mac Chiang "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:bxt_da7219_max98357a"); MODULE_ALIAS("platform:glk_da7219_max98357a"); +MODULE_ALIAS("platform:cml_da7219_max98357a"); diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 771b0ef21051..985aa366c9e8 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -19,6 +19,11 @@ static struct snd_soc_acpi_codecs cml_codecs = { .codecs = {"10EC5682"} }; +static struct snd_soc_acpi_codecs cml_spk_codecs = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { { .id = "INT34C2", @@ -28,6 +33,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cnl-rt274.tplg", }, + { + .id = "DLGS7219", + .drv_name = "cml_da7219_max98357a", + .quirk_data = &cml_spk_codecs, + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", + }, { .id = "MX98357A", .drv_name = "sof_rt5682", diff --git a/sound/soc/intel/common/soc-intel-quirks.h b/sound/soc/intel/common/soc-intel-quirks.h index 4718fd3cf636..e6357d306cb8 100644 --- a/sound/soc/intel/common/soc-intel-quirks.h +++ b/sound/soc/intel/common/soc-intel-quirks.h @@ -36,6 +36,7 @@ SOC_INTEL_IS_CPU(byt, INTEL_FAM6_ATOM_SILVERMONT); SOC_INTEL_IS_CPU(cht, INTEL_FAM6_ATOM_AIRMONT); SOC_INTEL_IS_CPU(apl, INTEL_FAM6_ATOM_GOLDMONT); SOC_INTEL_IS_CPU(glk, INTEL_FAM6_ATOM_GOLDMONT_PLUS); +SOC_INTEL_IS_CPU(cml, INTEL_FAM6_KABYLAKE_MOBILE); static inline bool soc_intel_is_byt_cr(struct platform_device *pdev) { @@ -110,6 +111,10 @@ static inline bool soc_intel_is_glk(void) return false; } +static inline bool soc_intel_is_cml(void) +{ + return false; +} #endif #endif /* _SND_SOC_INTEL_QUIRKS_H */ -- cgit v1.2.3 From 5f7af9ecebce7fab78b0237b0cd998f2ed3de03c Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Thu, 15 Aug 2019 10:57:46 -0500 Subject: ASoC: Intel: common: add ACPI matching tables for Tiger Lake Initial support for TGL w/ RT1308 Signed-off-by: Pan Xiuli Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190815155749.29304-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-acpi-intel-match.h | 1 + sound/soc/intel/common/Makefile | 1 + sound/soc/intel/common/soc-acpi-intel-tgl-match.c | 24 +++++++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 sound/soc/intel/common/soc-acpi-intel-tgl-match.c (limited to 'sound') diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index bb5e1e4ce8bf..ce6c4a970939 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -25,6 +25,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 56c81e20b5bf..a14aca62ff96 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -8,6 +8,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ + soc-acpi-intel-tgl-match.o \ soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c new file mode 100644 index 000000000000..57a6298d6dca --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-tgl-match.c - tables and support for ICL ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { + { + .id = "10EC1308", + .drv_name = "tgl_rt1308", + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-rt1308.tplg", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); -- cgit v1.2.3 From 1205c81edd5ef220ca32318572e499b4b180b1f3 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Thu, 15 Aug 2019 10:57:47 -0500 Subject: ASoC: SOF: Intel: initial support for Tiger Lake. Add Kconfig, PCI ID and chip info for Tiger Lake platform. Note that the core mask is different from previous platforms, only Core0 can be controlled by the host. Additional patches will be required for multi-core functionality. Signed-off-by: Pan Xiuli Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190815155749.29304-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 16 ++++++++++++++++ sound/soc/sof/intel/cnl.c | 16 ++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/sof-pci-dev.c | 22 ++++++++++++++++++++++ 4 files changed, 55 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 545071afbe18..0dc5da661b61 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -27,6 +27,7 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT select SND_SOC_SOF_COMETLAKE_LP if SND_SOC_SOF_COMETLAKE_LP_SUPPORT select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT + select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -212,6 +213,21 @@ config SND_SOC_SOF_COMETLAKE_H_SUPPORT Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_TIGERLAKE_SUPPORT + bool "SOF support for Tigerlake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Tigerlake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_TIGERLAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 6d7d9c93252c..5de281fcc122 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -295,3 +295,19 @@ const struct sof_intel_dsp_desc icl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL(icl_chip_info); + +const struct sof_intel_dsp_desc tgl_chip_info = { + /* Tigerlake */ + .cores_num = 4, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL(tgl_chip_info); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 6db3dcbab3bd..cbb431f7835d 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -599,5 +599,6 @@ extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc icl_chip_info; +extern const struct sof_intel_dsp_desc tgl_chip_info; #endif diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 6fd3df7c57a3..9f92504ad5b4 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -203,6 +203,24 @@ static const struct sof_dev_desc kbl_desc = { }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) +static const struct sof_dev_desc tgl_desc = { + .machines = snd_soc_acpi_intel_tgl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &tgl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-tgl.ri", + .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -384,6 +402,10 @@ static const struct pci_device_id sof_pci_ids[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) { PCI_DEVICE(0x8086, 0x06c8), .driver_data = (unsigned long)&cml_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) + { PCI_DEVICE(0x8086, 0xa0c8), + .driver_data = (unsigned long)&tgl_desc}, #endif { 0, } }; -- cgit v1.2.3 From f4ead53241c7dcd2f3130e059cb3dfdec0ec9871 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Thu, 15 Aug 2019 10:57:48 -0500 Subject: ASoC: Intel: common: add ACPI matching tables for EHL There are no upstream machine drivers just yet so just add dummy table for compilation in nocodec-mode. Signed-off-by: Pan Xiuli Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190815155749.29304-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-acpi-intel-match.h | 1 + sound/soc/intel/common/Makefile | 2 +- sound/soc/intel/common/soc-acpi-intel-ehl-match.c | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-ehl-match.c (limited to 'sound') diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index ce6c4a970939..6c9929abd90b 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -26,6 +26,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index a14aca62ff96..18d9630ae9a2 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -8,7 +8,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ - soc-acpi-intel-tgl-match.o \ + soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o diff --git a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c new file mode 100644 index 000000000000..a1290c3fa99f --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-ehl-match.c - tables and support for EHL ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ehl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); -- cgit v1.2.3 From 6173269038e98408c27cfb438ff07d463fbd0b33 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Thu, 15 Aug 2019 10:57:49 -0500 Subject: ASoC: SOF: Intel: initial support for Elkhart Lake Add Kconfig, PCI ID and chip info for EHL platform. Note that the core mask is different from previous platforms, only Core0 can be controlled by the host. Additional patches will be required for multi-core functionality. Signed-off-by: Pan Xiuli Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190815155749.29304-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 16 ++++++++++++++++ sound/soc/sof/intel/cnl.c | 16 ++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/sof-pci-dev.c | 22 ++++++++++++++++++++++ 4 files changed, 55 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 0dc5da661b61..889b6202d054 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -28,6 +28,7 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_COMETLAKE_LP if SND_SOC_SOF_COMETLAKE_LP_SUPPORT select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT + select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -228,6 +229,21 @@ config SND_SOC_SOF_TIGERLAKE This option is not user-selectable but automagically handled by 'select' statements at a higher level +config SND_SOC_SOF_ELKHARTLAKE_SUPPORT + bool "SOF support for ElkhartLake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the ElkhartLake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_ELKHARTLAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 5de281fcc122..4ddd73762d81 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -311,3 +311,19 @@ const struct sof_intel_dsp_desc tgl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL(tgl_chip_info); + +const struct sof_intel_dsp_desc ehl_chip_info = { + /* Elkhartlake */ + .cores_num = 4, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL(ehl_chip_info); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index cbb431f7835d..5591841a1b6f 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -600,5 +600,6 @@ extern const struct sof_intel_dsp_desc cnl_chip_info; extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc icl_chip_info; extern const struct sof_intel_dsp_desc tgl_chip_info; +extern const struct sof_intel_dsp_desc ehl_chip_info; #endif diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 9f92504ad5b4..d66412a77873 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -221,6 +221,24 @@ static const struct sof_dev_desc tgl_desc = { }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) +static const struct sof_dev_desc ehl_desc = { + .machines = snd_soc_acpi_intel_ehl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &ehl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-ehl.ri", + .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -406,6 +424,10 @@ static const struct pci_device_id sof_pci_ids[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) { PCI_DEVICE(0x8086, 0xa0c8), .driver_data = (unsigned long)&tgl_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) + { PCI_DEVICE(0x8086, 0x4b55), + .driver_data = (unsigned long)&ehl_desc}, #endif { 0, } }; -- cgit v1.2.3 From 246bb4aaa4f4314816ae6835f3c6cc6dc7a10f4f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 15 Aug 2019 21:42:51 +0200 Subject: Revert "ALSA: hda: Add codec on bus address table lately" This reverts commit ee5f85d9290f ("ALSA: hda: Add codec on bus address table lately"). The commit caused several regression since I've overlooked that the function doesn't manage only the caddr_tbl but also the codec linked list that is referred indirectly in the other drivers. Revert for now to make everything back to work. Fixes: ee5f85d9290f ("ALSA: hda: Add codec on bus address table lately") Reported-by: Chris Wilson Signed-off-by: Takashi Iwai --- sound/hda/hdac_device.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index bf83d7062ef6..9f3e37511408 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -61,6 +61,10 @@ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus, pm_runtime_get_noresume(&codec->dev); atomic_set(&codec->in_pm, 0); + err = snd_hdac_bus_add_device(bus, codec); + if (err < 0) + goto error; + /* fill parameters */ codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, AC_PAR_VENDOR_ID); @@ -139,22 +143,15 @@ int snd_hdac_device_register(struct hdac_device *codec) err = device_add(&codec->dev); if (err < 0) return err; - err = snd_hdac_bus_add_device(codec->bus, codec); - if (err < 0) - goto error; mutex_lock(&codec->widget_lock); err = hda_widget_sysfs_init(codec); mutex_unlock(&codec->widget_lock); - if (err < 0) - goto error_remove; + if (err < 0) { + device_del(&codec->dev); + return err; + } return 0; - - error_remove: - snd_hdac_bus_remove_device(codec->bus, codec); - error: - device_del(&codec->dev); - return err; } EXPORT_SYMBOL_GPL(snd_hdac_device_register); @@ -168,8 +165,8 @@ void snd_hdac_device_unregister(struct hdac_device *codec) mutex_lock(&codec->widget_lock); hda_widget_sysfs_exit(codec); mutex_unlock(&codec->widget_lock); - snd_hdac_bus_remove_device(codec->bus, codec); device_del(&codec->dev); + snd_hdac_bus_remove_device(codec->bus, codec); } } EXPORT_SYMBOL_GPL(snd_hdac_device_unregister); -- cgit v1.2.3 From 0fc1e447e9e474c2460df8d0378f899b8813e1d2 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Fri, 16 Aug 2019 14:27:39 +0800 Subject: ALSA: hda - Expand pin_match function to match upcoming new tbls With the existing pintbl, we already have many entries in it. it is better to figure out a new way to reduce the size of the pintbl. We plan to define a new tbl which will match more machines with a single tbl, To do that, this function doesn't need to match all valid pins between machine and tbl, it just needs to match all pins defined in the tbl with the machine. And the plan is to move some tbls from pin_fixup_tbl to fallback_pin_fixup_tbl gradually. Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_auto_parser.c | 12 ++++++++---- sound/pci/hda/hda_local.h | 3 ++- sound/pci/hda/patch_realtek.c | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 92390d457567..8a134f750bae 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -884,7 +884,8 @@ EXPORT_SYMBOL_GPL(snd_hda_apply_fixup); #define IGNORE_SEQ_ASSOC (~(AC_DEFCFG_SEQUENCE | AC_DEFCFG_DEF_ASSOC)) static bool pin_config_match(struct hda_codec *codec, - const struct hda_pintbl *pins) + const struct hda_pintbl *pins, + bool match_all_pins) { const struct hda_pincfg *pin; int i; @@ -908,7 +909,8 @@ static bool pin_config_match(struct hda_codec *codec, return false; } } - if (!found && (cfg & 0xf0000000) != 0x40000000) + if (match_all_pins && + !found && (cfg & 0xf0000000) != 0x40000000) return false; } @@ -920,10 +922,12 @@ static bool pin_config_match(struct hda_codec *codec, * @codec: the HDA codec * @pin_quirk: zero-terminated pin quirk list * @fixlist: the fixup list + * @match_all_pins: all valid pins must match with the table entries */ void snd_hda_pick_pin_fixup(struct hda_codec *codec, const struct snd_hda_pin_quirk *pin_quirk, - const struct hda_fixup *fixlist) + const struct hda_fixup *fixlist, + bool match_all_pins) { const struct snd_hda_pin_quirk *pq; @@ -935,7 +939,7 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, continue; if (codec->core.vendor_id != pq->codec) continue; - if (pin_config_match(codec, pq->pins)) { + if (pin_config_match(codec, pq->pins, match_all_pins)) { codec->fixup_id = pq->value; #ifdef CONFIG_SND_DEBUG_VERBOSE codec->fixup_name = pq->name; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 349a8312d06a..3942e1b528d8 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -361,7 +361,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_fixup *fixlist); void snd_hda_pick_pin_fixup(struct hda_codec *codec, const struct snd_hda_pin_quirk *pin_quirk, - const struct hda_fixup *fixlist); + const struct hda_fixup *fixlist, + bool match_all_pins); /* helper macros to retrieve pin default-config values */ #define get_defcfg_connect(cfg) \ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index cb7baa65b298..9562045c49c6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7958,7 +7958,7 @@ static int patch_alc269(struct hda_codec *codec) snd_hda_pick_fixup(codec, alc269_fixup_models, alc269_fixup_tbl, alc269_fixups); - snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups); + snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups, true); snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl, alc269_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -8943,7 +8943,7 @@ static int patch_alc662(struct hda_codec *codec) snd_hda_pick_fixup(codec, alc662_fixup_models, alc662_fixup_tbl, alc662_fixups); - snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups); + snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups, true); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); -- cgit v1.2.3 From 7c0a69394c265f2bb674c3f5daadfdd5c15ea0d1 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Fri, 16 Aug 2019 14:27:40 +0800 Subject: ALSA: hda - Define a fallback_pin_fixup_tbl for alc269 family We have another Dell laptop which needs the DELL4_MIC_NO_PRESENCE, and this laptop has different pincfg definitions from existing ones in the pintbl, rather adding a new entry, let us define a tbl in the fallback_pin_fixup_tbl and this tbl will match all dell machines with alc289 codec and the pins of 0x19 and 0x1b are undef by default. Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9562045c49c6..b6ae452a1d8f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7656,10 +7656,6 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60120}, {0x14, 0x90170110}, {0x21, 0x0321101f}), - SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, - {0x12, 0xb7a60130}, - {0x14, 0x90170110}, - {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC290_STANDARD_PINS, {0x15, 0x04211040}, @@ -7769,6 +7765,19 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {} }; +/* This is the fallback pin_fixup_tbl for alc269 family, to make the tbl match + * more machines, don't need to match all valid pins, just need to match + * all the pins defined in the tbl. Just because of this reason, it is possible + * that a single machine matches multiple tbls, so there is one limitation: + * at most one tbl is allowed to define for the same vendor and same codec + */ +static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = { + SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, + {0x19, 0x40000000}, + {0x1b, 0x40000000}), + {} +}; + static void alc269_fill_coef(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -7959,6 +7968,7 @@ static int patch_alc269(struct hda_codec *codec) snd_hda_pick_fixup(codec, alc269_fixup_models, alc269_fixup_tbl, alc269_fixups); snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups, true); + snd_hda_pick_pin_fixup(codec, alc269_fallback_pin_fixup_tbl, alc269_fixups, false); snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl, alc269_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); -- cgit v1.2.3 From 8661ab5b23d6d30d8687fc05bc1dba8f9a64b444 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 16 Aug 2019 01:03:14 -0400 Subject: ASoC: imx-audmux: Add driver suspend and resume to support MEGA Fast For i.MX6 SoloX, there is a mode of the SoC to shutdown all power source of modules during system suspend and resume procedure. Thus, AUDMUX needs to save all the values of registers before the system suspend and restore them after the system resume. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1565931794-7218-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-audmux.c | 54 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index b2351cd33b0f..16ede3b5cb32 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -23,6 +23,8 @@ static struct clk *audmux_clk; static void __iomem *audmux_base; +static u32 *regcache; +static u32 reg_max; #define IMX_AUDMUX_V2_PTCR(x) ((x) * 8) #define IMX_AUDMUX_V2_PDCR(x) ((x) * 8 + 4) @@ -317,8 +319,23 @@ static int imx_audmux_probe(struct platform_device *pdev) if (of_id) pdev->id_entry = of_id->data; audmux_type = pdev->id_entry->driver_data; - if (audmux_type == IMX31_AUDMUX) + + switch (audmux_type) { + case IMX31_AUDMUX: audmux_debugfs_init(); + reg_max = 14; + break; + case IMX21_AUDMUX: + reg_max = 6; + break; + default: + dev_err(&pdev->dev, "unsupported version!\n"); + return -EINVAL; + } + + regcache = devm_kzalloc(&pdev->dev, sizeof(u32) * reg_max, GFP_KERNEL); + if (!regcache) + return -ENOMEM; if (of_id) imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node); @@ -334,12 +351,47 @@ static int imx_audmux_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int imx_audmux_suspend(struct device *dev) +{ + int i; + + clk_prepare_enable(audmux_clk); + + for (i = 0; i < reg_max; i++) + regcache[i] = readl(audmux_base + i * 4); + + clk_disable_unprepare(audmux_clk); + + return 0; +} + +static int imx_audmux_resume(struct device *dev) +{ + int i; + + clk_prepare_enable(audmux_clk); + + for (i = 0; i < reg_max; i++) + writel(regcache[i], audmux_base + i * 4); + + clk_disable_unprepare(audmux_clk); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops imx_audmux_pm = { + SET_SYSTEM_SLEEP_PM_OPS(imx_audmux_suspend, imx_audmux_resume) +}; + static struct platform_driver imx_audmux_driver = { .probe = imx_audmux_probe, .remove = imx_audmux_remove, .id_table = imx_audmux_ids, .driver = { .name = DRIVER_NAME, + .pm = &imx_audmux_pm, .of_match_table = imx_audmux_dt_ids, } }; -- cgit v1.2.3 From f59b16ef4ccea1b52f1c4e4c60ce507dc0bcc0ad Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 15 Aug 2019 14:20:15 -0500 Subject: ASoC: SOF: topology: Add dummy support for i.MX8 DAIs Add dummy support for SAI/ESAI digital audio interface IPs found on i.MX8 boards. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190815192018.30570-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/dai.h | 2 ++ include/uapi/sound/sof/tokens.h | 8 ++++++++ sound/soc/sof/topology.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) (limited to 'sound') diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index da9825ad41d4..86494294274e 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -50,6 +50,8 @@ enum sof_ipc_dai_type { SOF_DAI_INTEL_DMIC, /**< Intel DMIC */ SOF_DAI_INTEL_HDA, /**< Intel HD/A */ SOF_DAI_INTEL_SOUNDWIRE, /**< Intel SoundWire */ + SOF_DAI_IMX_SAI, /**< i.MX SAI */ + SOF_DAI_IMX_ESAI, /**< i.MX ESAI */ }; /* general purpose DAI configuration */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 6435240cef13..8f996857fb24 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -106,4 +106,12 @@ /* for backward compatibility */ #define SOF_TKN_EFFECT_TYPE SOF_TKN_PROCESS_TYPE +/* SAI */ +#define SOF_TKN_IMX_SAI_FIRST_TOKEN 1000 +/* TODO: Add SAI tokens */ + +/* ESAI */ +#define SOF_TKN_IMX_ESAI_FIRST_TOKEN 1100 +/* TODO: Add ESAI tokens */ + #endif diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 9cffea142395..a215bf58b138 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -346,6 +346,8 @@ static const struct sof_dai_types sof_dais[] = { {"SSP", SOF_DAI_INTEL_SSP}, {"HDA", SOF_DAI_INTEL_HDA}, {"DMIC", SOF_DAI_INTEL_DMIC}, + {"SAI", SOF_DAI_IMX_SAI}, + {"ESAI", SOF_DAI_IMX_ESAI}, }; static enum sof_ipc_dai_type find_dai(const char *name) @@ -2513,6 +2515,26 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, return ret; } +static int sof_link_sai_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + /*TODO: Add implementation */ + return 0; +} + +static int sof_link_esai_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + /*TODO: Add implementation */ + return 0; +} + static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg, @@ -2837,6 +2859,14 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, ret = sof_link_hda_load(scomp, index, link, cfg, hw_config, &config); break; + case SOF_DAI_IMX_SAI: + ret = sof_link_sai_load(scomp, index, link, cfg, hw_config, + &config); + break; + case SOF_DAI_IMX_ESAI: + ret = sof_link_esai_load(scomp, index, link, cfg, hw_config, + &config); + break; default: dev_err(sdev->dev, "error: invalid DAI type %d\n", config.type); ret = -EINVAL; -- cgit v1.2.3 From 4d6bbf1a015c84ba05af9d8c59dd9c55cad4e668 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 15 Aug 2019 14:20:17 -0500 Subject: ASoC: SOF: topology: initial support for Intel ALH DAI type The Audio Link Hub DAI does not require any static configuration from topology for now. We still need to pass the frame rate and format to firmware. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190815192018.30570-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index a215bf58b138..28a7a6e06a53 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -346,6 +346,7 @@ static const struct sof_dai_types sof_dais[] = { {"SSP", SOF_DAI_INTEL_SSP}, {"HDA", SOF_DAI_INTEL_HDA}, {"DMIC", SOF_DAI_INTEL_DMIC}, + {"ALH", SOF_DAI_INTEL_ALH}, {"SAI", SOF_DAI_IMX_SAI}, {"ESAI", SOF_DAI_IMX_ESAI}, }; @@ -2763,6 +2764,40 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, return ret; } +static int sof_link_alh_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_reply reply; + u32 size = sizeof(*config); + int ret; + + /* init IPC */ + config->hdr.size = size; + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, &reply, + sizeof(reply)); + + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DAI config for ALH %d\n", + config->dai_index); + return ret; + } + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(sdev->dev, "error: failed to save DAI config for ALH %d\n", + config->dai_index); + + return ret; +} + /* DAI link - used for any driver specific init */ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, @@ -2859,6 +2894,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, ret = sof_link_hda_load(scomp, index, link, cfg, hw_config, &config); break; + case SOF_DAI_INTEL_ALH: + ret = sof_link_alh_load(scomp, index, link, cfg, hw_config, + &config); + break; case SOF_DAI_IMX_SAI: ret = sof_link_sai_load(scomp, index, link, cfg, hw_config, &config); @@ -2924,7 +2963,8 @@ found: switch (sof_dai->dai_config->type) { case SOF_DAI_INTEL_SSP: case SOF_DAI_INTEL_DMIC: - /* no resource needs to be released for SSP and DMIC */ + case SOF_DAI_INTEL_ALH: + /* no resource needs to be released for SSP, DMIC and ALH */ break; case SOF_DAI_INTEL_HDA: ret = sof_link_hda_unload(sdev, link); -- cgit v1.2.3 From 6e3360cd07ec2d4a53919dc62947f9769d8fdac4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 15 Aug 2019 14:20:18 -0500 Subject: ASoC: SOF: pcm: add ALH support Even if ALH has no specific configuration, we still need to handle the common parameters for all DAIs Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190815192018.30570-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 8612896673a5..e3f6a6dc0f36 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -675,6 +675,9 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, case SOF_DAI_INTEL_HDA: /* do nothing for HDA dai_link */ break; + case SOF_DAI_INTEL_ALH: + /* do nothing for ALH dai_link */ + break; default: dev_err(sdev->dev, "error: invalid DAI type %d\n", dai->dai_config->type); -- cgit v1.2.3 From c372a35550c8d60f673b20210eea58a06d6d38cb Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Tue, 20 Aug 2019 15:16:04 +0900 Subject: ASoC: uniphier: Fix double reset assersion when transitioning to suspend state When transitioning to supend state, uniphier_aio_dai_suspend() is called and asserts reset lines and disables clocks. However, if there are two or more DAIs, uniphier_aio_dai_suspend() are called multiple times, and double reset assersion will cause. This patch defines the counter that has the number of DAIs at first, and whenever uniphier_aio_dai_suspend() are called, it decrements the counter. And only if the counter is zero, it asserts reset lines and disables clocks. In the same way, uniphier_aio_dai_resume() are called, it increments the counter after deasserting reset lines and enabling clocks. Fixes: 139a34200233 ("ASoC: uniphier: add support for UniPhier AIO CPU DAI driver") Signed-off-by: Kunihiko Hayashi Link: https://lore.kernel.org/r/1566281764-14059-1-git-send-email-hayashi.kunihiko@socionext.com Signed-off-by: Mark Brown --- sound/soc/uniphier/aio-cpu.c | 31 +++++++++++++++++++++---------- sound/soc/uniphier/aio.h | 1 + 2 files changed, 22 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c index ee90e6c3937c..2ae582a99b63 100644 --- a/sound/soc/uniphier/aio-cpu.c +++ b/sound/soc/uniphier/aio-cpu.c @@ -424,8 +424,11 @@ int uniphier_aio_dai_suspend(struct snd_soc_dai *dai) { struct uniphier_aio *aio = uniphier_priv(dai); - reset_control_assert(aio->chip->rst); - clk_disable_unprepare(aio->chip->clk); + aio->chip->num_wup_aios--; + if (!aio->chip->num_wup_aios) { + reset_control_assert(aio->chip->rst); + clk_disable_unprepare(aio->chip->clk); + } return 0; } @@ -439,13 +442,15 @@ int uniphier_aio_dai_resume(struct snd_soc_dai *dai) if (!aio->chip->active) return 0; - ret = clk_prepare_enable(aio->chip->clk); - if (ret) - return ret; + if (!aio->chip->num_wup_aios) { + ret = clk_prepare_enable(aio->chip->clk); + if (ret) + return ret; - ret = reset_control_deassert(aio->chip->rst); - if (ret) - goto err_out_clock; + ret = reset_control_deassert(aio->chip->rst); + if (ret) + goto err_out_clock; + } aio_iecout_set_enable(aio->chip, true); aio_chip_init(aio->chip); @@ -458,7 +463,7 @@ int uniphier_aio_dai_resume(struct snd_soc_dai *dai) ret = aio_init(sub); if (ret) - goto err_out_clock; + goto err_out_reset; if (!sub->setting) continue; @@ -466,11 +471,16 @@ int uniphier_aio_dai_resume(struct snd_soc_dai *dai) aio_port_reset(sub); aio_src_reset(sub); } + aio->chip->num_wup_aios++; return 0; +err_out_reset: + if (!aio->chip->num_wup_aios) + reset_control_assert(aio->chip->rst); err_out_clock: - clk_disable_unprepare(aio->chip->clk); + if (!aio->chip->num_wup_aios) + clk_disable_unprepare(aio->chip->clk); return ret; } @@ -619,6 +629,7 @@ int uniphier_aio_probe(struct platform_device *pdev) return PTR_ERR(chip->rst); chip->num_aios = chip->chip_spec->num_dais; + chip->num_wup_aios = chip->num_aios; chip->aios = devm_kcalloc(dev, chip->num_aios, sizeof(struct uniphier_aio), GFP_KERNEL); diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h index ca6ccbae0ee8..a7ff7e556429 100644 --- a/sound/soc/uniphier/aio.h +++ b/sound/soc/uniphier/aio.h @@ -285,6 +285,7 @@ struct uniphier_aio_chip { struct uniphier_aio *aios; int num_aios; + int num_wup_aios; struct uniphier_aio_pll *plls; int num_plls; -- cgit v1.2.3 From 18dd62ae3bc31baa0473e4a09e46c02e0bdc57a0 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 20 Aug 2019 14:34:13 +0200 Subject: ASoC: meson: axg-tdm-formatter: free reset on device removal Use the devm variant to get the formatter reset so it is properly freed on device removal Fixes: 751bd5db5260 ("ASoC: meson: axg-tdm-formatter: add reset") Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190820123413.22249-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-tdm-formatter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c index 2e498201139f..1a0bf9d3836d 100644 --- a/sound/soc/meson/axg-tdm-formatter.c +++ b/sound/soc/meson/axg-tdm-formatter.c @@ -327,7 +327,7 @@ int axg_tdm_formatter_probe(struct platform_device *pdev) } /* Formatter dedicated reset line */ - formatter->reset = reset_control_get_optional_exclusive(dev, NULL); + formatter->reset = devm_reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(formatter->reset)) { ret = PTR_ERR(formatter->reset); if (ret != -EPROBE_DEFER) -- cgit v1.2.3 From 351b31002c1853af078ebfffd4b67bfc3d19e3dd Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 20 Aug 2019 14:35:10 +0200 Subject: ASoC: meson: g12a-tohdmitx: require regmap mmio The tohdmitx glue uses regmap MMIO so it should require it. Fixes: c8609f3870f7 ("ASoC: meson: add g12a tohdmitx control") Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190820123510.22491-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig index 63b38c123103..2e3676147cea 100644 --- a/sound/soc/meson/Kconfig +++ b/sound/soc/meson/Kconfig @@ -87,6 +87,7 @@ config SND_MESON_AXG_PDM config SND_MESON_G12A_TOHDMITX tristate "Amlogic G12A To HDMI TX Control Support" + select REGMAP_MMIO imply SND_SOC_HDMI_CODEC help Select Y or M to add support for HDMI audio on the g12a SoC -- cgit v1.2.3 From 404be07f4ed27697f5fa69162f67a94555738595 Mon Sep 17 00:00:00 2001 From: Daniel Stuart Date: Thu, 15 Aug 2019 14:12:55 -0300 Subject: ASoC: intel: cht_bsw_max98090_ti: Add all Chromebooks that need pmc_plt_clk_0 quirk Every single baytrail chromebook sets PMC to 0, as can be seeing below by searching through coreboot source code: $ grep -rl "PMC_PLT_CLK\[0\]" . ./rambi/variants/glimmer/devicetree.cb ./rambi/variants/clapper/devicetree.cb ./rambi/variants/swanky/devicetree.cb ./rambi/variants/enguarde/devicetree.cb ./rambi/variants/winky/devicetree.cb ./rambi/variants/kip/devicetree.cb ./rambi/variants/squawks/devicetree.cb ./rambi/variants/orco/devicetree.cb ./rambi/variants/ninja/devicetree.cb ./rambi/variants/heli/devicetree.cb ./rambi/variants/sumo/devicetree.cb ./rambi/variants/banjo/devicetree.cb ./rambi/variants/candy/devicetree.cb ./rambi/variants/gnawty/devicetree.cb ./rambi/variants/rambi/devicetree.cb ./rambi/variants/quawks/devicetree.cb Plus, Cyan (only non-baytrail chromebook with max98090) also needs this patch for audio to work. Thus, this commit adds all the missing devices to bsw_max98090 quirk table, implemented by commit a182ecd3809c ("ASoC: intel: cht_bsw_max98090_ti: Add quirk for boards using pmc_plt_clk_0"). Signed-off-by: Daniel Stuart Link: https://lore.kernel.org/r/20190815171300.30126-1-daniel.stuart14@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 98 ++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 33eb72545be6..83b978e7b4c4 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -399,6 +399,20 @@ static struct snd_soc_card snd_soc_card_cht = { }; static const struct dmi_system_id cht_max98090_quirk_table[] = { + { + /* Banjo model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Banjo"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Candy model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Candy"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, { /* Clapper model Chromebook */ .matches = { @@ -406,6 +420,27 @@ static const struct dmi_system_id cht_max98090_quirk_table[] = { }, .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, }, + { + /* Cyan model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Cyan"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Enguarde model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Enguarde"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Glimmer model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Glimmer"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, { /* Gnawty model Chromebook (Acer Chromebook CB3-111) */ .matches = { @@ -413,6 +448,62 @@ static const struct dmi_system_id cht_max98090_quirk_table[] = { }, .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, }, + { + /* Heli model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Heli"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Kip model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Kip"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Ninja model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Ninja"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Orco model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Orco"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Quawks model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Quawks"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Rambi model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Rambi"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Squawks model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Squawks"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Sumo model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Sumo"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, { /* Swanky model Chromebook (Toshiba Chromebook 2) */ .matches = { @@ -420,6 +511,13 @@ static const struct dmi_system_id cht_max98090_quirk_table[] = { }, .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, }, + { + /* Winky model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Winky"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, {} }; -- cgit v1.2.3 From 22afe6242387eca1ac3905fbde7bef38deb0357d Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Tue, 20 Aug 2019 13:02:35 +0200 Subject: ASoC: wm8904: fix typo in DAPM kcontrol name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trivial fix for typo in "Capture Inverting Mux"es' name. Signed-off-by: Michał Mirosław Acked-by: Charles Keepax Link: https://lore.kernel.org/r/f95ae1085f9f3c137a122c4d95728711613c15f7.1566298834.git.mirq-linux@rere.qmqm.pl Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 5ebdd1d9afde..525e4ef654a1 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -866,7 +866,7 @@ static SOC_ENUM_SINGLE_DECL(lin_inv_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 4, lin_text); static const struct snd_kcontrol_new lin_inv_mux = - SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum); + SOC_DAPM_ENUM("Left Capture Inverting Mux", lin_inv_enum); static const char *rin_text[] = { "IN1R", "IN2R", "IN3R" @@ -882,7 +882,7 @@ static SOC_ENUM_SINGLE_DECL(rin_inv_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 4, rin_text); static const struct snd_kcontrol_new rin_inv_mux = - SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum); + SOC_DAPM_ENUM("Right Capture Inverting Mux", rin_inv_enum); static const char *aif_text[] = { "Left", "Right" -- cgit v1.2.3 From 0a05f2e865ad6e461cada8f931b34551287dbba2 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Tue, 20 Aug 2019 13:02:37 +0200 Subject: ASoC: wm8904: implement input mode select as a mux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make '* Capture Mode' a mux. This makes DAPM know that in single-ended mode only inverting mux paths need to be enabled. Signed-off-by: Michał Mirosław Acked-by: Charles Keepax Link: https://lore.kernel.org/r/125cd3c9f298da9b08a4d6002d4c00d70a898950.1566298834.git.mirq-linux@rere.qmqm.pl Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 52 ++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 525e4ef654a1..bcb3c9d5abf0 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -545,18 +545,6 @@ static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0); static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); -static const char *input_mode_text[] = { - "Single-Ended", "Differential Line", "Differential Mic" -}; - -static SOC_ENUM_SINGLE_DECL(lin_mode, - WM8904_ANALOGUE_LEFT_INPUT_1, 0, - input_mode_text); - -static SOC_ENUM_SINGLE_DECL(rin_mode, - WM8904_ANALOGUE_RIGHT_INPUT_1, 0, - input_mode_text); - static const char *hpf_mode_text[] = { "Hi-fi", "Voice 1", "Voice 2", "Voice 3" }; @@ -591,9 +579,6 @@ static const struct snd_kcontrol_new wm8904_adc_snd_controls[] = { SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8904_ADC_DIGITAL_VOLUME_LEFT, WM8904_ADC_DIGITAL_VOLUME_RIGHT, 1, 119, 0, digital_tlv), -SOC_ENUM("Left Capture Mode", lin_mode), -SOC_ENUM("Right Capture Mode", rin_mode), - /* No TLV since it depends on mode */ SOC_DOUBLE_R("Capture Volume", WM8904_ANALOGUE_LEFT_INPUT_0, WM8904_ANALOGUE_RIGHT_INPUT_0, 0, 31, 0), @@ -852,6 +837,10 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, return 0; } +static const char *input_mode_text[] = { + "Single-Ended", "Differential Line", "Differential Mic" +}; + static const char *lin_text[] = { "IN1L", "IN2L", "IN3L" }; @@ -868,6 +857,13 @@ static SOC_ENUM_SINGLE_DECL(lin_inv_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 4, static const struct snd_kcontrol_new lin_inv_mux = SOC_DAPM_ENUM("Left Capture Inverting Mux", lin_inv_enum); +static SOC_ENUM_SINGLE_DECL(lin_mode_enum, + WM8904_ANALOGUE_LEFT_INPUT_1, 0, + input_mode_text); + +static const struct snd_kcontrol_new lin_mode = + SOC_DAPM_ENUM("Left Capture Mode", lin_mode_enum); + static const char *rin_text[] = { "IN1R", "IN2R", "IN3R" }; @@ -884,6 +880,13 @@ static SOC_ENUM_SINGLE_DECL(rin_inv_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 4, static const struct snd_kcontrol_new rin_inv_mux = SOC_DAPM_ENUM("Right Capture Inverting Mux", rin_inv_enum); +static SOC_ENUM_SINGLE_DECL(rin_mode_enum, + WM8904_ANALOGUE_RIGHT_INPUT_1, 0, + input_mode_text); + +static const struct snd_kcontrol_new rin_mode = + SOC_DAPM_ENUM("Right Capture Mode", rin_mode_enum); + static const char *aif_text[] = { "Left", "Right" }; @@ -932,9 +935,11 @@ SND_SOC_DAPM_SUPPLY("MICBIAS", WM8904_MIC_BIAS_CONTROL_0, 0, 0, NULL, 0), SND_SOC_DAPM_MUX("Left Capture Mux", SND_SOC_NOPM, 0, 0, &lin_mux), SND_SOC_DAPM_MUX("Left Capture Inverting Mux", SND_SOC_NOPM, 0, 0, &lin_inv_mux), +SND_SOC_DAPM_MUX("Left Capture Mode", SND_SOC_NOPM, 0, 0, &lin_mode), SND_SOC_DAPM_MUX("Right Capture Mux", SND_SOC_NOPM, 0, 0, &rin_mux), SND_SOC_DAPM_MUX("Right Capture Inverting Mux", SND_SOC_NOPM, 0, 0, &rin_inv_mux), +SND_SOC_DAPM_MUX("Right Capture Mode", SND_SOC_NOPM, 0, 0, &rin_mode), SND_SOC_DAPM_PGA("Left Capture PGA", WM8904_POWER_MANAGEMENT_0, 1, 0, NULL, 0), @@ -1057,6 +1062,12 @@ static const struct snd_soc_dapm_route adc_intercon[] = { { "Left Capture Inverting Mux", "IN2L", "IN2L" }, { "Left Capture Inverting Mux", "IN3L", "IN3L" }, + { "Left Capture Mode", "Single-Ended", "Left Capture Inverting Mux" }, + { "Left Capture Mode", "Differential Line", "Left Capture Mux" }, + { "Left Capture Mode", "Differential Line", "Left Capture Inverting Mux" }, + { "Left Capture Mode", "Differential Mic", "Left Capture Mux" }, + { "Left Capture Mode", "Differential Mic", "Left Capture Inverting Mux" }, + { "Right Capture Mux", "IN1R", "IN1R" }, { "Right Capture Mux", "IN2R", "IN2R" }, { "Right Capture Mux", "IN3R", "IN3R" }, @@ -1065,11 +1076,14 @@ static const struct snd_soc_dapm_route adc_intercon[] = { { "Right Capture Inverting Mux", "IN2R", "IN2R" }, { "Right Capture Inverting Mux", "IN3R", "IN3R" }, - { "Left Capture PGA", NULL, "Left Capture Mux" }, - { "Left Capture PGA", NULL, "Left Capture Inverting Mux" }, + { "Right Capture Mode", "Single-Ended", "Right Capture Inverting Mux" }, + { "Right Capture Mode", "Differential Line", "Right Capture Mux" }, + { "Right Capture Mode", "Differential Line", "Right Capture Inverting Mux" }, + { "Right Capture Mode", "Differential Mic", "Right Capture Mux" }, + { "Right Capture Mode", "Differential Mic", "Right Capture Inverting Mux" }, - { "Right Capture PGA", NULL, "Right Capture Mux" }, - { "Right Capture PGA", NULL, "Right Capture Inverting Mux" }, + { "Left Capture PGA", NULL, "Left Capture Mode" }, + { "Right Capture PGA", NULL, "Right Capture Mode" }, { "AIFOUTL Mux", "Left", "ADCL" }, { "AIFOUTL Mux", "Right", "ADCR" }, -- cgit v1.2.3 From bf283a05c09b58db83afbb1a8a3c6a684c56c1bb Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:08 +0200 Subject: ASoC: sun4i-i2s: Register regmap and PCM before our component So far the regmap and the dmaengine PCM are registered after our component has been, which means that our driver isn't properly initialised by then. Let's fix that. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/67e303f37f141ef73ce9ed47d7f831b63c694424.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 7fa5c61169db..85c3b2c8cd77 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1148,11 +1148,9 @@ static int sun4i_i2s_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = devm_snd_soc_register_component(&pdev->dev, - &sun4i_i2s_component, - &sun4i_i2s_dai, 1); + ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s); if (ret) { - dev_err(&pdev->dev, "Could not register DAI\n"); + dev_err(&pdev->dev, "Could not initialise regmap fields\n"); goto err_suspend; } @@ -1162,9 +1160,11 @@ static int sun4i_i2s_probe(struct platform_device *pdev) goto err_suspend; } - ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s); + ret = devm_snd_soc_register_component(&pdev->dev, + &sun4i_i2s_component, + &sun4i_i2s_dai, 1); if (ret) { - dev_err(&pdev->dev, "Could not initialise regmap fields\n"); + dev_err(&pdev->dev, "Could not register DAI\n"); goto err_suspend; } -- cgit v1.2.3 From a49d24e7d8d4fd4edf59e6373983e0bf4a2cca15 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:09 +0200 Subject: ASoC: sun4i-i2s: Switch to devm for PCM register Since the introduction of the driver, a new managed helper for the dmaengine PCM registration has been created. Let's use it to simplify a bit our probe and remove functions. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/606d271187091e858e8c15e20555af0b79798fe1.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index d97d694c48df..70608fa30bf2 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1154,7 +1154,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev) goto err_suspend; } - ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) { dev_err(&pdev->dev, "Could not register PCM\n"); goto err_suspend; @@ -1183,8 +1183,6 @@ static int sun4i_i2s_remove(struct platform_device *pdev) { struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev); - snd_dmaengine_pcm_unregister(&pdev->dev); - pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) sun4i_i2s_runtime_suspend(&pdev->dev); -- cgit v1.2.3 From 7df8f9a20196072162d9dc8fe99943f2d35f23d5 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:14 +0200 Subject: ASoC: sun4i-i2s: Don't use the oversample to calculate BCLK The BCLK divider should be calculated using the parameters that actually make the BCLK rate: the number of channels, the sampling rate and the sample width. We've been using the oversample_rate previously because in the former SoCs, the BCLK's parent is MCLK, which in turn is being used to generate the oversample rate, so we end up with something like this: oversample = mclk_rate / sampling_rate bclk_div = oversample / word_size / channels So, bclk_div = mclk_rate / sampling_rate / word_size / channels. And this is actually better, since the oversampling ratio only plays a role because the MCLK is its parent, not because of what BCLK is supposed to be. Furthermore, that assumption of MCLK being the parent has been broken on newer SoCs, so let's use the proper formula, and have the parent rate as an argument. Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3") Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Fixes: 66ecce332538 ("ASoC: sun4i-i2s: Add compatibility with A64 codec I2S") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/c3595e3a9788c2ef2dcc30aa3c8c4953bb5cc249.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 70608fa30bf2..d879db581073 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -222,10 +222,11 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { }; static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, - unsigned int oversample_rate, + unsigned long parent_rate, + unsigned int sampling_rate, unsigned int word_size) { - int div = oversample_rate / word_size / 2; + int div = parent_rate / sampling_rate / word_size / 2; int i; for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) { @@ -315,8 +316,8 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, return -EINVAL; } - bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, - word_size); + bclk_div = sun4i_i2s_get_bclk_div(i2s, i2s->mclk_freq, + rate, word_size); if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL; -- cgit v1.2.3 From c7dd0828c088a71f30de8d249f63b2fa9f0d322d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:10 +0200 Subject: ASoC: sun4i-i2s: Replace call to params_channels by local variable The sun4i_i2s_hw_params already has a variable holding the value returned by params_channels, so let's just use that variable instead of calling params_channels multiple times. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/c0faaac69ad40248f24eed3c3b2fa1ccc4a85b70.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index d879db581073..77b7b81daf74 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -412,10 +412,9 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, /* Configure the channels */ regmap_field_write(i2s->field_txchansel, - SUN4I_I2S_CHAN_SEL(params_channels(params))); - + SUN4I_I2S_CHAN_SEL(channels)); regmap_field_write(i2s->field_rxchansel, - SUN4I_I2S_CHAN_SEL(params_channels(params))); + SUN4I_I2S_CHAN_SEL(channels)); if (i2s->variant->has_chsel_tx_chen) regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, -- cgit v1.2.3 From 8bcf62b73e5421df94deca95d7d7c152997fe5b4 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:13 +0200 Subject: ASoC: sun4i-i2s: Rework MCLK divider calculation The MCLK divider calculation is currently computing the ideal divider using the oversample rate, the sample rate and the parent rate. However, since we have access to the frequency is supposed to be running at already, and as it turns out we're using it to compute the oversample rate, we can just use the ratio between the parent rate and the MCLK rate to simplify a bit the formula. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/dcc5deb2eb650758d268bddd20f60ba58856d024.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 77b7b81daf74..0a5fb9d4b289 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -240,11 +240,10 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, } static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, - unsigned int oversample_rate, - unsigned int module_rate, - unsigned int sampling_rate) + unsigned long parent_rate, + unsigned long mclk_rate) { - int div = module_rate / sampling_rate / oversample_rate; + int div = parent_rate / mclk_rate; int i; for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) { @@ -323,8 +322,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, return -EINVAL; } - mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, - clk_rate, rate); + mclk_div = sun4i_i2s_get_mclk_div(i2s, clk_rate, i2s->mclk_freq); if (mclk_div < 0) { dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div); return -EINVAL; -- cgit v1.2.3 From d5e120422db8808e1c8b1507900ca393a877c58f Mon Sep 17 00:00:00 2001 From: Daniel Stuart Date: Thu, 15 Aug 2019 14:12:55 -0300 Subject: ASoC: intel: cht_bsw_max98090_ti: Add all Chromebooks that need pmc_plt_clk_0 quirk Every single baytrail chromebook sets PMC to 0, as can be seeing below by searching through coreboot source code: $ grep -rl "PMC_PLT_CLK\[0\]" . ./rambi/variants/glimmer/devicetree.cb ./rambi/variants/clapper/devicetree.cb ./rambi/variants/swanky/devicetree.cb ./rambi/variants/enguarde/devicetree.cb ./rambi/variants/winky/devicetree.cb ./rambi/variants/kip/devicetree.cb ./rambi/variants/squawks/devicetree.cb ./rambi/variants/orco/devicetree.cb ./rambi/variants/ninja/devicetree.cb ./rambi/variants/heli/devicetree.cb ./rambi/variants/sumo/devicetree.cb ./rambi/variants/banjo/devicetree.cb ./rambi/variants/candy/devicetree.cb ./rambi/variants/gnawty/devicetree.cb ./rambi/variants/rambi/devicetree.cb ./rambi/variants/quawks/devicetree.cb Plus, Cyan (only non-baytrail chromebook with max98090) also needs this patch for audio to work. Thus, this commit adds all the missing devices to bsw_max98090 quirk table, implemented by commit a182ecd3809c ("ASoC: intel: cht_bsw_max98090_ti: Add quirk for boards using pmc_plt_clk_0"). Signed-off-by: Daniel Stuart Link: https://lore.kernel.org/r/20190815171300.30126-1-daniel.stuart14@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 98 ++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 1db9a95e6a79..eaf3e2208a06 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -398,6 +398,20 @@ static struct snd_soc_card snd_soc_card_cht = { }; static const struct dmi_system_id cht_max98090_quirk_table[] = { + { + /* Banjo model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Banjo"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Candy model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Candy"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, { /* Clapper model Chromebook */ .matches = { @@ -405,6 +419,27 @@ static const struct dmi_system_id cht_max98090_quirk_table[] = { }, .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, }, + { + /* Cyan model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Cyan"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Enguarde model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Enguarde"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Glimmer model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Glimmer"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, { /* Gnawty model Chromebook (Acer Chromebook CB3-111) */ .matches = { @@ -412,6 +447,62 @@ static const struct dmi_system_id cht_max98090_quirk_table[] = { }, .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, }, + { + /* Heli model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Heli"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Kip model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Kip"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Ninja model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Ninja"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Orco model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Orco"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Quawks model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Quawks"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Rambi model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Rambi"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Squawks model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Squawks"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + { + /* Sumo model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Sumo"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, { /* Swanky model Chromebook (Toshiba Chromebook 2) */ .matches = { @@ -419,6 +510,13 @@ static const struct dmi_system_id cht_max98090_quirk_table[] = { }, .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, }, + { + /* Winky model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Winky"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, {} }; -- cgit v1.2.3 From d70be625f25af7a2bc91b7d17d205f6071f08f2f Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:11 +0200 Subject: ASoC: sun4i-i2s: Move the channel configuration to a callback The two main generations of our I2S controller require a slightly different channel configuration, mostly because of a quite different register layout and some additional registers being needed on the newer generation. This used to be controlled through a bunch of booleans, however this proved to be quite impractical, especially since a bunch of SoCs forgot to set those parameters and therefore were broken from that point of view. Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/6414463de69584e8227fa495b13aa5f4798e1f0e.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 156 ++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 87 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 2c909c6cafa9..42e45c9a947a 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -80,6 +80,7 @@ #define SUN4I_I2S_TX_CNT_REG 0x2c #define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 +#define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0) #define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0) #define SUN4I_I2S_TX_CHAN_MAP_REG 0x34 @@ -122,8 +123,6 @@ struct sun4i_i2s; * @has_reset: SoC needs reset deasserted. * @has_slave_select_bit: SoC has a bit to enable slave mode. * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. - * @has_chcfg: tx and rx slot number need to be set. - * @has_chsel_tx_chen: SoC requires that the tx channels are enabled. * @has_chsel_offset: SoC uses offset for selecting dai operational mode. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. @@ -135,17 +134,11 @@ struct sun4i_i2s; * @field_fmt_bclk: regmap field to set clk polarity. * @field_fmt_lrclk: regmap field to set frame polarity. * @field_fmt_mode: regmap field to set the operational mode. - * @field_txchanmap: location of the tx channel mapping register. - * @field_rxchanmap: location of the rx channel mapping register. - * @field_txchansel: location of the tx channel select bit fields. - * @field_rxchansel: location of the rx channel select bit fields. */ struct sun4i_i2s_quirks { bool has_reset; bool has_slave_select_bit; bool has_fmt_set_lrck_period; - bool has_chcfg; - bool has_chsel_tx_chen; bool has_chsel_offset; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; @@ -159,13 +152,11 @@ struct sun4i_i2s_quirks { struct reg_field field_fmt_bclk; struct reg_field field_fmt_lrclk; struct reg_field field_fmt_mode; - struct reg_field field_txchanmap; - struct reg_field field_rxchanmap; - struct reg_field field_txchansel; - struct reg_field field_rxchansel; s8 (*get_sr)(const struct sun4i_i2s *, int); s8 (*get_wss)(const struct sun4i_i2s *, int); + int (*set_chan_cfg)(const struct sun4i_i2s *, + const struct snd_pcm_hw_params *); }; struct sun4i_i2s { @@ -186,10 +177,6 @@ struct sun4i_i2s { struct regmap_field *field_fmt_bclk; struct regmap_field *field_fmt_lrclk; struct regmap_field *field_fmt_mode; - struct regmap_field *field_txchanmap; - struct regmap_field *field_rxchanmap; - struct regmap_field *field_txchansel; - struct regmap_field *field_rxchansel; const struct sun4i_i2s_quirks *variant; }; @@ -380,44 +367,77 @@ static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width) return (width - 8) / 4 + 1; } -static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) +static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, + const struct snd_pcm_hw_params *params) { - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - int sr, wss, channels; - u32 width; + unsigned int channels = params_channels(params); - channels = params_channels(params); - if (channels != 2) { - dev_err(dai->dev, "Unsupported number of channels: %d\n", - channels); + if (channels != 2) return -EINVAL; - } - if (i2s->variant->has_chcfg) { - regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, - SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, - SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); - regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, - SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, - SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); - } + /* Map the channels for playback and capture */ + regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210); + regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210); + + /* Configure the channels */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, + SUN4I_I2S_CHAN_SEL(channels)); + regmap_update_bits(i2s->regmap, SUN4I_I2S_RX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, + SUN4I_I2S_CHAN_SEL(channels)); + + return 0; +} + +static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, + const struct snd_pcm_hw_params *params) +{ + unsigned int channels = params_channels(params); + + if (channels != 2) + return -EINVAL; /* Map the channels for playback and capture */ - regmap_field_write(i2s->field_txchanmap, 0x76543210); - regmap_field_write(i2s->field_rxchanmap, 0x00003210); + regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); + regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210); /* Configure the channels */ - regmap_field_write(i2s->field_txchansel, + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels)); - regmap_field_write(i2s->field_rxchansel, + + regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels)); - if (i2s->variant->has_chsel_tx_chen) - regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_EN_MASK, - SUN8I_I2S_TX_CHAN_EN(channels)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); + + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_EN_MASK, + SUN8I_I2S_TX_CHAN_EN(channels)); + + return 0; +} + +static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + int ret, sr, wss; + u32 width; + + ret = i2s->variant->set_chan_cfg(i2s, params); + if (ret < 0) { + dev_err(dai->dev, "Invalid channel configuration\n"); + return ret; + } switch (params_physical_width(params)) { case 16: @@ -915,12 +935,9 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .has_slave_select_bit = true, .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, }; static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { @@ -934,12 +951,9 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .has_slave_select_bit = true, .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, }; static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { @@ -953,12 +967,9 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .has_slave_select_bit = true, .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, + .set_chan_cfg = sun8i_i2s_set_chan_cfg, }; static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { @@ -968,8 +979,6 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .mclk_offset = 1, .bclk_offset = 2, .has_fmt_set_lrck_period = true, - .has_chcfg = true, - .has_chsel_tx_chen = true, .has_chsel_offset = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), @@ -977,12 +986,9 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19), .field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5), - .field_txchanmap = REG_FIELD(SUN8I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, + .set_chan_cfg = sun8i_i2s_set_chan_cfg, }; static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { @@ -996,12 +1002,9 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, }; static int sun4i_i2s_init_regmap_fields(struct device *dev, @@ -1043,28 +1046,7 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev, if (IS_ERR(i2s->field_fmt_mode)) return PTR_ERR(i2s->field_fmt_mode); - i2s->field_txchanmap = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_txchanmap); - if (IS_ERR(i2s->field_txchanmap)) - return PTR_ERR(i2s->field_txchanmap); - - i2s->field_rxchanmap = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_rxchanmap); - if (IS_ERR(i2s->field_rxchanmap)) - return PTR_ERR(i2s->field_rxchanmap); - - i2s->field_txchansel = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_txchansel); - if (IS_ERR(i2s->field_txchansel)) - return PTR_ERR(i2s->field_txchansel); - - i2s->field_rxchansel = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_rxchansel); - return PTR_ERR_OR_ZERO(i2s->field_rxchansel); + return 0; } static int sun4i_i2s_probe(struct platform_device *pdev) -- cgit v1.2.3 From 71137bcd0a9a778f9407a3bee46c62fcccee4f83 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:12 +0200 Subject: ASoC: sun4i-i2s: Move the format configuration to a callback The two main generations of our I2S controller require a slightly different format configuration, mostly because of a quite different register layout and some additional registers being needed on the newer generation. This used to be controlled through a bunch of booleans, however this proved to be quite impractical, especially since a bunch of SoCs forgot to set those parameters and therefore were broken from that point of view. Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/dc818644c3e40734e7a97247c994b1fca1c3c047.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 199 +++++++++++++++++++++++--------------------- 1 file changed, 106 insertions(+), 93 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 42e45c9a947a..93ea627e2f1f 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -93,6 +93,11 @@ #define SUN8I_I2S_CTRL_BCLK_OUT BIT(18) #define SUN8I_I2S_CTRL_LRCK_OUT BIT(17) +#define SUN8I_I2S_CTRL_MODE_MASK GENMASK(5, 4) +#define SUN8I_I2S_CTRL_MODE_RIGHT (2 << 4) +#define SUN8I_I2S_CTRL_MODE_LEFT (1 << 4) +#define SUN8I_I2S_CTRL_MODE_PCM (0 << 4) + #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8) #define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8) @@ -121,9 +126,7 @@ struct sun4i_i2s; * struct sun4i_i2s_quirks - Differences between SoC variants. * * @has_reset: SoC needs reset deasserted. - * @has_slave_select_bit: SoC has a bit to enable slave mode. * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. - * @has_chsel_offset: SoC uses offset for selecting dai operational mode. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. * @mclk_offset: Value by which mclkdiv needs to be adjusted. @@ -133,13 +136,10 @@ struct sun4i_i2s; * @field_fmt_sr: regmap field to set sample resolution. * @field_fmt_bclk: regmap field to set clk polarity. * @field_fmt_lrclk: regmap field to set frame polarity. - * @field_fmt_mode: regmap field to set the operational mode. */ struct sun4i_i2s_quirks { bool has_reset; - bool has_slave_select_bit; bool has_fmt_set_lrck_period; - bool has_chsel_offset; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; unsigned int mclk_offset; @@ -151,12 +151,12 @@ struct sun4i_i2s_quirks { struct reg_field field_fmt_sr; struct reg_field field_fmt_bclk; struct reg_field field_fmt_lrclk; - struct reg_field field_fmt_mode; s8 (*get_sr)(const struct sun4i_i2s *, int); s8 (*get_wss)(const struct sun4i_i2s *, int); int (*set_chan_cfg)(const struct sun4i_i2s *, const struct snd_pcm_hw_params *); + int (*set_fmt)(const struct sun4i_i2s *, unsigned int); }; struct sun4i_i2s { @@ -176,7 +176,6 @@ struct sun4i_i2s { struct regmap_field *field_fmt_sr; struct regmap_field *field_fmt_bclk; struct regmap_field *field_fmt_lrclk; - struct regmap_field *field_fmt_mode; const struct sun4i_i2s_quirks *variant; }; @@ -465,52 +464,117 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, params_width(params)); } -static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, + unsigned int fmt) { - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); u32 val; - u32 offset = 0; - u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; - u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; /* DAI Mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: val = SUN4I_I2S_FMT0_FMT_I2S; - offset = 1; break; + case SND_SOC_DAIFMT_LEFT_J: val = SUN4I_I2S_FMT0_FMT_LEFT_J; break; + case SND_SOC_DAIFMT_RIGHT_J: val = SUN4I_I2S_FMT0_FMT_RIGHT_J; break; + default: - dev_err(dai->dev, "Unsupported format: %d\n", - fmt & SND_SOC_DAIFMT_FORMAT_MASK); return -EINVAL; } - if (i2s->variant->has_chsel_offset) { - /* - * offset being set indicates that we're connected to an i2s - * device, however offset is only used on the sun8i block and - * i2s shares the same setting with the LJ format. Increment - * val so that the bit to value to write is correct. - */ - if (offset > 0) - val++; - /* blck offset determines whether i2s or LJ */ - regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_OFFSET_MASK, - SUN8I_I2S_TX_CHAN_OFFSET(offset)); - - regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_OFFSET_MASK, - SUN8I_I2S_TX_CHAN_OFFSET(offset)); + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN4I_I2S_FMT0_FMT_MASK, val); + + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* BCLK and LRCLK master */ + val = SUN4I_I2S_CTRL_MODE_MASTER; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + /* BCLK and LRCLK slave */ + val = SUN4I_I2S_CTRL_MODE_SLAVE; + break; + + default: + return -EINVAL; } + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_MODE_MASK, val); + return 0; +} - regmap_field_write(i2s->field_fmt_mode, val); +static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, + unsigned int fmt) +{ + u32 mode, val; + u8 offset; + + /* DAI Mode */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + mode = SUN8I_I2S_CTRL_MODE_LEFT; + offset = 1; + break; + + case SND_SOC_DAIFMT_LEFT_J: + mode = SUN8I_I2S_CTRL_MODE_LEFT; + offset = 0; + break; + + case SND_SOC_DAIFMT_RIGHT_J: + mode = SUN8I_I2S_CTRL_MODE_RIGHT; + offset = 0; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN8I_I2S_CTRL_MODE_MASK, mode); + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_OFFSET_MASK, + SUN8I_I2S_TX_CHAN_OFFSET(offset)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_OFFSET_MASK, + SUN8I_I2S_TX_CHAN_OFFSET(offset)); + + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* BCLK and LRCLK master */ + val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + /* BCLK and LRCLK slave */ + val = 0; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, + val); + + return 0; +} + +static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; + u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; + int ret; /* DAI clock polarity */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -538,50 +602,10 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) regmap_field_write(i2s->field_fmt_bclk, bclk_polarity); regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity); - if (i2s->variant->has_slave_select_bit) { - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* BCLK and LRCLK master */ - val = SUN4I_I2S_CTRL_MODE_MASTER; - break; - case SND_SOC_DAIFMT_CBM_CFM: - /* BCLK and LRCLK slave */ - val = SUN4I_I2S_CTRL_MODE_SLAVE; - break; - default: - dev_err(dai->dev, "Unsupported slave setting: %d\n", - fmt & SND_SOC_DAIFMT_MASTER_MASK); - return -EINVAL; - } - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN4I_I2S_CTRL_MODE_MASK, - val); - } else { - /* - * The newer i2s block does not have a slave select bit, - * instead the clk pins are configured as inputs. - */ - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* BCLK and LRCLK master */ - val = SUN8I_I2S_CTRL_BCLK_OUT | - SUN8I_I2S_CTRL_LRCK_OUT; - break; - case SND_SOC_DAIFMT_CBM_CFM: - /* BCLK and LRCLK slave */ - val = 0; - break; - default: - dev_err(dai->dev, "Unsupported slave setting: %d\n", - fmt & SND_SOC_DAIFMT_MASTER_MASK); - return -EINVAL; - } - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN8I_I2S_CTRL_BCLK_OUT | - SUN8I_I2S_CTRL_LRCK_OUT, - val); + ret = i2s->variant->set_fmt(i2s, fmt); + if (ret) { + dev_err(dai->dev, "Unsupported format configuration\n"); + return ret; } /* Set significant bits in our FIFOs */ @@ -933,11 +957,10 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), - .has_slave_select_bit = true, - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, }; static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { @@ -949,11 +972,10 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), - .has_slave_select_bit = true, - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, }; static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { @@ -965,11 +987,10 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), - .has_slave_select_bit = true, - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, .set_chan_cfg = sun8i_i2s_set_chan_cfg, + .set_fmt = sun8i_i2s_set_soc_fmt, }; static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { @@ -979,32 +1000,30 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .mclk_offset = 1, .bclk_offset = 2, .has_fmt_set_lrck_period = true, - .has_chsel_offset = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19), - .field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5), .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, .set_chan_cfg = sun8i_i2s_set_chan_cfg, + .set_fmt = sun8i_i2s_set_soc_fmt, }; static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, - .has_slave_select_bit = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, }; static int sun4i_i2s_init_regmap_fields(struct device *dev, @@ -1040,12 +1059,6 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev, if (IS_ERR(i2s->field_fmt_lrclk)) return PTR_ERR(i2s->field_fmt_lrclk); - i2s->field_fmt_mode = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_fmt_mode); - if (IS_ERR(i2s->field_fmt_mode)) - return PTR_ERR(i2s->field_fmt_mode); - return 0; } -- cgit v1.2.3 From fb19739d7f688142b61d0fca476188c4fd9e937a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:15 +0200 Subject: ASoC: sun4i-i2s: Use module clock as BCLK parent on newer SoCs On the first generation of Allwinner SoCs (A10-A31), the i2s controller was using the MCLK as BCLK parent. However, this changed since the introduction of the A83t and BCLK now uses the module clock as its parent. Let's introduce a hook to get the parent rate and use that in our divider calculations. Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3") Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/0b6665be216b3bd0e7bc43724818f05f3f8ee881.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 93ea627e2f1f..acfcdb26086a 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -152,6 +152,7 @@ struct sun4i_i2s_quirks { struct reg_field field_fmt_bclk; struct reg_field field_fmt_lrclk; + unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *); s8 (*get_sr)(const struct sun4i_i2s *, int); s8 (*get_wss)(const struct sun4i_i2s *, int); int (*set_chan_cfg)(const struct sun4i_i2s *, @@ -207,6 +208,16 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { /* TODO - extend divide ratio supported by newer SoCs */ }; +static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) +{ + return i2s->mclk_freq; +} + +static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) +{ + return clk_get_rate(i2s->mod_clk); +} + static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, unsigned long parent_rate, unsigned int sampling_rate, @@ -259,7 +270,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int word_size) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - unsigned int oversample_rate, clk_rate; + unsigned int oversample_rate, clk_rate, bclk_parent_rate; int bclk_div, mclk_div; int ret; @@ -301,7 +312,8 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, return -EINVAL; } - bclk_div = sun4i_i2s_get_bclk_div(i2s, i2s->mclk_freq, + bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); + bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, rate, word_size); if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); @@ -957,6 +969,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), + .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, .set_chan_cfg = sun4i_i2s_set_chan_cfg, @@ -972,6 +985,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), + .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, .set_chan_cfg = sun4i_i2s_set_chan_cfg, @@ -987,6 +1001,7 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), + .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, .set_chan_cfg = sun8i_i2s_set_chan_cfg, @@ -1005,6 +1020,7 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19), + .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, .set_chan_cfg = sun8i_i2s_set_chan_cfg, @@ -1020,6 +1036,7 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), + .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, .set_chan_cfg = sun4i_i2s_set_chan_cfg, -- cgit v1.2.3 From c1d3a921d72bd21f266ca28c15213fbe78160a4b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:16 +0200 Subject: ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs From: Marcus Cooper The clock division dividers have changed between the older (A10/A31) and newer (H3, A64, etc) SoCs. While this was addressed through an offset on some SoCs, it was missing some dividers as well, so the support wasn't perfect. Let's introduce a pointer in the quirk structure for the divider calculation functions to use so we can have the proper range now. Signed-off-by: Marcus Cooper [Maxime: Fix the commit log, use a field in the quirk structure] Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/0e5b4abf06cd3202354315201c6af44caeb20236.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 63 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index acfcdb26086a..0a7f1d0f7371 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -129,8 +129,6 @@ struct sun4i_i2s; * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. - * @mclk_offset: Value by which mclkdiv needs to be adjusted. - * @bclk_offset: Value by which bclkdiv needs to be adjusted. * @field_clkdiv_mclk_en: regmap field to enable mclk output. * @field_fmt_wss: regmap field to set word select size. * @field_fmt_sr: regmap field to set sample resolution. @@ -142,8 +140,6 @@ struct sun4i_i2s_quirks { bool has_fmt_set_lrck_period; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; - unsigned int mclk_offset; - unsigned int bclk_offset; /* Register fields for i2s */ struct reg_field field_clkdiv_mclk_en; @@ -152,6 +148,11 @@ struct sun4i_i2s_quirks { struct reg_field field_fmt_bclk; struct reg_field field_fmt_lrclk; + const struct sun4i_i2s_clk_div *bclk_dividers; + unsigned int num_bclk_dividers; + const struct sun4i_i2s_clk_div *mclk_dividers; + unsigned int num_mclk_dividers; + unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *); s8 (*get_sr)(const struct sun4i_i2s *, int); s8 (*get_wss)(const struct sun4i_i2s *, int); @@ -208,6 +209,24 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { /* TODO - extend divide ratio supported by newer SoCs */ }; +static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = { + { .div = 1, .val = 1 }, + { .div = 2, .val = 2 }, + { .div = 4, .val = 3 }, + { .div = 6, .val = 4 }, + { .div = 8, .val = 5 }, + { .div = 12, .val = 6 }, + { .div = 16, .val = 7 }, + { .div = 24, .val = 8 }, + { .div = 32, .val = 9 }, + { .div = 48, .val = 10 }, + { .div = 64, .val = 11 }, + { .div = 96, .val = 12 }, + { .div = 128, .val = 13 }, + { .div = 176, .val = 14 }, + { .div = 192, .val = 15 }, +}; + static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) { return i2s->mclk_freq; @@ -223,11 +242,12 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, unsigned int sampling_rate, unsigned int word_size) { + const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers; int div = parent_rate / sampling_rate / word_size / 2; int i; - for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) { - const struct sun4i_i2s_clk_div *bdiv = &sun4i_i2s_bclk_div[i]; + for (i = 0; i < i2s->variant->num_bclk_dividers; i++) { + const struct sun4i_i2s_clk_div *bdiv = ÷rs[i]; if (bdiv->div == div) return bdiv->val; @@ -240,11 +260,12 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, unsigned long parent_rate, unsigned long mclk_rate) { + const struct sun4i_i2s_clk_div *dividers = i2s->variant->mclk_dividers; int div = parent_rate / mclk_rate; int i; - for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) { - const struct sun4i_i2s_clk_div *mdiv = &sun4i_i2s_mclk_div[i]; + for (i = 0; i < i2s->variant->num_mclk_dividers; i++) { + const struct sun4i_i2s_clk_div *mdiv = ÷rs[i]; if (mdiv->div == div) return mdiv->val; @@ -326,10 +347,6 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, return -EINVAL; } - /* Adjust the clock division values if needed */ - bclk_div += i2s->variant->bclk_offset; - mclk_div += i2s->variant->mclk_offset; - regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, SUN4I_I2S_CLK_DIV_BCLK(bclk_div) | SUN4I_I2S_CLK_DIV_MCLK(mclk_div)); @@ -969,6 +986,10 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, @@ -985,6 +1006,10 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, @@ -1001,6 +1026,10 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), + .bclk_dividers = sun8i_i2s_clk_div, + .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), + .mclk_dividers = sun8i_i2s_clk_div, + .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, @@ -1012,14 +1041,16 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, - .mclk_offset = 1, - .bclk_offset = 2, .has_fmt_set_lrck_period = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19), + .bclk_dividers = sun8i_i2s_clk_div, + .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), + .mclk_dividers = sun8i_i2s_clk_div, + .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, @@ -1036,6 +1067,10 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, -- cgit v1.2.3 From cf2c0e1ce9544df42170fb921f12da82dc0cc8d6 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:17 +0200 Subject: ASoC: sun4i-i2s: RX and TX counter registers are swapped The RX and TX counters registers offset have been swapped, fix that. Fixes: fa7c0d13cb26 ("ASoC: sunxi: Add Allwinner A10 Digital Audio driver") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/8b26477560ad5fd8f69e037b167c5e61de5c26a3.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 0a7f1d0f7371..53c95e5289f5 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -76,8 +76,8 @@ #define SUN4I_I2S_CLK_DIV_MCLK_MASK GENMASK(3, 0) #define SUN4I_I2S_CLK_DIV_MCLK(mclk) ((mclk) << 0) -#define SUN4I_I2S_RX_CNT_REG 0x28 -#define SUN4I_I2S_TX_CNT_REG 0x2c +#define SUN4I_I2S_TX_CNT_REG 0x28 +#define SUN4I_I2S_RX_CNT_REG 0x2c #define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 #define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0) -- cgit v1.2.3 From 515fcfbc773632e160f4b94e8df8d278a8d704f7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:19 +0200 Subject: ASoC: sun4i-i2s: Fix LRCK and BCLK polarity offsets on newer SoCs The LRCK and BCLK polarity offsets on newer SoCs has been changed, yet the driver didn't take it into account for all of them. This was taken into account for the H3, but not the A83t. This was handled using a reg_field for the H3. However, the value in that field will not be the same, so reg_field is not adapted in that case. Let's change for proper calls with the regular values. Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/9cbdde80a299288878e58225df4d7884e0301348.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 118 ++++++++++++++++++++++---------------------- 1 file changed, 60 insertions(+), 58 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 53c95e5289f5..e3eadfe38aaf 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -46,8 +46,6 @@ #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0) #define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0) #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0) -#define SUN4I_I2S_FMT0_POLARITY_INVERTED (1) -#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0) #define SUN4I_I2S_FMT1_REG 0x08 #define SUN4I_I2S_FIFO_TX_REG 0x0c @@ -98,8 +96,14 @@ #define SUN8I_I2S_CTRL_MODE_LEFT (1 << 4) #define SUN8I_I2S_CTRL_MODE_PCM (0 << 4) +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19) +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19) +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19) #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8) #define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8) +#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7) +#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7) +#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7) #define SUN8I_I2S_INT_STA_REG 0x0c #define SUN8I_I2S_FIFO_TX_REG 0x20 @@ -132,8 +136,6 @@ struct sun4i_i2s; * @field_clkdiv_mclk_en: regmap field to enable mclk output. * @field_fmt_wss: regmap field to set word select size. * @field_fmt_sr: regmap field to set sample resolution. - * @field_fmt_bclk: regmap field to set clk polarity. - * @field_fmt_lrclk: regmap field to set frame polarity. */ struct sun4i_i2s_quirks { bool has_reset; @@ -145,8 +147,6 @@ struct sun4i_i2s_quirks { struct reg_field field_clkdiv_mclk_en; struct reg_field field_fmt_wss; struct reg_field field_fmt_sr; - struct reg_field field_fmt_bclk; - struct reg_field field_fmt_lrclk; const struct sun4i_i2s_clk_div *bclk_dividers; unsigned int num_bclk_dividers; @@ -176,8 +176,6 @@ struct sun4i_i2s { struct regmap_field *field_clkdiv_mclk_en; struct regmap_field *field_fmt_wss; struct regmap_field *field_fmt_sr; - struct regmap_field *field_fmt_bclk; - struct regmap_field *field_fmt_lrclk; const struct sun4i_i2s_quirks *variant; }; @@ -498,6 +496,33 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, { u32 val; + /* DAI clock polarity */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + /* Invert both clocks */ + val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED | + SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_IB_NF: + /* Invert bit clock */ + val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_IF: + /* Invert frame clock */ + val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_NF: + val = 0; + break; + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK | + SUN4I_I2S_FMT0_BCLK_POLARITY_MASK, + val); + /* DAI Mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -545,6 +570,33 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, u32 mode, val; u8 offset; + /* DAI clock polarity */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + /* Invert both clocks */ + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | + SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_IB_NF: + /* Invert bit clock */ + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_IF: + /* Invert frame clock */ + val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_NF: + val = 0; + break; + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK | + SUN8I_I2S_FMT0_BCLK_POLARITY_MASK, + val); + /* DAI Mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -601,36 +653,8 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; - u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; int ret; - /* DAI clock polarity */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_IB_IF: - /* Invert both clocks */ - bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - break; - case SND_SOC_DAIFMT_IB_NF: - /* Invert bit clock */ - bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - break; - case SND_SOC_DAIFMT_NB_IF: - /* Invert frame clock */ - lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - break; - case SND_SOC_DAIFMT_NB_NF: - break; - default: - dev_err(dai->dev, "Unsupported clock polarity: %d\n", - fmt & SND_SOC_DAIFMT_INV_MASK); - return -EINVAL; - } - - regmap_field_write(i2s->field_fmt_bclk, bclk_polarity); - regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity); - ret = i2s->variant->set_fmt(i2s, fmt); if (ret) { dev_err(dai->dev, "Unsupported format configuration\n"); @@ -984,8 +1008,6 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .bclk_dividers = sun4i_i2s_bclk_div, .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), .mclk_dividers = sun4i_i2s_mclk_div, @@ -1004,8 +1026,6 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .bclk_dividers = sun4i_i2s_bclk_div, .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), .mclk_dividers = sun4i_i2s_mclk_div, @@ -1024,8 +1044,6 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .bclk_dividers = sun8i_i2s_clk_div, .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .mclk_dividers = sun8i_i2s_clk_div, @@ -1045,8 +1063,6 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19), .bclk_dividers = sun8i_i2s_clk_div, .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .mclk_dividers = sun8i_i2s_clk_div, @@ -1065,8 +1081,6 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), .bclk_dividers = sun4i_i2s_bclk_div, .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), .mclk_dividers = sun4i_i2s_mclk_div, @@ -1099,18 +1113,6 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev, if (IS_ERR(i2s->field_fmt_sr)) return PTR_ERR(i2s->field_fmt_sr); - i2s->field_fmt_bclk = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_fmt_bclk); - if (IS_ERR(i2s->field_fmt_bclk)) - return PTR_ERR(i2s->field_fmt_bclk); - - i2s->field_fmt_lrclk = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_fmt_lrclk); - if (IS_ERR(i2s->field_fmt_lrclk)) - return PTR_ERR(i2s->field_fmt_lrclk); - return 0; } -- cgit v1.2.3 From dd657eae8164f7e4bafe8b875031a7c6c50646a9 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:20 +0200 Subject: ASoC: sun4i-i2s: Fix the LRCK polarity The LRCK polarity "normal" polarity in the I2S/TDM specs and in the Allwinner datasheet are not the same. In the case where the i2s controller is being used as the LRCK master, it's pretty clear when looked at under a scope. Let's fix this, and add a comment to clear up as much the confusion as possible. Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3") Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/e03fb6b2a916223070b9f18405b0ef117a452ff4.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index e3eadfe38aaf..29b5eacd3abe 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -570,23 +570,29 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, u32 mode, val; u8 offset; - /* DAI clock polarity */ + /* + * DAI clock polarity + * + * The setup for LRCK contradicts the datasheet, but under a + * scope it's clear that the LRCK polarity is reversed + * compared to the expected polarity on the bus. + */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_IB_IF: /* Invert both clocks */ - val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | - SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; break; case SND_SOC_DAIFMT_IB_NF: /* Invert bit clock */ - val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | + SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; break; case SND_SOC_DAIFMT_NB_IF: /* Invert frame clock */ - val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + val = 0; break; case SND_SOC_DAIFMT_NB_NF: - val = 0; + val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; break; default: return -EINVAL; -- cgit v1.2.3 From 2e04fc4dbf50195262aa5a2ae6d35baa5b598cae Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:21 +0200 Subject: ASoC: sun4i-i2s: Fix WSS and SR fields for the A83t The A83t has the same bit fields offsets than the A10 and A31, while this was the first device with the new layout, fix that. Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/d93f0943cc39d880750daf459a0eeab34c63518e.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 29b5eacd3abe..59d809df8d2a 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1048,8 +1048,8 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), - .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), - .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), + .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), + .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), .bclk_dividers = sun8i_i2s_clk_div, .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), .mclk_dividers = sun8i_i2s_clk_div, -- cgit v1.2.3 From bf943d527987c38f6fb11f9515e0cf2839286eb8 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:22 +0200 Subject: ASoC: sun4i-i2s: Fix MCLK Enable bit offset on A83t The A83t, unlike previous SoCs, has the MCLK enable bit at the 8th bit of the CLK_DIV register, unlike what is declared in the driver. Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/43b07f8cd8e0e280c64ce61d57c307678c923e9b.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 59d809df8d2a..0fce3c476772 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1047,7 +1047,7 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, - .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), + .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), .bclk_dividers = sun8i_i2s_clk_div, -- cgit v1.2.3 From 69e450e50ca6dde566f3ac3f2c329fb0492441ef Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:23 +0200 Subject: ASoC: sun4i-i2s: Fix the LRCK period on A83t Unlike the previous SoCs, the A83t, like the newer ones, need the LRCK bitfield to be set. Let's add it. Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/6a0ee0bc1375bcb53840d3fb2d2f3d9732b8e57e.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 0fce3c476772..9468584f4eb0 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1047,6 +1047,7 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, + .has_fmt_set_lrck_period = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), -- cgit v1.2.3 From 3e9acd7ac6933cdc20c441bbf9a38ed9e42e1490 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:24 +0200 Subject: ASoC: sun4i-i2s: Remove duplicated quirks structure The A83t and H3 have the same quirks, so it doesn't make sense to duplicate the quirks structure. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/5ade5de27d23918c5ef30387c23aead951d5ad64.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 9468584f4eb0..4c636f1cf7dc 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1062,25 +1062,6 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .set_fmt = sun8i_i2s_set_soc_fmt, }; -static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { - .has_reset = true, - .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, - .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, - .has_fmt_set_lrck_period = true, - .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), - .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), - .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), - .bclk_dividers = sun8i_i2s_clk_div, - .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), - .mclk_dividers = sun8i_i2s_clk_div, - .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), - .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, - .get_sr = sun8i_i2s_get_sr_wss, - .get_wss = sun8i_i2s_get_sr_wss, - .set_chan_cfg = sun8i_i2s_set_chan_cfg, - .set_fmt = sun8i_i2s_set_soc_fmt, -}; - static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, @@ -1262,7 +1243,7 @@ static const struct of_device_id sun4i_i2s_match[] = { }, { .compatible = "allwinner,sun8i-h3-i2s", - .data = &sun8i_h3_i2s_quirks, + .data = &sun8i_a83t_i2s_quirks, }, { .compatible = "allwinner,sun50i-a64-codec-i2s", -- cgit v1.2.3 From 0083a507a78fdfa868acc0709408b59e72488a61 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:25 +0200 Subject: ASoC: sun4i-i2s: Pass the channels number as an argument The channels number have been hardcoded to 2 so far, while the controller supports more than that. Remove the instance where it has been hardcoded to compute the BCLK divider, and pass it through as an argument to ease further support of more channels. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/48887cf7abfaab6597db233b24d7a088a913e48a.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 4c636f1cf7dc..6b172dfbc25d 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -238,10 +238,11 @@ static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, unsigned long parent_rate, unsigned int sampling_rate, + unsigned int channels, unsigned int word_size) { const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers; - int div = parent_rate / sampling_rate / word_size / 2; + int div = parent_rate / sampling_rate / word_size / channels; int i; for (i = 0; i < i2s->variant->num_bclk_dividers; i++) { @@ -286,6 +287,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample) static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int rate, + unsigned int channels, unsigned int word_size) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -333,7 +335,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, - rate, word_size); + rate, channels, word_size); if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL; @@ -488,7 +490,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, regmap_field_write(i2s->field_fmt_sr, sr); return sun4i_i2s_set_clk_rate(dai, params_rate(params), - params_width(params)); + 2, params_width(params)); } static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, -- cgit v1.2.3 From bbf9a127abca4aac5cc75f882bc7efcc398e86ae Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:26 +0200 Subject: ASoC: sun4i-i2s: Support more channels We've been limited to 2 channels in the driver while the controller supports from 1 to 8 channels, in both capture and playback. let's remove the hardcoded checks and numbers, and extend the range of channel numbers we can use. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/27d9de5cd56f3a544851b8cd8af08bf836d19637.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 6b172dfbc25d..9e691baee1e8 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -400,9 +400,6 @@ static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, { unsigned int channels = params_channels(params); - if (channels != 2) - return -EINVAL; - /* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210); regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210); @@ -423,9 +420,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, { unsigned int channels = params_channels(params); - if (channels != 2) - return -EINVAL; - /* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210); @@ -458,6 +452,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int channels = params_channels(params); int ret, sr, wss; u32 width; @@ -490,7 +485,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, regmap_field_write(i2s->field_fmt_sr, sr); return sun4i_i2s_set_clk_rate(dai, params_rate(params), - 2, params_width(params)); + channels, params_width(params)); } static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, @@ -814,15 +809,15 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = { .probe = sun4i_i2s_dai_probe, .capture = { .stream_name = "Capture", - .channels_min = 2, - .channels_max = 2, + .channels_min = 1, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .playback = { .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, + .channels_min = 1, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, -- cgit v1.2.3 From 988b59467b2b14523a266957affbe9eca3e99fc9 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Tue, 20 Aug 2019 19:24:09 +0300 Subject: ASoC: mchp-i2s-mcc: Fix unprepare of GCLK If hw_free() gets called after hw_params(), GCLK remains prepared, preventing further use of it. This patch fixes this by unpreparing the clock in hw_free() or if hw_params() gets an error. Fixes: 7e0cdf545a55 ("ASoC: mchp-i2s-mcc: add driver for I2SC Multi-Channel Controller") Signed-off-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20190820162411.24836-2-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- sound/soc/atmel/mchp-i2s-mcc.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 86495883ca3f..319f975586f1 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -670,8 +670,13 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, } ret = regmap_write(dev->regmap, MCHP_I2SMCC_MRA, mra); - if (ret < 0) + if (ret < 0) { + if (dev->gclk_use) { + clk_unprepare(dev->gclk); + dev->gclk_use = 0; + } return ret; + } return regmap_write(dev->regmap, MCHP_I2SMCC_MRB, mrb); } @@ -708,9 +713,13 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream, regmap_write(dev->regmap, MCHP_I2SMCC_CR, MCHP_I2SMCC_CR_CKDIS); if (dev->gclk_running) { - clk_disable_unprepare(dev->gclk); + clk_disable(dev->gclk); dev->gclk_running = 0; } + if (dev->gclk_use) { + clk_unprepare(dev->gclk); + dev->gclk_use = 0; + } } return 0; -- cgit v1.2.3 From 0f6fc97501b790c971b11b52a654009d21c45238 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Tue, 20 Aug 2019 19:24:10 +0300 Subject: ASoC: mchp-i2s-mcc: Wait for RX/TX RDY only if controller is running Since hw_free() can be called multiple times and not just after a stop trigger command, we should check whether the RX or TX ready interrupt was truly enabled previously. For this, we assure that the condition of the wait event is always true, except when RX/TX interrupts are enabled. Fixes: 7e0cdf545a55 ("ASoC: mchp-i2s-mcc: add driver for I2SC Multi-Channel Controller") Signed-off-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20190820162411.24836-3-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- sound/soc/atmel/mchp-i2s-mcc.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 319f975586f1..ab7d5f98e759 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -691,22 +691,24 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream, err = wait_event_interruptible_timeout(dev->wq_txrdy, dev->tx_rdy, msecs_to_jiffies(500)); + if (err == 0) { + dev_warn_once(dev->dev, + "Timeout waiting for Tx ready\n"); + regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, + MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)); + dev->tx_rdy = 1; + } } else { err = wait_event_interruptible_timeout(dev->wq_rxrdy, dev->rx_rdy, msecs_to_jiffies(500)); - } - - if (err == 0) { - u32 idra; - - dev_warn_once(dev->dev, "Timeout waiting for %s\n", - is_playback ? "Tx ready" : "Rx ready"); - if (is_playback) - idra = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels); - else - idra = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels); - regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra); + if (err == 0) { + dev_warn_once(dev->dev, + "Timeout waiting for Rx ready\n"); + regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, + MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); + dev->rx_rdy = 1; + } } if (!mchp_i2s_mcc_is_running(dev)) { @@ -818,6 +820,8 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) init_waitqueue_head(&dev->wq_txrdy); init_waitqueue_head(&dev->wq_rxrdy); + dev->tx_rdy = 1; + dev->rx_rdy = 1; snd_soc_dai_init_dma_data(dai, &dev->playback, &dev->capture); -- cgit v1.2.3 From c9cff337eab394c4dc8b128dde7308a1dd2e653a Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Tue, 20 Aug 2019 19:24:11 +0300 Subject: ASoC: mchp-i2s-mcc: Fix simultaneous capture and playback in master mode This controller supports capture and playback running at the same time, with the limitation that both capture and playback must be configured the same way (sample rate, sample format, number of channels, etc). For this, we have to assure that the configuration registers look the same when capture and playback are initiated. This patch fixes a bug in which the controller is in master mode and the hw_params() callback fails for the second audio stream. The fail occurs because the divisors are calculated after comparing the configuration registers for capture and playback. The fix consists in calculating the divisors before comparing the configuration registers. BCLK and LRC are then configured and started only if the controller is not already running. Fixes: 7e0cdf545a55 ("ASoC: mchp-i2s-mcc: add driver for I2SC Multi-Channel Controller") Signed-off-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20190820162411.24836-4-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- sound/soc/atmel/mchp-i2s-mcc.c | 70 ++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 86495883ca3f..9a406144b18f 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -392,11 +392,11 @@ static int mchp_i2s_mcc_clk_get_rate_diff(struct clk *clk, } static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev, - unsigned int bclk, unsigned int *mra) + unsigned int bclk, unsigned int *mra, + unsigned long *best_rate) { unsigned long clk_rate; unsigned long lcm_rate; - unsigned long best_rate = 0; unsigned long best_diff_rate = ~0; unsigned int sysclk; struct clk *best_clk = NULL; @@ -423,7 +423,7 @@ static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev, (clk_rate == bclk || clk_rate / (bclk * 2) <= GENMASK(5, 0)); clk_rate += lcm_rate) { ret = mchp_i2s_mcc_clk_get_rate_diff(dev->gclk, clk_rate, - &best_clk, &best_rate, + &best_clk, best_rate, &best_diff_rate); if (ret) { dev_err(dev->dev, "gclk error for rate %lu: %d", @@ -437,7 +437,7 @@ static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev, } ret = mchp_i2s_mcc_clk_get_rate_diff(dev->pclk, clk_rate, - &best_clk, &best_rate, + &best_clk, best_rate, &best_diff_rate); if (ret) { dev_err(dev->dev, "pclk error for rate %lu: %d", @@ -459,33 +459,17 @@ static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev, dev_dbg(dev->dev, "source CLK is %s with rate %lu, diff %lu\n", best_clk == dev->pclk ? "pclk" : "gclk", - best_rate, best_diff_rate); - - /* set the rate */ - ret = clk_set_rate(best_clk, best_rate); - if (ret) { - dev_err(dev->dev, "unable to set rate %lu to %s: %d\n", - best_rate, best_clk == dev->pclk ? "PCLK" : "GCLK", - ret); - return ret; - } + *best_rate, best_diff_rate); /* Configure divisors */ if (dev->sysclk) - *mra |= MCHP_I2SMCC_MRA_IMCKDIV(best_rate / (2 * sysclk)); - *mra |= MCHP_I2SMCC_MRA_ISCKDIV(best_rate / (2 * bclk)); + *mra |= MCHP_I2SMCC_MRA_IMCKDIV(*best_rate / (2 * sysclk)); + *mra |= MCHP_I2SMCC_MRA_ISCKDIV(*best_rate / (2 * bclk)); - if (best_clk == dev->gclk) { + if (best_clk == dev->gclk) *mra |= MCHP_I2SMCC_MRA_SRCCLK_GCLK; - ret = clk_prepare(dev->gclk); - if (ret < 0) - dev_err(dev->dev, "unable to prepare GCLK: %d\n", ret); - else - dev->gclk_use = 1; - } else { + else *mra |= MCHP_I2SMCC_MRA_SRCCLK_PCLK; - dev->gclk_use = 0; - } return 0; } @@ -502,6 +486,7 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + unsigned long rate = 0; struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); u32 mra = 0; u32 mrb = 0; @@ -640,6 +625,17 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + if (set_divs) { + bclk_rate = frame_length * params_rate(params); + ret = mchp_i2s_mcc_config_divs(dev, bclk_rate, &mra, + &rate); + if (ret) { + dev_err(dev->dev, + "unable to configure the divisors: %d\n", ret); + return ret; + } + } + /* * If we are already running, the wanted setup must be * the same with the one that's currently ongoing @@ -656,19 +652,27 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, return 0; } - /* Save the number of channels to know what interrupts to enable */ - dev->channels = channels; - - if (set_divs) { - bclk_rate = frame_length * params_rate(params); - ret = mchp_i2s_mcc_config_divs(dev, bclk_rate, &mra); + if (mra & MCHP_I2SMCC_MRA_SRCCLK_GCLK && !dev->gclk_use) { + /* set the rate */ + ret = clk_set_rate(dev->gclk, rate); if (ret) { - dev_err(dev->dev, "unable to configure the divisors: %d\n", - ret); + dev_err(dev->dev, + "unable to set rate %lu to GCLK: %d\n", + rate, ret); + return ret; + } + + ret = clk_prepare(dev->gclk); + if (ret < 0) { + dev_err(dev->dev, "unable to prepare GCLK: %d\n", ret); return ret; } + dev->gclk_use = 1; } + /* Save the number of channels to know what interrupts to enable */ + dev->channels = channels; + ret = regmap_write(dev->regmap, MCHP_I2SMCC_MRA, mra); if (ret < 0) return ret; -- cgit v1.2.3 From 6eeb60be5ebb73b2e5911e26fb1aed02940b7d09 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 14 Aug 2019 11:29:10 +0300 Subject: ASoC: fsl_sai: Add support for imx8qm SAI module on imx8qm features a register map similar with imx6 series (it doesn't have VERID and PARAM registers at the beginning of address spece). Also, it has one FIFO which can help up to 64 * 32 bit samples. Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20190814082911.665-2-daniel.baluta@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 4a346fcb5630..728307acab90 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1031,12 +1031,19 @@ static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = { .reg_offset = 8, }; +static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = { + .use_imx_pcm = true, + .fifo_depth = 64, + .reg_offset = 0, +}; + static const struct of_device_id fsl_sai_ids[] = { { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data }, { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data }, { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6sx_data }, { .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 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_sai_ids); -- cgit v1.2.3 From b03bfaec1d52123d5d941488f71e06964535e471 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 20 Aug 2019 14:04:54 +0900 Subject: ASoC: soc-core: merge snd_soc_initialize_card_lists() snd_soc_initialize_card_lists() is doing card related INIT_LIST_HEAD(), but, it is already doing at snd_soc_register_card(). We don't need to do it separately. This patch merges these. Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/877e781ldq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 10 ---------- sound/soc/soc-core.c | 13 ++++++++----- 2 files changed, 8 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 5c841c2ee814..f264c6509f00 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1220,16 +1220,6 @@ static inline void *snd_soc_card_get_drvdata(struct snd_soc_card *card) return card->drvdata; } -static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) -{ - INIT_LIST_HEAD(&card->widgets); - INIT_LIST_HEAD(&card->paths); - INIT_LIST_HEAD(&card->dapm_list); - INIT_LIST_HEAD(&card->aux_comp_list); - INIT_LIST_HEAD(&card->component_dev_list); - INIT_LIST_HEAD(&card->list); -} - static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) { if (mc->reg == mc->rreg && mc->shift == mc->rshift) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b3f820fb53e6..d428491d51a7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2370,15 +2370,18 @@ int snd_soc_register_card(struct snd_soc_card *card) dev_set_drvdata(card->dev, card); - snd_soc_initialize_card_lists(card); - + INIT_LIST_HEAD(&card->widgets); + INIT_LIST_HEAD(&card->paths); + INIT_LIST_HEAD(&card->dapm_list); + INIT_LIST_HEAD(&card->aux_comp_list); + INIT_LIST_HEAD(&card->component_dev_list); + INIT_LIST_HEAD(&card->list); INIT_LIST_HEAD(&card->dai_link_list); - INIT_LIST_HEAD(&card->rtd_list); - card->num_rtd = 0; - INIT_LIST_HEAD(&card->dapm_dirty); INIT_LIST_HEAD(&card->dobj_list); + + card->num_rtd = 0; card->instantiated = 0; mutex_init(&card->mutex); mutex_init(&card->dapm_mutex); -- cgit v1.2.3 From c26a8841119826badc8d358a4266880f83359f26 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 20 Aug 2019 14:04:58 +0900 Subject: ASoC: soc-core: remove unneeded dai_link check from snd_soc_remove_dai_link() snd_soc_remove_dai_link() has card connected dai_link check. but 1) we need to call list_del() anyway, because it is "remove" function, 2) It is doing many thing for this card / dai_link already before checking dai_link. This patch removes poinless dai_link check Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/875zms1ldm.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d428491d51a7..6df880be1622 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1182,8 +1182,6 @@ EXPORT_SYMBOL_GPL(snd_soc_add_dai_link); void snd_soc_remove_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - struct snd_soc_dai_link *link, *_link; - if (dai_link->dobj.type && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { dev_err(card->dev, "Invalid dai link type %d\n", @@ -1199,12 +1197,7 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, if (dai_link->dobj.type && card->remove_dai_link) card->remove_dai_link(card, dai_link); - for_each_card_links_safe(card, link, _link) { - if (link == dai_link) { - list_del(&link->list); - return; - } - } + list_del(&dai_link->list); } EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); -- cgit v1.2.3 From 137befe19f310400a8b20fd8a4ce8c4141aafde0 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:27 +0200 Subject: ASoC: sun4i-i2s: Add support for TDM slots The i2s controller supports TDM, for up to 8 slots. Let's support the TDM API. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/26392af30b3e7b31ee48d5b867d45be8675db046.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 9e691baee1e8..8326b8cfa569 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -168,6 +168,8 @@ struct sun4i_i2s { struct reset_control *rst; unsigned int mclk_freq; + unsigned int slots; + unsigned int slot_width; struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; @@ -287,7 +289,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample) static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int rate, - unsigned int channels, + unsigned int slots, unsigned int word_size) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -335,7 +337,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, - rate, channels, word_size); + rate, slots, word_size); if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL; @@ -419,6 +421,10 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, const struct snd_pcm_hw_params *params) { unsigned int channels = params_channels(params); + unsigned int slots = channels; + + if (i2s->slots) + slots = i2s->slots; /* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); @@ -428,7 +434,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels)); - regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, SUN4I_I2S_CHAN_SEL_MASK, SUN4I_I2S_CHAN_SEL(channels)); @@ -452,10 +457,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int word_size = params_width(params); unsigned int channels = params_channels(params); + unsigned int slots = channels; int ret, sr, wss; u32 width; + if (i2s->slots) + slots = i2s->slots; + + if (i2s->slot_width) + word_size = i2s->slot_width; + ret = i2s->variant->set_chan_cfg(i2s, params); if (ret < 0) { dev_err(dai->dev, "Invalid channel configuration\n"); @@ -477,15 +490,14 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, if (sr < 0) return -EINVAL; - wss = i2s->variant->get_wss(i2s, params_width(params)); + wss = i2s->variant->get_wss(i2s, word_size); if (wss < 0) return -EINVAL; regmap_field_write(i2s->field_fmt_wss, wss); regmap_field_write(i2s->field_fmt_sr, sr); - return sun4i_i2s_set_clk_rate(dai, params_rate(params), - channels, params_width(params)); + return sun4i_i2s_set_clk_rate(dai, params_rate(params), slots, word_size); } static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, @@ -785,10 +797,26 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, return 0; } +static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + + if (slots > 8) + return -EINVAL; + + i2s->slots = slots; + i2s->slot_width = slot_width; + + return 0; +} + static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { .hw_params = sun4i_i2s_hw_params, .set_fmt = sun4i_i2s_set_fmt, .set_sysclk = sun4i_i2s_set_sysclk, + .set_tdm_slot = sun4i_i2s_set_tdm_slot, .trigger = sun4i_i2s_trigger, }; -- cgit v1.2.3 From 5389f4765789e4ecf9831bc968562befdd2f3bee Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 21 Aug 2019 15:06:53 +0200 Subject: ASoC: sun4i-i2s: Use the physical / slot width for the clocks The clock dividers function has been using the word size to compute the clock rate at which it's supposed to be running, but the proper formula would be to use the physical width and / or slot width in TDM. It doesn't make any difference at the moment since all the formats supported have the same sample width and physical width, but it's not going to last forever. Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/41a359d9885f397e066816961e5e3236afcbe0a1.1566392800.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 8326b8cfa569..cdc3fa60ff33 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -290,7 +290,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample) static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int rate, unsigned int slots, - unsigned int word_size) + unsigned int slot_width) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); unsigned int oversample_rate, clk_rate, bclk_parent_rate; @@ -337,7 +337,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, - rate, slots, word_size); + rate, slots, slot_width); if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL; @@ -458,6 +458,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); unsigned int word_size = params_width(params); + unsigned int slot_width = params_physical_width(params); unsigned int channels = params_channels(params); unsigned int slots = channels; int ret, sr, wss; @@ -467,7 +468,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, slots = i2s->slots; if (i2s->slot_width) - word_size = i2s->slot_width; + slot_width = i2s->slot_width; ret = i2s->variant->set_chan_cfg(i2s, params); if (ret < 0) { @@ -490,14 +491,15 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, if (sr < 0) return -EINVAL; - wss = i2s->variant->get_wss(i2s, word_size); + wss = i2s->variant->get_wss(i2s, slot_width); if (wss < 0) return -EINVAL; regmap_field_write(i2s->field_fmt_wss, wss); regmap_field_write(i2s->field_fmt_sr, sr); - return sun4i_i2s_set_clk_rate(dai, params_rate(params), slots, word_size); + return sun4i_i2s_set_clk_rate(dai, params_rate(params), + slots, slot_width); } static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, -- cgit v1.2.3 From 9e8a93ac27d101e0ace024196a4bc3386568cc00 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 21 Aug 2019 15:06:54 +0200 Subject: ASoC: sun4i-i2s: Use the actual format width instead of an hardcoded one The LRCK period field in the FMT0 register holds the number of LRCK period for one channel in I2S mode. This has been hardcoded to 32, while it really should be the physical width of the format, which creates an improper clock when using a 16bit format, with the i2s controller as LRCK master. Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/f08a0c3605cd1d79752b38d704690190183f7865.1566392800.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index cdc3fa60ff33..9ef784b8867c 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -359,7 +359,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, if (i2s->variant->has_fmt_set_lrck_period) regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, - SUN8I_I2S_FMT0_LRCK_PERIOD(32)); + SUN8I_I2S_FMT0_LRCK_PERIOD(slot_width)); return 0; } -- cgit v1.2.3 From 84884c7ad5e8794aa19e48eaa8de93f4e1d26af9 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 21 Aug 2019 15:06:55 +0200 Subject: ASoC: sun4i-i2s: Replace call to params_width by local variable The sun4i_i2s_hw_params function already has a variable holding the value returned by params_width, so let's just use that variable instead of calling params_width multiple times. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/f85a1c1e014080a4bbc3abd19bc8fdcb86f0981a.1566392800.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 9ef784b8867c..69162af9fd65 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -487,7 +487,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, } i2s->playback_dma_data.addr_width = width; - sr = i2s->variant->get_sr(i2s, params_width(params)); + sr = i2s->variant->get_sr(i2s, word_size); if (sr < 0) return -EINVAL; -- cgit v1.2.3 From 7ae7834ec446e5f7fed9bb990d16354853a206d0 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 21 Aug 2019 15:06:56 +0200 Subject: ASoC: sun4i-i2s: Add support for DSP formats In addition to the I2S format, the controller also supports the DSP_* formats. This requires some extra care on the LRCK period calculation, since the controller, with the PCM formats, require that the value set is no longer the periods of LRCK for a single channel, but for all of them. Let's add the code to deal with this, and support the DSP_A and DSP_B formats. Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/5562db1ac8759f12b1b87c3258223eed629ef771.1566392800.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 69162af9fd65..57bf2a33753e 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -130,7 +130,6 @@ struct sun4i_i2s; * struct sun4i_i2s_quirks - Differences between SoC variants. * * @has_reset: SoC needs reset deasserted. - * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. * @field_clkdiv_mclk_en: regmap field to enable mclk output. @@ -139,7 +138,6 @@ struct sun4i_i2s; */ struct sun4i_i2s_quirks { bool has_reset; - bool has_fmt_set_lrck_period; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; @@ -167,6 +165,7 @@ struct sun4i_i2s { struct regmap *regmap; struct reset_control *rst; + unsigned int format; unsigned int mclk_freq; unsigned int slots; unsigned int slot_width; @@ -355,12 +354,6 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, regmap_field_write(i2s->field_clkdiv_mclk_en, 1); - /* Set sync period */ - if (i2s->variant->has_fmt_set_lrck_period) - regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, - SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, - SUN8I_I2S_FMT0_LRCK_PERIOD(slot_width)); - return 0; } @@ -422,6 +415,7 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, { unsigned int channels = params_channels(params); unsigned int slots = channels; + unsigned int lrck_period; if (i2s->slots) slots = i2s->slots; @@ -445,6 +439,26 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); + switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + lrck_period = params_physical_width(params) * slots; + break; + + case SND_SOC_DAIFMT_I2S: + lrck_period = params_physical_width(params); + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, + SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, SUN8I_I2S_TX_CHAN_EN_MASK, SUN8I_I2S_TX_CHAN_EN(channels)); @@ -616,6 +630,16 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, /* DAI Mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + mode = SUN8I_I2S_CTRL_MODE_PCM; + offset = 1; + break; + + case SND_SOC_DAIFMT_DSP_B: + mode = SUN8I_I2S_CTRL_MODE_PCM; + offset = 0; + break; + case SND_SOC_DAIFMT_I2S: mode = SUN8I_I2S_CTRL_MODE_LEFT; offset = 1; @@ -684,6 +708,9 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK, SUN4I_I2S_FIFO_CTRL_TX_MODE(1) | SUN4I_I2S_FIFO_CTRL_RX_MODE(1)); + + i2s->format = fmt; + return 0; } @@ -1074,7 +1101,6 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, - .has_fmt_set_lrck_period = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), -- cgit v1.2.3 From 2722b535337b35a9c0be50de687cccda4ab9468d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Aug 2019 09:55:37 +0200 Subject: ALSA: hda/realtek - Check beep whitelist before assigning in all codecs Some Realtek codec parsers didn't check the availability of PC beep. Add has_cdefine_beep() check appropriately. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b6ae452a1d8f..19831521bd95 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2848,7 +2848,8 @@ static int patch_alc268(struct hda_codec *codec) return err; spec = codec->spec; - spec->gen.beep_nid = 0x01; + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x01; spec->shutup = alc_eapd_shutup; @@ -8102,7 +8103,8 @@ static int patch_alc861(struct hda_codec *codec) return err; spec = codec->spec; - spec->gen.beep_nid = 0x23; + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x23; #ifdef CONFIG_PM spec->power_hook = alc_power_eapd; @@ -8203,7 +8205,8 @@ static int patch_alc861vd(struct hda_codec *codec) return err; spec = codec->spec; - spec->gen.beep_nid = 0x23; + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x23; spec->shutup = alc_eapd_shutup; -- cgit v1.2.3 From 051c78af14fcd74a22b5af45548ad9d588247cc7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Aug 2019 09:58:07 +0200 Subject: ALSA: hda/realtek - Blacklist PC beep for Lenovo ThinkCentre M73/93 Lenovo ThinkCentre M73 and M93 don't seem to have a proper beep although the driver tries to probe and set up blindly. Blacklist these machines for suppressing the beep creation. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=204635 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 19831521bd95..0585484a469a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1065,6 +1065,9 @@ static const struct snd_pci_quirk beep_white_list[] = { SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1), SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), + /* blacklist -- no beep available */ + SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0), + SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0), {} }; -- cgit v1.2.3 From 57f8770620e9b51c61089751f0b5ad3dbe376ff2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Aug 2019 17:17:09 +0200 Subject: ALSA: usb-audio: More validations of descriptor units Introduce a new helper to validate each audio descriptor unit before and check the unit before actually accessing it. This should harden against the OOB access cases with malformed descriptors that have been recently frequently reported by fuzzers. The existing descriptor checks are still kept although they become superfluous after this patch. They'll be cleaned up eventually later. Signed-off-by: Takashi Iwai --- sound/usb/Makefile | 3 +- sound/usb/helper.h | 4 + sound/usb/mixer.c | 10 ++ sound/usb/power.c | 2 + sound/usb/quirks.c | 3 + sound/usb/stream.c | 25 ++-- sound/usb/validate.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 366 insertions(+), 13 deletions(-) create mode 100644 sound/usb/validate.c (limited to 'sound') diff --git a/sound/usb/Makefile b/sound/usb/Makefile index e1ce257ab705..d27a21b0ff9c 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -16,7 +16,8 @@ snd-usb-audio-objs := card.o \ power.o \ proc.o \ quirks.o \ - stream.o + stream.o \ + validate.o snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o diff --git a/sound/usb/helper.h b/sound/usb/helper.h index 6afb70156ec4..5e8a18b4e7b9 100644 --- a/sound/usb/helper.h +++ b/sound/usb/helper.h @@ -31,4 +31,8 @@ static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip) return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber; } +/* in validate.c */ +bool snd_usb_validate_audio_desc(void *p, int protocol); +bool snd_usb_validate_midi_desc(void *p); + #endif /* __USBAUDIO_HELPER_H */ diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index eceab19766db..a1093fb9bf09 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -785,6 +785,8 @@ static int __check_input_term(struct mixer_build *state, int id, p1 = find_audio_control_unit(state, id); if (!p1) break; + if (!snd_usb_validate_audio_desc(p1, protocol)) + break; /* bad descriptor */ hdr = p1; term->id = id; @@ -2775,6 +2777,11 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) return -EINVAL; } + if (!snd_usb_validate_audio_desc(p1, protocol)) { + usb_audio_dbg(state->chip, "invalid unit %d\n", unitid); + return 0; /* skip invalid unit */ + } + if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { switch (p1[2]) { case UAC_INPUT_TERMINAL: @@ -3145,6 +3152,9 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, mixer->hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) { + if (!snd_usb_validate_audio_desc(p, mixer->protocol)) + continue; /* skip invalid descriptor */ + if (mixer->protocol == UAC_VERSION_1) { struct uac1_output_terminal_descriptor *desc = p; diff --git a/sound/usb/power.c b/sound/usb/power.c index bd303a1ba1b7..606a2cb23eab 100644 --- a/sound/usb/power.c +++ b/sound/usb/power.c @@ -31,6 +31,8 @@ snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface, struct uac3_power_domain_descriptor *pd_desc = p; int i; + if (!snd_usb_validate_audio_desc(p, UAC_VERSION_3)) + continue; for (i = 0; i < pd_desc->bNrEntities; i++) { if (pd_desc->baEntityID[i] == id) { pd->pd_id = pd_desc->bPowerDomainID; diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 78858918cbc1..7e9735aa7ac9 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -248,6 +248,9 @@ static int create_yamaha_midi_quirk(struct snd_usb_audio *chip, NULL, USB_MS_MIDI_OUT_JACK); if (!injd && !outjd) return -ENODEV; + if (!snd_usb_validate_midi_desc(injd) || + !snd_usb_validate_midi_desc(outjd)) + return -ENODEV; if (injd && (injd->bLength < 5 || (injd->bJackType != USB_MS_EMBEDDED && injd->bJackType != USB_MS_EXTERNAL))) diff --git a/sound/usb/stream.c b/sound/usb/stream.c index e852c7fd6109..a0649c8ae460 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -627,16 +627,14 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, */ static void * snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, - int terminal_id, bool uac23) + int terminal_id, int protocol) { struct uac2_input_terminal_descriptor *term = NULL; - size_t minlen = uac23 ? sizeof(struct uac2_input_terminal_descriptor) : - sizeof(struct uac_input_terminal_descriptor); while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, ctrl_iface->extralen, term, UAC_INPUT_TERMINAL))) { - if (term->bLength < minlen) + if (!snd_usb_validate_audio_desc(term, protocol)) continue; if (term->bTerminalID == terminal_id) return term; @@ -647,7 +645,7 @@ snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, static void * snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, - int terminal_id) + int terminal_id, int protocol) { /* OK to use with both UAC2 and UAC3 */ struct uac2_output_terminal_descriptor *term = NULL; @@ -655,8 +653,9 @@ snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, ctrl_iface->extralen, term, UAC_OUTPUT_TERMINAL))) { - if (term->bLength >= sizeof(*term) && - term->bTerminalID == terminal_id) + if (!snd_usb_validate_audio_desc(term, protocol)) + continue; + if (term->bTerminalID == terminal_id) return term; } @@ -731,7 +730,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, as->bTerminalLink, - false); + protocol); if (iterm) { num_channels = iterm->bNrChannels; chconfig = le16_to_cpu(iterm->wChannelConfig); @@ -767,7 +766,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, */ input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, as->bTerminalLink, - true); + protocol); if (input_term) { clock = input_term->bCSourceID; if (!chconfig && (num_channels == input_term->bNrChannels)) @@ -776,7 +775,8 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, } output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); + as->bTerminalLink, + protocol); if (output_term) { clock = output_term->bCSourceID; goto found_clock; @@ -1002,14 +1002,15 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, */ input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, as->bTerminalLink, - true); + UAC_VERSION_3); if (input_term) { clock = input_term->bCSourceID; goto found_clock; } output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); + as->bTerminalLink, + UAC_VERSION_3); if (output_term) { clock = output_term->bCSourceID; goto found_clock; diff --git a/sound/usb/validate.c b/sound/usb/validate.c new file mode 100644 index 000000000000..3c8f73a0eb12 --- /dev/null +++ b/sound/usb/validate.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Validation of USB-audio class descriptors +// + +#include +#include +#include +#include +#include +#include +#include "usbaudio.h" +#include "helper.h" + +struct usb_desc_validator { + unsigned char protocol; + unsigned char type; + bool (*func)(const void *p, const struct usb_desc_validator *v); + size_t size; +}; + +#define UAC_VERSION_ALL (unsigned char)(-1) + +/* UAC1 only */ +static bool validate_uac1_header(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac1_ac_header_descriptor *d = p; + + return d->bLength >= sizeof(*d) && + d->bLength >= sizeof(*d) + d->bInCollection; +} + +/* for mixer unit; covering all UACs */ +static bool validate_mixer_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac_mixer_unit_descriptor *d = p; + size_t len; + + if (d->bLength < sizeof(*d) || !d->bNrInPins) + return false; + len = sizeof(*d) + d->bNrInPins; + /* We can't determine the bitmap size only from this unit descriptor, + * so just check with the remaining length. + * The actual bitmap is checked at mixer unit parser. + */ + switch (v->protocol) { + case UAC_VERSION_1: + default: + len += 2 + 1; /* wChannelConfig, iChannelNames */ + /* bmControls[n*m] */ + len += 1; /* iMixer */ + break; + case UAC_VERSION_2: + len += 4 + 1; /* bmChannelConfig, iChannelNames */ + /* bmMixerControls[n*m] */ + len += 1 + 1; /* bmControls, iMixer */ + break; + case UAC_VERSION_3: + len += 2; /* wClusterDescrID */ + /* bmMixerControls[n*m] */ + break; + } + return d->bLength >= len; +} + +/* both for processing and extension units; covering all UACs */ +static bool validate_processing_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac_processing_unit_descriptor *d = p; + const unsigned char *hdr = p; + size_t len, m; + + if (d->bLength < sizeof(*d)) + return false; + len = d->bLength < sizeof(*d) + d->bNrInPins; + if (d->bLength < len) + return false; + switch (v->protocol) { + case UAC_VERSION_1: + default: + /* bNrChannels, wChannelConfig, iChannelNames, bControlSize */ + len += 1 + 2 + 1 + 1; + if (d->bLength < len) /* bControlSize */ + return false; + m = hdr[len]; + len += 1 + m + 1; /* bControlSize, bmControls, iProcessing */ + break; + case UAC_VERSION_2: + /* bNrChannels, bmChannelConfig, iChannelNames */ + len += 1 + 4 + 1; + if (v->type == UAC2_PROCESSING_UNIT_V2) + len += 2; /* bmControls -- 2 bytes for PU */ + else + len += 1; /* bmControls -- 1 byte for EU */ + len += 1; /* iProcessing */ + break; + case UAC_VERSION_3: + /* wProcessingDescrStr, bmControls */ + len += 2 + 4; + break; + } + if (d->bLength < len) + return false; + + switch (v->protocol) { + case UAC_VERSION_1: + default: + if (v->type == UAC1_EXTENSION_UNIT) + return true; /* OK */ + switch (d->wProcessType) { + case UAC_PROCESS_UP_DOWNMIX: + case UAC_PROCESS_DOLBY_PROLOGIC: + if (d->bLength < len + 1) /* bNrModes */ + return false; + m = hdr[len]; + len += 1 + m * 2; /* bNrModes, waModes(n) */ + break; + default: + break; + } + break; + case UAC_VERSION_2: + if (v->type == UAC2_EXTENSION_UNIT_V2) + return true; /* OK */ + switch (d->wProcessType) { + case UAC2_PROCESS_UP_DOWNMIX: + case UAC2_PROCESS_DOLBY_PROLOCIC: /* SiC! */ + if (d->bLength < len + 1) /* bNrModes */ + return false; + m = hdr[len]; + len += 1 + m * 4; /* bNrModes, daModes(n) */ + break; + default: + break; + } + break; + case UAC_VERSION_3: + if (v->type == UAC3_EXTENSION_UNIT) { + len += 2; /* wClusterDescrID */ + break; + } + switch (d->wProcessType) { + case UAC3_PROCESS_UP_DOWNMIX: + if (d->bLength < len + 1) /* bNrModes */ + return false; + m = hdr[len]; + len += 1 + m * 2; /* bNrModes, waClusterDescrID(n) */ + break; + case UAC3_PROCESS_MULTI_FUNCTION: + len += 2 + 4; /* wClusterDescrID, bmAlgorighms */ + break; + default: + break; + } + break; + } + if (d->bLength < len) + return false; + + return true; +} + +/* both for selector and clock selector units; covering all UACs */ +static bool validate_selector_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac_selector_unit_descriptor *d = p; + size_t len; + + if (d->bLength < sizeof(*d)) + return false; + len = sizeof(*d) + d->bNrInPins; + switch (v->protocol) { + case UAC_VERSION_1: + default: + len += 1; /* iSelector */ + break; + case UAC_VERSION_2: + len += 1 + 1; /* bmControls, iSelector */ + break; + case UAC_VERSION_3: + len += 4 + 2; /* bmControls, wSelectorDescrStr */ + break; + } + return d->bLength >= len; +} + +static bool validate_uac1_feature_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac_feature_unit_descriptor *d = p; + + if (d->bLength < sizeof(*d) || !d->bControlSize) + return false; + /* at least bmaControls(0) for master channel + iFeature */ + return d->bLength >= sizeof(*d) + d->bControlSize + 1; +} + +static bool validate_uac2_feature_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac2_feature_unit_descriptor *d = p; + + if (d->bLength < sizeof(*d)) + return false; + /* at least bmaControls(0) for master channel + iFeature */ + return d->bLength >= sizeof(*d) + 4 + 1; +} + +static bool validate_uac3_feature_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac3_feature_unit_descriptor *d = p; + + if (d->bLength < sizeof(*d)) + return false; + /* at least bmaControls(0) for master channel + wFeatureDescrStr */ + return d->bLength >= sizeof(*d) + 4 + 2; +} + +static bool validate_midi_out_jack(const void *p, + const struct usb_desc_validator *v) +{ + const struct usb_midi_out_jack_descriptor *d = p; + + return d->bLength >= sizeof(*d) && + d->bLength >= sizeof(*d) + d->bNrInputPins * 2; +} + +#define FIXED(p, t, s) { .protocol = (p), .type = (t), .size = sizeof(s) } +#define FUNC(p, t, f) { .protocol = (p), .type = (t), .func = (f) } + +static struct usb_desc_validator audio_validators[] = { + /* UAC1 */ + FUNC(UAC_VERSION_1, UAC_HEADER, validate_uac1_header), + FIXED(UAC_VERSION_1, UAC_INPUT_TERMINAL, + struct uac_input_terminal_descriptor), + FIXED(UAC_VERSION_1, UAC_OUTPUT_TERMINAL, + struct uac1_output_terminal_descriptor), + FUNC(UAC_VERSION_1, UAC_MIXER_UNIT, validate_mixer_unit), + FUNC(UAC_VERSION_1, UAC_SELECTOR_UNIT, validate_selector_unit), + FUNC(UAC_VERSION_1, UAC_FEATURE_UNIT, validate_uac1_feature_unit), + FUNC(UAC_VERSION_1, UAC1_PROCESSING_UNIT, validate_processing_unit), + FUNC(UAC_VERSION_1, UAC1_EXTENSION_UNIT, validate_processing_unit), + + /* UAC2 */ + FIXED(UAC_VERSION_2, UAC_HEADER, struct uac2_ac_header_descriptor), + FIXED(UAC_VERSION_2, UAC_INPUT_TERMINAL, + struct uac2_input_terminal_descriptor), + FIXED(UAC_VERSION_2, UAC_OUTPUT_TERMINAL, + struct uac2_output_terminal_descriptor), + FUNC(UAC_VERSION_2, UAC_MIXER_UNIT, validate_mixer_unit), + FUNC(UAC_VERSION_2, UAC_SELECTOR_UNIT, validate_selector_unit), + FUNC(UAC_VERSION_2, UAC_FEATURE_UNIT, validate_uac2_feature_unit), + /* UAC_VERSION_2, UAC2_EFFECT_UNIT: not implemented yet */ + FUNC(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2, validate_processing_unit), + FUNC(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2, validate_processing_unit), + FIXED(UAC_VERSION_2, UAC2_CLOCK_SOURCE, + struct uac_clock_source_descriptor), + FUNC(UAC_VERSION_2, UAC2_CLOCK_SELECTOR, validate_selector_unit), + FIXED(UAC_VERSION_2, UAC2_CLOCK_MULTIPLIER, + struct uac_clock_multiplier_descriptor), + /* UAC_VERSION_2, UAC2_SAMPLE_RATE_CONVERTER: not implemented yet */ + + /* UAC3 */ + FIXED(UAC_VERSION_2, UAC_HEADER, struct uac3_ac_header_descriptor), + FIXED(UAC_VERSION_3, UAC_INPUT_TERMINAL, + struct uac3_input_terminal_descriptor), + FIXED(UAC_VERSION_3, UAC_OUTPUT_TERMINAL, + struct uac3_output_terminal_descriptor), + /* UAC_VERSION_3, UAC3_EXTENDED_TERMINAL: not implemented yet */ + FUNC(UAC_VERSION_3, UAC3_MIXER_UNIT, validate_mixer_unit), + FUNC(UAC_VERSION_3, UAC3_SELECTOR_UNIT, validate_selector_unit), + FUNC(UAC_VERSION_3, UAC_FEATURE_UNIT, validate_uac3_feature_unit), + /* UAC_VERSION_3, UAC3_EFFECT_UNIT: not implemented yet */ + FUNC(UAC_VERSION_3, UAC3_PROCESSING_UNIT, validate_processing_unit), + FUNC(UAC_VERSION_3, UAC3_EXTENSION_UNIT, validate_processing_unit), + FIXED(UAC_VERSION_3, UAC3_CLOCK_SOURCE, + struct uac3_clock_source_descriptor), + FUNC(UAC_VERSION_3, UAC3_CLOCK_SELECTOR, validate_selector_unit), + FIXED(UAC_VERSION_3, UAC3_CLOCK_MULTIPLIER, + struct uac3_clock_multiplier_descriptor), + /* UAC_VERSION_3, UAC3_SAMPLE_RATE_CONVERTER: not implemented yet */ + /* UAC_VERSION_3, UAC3_CONNECTORS: not implemented yet */ + { } /* terminator */ +}; + +static struct usb_desc_validator midi_validators[] = { + FIXED(UAC_VERSION_ALL, USB_MS_HEADER, + struct usb_ms_header_descriptor), + FIXED(UAC_VERSION_ALL, USB_MS_MIDI_IN_JACK, + struct usb_midi_in_jack_descriptor), + FUNC(UAC_VERSION_ALL, USB_MS_MIDI_OUT_JACK, + validate_midi_out_jack), + { } /* terminator */ +}; + + +/* Validate the given unit descriptor, return true if it's OK */ +static bool validate_desc(unsigned char *hdr, int protocol, + const struct usb_desc_validator *v) +{ + if (hdr[1] != USB_DT_CS_INTERFACE) + return true; /* don't care */ + + for (; v->type; v++) { + if (v->type == hdr[2] && + (v->protocol == UAC_VERSION_ALL || + v->protocol == protocol)) { + if (v->func) + return v->func(hdr, v); + /* check for the fixed size */ + return hdr[0] >= v->size; + } + } + + return true; /* not matching, skip validation */ +} + +bool snd_usb_validate_audio_desc(void *p, int protocol) +{ + return validate_desc(p, protocol, audio_validators); +} + +bool snd_usb_validate_midi_desc(void *p) +{ + return validate_desc(p, UAC_VERSION_1, midi_validators); +} + -- cgit v1.2.3 From 68e9fde245591d18200f8a9054cac22339437adb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 15 Aug 2019 16:30:39 +0200 Subject: ALSA: usb-audio: Simplify parse_audio_unit() Minor code refactoring by combining the UAC version and the type in the switch-case flow, so that we reduce the indentation and redundancy. One good bonus is that the duplicated definition of the same type value (e.g. UAC2_EFFECT_UNIT) can be handled more cleanly. Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 95 +++++++++++++++++++++++-------------------------------- 1 file changed, 39 insertions(+), 56 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index a1093fb9bf09..34def5911af2 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2782,62 +2782,45 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) return 0; /* skip invalid unit */ } - if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { - switch (p1[2]) { - case UAC_INPUT_TERMINAL: - return parse_audio_input_terminal(state, unitid, p1); - case UAC_MIXER_UNIT: - return parse_audio_mixer_unit(state, unitid, p1); - case UAC2_CLOCK_SOURCE: - return parse_clock_source_unit(state, unitid, p1); - case UAC_SELECTOR_UNIT: - case UAC2_CLOCK_SELECTOR: - return parse_audio_selector_unit(state, unitid, p1); - case UAC_FEATURE_UNIT: - return parse_audio_feature_unit(state, unitid, p1); - case UAC1_PROCESSING_UNIT: - /* UAC2_EFFECT_UNIT has the same value */ - if (protocol == UAC_VERSION_1) - return parse_audio_processing_unit(state, unitid, p1); - else - return 0; /* FIXME - effect units not implemented yet */ - case UAC1_EXTENSION_UNIT: - /* UAC2_PROCESSING_UNIT_V2 has the same value */ - if (protocol == UAC_VERSION_1) - return parse_audio_extension_unit(state, unitid, p1); - else /* UAC_VERSION_2 */ - return parse_audio_processing_unit(state, unitid, p1); - case UAC2_EXTENSION_UNIT_V2: - return parse_audio_extension_unit(state, unitid, p1); - default: - usb_audio_err(state->chip, - "unit %u: unexpected type 0x%02x\n", unitid, p1[2]); - return -EINVAL; - } - } else { /* UAC_VERSION_3 */ - switch (p1[2]) { - case UAC_INPUT_TERMINAL: - return parse_audio_input_terminal(state, unitid, p1); - case UAC3_MIXER_UNIT: - return parse_audio_mixer_unit(state, unitid, p1); - case UAC3_CLOCK_SOURCE: - return parse_clock_source_unit(state, unitid, p1); - case UAC3_SELECTOR_UNIT: - case UAC3_CLOCK_SELECTOR: - return parse_audio_selector_unit(state, unitid, p1); - case UAC3_FEATURE_UNIT: - return parse_audio_feature_unit(state, unitid, p1); - case UAC3_EFFECT_UNIT: - return 0; /* FIXME - effect units not implemented yet */ - case UAC3_PROCESSING_UNIT: - return parse_audio_processing_unit(state, unitid, p1); - case UAC3_EXTENSION_UNIT: - return parse_audio_extension_unit(state, unitid, p1); - default: - usb_audio_err(state->chip, - "unit %u: unexpected type 0x%02x\n", unitid, p1[2]); - return -EINVAL; - } +#define PTYPE(a, b) ((a) << 8 | (b)) + switch (PTYPE(protocol, p1[2])) { + case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL): + case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL): + case PTYPE(UAC_VERSION_3, UAC_INPUT_TERMINAL): + return parse_audio_input_terminal(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC_MIXER_UNIT): + case PTYPE(UAC_VERSION_2, UAC_MIXER_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_MIXER_UNIT): + return parse_audio_mixer_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SOURCE): + case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SOURCE): + return parse_clock_source_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_2, UAC_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SELECTOR): + case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SELECTOR): + return parse_audio_selector_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC_FEATURE_UNIT): + case PTYPE(UAC_VERSION_2, UAC_FEATURE_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_FEATURE_UNIT): + return parse_audio_feature_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC1_PROCESSING_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2): + case PTYPE(UAC_VERSION_3, UAC3_PROCESSING_UNIT): + return parse_audio_processing_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2): + case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT): + return parse_audio_extension_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT): + return 0; /* FIXME - effect units not implemented yet */ + default: + usb_audio_err(state->chip, + "unit %u: unexpected type 0x%02x\n", + unitid, p1[2]); + return -EINVAL; } } -- cgit v1.2.3 From 52c3e317a857091fd746e15179a637f32be4d337 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Aug 2019 08:23:10 +0200 Subject: ALSA: usb-audio: Unify the release of usb_mixer_elem_info objects Instead of the direct kfree() calls, introduce a new local helper to release the usb_mixer_elem_info object. This will be extended to do more than a single kfree() in the later patches. Also, use the standard goto instead of multiple calls in parse_audio_selector_unit() error paths. Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 34def5911af2..277660fd6e0a 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1026,10 +1026,15 @@ static struct usb_feature_control_info audio_feature_info[] = { { UAC2_FU_PHASE_INVERTER, "Phase Inverter Control", USB_MIXER_BOOLEAN, -1 }, }; +static void usb_mixer_elem_info_free(struct usb_mixer_elem_info *cval) +{ + kfree(cval); +} + /* private_free callback */ void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl) { - kfree(kctl->private_data); + usb_mixer_elem_info_free(kctl->private_data); kctl->private_data = NULL; } @@ -1552,7 +1557,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer, ctl_info = get_feature_control_info(control); if (!ctl_info) { - kfree(cval); + usb_mixer_elem_info_free(cval); return; } if (mixer->protocol == UAC_VERSION_1) @@ -1585,7 +1590,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer, if (!kctl) { usb_audio_err(mixer->chip, "cannot malloc kcontrol\n"); - kfree(cval); + usb_mixer_elem_info_free(cval); return; } kctl->private_free = snd_usb_mixer_elem_free; @@ -1755,7 +1760,7 @@ static void build_connector_control(struct usb_mixer_interface *mixer, kctl = snd_ctl_new1(&usb_connector_ctl_ro, cval); if (!kctl) { usb_audio_err(mixer->chip, "cannot malloc kcontrol\n"); - kfree(cval); + usb_mixer_elem_info_free(cval); return; } get_connector_control_name(mixer, term, is_input, kctl->id.name, @@ -1808,7 +1813,7 @@ static int parse_clock_source_unit(struct mixer_build *state, int unitid, kctl = snd_ctl_new1(&usb_bool_master_control_ctl_ro, cval); if (!kctl) { - kfree(cval); + usb_mixer_elem_info_free(cval); return -ENOMEM; } @@ -2070,7 +2075,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); if (!kctl) { usb_audio_err(state->chip, "cannot malloc kcontrol\n"); - kfree(cval); + usb_mixer_elem_info_free(cval); return; } kctl->private_free = snd_usb_mixer_elem_free; @@ -2468,7 +2473,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); if (!kctl) { - kfree(cval); + usb_mixer_elem_info_free(cval); return -ENOMEM; } kctl->private_free = snd_usb_mixer_elem_free; @@ -2606,7 +2611,7 @@ static void usb_mixer_selector_elem_free(struct snd_kcontrol *kctl) if (kctl->private_data) { struct usb_mixer_elem_info *cval = kctl->private_data; num_ins = cval->max; - kfree(cval); + usb_mixer_elem_info_free(cval); kctl->private_data = NULL; } if (kctl->private_value) { @@ -2678,10 +2683,10 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, break; } - namelist = kmalloc_array(desc->bNrInPins, sizeof(char *), GFP_KERNEL); + namelist = kcalloc(desc->bNrInPins, sizeof(char *), GFP_KERNEL); if (!namelist) { - kfree(cval); - return -ENOMEM; + err = -ENOMEM; + goto error_cval; } #define MAX_ITEM_NAME_LEN 64 for (i = 0; i < desc->bNrInPins; i++) { @@ -2689,11 +2694,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, len = 0; namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL); if (!namelist[i]) { - while (i--) - kfree(namelist[i]); - kfree(namelist); - kfree(cval); - return -ENOMEM; + err = -ENOMEM; + goto error_name; } len = check_mapped_selector_name(state, unitid, i, namelist[i], MAX_ITEM_NAME_LEN); @@ -2707,10 +2709,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval); if (! kctl) { usb_audio_err(state->chip, "cannot malloc kcontrol\n"); - for (i = 0; i < desc->bNrInPins; i++) - kfree(namelist[i]); - kfree(namelist); - kfree(cval); + err = -ENOMEM; + goto error_name; return -ENOMEM; } kctl->private_value = (unsigned long)namelist; @@ -2757,6 +2757,14 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n", cval->head.id, kctl->id.name, desc->bNrInPins); return snd_usb_mixer_add_control(&cval->head, kctl); + + error_name: + for (i = 0; i < desc->bNrInPins; i++) + kfree(namelist[i]); + kfree(namelist); + error_cval: + usb_mixer_elem_info_free(cval); + return err; } /* -- cgit v1.2.3 From b8e4f1fdfa422398c2d6c47bfb7d1feb3046d70a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Aug 2019 09:25:27 +0200 Subject: ALSA: usb-audio: Remove superfluous bLength checks Now that we got the more comprehensive validation code for USB-audio descriptors, the check of overflow in each descriptor unit parser became superfluous. Drop some of the obvious cases. Signed-off-by: Takashi Iwai --- sound/usb/clock.c | 14 ++++------ sound/usb/mixer.c | 84 ------------------------------------------------------- 2 files changed, 6 insertions(+), 92 deletions(-) (limited to 'sound') diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 72e9bdf76115..6b8c14f9b5d4 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -38,39 +38,37 @@ static void *find_uac_clock_desc(struct usb_host_interface *iface, int id, static bool validate_clock_source_v2(void *p, int id) { struct uac_clock_source_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; + return cs->bClockID == id; } static bool validate_clock_source_v3(void *p, int id) { struct uac3_clock_source_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; + return cs->bClockID == id; } static bool validate_clock_selector_v2(void *p, int id) { struct uac_clock_selector_descriptor *cs = p; - return cs->bLength >= sizeof(*cs) && cs->bClockID == id && - cs->bLength == 7 + cs->bNrInPins; + return cs->bClockID == id; } static bool validate_clock_selector_v3(void *p, int id) { struct uac3_clock_selector_descriptor *cs = p; - return cs->bLength >= sizeof(*cs) && cs->bClockID == id && - cs->bLength == 11 + cs->bNrInPins; + return cs->bClockID == id; } static bool validate_clock_multiplier_v2(void *p, int id) { struct uac_clock_multiplier_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; + return cs->bClockID == id; } static bool validate_clock_multiplier_v3(void *p, int id) { struct uac3_clock_multiplier_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; + return cs->bClockID == id; } #define DEFINE_FIND_HELPER(name, obj, validator, type) \ diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 277660fd6e0a..c9777d8a76f5 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -740,13 +740,6 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state, { int mu_channels; - if (desc->bLength < sizeof(*desc)) - return -EINVAL; - if (!desc->bNrInPins) - return -EINVAL; - if (desc->bLength < sizeof(*desc) + desc->bNrInPins) - return -EINVAL; - switch (state->mixer->protocol) { case UAC_VERSION_1: case UAC_VERSION_2: @@ -1781,13 +1774,6 @@ static int parse_clock_source_unit(struct mixer_build *state, int unitid, if (state->mixer->protocol != UAC_VERSION_2) return -EINVAL; - if (hdr->bLength != sizeof(*hdr)) { - usb_audio_dbg(state->chip, - "Bogus clock source descriptor length of %d, ignoring.\n", - hdr->bLength); - return 0; - } - /* * The only property of this unit we are interested in is the * clock source validity. If that isn't readable, just bail out. @@ -1846,62 +1832,20 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, __u8 *bmaControls; if (state->mixer->protocol == UAC_VERSION_1) { - if (hdr->bLength < 7) { - usb_audio_err(state->chip, - "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } csize = hdr->bControlSize; - if (!csize) { - usb_audio_dbg(state->chip, - "unit %u: invalid bControlSize == 0\n", - unitid); - return -EINVAL; - } channels = (hdr->bLength - 7) / csize - 1; bmaControls = hdr->bmaControls; - if (hdr->bLength < 7 + csize) { - usb_audio_err(state->chip, - "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } } else if (state->mixer->protocol == UAC_VERSION_2) { struct uac2_feature_unit_descriptor *ftr = _ftr; - if (hdr->bLength < 6) { - usb_audio_err(state->chip, - "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } csize = 4; channels = (hdr->bLength - 6) / 4 - 1; bmaControls = ftr->bmaControls; - if (hdr->bLength < 6 + csize) { - usb_audio_err(state->chip, - "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } } else { /* UAC_VERSION_3 */ struct uac3_feature_unit_descriptor *ftr = _ftr; - if (hdr->bLength < 7) { - usb_audio_err(state->chip, - "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } csize = 4; channels = (ftr->bLength - 7) / 4 - 1; bmaControls = ftr->bmaControls; - if (hdr->bLength < 7 + csize) { - usb_audio_err(state->chip, - "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } } /* parse the source unit */ @@ -2101,15 +2045,11 @@ static int parse_audio_input_terminal(struct mixer_build *state, int unitid, if (state->mixer->protocol == UAC_VERSION_2) { struct uac2_input_terminal_descriptor *d_v2 = raw_desc; - if (d_v2->bLength < sizeof(*d_v2)) - return -EINVAL; control = UAC2_TE_CONNECTOR; term_id = d_v2->bTerminalID; bmctls = le16_to_cpu(d_v2->bmControls); } else if (state->mixer->protocol == UAC_VERSION_3) { struct uac3_input_terminal_descriptor *d_v3 = raw_desc; - if (d_v3->bLength < sizeof(*d_v3)) - return -EINVAL; control = UAC3_TE_INSERTION; term_id = d_v3->bTerminalID; bmctls = le32_to_cpu(d_v3->bmControls); @@ -2371,18 +2311,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, const char *name = extension_unit ? "Extension Unit" : "Processing Unit"; - if (desc->bLength < 13) { - usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid); - return -EINVAL; - } - num_ins = desc->bNrInPins; - if (desc->bLength < 13 + num_ins || - desc->bLength < num_ins + uac_processing_unit_bControlSize(desc, state->mixer->protocol)) { - usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid); - return -EINVAL; - } - for (i = 0; i < num_ins; i++) { err = parse_audio_unit(state, desc->baSourceID[i]); if (err < 0) @@ -2637,13 +2566,6 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, const struct usbmix_name_map *map; char **namelist; - if (desc->bLength < 5 || !desc->bNrInPins || - desc->bLength < 5 + desc->bNrInPins) { - usb_audio_err(state->chip, - "invalid SELECTOR UNIT descriptor %d\n", unitid); - return -EINVAL; - } - for (i = 0; i < desc->bNrInPins; i++) { err = parse_audio_unit(state, desc->baSourceID[i]); if (err < 0) @@ -3149,8 +3071,6 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) if (mixer->protocol == UAC_VERSION_1) { struct uac1_output_terminal_descriptor *desc = p; - if (desc->bLength < sizeof(*desc)) - continue; /* invalid descriptor? */ /* mark terminal ID as visited */ set_bit(desc->bTerminalID, state.unitbitmap); state.oterm.id = desc->bTerminalID; @@ -3162,8 +3082,6 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) } else if (mixer->protocol == UAC_VERSION_2) { struct uac2_output_terminal_descriptor *desc = p; - if (desc->bLength < sizeof(*desc)) - continue; /* invalid descriptor? */ /* mark terminal ID as visited */ set_bit(desc->bTerminalID, state.unitbitmap); state.oterm.id = desc->bTerminalID; @@ -3189,8 +3107,6 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) } else { /* UAC_VERSION_3 */ struct uac3_output_terminal_descriptor *desc = p; - if (desc->bLength < sizeof(*desc)) - continue; /* invalid descriptor? */ /* mark terminal ID as visited */ set_bit(desc->bTerminalID, state.unitbitmap); state.oterm.id = desc->bTerminalID; -- cgit v1.2.3 From 0ce6a624473e7e5752a84416f85f73d082308edd Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 22 Aug 2019 22:30:07 +0800 Subject: ASoC: AMD: Fix Kconfig warning without GPIOLIB While do rand build without GPIOLIB, we get Kconfig warning:\ WARNING: unmet direct dependencies detected for SND_SOC_MAX98357A Depends on [n]: SOUND [=y] && !UML && SND [=m] && SND_SOC [=m] && GPIOLIB [=n] Selected by [m]: - SND_SOC_AMD_CZ_DA7219MX98357_MACH [=m] && SOUND [=y] && !UML && SND [=m] && SND_SOC [=m] && SND_SOC_AMD_ACP [=m] && I2C [=y] Add GPIOLIB dependency to fix this. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190822143007.73644-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/amd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 9ca9214cb7fb..5f40517717c4 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -10,7 +10,7 @@ config SND_SOC_AMD_CZ_DA7219MX98357_MACH select SND_SOC_MAX98357A select SND_SOC_ADAU7002 select REGULATOR - depends on SND_SOC_AMD_ACP && I2C + depends on SND_SOC_AMD_ACP && I2C && GPIOLIB help This option enables machine driver for DA7219 and MAX9835. -- cgit v1.2.3 From b9132b89933177286fb427bd03affcebc4d649e1 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 21 Aug 2019 11:47:29 -0500 Subject: ASoC: SOF: Add OF DSP device support Add support for device tree based SOF DSP devices. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190821164730.7385-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 10 ++++ sound/soc/sof/Makefile | 3 + sound/soc/sof/sof-of-dev.c | 143 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 sound/soc/sof/sof-of-dev.c (limited to 'sound') diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index fb01f0ca6027..01acb580b817 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -36,6 +36,16 @@ config SND_SOC_SOF_ACPI Say Y if you need this option If unsure select "N". +config SND_SOC_SOF_OF + tristate "SOF OF enumeration support" + depends on OF || COMPILE_TEST + select SND_SOC_SOF + select SND_SOC_SOF_OPTIONS + help + This adds support for Device Tree enumeration. This option is + required to enable i.MX8 devices. + Say Y if you need this option. If unsure select "N". + config SND_SOC_SOF_OPTIONS tristate help diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 585fb6917489..772c452d1ae2 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -5,6 +5,8 @@ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ snd-sof-pci-objs := sof-pci-dev.o snd-sof-acpi-objs := sof-acpi-dev.o +snd-sof-of-objs := sof-of-dev.o + snd-sof-nocodec-objs := nocodec.o obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o @@ -12,6 +14,7 @@ obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o obj-$(CONFIG_SND_SOC_SOF_ACPI) += snd-sof-acpi.o +obj-$(CONFIG_SND_SOC_SOF_OF) += snd-sof-of.o obj-$(CONFIG_SND_SOC_SOF_PCI) += snd-sof-pci.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c new file mode 100644 index 000000000000..28a9692974e5 --- /dev/null +++ b/sound/soc/sof/sof-of-dev.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// Copyright 2019 NXP +// +// Author: Daniel Baluta +// + +#include +#include +#include +#include + +#include "ops.h" + +extern struct snd_sof_dsp_ops sof_imx8_ops; + +/* platform specific devices */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) +static struct sof_dev_desc sof_of_imx8qxp_desc = { + .default_fw_path = "imx/sof", + .default_tplg_path = "imx/sof-tplg", + .nocodec_fw_filename = "sof-imx8.ri", + .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", + .ops = &sof_imx8_ops, +}; +#endif + +static const struct dev_pm_ops sof_of_pm = { + SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) + SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, + NULL) +}; + +static void sof_of_probe_complete(struct device *dev) +{ + /* allow runtime_pm */ + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); +} + +static int sof_of_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct sof_dev_desc *desc; + /*TODO: create a generic snd_soc_xxx_mach */ + struct snd_soc_acpi_mach *mach; + struct snd_sof_pdata *sof_pdata; + const struct snd_sof_dsp_ops *ops; + int ret; + + dev_info(&pdev->dev, "DT DSP detected"); + + sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); + if (!sof_pdata) + return -ENOMEM; + + desc = device_get_match_data(dev); + if (!desc) + return -ENODEV; + + /* get ops for platform */ + ops = desc->ops; + if (!ops) { + dev_err(dev, "error: no matching DT descriptor ops\n"); + return -ENODEV; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) + /* force nocodec mode */ + dev_warn(dev, "Force to use nocodec mode\n"); + mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + if (!mach) + return -ENOMEM; + ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); + if (ret < 0) + return ret; +#else + /* TODO: implement case where we actually have a codec */ + return -ENODEV; +#endif + + if (mach) + mach->mach_params.platform = dev_name(dev); + + sof_pdata->machine = mach; + sof_pdata->desc = desc; + sof_pdata->dev = &pdev->dev; + sof_pdata->platform = dev_name(dev); + + /* TODO: read alternate fw and tplg filenames from DT */ + sof_pdata->fw_filename_prefix = sof_pdata->desc->default_fw_path; + sof_pdata->tplg_filename_prefix = sof_pdata->desc->default_tplg_path; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + /* set callback to enable runtime_pm */ + sof_pdata->sof_probe_complete = sof_of_probe_complete; +#endif + /* call sof helper for DSP hardware probe */ + ret = snd_sof_device_probe(dev, sof_pdata); + if (ret) { + dev_err(dev, "error: failed to probe DSP hardware\n"); + return ret; + } + +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + sof_of_probe_complete(dev); +#endif + + return ret; +} + +static int sof_of_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + /* call sof helper for DSP hardware remove */ + snd_sof_device_remove(&pdev->dev); + + return 0; +} + +static const struct of_device_id sof_of_ids[] = { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) + { .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc}, +#endif + { } +}; +MODULE_DEVICE_TABLE(of, sof_of_ids); + +/* DT driver definition */ +static struct platform_driver snd_sof_of_driver = { + .probe = sof_of_probe, + .remove = sof_of_remove, + .driver = { + .name = "sof-audio-of", + .pm = &sof_of_pm, + .of_match_table = sof_of_ids, + }, +}; +module_platform_driver(snd_sof_of_driver); + +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 202acc565a1f050f82fdab646fd9c86bfdb21733 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 21 Aug 2019 11:47:30 -0500 Subject: ASoC: SOF: imx: Add i.MX8 HW support Add support for the audio DSP hardware found on NXP i.MX8 platform. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190821164730.7385-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 1 + sound/soc/sof/Makefile | 1 + sound/soc/sof/imx/Kconfig | 22 +++ sound/soc/sof/imx/Makefile | 4 + sound/soc/sof/imx/imx8.c | 394 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 422 insertions(+) create mode 100644 sound/soc/sof/imx/Kconfig create mode 100644 sound/soc/sof/imx/Makefile create mode 100644 sound/soc/sof/imx/imx8.c (limited to 'sound') diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 01acb580b817..bb8036ae567e 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -173,6 +173,7 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE When selected, the probe is handled in two steps, for example to avoid lockdeps if request_module is used in the probe. +source "sound/soc/sof/imx/Kconfig" source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/xtensa/Kconfig" diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 772c452d1ae2..b0a6f01bdc44 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -18,4 +18,5 @@ obj-$(CONFIG_SND_SOC_SOF_OF) += snd-sof-of.o obj-$(CONFIG_SND_SOC_SOF_PCI) += snd-sof-pci.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ +obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/ obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig new file mode 100644 index 000000000000..fd73d8402dbf --- /dev/null +++ b/sound/soc/sof/imx/Kconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) + +config SND_SOC_SOF_IMX_TOPLEVEL + bool "SOF support for NXP i.MX audio DSPs" + depends on ARM64 && SND_SOC_SOF_OF || COMPILE_TEST + help + This adds support for Sound Open Firmware for NXP i.MX platforms. + Say Y if you have such a device. + If unsure select "N". + +if SND_SOC_SOF_IMX_TOPLEVEL + +config SND_SOC_SOF_IMX8 + tristate "SOF support for i.MX8" + depends on IMX_SCU + depends on IMX_DSP + help + This adds support for Sound Open Firmware for NXP i.MX8 platforms + Say Y if you have such a device. + If unsure select "N". + +endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL diff --git a/sound/soc/sof/imx/Makefile b/sound/soc/sof/imx/Makefile new file mode 100644 index 000000000000..6ef908e8c807 --- /dev/null +++ b/sound/soc/sof/imx/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +snd-sof-imx8-objs := imx8.o + +obj-$(CONFIG_SND_SOC_SOF_IMX8) += snd-sof-imx8.o diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c new file mode 100644 index 000000000000..e502f584207f --- /dev/null +++ b/sound/soc/sof/imx/imx8.c @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// Copyright 2019 NXP +// +// Author: Daniel Baluta +// +// Hardware interface for audio DSP on i.MX8 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include "../ops.h" + +/* DSP memories */ +#define IRAM_OFFSET 0x10000 +#define IRAM_SIZE (2 * 1024) +#define DRAM0_OFFSET 0x0 +#define DRAM0_SIZE (32 * 1024) +#define DRAM1_OFFSET 0x8000 +#define DRAM1_SIZE (32 * 1024) +#define SYSRAM_OFFSET 0x18000 +#define SYSRAM_SIZE (256 * 1024) +#define SYSROM_OFFSET 0x58000 +#define SYSROM_SIZE (192 * 1024) + +#define RESET_VECTOR_VADDR 0x596f8000 + +#define MBOX_OFFSET 0x800000 +#define MBOX_SIZE 0x1000 + +struct imx8_priv { + struct device *dev; + struct snd_sof_dev *sdev; + + /* DSP IPC handler */ + struct imx_dsp_ipc *dsp_ipc; + struct platform_device *ipc_dev; + + /* System Controller IPC handler */ + struct imx_sc_ipc *sc_ipc; + + /* Power domain handling */ + int num_domains; + struct device **pd_dev; + struct device_link **link; + +}; + +static void imx8_get_reply(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc_msg *msg = sdev->msg; + struct sof_ipc_reply reply; + int ret = 0; + + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt\n"); + return; + } + + /* get reply */ + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + + if (reply.error < 0) { + memcpy(msg->reply_data, &reply, sizeof(reply)); + ret = reply.error; + } else { + /* reply has correct size? */ + if (reply.hdr.size != msg->reply_size) { + dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", + msg->reply_size, reply.hdr.size); + ret = -EINVAL; + } + + /* read the message */ + if (msg->reply_size > 0) + sof_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); + } + + msg->reply_error = ret; +} + +static int imx8_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MBOX_OFFSET; +} + +static int imx8_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MBOX_OFFSET; +} + +void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc) +{ + struct imx8_priv *priv = imx_dsp_get_data(ipc); + unsigned long flags; + + spin_lock_irqsave(&priv->sdev->ipc_lock, flags); + imx8_get_reply(priv->sdev); + snd_sof_ipc_reply(priv->sdev, 0); + spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); +} + +void imx8_dsp_handle_request(struct imx_dsp_ipc *ipc) +{ + struct imx8_priv *priv = imx_dsp_get_data(ipc); + + snd_sof_ipc_msgs_rx(priv->sdev); +} + +struct imx_dsp_ops dsp_ops = { + .handle_reply = imx8_dsp_handle_reply, + .handle_request = imx8_dsp_handle_request, +}; + +static int imx8_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct imx8_priv *priv = (struct imx8_priv *)sdev->private; + + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + imx_dsp_ring_doorbell(priv->dsp_ipc, 0); + + return 0; +} + +/* + * DSP control. + */ +static int imx8_run(struct snd_sof_dev *sdev) +{ + struct imx8_priv *dsp_priv = (struct imx8_priv *)sdev->private; + int ret; + + ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + IMX_SC_C_OFS_SEL, 1); + if (ret < 0) { + dev_err(sdev->dev, "Error system address offset source select\n"); + return ret; + } + + ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + IMX_SC_C_OFS_AUDIO, 0x80); + if (ret < 0) { + dev_err(sdev->dev, "Error system address offset of AUDIO\n"); + return ret; + } + + ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + IMX_SC_C_OFS_PERIPH, 0x5A); + if (ret < 0) { + dev_err(sdev->dev, "Error system address offset of PERIPH %d\n", + ret); + return ret; + } + + ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + IMX_SC_C_OFS_IRQ, 0x51); + if (ret < 0) { + dev_err(sdev->dev, "Error system address offset of IRQ\n"); + return ret; + } + + imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true, + RESET_VECTOR_VADDR); + + return 0; +} + +static int imx8_probe(struct snd_sof_dev *sdev) +{ + struct platform_device *pdev = + container_of(sdev->dev, struct platform_device, dev); + struct device_node *np = pdev->dev.of_node; + struct device_node *res_node; + struct resource *mmio; + struct imx8_priv *priv; + struct resource res; + u32 base, size; + int ret = 0; + int i; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + sdev->private = priv; + priv->dev = sdev->dev; + priv->sdev = sdev; + + /* power up device associated power domains */ + priv->num_domains = of_count_phandle_with_args(np, "power-domains", + "#power-domain-cells"); + if (priv->num_domains < 0) { + dev_err(sdev->dev, "no power-domains property in %pOF\n", np); + return priv->num_domains; + } + + priv->pd_dev = devm_kmalloc_array(&pdev->dev, priv->num_domains, + sizeof(*priv->pd_dev), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->link = devm_kmalloc_array(&pdev->dev, priv->num_domains, + sizeof(*priv->link), GFP_KERNEL); + if (!priv->link) + return -ENOMEM; + + for (i = 0; i < priv->num_domains; i++) { + priv->pd_dev[i] = dev_pm_domain_attach_by_id(&pdev->dev, i); + if (IS_ERR(priv->pd_dev[i])) { + ret = PTR_ERR(priv->pd_dev[i]); + goto exit_unroll_pm; + } + priv->link[i] = device_link_add(&pdev->dev, priv->pd_dev[i], + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (IS_ERR(priv->link[i])) { + ret = PTR_ERR(priv->link[i]); + dev_pm_domain_detach(priv->pd_dev[i], false); + goto exit_unroll_pm; + } + } + + ret = imx_scu_get_handle(&priv->sc_ipc); + if (ret) { + dev_err(sdev->dev, "Cannot obtain SCU handle (err = %d)\n", + ret); + goto exit_unroll_pm; + } + + priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp", + PLATFORM_DEVID_NONE, + pdev, sizeof(*pdev)); + if (IS_ERR(priv->ipc_dev)) { + ret = PTR_ERR(priv->ipc_dev); + goto exit_unroll_pm; + } + + priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev); + if (!priv->dsp_ipc) { + /* DSP IPC driver not probed yet, try later */ + ret = -EPROBE_DEFER; + dev_err(sdev->dev, "Failed to get drvdata\n"); + goto exit_pdev_unregister; + } + + imx_dsp_set_data(priv->dsp_ipc, priv); + priv->dsp_ipc->ops = &dsp_ops; + + /* DSP base */ + mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n"); + ret = -EINVAL; + goto exit_pdev_unregister; + } + + sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) { + dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n", + base, size); + ret = -ENODEV; + goto exit_pdev_unregister; + } + sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM; + + res_node = of_parse_phandle(np, "memory-region", 0); + if (!res_node) { + dev_err(&pdev->dev, "failed to get memory region node\n"); + ret = -ENODEV; + goto exit_pdev_unregister; + } + + ret = of_address_to_resource(res_node, 0, &res); + if (ret) { + dev_err(&pdev->dev, "failed to get reserved region address\n"); + goto exit_pdev_unregister; + } + + sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start, + res.end - res.start + + 1); + if (IS_ERR(sdev->bar[SOF_FW_BLK_TYPE_SRAM])) { + dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n", + base, size); + ret = PTR_ERR(sdev->bar[SOF_FW_BLK_TYPE_SRAM]); + goto exit_pdev_unregister; + } + sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; + + return 0; + +exit_pdev_unregister: + platform_device_unregister(priv->ipc_dev); +exit_unroll_pm: + while (--i >= 0) { + device_link_del(priv->link[i]); + dev_pm_domain_detach(priv->pd_dev[i], false); + } + + return ret; +} + +static int imx8_remove(struct snd_sof_dev *sdev) +{ + struct imx8_priv *priv = (struct imx8_priv *)sdev->private; + int i; + + platform_device_unregister(priv->ipc_dev); + + for (i = 0; i < priv->num_domains; i++) { + device_link_del(priv->link[i]); + dev_pm_domain_detach(priv->pd_dev[i], false); + } + + return 0; +} + +/* on i.MX8 there is 1 to 1 match between type and BAR idx */ +int imx8_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + return type; +} + +void imx8_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); +} + +int imx8_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + return 0; +} + +static struct snd_soc_dai_driver imx8_dai[] = { +{ + .name = "esai-port", +}, +}; + +/* i.MX8 ops */ +struct snd_sof_dsp_ops sof_imx8_ops = { + /* probe and remove */ + .probe = imx8_probe, + .remove = imx8_remove, + /* DSP core boot */ + .run = imx8_run, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* ipc */ + .send_msg = imx8_send_msg, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = imx8_get_mailbox_offset, + .get_window_offset = imx8_get_window_offset, + + .ipc_msg_data = imx8_ipc_msg_data, + .ipc_pcm_params = imx8_ipc_pcm_params, + + /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + .get_bar_index = imx8_get_bar_index, + /* firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = imx8_dai, + .num_drv = 1, /* we have only 1 ESAI interface on i.MX8 */ +}; +EXPORT_SYMBOL(sof_imx8_ops); + +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From c101fb29737f4558bf589d0d66371d9e21040568 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 22 Aug 2019 22:36:08 +0800 Subject: ASoC: wm8988: fix typo in wm8988_right_line_controls sound/soc/codecs/wm8988.c:270:30: warning: wm8988_rline_enum defined but not used [-Wunused-const-variable=] wm8988_rline_enum should be used in wm8988_right_line_controls. Reported-by: Hulk Robot Fixes: 5409fb4e327a ("ASoC: Add WM8988 CODEC driver") Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190822143608.59824-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8988.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 25e74cf0666a..85bfd041d546 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -273,7 +273,7 @@ static const struct soc_enum wm8988_rline_enum = wm8988_line_texts, wm8988_line_values); static const struct snd_kcontrol_new wm8988_right_line_controls = - SOC_DAPM_ENUM("Route", wm8988_lline_enum); + SOC_DAPM_ENUM("Route", wm8988_rline_enum); /* Left Mixer */ static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = { -- cgit v1.2.3 From 97aad5ce88164bc5f884b5234f015ac553ea2fe5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 22 Aug 2019 22:37:47 +0800 Subject: ASoC: mediatek: mt2701: Fix -Wunused-const-variable warnings sound/soc/mediatek/mt2701/mt2701-afe-common.h:66:27: warning: mt2701_afe_backup_list defined but not used [-Wunused-const-variable=] mt2701_afe_backup_list is only used in mt2701-afe-pcm.c, so just move the definition over there. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190822143747.20944-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-afe-common.h | 21 --------------------- sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h index d44faba27d3c..32bef5e2a56d 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-common.h +++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h @@ -63,27 +63,6 @@ enum audio_base_clock { MT2701_BASE_CLK_NUM, }; -static const unsigned int mt2701_afe_backup_list[] = { - AUDIO_TOP_CON0, - AUDIO_TOP_CON4, - AUDIO_TOP_CON5, - ASYS_TOP_CON, - AFE_CONN0, - AFE_CONN1, - AFE_CONN2, - AFE_CONN3, - AFE_CONN15, - AFE_CONN16, - AFE_CONN17, - AFE_CONN18, - AFE_CONN19, - AFE_CONN20, - AFE_CONN21, - AFE_CONN22, - AFE_DAC_CON0, - AFE_MEMIF_PBUF_SIZE, -}; - struct mt2701_i2s_data { int i2s_ctrl_reg; int i2s_asrc_fs_shift; diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index d7f5defa50c2..76502ba261c8 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -60,6 +60,27 @@ static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = { { .rate = 352800, .regvalue = 24 }, }; +static const unsigned int mt2701_afe_backup_list[] = { + AUDIO_TOP_CON0, + AUDIO_TOP_CON4, + AUDIO_TOP_CON5, + ASYS_TOP_CON, + AFE_CONN0, + AFE_CONN1, + AFE_CONN2, + AFE_CONN3, + AFE_CONN15, + AFE_CONN16, + AFE_CONN17, + AFE_CONN18, + AFE_CONN19, + AFE_CONN20, + AFE_CONN21, + AFE_CONN22, + AFE_DAC_CON0, + AFE_MEMIF_PBUF_SIZE, +}; + static int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num) { struct mt2701_afe_private *afe_priv = afe->platform_priv; -- cgit v1.2.3 From 6191cbde5ff02ef5307e7b2e4f5b8f7607c2b1df Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Thu, 22 Aug 2019 20:51:00 +0800 Subject: ASoC: mediatek: mt8183: switch tdm pins gpio function when playback on or off Pull TDM pins down when TDM BE shutdown to avoid current leakage. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1566478261-13464-2-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- .../mt8183/mt8183-mt6358-ts3a227-max98357.c | 115 +++++++++++++++++++-- 1 file changed, 109 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 272766c1b859..fe8a7461ace5 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -46,6 +46,32 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static const struct snd_soc_dapm_widget +mt8183_mt6358_ts3a227_max98357_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("IT6505_8CH"), +}; + +static const struct snd_soc_dapm_route +mt8183_mt6358_ts3a227_max98357_dapm_routes[] = { + {"IT6505_8CH", NULL, "TDM"}, +}; + +enum PINCTRL_PIN_STATE { + PIN_STATE_DEFAULT = 0, + PIN_TDM_OUT_ON, + PIN_TDM_OUT_OFF, + PIN_STATE_MAX +}; + +static const char * const mt8183_pin_str[PIN_STATE_MAX] = { + "default", "aud_tdm_out_on", "aud_tdm_out_off", +}; + +struct mt8183_mt6358_ts3a227_max98357_priv { + struct pinctrl *pinctrl; + struct pinctrl_state *pin_states[PIN_STATE_MAX]; +}; + static int mt8183_mt6358_ts3a227_max98357_bt_sco_startup( struct snd_pcm_substream *substream) @@ -173,6 +199,47 @@ SND_SOC_DAILINK_DEFS(tdm, DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); +static int mt8183_mt6358_tdm_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt8183_mt6358_ts3a227_max98357_priv *priv = + snd_soc_card_get_drvdata(rtd->card); + int ret; + + if (IS_ERR(priv->pin_states[PIN_TDM_OUT_ON])) + return PTR_ERR(priv->pin_states[PIN_TDM_OUT_ON]); + + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_TDM_OUT_ON]); + if (ret) + dev_err(rtd->card->dev, "%s failed to select state %d\n", + __func__, ret); + + return ret; +} + +static void mt8183_mt6358_tdm_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt8183_mt6358_ts3a227_max98357_priv *priv = + snd_soc_card_get_drvdata(rtd->card); + int ret; + + if (IS_ERR(priv->pin_states[PIN_TDM_OUT_OFF])) + return; + + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_TDM_OUT_OFF]); + if (ret) + dev_err(rtd->card->dev, "%s failed to select state %d\n", + __func__, ret); +} + +static struct snd_soc_ops mt8183_mt6358_tdm_ops = { + .startup = mt8183_mt6358_tdm_startup, + .shutdown = mt8183_mt6358_tdm_shutdown, +}; + static struct snd_soc_dai_link mt8183_mt6358_ts3a227_max98357_dai_links[] = { /* FE */ @@ -325,6 +392,8 @@ mt8183_mt6358_ts3a227_max98357_dai_links[] = { .no_pcm = 1, .dpcm_playback = 1, .ignore_suspend = 1, + .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, + .ops = &mt8183_mt6358_tdm_ops, SND_SOC_DAILINK_REG(tdm), }, }; @@ -371,7 +440,8 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) struct snd_soc_card *card = &mt8183_mt6358_ts3a227_max98357_card; struct device_node *platform_node; struct snd_soc_dai_link *dai_link; - struct pinctrl *default_pins; + struct mt8183_mt6358_ts3a227_max98357_priv *priv; + int ret; int i; card->dev = &pdev->dev; @@ -397,12 +467,45 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) card->num_aux_devs = 1; } - default_pins = - devm_pinctrl_get_select(&pdev->dev, PINCTRL_STATE_DEFAULT); - if (IS_ERR(default_pins)) { - dev_err(&pdev->dev, "%s set pins failed\n", + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + snd_soc_card_set_drvdata(card, priv); + + priv->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(priv->pinctrl)) { + dev_err(&pdev->dev, "%s devm_pinctrl_get failed\n", __func__); - return PTR_ERR(default_pins); + return PTR_ERR(priv->pinctrl); + } + + for (i = 0 ; i < PIN_STATE_MAX ; i++) { + priv->pin_states[i] = pinctrl_lookup_state(priv->pinctrl, + mt8183_pin_str[i]); + if (IS_ERR(priv->pin_states[i])) { + ret = PTR_ERR(priv->pin_states[i]); + dev_info(&pdev->dev, "%s Can't find pin state %s %d\n", + __func__, mt8183_pin_str[i], ret); + } + } + + if (!IS_ERR(priv->pin_states[PIN_TDM_OUT_OFF])) { + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_TDM_OUT_OFF]); + if (ret) + dev_info(&pdev->dev, + "%s failed to select state %d\n", + __func__, ret); + } + + if (!IS_ERR(priv->pin_states[PIN_STATE_DEFAULT])) { + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_STATE_DEFAULT]); + if (ret) + dev_info(&pdev->dev, + "%s failed to select state %d\n", + __func__, ret); } return devm_snd_soc_register_card(&pdev->dev, card); -- cgit v1.2.3 From 4168ddabb480bef818c93f378428632fb681b500 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 20 Aug 2019 14:04:49 +0900 Subject: ASoC: soc-core: use device_register() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. soc-core.c is using device_unregiser(), but there is no its paired device_regiser(). We can find its code at soc_post_component_init() which is using device_initialize() and device_add(). Here, device_initialize() + device_add() = device_register(). -- linux/drivers/base/core.c -- int device_register(struct device *dev) { device_initialize(dev); return device_add(dev); } device_initialize() is doing each dev member's initialization only, not related to device parent/release/groups. Thus, we can postpone it. let's use device_register() instead of device_initialize()/device_add(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/878sro1ldw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6df880be1622..3860d8521734 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1347,7 +1347,6 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL); if (!rtd->dev) return -ENOMEM; - device_initialize(rtd->dev); rtd->dev->parent = rtd->card->dev; rtd->dev->release = rtd_release; rtd->dev->groups = soc_dev_attr_groups; @@ -1357,7 +1356,7 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients); - ret = device_add(rtd->dev); + ret = device_register(rtd->dev); if (ret < 0) { /* calling put_device() here to free the rtd->dev */ put_device(rtd->dev); -- cgit v1.2.3 From a33c0d166cc5bcb3b9718649b84974216709acb1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 20 Aug 2019 14:05:02 +0900 Subject: ASoC: soc-core: add NOTE to snd_soc_rtdcom_lookup() We can find specified name component via snd_soc_rtdcom_lookup(). But, it is not enough under multi CPU/Codec/Platform, because many components which have same driver name might be connected to same rtd. Not using this function as much as possible is best solution, but some drivers are already deeply depended to it. We can expand this function, for example having "num" which specifies found order at parameter, etc (In such case, it need to have fixed probing order). Or, use different driver name in such component, etc. We will have such issue if multi CPU/Codec/Platform were supported. To indicate it, this patch adds NOTE to this function. Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/874l2c1ldi.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3860d8521734..0ed6576bfef4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -315,6 +315,14 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, if (!driver_name) return NULL; + /* + * NOTE + * + * snd_soc_rtdcom_lookup() will find component from rtd by using + * specified driver name. + * But, if many components which have same driver name are connected + * to 1 rtd, this function will return 1st found component. + */ for_each_rtdcom(rtd, rtdcom) { const char *component_name = rtdcom->component->driver->name; -- cgit v1.2.3 From a4de83a385670c22c31e9bbb726595a447b32ba4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 20 Aug 2019 14:05:10 +0900 Subject: ASoC: soc-core: soc_cleanup_card_resources() become void There is no need to check return value for soc_cleanup_card_resources(). Let't makes it as void. Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/871rxg1lda.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0ed6576bfef4..1be069c2ac8d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1885,7 +1885,7 @@ match: } } -static int soc_cleanup_card_resources(struct snd_soc_card *card) +static void soc_cleanup_card_resources(struct snd_soc_card *card) { /* free the ALSA card at first; this syncs with pending operations */ if (card->snd_card) { @@ -1906,8 +1906,6 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) /* remove the card */ if (card->remove) card->remove(card); - - return 0; } static int snd_soc_instantiate_card(struct snd_soc_card *card) -- cgit v1.2.3 From 43ca5dab978294eae26a36f8989b6f0769da4256 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 20 Aug 2019 14:05:32 +0900 Subject: ASoC: soc-topology: use for_each_component_dais() at remove_dai() commit 52abe6cc1866a ("ASoC: topology: fix oops/use-after-free case with dai driver") fixups remove_dai() error, but it is using list_for_each_entry() for component->dai_list. We already have for_each_component_dais() macro for it. Let's use exising method. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tvaczazd.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index dc463f1a9e24..b8690715abb5 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -530,7 +530,7 @@ static void remove_dai(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->dai_unload) dobj->ops->dai_unload(comp, dobj); - list_for_each_entry(dai, &comp->dai_list, list) + for_each_component_dais(comp, dai) if (dai->driver == dai_drv) dai->driver = NULL; -- cgit v1.2.3 From 8d92bb516831e80fac916701447ee6e9f0a6f0f2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 20 Aug 2019 14:05:16 +0900 Subject: ASoC: soc-core: initialize component list It might return without initializing in error case. In such case, uninitialized variable might be used at error handler. This patch initializes all necessary variable before return. Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87zhk4zazt.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1be069c2ac8d..1a17cb1bc03b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2647,6 +2647,9 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, { struct snd_soc_dapm_context *dapm; + INIT_LIST_HEAD(&component->dai_list); + mutex_init(&component->io_mutex); + component->name = fmt_single_name(dev, &component->id); if (!component->name) { dev_err(dev, "ASoC: Failed to allocate name\n"); @@ -2663,9 +2666,6 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, dapm->idle_bias_off = !driver->idle_bias_on; dapm->suspend_bias_off = driver->suspend_bias_off; - INIT_LIST_HEAD(&component->dai_list); - mutex_init(&component->io_mutex); - return 0; } -- cgit v1.2.3 From b2f3e0c9e4ee2e07fd880cc0c4da20c42d633d4b Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Thu, 22 Aug 2019 00:11:38 +0300 Subject: ASoC: SOF: topology: fix get control data return type and arguments sof_get_control_data returns negative values even though the return value is defined unsigned (size_t). So change the return value type to int and add the data size as pointer argument to sof_get_control_data to avoid ambiquity in the meaning of the return type. Fixes: cac974a51ebb ("ASoC: SOF: topology: use set_get_data in process load") Reported by: Dan Carpenter Signed-off-by: Jaska Uimonen Link: https://lore.kernel.org/r/20190821211138.14618-1-jaska.uimonen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 28a7a6e06a53..fc85efbad378 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1752,17 +1752,19 @@ err: return ret; } -static size_t sof_get_control_data(struct snd_sof_dev *sdev, - struct snd_soc_dapm_widget *widget, - struct sof_widget_data *wdata) +static int sof_get_control_data(struct snd_sof_dev *sdev, + struct snd_soc_dapm_widget *widget, + struct sof_widget_data *wdata, + size_t *size) { const struct snd_kcontrol_new *kc; struct soc_mixer_control *sm; struct soc_bytes_ext *sbe; struct soc_enum *se; - size_t size = 0; int i; + *size = 0; + for (i = 0; i < widget->num_kcontrols; i++) { kc = &widget->kcontrol_news[i]; @@ -1800,7 +1802,7 @@ static size_t sof_get_control_data(struct snd_sof_dev *sdev, if (wdata[i].pdata->magic != SOF_ABI_MAGIC) return -EINVAL; - size += wdata[i].pdata->size; + *size += wdata[i].pdata->size; /* get data type */ switch (wdata[i].control->cmd) { @@ -1819,7 +1821,7 @@ static size_t sof_get_control_data(struct snd_sof_dev *sdev, } } - return size; + return 0; } static int sof_process_load(struct snd_soc_component *scomp, int index, @@ -1855,12 +1857,11 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, return -ENOMEM; /* get possible component controls and get size of all pdata */ - ipc_data_size = sof_get_control_data(sdev, widget, wdata); + ret = sof_get_control_data(sdev, widget, wdata, + &ipc_data_size); - if (ipc_data_size <= 0) { - ret = ipc_data_size; + if (ret < 0) goto out; - } } ipc_size = sizeof(struct sof_ipc_comp_process) + -- cgit v1.2.3 From 495efdb01f89a5fc53f9b2e61f5726d804d4a15d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 20 Aug 2019 14:05:20 +0900 Subject: ASoC: soc-core: initialize list at one place Initialize component related list at random place is very difficult to read. This patch initialize it at snd_soc_component_initialize(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87y2zozazp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1a17cb1bc03b..0af83963289f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1272,7 +1272,6 @@ static int soc_probe_component(struct snd_soc_card *card, component->card = card; dapm->card = card; - INIT_LIST_HEAD(&component->card_list); INIT_LIST_HEAD(&dapm->list); soc_set_name_prefix(card, component); @@ -2648,6 +2647,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, struct snd_soc_dapm_context *dapm; INIT_LIST_HEAD(&component->dai_list); + INIT_LIST_HEAD(&component->dobj_list); + INIT_LIST_HEAD(&component->card_list); mutex_init(&component->io_mutex); component->name = fmt_single_name(dev, &component->id); @@ -2733,7 +2734,6 @@ static void snd_soc_component_add(struct snd_soc_component *component) /* see for_each_component */ list_add(&component->list, &component_list); - INIT_LIST_HEAD(&component->dobj_list); mutex_unlock(&client_mutex); } -- cgit v1.2.3 From 542694df7511977c3baa6ba855126a0cce883977 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 23 Aug 2019 09:58:32 +0900 Subject: ASoC: soc-core: rename soc_post_component_init() to soc_rtd_init() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and it will be difficult to debug. From function name point of view, "soc_post_component_init()" sounds like "component initialize function". But in reality it is rtd setup function. This patch renames soc_post_component_init() to soc_rtd_init() Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v9uo7lc3.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0af83963289f..3c087b478398 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1340,13 +1340,12 @@ err_probe: return ret; } -static void rtd_release(struct device *dev) +static void soc_rtd_release(struct device *dev) { kfree(dev); } -static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, - const char *name) +static int soc_rtd_init(struct snd_soc_pcm_runtime *rtd, const char *name) { int ret = 0; @@ -1355,7 +1354,7 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, if (!rtd->dev) return -ENOMEM; rtd->dev->parent = rtd->card->dev; - rtd->dev->release = rtd_release; + rtd->dev->release = soc_rtd_release; rtd->dev->groups = soc_dev_attr_groups; dev_set_name(rtd->dev, "%s", name); dev_set_drvdata(rtd->dev, rtd); @@ -1483,7 +1482,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, return ret; } - ret = soc_post_component_init(rtd, dai_link->name); + ret = soc_rtd_init(rtd, dai_link->name); if (ret) return ret; -- cgit v1.2.3 From e0ccdef92653f8867e2d1667facfd3c23699f540 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Aug 2019 12:38:07 +0200 Subject: ALSA: usb-audio: Clean up check_input_term() The primary changes in this patch are cleanups of __check_input_term() and move to a non-nested switch-case block by evaluating the pair of UAC version and the unit type, as we've done for parse_audio_unit(). Also each parser is split into the function for readability. Now, a slight behavior change by this cleanup is the handling of processing and extension units. Formerly we've dealt with them differently between UAC1/2 and UAC3; the latter returns an error if no input sources are available, while the former continues to parse. In this patch, unify the behavior in all cases: when input sources are available, it parses recursively, then override the type and the id, as well as channel information if not provided yet. Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 401 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 209 insertions(+), 192 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index a0468c4a6326..83d22f241bdd 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -758,224 +758,242 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state, } /* - * parse the source unit recursively until it reaches to a terminal - * or a branched unit. + * Parse Input Terminal Unit */ static int __check_input_term(struct mixer_build *state, int id, - struct usb_audio_term *term) + struct usb_audio_term *term); + +static int parse_term_uac1_iterm_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) { - int protocol = state->mixer->protocol; + struct uac_input_terminal_descriptor *d = p1; + + term->type = le16_to_cpu(d->wTerminalType); + term->channels = d->bNrChannels; + term->chconfig = le16_to_cpu(d->wChannelConfig); + term->name = d->iTerminal; + return 0; +} + +static int parse_term_uac2_iterm_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac2_input_terminal_descriptor *d = p1; int err; - void *p1; - unsigned char *hdr; - memset(term, 0, sizeof(*term)); - for (;;) { - /* a loop in the terminal chain? */ - if (test_and_set_bit(id, state->termbitmap)) - return -EINVAL; + /* call recursively to verify the referenced clock entity */ + err = __check_input_term(state, d->bCSourceID, term); + if (err < 0) + return err; - p1 = find_audio_control_unit(state, id); - if (!p1) - break; - if (!snd_usb_validate_audio_desc(p1, protocol)) - break; /* bad descriptor */ + /* save input term properties after recursion, + * to ensure they are not overriden by the recursion calls + */ + term->id = id; + term->type = le16_to_cpu(d->wTerminalType); + term->channels = d->bNrChannels; + term->chconfig = le32_to_cpu(d->bmChannelConfig); + term->name = d->iTerminal; + return 0; +} - hdr = p1; - term->id = id; +static int parse_term_uac3_iterm_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac3_input_terminal_descriptor *d = p1; + int err; - if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { - switch (hdr[2]) { - case UAC_INPUT_TERMINAL: - if (protocol == UAC_VERSION_1) { - struct uac_input_terminal_descriptor *d = p1; - - term->type = le16_to_cpu(d->wTerminalType); - term->channels = d->bNrChannels; - term->chconfig = le16_to_cpu(d->wChannelConfig); - term->name = d->iTerminal; - } else { /* UAC_VERSION_2 */ - struct uac2_input_terminal_descriptor *d = p1; - - /* call recursively to verify that the - * referenced clock entity is valid */ - err = __check_input_term(state, d->bCSourceID, term); - if (err < 0) - return err; + /* call recursively to verify the referenced clock entity */ + err = __check_input_term(state, d->bCSourceID, term); + if (err < 0) + return err; - /* save input term properties after recursion, - * to ensure they are not overriden by the - * recursion calls */ - term->id = id; - term->type = le16_to_cpu(d->wTerminalType); - term->channels = d->bNrChannels; - term->chconfig = le32_to_cpu(d->bmChannelConfig); - term->name = d->iTerminal; - } - return 0; - case UAC_FEATURE_UNIT: { - /* the header is the same for v1 and v2 */ - struct uac_feature_unit_descriptor *d = p1; + /* save input term properties after recursion, + * to ensure they are not overriden by the recursion calls + */ + term->id = id; + term->type = le16_to_cpu(d->wTerminalType); - id = d->bSourceID; - break; /* continue to parse */ - } - case UAC_MIXER_UNIT: { - struct uac_mixer_unit_descriptor *d = p1; - - term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ - term->channels = uac_mixer_unit_bNrChannels(d); - term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol); - term->name = uac_mixer_unit_iMixer(d); - return 0; - } - case UAC_SELECTOR_UNIT: - case UAC2_CLOCK_SELECTOR: { - struct uac_selector_unit_descriptor *d = p1; - /* call recursively to retrieve the channel info */ - err = __check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; - term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ - term->id = id; - term->name = uac_selector_unit_iSelector(d); - return 0; - } - case UAC1_PROCESSING_UNIT: - /* UAC2_EFFECT_UNIT */ - if (protocol == UAC_VERSION_1) - term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ - else /* UAC_VERSION_2 */ - term->type = UAC3_EFFECT_UNIT << 16; /* virtual type */ - /* fall through */ - case UAC1_EXTENSION_UNIT: - /* UAC2_PROCESSING_UNIT_V2 */ - if (protocol == UAC_VERSION_1 && !term->type) - term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */ - else if (protocol == UAC_VERSION_2 && !term->type) - term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ - /* fall through */ - case UAC2_EXTENSION_UNIT_V2: { - struct uac_processing_unit_descriptor *d = p1; - - if (protocol == UAC_VERSION_2 && - hdr[2] == UAC2_EFFECT_UNIT) { - /* UAC2/UAC1 unit IDs overlap here in an - * uncompatible way. Ignore this unit for now. - */ - return 0; - } + err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID)); + if (err < 0) + return err; + term->channels = err; - if (d->bNrInPins) { - id = d->baSourceID[0]; - break; /* continue to parse */ - } - if (!term->type) - term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */ + /* REVISIT: UAC3 IT doesn't have channels cfg */ + term->chconfig = 0; - term->channels = uac_processing_unit_bNrChannels(d); - term->chconfig = uac_processing_unit_wChannelConfig(d, protocol); - term->name = uac_processing_unit_iProcessing(d, protocol); - return 0; - } - case UAC2_CLOCK_SOURCE: { - struct uac_clock_source_descriptor *d = p1; + term->name = le16_to_cpu(d->wTerminalDescrStr); + return 0; +} - term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ - term->id = id; - term->name = d->iClockSource; - return 0; - } - default: - return -ENODEV; - } - } else { /* UAC_VERSION_3 */ - switch (hdr[2]) { - case UAC_INPUT_TERMINAL: { - struct uac3_input_terminal_descriptor *d = p1; - - /* call recursively to verify that the - * referenced clock entity is valid */ - err = __check_input_term(state, d->bCSourceID, term); - if (err < 0) - return err; +static int parse_term_mixer_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac_mixer_unit_descriptor *d = p1; + int protocol = state->mixer->protocol; + int err; - /* save input term properties after recursion, - * to ensure they are not overriden by the - * recursion calls */ - term->id = id; - term->type = le16_to_cpu(d->wTerminalType); + err = uac_mixer_unit_get_channels(state, d); + if (err <= 0) + return err; - err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID)); - if (err < 0) - return err; - term->channels = err; + term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ + term->channels = err; + if (protocol != UAC_VERSION_3) { + term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol); + term->name = uac_mixer_unit_iMixer(d); + } + return 0; +} + +static int parse_term_selector_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac_selector_unit_descriptor *d = p1; + int err; - /* REVISIT: UAC3 IT doesn't have channels cfg */ - term->chconfig = 0; + /* call recursively to retrieve the channel info */ + err = __check_input_term(state, d->baSourceID[0], term); + if (err < 0) + return err; + term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ + term->id = id; + if (state->mixer->protocol != UAC_VERSION_3) + term->name = uac_selector_unit_iSelector(d); + return 0; +} - term->name = le16_to_cpu(d->wTerminalDescrStr); - return 0; - } - case UAC3_FEATURE_UNIT: { - struct uac3_feature_unit_descriptor *d = p1; +static int parse_term_proc_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id, int vtype) +{ + struct uac_processing_unit_descriptor *d = p1; + int protocol = state->mixer->protocol; + int err; - id = d->bSourceID; - break; /* continue to parse */ - } - case UAC3_CLOCK_SOURCE: { - struct uac3_clock_source_descriptor *d = p1; + if (d->bNrInPins) { + /* call recursively to retrieve the channel info */ + err = __check_input_term(state, d->baSourceID[0], term); + if (err < 0) + return err; + } - term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ - term->id = id; - term->name = le16_to_cpu(d->wClockSourceStr); - return 0; - } - case UAC3_MIXER_UNIT: { - struct uac_mixer_unit_descriptor *d = p1; + term->type = vtype << 16; /* virtual type */ + term->id = id; - err = uac_mixer_unit_get_channels(state, d); - if (err <= 0) - return err; + if (protocol == UAC_VERSION_3) + return 0; - term->channels = err; - term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ + if (!term->channels) { + term->channels = uac_processing_unit_bNrChannels(d); + term->chconfig = uac_processing_unit_wChannelConfig(d, protocol); + } + term->name = uac_processing_unit_iProcessing(d, protocol); + return 0; +} - return 0; - } - case UAC3_SELECTOR_UNIT: - case UAC3_CLOCK_SELECTOR: { - struct uac_selector_unit_descriptor *d = p1; - /* call recursively to retrieve the channel info */ - err = __check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; - term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ - term->id = id; - term->name = 0; /* TODO: UAC3 Class-specific strings */ +static int parse_term_uac2_clock_source(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac_clock_source_descriptor *d = p1; - return 0; - } - case UAC3_PROCESSING_UNIT: { - struct uac_processing_unit_descriptor *d = p1; + term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ + term->id = id; + term->name = d->iClockSource; + return 0; +} - if (!d->bNrInPins) - return -EINVAL; +static int parse_term_uac3_clock_source(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac3_clock_source_descriptor *d = p1; - /* call recursively to retrieve the channel info */ - err = __check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; + term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ + term->id = id; + term->name = le16_to_cpu(d->wClockSourceStr); + return 0; +} - term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ - term->id = id; - term->name = 0; /* TODO: UAC3 Class-specific strings */ +#define PTYPE(a, b) ((a) << 8 | (b)) - return 0; - } - default: - return -ENODEV; - } +/* + * parse the source unit recursively until it reaches to a terminal + * or a branched unit. + */ +static int __check_input_term(struct mixer_build *state, int id, + struct usb_audio_term *term) +{ + int protocol = state->mixer->protocol; + void *p1; + unsigned char *hdr; + + for (;;) { + /* a loop in the terminal chain? */ + if (test_and_set_bit(id, state->termbitmap)) + return -EINVAL; + + p1 = find_audio_control_unit(state, id); + if (!p1) + break; + if (!snd_usb_validate_audio_desc(p1, protocol)) + break; /* bad descriptor */ + + hdr = p1; + term->id = id; + + switch (PTYPE(protocol, hdr[2])) { + case PTYPE(UAC_VERSION_1, UAC_FEATURE_UNIT): + case PTYPE(UAC_VERSION_2, UAC_FEATURE_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_FEATURE_UNIT): { + /* the header is the same for all versions */ + struct uac_feature_unit_descriptor *d = p1; + + id = d->bSourceID; + break; /* continue to parse */ + } + case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL): + return parse_term_uac1_iterm_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL): + return parse_term_uac2_iterm_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_3, UAC_INPUT_TERMINAL): + return parse_term_uac3_iterm_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_1, UAC_MIXER_UNIT): + case PTYPE(UAC_VERSION_2, UAC_MIXER_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_MIXER_UNIT): + return parse_term_mixer_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_1, UAC_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_2, UAC_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SELECTOR): + case PTYPE(UAC_VERSION_3, UAC3_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SELECTOR): + return parse_term_selector_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_1, UAC1_PROCESSING_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2): + case PTYPE(UAC_VERSION_3, UAC3_PROCESSING_UNIT): + return parse_term_proc_unit(state, term, p1, id, + UAC3_PROCESSING_UNIT); + case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT): + return parse_term_proc_unit(state, term, p1, id, + UAC3_EFFECT_UNIT); + case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2): + case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT): + return parse_term_proc_unit(state, term, p1, id, + UAC3_EXTENSION_UNIT); + case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SOURCE): + return parse_term_uac2_clock_source(state, term, p1, id); + case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SOURCE): + return parse_term_uac3_clock_source(state, term, p1, id); + default: + return -ENODEV; } } return -ENODEV; @@ -2712,7 +2730,6 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) return 0; /* skip invalid unit */ } -#define PTYPE(a, b) ((a) << 8 | (b)) switch (PTYPE(protocol, p1[2])) { case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL): case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL): -- cgit v1.2.3 From 60849562a5db4a1eee2160167e4dce4590d3eafe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Aug 2019 13:55:21 +0200 Subject: ALSA: usb-audio: Fix possible NULL dereference at create_yamaha_midi_quirk() The previous addition of descriptor validation may lead to a NULL dereference at create_yamaha_midi_quirk() when either injd or outjd is NULL. Add proper non-NULL checks. Fixes: 57f8770620e9 ("ALSA: usb-audio: More validations of descriptor units") Reported-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 7e9735aa7ac9..5c0fa5cf1987 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -248,8 +248,8 @@ static int create_yamaha_midi_quirk(struct snd_usb_audio *chip, NULL, USB_MS_MIDI_OUT_JACK); if (!injd && !outjd) return -ENODEV; - if (!snd_usb_validate_midi_desc(injd) || - !snd_usb_validate_midi_desc(outjd)) + if (!(injd && snd_usb_validate_midi_desc(injd)) || + !(outjd && snd_usb_validate_midi_desc(outjd))) return -ENODEV; if (injd && (injd->bLength < 5 || (injd->bJackType != USB_MS_EMBEDDED && -- cgit v1.2.3 From b39e077fcb283dd96dd251a3abeba585402c61fe Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 26 Aug 2019 16:45:50 +0300 Subject: ALSA: usb-audio: remove some dead code We recently cleaned up the error handling in commit 52c3e317a857 ("ALSA: usb-audio: Unify the release of usb_mixer_elem_info objects") but accidentally left this stray return. Fixes: 52c3e317a857 ("ALSA: usb-audio: Unify the release of usb_mixer_elem_info objects") Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 83d22f241bdd..3fd1d1749edf 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2651,7 +2651,6 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, usb_audio_err(state->chip, "cannot malloc kcontrol\n"); err = -ENOMEM; goto error_name; - return -ENOMEM; } kctl->private_value = (unsigned long)namelist; kctl->private_free = usb_mixer_selector_elem_free; -- cgit v1.2.3 From 4c098dab121a4164e9daa4d1ddbc59e93054e79e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 26 Aug 2019 22:54:15 +0900 Subject: ALSA: oxfw: fix NULL pointer dereference to unused stream structure ALSA oxfw driver supports Griffin FireWave. This device supports one isochronous stream for PCM playback. Current driver executes code to wait event for stream structure of opposite direction. This causes NULL pointer dereference. This commit fixes the bug. Fixes: ac5d77864cfc ("ALSA: oxfw: support AMDTP domain") Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-stream.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 0318dc4dcc55..3c9a796b6526 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -350,13 +350,18 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw) // Wait first packet. if (!amdtp_stream_wait_callback(&oxfw->rx_stream, - CALLBACK_TIMEOUT) || - !amdtp_stream_wait_callback(&oxfw->tx_stream, CALLBACK_TIMEOUT)) { err = -ETIMEDOUT; goto error; } + if (oxfw->has_output) { + if (!amdtp_stream_wait_callback(&oxfw->tx_stream, + CALLBACK_TIMEOUT)) { + err = -ETIMEDOUT; + goto error; + } + } } return 0; -- cgit v1.2.3 From b9a4805a4ac1200326ee0c78df0ae3faceabad49 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 23 Aug 2019 20:59:39 +0800 Subject: ASoC: SOF: imx8: Make some functions static Fix sparse warnings: sound/soc/sof/imx/imx8.c:104:6: warning: symbol 'imx8_dsp_handle_reply' was not declared. Should it be static? sound/soc/sof/imx/imx8.c:115:6: warning: symbol 'imx8_dsp_handle_request' was not declared. Should it be static? sound/soc/sof/imx/imx8.c:336:5: warning: symbol 'imx8_get_bar_index' was not declared. Should it be static? sound/soc/sof/imx/imx8.c:341:6: warning: symbol 'imx8_ipc_msg_data' was not declared. Should it be static? sound/soc/sof/imx/imx8.c:348:5: warning: symbol 'imx8_ipc_pcm_params' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: YueHaibing Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/20190823125939.30012-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index e502f584207f..640472491037 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -101,7 +101,7 @@ static int imx8_get_window_offset(struct snd_sof_dev *sdev, u32 id) return MBOX_OFFSET; } -void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc) +static void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc) { struct imx8_priv *priv = imx_dsp_get_data(ipc); unsigned long flags; @@ -112,7 +112,7 @@ void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc) spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); } -void imx8_dsp_handle_request(struct imx_dsp_ipc *ipc) +static void imx8_dsp_handle_request(struct imx_dsp_ipc *ipc) { struct imx8_priv *priv = imx_dsp_get_data(ipc); @@ -333,21 +333,21 @@ static int imx8_remove(struct snd_sof_dev *sdev) } /* on i.MX8 there is 1 to 1 match between type and BAR idx */ -int imx8_get_bar_index(struct snd_sof_dev *sdev, u32 type) +static int imx8_get_bar_index(struct snd_sof_dev *sdev, u32 type) { return type; } -void imx8_ipc_msg_data(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - void *p, size_t sz) +static void imx8_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) { sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); } -int imx8_ipc_pcm_params(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - const struct sof_ipc_pcm_params_reply *reply) +static int imx8_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) { return 0; } -- cgit v1.2.3 From 9573820eb1951e0cb0f329886abcb4153f2ea798 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 27 Aug 2019 11:55:15 -0400 Subject: ASoC: imx-audmix: register the card on a proper dev This platform device is registered from "fsl_audmix", which is its parent device. If use pdev->dev.parent for the priv->card.dev, the value set by dev_set_drvdata in parent device will be covered by the value in child device. Fixes: b86ef5367761 ("ASoC: fsl: Add Audio Mixer machine driver") Signed-off-by: Viorel Suman Signed-off-by: Shengjiu Wang Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/1566921315-23402-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-audmix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c index 9e1cb18859ce..71590ca6394b 100644 --- a/sound/soc/fsl/imx-audmix.c +++ b/sound/soc/fsl/imx-audmix.c @@ -325,14 +325,14 @@ static int imx_audmix_probe(struct platform_device *pdev) priv->card.num_configs = priv->num_dai_conf; priv->card.dapm_routes = priv->dapm_routes; priv->card.num_dapm_routes = priv->num_dapm_routes; - priv->card.dev = pdev->dev.parent; + priv->card.dev = &pdev->dev; priv->card.owner = THIS_MODULE; priv->card.name = "imx-audmix"; platform_set_drvdata(pdev, &priv->card); snd_soc_card_set_drvdata(&priv->card, priv); - ret = devm_snd_soc_register_card(pdev->dev.parent, &priv->card); + ret = devm_snd_soc_register_card(&pdev->dev, &priv->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed\n"); return ret; -- cgit v1.2.3 From 455b1d42e82c6027b9763f0055b54e45ff6cd7fd Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 27 Aug 2019 11:32:05 +0200 Subject: ASoC: sunxi: Revert initial A83t support This reverts commit 3e9acd7ac6933c (ASoC: sun4i-i2s: Remove duplicated quirks structure"). It turns out that while one I2S controller is described in the A83t datasheet, the driver supports another, undocumented, one that has been inherited from the older SoCs, while the documented one uses the new design. Fixes: 3e9acd7ac693 ("ASoC: sun4i-i2s: Remove duplicated quirks structure") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20190827093206.17919-1-mripard@kernel.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 57bf2a33753e..a6a3f772fdf0 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1097,6 +1097,11 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .set_fmt = sun4i_i2s_set_soc_fmt, }; +/* + * This doesn't describe the TDM controller documented in the A83t + * datasheet, but the three undocumented I2S controller that use the + * older design. + */ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, @@ -1115,6 +1120,24 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .set_fmt = sun8i_i2s_set_soc_fmt, }; +static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { + .has_reset = true, + .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, + .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, + .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), + .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), + .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), + .bclk_dividers = sun8i_i2s_clk_div, + .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), + .mclk_dividers = sun8i_i2s_clk_div, + .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), + .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, + .get_sr = sun8i_i2s_get_sr_wss, + .get_wss = sun8i_i2s_get_sr_wss, + .set_chan_cfg = sun8i_i2s_set_chan_cfg, + .set_fmt = sun8i_i2s_set_soc_fmt, +}; + static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, @@ -1296,7 +1319,7 @@ static const struct of_device_id sun4i_i2s_match[] = { }, { .compatible = "allwinner,sun8i-h3-i2s", - .data = &sun8i_a83t_i2s_quirks, + .data = &sun8i_h3_i2s_quirks, }, { .compatible = "allwinner,sun50i-a64-codec-i2s", -- cgit v1.2.3 From dd23e1d566d0f74aa3b68ab3237927bb15f0e644 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Aug 2019 16:37:50 +0200 Subject: ALSA: hda - Allow runtime PM for controller if component notifier is used Currently we disallow the runtime PM of the HD-audio controller if it's bound with HDMI/DP on Nvidia / AMD unless it's for dGPU. This is for keeping the link up to get the proper notification for ELD hotplug. As explained in the commit 37a3a98ef601 ("ALSA: hda - Enable runtime PM only for discrete GPU"), this keep-power-up behavior is rather a stop-gap solution until the ELD notification via audio component. And now we finally got the audio component for these graphics drivers via commit ade49db337a9 ("ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI"), so it's time to change. This patch makes HD-audio controller again runtime-suspendable when the device gets bound with audio component in HDMI codec driver. For making it easier to access from the codec driver, move the flag into the common hda_bus object instead of hda_intel flag. Also rename it to keep_power, to indicate the actual meaning. Signed-off-by: Takashi Iwai --- include/sound/hda_codec.h | 1 + sound/pci/hda/hda_intel.c | 11 +++++------ sound/pci/hda/hda_intel.h | 1 - sound/pci/hda/patch_hdmi.c | 4 +++- 4 files changed, 9 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 871993696c5f..9a0393cf024c 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -59,6 +59,7 @@ struct hda_bus { unsigned int in_reset:1; /* during reset operation */ unsigned int no_response_fallback:1; /* don't fallback at RIRB error */ unsigned int bus_probing :1; /* during probing process */ + unsigned int keep_power:1; /* keep power up for notification */ int primary_dig_out_type; /* primary digital out PCM type */ unsigned int mixer_assigned; /* codec addr for mixer name */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 4496fce21300..91e71be42fa4 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -356,7 +356,7 @@ enum { */ #ifdef SUPPORT_VGA_SWITCHEROO #define use_vga_switcheroo(chip) ((chip)->use_vga_switcheroo) -#define needs_eld_notify_link(chip) ((chip)->need_eld_notify_link) +#define needs_eld_notify_link(chip) ((chip)->bus.keep_power) #else #define use_vga_switcheroo(chip) 0 #define needs_eld_notify_link(chip) false @@ -1145,7 +1145,7 @@ static int azx_runtime_idle(struct device *dev) return -EBUSY; /* ELD notification gets broken when HD-audio bus is off */ - if (needs_eld_notify_link(hda)) + if (needs_eld_notify_link(chip)) return -EBUSY; return 0; @@ -1256,7 +1256,7 @@ static void setup_vga_switcheroo_runtime_pm(struct azx *chip) struct hda_intel *hda = container_of(chip, struct hda_intel, chip); struct hda_codec *codec; - if (hda->use_vga_switcheroo && !hda->need_eld_notify_link) { + if (hda->use_vga_switcheroo && !needs_eld_notify_link(chip)) { list_for_each_codec(codec, &chip->bus) codec->auto_runtime_pm = 1; /* reset the power save setup */ @@ -1270,10 +1270,9 @@ static void azx_vs_gpu_bound(struct pci_dev *pci, { struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); if (client_id == VGA_SWITCHEROO_DIS) - hda->need_eld_notify_link = 0; + chip->bus.keep_power = 0; setup_vga_switcheroo_runtime_pm(chip); } @@ -1285,7 +1284,7 @@ static void init_vga_switcheroo(struct azx *chip) dev_info(chip->card->dev, "Handle vga_switcheroo audio client\n"); hda->use_vga_switcheroo = 1; - hda->need_eld_notify_link = 1; /* cleared in gpu_bound op */ + chip->bus.keep_power = 1; /* cleared in either gpu_bound op or codec probe */ chip->driver_caps |= AZX_DCAPS_PM_RUNTIME; pci_dev_put(p); } diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h index 1468865e0342..2acfff3da1a0 100644 --- a/sound/pci/hda/hda_intel.h +++ b/sound/pci/hda/hda_intel.h @@ -25,7 +25,6 @@ struct hda_intel { /* vga_switcheroo setup */ unsigned int use_vga_switcheroo:1; - unsigned int need_eld_notify_link:1; unsigned int vga_switcheroo_registered:1; unsigned int init_failed:1; /* delayed init failed */ diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 933c7bf47ef6..83b8b9d27711 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2542,8 +2542,10 @@ static void generic_acomp_init(struct hda_codec *codec, spec->port2pin = port2pin; setup_drm_audio_ops(codec, ops); if (!snd_hdac_acomp_init(&codec->bus->core, &spec->drm_audio_ops, - match_bound_vga, 0)) + match_bound_vga, 0)) { spec->acomp_registered = true; + codec->bus->keep_power = 0; + } } /* -- cgit v1.2.3 From 3cdc3c9fd9fa92bcef777512d9f4eef854f9a4ed Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 26 Aug 2019 11:26:42 +0800 Subject: ASoC: mediatek: mt8183: remove unused DAPM-related variables Remove unused variable mt8183_mt6358_ts3a227_max98357_dapm_widgets and mt8183_mt6358_ts3a227_max98357_dapm_routes. They are accidentially included when rebasing commits. Fixes: 6191cbde5ff0 ("ASoC: mediatek: mt8183: switch tdm pins gpio function when playback on or off") Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20190826032642.27324-1-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index fe8a7461ace5..951706fa75fc 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -46,16 +46,6 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static const struct snd_soc_dapm_widget -mt8183_mt6358_ts3a227_max98357_dapm_widgets[] = { - SND_SOC_DAPM_OUTPUT("IT6505_8CH"), -}; - -static const struct snd_soc_dapm_route -mt8183_mt6358_ts3a227_max98357_dapm_routes[] = { - {"IT6505_8CH", NULL, "TDM"}, -}; - enum PINCTRL_PIN_STATE { PIN_STATE_DEFAULT = 0, PIN_TDM_OUT_ON, -- cgit v1.2.3 From 393151c211006cc5ac6af26ecd9982dd916a8104 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 26 Aug 2019 12:00:03 +0000 Subject: ASoC: SOF: imx8: Fix return value check in imx8_probe() In case of error, the function devm_ioremap_wc() returns NULL pointer not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Fixes: 202acc565a1f ("ASoC: SOF: imx: Add i.MX8 HW support") Signed-off-by: Wei Yongjun Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/20190826120003.183279-1-weiyongjun1@huawei.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 640472491037..c9d849ced54a 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -296,10 +296,10 @@ static int imx8_probe(struct snd_sof_dev *sdev) sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start, res.end - res.start + 1); - if (IS_ERR(sdev->bar[SOF_FW_BLK_TYPE_SRAM])) { + if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n", base, size); - ret = PTR_ERR(sdev->bar[SOF_FW_BLK_TYPE_SRAM]); + ret = -ENOMEM; goto exit_pdev_unregister; } sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; -- cgit v1.2.3 From 9ec05d4723bf83dd272cef5ccf508e5fe4d30fa3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 27 Aug 2019 14:31:31 +0200 Subject: ASoC: sun4i: Revert A83t description The last set of reworks included some fixes to change the A83t behaviour and "fix" it. It turns out that the controller described in the datasheet and the one supported here are not the same, yet the A83t has the two of them, and the one supported in the driver wasn't the one described in the datasheet. Fix this by reintroducing the proper quirks. Fixes: 69e450e50ca6 ("ASoC: sun4i-i2s: Fix the LRCK period on A83t") Fixes: bf943d527987 ("ASoC: sun4i-i2s: Fix MCLK Enable bit offset on A83t") Fixes: 2e04fc4dbf50 ("ASoC: sun4i-i2s: Fix WSS and SR fields for the A83t") Fixes: 515fcfbc7736 ("ASoC: sun4i-i2s: Fix LRCK and BCLK polarity offsets on newer SoCs") Fixes: c1d3a921d72b ("ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs") Fixes: fb19739d7f68 ("ASoC: sun4i-i2s: Use module clock as BCLK parent on newer SoCs") Fixes: 71137bcd0a9a ("ASoC: sun4i-i2s: Move the format configuration to a callback") Fixes: d70be625f25a ("ASoC: sun4i-i2s: Move the channel configuration to a callback") Reported-by: Chen-Yu Tsai Tested-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20190827123131.29129-2-mripard@kernel.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index a6a3f772fdf0..d0a8d5810c0a 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1106,18 +1106,18 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, - .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), - .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), - .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), - .bclk_dividers = sun8i_i2s_clk_div, - .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), - .mclk_dividers = sun8i_i2s_clk_div, - .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), - .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, - .get_sr = sun8i_i2s_get_sr_wss, - .get_wss = sun8i_i2s_get_sr_wss, - .set_chan_cfg = sun8i_i2s_set_chan_cfg, - .set_fmt = sun8i_i2s_set_soc_fmt, + .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), + .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), + .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), + .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, + .get_sr = sun4i_i2s_get_sr, + .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, }; static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { -- cgit v1.2.3 From a325c7bc3a92f1d5ba8cff10d7ab93a989cdeb80 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 26 Aug 2019 16:18:55 +0300 Subject: ASoC: SOF: imx8: Fix an is IS_ERR() vs NULL check The device_link_add() function only returns NULL on error, it doesn't return error pointers. Fixes: 202acc565a1f ("ASoC: SOF: imx: Add i.MX8 HW support") Signed-off-by: Dan Carpenter Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/20190826131855.GA6840@mwanda Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index c9d849ced54a..2a22b18e5ec0 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -227,8 +227,8 @@ static int imx8_probe(struct snd_sof_dev *sdev) DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); - if (IS_ERR(priv->link[i])) { - ret = PTR_ERR(priv->link[i]); + if (!priv->link[i]) { + ret = -ENOMEM; dev_pm_domain_detach(priv->pd_dev[i], false); goto exit_unroll_pm; } -- cgit v1.2.3 From 17d29ff98fd4b70e9ccdac5e95e18a087e2737ef Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Tue, 27 Aug 2019 16:17:07 +0200 Subject: ASoC: Intel: Skylake: Use correct function to access iomem space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For copying from __iomem, we should use __ioread32_copy. reported by sparse: sound/soc/intel/skylake/skl-debug.c:437:34: warning: incorrect type in argument 1 (different address spaces) sound/soc/intel/skylake/skl-debug.c:437:34: expected void [noderef] *to sound/soc/intel/skylake/skl-debug.c:437:34: got unsigned char * sound/soc/intel/skylake/skl-debug.c:437:51: warning: incorrect type in argument 2 (different address spaces) sound/soc/intel/skylake/skl-debug.c:437:51: expected void const *from sound/soc/intel/skylake/skl-debug.c:437:51: got void [noderef] *[assigned] fw_reg_addr Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20190827141712.21015-2-amadeuszx.slawinski@linux.intel.com Reviewed-by: Pierre-Louis Bossart Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/intel/skylake/skl-debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c index b9b4a72a4334..b28a9c2b0380 100644 --- a/sound/soc/intel/skylake/skl-debug.c +++ b/sound/soc/intel/skylake/skl-debug.c @@ -188,7 +188,7 @@ static ssize_t fw_softreg_read(struct file *file, char __user *user_buf, memset(d->fw_read_buff, 0, FW_REG_BUF); if (w0_stat_sz > 0) - __iowrite32_copy(d->fw_read_buff, fw_reg_addr, w0_stat_sz >> 2); + __ioread32_copy(d->fw_read_buff, fw_reg_addr, w0_stat_sz >> 2); for (offset = 0; offset < FW_REG_SIZE; offset += 16) { ret += snprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset); -- cgit v1.2.3 From 810f3b860850148788fc1ed8a6f5f807199fed65 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Tue, 27 Aug 2019 16:17:08 +0200 Subject: ASoC: Intel: Fix use of potentially uninitialized variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If ipc->ops.reply_msg_match is NULL, we may end up using uninitialized mask value. reported by smatch: sound/soc/intel/common/sst-ipc.c:266 sst_ipc_reply_find_msg() error: uninitialized symbol 'mask'. Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20190827141712.21015-3-amadeuszx.slawinski@linux.intel.com Reviewed-by: Pierre-Louis Bossart Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/intel/common/sst-ipc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index ef5b66af1cd2..3a66121ee9bb 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -222,6 +222,8 @@ struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, if (ipc->ops.reply_msg_match != NULL) header = ipc->ops.reply_msg_match(header, &mask); + else + mask = (u64)-1; if (list_empty(&ipc->rx_list)) { dev_err(ipc->dev, "error: rx list empty but received 0x%llx\n", -- cgit v1.2.3 From db33f00d15a63d269e283bad3f6f61eb00d2bc9d Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Tue, 27 Aug 2019 16:17:09 +0200 Subject: ASoC: dapm: Expose snd_soc_dapm_new_control_unlocked properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use snd_soc_dapm_new_control_unlocked for topology and have local declaration, instead declare it properly in header like already declared snd_soc_dapm_new_control. Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20190827141712.21015-4-amadeuszx.slawinski@linux.intel.com Reviewed-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 3 +++ sound/soc/soc-topology.c | 6 ------ 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index c00a0b8ade08..8a90816a6eb5 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -402,6 +402,9 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *snd_soc_dapm_new_control( struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget); +struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked( + struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_widget *widget); int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, struct snd_soc_dai *dai); int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index dc463f1a9e24..2eca85c04a3e 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -80,12 +80,6 @@ struct soc_tplg { static int soc_tplg_process_headers(struct soc_tplg *tplg); static void soc_tplg_complete(struct soc_tplg *tplg); -struct snd_soc_dapm_widget * -snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget); -struct snd_soc_dapm_widget * -snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget); static void soc_tplg_denum_remove_texts(struct soc_enum *se); static void soc_tplg_denum_remove_values(struct soc_enum *se); -- cgit v1.2.3 From 855a06da37a773fd073d51023ac9d07988c87da8 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Tue, 27 Aug 2019 16:17:12 +0200 Subject: ASoC: Intel: NHLT: Fix debug print format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit oem_table_id is 8 chars long, so we need to limit it, otherwise it may print some unprintable characters into dmesg. Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20190827141712.21015-7-amadeuszx.slawinski@linux.intel.com Reviewed-by: Pierre-Louis Bossart Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/intel/skylake/skl-nhlt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 1132109cb992..e01815cec6fd 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -225,7 +225,7 @@ int skl_nhlt_update_topology_bin(struct skl *skl) struct hdac_bus *bus = skl_to_bus(skl); struct device *dev = bus->dev; - dev_dbg(dev, "oem_id %.6s, oem_table_id %8s oem_revision %d\n", + dev_dbg(dev, "oem_id %.6s, oem_table_id %.8s oem_revision %d\n", nhlt->header.oem_id, nhlt->header.oem_table_id, nhlt->header.oem_revision); -- cgit v1.2.3 From 0cc33cecb4a1de5b55d382b8e24a128a3551a031 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Tue, 27 Aug 2019 16:17:10 +0200 Subject: ASoC: Intel: Skylake: Print module type instead of id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we are printing module params, we were actually printing module id instead of type, but debug message was saying that number we get is type. So print module type, as it is useful when debugging paths, but also keep printing module id, as it is used in all other logs. Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20190827141712.21015-5-amadeuszx.slawinski@linux.intel.com Reviewed-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index d43496c5f29e..476ef1897961 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -867,8 +867,9 @@ static int skl_set_module_format(struct skl_dev *skl, } - dev_dbg(skl->dev, "Module type=%d config size: %d bytes\n", - module_config->id.module_id, param_size); + dev_dbg(skl->dev, "Module type=%d id=%d config size: %d bytes\n", + module_config->m_type, module_config->id.module_id, + param_size); print_hex_dump_debug("Module params:", DUMP_PREFIX_OFFSET, 8, 4, *param_data, param_size, false); return 0; -- cgit v1.2.3 From 6f43791713c5bb1212ec8497034275dfdbba5cbd Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Tue, 27 Aug 2019 16:17:11 +0200 Subject: ASoC: Intel: Skylake: Release topology when we are done with it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently topology is kept in memory while driver is running. It's unnecessary, as it's only needed during parsing. Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20190827141712.21015-6-amadeuszx.slawinski@linux.intel.com Reviewed-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 20 ++++++++++---------- sound/soc/intel/skylake/skl.h | 1 - 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index ae5c75d03fdc..69cd7a81bf2a 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -3579,23 +3579,25 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus) * The complete tplg for SKL is loaded as index 0, we don't use * any other index */ - ret = snd_soc_tplg_component_load(component, - &skl_tplg_ops, fw, 0); + ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw, 0); if (ret < 0) { dev_err(bus->dev, "tplg component load failed%d\n", ret); - release_firmware(fw); - return -EINVAL; + goto err; } - skl->tplg = fw; ret = skl_tplg_create_pipe_widget_list(component); - if (ret < 0) - return ret; + if (ret < 0) { + dev_err(bus->dev, "tplg create pipe widget list failed%d\n", + ret); + goto err; + } list_for_each_entry(ppl, &skl->ppl_list, node) skl_tplg_set_pipe_type(skl, ppl->pipe); - return 0; +err: + release_firmware(fw); + return ret; } void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus) @@ -3609,6 +3611,4 @@ void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus) /* clean up topology */ snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); - - release_firmware(skl->tplg); } diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index f8c714153610..2bfbf59277c4 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -75,7 +75,6 @@ struct skl_dev { const char *fw_name; char tplg_name[64]; unsigned short pci_id; - const struct firmware *tplg; int supend_active; -- cgit v1.2.3 From f972d02fee2496024cfd6f59021c9d89d54922a6 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Tue, 27 Aug 2019 00:38:59 +0900 Subject: ASoC: es8316: fix headphone mixer volume table This patch fix setting table of Headphone mixer volume. Current code uses 4 ... 7 values but these values are prohibited. Correct settings are the following: 0000 -12dB 0001 -10.5dB 0010 -9dB 0011 -7.5dB 0100 -6dB 1000 -4.5dB 1001 -3dB 1010 -1.5dB 1011 0dB Signed-off-by: Katsuhiro Suzuki Reviewed-by: Daniel Drake Link: https://lore.kernel.org/r/20190826153900.25969-1-katsuhiro@katsuster.net Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 6db002cc2058..96d04896193f 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -51,7 +51,10 @@ static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9600, 50, 1); static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_max_gain_tlv, -650, 150, 0); static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_min_gain_tlv, -1200, 150, 0); static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_target_tlv, -1650, 150, 0); -static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(hpmixer_gain_tlv, -1200, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(hpmixer_gain_tlv, + 0, 4, TLV_DB_SCALE_ITEM(-1200, 150, 0), + 8, 11, TLV_DB_SCALE_ITEM(-450, 150, 0), +); static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(adc_pga_gain_tlv, 0, 0, TLV_DB_SCALE_ITEM(-350, 0, 0), @@ -89,7 +92,7 @@ static const struct snd_kcontrol_new es8316_snd_controls[] = { SOC_DOUBLE_TLV("Headphone Playback Volume", ES8316_CPHP_ICAL_VOL, 4, 0, 3, 1, hpout_vol_tlv), SOC_DOUBLE_TLV("Headphone Mixer Volume", ES8316_HPMIX_VOL, - 0, 4, 7, 0, hpmixer_gain_tlv), + 0, 4, 11, 0, hpmixer_gain_tlv), SOC_ENUM("Playback Polarity", dacpol), SOC_DOUBLE_R_TLV("DAC Playback Volume", ES8316_DAC_VOLL, -- cgit v1.2.3 From f6e77921969003eaf5dbae9c0b5feeb20c6caf50 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Tue, 27 Aug 2019 00:39:00 +0900 Subject: ASoC: es8316: fix inverted L/R of headphone mixer volume This patch fixes inverted Left-Right channel of headphone mixer volume by wrong shift_left, shift_right values. Signed-off-by: Katsuhiro Suzuki Reviewed-by: Daniel Drake Link: https://lore.kernel.org/r/20190826153900.25969-2-katsuhiro@katsuster.net Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 96d04896193f..ed2959dbe1fb 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -92,7 +92,7 @@ static const struct snd_kcontrol_new es8316_snd_controls[] = { SOC_DOUBLE_TLV("Headphone Playback Volume", ES8316_CPHP_ICAL_VOL, 4, 0, 3, 1, hpout_vol_tlv), SOC_DOUBLE_TLV("Headphone Mixer Volume", ES8316_HPMIX_VOL, - 0, 4, 11, 0, hpmixer_gain_tlv), + 4, 0, 11, 0, hpmixer_gain_tlv), SOC_ENUM("Playback Polarity", dacpol), SOC_DOUBLE_R_TLV("DAC Playback Volume", ES8316_DAC_VOLL, -- cgit v1.2.3 From e9e897d5fdba9bda3a8c80ea39761413725f198c Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 26 Aug 2019 17:00:52 +0800 Subject: ASoC: rt1011: add mutex protection to set_fmt/set_tdm_slot The calibration process at booting will reset registers and bypass cache to make sure the calibration is done. We add mutex protection to avoid unexpected settings while the registration process and calibration are interleaved. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20190826090052.1875-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index 0a6ff13d76e1..ed28250d5e34 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1619,14 +1619,18 @@ static int rt1011_hw_params(struct snd_pcm_substream *substream, static int rt1011_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_component *component = dai->component; + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); unsigned int reg_val = 0, reg_bclk_inv = 0; + int ret = 0; + snd_soc_dapm_mutex_lock(dapm); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: reg_val |= RT1011_I2S_TDM_MS_S; break; default: - return -EINVAL; + ret = -EINVAL; } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -1636,7 +1640,7 @@ static int rt1011_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) reg_bclk_inv |= RT1011_TDM_INV_BCLK; break; default: - return -EINVAL; + ret = -EINVAL; } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -1652,7 +1656,7 @@ static int rt1011_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) reg_val |= RT1011_I2S_TDM_DF_PCM_B; break; default: - return -EINVAL; + ret = -EINVAL; } switch (dai->id) { @@ -1667,9 +1671,11 @@ static int rt1011_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) break; default: dev_err(component->dev, "Invalid dai->id: %d\n", dai->id); - return -EINVAL; + ret = -EINVAL; } - return 0; + + snd_soc_dapm_mutex_unlock(dapm); + return ret; } static int rt1011_set_component_sysclk(struct snd_soc_component *component, @@ -1788,8 +1794,12 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct snd_soc_component *component = dai->component; + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); unsigned int val = 0, tdm_en = 0; + int ret = 0; + snd_soc_dapm_mutex_lock(dapm); if (rx_mask || tx_mask) tdm_en = RT1011_TDM_I2S_DOCK_EN_1; @@ -1809,7 +1819,7 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai, case 2: break; default: - return -EINVAL; + ret = -EINVAL; } switch (slot_width) { @@ -1828,7 +1838,7 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai, case 16: break; default: - return -EINVAL; + ret = -EINVAL; } snd_soc_component_update_bits(component, RT1011_TDM1_SET_1, @@ -1845,7 +1855,8 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai, RT1011_ADCDAT1_PIN_CONFIG | RT1011_ADCDAT2_PIN_CONFIG, RT1011_ADCDAT1_OUTPUT | RT1011_ADCDAT2_OUTPUT); - return 0; + snd_soc_dapm_mutex_unlock(dapm); + return ret; } static int rt1011_probe(struct snd_soc_component *component) -- cgit v1.2.3 From d2ac1fe0342ce2b44621f60d053800e2d94f1d21 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Sat, 24 Aug 2019 12:58:46 +0800 Subject: ASoC: mediatek: mt8183: fix tdm out data align issue Mt8183 tdm out support S16_LE/S24_LE/S32_LE formats. When output S32_LE, we need set hd_align so that memif can output MSB 24bits. When output S24_LE, we need reset hd_align so that memif can output LSB 24bits. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1566622726-27113-1-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/common/mtk-afe-fe-dai.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c index d16563408465..10ea4fdbeb1e 100644 --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c @@ -241,7 +241,7 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; int hd_audio = 0; - int hd_align = 1; + int hd_align = 0; /* set hd mode */ switch (substream->runtime->format) { @@ -254,7 +254,6 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, break; case SNDRV_PCM_FORMAT_S24_LE: hd_audio = 1; - hd_align = 0; break; default: dev_err(afe->dev, "%s() error: unsupported format %d\n", -- cgit v1.2.3 From b429ca49406501e2c48c2a137eab12910c21ad0c Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 27 Aug 2019 18:13:46 -0400 Subject: ASoC: cs42xx8: Force suspend/resume during system suspend/resume Use force_suspend/resume to make sure clocks are disabled/enabled accordingly during system suspend/resume. Signed-off-by: Dong Aisheng Signed-off-by: Shengjiu Wang Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/1566944026-18113-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42xx8.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 5b049fcdba20..94b1adb088fd 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -684,6 +684,8 @@ static int cs42xx8_runtime_suspend(struct device *dev) #endif const struct dev_pm_ops cs42xx8_pm = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL) }; EXPORT_SYMBOL_GPL(cs42xx8_pm); -- cgit v1.2.3 From 18291410557fb860706d1889505cc15d6e31d790 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Sat, 24 Aug 2019 22:26:52 +0200 Subject: ASoC: atmel: enable SOC_SSC_PDC and SOC_SSC_DMA in Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow SSC to be used on platforms described using audio-graph-card in Device Tree. Signed-off-by: Michał Mirosław Reviewed-by: Codrin Ciubotariu Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/233d5461f4448df151755de7b69a0cd3ad310d5c.1566677788.git.mirq-linux@rere.qmqm.pl Signed-off-by: Mark Brown --- sound/soc/atmel/Kconfig | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 06c1d5ce642c..f118c229ed82 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -12,25 +12,31 @@ if SND_ATMEL_SOC config SND_ATMEL_SOC_PDC tristate depends on HAS_DMA - default m if SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=m - default y if SND_ATMEL_SOC_SSC_PDC=y || (SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=y) - -config SND_ATMEL_SOC_SSC_PDC - tristate config SND_ATMEL_SOC_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM - default m if SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=m - default y if SND_ATMEL_SOC_SSC_DMA=y || (SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=y) - -config SND_ATMEL_SOC_SSC_DMA - tristate config SND_ATMEL_SOC_SSC tristate - default y if SND_ATMEL_SOC_SSC_DMA=y || SND_ATMEL_SOC_SSC_PDC=y - default m if SND_ATMEL_SOC_SSC_DMA=m || SND_ATMEL_SOC_SSC_PDC=m + +config SND_ATMEL_SOC_SSC_PDC + tristate "SoC PCM DAI support for AT91 SSC controller using PDC" + depends on ATMEL_SSC + select SND_ATMEL_SOC_PDC + select SND_ATMEL_SOC_SSC + help + Say Y or M if you want to add support for Atmel SSC interface + in PDC mode configured using audio-graph-card in device-tree. + +config SND_ATMEL_SOC_SSC_DMA + tristate "SoC PCM DAI support for AT91 SSC controller using DMA" + depends on ATMEL_SSC + select SND_ATMEL_SOC_DMA + select SND_ATMEL_SOC_SSC + help + Say Y or M if you want to add support for Atmel SSC interface + in DMA mode configured using audio-graph-card in device-tree. config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" -- cgit v1.2.3 From db8e3e2091c3ccc4e1dde0f78b3111301cf129e9 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Sat, 24 Aug 2019 22:26:53 +0200 Subject: ASoC: atmel_ssc_dai: rework DAI format configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework DAI format calculation in preparation for adding more formats later. As a side-effect this enables all CBM/CBS x CFM/CFS combinations for supported formats. (Note: the additional modes are not tested.) Note: this changes FSEDGE to POSITIVE for I2S CBM_CFS mode as the TXSYN interrupt is not used anyway. Signed-off-by: Michał Mirosław Link: https://lore.kernel.org/r/f5949b0326fdcdca072f3ed03f77de9e207631cd.1566677788.git.mirq-linux@rere.qmqm.pl Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 288 +++++++++++----------------------------- 1 file changed, 81 insertions(+), 207 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 6f89483ac88c..7dc6ec9b8c7a 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -471,7 +471,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, int dir, channels, bits; u32 tfmr, rfmr, tcmr, rcmr; int ret; - int fslen, fslen_ext; + int fslen, fslen_ext, fs_osync, fs_edge; u32 cmr_div; u32 tcmr_period; u32 rcmr_period; @@ -558,233 +558,107 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, /* * Compute SSC register settings. */ - switch (ssc_p->daifmt - & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + fslen_ext = (bits - 1) / 16; + fslen = (bits - 1) % 16; + + switch (ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { + + case SND_SOC_DAIFMT_I2S: + fs_osync = SSC_FSOS_NEGATIVE; + fs_edge = SSC_START_FALLING_RF; + + rcmr = SSC_BF(RCMR_STTDLY, 1); + tcmr = SSC_BF(TCMR_STTDLY, 1); + + break; + + case SND_SOC_DAIFMT_DSP_A: /* - * I2S format, SSC provides BCLK and LRC clocks. + * DSP/PCM Mode A format * - * The SSC transmit and receive clocks are generated - * from the MCK divider, and the BCLK signal - * is output on the SSC TK line. + * Data is transferred on first BCLK after LRC pulse rising + * edge.If stereo, the right channel data is contiguous with + * the left channel data. */ + fs_osync = SSC_FSOS_POSITIVE; + fs_edge = SSC_START_RISING_RF; + fslen = fslen_ext = 0; - if (bits > 16 && !ssc->pdata->has_fslen_ext) { - dev_err(dai->dev, - "sample size %d is too large for SSC device\n", - bits); - return -EINVAL; - } + rcmr = SSC_BF(RCMR_STTDLY, 1); + tcmr = SSC_BF(TCMR_STTDLY, 1); - fslen_ext = (bits - 1) / 16; - fslen = (bits - 1) % 16; - - rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_FALLING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_DIV); - - rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext) - | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(RFMR_FSLEN, fslen) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_FALLING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) - | SSC_BF(TCMR_CKS, SSC_CKS_DIV); - - tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext) - | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(TFMR_FSLEN, fslen) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); break; - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: - /* I2S format, CODEC supplies BCLK and LRC clocks. */ - rcmr = SSC_BF(RCMR_PERIOD, 0) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_FALLING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_PIN : SSC_CKS_CLOCK); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, 0) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_FALLING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_CLOCK : SSC_CKS_PIN); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(TFMR_FSLEN, 0) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; + default: + printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", + ssc_p->daifmt); + return -EINVAL; + } - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFS: - /* I2S format, CODEC supplies BCLK, SSC supplies LRCLK. */ - if (bits > 16 && !ssc->pdata->has_fslen_ext) { - dev_err(dai->dev, - "sample size %d is too large for SSC device\n", - bits); - return -EINVAL; - } + if (!atmel_ssc_cfs(ssc_p)) { + fslen = fslen_ext = 0; + rcmr_period = tcmr_period = 0; + fs_osync = SSC_FSOS_NONE; + } - fslen_ext = (bits - 1) / 16; - fslen = (bits - 1) % 16; - - rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_FALLING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_PIN : SSC_CKS_CLOCK); - - rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext) - | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(RFMR_FSLEN, fslen) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_FALLING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_CLOCK : SSC_CKS_PIN); - - tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext) - | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_NEGATIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(TFMR_FSLEN, fslen) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; + rcmr |= SSC_BF(RCMR_START, fs_edge); + tcmr |= SSC_BF(TCMR_START, fs_edge); - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: + if (atmel_ssc_cbs(ssc_p)) { /* - * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. + * SSC provides BCLK * * The SSC transmit and receive clocks are generated from the * MCK divider, and the BCLK signal is output * on the SSC TK line. */ - rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) - | SSC_BF(RCMR_STTDLY, 1) - | SSC_BF(RCMR_START, SSC_START_RISING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_DIV); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) - | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) - | SSC_BF(TCMR_STTDLY, 1) - | SSC_BF(TCMR_START, SSC_START_RISING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) - | SSC_BF(TCMR_CKS, SSC_CKS_DIV); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) - | SSC_BF(TFMR_FSLEN, 0) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; + rcmr |= SSC_BF(RCMR_CKS, SSC_CKS_DIV) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE); - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: - /* - * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks. - * - * Data is transferred on first BCLK after LRC pulse rising - * edge.If stereo, the right channel data is contiguous with - * the left channel data. - */ - rcmr = SSC_BF(RCMR_PERIOD, 0) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_RISING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_PIN : SSC_CKS_CLOCK); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, 0) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_RISING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_CLOCK : SSC_CKS_PIN); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(TFMR_FSLEN, 0) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; + tcmr |= SSC_BF(TCMR_CKS, SSC_CKS_DIV) + | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS); + } else { + rcmr |= SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_PIN : SSC_CKS_CLOCK) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE); - default: - printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", - ssc_p->daifmt); + tcmr |= SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_CLOCK : SSC_CKS_PIN) + | SSC_BF(TCMR_CKO, SSC_CKO_NONE); + } + + rcmr |= SSC_BF(RCMR_PERIOD, rcmr_period) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING); + + tcmr |= SSC_BF(TCMR_PERIOD, tcmr_period) + | SSC_BF(TCMR_CKI, SSC_CKI_FALLING); + + rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext) + | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, fs_osync) + | SSC_BF(RFMR_FSLEN, fslen) + | SSC_BF(RFMR_DATNB, (channels - 1)) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext) + | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, fs_osync) + | SSC_BF(TFMR_FSLEN, fslen) + | SSC_BF(TFMR_DATNB, (channels - 1)) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); + + if (fslen_ext && !ssc->pdata->has_fslen_ext) { + dev_err(dai->dev, "sample size %d is too large for SSC device\n", + bits); return -EINVAL; } + pr_debug("atmel_ssc_hw_params: " "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr); -- cgit v1.2.3 From 376142b7bbc1edef2900ddc300a006f8c056b0d5 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Sat, 24 Aug 2019 22:26:54 +0200 Subject: ASoC: atmel_ssc_dai: implement left-justified data mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable support for left-justified data mode for SSC-codec link. Signed-off-by: Michał Mirosław Reviewed-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/44fa6b700421e80778f20ff9ead2b148cf6d2e92.1566677788.git.mirq-linux@rere.qmqm.pl Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 7dc6ec9b8c7a..48e9eef34c0f 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -564,6 +564,15 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, switch (ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_LEFT_J: + fs_osync = SSC_FSOS_POSITIVE; + fs_edge = SSC_START_RISING_RF; + + rcmr = SSC_BF(RCMR_STTDLY, 0); + tcmr = SSC_BF(TCMR_STTDLY, 0); + + break; + case SND_SOC_DAIFMT_I2S: fs_osync = SSC_FSOS_NEGATIVE; fs_edge = SSC_START_FALLING_RF; -- cgit v1.2.3 From eb7505d52a2f8b0cfc3fd7146d8cb2dab5a73f0d Mon Sep 17 00:00:00 2001 From: Jussi Laako Date: Wed, 28 Aug 2019 00:08:46 +0300 Subject: ALSA: usb-audio: DSD auto-detection for Playback Designs Add DSD support auto-detection for newer Playback Designs devices. Older device generations have a different USB interface implementation. Keep the auto-detection VID whitelist sorted. Signed-off-by: Jussi Laako Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 5c0fa5cf1987..08ec3dac5dfe 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1566,7 +1566,8 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, struct usb_interface *iface; /* Playback Designs */ - if (USB_ID_VENDOR(chip->usb_id) == 0x23ba) { + if (USB_ID_VENDOR(chip->usb_id) == 0x23ba && + USB_ID_PRODUCT(chip->usb_id) < 0x0110) { switch (fp->altsetting) { case 1: fp->dsd_dop = true; @@ -1654,8 +1655,9 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, * from XMOS/Thesycon */ switch (USB_ID_VENDOR(chip->usb_id)) { - case 0x20b1: /* XMOS based devices */ case 0x152a: /* Thesycon devices */ + case 0x20b1: /* XMOS based devices */ + case 0x23ba: /* Playback Designs */ case 0x25ce: /* Mytek devices */ case 0x2ab6: /* T+A devices */ if (fp->dsd_raw) -- cgit v1.2.3 From 0067e154b11e236d62a7a8205f321b097c21a35b Mon Sep 17 00:00:00 2001 From: Jussi Laako Date: Wed, 28 Aug 2019 00:08:47 +0300 Subject: ALSA: usb-audio: Update DSD support quirks for Oppo and Rotel Oppo has issued firmware updates that change alt setting used for DSD support. However, these devices seem to support auto-detection, so support is moved from explicit whitelisting to auto-detection. Also Rotel devices have USB interfaces that support DSD with auto-detection. Signed-off-by: Jussi Laako Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 08ec3dac5dfe..25faf2d3c639 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1584,9 +1584,6 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, /* XMOS based USB DACs */ switch (chip->usb_id) { case USB_ID(0x1511, 0x0037): /* AURALiC VEGA */ - case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */ - case USB_ID(0x22d9, 0x0436): /* OPPO Sonica */ - case USB_ID(0x22d9, 0x0461): /* OPPO UDP-205 */ case USB_ID(0x2522, 0x0012): /* LH Labs VI DAC Infinity */ case USB_ID(0x2772, 0x0230): /* Pro-Ject Pre Box S2 Digital */ if (fp->altsetting == 2) @@ -1600,7 +1597,6 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, case USB_ID(0x16d0, 0x0733): /* Furutech ADL Stratos */ case USB_ID(0x16d0, 0x09db): /* NuPrime Audio DAC-9 */ case USB_ID(0x1db5, 0x0003): /* Bryston BDA3 */ - case USB_ID(0x22d9, 0x0426): /* OPPO HA-2 */ case USB_ID(0x22e1, 0xca01): /* HDTA Serenade DSD */ case USB_ID(0x249c, 0x9326): /* M2Tech Young MkIII */ case USB_ID(0x2616, 0x0106): /* PS Audio NuWave DAC */ @@ -1657,8 +1653,10 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, switch (USB_ID_VENDOR(chip->usb_id)) { case 0x152a: /* Thesycon devices */ case 0x20b1: /* XMOS based devices */ + case 0x22d9: /* Oppo */ case 0x23ba: /* Playback Designs */ case 0x25ce: /* Mytek devices */ + case 0x278b: /* Rotel? */ case 0x2ab6: /* T+A devices */ if (fp->dsd_raw) return SNDRV_PCM_FMTBIT_DSD_U32_BE; -- cgit v1.2.3 From 8e58c521bcb823bfd6e81f4a85b76afdce098b1d Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Sat, 24 Aug 2019 12:37:24 +0800 Subject: ASoC: mediatek: mt8183: tdm hw support tdm out and 8ch i2s out This patch refined tdm driver code, and allow tdm hw to support two configurations in machine driver to output tdm signal or i2s signal. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1566621445-26989-3-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-dai-tdm.c | 175 +++++++++++++++++---- .../mt8183/mt8183-mt6358-ts3a227-max98357.c | 3 + 2 files changed, 144 insertions(+), 34 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c index 8983d54a9b67..d34cabdbf889 100644 --- a/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c +++ b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c @@ -15,13 +15,30 @@ struct mtk_afe_tdm_priv { int bck_id; int bck_rate; - + int tdm_out_mode; + int bck_invert; + int lck_invert; int mclk_id; int mclk_multiple; /* according to sample rate */ int mclk_rate; int mclk_apll; }; +enum { + TDM_OUT_I2S = 0, + TDM_OUT_TDM = 1, +}; + +enum { + TDM_BCK_NON_INV = 0, + TDM_BCK_INV = 1, +}; + +enum { + TDM_LCK_NON_INV = 0, + TDM_LCK_INV = 1, +}; + enum { TDM_WLEN_16_BIT = 1, TDM_WLEN_32_BIT = 2, @@ -93,6 +110,25 @@ static unsigned int get_tdm_ch(unsigned int ch) } } +static unsigned int get_tdm_ch_fixup(unsigned int channels) +{ + if (channels > 4) + return 8; + else if (channels > 2) + return 4; + else + return 2; +} + +static unsigned int get_tdm_ch_per_sdata(unsigned int mode, + unsigned int channels) +{ + if (mode == TDM_OUT_TDM) + return get_tdm_ch_fixup(channels); + else + return 2; +} + /* interconnection */ enum { HDMI_CONN_CH0 = 0, @@ -433,8 +469,11 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, struct mt8183_afe_private *afe_priv = afe->platform_priv; int tdm_id = dai->id; struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id]; + unsigned int tdm_out_mode = tdm_priv->tdm_out_mode; unsigned int rate = params_rate(params); unsigned int channels = params_channels(params); + unsigned int out_channels_per_sdata = + get_tdm_ch_per_sdata(tdm_out_mode, channels); snd_pcm_format_t format = params_format(params); unsigned int tdm_con = 0; @@ -448,7 +487,7 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, /* calculate bck */ tdm_priv->bck_rate = rate * - channels * + out_channels_per_sdata * snd_pcm_format_physical_width(format); if (tdm_priv->bck_rate > tdm_priv->mclk_rate) @@ -461,50 +500,70 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, __func__, tdm_id, rate, channels, format, tdm_priv->mclk_rate, tdm_priv->bck_rate); + dev_info(afe->dev, "%s(), out_channels_per_sdata = %d\n", + __func__, out_channels_per_sdata); /* set tdm */ - tdm_con = 1 << BCK_INVERSE_SFT; - tdm_con |= 1 << LRCK_INVERSE_SFT; - tdm_con |= 1 << DELAY_DATA_SFT; + if (tdm_priv->bck_invert) + tdm_con |= 1 << BCK_INVERSE_SFT; + + if (tdm_priv->lck_invert) + tdm_con |= 1 << LRCK_INVERSE_SFT; + + if (tdm_priv->tdm_out_mode == TDM_OUT_I2S) { + tdm_con |= 1 << DELAY_DATA_SFT; + tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT; + } else if (tdm_priv->tdm_out_mode == TDM_OUT_TDM) { + tdm_con |= 0 << DELAY_DATA_SFT; + tdm_con |= 0 << LRCK_TDM_WIDTH_SFT; + } + tdm_con |= 1 << LEFT_ALIGN_SFT; tdm_con |= get_tdm_wlen(format) << WLEN_SFT; - tdm_con |= get_tdm_ch(channels) << CHANNEL_NUM_SFT; + tdm_con |= get_tdm_ch(out_channels_per_sdata) << CHANNEL_NUM_SFT; tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT; - tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT; regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con); - switch (channels) { - case 1: - case 2: + if (out_channels_per_sdata == 2) { + switch (channels) { + case 1: + case 2: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 3: + case 4: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 5: + case 6: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 7: + case 8: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT; + break; + default: + tdm_con = 0; + } + } else { tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT; tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; - break; - case 3: - case 4: - tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; - tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; - tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; - tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; - break; - case 5: - case 6: - tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; - tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; - tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; - tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; - break; - case 7: - case 8: - tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; - tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; - tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; - tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT; - break; - default: - tdm_con = 0; } + regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con); regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, @@ -573,10 +632,58 @@ static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai, return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq); } +static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; + + if (!tdm_priv) { + dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + /* DAI mode*/ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + tdm_priv->tdm_out_mode = TDM_OUT_I2S; + break; + case SND_SOC_DAIFMT_DSP_A: + tdm_priv->tdm_out_mode = TDM_OUT_TDM; + break; + default: + tdm_priv->tdm_out_mode = TDM_OUT_I2S; + } + + /* DAI clock inversion*/ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + tdm_priv->bck_invert = TDM_BCK_NON_INV; + tdm_priv->lck_invert = TDM_LCK_NON_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + tdm_priv->bck_invert = TDM_BCK_NON_INV; + tdm_priv->lck_invert = TDM_LCK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + tdm_priv->bck_invert = TDM_BCK_INV; + tdm_priv->lck_invert = TDM_LCK_NON_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + default: + tdm_priv->bck_invert = TDM_BCK_INV; + tdm_priv->lck_invert = TDM_LCK_INV; + break; + } + + return 0; +} + static const struct snd_soc_dai_ops mtk_dai_tdm_ops = { .hw_params = mtk_dai_tdm_hw_params, .trigger = mtk_dai_tdm_trigger, .set_sysclk = mtk_dai_tdm_set_sysclk, + .set_fmt = mtk_dai_tdm_set_fmt, }; /* dai driver */ diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 951706fa75fc..560fcc5923a4 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -380,6 +380,9 @@ mt8183_mt6358_ts3a227_max98357_dai_links[] = { { .name = "TDM", .no_pcm = 1, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_IB_IF | + SND_SOC_DAIFMT_CBM_CFM, .dpcm_playback = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, -- cgit v1.2.3 From 2c650fd5a53beace2e7507f478562f0dd1885b89 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Sat, 24 Aug 2019 12:37:25 +0800 Subject: ASoC: mediatek: mt8183: fix tdm out data is valid on rising edge This patch correct tdm out bck inverse register to AUDIO_TOP_CON3[3]. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1566621445-26989-4-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-dai-tdm.c | 4 +++- sound/soc/mediatek/mt8183/mt8183-reg.h | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c index d34cabdbf889..0d69cf440407 100644 --- a/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c +++ b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c @@ -505,7 +505,9 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, /* set tdm */ if (tdm_priv->bck_invert) - tdm_con |= 1 << BCK_INVERSE_SFT; + regmap_update_bits(afe->regmap, AUDIO_TOP_CON3, + BCK_INVERSE_MASK_SFT, + 0x1 << BCK_INVERSE_SFT); if (tdm_priv->lck_invert) tdm_con |= 1 << LRCK_INVERSE_SFT; diff --git a/sound/soc/mediatek/mt8183/mt8183-reg.h b/sound/soc/mediatek/mt8183/mt8183-reg.h index e0482f2826da..e544a09e1913 100644 --- a/sound/soc/mediatek/mt8183/mt8183-reg.h +++ b/sound/soc/mediatek/mt8183/mt8183-reg.h @@ -413,6 +413,11 @@ #define AFE_MAX_REGISTER AFE_GENERAL2_ASRC_2CH_CON13 #define AFE_IRQ_STATUS_BITS 0x1fff +/* AUDIO_TOP_CON3 */ +#define BCK_INVERSE_SFT 3 +#define BCK_INVERSE_MASK 0x1 +#define BCK_INVERSE_MASK_SFT (0x1 << 3) + /* AFE_DAC_CON0 */ #define AWB2_ON_SFT 29 #define AWB2_ON_MASK 0x1 @@ -1596,9 +1601,6 @@ #define TDM_EN_SFT 0 #define TDM_EN_MASK 0x1 #define TDM_EN_MASK_SFT (0x1 << 0) -#define BCK_INVERSE_SFT 1 -#define BCK_INVERSE_MASK 0x1 -#define BCK_INVERSE_MASK_SFT (0x1 << 1) #define LRCK_INVERSE_SFT 2 #define LRCK_INVERSE_MASK 0x1 #define LRCK_INVERSE_MASK_SFT (0x1 << 2) -- cgit v1.2.3 From 4cc4531c310e592cf624148ae59c64f930f12e39 Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Thu, 22 Aug 2019 10:56:50 +0100 Subject: ALSA: pcm: add support for 352.8KHz and 384KHz sample rate Most of the modern codecs supports 352.8KHz and 384KHz sample rates. Currenlty HW params fails to set 352.8Kz and 384KHz sample rate as these are not in known rates list. Add these new rates to known list to allow them. This patch also adds defines in pcm.h so that drivers can use it. Signed-off-by: Vidyakumar Athota Signed-off-by: Banajit Goswami Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20190822095653.7200-2-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- include/sound/pcm.h | 5 +++++ sound/core/pcm_native.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 1e9bb1c91770..bbe6eb1ff5d2 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -117,6 +117,8 @@ struct snd_pcm_ops { #define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */ #define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */ #define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */ +#define SNDRV_PCM_RATE_352800 (1<<13) /* 352800Hz */ +#define SNDRV_PCM_RATE_384000 (1<<14) /* 384000Hz */ #define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */ #define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */ @@ -129,6 +131,9 @@ struct snd_pcm_ops { SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000) #define SNDRV_PCM_RATE_8000_192000 (SNDRV_PCM_RATE_8000_96000|SNDRV_PCM_RATE_176400|\ SNDRV_PCM_RATE_192000) +#define SNDRV_PCM_RATE_8000_384000 (SNDRV_PCM_RATE_8000_192000|\ + SNDRV_PCM_RATE_352800|\ + SNDRV_PCM_RATE_384000) #define _SNDRV_PCM_FMTBIT(fmt) (1ULL << (__force int)SNDRV_PCM_FORMAT_##fmt) #define SNDRV_PCM_FMTBIT_S8 _SNDRV_PCM_FMTBIT(S8) #define SNDRV_PCM_FMTBIT_U8 _SNDRV_PCM_FMTBIT(U8) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 860543a4c840..34390be3fb0f 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2168,7 +2168,7 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params, static const unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, - 48000, 64000, 88200, 96000, 176400, 192000 + 48000, 64000, 88200, 96000, 176400, 192000, 352800, 384000 }; const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { -- cgit v1.2.3 From a8a652bfac7f4a60dfbe07a8c95c65506601b2e1 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 22 Aug 2019 10:56:51 +0100 Subject: ASoC: wcd9335: Fix primary interpolator max rate On this codec SLIMBus RX path supports 384000 rate on primary interpolator. Add this missing rate as supported rate. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20190822095653.7200-3-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 956602788d0e..03f8a94bba2f 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -2071,9 +2071,10 @@ static struct snd_soc_dai_driver wcd9335_slim_dais[] = { .id = AIF1_PB, .playback = { .stream_name = "AIF1 Playback", - .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK | + SNDRV_PCM_RATE_384000, .formats = WCD9335_FORMATS_S16_S24_LE, - .rate_max = 192000, + .rate_max = 384000, .rate_min = 8000, .channels_min = 1, .channels_max = 2, @@ -2099,10 +2100,11 @@ static struct snd_soc_dai_driver wcd9335_slim_dais[] = { .id = AIF2_PB, .playback = { .stream_name = "AIF2 Playback", - .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK | + SNDRV_PCM_RATE_384000, .formats = WCD9335_FORMATS_S16_S24_LE, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, .channels_min = 1, .channels_max = 2, }, @@ -2127,10 +2129,11 @@ static struct snd_soc_dai_driver wcd9335_slim_dais[] = { .id = AIF3_PB, .playback = { .stream_name = "AIF3 Playback", - .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK | + SNDRV_PCM_RATE_384000, .formats = WCD9335_FORMATS_S16_S24_LE, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, .channels_min = 1, .channels_max = 2, }, @@ -2155,10 +2158,11 @@ static struct snd_soc_dai_driver wcd9335_slim_dais[] = { .id = AIF4_PB, .playback = { .stream_name = "AIF4 Playback", - .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK | + SNDRV_PCM_RATE_384000, .formats = WCD9335_FORMATS_S16_S24_LE, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, .channels_min = 1, .channels_max = 2, }, -- cgit v1.2.3 From 6e26d193d15029a65e0904ad85d6d8634817c3a6 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 29 Aug 2019 23:37:19 +0900 Subject: ALSA: dice: fix error path for initialization of stream structures When introducing AMDTP domain to ALSA dice driver, error path does not handle error correctly. This commit fixes the bug. Fixes: e9f21129b8d8 ("ALSA: dice: support AMDTP domain") Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index af8c5a2c28f3..f6a8627ae5a2 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -570,7 +570,7 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice) destroy_stream(dice, AMDTP_OUT_STREAM, i); for (i = 0; i < MAX_STREAMS; i++) destroy_stream(dice, AMDTP_IN_STREAM, i); - break; + goto end; } } -- cgit v1.2.3 From f155e79ab516c9ed2adb2f337fb4ff58b7474428 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 29 Aug 2019 23:38:08 +0900 Subject: ALSA: firewire-lib: fix isoc cycle count to which rx packet is scheduled When introducing the list of packet descriptor, for rx packet, the calculation of scheduled isoc cycle is omitted. This commit fixes the bug. Fixes: f4f6ae7b7c1f ("ALSA: firewire-lib: use packet descriptor for IT context") Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 1a92855c7647..88270257e896 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -732,7 +732,7 @@ static void generate_ideal_pkt_descs(struct amdtp_stream *s, struct pkt_desc *desc = descs + i; unsigned int index = (s->packet_index + i) % QUEUE_LENGTH; - desc->cycle = compute_cycle_count(*ctx_header); + desc->cycle = compute_it_cycle(*ctx_header); desc->syt = calculate_syt(s, desc->cycle); desc->data_blocks = calculate_data_blocks(s, desc->syt); -- cgit v1.2.3 From 696d05225cebffd172008d212657be90e823eac0 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 28 Aug 2019 13:20:17 -0400 Subject: ASoC: fsl_ssi: Fix clock control issue in master mode The test case is arecord -Dhw:0 -d 10 -f S16_LE -r 48000 -c 2 temp.wav & aplay -Dhw:0 -d 30 -f S16_LE -r 48000 -c 2 test.wav There will be error after end of arecord: aplay: pcm_write:2051: write error: Input/output error Capture and Playback work in parallel in master mode, one substream stops, the other substream is impacted, the reason is that clock is disabled wrongly. The clock's reference count is not increased when second substream starts, the hw_param() function returns in the beginning because first substream is enabled, then in end of first substream, the hw_free() disables the clock. This patch is to move the clock enablement to the place before checking of the device enablement in hw_param(). Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1567012817-12625-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index fa862af25c1a..085855f9b08d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -799,15 +799,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, u32 wl = SSI_SxCCR_WL(sample_size); int ret; - /* - * SSI is properly configured if it is enabled and running in - * the synchronous mode; Note that AC97 mode is an exception - * that should set separate configurations for STCCR and SRCCR - * despite running in the synchronous mode. - */ - if (ssi->streams && ssi->synchronous) - return 0; - if (fsl_ssi_is_i2s_master(ssi)) { ret = fsl_ssi_set_bclk(substream, dai, hw_params); if (ret) @@ -823,6 +814,15 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } } + /* + * SSI is properly configured if it is enabled and running in + * the synchronous mode; Note that AC97 mode is an exception + * that should set separate configurations for STCCR and SRCCR + * despite running in the synchronous mode. + */ + if (ssi->streams && ssi->synchronous) + return 0; + if (!fsl_ssi_is_ac97(ssi)) { /* * Keep the ssi->i2s_net intact while having a local variable -- cgit v1.2.3 From cc9bbb6cde6c321706f1eff79d077b4a91cd5d12 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 28 Aug 2019 11:51:02 +0200 Subject: ASoC: Intel: Baytrail: Fix implicit fallthrough warning Append fallthrough statement to fix warning reported during compilation. Fixes: b80d19c166c4 ("ASoC: Intel: Restore Baytrail ADSP streams only when ADSP was in reset") Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190828095102.15737-1-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/baytrail/sst-baytrail-pcm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c index 9cbc982d46a9..54f2ee3010ee 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c @@ -193,6 +193,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) break; case SNDRV_PCM_TRIGGER_SUSPEND: pdata->restore_stream = false; + /* fallthrough */ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: sst_byt_stream_pause(byt, pcm_data->stream); break; -- cgit v1.2.3 From 6af86bdb8ad41f4cf1292d3b10857dc322758328 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 30 Aug 2019 10:14:56 +0900 Subject: ALSA: firewire-motu: add support for MOTU 4pre MOTU 4pre was launched in 2012 by MOTU, Inc. This commit allows userspace applications can transmit and receive PCM frames and MIDI messages for this model via ALSA PCM interface and RawMidi/Sequencer interfaces. The device supports MOTU protocol version 3. Unlike the other devices, the device is simply designed. The size of data block is fixed to 10 quadlets during available sampling rates (44.1 - 96.0 kHz). Each data block includes 1 source packet header, 2 data chunks for messages, 8 data chunks for PCM samples and 2 data chunks for padding to quadlet alignment. The device has no MIDI, optical, BNC and AES/EBU interfaces. Like support for the other MOTU devices, the quality of playback sound is not enough good with periodical noise yet. $ python2 crpp < ~/git/am-config-rom/motu/motu-4pre.img ROM header and bus information block ----------------------------------------------------------------- 400 041078cc bus_info_length 4, crc_length 16, crc 30924 404 31333934 bus_name "1394" 408 20ff7000 irmc 0, cmc 0, isc 1, bmc 0, cyc_clk_acc 255, max_rec 7 (256) 40c 0001f200 company_id 0001f2 | 410 000a41c5 device_id 00000a41c5 | EUI-64 0001f200000a41c5 root directory ----------------------------------------------------------------- 414 0004ef04 directory_length 4, crc 61188 418 030001f2 vendor 41c 0c0083c0 node capabilities per IEEE 1394 420 d1000002 --> unit directory at 428 424 8d000005 --> eui-64 leaf at 438 unit directory at 428 ----------------------------------------------------------------- 428 0003ceda directory_length 3, crc 52954 42c 120001f2 specifier id 430 13000045 version 434 17103800 model eui-64 leaf at 438 ----------------------------------------------------------------- 438 0002d248 leaf_length 2, crc 53832 43c 0001f200 company_id 0001f2 | 440 000a41c5 device_id 00000a41c5 | EUI-64 0001f200000a41c5 Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/motu/motu.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound') diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index 03cda2166ea3..72908b4de77c 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -247,6 +247,17 @@ static const struct snd_motu_spec motu_audio_express = { .analog_out_ports = 4, }; +static const struct snd_motu_spec motu_4pre = { + .name = "4pre", + .protocol = &snd_motu_protocol_v3, + .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | + SND_MOTU_SPEC_TX_MICINST_CHUNK | + SND_MOTU_SPEC_TX_RETURN_CHUNK | + SND_MOTU_SPEC_RX_SEPARETED_MAIN, + .analog_in_ports = 2, + .analog_out_ports = 2, +}; + #define SND_MOTU_DEV_ENTRY(model, data) \ { \ .match_flags = IEEE1394_MATCH_VENDOR_ID | \ @@ -265,6 +276,7 @@ static const struct ieee1394_device_id motu_id_table[] = { SND_MOTU_DEV_ENTRY(0x000015, &motu_828mk3), /* FireWire only. */ SND_MOTU_DEV_ENTRY(0x000035, &motu_828mk3), /* Hybrid. */ SND_MOTU_DEV_ENTRY(0x000033, &motu_audio_express), + SND_MOTU_DEV_ENTRY(0x000045, &motu_4pre), { } }; MODULE_DEVICE_TABLE(ieee1394, motu_id_table); -- cgit v1.2.3 From a2dc6f82fd86fa165222f6062e2478fd122f9f1c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 30 Aug 2019 13:38:39 +0300 Subject: ASoC: ti: davinci-i2s: Move the XSYNCERR workaround to .prepare callback Currently the driver uses snd_soc_rtdcom_lookup() in it's mcbsp_start function to try to stop/restart the DMA as the initial XSYNCERR workaround need to be done before the DMA is armed. There are couple of things wrong with this: - the driver crashes with NULL pointer dereference as the component->driver->ops is actually NULL - the driver should not use snd_soc_rtdcom_lookup() in the first place - Fiddling with DMA is never a good thing Move the workaround handling to .prepare which is called before the DMA is armed, so it complies with the requirements. Reported-by (usage of snd_soc_rtdcom_lookup): Kuninori Morimoto Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190830103841.25128-3-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-i2s.c | 82 +++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 48 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 92c1bdc69086..27afdbb9adf3 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -187,57 +187,9 @@ static void toggle_clock(struct davinci_mcbsp_dev *dev, int playback) static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); u32 spcr; u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST; - spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - if (spcr & mask) { - /* start off disabled */ - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, - spcr & ~mask); - toggle_clock(dev, playback); - } - if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM | - DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM)) { - /* Start the sample generator */ - spcr |= DAVINCI_MCBSP_SPCR_GRST; - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); - } - - if (playback) { - /* Stop the DMA to avoid data loss */ - /* while the transmitter is out of reset to handle XSYNCERR */ - if (component->driver->ops->trigger) { - int ret = component->driver->ops->trigger(substream, - SNDRV_PCM_TRIGGER_STOP); - if (ret < 0) - printk(KERN_DEBUG "Playback DMA stop failed\n"); - } - - /* Enable the transmitter */ - spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - spcr |= DAVINCI_MCBSP_SPCR_XRST; - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); - - /* wait for any unexpected frame sync error to occur */ - udelay(100); - - /* Disable the transmitter to clear any outstanding XSYNCERR */ - spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - spcr &= ~DAVINCI_MCBSP_SPCR_XRST; - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); - toggle_clock(dev, playback); - - /* Restart the DMA */ - if (component->driver->ops->trigger) { - int ret = component->driver->ops->trigger(substream, - SNDRV_PCM_TRIGGER_START); - if (ret < 0) - printk(KERN_DEBUG "Playback DMA start failed\n"); - } - } /* Enable transmitter or receiver */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); @@ -575,7 +527,41 @@ static int davinci_i2s_prepare(struct snd_pcm_substream *substream, { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + u32 spcr; + u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST; + davinci_mcbsp_stop(dev, playback); + + spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + if (spcr & mask) { + /* start off disabled */ + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, + spcr & ~mask); + toggle_clock(dev, playback); + } + if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM | + DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM)) { + /* Start the sample generator */ + spcr |= DAVINCI_MCBSP_SPCR_GRST; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); + } + + if (playback) { + /* Enable the transmitter */ + spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + spcr |= DAVINCI_MCBSP_SPCR_XRST; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); + + /* wait for any unexpected frame sync error to occur */ + udelay(100); + + /* Disable the transmitter to clear any outstanding XSYNCERR */ + spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + spcr &= ~DAVINCI_MCBSP_SPCR_XRST; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); + toggle_clock(dev, playback); + } + return 0; } -- cgit v1.2.3 From 2231b2c63f869528504195f202d9585a4f00f143 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 30 Aug 2019 13:38:38 +0300 Subject: ASoC: ti: davinci-i2s: Add S32_LE as support format ASP/McBSP can support 8/16/20/24/32 bits word in theory. I have only tested S16_LE and S32_LE, the other formats might not work so only extend the supported formats with S32_LE for now. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190830103841.25128-2-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-i2s.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 92c1bdc69086..f04d9fb5130f 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -612,6 +612,8 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, } #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 +#define DAVINCI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { .shutdown = davinci_i2s_shutdown, @@ -639,12 +641,14 @@ static struct snd_soc_dai_driver davinci_i2s_dai = { .channels_min = 2, .channels_max = 2, .rates = DAVINCI_I2S_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .formats = DAVINCI_I2S_FORMATS, + }, .capture = { .channels_min = 2, .channels_max = 2, .rates = DAVINCI_I2S_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .formats = DAVINCI_I2S_FORMATS, + }, .ops = &davinci_i2s_dai_ops, }; -- cgit v1.2.3 From 27b7def93aaba0838eb90e6b3c3110a856bb09fc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 30 Aug 2019 13:38:40 +0300 Subject: ASoC: ti: edma-pcm: Fix for legacy dma_slave_map based channel lookup Most of the daVinci devices does not boot with DT. In this case the DMA channel is looked up with dma_slave_map and for that the chan_names[] must be configured. Both McASP and ASP/McBSP uses "tx" and "rx" as channel names, so we can just do this when the dev->of_node is not valid. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190830103841.25128-4-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/ti/edma-pcm.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/ti/edma-pcm.c b/sound/soc/ti/edma-pcm.c index 3ebea1bd15cb..634b040b65f0 100644 --- a/sound/soc/ti/edma-pcm.c +++ b/sound/soc/ti/edma-pcm.c @@ -39,7 +39,22 @@ static const struct snd_dmaengine_pcm_config edma_dmaengine_pcm_config = { int edma_pcm_platform_register(struct device *dev) { - return devm_snd_dmaengine_pcm_register(dev, &edma_dmaengine_pcm_config, 0); + struct snd_dmaengine_pcm_config *config; + + if (dev->of_node) + return devm_snd_dmaengine_pcm_register(dev, + &edma_dmaengine_pcm_config, 0); + + config = devm_kzalloc(dev, sizeof(*config), GFP_KERNEL); + if (!config) + return -ENOMEM; + + *config = edma_dmaengine_pcm_config; + + config->chan_names[0] = "tx"; + config->chan_names[1] = "rx"; + + return devm_snd_dmaengine_pcm_register(dev, config, 0); } EXPORT_SYMBOL_GPL(edma_pcm_platform_register); -- cgit v1.2.3 From 69f34053f883a53e86fa8ff7b99a81d8b5d50dae Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 30 Aug 2019 13:38:41 +0300 Subject: ASoC: ti: davinci-evm: Do not fail if the dai_set_sysclk returns -ENOTSUPP The davinci McBSP (davinci-i2s) driver does not implement the set_sysclk callback, which is fine and should not be treated as error. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190830103841.25128-5-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-evm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c index bfd8d1a03ba7..686b23d7a90d 100644 --- a/sound/soc/ti/davinci-evm.c +++ b/sound/soc/ti/davinci-evm.c @@ -68,7 +68,7 @@ static int evm_hw_params(struct snd_pcm_substream *substream, /* set the CPU system clock */ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT); - if (ret < 0) + if (ret < 0 && ret != -ENOTSUPP) return ret; return 0; -- cgit v1.2.3 From ca964edf0ddbfec2cb10b3d251d09598e7ca9b13 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 22 Aug 2019 13:36:13 +0200 Subject: ASoC: Intel: Haswell: Adjust machine device private context Apart from Haswell machines, all other devices have their private data set to snd_soc_acpi_mach instance. Changes for HSW/ BDW boards introduced with series: https://patchwork.kernel.org/cover/10782035/ added support for dai_link platform_name adjustments within card probe routines. These take for granted private_data points to snd_soc_acpi_mach whereas for Haswell, it's sst_pdata instead. Change private context of platform_device - representing machine board - to address this. Fixes: e87055d732e3 ("ASoC: Intel: haswell: platform name fixup support") Fixes: 7e40ddcf974a ("ASoC: Intel: bdw-rt5677: platform name fixup support") Fixes: 2d067b2807f9 ("ASoC: Intel: broadwell: platform name fixup support") Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190822113616.22702-2-cezary.rojewski@intel.com Tested-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-acpi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c index 0e8e0a7a11df..5854868650b9 100644 --- a/sound/soc/intel/common/sst-acpi.c +++ b/sound/soc/intel/common/sst-acpi.c @@ -141,11 +141,12 @@ static int sst_acpi_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, sst_acpi); + mach->pdata = sst_pdata; /* register machine driver */ sst_acpi->pdev_mach = platform_device_register_data(dev, mach->drv_name, -1, - sst_pdata, sizeof(*sst_pdata)); + mach, sizeof(*mach)); if (IS_ERR(sst_acpi->pdev_mach)) return PTR_ERR(sst_acpi->pdev_mach); -- cgit v1.2.3 From 1fc3e6b2ac3f8125ae54685c600d594d690a268a Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 22 Aug 2019 13:36:14 +0200 Subject: ASoC: Intel: haswell: Simplify device probe With legacy ADSP private context adjusted, there is no need for double safety. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190822113616.22702-3-cezary.rojewski@intel.com Tested-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/haswell.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index 4d3822cff98c..3dadf9bff796 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -188,18 +188,14 @@ static struct snd_soc_card haswell_rt5640 = { static int haswell_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach; - const char *platform_name = NULL; int ret; haswell_rt5640.dev = &pdev->dev; /* override plaform name, if required */ mach = (&pdev->dev)->platform_data; - if (mach) /* extra check since legacy does not pass parameters */ - platform_name = mach->mach_params.platform; - ret = snd_soc_fixup_dai_links_platform_name(&haswell_rt5640, - platform_name); + mach->mach_params.platform); if (ret) return ret; -- cgit v1.2.3 From c25e93bba90b3f194c43a37fe2fcdb0727c4ab84 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 22 Aug 2019 13:36:15 +0200 Subject: ASoC: Intel: bdw-rt5677: Simplify device probe With legacy ADSP private context adjusted, there is no need for double safety. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190822113616.22702-4-cezary.rojewski@intel.com Tested-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bdw-rt5677.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index e8e9c3dc82a5..4a4d3353e26d 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -340,7 +340,6 @@ static int bdw_rt5677_probe(struct platform_device *pdev) { struct bdw_rt5677_priv *bdw_rt5677; struct snd_soc_acpi_mach *mach; - const char *platform_name = NULL; int ret; bdw_rt5677_card.dev = &pdev->dev; @@ -355,11 +354,8 @@ static int bdw_rt5677_probe(struct platform_device *pdev) /* override plaform name, if required */ mach = (&pdev->dev)->platform_data; - if (mach) /* extra check since legacy does not pass parameters */ - platform_name = mach->mach_params.platform; - ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt5677_card, - platform_name); + mach->mach_params.platform); if (ret) return ret; -- cgit v1.2.3 From 54d037d5a466ce518ee4bb81f39b79ac7d843ba6 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 22 Aug 2019 13:36:16 +0200 Subject: ASoC: Intel: broadwell: Simplify device probe With legacy ADSP private context adjusted, there is no need for double safety. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190822113616.22702-5-cezary.rojewski@intel.com Tested-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/broadwell.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index ab38ef30dfff..db7e1e87156d 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -270,18 +270,14 @@ static struct snd_soc_card broadwell_rt286 = { static int broadwell_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach; - const char *platform_name = NULL; int ret; broadwell_rt286.dev = &pdev->dev; /* override plaform name, if required */ mach = (&pdev->dev)->platform_data; - if (mach) /* extra check since legacy does not pass parameters */ - platform_name = mach->mach_params.platform; - ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286, - platform_name); + mach->mach_params.platform); if (ret) return ret; -- cgit v1.2.3 From 37638af8135c44e9c9e4b2744eadfd3839efc023 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 29 Aug 2019 16:42:13 -0500 Subject: ASoC: SOF/Intel: fix selection of SND_INTEL_NHTL We should only select SND_INTEL_NHLT when ACPI is defined. This was done for the legacy HDAudio driver but not for DSP-enabled cases, leading to compilation errors with randconfig. Fix by aligning on the same solution. For the Skylake driver this is overkill since there is a top-level dependency on ACPI, but it doesn't hurt and it's better to have consistency. Fixes: 68b953aeb50d9 ('ASoC: SOF: Intel: hda: fixup HDaudio topology name with DMIC number') Reported-by: Randy Dunlap Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190829214213.11653-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 2 +- sound/soc/sof/intel/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a3ec17fd63cd..01c99750212a 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -215,7 +215,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON select SND_SOC_INTEL_SST select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC select SND_SOC_ACPI_INTEL_MATCH - select SND_INTEL_NHLT + select SND_INTEL_NHLT if ACPI help If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ GeminiLake or CannonLake platform with the DSP enabled in the BIOS diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 889b6202d054..479ba249e219 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -286,7 +286,7 @@ config SND_SOC_SOF_HDA tristate select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC - select SND_INTEL_NHLT + select SND_INTEL_NHLT if ACPI help This option is not user-selectable but automagically handled by 'select' statements at a higher level -- cgit v1.2.3 From 96ed76983307a8a24400495e4e6453607e765fcf Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 30 Aug 2019 15:42:37 +0800 Subject: ASoC: mediatek: mt8183: move private structure Move private structure to the beginning of file to declare earlier so that most functions can see it. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20190830074240.195166-2-tzungbi@google.com Signed-off-by: Mark Brown --- .../mt8183/mt8183-mt6358-ts3a227-max98357.c | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 560fcc5923a4..1d4a1600f768 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -17,6 +17,22 @@ static struct snd_soc_jack headset_jack; +enum PINCTRL_PIN_STATE { + PIN_STATE_DEFAULT = 0, + PIN_TDM_OUT_ON, + PIN_TDM_OUT_OFF, + PIN_STATE_MAX +}; + +static const char * const mt8183_pin_str[PIN_STATE_MAX] = { + "default", "aud_tdm_out_on", "aud_tdm_out_off", +}; + +struct mt8183_mt6358_ts3a227_max98357_priv { + struct pinctrl *pinctrl; + struct pinctrl_state *pin_states[PIN_STATE_MAX]; +}; + static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -46,22 +62,6 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -enum PINCTRL_PIN_STATE { - PIN_STATE_DEFAULT = 0, - PIN_TDM_OUT_ON, - PIN_TDM_OUT_OFF, - PIN_STATE_MAX -}; - -static const char * const mt8183_pin_str[PIN_STATE_MAX] = { - "default", "aud_tdm_out_on", "aud_tdm_out_off", -}; - -struct mt8183_mt6358_ts3a227_max98357_priv { - struct pinctrl *pinctrl; - struct pinctrl_state *pin_states[PIN_STATE_MAX]; -}; - static int mt8183_mt6358_ts3a227_max98357_bt_sco_startup( struct snd_pcm_substream *substream) -- cgit v1.2.3 From 95d779b4b8e7a62d53c7afeba45207089dcee4c8 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 30 Aug 2019 15:42:38 +0800 Subject: ASoC: mediatek: mt8183: move headset jack to card-specific storage Move headset jack descriptor from module global scope to card-specific storage to make its ownership more explicit. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20190830074240.195166-3-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 1d4a1600f768..a7ad41b6e885 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -15,8 +15,6 @@ #include "mt8183-afe-common.h" #include "../../codecs/ts3a227e.h" -static struct snd_soc_jack headset_jack; - enum PINCTRL_PIN_STATE { PIN_STATE_DEFAULT = 0, PIN_TDM_OUT_ON, @@ -31,6 +29,7 @@ static const char * const mt8183_pin_str[PIN_STATE_MAX] = { struct mt8183_mt6358_ts3a227_max98357_priv { struct pinctrl *pinctrl; struct pinctrl_state *pin_states[PIN_STATE_MAX]; + struct snd_soc_jack headset_jack; }; static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream, @@ -410,6 +409,8 @@ static int mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component) { int ret; + struct mt8183_mt6358_ts3a227_max98357_priv *priv = + snd_soc_card_get_drvdata(component->card); /* Enable Headset and 4 Buttons Jack detection */ ret = snd_soc_card_jack_new(&mt8183_mt6358_ts3a227_max98357_card, @@ -417,12 +418,12 @@ 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, - &headset_jack, + &priv->headset_jack, NULL, 0); if (ret) return ret; - ret = ts3a227e_enable_jack_detect(component, &headset_jack); + ret = ts3a227e_enable_jack_detect(component, &priv->headset_jack); return ret; } -- cgit v1.2.3 From fc347483b87f029c1bc18a8492623ca21dcd7607 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 30 Aug 2019 15:42:39 +0800 Subject: ASoC: mediatek: mt8183: remove forward declaration of headset_init The forward declaration of mt8183_mt6358_ts3a227_max98357_headset_init is for cyclic dependency between card, headset_dev, and headset_init. It used to be: - card depends on headset_dev - headset_dev depends on headset_init - headset_init depends on card Commit a962a809e5e4 ("ASoC: mediatek: mt8183: make headset codec optional") removed the cyclic dependency. Thus, it is safe to remove the forward declaration. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20190830074240.195166-4-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index a7ad41b6e885..30a7735c4af3 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -390,14 +390,6 @@ mt8183_mt6358_ts3a227_max98357_dai_links[] = { }, }; -static int -mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *cpnt); - -static struct snd_soc_aux_dev mt8183_mt6358_ts3a227_max98357_headset_dev = { - .dlc = COMP_EMPTY(), - .init = mt8183_mt6358_ts3a227_max98357_headset_init, -}; - static struct snd_soc_card mt8183_mt6358_ts3a227_max98357_card = { .name = "mt8183_mt6358_ts3a227_max98357", .owner = THIS_MODULE, @@ -428,6 +420,11 @@ mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component) return ret; } +static struct snd_soc_aux_dev mt8183_mt6358_ts3a227_max98357_headset_dev = { + .dlc = COMP_EMPTY(), + .init = mt8183_mt6358_ts3a227_max98357_headset_init, +}; + static int mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) { -- cgit v1.2.3 From e5b3ae3e8c4772106713698075a87bff1e86e710 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 30 Aug 2019 15:42:40 +0800 Subject: ASoC: mediatek: mt8183: fix space issues Fix space issues: - No space before ';'. - No trailing blank line. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20190830074240.195166-5-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 30a7735c4af3..bb9cdc0d6552 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -471,7 +471,7 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) return PTR_ERR(priv->pinctrl); } - for (i = 0 ; i < PIN_STATE_MAX ; i++) { + for (i = 0; i < PIN_STATE_MAX; i++) { priv->pin_states[i] = pinctrl_lookup_state(priv->pinctrl, mt8183_pin_str[i]); if (IS_ERR(priv->pin_states[i])) { @@ -526,4 +526,3 @@ MODULE_DESCRIPTION("MT8183-MT6358-TS3A227-MAX98357 ALSA SoC machine driver"); MODULE_AUTHOR("Shunli Wang "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("mt8183_mt6358_ts3a227_max98357 soc card"); - -- cgit v1.2.3 From 9a7c9fe1203eb360b3a01b65a18bcd0de6670c53 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 23 Aug 2019 09:58:37 +0900 Subject: ASoC: soc-core: add soc_rtd_free() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and it will be difficult to debug. soc_rtd_init() was soc_post_component_init(), but there was no its paired soc_post_component_free(), but it is done at soc_remove_link_dais(). This means it is difficult to find related code. This patch adds soc_rtd_free() which is paired soc_rtd_init(). soc_rtd_xxx() will be more cleanuped in the future. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tva87lby.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3c087b478398..3754a08baf62 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -975,17 +975,15 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) dai->probed = 0; } +static void soc_rtd_free(struct snd_soc_pcm_runtime *rtd); /* remove me */ static void soc_remove_link_dais(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, int order) { int i; struct snd_soc_dai *codec_dai; - /* unregister the rtd device */ - if (rtd->dev_registered) { - device_unregister(rtd->dev); - rtd->dev_registered = 0; - } + /* finalize rtd device */ + soc_rtd_free(rtd); /* remove the CODEC DAI */ for_each_rtd_codec_dai(rtd, i, codec_dai) @@ -1340,6 +1338,15 @@ err_probe: return ret; } +static void soc_rtd_free(struct snd_soc_pcm_runtime *rtd) +{ + if (rtd->dev_registered) { + /* we don't need to call kfree() for rtd->dev */ + device_unregister(rtd->dev); + rtd->dev_registered = 0; + } +} + static void soc_rtd_release(struct device *dev) { kfree(dev); -- cgit v1.2.3 From ffd60fba19d9752f553aac367cd40362011ab6c9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 23 Aug 2019 09:58:42 +0900 Subject: ASoC: soc-core: move soc_probe_component() position It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and it will be difficult to debug. soc_probe_comonent() has paired soc_remove_comonent(), but, these are implemented at different place. So it is difficult to confirm code. This patch moves soc_probe_component() next to soc_remove_component(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sgps7lbt.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 261 +++++++++++++++++++++++++-------------------------- 1 file changed, 130 insertions(+), 131 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3754a08baf62..8fa1cfcc6f17 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -938,6 +938,41 @@ _err_defer: return -EPROBE_DEFER; } +static void soc_set_of_name_prefix(struct snd_soc_component *component) +{ + struct device_node *of_node = soc_component_to_node(component); + const char *str; + int ret; + + ret = of_property_read_string(of_node, "sound-name-prefix", &str); + if (!ret) + component->name_prefix = str; +} + +static void soc_set_name_prefix(struct snd_soc_card *card, + struct snd_soc_component *component) +{ + int i; + + for (i = 0; i < card->num_configs && card->codec_conf; i++) { + struct snd_soc_codec_conf *map = &card->codec_conf[i]; + struct device_node *of_node = soc_component_to_node(component); + + if (map->of_node && of_node != map->of_node) + continue; + if (map->dev_name && strcmp(component->name, map->dev_name)) + continue; + component->name_prefix = map->name_prefix; + return; + } + + /* + * If there is no configuration table or no match in the table, + * check if a prefix is provided in the node + */ + soc_set_of_name_prefix(component); +} + static void soc_cleanup_component(struct snd_soc_component *component) { snd_soc_component_set_jack(component, NULL, NULL); @@ -958,6 +993,101 @@ static void soc_remove_component(struct snd_soc_component *component) soc_cleanup_component(component); } +static int soc_probe_component(struct snd_soc_card *card, + struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct snd_soc_dai *dai; + int ret; + + if (!strcmp(component->name, "snd-soc-dummy")) + return 0; + + if (component->card) { + if (component->card != card) { + dev_err(component->dev, + "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n", + card->name, component->card->name); + return -ENODEV; + } + return 0; + } + + ret = snd_soc_component_module_get_when_probe(component); + if (ret < 0) + return ret; + + component->card = card; + dapm->card = card; + INIT_LIST_HEAD(&dapm->list); + soc_set_name_prefix(card, component); + + soc_init_component_debugfs(component); + + ret = snd_soc_dapm_new_controls(dapm, + component->driver->dapm_widgets, + component->driver->num_dapm_widgets); + + if (ret != 0) { + dev_err(component->dev, + "Failed to create new controls %d\n", ret); + goto err_probe; + } + + for_each_component_dais(component, dai) { + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret != 0) { + dev_err(component->dev, + "Failed to create DAI widgets %d\n", ret); + goto err_probe; + } + } + + ret = snd_soc_component_probe(component); + if (ret < 0) { + dev_err(component->dev, + "ASoC: failed to probe component %d\n", ret); + goto err_probe; + } + WARN(dapm->idle_bias_off && + dapm->bias_level != SND_SOC_BIAS_OFF, + "codec %s can not start from non-off bias with idle_bias_off==1\n", + component->name); + + /* machine specific init */ + if (component->init) { + ret = component->init(component); + if (ret < 0) { + dev_err(component->dev, + "Failed to do machine specific init %d\n", ret); + goto err_probe; + } + } + + ret = snd_soc_add_component_controls(component, + component->driver->controls, + component->driver->num_controls); + if (ret < 0) + goto err_probe; + + ret = snd_soc_dapm_add_routes(dapm, + component->driver->dapm_routes, + component->driver->num_dapm_routes); + if (ret < 0) + goto err_probe; + + list_add(&dapm->list, &card->dapm_list); + /* see for_each_card_components */ + list_add(&component->card_list, &card->component_dev_list); + +err_probe: + if (ret < 0) + soc_cleanup_component(component); + + return ret; +} + static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; @@ -1207,137 +1337,6 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); -static void soc_set_of_name_prefix(struct snd_soc_component *component) -{ - struct device_node *component_of_node = soc_component_to_node(component); - const char *str; - int ret; - - ret = of_property_read_string(component_of_node, "sound-name-prefix", - &str); - if (!ret) - component->name_prefix = str; -} - -static void soc_set_name_prefix(struct snd_soc_card *card, - struct snd_soc_component *component) -{ - int i; - - for (i = 0; i < card->num_configs && card->codec_conf; i++) { - struct snd_soc_codec_conf *map = &card->codec_conf[i]; - struct device_node *component_of_node = soc_component_to_node(component); - - if (map->of_node && component_of_node != map->of_node) - continue; - if (map->dev_name && strcmp(component->name, map->dev_name)) - continue; - component->name_prefix = map->name_prefix; - return; - } - - /* - * If there is no configuration table or no match in the table, - * check if a prefix is provided in the node - */ - soc_set_of_name_prefix(component); -} - -static int soc_probe_component(struct snd_soc_card *card, - struct snd_soc_component *component) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - struct snd_soc_dai *dai; - int ret; - - if (!strcmp(component->name, "snd-soc-dummy")) - return 0; - - if (component->card) { - if (component->card != card) { - dev_err(component->dev, - "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n", - card->name, component->card->name); - return -ENODEV; - } - return 0; - } - - ret = snd_soc_component_module_get_when_probe(component); - if (ret < 0) - return ret; - - component->card = card; - dapm->card = card; - INIT_LIST_HEAD(&dapm->list); - soc_set_name_prefix(card, component); - - soc_init_component_debugfs(component); - - ret = snd_soc_dapm_new_controls(dapm, - component->driver->dapm_widgets, - component->driver->num_dapm_widgets); - - if (ret != 0) { - dev_err(component->dev, - "Failed to create new controls %d\n", ret); - goto err_probe; - } - - for_each_component_dais(component, dai) { - ret = snd_soc_dapm_new_dai_widgets(dapm, dai); - if (ret != 0) { - dev_err(component->dev, - "Failed to create DAI widgets %d\n", ret); - goto err_probe; - } - } - - ret = snd_soc_component_probe(component); - if (ret < 0) { - dev_err(component->dev, - "ASoC: failed to probe component %d\n", ret); - goto err_probe; - } - WARN(dapm->idle_bias_off && - dapm->bias_level != SND_SOC_BIAS_OFF, - "codec %s can not start from non-off bias with idle_bias_off==1\n", - component->name); - - /* machine specific init */ - if (component->init) { - ret = component->init(component); - if (ret < 0) { - dev_err(component->dev, - "Failed to do machine specific init %d\n", ret); - goto err_probe; - } - } - - ret = snd_soc_add_component_controls(component, - component->driver->controls, - component->driver->num_controls); - if (ret < 0) - goto err_probe; - - ret = snd_soc_dapm_add_routes(dapm, - component->driver->dapm_routes, - component->driver->num_dapm_routes); - if (ret < 0) - goto err_probe; - - list_add(&dapm->list, &card->dapm_list); - /* see for_each_card_components */ - list_add(&component->card_list, &card->component_dev_list); - -err_probe: - if (ret < 0) - soc_cleanup_component(component); - - return ret; -} - static void soc_rtd_free(struct snd_soc_pcm_runtime *rtd) { if (rtd->dev_registered) { -- cgit v1.2.3 From b614beafa495c7f6fbc15cb6977e3fe48beea1e5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 23 Aug 2019 09:58:47 +0900 Subject: ASoC: soc-core: dapm related setup at one place Current ASoC setups some dapm related member at snd_soc_component_initialize() which is called when component was registered, and setups remaining member at soc_probe_component() which is called when component was probed. This kind of setup separation is no meanings, and it is very difficult to read and confusable. This patch setups all dapm settings at one place. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r25c7lbo.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8fa1cfcc6f17..21c005a044e8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1019,12 +1019,19 @@ static int soc_probe_component(struct snd_soc_card *card, return ret; component->card = card; - dapm->card = card; - INIT_LIST_HEAD(&dapm->list); soc_set_name_prefix(card, component); soc_init_component_debugfs(component); + INIT_LIST_HEAD(&dapm->list); + dapm->card = card; + dapm->dev = component->dev; + dapm->component = component; + dapm->bias_level = SND_SOC_BIAS_OFF; + dapm->idle_bias_off = !component->driver->idle_bias_on; + dapm->suspend_bias_off = component->driver->suspend_bias_off; + list_add(&dapm->list, &card->dapm_list); + ret = snd_soc_dapm_new_controls(dapm, component->driver->dapm_widgets, component->driver->num_dapm_widgets); @@ -1077,7 +1084,6 @@ static int soc_probe_component(struct snd_soc_card *card, if (ret < 0) goto err_probe; - list_add(&dapm->list, &card->dapm_list); /* see for_each_card_components */ list_add(&component->card_list, &card->component_dev_list); @@ -2649,8 +2655,6 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dai); static int snd_soc_component_initialize(struct snd_soc_component *component, const struct snd_soc_component_driver *driver, struct device *dev) { - struct snd_soc_dapm_context *dapm; - INIT_LIST_HEAD(&component->dai_list); INIT_LIST_HEAD(&component->dobj_list); INIT_LIST_HEAD(&component->card_list); @@ -2665,13 +2669,6 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->dev = dev; component->driver = driver; - dapm = snd_soc_component_get_dapm(component); - dapm->dev = dev; - dapm->component = component; - dapm->bias_level = SND_SOC_BIAS_OFF; - dapm->idle_bias_off = !driver->idle_bias_on; - dapm->suspend_bias_off = driver->suspend_bias_off; - return 0; } -- cgit v1.2.3 From 95c267dd20431f0eb54ca204bd73a7d85c532a37 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 23 Aug 2019 09:58:52 +0900 Subject: ASoC: soc-core: add snd_soc_dapm_init() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and it will be difficult to debug. soc-dapm has snd_soc_dapm_free() which cleanups debugfs, widgets, list. But, there is no paired initialize function. This patch adds snd_soc_dapm_init() and initilaizing dapm Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pnkw7lbj.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 3 +++ sound/soc/soc-core.c | 14 ++------------ sound/soc/soc-dapm.c | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 2aa73d6dd7be..dd993dd29229 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -416,6 +416,9 @@ int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, /* dapm path setup */ int snd_soc_dapm_new_widgets(struct snd_soc_card *card); void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); +void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm, + struct snd_soc_card *card, + struct snd_soc_component *component); int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num); int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 21c005a044e8..8e831ae59eb8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1023,14 +1023,7 @@ static int soc_probe_component(struct snd_soc_card *card, soc_init_component_debugfs(component); - INIT_LIST_HEAD(&dapm->list); - dapm->card = card; - dapm->dev = component->dev; - dapm->component = component; - dapm->bias_level = SND_SOC_BIAS_OFF; - dapm->idle_bias_off = !component->driver->idle_bias_on; - dapm->suspend_bias_off = component->driver->suspend_bias_off; - list_add(&dapm->list, &card->dapm_list); + snd_soc_dapm_init(dapm, card, component); ret = snd_soc_dapm_new_controls(dapm, component->driver->dapm_widgets, @@ -1937,10 +1930,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); - card->dapm.bias_level = SND_SOC_BIAS_OFF; - card->dapm.dev = card->dev; - card->dapm.card = card; - list_add(&card->dapm.list, &card->dapm_list); + snd_soc_dapm_init(&card->dapm, card, NULL); /* check whether any platform is ignore machine FE and using topology */ soc_check_tplg_fes(card); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 10819b3e0b98..b6378f025836 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4717,6 +4717,27 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) } EXPORT_SYMBOL_GPL(snd_soc_dapm_free); +void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm, + struct snd_soc_card *card, + struct snd_soc_component *component) +{ + dapm->card = card; + dapm->component = component; + dapm->bias_level = SND_SOC_BIAS_OFF; + + if (component) { + dapm->dev = component->dev; + dapm->idle_bias_off = !component->driver->idle_bias_on, + dapm->suspend_bias_off = component->driver->suspend_bias_off; + } else { + dapm->dev = card->dev; + } + + INIT_LIST_HEAD(&dapm->list); + list_add(&dapm->list, &card->dapm_list); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_init); + static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm) { struct snd_soc_card *card = dapm->card; -- cgit v1.2.3 From 6fb035502956ad1f338ca61c057653d5372ffd8c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 23 Aug 2019 09:58:58 +0900 Subject: ASoC: soc-core: move soc_probe_link_components() position It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and it will be difficult to debug. soc_probe_link_components() has paired soc_remove_link_components(), but, these are implemented at different place. So it is difficult to confirm code. This patch moves soc_probe_link_components() next to soc_remove_link_components(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o90g7lbd.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8e831ae59eb8..2a166abaade1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1135,6 +1135,26 @@ static void soc_remove_link_components(struct snd_soc_card *card, } } +static int soc_probe_link_components(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) +{ + struct snd_soc_component *component; + struct snd_soc_rtdcom_list *rtdcom; + int ret; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (component->driver->probe_order == order) { + ret = soc_probe_component(card, component); + if (ret < 0) + return ret; + } + } + + return 0; +} + static void soc_remove_dai_links(struct snd_soc_card *card) { int order; @@ -1379,26 +1399,6 @@ static int soc_rtd_init(struct snd_soc_pcm_runtime *rtd, const char *name) return 0; } -static int soc_probe_link_components(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, int order) -{ - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; - int ret; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (component->driver->probe_order == order) { - ret = soc_probe_component(card, component); - if (ret < 0) - return ret; - } - } - - return 0; -} - static int soc_probe_dai(struct snd_soc_dai *dai, int order) { int ret; -- cgit v1.2.3 From 39c66b6ef6f3aaf5bac61555db70ffb2864161c6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 3 Sep 2019 17:15:54 +0900 Subject: ASoC: simple-card: indicate rebind issue ALSA SoC try to rebind Sound Card if Card/CPU/Codec/Platform were unbinded and re-binded again. But, Simple Card might can't rebind again if user do for example unbind CPU or Codec driver bind CPU or Codec driver Because Simple Card is still pointing old/unbinded CPU or Codec driver's DAI name at dlc->dai_name. To avoid this issue, it needs to alloc memory and keep DAI name even though if CPU or Codec driver was unbinded. Or, always do unbind/bind at Sound Card. For now, this patch indicates this issue as FIXME. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tv9tu75x.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 0eac3bcb9736..fc9c753db8dd 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -46,7 +46,25 @@ static int asoc_simple_parse_dai(struct device_node *node, if (ret) return ret; - /* Get dai->name */ + /* + * FIXME + * + * Here, dlc->dai_name is pointer to CPU/Codec DAI name. + * If user unbinded CPU or Codec driver, but not for Sound Card, + * dlc->dai_name is keeping unbinded CPU or Codec + * driver's pointer. + * + * If user re-bind CPU or Codec driver again, ALSA SoC will try + * to rebind Card via snd_soc_try_rebind_card(), but because of + * above reason, it might can't bind Sound Card. + * Because Sound Card is pointing to released dai_name pointer. + * + * To avoid this rebind Card issue, + * 1) It needs to alloc memory to keep dai_name eventhough + * CPU or Codec driver was unbinded, or + * 2) user need to rebind Sound Card everytime + * if he unbinded CPU or Codec. + */ ret = snd_soc_of_get_dai_name(node, &dlc->dai_name); if (ret < 0) return ret; -- cgit v1.2.3 From 157ab71286e6dd71676052275ab5dfa3955c5cdb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 3 Sep 2019 17:16:05 +0900 Subject: ASoC: audio-graph: indicate rebind issue ALSA SoC try to rebind Sound Card if Card/CPU/Codec/Platform were unbinded and re-binded again. But, Audio Graph Card might can't rebind again if user do for example unbind CPU or Codec driver bind CPU or Codec driver Because Audio Graph Card is still pointing old/unbinded CPU or Codec driver's DAI name at dlc->dai_name. To avoid this issue, it needs to alloc memory and keep DAI name even though if CPU or Codec driver was unbinded. Or, always do unbind/bind at Sound Card. For now, this patch indicates this issue as FIXME. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sgpdu75m.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'sound') diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 288df245b2f0..6007e6305735 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -129,6 +129,25 @@ static int asoc_simple_parse_dai(struct device_node *ep, args.args[0] = graph_get_dai_id(ep); args.args_count = (of_graph_get_endpoint_count(node) > 1); + /* + * FIXME + * + * Here, dlc->dai_name is pointer to CPU/Codec DAI name. + * If user unbinded CPU or Codec driver, but not for Sound Card, + * dlc->dai_name is keeping unbinded CPU or Codec + * driver's pointer. + * + * If user re-bind CPU or Codec driver again, ALSA SoC will try + * to rebind Card via snd_soc_try_rebind_card(), but because of + * above reason, it might can't bind Sound Card. + * Because Sound Card is pointing to released dai_name pointer. + * + * To avoid this rebind Card issue, + * 1) It needs to alloc memory to keep dai_name eventhough + * CPU or Codec driver was unbinded, or + * 2) user need to rebind Sound Card everytime + * if he unbinded CPU or Codec. + */ ret = snd_soc_get_dai_name(&args, &dlc->dai_name); if (ret < 0) return ret; -- cgit v1.2.3 From 6dd567dc964878c04269a44114ef13693712edf1 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Wed, 4 Sep 2019 01:53:20 +0900 Subject: ASoC: es8316: add clock control of MCLK This patch introduce clock property for MCLK master freq control. Driver will set rate of MCLK master if set_sysclk is called and changing sysclk by board driver. [Modified slightly to apply without an earlier patch in the series due to context diffs -- broonie] Signed-off-by: Katsuhiro Suzuki Link: https://lore.kernel.org/r/20190903165322.20791-2-katsuhiro@katsuster.net Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 6db002cc2058..6248b01ca049 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -33,6 +34,7 @@ static const unsigned int supported_mclk_lrck_ratios[] = { struct es8316_priv { struct mutex lock; + struct clk *mclk; struct regmap *regmap; struct snd_soc_component *component; struct snd_soc_jack *jack; @@ -360,7 +362,7 @@ static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai, { struct snd_soc_component *component = codec_dai->component; struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); - int i; + int i, ret; int count = 0; es8316->sysclk = freq; @@ -368,6 +370,12 @@ static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai, if (freq == 0) return 0; + if (es8316->mclk) { + ret = clk_set_rate(es8316->mclk, freq); + if (ret) + return ret; + } + /* Limit supported sample rates to ones that can be autodetected * by the codec running in slave mode. */ @@ -697,9 +705,26 @@ static int es8316_set_jack(struct snd_soc_component *component, static int es8316_probe(struct snd_soc_component *component) { struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + int ret; es8316->component = component; + es8316->mclk = devm_clk_get(component->dev, "mclk"); + if (PTR_ERR(es8316->mclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (IS_ERR(es8316->mclk)) { + dev_err(component->dev, "clock is invalid, ignored\n"); + es8316->mclk = NULL; + } + + if (es8316->mclk) { + ret = clk_prepare_enable(es8316->mclk); + if (ret) { + dev_err(component->dev, "unable to enable clock\n"); + return ret; + } + } + /* Reset codec and enable current state machine */ snd_soc_component_write(component, ES8316_RESET, 0x3f); usleep_range(5000, 5500); @@ -722,8 +747,17 @@ static int es8316_probe(struct snd_soc_component *component) return 0; } +static void es8316_remove(struct snd_soc_component *component) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + if (es8316->mclk) + clk_disable_unprepare(es8316->mclk); +} + static const struct snd_soc_component_driver soc_component_dev_es8316 = { .probe = es8316_probe, + .remove = es8316_remove, .set_jack = es8316_set_jack, .controls = es8316_snd_controls, .num_controls = ARRAY_SIZE(es8316_snd_controls), -- cgit v1.2.3 From dfafc1822f6826c9d250223f59ce8c3b227866a6 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 4 Sep 2019 15:48:33 +0800 Subject: ASoC: amd: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190904074833.23572-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-pcm-dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index d26653f81416..52225b4b6382 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -1251,8 +1251,7 @@ static int acp_audio_probe(struct platform_device *pdev) if (!audio_drv_data) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - audio_drv_data->acp_mmio = devm_ioremap_resource(&pdev->dev, res); + audio_drv_data->acp_mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(audio_drv_data->acp_mmio)) return PTR_ERR(audio_drv_data->acp_mmio); -- cgit v1.2.3 From f295495ec657c5fb2cff355456c2a20c4c945d93 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 4 Sep 2019 16:25:07 +0800 Subject: ASoC: ep93xx: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190904082507.24300-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/cirrus/ep93xx-ac97.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c index 84c967fcab6b..e21eaa1893d1 100644 --- a/sound/soc/cirrus/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c @@ -362,7 +362,6 @@ static const struct snd_soc_component_driver ep93xx_ac97_component = { static int ep93xx_ac97_probe(struct platform_device *pdev) { struct ep93xx_ac97_info *info; - struct resource *res; int irq; int ret; @@ -370,8 +369,7 @@ static int ep93xx_ac97_probe(struct platform_device *pdev) if (!info) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->regs = devm_ioremap_resource(&pdev->dev, res); + info->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(info->regs)) return PTR_ERR(info->regs); -- cgit v1.2.3 From 2f302d476c960fdf8481399a46b8df92408d06e2 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 4 Sep 2019 16:34:12 +0800 Subject: ASoC: sirf-audio: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190904083412.18700-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/sirf-audio-codec.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c index 9009a7407b7a..a061d78473ac 100644 --- a/sound/soc/codecs/sirf-audio-codec.c +++ b/sound/soc/codecs/sirf-audio-codec.c @@ -459,7 +459,6 @@ static int sirf_audio_codec_driver_probe(struct platform_device *pdev) int ret; struct sirf_audio_codec *sirf_audio_codec; void __iomem *base; - struct resource *mem_res; sirf_audio_codec = devm_kzalloc(&pdev->dev, sizeof(struct sirf_audio_codec), GFP_KERNEL); @@ -468,8 +467,7 @@ static int sirf_audio_codec_driver_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sirf_audio_codec); - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem_res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); -- cgit v1.2.3 From a813d0e8884e514e6e1b28ad3b22f7658d446b16 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 4 Sep 2019 16:39:09 +0800 Subject: ASoC: tegra: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190904083909.18804-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_ahub.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 952381260dc3..635eacbd28d4 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -511,7 +511,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) const struct tegra30_ahub_soc_data *soc_data; struct reset_control *rst; int i; - struct resource *res0, *res1; + struct resource *res0; void __iomem *regs_apbif, *regs_ahub; int ret = 0; @@ -587,8 +587,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) } regcache_cache_only(ahub->regmap_apbif, true); - res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - regs_ahub = devm_ioremap_resource(&pdev->dev, res1); + regs_ahub = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(regs_ahub)) return PTR_ERR(regs_ahub); -- cgit v1.2.3 From 04f770d968344ca95b55cf7b50452888ec5440e7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2019 09:14:35 +0900 Subject: ASoC: soc-core: add comment to jack at soc_remove_component() Basically, driver which setups snd_soc_component_set_jack() need to release it by themselves. But, as framework level robustness, soc_remove_component() also releases it. To avoid code reader confuse, this patch makes it clarify. This patch makes it clarify. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/875zm8q5n8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2a166abaade1..05a2aff843aa 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -975,7 +975,9 @@ static void soc_set_name_prefix(struct snd_soc_card *card, static void soc_cleanup_component(struct snd_soc_component *component) { + /* For framework level robustness */ snd_soc_component_set_jack(component, NULL, NULL); + list_del(&component->card_list); snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); -- cgit v1.2.3 From 1ab1b340f037760ec9944a9a4911e85f29fc6e2c Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 4 Sep 2019 21:03:06 -0700 Subject: ASoC: qcom: common: Include link-name in error messages Reading out the link-name earlier and including it in the various error messages makes it much more convenient to figure out what links have unmet dependencies. Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20190905040306.21399-1-bjorn.andersson@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/common.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index 2c7348ddbbb3..6c20bdd850f3 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -53,12 +53,18 @@ int qcom_snd_parse_of(struct snd_soc_card *card) link->num_cpus = 1; link->num_platforms = 1; + ret = of_property_read_string(np, "link-name", &link->name); + if (ret) { + dev_err(card->dev, "error getting codec dai_link name\n"); + goto err; + } + cpu = of_get_child_by_name(np, "cpu"); platform = of_get_child_by_name(np, "platform"); codec = of_get_child_by_name(np, "codec"); if (!cpu) { - dev_err(dev, "Can't find cpu DT node\n"); + dev_err(dev, "%s: Can't find cpu DT node\n", link->name); ret = -EINVAL; goto err; } @@ -66,7 +72,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) ret = of_parse_phandle_with_args(cpu, "sound-dai", "#sound-dai-cells", 0, &args); if (ret) { - dev_err(card->dev, "error getting cpu phandle\n"); + dev_err(card->dev, "%s: error getting cpu phandle\n", link->name); goto err; } link->cpus->of_node = args.np; @@ -74,7 +80,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) ret = snd_soc_of_get_dai_name(cpu, &link->cpus->dai_name); if (ret) { - dev_err(card->dev, "error getting cpu dai name\n"); + dev_err(card->dev, "%s: error getting cpu dai name\n", link->name); goto err; } @@ -83,14 +89,14 @@ int qcom_snd_parse_of(struct snd_soc_card *card) "sound-dai", 0); if (!link->platforms->of_node) { - dev_err(card->dev, "platform dai not found\n"); + dev_err(card->dev, "%s: platform dai not found\n", link->name); ret = -EINVAL; goto err; } ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); if (ret < 0) { - dev_err(card->dev, "codec dai not found\n"); + dev_err(card->dev, "%s: codec dai not found\n", link->name); goto err; } link->no_pcm = 1; @@ -110,12 +116,6 @@ int qcom_snd_parse_of(struct snd_soc_card *card) } link->ignore_suspend = 1; - ret = of_property_read_string(np, "link-name", &link->name); - if (ret) { - dev_err(card->dev, "error getting codec dai_link name\n"); - goto err; - } - link->nonatomic = 1; link->dpcm_playback = 1; link->dpcm_capture = 1; -- cgit v1.2.3 From 8fcd2d914e786033e589b4eb8cb62d37d0fa9701 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 5 Sep 2019 14:01:15 +0200 Subject: ASoC: meson: axg-frddr: expose all 8 outputs The FRDDR component, as it, has a maximum of 8 outputs. Depending on the SoC, these may not all be connected. Instead of decribing only the connected outputs of each SoC, describe them all and let ASoC routing do the rest. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190905120120.31752-4-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-frddr.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index 2b8807737b2b..0968e8375000 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -104,7 +104,7 @@ static struct snd_soc_dai_driver axg_frddr_dai_drv = { }; static const char * const axg_frddr_sel_texts[] = { - "OUT 0", "OUT 1", "OUT 2", "OUT 3" + "OUT 0", "OUT 1", "OUT 2", "OUT 3", "OUT 4", "OUT 5", "OUT 6", "OUT 7", }; static SOC_ENUM_SINGLE_DECL(axg_frddr_sel_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, @@ -120,6 +120,10 @@ static const struct snd_soc_dapm_widget axg_frddr_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0), }; static const struct snd_soc_dapm_route axg_frddr_dapm_routes[] = { @@ -128,6 +132,10 @@ static const struct snd_soc_dapm_route axg_frddr_dapm_routes[] = { { "OUT 1", "OUT 1", "SINK SEL" }, { "OUT 2", "OUT 2", "SINK SEL" }, { "OUT 3", "OUT 3", "SINK SEL" }, + { "OUT 4", "OUT 4", "SINK SEL" }, + { "OUT 5", "OUT 5", "SINK SEL" }, + { "OUT 6", "OUT 6", "SINK SEL" }, + { "OUT 7", "OUT 7", "SINK SEL" }, }; static const struct snd_soc_component_driver axg_frddr_component_drv = { @@ -162,16 +170,12 @@ static struct snd_soc_dai_driver g12a_frddr_dai_drv = { .pcm_new = axg_frddr_pcm_new, }; -static const char * const g12a_frddr_sel_texts[] = { - "OUT 0", "OUT 1", "OUT 2", "OUT 3", "OUT 4", -}; - static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, - g12a_frddr_sel_texts); + axg_frddr_sel_texts); static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel2_enum, FIFO_CTRL0, CTRL0_SEL2_SHIFT, - g12a_frddr_sel_texts); + axg_frddr_sel_texts); static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel3_enum, FIFO_CTRL0, CTRL0_SEL3_SHIFT, - g12a_frddr_sel_texts); + axg_frddr_sel_texts); static const struct snd_kcontrol_new g12a_frddr_out1_demux = SOC_DAPM_ENUM("Output Src 1", g12a_frddr_sel1_enum); @@ -211,6 +215,9 @@ static const struct snd_soc_dapm_widget g12a_frddr_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0), }; static const struct snd_soc_dapm_route g12a_frddr_dapm_routes[] = { @@ -228,16 +235,25 @@ static const struct snd_soc_dapm_route g12a_frddr_dapm_routes[] = { { "OUT 2", "OUT 2", "SINK 1 SEL" }, { "OUT 3", "OUT 3", "SINK 1 SEL" }, { "OUT 4", "OUT 4", "SINK 1 SEL" }, + { "OUT 5", "OUT 5", "SINK 1 SEL" }, + { "OUT 6", "OUT 6", "SINK 1 SEL" }, + { "OUT 7", "OUT 7", "SINK 1 SEL" }, { "OUT 0", "OUT 0", "SINK 2 SEL" }, { "OUT 1", "OUT 1", "SINK 2 SEL" }, { "OUT 2", "OUT 2", "SINK 2 SEL" }, { "OUT 3", "OUT 3", "SINK 2 SEL" }, { "OUT 4", "OUT 4", "SINK 2 SEL" }, + { "OUT 5", "OUT 5", "SINK 2 SEL" }, + { "OUT 6", "OUT 6", "SINK 2 SEL" }, + { "OUT 7", "OUT 7", "SINK 2 SEL" }, { "OUT 0", "OUT 0", "SINK 3 SEL" }, { "OUT 1", "OUT 1", "SINK 3 SEL" }, { "OUT 2", "OUT 2", "SINK 3 SEL" }, { "OUT 3", "OUT 3", "SINK 3 SEL" }, { "OUT 4", "OUT 4", "SINK 3 SEL" }, + { "OUT 5", "OUT 5", "SINK 3 SEL" }, + { "OUT 6", "OUT 6", "SINK 3 SEL" }, + { "OUT 7", "OUT 7", "SINK 3 SEL" }, }; static const struct snd_soc_component_driver g12a_frddr_component_drv = { -- cgit v1.2.3 From 6beced211c22dd8c3e546c956512fddd8e09884f Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 5 Sep 2019 14:01:16 +0200 Subject: ASoC: meson: axg-toddr: expose all 8 inputs The TODDR component, as it, has a maximum of 8 input. Depending on the SoC, these may not all be connected or some input components may not be supported Instead of decribing only the connected inputs, describe them all and let ASoC routing do the rest. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190905120120.31752-5-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-toddr.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index 4f63e434fad4..2e9a2e5862ce 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c @@ -142,16 +142,11 @@ static struct snd_soc_dai_driver axg_toddr_dai_drv = { }; static const char * const axg_toddr_sel_texts[] = { - "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 6" + "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 5", "IN 6", "IN 7" }; -static const unsigned int axg_toddr_sel_values[] = { - 0, 1, 2, 3, 4, 6 -}; - -static SOC_VALUE_ENUM_SINGLE_DECL(axg_toddr_sel_enum, FIFO_CTRL0, - CTRL0_SEL_SHIFT, CTRL0_SEL_MASK, - axg_toddr_sel_texts, axg_toddr_sel_values); +static SOC_ENUM_SINGLE_DECL(axg_toddr_sel_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, + axg_toddr_sel_texts); static const struct snd_kcontrol_new axg_toddr_in_mux = SOC_DAPM_ENUM("Input Source", axg_toddr_sel_enum); @@ -163,7 +158,9 @@ static const struct snd_soc_dapm_widget axg_toddr_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 5", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("IN 6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 7", NULL, 0, SND_SOC_NOPM, 0, 0), }; static const struct snd_soc_dapm_route axg_toddr_dapm_routes[] = { @@ -173,7 +170,9 @@ static const struct snd_soc_dapm_route axg_toddr_dapm_routes[] = { { "SRC SEL", "IN 2", "IN 2" }, { "SRC SEL", "IN 3", "IN 3" }, { "SRC SEL", "IN 4", "IN 4" }, + { "SRC SEL", "IN 5", "IN 5" }, { "SRC SEL", "IN 6", "IN 6" }, + { "SRC SEL", "IN 7", "IN 7" }, }; static const struct snd_soc_component_driver axg_toddr_component_drv = { -- cgit v1.2.3 From cde9f12e5f0d288d516c810f95c2ee4c171e0245 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 5 Sep 2019 14:01:17 +0200 Subject: ASoC: meson: tdmin: expose all 16 inputs The TDMIN component, as it, has a maximum of 16 input. Depending on the SoC, these may not all be connected. Instead of decribing only the connected inputs of each SoC, describe them all and let ASoC routing do the rest. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190905120120.31752-6-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-tdmin.c | 47 ++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-tdmin.c b/sound/soc/meson/axg-tdmin.c index cb87f17f3e95..973d4c02ef8d 100644 --- a/sound/soc/meson/axg-tdmin.c +++ b/sound/soc/meson/axg-tdmin.c @@ -43,7 +43,8 @@ static const struct regmap_config axg_tdmin_regmap_cfg = { }; static const char * const axg_tdmin_sel_texts[] = { - "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 5", + "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 5", "IN 6", "IN 7", + "IN 8", "IN 9", "IN 10", "IN 11", "IN 12", "IN 13", "IN 14", "IN 15", }; /* Change to special mux control to reset dapm */ @@ -164,12 +165,22 @@ static int axg_tdmin_prepare(struct regmap *map, } static const struct snd_soc_dapm_widget axg_tdmin_dapm_widgets[] = { - SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("IN 5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 7", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 8", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 9", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 10", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 11", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 12", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 13", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 14", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 15", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_tdmin_in_mux), SND_SOC_DAPM_PGA_E("DEC", SND_SOC_NOPM, 0, 0, NULL, 0, axg_tdm_formatter_event, @@ -178,12 +189,22 @@ static const struct snd_soc_dapm_widget axg_tdmin_dapm_widgets[] = { }; static const struct snd_soc_dapm_route axg_tdmin_dapm_routes[] = { - { "SRC SEL", "IN 0", "IN 0" }, - { "SRC SEL", "IN 1", "IN 1" }, - { "SRC SEL", "IN 2", "IN 2" }, - { "SRC SEL", "IN 3", "IN 3" }, - { "SRC SEL", "IN 4", "IN 4" }, - { "SRC SEL", "IN 5", "IN 5" }, + { "SRC SEL", "IN 0", "IN 0" }, + { "SRC SEL", "IN 1", "IN 1" }, + { "SRC SEL", "IN 2", "IN 2" }, + { "SRC SEL", "IN 3", "IN 3" }, + { "SRC SEL", "IN 4", "IN 4" }, + { "SRC SEL", "IN 5", "IN 5" }, + { "SRC SEL", "IN 6", "IN 6" }, + { "SRC SEL", "IN 7", "IN 7" }, + { "SRC SEL", "IN 8", "IN 8" }, + { "SRC SEL", "IN 9", "IN 9" }, + { "SRC SEL", "IN 10", "IN 10" }, + { "SRC SEL", "IN 11", "IN 11" }, + { "SRC SEL", "IN 12", "IN 12" }, + { "SRC SEL", "IN 13", "IN 13" }, + { "SRC SEL", "IN 14", "IN 14" }, + { "SRC SEL", "IN 15", "IN 15" }, { "DEC", NULL, "SRC SEL" }, { "OUT", NULL, "DEC" }, }; -- cgit v1.2.3 From 52dd80d8f7386483bc60b2b7470e47a2e6f61d7c Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 5 Sep 2019 14:01:18 +0200 Subject: ASoC: meson: axg-frddr: add sm1 support On sm1, the output routing bits have moved to CTRL2 register Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190905120120.31752-7-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-fifo.c | 2 +- sound/soc/meson/axg-fifo.h | 1 + sound/soc/meson/axg-frddr.c | 73 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index 80a3dde35b5c..5a3749938900 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -306,7 +306,7 @@ static const struct regmap_config axg_fifo_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .max_register = FIFO_INIT_ADDR, + .max_register = FIFO_CTRL2, }; int axg_fifo_probe(struct platform_device *pdev) diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h index 5caf81241dfe..bb1e2ce50256 100644 --- a/sound/soc/meson/axg-fifo.h +++ b/sound/soc/meson/axg-fifo.h @@ -61,6 +61,7 @@ struct snd_soc_pcm_runtime; #define STATUS1_INT_STS(x) ((x) << 0) #define FIFO_STATUS2 0x18 #define FIFO_INIT_ADDR 0x24 +#define FIFO_CTRL2 0x28 struct axg_fifo { struct regmap *map; diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index 0968e8375000..6ab111c31b28 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -23,6 +23,12 @@ #define CTRL0_SEL3_SHIFT 8 #define CTRL0_SEL3_EN_SHIFT 11 #define CTRL1_FRDDR_FORCE_FINISH BIT(12) +#define CTRL2_SEL1_SHIFT 0 +#define CTRL2_SEL1_EN_SHIFT 4 +#define CTRL2_SEL2_SHIFT 8 +#define CTRL2_SEL2_EN_SHIFT 12 +#define CTRL2_SEL3_SHIFT 16 +#define CTRL2_SEL3_EN_SHIFT 20 static int g12a_frddr_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) @@ -269,6 +275,70 @@ static const struct axg_fifo_match_data g12a_frddr_match_data = { .dai_drv = &g12a_frddr_dai_drv }; +/* On SM1, the output selection in on CTRL2 */ +static const struct snd_kcontrol_new sm1_frddr_out1_enable = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2, + CTRL2_SEL1_EN_SHIFT, 1, 0); +static const struct snd_kcontrol_new sm1_frddr_out2_enable = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2, + CTRL2_SEL2_EN_SHIFT, 1, 0); +static const struct snd_kcontrol_new sm1_frddr_out3_enable = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2, + CTRL2_SEL3_EN_SHIFT, 1, 0); + +static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel1_enum, FIFO_CTRL2, CTRL2_SEL1_SHIFT, + axg_frddr_sel_texts); +static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel2_enum, FIFO_CTRL2, CTRL2_SEL2_SHIFT, + axg_frddr_sel_texts); +static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel3_enum, FIFO_CTRL2, CTRL2_SEL3_SHIFT, + axg_frddr_sel_texts); + +static const struct snd_kcontrol_new sm1_frddr_out1_demux = + SOC_DAPM_ENUM("Output Src 1", sm1_frddr_sel1_enum); +static const struct snd_kcontrol_new sm1_frddr_out2_demux = + SOC_DAPM_ENUM("Output Src 2", sm1_frddr_sel2_enum); +static const struct snd_kcontrol_new sm1_frddr_out3_demux = + SOC_DAPM_ENUM("Output Src 3", sm1_frddr_sel3_enum); + +static const struct snd_soc_dapm_widget sm1_frddr_dapm_widgets[] = { + SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0, + &sm1_frddr_out1_enable), + SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0, + &sm1_frddr_out2_enable), + SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0, + &sm1_frddr_out3_enable), + SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0, + &sm1_frddr_out1_demux), + SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0, + &sm1_frddr_out2_demux), + SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0, + &sm1_frddr_out3_demux), + SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_component_driver sm1_frddr_component_drv = { + .dapm_widgets = sm1_frddr_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sm1_frddr_dapm_widgets), + .dapm_routes = g12a_frddr_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes), + .ops = &g12a_fifo_pcm_ops +}; + +static const struct axg_fifo_match_data sm1_frddr_match_data = { + .component_drv = &sm1_frddr_component_drv, + .dai_drv = &g12a_frddr_dai_drv +}; + static const struct of_device_id axg_frddr_of_match[] = { { .compatible = "amlogic,axg-frddr", @@ -276,6 +346,9 @@ static const struct of_device_id axg_frddr_of_match[] = { }, { .compatible = "amlogic,g12a-frddr", .data = &g12a_frddr_match_data, + }, { + .compatible = "amlogic,sm1-frddr", + .data = &sm1_frddr_match_data, }, {} }; MODULE_DEVICE_TABLE(of, axg_frddr_of_match); -- cgit v1.2.3 From 5ac825c3d85e6c1cb8e43d67d8cb95a2a1e2bc60 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 5 Sep 2019 14:01:19 +0200 Subject: ASoC: meson: axg-toddr: add sm1 support On sm1, the maximum number TODDR inputs is extended to 16. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190905120120.31752-8-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-toddr.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'sound') diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index 2e9a2e5862ce..c8ea2145f576 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c @@ -25,6 +25,7 @@ #define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3) #define CTRL0_TODDR_LSB_POS(x) ((x) << 3) #define CTRL1_TODDR_FORCE_FINISH BIT(25) +#define CTRL1_SEL_SHIFT 28 #define TODDR_MSB_POS 31 @@ -221,6 +222,70 @@ static const struct axg_fifo_match_data g12a_toddr_match_data = { .dai_drv = &g12a_toddr_dai_drv }; +static const char * const sm1_toddr_sel_texts[] = { + "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 5", "IN 6", "IN 7", + "IN 8", "IN 9", "IN 10", "IN 11", "IN 12", "IN 13", "IN 14", "IN 15" +}; + +static SOC_ENUM_SINGLE_DECL(sm1_toddr_sel_enum, FIFO_CTRL1, CTRL1_SEL_SHIFT, + sm1_toddr_sel_texts); + +static const struct snd_kcontrol_new sm1_toddr_in_mux = + SOC_DAPM_ENUM("Input Source", sm1_toddr_sel_enum); + +static const struct snd_soc_dapm_widget sm1_toddr_dapm_widgets[] = { + SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &sm1_toddr_in_mux), + SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 7", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 8", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 9", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 10", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 11", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 12", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 13", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 14", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 15", NULL, 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route sm1_toddr_dapm_routes[] = { + { "Capture", NULL, "SRC SEL" }, + { "SRC SEL", "IN 0", "IN 0" }, + { "SRC SEL", "IN 1", "IN 1" }, + { "SRC SEL", "IN 2", "IN 2" }, + { "SRC SEL", "IN 3", "IN 3" }, + { "SRC SEL", "IN 4", "IN 4" }, + { "SRC SEL", "IN 5", "IN 5" }, + { "SRC SEL", "IN 6", "IN 6" }, + { "SRC SEL", "IN 7", "IN 7" }, + { "SRC SEL", "IN 8", "IN 8" }, + { "SRC SEL", "IN 9", "IN 9" }, + { "SRC SEL", "IN 10", "IN 10" }, + { "SRC SEL", "IN 11", "IN 11" }, + { "SRC SEL", "IN 12", "IN 12" }, + { "SRC SEL", "IN 13", "IN 13" }, + { "SRC SEL", "IN 14", "IN 14" }, + { "SRC SEL", "IN 15", "IN 15" }, +}; + +static const struct snd_soc_component_driver sm1_toddr_component_drv = { + .dapm_widgets = sm1_toddr_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sm1_toddr_dapm_widgets), + .dapm_routes = sm1_toddr_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sm1_toddr_dapm_routes), + .ops = &g12a_fifo_pcm_ops +}; + +static const struct axg_fifo_match_data sm1_toddr_match_data = { + .component_drv = &sm1_toddr_component_drv, + .dai_drv = &g12a_toddr_dai_drv +}; + static const struct of_device_id axg_toddr_of_match[] = { { .compatible = "amlogic,axg-toddr", @@ -228,6 +293,9 @@ static const struct of_device_id axg_toddr_of_match[] = { }, { .compatible = "amlogic,g12a-toddr", .data = &g12a_toddr_match_data, + }, { + .compatible = "amlogic,sm1-toddr", + .data = &sm1_toddr_match_data, }, {} }; MODULE_DEVICE_TABLE(of, axg_toddr_of_match); -- cgit v1.2.3 From 329299d6652fa287a0551ae412cc0227d539a0fe Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 5 Sep 2019 14:01:20 +0200 Subject: ASoC: meson: tdmout: add sm1 support On the sm1, the TDMOUT number of input is extended and the the gain enable bit moved to accommodate this extension Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190905120120.31752-9-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-tdmout.c | 103 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 84 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-tdmout.c b/sound/soc/meson/axg-tdmout.c index 86537fc0ecb5..418ec314b37d 100644 --- a/sound/soc/meson/axg-tdmout.c +++ b/sound/soc/meson/axg-tdmout.c @@ -24,6 +24,7 @@ #define TDMOUT_CTRL1 0x04 #define TDMOUT_CTRL1_TYPE_MASK GENMASK(6, 4) #define TDMOUT_CTRL1_TYPE(x) ((x) << 4) +#define SM1_TDMOUT_CTRL1_GAIN_EN 7 #define TDMOUT_CTRL1_MSB_POS_MASK GENMASK(12, 8) #define TDMOUT_CTRL1_MSB_POS(x) ((x) << 8) #define TDMOUT_CTRL1_SEL_SHIFT 24 @@ -51,25 +52,6 @@ static const struct regmap_config axg_tdmout_regmap_cfg = { .max_register = TDMOUT_MASK_VAL, }; -static const struct snd_kcontrol_new axg_tdmout_controls[] = { - SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0), - SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0), - SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0), - SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0), - SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1, - TDMOUT_CTRL1_GAIN_EN, 1, 0), -}; - -static const char * const tdmout_sel_texts[] = { - "IN 0", "IN 1", "IN 2", -}; - -static SOC_ENUM_SINGLE_DECL(axg_tdmout_sel_enum, TDMOUT_CTRL1, - TDMOUT_CTRL1_SEL_SHIFT, tdmout_sel_texts); - -static const struct snd_kcontrol_new axg_tdmout_in_mux = - SOC_DAPM_ENUM("Input Source", axg_tdmout_sel_enum); - static struct snd_soc_dai * axg_tdmout_get_be(struct snd_soc_dapm_widget *w) { @@ -197,6 +179,25 @@ static int axg_tdmout_prepare(struct regmap *map, return axg_tdm_formatter_set_channel_masks(map, ts, TDMOUT_MASK0); } +static const struct snd_kcontrol_new axg_tdmout_controls[] = { + SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0), + SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0), + SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0), + SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0), + SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1, + TDMOUT_CTRL1_GAIN_EN, 1, 0), +}; + +static const char * const axg_tdmout_sel_texts[] = { + "IN 0", "IN 1", "IN 2", +}; + +static SOC_ENUM_SINGLE_DECL(axg_tdmout_sel_enum, TDMOUT_CTRL1, + TDMOUT_CTRL1_SEL_SHIFT, axg_tdmout_sel_texts); + +static const struct snd_kcontrol_new axg_tdmout_in_mux = + SOC_DAPM_ENUM("Input Source", axg_tdmout_sel_enum); + static const struct snd_soc_dapm_widget axg_tdmout_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), @@ -252,6 +253,67 @@ static const struct axg_tdm_formatter_driver g12a_tdmout_drv = { }, }; +static const struct snd_kcontrol_new sm1_tdmout_controls[] = { + SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0), + SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0), + SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0), + SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0), + SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1, + SM1_TDMOUT_CTRL1_GAIN_EN, 1, 0), +}; + +static const char * const sm1_tdmout_sel_texts[] = { + "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", +}; + +static SOC_ENUM_SINGLE_DECL(sm1_tdmout_sel_enum, TDMOUT_CTRL1, + TDMOUT_CTRL1_SEL_SHIFT, sm1_tdmout_sel_texts); + +static const struct snd_kcontrol_new sm1_tdmout_in_mux = + SOC_DAPM_ENUM("Input Source", sm1_tdmout_sel_enum); + +static const struct snd_soc_dapm_widget sm1_tdmout_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &sm1_tdmout_in_mux), + SND_SOC_DAPM_PGA_E("ENC", SND_SOC_NOPM, 0, 0, NULL, 0, + axg_tdm_formatter_event, + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)), + SND_SOC_DAPM_AIF_OUT("OUT", NULL, 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route sm1_tdmout_dapm_routes[] = { + { "SRC SEL", "IN 0", "IN 0" }, + { "SRC SEL", "IN 1", "IN 1" }, + { "SRC SEL", "IN 2", "IN 2" }, + { "SRC SEL", "IN 3", "IN 3" }, + { "SRC SEL", "IN 4", "IN 4" }, + { "ENC", NULL, "SRC SEL" }, + { "OUT", NULL, "ENC" }, +}; + +static const struct snd_soc_component_driver sm1_tdmout_component_drv = { + .controls = sm1_tdmout_controls, + .num_controls = ARRAY_SIZE(sm1_tdmout_controls), + .dapm_widgets = sm1_tdmout_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sm1_tdmout_dapm_widgets), + .dapm_routes = sm1_tdmout_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sm1_tdmout_dapm_routes), +}; + +static const struct axg_tdm_formatter_driver sm1_tdmout_drv = { + .component_drv = &sm1_tdmout_component_drv, + .regmap_cfg = &axg_tdmout_regmap_cfg, + .ops = &axg_tdmout_ops, + .quirks = &(const struct axg_tdm_formatter_hw) { + .invert_sclk = true, + .skew_offset = 2, + }, +}; + static const struct of_device_id axg_tdmout_of_match[] = { { .compatible = "amlogic,axg-tdmout", @@ -259,6 +321,9 @@ static const struct of_device_id axg_tdmout_of_match[] = { }, { .compatible = "amlogic,g12a-tdmout", .data = &g12a_tdmout_drv, + }, { + .compatible = "amlogic,sm1-tdmout", + .data = &sm1_tdmout_drv, }, {} }; MODULE_DEVICE_TABLE(of, axg_tdmout_of_match); -- cgit v1.2.3 From f4df4e4042b045c6ddbaff878a17ae169fe68ba6 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 5 Sep 2019 14:44:00 +0800 Subject: ASoC: SOF: imx8: Fix COMPILE_TEST error When do compile test, if SND_SOC_SOF_OF is not set, we get: sound/soc/sof/imx/imx8.o: In function `imx8_dsp_handle_request': imx8.c:(.text+0xb0): undefined reference to `snd_sof_ipc_msgs_rx' sound/soc/sof/imx/imx8.o: In function `imx8_ipc_msg_data': imx8.c:(.text+0xf4): undefined reference to `sof_mailbox_read' sound/soc/sof/imx/imx8.o: In function `imx8_dsp_handle_reply': imx8.c:(.text+0x160): undefined reference to `sof_mailbox_read' Make SND_SOC_SOF_IMX_TOPLEVEL always depends on SND_SOC_SOF_OF Reported-by: Hulk Robot Fixes: 202acc565a1f ("ASoC: SOF: imx: Add i.MX8 HW support") Signed-off-by: YueHaibing Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190905064400.24800-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig index fd73d8402dbf..5acae75f5750 100644 --- a/sound/soc/sof/imx/Kconfig +++ b/sound/soc/sof/imx/Kconfig @@ -2,7 +2,8 @@ config SND_SOC_SOF_IMX_TOPLEVEL bool "SOF support for NXP i.MX audio DSPs" - depends on ARM64 && SND_SOC_SOF_OF || COMPILE_TEST + depends on ARM64|| COMPILE_TEST + depends on SND_SOC_SOF_OF help This adds support for Sound Open Firmware for NXP i.MX platforms. Say Y if you have such a device. -- cgit v1.2.3 From f953e72c9ca60ef13bb9680af8a5baf92cb93e52 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 5 Sep 2019 16:48:26 +0100 Subject: ALSA: hda/hdmi: remove redundant assignment to variable pcm_idx Variable pcm_idx is being initialized with a value that is never read and is being re-assigned immediately afterwards. The assignment is redundant and hence can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190905154826.5916-1-colin.king@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 83b8b9d27711..bca5de78e9ad 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1440,7 +1440,7 @@ static bool update_eld(struct hda_codec *codec, struct hdmi_spec *spec = codec->spec; bool old_eld_valid = pin_eld->eld_valid; bool eld_changed; - int pcm_idx = -1; + int pcm_idx; /* for monitor disconnection, save pcm_idx firstly */ pcm_idx = per_pin->pcm_idx; -- cgit v1.2.3 From 00066e9733f629e536f6b7957de2ce11a85fe15a Mon Sep 17 00:00:00 2001 From: Sergey Bostandzhyan Date: Fri, 6 Sep 2019 11:33:43 +0200 Subject: Add Acer Aspire Ethos 8951G model quirk This notebook has 6 built in speakers for 5.1 surround support, however only two got autodetected and have also not been assigned correctly. This patch enables all speakers and also fixes muting when headphones are plugged in. The speaker layout is as follows: pin 0x15 Front Left / Front Right pin 0x18 Front Center / Subwoofer pin 0x1b Rear Left / Rear Right (Surround) The quirk will be enabled automatically on this hardware, but can also be activated manually via the model=aspire-ethos module parameter. Caveat: pin 0x1b is shared between headphones jack and surround speakers. When headphones are plugged in, the surround speakers get muted automatically by the hardware, however all other speakers remain unmuted. Currently it's not possible to make use of the generic automute function in the driver, because such shared pins are not supported. If we would change the pin settings to identify the pin as headphones, the surround channel and thus the ability to select 5.1 profiles would get lost. This quirk solves the above problem by monitoring jack state of 0x1b and by connecting/disconnecting all remaining speaker pins when something gets plugged in or unplugged from the headphones jack port. Signed-off-by: Sergey Bostandzhyan Link: https://lore.kernel.org/r/20190906093343.GA7640@xn--80adja5bqm.su Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 71 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bddb1a28edc3..7a3c5ca21d32 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8341,6 +8341,45 @@ static void alc662_fixup_usi_headset_mic(struct hda_codec *codec, } } +static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec, + struct hda_jack_callback *cb) +{ + /* surround speakers at 0x1b already get muted automatically when + * headphones are plugged in, but we have to mute/unmute the remaining + * channels manually: + * 0x15 - front left/front right + * 0x18 - front center/ LFE + */ + if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) { + snd_hda_set_pin_ctl_cache(codec, 0x15, 0); + snd_hda_set_pin_ctl_cache(codec, 0x18, 0); + } else { + snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT); + snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT); + } +} + +static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + /* Pin 0x1b: shared headphones jack and surround speakers */ + if (!is_jack_detectable(codec, 0x1b)) + return; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_jack_detect_enable_callback(codec, 0x1b, + alc662_aspire_ethos_mute_speakers); + break; + case HDA_FIXUP_ACT_INIT: + /* Make sure to start in a correct state, i.e. if + * headphones have been plugged in before powering up the system + */ + alc662_aspire_ethos_mute_speakers(codec, NULL); + break; + } +} + static struct coef_fw alc668_coefs[] = { WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0), WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80), @@ -8412,6 +8451,9 @@ enum { ALC662_FIXUP_USI_FUNC, ALC662_FIXUP_USI_HEADSET_MODE, ALC662_FIXUP_LENOVO_MULTI_CODECS, + ALC669_FIXUP_ACER_ASPIRE_ETHOS, + ALC669_FIXUP_ACER_ASPIRE_ETHOS_SUBWOOFER, + ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET, }; static const struct hda_fixup alc662_fixups[] = { @@ -8738,6 +8780,33 @@ static const struct hda_fixup alc662_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc233_alc662_fixup_lenovo_dual_codecs, }, + [ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc662_fixup_aspire_ethos_hp, + }, + [ALC669_FIXUP_ACER_ASPIRE_ETHOS_SUBWOOFER] = { + .type = HDA_FIXUP_VERBS, + /* subwoofer needs an extra GPIO setting to become audible */ + .v.verbs = (const struct hda_verb[]) { + {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + { } + }, + .chained = true, + .chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET + }, + [ALC669_FIXUP_ACER_ASPIRE_ETHOS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x92130110 }, /* front speakers */ + { 0x18, 0x99130111 }, /* center/subwoofer */ + { 0x1b, 0x11130012 }, /* surround plus jack for HP */ + { } + }, + .chained = true, + .chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_SUBWOOFER + }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { @@ -8783,6 +8852,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68), SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON), SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), + SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS), #if 0 /* Below is a quirk table taken from the old code. @@ -8876,6 +8946,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = { {.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"}, {.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"}, {.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"}, + {.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"}, {} }; -- cgit v1.2.3 From e6e2fe2b8f7a4abd24170225050597ebc9f1427b Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 6 Sep 2019 21:55:44 +0900 Subject: ALSA: firewire-tascam: add note for FE-8 TASCAM FE-8 is the rest of model in TASCAM FireWire series. This device has no functionality to process audio signal and MIDI messages. Instead, it transfers control messages to host system corresponding to operations for some faders, buttons and knobs on its surface. Unlike the other devices in this series, the control messages are transmitted by asynchronous transactions. Some registers of device are used for registration of destination address for the transaction. The transaction includes quadlet-aligned data up to 32 quadlets. Userspace applications can receive the transaction and parse it for control message via Linux FireWire subsystem, without any support by ALSA firewire-tascam driver. Therefore the driver gives no support for it. This commit removes placeholder for FE-8 and add some comment for its functionalities as notes. $ python2 linux-firewire-utils/src/crpp < ~/git/am-config-rom/tascam/tascam-fe8.img ROM header and bus information block ----------------------------------------------------------------- 400 040f4798 bus_info_length 4, crc_length 15, crc 18328 (should be 14256) 404 31333934 bus_name "1394" 408 20ff7002 irmc 0, cmc 0, isc 1, bmc 0, cyc_clk_acc 255, max_rec 7 (256) 40c 00022eff company_id 00022e | 410 a094dcb7 device_id ffa094dcb7 | EUI-64 00022effa094dcb7 root directory ----------------------------------------------------------------- 414 0004bccc directory_length 4, crc 48332 418 0300022e vendor 41c 0c0083c0 node capabilities per IEEE 1394 420 8d000006 --> eui-64 leaf at 438 424 d1000001 --> unit directory at 428 unit directory at 428 ----------------------------------------------------------------- 428 0003eda4 directory_length 3, crc 60836 42c 1200022e specifier id 430 13800001 version 434 d4000004 --> dependent info directory at 444 eui-64 leaf at 438 ----------------------------------------------------------------- 438 0002461e leaf_length 2, crc 17950 43c 00022eff company_id 00022e | 440 a094dcb7 device_id ffa094dcb7 | EUI-64 00022effa094dcb7 dependent info directory at 444 ----------------------------------------------------------------- 444 0002ae47 directory_length 2, crc 44615 448 81000002 --> descriptor leaf at 450 44c 82000006 --> bus dependent info leaf at 464 descriptor leaf at 450 ----------------------------------------------------------------- 450 0004a79e leaf_length 4, crc 42910 454 00000000 textual descriptor 458 00000000 minimal ASCII 45c 54415343 "TASC" 460 414d0000 "AM" bus dependent info leaf at 464 ----------------------------------------------------------------- 464 0004a7d8 leaf_length 4, crc 42968 468 00000000 46c 00000000 470 46452d38 474 00000000 Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20190906125544.13800-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/tascam/tascam.c | 4 +++- sound/firewire/tascam/tascam.h | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c index 231052db5680..addc464503bc 100644 --- a/sound/firewire/tascam/tascam.c +++ b/sound/firewire/tascam/tascam.c @@ -39,6 +39,9 @@ static const struct snd_tscm_spec model_specs[] = { .midi_capture_ports = 2, .midi_playback_ports = 4, }, + // This kernel module doesn't support FE-8 because the most of features + // can be implemented in userspace without any specific support of this + // module. }; static int identify_model(struct snd_tscm *tscm) @@ -214,7 +217,6 @@ static const struct ieee1394_device_id snd_tscm_id_table[] = { .vendor_id = 0x00022e, .specifier_id = 0x00022e, }, - /* FE-08 requires reverse-engineering because it just has faders. */ {} }; MODULE_DEVICE_TABLE(ieee1394, snd_tscm_id_table); diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h index 64a2e4d2bbfe..15bd335fa07f 100644 --- a/sound/firewire/tascam/tascam.h +++ b/sound/firewire/tascam/tascam.h @@ -129,6 +129,26 @@ struct snd_tscm { #define TSCM_OFFSET_MIDI_RX_QUAD 0x4000 +// Although FE-8 supports the above registers, it has no I/O interfaces for +// audio samples and music messages. Otherwise it supports another notification +// for status and control message as well as LED brightening. The message +// consists of quadlet-aligned data up to 32 quadlets. The first byte of message +// is fixed to 0x40. The second byte is between 0x00 to 0x1f and represent each +// control: +// fader: 0x00-0x07 +// button: 0x0d, 0x0e +// knob: 0x14-0x1b +// sensing: 0x0b +// +// The rest two bytes represent state of the controls; e.g. current value for +// fader and knob, bitmasks for button and sensing. +// Just after turning on, 32 quadlets messages with 0x00-0x1f are immediately +// sent in one transaction. After, several quadlets are sent in one transaction. +// +// TSCM_OFFSET_FE8_CTL_TX_ON 0x0310 +// TSCM_OFFSET_FE8_CTL_TX_ADDR_HI 0x0314 +// TSCM_OFFSET_FE8_CTL_TX_ADDR_LO 0x0318 + enum snd_tscm_clock { SND_TSCM_CLOCK_INTERNAL = 0, SND_TSCM_CLOCK_WORD = 1, -- cgit v1.2.3 From 8d0d5c3fa16f050024ff13df106b70466aacbf3b Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 6 Sep 2019 22:14:14 +0900 Subject: ALSA: firewire-lib: remove WARN_ON() at destruction of AMDTP domain The destructor of AMDTP domain has WARN_ON() for the list of associated AMDTP stream. Although this reminds a case that developers forget to program consumer drivers to stop AMDTP domain, it hits when AMDTP domain is not initialized yet. This occurs when initialization of sound card fails as well and it's superfluous. This commit removes the WARN_ON. Although the API to AMDTP domain does nothing, it's left for future usage. Fixes: 3ec3d7a3ff106 ("ALSA: firewire-lib: add AMDTP domain structure to handle several isoc contexts") Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20190906131414.15370-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 88270257e896..e50e28f77e74 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1153,7 +1153,8 @@ EXPORT_SYMBOL_GPL(amdtp_domain_init); */ void amdtp_domain_destroy(struct amdtp_domain *d) { - WARN_ON(!list_empty(&d->streams)); + // At present nothing to do. + return; } EXPORT_SYMBOL_GPL(amdtp_domain_destroy); -- cgit v1.2.3 From 789492f0c86505e63369907bcb1afdf52dec9366 Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Fri, 6 Sep 2019 16:21:19 +0800 Subject: ALSA: lx6464es - add support for LX6464ESe pci express variant The pci express variant of the digigram lx6464es card has a different device ID, but works without changes to the driver. Thanks to Nikolas Slottke for reporting and testing. Signed-off-by: Tim Blechmann Link: https://lore.kernel.org/r/20190906082119.40971-1-tim@klingt.org Signed-off-by: Takashi Iwai --- include/linux/pci_ids.h | 2 ++ sound/pci/lx6464es/lx6464es.c | 8 ++++++++ 2 files changed, 10 insertions(+) (limited to 'sound') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index c842735a4f45..901c5b2f76de 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1951,6 +1951,8 @@ #define PCI_VENDOR_ID_DIGIGRAM 0x1369 #define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM 0xc001 #define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM 0xc002 +#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ESE_SERIAL_SUBSYSTEM 0xc021 +#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ESE_CAE_SERIAL_SUBSYSTEM 0xc022 #define PCI_VENDOR_ID_KAWASAKI 0x136b #define PCI_DEVICE_ID_MCHIP_KL5A72002 0xff01 diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 583ca7384d83..fe10714380f2 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -49,6 +49,14 @@ static const struct pci_device_id snd_lx6464es_ids[] = { PCI_VENDOR_ID_DIGIGRAM, PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM), }, /* LX6464ES-CAE */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES, + PCI_VENDOR_ID_DIGIGRAM, + PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ESE_SERIAL_SUBSYSTEM), + }, /* LX6464ESe */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES, + PCI_VENDOR_ID_DIGIGRAM, + PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ESE_CAE_SERIAL_SUBSYSTEM), + }, /* LX6464ESe-CAE */ { 0, }, }; -- cgit v1.2.3 From 2ec42f3147e1610716f184b02e65d7f493eed925 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 6 Sep 2019 08:55:24 +0300 Subject: ASoC: dmaengine: Make the pcm->name equal to pcm->id if the name is not set Some tools use the snd_pcm_info_get_name() to try to identify PCMs or for other purposes. Currently it is left empty with the dmaengine-pcm, in this case copy the pcm->id string as pcm->name. For example IGT is using this to find the HDMI PCM for testing audio on it. Signed-off-by: Peter Ujfalusi Reported-by: Arthur She Link: https://lore.kernel.org/r/20190906055524.7393-1-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/soc-generic-dmaengine-pcm.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 748f5f641002..d93db2c2b527 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -306,6 +306,12 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!dmaengine_pcm_can_report_residue(dev, pcm->chan[i])) pcm->flags |= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE; + + if (rtd->pcm->streams[i].pcm->name[0] == '\0') { + strncpy(rtd->pcm->streams[i].pcm->name, + rtd->pcm->streams[i].pcm->id, + sizeof(rtd->pcm->streams[i].pcm->name)); + } } return 0; -- cgit v1.2.3 From 73681f4f1426847b421649c6aa6c2dc303acc7c8 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Sat, 7 Sep 2019 13:16:50 +0200 Subject: ASoC: ams-delta: Take control over audio mute GPIO pins Since commit 1137ceee76ba ("ARM: OMAP1: ams-delta: Don't request unused GPIOs"), on-board audio has appeared muted. It has been discovered that believed to be unused GPIO pins "hookflash1" and "hookflash2" need to be set low for audible sound in handsfree and handset mode respectively. According to Amstrad E3 wiki, the purpose of both pins hasn't been clearly identified. Original Amstrad software used to produce a high pulse on them when the phone was taken off hook or recall was pressed. With the current findings, we can assume the pins provide a kind of audio mute function, separately for handset and handsfree operation modes. Commit 2afdb4c41d78 ("ARM: OMAP1: ams-delta: Fix audio permanently muted") attempted to fix the issue temporarily by hogging the GPIO pin "hookflash1" renamed to "audio_mute", however the fix occurred incomplete as it restored audible sound only for handsfree mode. Stop hogging that pin, rename the pins to "handsfree_mute" and "handset_mute" respectively and implement appropriate DAPM event callbacks for "Speaker" and "Earpiece" DAPM widgets. Fixes: 1137ceee76ba ("ARM: OMAP1: ams-delta: Don't request unused GPIOs") Signed-off-by: Janusz Krzysztofik Reviewed-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190907111650.15440-1-jmkrzyszt@gmail.com Signed-off-by: Mark Brown --- arch/arm/mach-omap1/board-ams-delta.c | 10 ++++++---- sound/soc/ti/ams-delta.c | 31 +++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index 36498ea1b2f3..c2affc727967 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -245,8 +245,8 @@ static struct platform_device latch2_gpio_device = { #define LATCH2_PIN_SCARD_CMDVCC 11 #define LATCH2_PIN_MODEM_NRESET 12 #define LATCH2_PIN_MODEM_CODEC 13 -#define LATCH2_PIN_AUDIO_MUTE 14 -#define LATCH2_PIN_HOOKFLASH 15 +#define LATCH2_PIN_HANDSFREE_MUTE 14 +#define LATCH2_PIN_HANDSET_MUTE 15 static struct regulator_consumer_supply modem_nreset_consumers[] = { REGULATOR_SUPPLY("RESET#", "serial8250.1"), @@ -475,6 +475,10 @@ static struct gpiod_lookup_table ams_delta_audio_gpio_table = { "hook_switch", 0), GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_MODEM_CODEC, "modem_codec", 0), + GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_HANDSFREE_MUTE, + "handsfree_mute", 0), + GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_HANDSET_MUTE, + "handset_mute", 0), { }, }, }; @@ -589,8 +593,6 @@ static int gpiochip_match_by_label(struct gpio_chip *chip, void *data) static struct gpiod_hog ams_delta_gpio_hogs[] = { GPIO_HOG(LATCH2_LABEL, LATCH2_PIN_KEYBRD_DATAOUT, "keybrd_dataout", GPIO_ACTIVE_HIGH, GPIOD_OUT_LOW), - GPIO_HOG(LATCH2_LABEL, LATCH2_PIN_AUDIO_MUTE, "audio_mute", - GPIO_ACTIVE_HIGH, GPIOD_OUT_LOW), {}, }; diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c index dee8fc70a64f..8e2fb81ad05c 100644 --- a/sound/soc/ti/ams-delta.c +++ b/sound/soc/ti/ams-delta.c @@ -23,14 +23,31 @@ #include "omap-mcbsp.h" #include "../codecs/cx20442.h" +static struct gpio_desc *handset_mute; +static struct gpio_desc *handsfree_mute; + +static int ams_delta_event_handset(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + gpiod_set_value_cansleep(handset_mute, !SND_SOC_DAPM_EVENT_ON(event)); + return 0; +} + +static int ams_delta_event_handsfree(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + gpiod_set_value_cansleep(handsfree_mute, !SND_SOC_DAPM_EVENT_ON(event)); + return 0; +} + /* Board specific DAPM widgets */ static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = { /* Handset */ SND_SOC_DAPM_MIC("Mouthpiece", NULL), - SND_SOC_DAPM_HP("Earpiece", NULL), + SND_SOC_DAPM_HP("Earpiece", ams_delta_event_handset), /* Handsfree/Speakerphone */ SND_SOC_DAPM_MIC("Microphone", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_SPK("Speaker", ams_delta_event_handsfree), }; /* How they are connected to codec pins */ @@ -542,6 +559,16 @@ static int ams_delta_probe(struct platform_device *pdev) card->dev = &pdev->dev; + handset_mute = devm_gpiod_get(card->dev, "handset_mute", + GPIOD_OUT_HIGH); + if (IS_ERR(handset_mute)) + return PTR_ERR(handset_mute); + + handsfree_mute = devm_gpiod_get(card->dev, "handsfree_mute", + GPIOD_OUT_HIGH); + if (IS_ERR(handsfree_mute)) + return PTR_ERR(handsfree_mute); + ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); -- cgit v1.2.3 From 0db0c62c88b84b135bbaf784499a08e536354a43 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Sun, 8 Sep 2019 01:36:52 +0900 Subject: ASoC: es8316: fix redundant codes of clock This patch removes redundant null checks for optional MCLK clock. And fix DT binding document for changing clock property to optional from required. Signed-off-by: Katsuhiro Suzuki Link: https://lore.kernel.org/r/20190907163653.9382-1-katsuhiro@katsuster.net Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/everest,es8316.txt | 3 +++ sound/soc/codecs/es8316.c | 31 +++++++++------------- 2 files changed, 16 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.txt b/Documentation/devicetree/bindings/sound/everest,es8316.txt index aefcff9c48a2..1bf03c5f2af4 100644 --- a/Documentation/devicetree/bindings/sound/everest,es8316.txt +++ b/Documentation/devicetree/bindings/sound/everest,es8316.txt @@ -6,6 +6,9 @@ Required properties: - compatible : should be "everest,es8316" - reg : the I2C address of the device for I2C + +Optional properties: + - clocks : a list of phandle, should contain entries for clock-names - clock-names : should include as follows: "mclk" : master clock (MCLK) of the device diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 6248b01ca049..e9fa4981ccef 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -370,11 +370,9 @@ static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai, if (freq == 0) return 0; - if (es8316->mclk) { - ret = clk_set_rate(es8316->mclk, freq); - if (ret) - return ret; - } + ret = clk_set_rate(es8316->mclk, freq); + if (ret) + return ret; /* Limit supported sample rates to ones that can be autodetected * by the codec running in slave mode. @@ -709,20 +707,18 @@ static int es8316_probe(struct snd_soc_component *component) es8316->component = component; - es8316->mclk = devm_clk_get(component->dev, "mclk"); - if (PTR_ERR(es8316->mclk) == -EPROBE_DEFER) - return -EPROBE_DEFER; + es8316->mclk = devm_clk_get_optional(component->dev, "mclk"); if (IS_ERR(es8316->mclk)) { - dev_err(component->dev, "clock is invalid, ignored\n"); - es8316->mclk = NULL; + dev_err(component->dev, "unable to get mclk\n"); + return PTR_ERR(es8316->mclk); } + if (!es8316->mclk) + dev_warn(component->dev, "assuming static mclk\n"); - if (es8316->mclk) { - ret = clk_prepare_enable(es8316->mclk); - if (ret) { - dev_err(component->dev, "unable to enable clock\n"); - return ret; - } + ret = clk_prepare_enable(es8316->mclk); + if (ret) { + dev_err(component->dev, "unable to enable mclk\n"); + return ret; } /* Reset codec and enable current state machine */ @@ -751,8 +747,7 @@ static void es8316_remove(struct snd_soc_component *component) { struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); - if (es8316->mclk) - clk_disable_unprepare(es8316->mclk); + clk_disable_unprepare(es8316->mclk); } static const struct snd_soc_component_driver soc_component_dev_es8316 = { -- cgit v1.2.3 From ebe02a5b9ef05e3b812af3d628cdf6206d9ba610 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Sun, 8 Sep 2019 01:36:53 +0900 Subject: ASoC: es8316: support fixed and variable both clock rates This patch supports some type of machine drivers that set 0 to mclk when sound device goes to idle state. After applied this patch, sysclk == 0 means there is no constraint of sound rate and other values will set constraints which is derived by sysclk setting. Original code refuses sysclk == 0 setting. But some boards and SoC (such as RockPro64 and RockChip I2S) has connected SoC MCLK out to ES8316 MCLK in. In this case, SoC side I2S will choose suitable frequency of MCLK such as fs * mclk-fs when user starts playing or capturing. Bad scenario as follows (mclk-fs = 256): - Initialize sysclk by correct value (Ex. 12.288MHz) - ES8316 set constraints of PCM rate by sysclk 48kHz (1/256), 32kHz (1/384), 30.720kHz (1/400), 24kHz (1/512), 16kHz (1/768), 12kHz (1/1024) - Play 48kHz sound, it's acceptable - Sysclk is not changed - Play 32kHz sound, it's acceptable - Set sysclk by 8.192MHz (= fs * mclk-fs = 32k * 256) - ES8316 set constraints of PCM rate by sysclk 32kHz (1/256), 21.33kHz (1/384), 20.48kHz (1/400), 16kHz (1/512), 10.66kHz (1/768), 8kHz (1/1024) - Play 48kHz again, but it's NOT acceptable because constraints list does not allow 48kHz Signed-off-by: Katsuhiro Suzuki Link: https://lore.kernel.org/r/20190907163653.9382-2-katsuhiro@katsuster.net Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index e9fa4981ccef..9150e7068467 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -367,8 +367,12 @@ static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai, es8316->sysclk = freq; - if (freq == 0) + if (freq == 0) { + es8316->sysclk_constraints.list = NULL; + es8316->sysclk_constraints.count = 0; + return 0; + } ret = clk_set_rate(es8316->mclk, freq); if (ret) @@ -447,17 +451,10 @@ static int es8316_pcm_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); - if (es8316->sysclk == 0) { - dev_err(component->dev, "No sysclk provided\n"); - return -EINVAL; - } - - /* The set of sample rates that can be supported depends on the - * MCLK supplied to the CODEC. - */ - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &es8316->sysclk_constraints); + if (es8316->sysclk_constraints.list) + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &es8316->sysclk_constraints); return 0; } @@ -469,11 +466,19 @@ 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; + int i; - if (!es8316->sysclk) { - dev_err(component->dev, "No MCLK configured\n"); - return -EINVAL; + /* Validate supported sample rates that are autodetected from MCLK */ + for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) { + const unsigned int ratio = supported_mclk_lrck_ratios[i]; + + if (es8316->sysclk % ratio != 0) + continue; + if (es8316->sysclk / ratio == params_rate(params)) + break; } + if (i == NR_SUPPORTED_MCLK_LRCK_RATIOS) + return -EINVAL; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: -- cgit v1.2.3 From 78b93b04771bdbefe94b84222506ba992f579c98 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 6 Sep 2019 17:14:04 +0100 Subject: ASoC: codecs: ad193x: make two arrays static const, makes object smaller Don't populate the arrays on the stack but instead make them static const. Makes the object code smaller by 37 bytes. Before: text data bss dec hex filename 16253 7200 0 23453 5b9d sound/soc/codecs/ad193x.o After: text data bss dec hex filename 16056 7360 0 23416 5b78 sound/soc/codecs/ad193x.o (gcc version 9.2.1, amd64) Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190906161404.1440-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/codecs/ad193x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index fb04c9379b71..980e024a5720 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -416,7 +416,7 @@ static struct snd_soc_dai_driver ad193x_no_adc_dai = { /* codec register values to set after reset */ static void ad193x_reg_default_init(struct ad193x_priv *ad193x) { - const struct reg_sequence reg_init[] = { + static const struct reg_sequence reg_init[] = { { 0, 0x99 }, /* PLL_CLK_CTRL0: pll input: mclki/xi 12.288Mhz */ { 1, 0x04 }, /* PLL_CLK_CTRL1: no on-chip Vref */ { 2, 0x40 }, /* DAC_CTRL0: TDM mode */ @@ -432,7 +432,7 @@ static void ad193x_reg_default_init(struct ad193x_priv *ad193x) { 12, 0x00 }, /* DAC_L4_VOL: no attenuation */ { 13, 0x00 }, /* DAC_R4_VOL: no attenuation */ }; - const struct reg_sequence reg_adc_init[] = { + static const struct reg_sequence reg_adc_init[] = { { 14, 0x03 }, /* ADC_CTRL0: high-pass filter enable */ { 15, 0x43 }, /* ADC_CTRL1: sata delay=1, adc aux mode */ { 16, 0x00 }, /* ADC_CTRL2: reset */ -- cgit v1.2.3 From f1879d7b98dc9081cffc7718b644c6c41628cd18 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Sun, 8 Sep 2019 02:43:32 +0900 Subject: ASoC: rockchip: ignore 0Hz sysclk This patch ignores sysclk setting if it is 0Hz. Some codecs treat 0Hz sysclk as signal of applying no constraints. This driver does not have such feature but current implementation outputs 'Failed to set mclk' error message if machine driver sets 0Hz sysclk to this driver. Signed-off-by: Katsuhiro Suzuki Link: https://lore.kernel.org/r/20190907174332.19586-1-katsuhiro@katsuster.net Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 88ebaf6e1880..af2d5a6124c8 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -419,6 +419,9 @@ static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, struct rk_i2s_dev *i2s = to_info(cpu_dai); int ret; + if (freq == 0) + return 0; + ret = clk_set_rate(i2s->mclk, freq); if (ret) dev_err(i2s->dev, "Fail to set mclk %d\n", ret); -- cgit v1.2.3 From 2458adb8f92ad4d07ef7ab27c5bafa1d3f4678d6 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Sun, 8 Sep 2019 02:45:01 +0900 Subject: SoC: simple-card-utils: set 0Hz to sysclk when shutdown This patch set 0Hz to sysclk when shutdown the card. Some codecs set rate constraints that derives from sysclk. This mechanism works correctly if machine drivers give fixed frequency. But simple-audio and audio-graph card set variable clock rate if 'mclk-fs' property exists. In this case, rate constraints will go bad scenario. For example a codec accepts three limited rates (mclk / 256, mclk / 384, mclk / 512). Bad scenario as follows (mclk-fs = 256): - Initialize sysclk by correct value (Ex. 12.288MHz) - Codec set constraints of PCM rate by sysclk 48kHz (1/256), 32kHz (1/384), 24kHz (1/512) - Play 48kHz sound, it's acceptable - Sysclk is not changed - Play 32kHz sound, it's acceptable - Set sysclk to 8.192MHz (= fs * mclk-fs = 32k * 256) - Codec set constraints of PCM rate by sysclk 32kHz (1/256), 21.33kHz (1/384), 16kHz (1/512) - Play 48kHz again, but it's NOT acceptable because constraints do not allow 48kHz So codecs treat 0Hz sysclk as signal of applying no constraints to avoid this problem. Signed-off-by: Katsuhiro Suzuki Link: https://lore.kernel.org/r/20190907174501.19833-1-katsuhiro@katsuster.net Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 556b1a789629..9b794775df53 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -213,10 +213,17 @@ EXPORT_SYMBOL_GPL(asoc_simple_startup); void asoc_simple_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); + if (dai_props->mclk_fs) { + snd_soc_dai_set_sysclk(codec_dai, 0, 0, SND_SOC_CLOCK_IN); + snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT); + } + asoc_simple_clk_disable(dai_props->cpu_dai); asoc_simple_clk_disable(dai_props->codec_dai); -- cgit v1.2.3 From 2b70d5776e8b173e3b36a2ef63d94428c6a80e1f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 7 Sep 2019 08:37:17 +0100 Subject: ASoC: rt1011: make array pd static const, makes object smaller Don't populate the array pd on the stack but instead make it static const. Makes the object code smaller by 100 bytes. Before: text data bss dec hex filename 51463 13016 128 64607 fc5f sound/soc/codecs/rt1011.o After: text data bss dec hex filename 51299 13080 128 64507 fbfb sound/soc/codecs/rt1011.o (gcc version 9.2.1, amd64) Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190907073717.21632-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index fa34565a3938..a92a0bacd812 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1519,7 +1519,8 @@ static const struct snd_soc_dapm_route rt1011_dapm_routes[] = { static int rt1011_get_clk_info(int sclk, int rate) { - int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; + int i; + static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; if (sclk <= 0 || rate <= 0) return -EINVAL; -- cgit v1.2.3 From b61b1e35ed06db180968cb5ca0fbf8b8887ccb93 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 7 Sep 2019 08:41:56 +0100 Subject: ASoC: rt1305: make array pd static const, makes object smaller Don't populate the array pd on the stack but instead make it static const. Makes the object code smaller by 93 bytes. Before: text data bss dec hex filename 38961 9784 64 48809 bea9 sound/soc/codecs/rt1305.o After: text data bss dec hex filename 38804 9848 64 48716 be4c sound/soc/codecs/rt1305.o (gcc version 9.2.1, amd64) Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190907074156.21907-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1305.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c index 9909369483f0..e27742abfa76 100644 --- a/sound/soc/codecs/rt1305.c +++ b/sound/soc/codecs/rt1305.c @@ -608,7 +608,8 @@ static const struct snd_soc_dapm_route rt1305_dapm_routes[] = { static int rt1305_get_clk_info(int sclk, int rate) { - int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; + int i; + static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; if (sclk <= 0 || rate <= 0) return -EINVAL; -- cgit v1.2.3 From 13ab0d1ab8ae4d1b3b247fd5caec2c10e35c7269 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 7 Sep 2019 08:46:34 +0100 Subject: ASoC: rt1308: make array pd static const, makes object smaller Don't populate the array pd on the stack but instead make it static const. Makes the object code smaller by 82 bytes. Before: text data bss dec hex filename 26548 7288 64 33900 846c sound/soc/codecs/rt1308.o After: text data bss dec hex filename 26370 7384 64 33818 841a sound/soc/codecs/rt1308.o (gcc version 9.2.1, amd64) Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190907074634.22144-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1308.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index 6f2ee6809dbb..b75931a69a1c 100644 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -436,7 +436,8 @@ static const struct snd_soc_dapm_route rt1308_dapm_routes[] = { static int rt1308_get_clk_info(int sclk, int rate) { - int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; + int i; + static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; if (sclk <= 0 || rate <= 0) return -EINVAL; -- cgit v1.2.3 From 62f07a6b6dbaf0e7196b6911111d4666b5d03518 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2019 09:14:46 +0900 Subject: ASoC: soc-core: self contained soc_probe_link_components() Current soc_probe_link_components() implementation is very half, thus it is very difficult to read. for_each_comp_order(xxx) { for_each_card_rtds(xxx) { => ret = soc_probe_link_components(xxx); ... } } This patch does all for_each_xxx() under soc_probe_link_components(), and makes it to self contained. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874l1sq5mx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 05a2aff843aa..04b98e6c7b2a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1137,20 +1137,25 @@ static void soc_remove_link_components(struct snd_soc_card *card, } } -static int soc_probe_link_components(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, int order) +static int soc_probe_link_components(struct snd_soc_card *card) { struct snd_soc_component *component; + struct snd_soc_pcm_runtime *rtd; struct snd_soc_rtdcom_list *rtdcom; - int ret; + int ret, order; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; + for_each_comp_order(order) { + for_each_card_rtds(card, rtd) { + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; - if (component->driver->probe_order == order) { - ret = soc_probe_component(card, component); - if (ret < 0) - return ret; + if (component->driver->probe_order != order) + continue; + + ret = soc_probe_component(card, component); + if (ret < 0) + return ret; + } } } @@ -1990,16 +1995,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* probe all components used by DAI links on this card */ - for_each_comp_order(order) { - for_each_card_rtds(card, rtd) { - ret = soc_probe_link_components(card, rtd, order); - if (ret < 0) { - dev_err(card->dev, - "ASoC: failed to instantiate card %d\n", - ret); - goto probe_end; - } - } + ret = soc_probe_link_components(card); + if (ret < 0) { + dev_err(card->dev, + "ASoC: failed to instantiate card %d\n", ret); + goto probe_end; } /* probe auxiliary components */ -- cgit v1.2.3 From b006c0c6ed0dc779e64a8d7a25f5cf316fa3562c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2019 09:14:51 +0900 Subject: ASoC: soc-core: self contained soc_remove_link_components() Current soc_remove_link_components() implementation is very half, thus it is very difficult to read. for_each_comp_order(xxx) { for_each_card_rtds(xxx) => soc_remove_link_components(xxx); } This patch does all for_each_xxx() under soc_remove_link_components(), and makes it to self contained. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8736hcq5ms.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 04b98e6c7b2a..fbaf4dd597b5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1123,17 +1123,24 @@ static void soc_remove_link_dais(struct snd_soc_card *card, soc_remove_dai(rtd->cpu_dai, order); } -static void soc_remove_link_components(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, int order) +static void soc_remove_link_components(struct snd_soc_card *card) { struct snd_soc_component *component; + struct snd_soc_pcm_runtime *rtd; struct snd_soc_rtdcom_list *rtdcom; + int order; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; + for_each_comp_order(order) { + for_each_card_rtds(card, rtd) { + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (component->driver->remove_order != order) + continue; - if (component->driver->remove_order == order) - soc_remove_component(component); + soc_remove_component(component); + } + } } } @@ -1173,10 +1180,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card) soc_remove_link_dais(card, rtd, order); } - for_each_comp_order(order) { - for_each_card_rtds(card, rtd) - soc_remove_link_components(card, rtd, order); - } + soc_remove_link_components(card); for_each_card_links_safe(card, link, _link) { if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK) @@ -2394,20 +2398,13 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) { - struct snd_soc_pcm_runtime *rtd; - int order; - if (card->instantiated) { card->instantiated = false; snd_soc_dapm_shutdown(card); snd_soc_flush_all_delayed_work(card); /* remove all components used by DAI links on this card */ - for_each_comp_order(order) { - for_each_card_rtds(card, rtd) { - soc_remove_link_components(card, rtd, order); - } - } + soc_remove_link_components(card); soc_cleanup_card_resources(card); if (!unregister) -- cgit v1.2.3 From 4ca47d21bf7aa044c703688fa715862183dd6a3c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2019 09:14:57 +0900 Subject: ASoC: soc-core: self contained soc_remove_link_dais() Current soc_remove_link_dais() implementation is very half, thus it is very difficult to read. for_each_comp_order(xxx) { for_each_card_rtds(xxx) => soc_remove_link_dais(xxx); } This patch does all for_each_xxx() under soc_remove_link_dais(), and makes it to self contained. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/871rwwq5mm.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fbaf4dd597b5..0a13f9461303 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1107,20 +1107,26 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) } static void soc_rtd_free(struct snd_soc_pcm_runtime *rtd); /* remove me */ -static void soc_remove_link_dais(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, int order) +static void soc_remove_link_dais(struct snd_soc_card *card) { int i; struct snd_soc_dai *codec_dai; + struct snd_soc_pcm_runtime *rtd; + int order; + + for_each_comp_order(order) { + for_each_card_rtds(card, rtd) { - /* finalize rtd device */ - soc_rtd_free(rtd); + /* finalize rtd device */ + soc_rtd_free(rtd); - /* remove the CODEC DAI */ - for_each_rtd_codec_dai(rtd, i, codec_dai) - soc_remove_dai(codec_dai, order); + /* remove the CODEC DAI */ + for_each_rtd_codec_dai(rtd, i, codec_dai) + soc_remove_dai(codec_dai, order); - soc_remove_dai(rtd->cpu_dai, order); + soc_remove_dai(rtd->cpu_dai, order); + } + } } static void soc_remove_link_components(struct snd_soc_card *card) @@ -1171,14 +1177,9 @@ static int soc_probe_link_components(struct snd_soc_card *card) static void soc_remove_dai_links(struct snd_soc_card *card) { - int order; - struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link *link, *_link; - for_each_comp_order(order) { - for_each_card_rtds(card, rtd) - soc_remove_link_dais(card, rtd, order); - } + soc_remove_link_dais(card); soc_remove_link_components(card); -- cgit v1.2.3 From a7d44f78063d642406132c2ed1dc6033d0d03cfe Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2019 09:15:06 +0900 Subject: ASoC: soc-core: move soc_probe_dai() next to soc_remove_dai() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and it will be difficult to debug. This patch moves soc_probe_dai() next to soc_remove_dai() which is paired function. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zhjkor1x.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0a13f9461303..3ca5a21bfa6a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1106,6 +1106,26 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) dai->probed = 0; } +static int soc_probe_dai(struct snd_soc_dai *dai, int order) +{ + int ret; + + if (dai->probed || + dai->driver->probe_order != order) + return 0; + + ret = snd_soc_dai_probe(dai); + if (ret < 0) { + dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n", + dai->name, ret); + return ret; + } + + dai->probed = 1; + + return 0; +} + static void soc_rtd_free(struct snd_soc_pcm_runtime *rtd); /* remove me */ static void soc_remove_link_dais(struct snd_soc_card *card) { @@ -1411,26 +1431,6 @@ static int soc_rtd_init(struct snd_soc_pcm_runtime *rtd, const char *name) return 0; } -static int soc_probe_dai(struct snd_soc_dai *dai, int order) -{ - int ret; - - if (dai->probed || - dai->driver->probe_order != order) - return 0; - - ret = snd_soc_dai_probe(dai); - if (ret < 0) { - dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n", - dai->name, ret); - return ret; - } - - dai->probed = 1; - - return 0; -} - static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, struct snd_soc_pcm_runtime *rtd) { -- cgit v1.2.3 From c4b4698291a1d1c55665ae906779d1b685d5aa66 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2019 09:15:12 +0900 Subject: ASoC: soc-core: add new soc_link_init() Current soc_probe_link_dais() (1) is called under probe_order (2), and it will initialize dai_link related settings at *Last* turn (3)(B). It is very complex code. static int soc_probe_link_dais(..., order) { (A) /* probe DAIs here */ ... (3) if (order != SND_SOC_COMP_ORDER_LAST) return 0; (B) /* initialize dai_link related settings */ ... } static int snd_soc_instantiate_card(...) { ... (2) for_each_comp_order(order) { for_each_card_rtds(...) { (1) ret = soc_probe_link_dais(..., order); } } } This patch separes soc_probe_link_dais() into "DAI probe" portion (A), and dai_link settings portion (B). The later is named as soc_link_init() by this patch. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y2z4or1r.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3ca5a21bfa6a..1e74ab8e6a25 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1455,19 +1455,13 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, static int soc_probe_link_dais(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; struct snd_soc_dai *codec_dai; - int i, ret, num; + int i, ret; dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", card->name, rtd->num, order); - /* set default power off timeout */ - rtd->pmdown_time = pmdown_time; - ret = soc_probe_dai(cpu_dai, order); if (ret) return ret; @@ -1479,9 +1473,20 @@ static int soc_probe_link_dais(struct snd_soc_card *card, return ret; } - /* complete DAI probe during last probe */ - if (order != SND_SOC_COMP_ORDER_LAST) - return 0; + return 0; +} + +static int soc_link_init(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai_link *dai_link = rtd->dai_link; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + int ret, num; + + /* set default power off timeout */ + rtd->pmdown_time = pmdown_time; /* do machine specific initialization */ if (dai_link->init) { @@ -2041,6 +2046,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } } + for_each_card_rtds(card, rtd) + soc_link_init(card, rtd); + snd_soc_dapm_link_dai_widgets(card); snd_soc_dapm_connect_dai_link_widgets(card); -- cgit v1.2.3 From c7e73774f2f4213e75670f393a7b253620e04441 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2019 09:15:17 +0900 Subject: ASoC: soc-core: self contained soc_probe_link_dais() Current soc_probe_link_dais() implementation is very half, thus it is very difficult to read. for_each_comp_order(xxx) { for_each_card_rtds(xxx) => soc_probe_link_dais(xxx); } This patch does all for_each_xxx() under soc_probe_link_dais(), and makes it to self contained. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87woeoor1m.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1e74ab8e6a25..36b86e3c193c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1452,25 +1452,30 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, return 0; } -static int soc_probe_link_dais(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, int order) +static int soc_probe_link_dais(struct snd_soc_card *card) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; - int i, ret; + struct snd_soc_pcm_runtime *rtd; + int i, order, ret; - dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", - card->name, rtd->num, order); + for_each_comp_order(order) { + for_each_card_rtds(card, rtd) { - ret = soc_probe_dai(cpu_dai, order); - if (ret) - return ret; + dev_dbg(card->dev, + "ASoC: probe %s dai link %d late %d\n", + card->name, rtd->num, order); - /* probe the CODEC DAI */ - for_each_rtd_codec_dai(rtd, i, codec_dai) { - ret = soc_probe_dai(codec_dai, order); - if (ret) - return ret; + ret = soc_probe_dai(rtd->cpu_dai, order); + if (ret) + return ret; + + /* probe the CODEC DAI */ + for_each_rtd_codec_dai(rtd, i, codec_dai) { + ret = soc_probe_dai(codec_dai, order); + if (ret) + return ret; + } + } } return 0; @@ -1933,7 +1938,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link *dai_link; struct snd_soc_aux_dev *aux; - int ret, i, order; + int ret, i; mutex_lock(&client_mutex); for_each_card_prelinks(card, i, dai_link) { @@ -2034,16 +2039,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* probe all DAI links on this card */ - for_each_comp_order(order) { - for_each_card_rtds(card, rtd) { - ret = soc_probe_link_dais(card, rtd, order); - if (ret < 0) { - dev_err(card->dev, - "ASoC: failed to instantiate card %d\n", - ret); - goto probe_end; - } - } + ret = soc_probe_link_dais(card); + if (ret < 0) { + dev_err(card->dev, + "ASoC: failed to instantiate card %d\n", ret); + goto probe_end; } for_each_card_rtds(card, rtd) -- cgit v1.2.3 From bc7c16c226a919a509e4161c905bfe9981a17f02 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2019 09:15:23 +0900 Subject: ASoC: soc-core: move soc_probe_link_dais() next to soc_remove_link_dais() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and it will be difficult to debug. This patch moves soc_probe_link_dais() next to soc_remove_link_dais() which is paired function. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v9u8or1g.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 58 ++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 36b86e3c193c..20381f69a34b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1149,6 +1149,35 @@ static void soc_remove_link_dais(struct snd_soc_card *card) } } +static int soc_probe_link_dais(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai; + struct snd_soc_pcm_runtime *rtd; + int i, order, ret; + + for_each_comp_order(order) { + for_each_card_rtds(card, rtd) { + + dev_dbg(card->dev, + "ASoC: probe %s dai link %d late %d\n", + card->name, rtd->num, order); + + ret = soc_probe_dai(rtd->cpu_dai, order); + if (ret) + return ret; + + /* probe the CODEC DAI */ + for_each_rtd_codec_dai(rtd, i, codec_dai) { + ret = soc_probe_dai(codec_dai, order); + if (ret) + return ret; + } + } + } + + return 0; +} + static void soc_remove_link_components(struct snd_soc_card *card) { struct snd_soc_component *component; @@ -1452,35 +1481,6 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, return 0; } -static int soc_probe_link_dais(struct snd_soc_card *card) -{ - struct snd_soc_dai *codec_dai; - struct snd_soc_pcm_runtime *rtd; - int i, order, ret; - - for_each_comp_order(order) { - for_each_card_rtds(card, rtd) { - - dev_dbg(card->dev, - "ASoC: probe %s dai link %d late %d\n", - card->name, rtd->num, order); - - ret = soc_probe_dai(rtd->cpu_dai, order); - if (ret) - return ret; - - /* probe the CODEC DAI */ - for_each_rtd_codec_dai(rtd, i, codec_dai) { - ret = soc_probe_dai(codec_dai, order); - if (ret) - return ret; - } - } - } - - return 0; -} - static int soc_link_init(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd) { -- cgit v1.2.3 From bee886f1ea9d9e58bef8204c543a409c399f8744 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2019 09:15:28 +0900 Subject: ASoC: soc-core: self contained soc_bind_aux_dev() Current soc_bind_aux_dev() implementation is very half, thus it is very unreadable. for_each_card_pre_auxs(xxx) { => ret = soc_bind_aux_dev(xxx); ... } This patch does all for_each_xxx() under soc_bind_aux_dev(), and makes it to self contained. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tv9sor1b.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 20381f69a34b..d7761df03e19 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1559,20 +1559,22 @@ static int soc_link_init(struct snd_soc_card *card, return ret; } -static int soc_bind_aux_dev(struct snd_soc_card *card, - struct snd_soc_aux_dev *aux_dev) +static int soc_bind_aux_dev(struct snd_soc_card *card) { struct snd_soc_component *component; + struct snd_soc_aux_dev *aux; + int i; - /* codecs, usually analog devices */ - component = soc_find_component(&aux_dev->dlc); - if (!component) - return -EPROBE_DEFER; - - component->init = aux_dev->init; - /* see for_each_card_auxs */ - list_add(&component->card_aux_list, &card->aux_comp_list); + for_each_card_pre_auxs(card, i, aux) { + /* codecs, usually analog devices */ + component = soc_find_component(&aux->dlc); + if (!component) + return -EPROBE_DEFER; + component->init = aux->init; + /* see for_each_card_auxs */ + list_add(&component->card_aux_list, &card->aux_comp_list); + } return 0; } @@ -1937,7 +1939,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link *dai_link; - struct snd_soc_aux_dev *aux; int ret, i; mutex_lock(&client_mutex); @@ -1965,11 +1966,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* bind aux_devs too */ - for_each_card_pre_auxs(card, i, aux) { - ret = soc_bind_aux_dev(card, aux); - if (ret != 0) - goto probe_end; - } + ret = soc_bind_aux_dev(card); + if (ret < 0) + goto probe_end; /* add predefined DAI links to the list */ for_each_card_prelinks(card, i, dai_link) { -- cgit v1.2.3 From 4893a2eb34a9722501915a0b75844aa11956c10d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2019 09:15:35 +0900 Subject: ASoC: soc-core: add soc_unbind_aux_dev() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and it will be difficult to debug. soc-core.c has soc_bind_aux_dev(), but, there is no its paired soc_unbind_aux_dev(). This patch adds soc_unbind_aux_dev(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sgpcor14.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d7761df03e19..2960070e68bc 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1559,6 +1559,12 @@ static int soc_link_init(struct snd_soc_card *card, return ret; } +static void soc_unbind_aux_dev(struct snd_soc_component *component) +{ + component->init = NULL; + list_del(&component->card_aux_list); +} + static int soc_bind_aux_dev(struct snd_soc_card *card) { struct snd_soc_component *component; @@ -1612,7 +1618,7 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) if (comp->driver->remove_order == order) { soc_remove_component(comp); /* remove it from the card's aux_comp_list */ - list_del(&comp->card_aux_list); + soc_unbind_aux_dev(comp); } } } -- cgit v1.2.3 From e8fbd2505242467044ec51bf57c642a50ed28a14 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Sep 2019 09:15:40 +0900 Subject: ASoC: soc-core: self contained soc_unbind_aux_dev() Current soc_unbind_aux_dev() implementation is very half, thus it is very unreadable. for_each_comp_order(order) { for_each_card_auxs_safe(card, comp, _comp) { (1) if (comp->driver->remove_order == order) { ... => soc_unbind_aux_dev(comp); } } soc_unbind_aux_dev() itself is not related to remove_order (1). And, it is called from soc_remove_aux_devices(), even though its paired function soc_bind_aux_dev() is called from snd_soc_instantiate_card(). It is very unbalance, and very difficult to understand. This patch do 1) update soc_bind_aux_dev() to self contained 2) call it from soc_cleanup_card_resources() to make up balance Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r24wor0z.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2960070e68bc..35f48e9c5ead 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1559,10 +1559,14 @@ static int soc_link_init(struct snd_soc_card *card, return ret; } -static void soc_unbind_aux_dev(struct snd_soc_component *component) +static void soc_unbind_aux_dev(struct snd_soc_card *card) { - component->init = NULL; - list_del(&component->card_aux_list); + struct snd_soc_component *component, *_component; + + for_each_card_auxs_safe(card, component, _component) { + component->init = NULL; + list_del(&component->card_aux_list); + } } static int soc_bind_aux_dev(struct snd_soc_card *card) @@ -1614,12 +1618,8 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) for_each_comp_order(order) { for_each_card_auxs_safe(card, comp, _comp) { - - if (comp->driver->remove_order == order) { + if (comp->driver->remove_order == order) soc_remove_component(comp); - /* remove it from the card's aux_comp_list */ - soc_unbind_aux_dev(comp); - } } } } @@ -1932,6 +1932,7 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) /* remove auxiliary devices */ soc_remove_aux_devices(card); + soc_unbind_aux_dev(card); snd_soc_dapm_free(&card->dapm); soc_cleanup_card_debugfs(card); -- cgit v1.2.3 From 33b773dc9288eb15d3216628d1d2381103d854a9 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Fri, 6 Sep 2019 12:46:23 -0700 Subject: ASoC: rt5677: Remove magic number register writes In order to simplify understanding what register values are being written to the codec for debugging more advanced features (such as hotwording) it is best to remove magic numbers Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20190906194636.217881-2-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index c779dc3474f9..5b6ca3ced13b 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -691,10 +691,12 @@ static void rt5677_set_dsp_mode(struct snd_soc_component *component, bool on) struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); if (on) { - regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x2); + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, + RT5677_PWR_DSP, RT5677_PWR_DSP); rt5677->is_dsp_mode = true; } else { - regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x0); + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, + RT5677_PWR_DSP, 0x0); rt5677->is_dsp_mode = false; } } @@ -4466,7 +4468,8 @@ static int rt5677_set_bias_level(struct snd_soc_component *component, regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, - 0x0055); + 5 << RT5677_LDO1_SEL_SFT | + 5 << RT5677_LDO2_SEL_SFT); regmap_update_bits(rt5677->regmap, RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00); @@ -4491,7 +4494,9 @@ static int rt5677_set_bias_level(struct snd_soc_component *component, regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x0); regmap_write(rt5677->regmap, RT5677_PWR_DIG1, 0x0000); regmap_write(rt5677->regmap, RT5677_PWR_DIG2, 0x0000); - regmap_write(rt5677->regmap, RT5677_PWR_ANLG1, 0x0022); + regmap_write(rt5677->regmap, RT5677_PWR_ANLG1, + 2 << RT5677_LDO1_SEL_SFT | + 2 << RT5677_LDO2_SEL_SFT); regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000); regmap_update_bits(rt5677->regmap, RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000); @@ -4719,7 +4724,8 @@ static int rt5677_probe(struct snd_soc_component *component) regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, ~RT5677_IRQ_DEBOUNCE_SEL_MASK, 0x0020); - regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00); + regmap_write(rt5677->regmap, RT5677_PWR_DSP2, + RT5677_PWR_SLIM_ISO | RT5677_PWR_CORE_ISO); for (i = 0; i < RT5677_GPIO_NUM; i++) rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]); -- cgit v1.2.3 From dfe58f2011595e7512bde9dffbd0abfc3a736ab7 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Fri, 6 Sep 2019 12:46:24 -0700 Subject: ASoC: rt5677: keep analog power register at SND_SOC_BIAS_OFF Instead of clearing RT5677_PWR_ANLG2 (MX-64h) to 0 at SND_SOC_BIAS_OFF, we only clear the RT5677_PWR_CORE bit which is set at SND_SOC_BIAS_PREPARE. MICBIAS control bits are left unchanged. This fixed the bug where if MICBIAS1 widget is forced on, MICBIAS control bits will be cleared at suspend and never turned back on again, since DAPM thinks the widget is always on. Signed-off-by: Ben Zhang Signed-off-by: Curtis Malainey Link: https://lore.kernel.org/r/20190906194636.217881-3-cujomalainey@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 5b6ca3ced13b..315a3d39bc09 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4493,11 +4493,11 @@ static int rt5677_set_bias_level(struct snd_soc_component *component, case SND_SOC_BIAS_OFF: regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x0); regmap_write(rt5677->regmap, RT5677_PWR_DIG1, 0x0000); - regmap_write(rt5677->regmap, RT5677_PWR_DIG2, 0x0000); regmap_write(rt5677->regmap, RT5677_PWR_ANLG1, 2 << RT5677_LDO1_SEL_SFT | 2 << RT5677_LDO2_SEL_SFT); - regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000); + regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, + RT5677_PWR_CORE, 0); regmap_update_bits(rt5677->regmap, RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000); -- cgit v1.2.3 From 6fa5963c37a2e3335eba0b7455e35a01318ebc15 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Wed, 17 Jul 2019 16:33:23 +0800 Subject: ASoC: hdmi-codec: Add an op to set callback function for plug event Add an op in hdmi_codec_ops so codec driver can register callback function to handle plug event. Driver in DRM can use this callback function to report connector status. Signed-off-by: Cheng-Yi Chiang Link: https://lore.kernel.org/r/20190717083327.47646-2-cychiang@chromium.org Reviewed-by: Tzung-Bi Shih Signed-off-by: Mark Brown --- include/sound/hdmi-codec.h | 17 ++++++++++++++++ sound/soc/codecs/hdmi-codec.c | 46 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) (limited to 'sound') diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h index 7fea496f1f34..83b17682e01c 100644 --- a/include/sound/hdmi-codec.h +++ b/include/sound/hdmi-codec.h @@ -47,6 +47,9 @@ struct hdmi_codec_params { int channels; }; +typedef void (*hdmi_codec_plugged_cb)(struct device *dev, + bool plugged); + struct hdmi_codec_pdata; struct hdmi_codec_ops { /* @@ -88,6 +91,14 @@ struct hdmi_codec_ops { */ int (*get_dai_id)(struct snd_soc_component *comment, struct device_node *endpoint); + + /* + * Hook callback function to handle connector plug event. + * Optional + */ + int (*hook_plugged_cb)(struct device *dev, void *data, + hdmi_codec_plugged_cb fn, + struct device *codec_dev); }; /* HDMI codec initalization data */ @@ -99,6 +110,12 @@ struct hdmi_codec_pdata { void *data; }; +struct snd_soc_component; +struct snd_soc_jack; + +int hdmi_codec_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack); + #define HDMI_CODEC_DRV_NAME "hdmi-audio-codec" #endif /* __HDMI_CODEC_H__ */ diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 0bf1c8cad108..b5fd8f08726e 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -274,6 +275,8 @@ struct hdmi_codec_priv { struct snd_pcm_chmap *chmap_info; unsigned int chmap_idx; struct mutex lock; + struct snd_soc_jack *jack; + unsigned int jack_status; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { @@ -663,6 +666,49 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai) return 0; } +static void hdmi_codec_jack_report(struct hdmi_codec_priv *hcp, + unsigned int jack_status) +{ + if (hcp->jack && jack_status != hcp->jack_status) { + snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_LINEOUT); + hcp->jack_status = jack_status; + } +} + +static void plugged_cb(struct device *dev, bool plugged) +{ + struct hdmi_codec_priv *hcp = dev_get_drvdata(dev); + + if (plugged) + hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT); + else + hdmi_codec_jack_report(hcp, 0); +} + +/** + * hdmi_codec_set_jack_detect - register HDMI plugged callback + * @component: the hdmi-codec instance + * @jack: ASoC jack to report (dis)connection events on + */ +int hdmi_codec_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); + int ret = -EOPNOTSUPP; + + if (hcp->hcd.ops->hook_plugged_cb) { + hcp->jack = jack; + ret = hcp->hcd.ops->hook_plugged_cb(component->dev->parent, + hcp->hcd.data, + plugged_cb, + component->dev); + if (ret) + hcp->jack = NULL; + } + return ret; +} +EXPORT_SYMBOL_GPL(hdmi_codec_set_jack_detect); + static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) { struct hdmi_codec_daifmt *cf = dai->playback_dma_data; -- cgit v1.2.3